Skip to content

Commit

Permalink
Merge pull request #323 from pulp-platform/fix/axi_dw_downsizer
Browse files Browse the repository at this point in the history
axi_dw_downsizer: Fix `i_forward_b_beats_queue` underflow
  • Loading branch information
micprog committed Jul 18, 2024
2 parents 07ad48c + 1d04d88 commit 3e88ef2
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `axi_bus_compare`: Fix mismatch detection.
- `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request.
Bump `common_cells` for `mem_to_banks` fix.
- `axi_dw_downsizer`: Fix `i_forward_b_beats_queue` underflow.

## 0.39.3 - 2024-05-08
### Added
Expand Down
8 changes: 8 additions & 0 deletions scripts/run_vsim.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ exec_test() {
call_vsim tb_$1
;;
axi_dw_downsizer)
call_vsim tb_axi_dw_downsizer \
-gTbAxiSlvPortDataWidth=32 \
-gTbAxiMstPortDataWidth=16 \
-gTbInitialBStallCycles=100000 -t 1ps
call_vsim tb_axi_dw_downsizer \
-gTbAxiSlvPortDataWidth=32 \
-gTbAxiMstPortDataWidth=16 \
-gTbInitialRStallCycles=100000 -t 1ps
for AxiSlvPortDataWidth in 8 16 32 64 128 256 512 1024; do
for (( AxiMstPortDataWidth = 8; \
AxiMstPortDataWidth < $AxiSlvPortDataWidth; \
Expand Down
61 changes: 41 additions & 20 deletions src/axi_dw_downsizer.sv
Original file line number Diff line number Diff line change
Expand Up @@ -545,9 +545,9 @@ module axi_dw_downsizer #(
end

// Request was accepted
if (!r_req_q.ar_valid)
if (!r_req_q.ar_valid) begin
// Our turn
if ((idqueue_id == t) && idqueue_valid)
if ((idqueue_id == t) && idqueue_valid) begin
// Ready to accept more data
if (!slv_r_valid_tran[t] || (slv_r_valid_tran[t] && slv_r_ready_tran[t])) begin
mst_r_ready_tran[t] = 1'b1;
Expand All @@ -557,12 +557,13 @@ module axi_dw_downsizer #(
automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiSlvPortStrbWidth)-1:0];

// Serialization
for (int b = 0; b < AxiSlvPortStrbWidth; b++)
for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin
if ((b >= slv_port_offset) &&
(b - slv_port_offset < (1 << r_req_q.orig_ar_size)) &&
(b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin
r_data[b] = mst_resp.r.data[8*(b + mst_port_offset - slv_port_offset) +: 8];
end
end

r_req_d.burst_len = r_req_q.burst_len - 1 ;
r_req_d.ar.len = r_req_q.ar.len - 1 ;
Expand All @@ -583,33 +584,44 @@ module axi_dw_downsizer #(
end
endcase

if (r_req_q.burst_len == 0)
if (r_req_q.burst_len == 0) begin
idqueue_pop[t] = 1'b1;
end

case (r_state_q)
R_PASSTHROUGH :
R_PASSTHROUGH : begin
// Forward data as soon as we can
r_req_d.r_valid = 1'b1;
end

R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE:
R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE: begin
// Forward when the burst is finished, or after filling up a word
if (r_req_q.burst_len == 0 || (aligned_addr(r_req_d.ar.addr, r_req_q.orig_ar_size) != aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size)))
if (r_req_q.burst_len == 0 ||
(aligned_addr(r_req_d.ar.addr, r_req_q.orig_ar_size) !=
aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size) )) begin
r_req_d.r_valid = 1'b1;
end
end
endcase

// Trigger another burst request, if needed
if (r_state_q == R_SPLIT_INCR_DOWNSIZE)
if (r_state_q == R_SPLIT_INCR_DOWNSIZE) begin
// Finished current burst, but whole transaction hasn't finished
if (r_req_q.ar.len == '0 && r_req_q.burst_len != '0) begin
r_req_d.ar_valid = !r_req_q.injected_aw;
r_req_d.ar.len = (r_req_d.burst_len <= 255) ? r_req_d.burst_len : 255;
end
end
end
end
end
end

if (slv_r_valid_tran[t] && slv_r_ready_tran[t])
if (r_req_q.burst_len == '1)
if (slv_r_valid_tran[t] && slv_r_ready_tran[t]) begin
if (r_req_q.burst_len == '1) begin
r_state_d = R_IDLE;
end
end
end
endcase
end
Expand Down Expand Up @@ -709,8 +721,9 @@ module axi_dw_downsizer #(
mst_req.b_ready = slv_req_i.b_ready;

// Got an ack on the B channel. Pop transaction.
if (mst_req.b_ready && mst_resp.b_valid)
if (mst_req.b_ready && mst_resp.b_valid) begin
forward_b_beat_pop = 1'b1;
end
end else begin
// Otherwise, just acknowlegde the B beats
slv_resp_o.b_valid = 1'b0 ;
Expand All @@ -727,26 +740,28 @@ module axi_dw_downsizer #(
case (w_state_q)
W_PASSTHROUGH, W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin
// Request was accepted
if (!w_req_q.aw_valid)
if (!w_req_q.aw_valid) begin
if (slv_req_i.w_valid) begin
automatic addr_t mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiMstPortStrbWidth)-1:0];
automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0];

// Valid output
mst_req.w_valid = 1'b1 ;
mst_req.w_valid = !(forward_b_beat_full && w_req_q.aw.len == 0);
mst_req.w.last = w_req_q.aw.len == 0;
mst_req.w.user = slv_req_i.w.user ;

// Lane steering
for (int b = 0; b < AxiSlvPortStrbWidth; b++)
for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin
if ((b >= slv_port_offset) &&
(b - slv_port_offset < (1 << w_req_q.orig_aw_size)) &&
(b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin
w_data[b + mst_port_offset - slv_port_offset] = slv_req_i.w.data[8*b +: 8];
mst_req.w.strb[b + mst_port_offset - slv_port_offset] = slv_req_i.w.strb[b] ;
end
end
mst_req.w.data = w_data;
end
end

// Acknowledgment
if (mst_resp.w_ready && mst_req.w_valid) begin
Expand All @@ -763,27 +778,33 @@ module axi_dw_downsizer #(
endcase

case (w_state_q)
W_PASSTHROUGH:
W_PASSTHROUGH: begin
slv_resp_o.w_ready = 1'b1;
end

W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE:
if (w_req_q.burst_len == 0 || (aligned_addr(w_req_d.aw.addr, w_req_q.orig_aw_size) != aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size)))
W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin
if (w_req_q.burst_len == 0 ||
(aligned_addr(w_req_d.aw.addr, w_req_q.orig_aw_size) !=
aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size) )) begin
slv_resp_o.w_ready = 1'b1;
end
end
endcase

// Trigger another burst request, if needed
if (w_state_q == W_SPLIT_INCR_DOWNSIZE)
if (w_state_q == W_SPLIT_INCR_DOWNSIZE) begin
// Finished current burst, but whole transaction hasn't finished
if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0 && !forward_b_beat_full) begin
if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0) begin
w_req_d.aw_valid = 1'b1;
w_req_d.aw.len = (w_req_d.burst_len <= 255) ? w_req_d.burst_len : 255;

// We will receive an extraneous B beat. Ignore it.
forward_b_beat_i = 1'b0;
forward_b_beat_push = 1'b1;
end
end

if (w_req_q.burst_len == 0 && !forward_b_beat_full) begin
if (w_req_q.burst_len == 0) begin
w_state_d = W_IDLE;

forward_b_beat_push = 1'b1;
Expand Down
31 changes: 30 additions & 1 deletion test/tb_axi_dw_downsizer.sv
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module tb_axi_dw_downsizer #(
parameter int unsigned TbAxiSlvPortDataWidth = 64 ,
parameter int unsigned TbAxiMstPortDataWidth = 32 ,
parameter int unsigned TbAxiUserWidth = 8 ,
parameter int unsigned TbInitialBStallCycles = 0,
parameter int unsigned TbInitialRStallCycles = 0,
// TB Parameters
parameter time TbCyclTime = 10ns,
parameter time TbApplTime = 2ns ,
Expand All @@ -35,6 +37,9 @@ module tb_axi_dw_downsizer #(
logic rst_n;
logic eos;

int unsigned b_stall;
int unsigned r_stall;

clk_rst_gen #(
.ClkPeriod (TbCyclTime),
.RstClkCycles (5 )
Expand Down Expand Up @@ -65,7 +70,31 @@ module tb_axi_dw_downsizer #(
.AXI_USER_WIDTH(TbAxiUserWidth )
) master ();

`AXI_ASSIGN(master, master_dv)
`AXI_ASSIGN_AW(master, master_dv)
`AXI_ASSIGN_W(master, master_dv)
`AXI_ASSIGN_AR(master, master_dv)
assign master_dv.b_id = master.b_id;
assign master_dv.b_resp = master.b_resp;
assign master_dv.b_user = master.b_user;
assign master_dv.b_valid = b_stall != 0 ? 1'b0 : master.b_valid;
assign master.b_ready = b_stall != 0 ? 1'b0 : master_dv.b_ready;
assign master_dv.r_id = master.r_id;
assign master_dv.r_data = master.r_data;
assign master_dv.r_resp = master.r_resp;
assign master_dv.r_last = master.r_last;
assign master_dv.r_user = master.r_user;
assign master_dv.r_valid = r_stall != 0 ? 1'b0 : master.r_valid;
assign master.r_ready = r_stall != 0 ? 1'b0 : master_dv.r_ready;

always_ff @(posedge clk or negedge rst_n) begin : proc_
if(~rst_n) begin
b_stall <= TbInitialBStallCycles;
r_stall <= TbInitialRStallCycles;
end else begin
b_stall <= b_stall == 0 ? 0 : b_stall-1;
r_stall <= r_stall == 0 ? 0 : r_stall-1;
end
end

axi_test::axi_rand_master #(
.AW (TbAxiAddrWidth ),
Expand Down

0 comments on commit 3e88ef2

Please sign in to comment.