OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.