OpenCores
URL https://opencores.org/ocsvn/wb2axip/wb2axip/trunk

Subversion Repositories wb2axip

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /wb2axip/trunk/rtl
    from Rev 15 to Rev 16
    Reverse comparison

Rev 15 → Rev 16

/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)/
 
/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
/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
/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
 
/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
/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
 
/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
 
/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
/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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
/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
 
/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
/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
/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.