Skip to content

Commit

Permalink
Rewrite simpler axi_id_serializer
Browse files Browse the repository at this point in the history
Removes demux and mux inside
  • Loading branch information
micprog committed May 22, 2024
1 parent 9402c8a commit 7a8d0ab
Showing 1 changed file with 116 additions and 204 deletions.
320 changes: 116 additions & 204 deletions src/axi_id_serialize.sv
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Paul Scheffler <paulsc@iis.ee.ethz.ch>
// - Michael Rogenmoser <michaero@iis.ee.ethz.ch>

`include "axi/assign.svh"
`include "axi/typedef.svh"
Expand All @@ -29,9 +30,6 @@
module axi_id_serialize #(
/// ID width of the AXI4+ATOP slave port
parameter int unsigned AxiSlvPortIdWidth = 32'd0,
/// Maximum number of transactions that can be in flight at the slave port. Reads and writes are
/// counted separately (except for ATOPs, which count as both read and write).
parameter int unsigned AxiSlvPortMaxTxns = 32'd0,
/// ID width of the AXI4+ATOP master port
parameter int unsigned AxiMstPortIdWidth = 32'd0,
/// Maximum number of different IDs that can be in flight at the master port. Reads and writes
Expand All @@ -41,14 +39,6 @@ module axi_id_serialize #(
parameter int unsigned AxiMstPortMaxUniqIds = 32'd0,
/// Maximum number of in-flight transactions with the same ID at the master port.
parameter int unsigned AxiMstPortMaxTxnsPerId = 32'd0,
/// Address width of both AXI4+ATOP ports
parameter int unsigned AxiAddrWidth = 32'd0,
/// Data width of both AXI4+ATOP ports
parameter int unsigned AxiDataWidth = 32'd0,
/// User width of both AXI4+ATOP ports
parameter int unsigned AxiUserWidth = 32'd0,
/// Enable support for AXI4+ATOP atomics
parameter bit AtopSupport = 1'b1,
/// Request struct type of the AXI4+ATOP slave port
parameter type slv_req_t = logic,
/// Response struct type of the AXI4+ATOP slave port
Expand All @@ -66,7 +56,13 @@ module axi_id_serialize #(
/// Number of Entries in the explicit ID map (default: None)
parameter int unsigned IdMapNumEntries = 32'd0,
/// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID.
parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}}
parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}},
// unused parameters, no longer needed, left for backwards-compatibility
parameter int unsigned AxiSlvPortMaxTxns = 32'd0, // unused
parameter int unsigned AxiAddrWidth = 32'd0,
parameter int unsigned AxiDataWidth = 32'd0,
parameter int unsigned AxiUserWidth = 32'd0,
parameter bit AtopSupport = 1'b1
) (
/// Rising-edge clock of both ports
input logic clk_i,
Expand All @@ -87,73 +83,9 @@ module axi_id_serialize #(
/// Slice of slave port IDs that determines the master port ID
typedef logic [SelectWidth-1:0] select_t;

/// ID width after the multiplexer
localparam int unsigned MuxIdWidth = (AxiMstPortMaxUniqIds > 32'd1) ? SelectWidth + 32'd1 : 32'd1;

/// ID after serializer (i.e., with a constant value of zero)
typedef logic [0:0] ser_id_t;
/// ID after the multiplexer
typedef logic [MuxIdWidth-1:0] mux_id_t;
/// ID at the slave port
typedef logic [AxiSlvPortIdWidth-1:0] slv_id_t;
/// ID at the master port
typedef logic [AxiMstPortIdWidth-1:0] mst_id_t;
/// Address in any AXI channel
typedef logic [AxiAddrWidth-1:0] addr_t;
/// Data in any AXI channel
typedef logic [AxiDataWidth-1:0] data_t;
/// Strobe in any AXI channel
typedef logic [AxiDataWidth/8-1:0] strb_t;
/// User signal in any AXI channel
typedef logic [AxiUserWidth-1:0] user_t;

/// W channel at any interface
`AXI_TYPEDEF_W_CHAN_T(w_t, data_t, strb_t, user_t)

/// AW channel at slave port
`AXI_TYPEDEF_AW_CHAN_T(slv_aw_t, addr_t, slv_id_t, user_t)
/// B channel at slave port
`AXI_TYPEDEF_B_CHAN_T(slv_b_t, slv_id_t, user_t)
/// AR channel at slave port
`AXI_TYPEDEF_AR_CHAN_T(slv_ar_t, addr_t, slv_id_t, user_t)
/// R channel at slave port
`AXI_TYPEDEF_R_CHAN_T(slv_r_t, data_t, slv_id_t, user_t)

/// AW channel after serializer
`AXI_TYPEDEF_AW_CHAN_T(ser_aw_t, addr_t, ser_id_t, user_t)
/// B channel after serializer
`AXI_TYPEDEF_B_CHAN_T(ser_b_t, ser_id_t, user_t)
/// AR channel after serializer
`AXI_TYPEDEF_AR_CHAN_T(ser_ar_t, addr_t, ser_id_t, user_t)
/// R channel after serializer
`AXI_TYPEDEF_R_CHAN_T(ser_r_t, data_t, ser_id_t, user_t)
/// AXI Requests from serializer
`AXI_TYPEDEF_REQ_T(ser_req_t, ser_aw_t, w_t, ser_ar_t)
/// AXI responses to serializer
`AXI_TYPEDEF_RESP_T(ser_resp_t, ser_b_t, ser_r_t)

/// AW channel after the multiplexer
`AXI_TYPEDEF_AW_CHAN_T(mux_aw_t, addr_t, mux_id_t, user_t)
/// B channel after the multiplexer
`AXI_TYPEDEF_B_CHAN_T(mux_b_t, mux_id_t, user_t)
/// AR channel after the multiplexer
`AXI_TYPEDEF_AR_CHAN_T(mux_ar_t, addr_t, mux_id_t, user_t)
/// R channel after the multiplexer
`AXI_TYPEDEF_R_CHAN_T(mux_r_t, data_t, mux_id_t, user_t)
/// AXI requests from the multiplexer
`AXI_TYPEDEF_REQ_T(mux_req_t, mux_aw_t, w_t, mux_ar_t)
/// AXI responses to the multiplexer
`AXI_TYPEDEF_RESP_T(mux_resp_t, mux_b_t, mux_r_t)

/// AW channel at master port
`AXI_TYPEDEF_AW_CHAN_T(mst_aw_t, addr_t, mst_id_t, user_t)
/// B channel at master port
`AXI_TYPEDEF_B_CHAN_T(mst_b_t, mst_id_t, user_t)
/// AR channel at master port
`AXI_TYPEDEF_AR_CHAN_T(mst_ar_t, addr_t, mst_id_t, user_t)
/// R channel at master port
`AXI_TYPEDEF_R_CHAN_T(mst_r_t, data_t, mst_id_t, user_t)


/// Type for slave ID map
typedef mst_id_t [2**AxiSlvPortIdWidth-1:0] slv_id_map_t;

Expand All @@ -172,49 +104,68 @@ module axi_id_serialize #(
/// Input-to-output ID map used
localparam slv_id_map_t SlvIdMap = map_slv_ids();

select_t slv_aw_select, slv_ar_select;
select_t slv_aw_select, slv_ar_select, slv_b_select, slv_r_select;
assign slv_aw_select = select_t'(SlvIdMap[slv_req_i.aw.id]);
assign slv_ar_select = select_t'(SlvIdMap[slv_req_i.ar.id]);

slv_req_t [AxiMstPortMaxUniqIds-1:0] to_serializer_reqs;
slv_resp_t [AxiMstPortMaxUniqIds-1:0] to_serializer_resps;

axi_demux #(
.AxiIdWidth ( AxiSlvPortIdWidth ),
.aw_chan_t ( slv_aw_t ),
.w_chan_t ( w_t ),
.b_chan_t ( slv_b_t ),
.ar_chan_t ( slv_ar_t ),
.r_chan_t ( slv_r_t ),
.axi_req_t ( slv_req_t ),
.axi_resp_t ( slv_resp_t ),
.NoMstPorts ( AxiMstPortMaxUniqIds ),
.MaxTrans ( AxiSlvPortMaxTxns ),
.AxiLookBits ( AxiSlvPortIdWidth ),
.AtopSupport ( AtopSupport ),
.SpillAw ( 1'b1 ),
.SpillW ( 1'b0 ),
.SpillB ( 1'b0 ),
.SpillAr ( 1'b1 ),
.SpillR ( 1'b0 )
) i_axi_demux (
.clk_i,
.rst_ni,
.test_i ( 1'b0 ),
.slv_req_i ( slv_req_i ),
.slv_aw_select_i ( slv_aw_select ),
.slv_ar_select_i ( slv_ar_select ),
.slv_resp_o ( slv_resp_o ),
.mst_reqs_o ( to_serializer_reqs ),
.mst_resps_i ( to_serializer_resps )
logic [AxiMstPortMaxUniqIds-1:0] to_serializer_resps_b_valid,
to_serializer_resps_r_valid;

onehot_to_bin #(
.ONEHOT_WIDTH( AxiMstPortMaxUniqIds )
) i_slv_b_select (
.onehot(to_serializer_resps_b_valid),
.bin (slv_b_select)
);

onehot_to_bin #(
.ONEHOT_WIDTH( AxiMstPortMaxUniqIds )
) i_slv_r_select (
.onehot(to_serializer_resps_r_valid),
.bin (slv_r_select)
);

// Due to static ID mapping, ID consistency checking is not needed.
always_comb begin
// AW, W, AR
for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin
to_serializer_reqs[i] = slv_req_i; // .aw, .w, .ar
to_serializer_reqs[i].aw_valid = '0;
to_serializer_reqs[i].w_valid = '0;
to_serializer_reqs[i].ar_valid = '0;
end
to_serializer_reqs[slv_aw_select].aw_valid = slv_req_i.aw_valid;
slv_resp_o.aw_ready = to_serializer_resps[slv_aw_select].aw_ready;

slv_resp_o.w_ready = mst_resp_i.w_ready;

to_serializer_reqs[slv_ar_select].ar_valid = slv_req_i.ar_valid;
slv_resp_o.ar_ready = to_serializer_resps[slv_ar_select].ar_ready;

// B, R (these are passed through or both gated inside the serializer)
slv_resp_o.b_valid = |to_serializer_resps_b_valid;
slv_resp_o.b = to_serializer_resps[slv_b_select].b;
slv_resp_o.r_valid = |to_serializer_resps_r_valid;
slv_resp_o.r = to_serializer_resps[slv_r_select].r;
for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin
to_serializer_resps_b_valid[i] = to_serializer_resps[i].b_valid;
to_serializer_resps_r_valid[i] = to_serializer_resps[i].r_valid;

to_serializer_reqs[i].b_ready = slv_req_i.b_ready;
to_serializer_reqs[i].r_ready = slv_req_i.r_ready;
end
end

slv_req_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_reqs;
slv_resp_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_resps;
ser_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs;
ser_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps;
mst_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs;
mst_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps;

for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin : gen_serializers
// serializer takes care to ensure unique IDs for ATOPs
axi_serializer #(
.MaxReadTxns ( AxiMstPortMaxTxnsPerId ),
.MaxWriteTxns ( AxiMstPortMaxTxnsPerId ),
Expand All @@ -231,110 +182,71 @@ module axi_id_serialize #(
);
always_comb begin
`AXI_SET_REQ_STRUCT(from_serializer_reqs[i], tmp_serializer_reqs[i])
// Truncate to ID width 1 as all requests have ID '0.
from_serializer_reqs[i].aw.id = tmp_serializer_reqs[i].aw.id[0];
from_serializer_reqs[i].ar.id = tmp_serializer_reqs[i].ar.id[0];
from_serializer_reqs[i].aw.id = i;
from_serializer_reqs[i].ar.id = i;
`AXI_SET_RESP_STRUCT(tmp_serializer_resps[i], from_serializer_resps[i])
// Zero-extend response IDs.
tmp_serializer_resps[i].b.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].b.id};
tmp_serializer_resps[i].r.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].r.id};
tmp_serializer_resps[i].b.id = '0;
tmp_serializer_resps[i].r.id = '0;
end
end

mux_req_t axi_mux_req;
mux_resp_t axi_mux_resp;

axi_mux #(
.SlvAxiIDWidth ( 32'd1 ),
.slv_aw_chan_t ( ser_aw_t ),
.mst_aw_chan_t ( mux_aw_t ),
.w_chan_t ( w_t ),
.slv_b_chan_t ( ser_b_t ),
.mst_b_chan_t ( mux_b_t ),
.slv_ar_chan_t ( ser_ar_t ),
.mst_ar_chan_t ( mux_ar_t ),
.slv_r_chan_t ( ser_r_t ),
.mst_r_chan_t ( mux_r_t ),
.slv_req_t ( ser_req_t ),
.slv_resp_t ( ser_resp_t ),
.mst_req_t ( mux_req_t ),
.mst_resp_t ( mux_resp_t ),
.NoSlvPorts ( AxiMstPortMaxUniqIds ),
.MaxWTrans ( AxiMstPortMaxTxnsPerId ),
.FallThrough ( 1'b0 ),
.SpillAw ( 1'b1 ),
.SpillW ( 1'b0 ),
.SpillB ( 1'b0 ),
.SpillAr ( 1'b1 ),
.SpillR ( 1'b0 )
) i_axi_mux (
.clk_i,
.rst_ni,
.test_i ( 1'b0 ),
.slv_reqs_i ( from_serializer_reqs ),
.slv_resps_o ( from_serializer_resps ),
.mst_req_o ( axi_mux_req ),
.mst_resp_i ( axi_mux_resp )
logic [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs_aw_valid,
from_serializer_reqs_w_valid,
from_serializer_reqs_ar_valid,
from_serializer_reqs_b_ready,
from_serializer_reqs_r_ready;

select_t mst_aw_select, mst_w_select, mst_ar_select;

onehot_to_bin #(
.ONEHOT_WIDTH( AxiMstPortMaxUniqIds )
) i_mst_aw_select (
.onehot(from_serializer_reqs_aw_valid),
.bin (mst_aw_select)
);

// Shift the ID one down if needed, as mux prepends IDs
if (MuxIdWidth > 32'd1) begin : gen_id_shift
always_comb begin
`AXI_SET_REQ_STRUCT(mst_req_o, axi_mux_req)
mst_req_o.aw.id = mst_id_t'(axi_mux_req.aw.id >> 32'd1);
mst_req_o.ar.id = mst_id_t'(axi_mux_req.ar.id >> 32'd1);
`AXI_SET_RESP_STRUCT(axi_mux_resp, mst_resp_i)
axi_mux_resp.b.id = mux_id_t'(mst_resp_i.b.id << 32'd1);
axi_mux_resp.r.id = mux_id_t'(mst_resp_i.r.id << 32'd1);
onehot_to_bin #(
.ONEHOT_WIDTH( AxiMstPortMaxUniqIds )
) i_mst_w_select (
.onehot(from_serializer_reqs_w_valid),
.bin (mst_w_select)
);

onehot_to_bin #(
.ONEHOT_WIDTH( AxiMstPortMaxUniqIds )
) i_mst_ar_select (
.onehot(from_serializer_reqs_ar_valid),
.bin (mst_ar_select)
);

always_comb begin
mst_req_o.aw_valid = |from_serializer_reqs_aw_valid;
mst_req_o.aw = from_serializer_reqs[mst_aw_select].aw;
mst_req_o.w_valid = slv_req_i.w_valid;
mst_req_o.w = slv_req_i.w;
mst_req_o.ar_valid = |from_serializer_reqs_ar_valid;
mst_req_o.ar = from_serializer_reqs[mst_ar_select].ar;
for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin
from_serializer_reqs_aw_valid[i] = from_serializer_reqs[i].aw_valid;
from_serializer_reqs_ar_valid[i] = from_serializer_reqs[i].ar_valid;

from_serializer_resps[i].aw_ready = mst_resp_i.aw_ready;
from_serializer_resps[i].ar_ready = mst_resp_i.ar_ready;
end
end else begin : gen_no_id_shift
axi_id_prepend #(
.NoBus ( 32'd1 ),
.AxiIdWidthSlvPort ( MuxIdWidth ),
.AxiIdWidthMstPort ( AxiMstPortIdWidth ),
.slv_aw_chan_t ( mux_aw_t ),
.slv_w_chan_t ( w_t ),
.slv_b_chan_t ( mux_b_t ),
.slv_ar_chan_t ( mux_ar_t ),
.slv_r_chan_t ( mux_r_t ),
.mst_aw_chan_t ( mst_aw_t ),
.mst_w_chan_t ( w_t ),
.mst_b_chan_t ( mst_b_t ),
.mst_ar_chan_t ( mst_ar_t ),
.mst_r_chan_t ( mst_r_t )
) i_axi_id_prepend (
.pre_id_i ( '0 ),
.slv_aw_chans_i ( axi_mux_req.aw ),
.slv_aw_valids_i ( axi_mux_req.aw_valid ),
.slv_aw_readies_o ( axi_mux_resp.aw_ready ),
.slv_w_chans_i ( axi_mux_req.w ),
.slv_w_valids_i ( axi_mux_req.w_valid ),
.slv_w_readies_o ( axi_mux_resp.w_ready ),
.slv_b_chans_o ( axi_mux_resp.b ),
.slv_b_valids_o ( axi_mux_resp.b_valid ),
.slv_b_readies_i ( axi_mux_req.b_ready ),
.slv_ar_chans_i ( axi_mux_req.ar ),
.slv_ar_valids_i ( axi_mux_req.ar_valid ),
.slv_ar_readies_o ( axi_mux_resp.ar_ready ),
.slv_r_chans_o ( axi_mux_resp.r ),
.slv_r_valids_o ( axi_mux_resp.r_valid ),
.slv_r_readies_i ( axi_mux_req.r_ready ),
.mst_aw_chans_o ( mst_req_o.aw ),
.mst_aw_valids_o ( mst_req_o.aw_valid ),
.mst_aw_readies_i ( mst_resp_i.aw_ready ),
.mst_w_chans_o ( mst_req_o.w ),
.mst_w_valids_o ( mst_req_o.w_valid ),
.mst_w_readies_i ( mst_resp_i.w_ready ),
.mst_b_chans_i ( mst_resp_i.b ),
.mst_b_valids_i ( mst_resp_i.b_valid ),
.mst_b_readies_o ( mst_req_o.b_ready ),
.mst_ar_chans_o ( mst_req_o.ar ),
.mst_ar_valids_o ( mst_req_o.ar_valid ),
.mst_ar_readies_i ( mst_resp_i.ar_ready ),
.mst_r_chans_i ( mst_resp_i.r ),
.mst_r_valids_i ( mst_resp_i.r_valid ),
.mst_r_readies_o ( mst_req_o.r_ready )
);

for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin
from_serializer_reqs_b_ready[i] = from_serializer_reqs[i].b_ready;
from_serializer_reqs_r_ready[i] = from_serializer_reqs[i].r_ready;
from_serializer_resps[i].b_valid = '0;
from_serializer_resps[i].r_valid = '0;
from_serializer_resps[i].b = mst_resp_i.b;
from_serializer_resps[i].r = mst_resp_i.r;
end
from_serializer_resps[mst_resp_i.b.id].b_valid = mst_resp_i.b_valid;
mst_req_o.b_ready = from_serializer_reqs[mst_resp_i.b.id].b_ready;
from_serializer_resps[mst_resp_i.r.id].r_valid = mst_resp_i.r_valid;
mst_req_o.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready;
end

// pragma translate_off
Expand Down

0 comments on commit 7a8d0ab

Please sign in to comment.