URL
https://opencores.org/ocsvn/wb2axip/wb2axip/trunk
Subversion Repositories wb2axip
Compare Revisions
- This comparison shows the changes necessary to convert path
/wb2axip
- from Rev 15 to Rev 16
- ↔ Reverse comparison
Rev 15 → Rev 16
/trunk/Makefile
34,7 → 34,7
## |
## |
.PHONY: all |
all: archive rtl bench |
all: archive rtl formal |
# all: verilated sw bench bit |
# |
# Could also depend upon load, if desired, but not necessary |
58,6 → 58,10
bench: rtl |
cd bench/cpp ; $(MAKE) --no-print-directory |
|
.PHONY: formal |
formal: |
$(MAKE) --no-print-directory -C bench/formal |
|
.PHONY: doc |
doc: |
cd doc ; $(MAKE) --no-print-directory |
/trunk/README.md
14,40 → 14,42
transaction per clock (pipelined), although [(due to Xilinx's MIG design) |
the delay may be up to 27 clocks](http://opencores.org/project,wbddr3). (Ouch!) |
|
Since the initial build of the core, I've added the |
[WB to AXI lite](rtl/wbm2axilite.v) bridge. This is also a pipelined bridge, |
and like the original one it is also formally verified. |
|
# AXI to Wishbone conversion |
|
Since the project began, a full-fledged [AXI4 to Wishbone bridge](rtl/axim2wbsp.v) has been added to the project. |
This converter handles synchronizing the write channels, turning AXI read/write |
requests into pipeline wishbone requests, maintaining the AXI ID fields, etc. |
It ignores the AXI xSIZE, xLOCK, xCACHE, xPROT, and xQOS fields. It supports |
xBURST types of FIXED (2'b00) and INCR (2'b01), but not WRAP (2'b10) or |
reserved (2'b11). It does not (yet) support bridging between busses of |
different widths, so both the AXI and the WB bus must have the same width. |
As of 20181228, the project now contains an |
[AXI4 lite read channel to wishbone interface](rtl/axilrd2wbsp.v), and also an |
[AXI4 lite write channel to wishbone interface](rtl/axilwr2wbsp.v). |
A third core, the [AXI-lite to WB core](rtl/axlite2wbsp.v) combines these |
two together using a [Wishbone arbiter](rtl/wbartbiter.v). All four of these |
designs have been formally verified, and should be reliable to use. |
|
AXI4 is a complicated protocol, however, especially when |
[compared to WB](http://zipcpu.com/zipcpu/2017/11/07/wb-formal.html). |
As of 20190101, [this AXI-lite to WB bridge](rtl/axlite2wbsp.v) has been |
FPGA proven. |
|
_Finally, whereas the [bridge](rtl/axim2wbsp.v) has been written, it has yet |
to be significantly tested or formally proven. If you are interested in |
helping to test it, please contact me at (zipcpu (at) gmail.com). Until |
that time, it must be said that the result is subject to change._ |
The full AXI4 protocol, however, is rather complicated--especially when |
[compared to WB](http://zipcpu.com/zipcpu/2017/11/07/wb-formal.html). As a |
result, while there is a full-fledged |
[AXI4 to Wishbone bridge](rtl/axim2wbsp.v) within this project, |
this bridge is still not ready for prime time. It is designed to |
synchronize the write channels, turning AXI read/write requests into pipeline |
wishbone requests, maintaining the AXI ID fields, handle burst transactions, |
etc. As designed, it ignores the AXI xSIZE, xLOCK, xCACHE, xPROT, and xQOS |
fields, while supporting xBURST types of FIXED (2'b00) and INCR (2'b01) |
but not WRAP (2'b10) or reserved (2'b11). The design supports bridging |
between busses of different widths. The only problem is ... |
this full AXI4 to WB converter _doesn't work_ (yet). I know this because it |
doesn't yet pass formal verification. |
|
# Formal Verification |
|
This particular version of the tools includes an initial attempt at |
formally proving that the core(s) work. |
|
Currently, the project contains formal specifications for |
[Avalon](bench/formal/fav_slave.v), [Wishbone](bench/formal/fwb_slave.v), and |
[AXI](bench/formal/faxi_slave.v) busses. Components with working proofs |
include the [WB to AXI](rtl/wbm2axisp.v) bridge as well as the |
[WB arbiter](rtl/wbarbiter.v) needed for the [AXI to WB](rtl/axim2wbsp.v). |
I also have a working proof for an Avalon to WB bridge that isn't posted |
here. |
[AXI](bench/formal/faxi_slave.v) busses. |
|
The [AXI4 to Wishbone bridge](rtl/axim2wbsp.v) remains a work in progress |
that isn't getting a lot of attention. |
|
# Commercial Applications |
|
Should you find the GPLv3 license insufficient for your needs, other licenses |
57,5 → 59,6
|
I'd like to thank @wallento for his initial work on a |
[Wishbone to AXI converter](https://github.com/wallento/wb2axi), and his |
encouragement to improve upon it. While this isn't a fork of his work, it |
takes its motivation from his work. |
encouragement to improve upon it. While this isn't a fork of his work, the |
[pipelined wishbone to AXI bridge](rtl/wbm2axisp.v) took its initial |
motivation from his work. |
/trunk/bench/cpp/aximemsim.cpp
11,27 → 11,30
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2016-2018, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
/trunk/bench/cpp/aximemsim.h
14,27 → 14,30
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2016-2018, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
/trunk/bench/formal/Makefile
15,30 → 15,34
## |
################################################################################ |
## |
## Copyright (C) 2017, Gisselquist Technology, LLC |
## Copyright (C) 2017-2018, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## This file is part of the pipelined Wishbone to AXI converter project, a |
## project that contains multiple bus bridging designs and formal bus property |
## sets. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## The bus bridge designs and property sets are free RTL designs: you can |
## redistribute them and/or modify any of them under the terms of the GNU |
## Lesser General Public License as published by the Free Software Foundation, |
## either version 3 of the License, or (at your option) any later version. |
## |
## You should have received a copy of the GNU General Public License along |
## with this program. (It's in the $(ROOT)/doc directory. Run make with no |
## target there if the PDF file isn't present.) If not, see |
## The bus bridge designs and property sets are distributed in the hope that |
## they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
## warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
## GNU Lesser General Public License for more details. |
## |
## You should have received a copy of the GNU Lesser General Public License |
## along with these designs. (It's in the $(ROOT)/doc directory. Run make |
## with no target there if the PDF file isn't present.) If not, see |
## <http://www.gnu.org/licenses/> for a copy. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## License: LGPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/lgpl.html |
## |
################################################################################ |
## |
## |
TESTS := wbm2axisp wbarbiter # axim2wbsp |
TESTS := wbarbiter wbm2axilite axilrd2wbsp axilwr2wbsp demoaxi axlite2wbsp wbxbar # wbm2axisp axim2wbsp |
.PHONY: $(TESTS) |
all: $(TESTS) |
RTL := ../../rtl |
50,45 → 54,214
# BMCARGS := $(SOLVER) |
INDARGS := $(SOLVER) -i |
|
WBARB := wbarbiter |
WB2AXI := wbm2axisp |
AXI2WB := axim2wbsp |
DEMOAXI := demoaxi |
WBARB := wbarbiter |
WB2AXI := wbm2axisp |
AXI2WB := axim2wbsp |
WB2LITE := wbm2axilite |
RDLITE := axilrd2wbsp |
WRLITE := axilwr2wbsp |
AXLITE := axlite2wbsp |
XILINXDEMO := xlnxdemo |
WBXBAR := wbxbar |
WBXBAR4x8 := wbxbar4x8 |
WBXBAR1x8 := wbxbar1x8 |
WBXBAR4x1 := wbxbar4x1 |
WB := fwb_master.v fwb_slave.v |
|
$(WBARB).smt2: $(RTL)/$(WBARB).v fwb_master.v fwb_slave.v $(WBARB).ys |
yosys -ql $(WBARB).yslog -s $(WBARB).ys |
.PHONY: $(WBARB) $(WB2AXI) $(RDLITE) $(WRLITE) $(AXLITE) $(WB2LITE) $(DEMOAXI) |
|
$(WB2AXI).smt2: $(RTL)/$(WB2AXI).v $(WB2AXI).ys fwb_slave.v faxi_master.v |
yosys -ql $(WB2AXI).yslog -s $(WB2AXI).ys |
$(WBARB): $(WBARB)_prf/PASS $(WBARB)_cvr/PASS |
$(WBARB)_prf/PASS: $(RTL)/$(WBARB).v $(WBARB).sby $(WB) |
sby -f $(WBARB).sby |
$(WBARB)_cvr/PASS: $(RTL)/$(WBARB).v $(WBARB).sby $(WB) |
sby -f $(WBARB).sby |
|
$(AXI2WB).smt2: $(RTL)/$(AXI2WB).v $(AXI2WB).ys fwb_master.v faxi_slave.v |
$(AXI2WB).smt2: $(RTL)/aximwr2wbsp.v $(RTL)/aximrd2wbsp.v |
$(AXI2WB).smt2: $(RTL)/wbarbiter.v |
yosys -ql $(AXI2WB).yslog -s $(AXI2WB).ys |
.PHONY: $(WB2AXI) |
$(WB2AXI): $(WB2AXI)/PASS |
$(WB2AXI)/PASS: $(RTL)/$(WB2AXI).v $(WB2AXI).sby $(WB) |
sby -f $(WB2AXI).sby |
|
$(WBARB) : $(WBARB).check |
$(WBARB).check: $(WBARB).smt2 |
rm -f $@ |
$(SMTBMC) $(BMCARGS) -t 36 --dump-vcd $(WBARB).vcd $(WBARB).smt2 |
$(SMTBMC) $(INDARGS) -t 32 --dump-vcd $(WBARB).vcd $(WBARB).smt2 |
touch $@ |
$(RDLITE): $(RDLITE)_prf/PASS $(RDLITE)_cvr/PASS |
$(RDLITE)_prf/PASS: $(RDLITE).sby $(RTL)/$(RDLITE).v $(WB) |
sby -f $(RDLITE).sby prf |
$(RDLITE)_cvr/PASS: $(RDLITE).sby $(RTL)/$(RDLITE).v $(WB) |
sby -f $(RDLITE).sby cvr |
|
$(WB2AXI) : $(WB2AXI).check |
$(WB2AXI).check: $(WB2AXI).smt2 |
rm -f $@ |
$(SMTBMC) $(BMCARGS) -t 36 --dump-vcd $(WB2AXI).vcd $(WB2AXI).smt2 |
$(SMTBMC) $(INDARGS) -t 32 --dump-vcd $(WB2AXI).vcd $(WB2AXI).smt2 |
touch $@ |
$(WRLITE): $(WRLITE)_prf/PASS $(WRLITE)_cvr/PASS |
$(WRLITE)_prf/PASS: $(WRLITE).sby $(RTL)/$(WRLITE).v $(WB) |
sby -f $(WRLITE).sby prf |
$(WRLITE)_cvr/PASS: $(WRLITE).sby $(RTL)/$(WRLITE).v $(WB) |
sby -f $(WRLITE).sby cvr |
|
$(AXI2WB) : $(AXI2WB).check |
$(AXI2WB).check: $(AXI2WB).smt2 |
rm -f $@ |
$(SMTBMC) $(BMCARGS) -t 60 --dump-vcd $(AXI2WB).vcd $(AXI2WB).smt2 |
$(SMTBMC) $(INDARGS) -t 58 --dump-vcd $(AXI2WB).vcd $(AXI2WB).smt2 |
touch $@ |
$(AXLITE): $(AXLITE)_prf/PASS $(AXLITE)_cvr/PASS |
AXLITE_DEPS := $(RTL)/$(RDLITE).v $(RTL)/$(WRLITE).v \ |
$(RTL)/$(WBARB).v fwb_master.v faxil_slave.v \ |
$(AXLITE).sby $(RTL)/$(AXLITE).v \ |
$(RDLITE)_prf/PASS $(RDLITE)_cvr/PASS \ |
$(WRLITE)_prf/PASS $(WRLITE)_cvr/PASS |
|
$(AXLITE)_prf/PASS: $(AXLITE_DEPS) |
sby -f $(AXLITE).sby prf |
|
$(AXLITE)_cvr/PASS: $(AXLITE_DEPS) |
sby -f $(AXLITE).sby cvr |
|
.PHONY: $(WB2LITE) |
$(WB2LITE): $(WB2LITE)_cvr/PASS $(WB2LITE)_prf/PASS |
$(WB2LITE)_prf/PASS: $(RTL)/$(WB2LITE).v |
$(WB2LITE)_prf/PASS: $(WB2LITE).sby fwb_slave.v faxil_master.v |
sby -f $(WB2LITE).sby prf |
|
$(WB2LITE)_cvr/PASS: $(RTL)/$(WB2LITE).v |
$(WB2LITE)_cvr/PASS: $(WB2LITE).sby fwb_slave.v faxil_master.v |
sby -f $(WB2LITE).sby cvr |
|
$(DEMOAXI): $(DEMOAXI)_prf/PASS $(DEMOAXI)_cvr/PASS |
$(DEMOAXI)_prf/PASS: $(RTL)/$(DEMOAXI).v $(DEMOAXI).sby faxil_slave.v |
sby -f $(DEMOAXI).sby prf |
$(DEMOAXI)_cvr/PASS: $(RTL)/$(DEMOAXI).v $(DEMOAXI).sby faxil_slave.v |
sby -f $(DEMOAXI).sby cvr |
|
.PHONY: $(XILINXDEMO) |
$(XILINXDEMO): $(XILINXDEMO)_prf/PASS $(XILINXDEMO)_cvr/PASS |
$(XILINXDEMO)_prf/PASS: $(XILINXDEMO).v $(XILINXDEMO).sby faxil_slave.v |
sby -f $(XILINXDEMO).sby prf |
$(XILINXDEMO)_cvr/PASS: $(XILINXDEMO).v $(XILINXDEMO).sby faxil_slave.v |
sby -f $(XILINXDEMO).sby cvr |
|
|
.PHONY: $(AXI2WB) |
$(AXI2WB)/PASS: $(RTL)/$(AXI2WB).v $(AXI2WB).sby |
$(AXI2WB)/PASS: $(WB) |
$(AXI2WB)/PASS: faxi_slave.v |
$(AXI2WB)/PASS: f_order.v |
$(AXI2WB)/PASS: $(RTL)/aximwr2wbsp.v $(RTL)/aximrd2wbsp.v |
$(AXI2WB)/PASS: $(RTL)/wbarbiter.v |
echo "The AXI2WB bridge does not work yet, so I do not expect this one to pass" |
echo sby -f $(AXI2WB).sby |
|
.PHONY: $(WBXBAR) $(WBXBAR4x8) $(WBXBAR1x8) $(WBXBAR4x1) |
$(WBXBAR): $(WBXBAR4x8) $(WBXBAR1x8) $(WBXBAR4x1) |
$(WBXBAR4x8): wbxbar_prf4x8_buflp/PASS |
wbxbar_prf4x8_buflp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_buflp |
$(WBXBAR4x8): wbxbar_prf4x8_buf/PASS |
wbxbar_prf4x8_buf/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_buf |
$(WBXBAR4x8): wbxbar_prf4x8_lp/PASS |
wbxbar_prf4x8_lp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_lp |
$(WBXBAR4x8): wbxbar_prf4x8_cheap/PASS |
wbxbar_prf4x8_cheap/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_cheap |
$(WBXBAR4x8): wbxbar_prf4x8_buflpko/PASS |
wbxbar_prf4x8_buflpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_buflpko |
$(WBXBAR4x8): wbxbar_prf4x8_bufko/PASS |
wbxbar_prf4x8_bufko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_bufko |
$(WBXBAR4x8): wbxbar_prf4x8_lpko/PASS |
wbxbar_prf4x8_lpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_lpko |
$(WBXBAR4x8): wbxbar_prf4x8_cheapko/PASS |
wbxbar_prf4x8_cheapko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_cheapko |
$(WBXBAR4x8): wbxbar_prf4x8_buflpkos/PASS |
wbxbar_prf4x8_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_buflpkos |
$(WBXBAR4x8): wbxbar_prf4x8_bufkos/PASS |
wbxbar_prf4x8_bufkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_bufkos |
$(WBXBAR4x8): wbxbar_prf4x8_lpkos/PASS |
wbxbar_prf4x8_lpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_lpkos |
$(WBXBAR4x8): wbxbar_prf4x8_cheapkos/PASS |
wbxbar_prf4x8_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x8_cheapkos |
$(WBXBAR1x8): wbxbar_prf1x8_buflp/PASS |
wbxbar_prf1x8_buflp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_buflp |
$(WBXBAR1x8): wbxbar_prf1x8_buf/PASS |
wbxbar_prf1x8_buf/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_buf |
$(WBXBAR1x8): wbxbar_prf1x8_lp/PASS |
wbxbar_prf1x8_lp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_lp |
$(WBXBAR1x8): wbxbar_prf1x8_cheap/PASS |
wbxbar_prf1x8_cheap/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_cheap |
$(WBXBAR1x8): wbxbar_prf1x8_buflpko/PASS |
wbxbar_prf1x8_buflpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_buflpko |
$(WBXBAR1x8): wbxbar_prf1x8_bufko/PASS |
wbxbar_prf1x8_bufko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_bufko |
$(WBXBAR1x8): wbxbar_prf1x8_lpko/PASS |
wbxbar_prf1x8_lpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_lpko |
$(WBXBAR1x8): wbxbar_prf1x8_cheapko/PASS |
wbxbar_prf1x8_cheapko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_cheapko |
$(WBXBAR1x8): wbxbar_prf1x8_buflpkos/PASS |
wbxbar_prf1x8_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_buflpkos |
$(WBXBAR1x8): wbxbar_prf1x8_bufkos/PASS |
wbxbar_prf1x8_bufkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_bufkos |
$(WBXBAR1x8): wbxbar_prf1x8_lpkos/PASS |
wbxbar_prf1x8_lpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_lpkos |
$(WBXBAR1x8): wbxbar_prf1x8_cheapkos/PASS |
wbxbar_prf1x8_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf1x8_cheapkos |
$(WBXBAR4x1): wbxbar_prf4x1_buflp/PASS |
wbxbar_prf4x1_buflp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_buflp |
$(WBXBAR4x1): wbxbar_prf4x1_buf/PASS |
wbxbar_prf4x1_buf/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_buf |
$(WBXBAR4x1): wbxbar_prf4x1_lp/PASS |
wbxbar_prf4x1_lp/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_lp |
$(WBXBAR4x1): wbxbar_prf4x1_cheap/PASS |
wbxbar_prf4x1_cheap/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_cheap |
$(WBXBAR4x1): wbxbar_prf4x1_buflpko/PASS |
wbxbar_prf4x1_buflpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_buflpko |
$(WBXBAR4x1): wbxbar_prf4x1_bufko/PASS |
wbxbar_prf4x1_bufko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_bufko |
$(WBXBAR4x1): wbxbar_prf4x1_lpko/PASS |
wbxbar_prf4x1_lpko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_lpko |
$(WBXBAR4x1): wbxbar_prf4x1_cheapko/PASS |
wbxbar_prf4x1_cheapko/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_cheapko |
$(WBXBAR4x1): wbxbar_prf4x1_buflpkos/PASS |
wbxbar_prf4x1_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_buflpkos |
$(WBXBAR4x1): wbxbar_prf4x1_bufkos/PASS |
wbxbar_prf4x1_bufkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_bufkos |
$(WBXBAR4x1): wbxbar_prf4x1_lpkos/PASS |
wbxbar_prf4x1_lpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_lpkos |
$(WBXBAR4x1): wbxbar_prf4x1_cheapkos/PASS |
wbxbar_prf4x1_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) |
sby -f $(WBXBAR).sby prf4x1_cheapkos |
|
.PHONY: clean |
clean: |
rm -f $(WBARB).smt2 $(WBARB).yslog $(WBARB)*.vcd |
rm -f $(WB2AXI).smt2 $(WB2AXI).yslog $(WB2AXI)*.vcd |
rm -f $(AXI2WB).smt2 $(AXI2WB).yslog $(AXI2WB)*.vcd |
rm -f *.check |
rm -rf $(WBARB)_prf/ $(WBARB)_cvr/ |
rm -rf $(WB2LITE)_cvr/ $(WB2LITE)_prf/ |
rm -rf $(RDLITE)_cvr/ $(RDLITE)_prf |
rm -rf $(WRLITE)_cvr/ $(WRLITE)_prf |
rm -rf $(AXLITE)_cvr/ $(AXLITE)_prf |
rm -rf $(DEMOAXI)_cvr/ $(DEMOAXI)_prf |
@# The three broken cores, to include Xilinx's |
rm -rf $(WB2AXI)/ |
rm -rf $(AXI2WB)/ |
rm -rf $(XILINXDEMO)_cvr/ $(XILINXDEMO)_prf |
# rm -f *.check |
/trunk/bench/formal/axilrd2wbsp.gtkw
0,0 → 1,70
[*] |
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI |
[*] Fri Dec 28 05:15:33 2018 |
[*] |
[dumpfile] "(null)" |
[savefile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/axilrd2wbsp.gtkw" |
[timestart] 0 |
[size] 1898 600 |
[pos] -1 -1 |
*-5.054117 210 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[sst_width] 270 |
[signals_width] 210 |
[sst_expanded] 1 |
[sst_vpaned_height] 143 |
@28 |
[color] 3 |
axilrd2wbsp.i_axi_reset_n |
[color] 3 |
axilrd2wbsp.i_clk |
@200 |
- |
@28 |
axilrd2wbsp.i_axi_arvalid |
axilrd2wbsp.o_axi_arready |
@22 |
axilrd2wbsp.i_axi_araddr[27:0] |
axilrd2wbsp.i_axi_arcache[3:0] |
@28 |
axilrd2wbsp.i_axi_arprot[2:0] |
@200 |
- |
@28 |
[color] 2 |
axilrd2wbsp.o_axi_rvalid |
[color] 2 |
axilrd2wbsp.i_axi_rready |
@22 |
[color] 2 |
axilrd2wbsp.o_axi_rdata[31:0] |
@28 |
[color] 2 |
axilrd2wbsp.o_axi_rresp[1:0] |
@200 |
- |
@28 |
axilrd2wbsp.o_wb_cyc |
axilrd2wbsp.o_wb_stb |
@22 |
axilrd2wbsp.o_wb_addr[25:0] |
@28 |
[color] 2 |
axilrd2wbsp.i_wb_stall |
[color] 2 |
axilrd2wbsp.i_wb_ack |
@23 |
[color] 2 |
axilrd2wbsp.i_wb_data[31:0] |
@28 |
[color] 2 |
axilrd2wbsp.i_wb_err |
@200 |
- |
@28 |
[color] 3 |
axilrd2wbsp.r_stb |
@22 |
[color] 3 |
axilrd2wbsp.r_addr[25:0] |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/bench/formal/axilrd2wbsp.sby
0,0 → 1,23
[tasks] |
cvr |
prf |
|
[options] |
prf: mode prove |
prf: depth 5 |
cvr: mode cover |
cvr: depth 32 |
|
[engines] |
smtbmc |
|
[script] |
read -formal -D AXILRD2WBSP axilrd2wbsp.v |
read -formal -D AXILRD2WBSP faxil_slave.v |
read -formal -D AXILRD2WBSP fwb_master.v |
prep -top axilrd2wbsp |
|
[files] |
../../rtl/axilrd2wbsp.v |
faxil_slave.v |
fwb_master.v |
/trunk/bench/formal/axilwr2wbsp.sby
0,0 → 1,23
[tasks] |
prf |
cvr |
|
[options] |
prf: mode prove |
prf: depth 5 |
cvr: mode cover |
cvr: depth 40 |
|
[engines] |
smtbmc |
|
[script] |
read -formal -D AXILWR2WBSP axilwr2wbsp.v |
read -formal -D AXILWR2WBSP faxil_slave.v |
read -formal -D AXILWR2WBSP fwb_master.v |
prep -top axilwr2wbsp |
|
[files] |
../../rtl/axilwr2wbsp.v |
faxil_slave.v |
fwb_master.v |
/trunk/bench/formal/axim2wbsp.ys
5,7 → 5,6
read_verilog -D AXIM2WBSP -formal fwb_master.v |
read_verilog -D AXIM2WBSP -formal fwb_slave.v |
read_verilog -D AXIM2WBSP -formal faxi_slave.v |
read_verilog -D AXIM2WBSP -formal f_order.v |
prep -top axim2wbsp -nordff |
clk2fflogic |
opt -share_all |
write_smt2 -wires axim2wbsp.smt2 |
/trunk/bench/formal/axlite2wbsp.gtkw
0,0 → 1,122
[*] |
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI |
[*] Fri Dec 28 11:45:02 2018 |
[*] |
[dumpfile] "(null)" |
[savefile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/axlite2wbsp.gtkw" |
[timestart] 0 |
[size] 1920 1021 |
[pos] -1 -1 |
*-6.124164 160 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[treeopen] axlite2wbsp. |
[treeopen] axlite2wbsp.ARB_WB. |
[treeopen] axlite2wbsp.AXI_RD. |
[treeopen] axlite2wbsp.AXI_RD.axi_read_decoder. |
[treeopen] axlite2wbsp.AXI_WR. |
[treeopen] axlite2wbsp.AXI_WR.axi_write_decoder. |
[sst_width] 270 |
[signals_width] 210 |
[sst_expanded] 1 |
[sst_vpaned_height] 290 |
@28 |
[color] 3 |
axlite2wbsp.i_axi_reset_n |
[color] 3 |
axlite2wbsp.o_reset |
[color] 3 |
axlite2wbsp.i_clk |
@200 |
- |
@28 |
[color] 2 |
axlite2wbsp.i_axi_awvalid |
[color] 2 |
axlite2wbsp.o_axi_awready |
@22 |
[color] 2 |
axlite2wbsp.i_axi_awaddr[27:0] |
@c00022 |
[color] 2 |
axlite2wbsp.i_axi_awcache[3:0] |
@28 |
(0)axlite2wbsp.i_axi_awcache[3:0] |
(1)axlite2wbsp.i_axi_awcache[3:0] |
(2)axlite2wbsp.i_axi_awcache[3:0] |
(3)axlite2wbsp.i_axi_awcache[3:0] |
@1401200 |
-group_end |
@28 |
[color] 2 |
axlite2wbsp.i_axi_awprot[2:0] |
@200 |
- |
@28 |
[color] 2 |
axlite2wbsp.i_axi_wvalid |
[color] 2 |
axlite2wbsp.o_axi_wready |
@22 |
[color] 2 |
axlite2wbsp.i_axi_wdata[31:0] |
[color] 2 |
axlite2wbsp.i_axi_wstrb[3:0] |
@28 |
[color] 2 |
axlite2wbsp.AXI_WR.axi_write_decoder.err_state |
@200 |
- |
@28 |
[color] 3 |
axlite2wbsp.o_axi_bvalid |
[color] 3 |
axlite2wbsp.i_axi_bready |
[color] 3 |
axlite2wbsp.o_axi_bresp[1:0] |
@200 |
- |
@28 |
axlite2wbsp.i_axi_arvalid |
axlite2wbsp.o_axi_arready |
@22 |
axlite2wbsp.i_axi_araddr[27:0] |
axlite2wbsp.i_axi_arcache[3:0] |
@28 |
axlite2wbsp.i_axi_arprot[2:0] |
@200 |
- |
@28 |
[color] 2 |
axlite2wbsp.o_axi_rvalid |
[color] 2 |
axlite2wbsp.i_axi_rready |
@22 |
[color] 2 |
axlite2wbsp.o_axi_rdata[31:0] |
@28 |
[color] 2 |
axlite2wbsp.o_axi_rresp[1:0] |
[color] 2 |
axlite2wbsp.AXI_RD.axi_read_decoder.err_state |
@200 |
- |
@28 |
axlite2wbsp.o_wb_cyc |
axlite2wbsp.o_wb_stb |
axlite2wbsp.o_wb_we |
@22 |
axlite2wbsp.o_wb_addr[25:0] |
axlite2wbsp.o_wb_data[31:0] |
axlite2wbsp.o_wb_sel[3:0] |
@28 |
[color] 2 |
axlite2wbsp.i_wb_stall |
[color] 2 |
axlite2wbsp.i_wb_ack |
@22 |
[color] 2 |
axlite2wbsp.i_wb_data[31:0] |
@28 |
[color] 2 |
axlite2wbsp.i_wb_err |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/bench/formal/axlite2wbsp.sby
0,0 → 1,31
[tasks] |
cvr |
prf |
|
[options] |
prf: mode prove |
prf: depth 5 |
cvr: mode cover |
cvr: depth 40 |
|
[engines] |
smtbmc |
|
[script] |
read -formal -D AXLITE2WBSP axlite2wbsp.v |
read -formal -D AXLITE2WBSP axilrd2wbsp.v |
read -formal -D AXLITE2WBSP axilwr2wbsp.v |
read -formal -D AXLITE2WBSP wbarbiter.v |
read -formal -D AXLITE2WBSP faxil_slave.v |
read -formal -D AXLITE2WBSP fwb_master.v |
read -formal -D AXLITE2WBSP fwb_slave.v |
prep -top axlite2wbsp |
|
[files] |
../../rtl/axlite2wbsp.v |
../../rtl/axilrd2wbsp.v |
../../rtl/axilwr2wbsp.v |
../../rtl/wbarbiter.v |
faxil_slave.v |
fwb_master.v |
fwb_slave.v |
/trunk/bench/formal/demoaxi.gtkw
0,0 → 1,71
[*] |
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI |
[*] Wed Dec 26 15:57:11 2018 |
[*] |
[dumpfile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/demoaxi_cvr/engine_0/trace2.vcd" |
[dumpfile_mtime] "Wed Dec 26 15:51:31 2018" |
[dumpfile_size] 26484 |
[savefile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/demoaxi.gtkw" |
[timestart] 0 |
[size] 1600 600 |
[pos] -1 -1 |
*-6.254814 180 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[sst_width] 270 |
[signals_width] 200 |
[sst_expanded] 1 |
[sst_vpaned_height] 143 |
@29 |
[color] 3 |
demoaxi.S_AXI_ARESETN |
[color] 3 |
demoaxi.S_AXI_ACLK |
@200 |
- |
@28 |
demoaxi.S_AXI_AWVALID |
demoaxi.S_AXI_AWREADY |
@22 |
demoaxi.S_AXI_AWADDR[7:0] |
@28 |
demoaxi.S_AXI_AWPROT[2:0] |
@200 |
- |
@28 |
demoaxi.S_AXI_WVALID |
demoaxi.S_AXI_WREADY |
@22 |
demoaxi.S_AXI_WDATA[31:0] |
demoaxi.S_AXI_WSTRB[3:0] |
@200 |
- |
@28 |
[color] 2 |
demoaxi.S_AXI_BVALID |
[color] 2 |
demoaxi.S_AXI_BREADY |
[color] 2 |
demoaxi.S_AXI_BRESP[1:0] |
@200 |
- |
@28 |
demoaxi.S_AXI_ARVALID |
demoaxi.S_AXI_ARREADY |
@22 |
demoaxi.S_AXI_ARADDR[7:0] |
@28 |
demoaxi.S_AXI_ARPROT[2:0] |
@200 |
- |
@28 |
[color] 2 |
demoaxi.S_AXI_RVALID |
[color] 2 |
demoaxi.S_AXI_RREADY |
@22 |
[color] 2 |
demoaxi.S_AXI_RDATA[31:0] |
@28 |
[color] 2 |
demoaxi.S_AXI_RRESP[1:0] |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/bench/formal/demoaxi.sby
0,0 → 1,21
[tasks] |
prf |
cvr |
|
[options] |
prf: mode prove |
prf: depth 26 |
cvr: mode cover |
cvr: depth 40 |
|
[engines] |
smtbmc |
|
[script] |
read -formal demoaxi.v |
read -formal faxil_slave.v |
prep -top demoaxi |
|
[files] |
../../rtl/demoaxi.v |
faxil_slave.v |
/trunk/bench/formal/fav_slave.v
15,25 → 15,28
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
88,31 → 91,106
always @(*) |
assert((f_past_valid) || (i_reset)); |
|
wire [AW:0] f_rd_request; |
assign f_rd_request = { i_av_read, i_av_address }; |
wire [AW+(DW/8):0] f_rd_request; |
assign f_rd_request = { i_av_read, i_av_byteenable, i_av_address }; |
|
wire [(AW+DW+(DW/8)):0] f_wr_request; |
assign f_wr_request = { i_av_write, i_av_address, i_av_writedata, |
i_av_byteenable }; |
|
///////////////////////////// |
// |
// Require that nothing changes, save on a clock tick. |
// |
// This is only required if yosys is using the clk2fflogic |
// command, a command only required if multiple clocks are |
// in use. Since this can greatly slow down formal proofs, |
// we limit any code associated with this option to only |
// those times the option is in play. |
// |
///////////////////////////// |
|
always @($global_clock) |
if ((f_past_valid)&&(!$rose(i_clk))) |
generate if (F_OPT_CLK2FFLOGIC) |
begin |
assume($stable(f_rd_request)); |
assume($stable(f_wr_request)); |
assume($stable(i_av_lock)); |
always @($global_clock) |
if ((f_past_valid)&&(!$rose(i_clk))) |
begin |
assume($stable(f_rd_request)); |
assume($stable(f_wr_request)); |
assume($stable(i_av_lock)); |
|
assert($stable(i_av_readdatavalid)); |
assert($stable(i_av_writeresponsevalid)); |
assert($stable(i_av_readdata)); |
assert($stable(i_av_response)); |
end |
assert($stable(i_av_readdatavalid)); |
assert($stable(i_av_writeresponsevalid)); |
assert($stable(i_av_readdata)); |
assert($stable(i_av_response)); |
end |
end endgenerate |
|
///////////////////////////// |
// |
// Assumptions about a slave's inputs |
// |
///////////////////////////// |
|
|
initial assume(!i_av_read); |
initial assume(!i_av_write); |
initial assume(!i_av_lock); |
// |
initial assert(!i_av_readdatavalid); |
initial assert(!i_av_writeresponsevalid); |
// |
|
always @(posedge i_clk) |
if (i_reset) |
begin |
assume(!i_av_read); |
assume(!i_av_write); |
assume(!i_av_lock); |
end |
|
always @(*) |
if (i_av_write) |
assume(|i_av_byteenable); |
|
// It is a protocol violation to issue both read and write requests |
// on the same clock |
always @(*) |
assume((!i_av_read)||(!i_av_write)); |
|
// Once a read request has been placed upon the bus, it will remain |
// there until wait request goes low |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_read))) |
assume((i_reset)||(f_rd_request == $past(f_rd_request))); |
|
// Same thing for a write request |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_write))) |
assume((i_reset)||(f_wr_request == $past(f_wr_request))); |
|
// A lock request can only be asserted at the same time a read or |
// write request is being made. |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_av_lock))) |
assume((!i_av_lock)||(i_av_read)||(i_av_write)); |
|
// A lock request can only be de-asserted following the last read |
// or write request made with it asserted |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_av_lock) |
&&(!i_av_read)&&(!i_av_write))) |
assume((i_reset)||(i_av_lock) |
||(i_av_read)||(i_av_write)); |
|
|
///////////////////////////// |
// |
// Internal state variables |
// |
///////////////////////////// |
|
// Count the number of read requests |
initial f_rd_nreqs = 0; |
always @(posedge i_clk) |
if (i_reset) |
120,6 → 198,7
else if ((i_av_read)&&(!i_av_waitrequest)) |
f_rd_nreqs <= f_rd_nreqs + 1'b1; |
|
// Count the number of read acknowledgements |
initial f_rd_nacks = 0; |
always @(posedge i_clk) |
if (i_reset) |
127,8 → 206,11
else if (i_av_readdatavalid) |
f_rd_nacks <= f_rd_nacks + 1'b1; |
|
assign f_rd_outstanding = f_rd_nreqs - f_rd_nacks; |
// The difference between read requests and acknowledgements is |
// the number of outstanding read requests |
assign f_rd_outstanding = (i_reset) ? 0 : (f_rd_nreqs - f_rd_nacks); |
|
// Count the number of write requests |
initial f_wr_nreqs = 0; |
always @(posedge i_clk) |
if (i_reset) |
136,6 → 218,7
else if ((i_av_write)&&(!i_av_waitrequest)) |
f_wr_nreqs <= f_wr_nreqs + 1'b1; |
|
// Count the number of write acknowledgements/responses |
initial f_wr_nacks = 0; |
always @(posedge i_clk) |
if (i_reset) |
172,26 → 255,85
assert(f_wr_nacks == 0); |
end |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_read))) |
assume($stable(f_rd_request)); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_write))) |
assume($stable(f_wr_request)); |
|
// Just like a read and write request cannot both be made at the same |
// time, neither can both responses come back at the same time |
always @(*) |
assume((!i_av_read)||(!i_av_write)); |
|
always @(*) |
assert((!i_av_writeresponsevalid)||(!i_av_readdatavalid)); |
|
// If nothing is outstanding, then there should be no responses. |
// If i_reset is asserted, a response may have been registered, and |
// so may still return on this clock. |
always @(posedge i_clk) |
if (f_rd_outstanding == 0) |
if ((f_rd_outstanding == 0)&&(!i_reset) |
&&((!i_av_read)||(i_av_waitrequest))) |
assert(!i_av_readdatavalid); |
|
always @(posedge i_clk) |
if (f_wr_outstanding == 0) |
if ((f_wr_outstanding == 0)&&(!i_reset) |
&&((!i_av_write)||(i_av_waitrequest))) |
assert(!i_av_writeresponsevalid); |
|
always @(*) |
assert({1'b0, f_wr_outstanding} + { 1'b0, f_rd_outstanding } |
< F_MAX_REQUESTS); |
|
generate if (F_OPT_MAX_STALL > 0) |
begin |
reg [(LGWAIT-1):0] stall_count; |
|
initial stall_count = 0; |
always @(posedge i_clk) |
if (i_reset) |
stall_count <= 0; |
else if (((i_av_read)||(i_av_write))&&(i_av_waitrequest)) |
stall_count <= stall_count + 1'b1; |
else |
stall_count <= 0; |
|
always @(*) |
assert((i_reset)||(stall_count < F_OPT_MAX_STALL)); |
end endgenerate |
|
generate if (F_OPT_MAX_WAIT > 0) |
begin |
reg [(LGWAIT-1):0] read_wait, write_wait; |
|
// |
// Insist on a minimum amount of time to wait for a *read* |
// response. |
// |
always @(posedge i_clk) |
if (i_reset) |
read_wait <= 0; |
else if ((i_av_readdatavalid) |
||((i_av_read)&&(!i_av_waitrequest))) |
read_wait <= 0; |
else if (f_rd_outstanding > 0) |
read_wait <= read_wait + 1'b1; |
|
always @(*) |
assert((i_av_readdatavalid) |
||(f_rd_outstanding == 0) |
||(read_wait < F_OPT_MAX_WAIT)); |
|
|
// |
// Insist on a minimum amount of time to wait for a *write* |
// response. |
// |
always @(posedge i_clk) |
if (i_reset) |
write_wait <= 0; |
else if ((i_av_writeresponsevalid) |
||((i_av_write)&&(!i_av_waitrequest))) |
write_wait <= 0; |
else if (f_wr_outstanding > 0) |
write_wait <= write_wait + 1'b1; |
|
always @(*) |
assert((i_av_writeresponsevalid) |
||(f_wr_outstanding == 0) |
||(write_wait < F_OPT_MAX_WAIT)); |
end endgenerate |
|
endmodule |
/trunk/bench/formal/faxi_master.v
13,25 → 13,28
// |
// Copyright (C) 2017, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
44,18 → 47,20
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width (log wordsize) |
localparam DW = C_AXI_DATA_WIDTH, |
localparam AW = C_AXI_ADDR_WIDTH, |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXSTALL = 3, |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3, |
parameter [0:0] F_STRICT_ORDER = 0, // Reorder, or not? 0 -> Reorder |
parameter [0:0] F_CONSECUTIVE_IDS= 0, // 0=ID's must be consecutive |
parameter [0:0] F_OPT_BURSTS = 1'b1, // Check burst lengths |
parameter [0:0] F_CHECK_IDS = 1'b1 // Check ID's upon issue&return |
parameter [0:0] F_CHECK_IDS = 1'b1, // Check ID's upon issue&return |
parameter [7:0] F_AXI_MAXBURST = 8'hff,// Maximum burst length, minus 1 |
parameter [0:0] F_OPT_CLK2FFLOGIC= 1'b0, // Multiple clock testing? |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXSTALL = 3, |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3 |
) ( |
input i_clk, // System clock |
input i_axi_reset_n, |
input wire i_clk, // System clock |
input wire i_axi_reset_n, |
|
// AXI write address channel signals |
input i_axi_awready, // Slave is ready to accept |
input wire i_axi_awready,//Slave is ready to accept |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_awid, // Write ID |
input wire [AW-1:0] i_axi_awaddr, // Write address |
input wire [7:0] i_axi_awlen, // Write Burst Length |
76,7 → 81,7
|
// AXI write response channel signals |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_bid, // Response ID |
input wire [1:0] i_axi_bresp, // Write response |
input wire [1:0] i_axi_bresp, // Write response |
input wire i_axi_bvalid, // Write reponse valid |
input wire i_axi_bready, // Response ready |
|
95,9 → 100,9
|
// AXI read data channel signals |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid, // Response ID |
input wire [1:0] i_axi_rresp, // Read response |
input wire [1:0] i_axi_rresp, // Read response |
input wire i_axi_rvalid, // Read reponse valid |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire i_axi_rlast, // Read last |
input wire i_axi_rready, // Read Response ready |
// |
106,8 → 111,10
output reg [(C_AXI_ID_WIDTH-1):0] f_axi_awr_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_rd_id_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_awr_id_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_wr_id_outstanding |
|
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_wr_id_outstanding, |
// output reg [(9-1):0] f_axi_wr_pending, |
// output reg [(9-1):0] f_axi_rd_count, |
output reg [(9-1):0] f_axi_wr_count |
); |
reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_wr_id_complete; |
|
130,6 → 137,8
: 8)))); |
localparam LGFIFOLN = C_AXI_ID_WIDTH; |
localparam FIFOLN = (1<<LGFIFOLN); |
localparam F_LGDEPTH = C_AXI_ID_WIDTH; |
localparam F_AXI_MAXWAIT = F_AXI_MAXSTALL; |
|
|
//***************************************************************************** |
136,22 → 145,6
// Internal register and wire declarations |
//***************************************************************************** |
|
// Things we're not changing ... |
always @(*) |
begin |
assert(i_axi_awlen == 8'h0); // Burst length is one |
assert(i_axi_awsize == 3'b101); // maximum bytes per burst is 32 |
assert(i_axi_awburst == 2'b01); // Incrementing address (ignored) |
assert(i_axi_arburst == 2'b01); // Incrementing address (ignored) |
assert(i_axi_awlock == 1'b0); // Normal signaling |
assert(i_axi_arlock == 1'b0); // Normal signaling |
assert(i_axi_awcache == 4'h2); // Normal: no cache, no buffer |
assert(i_axi_arcache == 4'h2); // Normal: no cache, no buffer |
assert(i_axi_awprot == 3'b010);// Unpriviledged, unsecure, data access |
assert(i_axi_arprot == 3'b010);// Unpriviledged, unsecure, data access |
assert(i_axi_awqos == 4'h0); // Lowest quality of service (unused) |
assert(i_axi_arqos == 4'h0); // Lowest quality of service (unused) |
end |
|
// wire w_fifo_full; |
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req, |
166,6 → 159,9
assign axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]); |
assign axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]); |
|
`define SLAVE_ASSUME assert |
`define SLAVE_ASSERT assume |
|
// |
// Setup |
// |
176,239 → 172,278
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
always @(*) |
if (!f_past_valid) |
assert(!i_axi_reset_n); |
if (!f_past_valid) |
assert(!i_axi_reset_n); |
|
// |
// All signals must be synchronous with the clock |
// |
always @($global_clock) |
if (f_past_valid) begin |
// Assume our inputs will only change on the positive edge |
// of the clock |
if (!$rose(i_clk)) |
begin |
// AXI inputs |
assume($stable(i_axi_awready)); |
assume($stable(i_axi_wready)); |
// |
assume($stable(i_axi_bid)); |
assume($stable(i_axi_bresp)); |
assume($stable(i_axi_bvalid)); |
assume($stable(i_axi_arready)); |
// |
assume($stable(i_axi_rid)); |
assume($stable(i_axi_rresp)); |
assume($stable(i_axi_rvalid)); |
assume($stable(i_axi_rdata)); |
assume($stable(i_axi_rlast)); |
// |
// AXI outputs |
// |
assert($stable(i_axi_awvalid)); |
assert($stable(i_axi_awid)); |
assert($stable(i_axi_awlen)); |
assert($stable(i_axi_awsize)); |
assert($stable(i_axi_awlock)); |
assert($stable(i_axi_awcache)); |
assert($stable(i_axi_awprot)); |
assert($stable(i_axi_awqos)); |
// |
assert($stable(i_axi_wvalid)); |
assert($stable(i_axi_wdata)); |
assert($stable(i_axi_wstrb)); |
assert($stable(i_axi_wlast)); |
// |
assert($stable(i_axi_arvalid)); |
assert($stable(i_axi_arid)); |
assert($stable(i_axi_arlen)); |
assert($stable(i_axi_arsize)); |
assert($stable(i_axi_arburst)); |
assert($stable(i_axi_arlock)); |
assert($stable(i_axi_arprot)); |
assert($stable(i_axi_arqos)); |
// |
assert($stable(i_axi_bready)); |
// |
assert($stable(i_axi_rready)); |
// |
// Formal outputs |
// |
assert($stable(f_axi_rd_outstanding)); |
assert($stable(f_axi_wr_outstanding)); |
assert($stable(f_axi_awr_outstanding)); |
generate if (F_OPT_CLK2FFLOGIC) |
begin |
|
always @($global_clock) |
if (f_past_valid) begin |
// Assume our inputs will only change on the positive |
// edge of the clock |
if (!$rose(i_clk)) |
begin |
// AXI inputs |
assume($stable(i_axi_awready)); |
assume($stable(i_axi_wready)); |
// |
assume($stable(i_axi_bid)); |
assume($stable(i_axi_bresp)); |
assume($stable(i_axi_bvalid)); |
assume($stable(i_axi_arready)); |
// |
assume($stable(i_axi_rid)); |
assume($stable(i_axi_rresp)); |
assume($stable(i_axi_rvalid)); |
assume($stable(i_axi_rdata)); |
assume($stable(i_axi_rlast)); |
// |
// AXI outputs |
// |
assert($stable(i_axi_awvalid)); |
assert($stable(i_axi_awid)); |
assert($stable(i_axi_awlen)); |
assert($stable(i_axi_awsize)); |
assert($stable(i_axi_awlock)); |
assert($stable(i_axi_awcache)); |
assert($stable(i_axi_awprot)); |
assert($stable(i_axi_awqos)); |
// |
assert($stable(i_axi_wvalid)); |
assert($stable(i_axi_wdata)); |
assert($stable(i_axi_wstrb)); |
assert($stable(i_axi_wlast)); |
// |
assert($stable(i_axi_arvalid)); |
assert($stable(i_axi_arid)); |
assert($stable(i_axi_arlen)); |
assert($stable(i_axi_arsize)); |
assert($stable(i_axi_arburst)); |
assert($stable(i_axi_arlock)); |
assert($stable(i_axi_arprot)); |
assert($stable(i_axi_arqos)); |
// |
assert($stable(i_axi_bready)); |
// |
assert($stable(i_axi_rready)); |
// |
// Formal outputs |
// |
assert($stable(f_axi_rd_outstanding)); |
assert($stable(f_axi_wr_outstanding)); |
assert($stable(f_axi_awr_outstanding)); |
end |
end |
end |
end endgenerate |
|
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Reset properties |
// |
// |
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// If asserted, the reset must be asserted for a minimum of 16 clocks |
reg [3:0] f_reset_length; |
initial f_reset_length = 0; |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))) |
if (i_axi_reset_n) |
f_reset_length <= 0; |
else if (!(&f_reset_length)) |
f_reset_length <= f_reset_length + 1'b1; |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
`SLAVE_ASSUME(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
`SLAVE_ASSUME(!i_axi_reset_n); |
|
always @(posedge i_clk) |
if ((!f_past_valid)||(!$past(i_axi_reset_n))) |
begin |
assert(!i_axi_arvalid); |
assert(!i_axi_awvalid); |
assert(!i_axi_wvalid); |
assume(!i_axi_bvalid); |
assume(!i_axi_rvalid); |
`SLAVE_ASSUME(!i_axi_arvalid); |
`SLAVE_ASSUME(!i_axi_awvalid); |
`SLAVE_ASSUME(!i_axi_wvalid); |
// |
`SLAVE_ASSERT(!i_axi_bvalid); |
`SLAVE_ASSERT(!i_axi_rvalid); |
end |
|
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Stability assumptions, AXI inputs/responses |
// Stability properties--what happens if valid and not ready |
// |
// |
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
|
// Assume any response from the bus will not change prior to that |
// response being accepted |
always @(posedge i_clk) |
if (f_past_valid) |
if ((f_past_valid)&&($past(i_axi_reset_n))) |
begin |
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
// Write address channel |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
assume(i_axi_rid == $past(i_axi_rid)); |
assume(i_axi_rresp == $past(i_axi_rresp)); |
assume(i_axi_rdata == $past(i_axi_rdata)); |
assume(i_axi_rlast == $past(i_axi_rlast)); |
`SLAVE_ASSUME(i_axi_awvalid); |
`SLAVE_ASSUME(i_axi_awaddr == $past(i_axi_awaddr)); |
`SLAVE_ASSUME($stable(i_axi_awid)); |
`SLAVE_ASSUME($stable(i_axi_awlen)); |
`SLAVE_ASSUME($stable(i_axi_awsize)); |
`SLAVE_ASSUME($stable(i_axi_awburst)); |
`SLAVE_ASSUME($stable(i_axi_awlock)); |
`SLAVE_ASSUME($stable(i_axi_awcache)); |
`SLAVE_ASSUME($stable(i_axi_awprot)); |
`SLAVE_ASSUME($stable(i_axi_awqos)); |
end |
|
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
// Write data channel |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
assume(i_axi_bid == $past(i_axi_bid)); |
assume(i_axi_bresp == $past(i_axi_bresp)); |
`SLAVE_ASSUME(i_axi_wvalid); |
`SLAVE_ASSUME(i_axi_wstrb == $past(i_axi_wstrb)); |
`SLAVE_ASSUME(i_axi_wdata == $past(i_axi_wdata)); |
`SLAVE_ASSUME(i_axi_wlast); |
end |
end |
|
// Nothing should be returning a result on the first clock |
initial assume(!i_axi_bvalid); |
initial assume(!i_axi_rvalid); |
// |
initial assert(!i_axi_arvalid); |
initial assert(!i_axi_awvalid); |
initial assert(!i_axi_wvalid); |
// Incoming Read address channel |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
`SLAVE_ASSUME(i_axi_arvalid); |
`SLAVE_ASSUME(i_axi_arid == $past(i_axi_arid)); |
`SLAVE_ASSUME(i_axi_araddr == $past(i_axi_araddr)); |
`SLAVE_ASSUME(i_axi_arlen == $past(i_axi_arlen)); |
`SLAVE_ASSUME(i_axi_arsize == $past(i_axi_arsize)); |
`SLAVE_ASSUME(i_axi_arburst == $past(i_axi_arburst)); |
`SLAVE_ASSUME(i_axi_arlock == $past(i_axi_arlock)); |
`SLAVE_ASSUME(i_axi_arcache == $past(i_axi_arcache)); |
`SLAVE_ASSUME(i_axi_arprot == $past(i_axi_arprot)); |
`SLAVE_ASSUME(i_axi_arqos == $past(i_axi_arqos)); |
end |
|
////////////////////////////////////////////// |
// |
// |
// Stability assumptions, AXI outputs/requests |
// |
// |
////////////////////////////////////////////// |
// Assume any response from the bus will not change prior to that |
// response being accepted |
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
begin |
`SLAVE_ASSERT(i_axi_rvalid); |
`SLAVE_ASSERT(i_axi_rid == $past(i_axi_rid)); |
`SLAVE_ASSERT(i_axi_rresp == $past(i_axi_rresp)); |
`SLAVE_ASSERT(i_axi_rdata == $past(i_axi_rdata)); |
`SLAVE_ASSERT(i_axi_rlast == $past(i_axi_rlast)); |
end |
|
// Read address chanel |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
assert(i_axi_arvalid); |
assert($stable(i_axi_arid)); |
assert($stable(i_axi_araddr)); |
assert($stable(i_axi_arlen)); |
assert($stable(i_axi_arsize)); |
assert($stable(i_axi_arburst)); |
assert($stable(i_axi_arlock)); |
assert($stable(i_axi_arcache)); |
assert($stable(i_axi_arprot)); |
assert($stable(i_axi_arqos)); |
assert($stable(i_axi_arvalid)); |
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
begin |
`SLAVE_ASSERT(i_axi_bvalid); |
`SLAVE_ASSERT(i_axi_bid == $past(i_axi_bid)); |
`SLAVE_ASSERT(i_axi_bresp == $past(i_axi_bresp)); |
end |
end |
|
// If valid, but not ready, on any channel is true, nothing changes |
// until valid && ready |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
assert($stable(i_axi_awid)); |
assert($stable(i_axi_awaddr)); |
assert($stable(i_axi_awlen)); |
assert($stable(i_axi_awsize)); |
assert($stable(i_axi_awburst)); |
assert($stable(i_axi_awlock)); |
assert($stable(i_axi_awcache)); |
assert($stable(i_axi_awprot)); |
assert($stable(i_axi_awqos)); |
assert($stable(i_axi_awvalid)); |
end |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
// AXI write data channel signals |
assert($stable(i_axi_wdata)); |
assert($stable(i_axi_wstrb)); |
assert($stable(i_axi_wlast)); |
assert($stable(i_axi_wvalid)); |
end |
|
// Nothing should be returned or requested on the first clock |
initial `SLAVE_ASSUME(!i_axi_arvalid); |
initial `SLAVE_ASSUME(!i_axi_awvalid); |
initial `SLAVE_ASSUME(!i_axi_wvalid); |
// |
// |
initial `SLAVE_ASSERT(!i_axi_bvalid); |
initial `SLAVE_ASSERT(!i_axi_rvalid); |
|
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist upon a maximum delay before a request is accepted |
// |
// |
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write address channel |
// |
// |
reg [(C_AXI_ID_WIDTH):0] f_axi_awstall; |
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
generate if (F_AXI_MAXWAIT > 0) |
begin : CHECK_STALL_COUNT |
// |
// AXI write address channel |
// |
// |
reg [(F_LGDEPTH-1):0] f_axi_awstall, |
f_axi_wstall, |
f_axi_arstall, |
f_axi_bstall, |
f_axi_rstall; |
|
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)) |
f_axi_awstall <= 0; |
else |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_awstall <= f_axi_awstall + 1'b1; |
always @(*) |
assume((F_AXI_MAXSTALL==0)||(f_axi_awstall < F_AXI_MAXSTALL)); |
|
// |
// AXI write data channel |
// |
// |
// AXI explicitly allows write bursts with zero strobes. This is part |
// of how a transaction is aborted (if at all). |
//always @(*) if (i_axi_wvalid) assert(|i_axi_wstrb); |
always @(*) |
`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT); |
|
reg [(C_AXI_ID_WIDTH):0] f_axi_wstall; |
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
// |
// AXI write data channel |
// |
// |
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)) |
f_axi_wstall <= 0; |
else |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_wstall <= f_axi_wstall + 1'b1; |
always @(*) |
assume((F_AXI_MAXSTALL==0)||(f_axi_wstall < F_AXI_MAXSTALL)); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT); |
|
// |
// AXI read address channel |
// |
// |
reg [(C_AXI_ID_WIDTH):0] f_axi_arstall; |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
// |
// AXI read address channel |
// |
// |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)) |
f_axi_arstall <= 0; |
else |
else if ((!i_axi_rvalid)||(i_axi_rready)) |
f_axi_arstall <= f_axi_arstall + 1'b1; |
always @(*) |
assume((F_AXI_MAXSTALL==0)||(f_axi_arstall < F_AXI_MAXSTALL)); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT); |
|
// AXI write response channel |
initial f_axi_bstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready)) |
f_axi_bstall <= 0; |
else |
f_axi_bstall <= f_axi_bstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXWAIT); |
|
// AXI read response channel |
initial f_axi_rstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready)) |
f_axi_rstall <= 0; |
else |
f_axi_rstall <= f_axi_rstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXWAIT); |
|
end endgenerate |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Count outstanding transactions |
// Count outstanding transactions. With these measures, we count |
// once per any burst. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
442,11 → 477,11
|
// Do not let the number of outstanding requests overflow |
always @(posedge i_clk) |
assert(f_axi_wr_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_wr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
assert(f_axi_awr_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
assert(f_axi_rd_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_rd_outstanding < {(F_LGDEPTH){1'b1}}); |
|
//////////////////////////////////////////////////////////////////////// |
// |
458,44 → 493,48
// |
//////////////////////////////////////////////////////////////////////// |
|
reg [(C_AXI_ID_WIDTH):0] f_axi_wr_ack_delay, |
f_axi_awr_ack_delay, |
f_axi_rd_ack_delay; |
generate if (F_AXI_MAXDELAY > 0) |
begin : CHECK_MAX_DELAY |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_rd_ack)) |
reg [(C_AXI_ID_WIDTH):0] f_axi_wr_ack_delay, |
f_axi_awr_ack_delay, |
f_axi_rd_ack_delay; |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0)) |
f_axi_rd_ack_delay <= 0; |
else if (f_axi_rd_outstanding > 0) |
else |
f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1; |
|
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_wr_ack)) |
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_bvalid)||(f_axi_wr_outstanding==0)) |
f_axi_wr_ack_delay <= 0; |
else if (f_axi_wr_outstanding > 0) |
f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1; |
|
initial f_axi_awr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_wr_ack)) |
initial f_axi_awr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_bvalid)||(f_axi_awr_outstanding == 0)) |
f_axi_awr_ack_delay <= 0; |
else if (f_axi_awr_outstanding > 0) |
else |
f_axi_awr_ack_delay <= f_axi_awr_ack_delay + 1'b1; |
|
always @(posedge i_clk) |
assume((F_AXI_MAXDELAY==0)||(f_axi_rd_ack_delay < F_AXI_MAXDELAY)); |
always @(*) |
`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY); |
|
always @(posedge i_clk) |
assume((F_AXI_MAXDELAY==0)||(f_axi_wr_ack_delay < F_AXI_MAXDELAY)); |
always @(*) |
`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY); |
|
always @(posedge i_clk) |
assume((F_AXI_MAXDELAY==0)||(f_axi_awr_ack_delay < F_AXI_MAXDELAY)); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_awr_ack_delay < F_AXI_MAXDELAY); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Assume all acknowledgements must follow requests |
// Assume acknowledgements must follow requests |
// |
// The outstanding count is a count of bursts, but the acknowledgements |
// we are looking for are individual. Hence, there should be no |
509,21 → 548,21
// AXI write response channel |
// |
always @(posedge i_clk) |
if ((!axi_awr_req)&&(axi_wr_ack)) |
assume(f_axi_awr_outstanding > 0); |
if ((!axi_awr_req)&&(i_axi_bvalid)) |
`SLAVE_ASSERT(f_axi_awr_outstanding > 0); |
|
always @(posedge i_clk) |
if ((!axi_wr_req)&&(axi_wr_ack)) |
assume(f_axi_wr_outstanding > 0); |
if ((!axi_wr_req)&&(i_axi_bvalid)) |
`SLAVE_ASSERT(f_axi_wr_outstanding > 0); |
|
// |
// AXI read data channel signals |
// |
initial f_axi_rd_outstanding = 0; |
always @(posedge i_clk) |
if ((!axi_ard_req)&&(axi_rd_ack)) |
assume(f_axi_rd_outstanding > 0); |
if ((!axi_ard_req)&&(i_axi_rvalid)) |
`SLAVE_ASSERT(f_axi_rd_outstanding > 0); |
|
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Manage the ID buffer. Basic rules apply such as you can't |
534,7 → 573,7
// transactions and not necessarily the individual values. |
// |
// |
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// Now, let's look into that FIFO. Without it, we know nothing about |
// the ID's |
|
648,13 → 687,13
end |
|
always @(*) |
assert((!F_CHECK_IDS)||(f_axi_awr_outstanding== f_axi_awr_id_outstanding_count)); |
`SLAVE_ASSUME((!F_CHECK_IDS)||(f_axi_awr_outstanding== f_axi_awr_id_outstanding_count)); |
|
always @(*) |
assert((!F_CHECK_IDS)||(f_axi_wr_outstanding == f_axi_wr_id_outstanding_count)); |
`SLAVE_ASSUME((!F_CHECK_IDS)||(f_axi_wr_outstanding == f_axi_wr_id_outstanding_count)); |
|
always @(*) |
assert((!F_CHECK_IDS)||(f_axi_rd_outstanding == f_axi_rd_id_outstanding_count)); |
`SLAVE_ASSUME((!F_CHECK_IDS)||(f_axi_rd_outstanding == f_axi_rd_id_outstanding_count)); |
|
always @(*) |
assume( ((f_axi_wr_id_complete)&(~f_axi_awr_id_outstanding)) == 0); |
685,6 → 724,7
f_wr_pending <= i_axi_awlen+9'h1; |
assert(f_wr_pending == 0); |
r_last_wr_id_valid <= 1'b1; |
`SLAVE_ASSUME(i_axi_awlen <= F_AXI_MAXBURST); |
end |
|
if (axi_ard_req) |
716,7 → 756,7
|
r_last_rd_id <= i_axi_rid; |
if ((axi_rd_ack)&&(r_last_rd_id_valid)) |
assume(i_axi_rid == r_last_rd_id); |
`SLAVE_ASSERT(i_axi_rid == r_last_rd_id); |
end |
|
if ((axi_rd_ack)&&(i_axi_rlast)) |
731,8 → 771,8
// Since we aren't allowing bursts, *every* |
// write data and read data must always be the last |
// value |
assert((i_axi_wlast)||(!i_axi_wvalid)); |
assume((i_axi_rlast)||(!i_axi_rvalid)); |
`SLAVE_ASSUME((i_axi_wlast)||(!i_axi_wvalid)); |
`SLAVE_ASSERT((i_axi_rlast)||(!i_axi_rvalid)); |
|
assert((!i_axi_arvalid)||(i_axi_arlen==0)); |
assert((!i_axi_awvalid)||(i_axi_awlen==0)); |
/trunk/bench/formal/faxi_slave.v
4,7 → 4,9
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: |
// Purpose: This file contains a set of formal properties which can be |
// used to formally verify that a core truly follows the full |
// AXI4 specification. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
11,27 → 13,30
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2017, Gisselquist Technology, LLC |
// Copyright (C) 2017-2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
44,19 → 49,19
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width (log wordsize) |
localparam DW = C_AXI_DATA_WIDTH, |
localparam AW = C_AXI_ADDR_WIDTH, |
parameter [0:0] F_OPT_BURSTS = 1'b1, // Check burst lengths |
parameter [7:0] F_AXI_MAXBURST = 8'hff,// Maximum burst length, minus 1 |
parameter F_LGDEPTH = 10, |
parameter F_LGFIFO = 3, |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXSTALL = 3, |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3, |
parameter [0:0] F_STRICT_ORDER = 0, // Reorder, or not? 0 -> Reorder |
parameter [0:0] F_CONSECUTIVE_IDS= 0, // 0=ID's must be consecutive |
parameter [0:0] F_OPT_BURSTS = 1'b1, // Check burst lengths |
parameter [0:0] F_CHECK_IDS = 1'b1 // Check ID's upon issue&return |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3 |
) ( |
input i_clk, // System clock |
input i_axi_reset_n, |
input wire i_clk, // System clock |
input wire i_axi_reset_n, |
|
// AXI write address channel signals |
input i_axi_awready, // Slave is ready to accept |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_awid, // Write ID |
input wire i_axi_awready,//Slave is ready to accept |
// input wire [C_AXI_ID_WIDTH-1:0] i_axi_awid, // Write ID |
input wire [AW-1:0] i_axi_awaddr, // Write address |
input wire [7:0] i_axi_awlen, // Write Burst Length |
input wire [2:0] i_axi_awsize, // Write Burst size |
75,14 → 80,14
input wire i_axi_wvalid, // Write valid |
|
// AXI write response channel signals |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_bid, // Response ID |
input wire [1:0] i_axi_bresp, // Write response |
// input wire [C_AXI_ID_WIDTH-1:0] i_axi_bid, // Response ID |
input wire [1:0] i_axi_bresp, // Write response |
input wire i_axi_bvalid, // Write reponse valid |
input wire i_axi_bready, // Response ready |
|
// AXI read address channel signals |
input wire i_axi_arready, // Read address ready |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_arid, // Read ID |
// input wire [C_AXI_ID_WIDTH-1:0] i_axi_arid, // Read ID |
input wire [AW-1:0] i_axi_araddr, // Read address |
input wire [7:0] i_axi_arlen, // Read Burst Length |
input wire [2:0] i_axi_arsize, // Read Burst size |
94,22 → 99,27
input wire i_axi_arvalid, // Read address valid |
|
// AXI read data channel signals |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid, // Response ID |
input wire [1:0] i_axi_rresp, // Read response |
// input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid, // Response ID |
input wire [1:0] i_axi_rresp, // Read response |
input wire i_axi_rvalid, // Read reponse valid |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire i_axi_rlast, // Read last |
input wire i_axi_rready, // Read Response ready |
// |
output reg [(C_AXI_ID_WIDTH-1):0] f_axi_rd_outstanding, |
output reg [(C_AXI_ID_WIDTH-1):0] f_axi_wr_outstanding, |
output reg [(C_AXI_ID_WIDTH-1):0] f_axi_awr_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_rd_id_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_awr_id_outstanding, |
output reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_wr_id_outstanding |
|
output reg [F_LGDEPTH-1:0] f_axi_rd_nbursts, |
output reg [F_LGDEPTH-1:0] f_axi_rd_outstanding, |
output reg [F_LGDEPTH-1:0] f_axi_wr_nbursts, |
output reg [F_LGDEPTH-1:0] f_axi_awr_outstanding, |
output reg [F_LGDEPTH-1:0] f_axi_awr_nbursts, |
// Address writes without write valids |
// |
// output reg [(9-1):0] f_axi_wr_pending, |
// |
// RD_COUNT: increment on read w/o last, cleared on read w/ last |
output reg [(9-1):0] f_axi_rd_count, |
output reg [(72-1):0] f_axi_rdfifo |
); |
reg [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_wr_id_complete; |
reg [(9-1):0] f_axi_wr_count; |
|
//***************************************************************************** |
// Parameter declarations |
130,6 → 140,7
: 8)))); |
localparam LGFIFOLN = C_AXI_ID_WIDTH; |
localparam FIFOLN = (1<<LGFIFOLN); |
localparam F_AXI_MAXWAIT = F_AXI_MAXSTALL; |
|
|
//***************************************************************************** |
136,22 → 147,6
// Internal register and wire declarations |
//***************************************************************************** |
|
// Things we're not changing ... |
always @(*) |
begin |
assume(i_axi_awlen == 8'h0); // Burst length is one |
assume(i_axi_awsize == 3'b101); // maximum bytes per burst is 32 |
assume(i_axi_awburst == 2'b01); // Incrementing address (ignored) |
assume(i_axi_arburst == 2'b01); // Incrementing address (ignored) |
assume(i_axi_awlock == 1'b0); // Normal signaling |
assume(i_axi_arlock == 1'b0); // Normal signaling |
assume(i_axi_awcache == 4'h2); // Normal: no cache, no buffer |
assume(i_axi_arcache == 4'h2); // Normal: no cache, no buffer |
assume(i_axi_awprot == 3'b010);// Unpriviledged, unsecure, data access |
assume(i_axi_arprot == 3'b010);// Unpriviledged, unsecure, data access |
assume(i_axi_awqos == 4'h0); // Lowest quality of service (unused) |
assume(i_axi_arqos == 4'h0); // Lowest quality of service (unused) |
end |
|
// wire w_fifo_full; |
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req, |
166,6 → 161,9
assign axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]); |
assign axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]); |
|
`define SLAVE_ASSUME assume |
`define SLAVE_ASSERT assert |
|
// |
// Setup |
// |
176,235 → 174,240
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
// WAS AN ASSERT |
|
//////////////////////////////////////////////////////////////////////// |
// |
// All signals must be synchronous with the clock |
// |
always @($global_clock) |
if (f_past_valid) begin |
// Assume our inputs will only change on the positive edge |
// of the clock |
if (!$rose(i_clk)) |
begin |
// AXI inputs |
assert($stable(i_axi_awready)); |
assert($stable(i_axi_wready)); |
// |
assert($stable(i_axi_bid)); |
assert($stable(i_axi_bresp)); |
assert($stable(i_axi_bvalid)); |
assert($stable(i_axi_arready)); |
// |
assert($stable(i_axi_rid)); |
assert($stable(i_axi_rresp)); |
assert($stable(i_axi_rvalid)); |
assert($stable(i_axi_rdata)); |
assert($stable(i_axi_rlast)); |
// |
// AXI outputs |
// |
assume($stable(i_axi_awvalid)); |
assume($stable(i_axi_awid)); |
assume($stable(i_axi_awlen)); |
assume($stable(i_axi_awsize)); |
assume($stable(i_axi_awlock)); |
assume($stable(i_axi_awcache)); |
assume($stable(i_axi_awprot)); |
assume($stable(i_axi_awqos)); |
// |
assume($stable(i_axi_wvalid)); |
assume($stable(i_axi_wdata)); |
assume($stable(i_axi_wstrb)); |
assume($stable(i_axi_wlast)); |
// |
assume($stable(i_axi_arvalid)); |
assume($stable(i_axi_arid)); |
assume($stable(i_axi_arlen)); |
assume($stable(i_axi_arsize)); |
assume($stable(i_axi_arburst)); |
assume($stable(i_axi_arlock)); |
assume($stable(i_axi_arprot)); |
assume($stable(i_axi_arqos)); |
// |
assume($stable(i_axi_bready)); |
// |
assume($stable(i_axi_rready)); |
// |
// Formal outputs |
// |
assume($stable(f_axi_rd_outstanding)); |
assume($stable(f_axi_wr_outstanding)); |
assume($stable(f_axi_awr_outstanding)); |
end |
end |
|
//////////////////////////////////////////////////// |
// Reset properties |
// |
// |
// Reset properties |
//////////////////////////////////////////////////////////////////////// |
localparam [0:0] F_OPT_ASSUME_RESET = 1'b1; |
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_INITIAL_RESET |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
end else begin : ASSERT_INITIAL_RESET |
always @(*) |
if (!f_past_valid) |
assert(!i_axi_reset_n); |
end endgenerate |
// |
// |
//////////////////////////////////////////////////// |
// If asserted, the reset must be asserted for a minimum of 16 clocks |
reg [3:0] f_reset_length; |
initial f_reset_length = 0; |
always @(posedge i_clk) |
if (i_axi_reset_n) |
f_reset_length <= 0; |
else if (!(&f_reset_length)) |
f_reset_length <= f_reset_length + 1'b1; |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
`SLAVE_ASSUME(!i_axi_reset_n); |
|
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_RESET |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assume(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assume(!i_axi_reset_n); |
|
end else begin : ASSERT_RESET |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assert(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assert(!i_axi_reset_n); |
|
end endgenerate |
|
always @(posedge i_clk) |
if ((!f_past_valid)||(!$past(i_axi_reset_n))) |
begin |
assume(!i_axi_arvalid); |
assume(!i_axi_awvalid); |
assume(!i_axi_wvalid); |
assert(!i_axi_bvalid); |
assert(!i_axi_rvalid); |
`SLAVE_ASSUME(!i_axi_arvalid); |
`SLAVE_ASSUME(!i_axi_awvalid); |
`SLAVE_ASSUME(!i_axi_wvalid); |
// |
`SLAVE_ASSERT(!i_axi_bvalid); |
`SLAVE_ASSERT(!i_axi_rvalid); |
end |
|
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Stability assumptions, AXI inputs/responses |
// Stability properties--what happens if valid and not ready |
// |
// |
//////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
|
// Assume any response from the bus will not change prior to that |
// response being accepted |
always @(posedge i_clk) |
if (f_past_valid) |
if ((f_past_valid)&&($past(i_axi_reset_n))) |
begin |
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
// Write address channel |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
assert(i_axi_rid == $past(i_axi_rid)); |
assert(i_axi_rresp == $past(i_axi_rresp)); |
assert(i_axi_rdata == $past(i_axi_rdata)); |
assert(i_axi_rlast == $past(i_axi_rlast)); |
`SLAVE_ASSUME(i_axi_awvalid); |
`SLAVE_ASSUME(i_axi_awaddr == $past(i_axi_awaddr)); |
// `SLAVE_ASSUME($stable(i_axi_awid)); |
`SLAVE_ASSUME($stable(i_axi_awlen)); |
`SLAVE_ASSUME($stable(i_axi_awsize)); |
`SLAVE_ASSUME($stable(i_axi_awburst)); |
`SLAVE_ASSUME($stable(i_axi_awlock)); |
`SLAVE_ASSUME($stable(i_axi_awcache)); |
`SLAVE_ASSUME($stable(i_axi_awprot)); |
`SLAVE_ASSUME($stable(i_axi_awqos)); |
end |
|
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
// Write data channel |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
assert(i_axi_bid == $past(i_axi_bid)); |
assert(i_axi_bresp == $past(i_axi_bresp)); |
`SLAVE_ASSUME(i_axi_wvalid); |
`SLAVE_ASSUME($stable(i_axi_wstrb)); |
`SLAVE_ASSUME($stable(i_axi_wdata)); |
`SLAVE_ASSUME($stable(i_axi_wlast)); |
end |
end |
|
// Nothing should be returning a result on the first clock |
initial assert(!i_axi_bvalid); |
initial assert(!i_axi_rvalid); |
// |
initial assume(!i_axi_arvalid); |
initial assume(!i_axi_awvalid); |
initial assume(!i_axi_wvalid); |
// Incoming Read address channel |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
`SLAVE_ASSUME(i_axi_arvalid); |
// `SLAVE_ASSUME($stable(i_axi_arid)); |
`SLAVE_ASSUME($stable(i_axi_araddr)); |
`SLAVE_ASSUME($stable(i_axi_arlen)); |
`SLAVE_ASSUME($stable(i_axi_arsize)); |
`SLAVE_ASSUME($stable(i_axi_arburst)); |
`SLAVE_ASSUME($stable(i_axi_arlock)); |
`SLAVE_ASSUME($stable(i_axi_arcache)); |
`SLAVE_ASSUME($stable(i_axi_arprot)); |
`SLAVE_ASSUME($stable(i_axi_arqos)); |
end |
|
////////////////////////////////////////////// |
// |
// |
// Stability assumptions, AXI outputs/requests |
// |
// |
////////////////////////////////////////////// |
// Assume any response from the bus will not change prior to that |
// response being accepted |
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
begin |
`SLAVE_ASSERT(i_axi_rvalid); |
// `SLAVE_ASSERT($stable(i_axi_rid)); |
`SLAVE_ASSERT($stable(i_axi_rresp)); |
`SLAVE_ASSERT($stable(i_axi_rdata)); |
`SLAVE_ASSERT($stable(i_axi_rlast)); |
end |
|
// Read address chanel |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
assume(i_axi_arvalid); |
assume($stable(i_axi_arid)); |
assume($stable(i_axi_araddr)); |
assume($stable(i_axi_arlen)); |
assume($stable(i_axi_arsize)); |
assume($stable(i_axi_arburst)); |
assume($stable(i_axi_arlock)); |
assume($stable(i_axi_arcache)); |
assume($stable(i_axi_arprot)); |
assume($stable(i_axi_arqos)); |
assume($stable(i_axi_arvalid)); |
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
begin |
`SLAVE_ASSERT(i_axi_bvalid); |
/// `SLAVE_ASSERT($stable(i_axi_bid)); |
`SLAVE_ASSERT($stable(i_axi_bresp)); |
end |
end |
|
// If valid, but not ready, on any channel is true, nothing changes |
// until valid && ready |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
assume($stable(i_axi_awid)); |
assume($stable(i_axi_awaddr)); |
assume($stable(i_axi_awlen)); |
assume($stable(i_axi_awsize)); |
assume($stable(i_axi_awburst)); |
assume($stable(i_axi_awlock)); |
assume($stable(i_axi_awcache)); |
assume($stable(i_axi_awprot)); |
assume($stable(i_axi_awqos)); |
assume($stable(i_axi_awvalid)); |
end |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
// AXI write data channel signals |
assume($stable(i_axi_wdata)); |
assume($stable(i_axi_wstrb)); |
assume($stable(i_axi_wlast)); |
assume($stable(i_axi_wvalid)); |
end |
|
// Nothing should be returned or requested on the first clock |
initial `SLAVE_ASSUME(!i_axi_arvalid); |
initial `SLAVE_ASSUME(!i_axi_awvalid); |
initial `SLAVE_ASSUME(!i_axi_wvalid); |
// |
// |
initial `SLAVE_ASSERT(!i_axi_bvalid); |
initial `SLAVE_ASSERT(!i_axi_rvalid); |
|
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist upon a maximum delay before a request is accepted |
// |
// |
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write address channel |
// |
// |
reg [(C_AXI_ID_WIDTH):0] f_axi_awstall; |
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
generate if (F_AXI_MAXWAIT > 0) |
begin : CHECK_STALL_COUNT |
// |
// AXI write address channel |
// |
// |
reg [(F_LGDEPTH-1):0] f_axi_awstall, |
f_axi_wstall, |
f_axi_arstall, |
f_axi_bstall, |
f_axi_rstall; |
|
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)) |
f_axi_awstall <= 0; |
else |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_awstall <= f_axi_awstall + 1'b1; |
always @(*) |
assert((F_AXI_MAXSTALL==0)||(f_axi_awstall < F_AXI_MAXSTALL)); |
|
// |
// AXI write data channel |
// |
// |
// AXI explicitly allows write bursts with zero strobes. This is part |
// of how a transaction is aborted (if at all). |
//always @(*) if (i_axi_wvalid) assume(|i_axi_wstrb); |
always @(*) |
`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT); |
|
reg [(C_AXI_ID_WIDTH):0] f_axi_wstall; |
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
// |
// AXI write data channel |
// |
// |
// AXI explicitly allows write bursts with zero strobes. This is part |
// of how a transaction is aborted (if at all). |
|
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)) |
f_axi_wstall <= 0; |
else |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_wstall <= f_axi_wstall + 1'b1; |
always @(*) |
assert((F_AXI_MAXSTALL==0)||(f_axi_wstall < F_AXI_MAXSTALL)); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT); |
|
// |
// AXI read address channel |
// |
// |
reg [(C_AXI_ID_WIDTH):0] f_axi_arstall; |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
// |
// AXI read address channel |
// |
// |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)) |
f_axi_arstall <= 0; |
else |
else if ((!i_axi_rvalid)||(i_axi_rready)) |
f_axi_arstall <= f_axi_arstall + 1'b1; |
always @(*) |
assert((F_AXI_MAXSTALL==0)||(f_axi_arstall < F_AXI_MAXSTALL)); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT); |
|
// AXI write response channel |
initial f_axi_bstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready)) |
f_axi_bstall <= 0; |
else |
f_axi_bstall <= f_axi_bstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXWAIT); |
|
// AXI read response channel |
initial f_axi_rstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready)) |
f_axi_rstall <= 0; |
else |
f_axi_rstall <= f_axi_rstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXWAIT); |
|
end endgenerate |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
415,40 → 418,82
//////////////////////////////////////////////////////////////////////// |
initial f_axi_awr_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_awr_outstanding <= 0; |
else case({ (axi_awr_req), (axi_wr_ack) }) |
2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + 1'b1; |
2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1; |
default: begin end |
endcase |
if (!i_axi_reset_n) |
f_axi_awr_outstanding <= 0; |
else case({ (axi_awr_req), (axi_wr_req) }) |
2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + i_axi_awlen-1; |
2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1; |
2'b11: f_axi_awr_outstanding <= f_axi_awr_outstanding + i_axi_awlen; // +1 -1 |
default: begin end |
endcase |
|
initial f_axi_wr_outstanding = 0; |
initial f_axi_awr_nbursts = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_wr_outstanding <= 0; |
else case({ (axi_wr_req)&&(i_axi_wlast), (axi_wr_ack) }) |
2'b01: f_axi_wr_outstanding <= f_axi_wr_outstanding - 1'b1; |
2'b10: f_axi_wr_outstanding <= f_axi_wr_outstanding + 1'b1; |
endcase |
if (!i_axi_reset_n) |
f_axi_awr_nbursts <= 0; |
else case({ (axi_awr_req), (axi_wr_ack) }) |
2'b10: f_axi_awr_nbursts <= f_axi_awr_nbursts + 1'b1; |
2'b01: f_axi_awr_nbursts <= f_axi_awr_nbursts - 1'b1; |
default: begin end |
endcase |
|
initial f_axi_wr_nbursts = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_wr_nbursts <= 0; |
else case({ (axi_wr_req)&&(i_axi_wlast), (axi_wr_ack) }) |
2'b01: f_axi_wr_nbursts <= f_axi_wr_nbursts - 1'b1; |
2'b10: f_axi_wr_nbursts <= f_axi_wr_nbursts + 1'b1; |
default: begin end |
endcase |
|
initial f_axi_rd_nbursts = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rd_nbursts <= 0; |
else case({ (axi_ard_req), (axi_rd_ack)&&(i_axi_rlast) }) |
2'b01: f_axi_rd_nbursts <= f_axi_rd_nbursts - 1'b1; |
2'b10: f_axi_rd_nbursts <= f_axi_rd_nbursts + 1'b1; |
endcase |
|
initial f_axi_rd_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rd_outstanding <= 0; |
else case({ (axi_ard_req), (axi_rd_ack)&&(i_axi_rlast) }) |
2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1; |
2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + 1'b1; |
endcase |
if (!i_axi_reset_n) |
f_axi_rd_outstanding <= 0; |
else case({ (axi_ard_req), (axi_rd_ack) }) |
2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1; |
2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen+1; |
2'b11: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen; |
endcase |
|
// Do not let the number of outstanding requests overflow |
always @(posedge i_clk) |
assume(f_axi_wr_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
assume(f_axi_awr_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_rd_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
assume(f_axi_rd_outstanding < {(C_AXI_ID_WIDTH){1'b1}}); |
`SLAVE_ASSERT(f_axi_awr_nbursts < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_wr_nbursts < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_rd_nbursts < {(F_LGDEPTH){1'b1}}); |
|
// Cannot have outstanding values if there aren't any outstanding |
// bursts |
always @(posedge i_clk) |
if (f_axi_awr_outstanding > 0) |
`SLAVE_ASSERT(f_axi_awr_nbursts > 0); |
// else if (f_axi_awr_outstanding == 0) |
// Doesn't apply. Might have awr_outstanding == 0 and |
// awr_nbursts>0 |
always @(posedge i_clk) |
if (f_axi_rd_outstanding > 0) |
`SLAVE_ASSERT(f_axi_rd_nbursts > 0); |
else |
`SLAVE_ASSERT(f_axi_rd_nbursts == 0); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_rd_nbursts <= f_axi_rd_outstanding); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
459,44 → 504,51
// |
//////////////////////////////////////////////////////////////////////// |
|
reg [(C_AXI_ID_WIDTH):0] f_axi_wr_ack_delay, |
f_axi_awr_ack_delay, |
f_axi_rd_ack_delay; |
generate if (F_AXI_MAXDELAY > 0) |
begin : CHECK_MAX_DELAY |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_rd_ack)) |
reg [(C_AXI_ID_WIDTH):0] f_axi_wr_ack_delay, |
f_axi_awr_ack_delay, |
f_axi_rd_ack_delay; |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0)) |
f_axi_rd_ack_delay <= 0; |
else if (f_axi_rd_outstanding > 0) |
else |
f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1; |
|
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_wr_ack)) |
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||((i_axi_wvalid)&&(!i_axi_wlast)) |
||(i_axi_bvalid)||(f_axi_awr_outstanding==0)) |
f_axi_wr_ack_delay <= 0; |
else if (f_axi_wr_outstanding > 0) |
else |
f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1; |
|
initial f_axi_awr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(axi_wr_ack)) |
initial f_axi_awr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_bvalid)||(i_axi_wvalid) |
||(f_axi_awr_nbursts == 0) |
||(f_axi_wr_nbursts == 0)) |
f_axi_awr_ack_delay <= 0; |
else if (f_axi_awr_outstanding > 0) |
else |
f_axi_awr_ack_delay <= f_axi_awr_ack_delay + 1'b1; |
|
always @(posedge i_clk) |
assert((F_AXI_MAXDELAY==0)||(f_axi_rd_ack_delay < F_AXI_MAXDELAY)); |
always @(*) |
`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY); |
|
always @(posedge i_clk) |
assert((F_AXI_MAXDELAY==0)||(f_axi_wr_ack_delay < F_AXI_MAXDELAY)); |
always @(*) |
`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY); |
|
always @(posedge i_clk) |
assert((F_AXI_MAXDELAY==0)||(f_axi_awr_ack_delay < F_AXI_MAXDELAY)); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_awr_ack_delay < F_AXI_MAXDELAY); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Assume all acknowledgements must follow requests |
// Assume acknowledgements must follow requests |
// |
// The outstanding count is a count of bursts, but the acknowledgements |
// we are looking for are individual. Hence, there should be no |
510,248 → 562,202
// AXI write response channel |
// |
always @(posedge i_clk) |
if ((!axi_awr_req)&&(axi_wr_ack)) |
assert(f_axi_awr_outstanding > 0); |
always @(posedge i_clk) |
if ((!axi_wr_req)&&(axi_wr_ack)) |
assert(f_axi_wr_outstanding > 0); |
if (i_axi_bvalid) |
begin |
`SLAVE_ASSERT(f_axi_awr_nbursts > 0); |
`SLAVE_ASSERT(f_axi_wr_nbursts > 0); |
end |
|
// |
// AXI read data channel signals |
// |
initial f_axi_rd_outstanding = 0; |
always @(posedge i_clk) |
if ((!axi_ard_req)&&(axi_rd_ack)) |
assert(f_axi_rd_outstanding > 0); |
if (i_axi_rvalid) |
begin |
`SLAVE_ASSERT(f_axi_rd_outstanding > 0); |
`SLAVE_ASSERT(f_axi_rd_nbursts > 0); |
if (!i_axi_rlast) |
`SLAVE_ASSERT(f_axi_rd_outstanding > 1); |
end |
|
/////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Manage the ID buffer. Basic rules apply such as you can't |
// make a request of an already requested ID # before that ID |
// is returned, etc. |
// |
// Elements in this buffer reference transactions--possibly burst |
// transactions and not necessarily the individual values. |
// |
// |
/////////////////////////////////////////////////////////////////// |
// Now, let's look into that FIFO. Without it, we know nothing about |
// the ID's |
//////////////////////////////////////////////////////////////////////// |
|
initial f_axi_rd_id_outstanding = 0; |
initial f_axi_wr_id_outstanding = 0; |
initial f_axi_awr_id_outstanding = 0; |
initial f_axi_wr_id_complete = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
begin |
f_axi_rd_id_outstanding <= 0; |
f_axi_wr_id_outstanding <= 0; |
f_axi_wr_id_complete <= 0; |
f_axi_awr_id_outstanding <= 0; |
end else begin |
// When issuing a write |
if (axi_awr_req) |
begin |
if ((F_CONSECUTIVE_IDS)&&(F_CHECK_IDS)) |
assume(f_axi_awr_id_outstanding[i_axi_awid+1'b1] == 1'b0); |
assume((!F_CHECK_IDS) |
||(f_axi_awr_id_outstanding[i_axi_awid] == 1'b0)); |
assume((!F_CHECK_IDS) |
||(f_axi_wr_id_complete[i_axi_awid] == 1'b0)); |
f_axi_awr_id_outstanding[i_axi_awid] <= 1'b1; |
f_axi_wr_id_complete[i_axi_awid] <= 1'b0; |
end |
generate if (!F_OPT_BURSTS) |
begin |
|
if (axi_wr_req) |
begin |
if ((F_CONSECUTIVE_IDS)&&(F_CHECK_IDS)) |
assume(f_axi_wr_id_outstanding[i_axi_awid+1'b1] == 1'b0); |
assume((!F_CHECK_IDS) |
||(f_axi_wr_id_outstanding[i_axi_awid] == 1'b0)); |
f_axi_wr_id_outstanding[i_axi_awid] <= 1'b1; |
if (i_axi_wlast) |
begin |
assert(f_axi_wr_id_complete[i_axi_awid] == 1'b0); |
f_axi_wr_id_complete[i_axi_awid] <= 1'b1; |
end |
end |
always @(posedge i_clk) |
if (i_axi_awvalid) |
`SLAVE_ASSUME(i_axi_awlen == 0); |
|
// When issuing a read |
if (axi_ard_req) |
begin |
if ((F_CONSECUTIVE_IDS)&&(F_CHECK_IDS)) |
assume(f_axi_rd_id_outstanding[i_axi_arid+1'b1] == 1'b0); |
assume((!F_CHECK_IDS) |
||(f_axi_rd_id_outstanding[i_axi_arid] == 1'b0)); |
f_axi_rd_id_outstanding[i_axi_arid] <= 1'b1; |
end |
always @(posedge i_clk) |
if (i_axi_wvalid) |
`SLAVE_ASSUME(i_axi_wlast); |
|
// When a write is acknowledged |
if (axi_wr_ack) |
begin |
if (F_CHECK_IDS) |
begin |
assert(f_axi_awr_id_outstanding[i_axi_bid]); |
assert(f_axi_wr_id_outstanding[i_axi_bid]); |
assert((!F_STRICT_ORDER)||(!F_CONSECUTIVE_IDS) |
||(!f_axi_wr_id_outstanding[i_axi_bid-1'b1])); |
assert((!F_STRICT_ORDER)||(!F_CONSECUTIVE_IDS) |
||(!f_axi_awr_id_outstanding[i_axi_bid-1'b1])); |
assert(f_axi_wr_id_complete[i_axi_bid]); |
end |
f_axi_awr_id_outstanding[i_axi_bid] <= 1'b0; |
f_axi_wr_id_outstanding[i_axi_bid] <= 1'b0; |
f_axi_wr_id_complete[i_axi_bid] <= 1'b0; |
end |
always @(posedge i_clk) |
if (i_axi_arvalid) |
`SLAVE_ASSUME(i_axi_arlen == 0); |
|
// When a read is acknowledged |
if (axi_rd_ack) |
begin |
if (F_CHECK_IDS) |
begin |
assert(f_axi_rd_id_outstanding[i_axi_rid]); |
assert((!F_STRICT_ORDER)||(!F_CONSECUTIVE_IDS) |
||(!f_axi_rd_id_outstanding[i_axi_rid-1'b1])); |
always @(*) |
`SLAVE_ASSERT(f_axi_rd_nbursts == f_axi_rd_outstanding); |
end endgenerate |
|
reg [7:0] wrfifo [0:((1<<F_LGDEPTH)-1)]; |
reg [7:0] rdfifo [0:((1<<F_LGDEPTH)-1)]; |
reg [F_LGDEPTH-1:0] rd_rdaddr, wr_rdaddr, rd_wraddr, wr_wraddr; |
reg [7:0] rdfifo_data, wrfifo_data; |
reg [F_LGDEPTH-1:0] rdfifo_outstanding; |
wire [7:0] this_wlen; |
wire [F_LGDEPTH-1:0] wrfifo_fill, rdfifo_fill; |
|
/* |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
begin |
f_axi_wburst_fifo <= 0; |
end else case({ axi_awr_req , axi_wr_req, i_axi_wrlast }) |
3'b010: |
f_axi_wburst_fifo[7:0] <= f_axi_wburst_fifo[7:0]-1; |
3'b011: begin |
`SLAVE_ASSUME(f_axi_wburst_fifo[7:0] == 0); |
f_axi_wburst_fifo <= { 8'h0, f_axi_wburst_fifo[63:8] }; |
end |
3'b100: |
`SLAVE_ASSUME(f_axi_awr_nbursts < 8); |
f_axi_wburst_fifo <= f_axi_wburst_fifo |
| ((i_axi_awlen)<<(f_axi_awr_nbursts * 8)); |
3'b11: |
f_axi_wburst_fifo <= { 8'h0, f_axi_wburst_fifo[63:8] } |
| ((i_axi_awlen)<<((f_axi_awr_nbursts-1) * 8)); |
default: |
endcase |
*/ |
|
if (i_axi_rlast) |
f_axi_rd_id_outstanding[i_axi_rid] <= 1'b0; |
end |
// |
// Count the number of write elements received since the last wlast |
initial f_axi_wr_count = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_wr_count <= 0; |
else if (axi_wr_req) |
begin |
if (i_axi_wlast) |
f_axi_wr_count <= 1'b0; |
else |
f_axi_wr_count <= f_axi_wr_count + 1'b1; |
end |
|
// |
// Write information to the write FIFO |
initial wr_wraddr = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
wr_wraddr <= 0; |
else if (axi_awr_req) |
wr_wraddr <= wr_wraddr + 1'b1; |
|
reg [LGFIFOLN:0] f_axi_rd_id_outstanding_count, |
f_axi_awr_id_outstanding_count, |
f_axi_wr_id_outstanding_count; |
always @(posedge i_clk) |
if (axi_awr_req) |
wrfifo[wr_wraddr] <= { i_axi_awlen }; |
|
initial f_axi_rd_id_outstanding_count = 0; |
initial f_axi_awr_id_outstanding_count = 0; |
initial f_axi_wr_id_outstanding_count = 0; |
// |
// Read information from the write queue |
always @(*) |
begin |
// |
f_axi_rd_id_outstanding_count = 0; |
for(k=0; k< FIFOLN; k=k+1) |
if (f_axi_rd_id_outstanding[k]) |
f_axi_rd_id_outstanding_count |
= f_axi_rd_id_outstanding_count +1; |
// |
f_axi_wr_id_outstanding_count = 0; |
for(k=0; k< FIFOLN; k=k+1) |
if (f_axi_wr_id_outstanding[k]) |
f_axi_wr_id_outstanding_count = f_axi_wr_id_outstanding_count +1; |
f_axi_awr_id_outstanding_count = 0; |
for(k=0; k< FIFOLN; k=k+1) |
if (f_axi_awr_id_outstanding[k]) |
f_axi_awr_id_outstanding_count = f_axi_awr_id_outstanding_count +1; |
end |
wrfifo_data = wrfifo[wr_rdaddr]; |
|
always @(*) |
assume((!F_CHECK_IDS)||(f_axi_awr_outstanding== f_axi_awr_id_outstanding_count)); |
assign this_wlen = wrfifo_data; |
|
always @(*) |
assume((!F_CHECK_IDS)||(f_axi_wr_outstanding == f_axi_wr_id_outstanding_count)); |
if ((i_axi_wvalid)&&(i_axi_wlast)&&(f_axi_awr_nbursts>0)) |
`SLAVE_ASSUME(i_axi_wlast == (this_wlen == f_axi_wr_count)); |
|
always @(*) |
assume((!F_CHECK_IDS)||(f_axi_rd_outstanding == f_axi_rd_id_outstanding_count)); |
// Advance the read pointer for the write FIFO |
initial wr_rdaddr = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
wr_rdaddr <= 0; |
else if ((axi_wr_req)&&(i_axi_wlast)) |
wr_rdaddr <= wr_rdaddr + 1'b1; |
|
always @(*) |
assume( ((f_axi_wr_id_complete)&(~f_axi_awr_id_outstanding)) == 0); |
assign wrfifo_fill = wr_wraddr - wr_rdaddr; |
|
generate if (F_OPT_BURSTS) |
begin |
reg [(8-1):0] f_rd_pending [0:(FIFOLN-1)]; |
reg [(8-1):0] f_wr_pending, |
f_rd_count, f_wr_count; |
//////////////////////////////////////////////////////////////////////// |
// |
// Read FIFO |
// |
parameter NRDFIFO = 8; |
parameter WRDFIFO = 9; |
|
reg r_last_rd_id_valid, |
r_last_wr_id_valid; |
|
reg [(C_AXI_ID_WIDTH-1):0] r_last_wr_id, r_last_rd_id; |
initial f_axi_rd_count = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rd_count <= 0; |
else if (axi_rd_ack) |
begin |
if (i_axi_rlast) |
f_axi_rd_count <= 1'b0; |
else |
f_axi_rd_count <= f_axi_rd_count + 1'b1; |
end |
|
initial r_last_wr_id_valid = 1'b0; |
initial r_last_rd_id_valid = 1'b0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
begin |
r_last_wr_id_valid <= 1'b0; |
r_last_rd_id_valid <= 1'b0; |
f_wr_count <= 0; |
f_rd_count <= 0; |
end else begin |
if (axi_awr_req) |
begin |
f_wr_pending <= i_axi_awlen+9'h1; |
assume(f_wr_pending == 0); |
r_last_wr_id_valid <= 1'b1; |
end |
always @(*) |
`SLAVE_ASSUME(f_axi_rd_nbursts <= NRDFIFO); |
|
if (axi_ard_req) |
f_rd_pending[i_axi_arid] <= i_axi_arlen+9'h1; |
/* |
always @(*) |
if (i_axi_rvalid) |
begin |
if (i_axi_rlast) |
`SLAVE_ASSERT(f_axi_rdfifo[WRDFIFO-1:0] == f_axi_rd_count); |
else |
`SLAVE_ASSERT(f_axi_rdfifo[WRDFIFO-1:0] < f_axi_rd_count); |
end |
|
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rdfifo <= 0; |
else casez({ axi_ard_req, axi_rd_ack, i_axi_rlast }) |
3'b10?: f_axi_rdfifo[ f_axi_rd_nbursts*WRDFIFO +: WRDFIFO] |
<= { 1'b0, i_axi_arlen }; |
// 3'b010: f_axi_rdfifo[ 8:0] <= f_axi_rdfifo[8:0] - 1'b1; |
3'b011: f_axi_rdfifo <= { {(WRDFIFO){1'b0}}, |
f_axi_rdfifo[NRDFIFO*WRDFIFO-1:WRDFIFO] }; |
3'b111: begin |
f_axi_rdfifo <= { {(WRDFIFO){1'b0}}, |
f_axi_rdfifo[NRDFIFO*WRDFIFO-1:WRDFIFO] }; |
f_axi_rdfifo[ (f_axi_rd_nbursts-1)*WRDFIFO +: WRDFIFO] |
<= { 1'b0, i_axi_arlen }; |
end |
default: begin end |
endcase |
|
if ((axi_wr_req)&&(i_axi_wlast)) |
begin |
f_wr_count <= 0; |
r_last_wr_id_valid <= 1'b0; |
assume( |
// Either this is the last |
// of a series of requests we've |
// been waiting for, |
(f_wr_pending == f_wr_count - 9'h1) |
// *or* the only value |
// associated with an as yet |
// to be counted request |
||((axi_awr_req)&&(i_axi_awlen == 0))); |
end else if (axi_wr_req) |
f_wr_count <= f_wr_count + 1'b1; |
always @(*) |
if (f_axi_rd_nbursts < NRDFIFO) |
assert(f_axi_rdfifo[NRDFIFO * WRDFIFO-1: f_axi_rd_nbursts*WRDFIFO] == 0); |
|
if (axi_rd_ack) |
always @(*) |
begin |
rdfifo_outstanding = 0; |
for(k = 0; k < NRDFIFO; k=k+1) |
begin |
if (k < f_axi_rd_nbursts) |
begin |
if (i_axi_rlast) |
r_last_rd_id_valid <= 1'b0; |
else |
r_last_rd_id_valid <= 1'b1; |
|
r_last_rd_id <= i_axi_rid; |
if ((axi_rd_ack)&&(r_last_rd_id_valid)) |
assert(i_axi_rid == r_last_rd_id); |
rdfifo_outstanding = rdfifo_outstanding |
+ f_axi_rdfifo[k * WRDFIFO +: WRDFIFO] + 1; |
end |
|
if ((axi_rd_ack)&&(i_axi_rlast)) |
assume(f_rd_count == f_rd_pending[i_axi_rid]-9'h1); |
if ((axi_rd_ack)&&(i_axi_rlast)) |
f_rd_count <= 0; |
else if (axi_rd_ack) |
f_rd_count <= f_rd_count + 1'b1; |
assert(f_axi_rdfifo[k*WRDFIFO+(WRDFIFO-1)] == 1'b0); |
end |
end else begin |
always @(*) begin |
// Since we aren't allowing bursts, *every* |
// write data and read data must always be the last |
// value |
assume((i_axi_wlast)||(!i_axi_wvalid)); |
assert((i_axi_rlast)||(!i_axi_rvalid)); |
end |
|
assume((!i_axi_arvalid)||(i_axi_arlen==0)); |
assume((!i_axi_awvalid)||(i_axi_awlen==0)); |
end |
always @(posedge i_clk) |
assert(rdfifo_outstanding - f_axi_rd_count |
== f_axi_rd_outstanding); |
*/ |
|
always @(posedge i_clk) |
if (i_axi_awvalid) |
assume(i_axi_awlen == 0); |
always @(posedge i_clk) |
if (i_axi_arvalid) |
assume(i_axi_arlen == 0); |
always @(posedge i_clk) |
if (i_axi_wvalid) |
assume(i_axi_wlast); |
always @(posedge i_clk) |
if (i_axi_rvalid) |
assert(i_axi_rlast); |
end endgenerate |
|
`endif |
always @(*) |
f_axi_rdfifo = 0; |
endmodule |
/trunk/bench/formal/faxil_master.v
0,0 → 1,605
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: faxil_master.v (Formal properties of an AXI lite master) |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2018-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module faxil_master #( |
parameter C_AXI_DATA_WIDTH = 32,// Fixed, width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28,// AXI Address width (log wordsize) |
localparam DW = C_AXI_DATA_WIDTH, |
localparam AW = C_AXI_ADDR_WIDTH, |
parameter [0:0] F_OPT_HAS_CACHE = 1'b0, |
parameter [0:0] F_OPT_NO_READS = 1'b0, |
parameter [0:0] F_OPT_NO_WRITES = 1'b0, |
parameter [0:0] F_OPT_BRESP = 1'b1, |
parameter [0:0] F_OPT_RRESP = 1'b1, |
parameter [0:0] F_OPT_ASSUME_RESET = 1'b0, |
parameter F_LGDEPTH = 4, |
parameter [(F_LGDEPTH-1):0] F_AXI_MAXWAIT = 12, |
parameter [(F_LGDEPTH-1):0] F_AXI_MAXDELAY = 12 |
) ( |
input wire i_clk, // System clock |
input wire i_axi_reset_n, |
|
// AXI write address channel signals |
input wire i_axi_awready,//Slave is ready to accept |
input wire [AW-1:0] i_axi_awaddr, // Write address |
input wire [3:0] i_axi_awcache, // Write Cache type |
input wire [2:0] i_axi_awprot, // Write Protection type |
input wire i_axi_awvalid, // Write address valid |
|
// AXI write data channel signals |
input wire i_axi_wready, // Write data ready |
input wire [DW-1:0] i_axi_wdata, // Write data |
input wire [DW/8-1:0] i_axi_wstrb, // Write strobes |
input wire i_axi_wvalid, // Write valid |
|
// AXI write response channel signals |
input wire [1:0] i_axi_bresp, // Write response |
input wire i_axi_bvalid, // Write reponse valid |
input wire i_axi_bready, // Response ready |
|
// AXI read address channel signals |
input wire i_axi_arready, // Read address ready |
input wire [AW-1:0] i_axi_araddr, // Read address |
input wire [3:0] i_axi_arcache, // Read Cache type |
input wire [2:0] i_axi_arprot, // Read Protection type |
input wire i_axi_arvalid, // Read address valid |
|
// AXI read data channel signals |
input wire [1:0] i_axi_rresp, // Read response |
input wire i_axi_rvalid, // Read reponse valid |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire i_axi_rready, // Read Response ready |
// |
output reg [(F_LGDEPTH-1):0] f_axi_rd_outstanding, |
output reg [(F_LGDEPTH-1):0] f_axi_wr_outstanding, |
output reg [(F_LGDEPTH-1):0] f_axi_awr_outstanding |
); |
|
//***************************************************************************** |
// Parameter declarations |
//***************************************************************************** |
|
//***************************************************************************** |
// Internal register and wire declarations |
//***************************************************************************** |
|
// wire w_fifo_full; |
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req, |
axi_rd_err, axi_wr_err; |
// |
assign axi_ard_req = (i_axi_arvalid)&&(i_axi_arready); |
assign axi_awr_req = (i_axi_awvalid)&&(i_axi_awready); |
assign axi_wr_req = (i_axi_wvalid )&&(i_axi_wready); |
// |
assign axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready); |
assign axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready); |
assign axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]); |
assign axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]); |
|
`define SLAVE_ASSUME assert |
`define SLAVE_ASSERT assume |
|
// |
// Setup |
// |
reg f_past_valid; |
integer k; |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_INIITAL_RESET |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
end else begin : ASSERT_INIITAL_RESET |
always @(*) |
if (!f_past_valid) |
assert(!i_axi_reset_n); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Reset properties |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// If asserted, the reset must be asserted for a minimum of 16 clocks |
reg [3:0] f_reset_length; |
initial f_reset_length = 0; |
always @(posedge i_clk) |
if (i_axi_reset_n) |
f_reset_length <= 0; |
else if (!(&f_reset_length)) |
f_reset_length <= f_reset_length + 1'b1; |
|
|
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_RESET |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assume(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assume(!i_axi_reset_n); |
|
end else begin : ASSERT_RESET |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assert(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assert(!i_axi_reset_n); |
|
end endgenerate |
|
always @(posedge i_clk) |
if ((!f_past_valid)||(!$past(i_axi_reset_n))) |
begin |
`SLAVE_ASSUME(!i_axi_arvalid); |
`SLAVE_ASSUME(!i_axi_awvalid); |
`SLAVE_ASSUME(!i_axi_wvalid); |
// |
`SLAVE_ASSERT(!i_axi_bvalid); |
`SLAVE_ASSERT(!i_axi_rvalid); |
end |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Constant input assumptions (cache and prot) |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
always @(*) |
if (i_axi_awvalid) |
begin |
`SLAVE_ASSUME(i_axi_awprot == 3'h0); |
if (F_OPT_HAS_CACHE) |
// Normal non-cachable, but bufferable |
`SLAVE_ASSUME(i_axi_awcache == 4'h3); |
else |
// No caching capability |
`SLAVE_ASSUME(i_axi_awcache == 4'h0); |
end |
|
always @(*) |
if (i_axi_arvalid) |
begin |
`SLAVE_ASSUME(i_axi_arprot == 3'h0); |
if (F_OPT_HAS_CACHE) |
// Normal non-cachable, but bufferable |
`SLAVE_ASSUME(i_axi_arcache == 4'h3); |
else |
// No caching capability |
`SLAVE_ASSUME(i_axi_arcache == 4'h0); |
end |
|
always @(*) |
if ((i_axi_bvalid)&&(!F_OPT_BRESP)) |
`SLAVE_ASSERT(i_axi_bresp == 0); |
always @(*) |
if ((i_axi_rvalid)&&(!F_OPT_RRESP)) |
`SLAVE_ASSERT(i_axi_rresp == 0); |
always @(*) |
if (i_axi_bvalid) |
`SLAVE_ASSERT(i_axi_bresp != 2'b01); // Exclusive access not allowed |
always @(*) |
if (i_axi_rvalid) |
`SLAVE_ASSERT(i_axi_rresp != 2'b01); // Exclusive access not allowed |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Stability assumptions |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// Assume any response from the bus will not change prior to that |
// response being accepted |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_reset_n))) |
begin |
// Write address channel |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
`SLAVE_ASSUME(i_axi_awvalid); |
`SLAVE_ASSUME($stable(i_axi_awaddr)); |
end |
|
// Write data channel |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
`SLAVE_ASSUME(i_axi_wvalid); |
`SLAVE_ASSUME($stable(i_axi_wstrb)); |
`SLAVE_ASSUME($stable(i_axi_wdata)); |
end |
|
// Incoming Read address channel |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
`SLAVE_ASSUME(i_axi_arvalid); |
`SLAVE_ASSUME($stable(i_axi_araddr)); |
end |
|
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
begin |
`SLAVE_ASSERT(i_axi_rvalid); |
`SLAVE_ASSERT($stable(i_axi_rresp)); |
`SLAVE_ASSERT($stable(i_axi_rdata)); |
end |
|
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
begin |
`SLAVE_ASSERT(i_axi_bvalid); |
`SLAVE_ASSERT($stable(i_axi_bresp)); |
end |
end |
|
// Nothing should be returned or requested on the first clock |
initial `SLAVE_ASSUME(!i_axi_arvalid); |
initial `SLAVE_ASSUME(!i_axi_awvalid); |
initial `SLAVE_ASSUME(!i_axi_wvalid); |
// |
initial `SLAVE_ASSERT(!i_axi_bvalid); |
initial `SLAVE_ASSERT(!i_axi_rvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist upon a maximum delay before a request is accepted |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
generate if (F_AXI_MAXWAIT > 0) |
begin : CHECK_STALL_COUNT |
// |
// AXI write address channel |
// |
// |
reg [(F_LGDEPTH-1):0] f_axi_awstall, |
f_axi_wstall, |
f_axi_arstall, |
f_axi_bstall, |
f_axi_rstall; |
|
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)) |
f_axi_awstall <= 0; |
else if ((f_axi_awr_outstanding >= f_axi_wr_outstanding) |
&&(i_axi_awvalid && !i_axi_wvalid)) |
// If we are waiting for the write channel to be valid |
// then don't count stalls |
f_axi_awstall <= 0; |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_awstall <= f_axi_awstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT); |
|
// |
// AXI write data channel |
// |
// |
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)) |
f_axi_wstall <= 0; |
else if ((f_axi_wr_outstanding >= f_axi_awr_outstanding) |
&&(!i_axi_awvalid && i_axi_wvalid)) |
// If we are waiting for the write address channel |
// to be valid, then don't count stalls |
f_axi_wstall <= 0; |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_wstall <= f_axi_wstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT); |
|
// |
// AXI read address channel |
// |
// |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)) |
f_axi_arstall <= 0; |
else if ((!i_axi_rvalid)||(i_axi_rready)) |
f_axi_arstall <= f_axi_arstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT); |
|
// AXI write response channel |
initial f_axi_bstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready)) |
f_axi_bstall <= 0; |
else |
f_axi_bstall <= f_axi_bstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXWAIT); |
|
// AXI read response channel |
initial f_axi_rstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready)) |
f_axi_rstall <= 0; |
else |
f_axi_rstall <= f_axi_rstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXWAIT); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Xilinx extensions/guarantees to the AXI protocol |
// |
// 1. The address line will never be more than two clocks ahead of |
// the write data channel, and |
// 2. The write data channel will never be more than one clock |
// ahead of the address channel. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Rule number one: |
always @(posedge i_clk) |
if ((i_axi_reset_n)&&($past(i_axi_reset_n)) |
&&($past(i_axi_awvalid && !i_axi_wvalid,2)) |
&&($past(f_axi_awr_outstanding>=f_axi_wr_outstanding,2)) |
&&(!$past(i_axi_wvalid))) |
`SLAVE_ASSUME(i_axi_wvalid); |
|
// Rule number two: |
always @(posedge i_clk) |
if ((i_axi_reset_n)&&(!$past(i_axi_awvalid))&&($past(i_axi_wvalid)) |
&&(f_axi_awr_outstanding < f_axi_wr_outstanding)) |
`SLAVE_ASSUME(i_axi_awvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Count outstanding transactions. With these measures, we count |
// once per any burst. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
initial f_axi_awr_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_awr_outstanding <= 0; |
else case({ (axi_awr_req), (axi_wr_ack) }) |
2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + 1'b1; |
2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1; |
default: begin end |
endcase |
|
initial f_axi_wr_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_wr_outstanding <= 0; |
else case({ (axi_wr_req), (axi_wr_ack) }) |
2'b01: f_axi_wr_outstanding <= f_axi_wr_outstanding - 1'b1; |
2'b10: f_axi_wr_outstanding <= f_axi_wr_outstanding + 1'b1; |
endcase |
|
initial f_axi_rd_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rd_outstanding <= 0; |
else case({ (axi_ard_req), (axi_rd_ack) }) |
2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1; |
2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + 1'b1; |
endcase |
|
// |
// Do not let the number of outstanding requests overflow |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_wr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_rd_outstanding < {(F_LGDEPTH){1'b1}}); |
|
// |
// That means that requests need to stop when we're almost full |
always @(posedge i_clk) |
if (f_axi_awr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_awvalid); |
always @(posedge i_clk) |
if (f_axi_wr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_wvalid); |
always @(posedge i_clk) |
if (f_axi_rd_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_arvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist that all responses are returned in less than a maximum delay |
// In this case, we count responses within a burst, rather than entire |
// bursts. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
generate if (F_AXI_MAXDELAY > 0) |
begin : CHECK_MAX_DELAY |
|
reg [(F_LGDEPTH-1):0] f_axi_wr_ack_delay, |
f_axi_rd_ack_delay; |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0)) |
f_axi_rd_ack_delay <= 0; |
else |
f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1; |
|
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_bvalid)||(f_axi_wr_outstanding==0)) |
f_axi_wr_ack_delay <= 0; |
else if (f_axi_wr_outstanding > 0) |
f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Assume acknowledgements must follow requests |
// |
// The f_axi*outstanding counters count the number of requests. No |
// acknowledgment should issue without a pending request |
// burst. Further, the spec is clear: you can't acknowledge something |
// on the same clock you get the request. There must be at least one |
// clock delay. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write response channel |
// |
always @(posedge i_clk) |
if (i_axi_bvalid) |
begin |
`SLAVE_ASSERT(f_axi_awr_outstanding > 0); |
`SLAVE_ASSERT(f_axi_wr_outstanding > 0); |
end |
|
// |
// AXI read data channel signals |
// |
always @(posedge i_clk) |
if (i_axi_rvalid) |
`SLAVE_ASSERT(f_axi_rd_outstanding > 0); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Optionally disable either read or write channels (or both??) |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
initial assert((!F_OPT_NO_READS)||(!F_OPT_NO_WRITES)); |
|
generate if (F_OPT_NO_READS) |
begin : NO_READS |
|
always @(*) |
`SLAVE_ASSUME(i_axi_arvalid == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_rd_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(i_axi_rvalid == 0); |
|
end endgenerate |
|
generate if (F_OPT_NO_WRITES) |
begin : NO_WRITES |
|
always @(*) |
`SLAVE_ASSUME(i_axi_awvalid == 0); |
always @(*) |
`SLAVE_ASSUME(i_axi_wvalid == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_wr_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_awr_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(i_axi_bvalid == 0); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Cover properties |
// |
// We'll use this to prove that transactions are even possible, and |
// hence that we haven't so constrained the bus that nothing can take |
// place. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write response channel |
// |
always @(posedge i_clk) |
if (!F_OPT_NO_WRITES) |
cover((i_axi_bvalid)&&(i_axi_bready)); |
|
// |
// AXI read response channel |
// |
always @(posedge i_clk) |
if (!F_OPT_NO_READS) |
cover((i_axi_rvalid)&&(i_axi_rready)); |
endmodule |
/trunk/bench/formal/faxil_slave.v
0,0 → 1,605
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: faxil_slave.v (Formal properties of an AXI lite slave) |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2018-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module faxil_slave #( |
parameter C_AXI_DATA_WIDTH = 32,// Fixed, width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28,// AXI Address width (log wordsize) |
localparam DW = C_AXI_DATA_WIDTH, |
localparam AW = C_AXI_ADDR_WIDTH, |
parameter [0:0] F_OPT_HAS_CACHE = 1'b0, |
parameter [0:0] F_OPT_NO_READS = 1'b0, |
parameter [0:0] F_OPT_NO_WRITES = 1'b0, |
parameter [0:0] F_OPT_BRESP = 1'b1, |
parameter [0:0] F_OPT_RRESP = 1'b1, |
parameter [0:0] F_OPT_ASSUME_RESET = 1'b1, |
parameter F_LGDEPTH = 4, |
parameter [(F_LGDEPTH-1):0] F_AXI_MAXWAIT = 12, |
parameter [(F_LGDEPTH-1):0] F_AXI_MAXDELAY = 12 |
) ( |
input wire i_clk, // System clock |
input wire i_axi_reset_n, |
|
// AXI write address channel signals |
input wire i_axi_awready,//Slave is ready to accept |
input wire [AW-1:0] i_axi_awaddr, // Write address |
input wire [3:0] i_axi_awcache, // Write Cache type |
input wire [2:0] i_axi_awprot, // Write Protection type |
input wire i_axi_awvalid, // Write address valid |
|
// AXI write data channel signals |
input wire i_axi_wready, // Write data ready |
input wire [DW-1:0] i_axi_wdata, // Write data |
input wire [DW/8-1:0] i_axi_wstrb, // Write strobes |
input wire i_axi_wvalid, // Write valid |
|
// AXI write response channel signals |
input wire [1:0] i_axi_bresp, // Write response |
input wire i_axi_bvalid, // Write reponse valid |
input wire i_axi_bready, // Response ready |
|
// AXI read address channel signals |
input wire i_axi_arready, // Read address ready |
input wire [AW-1:0] i_axi_araddr, // Read address |
input wire [3:0] i_axi_arcache, // Read Cache type |
input wire [2:0] i_axi_arprot, // Read Protection type |
input wire i_axi_arvalid, // Read address valid |
|
// AXI read data channel signals |
input wire [1:0] i_axi_rresp, // Read response |
input wire i_axi_rvalid, // Read reponse valid |
input wire [DW-1:0] i_axi_rdata, // Read data |
input wire i_axi_rready, // Read Response ready |
// |
output reg [(F_LGDEPTH-1):0] f_axi_rd_outstanding, |
output reg [(F_LGDEPTH-1):0] f_axi_wr_outstanding, |
output reg [(F_LGDEPTH-1):0] f_axi_awr_outstanding |
); |
|
//***************************************************************************** |
// Parameter declarations |
//***************************************************************************** |
|
//***************************************************************************** |
// Internal register and wire declarations |
//***************************************************************************** |
|
// wire w_fifo_full; |
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req, |
axi_rd_err, axi_wr_err; |
// |
assign axi_ard_req = (i_axi_arvalid)&&(i_axi_arready); |
assign axi_awr_req = (i_axi_awvalid)&&(i_axi_awready); |
assign axi_wr_req = (i_axi_wvalid )&&(i_axi_wready); |
// |
assign axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready); |
assign axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready); |
assign axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]); |
assign axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]); |
|
`define SLAVE_ASSUME assume |
`define SLAVE_ASSERT assert |
|
// |
// Setup |
// |
reg f_past_valid; |
integer k; |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_INIITAL_RESET |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
end else begin : ASSERT_INIITAL_RESET |
always @(*) |
if (!f_past_valid) |
assert(!i_axi_reset_n); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Reset properties |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// If asserted, the reset must be asserted for a minimum of 16 clocks |
reg [3:0] f_reset_length; |
initial f_reset_length = 0; |
always @(posedge i_clk) |
if (i_axi_reset_n) |
f_reset_length <= 0; |
else if (!(&f_reset_length)) |
f_reset_length <= f_reset_length + 1'b1; |
|
|
generate if (F_OPT_ASSUME_RESET) |
begin : ASSUME_RESET |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assume(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assume(!i_axi_reset_n); |
|
end else begin : ASSERT_RESET |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length))) |
assert(!i_axi_reset_n); |
|
always @(*) |
if ((f_reset_length > 0)&&(f_reset_length < 4'hf)) |
assert(!i_axi_reset_n); |
|
end endgenerate |
|
always @(posedge i_clk) |
if ((!f_past_valid)||(!$past(i_axi_reset_n))) |
begin |
`SLAVE_ASSUME(!i_axi_arvalid); |
`SLAVE_ASSUME(!i_axi_awvalid); |
`SLAVE_ASSUME(!i_axi_wvalid); |
// |
`SLAVE_ASSERT(!i_axi_bvalid); |
`SLAVE_ASSERT(!i_axi_rvalid); |
end |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Constant input assumptions (cache and prot) |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
always @(*) |
if (i_axi_awvalid) |
begin |
`SLAVE_ASSUME(i_axi_awprot == 3'h0); |
if (F_OPT_HAS_CACHE) |
// Normal non-cachable, but bufferable |
`SLAVE_ASSUME(i_axi_awcache == 4'h3); |
else |
// No caching capability |
`SLAVE_ASSUME(i_axi_awcache == 4'h0); |
end |
|
always @(*) |
if (i_axi_arvalid) |
begin |
`SLAVE_ASSUME(i_axi_arprot == 3'h0); |
if (F_OPT_HAS_CACHE) |
// Normal non-cachable, but bufferable |
`SLAVE_ASSUME(i_axi_arcache == 4'h3); |
else |
// No caching capability |
`SLAVE_ASSUME(i_axi_arcache == 4'h0); |
end |
|
always @(*) |
if ((i_axi_bvalid)&&(!F_OPT_BRESP)) |
`SLAVE_ASSERT(i_axi_bresp == 0); |
always @(*) |
if ((i_axi_rvalid)&&(!F_OPT_RRESP)) |
`SLAVE_ASSERT(i_axi_rresp == 0); |
always @(*) |
if (i_axi_bvalid) |
`SLAVE_ASSERT(i_axi_bresp != 2'b01); // Exclusive access not allowed |
always @(*) |
if (i_axi_rvalid) |
`SLAVE_ASSERT(i_axi_rresp != 2'b01); // Exclusive access not allowed |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Stability assumptions |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// Assume any response from the bus will not change prior to that |
// response being accepted |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_axi_reset_n))) |
begin |
// Write address channel |
if ((f_past_valid)&&($past(i_axi_awvalid))&&(!$past(i_axi_awready))) |
begin |
`SLAVE_ASSUME(i_axi_awvalid); |
`SLAVE_ASSUME($stable(i_axi_awaddr)); |
end |
|
// Write data channel |
if ((f_past_valid)&&($past(i_axi_wvalid))&&(!$past(i_axi_wready))) |
begin |
`SLAVE_ASSUME(i_axi_wvalid); |
`SLAVE_ASSUME($stable(i_axi_wstrb)); |
`SLAVE_ASSUME($stable(i_axi_wdata)); |
end |
|
// Incoming Read address channel |
if ((f_past_valid)&&($past(i_axi_arvalid))&&(!$past(i_axi_arready))) |
begin |
`SLAVE_ASSUME(i_axi_arvalid); |
`SLAVE_ASSUME($stable(i_axi_araddr)); |
end |
|
if ((f_past_valid)&&($past(i_axi_rvalid))&&(!$past(i_axi_rready))) |
begin |
`SLAVE_ASSERT(i_axi_rvalid); |
`SLAVE_ASSERT($stable(i_axi_rresp)); |
`SLAVE_ASSERT($stable(i_axi_rdata)); |
end |
|
if ((f_past_valid)&&($past(i_axi_bvalid))&&(!$past(i_axi_bready))) |
begin |
`SLAVE_ASSERT(i_axi_bvalid); |
`SLAVE_ASSERT($stable(i_axi_bresp)); |
end |
end |
|
// Nothing should be returned or requested on the first clock |
initial `SLAVE_ASSUME(!i_axi_arvalid); |
initial `SLAVE_ASSUME(!i_axi_awvalid); |
initial `SLAVE_ASSUME(!i_axi_wvalid); |
// |
initial `SLAVE_ASSERT(!i_axi_bvalid); |
initial `SLAVE_ASSERT(!i_axi_rvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist upon a maximum delay before a request is accepted |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
generate if (F_AXI_MAXWAIT > 0) |
begin : CHECK_STALL_COUNT |
// |
// AXI write address channel |
// |
// |
reg [(F_LGDEPTH-1):0] f_axi_awstall, |
f_axi_wstall, |
f_axi_arstall, |
f_axi_bstall, |
f_axi_rstall; |
|
initial f_axi_awstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)) |
f_axi_awstall <= 0; |
else if ((f_axi_awr_outstanding >= f_axi_wr_outstanding) |
&&(i_axi_awvalid && !i_axi_wvalid)) |
// If we are waiting for the write channel to be valid |
// then don't count stalls |
f_axi_awstall <= 0; |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_awstall <= f_axi_awstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT); |
|
// |
// AXI write data channel |
// |
// |
initial f_axi_wstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)) |
f_axi_wstall <= 0; |
else if ((f_axi_wr_outstanding >= f_axi_awr_outstanding) |
&&(!i_axi_awvalid && i_axi_wvalid)) |
// If we are waiting for the write address channel |
// to be valid, then don't count stalls |
f_axi_wstall <= 0; |
else if ((!i_axi_bvalid)||(i_axi_bready)) |
f_axi_wstall <= f_axi_wstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT); |
|
// |
// AXI read address channel |
// |
// |
initial f_axi_arstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)) |
f_axi_arstall <= 0; |
else if ((!i_axi_rvalid)||(i_axi_rready)) |
f_axi_arstall <= f_axi_arstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT); |
|
// AXI write response channel |
initial f_axi_bstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready)) |
f_axi_bstall <= 0; |
else |
f_axi_bstall <= f_axi_bstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXWAIT); |
|
// AXI read response channel |
initial f_axi_rstall = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready)) |
f_axi_rstall <= 0; |
else |
f_axi_rstall <= f_axi_rstall + 1'b1; |
|
always @(*) |
`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXWAIT); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Xilinx extensions/guarantees to the AXI protocol |
// |
// 1. The address line will never be more than two clocks ahead of |
// the write data channel, and |
// 2. The write data channel will never be more than one clock |
// ahead of the address channel. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Rule number one: |
always @(posedge i_clk) |
if ((i_axi_reset_n)&&($past(i_axi_reset_n)) |
&&($past(i_axi_awvalid && !i_axi_wvalid,2)) |
&&($past(f_axi_awr_outstanding>=f_axi_wr_outstanding,2)) |
&&(!$past(i_axi_wvalid))) |
`SLAVE_ASSUME(i_axi_wvalid); |
|
// Rule number two: |
always @(posedge i_clk) |
if ((i_axi_reset_n)&&(!$past(i_axi_awvalid))&&($past(i_axi_wvalid)) |
&&(f_axi_awr_outstanding < f_axi_wr_outstanding)) |
`SLAVE_ASSUME(i_axi_awvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Count outstanding transactions. With these measures, we count |
// once per any burst. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
initial f_axi_awr_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_awr_outstanding <= 0; |
else case({ (axi_awr_req), (axi_wr_ack) }) |
2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + 1'b1; |
2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1; |
default: begin end |
endcase |
|
initial f_axi_wr_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_wr_outstanding <= 0; |
else case({ (axi_wr_req), (axi_wr_ack) }) |
2'b01: f_axi_wr_outstanding <= f_axi_wr_outstanding - 1'b1; |
2'b10: f_axi_wr_outstanding <= f_axi_wr_outstanding + 1'b1; |
endcase |
|
initial f_axi_rd_outstanding = 0; |
always @(posedge i_clk) |
if (!i_axi_reset_n) |
f_axi_rd_outstanding <= 0; |
else case({ (axi_ard_req), (axi_rd_ack) }) |
2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1; |
2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + 1'b1; |
endcase |
|
// |
// Do not let the number of outstanding requests overflow |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_wr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}}); |
always @(posedge i_clk) |
`SLAVE_ASSERT(f_axi_rd_outstanding < {(F_LGDEPTH){1'b1}}); |
|
// |
// That means that requests need to stop when we're almost full |
always @(posedge i_clk) |
if (f_axi_awr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_awvalid); |
always @(posedge i_clk) |
if (f_axi_wr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_wvalid); |
always @(posedge i_clk) |
if (f_axi_rd_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} ) |
assert(!i_axi_arvalid); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Insist that all responses are returned in less than a maximum delay |
// In this case, we count responses within a burst, rather than entire |
// bursts. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
generate if (F_AXI_MAXDELAY > 0) |
begin : CHECK_MAX_DELAY |
|
reg [(F_LGDEPTH-1):0] f_axi_wr_ack_delay, |
f_axi_rd_ack_delay; |
|
initial f_axi_rd_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0)) |
f_axi_rd_ack_delay <= 0; |
else |
f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1; |
|
initial f_axi_wr_ack_delay = 0; |
always @(posedge i_clk) |
if ((!i_axi_reset_n)||(i_axi_bvalid)||(f_axi_wr_outstanding==0)) |
f_axi_wr_ack_delay <= 0; |
else if (f_axi_wr_outstanding > 0) |
f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1; |
|
always @(*) |
`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY); |
|
always @(*) |
`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Assume acknowledgements must follow requests |
// |
// The f_axi*outstanding counters count the number of requests. No |
// acknowledgment should issue without a pending request |
// burst. Further, the spec is clear: you can't acknowledge something |
// on the same clock you get the request. There must be at least one |
// clock delay. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write response channel |
// |
always @(posedge i_clk) |
if (i_axi_bvalid) |
begin |
`SLAVE_ASSERT(f_axi_awr_outstanding > 0); |
`SLAVE_ASSERT(f_axi_wr_outstanding > 0); |
end |
|
// |
// AXI read data channel signals |
// |
always @(posedge i_clk) |
if (i_axi_rvalid) |
`SLAVE_ASSERT(f_axi_rd_outstanding > 0); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Optionally disable either read or write channels (or both??) |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
initial assert((!F_OPT_NO_READS)||(!F_OPT_NO_WRITES)); |
|
generate if (F_OPT_NO_READS) |
begin : NO_READS |
|
always @(*) |
`SLAVE_ASSUME(i_axi_arvalid == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_rd_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(i_axi_rvalid == 0); |
|
end endgenerate |
|
generate if (F_OPT_NO_WRITES) |
begin : NO_WRITES |
|
always @(*) |
`SLAVE_ASSUME(i_axi_awvalid == 0); |
always @(*) |
`SLAVE_ASSUME(i_axi_wvalid == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_wr_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(f_axi_awr_outstanding == 0); |
always @(*) |
`SLAVE_ASSERT(i_axi_bvalid == 0); |
|
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Cover properties |
// |
// We'll use this to prove that transactions are even possible, and |
// hence that we haven't so constrained the bus that nothing can take |
// place. |
// |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// AXI write response channel |
// |
always @(posedge i_clk) |
if (!F_OPT_NO_WRITES) |
cover((i_axi_bvalid)&&(i_axi_bready)); |
|
// |
// AXI read response channel |
// |
always @(posedge i_clk) |
if (!F_OPT_NO_READS) |
cover((i_axi_rvalid)&&(i_axi_rready)); |
endmodule |
/trunk/bench/formal/fwb_master.v
23,35 → 23,44
// slave inputs (the master outputs), and assertions are made about the |
// slave outputs (the master inputs). |
// |
// In order to make it easier to compare the slave against the master, |
// assumptions with respect to the slave have been marked with the |
// `SLAVE_ASSUME macro. Similarly, assertions the slave would make have |
// been marked with `SLAVE_ASSERT. This allows the master to redefine |
// these two macros to be from his perspective, and therefore the |
// diffs between the two files actually show true differences, rather |
// than just these differences in perspective. |
// |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2017, Gisselquist Technology, LLC |
// Copyright (C) 2017-2018, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
88,6 → 97,13
parameter [0:0] F_OPT_DISCONTINUOUS = 0; |
// |
// |
// If true, insist that there be a minimum of a single clock delay |
// between request and response. This defaults to off since the |
// wishbone specification specifically doesn't require this. However, |
// some interfaces do, so we allow it as an option here. |
parameter [0:0] F_OPT_MINCLOCK_DELAY = 0; |
// |
// |
localparam [(F_LGDEPTH-1):0] MAX_OUTSTANDING = {(F_LGDEPTH){1'b1}}; |
localparam MAX_DELAY = (F_MAX_STALL > F_MAX_ACK_DELAY) |
? F_MAX_STALL : F_MAX_ACK_DELAY; |
116,10 → 132,12
output reg [(F_LGDEPTH-1):0] f_nreqs, f_nacks; |
output wire [(F_LGDEPTH-1):0] f_outstanding; |
|
`define SLAVE_ASSUME assert |
`define SLAVE_ASSERT assume |
// |
// Let's just make sure our parameters are set up right |
// |
assert property(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}}); |
initial assert(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}}); |
|
// |
// Wrap the request line in a bundle. The top bit, named STB_BIT, |
138,8 → 156,8
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
always @(*) |
if (!f_past_valid) |
assume(i_reset); |
if (!f_past_valid) |
`SLAVE_ASSUME(i_reset); |
// |
// |
// Assertions regarding the initial (and reset) state |
149,38 → 167,25
// |
// Assume we start from a reset condition |
initial assert(i_reset); |
initial assert(!i_wb_cyc); |
initial assert(!i_wb_stb); |
initial `SLAVE_ASSUME(!i_wb_cyc); |
initial `SLAVE_ASSUME(!i_wb_stb); |
// |
initial assume(!i_wb_ack); |
initial assume(!i_wb_err); |
initial `SLAVE_ASSERT(!i_wb_ack); |
initial `SLAVE_ASSERT(!i_wb_err); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_reset))) |
if ((!f_past_valid)||($past(i_reset))) |
begin |
assert(!i_wb_cyc); |
assert(!i_wb_stb); |
`SLAVE_ASSUME(!i_wb_cyc); |
`SLAVE_ASSUME(!i_wb_stb); |
// |
assume(!i_wb_ack); |
assume(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end |
|
// Things can only change on the positive edge of the clock |
always @($global_clock) |
if ((f_past_valid)&&(!$rose(i_clk))) |
begin |
assert($stable(i_reset)); |
assert($stable(i_wb_cyc)); |
if (i_wb_we) |
assert($stable(f_request)); // The entire request should b stabl |
else |
assert($stable(f_request[(2+AW-1):(DW+DW/8)])); |
// |
assume($stable(i_wb_ack)); |
assume($stable(i_wb_stall)); |
assume($stable(i_wb_idata)); |
assume($stable(i_wb_err)); |
end |
always @(*) |
if (!f_past_valid) |
`SLAVE_ASSUME(!i_wb_cyc); |
|
// |
// |
192,12 → 197,12
// the transaction |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_err))&&($past(i_wb_cyc))) |
assert(!i_wb_cyc); |
`SLAVE_ASSUME(!i_wb_cyc); |
|
// STB can only be true if CYC is also true |
always @(posedge i_clk) |
if (i_wb_stb) |
assert(i_wb_cyc); |
always @(*) |
if (i_wb_stb) |
`SLAVE_ASSUME(i_wb_cyc); |
|
// If a request was both outstanding and stalled on the last clock, |
// then nothing should change on this clock regarding it. |
205,27 → 210,31
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_stb)) |
&&($past(i_wb_stall))&&(i_wb_cyc)) |
begin |
assert(i_wb_stb); |
assert($stable(f_request)); |
`SLAVE_ASSUME(i_wb_stb); |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
`SLAVE_ASSUME(i_wb_addr == $past(i_wb_addr)); |
`SLAVE_ASSUME(i_wb_sel == $past(i_wb_sel)); |
if (i_wb_we) |
`SLAVE_ASSUME(i_wb_data == $past(i_wb_data)); |
end |
|
// Within any series of STB/requests, the direction of the request |
// may not change. |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb)) |
assert(i_wb_we == $past(i_wb_we)); |
if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb)) |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
|
|
// Within any given bus cycle, the direction may *only* change when |
// there are no further outstanding requests. |
always @(posedge i_clk) |
if ((f_past_valid)&&(f_outstanding > 0)) |
assert(i_wb_we == $past(i_wb_we)); |
if ((f_past_valid)&&(f_outstanding > 0)) |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
|
// Write requests must also set one (or more) of i_wb_sel |
always @(posedge i_clk) |
if ((i_wb_stb)&&(i_wb_we)) |
assert(|i_wb_sel); |
// always @(*) |
// if ((i_wb_stb)&&(i_wb_we)) |
// `SLAVE_ASSUME(|i_wb_sel); |
|
|
// |
237,17 → 246,34
// If CYC was low on the last clock, then both ACK and ERR should be |
// low on this clock. |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_wb_cyc))) |
if ((f_past_valid)&&(!$past(i_wb_cyc))&&(!i_wb_cyc)) |
begin |
assume(!i_wb_ack); |
assume(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
// Stall may still be true--such as when we are not |
// selected at some arbiter between us and the slave |
end |
|
// |
// Any time the CYC line drops, it is possible that there may be a |
// remaining (registered) ACK or ERR that hasn't yet been returned. |
// Restrict such out of band returns so that they are *only* returned |
// if there is an outstanding operation. |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_cyc))&&(!i_wb_cyc)) |
begin |
if (($past(f_outstanding == 0)) |
&&((!$past(i_wb_stb && !i_wb_stall)) |
||($past(i_wb_ack|i_wb_err)))) |
begin |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end |
end |
|
// ACK and ERR may never both be true at the same time |
always @(*) |
assume((!i_wb_ack)||(!i_wb_err)); |
`SLAVE_ASSERT((!i_wb_ack)||(!i_wb_err)); |
|
generate if (F_MAX_STALL > 0) |
begin : MXSTALL |
260,13 → 286,14
|
initial f_stall_count = 0; |
always @(posedge i_clk) |
if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall)) |
f_stall_count <= f_stall_count + 1'b1; |
else |
f_stall_count <= 0; |
always @(posedge i_clk) |
if (i_wb_cyc) |
assume(f_stall_count < F_MAX_STALL); |
if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall)) |
f_stall_count <= f_stall_count + 1'b1; |
else |
f_stall_count <= 0; |
|
always @(*) |
if (i_wb_cyc) |
`SLAVE_ASSERT(f_stall_count < F_MAX_STALL); |
end endgenerate |
|
generate if (F_MAX_ACK_DELAY > 0) |
280,13 → 307,18
|
initial f_ackwait_count = 0; |
always @(posedge i_clk) |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err)) |
begin |
f_ackwait_count <= f_ackwait_count + 1'b1; |
assume(f_ackwait_count < F_MAX_ACK_DELAY); |
end else |
f_ackwait_count <= 0; |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err) |
&&(f_outstanding > 0)) |
f_ackwait_count <= f_ackwait_count + 1'b1; |
else |
f_ackwait_count <= 0; |
|
always @(*) |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err) |
&&(f_outstanding > 0)) |
`SLAVE_ASSERT(f_ackwait_count < F_MAX_ACK_DELAY); |
end endgenerate |
|
// |
294,10 → 326,10
// |
initial f_nreqs = 0; |
always @(posedge i_clk) |
if ((i_reset)||(!i_wb_cyc)) |
f_nreqs <= 0; |
else if ((i_wb_stb)&&(!i_wb_stall)) |
f_nreqs <= f_nreqs + 1'b1; |
if ((i_reset)||(!i_wb_cyc)) |
f_nreqs <= 0; |
else if ((i_wb_stb)&&(!i_wb_stall)) |
f_nreqs <= f_nreqs + 1'b1; |
|
|
// |
305,10 → 337,12
// |
initial f_nacks = 0; |
always @(posedge i_clk) |
if (!i_wb_cyc) |
f_nacks <= 0; |
else if ((i_wb_ack)||(i_wb_err)) |
f_nacks <= f_nacks + 1'b1; |
if (i_reset) |
f_nacks <= 0; |
else if (!i_wb_cyc) |
f_nacks <= 0; |
else if ((i_wb_ack)||(i_wb_err)) |
f_nacks <= f_nacks + 1'b1; |
|
// |
// The number of outstanding requests is the difference between |
316,38 → 350,37
// |
assign f_outstanding = (i_wb_cyc) ? (f_nreqs - f_nacks):0; |
|
always @(posedge i_clk) |
if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0)) |
begin |
if (i_wb_stb) |
assert(f_nreqs < F_MAX_REQUESTS); |
else |
assert(f_nreqs <= F_MAX_REQUESTS); |
assume(f_nacks <= f_nreqs); |
assert(f_outstanding < (1<<F_LGDEPTH)-1); |
end else |
assume(f_outstanding < (1<<F_LGDEPTH)-1); |
always @(*) |
if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0)) |
begin |
if (i_wb_stb) |
`SLAVE_ASSUME(f_nreqs < F_MAX_REQUESTS); |
else |
`SLAVE_ASSUME(f_nreqs <= F_MAX_REQUESTS); |
`SLAVE_ASSERT(f_nacks <= f_nreqs); |
assert(f_outstanding < (1<<F_LGDEPTH)-1); |
end else |
assume(f_outstanding < (1<<F_LGDEPTH)-1); |
|
always @(posedge i_clk) |
if ((i_wb_cyc)&&(f_outstanding == 0)) |
always @(*) |
if ((i_wb_cyc)&&(f_outstanding == 0)) |
begin |
// If nothing is outstanding, then there should be |
// no acknowledgements ... however, an acknowledgement |
// *can* come back on the same clock as the stb is |
// going out. |
if (F_OPT_MINCLOCK_DELAY) |
begin |
// If nothing is outstanding, then there should be |
// no acknowledgements |
assume(!i_wb_ack); |
// The same is not true of errors. It may be that an |
// error is created before the request gets through |
// assume(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end else begin |
`SLAVE_ASSERT((!i_wb_ack)||((i_wb_stb)&&(!i_wb_stall))); |
// The same is true of errors. They may not be |
// created before the request gets through |
`SLAVE_ASSERT((!i_wb_err)||((i_wb_stb)&&(!i_wb_stall))); |
end |
end |
|
// While the error signal may be asserted immediately before |
// anything is outstanding, it may only be asserted in |
// response to a transaction request--whether completed or |
// not. |
always @(posedge i_clk) |
if ((!i_wb_stb)&&(f_outstanding == 0)) |
assume(!i_wb_err); |
|
|
generate if (F_OPT_SOURCE) |
begin : SRC |
// Any opening bus request starts with both CYC and STB high |
357,8 → 390,8
// the CYC line may go high or low without actually affecting |
// the STB line of the slave. |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_wb_cyc))&&(i_wb_cyc)) |
assert(i_wb_stb); |
if ((f_past_valid)&&(!$past(i_wb_cyc))&&(i_wb_cyc)) |
`SLAVE_ASSUME(i_wb_stb); |
end endgenerate |
|
|
367,9 → 400,9
// If we aren't waiting for anything, and we aren't issuing |
// any requests, then then our transaction is over and we |
// should be dropping the CYC line. |
always @(posedge i_clk) |
if (f_outstanding == 0) |
assert((i_wb_stb)||(!i_wb_cyc)); |
always @(*) |
if (f_outstanding == 0) |
`SLAVE_ASSUME((i_wb_stb)||(!i_wb_cyc)); |
// Not all masters will abide by this restriction. Some |
// masters may wish to implement read-modify-write bus |
// interactions. These masters need to keep CYC high between |
392,10 → 425,10
begin |
if (!i_wb_cyc) |
begin |
restrict(!i_wb_stall); |
restrict($stable(i_wb_idata)); |
assume(!i_wb_stall); |
assume($stable(i_wb_idata)); |
end else if ((!$past(i_wb_ack))&&(!i_wb_ack)) |
restrict($stable(i_wb_idata)); |
assume($stable(i_wb_idata)); |
end |
end endgenerate |
|
410,8 → 443,8
// necessary, and the spec doesn't disallow them. Hence we |
// make this check optional. |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb))) |
assert(!i_wb_stb); |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb))) |
`SLAVE_ASSUME(!i_wb_stb); |
end endgenerate |
|
endmodule |
/trunk/bench/formal/fwb_slave.v
23,35 → 23,44
// master outputs (slave inputs)), and assumptions are made about the |
// master inputs (the slave outputs). |
// |
// In order to make it easier to compare the slave against the master, |
// assumptions with respect to the slave have been marked with the |
// `SLAVE_ASSUME macro. Similarly, assertions the slave would make have |
// been marked with `SLAVE_ASSERT. This allows the master to redefine |
// these two macros to be from his perspective, and therefore the |
// diffs between the two files actually show true differences, rather |
// than just these differences in perspective. |
// |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2017, Gisselquist Technology, LLC |
// Copyright (C) 2017-2018, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
81,6 → 90,14
parameter [0:0] F_OPT_DISCONTINUOUS = 0; |
// |
// |
// If true, insist that there be a minimum of a single clock delay |
// between request and response. This defaults to off since the |
// wishbone specification specifically doesn't require this. However, |
// some interfaces do, so we allow it as an option here. |
parameter [0:0] F_OPT_MINCLOCK_DELAY = 0; |
// |
// |
// |
localparam [(F_LGDEPTH-1):0] MAX_OUTSTANDING = {(F_LGDEPTH){1'b1}}; |
localparam MAX_DELAY = (F_MAX_STALL > F_MAX_ACK_DELAY) |
? F_MAX_STALL : F_MAX_ACK_DELAY; |
109,10 → 126,12
output reg [(F_LGDEPTH-1):0] f_nreqs, f_nacks; |
output wire [(F_LGDEPTH-1):0] f_outstanding; |
|
`define SLAVE_ASSUME assume |
`define SLAVE_ASSERT assert |
// |
// Let's just make sure our parameters are set up right |
// |
assert property(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}}); |
initial assert(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}}); |
|
// |
// Wrap the request line in a bundle. The top bit, named STB_BIT, |
131,8 → 150,8
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
always @(*) |
if (!f_past_valid) |
assume(i_reset); |
if (!f_past_valid) |
`SLAVE_ASSUME(i_reset); |
// |
// |
// Assertions regarding the initial (and reset) state |
141,40 → 160,26
|
// |
// Assume we start from a reset condition |
initial assume(i_reset); |
initial assume(!i_wb_cyc); |
initial assume(!i_wb_stb); |
initial assert(i_reset); |
initial `SLAVE_ASSUME(!i_wb_cyc); |
initial `SLAVE_ASSUME(!i_wb_stb); |
// |
initial assert(!i_wb_ack); |
initial assert(!i_wb_err); |
initial `SLAVE_ASSERT(!i_wb_ack); |
initial `SLAVE_ASSERT(!i_wb_err); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_reset))) |
if ((!f_past_valid)||($past(i_reset))) |
begin |
assume(!i_wb_cyc); |
assume(!i_wb_stb); |
`SLAVE_ASSUME(!i_wb_cyc); |
`SLAVE_ASSUME(!i_wb_stb); |
// |
assert(!i_wb_ack); |
assert(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end |
|
// Things can only change on the positive edge of the clock |
always @($global_clock) |
if ((f_past_valid)&&(!$rose(i_clk))) |
begin |
assume($stable(i_reset)); |
assume($stable(i_wb_cyc)); |
assume($stable(f_request)); |
if (i_wb_we) |
assume($stable(f_request)); // The entire request should b stabl |
else |
assume($stable(f_request[(2+AW-1):(DW+DW/8)])); |
// |
assert($stable(i_wb_ack)); |
assert($stable(i_wb_stall)); |
assert($stable(i_wb_idata)); |
assert($stable(i_wb_err)); |
end |
always @(*) |
if (!f_past_valid) |
`SLAVE_ASSUME(!i_wb_cyc); |
|
// |
// |
186,12 → 191,12
// the transaction |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_err))&&($past(i_wb_cyc))) |
assume(!i_wb_cyc); |
`SLAVE_ASSUME(!i_wb_cyc); |
|
// STB can only be true if CYC is also true |
always @(posedge i_clk) |
if (i_wb_stb) |
assume(i_wb_cyc); |
always @(*) |
if (i_wb_stb) |
`SLAVE_ASSUME(i_wb_cyc); |
|
// If a request was both outstanding and stalled on the last clock, |
// then nothing should change on this clock regarding it. |
199,27 → 204,31
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_stb)) |
&&($past(i_wb_stall))&&(i_wb_cyc)) |
begin |
assume(i_wb_stb); |
assume($stable(f_request)); |
`SLAVE_ASSUME(i_wb_stb); |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
`SLAVE_ASSUME(i_wb_addr == $past(i_wb_addr)); |
`SLAVE_ASSUME(i_wb_sel == $past(i_wb_sel)); |
if (i_wb_we) |
`SLAVE_ASSUME(i_wb_data == $past(i_wb_data)); |
end |
|
// Within any series of STB/requests, the direction of the request |
// may not change. |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb)) |
assume(i_wb_we == $past(i_wb_we)); |
if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb)) |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
|
|
// Within any given bus cycle, the direction may *only* change when |
// there are no further outstanding requests. |
always @(posedge i_clk) |
if ((f_past_valid)&&(f_outstanding > 0)) |
assume(i_wb_we == $past(i_wb_we)); |
if ((f_past_valid)&&(f_outstanding > 0)) |
`SLAVE_ASSUME(i_wb_we == $past(i_wb_we)); |
|
// Write requests must also set one (or more) of i_wb_sel |
always @(posedge i_clk) |
if ((i_wb_stb)&&(i_wb_we)) |
assume(|i_wb_sel); |
// always @(*) |
// if ((i_wb_stb)&&(i_wb_we)) |
// `SLAVE_ASSUME(|i_wb_sel); |
|
|
// |
231,17 → 240,29
// If CYC was low on the last clock, then both ACK and ERR should be |
// low on this clock. |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_wb_cyc))) |
if ((f_past_valid)&&(!$past(i_wb_cyc))&&(!i_wb_cyc)) |
begin |
assert(!i_wb_ack); |
assert(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
// Stall may still be true--such as when we are not |
// selected at some arbiter between us and the slave |
end |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_cyc))&&(!i_wb_cyc)) |
begin |
if (($past(f_outstanding == 0)) |
&&((!$past(i_wb_stb && !i_wb_stall)) |
||($past(i_wb_ack|i_wb_err)))) |
begin |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end |
end |
|
// ACK and ERR may never both be true at the same time |
always @(*) |
assume((!i_wb_ack)||(!i_wb_err)); |
`SLAVE_ASSERT((!i_wb_ack)||(!i_wb_err)); |
|
generate if (F_MAX_STALL > 0) |
begin : MXSTALL |
254,13 → 275,14
|
initial f_stall_count = 0; |
always @(posedge i_clk) |
if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall)) |
f_stall_count <= f_stall_count + 1'b1; |
else |
f_stall_count <= 0; |
always @(posedge i_clk) |
if (i_wb_cyc) |
assert(f_stall_count < F_MAX_STALL); |
if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall)) |
f_stall_count <= f_stall_count + 1'b1; |
else |
f_stall_count <= 0; |
|
always @(*) |
if (i_wb_cyc) |
`SLAVE_ASSERT(f_stall_count < F_MAX_STALL); |
end endgenerate |
|
generate if (F_MAX_ACK_DELAY > 0) |
274,13 → 296,18
|
initial f_ackwait_count = 0; |
always @(posedge i_clk) |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err)) |
begin |
f_ackwait_count <= f_ackwait_count + 1'b1; |
assert(f_ackwait_count < F_MAX_ACK_DELAY); |
end else |
f_ackwait_count <= 0; |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err) |
&&(f_outstanding > 0)) |
f_ackwait_count <= f_ackwait_count + 1'b1; |
else |
f_ackwait_count <= 0; |
|
always @(*) |
if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb) |
&&(!i_wb_ack)&&(!i_wb_err) |
&&(f_outstanding > 0)) |
`SLAVE_ASSERT(f_ackwait_count < F_MAX_ACK_DELAY); |
end endgenerate |
|
// |
288,10 → 315,10
// |
initial f_nreqs = 0; |
always @(posedge i_clk) |
if ((i_reset)||(!i_wb_cyc)) |
f_nreqs <= 0; |
else if ((i_wb_stb)&&(!i_wb_stall)) |
f_nreqs <= f_nreqs + 1'b1; |
if ((i_reset)||(!i_wb_cyc)) |
f_nreqs <= 0; |
else if ((i_wb_stb)&&(!i_wb_stall)) |
f_nreqs <= f_nreqs + 1'b1; |
|
|
// |
299,10 → 326,12
// |
initial f_nacks = 0; |
always @(posedge i_clk) |
if (!i_wb_cyc) |
f_nacks <= 0; |
else if ((i_wb_ack)||(i_wb_err)) |
f_nacks <= f_nacks + 1'b1; |
if (i_reset) |
f_nacks <= 0; |
else if (!i_wb_cyc) |
f_nacks <= 0; |
else if ((i_wb_ack)||(i_wb_err)) |
f_nacks <= f_nacks + 1'b1; |
|
// |
// The number of outstanding requests is the difference between |
310,45 → 339,45
// |
assign f_outstanding = (i_wb_cyc) ? (f_nreqs - f_nacks):0; |
|
always @(posedge i_clk) |
if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0)) |
begin |
if (i_wb_stb) |
assume(f_nreqs < F_MAX_REQUESTS); |
else |
assume(f_nreqs <= F_MAX_REQUESTS); |
assert(f_nacks <= f_nreqs); |
assert(f_outstanding < (1<<F_LGDEPTH)-1); |
end else |
assert(f_outstanding < (1<<F_LGDEPTH)-1); |
always @(*) |
if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0)) |
begin |
if (i_wb_stb) |
`SLAVE_ASSUME(f_nreqs < F_MAX_REQUESTS); |
else |
`SLAVE_ASSUME(f_nreqs <= F_MAX_REQUESTS); |
`SLAVE_ASSERT(f_nacks <= f_nreqs); |
assert(f_outstanding < (1<<F_LGDEPTH)-1); |
end else |
assume(f_outstanding < (1<<F_LGDEPTH)-1); |
|
always @(posedge i_clk) |
if ((i_wb_cyc)&&(f_outstanding == 0)) |
always @(*) |
if ((i_wb_cyc)&&(f_outstanding == 0)) |
begin |
// If nothing is outstanding, then there should be |
// no acknowledgements ... however, an acknowledgement |
// *can* come back on the same clock as the stb is |
// going out. |
if (F_OPT_MINCLOCK_DELAY) |
begin |
// If nothing is outstanding, then there should be |
// no acknowledgements |
assert(!i_wb_ack); |
// The same is not true of errors. It may be that an |
// error is created before the request gets through |
// assert(!i_wb_err); |
`SLAVE_ASSERT(!i_wb_ack); |
`SLAVE_ASSERT(!i_wb_err); |
end else begin |
`SLAVE_ASSERT((!i_wb_ack)||((i_wb_stb)&&(!i_wb_stall))); |
// The same is true of errors. They may not be |
// created before the request gets through |
`SLAVE_ASSERT((!i_wb_err)||((i_wb_stb)&&(!i_wb_stall))); |
end |
end |
|
// While the error signal may be asserted immediately before |
// anything is outstanding, it may only be asserted in |
// response to a transaction request--whether completed or |
// not. |
always @(posedge i_clk) |
if ((i_wb_cyc)&&(!i_wb_stb)&&(f_outstanding == 0)) |
assert(!i_wb_err); |
|
generate if (!F_OPT_RMW_BUS_OPTION) |
begin |
// If we aren't waiting for anything, and we aren't issuing |
// any requests, then then our transaction is over and we |
// should be dropping the CYC line. |
always @(posedge i_clk) |
if (f_outstanding == 0) |
assume((i_wb_stb)||(!i_wb_cyc)); |
always @(*) |
if (f_outstanding == 0) |
`SLAVE_ASSUME((i_wb_stb)||(!i_wb_cyc)); |
// Not all masters will abide by this restriction. Some |
// masters may wish to implement read-modify-write bus |
// interactions. These masters need to keep CYC high between |
367,8 → 396,8
// necessary, and the spec doesn't disallow them. Hence we |
// make this check optional. |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb))) |
assume(!i_wb_stb); |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb))) |
`SLAVE_ASSUME(!i_wb_stb); |
end endgenerate |
|
endmodule |
/trunk/bench/formal/wbarbiter.gtkw
0,0 → 1,72
[*] |
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI |
[*] Fri Dec 28 02:53:33 2018 |
[*] |
[dumpfile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/wbarbiter_cvr/engine_0/trace4.vcd" |
[dumpfile_mtime] "Fri Dec 28 02:48:56 2018" |
[dumpfile_size] 13681 |
[savefile] "/home/dan/jericho/work/rnd/opencores/wb2axip/trunk/bench/formal/wbarbiter.gtkw" |
[timestart] 0 |
[size] 1441 600 |
[pos] -1 -1 |
*-4.552812 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[sst_width] 270 |
[signals_width] 160 |
[sst_expanded] 1 |
[sst_vpaned_height] 143 |
@28 |
wbarbiter.i_clk |
wbarbiter.i_reset |
@200 |
- |
@28 |
wbarbiter.i_a_cyc |
wbarbiter.i_a_stb |
wbarbiter.i_a_we |
@22 |
wbarbiter.i_a_adr[31:0] |
wbarbiter.i_a_dat[31:0] |
wbarbiter.i_a_sel[3:0] |
@29 |
[color] 2 |
wbarbiter.o_a_stall |
[color] 2 |
wbarbiter.o_a_ack |
[color] 2 |
wbarbiter.o_a_err |
@200 |
- |
@28 |
wbarbiter.i_b_cyc |
wbarbiter.i_b_stb |
wbarbiter.i_b_we |
@22 |
wbarbiter.i_b_adr[31:0] |
wbarbiter.i_b_dat[31:0] |
wbarbiter.i_b_sel[3:0] |
@28 |
[color] 2 |
wbarbiter.o_b_stall |
[color] 2 |
wbarbiter.o_b_ack |
[color] 2 |
wbarbiter.o_b_err |
@200 |
- |
@28 |
wbarbiter.o_cyc |
wbarbiter.o_stb |
wbarbiter.o_we |
@22 |
wbarbiter.o_adr[31:0] |
wbarbiter.o_dat[31:0] |
wbarbiter.o_sel[3:0] |
@28 |
[color] 2 |
wbarbiter.i_ack |
[color] 2 |
wbarbiter.i_stall |
[color] 2 |
wbarbiter.i_err |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/bench/formal/wbarbiter.sby
0,0 → 1,23
[tasks] |
prf |
cvr |
|
[options] |
prf: mode prove |
prf: depth 4 |
cvr: mode cover |
cvr: depth 32 |
|
[engines] |
smtbmc |
|
[script] |
read -formal -D WBARBITER wbarbiter.v |
read -formal -D WBARBITER fwb_slave.v |
read -formal -D WBARBITER fwb_master.v |
prep -top wbarbiter |
|
[files] |
../../rtl/wbarbiter.v |
fwb_slave.v |
fwb_master.v |
/trunk/bench/formal/wbm2axilite.sby
0,0 → 1,23
[tasks] |
prf |
cvr |
|
[options] |
prf: mode prove |
prf: depth 18 |
cvr: mode cover |
cvr: depth 32 |
|
[engines] |
smtbmc |
|
[script] |
read -formal -D AXILRD2WBSP wbm2axilite.v |
read -formal -D AXILRD2WBSP faxil_master.v |
read -formal -D AXILRD2WBSP fwb_slave.v |
prep -top wbm2axilite |
|
[files] |
../../rtl/wbm2axilite.v |
faxil_master.v |
fwb_slave.v |
/trunk/bench/formal/wbm2axisp.ys
2,6 → 2,5
read_verilog -D WBM2AXISP -formal faxi_master.v |
read_verilog -D WBM2AXISP -formal fwb_slave.v |
prep -top wbm2axisp -nordff |
clk2fflogic |
opt -share_all |
write_smt2 -wires wbm2axisp.smt2 |
/trunk/bench/formal/wbxbar.sby
0,0 → 1,69
[tasks] |
prf4x8_buflp nxm opt_dblbuffer opt_lowpower |
prf4x8_buf nxm opt_dblbuffer |
prf4x8_lp nxm opt_lowpower |
prf4x8_cheap nxm |
prf4x8_buflpko nxm opt_dblbuffer opt_lowpower opt_timeout |
prf4x8_bufko nxm opt_dblbuffer opt_timeout |
prf4x8_lpko nxm opt_lowpower opt_timeout |
prf4x8_cheapko nxm opt_timeout |
prf4x8_buflpkos nxm opt_dblbuffer opt_lowpower opt_timeout opt_starvation |
prf4x8_bufkos nxm opt_dblbuffer opt_timeout opt_starvation |
prf4x8_lpkos nxm opt_lowpower opt_timeout opt_starvation |
prf4x8_cheapkos nxm opt_timeout opt_starvation |
prf1x8_buflp oxm opt_dblbuffer opt_lowpower |
prf1x8_buf oxm opt_dblbuffer |
prf1x8_lp oxm opt_lowpower |
prf1x8_cheap oxm |
prf1x8_buflpko oxm opt_dblbuffer opt_lowpower opt_timeout |
prf4x8_bufko oxm opt_dblbuffer opt_timeout |
prf1x8_lpko oxm opt_lowpower opt_timeout |
prf1x8_cheapko oxm opt_timeout |
prf1x8_buflpkos oxm opt_dblbuffer opt_lowpower opt_timeout opt_starvation |
prf1x8_bufkos oxm opt_dblbuffer opt_timeout opt_starvation |
prf1x8_lpkos oxm opt_lowpower opt_timeout opt_starvation |
prf1x8_cheapkos oxm opt_timeout opt_starvation |
prf4x1_buflp nxo opt_dblbuffer opt_lowpower |
prf4x1_buf nxo opt_dblbuffer |
prf4x1_lp nxo opt_lowpower |
prf4x1_cheap nxo |
prf4x1_buflpko nxo opt_dblbuffer opt_lowpower opt_timeout |
prf4x1_bufko nxo opt_dblbuffer opt_timeout |
prf4x1_lpko nxo opt_lowpower opt_timeout |
prf4x1_cheapko nxo opt_timeout |
prf4x1_buflpkos nxo opt_dblbuffer opt_lowpower opt_timeout opt_starvation |
prf4x1_bufkos nxo opt_dblbuffer opt_timeout opt_starvation |
prf4x1_lpkos nxo opt_lowpower opt_timeout opt_starvation |
prf4x1_cheapkos nxo opt_timeout opt_starvation |
|
[options] |
mode prove |
depth 5 |
|
[engines] |
# smtbmc boolector |
smtbmc |
# smtbmc z3 |
|
|
[script] |
read -formal wbxbar.v |
read -formal fwb_slave.v |
read -formal fwb_master.v |
nxm: chparam -set NM 4 -set NS 8 wbxbar |
oxm: chparam -set NM 1 -set NS 8 wbxbar |
nxo: chparam -set NM 4 -set NS 1 wbxbar |
opt_dblbuffer: chparam -set OPT_DBLBUFFER 1 wbxbar |
~opt_dblbuffer: chparam -set OPT_DBLBUFFER 0 wbxbar |
opt_lowpower: chparam -set OPT_LOWPOWER 1 wbxbar |
~opt_lowpower: chparam -set OPT_LOWPOWER 0 wbxbar |
opt_timeout: chparam -set OPT_TIMEOUT 20 wbxbar |
~opt_timeout: chparam -set OPT_TIMEOUT 0 wbxbar |
opt_starvation: chparam -set OPT_STARVATION_TIMEOUT 1 wbxbar |
~opt_starvation: chparam -set OPT_TIMEOUT 0 wbxbar |
prep -top wbxbar |
|
[files] |
../../rtl/wbxbar.v |
fwb_slave.v |
fwb_master.v |
/trunk/bench/formal/xlnxdemo.gtkw
0,0 → 1,62
[*] |
[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI |
[*] Thu Dec 27 16:19:38 2018 |
[*] |
[dumpfile] "/home/dan/work/rnd/opencores/wb2axip/trunk/bench/formal/xlnxdemo_cvr/engine_0/trace19.vcd" |
[dumpfile_mtime] "Thu Dec 27 03:40:12 2018" |
[dumpfile_size] 68959 |
[savefile] "/home/dan/work/rnd/opencores/wb2axip/trunk/bench/formal/xlnxdemo.gtkw" |
[timestart] 0 |
[size] 1473 600 |
[pos] -474 -1 |
*-6.470208 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[sst_width] 196 |
[signals_width] 166 |
[sst_expanded] 1 |
[sst_vpaned_height] 155 |
@29 |
[color] 3 |
xlnxdemo.S_AXI_ARESETN |
[color] 3 |
xlnxdemo.S_AXI_ACLK |
@200 |
- |
@28 |
xlnxdemo.S_AXI_AWVALID |
xlnxdemo.S_AXI_AWREADY |
@22 |
xlnxdemo.S_AXI_AWADDR[6:0] |
@200 |
- |
@28 |
xlnxdemo.S_AXI_WVALID |
xlnxdemo.S_AXI_WREADY |
@22 |
xlnxdemo.S_AXI_WSTRB[3:0] |
xlnxdemo.S_AXI_WDATA[31:0] |
@200 |
- |
@28 |
[color] 2 |
xlnxdemo.S_AXI_BVALID |
[color] 2 |
xlnxdemo.S_AXI_BREADY |
@200 |
- |
@28 |
xlnxdemo.S_AXI_ARVALID |
xlnxdemo.S_AXI_ARREADY |
@22 |
xlnxdemo.S_AXI_ARADDR[6:0] |
@200 |
- |
@28 |
[color] 2 |
xlnxdemo.S_AXI_RVALID |
[color] 2 |
xlnxdemo.S_AXI_RREADY |
@22 |
[color] 2 |
xlnxdemo.S_AXI_RDATA[31:0] |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/bench/formal/xlnxdemo.sby
0,0 → 1,21
[tasks] |
cvr |
prf |
|
[options] |
cvr: mode cover |
cvr: depth 60 |
prf: mode prove |
prf: depth 40 |
|
[engines] |
smtbmc |
|
[script] |
read -formal xlnxdemo.v |
read -formal faxil_slave.v |
prep -top xlnxdemo |
|
[files] |
xlnxdemo.v |
faxil_slave.v |
/trunk/bench/formal/xlnxdemo.v
0,0 → 1,1075
`default_nettype none // Added to the raw demo |
`timescale 1 ns / 1 ps |
// |
module xlnxdemo # |
( |
// Users to add parameters here |
|
// User parameters ends |
// Do not modify the parameters beyond this line |
|
// Width of S_AXI data bus |
parameter integer C_S_AXI_DATA_WIDTH = 32, |
// Width of S_AXI address bus |
parameter integer C_S_AXI_ADDR_WIDTH = 7 |
) |
( |
// Users to add ports here |
|
// User ports ends |
// Do not modify the ports beyond this line |
|
// Global Clock Signal |
input wire S_AXI_ACLK, |
// Global Reset Signal. This Signal is Active LOW |
input wire S_AXI_ARESETN, |
// Write address (issued by master, acceped by Slave) |
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, |
// Write channel Protection type. This signal indicates the |
// privilege and security level of the transaction, and whether |
// the transaction is a data access or an instruction access. |
input wire [2 : 0] S_AXI_AWPROT, |
// Write address valid. This signal indicates that the master signaling |
// valid write address and control information. |
input wire S_AXI_AWVALID, |
// Write address ready. This signal indicates that the slave is ready |
// to accept an address and associated control signals. |
output wire S_AXI_AWREADY, |
// Write data (issued by master, acceped by Slave) |
input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, |
// Write strobes. This signal indicates which byte lanes hold |
// valid data. There is one write strobe bit for each eight |
// bits of the write data bus. |
input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, |
// Write valid. This signal indicates that valid write |
// data and strobes are available. |
input wire S_AXI_WVALID, |
// Write ready. This signal indicates that the slave |
// can accept the write data. |
output wire S_AXI_WREADY, |
// Write response. This signal indicates the status |
// of the write transaction. |
output wire [1 : 0] S_AXI_BRESP, |
// Write response valid. This signal indicates that the channel |
// is signaling a valid write response. |
output wire S_AXI_BVALID, |
// Response ready. This signal indicates that the master |
// can accept a write response. |
input wire S_AXI_BREADY, |
// Read address (issued by master, acceped by Slave) |
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, |
// Protection type. This signal indicates the privilege |
// and security level of the transaction, and whether the |
// transaction is a data access or an instruction access. |
input wire [2 : 0] S_AXI_ARPROT, |
// Read address valid. This signal indicates that the channel |
// is signaling valid read address and control information. |
input wire S_AXI_ARVALID, |
// Read address ready. This signal indicates that the slave is |
// ready to accept an address and associated control signals. |
output wire S_AXI_ARREADY, |
// Read data (issued by slave) |
output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, |
// Read response. This signal indicates the status of the |
// read transfer. |
output wire [1 : 0] S_AXI_RRESP, |
// Read valid. This signal indicates that the channel is |
// signaling the required read data. |
output wire S_AXI_RVALID, |
// Read ready. This signal indicates that the master can |
// accept the read data and response information. |
input wire S_AXI_RREADY |
); |
|
// AXI4LITE signals |
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; |
reg axi_awready; |
reg axi_wready; |
reg [1 : 0] axi_bresp; |
reg axi_bvalid; |
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; |
reg axi_arready; |
reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; |
reg [1 : 0] axi_rresp; |
reg axi_rvalid; |
|
// Example-specific design signals |
// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH |
// ADDR_LSB is used for addressing 32/64 bit registers/memories |
// ADDR_LSB = 2 for 32 bits (n downto 2) |
// ADDR_LSB = 3 for 64 bits (n downto 3) |
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; |
localparam integer OPT_MEM_ADDR_BITS = 4; |
//---------------------------------------------- |
//-- Signals for user logic register space example |
//------------------------------------------------ |
//-- Number of Slave Registers 32 |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg4; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg5; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg6; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg7; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg8; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg9; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg10; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg11; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg12; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg13; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg14; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg15; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg16; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg17; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg18; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg19; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg20; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg21; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg22; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg23; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg24; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg25; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg26; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg27; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg28; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg29; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg30; |
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg31; |
wire slv_reg_rden; |
wire slv_reg_wren; |
reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; |
integer byte_index; |
|
// I/O Connections assignments |
|
assign S_AXI_AWREADY = axi_awready; |
assign S_AXI_WREADY = axi_wready; |
assign S_AXI_BRESP = axi_bresp; |
assign S_AXI_BVALID = axi_bvalid; |
assign S_AXI_ARREADY = axi_arready; |
assign S_AXI_RDATA = axi_rdata; |
assign S_AXI_RRESP = axi_rresp; |
assign S_AXI_RVALID = axi_rvalid; |
// Implement axi_awready generation |
// axi_awready is asserted for one S_AXI_ACLK clock cycle when both |
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is |
// de-asserted when reset is low. |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_awready <= 1'b0; |
end |
else |
begin |
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) |
begin |
// slave is ready to accept write address when |
// there is a valid write address and write data |
// on the write address and data bus. This design |
// expects no outstanding transactions. |
axi_awready <= 1'b1; |
end |
else |
begin |
axi_awready <= 1'b0; |
end |
end |
end |
|
// Implement axi_awaddr latching |
// This process is used to latch the address when both |
// S_AXI_AWVALID and S_AXI_WVALID are valid. |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_awaddr <= 0; |
end |
else |
begin |
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) |
begin |
// Write Address latching |
axi_awaddr <= S_AXI_AWADDR; |
end |
end |
end |
|
// Implement axi_wready generation |
// axi_wready is asserted for one S_AXI_ACLK clock cycle when both |
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is |
// de-asserted when reset is low. |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_wready <= 1'b0; |
end |
else |
begin |
if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID) |
begin |
// slave is ready to accept write data when |
// there is a valid write address and write data |
// on the write address and data bus. This design |
// expects no outstanding transactions. |
axi_wready <= 1'b1; |
end |
else |
begin |
axi_wready <= 1'b0; |
end |
end |
end |
|
// Implement memory mapped register select and write logic generation |
// The write data is accepted and written to memory mapped registers when |
// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to |
// select byte enables of slave registers while writing. |
// These registers are cleared when reset (active low) is applied. |
// Slave register write enable is asserted when valid address and data are available |
// and the slave is ready to accept the write address and write data. |
assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
slv_reg0 <= 0; |
slv_reg1 <= 0; |
slv_reg2 <= 0; |
slv_reg3 <= 0; |
slv_reg4 <= 0; |
slv_reg5 <= 0; |
slv_reg6 <= 0; |
slv_reg7 <= 0; |
slv_reg8 <= 0; |
slv_reg9 <= 0; |
slv_reg10 <= 0; |
slv_reg11 <= 0; |
slv_reg12 <= 0; |
slv_reg13 <= 0; |
slv_reg14 <= 0; |
slv_reg15 <= 0; |
slv_reg16 <= 0; |
slv_reg17 <= 0; |
slv_reg18 <= 0; |
slv_reg19 <= 0; |
slv_reg20 <= 0; |
slv_reg21 <= 0; |
slv_reg22 <= 0; |
slv_reg23 <= 0; |
slv_reg24 <= 0; |
slv_reg25 <= 0; |
slv_reg26 <= 0; |
slv_reg27 <= 0; |
slv_reg28 <= 0; |
slv_reg29 <= 0; |
slv_reg30 <= 0; |
slv_reg31 <= 0; |
end |
else begin |
if (slv_reg_wren) |
begin |
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) |
5'h00: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 0 |
slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h01: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 1 |
slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h02: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 2 |
slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h03: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 3 |
slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h04: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 4 |
slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h05: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 5 |
slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h06: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 6 |
slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h07: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 7 |
slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h08: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 8 |
slv_reg8[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h09: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 9 |
slv_reg9[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0A: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 10 |
slv_reg10[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0B: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 11 |
slv_reg11[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0C: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 12 |
slv_reg12[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0D: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 13 |
slv_reg13[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0E: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 14 |
slv_reg14[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h0F: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 15 |
slv_reg15[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h10: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 16 |
slv_reg16[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h11: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 17 |
slv_reg17[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h12: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 18 |
slv_reg18[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h13: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 19 |
slv_reg19[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h14: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 20 |
slv_reg20[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h15: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 21 |
slv_reg21[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h16: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 22 |
slv_reg22[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h17: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 23 |
slv_reg23[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h18: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 24 |
slv_reg24[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h19: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 25 |
slv_reg25[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1A: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 26 |
slv_reg26[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1B: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 27 |
slv_reg27[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1C: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 28 |
slv_reg28[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1D: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 29 |
slv_reg29[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1E: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 30 |
slv_reg30[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
5'h1F: |
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) |
if ( S_AXI_WSTRB[byte_index] == 1 ) begin |
// Respective byte enables are asserted as per write strobes |
// Slave register 31 |
slv_reg31[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; |
end |
default : begin |
slv_reg0 <= slv_reg0; |
slv_reg1 <= slv_reg1; |
slv_reg2 <= slv_reg2; |
slv_reg3 <= slv_reg3; |
slv_reg4 <= slv_reg4; |
slv_reg5 <= slv_reg5; |
slv_reg6 <= slv_reg6; |
slv_reg7 <= slv_reg7; |
slv_reg8 <= slv_reg8; |
slv_reg9 <= slv_reg9; |
slv_reg10 <= slv_reg10; |
slv_reg11 <= slv_reg11; |
slv_reg12 <= slv_reg12; |
slv_reg13 <= slv_reg13; |
slv_reg14 <= slv_reg14; |
slv_reg15 <= slv_reg15; |
slv_reg16 <= slv_reg16; |
slv_reg17 <= slv_reg17; |
slv_reg18 <= slv_reg18; |
slv_reg19 <= slv_reg19; |
slv_reg20 <= slv_reg20; |
slv_reg21 <= slv_reg21; |
slv_reg22 <= slv_reg22; |
slv_reg23 <= slv_reg23; |
slv_reg24 <= slv_reg24; |
slv_reg25 <= slv_reg25; |
slv_reg26 <= slv_reg26; |
slv_reg27 <= slv_reg27; |
slv_reg28 <= slv_reg28; |
slv_reg29 <= slv_reg29; |
slv_reg30 <= slv_reg30; |
slv_reg31 <= slv_reg31; |
end |
endcase |
end |
end |
end |
|
// Implement write response logic generation |
// The write response and response valid signals are asserted by the slave |
// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. |
// This marks the acceptance of address and indicates the status of |
// write transaction. |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_bvalid <= 0; |
axi_bresp <= 2'b0; |
end |
else |
begin |
if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) |
begin |
// indicates a valid write response is available |
axi_bvalid <= 1'b1; |
axi_bresp <= 2'b0; // 'OKAY' response |
end // work error responses in future |
else |
begin |
if (S_AXI_BREADY && axi_bvalid) |
//check if bready is asserted while bvalid is high) |
//(there is a possibility that bready is always asserted high) |
begin |
axi_bvalid <= 1'b0; |
end |
end |
end |
end |
|
// Implement axi_arready generation |
// axi_arready is asserted for one S_AXI_ACLK clock cycle when |
// S_AXI_ARVALID is asserted. axi_awready is |
// de-asserted when reset (active low) is asserted. |
// The read address is also latched when S_AXI_ARVALID is |
// asserted. axi_araddr is reset to zero on reset assertion. |
|
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_arready <= 1'b0; |
axi_araddr <= 7'b0; |
end |
else |
begin |
if (~axi_arready && S_AXI_ARVALID) |
begin |
// indicates that the slave has acceped the valid read address |
axi_arready <= 1'b1; |
// Read address latching |
axi_araddr <= S_AXI_ARADDR; |
end |
else |
begin |
axi_arready <= 1'b0; |
end |
end |
end |
|
// Implement axi_arvalid generation |
// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both |
// S_AXI_ARVALID and axi_arready are asserted. The slave registers |
// data are available on the axi_rdata bus at this instance. The |
// assertion of axi_rvalid marks the validity of read data on the |
// bus and axi_rresp indicates the status of read transaction.axi_rvalid |
// is deasserted on reset (active low). axi_rresp and axi_rdata are |
// cleared to zero on reset (active low). |
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_rvalid <= 0; |
axi_rresp <= 0; |
end |
else |
begin |
if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) |
begin |
// Valid read data is available at the read data bus |
axi_rvalid <= 1'b1; |
axi_rresp <= 2'b0; // 'OKAY' response |
end |
else if (axi_rvalid && S_AXI_RREADY) |
begin |
// Read data is accepted by the master |
axi_rvalid <= 1'b0; |
end |
end |
end |
|
// Implement memory mapped register select and read logic generation |
// Slave register read enable is asserted when valid address is available |
// and the slave is ready to accept the read address. |
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; |
always @(*) |
begin |
reg_data_out = 0; |
// Address decoding for reading registers |
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) |
5'h00 : reg_data_out = slv_reg0; |
5'h01 : reg_data_out = slv_reg1; |
5'h02 : reg_data_out = slv_reg2; |
5'h03 : reg_data_out = slv_reg3; |
5'h04 : reg_data_out = slv_reg4; |
5'h05 : reg_data_out = slv_reg5; |
5'h06 : reg_data_out = slv_reg6; |
5'h07 : reg_data_out = slv_reg7; |
5'h08 : reg_data_out = slv_reg8; |
5'h09 : reg_data_out = slv_reg9; |
5'h0A : reg_data_out = slv_reg10; |
5'h0B : reg_data_out = slv_reg11; |
5'h0C : reg_data_out = slv_reg12; |
5'h0D : reg_data_out = slv_reg13; |
5'h0E : reg_data_out = slv_reg14; |
5'h0F : reg_data_out = slv_reg15; |
5'h10 : reg_data_out = slv_reg16; |
5'h11 : reg_data_out = slv_reg17; |
5'h12 : reg_data_out = slv_reg18; |
5'h13 : reg_data_out = slv_reg19; |
5'h14 : reg_data_out = slv_reg20; |
5'h15 : reg_data_out = slv_reg21; |
5'h16 : reg_data_out = slv_reg22; |
5'h17 : reg_data_out = slv_reg23; |
5'h18 : reg_data_out = slv_reg24; |
5'h19 : reg_data_out = slv_reg25; |
5'h1A : reg_data_out = slv_reg26; |
5'h1B : reg_data_out = slv_reg27; |
5'h1C : reg_data_out = slv_reg28; |
5'h1D : reg_data_out = slv_reg29; |
5'h1E : reg_data_out = slv_reg30; |
5'h1F : reg_data_out = slv_reg31; |
default : reg_data_out = 0; |
endcase |
end |
|
// Output register or memory read data |
always @( posedge S_AXI_ACLK ) |
begin |
if ( S_AXI_ARESETN == 1'b0 ) |
begin |
axi_rdata <= 0; |
end |
else |
begin |
// When there is a valid read address (S_AXI_ARVALID) with |
// acceptance of read address by the slave (axi_arready), |
// output the read data |
if (slv_reg_rden) |
begin |
axi_rdata <= reg_data_out; // register read data |
end |
end |
end |
|
// Add user logic here |
|
// User logic ends |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Formal Verification section begins here. |
// |
// The following code was not part of the original Xilinx demo. |
// |
//////////////////////////////////////////////////////////////////////////////// |
`ifdef FORMAL |
localparam F_LGDEPTH = 4; |
|
wire [(F_LGDEPTH-1):0] f_axi_awr_outstanding, |
f_axi_wr_outstanding, |
f_axi_rd_outstanding; |
|
// |
// Connect our slave to the AXI-lite property set |
// |
faxil_slave #(// .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH), |
.F_LGDEPTH(F_LGDEPTH)) properties( |
.i_clk(S_AXI_ACLK), |
.i_axi_reset_n(S_AXI_ARESETN), |
// |
.i_axi_awaddr(S_AXI_AWADDR), |
.i_axi_awcache(4'h0), |
.i_axi_awprot(S_AXI_AWPROT), |
.i_axi_awvalid(S_AXI_AWVALID), |
.i_axi_awready(S_AXI_AWREADY), |
// |
.i_axi_wdata(S_AXI_WDATA), |
.i_axi_wstrb(S_AXI_WSTRB), |
.i_axi_wvalid(S_AXI_WVALID), |
.i_axi_wready(S_AXI_WREADY), |
// |
.i_axi_bresp(S_AXI_BRESP), |
.i_axi_bvalid(S_AXI_BVALID), |
.i_axi_bready(S_AXI_BREADY), |
// |
.i_axi_araddr(S_AXI_ARADDR), |
.i_axi_arprot(S_AXI_ARPROT), |
.i_axi_arcache(4'h0), |
.i_axi_arvalid(S_AXI_ARVALID), |
.i_axi_arready(S_AXI_ARREADY), |
// |
.i_axi_rdata(S_AXI_RDATA), |
.i_axi_rresp(S_AXI_RRESP), |
.i_axi_rvalid(S_AXI_RVALID), |
.i_axi_rready(S_AXI_RREADY), |
// |
.f_axi_rd_outstanding(f_axi_rd_outstanding), |
.f_axi_wr_outstanding(f_axi_wr_outstanding), |
.f_axi_awr_outstanding(f_axi_awr_outstanding)); |
|
reg f_past_valid; |
initial f_past_valid = 1'b0; |
always @(posedge S_AXI_ACLK) |
f_past_valid <= 1'b1; |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Properties necessary to pass induction |
// --- assuming we make it that far (we won't) |
// |
// |
always @(*) |
if (S_AXI_ARESETN) |
begin |
assert(f_axi_rd_outstanding == ((S_AXI_RVALID)? 1:0)); |
assert(f_axi_wr_outstanding == ((S_AXI_BVALID)? 1:0)); |
end |
|
always @(*) |
assert(f_axi_awr_outstanding == f_axi_wr_outstanding); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// |
// Cover properties |
// |
// |
// Make sure it is possible to change our register |
always @(posedge S_AXI_ACLK) |
cover($changed(slv_reg0)&&(slv_reg0 == 32'hdeadbeef)); |
|
always @(posedge S_AXI_ACLK) |
cover((axi_rvalid)&&(axi_rdata == 32'hdeadbeef) |
&&($past(axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 0))); |
|
// Make sure it is possible to read from our register |
always @(posedge S_AXI_ACLK) |
cover($past(reg_data_out == slv_reg0) |
&&($past(axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB])==0) |
&&(axi_rdata == slv_reg0)); |
|
// Performance test. See if we can retire a request on every other |
// instruction |
// |
// --- This first pair of cover statements will pass as written |
// |
// First a write check |
always @(posedge S_AXI_ACLK) |
cover( ((S_AXI_BVALID)&&(S_AXI_BREADY)) |
&&(!$past((S_AXI_BVALID)&&(S_AXI_BREADY),1)) |
&&( $past((S_AXI_BVALID)&&(S_AXI_BREADY),2)) |
&&(!$past((S_AXI_BVALID)&&(S_AXI_BREADY),3))); |
|
// Now a read check |
always @(posedge S_AXI_ACLK) |
cover( ((S_AXI_RVALID)&&(S_AXI_RREADY)) |
&&(!$past((S_AXI_RVALID)&&(S_AXI_RREADY),1)) |
&&( $past((S_AXI_RVALID)&&(S_AXI_RREADY),2)) |
&&(!$past((S_AXI_RVALID)&&(S_AXI_RREADY),3))); |
|
// Now let's see if we can retire one value every clock tick |
// |
// --- These two cover statements will fail, even though the ones |
// above will pass. This is why I call the design "crippled". |
// |
// First a write check |
always @(posedge S_AXI_ACLK) |
cover( ((S_AXI_BVALID)&&(S_AXI_BREADY)) |
&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),1)) |
&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),2)) |
&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),3))); |
|
// Now a read check |
always @(posedge S_AXI_ACLK) |
cover( ((S_AXI_RVALID)&&(S_AXI_RREADY)) |
&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),1)) |
&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),2)) |
&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),3))); |
|
// Now let's spend some time to develop a more complicated read |
// trace, showing the capabilities of the core. We'll avoid the |
// broken parts of the core, and just present ... something useful. |
// |
reg [12:0] fr_rdcover, fw_rdcover; |
|
initial fr_rdcover = 0; |
always @(posedge S_AXI_ACLK) |
if (!S_AXI_ARESETN) |
fr_rdcover <= 0; |
else |
fr_rdcover <= fw_rdcover; |
|
always @(*) |
if ((!S_AXI_ARESETN)||(S_AXI_AWVALID)||(S_AXI_WVALID)) |
fw_rdcover = 0; |
else begin |
// |
// A basic read request |
fw_rdcover[0] = (S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[1] = fr_rdcover[0] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[2] = fr_rdcover[1] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[3] = fr_rdcover[2] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[4] = fr_rdcover[3] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
// |
// A high speed/pipelined read request |
fw_rdcover[5] = fr_rdcover[4] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[6] = fr_rdcover[5] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[7] = fr_rdcover[6] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[8] = fr_rdcover[7] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[9] = fr_rdcover[8] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[10] = fr_rdcover[9] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[11] = fr_rdcover[10] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rdcover[12] = fr_rdcover[11] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
end |
|
always @(*) |
begin |
cover(fw_rdcover[0]); |
cover(fw_rdcover[1]); |
cover(fw_rdcover[2]); |
cover(fw_rdcover[3]); |
cover(fw_rdcover[4]); |
cover(fw_rdcover[5]); // |
cover(fw_rdcover[6]); |
cover(fw_rdcover[7]); |
cover(fw_rdcover[8]); |
cover(fw_rdcover[9]); |
cover(fw_rdcover[10]); |
cover(fw_rdcover[11]); |
cover(fw_rdcover[12]); |
end |
|
// |
// Now let's repeat our complicated cover approach for the write |
// channel. |
// |
reg [24:0] fr_wrcover, fw_wrcover; |
|
initial fr_wrcover = 0; |
always @(posedge S_AXI_ACLK) |
if (!S_AXI_ARESETN) |
fr_wrcover <= 0; |
else |
fr_wrcover <= fw_wrcover; |
|
always @(*) |
if ((!S_AXI_ARESETN)||(S_AXI_ARVALID)||(!S_AXI_BREADY)) |
fw_wrcover = 0; |
else begin |
// |
// A basic (synchronized) write request |
fw_wrcover[0] = (S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[1] = fr_wrcover[0] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[2] = fr_wrcover[1] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[3] = fr_wrcover[2] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[4] = fr_wrcover[3] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
// |
// Address before data |
fw_wrcover[5] = fr_wrcover[4] |
&&(S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[6] = fr_wrcover[5] |
&&(S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[7] = fr_wrcover[6] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[8] = fr_wrcover[7] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[9] = fr_wrcover[8] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[10] = fr_wrcover[9] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
// |
// Data before address |
fw_wrcover[11] = fr_wrcover[10] |
&&(!S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[12] = fr_wrcover[11] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[13] = fr_wrcover[12] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[14] = fr_wrcover[13] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[15] = fr_wrcover[14] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
// |
// A high speed/pipelined read request |
fw_wrcover[16] = fr_wrcover[15] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[17] = fr_wrcover[16] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[18] = fr_wrcover[17] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[19] = fr_wrcover[18] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[20] = fr_wrcover[19] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[21] = fr_wrcover[20] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID); |
fw_wrcover[22] = fr_wrcover[21] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[23] = fr_wrcover[22] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
fw_wrcover[24] = fr_wrcover[23] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID); |
end |
|
always @(*) |
begin |
cover(fw_wrcover[0]); |
cover(fw_wrcover[1]); |
cover(fw_wrcover[2]); |
cover(fw_wrcover[3]); |
cover(fw_wrcover[4]); |
cover(fw_wrcover[5]); // |
cover(fw_wrcover[6]); |
cover(fw_wrcover[7]); |
cover(fw_wrcover[8]); |
cover(fw_wrcover[9]); |
cover(fw_wrcover[11]); |
cover(fw_wrcover[12]); |
cover(fw_wrcover[13]); |
cover(fw_wrcover[14]); |
cover(fw_wrcover[15]); |
cover(fw_wrcover[16]); |
cover(fw_wrcover[17]); |
cover(fw_wrcover[18]); |
cover(fw_wrcover[19]); |
cover(fw_wrcover[20]); |
cover(fw_wrcover[21]); |
cover(fw_wrcover[22]); |
cover(fw_wrcover[23]); |
cover(fw_wrcover[24]); |
end |
`endif |
// |
// |
// Bug fixes section |
// |
// The lines below contain assumptions necessary to get the design |
// to work. They represent things Xilinx never thought of when |
// building their demo. |
// |
// The following lines are only questionable a bug |
initial axi_arready = 1'b0; |
initial axi_awready = 1'b0; |
initial axi_wready = 1'b0; |
initial axi_bvalid = 1'b0; |
initial axi_rvalid = 1'b0; |
|
// |
// This here is necessary to avoid the biggest bug within the design. |
// |
// If you uncomment the following two lines, the design will work as |
// intended. Only ... the bus now has more requirements to it. |
// |
// always @(posedge S_AXI_ACLK) |
// if ($past(S_AXI_ARESETN)) |
// assume((S_AXI_RREADY)&&(S_AXI_BREADY)); |
|
// verilator lint_off UNUSED |
wire [9:0] unused; |
assign unused = { S_AXI_ARPROT, S_AXI_AWPROT, |
axi_awaddr[1:0], axi_araddr[1:0] }; |
// verilator lint_on UNUSED |
endmodule |
/trunk/doc/Makefile
10,7 → 10,7
## Targets include: |
## all Builds all documents |
## |
## gpl-3.0.pdf Builds the GPL license these files are released |
## lgpl-3.0.pdf Builds the LGPL license these files are released |
## under. |
## |
## spec.pdf Builds the specification for the SDSPI |
21,43 → 21,47
## |
################################################################################ |
## |
## Copyright (C) 2015-2016, Gisselquist Technology, LLC |
## Copyright (C) 2015-2016,2018 Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## This file is part of the pipelined Wishbone to AXI converter project, a |
## project that contains multiple bus bridging designs and formal bus property |
## sets. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## The bus bridge designs and property sets are free RTL designs: you can |
## redistribute them and/or modify any of them under the terms of the GNU |
## Lesser General Public License as published by the Free Software Foundation, |
## either version 3 of the License, or (at your option) any later version. |
## |
## You should have received a copy of the GNU General Public License along |
## with this program. (It's in the $(ROOT)/doc directory, run make with no |
## target there if the PDF file isn't present.) If not, see |
## The bus bridge designs and property sets are distributed in the hope that |
## they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
## warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
## GNU Lesser General Public License for more details. |
## |
## You should have received a copy of the GNU Lesser General Public License |
## along with these designs. (It's in the $(ROOT)/doc directory. Run make |
## with no target there if the PDF file isn't present.) If not, see |
## <http://www.gnu.org/licenses/> for a copy. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## License: LGPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/lgpl.html |
## |
## |
################################################################################ |
## |
## |
all: gpl |
pdf: gpl spec |
all: lgpl |
pdf: lgpl spec |
DSRC := src |
|
.PHONY: gpl |
gpl: gpl-3.0.pdf |
.PHONY: lgpl |
LICENSE := lgpl-3.0 |
lgpl: $(LICENSE).pdf |
|
gpl-3.0.pdf: $(DSRC)/gpl-3.0.tex |
latex $(DSRC)/gpl-3.0.tex |
latex $(DSRC)/gpl-3.0.tex |
dvips -q -z -t letter -P pdf -o gpl-3.0.ps gpl-3.0.dvi |
ps2pdf -dAutoRotatePages=/All gpl-3.0.ps gpl-3.0.pdf |
rm gpl-3.0.dvi gpl-3.0.log gpl-3.0.aux gpl-3.0.ps |
$(LICENSE).pdf: $(DSRC)/$(LICENSE).tex |
latex $(DSRC)/$(LICENSE).tex |
latex $(DSRC)/$(LICENSE).tex |
dvips -q -z -t letter -P pdf -o $(LICENSE).ps $(LICENSE).dvi |
ps2pdf -dAutoRotatePages=/All $(LICENSE).ps $(LICENSE).pdf |
rm $(LICENSE).dvi $(LICENSE).log $(LICENSE).aux $(LICENSE).ps |
|
.PHONY: spec |
spec: spec.pdf |
79,5 → 83,4
rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc |
rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof |
rm -f $(DSRC)/spec.out spec.ps spec.pdf |
rm -f gpl-3.0.pdf |
|
rm -f $(LICENSE).pdf |
/trunk/doc/src/spec.tex
3,21 → 3,48
%% |
%% Filename: spec.tex |
%% |
%% Project: |
%% Project: Pipelined Wishbone to AXI coverter |
%% |
%% Purpose: |
%% Purpose: This document is a LaTeX description describing how to build |
%% a specification document for the cores within this Pipelined |
%% WB2AXI repository. |
%% |
%% Creator: |
%% Creator: Dan Gisselquist, Ph.D. |
%% Gisselquist Technology, LLC |
%% |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
%% |
%% Copyright (C) 2018, Gisselquist Technology, LLC |
%% |
%% This program is free software (firmware): you can redistribute it and/or |
%% modify it under the terms of the GNU General Public License as published |
%% by the Free Software Foundation, either version 3 of the License, or (at |
%% your option) any later version. |
%% |
%% This program is distributed in the hope that it will be useful, but WITHOUT |
%% ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
%% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
%% for more details. |
%% |
%% You should have received a copy of the GNU General Public License along |
%% with this program. (It's in the $(ROOT)/doc directory, run make with no |
%% target there if the PDF file isn't present.) If not, see |
%% <http://www.gnu.org/licenses/> for a copy. |
%% |
%% License: GPL, v3, as defined and found on www.gnu.org, |
%% http://www.gnu.org/licenses/gpl.html |
%% |
%% |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
%% |
%% |
\usepackage{import} |
\usepackage{bytefield} |
\project{Wishbone to AXI} |
\title{Specification} |
\author{Dan Gisselquist, Ph.D.} |
\email{dgisselq (at) opencores.org} |
\revision{Rev.~0.0} |
\email{zipcpu (at) gmail.com} |
\revision{Rev.~0.1} |
\begin{document} |
\pagestyle{gqtekspecplain} |
\titlepage |
25,17 → 52,27
Copyright (C) \theyear\today, Gisselquist Technology, LLC |
|
This project is free software (firmware): you can redistribute it and/or |
modify it under the terms of the GNU General Public License as published |
modify it under the terms of the GNU General Public License as published |
by the Free Software Foundation, either version 3 of the License, or (at |
your option) any later version. |
|
Some files within this repository have been released under the GNU Lesser |
General Public License. These components may be separated from this repository, |
and redistributed or modified under the terms of the Lesser GNU |
Public License, again as published by the Free Software Foundation, |
either vversion 3 of the License or (at your option) any later |
version. These files will identified as such in their headers. |
|
This program is distributed in the hope that it will be useful, but WITHOUT |
ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
for more details. |
for more details, or the GNU Lesser General Public License as appropriate. |
|
You should have received a copy of the GNU General Public License along |
with this program. If not, see \texttt{http://www.gnu.org/licenses/} for a copy. |
You should have received a copy of both the GNU General Public License as |
well as the GNU Lesser General Public License along with this repository. |
(They are both in the \$(ROOT)/doc directory. Run make with no target there |
if the PDF files are not present.) If not, see If not, see |
\texttt{http://www.gnu.org/licenses/} for a copy. |
\end{license} |
\begin{revisionhistory} |
0.0 & 9/6/2016 & D. Gisselquist & First draft\\\hline |
46,13 → 83,19
\listoffigures |
\listoftables |
\begin{preface} |
This controller is born of necessity. As long as Xilinx's proprietary IP |
makes it difficult to access memory, providing only access via the proprietary |
AXI bus, some conversion will be necessary for anyone who wishes to use a |
wishbone interface. |
The wishbone to AXI controller is born of necessity. As long as Xilinx's |
proprietary IP makes it difficult to access memory, providing only access |
via the proprietary AXI bus, some conversion will be necessary for anyone |
who wishes to use a wishbone interface. |
|
A special shout out and thanks go to Stephan Wallentowitz, for his first |
draft of such a converter, and to Olofk for encouraging me to write it. |
draft of such a converter, and to Olofk for encouraging me to write this |
initial core. |
|
The project has since grown into a general purpose set of both bus bridges |
and formal bus properties, to include support for Wishbone, AXI-lite, and |
Avalon busses. The full AXI implementation, together with the bridges |
between full AXI and other busses, remains a work in progress. |
\end{preface} |
|
\chapter{Introduction}\label{ch:intro} |
99,9 → 142,9
\begin{wishboneds} |
Revision level of wishbone & WB B4 spec \\\hline |
Type of interface & Slave, Read/Write, pipeline reads supported \\\hline |
Port size & 128--bit or 32--bit \\\hline |
Port size & Various and configurable \\\hline |
Port granularity & 8--bit \\\hline |
Maximum Operand Size & 128--bit or 32--bit \\\hline |
Maximum Operand Size & Various and configurable\\\hline |
Data transfer ordering & (Preserved) \\\hline |
Clock constraints & None.\\\hline |
Signal Names & \begin{tabular}{ll} |
/trunk/rtl/Makefile
17,25 → 17,29
## |
################################################################################ |
## |
## Copyright (C) 2016, Gisselquist Technology, LLC |
## Copyright (C) 2016,2018, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## This file is part of the pipelined Wishbone to AXI converter project, a |
## project that contains multiple bus bridging designs and formal bus property |
## sets. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## The bus bridge designs and property sets are free RTL designs: you can |
## redistribute them and/or modify any of them under the terms of the GNU |
## Lesser General Public License as published by the Free Software Foundation, |
## either version 3 of the License, or (at your option) any later version. |
## |
## You should have received a copy of the GNU General Public License along |
## with this program. (It's in the $(ROOT)/doc directory. Run make with no |
## target there if the PDF file isn't present.) If not, see |
## The bus bridge designs and property sets are distributed in the hope that |
## they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
## warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
## GNU Lesser General Public License for more details. |
## |
## You should have received a copy of the GNU Lesser General Public License |
## along with these designs. (It's in the $(ROOT)/doc directory. Run make |
## with no target there if the PDF file isn't present.) If not, see |
## <http://www.gnu.org/licenses/> for a copy. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## License: LGPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/lgpl.html |
## |
################################################################################ |
## |
47,7 → 51,7
VDIRFB:= $(FBDIR)/obj_dir |
|
.PHONY: test |
test: testwb testaxi |
test: testwb |
|
.PHONY: testwb |
.PHONY: testaxi |
58,13 → 62,45
.PHONY: axim2wbsp |
axim2wbsp: testaxi |
|
.PHONY: axilite |
|
testwb: $(VDIRFB)/Vwbm2axisp__ALL.a |
testaxi: $(VDIRFB)/Vaxim2wbsp__ALL.a |
axilite: $(VDIRFB)/Vwbm2axilite__ALL.a |
axilite: $(VDIRFB)/Vaxilrd2wbsp__ALL.a |
axilite: $(VDIRFB)/Vaxilwr2wbsp__ALL.a |
axilite: $(VDIRFB)/Vaxlite2wbsp__ALL.a |
|
.PHONY: wbm2axisp |
wbm2axisp: $(VDIRFB)/Vwbm2axisp__ALL.a |
$(VDIRFB)/Vwbm2axisp__ALL.a: $(VDIRFB)/Vwbm2axisp.h $(VDIRFB)/Vwbm2axisp.cpp |
$(VDIRFB)/Vwbm2axisp__ALL.a: $(VDIRFB)/Vwbm2axisp.mk |
$(VDIRFB)/Vwbm2axisp.h $(VDIRFB)/Vwbm2axisp.cpp $(VDIRFB)/Vwbm2axisp.mk: wbm2axisp.v |
|
.PHONY: wbm2axilite |
wbm2axilite: $(VDIRFB)/Vwbm2axilite__ALL.a |
$(VDIRFB)/Vwbm2axilite__ALL.a: $(VDIRFB)/Vwbm2axilite.h $(VDIRFB)/Vwbm2axilite.cpp |
$(VDIRFB)/Vwbm2axilite__ALL.a: $(VDIRFB)/Vwbm2axilite.mk |
$(VDIRFB)/Vwbm2axilite.h $(VDIRFB)/Vwbm2axilite.cpp $(VDIRFB)/Vwbm2axilite.mk: wbm2axilite.v |
|
.PHONY: axilrd2wbsp |
axilrd2wbsp: $(VDIRFB)/Vaxilrd2wbsp__ALL.a |
$(VDIRFB)/Vaxilrd2wbsp__ALL.a: $(VDIRFB)/Vaxilrd2wbsp.h $(VDIRFB)/Vaxilrd2wbsp.cpp |
$(VDIRFB)/Vaxilrd2wbsp__ALL.a: $(VDIRFB)/Vaxilrd2wbsp.mk |
$(VDIRFB)/Vaxilrd2wbsp.h $(VDIRFB)/Vaxilrd2wbsp.cpp $(VDIRFB)/Vaxilrd2wbsp.mk: axilrd2wbsp.v |
|
.PHONY: axilwr2wbsp |
axilwr2wbsp: $(VDIRFB)/Vaxilwr2wbsp__ALL.a |
$(VDIRFB)/Vaxilwr2wbsp__ALL.a: $(VDIRFB)/Vaxilwr2wbsp.h $(VDIRFB)/Vaxilwr2wbsp.cpp |
$(VDIRFB)/Vaxilwr2wbsp__ALL.a: $(VDIRFB)/Vaxilwr2wbsp.mk |
$(VDIRFB)/Vaxilwr2wbsp.h $(VDIRFB)/Vaxilwr2wbsp.cpp $(VDIRFB)/Vaxilwr2wbsp.mk: axilwr2wbsp.v |
|
.PHONY: axlite2wbsp |
axlite2wbsp: $(VDIRFB)/Vaxlite2wbsp__ALL.a |
$(VDIRFB)/Vaxlite2wbsp__ALL.a: $(VDIRFB)/Vaxlite2wbsp.h $(VDIRFB)/Vaxlite2wbsp.cpp |
$(VDIRFB)/Vaxlite2wbsp__ALL.a: $(VDIRFB)/Vaxlite2wbsp.mk |
$(VDIRFB)/Vaxlite2wbsp.h $(VDIRFB)/Vaxlite2wbsp.cpp $(VDIRFB)/Vaxlite2wbsp.mk: axlite2wbsp.v |
|
$(VDIRFB)/Vaxim2wbsp__ALL.a: $(VDIRFB)/Vaxim2wbsp.h $(VDIRFB)/Vaxim2wbsp.cpp |
$(VDIRFB)/Vaxim2wbsp__ALL.a: $(VDIRFB)/Vaxim2wbsp.mk |
$(VDIRFB)/Vaxim2wbsp.h $(VDIRFB)/Vaxim2wbsp.cpp $(VDIRFB)/Vaxim2wbsp.mk: \ |
82,4 → 118,3
rm -rf $(VDIRFB)/*.cpp |
rm -rf $(VDIRFB)/*.h |
rm -rf $(VDIRFB)/ |
|
/trunk/rtl/axilrd2wbsp.v
0,0 → 1,501
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: axilrd2wbsp.v (AXI lite to wishbone slave, read channel) |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: Bridge an AXI lite read channel pair to a single wishbone read |
// channel. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module axilrd2wbsp(i_clk, i_axi_reset_n, |
// AXI read address channel signals |
o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot, i_axi_arvalid, |
// AXI read data channel signals |
o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready, |
// We'll share the clock and the reset |
o_wb_cyc, o_wb_stb, o_wb_addr, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err |
`ifdef FORMAL |
, f_first, f_mid, f_last |
`endif |
); |
localparam C_AXI_DATA_WIDTH = 32;// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28; // AXI Address width |
localparam AW = C_AXI_ADDR_WIDTH-2;// WB Address width |
parameter LGFIFO = 3; |
|
input wire i_clk; // Bus clock |
input wire i_axi_reset_n; // Bus reset |
|
// AXI read address channel signals |
output reg o_axi_arready; // Read address ready |
input wire [C_AXI_ADDR_WIDTH-1:0] i_axi_araddr; // Read address |
input wire [3:0] i_axi_arcache; // Read Cache type |
input wire [2:0] i_axi_arprot; // Read Protection type |
input wire i_axi_arvalid; // Read address valid |
|
// AXI read data channel signals |
output reg [1:0] o_axi_rresp; // Read response |
output reg o_axi_rvalid; // Read reponse valid |
output wire [C_AXI_DATA_WIDTH-1:0] o_axi_rdata; // Read data |
input wire i_axi_rready; // Read Response ready |
|
// We'll share the clock and the reset |
output reg o_wb_cyc; |
output reg o_wb_stb; |
output reg [(AW-1):0] o_wb_addr; |
input wire i_wb_ack; |
input wire i_wb_stall; |
input [(C_AXI_DATA_WIDTH-1):0] i_wb_data; |
input wire i_wb_err; |
`ifdef FORMAL |
// Output connections only used in formal mode |
output wire [LGFIFO:0] f_first; |
output wire [LGFIFO:0] f_mid; |
output wire [LGFIFO:0] f_last; |
`endif |
|
localparam DW = C_AXI_DATA_WIDTH; |
|
wire w_reset; |
assign w_reset = (!i_axi_reset_n); |
|
reg r_stb; |
reg [AW-1:0] r_addr; |
|
localparam FLEN=(1<<LGFIFO); |
|
reg [DW-1:0] dfifo [0:(FLEN-1)]; |
reg fifo_full, fifo_empty; |
|
reg [LGFIFO:0] r_first, r_mid, r_last, r_next; |
wire [LGFIFO:0] w_first_plus_one; |
wire [LGFIFO:0] next_first, next_last, next_mid, fifo_fill; |
reg wb_pending, last_ack; |
reg [LGFIFO:0] wb_outstanding; |
|
|
initial o_wb_cyc = 1'b0; |
initial o_wb_stb = 1'b0; |
always @(posedge i_clk) |
if ((w_reset)||((o_wb_cyc)&&(i_wb_err))||(err_state)) |
o_wb_stb <= 1'b0; |
else if (r_stb || ((i_axi_arvalid)&&(o_axi_arready))) |
o_wb_stb <= 1'b1; |
else if ((o_wb_cyc)&&(!i_wb_stall)) |
o_wb_stb <= 1'b0; |
|
always @(*) |
o_wb_cyc = (wb_pending)||(o_wb_stb); |
|
always @(posedge i_clk) |
if (r_stb && !i_wb_stall) |
o_wb_addr <= r_addr; |
else if ((o_axi_arready)&&((!o_wb_stb)||(!i_wb_stall))) |
o_wb_addr <= i_axi_araddr[AW+1:2]; |
|
// Shadow request |
// r_stb, r_addr |
initial r_stb = 1'b0; |
always @(posedge i_clk) |
begin |
if ((i_axi_arvalid)&&(o_axi_arready)&&(o_wb_stb)&&(i_wb_stall)) |
begin |
r_stb <= 1'b1; |
r_addr <= i_axi_araddr[AW+1:2]; |
end else if ((!i_wb_stall)||(!o_wb_cyc)) |
r_stb <= 1'b0; |
|
if ((w_reset)||(o_wb_cyc)&&(i_wb_err)||(err_state)) |
r_stb <= 1'b0; |
end |
|
initial wb_pending = 0; |
initial wb_outstanding = 0; |
initial last_ack = 1; |
always @(posedge i_clk) |
if ((w_reset)||(!o_wb_cyc)||(i_wb_err)||(err_state)) |
begin |
wb_pending <= 1'b0; |
wb_outstanding <= 0; |
last_ack <= 1; |
end else case({ (o_wb_stb)&&(!i_wb_stall), i_wb_ack }) |
2'b01: begin |
wb_outstanding <= wb_outstanding - 1'b1; |
wb_pending <= (wb_outstanding >= 2); |
last_ack <= (wb_outstanding <= 2); |
end |
2'b10: begin |
wb_outstanding <= wb_outstanding + 1'b1; |
wb_pending <= 1'b1; |
last_ack <= (wb_outstanding == 0); |
end |
default: begin end |
endcase |
|
assign next_first = r_first + 1'b1; |
assign next_last = r_last + 1'b1; |
assign next_mid = r_mid + 1'b1; |
assign fifo_fill = (r_first - r_last); |
|
initial fifo_full = 1'b0; |
initial fifo_empty = 1'b1; |
always @(posedge i_clk) |
if (w_reset) |
begin |
fifo_full <= 1'b0; |
fifo_empty <= 1'b1; |
end else case({ (o_axi_rvalid)&&(i_axi_rready), |
(i_axi_arvalid)&&(o_axi_arready) }) |
2'b01: begin |
fifo_full <= (next_first[LGFIFO-1:0] == r_last[LGFIFO-1:0]) |
&&(next_first[LGFIFO]!=r_last[LGFIFO]); |
fifo_empty <= 1'b0; |
end |
2'b10: begin |
fifo_full <= 1'b0; |
fifo_empty <= 1'b0; |
end |
default: begin end |
endcase |
|
initial o_axi_arready = 1'b1; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_arready <= 1'b1; |
else if ((o_wb_cyc && i_wb_err) || err_state) |
// On any error, drop the ready flag until it's been flushed |
o_axi_arready <= 1'b0; |
else if ((i_axi_arvalid)&&(o_axi_arready)&&(o_wb_stb)&&(i_wb_stall)) |
// On any request where we are already busy, r_stb will get |
// set and we drop arready |
o_axi_arready <= 1'b0; |
else if (!o_axi_arready && o_wb_stb && i_wb_stall) |
// If we've already stalled on o_wb_stb, remain stalled until |
// the bus clears |
o_axi_arready <= 1'b0; |
else if (fifo_full && (!o_axi_rvalid || !i_axi_rready)) |
// If the FIFO is full, we must remain not ready until at |
// least one acknowledgment is accepted |
o_axi_arready <= 1'b0; |
else if ( (!o_axi_rvalid || !i_axi_rready) |
&& (i_axi_arvalid && o_axi_arready)) |
o_axi_arready <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0]) |
||(next_first[LGFIFO]==r_last[LGFIFO]); |
else |
o_axi_arready <= 1'b1; |
|
initial r_first = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_first <= 0; |
else if ((i_axi_arvalid)&&(o_axi_arready)) |
r_first <= r_first + 1'b1; |
|
initial r_mid = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_mid <= 0; |
else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
r_mid <= r_mid + 1'b1; |
else if ((err_state)&&(r_mid != r_first)) |
r_mid <= r_mid + 1'b1; |
|
initial r_last = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_last <= 0; |
else if ((o_axi_rvalid)&&(i_axi_rready)) |
r_last <= r_last + 1'b1; |
|
always @(posedge i_clk) |
if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
dfifo[r_mid[(LGFIFO-1):0]] <= i_wb_data; |
|
reg [LGFIFO:0] err_loc; |
always @(posedge i_clk) |
if ((o_wb_cyc)&&(i_wb_err)) |
err_loc <= r_mid; |
|
wire [DW-1:0] read_data; |
|
assign read_data = dfifo[r_last[LGFIFO-1:0]]; |
assign o_axi_rdata = read_data[DW-1:0]; |
initial o_axi_rresp = 2'b00; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_rresp <= 0; |
else if ((!o_axi_rvalid)||(i_axi_rready)) |
begin |
if ((!err_state)&&((!o_wb_cyc)||(!i_wb_err))) |
o_axi_rresp <= 2'b00; |
else if ((!err_state)&&(o_wb_cyc)&&(i_wb_err)) |
begin |
if (o_axi_rvalid) |
o_axi_rresp <= (r_mid == next_last) ? 2'b10 : 2'b00; |
else |
o_axi_rresp <= (r_mid == r_last) ? 2'b10 : 2'b00; |
end else if (err_state) |
begin |
if (next_last == err_loc) |
o_axi_rresp <= 2'b10; |
else if (o_axi_rresp[1]) |
o_axi_rresp <= 2'b11; |
end else |
o_axi_rresp <= 0; |
end |
|
|
reg err_state; |
initial err_state = 0; |
always @(posedge i_clk) |
if (w_reset) |
err_state <= 0; |
else if (r_first == r_last) |
err_state <= 0; |
else if ((o_wb_cyc)&&(i_wb_err)) |
err_state <= 1'b1; |
|
initial o_axi_rvalid = 1'b0; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_rvalid <= 0; |
else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
o_axi_rvalid <= 1'b1; |
else if ((o_axi_rvalid)&&(i_axi_rready)) |
begin |
if (err_state) |
o_axi_rvalid <= (next_last != r_first); |
else |
o_axi_rvalid <= (next_last != r_mid); |
end |
|
// Make Verilator happy |
// verilator lint_off UNUSED |
// verilator lint_on UNUSED |
|
`ifdef FORMAL |
reg f_past_valid; |
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
always @(*) |
if (!f_past_valid) |
assume(w_reset); |
|
always @(*) |
if (err_state) |
assert(!o_axi_arready); |
|
always @(*) |
if (err_state) |
assert((!o_wb_cyc)&&(!o_axi_arready)); |
|
always @(*) |
if ((fifo_empty)&&(!w_reset)) |
assert((!fifo_full)&&(r_first == r_last)&&(r_mid == r_last)); |
|
always @(*) |
if (fifo_full) |
assert((!fifo_empty) |
&&(r_first[LGFIFO-1:0] == r_last[LGFIFO-1:0]) |
&&(r_first[LGFIFO] != r_last[LGFIFO])); |
|
always @(*) |
assert(fifo_fill <= (1<<LGFIFO)); |
|
always @(*) |
if (fifo_full) |
assert(!o_axi_arready); |
always @(*) |
assert(fifo_full == (fifo_fill == (1<<LGFIFO))); |
always @(*) |
if (fifo_fill == (1<<LGFIFO)) |
assert(!o_axi_arready); |
always @(*) |
assert(wb_pending == (wb_outstanding != 0)); |
|
always @(*) |
assert(last_ack == (wb_outstanding <= 1)); |
|
|
assign f_first = r_first; |
assign f_mid = r_mid; |
assign f_last = r_last; |
|
wire [LGFIFO:0] f_wb_nreqs, f_wb_nacks, f_wb_outstanding; |
fwb_master #( |
.AW(AW), .DW(DW), .F_LGDEPTH(LGFIFO+1) |
) fwb(i_clk, w_reset, |
o_wb_cyc, o_wb_stb, 1'b0, o_wb_addr, 32'h0, 4'h0, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs,f_wb_nacks, f_wb_outstanding); |
|
always @(*) |
if (o_wb_cyc) |
assert(f_wb_outstanding == wb_outstanding); |
|
always @(*) |
if (o_wb_cyc) |
assert(wb_outstanding <= (1<<LGFIFO)); |
|
wire [LGFIFO:0] wb_fill; |
assign wb_fill = r_first - r_mid; |
always @(*) |
assert(wb_fill <= fifo_fill); |
always @(*) |
if (o_wb_stb) |
assert(wb_outstanding+1+((r_stb)?1:0) == wb_fill); |
|
else if (o_wb_cyc) |
assert(wb_outstanding == wb_fill); |
|
always @(*) |
if (r_stb) |
begin |
assert(o_wb_stb); |
assert(!o_axi_arready); |
end |
|
wire [LGFIFO:0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
|
faxil_slave #( |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_LGDEPTH(LGFIFO+1), |
.F_OPT_NO_WRITES(1'b1), |
.F_AXI_MAXWAIT(0), |
.F_AXI_MAXDELAY(0) |
) faxil(i_clk, i_axi_reset_n, |
// |
// AXI write address channel signals |
1'b0, i_axi_araddr, i_axi_arcache, i_axi_arprot, 1'b0, |
// AXI write data channel signals |
1'b0, 32'h0, 4'h0, 1'b0, |
// AXI write response channel signals |
2'b00, 1'b0, 1'b0, |
// AXI read address channel signals |
o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot, |
i_axi_arvalid, |
// AXI read data channel signals |
o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready, |
f_axi_rd_outstanding, f_axi_wr_outstanding, |
f_axi_awr_outstanding); |
|
always @(*) |
assert(f_axi_wr_outstanding == 0); |
always @(*) |
assert(f_axi_awr_outstanding == 0); |
always @(*) |
assert(f_axi_rd_outstanding == fifo_fill); |
|
wire [LGFIFO:0] f_mid_minus_err, f_err_minus_last, |
f_first_minus_err; |
assign f_mid_minus_err = f_mid - err_loc; |
assign f_err_minus_last = err_loc - f_last; |
assign f_first_minus_err = f_first - err_loc; |
always @(*) |
if (o_axi_rvalid) |
begin |
if (!err_state) |
assert(!o_axi_rresp[1]); |
else if (err_loc == f_last) |
assert(o_axi_rresp == 2'b10); |
else if (f_err_minus_last < (1<<LGFIFO)) |
assert(!o_axi_rresp[1]); |
else |
assert(o_axi_rresp[1]); |
end |
|
always @(*) |
if (err_state) |
assert(o_axi_rvalid == (r_first != r_last)); |
else |
assert(o_axi_rvalid == (r_mid != r_last)); |
|
always @(*) |
if (err_state) |
assert(f_first_minus_err <= (1<<LGFIFO)); |
|
always @(*) |
if (err_state) |
assert(f_first_minus_err != 0); |
|
always @(*) |
if (err_state) |
assert(f_mid_minus_err <= f_first_minus_err); |
|
always @(*) |
if ((f_past_valid)&&(i_axi_reset_n)&&(f_axi_rd_outstanding > 0)) |
begin |
if (err_state) |
assert((!o_wb_cyc)&&(f_wb_outstanding == 0)); |
else if (!o_wb_cyc) |
assert((o_axi_rvalid)&&(f_axi_rd_outstanding>0) |
&&(wb_fill == 0)); |
end |
|
// WB covers |
always @(*) |
cover(o_wb_cyc && o_wb_stb); |
|
always @(*) |
if (LGFIFO > 2) |
cover(o_wb_cyc && f_wb_outstanding > 2); |
|
always @(posedge i_clk) |
cover(o_wb_cyc && i_wb_ack |
&& $past(o_wb_cyc && i_wb_ack) |
&& $past(o_wb_cyc && i_wb_ack,2)); |
|
// AXI covers |
always @(*) |
cover(o_axi_rvalid && i_axi_rready); |
|
always @(posedge i_clk) |
cover(i_axi_arvalid && o_axi_arready |
&& $past(i_axi_arvalid && o_axi_arready) |
&& $past(i_axi_arvalid && o_axi_arready,2)); |
|
always @(posedge i_clk) |
cover(o_axi_rvalid && i_axi_rready |
&& $past(o_axi_rvalid && i_axi_rready) |
&& $past(o_axi_rvalid && i_axi_rready,2)); |
`endif |
endmodule |
/trunk/rtl/axilwr2wbsp.v
0,0 → 1,600
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: axilwr2wbsp.v (AXI lite to wishbone slave, read channel) |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: Bridge an AXI lite write channel triplet to a single wishbone |
// write channel. A full AXI lite to wishbone bridge will also |
// require the read channel and an arbiter. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module axilwr2wbsp(i_clk, i_axi_reset_n, |
// AXI write address channel signals |
o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot, i_axi_awvalid, |
// AXI write data channel signals |
o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid, |
// AXI write response channel signals |
o_axi_bresp, o_axi_bvalid, i_axi_bready, |
// We'll share the clock and the reset |
o_wb_cyc, o_wb_stb, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_err |
`ifdef FORMAL |
, f_first, f_mid, f_last, f_wpending |
`endif |
); |
parameter C_AXI_DATA_WIDTH = 32;// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28; // AXI Address width |
localparam AW = C_AXI_ADDR_WIDTH-2;// WB Address width |
parameter LGFIFO = 3; |
localparam DW = C_AXI_DATA_WIDTH; |
localparam FLEN=(1<<LGFIFO); |
|
|
input wire i_clk; // Bus clock |
input wire i_axi_reset_n; // Bus reset |
|
// AXI write address channel signals |
output reg o_axi_awready;//Slave is ready to accept |
input wire [AW+1:0] i_axi_awaddr; // Write address |
input wire [3:0] i_axi_awcache; // Write Cache type |
input wire [2:0] i_axi_awprot; // Write Protection type |
input wire i_axi_awvalid; // Write address valid |
|
// AXI write data channel signals |
output reg o_axi_wready; // Write data ready |
input wire [DW-1:0] i_axi_wdata; // Write data |
input wire [DW/8-1:0] i_axi_wstrb; // Write strobes |
input wire i_axi_wvalid; // Write valid |
|
// AXI write response channel signals |
output reg [1:0] o_axi_bresp; // Write response |
output reg o_axi_bvalid; // Write reponse valid |
input wire i_axi_bready; // Response ready |
|
// We'll share the clock and the reset |
output reg o_wb_cyc; |
output reg o_wb_stb; |
output reg [(AW-1):0] o_wb_addr; |
output reg [(DW-1):0] o_wb_data; |
output reg [(DW/8-1):0] o_wb_sel; |
input wire i_wb_ack; |
input wire i_wb_stall; |
input wire i_wb_err; |
`ifdef FORMAL |
// Output connections only used in formal mode |
output wire [LGFIFO:0] f_first; |
output wire [LGFIFO:0] f_mid; |
output wire [LGFIFO:0] f_last; |
output wire [1:0] f_wpending; |
`endif |
|
wire w_reset; |
assign w_reset = (!i_axi_reset_n); |
|
reg r_awvalid, r_wvalid; |
reg [AW-1:0] r_addr; |
reg [DW-1:0] r_data; |
reg [DW/8-1:0] r_sel; |
|
reg fifo_full, fifo_empty; |
|
reg [LGFIFO:0] r_first, r_mid, r_last, r_next; |
wire [LGFIFO:0] w_first_plus_one; |
wire [LGFIFO:0] next_first, next_last, next_mid, fifo_fill; |
reg wb_pending, last_ack; |
reg [LGFIFO:0] wb_outstanding; |
|
wire axi_write_accepted, pending_axi_write; |
|
assign pending_axi_write = |
((r_awvalid) || (i_axi_awvalid && o_axi_awready)) |
&&((r_wvalid)|| (i_axi_wvalid && o_axi_wready)); |
|
assign axi_write_accepted = |
(!o_wb_stb || !i_wb_stall) && (!fifo_full) && (!err_state) |
&& (pending_axi_write); |
|
initial o_wb_cyc = 1'b0; |
initial o_wb_stb = 1'b0; |
always @(posedge i_clk) |
if ((w_reset)||((o_wb_cyc)&&(i_wb_err))||(err_state)) |
o_wb_stb <= 1'b0; |
else if (axi_write_accepted) |
o_wb_stb <= 1'b1; |
else if ((o_wb_cyc)&&(!i_wb_stall)) |
o_wb_stb <= 1'b0; |
|
always @(*) |
o_wb_cyc = (wb_pending)||(o_wb_stb); |
|
always @(posedge i_clk) |
if (!o_wb_stb || !i_wb_stall) |
begin |
if (r_awvalid) |
o_wb_addr <= r_addr; |
else |
o_wb_addr <= i_axi_awaddr[AW+1:2]; |
|
if (r_wvalid) |
begin |
o_wb_data <= r_data; |
o_wb_sel <= r_sel; |
end else begin |
o_wb_data <= i_axi_wdata; |
o_wb_sel <= i_axi_wstrb; |
end |
end |
|
initial r_awvalid <= 1'b0; |
always @(posedge i_clk) |
begin |
if ((i_axi_awvalid)&&(o_axi_awready)) |
begin |
r_addr <= i_axi_awaddr[AW+1:2]; |
r_awvalid <= (!axi_write_accepted); |
end else if (axi_write_accepted) |
r_awvalid <= 1'b0; |
|
if (w_reset) |
r_awvalid <= 1'b0; |
end |
|
initial r_wvalid <= 1'b0; |
always @(posedge i_clk) |
begin |
if ((i_axi_wvalid)&&(o_axi_wready)) |
begin |
r_data <= i_axi_wdata; |
r_sel <= i_axi_wstrb; |
r_wvalid <= (!axi_write_accepted); |
end else if (axi_write_accepted) |
r_wvalid <= 1'b0; |
|
if (w_reset) |
r_wvalid <= 1'b0; |
end |
|
initial o_axi_awready = 1'b1; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_awready <= 1'b1; |
else if ((o_wb_stb && i_wb_stall) |
&&(r_awvalid || (i_axi_awvalid && o_axi_awready))) |
// Once a request has been received while the interface is |
// stalled, we must stall and wait for it to clear |
o_axi_awready <= 1'b0; |
else if (err_state && (r_awvalid || (i_axi_awvalid && o_axi_awready))) |
o_axi_awready <= 1'b0; |
else if ((r_awvalid || (i_axi_awvalid && o_axi_awready)) |
&&(!r_wvalid && (!i_axi_wvalid || !o_axi_wready))) |
// If the write address is given without any corresponding |
// write data, immediately stall and wait for the write data |
o_axi_awready <= 1'b0; |
else if (!o_axi_awready && o_wb_stb && i_wb_stall) |
// Once stalled, remain stalled while the WB bus is stalled |
o_axi_awready <= 1'b0; |
else if (fifo_full && (r_awvalid || (!o_axi_bvalid || !i_axi_bready))) |
// Once the FIFO is full, we must remain stalled until at |
// least one acknowledgment has been accepted |
o_axi_awready <= 1'b0; |
else if ((!o_axi_bvalid || !i_axi_bready) |
&& (r_awvalid || (i_axi_awvalid && o_axi_awready))) |
// If ever the FIFO becomes full, we must immediately drop |
// the o_axi_awready signal |
o_axi_awready <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0]) |
&&(next_first[LGFIFO]==r_last[LGFIFO]); |
else |
o_axi_awready <= 1'b1; |
|
initial o_axi_wready = 1'b1; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_wready <= 1'b1; |
else if ((o_wb_stb && i_wb_stall) |
&&(r_wvalid || (i_axi_wvalid && o_axi_wready))) |
// Once a request has been received while the interface is |
// stalled, we must stall and wait for it to clear |
o_axi_wready <= 1'b0; |
else if (err_state && (r_wvalid || (i_axi_wvalid && o_axi_wready))) |
o_axi_wready <= 1'b0; |
else if ((r_wvalid || (i_axi_wvalid && o_axi_wready)) |
&&(!r_awvalid && (!i_axi_awvalid || !o_axi_awready))) |
// If the write address is given without any corresponding |
// write data, immediately stall and wait for the write data |
o_axi_wready <= 1'b0; |
else if (!o_axi_wready && o_wb_stb && i_wb_stall) |
// Once stalled, remain stalled while the WB bus is stalled |
o_axi_wready <= 1'b0; |
else if (fifo_full && (r_wvalid || (!o_axi_bvalid || !i_axi_bready))) |
// Once the FIFO is full, we must remain stalled until at |
// least one acknowledgment has been accepted |
o_axi_wready <= 1'b0; |
else if ((!o_axi_bvalid || !i_axi_bready) |
&& (i_axi_wvalid && o_axi_wready)) |
// If ever the FIFO becomes full, we must immediately drop |
// the o_axi_wready signal |
o_axi_wready <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0]) |
&&(next_first[LGFIFO]==r_last[LGFIFO]); |
else |
o_axi_wready <= 1'b1; |
|
|
initial wb_pending = 0; |
initial wb_outstanding = 0; |
initial last_ack = 1; |
always @(posedge i_clk) |
if ((w_reset)||(!o_wb_cyc)||(i_wb_err)||(err_state)) |
begin |
wb_pending <= 1'b0; |
wb_outstanding <= 0; |
last_ack <= 1; |
end else case({ (o_wb_stb)&&(!i_wb_stall), i_wb_ack }) |
2'b01: begin |
wb_outstanding <= wb_outstanding - 1'b1; |
wb_pending <= (wb_outstanding >= 2); |
last_ack <= (wb_outstanding <= 2); |
end |
2'b10: begin |
wb_outstanding <= wb_outstanding + 1'b1; |
wb_pending <= 1'b1; |
last_ack <= (wb_outstanding == 0); |
end |
default: begin end |
endcase |
|
assign next_first = r_first + 1'b1; |
assign next_last = r_last + 1'b1; |
assign next_mid = r_mid + 1'b1; |
assign fifo_fill = (r_first - r_last); |
|
initial fifo_full = 1'b0; |
initial fifo_empty = 1'b1; |
always @(posedge i_clk) |
if (w_reset) |
begin |
fifo_full <= 1'b0; |
fifo_empty <= 1'b1; |
end else case({ (o_axi_bvalid)&&(i_axi_bready), |
(axi_write_accepted) }) |
2'b01: begin |
fifo_full <= (next_first[LGFIFO-1:0] == r_last[LGFIFO-1:0]) |
&&(next_first[LGFIFO]!=r_last[LGFIFO]); |
fifo_empty <= 1'b0; |
end |
2'b10: begin |
fifo_full <= 1'b0; |
fifo_empty <= 1'b0; |
end |
default: begin end |
endcase |
|
initial r_first = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_first <= 0; |
else if (axi_write_accepted) |
r_first <= r_first + 1'b1; |
|
initial r_mid = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_mid <= 0; |
else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
r_mid <= r_mid + 1'b1; |
else if ((err_state)&&(r_mid != r_first)) |
r_mid <= r_mid + 1'b1; |
|
initial r_last = 0; |
always @(posedge i_clk) |
if (w_reset) |
r_last <= 0; |
else if ((o_axi_bvalid)&&(i_axi_bready)) |
r_last <= r_last + 1'b1; |
|
reg [LGFIFO:0] err_loc; |
always @(posedge i_clk) |
if ((o_wb_cyc)&&(i_wb_err)) |
err_loc <= r_mid; |
|
wire [DW:0] read_data; |
|
initial o_axi_bresp = 2'b00; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_bresp <= 0; |
else if ((!o_axi_bvalid)||(i_axi_bready)) |
begin |
if ((!err_state)&&((!o_wb_cyc)||(!i_wb_err))) |
o_axi_bresp <= 2'b00; |
else if ((!err_state)&&(o_wb_cyc)&&(i_wb_err)) |
begin |
if (o_axi_bvalid) |
o_axi_bresp <= (r_mid == next_last) ? 2'b10 : 2'b00; |
else |
o_axi_bresp <= (r_mid == r_last) ? 2'b10 : 2'b00; |
end else if (err_state) |
begin |
if (next_last == err_loc) |
o_axi_bresp <= 2'b10; |
else if (o_axi_bresp[1]) |
o_axi_bresp <= 2'b11; |
end else |
o_axi_bresp <= 0; |
end |
|
|
reg err_state; |
initial err_state = 0; |
always @(posedge i_clk) |
if (w_reset) |
err_state <= 0; |
else if (r_first == r_last) |
err_state <= 0; |
else if ((o_wb_cyc)&&(i_wb_err)) |
err_state <= 1'b1; |
|
initial o_axi_bvalid = 1'b0; |
always @(posedge i_clk) |
if (w_reset) |
o_axi_bvalid <= 0; |
else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
o_axi_bvalid <= 1'b1; |
else if ((o_axi_bvalid)&&(i_axi_bready)) |
begin |
if (err_state) |
o_axi_bvalid <= (next_last != r_first); |
else |
o_axi_bvalid <= (next_last != r_mid); |
end |
|
// Make Verilator happy |
// verilator lint_off UNUSED |
// verilator lint_on UNUSED |
|
`ifdef FORMAL |
reg f_past_valid; |
wire f_axi_stalled; |
wire [LGFIFO:0] f_wb_nreqs, f_wb_nacks, f_wb_outstanding; |
wire [LGFIFO:0] wb_fill; |
wire [LGFIFO:0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
wire [LGFIFO:0] f_mid_minus_err, f_err_minus_last, |
f_first_minus_err; |
|
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
`ifdef AXILWR2WBSP |
`define ASSUME assume |
`else |
`define ASSUME assert |
`endif |
|
always @(*) |
if (!f_past_valid) |
`ASSUME(w_reset); |
|
always @(*) |
if (err_state) |
begin |
assert(!r_awvalid || !o_axi_awready); |
assert(!r_wvalid || !o_axi_wready); |
|
assert(!o_wb_cyc); |
end |
|
always @(*) |
if ((fifo_empty)&&(!w_reset)) |
assert((!fifo_full)&&(r_first == r_last)&&(r_mid == r_last)); |
|
always @(*) |
if (fifo_full) |
begin |
assert(!fifo_empty); |
assert(r_first[LGFIFO-1:0] == r_last[LGFIFO-1:0]); |
assert(r_first[LGFIFO] != r_last[LGFIFO]); |
end |
|
always @(*) |
assert(fifo_fill <= (1<<LGFIFO)); |
|
always @(*) |
if (fifo_full) |
begin |
assert(!r_awvalid || !o_axi_awready); |
assert(!r_wvalid || !o_axi_wready); |
end |
|
always @(*) |
assert(fifo_full == (fifo_fill >= (1<<LGFIFO))); |
always @(*) |
assert(wb_pending == (wb_outstanding != 0)); |
|
always @(*) |
assert(last_ack == (wb_outstanding <= 1)); |
|
|
assign f_first = r_first; |
assign f_mid = r_mid; |
assign f_last = r_last; |
assign f_wpending = { r_awvalid, r_wvalid }; |
|
fwb_master #( |
.AW(AW), .DW(DW), .F_LGDEPTH(LGFIFO+1) |
) fwb(i_clk, w_reset, |
o_wb_cyc, o_wb_stb, 1'b1, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, {(DW){1'b0}}, i_wb_err, |
f_wb_nreqs,f_wb_nacks, f_wb_outstanding); |
|
always @(*) |
if (o_wb_cyc) |
assert(f_wb_outstanding == wb_outstanding); |
|
always @(*) |
if (o_wb_cyc) |
assert(wb_outstanding <= (1<<LGFIFO)); |
|
assign wb_fill = r_first - r_mid; |
always @(*) |
assert(wb_fill <= fifo_fill); |
always @(*) |
if (!w_reset) |
begin |
if (o_wb_stb) |
assert(wb_outstanding+1 == wb_fill); |
else if (o_wb_cyc) |
assert(wb_outstanding == wb_fill); |
else if (!err_state) |
assert((wb_fill == 0)&&(wb_outstanding == 0)); |
end |
|
faxil_slave #( |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_LGDEPTH(LGFIFO+1), |
.F_OPT_NO_READS(1), |
.F_AXI_MAXWAIT(0), |
.F_AXI_MAXDELAY(0) |
) faxil(i_clk, i_axi_reset_n, |
// |
// AXI write address channel signals |
o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot, i_axi_awvalid, |
// AXI write data channel signals |
o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid, |
// AXI write response channel signals |
o_axi_bresp, o_axi_bvalid, i_axi_bready, |
// AXI read address channel signals |
1'b0, i_axi_awaddr, i_axi_awcache, i_axi_awprot, |
1'b0, |
// AXI read data channel signals |
o_axi_bresp, 1'b0, {(DW){1'b0}}, 1'b0, |
f_axi_rd_outstanding, f_axi_wr_outstanding, |
f_axi_awr_outstanding); |
|
always @(*) |
assert(f_axi_wr_outstanding - (r_wvalid ? 1:0) |
== f_axi_awr_outstanding - (r_awvalid ? 1:0)); |
always @(*) |
assert(f_axi_rd_outstanding == 0); |
always @(*) |
assert(f_axi_wr_outstanding - (r_wvalid ? 1:0) == fifo_fill); |
always @(*) |
assert(f_axi_awr_outstanding - (r_awvalid ? 1:0) == fifo_fill); |
always @(*) |
if (r_wvalid) assert(f_axi_wr_outstanding > 0); |
always @(*) |
if (r_awvalid) assert(f_axi_awr_outstanding > 0); |
|
assign f_mid_minus_err = f_mid - err_loc; |
assign f_err_minus_last = err_loc - f_last; |
assign f_first_minus_err = f_first - err_loc; |
always @(*) |
if (o_axi_bvalid) |
begin |
if (!err_state) |
assert(!o_axi_bresp[1]); |
else if (err_loc == f_last) |
assert(o_axi_bresp == 2'b10); |
else if (f_err_minus_last < (1<<LGFIFO)) |
assert(!o_axi_bresp[1]); |
else |
assert(o_axi_bresp[1]); |
end |
|
always @(*) |
if (err_state) |
assert(o_axi_bvalid == (r_first != r_last)); |
else |
assert(o_axi_bvalid == (r_mid != r_last)); |
|
always @(*) |
if (err_state) |
assert(f_first_minus_err <= (1<<LGFIFO)); |
|
always @(*) |
if (err_state) |
assert(f_first_minus_err != 0); |
|
always @(*) |
if (err_state) |
assert(f_mid_minus_err <= f_first_minus_err); |
|
assign f_axi_stalled = (fifo_full)||(err_state) |
||((o_wb_stb)&&(i_wb_stall)); |
|
always @(*) |
if ((r_awvalid)&&(f_axi_stalled)) |
assert(!o_axi_awready); |
always @(*) |
if ((r_wvalid)&&(f_axi_stalled)) |
assert(!o_axi_wready); |
|
|
// WB covers |
always @(*) |
cover(o_wb_cyc && o_wb_stb && !i_wb_stall); |
always @(*) |
cover(o_wb_cyc && i_wb_ack); |
|
always @(posedge i_clk) |
cover(o_wb_cyc && $past(o_wb_cyc && o_wb_stb && !i_wb_stall));// |
|
always @(posedge i_clk) |
cover(o_wb_cyc && o_wb_stb && !i_wb_stall |
&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall,2) |
&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall,4)); // |
|
always @(posedge i_clk) |
cover(o_wb_cyc && o_wb_stb && !i_wb_stall |
&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall) |
&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall)); // |
|
always @(posedge i_clk) |
cover(o_wb_cyc && i_wb_ack |
&& $past(o_wb_cyc && i_wb_ack) |
&& $past(o_wb_cyc && i_wb_ack)); // |
|
// AXI covers |
always @(posedge i_clk) |
cover(o_axi_bvalid && i_axi_bready |
&& $past(o_axi_bvalid && i_axi_bready,1) |
&& $past(o_axi_bvalid && i_axi_bready,2)); // |
|
`endif |
endmodule |
/trunk/rtl/axim2wbsp.v
1,3 → 1,4
`error This full featured AXI to WB converter does not (yet) work |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: axim2wbsp.v |
4,9 → 5,9
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: So ... this converter works in the other direction. This |
// converter takes AXI commands, and organizes them into pipelined |
// wishbone commands. |
// Purpose: So ... this converter works in the other direction from |
// wbm2axisp. This converter takes AXI commands, and organizes |
// them into pipelined wishbone commands. |
// |
// |
// We'll treat AXI as two separate busses: one for writes, another for |
19,30 → 20,35
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2016-2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module axim2wbsp( i_clk, i_axi_reset_n, |
// |
o_axi_awready, // Slave is ready to accept |
65,17 → 71,17
i_axi_arqos, // Read Protection type |
i_axi_arvalid, // Read address valid |
// |
o_axi_rid, // Response ID |
o_axi_rresp, // Read response |
o_axi_rvalid, // Read reponse valid |
o_axi_rdata, // Read data |
o_axi_rlast, // Read last |
i_axi_rready, // Read Response ready |
o_axi_rid, // Response ID |
o_axi_rresp, // Read response |
o_axi_rvalid, // Read reponse valid |
o_axi_rdata, // Read data |
o_axi_rlast, // Read last |
i_axi_rready, // Read Response ready |
// Wishbone interface |
o_reset, o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err); |
// |
parameter C_AXI_ID_WIDTH = 6; // The AXI id width used for R&W |
parameter C_AXI_ID_WIDTH = 2; // The AXI id width used for R&W |
// This is an int between 1-16 |
parameter C_AXI_DATA_WIDTH = 32;// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28; // AXI Address width |
86,6 → 92,16
:((C_AXI_DATA_WIDTH== 64) ? (C_AXI_ADDR_WIDTH-3) |
:((C_AXI_DATA_WIDTH==128) ? (C_AXI_ADDR_WIDTH-4) |
:(C_AXI_ADDR_WIDTH-5))))); |
parameter LGFIFO = 4; |
parameter [0:0] F_STRICT_ORDER = 0; |
parameter [0:0] F_CONSECUTIVE_IDS = 0; |
parameter [0:0] F_OPT_BURSTS = 1'b0; |
parameter [0:0] F_OPT_CLK2FFLOGIC = 1'b0; |
parameter F_MAXSTALL = 3; |
parameter F_MAXDELAY = 3; |
parameter [0:0] OPT_READONLY = 1'b1; |
parameter [0:0] OPT_WRITEONLY = 1'b0; |
parameter [7:0] OPT_MAXBURST = 8'h3; |
// |
input wire i_clk; // System clock |
input wire i_axi_reset_n; |
102,20 → 118,20
input wire [2:0] i_axi_awprot; // Write Protection type |
input wire [3:0] i_axi_awqos; // Write Quality of Svc |
input wire i_axi_awvalid; // Write address valid |
|
|
// AXI write data channel signals |
output wire o_axi_wready; // Write data ready |
input wire [C_AXI_DATA_WIDTH-1:0] i_axi_wdata; // Write data |
input wire [C_AXI_DATA_WIDTH/8-1:0] i_axi_wstrb; // Write strobes |
input wire i_axi_wlast; // Last write transaction |
input wire i_axi_wlast; // Last write transaction |
input wire i_axi_wvalid; // Write valid |
|
|
// AXI write response channel signals |
output wire [C_AXI_ID_WIDTH-1:0] o_axi_bid; // Response ID |
output wire [1:0] o_axi_bresp; // Write response |
output wire o_axi_bvalid; // Write reponse valid |
input wire i_axi_bready; // Response ready |
|
|
// AXI read address channel signals |
output wire o_axi_arready; // Read address ready |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_arid; // Read ID |
128,8 → 144,8
input wire [2:0] i_axi_arprot; // Read Protection type |
input wire [3:0] i_axi_arqos; // Read Protection type |
input wire i_axi_arvalid; // Read address valid |
|
// AXI read data channel signals |
|
// AXI read data channel signals |
output wire [C_AXI_ID_WIDTH-1:0] o_axi_rid; // Response ID |
output wire [1:0] o_axi_rresp; // Read response |
output wire o_axi_rvalid; // Read reponse valid |
169,10 → 185,27
assign w_wb_we = 1'b1; |
// verilator lint_on UNUSED |
|
`ifdef FORMAL |
wire [(LGFIFO-1):0] f_wr_fifo_ahead, f_wr_fifo_dhead, |
f_wr_fifo_neck, f_wr_fifo_torso, |
f_wr_fifo_tail, |
f_rd_fifo_head, f_rd_fifo_neck, |
f_rd_fifo_torso, f_rd_fifo_tail; |
wire [(LGFIFO-1):0] f_wb_nreqs, f_wb_nacks, |
f_wb_outstanding; |
wire [(LGFIFO-1):0] f_wb_wr_nreqs, f_wb_wr_nacks, |
f_wb_wr_outstanding; |
wire [(LGFIFO-1):0] f_wb_rd_nreqs, f_wb_rd_nacks, |
f_wb_rd_outstanding; |
`endif |
|
generate if (!OPT_READONLY) |
begin : AXI_WR |
aximwr2wbsp #( |
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH), |
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .AW(AW)) |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .AW(AW), |
.LGFIFO(LGFIFO)) |
axi_write_decoder( |
.i_axi_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// |
206,13 → 239,44
.o_wb_sel( w_wb_sel), |
.i_wb_ack( w_wb_ack), |
.i_wb_stall(w_wb_stall), |
.i_wb_err( w_wb_err)); |
.i_wb_err( w_wb_err) |
`ifdef FORMAL |
, |
.f_fifo_ahead(f_wr_fifo_ahead), |
.f_fifo_dhead(f_wr_fifo_dhead), |
.f_fifo_neck( f_wr_fifo_neck), |
.f_fifo_torso(f_wr_fifo_torso), |
.f_fifo_tail( f_wr_fifo_tail) |
`endif |
); |
end else begin |
assign w_wb_cyc = 0; |
assign w_wb_stb = 0; |
assign w_wb_addr = 0; |
assign w_wb_data = 0; |
assign w_wb_sel = 0; |
assign o_axi_awready = 0; |
assign o_axi_wready = 0; |
assign o_axi_bvalid = (i_axi_wvalid)&&(i_axi_wlast); |
assign o_axi_bresp = 2'b11; |
assign o_axi_bid = i_axi_awid; |
`ifdef FORMAL |
assign f_wr_fifo_ahead = 0; |
assign f_wr_fifo_dhead = 0; |
assign f_wr_fifo_neck = 0; |
assign f_wr_fifo_torso = 0; |
assign f_wr_fifo_tail = 0; |
`endif |
end endgenerate |
assign w_wb_we = 1'b1; |
|
generate if (!OPT_WRITEONLY) |
begin : AXI_RD |
aximrd2wbsp #( |
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH), |
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .AW(AW)) |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .AW(AW), |
.LGFIFO(LGFIFO)) |
axi_read_decoder( |
.i_axi_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// |
241,35 → 305,133
.i_wb_ack( r_wb_ack), |
.i_wb_stall(r_wb_stall), |
.i_wb_data( i_wb_data), |
.i_wb_err( r_wb_err)); |
.i_wb_err( r_wb_err) |
`ifdef FORMAL |
, |
.f_fifo_head(f_rd_fifo_head), |
.f_fifo_neck(f_rd_fifo_neck), |
.f_fifo_torso(f_rd_fifo_torso), |
.f_fifo_tail(f_rd_fifo_tail) |
`endif |
); |
end else begin |
assign r_wb_cyc = 0; |
assign r_wb_stb = 0; |
assign r_wb_addr = 0; |
// |
assign o_axi_arready = 1'b1; |
assign o_axi_rvalid = (i_axi_arvalid)&&(o_axi_arready); |
assign o_axi_rid = (i_axi_arid); |
assign o_axi_rvalid = (i_axi_arvalid); |
assign o_axi_rlast = (i_axi_arvalid); |
assign o_axi_rresp = (i_axi_arvalid) ? 2'b11 : 2'b00; |
assign o_axi_rdata = 0; |
`ifdef FORMAL |
assign f_rd_fifo_head = 0; |
assign f_rd_fifo_neck = 0; |
assign f_rd_fifo_torso = 0; |
assign f_rd_fifo_tail = 0; |
`endif |
end endgenerate |
|
wbarbiter #( |
generate if (OPT_READONLY) |
begin : ARB_RD |
assign o_wb_cyc = r_wb_cyc; |
assign o_wb_stb = r_wb_stb; |
assign o_wb_we = 1'b0; |
assign o_wb_addr = r_wb_addr; |
assign o_wb_data = 32'h0; |
assign o_wb_sel = 0; |
assign r_wb_ack = i_wb_ack; |
assign r_wb_stall= i_wb_stall; |
assign r_wb_ack = i_wb_ack; |
assign r_wb_err = i_wb_err; |
|
`ifdef FORMAL |
.F_LGDEPTH(C_AXI_DATA_WIDTH), |
fwb_master #(.DW(DW), .AW(AW), |
.F_LGDEPTH(LGFIFO), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY), |
.F_OPT_CLK2FFLOGIC(F_OPT_CLK2FFLOGIC)) |
f_wb(i_clk, !i_axi_reset_n, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
assign f_wb_rd_nreqs = f_wb_nreqs; |
assign f_wb_rd_nacks = f_wb_nacks; |
assign f_wb_rd_outstanding = f_wb_outstanding; |
`endif |
.DW(C_AXI_DATA_WIDTH), |
.AW(AW)) |
readorwrite(i_clk, !i_axi_reset_n, |
r_wb_cyc, r_wb_stb, 1'b0, r_wb_addr, w_wb_data, w_wb_sel, |
r_wb_ack, r_wb_stall, r_wb_err, |
w_wb_cyc, w_wb_stb, 1'b1, w_wb_addr, w_wb_data, w_wb_sel, |
w_wb_ack, w_wb_stall, w_wb_err, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_err); |
end else if (OPT_WRITEONLY) |
begin : ARB_WR |
assign o_wb_cyc = w_wb_cyc; |
assign o_wb_stb = w_wb_stb; |
assign o_wb_we = 1'b1; |
assign o_wb_addr = w_wb_addr; |
assign o_wb_data = w_wb_data; |
assign o_wb_sel = w_wb_sel; |
assign w_wb_ack = i_wb_ack; |
assign w_wb_stall= i_wb_stall; |
assign w_wb_ack = i_wb_ack; |
assign w_wb_err = i_wb_err; |
|
`ifdef FORMAL |
fwb_master #(.DW(DW), .AW(AW), |
.F_LGDEPTH(LGFIFO), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY)) |
f_wb(i_clk, !i_axi_reset_n, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
assign f_wb_wr_nreqs = f_wb_nreqs; |
assign f_wb_wr_nacks = f_wb_nacks; |
assign f_wb_wr_outstanding = f_wb_outstanding; |
`endif |
end else begin : ARB_WB |
wbarbiter #(.DW(DW), .AW(AW), |
.F_LGDEPTH(LGFIFO), |
.F_MAX_STALL(F_MAXSTALL), |
.F_OPT_CLK2FFLOGIC(F_OPT_CLK2FFLOGIC), |
.F_MAX_ACK_DELAY(F_MAXDELAY)) |
readorwrite(i_clk, !i_axi_reset_n, |
r_wb_cyc, r_wb_stb, 1'b0, r_wb_addr, w_wb_data, w_wb_sel, |
r_wb_ack, r_wb_stall, r_wb_err, |
w_wb_cyc, w_wb_stb, 1'b1, w_wb_addr, w_wb_data, w_wb_sel, |
w_wb_ack, w_wb_stall, w_wb_err, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_err |
`ifdef FORMAL |
, |
f_wb_rd_nreqs, f_wb_rd_nacks, f_wb_rd_outstanding, |
f_wb_wr_nreqs, f_wb_wr_nacks, f_wb_wr_outstanding, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding |
`endif |
); |
end endgenerate |
|
assign o_reset = (i_axi_reset_n == 1'b0); |
|
`ifdef FORMAL |
|
`ifdef AXIM2WBSP |
reg f_last_clk; |
generate if (F_OPT_CLK2FFLOGIC) |
begin |
reg f_last_clk; |
|
initial f_last_clk = 0; |
always @($global_clock) |
begin |
assume(i_clk == f_last_clk); |
f_last_clk <= !f_last_clk; |
end |
initial f_last_clk = 0; |
always @($global_clock) |
begin |
assume(i_clk == f_last_clk); |
f_last_clk <= !f_last_clk; |
|
if ((f_past_valid)&&(!$rose(i_clk))) |
assume($stable(i_axi_reset_n)); |
end |
end endgenerate |
`else |
`endif |
|
279,6 → 441,19
always @(posedge i_clk) |
f_past_valid = 1'b1; |
|
initial assume(!i_axi_reset_n); |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
|
generate if (F_OPT_CLK2FFLOGIC) |
begin |
|
always @($global_clock) |
if ((f_past_valid)&&(!$rose(i_clk))) |
assert($stable(i_axi_reset_n)); |
end endgenerate |
|
wire [(C_AXI_ID_WIDTH-1):0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
285,13 → 460,13
wire [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_rd_id_outstanding, |
f_axi_awr_id_outstanding, |
f_axi_wr_id_outstanding; |
wire [(C_AXI_ID_WIDTH-1):0] f_wb_nreqs, |
f_wb_nacks, f_wb_outstanding; |
wire [(C_AXI_ID_WIDTH-1):0] f_wb_wr_nreqs, |
f_wb_wr_nacks, f_wb_wr_outstanding; |
wire [(C_AXI_ID_WIDTH-1):0] f_wb_rd_nreqs, |
f_wb_rd_nacks, f_wb_rd_outstanding; |
wire [8:0] f_axi_wr_pending, |
f_axi_rd_count, |
f_axi_wr_count; |
|
/* |
generate if (!OPT_READONLY) |
begin : F_WB_WRITE |
fwb_slave #(.DW(DW), .AW(AW), |
.F_MAX_STALL(0), |
.F_MAX_ACK_DELAY(0), |
303,7 → 478,16
w_wb_sel, |
w_wb_ack, w_wb_stall, i_wb_data, w_wb_err, |
f_wb_wr_nreqs, f_wb_wr_nacks, f_wb_wr_outstanding); |
end else begin |
assign f_wb_wr_nreqs = 0; |
assign f_wb_wr_nacks = 0; |
assign f_wb_wr_outstanding = 0; |
end endgenerate |
*/ |
|
/* |
generate if (!OPT_WRITEONLY) |
begin : F_WB_READ |
fwb_slave #(.DW(DW), .AW(AW), |
.F_MAX_STALL(0), |
.F_MAX_ACK_DELAY(0), |
314,10 → 498,17
r_wb_cyc, r_wb_stb, r_wb_we, r_wb_addr, w_wb_data, w_wb_sel, |
r_wb_ack, r_wb_stall, i_wb_data, r_wb_err, |
f_wb_rd_nreqs, f_wb_rd_nacks, f_wb_rd_outstanding); |
end else begin |
assign f_wb_rd_nreqs = 0; |
assign f_wb_rd_nacks = 0; |
assign f_wb_rd_outstanding = 0; |
end endgenerate |
*/ |
|
/* |
fwb_master #(.DW(DW), .AW(AW), |
.F_MAX_STALL(3), |
.F_MAX_ACK_DELAY(3), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY), |
.F_LGDEPTH(C_AXI_ID_WIDTH)) |
f_wb(i_clk, !i_axi_reset_n, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
324,22 → 515,16
o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
*/ |
|
always @(*) |
assume(i_axi_awlen < 8'h4); |
|
always @(*) |
assume(i_axi_arlen < 8'h4); |
|
always @(*) |
assume(i_axi_arvalid == 0); |
|
faxi_slave #( |
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH), |
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_AXI_MAXSTALL(0), |
.F_AXI_MAXDELAY(0)) |
.F_AXI_MAXDELAY(0), |
.F_AXI_MAXBURST(OPT_MAXBURST), |
.F_OPT_CLK2FFLOGIC(F_OPT_CLK2FFLOGIC)) |
f_axi(.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// AXI write address channnel |
.i_axi_awready(o_axi_awready), |
360,29 → 545,29
.i_axi_wlast( i_axi_wlast), |
.i_axi_wvalid( i_axi_wvalid), |
// AXI write acknowledgement channel |
.i_axi_bid( o_axi_bid), // Response ID |
.i_axi_bresp( o_axi_bresp), // Write response |
.i_axi_bvalid(o_axi_bvalid), // Write reponse valid |
.i_axi_bready(i_axi_bready), // Response ready |
.i_axi_bid( o_axi_bid), |
.i_axi_bresp( o_axi_bresp), |
.i_axi_bvalid(o_axi_bvalid), |
.i_axi_bready(i_axi_bready), |
// AXI read address channel |
.i_axi_arready(o_axi_arready), // Read address ready |
.i_axi_arid( i_axi_arid), // Read ID |
.i_axi_araddr( i_axi_araddr), // Read address |
.i_axi_arlen( i_axi_arlen), // Read Burst Length |
.i_axi_arsize( i_axi_arsize), // Read Burst size |
.i_axi_arburst(i_axi_arburst), // Read Burst type |
.i_axi_arlock( i_axi_arlock), // Read lock type |
.i_axi_arcache(i_axi_arcache), // Read Cache type |
.i_axi_arprot( i_axi_arprot), // Read Protection type |
.i_axi_arqos( i_axi_arqos), // Read Protection type |
.i_axi_arvalid(i_axi_arvalid), // Read address valid |
.i_axi_arready(o_axi_arready), |
.i_axi_arid( i_axi_arid), |
.i_axi_araddr( i_axi_araddr), |
.i_axi_arlen( i_axi_arlen), |
.i_axi_arsize( i_axi_arsize), |
.i_axi_arburst(i_axi_arburst), |
.i_axi_arlock( i_axi_arlock), |
.i_axi_arcache(i_axi_arcache), |
.i_axi_arprot( i_axi_arprot), |
.i_axi_arqos( i_axi_arqos), |
.i_axi_arvalid(i_axi_arvalid), |
// AXI read data return |
.i_axi_rid( o_axi_rid), // Response ID |
.i_axi_rresp( o_axi_rresp), // Read response |
.i_axi_rvalid( o_axi_rvalid), // Read reponse valid |
.i_axi_rdata( o_axi_rdata), // Read data |
.i_axi_rlast( o_axi_rlast), // Read last |
.i_axi_rready( i_axi_rready), // Read Response ready |
.i_axi_rid( o_axi_rid), |
.i_axi_rresp( o_axi_rresp), |
.i_axi_rvalid( o_axi_rvalid), |
.i_axi_rdata( o_axi_rdata), |
.i_axi_rlast( o_axi_rlast), |
.i_axi_rready( i_axi_rready), |
// Quantify where we are within a transaction |
.f_axi_rd_outstanding( f_axi_rd_outstanding), |
.f_axi_wr_outstanding( f_axi_wr_outstanding), |
389,8 → 574,106
.f_axi_awr_outstanding(f_axi_awr_outstanding), |
.f_axi_rd_id_outstanding(f_axi_rd_id_outstanding), |
.f_axi_awr_id_outstanding(f_axi_awr_id_outstanding), |
.f_axi_wr_id_outstanding(f_axi_wr_id_outstanding)); |
.f_axi_wr_id_outstanding(f_axi_wr_id_outstanding), |
.f_axi_wr_pending(f_axi_wr_pending), |
.f_axi_rd_count(f_axi_rd_count), |
.f_axi_wr_count(f_axi_wr_count)); |
|
wire f_axi_ard_req, f_axi_awr_req, f_axi_wr_req, |
f_axi_rd_ack, f_axi_wr_ack; |
|
assign f_axi_ard_req = (i_axi_arvalid)&&(o_axi_arready); |
assign f_axi_awr_req = (i_axi_awvalid)&&(o_axi_awready); |
assign f_axi_wr_req = (i_axi_wvalid)&&(o_axi_wready); |
assign f_axi_wr_ack = (o_axi_bvalid)&&(i_axi_bready); |
assign f_axi_rd_ack = (o_axi_rvalid)&&(i_axi_rready); |
|
wire [(LGFIFO-1):0] f_awr_fifo_axi_used, |
f_dwr_fifo_axi_used, |
f_rd_fifo_axi_used, |
f_wr_fifo_wb_outstanding, |
f_rd_fifo_wb_outstanding; |
|
assign f_awr_fifo_axi_used = f_wr_fifo_ahead - f_wr_fifo_tail; |
assign f_dwr_fifo_axi_used = f_wr_fifo_dhead - f_wr_fifo_tail; |
assign f_rd_fifo_axi_used = f_rd_fifo_head - f_rd_fifo_tail; |
assign f_wr_fifo_wb_outstanding = f_wr_fifo_neck - f_wr_fifo_torso; |
assign f_rd_fifo_wb_outstanding = f_rd_fifo_neck - f_rd_fifo_torso; |
|
// The number of outstanding requests must always be greater than |
// the number of AXI requests creating them--since the AXI requests |
// may be burst requests. |
// |
always @(*) |
if (OPT_READONLY) |
begin |
assert(f_axi_awr_outstanding == 0); |
assert(f_axi_wr_outstanding == 0); |
assert(f_axi_awr_id_outstanding == 0); |
assert(f_axi_wr_id_outstanding == 0); |
assert(f_axi_wr_pending == 0); |
assert(f_axi_wr_count == 0); |
end else begin |
assert(f_awr_fifo_axi_used >= f_axi_awr_outstanding); |
assert(f_dwr_fifo_axi_used >= f_axi_wr_outstanding); |
assert(f_wr_fifo_ahead >= f_axi_awr_outstanding); |
end |
|
/* |
always @(*) |
assert((!w_wb_cyc) |
||(f_wr_fifo_wb_outstanding |
// -(((w_wb_stall)&&(w_wb_stb))? 1'b1:1'b0) |
+(((w_wb_ack)&&(w_wb_err))? 1'b1:1'b0) |
== f_wb_wr_outstanding)); |
*/ |
|
wire f_r_wb_req, f_r_wb_ack, f_r_wb_stall; |
assign f_r_wb_req = (r_wb_stb)&&(!r_wb_stall); |
assign f_r_wb_ack = (r_wb_cyc)&&((r_wb_ack)||(r_wb_err)); |
assign f_r_wb_stall=(r_wb_stb)&&(r_wb_stall); |
|
/* |
always @(*) |
if ((i_axi_reset_n)&&(r_wb_cyc)) |
assert(f_rd_fifo_wb_outstanding |
// -((f_r_wb_req)? 1'b1:1'b0) |
-((r_wb_stb)? 1'b1:1'b0) |
//+(((f_r_wb_ack)&&(!f_r_wb_req))? 1'b1:1'b0) |
== f_wb_rd_outstanding); |
*/ |
|
|
// |
assert property((!OPT_READONLY)||(!OPT_WRITEONLY)); |
|
always @(*) |
if (OPT_READONLY) |
begin |
assume(i_axi_awvalid == 0); |
assume(i_axi_wvalid == 0); |
end |
always @(*) |
if (OPT_WRITEONLY) |
assume(i_axi_arvalid == 0); |
|
always @(*) |
if (i_axi_awvalid) |
assume(i_axi_awburst[1] == 1'b0); |
always @(*) |
if (i_axi_arvalid) |
assume(i_axi_arburst[1] == 1'b0); |
|
always @(*) |
if (F_OPT_BURSTS) |
begin |
assume((!i_axi_arvalid)||(i_axi_arlen<= OPT_MAXBURST)); |
assume((!i_axi_awvalid)||(i_axi_awlen<= OPT_MAXBURST)); |
end else begin |
assume((!i_axi_arvalid)||(i_axi_arlen == 0)); |
assume((!i_axi_awvalid)||(i_axi_awlen == 0)); |
end |
|
`endif |
endmodule |
|
/trunk/rtl/aximrd2wbsp.v
7,37 → 7,49
// Purpose: Bridge an AXI read channel pair to a single wishbone read |
// channel. |
// |
// Rules: |
// 1. Any read channel error *must* be returned to the correct |
// read channel ID. In other words, we can't pipeline between IDs |
// 2. A FIFO must be used on getting a WB return, to make certain that |
// the AXI return channel is able to stall with no loss |
// 3. No request can be accepted unless there is room in the return |
// channel for it |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
// module aximrd2wbsp #( |
module aximrd2wbsp #( |
parameter C_AXI_ID_WIDTH = 6, // The AXI id width used for R&W |
// This is an int between 1-16 |
44,7 → 56,7
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width |
parameter AW = 26, // AXI Address width |
parameter LGFIFO = 4 |
parameter LGFIFO = 9 // Must be >= 8 |
// parameter WBMODE = "B4PIPELINE" |
// Could also be "BLOCK" |
) ( |
52,8 → 64,8
input wire i_axi_reset_n, // Bus reset |
|
// AXI read address channel signals |
output wire o_axi_arready, // Read address ready |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_arid, // Read ID |
output reg o_axi_arready, // Read address ready |
input wire [C_AXI_ID_WIDTH-1:0] i_axi_arid, // Read ID |
input wire [C_AXI_ADDR_WIDTH-1:0] i_axi_araddr, // Read address |
input wire [7:0] i_axi_arlen, // Read Burst Length |
input wire [2:0] i_axi_arsize, // Read Burst size |
75,11 → 87,18
// We'll share the clock and the reset |
output reg o_wb_cyc, |
output reg o_wb_stb, |
output wire [(AW-1):0] o_wb_addr, |
output reg [(AW-1):0] o_wb_addr, |
input wire i_wb_ack, |
input wire i_wb_stall, |
input [(C_AXI_DATA_WIDTH-1):0] i_wb_data, |
input wire [(C_AXI_DATA_WIDTH-1):0] i_wb_data, |
input wire i_wb_err |
`ifdef FORMAL |
// , |
// output wire [LGFIFO-1:0] f_fifo_head, |
// output wire [LGFIFO-1:0] f_fifo_neck, |
// output wire [LGFIFO-1:0] f_fifo_torso, |
// output wire [LGFIFO-1:0] f_fifo_tail |
`endif |
); |
|
localparam DW = C_AXI_DATA_WIDTH; |
88,206 → 107,265
assign w_reset = (i_axi_reset_n == 1'b0); |
|
|
reg [(C_AXI_ID_WIDTH+AW+1)-1:0] afifo [0:((1<<(LGFIFO))-1)]; |
reg [(DW+1)-1:0] dfifo [0:((1<<(LGFIFO))-1)]; |
reg [(C_AXI_ID_WIDTH+AW+1)-1:0] fifo_at_neck, afifo_at_tail; |
reg [(DW+1)-1:0] dfifo_at_tail; |
wire [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] i_rd_request; |
reg [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] r_rd_request; |
wire [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] w_rd_request; |
|
// We're going to need to keep track of transaction bursts in progress, |
// since the wishbone doesn't. For this, we'll use a FIFO, but with |
// multiple pointers: |
// |
// fifo_head - pointer to where to write the next incoming |
// bus request .. adjusted when |
// (o_axi_arready)&&(i_axi_arvalid) |
// fifo_neck - pointer to where to read from the FIFO in |
// order to issue another request. Used |
// when (o_wb_stb)&&(!i_wb_stall) |
// fifo_torso - pointer to where to write a wishbone |
// transaction upon return. |
// when (i_ack) |
// fifo_tail - pointer to where the last transaction is to |
// be retired when |
// (i_axi_rvalid)&&(i_axi_rready) |
// |
// All of these are to be set to zero upon a reset signal. |
// |
reg [LGFIFO-1:0] fifo_head, fifo_neck, fifo_torso, fifo_tail; |
reg [LGFIFO:0] next_ackptr, next_rptr; |
|
// Since we need to insure that these pointers wrap properly at |
// LGFIFO bits, and since it is confusing to do that within IF |
// statements, |
wire [LGFIFO-1:0] next_head, next_neck, next_torso, next_tail, |
almost_head; |
wire fifo_full; |
assign next_head = fifo_head + 1; |
assign next_neck = fifo_neck + 1; |
assign next_torso = fifo_torso + 1; |
assign next_tail = fifo_tail + 1; |
assign almost_head = fifo_head + 1; |
reg [C_AXI_ID_WIDTH:0] request_fifo [0:((1<<LGFIFO)-1)]; |
reg [C_AXI_ID_WIDTH:0] rsp_data; |
|
assign fifo_full = (almost_head == fifo_tail); |
reg [C_AXI_DATA_WIDTH:0] response_fifo [0:((1<<LGFIFO)-1)]; |
reg [C_AXI_DATA_WIDTH:0] ack_data; |
|
reg wr_last, filling_fifo, incr; |
reg [7:0] len; |
reg [(AW-1):0] wr_fifo_addr; |
reg [(C_AXI_ID_WIDTH-1):0] wr_fifo_id; |
reg advance_ack; |
|
// |
// |
// |
// |
// Here's our plan: Any time READY & VALID are both true, initiate a |
// transfer (unless one is ongoing). Hold READY false while initiating |
// any burst transaction. Keep the request RID and burst length stuffs |
// into a FIFO. |
// queue are both valid, issue the wishbone read request. Once a read |
// request returns, retire the value in the FIFO queue. |
// |
// The FIFO queue *must* include: |
// |
// RQ, ADDR, LAST |
// |
initial len = 0; |
initial filling_fifo = 0; |
initial fifo_head = 0; |
|
reg r_valid, last_stb, last_ack, err_state; |
reg [C_AXI_ID_WIDTH-1:0] axi_id; |
reg [LGFIFO:0] fifo_wptr, fifo_ackptr, fifo_rptr; |
reg incr; |
reg [7:0] stblen; |
|
wire [C_AXI_ID_WIDTH-1:0] w_id;// r_id; |
wire [C_AXI_ADDR_WIDTH-1:0] w_addr;// r_addr; |
wire [7:0] w_len;// r_len; |
wire [2:0] w_size;// r_size; |
wire [1:0] w_burst;// r_burst; |
wire [0:0] w_lock;// r_lock; |
wire [3:0] w_cache;// r_cache; |
wire [2:0] w_prot;// r_prot; |
wire [3:0] w_qos;// r_qos; |
wire [LGFIFO:0] fifo_fill; |
wire [LGFIFO:0] max_fifo_fill; |
wire accept_request; |
|
|
|
assign fifo_fill = (fifo_wptr - fifo_rptr); |
assign max_fifo_fill = (1<<LGFIFO); |
|
assign accept_request = (i_axi_reset_n)&&(!err_state) |
&&((!o_wb_cyc)||(!i_wb_err)) |
&&((!o_wb_stb)||(last_stb && !i_wb_stall)) |
&&(r_valid ||((i_axi_arvalid)&&(o_axi_arready))) |
// The request must fit into our FIFO before making |
// it |
&&(fifo_fill + {{(LGFIFO-8){1'b0}},w_len} +1 |
< max_fifo_fill) |
// One ID at a time, lest we return a bus error |
// to the wrong AXI master |
&&((fifo_fill == 0)||(w_id == axi_id)); |
|
|
assign i_rd_request = { i_axi_arid, i_axi_araddr, i_axi_arlen, |
i_axi_arsize, i_axi_arburst, i_axi_arcache, |
i_axi_arlock, i_axi_arprot, i_axi_arqos }; |
|
initial r_rd_request = 0; |
initial r_valid = 0; |
always @(posedge i_axi_clk) |
if (!i_axi_reset_n) |
begin |
wr_last <= 1'b0; |
r_rd_request <= 0; |
r_valid <= 1'b0; |
end else if ((i_axi_arvalid)&&(o_axi_arready)) |
begin |
r_rd_request <= i_rd_request; |
if (!accept_request) |
r_valid <= 1'b1; |
end else if (accept_request) |
r_valid <= 1'b0; |
|
if (filling_fifo) |
begin |
if (!fifo_full) |
begin |
len <= len - 1; |
if (len == 1) |
filling_fifo <= 1'b0; |
fifo_head <= next_head; |
wr_fifo_addr <= wr_fifo_addr |
+ {{(AW-1){1'b0}}, incr}; |
wr_last <= (len == 1); |
end |
end else begin |
wr_fifo_addr <= i_axi_araddr[(C_AXI_ADDR_WIDTH-1):(C_AXI_ADDR_WIDTH-AW)]; |
wr_fifo_id <= i_axi_arid; |
incr <= i_axi_arburst[0]; |
if ((o_axi_arready)&&(i_axi_arvalid)) |
begin |
fifo_head <= next_head; |
len <= i_axi_arlen; |
filling_fifo <= (i_axi_arlen != 0); |
wr_last <= 1'b1; |
end |
end |
always @(*) |
o_axi_arready = !r_valid; |
|
if (w_reset) |
begin |
len <= 0; |
filling_fifo <= 1'b0; |
fifo_head <= 0; |
end |
end |
/* |
assign r_id = r_rd_request[25 + C_AXI_ADDR_WIDTH +: C_AXI_ID_WIDTH]; |
assign r_addr = r_rd_request[25 +: C_AXI_ADDR_WIDTH]; |
assign r_len = r_rd_request[17 +: 8]; |
assign r_size = r_rd_request[14 +: 3]; |
assign r_burst = r_rd_request[12 +: 2]; |
assign r_lock = r_rd_request[11 +: 1]; |
assign r_cache = r_rd_request[ 7 +: 4]; |
assign r_prot = r_rd_request[ 4 +: 3]; |
assign r_qos = r_rd_request[ 0 +: 4]; |
*/ |
|
always @(posedge i_axi_clk) |
afifo[fifo_head] <= { wr_fifo_id, wr_last, wr_fifo_addr }; |
assign w_rd_request = (r_valid) ? (r_rd_request) : i_rd_request; |
|
reg err_state; |
initial o_wb_cyc = 1'b0; |
initial o_wb_stb = 1'b0; |
initial fifo_neck = 0; |
initial fifo_torso = 0; |
initial err_state = 0; |
assign w_id = w_rd_request[25 + C_AXI_ADDR_WIDTH +: C_AXI_ID_WIDTH]; |
assign w_addr = w_rd_request[25 +: C_AXI_ADDR_WIDTH]; |
assign w_len = w_rd_request[17 +: 8]; |
assign w_size = w_rd_request[14 +: 3]; |
assign w_burst = w_rd_request[12 +: 2]; |
assign w_lock = w_rd_request[11 +: 1]; |
assign w_cache = w_rd_request[ 7 +: 4]; |
assign w_prot = w_rd_request[ 4 +: 3]; |
assign w_qos = w_rd_request[ 0 +: 4]; |
|
initial o_wb_cyc = 0; |
initial o_wb_stb = 0; |
initial stblen = 0; |
initial incr = 0; |
initial last_stb = 0; |
always @(posedge i_axi_clk) |
if (w_reset) |
begin |
if (w_reset) |
o_wb_stb <= 1'b0; |
o_wb_cyc <= 1'b0; |
incr <= 1'b0; |
stblen <= 0; |
last_stb <= 0; |
end else if ((!o_wb_stb)||(!i_wb_stall)) |
begin |
if (accept_request) |
begin |
o_wb_cyc <= 1'b0; |
o_wb_stb <= 1'b0; |
// Process the new request |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
last_stb <= (w_len == 0); |
|
fifo_neck <= 0; |
fifo_torso <= 0; |
o_wb_addr <= w_addr[(C_AXI_ADDR_WIDTH-1):(C_AXI_ADDR_WIDTH-AW)]; |
incr <= w_burst[0]; |
stblen <= w_len; |
axi_id <= w_id; |
// end else if ((o_wb_cyc)&&(i_wb_err)||(err_state)) |
end else if (o_wb_stb && !last_stb) |
begin |
// Step forward on the burst request |
last_stb <= (stblen == 1); |
|
err_state <= 0; |
end else if (o_wb_stb) |
begin |
o_wb_addr <= o_wb_addr + ((incr)? 1'b1:1'b0); |
stblen <= stblen - 1'b1; |
|
if (i_wb_err) |
begin |
stblen <= 0; |
o_wb_stb <= 1'b0; |
err_state <= 1'b1; |
end else if (!i_wb_stall) |
begin |
o_wb_stb <= (fifo_head != next_neck); |
// && (WBMODE != "B3SINGLE"); |
// o_wb_cyc <= (WBMODE != "B3SINGLE"); |
o_wb_cyc <= 1'b0; |
end |
end else if (!o_wb_stb || last_stb) |
begin |
// End the request |
o_wb_stb <= 1'b0; |
last_stb <= 1'b0; |
stblen <= 0; |
|
if (!i_wb_stall) |
fifo_neck <= next_neck; |
if (i_wb_ack) |
fifo_torso <= next_torso; |
end else if (err_state) |
begin |
fifo_torso <= next_torso; |
if (fifo_neck == next_torso) |
err_state <= 1'b0; |
o_wb_cyc <= 1'b0; |
end else if (o_wb_cyc) |
begin |
if (i_wb_ack) |
fifo_torso <= next_torso; |
if (fifo_neck == next_torso) |
// Check for the last acknowledgment |
if ((i_wb_ack)&&(last_ack)) |
o_wb_cyc <= 1'b0; |
end else if (fifo_neck != fifo_head) |
begin |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
if (i_wb_err) |
o_wb_cyc <= 1'b0; |
end |
end else if ((o_wb_cyc)&&(i_wb_err)) |
begin |
stblen <= 0; |
o_wb_stb <= 1'b0; |
o_wb_cyc <= 1'b0; |
last_stb <= 1'b0; |
end |
|
always @(*) |
next_ackptr = fifo_ackptr + 1'b1; |
|
always @(*) |
begin |
last_ack = 1'b0; |
if (err_state) |
last_ack = 1'b1; |
else if ((o_wb_stb)&&(stblen == 0)&&(fifo_wptr == fifo_ackptr)) |
last_ack = 1'b1; |
else if ((fifo_wptr == next_ackptr)&&(!o_wb_stb)) |
last_ack = 1'b1; |
end |
|
initial fifo_wptr = 0; |
always @(posedge i_axi_clk) |
fifo_at_neck <= afifo[fifo_neck]; |
assign o_wb_addr = fifo_at_neck[(AW-1):0]; |
if (w_reset) |
fifo_wptr <= 0; |
else if (o_wb_cyc && i_wb_err) |
fifo_wptr <= fifo_wptr + {{(LGFIFO-8){1'b0}},stblen} |
+ ((o_wb_stb)? 1:0); |
else if ((o_wb_stb)&&(!i_wb_stall)) |
fifo_wptr <= fifo_wptr + 1'b1; |
|
initial fifo_ackptr = 0; |
always @(posedge i_axi_clk) |
dfifo[fifo_torso] <= { (err_state)||(i_wb_err), i_wb_data }; |
if (w_reset) |
fifo_ackptr <= 0; |
else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err))) |
fifo_ackptr <= fifo_ackptr + 1'b1; |
else if (err_state && (fifo_ackptr != fifo_wptr)) |
fifo_ackptr <= fifo_ackptr + 1'b1; |
|
always @(posedge i_axi_clk) |
if ((o_wb_stb)&&(!i_wb_stall)) |
request_fifo[fifo_wptr[LGFIFO-1:0]] <= { last_stb, axi_id }; |
|
always @(posedge i_axi_clk) |
if (w_reset) |
fifo_tail <= 0; |
else if ((o_axi_rvalid)&&(i_axi_rready)) |
fifo_tail <= next_tail; |
if ((o_wb_cyc && ((i_wb_ack)||(i_wb_err))) |
||(err_state && (fifo_ackptr != fifo_wptr))) |
response_fifo[fifo_ackptr[LGFIFO-1:0]] |
<= { (err_state||i_wb_err), i_wb_data }; |
|
initial fifo_rptr = 0; |
always @(posedge i_axi_clk) |
begin |
afifo_at_tail <= afifo[fifo_tail]; |
dfifo_at_tail <= dfifo[fifo_tail]; |
// o_axi_rdata <= dfifo[fifo_tail]; |
// o_axi_rlast <= afifo[fifo_tail]; |
// o_axi_rid <= afifo[fifo_tail]; |
end |
assign o_axi_rlast = afifo_at_tail[AW]; |
assign o_axi_rid = afifo_at_tail[(C_AXI_ID_WIDTH+AW):(AW+1)]; |
assign o_axi_rresp = { (2){dfifo_at_tail[DW]} }; |
assign o_axi_rdata = dfifo_at_tail[(DW-1):0]; |
if (w_reset) |
fifo_rptr <= 0; |
else if ((o_axi_rvalid)&&(i_axi_rready)) |
fifo_rptr <= fifo_rptr + 1'b1; |
|
initial o_axi_rvalid = 1'b0; |
always @(*) |
next_rptr = fifo_rptr + 1'b1; |
|
always @(posedge i_axi_clk) |
if (w_reset) |
o_axi_rvalid <= 0; |
else if (fifo_tail != fifo_neck) |
o_axi_rvalid <= (fifo_tail != fifo_neck + 1); |
if (advance_ack) |
ack_data <= response_fifo[fifo_rptr[LGFIFO-1:0]]; |
|
assign o_axi_arready = (!fifo_full)&&(!filling_fifo); |
always @(posedge i_axi_clk) |
if (advance_ack) |
rsp_data <= request_fifo[fifo_rptr[LGFIFO-1:0]]; |
|
always @(*) |
if ((o_axi_rvalid)&&(i_axi_rready)) |
advance_ack = (fifo_ackptr != next_rptr); |
else if ((!o_axi_rvalid)&&(fifo_ackptr != fifo_rptr)) |
advance_ack = 1'b1; |
else |
advance_ack = 1'b0; |
|
initial o_axi_rvalid = 0; |
always @(posedge i_axi_clk) |
if (w_reset) |
o_axi_rvalid <= 1'b0; |
else if (advance_ack) |
o_axi_rvalid <= 1'b1; |
else if (i_axi_rready) |
o_axi_rvalid <= 1'b0; |
|
initial err_state = 0; |
always @(posedge i_axi_clk) |
if (w_reset) |
err_state <= 1'b0; |
else if ((o_wb_cyc)&&(i_wb_err)) |
err_state <= 1'b1; |
else if ((!o_wb_stb)&&(fifo_wptr == fifo_rptr)) |
err_state <= 1'b0; |
|
assign o_axi_rlast = rsp_data[C_AXI_ID_WIDTH]; |
assign o_axi_rid = rsp_data[0 +: C_AXI_ID_WIDTH]; |
assign o_axi_rresp = {(2){ack_data[C_AXI_DATA_WIDTH]}}; |
assign o_axi_rdata = ack_data[0 +: C_AXI_DATA_WIDTH]; |
|
// Make Verilator happy |
// verilator lint_off UNUSED |
wire [(C_AXI_ID_WIDTH+1)+(C_AXI_ADDR_WIDTH-AW) |
+3+1+1+4+3+4-1:0] unused; |
+27-1:0] unused; |
assign unused = { i_axi_arsize, i_axi_arburst[1], |
i_axi_arlock, i_axi_arcache, i_axi_arprot, |
i_axi_arqos, |
fifo_at_neck[(C_AXI_ID_WIDTH+AW+1)-1:AW], |
i_axi_arlock, i_axi_arcache, i_axi_arprot, i_axi_arqos, |
w_burst[1], w_size, w_lock, w_cache, w_prot, w_qos, w_addr[1:0], |
i_axi_araddr[(C_AXI_ADDR_WIDTH-AW-1):0] }; |
// verilator lint_on UNUSED |
|
297,22 → 375,149
always @(posedge i_axi_clk) |
f_past_valid <= 1'b1; |
|
wire [LGFIFO-1:0] f_fifo_used, f_fifo_neck_used, |
f_fifo_torso_used; |
assign f_fifo_used = fifo_head - fifo_tail; |
assign f_fifo_neck_used = fifo_head - fifo_neck; |
assign f_fifo_torso_used = fifo_head - fifo_torso; |
//////////////////////////////////////////////////////////////////////// |
// |
// Assumptions |
// |
// |
always @(*) |
if (!f_past_valid) |
assume(w_reset); |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// Ad-hoc assertions |
// |
// |
always @(*) |
assert((f_fifo_used < {(LGFIFO){1'b1}})||(!o_axi_arready)); |
if (o_wb_stb) |
assert(last_stb == (stblen == 0)); |
else |
assert((!last_stb)&&(stblen == 0)); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// Error state |
// |
// |
/* |
always @(*) |
assert(f_fifo_neck_used <= f_fifo_used); |
assume(!i_wb_err); |
always @(*) |
assert(f_fifo_torso_used <= f_fifo_used); |
assert(!err_state); |
*/ |
always @(*) |
if ((!err_state)&&(o_axi_rvalid)) |
assert(o_axi_rresp == 2'b00); |
|
//////////////////////////////////////////////////////////////////////// |
// |
// FIFO pointers |
// |
// |
wire [LGFIFO:0] f_fifo_wb_used, f_fifo_ackremain, f_fifo_used; |
assign f_fifo_used = fifo_wptr - fifo_rptr; |
assign f_fifo_wb_used = fifo_wptr - fifo_ackptr; |
assign f_fifo_ackremain = fifo_ackptr - fifo_rptr; |
|
always @(*) |
if (o_wb_stb) |
assert(f_fifo_used + stblen + 1 < {(LGFIFO){1'b1}}); |
else |
assert(f_fifo_used < {(LGFIFO){1'b1}}); |
always @(*) |
assert(f_fifo_wb_used <= f_fifo_used); |
always @(*) |
assert(f_fifo_ackremain <= f_fifo_used); |
|
// Reset properties |
always @(posedge i_axi_clk) |
if ((f_past_valid)&&(!$past(i_axi_reset_n))) |
assert(f_fifo_used == 0); |
if ((!f_past_valid)||($past(w_reset))) |
begin |
assert(fifo_wptr == 0); |
assert(fifo_ackptr == 0); |
assert(fifo_rptr == 0); |
end |
|
localparam F_LGDEPTH = LGFIFO+1, F_LGRDFIFO = 72; // 9*F_LGFIFO; |
wire [(9-1):0] f_axi_rd_count; |
wire [(F_LGRDFIFO-1):0] f_axi_rdfifo; |
wire [(F_LGDEPTH-1):0] f_axi_rd_nbursts, f_axi_rd_outstanding, |
f_axi_awr_outstanding, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding; |
|
fwb_master #(.AW(AW), .DW(C_AXI_DATA_WIDTH), .F_MAX_STALL(2), |
.F_MAX_ACK_DELAY(3), .F_LGDEPTH(F_LGDEPTH), |
.F_OPT_DISCONTINUOUS(1)) |
fwb(i_axi_clk, w_reset, |
o_wb_cyc, o_wb_stb, 1'b0, o_wb_addr, {(DW){1'b0}}, 4'hf, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
always @(*) |
if (err_state) |
assert(f_wb_outstanding == 0); |
else |
assert(f_wb_outstanding == f_fifo_wb_used); |
|
|
faxi_slave #(.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_OPT_BURSTS(1'b0), |
.F_LGDEPTH(F_LGDEPTH), |
.F_AXI_MAXSTALL(0), |
.F_AXI_MAXDELAY(0)) |
faxi(.i_clk(i_axi_clk), .i_axi_reset_n(!w_reset), |
.i_axi_awready(1'b0), |
.i_axi_awaddr(0), |
.i_axi_awlen(0), |
.i_axi_awsize(0), |
.i_axi_awburst(0), |
.i_axi_awlock(0), |
.i_axi_awcache(0), |
.i_axi_awprot(0), |
.i_axi_awqos(0), |
.i_axi_awvalid(1'b0), |
// |
.i_axi_wready(1'b0), |
.i_axi_wdata(0), |
.i_axi_wstrb(0), |
.i_axi_wlast(0), |
.i_axi_wvalid(1'b0), |
// |
.i_axi_bresp(0), |
.i_axi_bvalid(1'b0), |
.i_axi_bready(1'b0), |
// |
.i_axi_arready(o_axi_arready), |
.i_axi_araddr(i_axi_araddr), |
.i_axi_arlen(i_axi_arlen), |
.i_axi_arsize(i_axi_arsize), |
.i_axi_arburst(i_axi_arburst), |
.i_axi_arlock(i_axi_arlock), |
.i_axi_arcache(i_axi_arcache), |
.i_axi_arprot(i_axi_arprot), |
.i_axi_arqos(i_axi_arqos), |
.i_axi_arvalid(i_axi_arvalid), |
// |
.i_axi_rresp(o_axi_rresp), |
.i_axi_rvalid(o_axi_rvalid), |
.i_axi_rdata(o_axi_rdata), |
.i_axi_rlast(o_axi_rlast), |
.i_axi_rready(i_axi_rready), |
// |
.f_axi_rd_nbursts(f_axi_rd_nbursts), |
.f_axi_rd_outstanding(f_axi_rd_outstanding), |
.f_axi_wr_nbursts(), |
.f_axi_awr_outstanding(f_axi_awr_outstanding), |
.f_axi_awr_nbursts(), |
// |
.f_axi_rd_count(f_axi_rd_count), |
.f_axi_rdfifo(f_axi_rdfifo)); |
|
always @(*) |
assert(f_axi_awr_outstanding == 0); |
|
`endif |
endmodule |
/trunk/rtl/aximwr2wbsp.v
1,3 → 1,4
`error This full featured AXI to WB converter does not (yet) work |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: aximwr2wbsp.v |
9,32 → 10,55
// |
// Still need to implement the lock feature. |
// |
// We're going to need to keep track of transaction bursts in progress, |
// since the wishbone doesn't. For this, we'll use a FIFO, but with |
// multiple pointers: |
// |
// fifo_ahead - pointer to where to write the next incoming |
// bus request .. adjusted when |
// (o_axi_awready)&&(i_axi_awvalid) |
// fifo_neck - pointer to where to read from the FIFO in |
// order to issue another request. Used |
// when (o_wb_stb)&&(!i_wb_stall) |
// fifo_torso - pointer to where to write a wishbone |
// transaction upon return. |
// when (i_ack) |
// fifo_tail - pointer to where the last transaction is to |
// be retired when |
// (i_axi_rvalid)&&(i_axi_rready) |
// |
// All of these are to be set to zero upon a reset signal. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
88,6 → 112,14
input wire i_wb_stall, |
// input [(C_AXI_DATA_WIDTH-1):0] i_wb_data, |
input wire i_wb_err |
`ifdef FORMAL |
, |
output wire [LGFIFO-1:0] f_fifo_ahead, |
output wire [LGFIFO-1:0] f_fifo_dhead, |
output wire [LGFIFO-1:0] f_fifo_neck, |
output wire [LGFIFO-1:0] f_fifo_torso, |
output wire [LGFIFO-1:0] f_fifo_tail |
`endif |
); |
|
localparam DW = C_AXI_DATA_WIDTH; |
121,9 → 153,10
reg [(AW-1):0] wr_fifo_addr; |
reg [(C_AXI_ID_WIDTH-1):0] wr_fifo_id; |
|
wire axi_aw_req, axi_wr_req; |
wire axi_aw_req, axi_wr_req, axi_wr_ack; |
assign axi_aw_req = (o_axi_awready)&&(i_axi_awvalid); |
assign axi_wr_req = (o_axi_wready)&&(i_axi_wvalid); |
assign axi_wr_ack = (o_axi_bvalid)&&(i_axi_bready); |
|
wire fifo_full; |
assign fifo_full = (next_ahead == fifo_tail)||(next_dhead ==fifo_tail); |
199,10 → 232,10
begin |
if (i_wb_err) |
begin |
o_wb_cyc <= 1'b0; |
o_wb_stb <= 1'b0; |
err_state <= 1'b0; |
end |
else if (!i_wb_stall) |
err_state <= 1'b1; |
end else if (!i_wb_stall) |
o_wb_stb <= (fifo_ahead != next_neck) |
&&(fifo_dhead != next_neck); |
|
214,10 → 247,12
|
if (fifo_neck == next_torso) |
o_wb_cyc <= 1'b0; |
end else if (err_state) |
end else if ((err_state)||(i_wb_err)) |
begin |
o_wb_cyc <= 1'b0; |
if (fifo_torso != fifo_neck) |
o_wb_stb <= 1'b0; |
err_state <= (err_state)||(i_wb_err); |
if ((o_wb_cyc)&&(fifo_torso != fifo_neck)) |
fifo_torso <= next_torso; |
if (fifo_neck == next_torso) |
err_state <= 1'b0; |
227,7 → 262,8
fifo_torso <= next_torso; |
if (fifo_neck == next_torso) |
o_wb_cyc <= 1'b0; |
end else if((fifo_ahead!= fifo_neck)&&(fifo_dhead != fifo_neck)) |
end else if((fifo_ahead!= fifo_neck) |
&&(fifo_dhead != fifo_neck)) |
begin |
o_wb_cyc <= 1; |
o_wb_stb <= 1; |
254,7 → 290,7
always @(posedge i_axi_clk) |
if (w_reset) |
fifo_tail <= 0; |
else if ((o_axi_bvalid)&&(i_axi_bready)) |
else if (axi_wr_ack) |
fifo_tail <= next_tail; |
|
always @(posedge i_axi_clk) |
310,6 → 346,16
assert((!o_wb_stb)|| |
((fifo_neck != fifo_ahead) |
&&(fifo_neck != fifo_dhead))); |
|
assign f_fifo_ahead = fifo_ahead; |
assign f_fifo_dhead = fifo_dhead; |
assign f_fifo_neck = fifo_neck; |
assign f_fifo_torso = fifo_torso; |
assign f_fifo_tail = fifo_tail; |
|
always @(*) |
if (i_axi_awvalid) |
assert(!i_axi_awburst[1]); |
`endif |
endmodule |
|
/trunk/rtl/axlite2wbsp.v
0,0 → 1,482
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: axlite2wbsp.v |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: Take an AXI lite input, and convert it into WB. |
// |
// We'll treat AXI as two separate busses: one for writes, another for |
// reads, further, we'll insist that the two channels AXI uses for writes |
// combine into one channel for our purposes. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module axlite2wbsp( i_clk, i_axi_reset_n, |
// |
o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot,i_axi_awvalid, |
// |
o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid, |
// |
o_axi_bresp, o_axi_bvalid, i_axi_bready, |
// |
o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot, i_axi_arvalid, |
// |
o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready, |
// |
// Wishbone interface |
o_reset, o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err); |
// |
parameter C_AXI_DATA_WIDTH = 32;// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28; // AXI Address width |
parameter LGFIFO = 4; |
parameter F_MAXSTALL = 3; |
parameter F_MAXDELAY = 3; |
parameter [0:0] OPT_READONLY = 1'b0; |
parameter [0:0] OPT_WRITEONLY = 1'b0; |
localparam F_LGDEPTH = LGFIFO+1; |
// |
input wire i_clk; // System clock |
input wire i_axi_reset_n; |
|
// AXI write address channel signals |
output wire o_axi_awready;//Slave is ready to accept |
input wire [C_AXI_ADDR_WIDTH-1:0] i_axi_awaddr; // Write address |
input wire [3:0] i_axi_awcache; // Write Cache type |
input wire [2:0] i_axi_awprot; // Write Protection type |
input wire i_axi_awvalid; // Write address valid |
|
// AXI write data channel signals |
output wire o_axi_wready; // Write data ready |
input wire [C_AXI_DATA_WIDTH-1:0] i_axi_wdata; // Write data |
input wire [C_AXI_DATA_WIDTH/8-1:0] i_axi_wstrb; // Write strobes |
input wire i_axi_wvalid; // Write valid |
|
// AXI write response channel signals |
output wire [1:0] o_axi_bresp; // Write response |
output wire o_axi_bvalid; // Write reponse valid |
input wire i_axi_bready; // Response ready |
|
// AXI read address channel signals |
output wire o_axi_arready; // Read address ready |
input wire [C_AXI_ADDR_WIDTH-1:0] i_axi_araddr; // Read address |
input wire [3:0] i_axi_arcache; // Read Cache type |
input wire [2:0] i_axi_arprot; // Read Protection type |
input wire i_axi_arvalid; // Read address valid |
|
// AXI read data channel signals |
output wire [1:0] o_axi_rresp; // Read response |
output wire o_axi_rvalid; // Read reponse valid |
output wire [C_AXI_DATA_WIDTH-1:0] o_axi_rdata; // Read data |
input wire i_axi_rready; // Read Response ready |
|
// We'll share the clock and the reset |
output wire o_reset; |
output wire o_wb_cyc; |
output wire o_wb_stb; |
output wire o_wb_we; |
output wire [(C_AXI_ADDR_WIDTH-3):0] o_wb_addr; |
output wire [(C_AXI_DATA_WIDTH-1):0] o_wb_data; |
output wire [(C_AXI_DATA_WIDTH/8-1):0] o_wb_sel; |
input wire i_wb_ack; |
input wire i_wb_stall; |
input wire [(C_AXI_DATA_WIDTH-1):0] i_wb_data; |
input wire i_wb_err; |
|
|
localparam DW = C_AXI_DATA_WIDTH; |
localparam AW = C_AXI_ADDR_WIDTH-2; |
// |
// |
// |
|
wire [(AW-1):0] w_wb_addr, r_wb_addr; |
wire [(C_AXI_DATA_WIDTH-1):0] w_wb_data; |
wire [(C_AXI_DATA_WIDTH/8-1):0] w_wb_sel; |
wire r_wb_err, r_wb_cyc, r_wb_stb, r_wb_stall, r_wb_ack; |
wire w_wb_err, w_wb_cyc, w_wb_stb, w_wb_stall, w_wb_ack; |
|
// verilator lint_off UNUSED |
wire r_wb_we, w_wb_we; |
|
assign r_wb_we = 1'b0; |
assign w_wb_we = 1'b1; |
// verilator lint_on UNUSED |
|
`ifdef FORMAL |
wire [LGFIFO:0] f_wr_fifo_first, f_rd_fifo_first, |
f_wr_fifo_mid, f_rd_fifo_mid, |
f_wr_fifo_last, f_rd_fifo_last; |
wire [(F_LGDEPTH-1):0] f_wb_nreqs, f_wb_nacks, |
f_wb_outstanding; |
wire [(F_LGDEPTH-1):0] f_wb_wr_nreqs, f_wb_wr_nacks, |
f_wb_wr_outstanding; |
wire [(F_LGDEPTH-1):0] f_wb_rd_nreqs, f_wb_rd_nacks, |
f_wb_rd_outstanding; |
wire f_pending_awvalid, f_pending_wvalid; |
`endif |
|
// |
// AXI-lite write channel to WB processing |
// |
generate if (!OPT_READONLY) |
begin : AXI_WR |
axilwr2wbsp #( |
// .F_LGDEPTH(F_LGDEPTH), |
// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), // .AW(AW), |
.LGFIFO(LGFIFO)) |
axi_write_decoder( |
.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// |
.o_axi_awready(o_axi_awready), |
.i_axi_awaddr( i_axi_awaddr), |
.i_axi_awcache(i_axi_awcache), |
.i_axi_awprot( i_axi_awprot), |
.i_axi_awvalid(i_axi_awvalid), |
// |
.o_axi_wready( o_axi_wready), |
.i_axi_wdata( i_axi_wdata), |
.i_axi_wstrb( i_axi_wstrb), |
.i_axi_wvalid( i_axi_wvalid), |
// |
.o_axi_bresp(o_axi_bresp), |
.o_axi_bvalid(o_axi_bvalid), |
.i_axi_bready(i_axi_bready), |
// |
.o_wb_cyc( w_wb_cyc), |
.o_wb_stb( w_wb_stb), |
.o_wb_addr( w_wb_addr), |
.o_wb_data( w_wb_data), |
.o_wb_sel( w_wb_sel), |
.i_wb_ack( w_wb_ack), |
.i_wb_stall(w_wb_stall), |
.i_wb_err( w_wb_err) |
`ifdef FORMAL |
, |
.f_first(f_wr_fifo_first), |
.f_mid( f_wr_fifo_mid), |
.f_last( f_wr_fifo_last), |
.f_wpending({ f_pending_awvalid, f_pending_wvalid }) |
`endif |
); |
end else begin |
assign w_wb_cyc = 0; |
assign w_wb_stb = 0; |
assign w_wb_addr = 0; |
assign w_wb_data = 0; |
assign w_wb_sel = 0; |
assign o_axi_awready = 0; |
assign o_axi_wready = 0; |
assign o_axi_bvalid = (i_axi_wvalid); |
assign o_axi_bresp = 2'b11; |
`ifdef FORMAL |
assign f_wr_fifo_first = 0; |
assign f_wr_fifo_mid = 0; |
assign f_wr_fifo_last = 0; |
assign f_pending_awvalid=0; |
assign f_pending_wvalid =0; |
`endif |
end endgenerate |
assign w_wb_we = 1'b1; |
|
// |
// AXI-lite read channel to WB processing |
// |
generate if (!OPT_WRITEONLY) |
begin : AXI_RD |
axilrd2wbsp #( |
// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.LGFIFO(LGFIFO)) |
axi_read_decoder( |
.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// |
.o_axi_arready(o_axi_arready), |
.i_axi_araddr( i_axi_araddr), |
.i_axi_arcache(i_axi_arcache), |
.i_axi_arprot( i_axi_arprot), |
.i_axi_arvalid(i_axi_arvalid), |
// |
.o_axi_rresp( o_axi_rresp), |
.o_axi_rvalid(o_axi_rvalid), |
.o_axi_rdata( o_axi_rdata), |
.i_axi_rready(i_axi_rready), |
// |
.o_wb_cyc( r_wb_cyc), |
.o_wb_stb( r_wb_stb), |
.o_wb_addr( r_wb_addr), |
.i_wb_ack( r_wb_ack), |
.i_wb_stall(r_wb_stall), |
.i_wb_data( i_wb_data), |
.i_wb_err( r_wb_err) |
`ifdef FORMAL |
, |
.f_first(f_rd_fifo_first), |
.f_mid( f_rd_fifo_mid), |
.f_last( f_rd_fifo_last) |
`endif |
); |
end else begin |
assign r_wb_cyc = 0; |
assign r_wb_stb = 0; |
assign r_wb_addr = 0; |
// |
assign o_axi_arready = 1'b1; |
assign o_axi_rvalid = (i_axi_arvalid)&&(o_axi_arready); |
assign o_axi_rresp = (i_axi_arvalid) ? 2'b11 : 2'b00; |
assign o_axi_rdata = 0; |
`ifdef FORMAL |
assign f_rd_fifo_first = 0; |
assign f_rd_fifo_mid = 0; |
assign f_rd_fifo_last = 0; |
`endif |
end endgenerate |
|
// |
// |
// The arbiter that pastes the two sides together |
// |
// |
generate if (OPT_READONLY) |
begin : ARB_RD |
assign o_wb_cyc = r_wb_cyc; |
assign o_wb_stb = r_wb_stb; |
assign o_wb_we = 1'b0; |
assign o_wb_addr = r_wb_addr; |
assign o_wb_data = 32'h0; |
assign o_wb_sel = 0; |
assign r_wb_ack = i_wb_ack; |
assign r_wb_stall= i_wb_stall; |
assign r_wb_ack = i_wb_ack; |
assign r_wb_err = i_wb_err; |
|
`ifdef FORMAL |
fwb_master #(.DW(DW), .AW(AW), |
.F_LGDEPTH(F_LGDEPTH), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY)) |
f_wb(i_clk, !i_axi_reset_n, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
assign f_wb_rd_nreqs = f_wb_nreqs; |
assign f_wb_rd_nacks = f_wb_nacks; |
assign f_wb_rd_outstanding = f_wb_outstanding; |
// |
assign f_wb_wr_nreqs = 0; |
assign f_wb_wr_nacks = 0; |
assign f_wb_wr_outstanding = 0; |
`endif |
end else if (OPT_WRITEONLY) |
begin : ARB_WR |
assign o_wb_cyc = w_wb_cyc; |
assign o_wb_stb = w_wb_stb; |
assign o_wb_we = 1'b1; |
assign o_wb_addr = w_wb_addr; |
assign o_wb_data = w_wb_data; |
assign o_wb_sel = w_wb_sel; |
assign w_wb_ack = i_wb_ack; |
assign w_wb_stall= i_wb_stall; |
assign w_wb_ack = i_wb_ack; |
assign w_wb_err = i_wb_err; |
|
`ifdef FORMAL |
fwb_master #(.DW(DW), .AW(AW), |
.F_LGDEPTH(F_LGDEPTH), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY)) |
f_wb(i_clk, !i_axi_reset_n, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
assign f_wb_wr_nreqs = f_wb_nreqs; |
assign f_wb_wr_nacks = f_wb_nacks; |
assign f_wb_wr_outstanding = f_wb_outstanding; |
// |
assign f_wb_rd_nreqs = 0; |
assign f_wb_rd_nacks = 0; |
assign f_wb_rd_outstanding = 0; |
`endif |
end else begin : ARB_WB |
wbarbiter #(.DW(DW), .AW(AW), |
.F_LGDEPTH(F_LGDEPTH), |
.F_MAX_STALL(F_MAXSTALL), |
.F_MAX_ACK_DELAY(F_MAXDELAY)) |
readorwrite(i_clk, !i_axi_reset_n, |
r_wb_cyc, r_wb_stb, 1'b0, r_wb_addr, w_wb_data, w_wb_sel, |
r_wb_ack, r_wb_stall, r_wb_err, |
w_wb_cyc, w_wb_stb, 1'b1, w_wb_addr, w_wb_data, w_wb_sel, |
w_wb_ack, w_wb_stall, w_wb_err, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel, |
i_wb_ack, i_wb_stall, i_wb_err |
`ifdef FORMAL |
, |
f_wb_rd_nreqs, f_wb_rd_nacks, f_wb_rd_outstanding, |
f_wb_wr_nreqs, f_wb_wr_nacks, f_wb_wr_outstanding, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding |
`endif |
); |
end endgenerate |
|
assign o_reset = (i_axi_reset_n == 1'b0); |
|
`ifdef FORMAL |
reg f_past_valid; |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid = 1'b1; |
|
initial assume(!i_axi_reset_n); |
always @(*) |
if (!f_past_valid) |
assume(!i_axi_reset_n); |
|
wire [(F_LGDEPTH-1):0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
wire [(F_LGDEPTH-1):0] f_axi_rd_id_outstanding, |
f_axi_awr_id_outstanding, |
f_axi_wr_id_outstanding; |
wire [8:0] f_axi_wr_pending, |
f_axi_rd_count, |
f_axi_wr_count; |
|
faxil_slave #( |
// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_LGDEPTH(F_LGDEPTH), |
.F_AXI_MAXWAIT(0), |
.F_AXI_MAXDELAY(0)) |
f_axi(.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n), |
// AXI write address channnel |
.i_axi_awready(o_axi_awready), |
.i_axi_awaddr( i_axi_awaddr), |
.i_axi_awcache(i_axi_awcache), |
.i_axi_awprot( i_axi_awprot), |
.i_axi_awvalid(i_axi_awvalid), |
// AXI write data channel |
.i_axi_wready( o_axi_wready), |
.i_axi_wdata( i_axi_wdata), |
.i_axi_wstrb( i_axi_wstrb), |
.i_axi_wvalid( i_axi_wvalid), |
// AXI write acknowledgement channel |
.i_axi_bresp( o_axi_bresp), |
.i_axi_bvalid(o_axi_bvalid), |
.i_axi_bready(i_axi_bready), |
// AXI read address channel |
.i_axi_arready(o_axi_arready), |
.i_axi_araddr( i_axi_araddr), |
.i_axi_arcache(i_axi_arcache), |
.i_axi_arprot( i_axi_arprot), |
.i_axi_arvalid(i_axi_arvalid), |
// AXI read data return |
.i_axi_rresp( o_axi_rresp), |
.i_axi_rvalid( o_axi_rvalid), |
.i_axi_rdata( o_axi_rdata), |
.i_axi_rready( i_axi_rready), |
// Quantify where we are within a transaction |
.f_axi_rd_outstanding( f_axi_rd_outstanding), |
.f_axi_wr_outstanding( f_axi_wr_outstanding), |
.f_axi_awr_outstanding(f_axi_awr_outstanding)); |
|
wire f_axi_ard_req, f_axi_awr_req, f_axi_wr_req, |
f_axi_rd_ack, f_axi_wr_ack; |
|
assign f_axi_ard_req = (i_axi_arvalid)&&(o_axi_arready); |
assign f_axi_awr_req = (i_axi_awvalid)&&(o_axi_awready); |
assign f_axi_wr_req = (i_axi_wvalid)&&(o_axi_wready); |
assign f_axi_wr_ack = (o_axi_bvalid)&&(i_axi_bready); |
assign f_axi_rd_ack = (o_axi_rvalid)&&(i_axi_rready); |
|
wire [LGFIFO:0] f_awr_fifo_axi_used, |
f_dwr_fifo_axi_used, |
f_rd_fifo_axi_used, |
f_wr_fifo_wb_outstanding, |
f_rd_fifo_wb_outstanding; |
|
assign f_awr_fifo_axi_used = f_wr_fifo_first - f_wr_fifo_last; |
assign f_rd_fifo_axi_used = f_rd_fifo_first - f_rd_fifo_last; |
assign f_wr_fifo_wb_outstanding = f_wr_fifo_first - f_wr_fifo_last; |
assign f_rd_fifo_wb_outstanding = f_rd_fifo_first - f_rd_fifo_last; |
|
always @(*) |
begin |
assert(f_axi_rd_outstanding == f_rd_fifo_axi_used); |
assert(f_axi_awr_outstanding == f_awr_fifo_axi_used+ (f_pending_awvalid?1:0)); |
assert(f_axi_wr_outstanding == f_awr_fifo_axi_used+ (f_pending_wvalid?1:0)); |
end |
|
always @(*) |
if (OPT_READONLY) |
begin |
assert(f_axi_awr_outstanding == 0); |
assert(f_axi_wr_outstanding == 0); |
end |
|
always @(*) |
if (OPT_WRITEONLY) |
begin |
assert(f_axi_ard_outstanding == 0); |
end |
|
// |
initial assert((!OPT_READONLY)||(!OPT_WRITEONLY)); |
|
always @(*) |
if (OPT_READONLY) |
begin |
assume(i_axi_awvalid == 0); |
assume(i_axi_wvalid == 0); |
|
assert(o_axi_bvalid == 0); |
end |
|
always @(*) |
if (OPT_WRITEONLY) |
begin |
assume(i_axi_arvalid == 0); |
assert(o_axi_rvalid == 0); |
end |
`endif |
endmodule |
|
/trunk/rtl/demoaxi.v
0,0 → 1,703
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: demoaxi.v |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: Demonstrate an AXI-lite bus design. The goal of this design |
// is to support a completely pipelined AXI-lite transaction |
// which can transfer one data item per clock. |
// |
// Note that the AXI spec requires that there be no combinatorial |
// logic between input ports and output ports. Hence all of the *valid |
// and *ready signals produced here are registered. This forces us into |
// the buffered handshake strategy. |
// |
// Some curious variable meanings below: |
// |
// !axi_arvalid is synonymous with having a request, but stalling because |
// of a current request sitting in axi_rvalid with !axi_rready |
// !axi_awvalid is also synonymous with having an axi address being |
// received, but either the axi_bvalid && !axi_bready, or |
// no write data has been received |
// !axi_wvalid is similar to axi_awvalid. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2018-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
|
`timescale 1 ns / 1 ps |
|
module demoaxi |
#( |
// Users to add parameters here |
parameter [0:0] OPT_READ_SIDEEFFECTS = 1, |
// User parameters ends |
// Do not modify the parameters beyond this line |
// Width of S_AXI data bus |
parameter integer C_S_AXI_DATA_WIDTH = 32, |
// Width of S_AXI address bus |
parameter integer C_S_AXI_ADDR_WIDTH = 8 |
) ( |
// Users to add ports here |
// No user ports (yet) in this design |
// User ports ends |
|
// Do not modify the ports beyond this line |
// Global Clock Signal |
input wire S_AXI_ACLK, |
// Global Reset Signal. This Signal is Active LOW |
input wire S_AXI_ARESETN, |
// Write address (issued by master, acceped by Slave) |
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, |
// Write channel Protection type. This signal indicates the |
// privilege and security level of the transaction, and whether |
// the transaction is a data access or an instruction access. |
input wire [2 : 0] S_AXI_AWPROT, |
// Write address valid. This signal indicates that the master |
// signaling valid write address and control information. |
input wire S_AXI_AWVALID, |
// Write address ready. This signal indicates that the slave |
// is ready to accept an address and associated control signals. |
output wire S_AXI_AWREADY, |
// Write data (issued by master, acceped by Slave) |
input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, |
// Write strobes. This signal indicates which byte lanes hold |
// valid data. There is one write strobe bit for each eight |
// bits of the write data bus. |
input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, |
// Write valid. This signal indicates that valid write |
// data and strobes are available. |
input wire S_AXI_WVALID, |
// Write ready. This signal indicates that the slave |
// can accept the write data. |
output wire S_AXI_WREADY, |
// Write response. This signal indicates the status |
// of the write transaction. |
output wire [1 : 0] S_AXI_BRESP, |
// Write response valid. This signal indicates that the channel |
// is signaling a valid write response. |
output wire S_AXI_BVALID, |
// Response ready. This signal indicates that the master |
// can accept a write response. |
input wire S_AXI_BREADY, |
// Read address (issued by master, acceped by Slave) |
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, |
// Protection type. This signal indicates the privilege |
// and security level of the transaction, and whether the |
// transaction is a data access or an instruction access. |
input wire [2 : 0] S_AXI_ARPROT, |
// Read address valid. This signal indicates that the channel |
// is signaling valid read address and control information. |
input wire S_AXI_ARVALID, |
// Read address ready. This signal indicates that the slave is |
// ready to accept an address and associated control signals. |
output wire S_AXI_ARREADY, |
// Read data (issued by slave) |
output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, |
// Read response. This signal indicates the status of the |
// read transfer. |
output wire [1 : 0] S_AXI_RRESP, |
// Read valid. This signal indicates that the channel is |
// signaling the required read data. |
output wire S_AXI_RVALID, |
// Read ready. This signal indicates that the master can |
// accept the read data and response information. |
input wire S_AXI_RREADY |
); |
|
// AXI4LITE signals |
reg axi_awready; |
reg axi_wready; |
reg [1 : 0] axi_bresp; |
reg axi_bvalid; |
reg axi_arready; |
reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; |
reg [1 : 0] axi_rresp; |
reg axi_rvalid; |
|
// Example-specific design signals |
// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH |
// ADDR_LSB is used for addressing 32/64 bit registers/memories |
// ADDR_LSB = 2 for 32 bits (n downto 2) |
// ADDR_LSB = 3 for 64 bits (n downto 3) |
localparam integer ADDR_LSB = 2; |
localparam integer AW = C_S_AXI_ADDR_WIDTH-2; |
localparam integer DW = C_S_AXI_DATA_WIDTH; |
//---------------------------------------------- |
//-- Signals for user logic register space example |
//------------------------------------------------ |
reg [DW-1:0] slv_mem [0:63]; |
|
// I/O Connections assignments |
|
assign S_AXI_AWREADY = axi_awready; |
assign S_AXI_WREADY = axi_wready; |
assign S_AXI_BRESP = axi_bresp; |
assign S_AXI_BVALID = axi_bvalid; |
assign S_AXI_ARREADY = axi_arready; |
assign S_AXI_RDATA = axi_rdata; |
assign S_AXI_RRESP = axi_rresp; |
assign S_AXI_RVALID = axi_rvalid; |
// Implement axi_*wready generation |
|
////////////////////////////////////// |
// |
// Read processing |
// |
// |
initial axi_rvalid = 1'b0; |
always @( posedge S_AXI_ACLK ) |
if (!S_AXI_ARESETN) |
axi_rvalid <= 0; |
else if (S_AXI_ARVALID) |
axi_rvalid <= 1'b1; |
else if ((S_AXI_RVALID)&&(!S_AXI_RREADY)) |
axi_rvalid <= 1'b1; |
else if (!axi_arready) |
axi_rvalid <= 1'b1; |
else |
axi_rvalid <= 1'b0; |
|
always @(*) |
axi_rresp = 0; // "OKAY" response |
|
reg [C_S_AXI_ADDR_WIDTH-1 : 0] dly_addr, rd_addr; |
|
always @(posedge S_AXI_ACLK) |
if (S_AXI_ARREADY) |
dly_addr <= S_AXI_ARADDR; |
|
always @(*) |
if (!axi_arready) |
rd_addr = dly_addr; |
else |
rd_addr = S_AXI_ARADDR; |
|
always @(posedge S_AXI_ACLK) |
if (((!S_AXI_RVALID)||(S_AXI_RREADY)) |
&&(!OPT_READ_SIDEEFFECTS |
||(!S_AXI_ARREADY || S_AXI_ARVALID))) |
// If the outgoing channel is not stalled (above) |
// then read |
axi_rdata <= slv_mem[rd_addr[AW+ADDR_LSB-1:ADDR_LSB]]; |
|
initial axi_arready = 1'b0; |
always @(posedge S_AXI_ACLK) |
if (!S_AXI_ARESETN) |
axi_arready <= 1'b1; |
else if ((S_AXI_RVALID)&&(!S_AXI_RREADY)) |
begin |
// Outgoing channel is stalled |
if (!axi_arready) |
// If something is already in the buffer, |
// axi_arready needs to stay low |
axi_arready <= 1'b0; |
else |
axi_arready <= (!S_AXI_ARVALID); |
end else |
axi_arready <= 1'b1; |
|
////////////////////////////////////// |
// |
// Write processing |
// |
// |
reg [C_S_AXI_ADDR_WIDTH-1 : 0] pre_waddr, waddr; |
reg [C_S_AXI_DATA_WIDTH-1 : 0] pre_wdata, wdata; |
reg [(C_S_AXI_DATA_WIDTH/8)-1 : 0] pre_wstrb, wstrb; |
|
// |
// The write address channel ready signal |
// |
initial axi_awready = 1'b1; |
always @(posedge S_AXI_ACLK) |
if (!S_AXI_ARESETN) |
axi_awready <= 1'b1; |
else if ((S_AXI_BVALID)&&(!S_AXI_BREADY)) |
begin |
// The output channel is stalled |
if (!axi_awready) |
// If our buffer is full, remain stalled |
axi_awready <= 1'b0; |
else |
// If the buffer is empty, accept one transaction |
// to fill it and then stall |
axi_awready <= (!S_AXI_AWVALID); |
end else if ((!axi_wready)||((S_AXI_WVALID)&&(S_AXI_WREADY))) |
// The output channel is clear, and write data |
// are available |
axi_awready <= 1'b1; |
else |
// If we were ready before, then remain ready unless an |
// address unaccompanied by data shows up |
axi_awready <= ((axi_awready)&&(!S_AXI_AWVALID)); |
|
// |
// The write data channel ready signal |
// |
initial axi_wready = 1'b1; |
always @(posedge S_AXI_ACLK) |
if (!S_AXI_ARESETN) |
axi_wready <= 1'b1; |
else if ((S_AXI_BVALID)&&(!S_AXI_BREADY)) |
begin |
// The output channel is stalled |
if (!axi_wready) |
axi_wready <= 1'b0; |
else |
axi_wready <= (!S_AXI_WVALID); |
end else if ((!axi_awready)||((S_AXI_AWVALID)&&(S_AXI_AWREADY))) |
// The output channel is clear, and a write address |
// is available |
axi_wready <= 1'b1; |
else |
// if we were ready before, and there's no new data avaialble |
// to cause us to stall, remain ready |
axi_wready <= (axi_wready)&&(!S_AXI_WVALID); |
|
|
// Buffer the address |
always @(posedge S_AXI_ACLK) |
if ((S_AXI_AWREADY)&&(S_AXI_AWVALID)) |
pre_waddr <= S_AXI_AWADDR; |
|
// Buffer the data |
always @(posedge S_AXI_ACLK) |
if ((S_AXI_WREADY)&&(S_AXI_WVALID)) |
begin |
pre_wdata <= S_AXI_WDATA; |
pre_wstrb <= S_AXI_WSTRB; |
end |
|
always @(*) |
if (!axi_awready) |
// Read the write address from our "buffer" |
waddr = pre_waddr; |
else |
waddr = S_AXI_AWADDR; |
|
always @(*) |
if (!axi_wready) |
begin |
// Read the write data from our "buffer" |
wstrb = pre_wstrb; |
wdata = pre_wdata; |
end else begin |
wstrb = S_AXI_WSTRB; |
wdata = S_AXI_WDATA; |
end |
|
|
always @( posedge S_AXI_ACLK ) |
// If the output channel isn't stalled, and |
if (((!S_AXI_BVALID)||(S_AXI_BREADY)) |
// If we have a valid address, and |
&&((!axi_awready)||(S_AXI_AWVALID)) |
// If we have valid data |
&&((!axi_wready)||((S_AXI_WVALID)))) |
begin |
if (wstrb[0]) |
slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][7:0] |
<= wdata[7:0]; |
if (wstrb[1]) |
slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][15:8] |
<= wdata[15:8]; |
if (wstrb[2]) |
slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][23:16] |
<= wdata[23:16]; |
if (wstrb[3]) |
slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][31:24] |
<= wdata[31:24]; |
end |
|
initial axi_bvalid = 1'b0; |
always @( posedge S_AXI_ACLK ) |
if (!S_AXI_ARESETN) |
axi_bvalid <= 1'b0; |
// |
// The outgoing response channel should indicate a valid write if ... |
// 1. We have a valid address, and |
else if (((!axi_awready)||(S_AXI_AWVALID)) |
// 2. We had valid data |
&&((!axi_wready)||((S_AXI_WVALID)))) |
// It doesn't matter here if we are stalled or not |
// We can keep setting ready as often as we want |
axi_bvalid <= 1'b1; |
else if (S_AXI_BREADY) |
axi_bvalid <= 1'b0; |
|
always @(*) |
axi_bresp = 2'b0; // "OKAY" response |
|
// Make Verilator happy |
// Verilator lint_off UNUSED |
wire [5*ADDR_LSB+5:0] unused; |
assign unused = { S_AXI_AWPROT, S_AXI_ARPROT, |
S_AXI_AWADDR[ADDR_LSB-1:0], |
dly_addr[ADDR_LSB-1:0], |
rd_addr[ADDR_LSB-1:0], |
waddr[ADDR_LSB-1:0], |
S_AXI_ARADDR[ADDR_LSB-1:0] }; |
// Verilator lint_on UNUSED |
|
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
`ifdef FORMAL |
localparam F_LGDEPTH = 4; |
|
wire [(F_LGDEPTH-1):0] f_axi_awr_outstanding, |
f_axi_wr_outstanding, |
f_axi_rd_outstanding; |
|
faxil_slave #(// .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH), |
// .F_OPT_NO_READS(1'b0), |
// .F_OPT_NO_WRITES(1'b0), |
.F_LGDEPTH(F_LGDEPTH)) |
properties ( |
.i_clk(S_AXI_ACLK), |
.i_axi_reset_n(S_AXI_ARESETN), |
// |
.i_axi_awaddr(S_AXI_AWADDR), |
.i_axi_awcache(4'h0), |
.i_axi_awprot(S_AXI_AWPROT), |
.i_axi_awvalid(S_AXI_AWVALID), |
.i_axi_awready(S_AXI_AWREADY), |
// |
.i_axi_wdata(S_AXI_WDATA), |
.i_axi_wstrb(S_AXI_WSTRB), |
.i_axi_wvalid(S_AXI_WVALID), |
.i_axi_wready(S_AXI_WREADY), |
// |
.i_axi_bresp(S_AXI_BRESP), |
.i_axi_bvalid(S_AXI_BVALID), |
.i_axi_bready(S_AXI_BREADY), |
// |
.i_axi_araddr(S_AXI_ARADDR), |
.i_axi_arprot(S_AXI_ARPROT), |
.i_axi_arcache(4'h0), |
.i_axi_arvalid(S_AXI_ARVALID), |
.i_axi_arready(S_AXI_ARREADY), |
// |
.i_axi_rdata(S_AXI_RDATA), |
.i_axi_rresp(S_AXI_RRESP), |
.i_axi_rvalid(S_AXI_RVALID), |
.i_axi_rready(S_AXI_RREADY), |
// |
.f_axi_rd_outstanding(f_axi_rd_outstanding), |
.f_axi_wr_outstanding(f_axi_wr_outstanding), |
.f_axi_awr_outstanding(f_axi_awr_outstanding)); |
|
reg f_past_valid; |
initial f_past_valid = 1'b0; |
always @(posedge S_AXI_ACLK) |
f_past_valid <= 1'b1; |
|
/////// |
// |
// Properties necessary to pass induction |
always @(*) |
if (S_AXI_ARESETN) |
begin |
if (!S_AXI_RVALID) |
assert(f_axi_rd_outstanding == 0); |
else if (!S_AXI_ARREADY) |
assert((f_axi_rd_outstanding == 2)||(f_axi_rd_outstanding == 1)); |
else |
assert(f_axi_rd_outstanding == 1); |
end |
|
always @(*) |
if (S_AXI_ARESETN) |
begin |
if (axi_bvalid) |
begin |
assert(f_axi_awr_outstanding == 1+(axi_awready ? 0:1)); |
assert(f_axi_wr_outstanding == 1+(axi_wready ? 0:1)); |
end else begin |
assert(f_axi_awr_outstanding == (axi_awready ? 0:1)); |
assert(f_axi_wr_outstanding == (axi_wready ? 0:1)); |
end |
end |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// Cover properties |
// |
// In addition to making sure the design returns a value, any value, |
// let's cover returning three values on adjacent clocks--just to prove |
// we can. |
// |
//////////////////////////////////////////////////////////////////////// |
// |
// |
always @( posedge S_AXI_ACLK ) |
if ((f_past_valid)&&(S_AXI_ARESETN)) |
cover(($past((S_AXI_BVALID && S_AXI_BREADY))) |
&&($past((S_AXI_BVALID && S_AXI_BREADY),2)) |
&&(S_AXI_BVALID && S_AXI_BREADY)); |
|
always @( posedge S_AXI_ACLK ) |
if ((f_past_valid)&&(S_AXI_ARESETN)) |
cover(($past((S_AXI_RVALID && S_AXI_RREADY))) |
&&($past((S_AXI_RVALID && S_AXI_RREADY),2)) |
&&(S_AXI_RVALID && S_AXI_RREADY)); |
|
// Let's go just one further, and verify we can do three returns in a |
// row. Why? It might just be possible that one value was waiting |
// already, and so we haven't yet tested that two requests could be |
// made in a row. |
always @( posedge S_AXI_ACLK ) |
if ((f_past_valid)&&(S_AXI_ARESETN)) |
cover(($past((S_AXI_BVALID && S_AXI_BREADY))) |
&&($past((S_AXI_BVALID && S_AXI_BREADY),2)) |
&&($past((S_AXI_BVALID && S_AXI_BREADY),3)) |
&&(S_AXI_BVALID && S_AXI_BREADY)); |
|
always @( posedge S_AXI_ACLK ) |
if ((f_past_valid)&&(S_AXI_ARESETN)) |
cover(($past((S_AXI_RVALID && S_AXI_RREADY))) |
&&($past((S_AXI_RVALID && S_AXI_RREADY),2)) |
&&($past((S_AXI_RVALID && S_AXI_RREADY),3)) |
&&(S_AXI_RVALID && S_AXI_RREADY)); |
|
// |
// Let's create a sophisticated cover statement designed to show off |
// how our core can handle stalls and non-valids, synchronizing |
// across multiple scenarios |
reg [22:0] fw_wrdemo_pipe, fr_wrdemo_pipe; |
always @(*) |
if (!S_AXI_ARESETN) |
fw_wrdemo_pipe = 0; |
else begin |
fw_wrdemo_pipe[0] = (S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[1] = fr_wrdemo_pipe[0] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[2] = fr_wrdemo_pipe[1] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
// |
// |
fw_wrdemo_pipe[3] = fr_wrdemo_pipe[2] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[4] = fr_wrdemo_pipe[3] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[5] = fr_wrdemo_pipe[4] |
&&(!S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[6] = fr_wrdemo_pipe[5] |
&&(S_AXI_AWVALID) |
&&( S_AXI_WVALID) |
&&( S_AXI_BREADY); |
fw_wrdemo_pipe[7] = fr_wrdemo_pipe[6] |
&&(!S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&( S_AXI_BREADY); |
fw_wrdemo_pipe[8] = fr_wrdemo_pipe[7] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[9] = fr_wrdemo_pipe[8] |
// &&(S_AXI_AWVALID) |
// &&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[10] = fr_wrdemo_pipe[9] |
// &&(S_AXI_AWVALID) |
// &&(S_AXI_WVALID) |
// &&(S_AXI_BREADY); |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[11] = fr_wrdemo_pipe[10] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(!S_AXI_BREADY); |
fw_wrdemo_pipe[12] = fr_wrdemo_pipe[11] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[13] = fr_wrdemo_pipe[12] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[14] = fr_wrdemo_pipe[13] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(f_axi_awr_outstanding == 0) |
&&(f_axi_wr_outstanding == 0) |
&&(S_AXI_BREADY); |
// |
// |
// |
fw_wrdemo_pipe[15] = fr_wrdemo_pipe[14] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[16] = fr_wrdemo_pipe[15] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[17] = fr_wrdemo_pipe[16] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[18] = fr_wrdemo_pipe[17] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(!S_AXI_BREADY); |
fw_wrdemo_pipe[19] = fr_wrdemo_pipe[18] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[20] = fr_wrdemo_pipe[19] |
&&(S_AXI_AWVALID) |
&&(S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[21] = fr_wrdemo_pipe[20] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
fw_wrdemo_pipe[22] = fr_wrdemo_pipe[21] |
&&(!S_AXI_AWVALID) |
&&(!S_AXI_WVALID) |
&&(S_AXI_BREADY); |
end |
|
always @(posedge S_AXI_ACLK) |
fr_wrdemo_pipe <= fw_wrdemo_pipe; |
|
always @(*) |
if (S_AXI_ARESETN) |
begin |
cover(fw_wrdemo_pipe[0]); |
cover(fw_wrdemo_pipe[1]); |
cover(fw_wrdemo_pipe[2]); |
cover(fw_wrdemo_pipe[3]); |
cover(fw_wrdemo_pipe[4]); |
cover(fw_wrdemo_pipe[5]); |
cover(fw_wrdemo_pipe[6]); |
cover(fw_wrdemo_pipe[7]); // |
cover(fw_wrdemo_pipe[8]); |
cover(fw_wrdemo_pipe[9]); |
cover(fw_wrdemo_pipe[10]); |
cover(fw_wrdemo_pipe[11]); |
cover(fw_wrdemo_pipe[12]); |
cover(fw_wrdemo_pipe[13]); |
cover(fw_wrdemo_pipe[14]); |
cover(fw_wrdemo_pipe[15]); |
cover(fw_wrdemo_pipe[16]); |
cover(fw_wrdemo_pipe[17]); |
cover(fw_wrdemo_pipe[18]); |
cover(fw_wrdemo_pipe[19]); |
cover(fw_wrdemo_pipe[20]); |
cover(fw_wrdemo_pipe[21]); |
cover(fw_wrdemo_pipe[22]); |
end |
|
// |
// Now let's repeat, but for a read demo |
reg [10:0] fw_rddemo_pipe, fr_rddemo_pipe; |
always @(*) |
if (!S_AXI_ARESETN) |
fw_rddemo_pipe = 0; |
else begin |
fw_rddemo_pipe[0] = (S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[1] = fr_rddemo_pipe[0] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[2] = fr_rddemo_pipe[1] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
// |
// |
fw_rddemo_pipe[3] = fr_rddemo_pipe[2] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[4] = fr_rddemo_pipe[3] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[5] = fr_rddemo_pipe[4] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[6] = fr_rddemo_pipe[5] |
&&(S_AXI_ARVALID) |
&&(!S_AXI_RREADY); |
fw_rddemo_pipe[7] = fr_rddemo_pipe[6] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[8] = fr_rddemo_pipe[7] |
&&(S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[9] = fr_rddemo_pipe[8] |
&&(!S_AXI_ARVALID) |
&&(S_AXI_RREADY); |
fw_rddemo_pipe[10] = fr_rddemo_pipe[9] |
&&(f_axi_rd_outstanding == 0); |
end |
|
initial fr_rddemo_pipe = 0; |
always @(posedge S_AXI_ACLK) |
fr_rddemo_pipe <= fw_rddemo_pipe; |
|
always @(*) |
begin |
cover(fw_rddemo_pipe[0]); |
cover(fw_rddemo_pipe[1]); |
cover(fw_rddemo_pipe[2]); |
cover(fw_rddemo_pipe[3]); |
cover(fw_rddemo_pipe[4]); |
cover(fw_rddemo_pipe[5]); |
cover(fw_rddemo_pipe[6]); |
cover(fw_rddemo_pipe[7]); |
cover(fw_rddemo_pipe[8]); |
cover(fw_rddemo_pipe[9]); |
cover(fw_rddemo_pipe[10]); |
end |
`endif |
endmodule |
/trunk/rtl/migsdram.v
24,25 → 24,28
// |
// Copyright (C) 2015-2017, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
/trunk/rtl/wbarbiter.v
6,37 → 6,58
// |
// Purpose: This is a priority bus arbiter. It allows two separate wishbone |
// masters to connect to the same bus, while also guaranteeing |
// that one master can have the bus with no delay any time the other |
// master is not using the bus. The goal is to eliminate as much |
// combinatorial logic as possible, while still guarateeing minimum access |
// time for the priority (last, or alternate) channel. |
// that the last master can have the bus with no delay any time it is |
// idle. The goal is to minimize the combinatorial logic required in this |
// process, while still minimizing access time. |
// |
// The core logic works like this: |
// |
// 1. If 'A' or 'B' asserts the o_cyc line, a bus cycle will begin, |
// with acccess granted to whomever requested it. |
// 2. If both 'A' and 'B' assert o_cyc at the same time, only 'A' |
// will be granted the bus. (If the alternating parameter |
// is set, A and B will alternate who gets the bus in |
// this case.) |
// 3. The bus will remain owned by whomever the bus was granted to |
// until they deassert the o_cyc line. |
// 4. At the end of a bus cycle, o_cyc is guaranteed to be |
// deasserted (low) for one clock. |
// 5. On the next clock, bus arbitration takes place again. If |
// 'A' requests the bus, no matter how long 'B' was |
// waiting, 'A' will then be granted the bus. (Unless |
// again the alternating parameter is set, then the |
// access is guaranteed to switch to B.) |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015,2017, Gisselquist Technology, LLC |
// Copyright (C) 2015-2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
52,13 → 73,20
i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel, |
o_b_ack, o_b_stall, o_b_err, |
// Combined/arbitrated bus |
o_cyc, o_stb, o_we, o_adr, o_dat, o_sel, i_ack, i_stall, i_err); |
o_cyc, o_stb, o_we, o_adr, o_dat, o_sel, i_ack, i_stall, i_err |
`ifdef FORMAL |
, |
f_a_nreqs, f_a_nacks, f_a_outstanding, |
f_b_nreqs, f_b_nacks, f_b_outstanding, |
f_nreqs, f_nacks, f_outstanding |
`endif |
); |
parameter DW=32, AW=32; |
parameter SCHEME="ALTERNATING"; |
parameter [0:0] OPT_ZERO_ON_IDLE = 1'b0; |
`ifdef FORMAL |
parameter F_MAX_STALL = 3; |
parameter F_MAX_ACK_DELAY = 3; |
parameter F_LGDEPTH=3; |
`endif |
|
// |
input wire i_clk, i_reset; |
80,6 → 108,12
output wire [(DW-1):0] o_dat; |
output wire [(DW/8-1):0] o_sel; |
input wire i_ack, i_stall, i_err; |
// |
`ifdef FORMAL |
output wire [(F_LGDEPTH-1):0] f_nreqs, f_nacks, f_outstanding, |
f_a_nreqs, f_a_nacks, f_a_outstanding, |
f_b_nreqs, f_b_nacks, f_b_outstanding; |
`endif |
|
// Go high immediately (new cycle) if ... |
// Previous cycle was low and *someone* is requesting a bus cycle |
202,13 → 236,7
`ifdef FORMAL |
|
`ifdef WBARBITER |
reg f_last_clk; |
initial assume(!i_clk); |
always @($global_clock) |
begin |
assume(i_clk != f_last_clk); |
f_last_clk <= i_clk; |
end |
|
`define ASSUME assume |
`else |
`define ASSUME assert |
216,7 → 244,7
|
reg f_past_valid; |
initial f_past_valid = 1'b0; |
always @($global_clock) |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
initial `ASSUME(!i_a_cyc); |
228,6 → 256,10
initial `ASSUME(!i_ack); |
initial `ASSUME(!i_err); |
|
always @(*) |
if (!f_past_valid) |
`ASSUME(i_reset); |
|
always @(posedge i_clk) |
begin |
if (o_cyc) |
236,14 → 268,10
assert($past(r_a_owner) == r_a_owner); |
end |
|
wire [(F_LGDEPTH-1):0] f_nreqs, f_nacks, f_outstanding, |
f_a_nreqs, f_a_nacks, f_a_outstanding, |
f_b_nreqs, f_b_nacks, f_b_outstanding; |
|
fwb_master #(.DW(DW), .AW(AW), |
.F_MAX_STALL(0), |
.F_MAX_STALL(F_MAX_STALL), |
.F_LGDEPTH(F_LGDEPTH), |
.F_MAX_ACK_DELAY(0), |
.F_MAX_ACK_DELAY(F_MAX_ACK_DELAY), |
.F_OPT_RMW_BUS_OPTION(1), |
.F_OPT_DISCONTINUOUS(1)) |
f_wbm(i_clk, i_reset, |
298,6 → 326,40
if ((f_past_valid)&&(r_a_owner != $past(r_a_owner))) |
assert(!$past(o_cyc)); |
|
reg f_prior_a_ack, f_prior_b_ack; |
|
initial f_prior_a_ack = 1'b0; |
always @(posedge i_clk) |
if ((i_reset)||(o_a_err)||(o_b_err)) |
f_prior_a_ack = 1'b0; |
else if ((o_cyc)&&(o_a_ack)) |
f_prior_a_ack <= 1'b1; |
|
initial f_prior_b_ack = 1'b0; |
always @(posedge i_clk) |
if ((i_reset)||(o_a_err)||(o_b_err)) |
f_prior_b_ack = 1'b0; |
else if ((o_cyc)&&(o_b_ack)) |
f_prior_b_ack <= 1'b1; |
|
always @(posedge i_clk) |
begin |
cover(f_prior_b_ack && o_cyc && o_a_ack); |
|
cover((o_cyc && o_a_ack) |
&&($past(o_cyc && o_a_ack)) |
&&($past(o_cyc && o_a_ack,2))); |
|
|
cover(f_prior_a_ack && o_cyc && o_b_ack); |
|
cover((o_cyc && o_b_ack) |
&&($past(o_cyc && o_b_ack)) |
&&($past(o_cyc && o_b_ack,2))); |
end |
|
always @(*) |
cover(o_cyc && o_b_ack); |
`endif |
endmodule |
|
/trunk/rtl/wbm2axilite.v
0,0 → 1,636
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbm2axilite.v (Wishbone master to AXI slave, pipelined) |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: Convert from a wishbone master to an AXI lite interface. The |
// big difference is that AXI lite doesn't support bursting, |
// or transaction ID's. This actually makes the task a *LOT* easier. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2018-2019, Gisselquist Technology, LLC |
// |
// This file is part of the pipelined Wishbone to AXI converter project, a |
// project that contains multiple bus bridging designs and formal bus property |
// sets. |
// |
// The bus bridge designs and property sets are free RTL designs: you can |
// redistribute them and/or modify any of them under the terms of the GNU |
// Lesser General Public License as published by the Free Software Foundation, |
// either version 3 of the License, or (at your option) any later version. |
// |
// The bus bridge designs and property sets are distributed in the hope that |
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public License |
// along with these designs. (It's in the $(ROOT)/doc directory. Run make |
// with no target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: LGPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/lgpl.html |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module wbm2axilite ( |
i_clk, i_reset, |
// AXI write address channel signals |
i_axi_awready, o_axi_awaddr, o_axi_awcache, o_axi_awprot, o_axi_awvalid, |
// AXI write data channel signals |
i_axi_wready, o_axi_wdata, o_axi_wstrb, o_axi_wvalid, |
// AXI write response channel signals |
i_axi_bresp, i_axi_bvalid, o_axi_bready, |
// AXI read address channel signals |
i_axi_arready, o_axi_araddr, o_axi_arcache, o_axi_arprot, o_axi_arvalid, |
// AXI read data channel signals |
i_axi_rresp, i_axi_rvalid, i_axi_rdata, o_axi_rready, |
// We'll share the clock and the reset |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel, |
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err); |
|
localparam C_AXI_DATA_WIDTH = 32;// Width of the AXI R&W data |
parameter C_AXI_ADDR_WIDTH = 28;// AXI Address width |
localparam DW = C_AXI_DATA_WIDTH;// Wishbone data width |
parameter AW = C_AXI_ADDR_WIDTH-2;// WB addr width (log wordsize) |
input wire i_clk; // System clock |
input wire i_reset;// Reset signal,drives AXI rst |
|
// AXI write address channel signals |
input wire i_axi_awready;//Slave is ready to accept |
output reg [C_AXI_ADDR_WIDTH-1:0] o_axi_awaddr; // Write address |
output wire [3:0] o_axi_awcache; // Write Cache type |
output wire [2:0] o_axi_awprot; // Write Protection type |
output reg o_axi_awvalid; // Write address valid |
|
// AXI write data channel signals |
input wire i_axi_wready; // Write data ready |
output reg [C_AXI_DATA_WIDTH-1:0] o_axi_wdata; // Write data |
output reg [C_AXI_DATA_WIDTH/8-1:0] o_axi_wstrb; // Write strobes |
output reg o_axi_wvalid; // Write valid |
|
// AXI write response channel signals |
input wire [1:0] i_axi_bresp; // Write response |
input wire i_axi_bvalid; // Write reponse valid |
output wire o_axi_bready; // Response ready |
|
// AXI read address channel signals |
input wire i_axi_arready; // Read address ready |
output reg [C_AXI_ADDR_WIDTH-1:0] o_axi_araddr; // Read address |
output wire [3:0] o_axi_arcache; // Read Cache type |
output wire [2:0] o_axi_arprot; // Read Protection type |
output reg o_axi_arvalid; // Read address valid |
|
// AXI read data channel signals |
input wire [1:0] i_axi_rresp; // Read response |
input wire i_axi_rvalid; // Read reponse valid |
input wire [C_AXI_DATA_WIDTH-1:0] i_axi_rdata; // Read data |
output wire o_axi_rready; // Read Response ready |
|
// We'll share the clock and the reset |
input wire i_wb_cyc; |
input wire i_wb_stb; |
input wire i_wb_we; |
input wire [(AW-1):0] i_wb_addr; |
input wire [(DW-1):0] i_wb_data; |
input wire [(DW/8-1):0] i_wb_sel; |
output reg o_wb_ack; |
output wire o_wb_stall; |
output reg [(DW-1):0] o_wb_data; |
output reg o_wb_err; |
|
//***************************************************************************** |
// Local Parameter declarations |
//***************************************************************************** |
|
localparam LG_AXI_DW = ( C_AXI_DATA_WIDTH == 8) ? 3 |
: ((C_AXI_DATA_WIDTH == 16) ? 4 |
: ((C_AXI_DATA_WIDTH == 32) ? 5 |
: ((C_AXI_DATA_WIDTH == 64) ? 6 |
: ((C_AXI_DATA_WIDTH == 128) ? 7 |
: 8)))); |
|
localparam LG_WB_DW = ( DW == 8) ? 3 |
: ((DW == 16) ? 4 |
: ((DW == 32) ? 5 |
: ((DW == 64) ? 6 |
: ((DW == 128) ? 7 |
: 8)))); |
localparam LGFIFOLN = 5; |
localparam FIFOLN = (1<<LGFIFOLN); |
|
|
//***************************************************************************** |
// Internal register and wire declarations |
//***************************************************************************** |
|
// Things we're not changing ... |
assign o_axi_awcache = 4'h3; // Normal: no cache, no buffer |
assign o_axi_arcache = 4'h3; // Normal: no cache, no buffer |
assign o_axi_awprot = 3'b000; // Unpriviledged, unsecure, data access |
assign o_axi_arprot = 3'b000; // Unpriviledged, unsecure, data access |
|
reg full_fifo, err_state, axi_reset_state, wb_we; |
reg [3:0] reset_count; |
reg pending; |
reg [LGFIFOLN-1:0] outstanding, err_pending; |
|
|
// Master bridge logic |
assign o_wb_stall = (full_fifo) |
||((!i_wb_we)&&( wb_we)&&(pending)) |
||(( i_wb_we)&&(!wb_we)&&(pending)) |
||(err_state)||(axi_reset_state) |
||(o_axi_arvalid)&&(!i_axi_arready) |
||(o_axi_awvalid)&&(!i_axi_awready) |
||(o_axi_wvalid)&&(!i_axi_wready); |
|
initial axi_reset_state = 1'b1; |
initial reset_count = 4'hf; |
always @(posedge i_clk) |
if (i_reset) |
begin |
axi_reset_state <= 1'b1; |
if (reset_count > 0) |
reset_count <= reset_count - 1'b1; |
end else if ((axi_reset_state)&&(reset_count > 0)) |
reset_count <= reset_count - 1'b1; |
else begin |
axi_reset_state <= 1'b0; |
reset_count <= 4'hf; |
end |
|
// Count outstanding transactions |
initial pending = 0; |
initial outstanding = 0; |
always @(posedge i_clk) |
if ((i_reset)||(axi_reset_state)) |
begin |
pending <= 0; |
outstanding <= 0; |
full_fifo <= 0; |
end else if ((err_state)||(!i_wb_cyc)) |
begin |
pending <= 0; |
outstanding <= 0; |
full_fifo <= 0; |
end else case({ ((i_wb_stb)&&(!o_wb_stall)), (o_wb_ack) }) |
2'b01: begin |
outstanding <= outstanding - 1'b1; |
pending <= (outstanding >= 2); |
full_fifo <= 1'b0; |
end |
2'b10: begin |
outstanding <= outstanding + 1'b1; |
pending <= 1'b1; |
full_fifo <= (outstanding >= {{(LGFIFOLN-2){1'b1}},2'b01});; |
end |
default: begin end |
endcase |
|
always @(posedge i_clk) |
if ((i_wb_stb)&&(!o_wb_stall)) |
wb_we <= i_wb_we; |
|
// |
// |
// Write address logic |
// |
initial o_axi_awvalid = 0; |
always @(posedge i_clk) |
if (i_reset) |
o_axi_awvalid <= 0; |
else |
o_axi_awvalid <= (!o_wb_stall)&&(i_wb_stb)&&(i_wb_we) |
||(o_axi_awvalid)&&(!i_axi_awready); |
|
always @(posedge i_clk) |
if (!o_wb_stall) |
o_axi_awaddr <= { i_wb_addr, 2'b00 }; |
|
// |
// |
// Read address logic |
// |
initial o_axi_arvalid = 1'b0; |
always @(posedge i_clk) |
if (i_reset) |
o_axi_arvalid <= 1'b0; |
else |
o_axi_arvalid <= (!o_wb_stall)&&(i_wb_stb)&&(!i_wb_we) |
||((o_axi_arvalid)&&(!i_axi_arready)); |
always @(posedge i_clk) |
if (!o_wb_stall) |
o_axi_araddr <= { i_wb_addr, 2'b00 }; |
|
// |
// |
// Write data logic |
// |
always @(posedge i_clk) |
if (!o_wb_stall) |
begin |
o_axi_wdata <= i_wb_data; |
o_axi_wstrb <= i_wb_sel; |
end |
|
initial o_axi_wvalid = 0; |
always @(posedge i_clk) |
if (i_reset) |
o_axi_wvalid <= 0; |
else |
o_axi_wvalid <= ((!o_wb_stall)&&(i_wb_stb)&&(i_wb_we)) |
||((o_axi_wvalid)&&(!i_axi_wready)); |
|
initial o_wb_ack = 1'b0; |
always @(posedge i_clk) |
if ((i_reset)||(!i_wb_cyc)||(err_state)) |
o_wb_ack <= 1'b0; |
else if (err_state) |
o_wb_ack <= 1'b0; |
else if ((i_axi_bvalid)&&(!i_axi_bresp[1])) |
o_wb_ack <= 1'b1; |
else if ((i_axi_rvalid)&&(!i_axi_rresp[1])) |
o_wb_ack <= 1'b1; |
else |
o_wb_ack <= 1'b0; |
|
always @(posedge i_clk) |
o_wb_data <= i_axi_rdata; |
|
// Read data channel / response logic |
assign o_axi_rready = 1'b1; |
assign o_axi_bready = 1'b1; |
|
initial o_wb_err = 1'b0; |
always @(posedge i_clk) |
if ((i_reset)||(!i_wb_cyc)||(err_state)) |
o_wb_err <= 1'b0; |
else if ((i_axi_bvalid)&&(i_axi_bresp[1])) |
o_wb_err <= 1'b1; |
else if ((i_axi_rvalid)&&(i_axi_rresp[1])) |
o_wb_err <= 1'b1; |
else |
o_wb_err <= 1'b0; |
|
initial err_state = 1'b0; |
always @(posedge i_clk) |
if (i_reset) |
err_state <= 0; |
else if ((i_axi_bvalid)&&(i_axi_bresp[1])) |
err_state <= 1'b1; |
else if ((i_axi_rvalid)&&(i_axi_rresp[1])) |
err_state <= 1'b1; |
else if ((pending)&&(!i_wb_cyc)) |
err_state <= 1'b1; |
else if (err_pending == 0) |
err_state <= 0; |
|
initial err_pending = 0; |
always @(posedge i_clk) |
if (i_reset) |
err_pending <= 0; |
else case({ ((i_wb_stb)&&(!o_wb_stall)), |
((i_axi_bvalid)||(i_axi_rvalid)) }) |
2'b01: err_pending <= err_pending - 1'b1; |
2'b10: err_pending <= err_pending + 1'b1; |
default: begin end |
endcase |
|
// Make verilator happy |
// verilator lint_off UNUSED |
wire [2:0] unused; |
assign unused = { i_wb_cyc, i_axi_bresp[0], i_axi_rresp[0] }; |
// verilator lint_on UNUSED |
|
///////////////////////////////////////////////////////////////////////// |
// |
// |
// |
// Formal methods section |
// |
// These are only relevant when *proving* that this translator works |
// |
// |
// |
///////////////////////////////////////////////////////////////////////// |
`ifdef FORMAL |
reg f_past_valid; |
// |
`define ASSUME assume |
`define ASSERT assert |
|
// Parameters |
initial assert(DW == 32); |
initial assert(C_AXI_ADDR_WIDTH == AW+2); |
// |
|
// |
// Setup |
// |
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
always @(*) |
if (!f_past_valid) |
`ASSUME(i_reset); |
|
////////////////////////////////////////////// |
// |
// |
// Assumptions about the WISHBONE inputs |
// |
// |
////////////////////////////////////////////// |
assume property(f_past_valid || i_reset); |
|
wire [(LGFIFOLN-1):0] f_wb_nreqs, f_wb_nacks,f_wb_outstanding; |
fwb_slave #(.DW(DW),.AW(AW), |
.F_MAX_STALL(0), |
.F_MAX_ACK_DELAY(0), |
.F_LGDEPTH(LGFIFOLN), |
.F_MAX_REQUESTS(FIFOLN-2)) |
f_wb(i_clk, i_reset, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, |
i_wb_data, i_wb_sel, |
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
wire [(LGFIFOLN-1):0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
|
faxil_master #( |
// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_LGDEPTH(LGFIFOLN), |
.F_AXI_MAXWAIT(3), |
.F_OPT_HAS_CACHE(1'b1), |
.F_AXI_MAXDELAY(3)) |
f_axil(.i_clk(i_clk), |
.i_axi_reset_n((!i_reset)&&(!axi_reset_state)), |
// Write address channel |
.i_axi_awready(i_axi_awready), |
.i_axi_awaddr( o_axi_awaddr), |
.i_axi_awcache(o_axi_awcache), |
.i_axi_awprot( o_axi_awprot), |
.i_axi_awvalid(o_axi_awvalid), |
// Write data channel |
.i_axi_wready( i_axi_wready), |
.i_axi_wdata( o_axi_wdata), |
.i_axi_wstrb( o_axi_wstrb), |
.i_axi_wvalid( o_axi_wvalid), |
// Write response channel |
.i_axi_bresp( i_axi_bresp), |
.i_axi_bvalid( i_axi_bvalid), |
.i_axi_bready( o_axi_bready), |
// Read address channel |
.i_axi_arready(i_axi_arready), |
.i_axi_araddr( o_axi_araddr), |
.i_axi_arcache(o_axi_arcache), |
.i_axi_arprot( o_axi_arprot), |
.i_axi_arvalid(o_axi_arvalid), |
// Read data channel |
.i_axi_rresp( i_axi_rresp), |
.i_axi_rvalid( i_axi_rvalid), |
.i_axi_rdata( i_axi_rdata), |
.i_axi_rready( o_axi_rready), |
// Counts |
.f_axi_rd_outstanding( f_axi_rd_outstanding), |
.f_axi_wr_outstanding( f_axi_wr_outstanding), |
.f_axi_awr_outstanding( f_axi_awr_outstanding) |
); |
|
////////////////////////////////////////////// |
// |
// |
// Assumptions about the AXI inputs |
// |
// |
////////////////////////////////////////////// |
|
|
////////////////////////////////////////////// |
// |
// |
// Assertions about the AXI4 ouputs |
// |
// |
////////////////////////////////////////////// |
|
// Write response channel |
always @(posedge i_clk) |
// We keep bready high, so the other condition doesn't |
// need to be checked |
assert(o_axi_bready); |
|
// AXI read data channel signals |
always @(posedge i_clk) |
// We keep o_axi_rready high, so the other condition's |
// don't need to be checked here |
assert(o_axi_rready); |
|
// |
// Let's look into write requests |
// |
initial assert(!o_axi_awvalid); |
initial assert(!o_axi_wvalid); |
always @(posedge i_clk) |
if ((!f_past_valid)||($past(i_reset))||($past(axi_reset_state))) |
begin |
assert(!o_axi_awvalid); |
assert(!o_axi_wvalid); |
end |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset)) |
&&($past((i_wb_stb)&&(i_wb_we)&&(!o_wb_stall)))) |
begin |
// Following any write request that we accept, awvalid |
// and wvalid should both be true |
assert(o_axi_awvalid); |
assert(o_axi_wvalid); |
assert(wb_we); |
end else if ((f_past_valid)&&($past(i_reset))) |
begin |
if ($past(i_axi_awready)) |
assert(!o_axi_awvalid); |
if ($past(i_axi_wready)) |
assert(!o_axi_wvalid); |
end |
|
// |
// AXI write address channel |
// |
always @(posedge i_clk) |
if ((f_past_valid)&&($past((i_wb_stb)&&(i_wb_we)&&(!o_wb_stall)))) |
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:0]), 2'b00 }); |
|
// |
// AXI write data channel |
// |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb)&&(i_wb_we)&&(!$past(o_wb_stall)))) |
begin |
assert(o_axi_wdata == $past(i_wb_data)); |
assert(o_axi_wstrb == $past(i_wb_sel)); |
end |
|
// |
// AXI read address channel |
// |
initial assert(!o_axi_arvalid); |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset)) |
&&($past((i_wb_stb)&&(!i_wb_we)&&(!o_wb_stall)))) |
begin |
assert(o_axi_arvalid); |
assert(o_axi_araddr == { $past(i_wb_addr), 2'b00 }); |
end |
// |
|
// |
// AXI write response channel |
// |
|
// |
// AXI read data channel signals |
// |
always @(posedge i_clk) |
if ((f_past_valid)&&(($past(i_reset))||($past(axi_reset_state)))) |
begin |
// Relate err_pending to outstanding |
assert(outstanding == 0); |
assert(err_pending == 0); |
end else if (!err_state) |
assert(err_pending == outstanding - ((o_wb_ack)||(o_wb_err))); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(($past(i_reset))||($past(axi_reset_state)))) |
begin |
assert(f_axi_awr_outstanding == 0); |
assert(f_axi_wr_outstanding == 0); |
assert(f_axi_rd_outstanding == 0); |
|
assert(f_wb_outstanding == 0); |
assert(!pending); |
assert(outstanding == 0); |
assert(err_pending == 0); |
end else if (wb_we) |
begin |
case({o_axi_awvalid,o_axi_wvalid}) |
2'b00: begin |
`ASSERT(f_axi_awr_outstanding == err_pending); |
`ASSERT(f_axi_wr_outstanding == err_pending); |
end |
2'b01: begin |
`ASSERT(f_axi_awr_outstanding == err_pending); |
`ASSERT(f_axi_wr_outstanding +1 == err_pending); |
end |
2'b10: begin |
`ASSERT(f_axi_awr_outstanding+1 == err_pending); |
`ASSERT(f_axi_wr_outstanding == err_pending); |
end |
2'b11: begin |
`ASSERT(f_axi_awr_outstanding+1 == err_pending); |
`ASSERT(f_axi_wr_outstanding +1 == err_pending); |
end |
endcase |
|
// |
`ASSERT(!o_axi_arvalid); |
`ASSERT(f_axi_rd_outstanding == 0); |
end else begin |
if (!o_axi_arvalid) |
`ASSERT(f_axi_rd_outstanding == err_pending); |
else |
`ASSERT(f_axi_rd_outstanding+1 == err_pending); |
|
`ASSERT(!o_axi_awvalid); |
`ASSERT(!o_axi_wvalid); |
`ASSERT(f_axi_awr_outstanding == 0); |
`ASSERT(f_axi_wr_outstanding == 0); |
end |
|
always @(*) |
if ((!i_reset)&&(i_wb_cyc)&&(!err_state)) |
`ASSERT(f_wb_outstanding == outstanding); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(err_state)) |
`ASSERT((o_wb_err)||(f_wb_outstanding == 0)); |
|
always @(posedge i_clk) |
`ASSERT(pending == (outstanding != 0)); |
// |
// Make sure we only create one request at a time |
always @(posedge i_clk) |
`ASSERT((!o_axi_arvalid)||(!o_axi_wvalid)); |
always @(posedge i_clk) |
`ASSERT((!o_axi_arvalid)||(!o_axi_awvalid)); |
always @(posedge i_clk) |
if (wb_we) |
`ASSERT(!o_axi_arvalid); |
else |
`ASSERT((!o_axi_awvalid)&&(!o_axi_wvalid)); |
|
always @(*) |
if (&outstanding[LGFIFOLN-1:1]) |
`ASSERT(full_fifo); |
always @(*) |
assert(outstanding < {(LGFIFOLN){1'b1}}); |
|
// AXI cover results |
always @(*) |
cover(i_axi_bvalid && o_axi_bready); |
always @(*) |
cover(i_axi_rvalid && o_axi_rready); |
|
always @(posedge i_clk) |
cover(i_axi_bvalid && o_axi_bready |
&& $past(i_axi_bvalid && o_axi_bready) |
&& $past(i_axi_bvalid && o_axi_bready,2)); |
|
always @(posedge i_clk) |
cover(i_axi_rvalid && o_axi_rready |
&& $past(i_axi_rvalid && o_axi_rready) |
&& $past(i_axi_rvalid && o_axi_rready,2)); |
|
// AXI cover requests |
always @(posedge i_clk) |
cover(o_axi_arvalid && i_axi_arready |
&& $past(o_axi_arvalid && i_axi_arready) |
&& $past(o_axi_arvalid && i_axi_arready,2)); |
|
always @(posedge i_clk) |
cover(o_axi_awvalid && i_axi_awready |
&& $past(o_axi_awvalid && i_axi_awready) |
&& $past(o_axi_awvalid && i_axi_awready,2)); |
|
always @(posedge i_clk) |
cover(o_axi_wvalid && i_axi_wready |
&& $past(o_axi_wvalid && i_axi_wready) |
&& $past(o_axi_wvalid && i_axi_wready,2)); |
|
always @(*) |
cover(i_axi_rvalid && o_axi_rready); |
|
// Wishbone cover results |
always @(*) |
cover(i_wb_cyc && o_wb_ack); |
|
always @(posedge i_clk) |
cover(i_wb_cyc && o_wb_ack |
&& $past(o_wb_ack)&&$past(o_wb_ack,2)); |
|
`endif |
endmodule |
/trunk/rtl/wbm2axisp.v
28,7 → 28,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016-2018, Gisselquist Technology, LLC |
// Copyright (C) 2016-2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
61,7 → 61,7
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width (log wordsize) |
parameter DW = 32, // Wishbone data width |
parameter AW = 26, // Wishbone address width (log wordsize) |
parameter [0:0] STRICT_ORDER = 1 // Reorder, or not? 0 -> Reorder |
parameter [0:0] STRICT_ORDER = 1 // Reorder, or not? 0 -> Reorder |
) ( |
input wire i_clk, // System clock |
input wire i_reset,// Reset signal,drives AXI rst |
165,7 → 165,7
assign o_axi_awqos = 4'h0; // Lowest quality of service (unused) |
assign o_axi_arqos = 4'h0; // Lowest quality of service (unused) |
|
reg wb_mid_cycle, wb_mid_abort; |
reg wb_mid_cycle, wb_last_cyc_stb, wb_mid_abort, wb_cyc_stb; |
wire wb_abort; |
|
// Command logic |
411,7 → 411,6
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req, |
axi_rd_err, axi_wr_err; |
// verilator lint_on UNUSED |
|
// |
assign axi_ard_req = (o_axi_arvalid)&&(i_axi_arready); |
assign axi_awr_req = (o_axi_awvalid)&&(i_axi_awready); |
431,6 → 430,10
// reorder buffer as well, to place our out of order bus responses |
// back into order. Responses on the wishbone, however, are *always* |
// done in order. |
`ifdef FORMAL |
reg [31:0] reorder_count; |
`endif |
integer k; |
generate |
if (STRICT_ORDER == 0) |
begin |
488,6 → 491,32
end |
end |
|
`ifdef FORMAL |
always @(*) |
begin |
reorder_count = 0; |
for(k=0; k<FIFOLN; k=k+1) |
if (reorder_fifo_valid[k]) |
reorder_count = reorder_count + 1; |
end |
|
reg [(FIFOLN-1):0] f_reorder_fifo_valid_zerod, |
f_reorder_fifo_err_zerod; |
always @(*) |
f_reorder_fifo_valid_zerod <= |
((reorder_fifo_valid >> fifo_tail) |
| (reorder_fifo_valid << (FIFOLN-fifo_tail))); |
always @(*) |
assert((f_reorder_fifo_valid_zerod & (~((1<<f_fifo_used)-1)))==0); |
// |
always @(*) |
f_reorder_fifo_err_zerod <= |
((reorder_fifo_valid >> fifo_tail) |
| (reorder_fifo_valid << (FIFOLN-fifo_tail))); |
always @(*) |
assert((f_reorder_fifo_err_zerod & (~((1<<f_fifo_used)-1)))==0); |
`endif |
|
reg r_fifo_full; |
initial r_fifo_full = 0; |
always @(posedge i_clk) |
534,6 → 563,11
end |
end |
|
`ifdef FORMAL |
always @(*) |
reorder_count = (reorder_fifo_valid) ? 1 : 0; |
`endif |
|
initial fifo_tail = 0; |
always @(posedge i_clk) |
if (i_reset) |
573,11 → 607,6
end |
|
assign w_fifo_full = r_fifo_full; |
|
// verilator lint_off UNUSED |
wire [2*C_AXI_ID_WIDTH-1:0] strict_unused; |
assign strict_unused = { i_axi_bid, i_axi_rid }; |
// verilator lint_on UNUSED |
end endgenerate |
|
// |
584,6 → 613,14
// Wishbone abort logic |
// |
|
// Did we just accept something? |
initial wb_cyc_stb = 1'b0; |
always @(posedge i_clk) |
if (i_reset) |
wb_cyc_stb <= 1'b0; |
else |
wb_cyc_stb <= (i_wb_cyc)&&(i_wb_stb)&&(!o_wb_stall); |
|
// Else, are we mid-cycle? |
initial wb_mid_cycle = 0; |
always @(posedge i_clk) |
617,11 → 654,6
||((o_axi_wvalid )&&(!i_axi_wready )) |
||((o_axi_arvalid)&&(!i_axi_arready))); |
|
// Make Verilator happy |
// verilator lint_off UNUSED |
wire [2:0] unused; |
assign unused = { i_axi_bresp[0], i_axi_rresp[0], i_axi_rlast }; |
// verilator lint_on UNUSED |
|
///////////////////////////////////////////////////////////////////////// |
// |
634,7 → 666,542
// |
// |
///////////////////////////////////////////////////////////////////////// |
`ifdef FORMAL |
reg f_err_state; |
// |
// This section has been removed from this release. |
// |
`ifdef WBM2AXISP |
// If we are the top-level of the design ... |
`define ASSUME assume |
`define FORMAL_CLOCK assume(i_clk == !f_last_clk); f_last_clk <= i_clk; |
`else |
`define ASSUME assert |
`define FORMAL_CLOCK f_last_clk <= i_clk; // Clock will be given to us valid already |
`endif |
|
reg [4:0] f_reset_counter; |
initial f_reset_counter = 1'b0; |
always @(posedge i_clk) |
if ((i_reset)&&(f_reset_counter < 5'h1f)) |
f_reset_counter <= f_reset_counter + 1'b1; |
else if (!i_reset) |
f_reset_counter <= 0; |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_reset))&&($past(f_reset_counter < 5'h10))) |
assume(i_reset); |
|
// Parameters |
initial assert( (C_AXI_DATA_WIDTH / DW == 4) |
||(C_AXI_DATA_WIDTH / DW == 2) |
||(C_AXI_DATA_WIDTH == DW)); |
// |
initial assert( C_AXI_ADDR_WIDTH - LG_AXI_DW + LG_WB_DW == AW); |
|
// |
// Setup |
// |
|
reg f_past_valid, f_last_clk; |
|
always @($global_clock) |
begin |
`FORMAL_CLOCK |
|
// Assume our inputs will only change on the positive edge |
// of the clock |
if (!$rose(i_clk)) |
begin |
// AXI inputs |
`ASSUME($stable(i_axi_awready)); |
`ASSUME($stable(i_axi_wready)); |
`ASSUME($stable(i_axi_bid)); |
`ASSUME($stable(i_axi_bresp)); |
`ASSUME($stable(i_axi_bvalid)); |
`ASSUME($stable(i_axi_arready)); |
`ASSUME($stable(i_axi_rid)); |
`ASSUME($stable(i_axi_rresp)); |
`ASSUME($stable(i_axi_rvalid)); |
`ASSUME($stable(i_axi_rdata)); |
`ASSUME($stable(i_axi_rlast)); |
// Wishbone inputs |
`ASSUME((i_reset)||($stable(i_reset))); |
`ASSUME($stable(i_wb_cyc)); |
`ASSUME($stable(i_wb_stb)); |
`ASSUME($stable(i_wb_we)); |
`ASSUME($stable(i_wb_addr)); |
`ASSUME($stable(i_wb_data)); |
`ASSUME($stable(i_wb_sel)); |
end |
end |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
////////////////////////////////////////////// |
// |
// |
// Assumptions about the WISHBONE inputs |
// |
// |
////////////////////////////////////////////// |
assume property(f_past_valid || i_reset); |
|
wire [(C_AXI_ID_WIDTH-1):0] f_wb_nreqs, f_wb_nacks,f_wb_outstanding; |
fwb_slave #(.DW(DW),.AW(AW), |
.F_MAX_STALL(0), |
.F_MAX_ACK_DELAY(0), |
.F_LGDEPTH(C_AXI_ID_WIDTH), |
.F_MAX_REQUESTS((1<<(C_AXI_ID_WIDTH))-2)) |
f_wb(i_clk, i_reset, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, |
i_wb_data, i_wb_sel, |
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err, |
f_wb_nreqs, f_wb_nacks, f_wb_outstanding); |
|
wire [(C_AXI_ID_WIDTH-1):0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
|
wire [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_rd_id_outstanding, |
f_axi_wr_id_outstanding, |
f_axi_awr_id_outstanding; |
|
faxi_master #( |
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH), |
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), |
.F_AXI_MAXSTALL(3), |
.F_AXI_MAXDELAY(3), |
.F_STRICT_ORDER(STRICT_ORDER), |
.F_CONSECUTIVE_IDS(1'b1), |
.F_OPT_BURSTS(1'b0), |
.F_CHECK_IDS(1'b1)) |
f_axi(.i_clk(i_clk), .i_axi_reset_n(!i_reset), |
// Write address channel |
.i_axi_awready(i_axi_awready), |
.i_axi_awid( o_axi_awid), |
.i_axi_awaddr( o_axi_awaddr), |
.i_axi_awlen( o_axi_awlen), |
.i_axi_awsize( o_axi_awsize), |
.i_axi_awburst(o_axi_awburst), |
.i_axi_awlock( o_axi_awlock), |
.i_axi_awcache(o_axi_awcache), |
.i_axi_awprot( o_axi_awprot), |
.i_axi_awqos( o_axi_awqos), |
.i_axi_awvalid(o_axi_awvalid), |
// Write data channel |
.i_axi_wready( i_axi_wready), |
.i_axi_wdata( o_axi_wdata), |
.i_axi_wstrb( o_axi_wstrb), |
.i_axi_wlast( o_axi_wlast), |
.i_axi_wvalid( o_axi_wvalid), |
// Write response channel |
.i_axi_bid( i_axi_bid), |
.i_axi_bresp( i_axi_bresp), |
.i_axi_bvalid( i_axi_bvalid), |
.i_axi_bready( o_axi_bready), |
// Read address channel |
.i_axi_arready(i_axi_arready), |
.i_axi_arid( o_axi_arid), |
.i_axi_araddr( o_axi_araddr), |
.i_axi_arlen( o_axi_arlen), |
.i_axi_arsize( o_axi_arsize), |
.i_axi_arburst(o_axi_arburst), |
.i_axi_arlock( o_axi_arlock), |
.i_axi_arcache(o_axi_arcache), |
.i_axi_arprot( o_axi_arprot), |
.i_axi_arqos( o_axi_arqos), |
.i_axi_arvalid(o_axi_arvalid), |
// Read data channel |
.i_axi_rid( i_axi_rid), |
.i_axi_rresp( i_axi_rresp), |
.i_axi_rvalid( i_axi_rvalid), |
.i_axi_rdata( i_axi_rdata), |
.i_axi_rlast( i_axi_rlast), |
.i_axi_rready( o_axi_rready), |
// Counts |
.f_axi_rd_outstanding( f_axi_rd_outstanding), |
.f_axi_wr_outstanding( f_axi_wr_outstanding), |
.f_axi_awr_outstanding( f_axi_awr_outstanding), |
// Outstanding ID's |
.f_axi_rd_id_outstanding( f_axi_rd_id_outstanding), |
.f_axi_wr_id_outstanding( f_axi_wr_id_outstanding), |
.f_axi_awr_id_outstanding(f_axi_awr_id_outstanding) |
); |
|
|
|
////////////////////////////////////////////// |
// |
// |
// Assumptions about the AXI inputs |
// |
// |
////////////////////////////////////////////// |
|
|
////////////////////////////////////////////// |
// |
// |
// Assertions about the AXI4 ouputs |
// |
// |
////////////////////////////////////////////// |
|
wire [(LGFIFOLN-1):0] f_last_transaction_id; |
assign f_last_transaction_id = transaction_id- 1; |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset))) |
begin |
assert(o_axi_awid == f_last_transaction_id); |
if ($past(o_wb_stall)) |
assert($stable(o_axi_awid)); |
end |
|
// Write response channel |
always @(posedge i_clk) |
// We keep bready high, so the other condition doesn't |
// need to be checked |
assert(o_axi_bready); |
|
// AXI read data channel signals |
always @(posedge i_clk) |
// We keep o_axi_rready high, so the other condition's |
// don't need to be checked here |
assert(o_axi_rready); |
|
// |
// Let's look into write requests |
// |
initial assert(!o_axi_awvalid); |
initial assert(!o_axi_wvalid); |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we))&&(!$past(o_wb_stall))) |
begin |
if ($past(i_reset)) |
begin |
assert(!o_axi_awvalid); |
assert(!o_axi_wvalid); |
end else begin |
// Following any write request that we accept, awvalid |
// and wvalid should both be true |
assert(o_axi_awvalid); |
assert(o_axi_wvalid); |
end |
end |
|
// Let's assume all responses will come within 120 clock ticks |
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3, |
F_AXI_MAXSTALL = 3; // 7'd120; |
localparam [(C_AXI_ID_WIDTH):0] F_WB_MAXDELAY = F_AXI_MAXDELAY + 4; |
|
// |
// AXI write address channel |
// |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall))) |
begin |
if (($past(i_reset))||(!$past(i_wb_stb))) |
assert(!o_axi_awvalid); |
else |
assert(o_axi_awvalid == $past(i_wb_we)); |
end |
// |
generate |
if (C_AXI_DATA_WIDTH == DW) |
begin |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:0]), axi_bottom_addr }); |
|
end else if (C_AXI_DATA_WIDTH / DW == 2) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:1]), axi_bottom_addr }); |
|
end else if (C_AXI_DATA_WIDTH / DW == 4) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:2]), axi_bottom_addr }); |
|
end endgenerate |
|
// |
// AXI write data channel |
// |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall))) |
begin |
if (($past(i_reset))||(!$past(i_wb_stb))) |
assert(!o_axi_wvalid); |
else |
assert(o_axi_wvalid == $past(i_wb_we)); |
end |
// |
generate |
if (C_AXI_DATA_WIDTH == DW) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we))) |
begin |
assert(o_axi_wdata == $past(i_wb_data)); |
assert(o_axi_wstrb == $past(i_wb_sel)); |
end |
|
end else if (C_AXI_DATA_WIDTH / DW == 2) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we))) |
begin |
case($past(i_wb_addr[0])) |
1'b0: assert(o_axi_wdata[( DW-1): 0] == $past(i_wb_data)); |
1'b1: assert(o_axi_wdata[(2*DW-1):DW] == $past(i_wb_data)); |
endcase |
|
case($past(i_wb_addr[0])) |
1'b0: assert(o_axi_wstrb == { no_sel,$past(i_wb_sel)}); |
1'b1: assert(o_axi_wstrb == { $past(i_wb_sel),no_sel}); |
endcase |
end |
|
end else if (C_AXI_DATA_WIDTH / DW == 4) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&(!$past(o_wb_stall))&&($past(i_wb_we))) |
begin |
case($past(i_wb_addr[1:0])) |
2'b00: assert(o_axi_wdata[ (DW-1): 0 ] == $past(i_wb_data)); |
2'b00: assert(o_axi_wdata[(2*DW-1):( DW)] == $past(i_wb_data)); |
2'b00: assert(o_axi_wdata[(3*DW-1):(2*DW)] == $past(i_wb_data)); |
2'b11: assert(o_axi_wdata[(4*DW-1):(3*DW)] == $past(i_wb_data)); |
endcase |
|
case($past(i_wb_addr[1:0])) |
2'b00: assert(o_axi_wstrb == { {(3){no_sel}},$past(i_wb_sel)}); |
2'b01: assert(o_axi_wstrb == { {(2){no_sel}},$past(i_wb_sel), {(1){no_sel}}}); |
2'b10: assert(o_axi_wstrb == { {(1){no_sel}},$past(i_wb_sel), {(2){no_sel}}}); |
2'b11: assert(o_axi_wstrb == { $past(i_wb_sel),{(3){no_sel}}}); |
endcase |
end |
end endgenerate |
|
// |
// AXI read address channel |
// |
initial assert(!o_axi_arvalid); |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall))) |
begin |
if (($past(i_reset))||(!$past(i_wb_stb))) |
assert(!o_axi_arvalid); |
else |
assert(o_axi_arvalid == !$past(i_wb_we)); |
end |
// |
generate |
if (C_AXI_DATA_WIDTH == DW) |
begin |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:0], axi_bottom_addr })); |
|
end else if (C_AXI_DATA_WIDTH / DW == 2) |
begin |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:1], axi_bottom_addr })); |
|
end else if (C_AXI_DATA_WIDTH / DW == 4) |
begin |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we)) |
&&(!$past(o_wb_stall))) |
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:2], axi_bottom_addr })); |
|
end endgenerate |
|
// |
// AXI write response channel |
// |
|
|
// |
// AXI read data channel signals |
// |
always @(posedge i_clk) |
`ASSUME(f_axi_rd_outstanding <= f_wb_outstanding); |
// |
always @(posedge i_clk) |
`ASSUME(f_axi_rd_outstanding + f_axi_wr_outstanding <= f_wb_outstanding); |
always @(posedge i_clk) |
`ASSUME(f_axi_rd_outstanding + f_axi_awr_outstanding <= f_wb_outstanding); |
// |
always @(posedge i_clk) |
`ASSUME(f_axi_rd_outstanding + f_axi_wr_outstanding +2 > f_wb_outstanding); |
always @(posedge i_clk) |
`ASSUME(f_axi_rd_outstanding + f_axi_awr_outstanding +2 > f_wb_outstanding); |
|
// Make sure we only create one request at a time |
always @(posedge i_clk) |
assert((!o_axi_arvalid)||(!o_axi_wvalid)); |
always @(posedge i_clk) |
assert((!o_axi_arvalid)||(!o_axi_awvalid)); |
|
// Now, let's look into that FIFO. Without it, we know nothing about the ID's |
|
// Error handling |
always @(posedge i_clk) |
if (!i_wb_cyc) |
f_err_state <= 0; |
else if (o_wb_err) |
f_err_state <= 1; |
always @(posedge i_clk) |
if ((f_past_valid)&&($past(f_err_state))&&( |
(!$past(o_wb_stall))||(!$past(i_wb_stb)))) |
`ASSUME(!i_wb_stb); |
|
// Head and tail pointers |
|
// The head should only increment when something goes through |
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(i_reset)) |
&&((!$past(i_wb_stb))||($past(o_wb_stall)))) |
assert($stable(fifo_head)); |
|
// Can't overrun the FIFO |
wire [(LGFIFOLN-1):0] f_fifo_tail_minus_one; |
assign f_fifo_tail_minus_one = fifo_tail - 1'b1; |
always @(posedge i_clk) |
if ((!f_past_valid)||($past(i_reset))) |
assert(fifo_head == fifo_tail); |
else if ((f_past_valid)&&($past(fifo_head == f_fifo_tail_minus_one))) |
assert(fifo_head != fifo_tail); |
|
reg f_pre_ack; |
|
wire [(LGFIFOLN-1):0] f_fifo_used; |
assign f_fifo_used = fifo_head - fifo_tail; |
|
initial assert(fifo_tail == 0); |
initial assert(reorder_fifo_valid == 0); |
initial assert(reorder_fifo_err == 0); |
initial f_pre_ack = 1'b0; |
always @(posedge i_clk) |
begin |
f_pre_ack <= (!wb_abort)&&((axi_rd_ack)||(axi_wr_ack)); |
if (STRICT_ORDER) |
begin |
`ASSUME((!axi_rd_ack)||(!axi_wr_ack)); |
|
if ((f_past_valid)&&(!$past(i_reset))) |
assert((!$past(i_wb_cyc)) |
||(o_wb_ack == $past(f_pre_ack))); |
end |
end |
|
// |
// Verify that there are no outstanding requests outside of the FIFO |
// window. This should never happen, but the formal tools need to know |
// that. |
// |
always @(*) |
begin |
assert((f_axi_rd_id_outstanding&f_axi_wr_id_outstanding)==0); |
assert((f_axi_rd_id_outstanding&f_axi_awr_id_outstanding)==0); |
|
if (fifo_head == fifo_tail) |
begin |
assert(f_axi_rd_id_outstanding == 0); |
assert(f_axi_wr_id_outstanding == 0); |
assert(f_axi_awr_id_outstanding == 0); |
end |
|
for(k=0; k<(1<<LGFIFOLN); k=k+1) |
begin |
if ( ((fifo_tail < fifo_head)&&(k < fifo_tail)) |
||((fifo_tail < fifo_head)&&(k >= fifo_head)) |
||((fifo_head < fifo_tail)&&(k >= fifo_head)&&(k < fifo_tail)) |
//||((fifo_head < fifo_tail)&&(k >=fifo_tail)) |
) |
begin |
assert(f_axi_rd_id_outstanding[k]==0); |
assert(f_axi_wr_id_outstanding[k]==0); |
assert(f_axi_awr_id_outstanding[k]==0); |
end |
end |
end |
|
generate |
if (STRICT_ORDER) |
begin : STRICTREQ |
|
reg [C_AXI_ID_WIDTH-1:0] f_last_axi_id; |
wire [C_AXI_ID_WIDTH-1:0] f_next_axi_id, |
f_expected_last_id; |
assign f_next_axi_id = f_last_axi_id + 1'b1; |
assign f_expected_last_id = fifo_head - 1'b1 - f_fifo_used; |
|
initial f_last_axi_id = -1; |
always @(posedge i_clk) |
if (i_reset) |
f_last_axi_id = -1; |
else if ((axi_rd_ack)||(axi_wr_ack)) |
f_last_axi_id <= f_next_axi_id; |
else if (f_fifo_used == 0) |
assert(f_last_axi_id == fifo_head-1'b1); |
|
always @(posedge i_clk) |
if (axi_rd_ack) |
`ASSUME(i_axi_rid == f_next_axi_id); |
else if (axi_wr_ack) |
`ASSUME(i_axi_bid == f_next_axi_id); |
end endgenerate |
|
reg f_pending, f_returning; |
initial f_pending = 1'b0; |
always @(*) |
f_pending <= (o_axi_arvalid)||(o_axi_awvalid); |
always @(*) |
f_returning <= (axi_rd_ack)||(axi_wr_ack); |
|
reg [(LGFIFOLN):0] f_pre_count; |
|
always @(*) |
f_pre_count <= f_axi_awr_outstanding |
+ f_axi_rd_outstanding |
+ reorder_count |
+ { {(LGFIFOLN){1'b0}}, (o_wb_ack) } |
+ { {(LGFIFOLN){1'b0}}, (f_pending) }; |
always @(posedge i_clk) |
assert((wb_abort)||(o_wb_err)||(f_pre_count == f_wb_outstanding)); |
|
always @(posedge i_clk) |
assert((wb_abort)||(o_wb_err)||(f_fifo_used == f_wb_outstanding |
// + {{(LGFIFOLN){1'b0}},f_past_valid)(i_wb_stb)&&(!o_wb_ack)} |
- {{(LGFIFOLN){1'b0}},(o_wb_ack)})); |
|
always @(posedge i_clk) |
if (o_axi_wvalid) |
assert(f_fifo_used != 0); |
always @(posedge i_clk) |
if (o_axi_arvalid) |
assert(f_fifo_used != 0); |
always @(posedge i_clk) |
if (o_axi_awvalid) |
assert(f_fifo_used != 0); |
|
`endif |
endmodule |
/trunk/rtl/wbxbar.v
0,0 → 1,1392
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbxbar.v |
// |
// Project: Pipelined Wishbone to AXI converter |
// |
// Purpose: A Configurable wishbone cross-bar interconnect |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2019, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module wbxbar(i_clk, i_reset, |
i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel, |
o_mstall, o_mack, o_mdata, o_merr, |
o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel, |
i_sstall, i_sack, i_sdata, i_serr); |
parameter NM = 4, NS=8; |
parameter AW = 20, DW=32; |
parameter [NS*AW-1:0] SADDR = { |
3'b111, 17'h0, |
3'b110, 17'h0, |
3'b101, 17'h0, |
3'b100, 17'h0, |
3'b011, 17'h0, |
3'b010, 17'h0, |
4'b0010, 16'h0, |
4'b0000, 16'h0 }; |
parameter [NS*AW-1:0] SMASK = (NS <= 1) ? 0 |
: { {(NS-2){ 3'b111, 17'h0 }}, {(2){ 4'b1111, 16'h0 }} }; |
// parameter [AW-1:0] SADDR = 0; |
// parameter [AW-1:0] SMASK = 0; |
// |
// LGMAXBURST is the log_2 of the length of the longest burst that |
// might be seen. It's used to set the size of the internal |
// counters that are used to make certain that the cross bar doesn't |
// switch while still waiting on a response. |
parameter LGMAXBURST=6; |
// |
// OPT_TIMEOUT is used to help recover from a misbehaving slave. If |
// set, this value will determine the number of clock cycles to wait |
// for a misbehaving slave before returning a bus error. Alternatively, |
// if set to zero, this functionality will be removed. |
parameter OPT_TIMEOUT = 0; // 1023; |
// |
// If OPT_TIMEOUT is set, then OPT_STARVATION_TIMEOUT may also be set. |
// The starvation timeout adds to the bus error timeout generation |
// the possibility that a master will wait OPT_TIMEOUT counts without |
// receiving the bus. This may be the case, for example, if one |
// bus master is consuming a peripheral to such an extent that there's |
// no time/room for another bus master to use it. In that case, when |
// the timeout runs out, the waiting bus master will be given a bus |
// error. |
parameter [0:0] OPT_STARVATION_TIMEOUT = 1'b0 && (OPT_TIMEOUT > 0); |
// |
// TIMEOUT_WIDTH is the number of bits in counter used to check on a |
// timeout. |
localparam TIMEOUT_WIDTH = $clog2(OPT_TIMEOUT); |
// |
// OPT_DBLBUFFER is used to register all of the outputs, and thus |
// avoid adding additional combinational latency through the core |
// that might require a slower clock speed. |
parameter [0:0] OPT_DBLBUFFER = 1'b1; |
// |
// OPT_LOWPOWER adds logic to try to force unused values to zero, |
// rather than to allow a variety of logic optimizations that could |
// be used to reduce the logic count of the device. Hence, OPT_LOWPOWER |
// will use more logic, but it won't drive bus wires unless there's a |
// value to drive onto them. |
parameter [0:0] OPT_LOWPOWER = 1'b1; |
// |
// LGNM is the log (base two) of the number of bus masters connecting |
// to this crossbar |
localparam LGNM = (NM>1) ? $clog2(NM) : 1; |
// |
// LGNM is the log (base two) of the number of slaves plus one come |
// out of the system. The extra "plus one" is used for a pseudo slave |
// representing the case where the given address doesn't connect to |
// any of the slaves. This address will generate a bus error. |
localparam LGNS = $clog2(NS+1); |
// |
// |
input wire i_clk, i_reset; |
// |
// Here are the bus inputs from each of the WB bus masters |
input wire [NM-1:0] i_mcyc, i_mstb, i_mwe; |
input wire [NM*AW-1:0] i_maddr; |
input wire [NM*DW-1:0] i_mdata; |
input wire [NM*DW/8-1:0] i_msel; |
// |
// .... and their return data |
output reg [NM-1:0] o_mstall, o_mack, o_merr; |
output reg [NM*DW-1:0] o_mdata; |
// |
// |
// Here are the output ports, used to control each of the various |
// slave ports that we are connected to |
output reg [NS-1:0] o_scyc, o_sstb, o_swe; |
output reg [NS*AW-1:0] o_saddr; |
output reg [NS*DW-1:0] o_sdata; |
output reg [NS*DW/8-1:0] o_ssel; |
// |
// ... and their return data back to us. |
input wire [NS-1:0] i_sstall, i_sack, i_serr; |
input wire [NS*DW-1:0] i_sdata; |
// |
// |
|
// At one time I used o_macc and o_sacc to put into the outgoing |
// trace file, just enough logic to tell me if a transaction was |
// taking place on the given clock. |
// |
// assign o_macc = (i_mstb & ~o_mstall); |
// assign o_sacc = (o_sstb & ~i_sstall); |
// |
// These definitions work with Verilator, just not with Yosys |
// reg [NM-1:0][NS:0] request; |
// reg [NM-1:0][NS-1:0] requested; |
// reg [NM-1:0][NS:0] grant; |
// |
// These definitions work with both |
reg [NS:0] request [0:NM-1]; |
reg [NS-1:0] requested [0:NM-1]; |
reg [NS:0] grant [0:NM-1]; |
reg [NM-1:0] mgrant; |
reg [NS-1:0] sgrant; |
|
wire [LGMAXBURST-1:0] w_mpending [0:NM-1]; |
reg [NM-1:0] mfull; |
reg [NM-1:0] mnearfull; |
reg [NM-1:0] mempty, timed_out; |
|
localparam NMFULL = (NM > 1) ? (1<<LGNM) : 1; |
localparam NSFULL = (1<<LGNS); |
reg [NMFULL-1:0] r_stb; |
reg [NMFULL-1:0] r_we; |
reg [AW-1:0] r_addr [0:NMFULL-1]; |
reg [DW-1:0] r_data [0:NMFULL-1]; |
reg [DW/8-1:0] r_sel [0:NMFULL-1]; |
wire [TIMEOUT_WIDTH-1:0] w_deadlock_timer [0:NM-1]; |
|
|
reg [LGNS-1:0] mindex [0:NMFULL-1]; |
reg [LGNM-1:0] sindex [0:NSFULL-1]; |
|
reg [NMFULL-1:0] m_cyc; |
reg [NMFULL-1:0] m_stb; |
reg [NMFULL-1:0] m_we; |
reg [AW-1:0] m_addr [0:NMFULL-1]; |
reg [DW-1:0] m_data [0:NMFULL-1]; |
reg [DW/8-1:0] m_sel [0:NMFULL-1]; |
// |
reg [NSFULL-1:0] s_stall; |
reg [DW-1:0] s_data [0:NSFULL-1]; |
reg [NSFULL-1:0] s_ack; |
reg [NSFULL-1:0] s_err; |
|
genvar N, M; |
integer iN, iM; |
generate for(N=0; N<NM; N=N+1) |
begin : DECODE_REQUEST |
reg none_sel; |
|
always @(*) |
begin |
none_sel = !m_stb[N]; |
for(iM=0; iM<NS; iM=iM+1) |
begin |
|
none_sel = none_sel |
|| (((m_addr[N] ^ SADDR[iM*AW +: AW]) |
&SMASK[iM*AW +: AW])==0); |
end |
|
|
none_sel = !none_sel; |
end |
|
always @(*) |
begin |
for(iM=0; iM<NS; iM=iM+1) |
request[N][iM] = m_stb[N] |
&&(((m_addr[N] ^ SADDR[iM*AW +: AW]) |
&SMASK[iM*AW +: AW])==0); |
|
// Is this address non-existant? |
request[N][NS] = m_stb[N] && none_sel; |
end |
|
always @(*) |
m_cyc[N] = i_mcyc[N]; |
always @(*) |
if (mfull[N]) |
m_stb[N] = 1'b0; |
else if (mnearfull[N]) |
m_stb[N] = i_mstb[N] && !r_stb[N]; |
else |
m_stb[N] = i_mstb[N] || (i_mcyc[N] && r_stb[N]); |
always @(*) |
m_we[N] = r_stb[N] ? r_we[N] : i_mwe[N]; |
always @(*) |
m_addr[N] = r_stb[N] ? r_addr[N] : i_maddr[N*AW +: AW]; |
always @(*) |
m_data[N] = r_stb[N] ? r_data[N] : i_mdata[N*DW +: DW]; |
always @(*) |
m_sel[N] = r_stb[N] ? r_sel[N]: i_msel[N*DW/8 +: DW/8]; |
|
end for(N=NM; N<NMFULL; N=N+1) |
begin |
// in case NM isn't one less than a power of two, complete |
// the set |
always @(*) |
m_cyc[N] = 0; |
always @(*) |
m_stb[N] = 0; |
always @(*) |
m_we[N] = 0; |
always @(*) |
m_addr[N] = 0; |
always @(*) |
m_data[N] = 0; |
always @(*) |
m_sel[N] = 0; |
|
end endgenerate |
|
always @(*) |
begin |
for(iM=0; iM<NS; iM=iM+1) |
begin |
requested[0][iM] = 0; |
for(iN=1; iN<NM; iN=iN+1) |
requested[iN][iM] |
= (request[iN-1][iM] || requested[iN-1][iM]); |
end |
end |
|
generate for(M=0; M<NS; M=M+1) |
begin |
|
always @(*) |
begin |
sgrant[M] = 0; |
for(iN=0; iN<NM; iN=iN+1) |
if (grant[iN][M]) |
sgrant[M] = 1; |
end |
|
always @(*) |
s_data[M] = i_sdata[M*DW +: DW]; |
always @(*) |
s_stall[M] = o_sstb[M] && i_sstall[M]; |
always @(*) |
s_ack[M] = o_scyc[M] && i_sack[M]; |
always @(*) |
s_err[M] = o_scyc[M] && i_serr[M]; |
end for(M=NS; M<NSFULL; M=M+1) |
begin |
|
always @(*) |
s_data[M] = 0; |
always @(*) |
s_stall[M] = 1; |
always @(*) |
s_ack[M] = 0; |
always @(*) |
s_err[M] = 1; |
// always @(*) sgrant[M] = 0; |
|
end endgenerate |
|
// |
// Arbitrate among masters to determine who gets to access a given |
// channel |
generate for(N=0; N<NM; N=N+1) |
begin : ARBITRATE_REQUESTS |
|
// This is done using a couple of variables. |
// |
// request[N][M] |
// This is true if master N is requesting to access slave |
// M. It is combinatorial, so it will be true if the |
// request is being made on the current clock. |
// |
// requested[N][M] |
// True if some other master, prior to N, has requested |
// channel M. This creates a basic priority arbiter, |
// such that lower numbered masters have access before |
// a greater numbered master |
// |
// grant[N][M] |
// True if a grant has been made for master N to access |
// slave channel M |
// |
// mgrant[N] |
// True if master N has been granted access to some slave |
// channel, any channel. |
// |
// mindex[N] |
// This is the number of the slave channel that master |
// N has been given access to |
// |
// sgrant[M] |
// True if there exists some master, N, that has been |
// granted access to this slave, hence grant[N][M] must |
// also be true |
// |
// sindex[M] |
// This is the index of the master that has access to |
// slave M, assuming sgrant[M]. Hence, if sgrant[M] |
// then grant[sindex[M]][M] must be true |
// |
reg stay_on_channel; |
|
always @(*) |
begin |
stay_on_channel = 0; |
for(iM=0; iM<NS; iM=iM+1) |
begin |
if (request[N][iM] && grant[N][iM]) |
stay_on_channel = 1; |
end |
end |
|
reg requested_channel_is_available; |
|
always @(*) |
begin |
requested_channel_is_available = 0; |
for(iM=0; iM<NS; iM=iM+1) |
begin |
if (request[N][iM] && !sgrant[iM] |
&& !requested[N][iM]) |
requested_channel_is_available = 1; |
end |
end |
|
initial grant[N] = 0; |
initial mgrant[N] = 0; |
always @(posedge i_clk) |
if (i_reset || !i_mcyc[N]) |
begin |
grant[N] <= 0; |
mgrant[N] <= 0; |
end else if (!mgrant[N] || mempty[N]) |
begin |
if (stay_on_channel) |
mgrant[N] <= 1'b1; |
else if (requested_channel_is_available) |
mgrant[N] <= 1'b1; |
else if (i_mstb[N] || r_stb[N]) |
mgrant[N] <= 1'b0; |
|
for(iM=0; iM<NS; iM=iM+1) |
begin |
|
if (request[N][iM] && grant[N][iM]) |
// Maintain any open channels |
grant[N][iM] <= 1; |
else if (request[N][iM] && !sgrant[iM] |
&& !requested[N][iM]) |
// Open a new channel if necessary |
grant[N][iM] <= 1; |
else if (i_mstb[N] || r_stb[N]) |
grant[N][iM] <= 0; |
|
end |
if (request[N][NS]) |
begin |
grant[N][NS] <= 1'b1; |
mgrant[N] <= 1'b1; |
end else begin |
grant[N][NS] <= 1'b0; |
if (grant[N][NS]) |
mgrant[N] <= 1'b1; |
end |
end |
|
if (NS == 1) |
begin |
|
always @(*) |
mindex[N] = 0; |
|
end else begin |
|
always @(posedge i_clk) |
if (!mgrant[N] || mempty[N]) |
begin |
|
for(iM=0; iM<NS; iM=iM+1) |
begin |
if (request[N][iM] && grant[N][iM]) |
begin |
// Maintain any open channels |
mindex[N] <= iM; |
end else if (request[N][iM] |
&& !sgrant[iM] |
&& !requested[N][iM]) |
begin |
// Open a new channel |
// if necessary |
mindex[N] <= iM; |
end |
end |
end |
end |
|
end for (N=NM; N<NMFULL; N=N+1) |
begin |
|
always @(*) |
mindex[N] = 0; |
|
end endgenerate |
|
// Calculate sindex. sindex[M] (indexed by slave ID) |
// references the master controlling this slave. This makes for |
// faster/cheaper logic on the return path, since we can now use |
// a fully populated LUT rather than a priority based return scheme |
generate for(M=0; M<NS; M=M+1) |
begin |
|
if (NM <= 1) |
begin |
|
// If there will only ever be one master, then we |
// can assume all slave indexes point to that master |
always @(*) |
sindex[M] = 0; |
|
end else begin : SINDEX_MORE_THAN_ONE_MASTER |
|
always @(posedge i_clk) |
for (iN=0; iN<NM; iN=iN+1) |
begin |
if (!mgrant[iN] || mempty[iN]) |
begin |
if (request[iN][M] && grant[iN][M]) |
sindex[M] <= iN; |
else if (request[iN][M] && !sgrant[M] |
&& !requested[iN][M]) |
sindex[M] <= iN; |
end |
end |
end |
|
end for(M=NS; M<NSFULL; M=M+1) |
begin |
// Assign the unused slave indexes to zero |
// |
// Remember, to full out a full 2^something set of slaves, |
// we may have more slave indexes than we actually have slaves |
|
always @(*) |
sindex[M] = 0; |
|
end endgenerate |
|
|
// |
// Assign outputs to the slaves, part one |
// |
// In this part, we assign the difficult outputs: o_scyc and o_sstb |
generate for(M=0; M<NS; M=M+1) |
begin |
|
initial o_scyc[M] = 0; |
initial o_sstb[M] = 0; |
always @(posedge i_clk) |
begin |
if (sgrant[M]) |
begin |
|
if (!i_mcyc[sindex[M]]) |
begin |
o_scyc[M] <= 1'b0; |
o_sstb[M] <= 1'b0; |
end else begin |
o_scyc[M] <= 1'b1; |
|
if (!s_stall[M]) |
o_sstb[M] <= m_stb[sindex[M]] |
&& request[sindex[M]][M] |
&& !mnearfull[sindex[M]]; |
end |
end else begin |
o_scyc[M] <= 1'b0; |
o_sstb[M] <= 1'b0; |
end |
|
if (i_reset || s_err[M]) |
begin |
o_scyc[M] <= 1'b0; |
o_sstb[M] <= 1'b0; |
end |
end |
end endgenerate |
|
// |
// Assign outputs to the slaves, part two |
// |
// These are the easy(er) outputs, since there are fewer properties |
// riding on them |
generate if ((NM == 1) && (!OPT_LOWPOWER)) |
begin |
// |
// This is the low logic version of our bus data outputs. |
// It only works if we only have one master. |
// |
// The basic idea here is that we share all of our bus outputs |
// between all of the various slaves. Since we only have one |
// bus master, this works. |
// |
always @(posedge i_clk) |
begin |
o_swe[0] <= o_swe[0]; |
o_saddr[0+: AW] <= o_saddr[0+:AW]; |
o_sdata[0+: DW] <= o_sdata[0+:DW]; |
o_ssel[0+:DW/8] <=o_ssel[0+:DW/8]; |
|
if (sgrant[mindex[0]] && !s_stall[mindex[0]]) |
begin |
o_swe[0] <= m_we[0]; |
o_saddr[0+: AW] <= m_addr[0]; |
o_sdata[0+: DW] <= m_data[0]; |
o_ssel[0+:DW/8] <= m_sel[0]; |
end |
end |
|
for(M=1; M<NS; M=M+1) |
always @(*) |
begin |
o_swe[M] = o_swe[0]; |
o_saddr[M*AW +: AW] = o_saddr[0 +: AW]; |
o_sdata[M*DW +: DW] = o_sdata[0 +: DW]; |
o_ssel[M*DW/8+:DW/8]= o_ssel[0 +: DW/8]; |
end |
|
end else for(M=0; M<NS; M=M+1) |
begin |
always @(posedge i_clk) |
begin |
if (OPT_LOWPOWER && !sgrant[M]) |
begin |
o_swe[M] <= 1'b0; |
o_saddr[M*AW +: AW] <= 0; |
o_sdata[M*DW +: DW] <= 0; |
o_ssel[M*(DW/8)+:DW/8]<= 0; |
end else if (!s_stall[M]) begin |
o_swe[M] <= m_we[sindex[M]]; |
o_saddr[M*AW +: AW] <= m_addr[sindex[M]]; |
if (OPT_LOWPOWER && !m_we[sindex[M]]) |
o_sdata[M*DW +: DW] <= 0; |
else |
o_sdata[M*DW +: DW] <= m_data[sindex[M]]; |
o_ssel[M*(DW/8)+:DW/8]<= m_sel[sindex[M]]; |
end |
|
end |
end endgenerate |
|
// |
// Assign return values to the masters |
generate if (OPT_DBLBUFFER) |
begin : DOUBLE_BUFFERRED_STALL |
|
for(N=0; N<NM; N=N+1) |
begin |
initial o_mstall[N] = 0; |
initial o_mack[N] = 0; |
initial o_merr[N] = 0; |
always @(posedge i_clk) |
begin |
iM = mindex[N]; |
o_mstall[N] <= o_mstall[N] |
|| (i_mstb[N] && !o_mstall[N]); |
o_mack[N] <= mgrant[N] && s_ack[mindex[N]]; |
o_merr[N] <= mgrant[N] && s_err[mindex[N]]; |
if (OPT_LOWPOWER && !mgrant[N]) |
o_mdata[N*DW +: DW] <= 0; |
else |
o_mdata[N*DW +: DW] <= s_data[mindex[N]]; |
|
if (mgrant[N]) |
begin |
if ((i_mstb[N]||o_mstall[N]) |
&& mnearfull[N]) |
o_mstall[N] <= 1'b1; |
else if ((i_mstb[N] || o_mstall[N]) |
&& !request[N][iM]) |
// Requesting another channel |
o_mstall[N] <= 1'b1; |
else if (!s_stall[iM]) |
// Downstream channel is clear |
o_mstall[N] <= 1'b0; |
else // if (o_sstb[mindex[N]] |
// && i_sstall[mindex[N]]) |
// Downstream channel is stalled |
o_mstall[N] <= i_mstb[N]; |
end |
|
if (mnearfull[N] && i_mstb[N]) |
o_mstall[N] <= 1'b1; |
|
if ((o_mstall[N] && grant[N][NS]) |
||(timed_out[N] && !o_mack[N])) |
begin |
o_mstall[N] <= 1'b0; |
o_mack[N] <= 1'b0; |
o_merr[N] <= 1'b1; |
end |
|
if (i_reset || !i_mcyc[N]) |
begin |
o_mstall[N] <= 1'b0; |
o_mack[N] <= 1'b0; |
o_merr[N] <= 1'b0; |
end |
end |
|
always @(*) |
r_stb[N] = o_mstall[N]; |
|
always @(posedge i_clk) |
if (OPT_LOWPOWER && !i_mcyc[N]) |
begin |
r_we[N] <= 0; |
r_addr[N] <= 0; |
r_data[N] <= 0; |
r_sel[N] <= 0; |
end else if ((!OPT_LOWPOWER || i_mstb[N]) && !o_mstall[N]) |
begin |
r_we[N] <= i_mwe[N]; |
r_addr[N] <= i_maddr[N*AW +: AW]; |
r_data[N] <= i_mdata[N*DW +: DW]; |
r_sel[N] <= i_msel[N*(DW/8) +: DW/8]; |
end |
end |
|
for(N=NM; N<NMFULL; N=N+1) |
begin |
|
always @(*) |
r_stb[N] <= 1'b0; |
|
always @(*) |
begin |
r_we[N] = 0; |
r_addr[N] = 0; |
r_data[N] = 0; |
r_sel[N] = 0; |
end |
end |
|
|
end else if (NS == 1) // && !OPT_DBLBUFFER |
begin : SINGLE_SLAVE |
|
for(N=0; N<NM; N=N+1) |
begin |
always @(*) |
begin |
o_mstall[N] = !mgrant[N] || s_stall[0] |
|| (i_mstb[N] && !request[N][0]); |
o_mack[N] = mgrant[N] && i_sack[0]; |
o_merr[N] = mgrant[N] && i_serr[0]; |
o_mdata[N*DW +: DW] = (!mgrant[N] && OPT_LOWPOWER) |
? 0 : i_sdata; |
|
if (mnearfull[N]) |
o_mstall[N] = 1'b1; |
|
if (timed_out[N]&&!o_mack[0]) |
begin |
o_mstall[N] = 1'b0; |
o_mack[N] = 1'b0; |
o_merr[N] = 1'b1; |
end |
|
if (grant[N][NS] && m_stb[N]) |
begin |
o_mstall[N] = 1'b0; |
o_mack[N] = 1'b0; |
o_merr[N] = 1'b1; |
end |
|
if (!m_cyc[N]) |
begin |
o_mack[N] = 1'b0; |
o_merr[N] = 1'b0; |
end |
end |
end |
|
for(N=0; N<NMFULL; N=N+1) |
begin |
|
always @(*) |
r_stb[N] <= 1'b0; |
|
always @(*) |
begin |
r_we[N] = 0; |
r_addr[N] = 0; |
r_data[N] = 0; |
r_sel[N] = 0; |
end |
end |
|
end else begin : SINGLE_BUFFER_STALL |
for(N=0; N<NM; N=N+1) |
begin |
// initial o_mstall[N] = 0; |
// initial o_mack[N] = 0; |
always @(*) |
begin |
o_mstall[N] = 1; |
o_mack[N] = mgrant[N] && s_ack[mindex[N]]; |
o_merr[N] = mgrant[N] && s_err[mindex[N]]; |
if (OPT_LOWPOWER && !mgrant[N]) |
o_mdata[N*DW +: DW] = 0; |
else |
o_mdata[N*DW +: DW] = s_data[mindex[N]]; |
|
if (mgrant[N]) |
begin |
iM = mindex[N]; |
o_mstall[N] = (s_stall[mindex[N]]) |
|| (i_mstb[N] && !request[N][iM]); |
end |
|
if (mnearfull[N]) |
o_mstall[N] = 1'b1; |
|
if (grant[N][NS] ||(timed_out[N]&&!o_mack[0])) |
begin |
o_mstall[N] = 1'b0; |
o_mack[N] = 1'b0; |
o_merr[N] = 1'b1; |
end |
|
if (!m_cyc[N]) |
begin |
o_mack[N] = 1'b0; |
o_merr[N] = 1'b0; |
end |
end |
end |
|
for(N=0; N<NMFULL; N=N+1) |
begin |
|
always @(*) |
r_stb[N] <= 1'b0; |
|
always @(*) |
begin |
r_we[N] = 0; |
r_addr[N] = 0; |
r_data[N] = 0; |
r_sel[N] = 0; |
end |
end |
|
end endgenerate |
|
// |
// Count the pending transactions per master |
generate for(N=0; N<NM; N=N+1) |
begin |
reg [LGMAXBURST-1:0] lclpending; |
initial lclpending = 0; |
initial mempty[N] = 1; |
initial mnearfull[N] = 0; |
initial mfull[N] = 0; |
always @(posedge i_clk) |
if (i_reset || !i_mcyc[N] || o_merr[N]) |
begin |
lclpending <= 0; |
mfull[N] <= 0; |
mempty[N] <= 1'b1; |
mnearfull[N]<= 0; |
end else case({ (i_mstb[N] && !o_mstall[N]), o_mack[N] }) |
2'b01: begin |
lclpending <= lclpending - 1'b1; |
mnearfull[N]<= mfull[N]; |
mfull[N] <= 1'b0; |
mempty[N] <= (lclpending == 1); |
end |
2'b10: begin |
lclpending <= lclpending + 1'b1; |
mnearfull[N]<= (&lclpending[LGMAXBURST-1:2])&&(lclpending[1:0] != 0); |
mfull[N] <= mnearfull[N]; |
mempty[N] <= 1'b0; |
end |
default: begin end |
endcase |
|
assign w_mpending[N] = lclpending; |
|
end endgenerate |
|
|
generate if (OPT_TIMEOUT > 0) |
begin : CHECK_TIMEOUT |
|
for(N=0; N<NM; N=N+1) |
begin |
|
reg [TIMEOUT_WIDTH-1:0] deadlock_timer; |
|
initial deadlock_timer = OPT_TIMEOUT; |
initial timed_out[N] = 1'b0; |
always @(posedge i_clk) |
if (i_reset || !i_mcyc[N] |
||((w_mpending[N] == 0) |
&&(!i_mstb[N] && !r_stb[N])) |
||((i_mstb[N] || r_stb[N]) |
&&(!o_mstall[N])) |
||(o_mack[N] || o_merr[N]) |
||(!OPT_STARVATION_TIMEOUT&&!mgrant[N])) |
begin |
deadlock_timer <= OPT_TIMEOUT; |
timed_out[N] <= 0; |
end else if (deadlock_timer > 0) |
begin |
deadlock_timer <= deadlock_timer - 1; |
timed_out[N] <= (deadlock_timer <= 1); |
end |
|
assign w_deadlock_timer[N] = deadlock_timer; |
end |
|
end else begin |
|
always @(*) |
timed_out = 0; |
|
end endgenerate |
|
`ifdef FORMAL |
localparam F_MAX_DELAY = 4; |
localparam F_LGDEPTH = LGMAXBURST; |
// |
reg f_past_valid; |
// |
// Our bus checker keeps track of the number of requests, |
// acknowledgments, and the number of outstanding transactions on |
// every channel, both the masters driving us |
wire [F_LGDEPTH-1:0] f_mreqs [0:NM-1]; |
wire [F_LGDEPTH-1:0] f_macks [0:NM-1]; |
wire [F_LGDEPTH-1:0] f_moutstanding [0:NM-1]; |
// |
// as well as the slaves that we drive ourselves |
wire [F_LGDEPTH-1:0] f_sreqs [0:NS-1]; |
wire [F_LGDEPTH-1:0] f_sacks [0:NS-1]; |
wire [F_LGDEPTH-1:0] f_soutstanding [0:NS-1]; |
|
|
initial assert(!OPT_STARVATION_TIMEOUT || OPT_TIMEOUT > 0); |
|
reg f_past_valid; |
initial f_past_valid = 0; |
always @(posedge i_clk) |
f_past_valid = 1'b1; |
|
always @(*) |
if (!f_past_valid) |
assume(i_reset); |
|
generate for(N=0; N<NM; N=N+1) |
begin |
always @(*) |
if (f_past_valid) |
for(iN=N+1; iN<NM; iN=iN+1) |
// Can't grant the same channel to two separate |
// masters. This applies to all but the error or |
// no-slave-selected channel |
assert((grant[N][NS-1:0] & grant[iN][NS-1:0])==0); |
|
for(M=1; M<=NS; M=M+1) |
begin |
// Can't grant two channels to the same master |
always @(*) |
if (f_past_valid && grant[N][M]) |
assert(grant[N][M-1:0] == 0); |
end |
|
|
always @(*) |
if (&w_mpending[N]) |
assert(o_merr[N] || o_mstall[N]); |
|
reg checkgrant; |
always @(*) |
if (f_past_valid) |
begin |
checkgrant = 0; |
for(iM=0; iM<NS; iM=iM+1) |
if (grant[N][iM]) |
checkgrant = 1; |
if (grant[N][NS]) |
checkgrant = 1; |
|
assert(checkgrant == mgrant[N]); |
end |
|
end endgenerate |
|
// Double check the grant mechanism and its dependent variables |
generate for(N=0; N<NM; N=N+1) |
begin |
|
for(M=0; M<NS; M=M+1) |
begin |
always @(*) |
if ((f_past_valid)&&grant[N][M]) |
begin |
assert(mgrant[N]); |
assert(mindex[N] == M); |
assert(sindex[M] == N); |
end |
end |
end endgenerate |
|
// Double check the timeout flags for consistency |
generate for(N=0; N<NM; N=N+1) |
begin |
always @(*) |
if (f_past_valid) |
begin |
assert(mempty[N] == (w_mpending[N] == 0)); |
assert(mnearfull[N]==(&w_mpending[N][LGMAXBURST-1:1])); |
assert(mfull[N] == (&w_mpending[N])); |
end |
end endgenerate |
|
`ifdef VERIFIC |
// |
// The Verific parser is currently broken, and doesn't allow |
// initial assumes or asserts. The following lines get us around that |
// |
always @(*) |
if (!f_past_valid) |
assume(sgrant == 0); |
|
generate for(M=0; M<NS; M=M+1) |
begin |
always @(*) |
if (!f_past_valid) |
begin |
assume(o_scyc[M] == 0); |
assume(o_sstb[M] == 0); |
end |
end endgenerate |
|
generate for(N=0; N<NM; N=N+1) |
begin |
always @(*) |
if (!f_past_valid) |
begin |
assume(grant[N] == 0); |
assume(mgrant[N] == 0); |
end |
end |
`endif |
|
//////////////////////////////////////////////////////////////////////// |
// |
// BUS CHECK |
// |
// Verify that every channel, whether master or slave, follows the rules |
// of the WB road. |
// |
//////////////////////////////////////////////////////////////////////// |
generate for(N=0; N<NM; N=N+1) |
begin : WB_SLAVE_CHECK |
|
fwb_slave #( |
.AW(AW), .DW(DW), |
.F_LGDEPTH(LGMAXBURST), |
.F_MAX_ACK_DELAY(0), |
.F_MAX_STALL(0) |
) slvi(i_clk, i_reset, |
i_mcyc[N], i_mstb[N], i_mwe[N], |
i_maddr[N*AW +: AW], i_mdata[N*DW +: DW], i_msel[N*(DW/8) +: (DW/8)], |
o_mack[N], o_mstall[N], o_mdata[N*DW +: DW], o_merr[N], |
f_mreqs[N], f_macks[N], f_moutstanding[N]); |
|
always @(*) |
if ((f_past_valid)&&(grant[N][NS])) |
assert(f_moutstanding[N] <= 1); |
|
always @(*) |
if ((f_past_valid)&&(grant[N][NS] && i_mcyc[N])) |
assert(o_mstall[N] || o_merr[N]); |
|
end endgenerate |
|
generate for(M=0; M<NS; M=M+1) |
begin : WB_MASTER_CHECK |
fwb_master #( |
.AW(AW), .DW(DW), |
.F_LGDEPTH(LGMAXBURST), |
.F_MAX_ACK_DELAY(F_MAX_DELAY), |
.F_MAX_STALL(2) |
) mstri(i_clk, i_reset, |
o_scyc[M], o_sstb[M], o_swe[M], |
o_saddr[M*AW +: AW], o_sdata[M*DW +: DW], |
o_ssel[M*(DW/8) +: (DW/8)], |
i_sack[M], i_sstall[M], s_data[M], i_serr[M], |
f_sreqs[M], f_sacks[M], f_soutstanding[M]); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
//////////////////////////////////////////////////////////////////////// |
generate for(N=0; N<NM; N=N+1) |
begin : CHECK_OUTSTANDING |
|
always @(posedge i_clk) |
if (i_mcyc[N]) |
assert(f_moutstanding[N] == w_mpending[N]); |
|
reg [LGMAXBURST:0] n_outstanding; |
always @(*) |
if (i_mcyc[N]) |
assert(f_moutstanding[N] >= |
(o_mstall[N] && OPT_DBLBUFFER) ? 1:0 |
+ (o_mack[N] && OPT_DBLBUFFER) ? 1:0); |
|
always @(*) |
n_outstanding = f_moutstanding[N] |
- ((o_mstall[N] && OPT_DBLBUFFER) ? 1:0) |
- ((o_mack[N] && OPT_DBLBUFFER) ? 1:0); |
always @(posedge i_clk) |
if (i_mcyc[N] && !mgrant[N] && !o_merr[N]) |
assert(f_moutstanding[N] |
== (o_mstall[N]&&OPT_DBLBUFFER ? 1:0)); |
else if (i_mcyc[N] && mgrant[N]) |
for(iM=0; iM<NS; iM=iM+1) |
if (grant[N][iM] && o_scyc[iM] && !i_serr[iM] && !o_merr[N]) |
assert(n_outstanding |
== {1'b0,f_soutstanding[iM]}+(o_sstb[iM] ? 1:0)); |
|
always @(*) |
if (i_mcyc[N] && r_stb[N] && OPT_DBLBUFFER) |
assume(i_mwe[N] == r_we[N]); |
|
always @(*) |
if (!OPT_DBLBUFFER && !mnearfull[N]) |
assert(i_mstb[N] == m_stb[N]); |
|
always @(*) |
if (!OPT_DBLBUFFER) |
assert(i_mwe[N] == m_we[N]); |
|
always @(*) |
for(iM=0; iM<NS; iM=iM+1) |
if (grant[N][iM] && i_mcyc[N]) |
begin |
if (f_soutstanding[iM] > 0) |
assert(i_mwe[N] == o_swe[iM]); |
if (o_sstb[iM]) |
assert(i_mwe[N] == o_swe[iM]); |
if (o_mack[N]) |
assert(i_mwe[N] == o_swe[iM]); |
if (o_scyc[iM] && i_sack[iM]) |
assert(i_mwe[N] == o_swe[iM]); |
if (o_merr[N] && !timed_out[N]) |
assert(i_mwe[N] == o_swe[iM]); |
if (o_scyc[iM] && i_serr[iM]) |
assert(i_mwe[N] == o_swe[iM]); |
end |
|
end endgenerate |
|
generate for(M=0; M<NS; M=M+1) |
begin |
always @(posedge i_clk) |
if (!$past(sgrant[M])) |
assert(!o_scyc[M]); |
end endgenerate |
|
//////////////////////////////////////////////////////////////////////// |
// |
// CONTRACT SECTION |
// |
// Here's the contract, in two parts: |
// |
// 1. Should ever a master (any master) wish to read from a slave |
// (any slave), he should be able to read a known value |
// from that slave (any value) from any arbitrary address |
// he might wish to read from (any address) |
// |
// 2. Should ever a master (any master) wish to write to a slave |
// (any slave), he should be able to write the exact |
// value he wants (any value) to the exact address he wants |
// (any address) |
// |
// special_master is an arbitrary constant chosen by the solver, |
// which can reference *any* possible master |
// special_address is an arbitrary constant chosen by the solver, |
// which can reference *any* possible address the master |
// might wish to access |
// special_value is an arbitrary value (at least during |
// induction) representing the current value within the |
// slave at the given address |
// |
// |
//////////////////////////////////////////////////////////////////////// |
// |
// Now let's pay attention to a special bus master and a special |
// address referencing a special bus slave. We'd like to assert |
// that we can access the values of every slave from every master. |
(* anyconst *) reg [(NM<=1)?0:(LGNM-1):0] special_master; |
reg [(NS<=1)?0:(LGNS-1):0] special_slave; |
(* anyconst *) reg [AW-1:0] special_address; |
reg [DW-1:0] special_value; |
|
always @(*) |
if (NM <= 1) |
assume(special_master == 0); |
always @(*) |
if (NS <= 1) |
assume(special_slave == 0); |
|
// |
// Decode the special address to discover the slave associated with it |
always @(*) |
begin |
special_slave = NS; |
for(iM=0; iM<NS; iM = iM+1) |
begin |
if (((special_address ^ SADDR[iM*AW +: AW]) |
&SMASK[iM*AW +: AW]) == 0) |
special_slave = iM; |
end |
end |
|
generate if (NS > 1) |
begin : DOUBLE_ADDRESS_CHECK |
// |
// Check that no slave address has been assigned twice. |
// This check only needs to be done once at the beginning |
// of the run, during the BMC section. |
reg address_found; |
|
always @(*) |
if (!f_past_valid) |
begin |
address_found = 0; |
for(iM=0; iM<NS; iM = iM+1) |
begin |
if (((special_address ^ SADDR[iM*AW +: AW]) |
&SMASK[iM*AW +: AW]) == 0) |
begin |
assert(address_found == 0); |
address_found = 1; |
end |
end |
end |
|
end endgenerate |
// |
// Let's assume this slave will acknowledge any request on the next |
// bus cycle after the stall goes low. Further, lets assume that |
// it never creates an error, and that it always responds to our special |
// address with the special data value given above. To do this, we'll |
// also need to make certain that the special value will change |
// following any write. |
// |
// These are the "assumptions" associated with our fictitious slave. |
initial assume(special_value == 0); |
always @(posedge i_clk) |
if (special_slave < NS) |
begin |
if ($past(o_sstb[special_slave] && !i_sstall[special_slave])) |
begin |
assume(i_sack[special_slave]); |
|
if ($past(!o_swe[special_slave]) |
&&($past(o_saddr[special_slave*AW +: AW]) == special_address)) |
assume(i_sdata[special_slave*DW+: DW] |
== special_value); |
end else |
assume(!i_sack[special_slave]); |
assume(!i_serr[special_slave]); |
|
if (o_scyc[special_slave]) |
assert(f_soutstanding[special_slave] |
== i_sack[special_slave]); |
|
if (o_sstb[special_slave] && !i_sstall[special_slave] |
&& o_swe[special_slave]) |
begin |
for(iM=0; iM < DW/8; iM=iM+1) |
if (o_ssel[special_slave * DW/8 + iM]) |
special_value[iM*8 +: 8] <= o_sdata[special_slave * DW + iM*8 +: 8]; |
end |
end |
|
// |
// Now its time to make some assertions. Specifically, we want to |
// assert that any time we read from this special slave, the special |
// value is returned. |
reg [2:0] read_seq; |
initial read_seq = 0; |
always @(posedge i_clk) |
if ((special_master < NM)&&(special_slave < NS) |
&&(i_mcyc[special_master]) |
&&(!timed_out[special_master])) |
begin |
read_seq <= 0; |
if ((grant[special_master][special_slave]) |
&&(m_stb[special_master]) |
&&(m_addr[special_master] == special_address) |
&&(!m_we[special_master]) |
) |
begin |
read_seq[0] <= 1; |
end |
|
if (|read_seq) |
begin |
assert(grant[special_master][special_slave]); |
assert(mgrant[special_master]); |
assert(sgrant[special_slave]); |
assert(mindex[special_master] == special_slave); |
assert(sindex[special_slave] == special_master); |
assert(!o_merr[special_master]); |
end |
|
if (read_seq[0] && !$past(s_stall[special_slave])) |
begin |
assert(o_scyc[special_slave]); |
assert(o_sstb[special_slave]); |
assert(!o_swe[special_slave]); |
assert(o_saddr[special_slave*AW +: AW] == special_address); |
|
read_seq[1] <= 1; |
|
end else if (read_seq[0] && $past(s_stall[special_slave])) |
begin |
assert($stable(m_stb[special_master])); |
assert(!m_we[special_master]); |
assert(m_addr[special_master] == special_address); |
|
read_seq[0] <= 1; |
end |
|
if (read_seq[1] && $past(s_stall[special_slave])) |
begin |
assert(o_scyc[special_slave]); |
assert(o_sstb[special_slave]); |
assert(!o_swe[special_slave]); |
assert(o_saddr[special_slave*AW +: AW] == special_address); |
read_seq[1] <= 1; |
end else if (read_seq[1] && !$past(s_stall[special_slave])) |
begin |
assert(i_sack[special_slave]); |
assert(i_sdata[special_slave*DW +: DW] == $past(special_value)); |
if (OPT_DBLBUFFER) |
read_seq[2] <= 1; |
end |
|
if (read_seq[2] || ((!OPT_DBLBUFFER)&&read_seq[1] |
&& !$past(s_stall[special_slave]))) |
begin |
assert(o_mack[special_master]); |
assert(o_mdata[special_master * DW +: DW] |
== $past(special_value,2)); |
end |
end else |
read_seq <= 0; |
|
// |
// Let's try a write assertion now. Specifically, on any request to |
// write to our special address, we want to assert that the special |
// value at that address can be written. |
reg [2:0] write_seq; |
initial write_seq = 0; |
always @(posedge i_clk) |
if ((special_master < NM)&&(special_slave < NS) |
&&(i_mcyc[special_master]) |
&&(!timed_out[special_master])) |
begin |
write_seq <= 0; |
if ((grant[special_master][special_slave]) |
&&(m_stb[special_master]) |
&&(m_addr[special_master] == special_address) |
&&(m_we[special_master])) |
begin |
// Our write sequence begins when our special master |
// has access to the bus, *and* he is trying to write |
// to our special address. |
write_seq[0] <= 1; |
end |
|
if (|write_seq) |
begin |
assert(grant[special_master][special_slave]); |
assert(mgrant[special_master]); |
assert(sgrant[special_slave]); |
assert(mindex[special_master] == special_slave); |
assert(sindex[special_slave] == special_master); |
assert(!o_merr[special_master]); |
end |
|
if (write_seq[0] && !$past(s_stall[special_slave])) |
begin |
assert(o_scyc[special_slave]); |
assert(o_sstb[special_slave]); |
assert(o_swe[special_slave]); |
assert(o_saddr[special_slave*AW +: AW] == special_address); |
assert(o_sdata[special_slave*DW +: DW] |
== $past(m_data[special_master])); |
assert(o_ssel[special_slave*DW/8 +: DW/8] |
== $past(m_sel[special_master])); |
|
write_seq[1] <= 1; |
|
end else if (write_seq[0] && $past(s_stall[special_slave])) |
begin |
assert($stable(m_stb[special_master])); |
assert(m_we[special_master]); |
assert(m_addr[special_master] == special_address); |
assert($stable(m_data[special_master])); |
assert($stable(m_sel[special_master])); |
|
write_seq[0] <= 1; |
end |
|
if (write_seq[1] && $past(s_stall[special_slave])) |
begin |
assert(o_scyc[special_slave]); |
assert(o_sstb[special_slave]); |
assert(o_swe[special_slave]); |
assert(o_saddr[special_slave*AW +: AW] == special_address); |
assert($stable(o_sdata[special_slave*DW +: DW])); |
assert($stable(o_ssel[special_slave*DW/8 +: DW/8])); |
write_seq[1] <= 1; |
end else if (write_seq[1] && !$past(s_stall[special_slave])) |
begin |
for(iM=0; iM<DW/8; iM=iM+1) |
begin |
if ($past(o_ssel[special_slave * DW/8 + iM])) |
assert(special_value[iM*8 +: 8] |
== $past(o_sdata[special_slave*DW+iM*8 +: 8])); |
end |
|
assert(i_sack[special_slave]); |
if (OPT_DBLBUFFER) |
write_seq[2] <= 1; |
end |
|
if (write_seq[2] || ((!OPT_DBLBUFFER)&&write_seq[1] |
&& !$past(s_stall[special_slave]))) |
assert(o_mack[special_master]); |
end else |
write_seq <= 0; |
|
`endif |
endmodule |