1 |
2 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
8 |
dgisselq |
// Filename: wbm2axisp.v (Wishbone master to AXI slave, pipelined)
|
4 |
2 |
dgisselq |
//
|
5 |
|
|
// Project: Pipelined Wishbone to AXI converter
|
6 |
|
|
//
|
7 |
|
|
// Purpose: The B4 Wishbone SPEC allows transactions at a speed as fast as
|
8 |
|
|
// one per clock. The AXI bus allows transactions at a speed of
|
9 |
|
|
// one read and one write transaction per clock. These capabilities work
|
10 |
|
|
// by allowing requests to take place prior to responses, such that the
|
11 |
|
|
// requests might go out at once per clock and take several clocks, and
|
12 |
|
|
// the responses may start coming back several clocks later. In other
|
13 |
|
|
// words, both protocols allow multiple transactions to be "in flight" at
|
14 |
|
|
// the same time. Current wishbone to AXI converters, however, handle only
|
15 |
|
|
// one transaction at a time: initiating the transaction, and then waiting
|
16 |
|
|
// for the transaction to complete before initiating the next.
|
17 |
|
|
//
|
18 |
|
|
// The purpose of this core is to maintain the speed of both busses, while
|
19 |
|
|
// transiting from the Wishbone (as master) to the AXI bus (as slave) and
|
20 |
|
|
// back again.
|
21 |
|
|
//
|
22 |
8 |
dgisselq |
// Since the AXI bus allows transactions to be reordered, whereas the
|
23 |
2 |
dgisselq |
// wishbone does not, this core can be configured to reorder return
|
24 |
|
|
// transactions as well.
|
25 |
|
|
//
|
26 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
27 |
|
|
// Gisselquist Technology, LLC
|
28 |
|
|
//
|
29 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
30 |
|
|
//
|
31 |
3 |
dgisselq |
// Copyright (C) 2016, Gisselquist Technology, LLC
|
32 |
2 |
dgisselq |
//
|
33 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
34 |
|
|
// modify it under the terms of the GNU General Public License as published
|
35 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
36 |
|
|
// your option) any later version.
|
37 |
|
|
//
|
38 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
39 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
40 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
41 |
|
|
// for more details.
|
42 |
|
|
//
|
43 |
|
|
// You should have received a copy of the GNU General Public License along
|
44 |
|
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
45 |
|
|
// target there if the PDF file isn't present.) If not, see
|
46 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
47 |
|
|
//
|
48 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
49 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
50 |
|
|
//
|
51 |
|
|
//
|
52 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
53 |
|
|
//
|
54 |
|
|
//
|
55 |
8 |
dgisselq |
`default_nettype none
|
56 |
|
|
//
|
57 |
2 |
dgisselq |
module wbm2axisp #(
|
58 |
8 |
dgisselq |
parameter C_AXI_ID_WIDTH = 3, // The AXI id width used for R&W
|
59 |
2 |
dgisselq |
// This is an int between 1-16
|
60 |
8 |
dgisselq |
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data
|
61 |
|
|
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width (log wordsize)
|
62 |
|
|
parameter DW = 8, // Wishbone data width
|
63 |
|
|
parameter AW = 26, // Wishbone address width (log wordsize)
|
64 |
|
|
parameter [0:0] STRICT_ORDER = 1 // Reorder, or not? 0 -> Reorder
|
65 |
2 |
dgisselq |
) (
|
66 |
|
|
input i_clk, // System clock
|
67 |
6 |
dgisselq |
// input i_reset,// Wishbone reset signal--unused
|
68 |
2 |
dgisselq |
|
69 |
|
|
// AXI write address channel signals
|
70 |
5 |
dgisselq |
input i_axi_awready, // Slave is ready to accept
|
71 |
6 |
dgisselq |
output reg [C_AXI_ID_WIDTH-1:0] o_axi_awid, // Write ID
|
72 |
|
|
output reg [C_AXI_ADDR_WIDTH-1:0] o_axi_awaddr, // Write address
|
73 |
5 |
dgisselq |
output wire [7:0] o_axi_awlen, // Write Burst Length
|
74 |
|
|
output wire [2:0] o_axi_awsize, // Write Burst size
|
75 |
|
|
output wire [1:0] o_axi_awburst, // Write Burst type
|
76 |
6 |
dgisselq |
output wire [0:0] o_axi_awlock, // Write lock type
|
77 |
5 |
dgisselq |
output wire [3:0] o_axi_awcache, // Write Cache type
|
78 |
|
|
output wire [2:0] o_axi_awprot, // Write Protection type
|
79 |
|
|
output wire [3:0] o_axi_awqos, // Write Quality of Svc
|
80 |
|
|
output reg o_axi_awvalid, // Write address valid
|
81 |
8 |
dgisselq |
|
82 |
2 |
dgisselq |
// AXI write data channel signals
|
83 |
5 |
dgisselq |
input i_axi_wready, // Write data ready
|
84 |
|
|
output reg [C_AXI_DATA_WIDTH-1:0] o_axi_wdata, // Write data
|
85 |
|
|
output reg [C_AXI_DATA_WIDTH/8-1:0] o_axi_wstrb, // Write strobes
|
86 |
8 |
dgisselq |
output wire o_axi_wlast, // Last write transaction
|
87 |
5 |
dgisselq |
output reg o_axi_wvalid, // Write valid
|
88 |
8 |
dgisselq |
|
89 |
2 |
dgisselq |
// AXI write response channel signals
|
90 |
5 |
dgisselq |
input [C_AXI_ID_WIDTH-1:0] i_axi_bid, // Response ID
|
91 |
|
|
input [1:0] i_axi_bresp, // Write response
|
92 |
|
|
input i_axi_bvalid, // Write reponse valid
|
93 |
|
|
output wire o_axi_bready, // Response ready
|
94 |
8 |
dgisselq |
|
95 |
2 |
dgisselq |
// AXI read address channel signals
|
96 |
5 |
dgisselq |
input i_axi_arready, // Read address ready
|
97 |
|
|
output wire [C_AXI_ID_WIDTH-1:0] o_axi_arid, // Read ID
|
98 |
6 |
dgisselq |
output wire [C_AXI_ADDR_WIDTH-1:0] o_axi_araddr, // Read address
|
99 |
5 |
dgisselq |
output wire [7:0] o_axi_arlen, // Read Burst Length
|
100 |
|
|
output wire [2:0] o_axi_arsize, // Read Burst size
|
101 |
|
|
output wire [1:0] o_axi_arburst, // Read Burst type
|
102 |
6 |
dgisselq |
output wire [0:0] o_axi_arlock, // Read lock type
|
103 |
5 |
dgisselq |
output wire [3:0] o_axi_arcache, // Read Cache type
|
104 |
|
|
output wire [2:0] o_axi_arprot, // Read Protection type
|
105 |
|
|
output wire [3:0] o_axi_arqos, // Read Protection type
|
106 |
|
|
output reg o_axi_arvalid, // Read address valid
|
107 |
8 |
dgisselq |
|
108 |
|
|
// AXI read data channel signals
|
109 |
5 |
dgisselq |
input [C_AXI_ID_WIDTH-1:0] i_axi_rid, // Response ID
|
110 |
|
|
input [1:0] i_axi_rresp, // Read response
|
111 |
|
|
input i_axi_rvalid, // Read reponse valid
|
112 |
|
|
input [C_AXI_DATA_WIDTH-1:0] i_axi_rdata, // Read data
|
113 |
|
|
input i_axi_rlast, // Read last
|
114 |
|
|
output wire o_axi_rready, // Read Response ready
|
115 |
2 |
dgisselq |
|
116 |
|
|
// We'll share the clock and the reset
|
117 |
3 |
dgisselq |
input i_wb_cyc,
|
118 |
|
|
input i_wb_stb,
|
119 |
|
|
input i_wb_we,
|
120 |
6 |
dgisselq |
input [(AW-1):0] i_wb_addr,
|
121 |
|
|
input [(DW-1):0] i_wb_data,
|
122 |
4 |
dgisselq |
input [(DW/8-1):0] i_wb_sel,
|
123 |
3 |
dgisselq |
output reg o_wb_ack,
|
124 |
|
|
output wire o_wb_stall,
|
125 |
6 |
dgisselq |
output reg [(DW-1):0] o_wb_data,
|
126 |
3 |
dgisselq |
output reg o_wb_err
|
127 |
2 |
dgisselq |
);
|
128 |
|
|
|
129 |
|
|
//*****************************************************************************
|
130 |
|
|
// Parameter declarations
|
131 |
|
|
//*****************************************************************************
|
132 |
|
|
|
133 |
8 |
dgisselq |
localparam LG_AXI_DW = ( C_AXI_DATA_WIDTH == 8) ? 3
|
134 |
|
|
: ((C_AXI_DATA_WIDTH == 16) ? 4
|
135 |
|
|
: ((C_AXI_DATA_WIDTH == 32) ? 5
|
136 |
|
|
: ((C_AXI_DATA_WIDTH == 64) ? 6
|
137 |
|
|
: ((C_AXI_DATA_WIDTH == 128) ? 7
|
138 |
|
|
: 8))));
|
139 |
2 |
dgisselq |
|
140 |
8 |
dgisselq |
localparam LG_WB_DW = ( DW == 8) ? 3
|
141 |
|
|
: ((DW == 16) ? 4
|
142 |
|
|
: ((DW == 32) ? 5
|
143 |
|
|
: ((DW == 64) ? 6
|
144 |
|
|
: ((DW == 128) ? 7
|
145 |
|
|
: 8))));
|
146 |
|
|
localparam LGFIFOLN = C_AXI_ID_WIDTH;
|
147 |
|
|
localparam FIFOLN = (1<<LGFIFOLN);
|
148 |
|
|
|
149 |
|
|
|
150 |
2 |
dgisselq |
//*****************************************************************************
|
151 |
|
|
// Internal register and wire declarations
|
152 |
|
|
//*****************************************************************************
|
153 |
|
|
|
154 |
|
|
// Things we're not changing ...
|
155 |
8 |
dgisselq |
assign o_axi_awlen = 8'h0; // Burst length is one
|
156 |
|
|
assign o_axi_awsize = 3'b101; // maximum bytes per burst is 32
|
157 |
5 |
dgisselq |
assign o_axi_awburst = 2'b01; // Incrementing address (ignored)
|
158 |
|
|
assign o_axi_arburst = 2'b01; // Incrementing address (ignored)
|
159 |
6 |
dgisselq |
assign o_axi_awlock = 1'b0; // Normal signaling
|
160 |
|
|
assign o_axi_arlock = 1'b0; // Normal signaling
|
161 |
5 |
dgisselq |
assign o_axi_awcache = 4'h2; // Normal: no cache, no buffer
|
162 |
|
|
assign o_axi_arcache = 4'h2; // Normal: no cache, no buffer
|
163 |
6 |
dgisselq |
assign o_axi_awprot = 3'b010; // Unpriviledged, unsecure, data access
|
164 |
|
|
assign o_axi_arprot = 3'b010; // Unpriviledged, unsecure, data access
|
165 |
8 |
dgisselq |
assign o_axi_awqos = 4'h0; // Lowest quality of service (unused)
|
166 |
|
|
assign o_axi_arqos = 4'h0; // Lowest quality of service (unused)
|
167 |
2 |
dgisselq |
|
168 |
8 |
dgisselq |
reg wb_mid_cycle, wb_last_cyc_stb, wb_mid_abort;
|
169 |
|
|
wire wb_cyc_stb;
|
170 |
2 |
dgisselq |
// Command logic
|
171 |
8 |
dgisselq |
// Transaction ID logic
|
172 |
|
|
wire [(LGFIFOLN-1):0] fifo_head;
|
173 |
|
|
reg [(C_AXI_ID_WIDTH-1):0] transaction_id;
|
174 |
|
|
|
175 |
|
|
initial transaction_id = 0;
|
176 |
|
|
always @(posedge i_clk)
|
177 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
178 |
|
|
transaction_id <= transaction_id + 1'b1;
|
179 |
|
|
|
180 |
|
|
assign fifo_head = transaction_id;
|
181 |
|
|
|
182 |
|
|
wire [(DW/8-1):0] no_sel;
|
183 |
|
|
wire [(LG_AXI_DW-4):0] axi_bottom_addr;
|
184 |
|
|
assign no_sel = 0;
|
185 |
|
|
assign axi_bottom_addr = 0;
|
186 |
|
|
|
187 |
|
|
|
188 |
2 |
dgisselq |
// Write address logic
|
189 |
|
|
|
190 |
8 |
dgisselq |
initial o_axi_awvalid = 0;
|
191 |
2 |
dgisselq |
always @(posedge i_clk)
|
192 |
5 |
dgisselq |
o_axi_awvalid <= (!o_wb_stall)&&(i_wb_stb)&&(i_wb_we)
|
193 |
8 |
dgisselq |
||(o_axi_awvalid)&&(!i_axi_awready);
|
194 |
2 |
dgisselq |
|
195 |
6 |
dgisselq |
generate
|
196 |
8 |
dgisselq |
|
197 |
|
|
initial o_axi_awid = -1;
|
198 |
|
|
always @(posedge i_clk)
|
199 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
200 |
|
|
o_axi_awid <= transaction_id;
|
201 |
|
|
|
202 |
|
|
if (C_AXI_DATA_WIDTH == DW)
|
203 |
6 |
dgisselq |
begin
|
204 |
|
|
always @(posedge i_clk)
|
205 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall)) // 26 bit address becomes 28 bit ...
|
206 |
|
|
o_axi_awaddr <= { i_wb_addr[AW-1:0], axi_bottom_addr };
|
207 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 2)
|
208 |
6 |
dgisselq |
begin
|
209 |
8 |
dgisselq |
|
210 |
6 |
dgisselq |
always @(posedge i_clk)
|
211 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall)) // 26 bit address becomes 28 bit ...
|
212 |
|
|
o_axi_awaddr <= { i_wb_addr[AW-1:1], axi_bottom_addr };
|
213 |
|
|
|
214 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 4)
|
215 |
|
|
begin
|
216 |
|
|
always @(posedge i_clk)
|
217 |
|
|
if ((i_wb_stb)&&(!o_wb_stall)) // 26 bit address becomes 28 bit ...
|
218 |
|
|
o_axi_awaddr <= { i_wb_addr[AW-1:2], axi_bottom_addr };
|
219 |
6 |
dgisselq |
end endgenerate
|
220 |
|
|
|
221 |
2 |
dgisselq |
|
222 |
|
|
// Read address logic
|
223 |
8 |
dgisselq |
assign o_axi_arid = o_axi_awid;
|
224 |
5 |
dgisselq |
assign o_axi_araddr = o_axi_awaddr;
|
225 |
|
|
assign o_axi_arlen = o_axi_awlen;
|
226 |
|
|
assign o_axi_arsize = 3'b101; // maximum bytes per burst is 32
|
227 |
8 |
dgisselq |
initial o_axi_arvalid = 1'b0;
|
228 |
2 |
dgisselq |
always @(posedge i_clk)
|
229 |
5 |
dgisselq |
o_axi_arvalid <= (!o_wb_stall)&&(i_wb_stb)&&(!i_wb_we)
|
230 |
8 |
dgisselq |
||(o_axi_arvalid)&&(!i_axi_arready);
|
231 |
2 |
dgisselq |
|
232 |
|
|
// Write data logic
|
233 |
4 |
dgisselq |
generate
|
234 |
8 |
dgisselq |
if (C_AXI_DATA_WIDTH == DW)
|
235 |
4 |
dgisselq |
begin
|
236 |
8 |
dgisselq |
|
237 |
4 |
dgisselq |
always @(posedge i_clk)
|
238 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall))
|
239 |
|
|
o_axi_wdata <= i_wb_data;
|
240 |
|
|
|
241 |
4 |
dgisselq |
always @(posedge i_clk)
|
242 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall))
|
243 |
|
|
o_axi_wstrb<= i_wb_sel;
|
244 |
|
|
|
245 |
|
|
end else if (C_AXI_DATA_WIDTH/2 == DW)
|
246 |
|
|
begin
|
247 |
|
|
|
248 |
|
|
always @(posedge i_clk)
|
249 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
250 |
|
|
o_axi_wdata <= { i_wb_data, i_wb_data };
|
251 |
|
|
|
252 |
|
|
always @(posedge i_clk)
|
253 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
254 |
|
|
case(i_wb_addr[0])
|
255 |
|
|
1'b0:o_axi_wstrb<={ no_sel,i_wb_sel };
|
256 |
|
|
1'b1:o_axi_wstrb<={i_wb_sel, no_sel };
|
257 |
4 |
dgisselq |
endcase
|
258 |
8 |
dgisselq |
|
259 |
|
|
end else if (C_AXI_DATA_WIDTH/4 == DW)
|
260 |
4 |
dgisselq |
begin
|
261 |
8 |
dgisselq |
|
262 |
4 |
dgisselq |
always @(posedge i_clk)
|
263 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall))
|
264 |
|
|
o_axi_wdata <= { i_wb_data, i_wb_data, i_wb_data, i_wb_data };
|
265 |
|
|
|
266 |
4 |
dgisselq |
always @(posedge i_clk)
|
267 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall))
|
268 |
|
|
case(i_wb_addr[1:0])
|
269 |
|
|
2'b00:o_axi_wstrb<={ no_sel, no_sel, no_sel, i_wb_sel };
|
270 |
|
|
2'b01:o_axi_wstrb<={ no_sel, no_sel, i_wb_sel, no_sel };
|
271 |
|
|
2'b10:o_axi_wstrb<={ no_sel, i_wb_sel, no_sel, no_sel };
|
272 |
|
|
2'b11:o_axi_wstrb<={ i_wb_sel, no_sel, no_sel, no_sel };
|
273 |
|
|
endcase
|
274 |
|
|
|
275 |
4 |
dgisselq |
end endgenerate
|
276 |
|
|
|
277 |
5 |
dgisselq |
assign o_axi_wlast = 1'b1;
|
278 |
8 |
dgisselq |
initial o_axi_wvalid = 0;
|
279 |
2 |
dgisselq |
always @(posedge i_clk)
|
280 |
5 |
dgisselq |
o_axi_wvalid <= ((!o_wb_stall)&&(i_wb_stb)&&(i_wb_we))
|
281 |
8 |
dgisselq |
||(o_axi_wvalid)&&(!i_axi_wready);
|
282 |
2 |
dgisselq |
|
283 |
8 |
dgisselq |
// Read data channel / response logic
|
284 |
5 |
dgisselq |
assign o_axi_rready = 1'b1;
|
285 |
|
|
assign o_axi_bready = 1'b1;
|
286 |
2 |
dgisselq |
|
287 |
8 |
dgisselq |
wire [(LGFIFOLN-1):0] n_fifo_head, nn_fifo_head;
|
288 |
|
|
assign n_fifo_head = fifo_head+1'b1;
|
289 |
|
|
assign nn_fifo_head = { fifo_head[(LGFIFOLN-1):1]+1'b1, fifo_head[0] };
|
290 |
|
|
|
291 |
|
|
|
292 |
2 |
dgisselq |
wire w_fifo_full;
|
293 |
8 |
dgisselq |
reg [(LGFIFOLN-1):0] fifo_tail;
|
294 |
|
|
|
295 |
2 |
dgisselq |
generate
|
296 |
8 |
dgisselq |
if (C_AXI_DATA_WIDTH == DW)
|
297 |
2 |
dgisselq |
begin
|
298 |
8 |
dgisselq |
if (STRICT_ORDER == 0)
|
299 |
|
|
begin
|
300 |
|
|
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data [0:(FIFOLN-1)];
|
301 |
3 |
dgisselq |
|
302 |
8 |
dgisselq |
always @(posedge i_clk)
|
303 |
|
|
if ((o_axi_rready)&&(i_axi_rvalid))
|
304 |
|
|
reorder_fifo_data[i_axi_rid] <= i_axi_rdata;
|
305 |
|
|
always @(posedge i_clk)
|
306 |
|
|
o_wb_data <= reorder_fifo_data[fifo_tail];
|
307 |
|
|
end else begin
|
308 |
|
|
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data;
|
309 |
6 |
dgisselq |
|
310 |
8 |
dgisselq |
always @(posedge i_clk)
|
311 |
|
|
reorder_fifo_data <= i_axi_rdata;
|
312 |
|
|
always @(posedge i_clk)
|
313 |
|
|
o_wb_data <= reorder_fifo_data;
|
314 |
|
|
end
|
315 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 2)
|
316 |
|
|
begin
|
317 |
|
|
reg reorder_fifo_addr [0:(FIFOLN-1)];
|
318 |
|
|
|
319 |
|
|
reg low_addr;
|
320 |
|
|
always @(posedge i_clk)
|
321 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
322 |
|
|
low_addr <= i_wb_addr[0];
|
323 |
|
|
always @(posedge i_clk)
|
324 |
|
|
if ((o_axi_arvalid)&&(i_axi_arready))
|
325 |
|
|
reorder_fifo_addr[o_axi_arid] <= low_addr;
|
326 |
|
|
|
327 |
|
|
if (STRICT_ORDER == 0)
|
328 |
4 |
dgisselq |
begin
|
329 |
8 |
dgisselq |
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data [0:(FIFOLN-1)];
|
330 |
3 |
dgisselq |
|
331 |
8 |
dgisselq |
always @(posedge i_clk)
|
332 |
|
|
if ((o_axi_rready)&&(i_axi_rvalid))
|
333 |
|
|
reorder_fifo_data[i_axi_rid] <= i_axi_rdata;
|
334 |
|
|
always @(posedge i_clk)
|
335 |
|
|
reorder_fifo_data[i_axi_rid] <= i_axi_rdata;
|
336 |
|
|
always @(posedge i_clk)
|
337 |
|
|
case(reorder_fifo_addr[fifo_tail])
|
338 |
|
|
1'b0: o_wb_data <=reorder_fifo_data[fifo_tail][( DW-1): 0 ];
|
339 |
|
|
1'b1: o_wb_data <=reorder_fifo_data[fifo_tail][(2*DW-1):( DW)];
|
340 |
|
|
endcase
|
341 |
|
|
end else begin
|
342 |
|
|
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data;
|
343 |
3 |
dgisselq |
|
344 |
4 |
dgisselq |
always @(posedge i_clk)
|
345 |
8 |
dgisselq |
reorder_fifo_data <= i_axi_rdata;
|
346 |
4 |
dgisselq |
always @(posedge i_clk)
|
347 |
8 |
dgisselq |
case(reorder_fifo_addr[fifo_tail])
|
348 |
|
|
1'b0: o_wb_data <=reorder_fifo_data[( DW-1): 0 ];
|
349 |
|
|
1'b1: o_wb_data <=reorder_fifo_data[(2*DW-1):( DW)];
|
350 |
|
|
endcase
|
351 |
|
|
end
|
352 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 4)
|
353 |
|
|
begin
|
354 |
|
|
reg [1:0] reorder_fifo_addr [0:(FIFOLN-1)];
|
355 |
3 |
dgisselq |
|
356 |
8 |
dgisselq |
|
357 |
|
|
reg [1:0] low_addr;
|
358 |
|
|
always @(posedge i_clk)
|
359 |
|
|
if ((i_wb_stb)&&(!o_wb_stall))
|
360 |
|
|
low_addr <= i_wb_addr[1:0];
|
361 |
|
|
always @(posedge i_clk)
|
362 |
|
|
if ((o_axi_arvalid)&&(i_axi_arready))
|
363 |
|
|
reorder_fifo_addr[o_axi_arid] <= low_addr;
|
364 |
|
|
|
365 |
|
|
if (STRICT_ORDER == 0)
|
366 |
|
|
begin
|
367 |
|
|
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data [0:(FIFOLN-1)];
|
368 |
|
|
|
369 |
4 |
dgisselq |
always @(posedge i_clk)
|
370 |
8 |
dgisselq |
if ((o_axi_rready)&&(i_axi_rvalid))
|
371 |
|
|
reorder_fifo_data[i_axi_rid] <= i_axi_rdata;
|
372 |
|
|
always @(posedge i_clk)
|
373 |
6 |
dgisselq |
case(reorder_fifo_addr[fifo_tail][1:0])
|
374 |
8 |
dgisselq |
2'b00: o_wb_data <=reorder_fifo_data[fifo_tail][( DW-1): 0 ];
|
375 |
|
|
2'b01: o_wb_data <=reorder_fifo_data[fifo_tail][(2*DW-1):( DW)];
|
376 |
|
|
2'b10: o_wb_data <=reorder_fifo_data[fifo_tail][(3*DW-1):(2*DW)];
|
377 |
|
|
2'b11: o_wb_data <=reorder_fifo_data[fifo_tail][(4*DW-1):(3*DW)];
|
378 |
4 |
dgisselq |
endcase
|
379 |
8 |
dgisselq |
end else begin
|
380 |
|
|
reg [(C_AXI_DATA_WIDTH-1):0] reorder_fifo_data;
|
381 |
4 |
dgisselq |
|
382 |
|
|
always @(posedge i_clk)
|
383 |
8 |
dgisselq |
reorder_fifo_data <= i_axi_rdata;
|
384 |
|
|
always @(posedge i_clk)
|
385 |
|
|
case(reorder_fifo_addr[fifo_tail][1:0])
|
386 |
|
|
2'b00: o_wb_data <=reorder_fifo_data[( DW-1): 0];
|
387 |
|
|
2'b01: o_wb_data <=reorder_fifo_data[(2*DW-1):( DW)];
|
388 |
|
|
2'b10: o_wb_data <=reorder_fifo_data[(3*DW-1):(2*DW)];
|
389 |
|
|
2'b11: o_wb_data <=reorder_fifo_data[(4*DW-1):(3*DW)];
|
390 |
|
|
endcase
|
391 |
4 |
dgisselq |
end
|
392 |
8 |
dgisselq |
end
|
393 |
4 |
dgisselq |
|
394 |
8 |
dgisselq |
endgenerate
|
395 |
4 |
dgisselq |
|
396 |
8 |
dgisselq |
wire axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
|
397 |
|
|
axi_rd_err, axi_wr_err;
|
398 |
|
|
//
|
399 |
|
|
assign axi_ard_req = (o_axi_arvalid)&&(i_axi_arready);
|
400 |
|
|
assign axi_awr_req = (o_axi_awvalid)&&(i_axi_awready);
|
401 |
|
|
assign axi_wr_req = (o_axi_wvalid )&&(i_axi_wready);
|
402 |
|
|
//
|
403 |
|
|
assign axi_rd_ack = (i_axi_rvalid)&&(o_axi_rready);
|
404 |
|
|
assign axi_wr_ack = (i_axi_bvalid)&&(o_axi_bready);
|
405 |
|
|
assign axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
|
406 |
|
|
assign axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
|
407 |
2 |
dgisselq |
|
408 |
8 |
dgisselq |
//
|
409 |
|
|
// We're going to need a FIFO on the return to make certain that we can
|
410 |
|
|
// select the right bits from the return value, in the case where
|
411 |
|
|
// DW != the axi data width.
|
412 |
|
|
//
|
413 |
|
|
// If we aren't using a strict order, this FIFO is can be used as a
|
414 |
|
|
// reorder buffer as well, to place our out of order bus responses
|
415 |
|
|
// back into order. Responses on the wishbone, however, are *always*
|
416 |
|
|
// done in order.
|
417 |
|
|
`ifdef FORMAL
|
418 |
|
|
reg [31:0] reorder_count;
|
419 |
|
|
`endif
|
420 |
|
|
integer k;
|
421 |
|
|
generate
|
422 |
|
|
if (STRICT_ORDER == 0)
|
423 |
|
|
begin
|
424 |
|
|
// Reorder FIFO
|
425 |
|
|
//
|
426 |
|
|
// FIFO reorder buffer
|
427 |
|
|
reg [(FIFOLN-1):0] reorder_fifo_valid;
|
428 |
|
|
reg [(FIFOLN-1):0] reorder_fifo_err;
|
429 |
2 |
dgisselq |
|
430 |
8 |
dgisselq |
initial reorder_fifo_valid = 0;
|
431 |
|
|
initial reorder_fifo_err = 0;
|
432 |
|
|
|
433 |
|
|
|
434 |
|
|
initial fifo_tail = 0;
|
435 |
|
|
initial o_wb_ack = 0;
|
436 |
|
|
initial o_wb_err = 0;
|
437 |
2 |
dgisselq |
always @(posedge i_clk)
|
438 |
|
|
begin
|
439 |
8 |
dgisselq |
if (axi_rd_ack)
|
440 |
2 |
dgisselq |
begin
|
441 |
5 |
dgisselq |
reorder_fifo_valid[i_axi_rid] <= 1'b1;
|
442 |
8 |
dgisselq |
reorder_fifo_err[i_axi_rid] <= axi_rd_err;
|
443 |
2 |
dgisselq |
end
|
444 |
8 |
dgisselq |
if (axi_wr_ack)
|
445 |
2 |
dgisselq |
begin
|
446 |
5 |
dgisselq |
reorder_fifo_valid[i_axi_bid] <= 1'b1;
|
447 |
8 |
dgisselq |
reorder_fifo_err[i_axi_bid] <= axi_wr_err;
|
448 |
2 |
dgisselq |
end
|
449 |
|
|
|
450 |
|
|
if (reorder_fifo_valid[fifo_tail])
|
451 |
|
|
begin
|
452 |
8 |
dgisselq |
o_wb_ack <= (!wb_abort)&&(!reorder_fifo_err[fifo_tail]);
|
453 |
|
|
o_wb_err <= (!wb_abort)&&( reorder_fifo_err[fifo_tail]);
|
454 |
|
|
fifo_tail <= fifo_tail + 1'b1;
|
455 |
2 |
dgisselq |
reorder_fifo_valid[fifo_tail] <= 1'b0;
|
456 |
|
|
reorder_fifo_err[fifo_tail] <= 1'b0;
|
457 |
|
|
end else begin
|
458 |
|
|
o_wb_ack <= 1'b0;
|
459 |
|
|
o_wb_err <= 1'b0;
|
460 |
|
|
end
|
461 |
|
|
|
462 |
|
|
if (!i_wb_cyc)
|
463 |
|
|
begin
|
464 |
8 |
dgisselq |
// reorder_fifo_valid <= 0;
|
465 |
|
|
// reorder_fifo_err <= 0;
|
466 |
2 |
dgisselq |
o_wb_err <= 1'b0;
|
467 |
|
|
o_wb_ack <= 1'b0;
|
468 |
|
|
end
|
469 |
|
|
end
|
470 |
|
|
|
471 |
8 |
dgisselq |
`ifdef FORMAL
|
472 |
|
|
always @(*)
|
473 |
|
|
begin
|
474 |
|
|
reorder_count = 0;
|
475 |
|
|
for(k=0; k<FIFOLN; k=k+1)
|
476 |
|
|
if (reorder_fifo_valid[k])
|
477 |
|
|
reorder_count = reorder_count + 1;
|
478 |
|
|
end
|
479 |
|
|
|
480 |
|
|
reg [(FIFOLN-1):0] f_reorder_fifo_valid_zerod,
|
481 |
|
|
f_reorder_fifo_err_zerod;
|
482 |
|
|
always @(*)
|
483 |
|
|
f_reorder_fifo_valid_zerod <=
|
484 |
|
|
((reorder_fifo_valid >> fifo_tail)
|
485 |
|
|
| (reorder_fifo_valid << (FIFOLN-fifo_tail)));
|
486 |
|
|
always @(*)
|
487 |
|
|
assert((f_reorder_fifo_valid_zerod & (~((1<<f_fifo_used)-1)))==0);
|
488 |
|
|
//
|
489 |
|
|
always @(*)
|
490 |
|
|
f_reorder_fifo_err_zerod <=
|
491 |
|
|
((reorder_fifo_valid >> fifo_tail)
|
492 |
|
|
| (reorder_fifo_valid << (FIFOLN-fifo_tail)));
|
493 |
|
|
always @(*)
|
494 |
|
|
assert((f_reorder_fifo_err_zerod & (~((1<<f_fifo_used)-1)))==0);
|
495 |
|
|
`endif
|
496 |
|
|
|
497 |
3 |
dgisselq |
reg r_fifo_full;
|
498 |
8 |
dgisselq |
initial r_fifo_full = 0;
|
499 |
2 |
dgisselq |
always @(posedge i_clk)
|
500 |
|
|
begin
|
501 |
8 |
dgisselq |
if ((i_wb_stb)&&(!o_wb_stall)
|
502 |
2 |
dgisselq |
&&(reorder_fifo_valid[fifo_tail]))
|
503 |
|
|
r_fifo_full <= (fifo_tail==n_fifo_head);
|
504 |
8 |
dgisselq |
else if ((i_wb_stb)&&(!o_wb_stall))
|
505 |
2 |
dgisselq |
r_fifo_full <= (fifo_tail==nn_fifo_head);
|
506 |
|
|
else if (reorder_fifo_valid[fifo_tail])
|
507 |
|
|
r_fifo_full <= 1'b0;
|
508 |
|
|
else
|
509 |
|
|
r_fifo_full <= (fifo_tail==n_fifo_head);
|
510 |
|
|
end
|
511 |
|
|
assign w_fifo_full = r_fifo_full;
|
512 |
|
|
end else begin
|
513 |
6 |
dgisselq |
//
|
514 |
8 |
dgisselq |
// Strict ordering
|
515 |
6 |
dgisselq |
//
|
516 |
8 |
dgisselq |
reg reorder_fifo_valid;
|
517 |
|
|
reg reorder_fifo_err;
|
518 |
|
|
|
519 |
|
|
initial reorder_fifo_valid = 1'b0;
|
520 |
|
|
initial reorder_fifo_err = 1'b0;
|
521 |
2 |
dgisselq |
always @(posedge i_clk)
|
522 |
8 |
dgisselq |
if (axi_rd_ack)
|
523 |
|
|
begin
|
524 |
|
|
reorder_fifo_valid <= 1'b1;
|
525 |
|
|
reorder_fifo_err <= axi_rd_err;
|
526 |
|
|
end else if (axi_wr_ack)
|
527 |
|
|
begin
|
528 |
|
|
reorder_fifo_valid <= 1'b1;
|
529 |
|
|
reorder_fifo_err <= axi_wr_err;
|
530 |
|
|
end else begin
|
531 |
|
|
reorder_fifo_valid <= 1'b0;
|
532 |
|
|
reorder_fifo_err <= 1'b0;
|
533 |
|
|
end
|
534 |
|
|
|
535 |
|
|
always @(*)
|
536 |
|
|
reorder_count = (reorder_fifo_valid) ? 1 : 0;
|
537 |
|
|
|
538 |
|
|
initial fifo_tail = 0;
|
539 |
2 |
dgisselq |
always @(posedge i_clk)
|
540 |
8 |
dgisselq |
if (reorder_fifo_valid)
|
541 |
|
|
fifo_tail <= fifo_tail + 6'h1;
|
542 |
|
|
|
543 |
|
|
initial o_wb_ack = 0;
|
544 |
2 |
dgisselq |
always @(posedge i_clk)
|
545 |
8 |
dgisselq |
o_wb_ack <= (reorder_fifo_valid)&&(i_wb_cyc)&&(!wb_abort);
|
546 |
|
|
|
547 |
|
|
initial o_wb_err = 0;
|
548 |
|
|
always @(posedge i_clk)
|
549 |
|
|
o_wb_err <= (reorder_fifo_err)&&(i_wb_cyc)&&(!wb_abort);
|
550 |
|
|
|
551 |
|
|
reg r_fifo_full;
|
552 |
|
|
initial r_fifo_full = 0;
|
553 |
|
|
always @(posedge i_clk)
|
554 |
|
|
begin
|
555 |
|
|
if ((i_wb_stb)&&(!o_wb_stall)
|
556 |
|
|
&&(reorder_fifo_valid))
|
557 |
|
|
r_fifo_full <= (fifo_tail==n_fifo_head);
|
558 |
|
|
else if ((i_wb_stb)&&(!o_wb_stall))
|
559 |
|
|
r_fifo_full <= (fifo_tail==nn_fifo_head);
|
560 |
|
|
else if (reorder_fifo_valid[fifo_tail])
|
561 |
|
|
r_fifo_full <= 1'b0;
|
562 |
|
|
else
|
563 |
|
|
r_fifo_full <= (fifo_tail==n_fifo_head);
|
564 |
|
|
end
|
565 |
|
|
|
566 |
|
|
assign w_fifo_full = r_fifo_full;
|
567 |
3 |
dgisselq |
end endgenerate
|
568 |
2 |
dgisselq |
|
569 |
8 |
dgisselq |
//
|
570 |
|
|
// Wishbone abort logic
|
571 |
|
|
//
|
572 |
|
|
|
573 |
|
|
// Did we just accept something?
|
574 |
|
|
always @(posedge i_clk)
|
575 |
|
|
wb_cyc_stb <= (i_wb_cyc)&&(i_wb_stb)&&(!o_wb_stall);
|
576 |
|
|
|
577 |
|
|
// Else, are we mid-cycle?
|
578 |
|
|
initial wb_mid_cycle = 0;
|
579 |
|
|
always @(posedge i_clk)
|
580 |
|
|
if ((fifo_head != fifo_tail)
|
581 |
|
|
||(o_axi_arvalid)||(o_axi_awvalid)
|
582 |
|
|
||(o_axi_wvalid)
|
583 |
|
|
||(i_wb_cyc)&&(i_wb_stb)&&(!o_wb_stall))
|
584 |
|
|
wb_mid_cycle <= 1'b1;
|
585 |
|
|
else
|
586 |
|
|
wb_mid_cycle <= 1'b0;
|
587 |
|
|
|
588 |
|
|
always @(posedge i_clk)
|
589 |
|
|
if (wb_mid_cycle)
|
590 |
|
|
wb_mid_abort <= (wb_mid_abort)||(!i_wb_cyc);
|
591 |
|
|
else
|
592 |
|
|
wb_mid_abort <= 1'b0;
|
593 |
|
|
|
594 |
|
|
wire wb_abort;
|
595 |
|
|
assign wb_abort = ((wb_mid_cycle)&&(!i_wb_cyc))||(wb_mid_abort);
|
596 |
|
|
|
597 |
2 |
dgisselq |
// Now, the difficult signal ... the stall signal
|
598 |
|
|
// Let's build for a single cycle input ... and only stall if something
|
599 |
|
|
// outgoing is valid and nothing is ready.
|
600 |
|
|
assign o_wb_stall = (i_wb_cyc)&&(
|
601 |
8 |
dgisselq |
(w_fifo_full)||(wb_mid_abort)
|
602 |
5 |
dgisselq |
||((o_axi_awvalid)&&(!i_axi_awready))
|
603 |
|
|
||((o_axi_wvalid )&&(!i_axi_wready ))
|
604 |
|
|
||((o_axi_arvalid)&&(!i_axi_arready)));
|
605 |
8 |
dgisselq |
|
606 |
|
|
|
607 |
|
|
/////////////////////////////////////////////////////////////////////////
|
608 |
|
|
//
|
609 |
|
|
//
|
610 |
|
|
//
|
611 |
|
|
// Formal methods section
|
612 |
|
|
//
|
613 |
|
|
// These are only relevant when *proving* that this translator works
|
614 |
|
|
//
|
615 |
|
|
//
|
616 |
|
|
//
|
617 |
|
|
/////////////////////////////////////////////////////////////////////////
|
618 |
|
|
`ifdef FORMAL
|
619 |
|
|
reg f_err_state;
|
620 |
|
|
//
|
621 |
|
|
`ifdef WBM2AXISP
|
622 |
|
|
// If we are the top-level of the design ...
|
623 |
|
|
`define ASSUME assume
|
624 |
|
|
`define FORMAL_CLOCK assume(i_clk == !f_last_clk); f_last_clk <= i_clk;
|
625 |
|
|
`else
|
626 |
|
|
`define ASSUME assert
|
627 |
|
|
`define FORMAL_CLOCK f_last_clk <= i_clk; // Clock will be given to us valid already
|
628 |
|
|
`endif
|
629 |
|
|
|
630 |
|
|
// Parameters
|
631 |
|
|
initial assert( (C_AXI_DATA_WIDTH / DW == 4)
|
632 |
|
|
||(C_AXI_DATA_WIDTH / DW == 2)
|
633 |
|
|
||(C_AXI_DATA_WIDTH == DW));
|
634 |
|
|
//
|
635 |
|
|
initial assert( C_AXI_ADDR_WIDTH - LG_AXI_DW + LG_WB_DW == AW);
|
636 |
|
|
|
637 |
|
|
//
|
638 |
|
|
// Setup
|
639 |
|
|
//
|
640 |
|
|
|
641 |
|
|
reg f_past_valid, f_last_clk;
|
642 |
|
|
|
643 |
|
|
always @($global_clock)
|
644 |
|
|
begin
|
645 |
|
|
`FORMAL_CLOCK
|
646 |
|
|
|
647 |
|
|
// Assume our inputs will only change on the positive edge
|
648 |
|
|
// of the clock
|
649 |
|
|
if (!$rose(i_clk))
|
650 |
|
|
begin
|
651 |
|
|
// AXI inputs
|
652 |
|
|
`ASSUME($stable(i_axi_awready));
|
653 |
|
|
`ASSUME($stable(i_axi_wready));
|
654 |
|
|
`ASSUME($stable(i_axi_bid));
|
655 |
|
|
`ASSUME($stable(i_axi_bresp));
|
656 |
|
|
`ASSUME($stable(i_axi_bvalid));
|
657 |
|
|
`ASSUME($stable(i_axi_arready));
|
658 |
|
|
`ASSUME($stable(i_axi_rid));
|
659 |
|
|
`ASSUME($stable(i_axi_rresp));
|
660 |
|
|
`ASSUME($stable(i_axi_rvalid));
|
661 |
|
|
`ASSUME($stable(i_axi_rdata));
|
662 |
|
|
`ASSUME($stable(i_axi_rlast));
|
663 |
|
|
// Wishbone inputs
|
664 |
|
|
`ASSUME($stable(i_wb_cyc));
|
665 |
|
|
`ASSUME($stable(i_wb_stb));
|
666 |
|
|
`ASSUME($stable(i_wb_we));
|
667 |
|
|
`ASSUME($stable(i_wb_addr));
|
668 |
|
|
`ASSUME($stable(i_wb_data));
|
669 |
|
|
`ASSUME($stable(i_wb_sel));
|
670 |
|
|
end
|
671 |
|
|
end
|
672 |
|
|
|
673 |
|
|
initial f_past_valid = 1'b0;
|
674 |
|
|
always @(posedge i_clk)
|
675 |
|
|
f_past_valid <= 1'b1;
|
676 |
|
|
|
677 |
|
|
//////////////////////////////////////////////
|
678 |
|
|
//
|
679 |
|
|
//
|
680 |
|
|
// Assumptions about the WISHBONE inputs
|
681 |
|
|
//
|
682 |
|
|
//
|
683 |
|
|
//////////////////////////////////////////////
|
684 |
|
|
wire i_reset;
|
685 |
|
|
assign i_reset = !f_past_valid;
|
686 |
|
|
|
687 |
|
|
wire [(C_AXI_ID_WIDTH-1):0] f_wb_nreqs, f_wb_nacks,f_wb_outstanding;
|
688 |
|
|
fwb_slave #(.DW(DW),.AW(AW),
|
689 |
|
|
.F_MAX_STALL(0),
|
690 |
|
|
.F_MAX_ACK_DELAY(0),
|
691 |
|
|
.F_LGDEPTH(C_AXI_ID_WIDTH),
|
692 |
|
|
.F_MAX_REQUESTS((1<<(C_AXI_ID_WIDTH))-2))
|
693 |
|
|
f_wb(i_clk, i_reset,
|
694 |
|
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr,
|
695 |
|
|
i_wb_data, i_wb_sel,
|
696 |
|
|
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
|
697 |
|
|
f_wb_nreqs, f_wb_nacks, f_wb_outstanding);
|
698 |
|
|
|
699 |
|
|
wire [(C_AXI_ID_WIDTH-1):0] f_axi_rd_outstanding,
|
700 |
|
|
f_axi_wr_outstanding,
|
701 |
|
|
f_axi_awr_outstanding;
|
702 |
|
|
|
703 |
|
|
wire [((1<<C_AXI_ID_WIDTH)-1):0] f_axi_rd_id_outstanding,
|
704 |
|
|
f_axi_wr_id_outstanding,
|
705 |
|
|
f_axi_awr_id_outstanding;
|
706 |
|
|
|
707 |
|
|
faxi_master #(
|
708 |
|
|
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
|
709 |
|
|
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
|
710 |
|
|
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
|
711 |
|
|
.F_AXI_MAXSTALL(3),
|
712 |
|
|
.F_AXI_MAXDELAY(3),
|
713 |
|
|
.F_STRICT_ORDER(STRICT_ORDER),
|
714 |
|
|
.F_CONSECUTIVE_IDS(1'b1),
|
715 |
|
|
.F_OPT_BURSTS(1'b0),
|
716 |
|
|
.F_CHECK_IDS(1'b1))
|
717 |
|
|
f_axi(.i_clk(i_clk), .i_axi_reset_n(!i_reset),
|
718 |
|
|
// Write address channel
|
719 |
|
|
.i_axi_awready(i_axi_awready),
|
720 |
|
|
.i_axi_awid( o_axi_awid),
|
721 |
|
|
.i_axi_awaddr( o_axi_awaddr),
|
722 |
|
|
.i_axi_awlen( o_axi_awlen),
|
723 |
|
|
.i_axi_awsize( o_axi_awsize),
|
724 |
|
|
.i_axi_awburst(o_axi_awburst),
|
725 |
|
|
.i_axi_awlock( o_axi_awlock),
|
726 |
|
|
.i_axi_awcache(o_axi_awcache),
|
727 |
|
|
.i_axi_awprot( o_axi_awprot),
|
728 |
|
|
.i_axi_awqos( o_axi_awqos),
|
729 |
|
|
.i_axi_awvalid(o_axi_awvalid),
|
730 |
|
|
// Write data channel
|
731 |
|
|
.i_axi_wready( i_axi_wready),
|
732 |
|
|
.i_axi_wdata( o_axi_wdata),
|
733 |
|
|
.i_axi_wstrb( o_axi_wstrb),
|
734 |
|
|
.i_axi_wlast( o_axi_wlast),
|
735 |
|
|
.i_axi_wvalid( o_axi_wvalid),
|
736 |
|
|
// Write response channel
|
737 |
|
|
.i_axi_bid( i_axi_bid),
|
738 |
|
|
.i_axi_bresp( i_axi_bresp),
|
739 |
|
|
.i_axi_bvalid( i_axi_bvalid),
|
740 |
|
|
.i_axi_bready( o_axi_bready),
|
741 |
|
|
// Read address channel
|
742 |
|
|
.i_axi_arready(i_axi_arready),
|
743 |
|
|
.i_axi_arid( o_axi_arid),
|
744 |
|
|
.i_axi_araddr( o_axi_araddr),
|
745 |
|
|
.i_axi_arlen( o_axi_arlen),
|
746 |
|
|
.i_axi_arsize( o_axi_arsize),
|
747 |
|
|
.i_axi_arburst(o_axi_arburst),
|
748 |
|
|
.i_axi_arlock( o_axi_arlock),
|
749 |
|
|
.i_axi_arcache(o_axi_arcache),
|
750 |
|
|
.i_axi_arprot( o_axi_arprot),
|
751 |
|
|
.i_axi_arqos( o_axi_arqos),
|
752 |
|
|
.i_axi_arvalid(o_axi_arvalid),
|
753 |
|
|
// Read data channel
|
754 |
|
|
.i_axi_rid( i_axi_rid),
|
755 |
|
|
.i_axi_rresp( i_axi_rresp),
|
756 |
|
|
.i_axi_rvalid( i_axi_rvalid),
|
757 |
|
|
.i_axi_rdata( i_axi_rdata),
|
758 |
|
|
.i_axi_rlast( i_axi_rlast),
|
759 |
|
|
.i_axi_rready( o_axi_rready),
|
760 |
|
|
// Counts
|
761 |
|
|
.f_axi_rd_outstanding( f_axi_rd_outstanding),
|
762 |
|
|
.f_axi_wr_outstanding( f_axi_wr_outstanding),
|
763 |
|
|
.f_axi_awr_outstanding( f_axi_awr_outstanding),
|
764 |
|
|
// Outstanding ID's
|
765 |
|
|
.f_axi_rd_id_outstanding( f_axi_rd_id_outstanding),
|
766 |
|
|
.f_axi_wr_id_outstanding( f_axi_wr_id_outstanding),
|
767 |
|
|
.f_axi_awr_id_outstanding(f_axi_awr_id_outstanding)
|
768 |
|
|
);
|
769 |
|
|
|
770 |
|
|
|
771 |
|
|
|
772 |
|
|
//////////////////////////////////////////////
|
773 |
|
|
//
|
774 |
|
|
//
|
775 |
|
|
// Assumptions about the AXI inputs
|
776 |
|
|
//
|
777 |
|
|
//
|
778 |
|
|
//////////////////////////////////////////////
|
779 |
|
|
|
780 |
|
|
|
781 |
|
|
//////////////////////////////////////////////
|
782 |
|
|
//
|
783 |
|
|
//
|
784 |
|
|
// Assertions about the AXI4 ouputs
|
785 |
|
|
//
|
786 |
|
|
//
|
787 |
|
|
//////////////////////////////////////////////
|
788 |
|
|
|
789 |
|
|
wire [(LGFIFOLN-1):0] f_last_transaction_id;
|
790 |
|
|
assign f_last_transaction_id = transaction_id- 1;
|
791 |
|
|
always @(posedge i_clk)
|
792 |
|
|
if (f_past_valid)
|
793 |
|
|
begin
|
794 |
|
|
assert(o_axi_awid == f_last_transaction_id);
|
795 |
|
|
if ($past(o_wb_stall))
|
796 |
|
|
assert($stable(o_axi_awid));
|
797 |
|
|
end
|
798 |
|
|
|
799 |
|
|
// Write response channel
|
800 |
|
|
always @(posedge i_clk)
|
801 |
|
|
// We keep bready high, so the other condition doesn't
|
802 |
|
|
// need to be checked
|
803 |
|
|
assert(o_axi_bready);
|
804 |
|
|
|
805 |
|
|
// AXI read data channel signals
|
806 |
|
|
always @(posedge i_clk)
|
807 |
|
|
// We keep o_axi_rready high, so the other condition's
|
808 |
|
|
// don't need to be checked here
|
809 |
|
|
assert(o_axi_rready);
|
810 |
|
|
|
811 |
|
|
//
|
812 |
|
|
// Let's look into write requests
|
813 |
|
|
//
|
814 |
|
|
initial assert(!o_axi_awvalid);
|
815 |
|
|
initial assert(!o_axi_wvalid);
|
816 |
|
|
always @(posedge i_clk)
|
817 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we))&&(!$past(o_wb_stall)))
|
818 |
|
|
begin
|
819 |
|
|
// Following any write request that we accept, awvalid and
|
820 |
|
|
// wvalid should both be true
|
821 |
|
|
assert(o_axi_awvalid);
|
822 |
|
|
assert(o_axi_wvalid);
|
823 |
|
|
end
|
824 |
|
|
|
825 |
|
|
// Let's assume all responses will come within 120 clock ticks
|
826 |
|
|
parameter [(C_AXI_ID_WIDTH-1):0] F_AXI_MAXDELAY = 3,
|
827 |
|
|
F_AXI_MAXSTALL = 3; // 7'd120;
|
828 |
|
|
localparam [(C_AXI_ID_WIDTH):0] F_WB_MAXDELAY = F_AXI_MAXDELAY + 4;
|
829 |
|
|
|
830 |
|
|
//
|
831 |
|
|
// AXI write address channel
|
832 |
|
|
//
|
833 |
|
|
always @(posedge i_clk)
|
834 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall)))
|
835 |
|
|
begin
|
836 |
|
|
if (!$past(i_wb_stb))
|
837 |
|
|
assert(!o_axi_awvalid);
|
838 |
|
|
else
|
839 |
|
|
assert(o_axi_awvalid == $past(i_wb_we));
|
840 |
|
|
end
|
841 |
|
|
//
|
842 |
|
|
generate
|
843 |
|
|
if (C_AXI_DATA_WIDTH == DW)
|
844 |
|
|
begin
|
845 |
|
|
always @(posedge i_clk)
|
846 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we))
|
847 |
|
|
&&(!$past(o_wb_stall)))
|
848 |
|
|
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:0]), axi_bottom_addr });
|
849 |
|
|
|
850 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 2)
|
851 |
|
|
begin
|
852 |
|
|
|
853 |
|
|
always @(posedge i_clk)
|
854 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we))
|
855 |
|
|
&&(!$past(o_wb_stall)))
|
856 |
|
|
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:1]), axi_bottom_addr });
|
857 |
|
|
|
858 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 4)
|
859 |
|
|
begin
|
860 |
|
|
|
861 |
|
|
always @(posedge i_clk)
|
862 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&($past(i_wb_stb))&&($past(i_wb_we))
|
863 |
|
|
&&(!$past(o_wb_stall)))
|
864 |
|
|
assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:2]), axi_bottom_addr });
|
865 |
|
|
|
866 |
|
|
end endgenerate
|
867 |
|
|
|
868 |
|
|
//
|
869 |
|
|
// AXI write data channel
|
870 |
|
|
//
|
871 |
|
|
always @(posedge i_clk)
|
872 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall)))
|
873 |
|
|
begin
|
874 |
|
|
if (!$past(i_wb_stb))
|
875 |
|
|
assert(!o_axi_wvalid);
|
876 |
|
|
else
|
877 |
|
|
assert(o_axi_wvalid == $past(i_wb_we));
|
878 |
|
|
end
|
879 |
|
|
//
|
880 |
|
|
generate
|
881 |
|
|
if (C_AXI_DATA_WIDTH == DW)
|
882 |
|
|
begin
|
883 |
|
|
|
884 |
|
|
always @(posedge i_clk)
|
885 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we)))
|
886 |
|
|
begin
|
887 |
|
|
assert(o_axi_wdata == $past(i_wb_data));
|
888 |
|
|
assert(o_axi_wstrb == $past(i_wb_sel));
|
889 |
|
|
end
|
890 |
|
|
|
891 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 2)
|
892 |
|
|
begin
|
893 |
|
|
|
894 |
|
|
always @(posedge i_clk)
|
895 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(i_wb_we)))
|
896 |
|
|
begin
|
897 |
|
|
case($past(i_wb_addr[0]))
|
898 |
|
|
1'b0: assert(o_axi_wdata[( DW-1): 0] == $past(i_wb_data));
|
899 |
|
|
1'b1: assert(o_axi_wdata[(2*DW-1):DW] == $past(i_wb_data));
|
900 |
|
|
endcase
|
901 |
|
|
|
902 |
|
|
case($past(i_wb_addr[0]))
|
903 |
|
|
1'b0: assert(o_axi_wstrb == { no_sel,$past(i_wb_sel)});
|
904 |
|
|
1'b1: assert(o_axi_wstrb == { $past(i_wb_sel),no_sel});
|
905 |
|
|
endcase
|
906 |
|
|
end
|
907 |
|
|
|
908 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 4)
|
909 |
|
|
begin
|
910 |
|
|
|
911 |
|
|
always @(posedge i_clk)
|
912 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&(!$past(o_wb_stall))&&($past(i_wb_we)))
|
913 |
|
|
begin
|
914 |
|
|
case($past(i_wb_addr[1:0]))
|
915 |
|
|
2'b00: assert(o_axi_wdata[ (DW-1): 0 ] == $past(i_wb_data));
|
916 |
|
|
2'b00: assert(o_axi_wdata[(2*DW-1):( DW)] == $past(i_wb_data));
|
917 |
|
|
2'b00: assert(o_axi_wdata[(3*DW-1):(2*DW)] == $past(i_wb_data));
|
918 |
|
|
2'b11: assert(o_axi_wdata[(4*DW-1):(3*DW)] == $past(i_wb_data));
|
919 |
|
|
endcase
|
920 |
|
|
|
921 |
|
|
case($past(i_wb_addr[1:0]))
|
922 |
|
|
2'b00: assert(o_axi_wstrb == { {(3){no_sel}},$past(i_wb_sel)});
|
923 |
|
|
2'b01: assert(o_axi_wstrb == { {(2){no_sel}},$past(i_wb_sel), {(1){no_sel}}});
|
924 |
|
|
2'b10: assert(o_axi_wstrb == { {(1){no_sel}},$past(i_wb_sel), {(2){no_sel}}});
|
925 |
|
|
2'b11: assert(o_axi_wstrb == { $past(i_wb_sel),{(3){no_sel}}});
|
926 |
|
|
endcase
|
927 |
|
|
end
|
928 |
|
|
end endgenerate
|
929 |
|
|
|
930 |
|
|
//
|
931 |
|
|
// AXI read address channel
|
932 |
|
|
//
|
933 |
|
|
initial assert(!o_axi_arvalid);
|
934 |
|
|
always @(posedge i_clk)
|
935 |
|
|
if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(o_wb_stall)))
|
936 |
|
|
begin
|
937 |
|
|
if (!$past(i_wb_stb))
|
938 |
|
|
assert(!o_axi_arvalid);
|
939 |
|
|
else
|
940 |
|
|
assert(o_axi_arvalid == !$past(i_wb_we));
|
941 |
|
|
end
|
942 |
|
|
//
|
943 |
|
|
generate
|
944 |
|
|
if (C_AXI_DATA_WIDTH == DW)
|
945 |
|
|
begin
|
946 |
|
|
always @(posedge i_clk)
|
947 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we))
|
948 |
|
|
&&(!$past(o_wb_stall)))
|
949 |
|
|
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:0], axi_bottom_addr }));
|
950 |
|
|
|
951 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 2)
|
952 |
|
|
begin
|
953 |
|
|
|
954 |
|
|
always @(posedge i_clk)
|
955 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we))
|
956 |
|
|
&&(!$past(o_wb_stall)))
|
957 |
|
|
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:1], axi_bottom_addr }));
|
958 |
|
|
|
959 |
|
|
end else if (C_AXI_DATA_WIDTH / DW == 4)
|
960 |
|
|
begin
|
961 |
|
|
always @(posedge i_clk)
|
962 |
|
|
if ((f_past_valid)&&($past(i_wb_stb))&&($past(!i_wb_we))
|
963 |
|
|
&&(!$past(o_wb_stall)))
|
964 |
|
|
assert(o_axi_araddr == $past({ i_wb_addr[AW-1:2], axi_bottom_addr }));
|
965 |
|
|
|
966 |
|
|
end endgenerate
|
967 |
|
|
|
968 |
|
|
//
|
969 |
|
|
// AXI write response channel
|
970 |
|
|
//
|
971 |
|
|
|
972 |
|
|
|
973 |
|
|
//
|
974 |
|
|
// AXI read data channel signals
|
975 |
|
|
//
|
976 |
|
|
always @(posedge i_clk)
|
977 |
|
|
`ASSUME(f_axi_rd_outstanding <= f_wb_outstanding);
|
978 |
|
|
//
|
979 |
|
|
always @(posedge i_clk)
|
980 |
|
|
`ASSUME(f_axi_rd_outstanding + f_axi_wr_outstanding <= f_wb_outstanding);
|
981 |
|
|
always @(posedge i_clk)
|
982 |
|
|
`ASSUME(f_axi_rd_outstanding + f_axi_awr_outstanding <= f_wb_outstanding);
|
983 |
|
|
//
|
984 |
|
|
always @(posedge i_clk)
|
985 |
|
|
`ASSUME(f_axi_rd_outstanding + f_axi_wr_outstanding +2 > f_wb_outstanding);
|
986 |
|
|
always @(posedge i_clk)
|
987 |
|
|
`ASSUME(f_axi_rd_outstanding + f_axi_awr_outstanding +2 > f_wb_outstanding);
|
988 |
|
|
|
989 |
|
|
// Make sure we only create one request at a time
|
990 |
|
|
always @(posedge i_clk)
|
991 |
|
|
assert((!o_axi_arvalid)||(!o_axi_wvalid));
|
992 |
|
|
always @(posedge i_clk)
|
993 |
|
|
assert((!o_axi_arvalid)||(!o_axi_awvalid));
|
994 |
|
|
|
995 |
|
|
// Now, let's look into that FIFO. Without it, we know nothing about the ID's
|
996 |
|
|
|
997 |
|
|
// Error handling
|
998 |
|
|
always @(posedge i_clk)
|
999 |
|
|
if (!i_wb_cyc)
|
1000 |
|
|
f_err_state <= 0;
|
1001 |
|
|
else if (o_wb_err)
|
1002 |
|
|
f_err_state <= 1;
|
1003 |
|
|
always @(posedge i_clk)
|
1004 |
|
|
if ((f_past_valid)&&($past(f_err_state))&&(
|
1005 |
|
|
(!$past(o_wb_stall))||(!$past(i_wb_stb))))
|
1006 |
|
|
`ASSUME(!i_wb_stb);
|
1007 |
|
|
|
1008 |
|
|
// Head and tail pointers
|
1009 |
|
|
|
1010 |
|
|
// The head should only increment when something goes through
|
1011 |
|
|
always @(posedge i_clk)
|
1012 |
|
|
if ((f_past_valid)&&((!$past(i_wb_stb))||($past(o_wb_stall))))
|
1013 |
|
|
assert($stable(fifo_head));
|
1014 |
|
|
|
1015 |
|
|
// Can't overrun the FIFO
|
1016 |
|
|
wire [(LGFIFOLN-1):0] f_fifo_tail_minus_one;
|
1017 |
|
|
assign f_fifo_tail_minus_one = fifo_tail - 1'b1;
|
1018 |
|
|
always @(posedge i_clk)
|
1019 |
|
|
if ((f_past_valid)&&($past(fifo_head == f_fifo_tail_minus_one)))
|
1020 |
|
|
assert(fifo_head != fifo_tail);
|
1021 |
|
|
|
1022 |
|
|
reg f_pre_ack;
|
1023 |
|
|
|
1024 |
|
|
wire [(LGFIFOLN-1):0] f_fifo_used;
|
1025 |
|
|
assign f_fifo_used = fifo_head - fifo_tail;
|
1026 |
|
|
|
1027 |
|
|
initial assert(fifo_tail == 0);
|
1028 |
|
|
initial assert(reorder_fifo_valid == 0);
|
1029 |
|
|
initial assert(reorder_fifo_err == 0);
|
1030 |
|
|
initial f_pre_ack = 1'b0;
|
1031 |
|
|
always @(posedge i_clk)
|
1032 |
|
|
begin
|
1033 |
|
|
f_pre_ack <= (!wb_abort)&&((axi_rd_ack)||(axi_wr_ack));
|
1034 |
|
|
if (STRICT_ORDER)
|
1035 |
|
|
begin
|
1036 |
|
|
`ASSUME((!axi_rd_ack)||(!axi_wr_ack));
|
1037 |
|
|
|
1038 |
|
|
if (f_past_valid)
|
1039 |
|
|
assert((!$past(i_wb_cyc))
|
1040 |
|
|
||(o_wb_ack == $past(f_pre_ack)));
|
1041 |
|
|
end
|
1042 |
|
|
end
|
1043 |
|
|
|
1044 |
|
|
//
|
1045 |
|
|
// Verify that there are no outstanding requests outside of the FIFO
|
1046 |
|
|
// window. This should never happen, but the formal tools need to know
|
1047 |
|
|
// that.
|
1048 |
|
|
//
|
1049 |
|
|
always @(*)
|
1050 |
|
|
begin
|
1051 |
|
|
assert((f_axi_rd_id_outstanding&f_axi_wr_id_outstanding)==0);
|
1052 |
|
|
assert((f_axi_rd_id_outstanding&f_axi_awr_id_outstanding)==0);
|
1053 |
|
|
|
1054 |
|
|
if (fifo_head == fifo_tail)
|
1055 |
|
|
begin
|
1056 |
|
|
assert(f_axi_rd_id_outstanding == 0);
|
1057 |
|
|
assert(f_axi_wr_id_outstanding == 0);
|
1058 |
|
|
assert(f_axi_awr_id_outstanding == 0);
|
1059 |
|
|
end
|
1060 |
|
|
|
1061 |
|
|
for(k=0; k<(1<<LGFIFOLN); k=k+1)
|
1062 |
|
|
begin
|
1063 |
|
|
if ( ((fifo_tail < fifo_head)&&(k < fifo_tail))
|
1064 |
|
|
||((fifo_tail < fifo_head)&&(k >= fifo_head))
|
1065 |
|
|
||((fifo_head < fifo_tail)&&(k >= fifo_head)&&(k < fifo_tail))
|
1066 |
|
|
//||((fifo_head < fifo_tail)&&(k >=fifo_tail))
|
1067 |
|
|
)
|
1068 |
|
|
begin
|
1069 |
|
|
assert(f_axi_rd_id_outstanding[k]==0);
|
1070 |
|
|
assert(f_axi_wr_id_outstanding[k]==0);
|
1071 |
|
|
assert(f_axi_awr_id_outstanding[k]==0);
|
1072 |
|
|
end
|
1073 |
|
|
end
|
1074 |
|
|
end
|
1075 |
|
|
|
1076 |
|
|
generate
|
1077 |
|
|
if (STRICT_ORDER)
|
1078 |
|
|
begin : STRICTREQ
|
1079 |
|
|
|
1080 |
|
|
reg [C_AXI_ID_WIDTH-1:0] f_last_axi_id;
|
1081 |
|
|
wire [C_AXI_ID_WIDTH-1:0] f_next_axi_id,
|
1082 |
|
|
f_expected_last_id;
|
1083 |
|
|
assign f_next_axi_id = f_last_axi_id + 1'b1;
|
1084 |
|
|
assign f_expected_last_id = fifo_head - 1'b1 - f_fifo_used;
|
1085 |
|
|
|
1086 |
|
|
initial f_last_axi_id = -1;
|
1087 |
|
|
always @(posedge i_clk)
|
1088 |
|
|
if (i_reset)
|
1089 |
|
|
f_last_axi_id = -1;
|
1090 |
|
|
else if ((axi_rd_ack)||(axi_wr_ack))
|
1091 |
|
|
f_last_axi_id <= f_next_axi_id;
|
1092 |
|
|
else if (f_fifo_used == 0)
|
1093 |
|
|
assert(f_last_axi_id == fifo_head-1'b1);
|
1094 |
|
|
|
1095 |
|
|
always @(posedge i_clk)
|
1096 |
|
|
if (axi_rd_ack)
|
1097 |
|
|
`ASSUME(i_axi_rid == f_next_axi_id);
|
1098 |
|
|
else if (axi_wr_ack)
|
1099 |
|
|
`ASSUME(i_axi_bid == f_next_axi_id);
|
1100 |
|
|
end endgenerate
|
1101 |
|
|
|
1102 |
|
|
reg f_pending, f_returning;
|
1103 |
|
|
initial f_pending = 1'b0;
|
1104 |
|
|
always @(*)
|
1105 |
|
|
f_pending <= (o_axi_arvalid)||(o_axi_awvalid);
|
1106 |
|
|
always @(*)
|
1107 |
|
|
f_returning <= (axi_rd_ack)||(axi_wr_ack);
|
1108 |
|
|
|
1109 |
|
|
reg [(LGFIFOLN):0] f_pre_count;
|
1110 |
|
|
|
1111 |
|
|
always @(*)
|
1112 |
|
|
f_pre_count <= f_axi_awr_outstanding
|
1113 |
|
|
+ f_axi_rd_outstanding
|
1114 |
|
|
+ reorder_count
|
1115 |
|
|
+ { {(LGFIFOLN){1'b0}}, (o_wb_ack) }
|
1116 |
|
|
+ { {(LGFIFOLN){1'b0}}, (f_pending) };
|
1117 |
|
|
always @(posedge i_clk)
|
1118 |
|
|
assert((wb_abort)||(o_wb_err)||(f_pre_count == f_wb_outstanding));
|
1119 |
|
|
|
1120 |
|
|
always @(posedge i_clk)
|
1121 |
|
|
assert((wb_abort)||(o_wb_err)||(f_fifo_used == f_wb_outstanding
|
1122 |
|
|
// + {{(LGFIFOLN){1'b0}},f_past_valid)(i_wb_stb)&&(!o_wb_ack)}
|
1123 |
|
|
- {{(LGFIFOLN){1'b0}},(o_wb_ack)}));
|
1124 |
|
|
|
1125 |
|
|
always @(posedge i_clk)
|
1126 |
|
|
if (o_axi_wvalid)
|
1127 |
|
|
assert(f_fifo_used != 0);
|
1128 |
|
|
always @(posedge i_clk)
|
1129 |
|
|
if (o_axi_arvalid)
|
1130 |
|
|
assert(f_fifo_used != 0);
|
1131 |
|
|
always @(posedge i_clk)
|
1132 |
|
|
if (o_axi_awvalid)
|
1133 |
|
|
assert(f_fifo_used != 0);
|
1134 |
|
|
|
1135 |
|
|
`endif
|
1136 |
2 |
dgisselq |
endmodule
|