Line 5... |
Line 5... |
// Project: Pipelined Wishbone to AXI converter
|
// Project: Pipelined Wishbone to AXI converter
|
//
|
//
|
// Purpose: Bridge an AXI read channel pair to a single wishbone read
|
// Purpose: Bridge an AXI read channel pair to a single wishbone read
|
// channel.
|
// 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.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// 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
|
// This file is part of the pipelined Wishbone to AXI converter project, a
|
// modify it under the terms of the GNU General Public License as published
|
// project that contains multiple bus bridging designs and formal bus property
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// sets.
|
// your option) any later version.
|
//
|
//
|
// The bus bridge designs and property sets are free RTL designs: you can
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// redistribute them and/or modify any of them under the terms of the GNU
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// Lesser General Public License as published by the Free Software Foundation,
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// either version 3 of the License, or (at your option) any later version.
|
// for more details.
|
//
|
//
|
// The bus bridge designs and property sets are distributed in the hope that
|
// You should have received a copy of the GNU General Public License along
|
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// target there if the PDF file isn't present.) If not, see
|
// 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.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: LGPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/lgpl.html
|
//
|
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
`default_nettype none
|
`default_nettype none
|
//
|
//
|
|
// module aximrd2wbsp #(
|
module aximrd2wbsp #(
|
module aximrd2wbsp #(
|
parameter C_AXI_ID_WIDTH = 6, // The AXI id width used for R&W
|
parameter C_AXI_ID_WIDTH = 6, // The AXI id width used for R&W
|
// This is an int between 1-16
|
// This is an int between 1-16
|
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data
|
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data
|
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width
|
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width
|
parameter AW = 26, // AXI Address width
|
parameter AW = 26, // AXI Address width
|
parameter LGFIFO = 4
|
parameter LGFIFO = 9 // Must be >= 8
|
// parameter WBMODE = "B4PIPELINE"
|
// parameter WBMODE = "B4PIPELINE"
|
// Could also be "BLOCK"
|
// Could also be "BLOCK"
|
) (
|
) (
|
input wire i_axi_clk, // Bus clock
|
input wire i_axi_clk, // Bus clock
|
input wire i_axi_reset_n, // Bus reset
|
input wire i_axi_reset_n, // Bus reset
|
|
|
// AXI read address channel signals
|
// AXI read address channel signals
|
output wire o_axi_arready, // Read address ready
|
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_ID_WIDTH-1:0] i_axi_arid, // Read ID
|
input wire [C_AXI_ADDR_WIDTH-1:0] i_axi_araddr, // Read address
|
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 [7:0] i_axi_arlen, // Read Burst Length
|
input wire [2:0] i_axi_arsize, // Read Burst size
|
input wire [2:0] i_axi_arsize, // Read Burst size
|
input wire [1:0] i_axi_arburst, // Read Burst type
|
input wire [1:0] i_axi_arburst, // Read Burst type
|
Line 73... |
Line 85... |
input wire i_axi_rready, // Read Response ready
|
input wire i_axi_rready, // Read Response ready
|
|
|
// We'll share the clock and the reset
|
// We'll share the clock and the reset
|
output reg o_wb_cyc,
|
output reg o_wb_cyc,
|
output reg o_wb_stb,
|
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_ack,
|
input wire i_wb_stall,
|
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
|
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;
|
localparam DW = C_AXI_DATA_WIDTH;
|
|
|
wire w_reset;
|
wire w_reset;
|
assign w_reset = (i_axi_reset_n == 1'b0);
|
assign w_reset = (i_axi_reset_n == 1'b0);
|
|
|
|
|
reg [(C_AXI_ID_WIDTH+AW+1)-1:0] afifo [0:((1<<(LGFIFO))-1)];
|
wire [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] i_rd_request;
|
reg [(DW+1)-1:0] dfifo [0:((1<<(LGFIFO))-1)];
|
reg [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] r_rd_request;
|
reg [(C_AXI_ID_WIDTH+AW+1)-1:0] fifo_at_neck, afifo_at_tail;
|
wire [C_AXI_ID_WIDTH+C_AXI_ADDR_WIDTH+25-1:0] w_rd_request;
|
reg [(DW+1)-1:0] dfifo_at_tail;
|
|
|
reg [LGFIFO:0] next_ackptr, next_rptr;
|
|
|
|
reg [C_AXI_ID_WIDTH:0] request_fifo [0:((1<<LGFIFO)-1)];
|
|
reg [C_AXI_ID_WIDTH:0] rsp_data;
|
|
|
|
reg [C_AXI_DATA_WIDTH:0] response_fifo [0:((1<<LGFIFO)-1)];
|
|
reg [C_AXI_DATA_WIDTH:0] ack_data;
|
|
|
|
reg advance_ack;
|
|
|
|
|
|
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;
|
|
|
// 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;
|
|
|
|
// 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;
|
|
|
|
assign fifo_full = (almost_head == fifo_tail);
|
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 };
|
|
|
reg wr_last, filling_fifo, incr;
|
initial r_rd_request = 0;
|
reg [7:0] len;
|
initial r_valid = 0;
|
reg [(AW-1):0] wr_fifo_addr;
|
|
reg [(C_AXI_ID_WIDTH-1):0] wr_fifo_id;
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// 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;
|
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
|
if (!i_axi_reset_n)
|
begin
|
begin
|
wr_last <= 1'b0;
|
r_rd_request <= 0;
|
|
r_valid <= 1'b0;
|
if (filling_fifo)
|
end else if ((i_axi_arvalid)&&(o_axi_arready))
|
begin
|
begin
|
if (!fifo_full)
|
r_rd_request <= i_rd_request;
|
begin
|
if (!accept_request)
|
len <= len - 1;
|
r_valid <= 1'b1;
|
if (len == 1)
|
end else if (accept_request)
|
filling_fifo <= 1'b0;
|
r_valid <= 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
|
|
|
|
if (w_reset)
|
|
begin
|
|
len <= 0;
|
|
filling_fifo <= 1'b0;
|
|
fifo_head <= 0;
|
|
end
|
|
end
|
|
|
|
always @(posedge i_axi_clk)
|
always @(*)
|
afifo[fifo_head] <= { wr_fifo_id, wr_last, wr_fifo_addr };
|
o_axi_arready = !r_valid;
|
|
|
reg err_state;
|
/*
|
initial o_wb_cyc = 1'b0;
|
assign r_id = r_rd_request[25 + C_AXI_ADDR_WIDTH +: C_AXI_ID_WIDTH];
|
initial o_wb_stb = 1'b0;
|
assign r_addr = r_rd_request[25 +: C_AXI_ADDR_WIDTH];
|
initial fifo_neck = 0;
|
assign r_len = r_rd_request[17 +: 8];
|
initial fifo_torso = 0;
|
assign r_size = r_rd_request[14 +: 3];
|
initial err_state = 0;
|
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];
|
|
*/
|
|
|
|
assign w_rd_request = (r_valid) ? (r_rd_request) : i_rd_request;
|
|
|
|
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)
|
always @(posedge i_axi_clk)
|
begin
|
|
if (w_reset)
|
if (w_reset)
|
begin
|
begin
|
o_wb_cyc <= 1'b0;
|
|
o_wb_stb <= 1'b0;
|
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
|
|
// Process the new request
|
|
o_wb_cyc <= 1'b1;
|
|
o_wb_stb <= 1'b1;
|
|
last_stb <= (w_len == 0);
|
|
|
fifo_neck <= 0;
|
o_wb_addr <= w_addr[(C_AXI_ADDR_WIDTH-1):(C_AXI_ADDR_WIDTH-AW)];
|
fifo_torso <= 0;
|
incr <= w_burst[0];
|
|
stblen <= w_len;
|
err_state <= 0;
|
axi_id <= w_id;
|
end else if (o_wb_stb)
|
// end else if ((o_wb_cyc)&&(i_wb_err)||(err_state))
|
|
end else if (o_wb_stb && !last_stb)
|
begin
|
begin
|
|
// Step forward on the burst request
|
|
last_stb <= (stblen == 1);
|
|
|
|
o_wb_addr <= o_wb_addr + ((incr)? 1'b1:1'b0);
|
|
stblen <= stblen - 1'b1;
|
|
|
if (i_wb_err)
|
if (i_wb_err)
|
begin
|
begin
|
|
stblen <= 0;
|
o_wb_stb <= 1'b0;
|
o_wb_stb <= 1'b0;
|
err_state <= 1'b1;
|
o_wb_cyc <= 1'b0;
|
end else if (!i_wb_stall)
|
|
begin
|
|
o_wb_stb <= (fifo_head != next_neck);
|
|
// && (WBMODE != "B3SINGLE");
|
|
// o_wb_cyc <= (WBMODE != "B3SINGLE");
|
|
end
|
end
|
|
end else if (!o_wb_stb || last_stb)
|
if (!i_wb_stall)
|
|
fifo_neck <= next_neck;
|
|
if (i_wb_ack)
|
|
fifo_torso <= next_torso;
|
|
end else if (err_state)
|
|
begin
|
begin
|
fifo_torso <= next_torso;
|
// End the request
|
if (fifo_neck == next_torso)
|
o_wb_stb <= 1'b0;
|
err_state <= 1'b0;
|
last_stb <= 1'b0;
|
|
stblen <= 0;
|
|
|
|
// Check for the last acknowledgment
|
|
if ((i_wb_ack)&&(last_ack))
|
o_wb_cyc <= 1'b0;
|
o_wb_cyc <= 1'b0;
|
end else if (o_wb_cyc)
|
if (i_wb_err)
|
begin
|
|
if (i_wb_ack)
|
|
fifo_torso <= next_torso;
|
|
if (fifo_neck == next_torso)
|
|
o_wb_cyc <= 1'b0;
|
o_wb_cyc <= 1'b0;
|
end else if (fifo_neck != fifo_head)
|
end
|
|
end else if ((o_wb_cyc)&&(i_wb_err))
|
begin
|
begin
|
o_wb_cyc <= 1'b1;
|
stblen <= 0;
|
o_wb_stb <= 1'b1;
|
o_wb_stb <= 1'b0;
|
|
o_wb_cyc <= 1'b0;
|
|
last_stb <= 1'b0;
|
end
|
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
|
end
|
|
|
|
initial fifo_wptr = 0;
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
fifo_at_neck <= afifo[fifo_neck];
|
if (w_reset)
|
assign o_wb_addr = fifo_at_neck[(AW-1):0];
|
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)
|
|
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)
|
always @(posedge i_axi_clk)
|
dfifo[fifo_torso] <= { (err_state)||(i_wb_err), i_wb_data };
|
if ((o_wb_stb)&&(!i_wb_stall))
|
|
request_fifo[fifo_wptr[LGFIFO-1:0]] <= { last_stb, axi_id };
|
|
|
|
always @(posedge i_axi_clk)
|
|
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)
|
always @(posedge i_axi_clk)
|
if (w_reset)
|
if (w_reset)
|
fifo_tail <= 0;
|
fifo_rptr <= 0;
|
else if ((o_axi_rvalid)&&(i_axi_rready))
|
else if ((o_axi_rvalid)&&(i_axi_rready))
|
fifo_tail <= next_tail;
|
fifo_rptr <= fifo_rptr + 1'b1;
|
|
|
|
always @(*)
|
|
next_rptr = fifo_rptr + 1'b1;
|
|
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
begin
|
if (advance_ack)
|
afifo_at_tail <= afifo[fifo_tail];
|
ack_data <= response_fifo[fifo_rptr[LGFIFO-1:0]];
|
dfifo_at_tail <= dfifo[fifo_tail];
|
|
// o_axi_rdata <= dfifo[fifo_tail];
|
always @(posedge i_axi_clk)
|
// o_axi_rlast <= afifo[fifo_tail];
|
if (advance_ack)
|
// o_axi_rid <= afifo[fifo_tail];
|
rsp_data <= request_fifo[fifo_rptr[LGFIFO-1:0]];
|
end
|
|
assign o_axi_rlast = afifo_at_tail[AW];
|
always @(*)
|
assign o_axi_rid = afifo_at_tail[(C_AXI_ID_WIDTH+AW):(AW+1)];
|
if ((o_axi_rvalid)&&(i_axi_rready))
|
assign o_axi_rresp = { (2){dfifo_at_tail[DW]} };
|
advance_ack = (fifo_ackptr != next_rptr);
|
assign o_axi_rdata = dfifo_at_tail[(DW-1):0];
|
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 o_axi_rvalid = 1'b0;
|
initial err_state = 0;
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
if (w_reset)
|
if (w_reset)
|
o_axi_rvalid <= 0;
|
err_state <= 1'b0;
|
else if (fifo_tail != fifo_neck)
|
else if ((o_wb_cyc)&&(i_wb_err))
|
o_axi_rvalid <= (fifo_tail != fifo_neck + 1);
|
err_state <= 1'b1;
|
|
else if ((!o_wb_stb)&&(fifo_wptr == fifo_rptr))
|
|
err_state <= 1'b0;
|
|
|
assign o_axi_arready = (!fifo_full)&&(!filling_fifo);
|
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
|
// Make Verilator happy
|
// verilator lint_off UNUSED
|
// verilator lint_off UNUSED
|
wire [(C_AXI_ID_WIDTH+1)+(C_AXI_ADDR_WIDTH-AW)
|
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],
|
assign unused = { i_axi_arsize, i_axi_arburst[1],
|
i_axi_arlock, i_axi_arcache, i_axi_arprot,
|
i_axi_arlock, i_axi_arcache, i_axi_arprot, i_axi_arqos,
|
i_axi_arqos,
|
w_burst[1], w_size, w_lock, w_cache, w_prot, w_qos, w_addr[1:0],
|
fifo_at_neck[(C_AXI_ID_WIDTH+AW+1)-1:AW],
|
|
i_axi_araddr[(C_AXI_ADDR_WIDTH-AW-1):0] };
|
i_axi_araddr[(C_AXI_ADDR_WIDTH-AW-1):0] };
|
// verilator lint_on UNUSED
|
// verilator lint_on UNUSED
|
|
|
`ifdef FORMAL
|
`ifdef FORMAL
|
reg f_past_valid;
|
reg f_past_valid;
|
initial f_past_valid = 1'b0;
|
initial f_past_valid = 1'b0;
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
f_past_valid <= 1'b1;
|
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;
|
// Assumptions
|
assign f_fifo_neck_used = fifo_head - fifo_neck;
|
//
|
assign f_fifo_torso_used = fifo_head - fifo_torso;
|
//
|
|
always @(*)
|
|
if (!f_past_valid)
|
|
assume(w_reset);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Ad-hoc assertions
|
|
//
|
|
//
|
always @(*)
|
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 @(*)
|
|
assume(!i_wb_err);
|
|
always @(*)
|
|
assert(!err_state);
|
|
*/
|
always @(*)
|
always @(*)
|
assert(f_fifo_neck_used <= f_fifo_used);
|
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 @(*)
|
always @(*)
|
assert(f_fifo_torso_used <= f_fifo_used);
|
assert(f_fifo_wb_used <= f_fifo_used);
|
|
always @(*)
|
|
assert(f_fifo_ackremain <= f_fifo_used);
|
|
|
|
// Reset properties
|
always @(posedge i_axi_clk)
|
always @(posedge i_axi_clk)
|
if ((f_past_valid)&&(!$past(i_axi_reset_n)))
|
if ((!f_past_valid)||($past(w_reset)))
|
assert(f_fifo_used == 0);
|
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
|
`endif
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|