Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

axi_demux: Replace write FIFO (w_fifo) with a write credit counter #253

Merged
merged 3 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
variables:
SYNOPSYS_DC: synopsys-2019.12 dc_shell -64bit
SYNOPSYS_DC: synopsys-2022.03 dc_shell -64bit

before_script:
- export PATH=~/.cargo/bin:$PATH
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added

### Changed
- `axi_demux`: Replace write FIFO (`w_fifo`) with a write credit counter.

### Fixed

Expand Down
1 change: 0 additions & 1 deletion src/axi_burst_splitter.sv
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ module axi_burst_splitter #(
.NoMstPorts ( 2 ),
.MaxTrans ( MaxTxns ),
.AxiLookBits ( IdWidth ),
.FallThrough ( 1'b1 ),
.SpillAw ( 1'b0 ),
.SpillW ( 1'b0 ),
.SpillB ( 1'b0 ),
Expand Down
88 changes: 49 additions & 39 deletions src/axi_demux.sv
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ module axi_demux #(
parameter int unsigned MaxTrans = 32'd8,
parameter int unsigned AxiLookBits = 32'd3,
parameter bit UniqueIds = 1'b0,
parameter bit FallThrough = 1'b0,
parameter bit SpillAw = 1'b1,
parameter bit SpillW = 1'b0,
parameter bit SpillB = 1'b0,
Expand All @@ -74,7 +73,8 @@ module axi_demux #(
input axi_resp_t [NoMstPorts-1:0] mst_resps_i
);

localparam int unsigned IdCounterWidth = MaxTrans > 1 ? $clog2(MaxTrans) : 1;
localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans);
typedef logic [IdCounterWidth-1:0] id_cnt_t;

//--------------------------------------
// Typedefs for the FIFOs / Queues
Expand Down Expand Up @@ -175,14 +175,14 @@ module axi_demux #(
// AW ID counter
select_t lookup_aw_select;
logic aw_select_occupied, aw_id_cnt_full;
logic aw_push;
// Upon an ATOP load, inject IDs from the AW into the AR channel
logic atop_inject;

// W FIFO: stores the decision to which master W beats should go
logic w_fifo_pop;
logic w_fifo_full, w_fifo_empty;
select_t w_select;
// W select counter: stores the decision to which master W beats should go
select_t w_select, w_select_q;
logic w_select_valid;
id_cnt_t w_open;
logic w_cnt_up, w_cnt_down;

// Register which locks the AW valid signal
logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock;
Expand Down Expand Up @@ -274,9 +274,9 @@ module axi_demux #(
lock_aw_valid_d = lock_aw_valid_q;
load_aw_lock = 1'b0;
// AW ID counter and W FIFO
aw_push = 1'b0;
w_cnt_up = 1'b0;
// ATOP injection into ar counter
atop_inject = 1'b0;
atop_inject = 1'b0;
// we had an arbitration decision, the valid is locked, wait for the transaction
if (lock_aw_valid_q) begin
aw_valid = 1'b1;
Expand All @@ -289,19 +289,23 @@ module axi_demux #(
atop_inject = slv_aw_chan_select.aw_chan.atop[axi_pkg::ATOP_R_RESP] & AtopSupport;
end
end else begin
// An AW can be handled if `i_aw_id_counter` and `i_w_fifo` are not full. An ATOP that
// An AW can be handled if `i_aw_id_counter` and `i_counter_open_w` are not full. An ATOP that
// requires an R response can be handled if additionally `i_ar_id_counter` is not full (this
// only applies if ATOPs are supported at all).
if (!aw_id_cnt_full && !w_fifo_full &&
if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) &&
(!(ar_id_cnt_full && slv_aw_chan_select.aw_chan.atop[axi_pkg::ATOP_R_RESP]) ||
!AtopSupport)) begin
// there is a valid AW vector make the id lookup and go further, if it passes
if (slv_aw_valid && (!aw_select_occupied ||
(slv_aw_chan_select.aw_select == lookup_aw_select))) begin
/// There is a valid AW vector make the id lookup and go further, if it passes.
/// Also stall if previous transmitted AWs still have active W's in flight.
/// This prevents deadlocking of the W channel. The counters are there for the
/// Handling of the B responses.
if (slv_aw_valid &&
((w_open == '0) || (w_select == slv_aw_chan_select.aw_select)) &&
(!aw_select_occupied || (slv_aw_chan_select.aw_select == lookup_aw_select))) begin
// connect the handshake
aw_valid = 1'b1;
// push arbitration to the W FIFO regardless, do not wait for the AW transaction
aw_push = 1'b1;
w_cnt_up = 1'b1;
// on AW transaction
if (aw_ready) begin
slv_aw_ready = 1'b1;
Expand Down Expand Up @@ -345,32 +349,36 @@ module axi_demux #(
.inject_i ( 1'b0 ),
.push_axi_id_i ( slv_aw_chan_select.aw_chan.id[0+:AxiLookBits] ),
.push_mst_select_i ( slv_aw_chan_select.aw_select ),
.push_i ( aw_push ),
.push_i ( w_cnt_up ),
.pop_axi_id_i ( slv_b_chan.id[0+:AxiLookBits] ),
.pop_i ( slv_b_valid & slv_b_ready )
);
// pop from ID counter on outward transaction
end

// FIFO to save W selection
fifo_v3 #(
.FALL_THROUGH ( FallThrough ),
thommythomaso marked this conversation as resolved.
Show resolved Hide resolved
.DEPTH ( MaxTrans ),
.dtype ( select_t )
) i_w_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.testmode_i( test_i ),
.full_o ( w_fifo_full ),
.empty_o ( w_fifo_empty ),
.usage_o ( ),
.data_i ( slv_aw_chan_select.aw_select ),
.push_i ( aw_push ), // controlled from proc_aw_chan
.data_o ( w_select ), // where the w beat should go
.pop_i ( w_fifo_pop ) // controlled from proc_w_chan
// This counter steers the demultiplexer of the W channel.
// `w_select` determines, which handshaking is connected.
// AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as
// `slv_aw_chan_select.aw_select`.
counter #(
.WIDTH ( IdCounterWidth ),
.STICKY_OVERFLOW ( 1'b0 )
) i_counter_open_w (
.clk_i,
.rst_ni,
.clear_i ( 1'b0 ),
.en_i ( w_cnt_up ^ w_cnt_down ),
.load_i ( 1'b0 ),
.down_i ( w_cnt_down ),
.d_i ( '0 ),
.q_o ( w_open ),
.overflow_o ( /*not used*/ )
);

`FFLARN(w_select_q, slv_aw_chan_select.aw_select, w_cnt_up, select_t'(0), clk_i, rst_ni)
assign w_select = (|w_open) ? w_select_q : slv_aw_chan_select.aw_select;
assign w_select_valid = w_cnt_up | (|w_open);

//--------------------------------------
// W Channel
//--------------------------------------
Expand Down Expand Up @@ -571,16 +579,16 @@ module axi_demux #(
.idx_o ( )
);

assign ar_ready = ar_valid & mst_resps_i[slv_ar_chan_select.ar_select].ar_ready;
assign aw_ready = aw_valid & mst_resps_i[slv_aw_chan_select.aw_select].aw_ready;
assign ar_ready = ar_valid & mst_resps_i[slv_ar_chan_select.ar_select].ar_ready;
assign aw_ready = aw_valid & mst_resps_i[slv_aw_chan_select.aw_select].aw_ready;

// process that defines the individual demuxes and assignments for the arbitration
// as mst_reqs_o has to be drivem from the same always comb block!
always_comb begin
// default assignments
mst_reqs_o = '0;
slv_w_ready = 1'b0;
w_fifo_pop = 1'b0;
w_cnt_down = 1'b0;

for (int unsigned i = 0; i < NoMstPorts; i++) begin
// AW channel
Expand All @@ -593,10 +601,10 @@ module axi_demux #(
// W channel
mst_reqs_o[i].w = slv_w_chan;
mst_reqs_o[i].w_valid = 1'b0;
if (!w_fifo_empty && (w_select == i)) begin
if (w_select_valid && (w_select == select_t'(i))) begin
mst_reqs_o[i].w_valid = slv_w_valid;
slv_w_ready = mst_resps_i[i].w_ready;
w_fifo_pop = slv_w_valid & mst_resps_i[i].w_ready & slv_w_chan.last;
w_cnt_down = slv_w_valid & mst_resps_i[i].w_ready & slv_w_chan.last;
end

// B channel
Expand Down Expand Up @@ -658,6 +666,9 @@ module axi_demux #(
internal_aw_select: assert property( @(posedge clk_i)
(aw_valid |-> slv_aw_chan_select.aw_select < NoMstPorts))
else $fatal(1, "slv_aw_chan_select.aw_select illegal while aw_valid.");
w_underflow: assert property( @(posedge clk_i)
((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else
$fatal(1, "W counter underflowed!");
`ASSUME(NoAtopAllowed, !AtopSupport && slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0)
`endif
`endif
Expand Down Expand Up @@ -858,7 +869,6 @@ module axi_demux_intf #(
.MaxTrans ( MAX_TRANS ),
.AxiLookBits ( AXI_LOOK_BITS ),
.UniqueIds ( UNIQUE_IDS ),
.FallThrough ( FALL_THROUGH ),
.SpillAw ( SPILL_AW ),
.SpillW ( SPILL_W ),
.SpillB ( SPILL_B ),
Expand Down
1 change: 0 additions & 1 deletion src/axi_id_serialize.sv
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ module axi_id_serialize #(
.NoMstPorts ( AxiMstPortMaxUniqIds ),
.MaxTrans ( AxiSlvPortMaxTxns ),
.AxiLookBits ( AxiSlvPortIdWidth ),
.FallThrough ( 1'b1 ),
.SpillAw ( 1'b1 ),
.SpillW ( 1'b0 ),
.SpillB ( 1'b0 ),
Expand Down
1 change: 0 additions & 1 deletion src/axi_isolate.sv
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ module axi_isolate #(
// We don't need many bits here as the common case will be to go for the pass-through.
.AxiLookBits ( 1 ),
.UniqueIds ( 1'b0 ),
.FallThrough ( 1'b1 ),
.SpillAw ( 1'b0 ),
.SpillW ( 1'b0 ),
.SpillB ( 1'b0 ),
Expand Down
1 change: 0 additions & 1 deletion src/axi_to_mem_banked.sv
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ module axi_to_mem_banked #(
.MaxTrans ( MemLatency+2 ), // allow multiple Ax vectors to not starve W channel
.AxiLookBits ( 32'd1 ), // select is fixed, do not need it
.UniqueIds ( 1'b0 ),
.FallThrough ( 1'b1 ),
.SpillAw ( 1'b1 ),
.SpillW ( 1'b1 ),
.SpillB ( 1'b1 ),
Expand Down
1 change: 0 additions & 1 deletion src/axi_xbar.sv
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ import cf_math_pkg::idx_width;
.MaxTrans ( Cfg.MaxMstTrans ),
.AxiLookBits ( Cfg.AxiIdUsedSlvPorts ),
.UniqueIds ( Cfg.UniqueIds ),
.FallThrough ( Cfg.FallThrough ),
.SpillAw ( Cfg.LatencyMode[9] ),
.SpillW ( Cfg.LatencyMode[8] ),
.SpillB ( Cfg.LatencyMode[7] ),
Expand Down