@@ -66,6 +66,18 @@ module axi_lite_dw_converter #(
6666 parameter int unsigned AxiSlvPortDataWidth = 32'd0 ,
6767 // / AXI4-Lite data width of the master port.
6868 parameter int unsigned AxiMstPortDataWidth = 32'd0 ,
69+ // / Whether to read a transaction size from the AR user bits
70+ parameter bit UserArSize = 1'b0 ,
71+ // / Whether to read a transaction size from the AW user bits
72+ parameter bit UserAwSize = 1'b0 ,
73+ // / Least significant bit (LSB) of size in AR user fields
74+ parameter int unsigned UserArSizeLsb = 32'd0 ,
75+ // / Least significant bit (LSB) of size in AW user fields
76+ parameter int unsigned UserAwSizeLsb = 32'd0 ,
77+ // / Assuming AW size in user field, maximum number of inflight reads.
78+ parameter int unsigned UserArMaxTxns = 32'd0 ,
79+ // / Assuming AW size in user field, maximum number of inflight writes.
80+ parameter int unsigned UserAwMaxTxns = 32'd0 ,
6981 // / AXI4-Lite AW channel struct type. This is for both ports the same.
7082 parameter type axi_lite_aw_t = logic ,
7183 // / AXI4-Lite W channel struct type of the slave port.
@@ -132,6 +144,7 @@ module axi_lite_dw_converter #(
132144 // Input spill register of the AW channel.
133145 axi_lite_aw_t aw_chan_spill;
134146 logic aw_chan_spill_valid, aw_chan_spill_ready;
147+ logic w_progress, aw_progress, b_progress;
135148
136149 spill_register # (
137150 .T ( axi_lite_aw_t ),
@@ -147,19 +160,35 @@ module axi_lite_dw_converter #(
147160 .data_o ( aw_chan_spill )
148161 );
149162
150- sel_t aw_sel_q, aw_sel_d;
163+ sel_t aw_sel_q, aw_sel_d, aw_sel_out ;
151164 logic aw_sel_load;
152165 // AW channel output assignment
153166 always_comb begin : proc_aw_chan_oup
154167 mst_req_o.aw = aw_chan_spill;
155- mst_req_o.aw.addr = out_address (aw_chan_spill.addr, aw_sel_q);
168+ mst_req_o.aw.addr = out_address (aw_chan_spill.addr, aw_sel_out);
169+ end
170+
171+ assign aw_progress = aw_chan_spill_valid & mst_res_i.aw_ready;
172+
173+ if (UserAwSize) begin : gen_user_aw
174+ // Couple AW, W, and B FIFO and make requests selectively
175+ sel_t aw_sel_end, aw_sel_base;
176+ assign aw_sel_end = UserAwSize ?
177+ (sel_t ' (1 ) << aw_chan_spill.user[UserAwSizeLsb: + axi_pkg :: SizeWidth]) >> SelOffset : '0 ;
178+ assign aw_sel_base = aw_chan_spill.aw.addr[SelOffset+ : SelWidth] & sel_t ' (aw_sel_end - 1 );
179+ assign aw_sel_out = aw_sel_q + aw_sel_base;
180+ assign mst_req_o.aw_valid = w_progress & b_progress & aw_chan_spill_valid;
181+ assign aw_chan_spill_ready = w_progress & b_progress & mst_res_i.aw_ready &
182+ ((& aw_sel_q) | (aw_sel_d == aw_sel_end));
183+ end else begin : gen_no_user_aw
184+ // AW, W, and B are uncoupled
185+ assign aw_sel_out = aw_sel_q;
186+ assign mst_req_o.aw_valid = aw_chan_spill_valid;
187+ assign aw_chan_spill_ready = mst_res_i.aw_ready & (& aw_sel_q);
156188 end
157- // Slave port aw is valid, if there is something in the spill register.
158- assign mst_req_o.aw_valid = aw_chan_spill_valid;
159- assign aw_chan_spill_ready = mst_res_i.aw_ready & (& aw_sel_q);
160189
161190 assign aw_sel_load = mst_req_o.aw_valid & mst_res_i.aw_ready;
162- assign aw_sel_d = sel_t ' (aw_sel_q + 1'b1 );
191+ assign aw_sel_d = sel_t ' (aw_sel_load ? '0 : aw_sel_q + 1'b1 );
163192 `FFLARN (aw_sel_q, aw_sel_d, aw_sel_load, '0 , clk_i, rst_ni)
164193
165194 // Input spill register of the W channel.
@@ -180,41 +209,82 @@ module axi_lite_dw_converter #(
180209 );
181210
182211 // Data multiplexer on the W channel
183- sel_t w_sel_q, w_sel_d;
184- logic w_sel_load;
212+ sel_t w_sel;
185213 // W channel output assignment
186214 assign mst_req_o.w = axi_lite_mst_w_t'{
187- data: w_chan_spill.data[w_sel_q * AxiMstPortDataWidth+ : AxiMstPortDataWidth],
188- strb: w_chan_spill.strb[w_sel_q * AxiMstPortStrbWidth+ : AxiMstPortStrbWidth],
215+ data: w_chan_spill.data[w_sel * AxiMstPortDataWidth+ : AxiMstPortDataWidth],
216+ strb: w_chan_spill.strb[w_sel * AxiMstPortStrbWidth+ : AxiMstPortStrbWidth],
189217 default : '0
190218 } ;
191- assign mst_req_o.w_valid = w_chan_spill_valid;
192- assign w_chan_spill_ready = mst_res_i.w_ready & (& w_sel_q);
193219
194- assign w_sel_load = mst_req_o.w_valid & mst_res_i.w_ready;
195- assign w_sel_d = sel_t ' (w_sel_q + 1'b1 );
196- `FFLARN (w_sel_q, w_sel_d, w_sel_load, '0 , clk_i, rst_ni)
220+ assign w_progress = w_chan_spill_valid & mst_res_i.w_ready;
221+
222+ if (UserAwSize) begin : gen_user_aw_w
223+ // We must couple the AW, W, and B FIFO; adopt AW channel counts here
224+ assign mst_req_o.w_valid = aw_progress & b_progress & w_chan_spill_valid;
225+ assign w_chan_spill_ready = aw_progress & b_progress & mst_res_i.w_ready;
226+ assign w_sel = aw_sel_out;
227+ end else begin : gen_no_user_aw_w
228+ // The W channel can operate uncoupled
229+ sel_t w_sel_q, w_sel_d;
230+ logic w_sel_load;
231+ assign w_sel_load = mst_req_o.w_valid & mst_res_i.w_ready;
232+ assign w_sel_d = sel_t ' (w_sel_q + 1'b1 );
233+ `FFLARN (w_sel_q, w_sel_d, w_sel_load, '0 , clk_i, rst_ni)
234+ assign mst_req_o.w_valid = w_chan_spill_valid;
235+ assign w_chan_spill_ready = mst_res_i.w_ready & (& w_sel_q);
236+ assign w_sel = w_sel_q;
237+ end
197238
198239 // B response aggregation
199240 // Slave port B output is the aggregated error of the last few B responses.
200241 sel_t b_sel_q, b_sel_d;
201242 axi_pkg :: resp_t b_resp_q, b_resp_d;
202243 logic b_resp_load;
244+ logic b_end;
203245
204246 assign slv_res_o.b = axi_lite_b_t'{
205247 resp: b_resp_q | mst_res_i.b.resp,
206248 default : '0
207249 } ;
250+
251+ if (UserAwSize) begin : gen_user_aw_b
252+ // When an upstream AW/W pair completes, store the expected downstream B count
253+ sel_t b_out;
254+ stream_fifo # (
255+ .FALL_THROUGH ( 1'b0 ),
256+ .DEPTH ( UserAwMaxTxns ),
257+ .T ( sel_t ),
258+ ) i_b_count_fifo (
259+ .clk_i,
260+ .rst_ni,
261+ .flush_i ( 1'b0 ),
262+ .testmode_i ( 1'b0 ),
263+ .usage_o ( ),
264+ .data_i ( aw_sel_out ),
265+ .valid_i ( mst_req_o.aw_valid & mst_resp_i.aw_ready ),
266+ .ready_o ( b_progress ),
267+ .data_o ( b_out ),
268+ .valid_o ( ), // TODO: Assert true when B comes in (`b_resp_load`)
269+ .ready_i ( b_end )
270+ );
271+ assign b_end = (& b_sel_q) | (b_sel_d == b_out);
272+ end else begin : gen_no_user_aw_b
273+ // Simply count payloads as for AW and W
274+ assign b_end = (& b_sel_q);
275+ assign b_progress = 1'b1 ;
276+ end
277+
208278 // Output is valid, if it is the last b response for the wide W, we have something
209279 // in the B FIFO and the B response is valid from the master port.
210- assign slv_res_o.b_valid = mst_res_i.b_valid & ( & b_sel_q) ;
280+ assign slv_res_o.b_valid = mst_res_i.b_valid & b_end ;
211281
212282 // Assign the b_channel ready output. The master port is ready if something is in the
213283 // B FIFO. Except, if it is the last one which should do a response on the slave port.
214- assign mst_req_o.b_ready = ( & b_sel_q) ? slv_req_i.b_ready : 1'b1 ;
284+ assign mst_req_o.b_ready = b_end ? slv_req_i.b_ready : 1'b1 ;
215285 // B channel error response retention FF
216- assign b_sel_d = sel_t ' (b_sel_q + 1'b1 );
217- assign b_resp_d = ( & b_sel_q) ? axi_pkg :: RESP_OKAY : (b_resp_q | mst_res_i.b.resp);
286+ assign b_sel_d = sel_t ' (b_end ? '0 : b_sel_q + 1'b1 );
287+ assign b_resp_d = b_end ? axi_pkg :: RESP_OKAY : (b_resp_q | mst_res_i.b.resp);
218288 assign b_resp_load = mst_res_i.b_valid & mst_req_o.b_ready;
219289 `FFLARN (b_sel_q, b_sel_d, b_resp_load, '0 , clk_i, rst_ni)
220290 `FFLARN (b_resp_q, b_resp_d, b_resp_load, axi_pkg :: RESP_OKAY , clk_i, rst_ni)
@@ -223,6 +293,7 @@ module axi_lite_dw_converter #(
223293 // Input spill register of the AW channel.
224294 axi_lite_ar_t ar_chan_spill;
225295 logic ar_chan_spill_valid, ar_chan_spill_ready;
296+ logic ar_progress, r_progress,
226297
227298 spill_register # (
228299 .T ( axi_lite_ar_t ),
@@ -238,32 +309,77 @@ module axi_lite_dw_converter #(
238309 .data_o ( ar_chan_spill )
239310 );
240311
241- sel_t ar_sel_q, ar_sel_d;
312+ sel_t ar_sel_q, ar_sel_d, ar_sel_out ;
242313 logic ar_sel_load;
243314 // AR channel output assignment
244315 always_comb begin : proc_ar_chan_oup
245316 mst_req_o.ar = ar_chan_spill;
246- mst_req_o.ar.addr = out_address (ar_chan_spill.addr, ar_sel_q);
317+ mst_req_o.ar.addr = out_address (ar_chan_spill.addr, ar_sel_out);
318+ end
319+
320+ assign ar_progress = ar_chan_spill_valid & mst_res_i.ar_ready;
321+
322+ if (UserAwSize) begin : gen_user_ar
323+ // Couple AR and R FIFO
324+ sel_t ar_sel_end, ar_sel_base;
325+ assign ar_sel_end = UserAwSize ?
326+ (sel_t ' (1 ) << ar_chan_spill.user[UserArSizeLsb: + axi_pkg :: SizeWidth]) >> SelOffset : '0 ;
327+ assign ar_sel_base = ar_chan_spill.ar.addr[SelOffset+ : SelWidth] & sel_t ' (ar_sel_end - 1 );
328+ assign ar_sel_out = ar_sel_q + ar_sel_base;
329+ assign mst_req_o.aw_valid = r_progress & ar_chan_spill_valid;
330+ assign aw_chan_spill_ready = r_progress & mst_res_i.ar_ready &
331+ ((& ar_sel_q) | (ar_sel_d == ar_sel_end));
332+ end else begin : gen_no_user_ar
333+ // AR and R are uncoupled
334+ assign ar_sel_out = ar_sel_q;
335+ assign mst_req_o.ar_valid = ar_chan_spill_valid;
336+ assign ar_chan_spill_ready = mst_res_i.ar_ready & (& ar_sel_q);
247337 end
248- // Slave port aw is valid, if there is something in the spill register.
249- assign mst_req_o.ar_valid = ar_chan_spill_valid;
250- assign ar_chan_spill_ready = mst_res_i.ar_ready & (& ar_sel_q);
251338
252339 assign ar_sel_load = mst_req_o.ar_valid & mst_res_i.ar_ready;
253- assign ar_sel_d = sel_t ' (ar_sel_q + 1'b1 );
340+ assign ar_sel_d = sel_t ' (ar_sel_load ? '0 : ar_sel_q + 1'b1 );
254341 `FFLARN (ar_sel_q, ar_sel_d, ar_sel_load, '0 , clk_i, rst_ni)
255342
256343 // Responses have to be aggregated, one FF less, as the last data is feed directly through.
257344 sel_t r_sel_q, r_sel_d;
258345 logic r_sel_load;
259346 axi_lite_mst_r_t [DownsizeFactor- 2 : 0 ] r_chan_mst_q;
260347 logic [DownsizeFactor- 2 : 0 ] r_chan_mst_load;
348+ logic r_end;
349+
350+ if (UserArSize) begin : gen_user_ar_r
351+ // When an upstream AR completes, store the expected downstream R count
352+ sel_t r_out;
353+ stream_fifo # (
354+ .FALL_THROUGH ( 1'b0 ),
355+ .DEPTH ( UserArMaxTxns ),
356+ .T ( sel_t ),
357+ ) i_r_count_fifo (
358+ .clk_i,
359+ .rst_ni,
360+ .flush_i ( 1'b0 ),
361+ .testmode_i ( 1'b0 ),
362+ .usage_o ( ),
363+ .data_i ( ar_sel_out ),
364+ .valid_i ( mst_req_o.ar_valid & mst_resp_i.ar_ready ),
365+ .ready_o ( r_progress ),
366+ .data_o ( r_out ),
367+ .valid_o ( ), // TODO: Assert true when R comes in (`r_sel_load`)
368+ .ready_i ( r_end )
369+ );
370+ assign r_end = (& r_sel_q) | (r_sel_d == r_out);
371+ end else begin : gen_no_user_ar_r
372+ // Simply count payloads as for AW and W
373+ assign r_end = (& r_sel_q);
374+ assign r_progress = 1'b1 ;
375+ end
376+
261377 for (genvar i = 0 ; unsigned '(i) < (DownsizeFactor- 1 ); i++ ) begin : gen_r_chan_ff
262378 assign r_chan_mst_load[i] = (sel_t ' (i) == r_sel_q) & mst_res_i.r_valid & mst_req_o.r_ready;
263379 `FFLARN (r_chan_mst_q[i], mst_res_i.r, r_chan_mst_load[i], axi_lite_mst_r_t'{ default : '0 } , clk_i, rst_ni)
264380 end
265381 assign r_sel_load = mst_res_i.r_valid & mst_req_o.r_ready;
266- assign r_sel_d = sel_t ' (r_sel_q + 1'b1 );
382+ assign r_sel_d = sel_t ' (r_sel_load ? '0 : r_sel_q + 1'b1 );
267383 `FFLARN (r_sel_q, r_sel_d, r_sel_load, '0 , clk_i, rst_ni)
268384
269385 always_comb begin : proc_r_chan_oup
@@ -273,16 +389,16 @@ module axi_lite_dw_converter #(
273389 } ;
274390 // Response is the OR of all responses
275391 for (int unsigned i = 0 ; i < (DownsizeFactor- 1 ); i++ ) begin
276- slv_res_o.r.resp = slv_res_o.r.resp | r_chan_mst_q[i].resp;
392+ slv_res_o.r.resp = slv_res_o.r.resp | (r_sel_q >= sel_t ' (i) ? r_chan_mst_q[i].resp : '0 ) ;
277393 slv_res_o.r.data[i* AxiMstPortDataWidth+ : AxiMstPortDataWidth] = r_chan_mst_q[i].data;
278394 end
279395 // The highest bits of the data can be directly the master port.
280396 slv_res_o.r.data[(DownsizeFactor- 1 )* AxiMstPortDataWidth+ : AxiMstPortDataWidth] =
281397 mst_res_i.r.data;
282398 end
283399
284- assign slv_res_o.r_valid = ( & r_sel_q) ? mst_res_i.r_valid : 1'b0 ;
285- assign mst_req_o.r_ready = ( & r_sel_q) ? slv_req_i.r_ready : 1'b1 ;
400+ assign slv_res_o.r_valid = r_end ? mst_res_i.r_valid : 1'b0 ;
401+ assign mst_req_o.r_ready = r_end ? slv_req_i.r_ready : 1'b1 ;
286402
287403 end else if (AxiMstPortDataWidth > AxiSlvPortDataWidth) begin : gen_upsizer
288404 // The upsize factor determines the amount of replication.
0 commit comments