diff --git a/Bender.yml b/Bender.yml index 8fa92168..404a0137 100644 --- a/Bender.yml +++ b/Bender.yml @@ -52,6 +52,8 @@ sources: - src/backend/idma_obi_write.sv - src/backend/idma_tilelink_read.sv - src/backend/idma_tilelink_write.sv + # Level 2 + - src/pulp_idma_wrap.sv # Generated content - target: rtl diff --git a/src/frontend/reg/tpl/idma_reg.sv.tpl b/src/frontend/reg/tpl/idma_reg.sv.tpl index 1183d9f1..40ae8fb7 100644 --- a/src/frontend/reg/tpl/idma_reg.sv.tpl +++ b/src/frontend/reg/tpl/idma_reg.sv.tpl @@ -60,6 +60,17 @@ module idma_${identifier} #( // register signals reg_rsp_t [NumRegs-1:0] dma_ctrl_rsp; + always_comb begin + stream_idx_o = '0; + for (int r = 0; r < NumRegs; r++) begin + for (int c = 0; c < NumStreams; c++) begin + if (dma_reg2hw[r].next_id[c].re) begin + stream_idx_o = c; + end + end + end + end + // generate the registers for (genvar i = 0; i < NumRegs; i++) begin : gen_core_regs @@ -87,12 +98,8 @@ module idma_${identifier} #( logic read_happens; always_comb begin : proc_launch read_happens = 1'b0; - stream_idx_o = '0; for (int c = 0; c < NumStreams; c++) begin read_happens |= dma_reg2hw[i].next_id[c].re; - if (dma_reg2hw[i].next_id[c].re) begin - stream_idx_o = c; - end end arb_valid[i] = read_happens; end @@ -114,8 +121,8 @@ module idma_${identifier} #( % endif // Protocols - arb_dma_req[i]${sep}src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); - arb_dma_req[i]${sep}dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); + arb_dma_req[i]${sep}opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); + arb_dma_req[i]${sep}opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); // Current backend only supports incremental burst arb_dma_req[i]${sep}opt.src.burst = axi_pkg::BURST_INCR; diff --git a/src/pulp_idma_wrap.sv b/src/pulp_idma_wrap.sv index a2be55f5..1e7ad6ee 100644 --- a/src/pulp_idma_wrap.sv +++ b/src/pulp_idma_wrap.sv @@ -17,6 +17,8 @@ `include "idma/typedef.svh" `include "register_interface/typedef.svh" +`define MY_MAX(a,b) (a > b ? a : b) + module pulp_idma_wrap #( parameter int unsigned NB_CORES = 4, parameter int unsigned AXI_ADDR_WIDTH = 32, @@ -38,7 +40,7 @@ module pulp_idma_wrap #( // mux read ports between tcdm-tcdm and tcdm-axi? parameter bit MUX_READ = 1'b0, // 4 ports per stream if read ports muxed, otherwise 6 - parameter int unsigned NB_TCDM_PORTS_PER_STRM = 4 + (~MUX_READ) * 2 + localparam int unsigned NB_TCDM_PORTS_PER_STRM = 4 + (!MUX_READ) * 2 ) ( // verilog_format: off // verible does not manage to align this :( input logic clk_i, input logic rst_ni, @@ -47,7 +49,7 @@ module pulp_idma_wrap #( XBAR_TCDM_BUS.Slave ctrl_slave[NB_CORES-1:0], hci_core_intf.master tcdm_master[NB_TCDM_PORTS_PER_STRM*NUM_BIDIR_STREAMS-1:0], output axi_req_t [NUM_BIDIR_STREAMS-1:0] ext_master_req_o, - input axi_resp_t [NUM_BIDIR_STREAMS-1:0] ext_master_rsp_i, + input axi_resp_t [NUM_BIDIR_STREAMS-1:0] ext_master_resp_i, output logic [NB_CORES-1:0] term_event_o, output logic [NB_CORES-1:0] term_irq_o, output logic [NB_PE_PORTS-1:0] term_event_pe_o, @@ -109,8 +111,12 @@ module pulp_idma_wrap #( typedef logic [AXI_USER_WIDTH-1:0] user_t; // // AXI4+ATOP channels typedefs - `AXI_TYPEDEF_ALL(axi, addr_t, id_t, data_t, strb_t, user_t) - + //`AXI_TYPEDEF_ALL(axi_int, addr_t, id_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(axi_aw_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(axi_w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(axi_b_chan_t, id_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(axi_ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(axi_r_chan_t, data_t, id_t, user_t) // Memory Init typedefs /// init read request typedef struct packed { @@ -360,18 +366,15 @@ module pulp_idma_wrap #( localparam int unsigned init_req_chan_width = $bits(init_req_chan_t); localparam int unsigned obi_a_chan_width = $bits(obi_a_chan_t); - function int unsigned max_width(input int unsigned a, b); - return (a > b) ? a : b; - endfunction typedef struct packed { init_req_chan_t req_chan; - logic [max_width(init_req_chan_width, obi_a_chan_width)-init_req_chan_width:0] padding; + logic [`MY_MAX(init_req_chan_width, obi_a_chan_width)-init_req_chan_width:0] padding; } init_read_req_chan_padded_t; typedef struct packed { obi_a_chan_t a_chan; - logic [max_width(init_req_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; + logic [`MY_MAX(init_req_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; } obi_read_a_chan_padded_t; typedef union packed { @@ -381,12 +384,12 @@ module pulp_idma_wrap #( typedef struct packed { axi_aw_chan_t aw_chan; - logic [max_width(axi_aw_chan_width, init_req_chan_width)-axi_aw_chan_width:0] padding; + logic [`MY_MAX(axi_aw_chan_width, init_req_chan_width)-axi_aw_chan_width:0] padding; } axi_write_aw_chan_padded_t; typedef struct packed { init_req_chan_t req_chan; - logic [max_width(axi_aw_chan_width, init_req_chan_width)-init_req_chan_width:0] padding; + logic [`MY_MAX(axi_aw_chan_width, init_req_chan_width)-init_req_chan_width:0] padding; } init_write_req_chan_padded_t; typedef union packed { @@ -417,7 +420,7 @@ module pulp_idma_wrap #( .idma_eh_req_t (idma_pkg::idma_eh_req_t), .idma_busy_t (idma_pkg::idma_busy_t), .axi_req_t (axi_req_t), - .axi_rsp_t (axi_rsp_t), + .axi_rsp_t (axi_resp_t), .init_req_t (init_req_t), .init_rsp_t (init_rsp_t), .obi_req_t (obi_req_t), @@ -475,23 +478,19 @@ module pulp_idma_wrap #( typedef struct packed { axi_ar_chan_t ar_chan; - logic [max_width( -axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) + logic [`MY_MAX( +axi_ar_chan_width, `MY_MAX(init_req_chan_width, obi_a_chan_width) )-axi_ar_chan_width:0] padding; } axi_read_ar_chan_padded_t; typedef struct packed { init_req_chan_t req_chan; - logic [max_width( -axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) -)-init_req_chan_width:0] padding; + logic [`MY_MAX(axi_ar_chan_width, `MY_MAX(init_req_chan_width, obi_a_chan_width))-init_req_chan_width:0] padding; } init_read_req_chan_padded_t; typedef struct packed { obi_a_chan_t a_chan; - logic [max_width( -axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) -)-obi_a_chan_width:0] padding; + logic [`MY_MAX(axi_ar_chan_width, `MY_MAX(init_req_chan_width, obi_a_chan_width))-obi_a_chan_width:0] padding; } obi_read_a_chan_padded_t; typedef union packed { @@ -502,12 +501,12 @@ axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) typedef struct packed { init_req_chan_t req_chan; - logic [max_width(init_req_chan_width, obi_a_chan_width)-init_req_chan_width:0] padding; + logic [`MY_MAX(init_req_chan_width, obi_a_chan_width)-init_req_chan_width:0] padding; } init_write_req_chan_padded_t; typedef struct packed { obi_a_chan_t a_chan; - logic [max_width(init_req_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; + logic [`MY_MAX(init_req_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; } obi_write_a_chan_padded_t; typedef union packed { @@ -538,7 +537,7 @@ axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) .idma_eh_req_t (idma_pkg::idma_eh_req_t), .idma_busy_t (idma_pkg::idma_busy_t), .axi_req_t (axi_req_t), - .axi_rsp_t (axi_rsp_t), + .axi_rsp_t (axi_resp_t), .init_req_t (init_req_t), .init_rsp_t (init_rsp_t), .obi_req_t (obi_req_t), @@ -580,8 +579,8 @@ axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) assign init_write_rsp.rsp_chan.init = '0; assign init_write_rsp.rsp_valid = init_read_req.req_valid; // might need spill register assign init_write_rsp.req_ready = 1'b1; - end // block: gen_cpy_in - end // block: gen_streams + end : gen_cpy_in + end : gen_streams // ------------------------------------------------------ @@ -589,8 +588,7 @@ axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) // ------------------------------------------------------ for (genvar s = 0; s < NUM_BIDIR_STREAMS; s++) begin if (MUX_READ) begin - obi_pkg::obi_cfg_t sbr_obi_cfg; - assign sbr_obi_cfg = obi_pkg::obi_default_cfg( + localparam obi_pkg::obi_cfg_t sbr_obi_cfg = obi_pkg::obi_default_cfg( AXI_ADDR_WIDTH, AXI_DATA_WIDTH, 0, obi_pkg::ObiMinimalOptionalConfig ); @@ -805,3 +803,4 @@ axi_ar_chan_width, max_width(init_req_chan_width, obi_a_chan_width) end endmodule +`undef MY_MAX diff --git a/target/rtl/idma_generated.sv b/target/rtl/idma_generated.sv index 13c47c20..4603c5bd 100644 --- a/target/rtl/idma_generated.sv +++ b/target/rtl/idma_generated.sv @@ -1305,7 +1305,7 @@ endmodule `include "common_cells/registers.svh" /// Implementing the transport layer in the iDMA backend. -module idma_transport_layer_rw_axi_rw_obi #( +module idma_transport_layer_r_obi_rw_init_w_axi #( /// Number of transaction that can be in-flight concurrently parameter int unsigned NumAxInFlight = 32'd2, /// Data width @@ -1335,6 +1335,9 @@ module idma_transport_layer_rw_axi_rw_obi #( /// AXI4+ATOP Request and Response channel type parameter type axi_req_t = logic, parameter type axi_rsp_t = logic, + /// Memory Init Request and Response channel type + parameter type init_req_t = logic, + parameter type init_rsp_t = logic, /// OBI Request and Response channel type parameter type obi_req_t = logic, parameter type obi_rsp_t = logic @@ -1346,10 +1349,10 @@ module idma_transport_layer_rw_axi_rw_obi #( /// Testmode in input logic testmode_i, - /// AXI4+ATOP read request - output axi_req_t axi_read_req_o, - /// AXI4+ATOP read response - input axi_rsp_t axi_read_rsp_i, + /// Memory Init read request + output init_req_t init_read_req_o, + /// Memory Init read response + input init_rsp_t init_read_rsp_i, /// OBI read request output obi_req_t obi_read_req_o, @@ -1361,10 +1364,10 @@ module idma_transport_layer_rw_axi_rw_obi #( /// AXI4+ATOP write response input axi_rsp_t axi_write_rsp_i, - /// OBI write request - output obi_req_t obi_write_req_o, - /// OBI write response - input obi_rsp_t obi_write_rsp_i, + /// Memory Init write request + output init_req_t init_write_req_o, + /// Memory Init write response + input init_rsp_t init_write_rsp_i, /// Read datapath request input r_dp_req_t r_dp_req_i, @@ -1434,36 +1437,36 @@ module idma_transport_layer_rw_axi_rw_obi #( typedef logic [7:0] byte_t; // inbound control signals to the read buffer: controlled by the read process - strb_t axi_buffer_in_valid, obi_buffer_in_valid, buffer_in_valid; + strb_t init_buffer_in_valid, obi_buffer_in_valid, buffer_in_valid; strb_t buffer_in_ready; // outbound control signals of the buffer: controlled by the write process strb_t buffer_out_valid, buffer_out_valid_shifted; - strb_t axi_buffer_out_ready, obi_buffer_out_ready, + strb_t axi_buffer_out_ready, init_buffer_out_ready, buffer_out_ready, buffer_out_ready_shifted; // shifted data flowing into the buffer - byte_t [StrbWidth-1:0] axi_buffer_in, obi_buffer_in, + byte_t [StrbWidth-1:0] init_buffer_in, obi_buffer_in, buffer_in, buffer_in_shifted; // aligned and coalesced data leaving the buffer byte_t [StrbWidth-1:0] buffer_out, buffer_out_shifted; // Read multiplexed signals - logic axi_r_chan_valid, obi_r_chan_valid; - logic axi_r_chan_ready, obi_r_chan_ready; - logic axi_r_dp_valid, obi_r_dp_valid; - logic axi_r_dp_ready, obi_r_dp_ready; - r_dp_rsp_t axi_r_dp_rsp, obi_r_dp_rsp; + logic init_r_chan_valid, obi_r_chan_valid; + logic init_r_chan_ready, obi_r_chan_ready; + logic init_r_dp_valid, obi_r_dp_valid; + logic init_r_dp_ready, obi_r_dp_ready; + r_dp_rsp_t init_r_dp_rsp, obi_r_dp_rsp; - logic axi_ar_ready, obi_ar_ready; + logic init_ar_ready, obi_ar_ready; // Write multiplexed signals - logic axi_w_dp_rsp_valid, obi_w_dp_rsp_valid; - logic axi_w_dp_rsp_ready, obi_w_dp_rsp_ready; - logic axi_w_dp_ready, obi_w_dp_ready; - w_dp_rsp_t axi_w_dp_rsp, obi_w_dp_rsp; + logic axi_w_dp_rsp_valid, init_w_dp_rsp_valid; + logic axi_w_dp_rsp_ready, init_w_dp_rsp_ready; + logic axi_w_dp_ready, init_w_dp_ready; + w_dp_rsp_t axi_w_dp_rsp, init_w_dp_rsp; - logic axi_aw_ready, obi_aw_ready; + logic axi_aw_ready, init_aw_ready; logic w_dp_req_valid, w_dp_req_ready; logic w_dp_rsp_mux_valid, w_dp_rsp_mux_ready; logic w_dp_rsp_valid, w_dp_rsp_ready; @@ -1478,33 +1481,31 @@ module idma_transport_layer_rw_axi_rw_obi #( // Read Ports //-------------------------------------- - idma_axi_read #( - .StrbWidth ( StrbWidth ), - .byte_t ( byte_t ), - .strb_t ( strb_t ), - .r_dp_req_t ( r_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .ar_chan_t ( read_meta_channel_t ), - .read_req_t ( axi_req_t ), - .read_rsp_t ( axi_rsp_t ) - ) i_idma_axi_read ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), + idma_init_read #( + .StrbWidth ( StrbWidth ), + .byte_t ( byte_t ), + .strb_t ( strb_t ), + .r_dp_req_t ( r_dp_req_t ), + .r_dp_rsp_t ( r_dp_rsp_t ), + .read_meta_chan_t ( read_meta_channel_t ), + .read_req_t ( init_req_t ), + .read_rsp_t ( init_rsp_t ) + ) i_idma_init_read ( .r_dp_req_i ( r_dp_req_i ), - .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_valid_i ), - .r_dp_ready_o ( axi_r_dp_ready ), - .r_dp_rsp_o ( axi_r_dp_rsp ), - .r_dp_valid_o ( axi_r_dp_valid ), - .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_ready_i ), - .ar_req_i ( ar_req_i.ar_req ), - .ar_valid_i ( (ar_req_i.src_protocol == idma_pkg::AXI) & ar_valid_i ), - .ar_ready_o ( axi_ar_ready ), - .read_req_o ( axi_read_req_o ), - .read_rsp_i ( axi_read_rsp_i ), - .r_chan_valid_o ( axi_r_chan_valid ), - .r_chan_ready_o ( axi_r_chan_ready ), - .buffer_in_o ( axi_buffer_in ), - .buffer_in_valid_o ( axi_buffer_in_valid ), + .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::INIT) & r_dp_valid_i ), + .r_dp_ready_o ( init_r_dp_ready ), + .r_dp_rsp_o ( init_r_dp_rsp ), + .r_dp_valid_o ( init_r_dp_valid ), + .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::INIT) & r_dp_ready_i ), + .read_meta_req_i ( ar_req_i.ar_req ), + .read_meta_valid_i ( (ar_req_i.src_protocol == idma_pkg::INIT) & ar_valid_i ), + .read_meta_ready_o ( init_ar_ready ), + .read_req_o ( init_read_req_o ), + .read_rsp_i ( init_read_rsp_i ), + .r_chan_valid_o ( init_r_chan_valid ), + .r_chan_ready_o ( init_r_chan_ready ), + .buffer_in_o ( init_buffer_in ), + .buffer_in_valid_o ( init_buffer_in_valid ), .buffer_in_ready_i ( buffer_in_ready ) ); @@ -1542,7 +1543,7 @@ module idma_transport_layer_rw_axi_rw_obi #( always_comb begin : gen_read_meta_channel_multiplexer case(ar_req_i.src_protocol) - idma_pkg::AXI: ar_ready_o = axi_ar_ready; + idma_pkg::INIT: ar_ready_o = init_ar_ready; idma_pkg::OBI: ar_ready_o = obi_ar_ready; default: ar_ready_o = 1'b0; endcase @@ -1550,16 +1551,16 @@ module idma_transport_layer_rw_axi_rw_obi #( always_comb begin : gen_read_multiplexer case(r_dp_req_i.src_protocol) - idma_pkg::AXI: begin - r_chan_valid_o = axi_r_chan_valid; - r_chan_ready_o = axi_r_chan_ready; + idma_pkg::INIT: begin + r_chan_valid_o = init_r_chan_valid; + r_chan_ready_o = init_r_chan_ready; - r_dp_ready_o = axi_r_dp_ready; - r_dp_rsp_o = axi_r_dp_rsp; - r_dp_valid_o = axi_r_dp_valid; + r_dp_ready_o = init_r_dp_ready; + r_dp_rsp_o = init_r_dp_rsp; + r_dp_valid_o = init_r_dp_valid; - buffer_in = axi_buffer_in; - buffer_in_valid = axi_buffer_in_valid; + buffer_in = init_buffer_in; + buffer_in_valid = init_buffer_in_valid; end idma_pkg::OBI: begin r_chan_valid_o = obi_r_chan_valid; @@ -1645,9 +1646,9 @@ module idma_transport_layer_rw_axi_rw_obi #( w_dp_req_ready = axi_w_dp_ready; buffer_out_ready = axi_buffer_out_ready; end - idma_pkg::OBI: begin - w_dp_req_ready = obi_w_dp_ready; - buffer_out_ready = obi_buffer_out_ready; + idma_pkg::INIT: begin + w_dp_req_ready = init_w_dp_ready; + buffer_out_ready = init_buffer_out_ready; end default: begin w_dp_req_ready = 1'b0; @@ -1660,7 +1661,7 @@ module idma_transport_layer_rw_axi_rw_obi #( always_comb begin : gen_write_meta_channel_multiplexer case(aw_req_i.dst_protocol) idma_pkg::AXI: aw_ready_o = axi_aw_ready; - idma_pkg::OBI: aw_ready_o = obi_aw_ready; + idma_pkg::INIT: aw_ready_o = init_aw_ready; default: aw_ready_o = 1'b0; endcase end @@ -1700,33 +1701,32 @@ module idma_transport_layer_rw_axi_rw_obi #( .buffer_out_ready_o ( axi_buffer_out_ready ) ); - idma_obi_write #( + idma_init_write #( .StrbWidth ( StrbWidth ), - .MaskInvalidData ( MaskInvalidData ), .byte_t ( byte_t ), .data_t ( data_t ), .strb_t ( strb_t ), .w_dp_req_t ( w_dp_req_t ), .w_dp_rsp_t ( w_dp_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), - .write_req_t ( obi_req_t ), - .write_rsp_t ( obi_rsp_t ) - ) i_idma_obi_write ( + .write_req_t ( init_req_t ), + .write_rsp_t ( init_rsp_t ) + ) i_idma_init_write ( .w_dp_req_i ( w_dp_req_i ), - .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::OBI) & w_dp_req_valid ), - .w_dp_ready_o ( obi_w_dp_ready ), + .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::INIT) & w_dp_req_valid ), + .w_dp_ready_o ( init_w_dp_ready ), .dp_poison_i ( dp_poison_i ), - .w_dp_rsp_o ( obi_w_dp_rsp ), - .w_dp_valid_o ( obi_w_dp_rsp_valid ), - .w_dp_ready_i ( obi_w_dp_rsp_ready ), - .aw_req_i ( aw_req_i.aw_req ), - .aw_valid_i ( (aw_req_i.dst_protocol == idma_pkg::OBI) & aw_valid_i ), - .aw_ready_o ( obi_aw_ready ), - .write_req_o ( obi_write_req_o ), - .write_rsp_i ( obi_write_rsp_i ), + .w_dp_rsp_o ( init_w_dp_rsp ), + .w_dp_valid_o ( init_w_dp_rsp_valid ), + .w_dp_ready_i ( init_w_dp_rsp_ready ), + .write_meta_req_i ( aw_req_i.aw_req ), + .write_meta_valid_i ( (aw_req_i.dst_protocol == idma_pkg::INIT) & aw_valid_i ), + .write_meta_ready_o ( init_aw_ready ), + .write_req_o ( init_write_req_o ), + .write_rsp_i ( init_write_rsp_i ), .buffer_out_i ( buffer_out_shifted ), .buffer_out_valid_i ( buffer_out_valid_shifted ), - .buffer_out_ready_o ( obi_buffer_out_ready ) + .buffer_out_ready_o ( init_buffer_out_ready ) ); //-------------------------------------- @@ -1763,7 +1763,7 @@ module idma_transport_layer_rw_axi_rw_obi #( w_dp_rsp_mux = '0; w_dp_rsp_mux_valid = 1'b0; axi_w_dp_rsp_ready = 1'b0; - obi_w_dp_rsp_ready = 1'b0; + init_w_dp_rsp_ready = 1'b0; if ( w_resp_fifo_out_valid ) begin case(w_resp_fifo_out_protocol) idma_pkg::AXI: begin @@ -1771,10 +1771,10 @@ module idma_transport_layer_rw_axi_rw_obi #( w_dp_rsp_mux = axi_w_dp_rsp; axi_w_dp_rsp_ready = w_dp_rsp_mux_ready; end - idma_pkg::OBI: begin - w_dp_rsp_mux_valid = obi_w_dp_rsp_valid; - w_dp_rsp_mux = obi_w_dp_rsp; - obi_w_dp_rsp_ready = w_dp_rsp_mux_ready; + idma_pkg::INIT: begin + w_dp_rsp_mux_valid = init_w_dp_rsp_valid; + w_dp_rsp_mux = init_w_dp_rsp; + init_w_dp_rsp_ready = w_dp_rsp_mux_ready; end default: begin w_dp_rsp_mux_valid = 1'b0; @@ -1834,7 +1834,7 @@ endmodule `include "common_cells/registers.svh" /// Implementing the transport layer in the iDMA backend. -module idma_transport_layer_r_obi_rw_init_w_axi #( +module idma_transport_layer_r_axi_rw_init_rw_obi #( /// Number of transaction that can be in-flight concurrently parameter int unsigned NumAxInFlight = 32'd2, /// Data width @@ -1878,6 +1878,11 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( /// Testmode in input logic testmode_i, + /// AXI4+ATOP read request + output axi_req_t axi_read_req_o, + /// AXI4+ATOP read response + input axi_rsp_t axi_read_rsp_i, + /// Memory Init read request output init_req_t init_read_req_o, /// Memory Init read response @@ -1888,16 +1893,16 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( /// OBI read response input obi_rsp_t obi_read_rsp_i, - /// AXI4+ATOP write request - output axi_req_t axi_write_req_o, - /// AXI4+ATOP write response - input axi_rsp_t axi_write_rsp_i, - /// Memory Init write request output init_req_t init_write_req_o, /// Memory Init write response input init_rsp_t init_write_rsp_i, + /// OBI write request + output obi_req_t obi_write_req_o, + /// OBI write response + input obi_rsp_t obi_write_rsp_i, + /// Read datapath request input r_dp_req_t r_dp_req_i, /// Read datapath request valid @@ -1966,36 +1971,36 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( typedef logic [7:0] byte_t; // inbound control signals to the read buffer: controlled by the read process - strb_t init_buffer_in_valid, obi_buffer_in_valid, buffer_in_valid; + strb_t axi_buffer_in_valid, init_buffer_in_valid, obi_buffer_in_valid, buffer_in_valid; strb_t buffer_in_ready; // outbound control signals of the buffer: controlled by the write process strb_t buffer_out_valid, buffer_out_valid_shifted; - strb_t axi_buffer_out_ready, init_buffer_out_ready, + strb_t init_buffer_out_ready, obi_buffer_out_ready, buffer_out_ready, buffer_out_ready_shifted; // shifted data flowing into the buffer - byte_t [StrbWidth-1:0] init_buffer_in, obi_buffer_in, + byte_t [StrbWidth-1:0] axi_buffer_in, init_buffer_in, obi_buffer_in, buffer_in, buffer_in_shifted; // aligned and coalesced data leaving the buffer byte_t [StrbWidth-1:0] buffer_out, buffer_out_shifted; // Read multiplexed signals - logic init_r_chan_valid, obi_r_chan_valid; - logic init_r_chan_ready, obi_r_chan_ready; - logic init_r_dp_valid, obi_r_dp_valid; - logic init_r_dp_ready, obi_r_dp_ready; - r_dp_rsp_t init_r_dp_rsp, obi_r_dp_rsp; + logic axi_r_chan_valid, init_r_chan_valid, obi_r_chan_valid; + logic axi_r_chan_ready, init_r_chan_ready, obi_r_chan_ready; + logic axi_r_dp_valid, init_r_dp_valid, obi_r_dp_valid; + logic axi_r_dp_ready, init_r_dp_ready, obi_r_dp_ready; + r_dp_rsp_t axi_r_dp_rsp, init_r_dp_rsp, obi_r_dp_rsp; - logic init_ar_ready, obi_ar_ready; + logic axi_ar_ready, init_ar_ready, obi_ar_ready; // Write multiplexed signals - logic axi_w_dp_rsp_valid, init_w_dp_rsp_valid; - logic axi_w_dp_rsp_ready, init_w_dp_rsp_ready; - logic axi_w_dp_ready, init_w_dp_ready; - w_dp_rsp_t axi_w_dp_rsp, init_w_dp_rsp; + logic init_w_dp_rsp_valid, obi_w_dp_rsp_valid; + logic init_w_dp_rsp_ready, obi_w_dp_rsp_ready; + logic init_w_dp_ready, obi_w_dp_ready; + w_dp_rsp_t init_w_dp_rsp, obi_w_dp_rsp; - logic axi_aw_ready, init_aw_ready; + logic init_aw_ready, obi_aw_ready; logic w_dp_req_valid, w_dp_req_ready; logic w_dp_rsp_mux_valid, w_dp_rsp_mux_ready; logic w_dp_rsp_valid, w_dp_rsp_ready; @@ -2010,6 +2015,36 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( // Read Ports //-------------------------------------- + idma_axi_read #( + .StrbWidth ( StrbWidth ), + .byte_t ( byte_t ), + .strb_t ( strb_t ), + .r_dp_req_t ( r_dp_req_t ), + .r_dp_rsp_t ( r_dp_rsp_t ), + .ar_chan_t ( read_meta_channel_t ), + .read_req_t ( axi_req_t ), + .read_rsp_t ( axi_rsp_t ) + ) i_idma_axi_read ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .r_dp_req_i ( r_dp_req_i ), + .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_valid_i ), + .r_dp_ready_o ( axi_r_dp_ready ), + .r_dp_rsp_o ( axi_r_dp_rsp ), + .r_dp_valid_o ( axi_r_dp_valid ), + .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_ready_i ), + .ar_req_i ( ar_req_i.ar_req ), + .ar_valid_i ( (ar_req_i.src_protocol == idma_pkg::AXI) & ar_valid_i ), + .ar_ready_o ( axi_ar_ready ), + .read_req_o ( axi_read_req_o ), + .read_rsp_i ( axi_read_rsp_i ), + .r_chan_valid_o ( axi_r_chan_valid ), + .r_chan_ready_o ( axi_r_chan_ready ), + .buffer_in_o ( axi_buffer_in ), + .buffer_in_valid_o ( axi_buffer_in_valid ), + .buffer_in_ready_i ( buffer_in_ready ) + ); + idma_init_read #( .StrbWidth ( StrbWidth ), .byte_t ( byte_t ), @@ -2072,6 +2107,7 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( always_comb begin : gen_read_meta_channel_multiplexer case(ar_req_i.src_protocol) + idma_pkg::AXI: ar_ready_o = axi_ar_ready; idma_pkg::INIT: ar_ready_o = init_ar_ready; idma_pkg::OBI: ar_ready_o = obi_ar_ready; default: ar_ready_o = 1'b0; @@ -2080,6 +2116,17 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( always_comb begin : gen_read_multiplexer case(r_dp_req_i.src_protocol) + idma_pkg::AXI: begin + r_chan_valid_o = axi_r_chan_valid; + r_chan_ready_o = axi_r_chan_ready; + + r_dp_ready_o = axi_r_dp_ready; + r_dp_rsp_o = axi_r_dp_rsp; + r_dp_valid_o = axi_r_dp_valid; + + buffer_in = axi_buffer_in; + buffer_in_valid = axi_buffer_in_valid; + end idma_pkg::INIT: begin r_chan_valid_o = init_r_chan_valid; r_chan_ready_o = init_r_chan_ready; @@ -2171,14 +2218,14 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( // Demux write request to correct write port always_comb begin : gen_write_multiplexer case(w_dp_req_i.dst_protocol) - idma_pkg::AXI: begin - w_dp_req_ready = axi_w_dp_ready; - buffer_out_ready = axi_buffer_out_ready; - end idma_pkg::INIT: begin w_dp_req_ready = init_w_dp_ready; buffer_out_ready = init_buffer_out_ready; end + idma_pkg::OBI: begin + w_dp_req_ready = obi_w_dp_ready; + buffer_out_ready = obi_buffer_out_ready; + end default: begin w_dp_req_ready = 1'b0; buffer_out_ready = '0; @@ -2189,8 +2236,8 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( // Demux write meta channel to correct write port always_comb begin : gen_write_meta_channel_multiplexer case(aw_req_i.dst_protocol) - idma_pkg::AXI: aw_ready_o = axi_aw_ready; idma_pkg::INIT: aw_ready_o = init_aw_ready; + idma_pkg::OBI: aw_ready_o = obi_aw_ready; default: aw_ready_o = 1'b0; endcase end @@ -2199,37 +2246,6 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( // Write Ports //-------------------------------------- - idma_axi_write #( - .StrbWidth ( StrbWidth ), - .MaskInvalidData ( MaskInvalidData ), - .byte_t ( byte_t ), - .data_t ( data_t ), - .strb_t ( strb_t ), - .w_dp_req_t ( w_dp_req_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .aw_chan_t ( write_meta_channel_t ), - .write_req_t ( axi_req_t ), - .write_rsp_t ( axi_rsp_t ) - ) i_idma_axi_write ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .w_dp_req_i ( w_dp_req_i ), - .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::AXI) & w_dp_req_valid ), - .w_dp_ready_o ( axi_w_dp_ready ), - .dp_poison_i ( dp_poison_i ), - .w_dp_rsp_o ( axi_w_dp_rsp ), - .w_dp_valid_o ( axi_w_dp_rsp_valid ), - .w_dp_ready_i ( axi_w_dp_rsp_ready ), - .aw_req_i ( aw_req_i.aw_req ), - .aw_valid_i ( (aw_req_i.dst_protocol == idma_pkg::AXI) & aw_valid_i ), - .aw_ready_o ( axi_aw_ready ), - .write_req_o ( axi_write_req_o ), - .write_rsp_i ( axi_write_rsp_i ), - .buffer_out_i ( buffer_out_shifted ), - .buffer_out_valid_i ( buffer_out_valid_shifted ), - .buffer_out_ready_o ( axi_buffer_out_ready ) - ); - idma_init_write #( .StrbWidth ( StrbWidth ), .byte_t ( byte_t ), @@ -2258,6 +2274,35 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( .buffer_out_ready_o ( init_buffer_out_ready ) ); + idma_obi_write #( + .StrbWidth ( StrbWidth ), + .MaskInvalidData ( MaskInvalidData ), + .byte_t ( byte_t ), + .data_t ( data_t ), + .strb_t ( strb_t ), + .w_dp_req_t ( w_dp_req_t ), + .w_dp_rsp_t ( w_dp_rsp_t ), + .write_meta_channel_t ( write_meta_channel_t ), + .write_req_t ( obi_req_t ), + .write_rsp_t ( obi_rsp_t ) + ) i_idma_obi_write ( + .w_dp_req_i ( w_dp_req_i ), + .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::OBI) & w_dp_req_valid ), + .w_dp_ready_o ( obi_w_dp_ready ), + .dp_poison_i ( dp_poison_i ), + .w_dp_rsp_o ( obi_w_dp_rsp ), + .w_dp_valid_o ( obi_w_dp_rsp_valid ), + .w_dp_ready_i ( obi_w_dp_rsp_ready ), + .aw_req_i ( aw_req_i.aw_req ), + .aw_valid_i ( (aw_req_i.dst_protocol == idma_pkg::OBI) & aw_valid_i ), + .aw_ready_o ( obi_aw_ready ), + .write_req_o ( obi_write_req_o ), + .write_rsp_i ( obi_write_rsp_i ), + .buffer_out_i ( buffer_out_shifted ), + .buffer_out_valid_i ( buffer_out_valid_shifted ), + .buffer_out_ready_o ( obi_buffer_out_ready ) + ); + //-------------------------------------- // Write Response FIFO //-------------------------------------- @@ -2291,20 +2336,20 @@ module idma_transport_layer_r_obi_rw_init_w_axi #( always_comb begin : gen_write_reponse_multiplexer w_dp_rsp_mux = '0; w_dp_rsp_mux_valid = 1'b0; - axi_w_dp_rsp_ready = 1'b0; init_w_dp_rsp_ready = 1'b0; + obi_w_dp_rsp_ready = 1'b0; if ( w_resp_fifo_out_valid ) begin case(w_resp_fifo_out_protocol) - idma_pkg::AXI: begin - w_dp_rsp_mux_valid = axi_w_dp_rsp_valid; - w_dp_rsp_mux = axi_w_dp_rsp; - axi_w_dp_rsp_ready = w_dp_rsp_mux_ready; - end idma_pkg::INIT: begin w_dp_rsp_mux_valid = init_w_dp_rsp_valid; w_dp_rsp_mux = init_w_dp_rsp; init_w_dp_rsp_ready = w_dp_rsp_mux_ready; end + idma_pkg::OBI: begin + w_dp_rsp_mux_valid = obi_w_dp_rsp_valid; + w_dp_rsp_mux = obi_w_dp_rsp; + obi_w_dp_rsp_ready = w_dp_rsp_mux_ready; + end default: begin w_dp_rsp_mux_valid = 1'b0; w_dp_rsp_mux = '0; @@ -2359,569 +2404,415 @@ endmodule // - Thomas Benz // - Tobias Senti -`include "idma/guard.svh" `include "common_cells/registers.svh" +`include "common_cells/assertions.svh" +`include "idma/guard.svh" -/// Implementing the transport layer in the iDMA backend. -module idma_transport_layer_r_axi_rw_init_rw_obi #( - /// Number of transaction that can be in-flight concurrently - parameter int unsigned NumAxInFlight = 32'd2, +/// Legalizes a generic 1D transfer according to the rules given by the +/// used protocol. +module idma_legalizer_rw_axi #( + /// Should both data shifts be done before the dataflow element? + /// If this is enabled, then the data inserted into the dataflow element + /// will no longer be word aligned, but only a single shifter is needed + parameter bit CombinedShifter = 1'b0, /// Data width - parameter int unsigned DataWidth = 32'd16, - /// The depth of the internal reorder buffer: - /// - '2': minimal possible configuration - /// - '3': efficiently handle misaligned transfers (recommended) - parameter int unsigned BufferDepth = 32'd3, - /// Mask invalid data on the manager interface - parameter bit MaskInvalidData = 1'b1, - /// Print the info of the FIFO configuration - parameter bit PrintFifoInfo = 1'b0, - /// `r_dp_req_t` type: - parameter type r_dp_req_t = logic, - /// `w_dp_req_t` type: - parameter type w_dp_req_t = logic, - /// `r_dp_rsp_t` type: - parameter type r_dp_rsp_t = logic, - /// `w_dp_rsp_t` type: - parameter type w_dp_rsp_t = logic, - /// Write Meta channel type - parameter type write_meta_channel_t = logic, - parameter type write_meta_channel_tagged_t = logic, - /// Read Meta channel type - parameter type read_meta_channel_t = logic, - parameter type read_meta_channel_tagged_t = logic, - /// AXI4+ATOP Request and Response channel type - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic, - /// Memory Init Request and Response channel type - parameter type init_req_t = logic, - parameter type init_rsp_t = logic, - /// OBI Request and Response channel type - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic + parameter int unsigned DataWidth = 32'd16, + /// Address width + parameter int unsigned AddrWidth = 32'd24, + /// 1D iDMA request type: + /// - `length`: the length of the transfer in bytes + /// - `*_addr`: the source / target byte addresses of the transfer + /// - `opt`: the options field + parameter type idma_req_t = logic, + /// Read request type + parameter type idma_r_req_t = logic, + /// Write request type + parameter type idma_w_req_t = logic, + /// Mutable transfer type + parameter type idma_mut_tf_t = logic, + /// Mutable options type + parameter type idma_mut_tf_opt_t = logic )( /// Clock input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, - /// Testmode in - input logic testmode_i, - /// AXI4+ATOP read request - output axi_req_t axi_read_req_o, - /// AXI4+ATOP read response - input axi_rsp_t axi_read_rsp_i, + /// 1D request + input idma_req_t req_i, + /// 1D request valid + input logic valid_i, + /// 1D request ready + output logic ready_o, - /// Memory Init read request - output init_req_t init_read_req_o, - /// Memory Init read response - input init_rsp_t init_read_rsp_i, + /// Read request; contains datapath and meta information + output idma_r_req_t r_req_o, + /// Read request valid + output logic r_valid_o, + /// Read request ready + input logic r_ready_i, - /// OBI read request - output obi_req_t obi_read_req_o, - /// OBI read response - input obi_rsp_t obi_read_rsp_i, + /// Write request; contains datapath and meta information + output idma_w_req_t w_req_o, + /// Write request valid + output logic w_valid_o, + /// Write request ready + input logic w_ready_i, - /// Memory Init write request - output init_req_t init_write_req_o, - /// Memory Init write response - input init_rsp_t init_write_rsp_i, + /// Invalidate the current burst transfer, stops emission of requests + input logic flush_i, + /// Kill the active 1D transfer; reload a new transfer + input logic kill_i, - /// OBI write request - output obi_req_t obi_write_req_o, - /// OBI write response - input obi_rsp_t obi_write_rsp_i, + /// Read machine of the legalizer is busy + output logic r_busy_o, + /// Write machine of the legalizer is busy + output logic w_busy_o +); + /// Stobe width + localparam int unsigned StrbWidth = DataWidth / 8; + /// Offset width + localparam int unsigned OffsetWidth = $clog2(StrbWidth); + /// The size of a page in byte + localparam int unsigned PageSize = 256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth; + /// The width of page offset byte addresses + localparam int unsigned PageAddrWidth = $clog2(PageSize); - /// Read datapath request - input r_dp_req_t r_dp_req_i, - /// Read datapath request valid - input logic r_dp_valid_i, - /// Read datapath request ready - output logic r_dp_ready_o, + /// Offset type + typedef logic [ OffsetWidth-1:0] offset_t; + /// Address type + typedef logic [ AddrWidth-1:0] addr_t; + /// Page address type + typedef logic [PageAddrWidth-1:0] page_addr_t; + /// Page length type + typedef logic [ PageAddrWidth:0] page_len_t; - /// Read datapath response - output r_dp_rsp_t r_dp_rsp_o, - /// Read datapath response valid - output logic r_dp_valid_o, - /// Read datapath response valid - input logic r_dp_ready_i, - /// Write datapath request - input w_dp_req_t w_dp_req_i, - /// Write datapath request valid - input logic w_dp_valid_i, - /// Write datapath request ready - output logic w_dp_ready_o, + // state: internally hold one transfer, this is mutated + idma_mut_tf_t r_tf_d, r_tf_q; + idma_mut_tf_t w_tf_d, w_tf_q; + idma_mut_tf_opt_t opt_tf_d, opt_tf_q; - /// Write datapath response - output w_dp_rsp_t w_dp_rsp_o, - /// Write datapath response valid - output logic w_dp_valid_o, - /// Write datapath response valid - input logic w_dp_ready_i, + // enable signals for next mutable transfer storage + logic r_tf_ena; + logic w_tf_ena; - /// Read meta request - input read_meta_channel_tagged_t ar_req_i, - /// Read meta request valid - input logic ar_valid_i, - /// Read meta request ready - output logic ar_ready_o, + // page boundaries + page_len_t r_page_num_bytes_to_pb; + page_len_t r_num_bytes_to_pb; + page_len_t w_page_num_bytes_to_pb; + page_len_t w_num_bytes_to_pb; + page_len_t c_num_bytes_to_pb; - /// Write meta request - input write_meta_channel_tagged_t aw_req_i, - /// Write meta request valid - input logic aw_valid_i, - /// Write meta request ready - output logic aw_ready_o, + // read process + page_len_t r_num_bytes_possible; + page_len_t r_num_bytes; + offset_t r_addr_offset; + logic r_done; - /// Datapath poison signal - input logic dp_poison_i, + // write process + page_len_t w_num_bytes_possible; + page_len_t w_num_bytes; + offset_t w_addr_offset; + logic w_done; - /// Response channel valid and ready - output logic r_chan_ready_o, - output logic r_chan_valid_o, - /// Read part of the datapath is busy - output logic r_dp_busy_o, - /// Write part of the datapath is busy - output logic w_dp_busy_o, - /// Buffer is busy - output logic buffer_busy_o -); - - /// Stobe width - localparam int unsigned StrbWidth = DataWidth / 8; - - /// Data type - typedef logic [DataWidth-1:0] data_t; - /// Offset type - typedef logic [StrbWidth-1:0] strb_t; - /// Byte type - typedef logic [7:0] byte_t; - - // inbound control signals to the read buffer: controlled by the read process - strb_t axi_buffer_in_valid, init_buffer_in_valid, obi_buffer_in_valid, buffer_in_valid; - - strb_t buffer_in_ready; - // outbound control signals of the buffer: controlled by the write process - strb_t buffer_out_valid, buffer_out_valid_shifted; - strb_t init_buffer_out_ready, obi_buffer_out_ready, - buffer_out_ready, buffer_out_ready_shifted; - - // shifted data flowing into the buffer - byte_t [StrbWidth-1:0] axi_buffer_in, init_buffer_in, obi_buffer_in, - buffer_in, buffer_in_shifted; - // aligned and coalesced data leaving the buffer - byte_t [StrbWidth-1:0] buffer_out, buffer_out_shifted; - - // Read multiplexed signals - logic axi_r_chan_valid, init_r_chan_valid, obi_r_chan_valid; - logic axi_r_chan_ready, init_r_chan_ready, obi_r_chan_ready; - logic axi_r_dp_valid, init_r_dp_valid, obi_r_dp_valid; - logic axi_r_dp_ready, init_r_dp_ready, obi_r_dp_ready; - r_dp_rsp_t axi_r_dp_rsp, init_r_dp_rsp, obi_r_dp_rsp; - - logic axi_ar_ready, init_ar_ready, obi_ar_ready; - - // Write multiplexed signals - logic init_w_dp_rsp_valid, obi_w_dp_rsp_valid; - logic init_w_dp_rsp_ready, obi_w_dp_rsp_ready; - logic init_w_dp_ready, obi_w_dp_ready; - w_dp_rsp_t init_w_dp_rsp, obi_w_dp_rsp; + //-------------------------------------- + // read boundary check + //-------------------------------------- + idma_legalizer_page_splitter #( + .OffsetWidth ( OffsetWidth ), + .PageAddrWidth ( PageSize ), + .addr_t ( addr_t ), + .page_len_t ( page_len_t ), + .page_addr_t ( page_addr_t ) + ) i_read_page_splitter ( + .not_bursting_i ( 1'b0 ), - logic init_aw_ready, obi_aw_ready; - logic w_dp_req_valid, w_dp_req_ready; - logic w_dp_rsp_mux_valid, w_dp_rsp_mux_ready; - logic w_dp_rsp_valid, w_dp_rsp_ready; - w_dp_rsp_t w_dp_rsp_mux; + .reduce_len_i ( opt_tf_q.src_reduce_len ), + .max_llen_i ( opt_tf_q.src_max_llen ), + + .addr_i ( r_tf_q.addr ), + .num_bytes_to_pb_o ( r_page_num_bytes_to_pb ) + ); - // Write Response FIFO signals - logic w_resp_fifo_in_valid, w_resp_fifo_in_ready; - idma_pkg::protocol_e w_resp_fifo_out_protocol; - logic w_resp_fifo_out_valid, w_resp_fifo_out_ready; + assign r_num_bytes_to_pb = r_page_num_bytes_to_pb; //-------------------------------------- - // Read Ports + // write boundary check //-------------------------------------- + idma_legalizer_page_splitter #( + .OffsetWidth ( OffsetWidth ), + .PageAddrWidth ( PageSize ), + .addr_t ( addr_t ), + .page_len_t ( page_len_t ), + .page_addr_t ( page_addr_t ) + ) i_write_page_splitter ( + .not_bursting_i ( 1'b0 ), - idma_axi_read #( - .StrbWidth ( StrbWidth ), - .byte_t ( byte_t ), - .strb_t ( strb_t ), - .r_dp_req_t ( r_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .ar_chan_t ( read_meta_channel_t ), - .read_req_t ( axi_req_t ), - .read_rsp_t ( axi_rsp_t ) - ) i_idma_axi_read ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .r_dp_req_i ( r_dp_req_i ), - .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_valid_i ), - .r_dp_ready_o ( axi_r_dp_ready ), - .r_dp_rsp_o ( axi_r_dp_rsp ), - .r_dp_valid_o ( axi_r_dp_valid ), - .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::AXI) & r_dp_ready_i ), - .ar_req_i ( ar_req_i.ar_req ), - .ar_valid_i ( (ar_req_i.src_protocol == idma_pkg::AXI) & ar_valid_i ), - .ar_ready_o ( axi_ar_ready ), - .read_req_o ( axi_read_req_o ), - .read_rsp_i ( axi_read_rsp_i ), - .r_chan_valid_o ( axi_r_chan_valid ), - .r_chan_ready_o ( axi_r_chan_ready ), - .buffer_in_o ( axi_buffer_in ), - .buffer_in_valid_o ( axi_buffer_in_valid ), - .buffer_in_ready_i ( buffer_in_ready ) + .reduce_len_i ( opt_tf_q.dst_reduce_len ), + .max_llen_i ( opt_tf_q.dst_max_llen ), + + .addr_i ( w_tf_q.addr ), + .num_bytes_to_pb_o ( w_page_num_bytes_to_pb ) ); - idma_init_read #( - .StrbWidth ( StrbWidth ), - .byte_t ( byte_t ), - .strb_t ( strb_t ), - .r_dp_req_t ( r_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .read_meta_chan_t ( read_meta_channel_t ), - .read_req_t ( init_req_t ), - .read_rsp_t ( init_rsp_t ) - ) i_idma_init_read ( - .r_dp_req_i ( r_dp_req_i ), - .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::INIT) & r_dp_valid_i ), - .r_dp_ready_o ( init_r_dp_ready ), - .r_dp_rsp_o ( init_r_dp_rsp ), - .r_dp_valid_o ( init_r_dp_valid ), - .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::INIT) & r_dp_ready_i ), - .read_meta_req_i ( ar_req_i.ar_req ), - .read_meta_valid_i ( (ar_req_i.src_protocol == idma_pkg::INIT) & ar_valid_i ), - .read_meta_ready_o ( init_ar_ready ), - .read_req_o ( init_read_req_o ), - .read_rsp_i ( init_read_rsp_i ), - .r_chan_valid_o ( init_r_chan_valid ), - .r_chan_ready_o ( init_r_chan_ready ), - .buffer_in_o ( init_buffer_in ), - .buffer_in_valid_o ( init_buffer_in_valid ), - .buffer_in_ready_i ( buffer_in_ready ) - ); + assign w_num_bytes_to_pb = w_page_num_bytes_to_pb; + + //-------------------------------------- + // page boundary check + //-------------------------------------- + // how many transfers are remaining when concerning both r/w pages? + // take the boundary that is closer + assign c_num_bytes_to_pb = (r_num_bytes_to_pb > w_num_bytes_to_pb) ? + w_num_bytes_to_pb : r_num_bytes_to_pb; - idma_obi_read #( - .StrbWidth ( StrbWidth ), - .byte_t ( byte_t ), - .strb_t ( strb_t ), - .r_dp_req_t ( r_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .read_meta_chan_t ( read_meta_channel_t ), - .read_req_t ( obi_req_t ), - .read_rsp_t ( obi_rsp_t ) - ) i_idma_obi_read ( - .r_dp_req_i ( r_dp_req_i ), - .r_dp_valid_i ( (r_dp_req_i.src_protocol == idma_pkg::OBI) & r_dp_valid_i ), - .r_dp_ready_o ( obi_r_dp_ready ), - .r_dp_rsp_o ( obi_r_dp_rsp ), - .r_dp_valid_o ( obi_r_dp_valid ), - .r_dp_ready_i ( (r_dp_req_i.src_protocol == idma_pkg::OBI) & r_dp_ready_i ), - .read_meta_req_i ( ar_req_i.ar_req ), - .read_meta_valid_i ( (ar_req_i.src_protocol == idma_pkg::OBI) & ar_valid_i ), - .read_meta_ready_o ( obi_ar_ready ), - .read_req_o ( obi_read_req_o ), - .read_rsp_i ( obi_read_rsp_i ), - .r_chan_valid_o ( obi_r_chan_valid ), - .r_chan_ready_o ( obi_r_chan_ready ), - .buffer_in_o ( obi_buffer_in ), - .buffer_in_valid_o ( obi_buffer_in_valid ), - .buffer_in_ready_i ( buffer_in_ready ) - ); //-------------------------------------- - // Read Multiplexers + // Synchronized R/W process //-------------------------------------- + always_comb begin : proc_num_bytes_possible + // Default: Coupled + r_num_bytes_possible = c_num_bytes_to_pb; + w_num_bytes_possible = c_num_bytes_to_pb; - always_comb begin : gen_read_meta_channel_multiplexer - case(ar_req_i.src_protocol) - idma_pkg::AXI: ar_ready_o = axi_ar_ready; - idma_pkg::INIT: ar_ready_o = init_ar_ready; - idma_pkg::OBI: ar_ready_o = obi_ar_ready; - default: ar_ready_o = 1'b0; - endcase + if (opt_tf_q.decouple_rw) begin + r_num_bytes_possible = r_num_bytes_to_pb; + w_num_bytes_possible = w_num_bytes_to_pb; + end end - always_comb begin : gen_read_multiplexer - case(r_dp_req_i.src_protocol) - idma_pkg::AXI: begin - r_chan_valid_o = axi_r_chan_valid; - r_chan_ready_o = axi_r_chan_ready; - - r_dp_ready_o = axi_r_dp_ready; - r_dp_rsp_o = axi_r_dp_rsp; - r_dp_valid_o = axi_r_dp_valid; + assign r_addr_offset = r_tf_q.addr[OffsetWidth-1:0]; + assign w_addr_offset = w_tf_q.addr[OffsetWidth-1:0]; - buffer_in = axi_buffer_in; - buffer_in_valid = axi_buffer_in_valid; - end - idma_pkg::INIT: begin - r_chan_valid_o = init_r_chan_valid; - r_chan_ready_o = init_r_chan_ready; + // legalization process -> read and write is coupled together + always_comb begin : proc_read_write_transaction - r_dp_ready_o = init_r_dp_ready; - r_dp_rsp_o = init_r_dp_rsp; - r_dp_valid_o = init_r_dp_valid; + // default: keep state + r_tf_d = r_tf_q; + w_tf_d = w_tf_q; + opt_tf_d = opt_tf_q; - buffer_in = init_buffer_in; - buffer_in_valid = init_buffer_in_valid; - end - idma_pkg::OBI: begin - r_chan_valid_o = obi_r_chan_valid; - r_chan_ready_o = obi_r_chan_ready; + // default: not done + r_done = 1'b0; + w_done = 1'b0; - r_dp_ready_o = obi_r_dp_ready; - r_dp_rsp_o = obi_r_dp_rsp; - r_dp_valid_o = obi_r_dp_valid; + //-------------------------------------- + // Legalize read transaction + //-------------------------------------- + // more bytes remaining than we can read + if (r_tf_q.length > r_num_bytes_possible) begin + r_num_bytes = r_num_bytes_possible; + // calculate remainder + r_tf_d.length = r_tf_q.length - r_num_bytes_possible; + // next address + r_tf_d.addr = r_tf_q.addr + r_num_bytes; - buffer_in = obi_buffer_in; - buffer_in_valid = obi_buffer_in_valid; + // remaining bytes fit in one burst + end else begin + r_num_bytes = r_tf_q.length[PageAddrWidth:0]; + // finished + r_tf_d.valid = 1'b0; + r_done = 1'b1; end - default: begin - r_chan_valid_o = 1'b0; - r_chan_ready_o = 1'b0; - r_dp_ready_o = 1'b0; - r_dp_rsp_o = '0; - r_dp_valid_o = 1'b0; + //-------------------------------------- + // Legalize write transaction + //-------------------------------------- + // more bytes remaining than we can write + if (w_tf_q.length > w_num_bytes_possible) begin + w_num_bytes = w_num_bytes_possible; + // calculate remainder + w_tf_d.length = w_tf_q.length - w_num_bytes_possible; + // next address + w_tf_d.addr = w_tf_q.addr + w_num_bytes; - buffer_in = '0; - buffer_in_valid = '0; + // remaining bytes fit in one burst + end else begin + w_num_bytes = w_tf_q.length[PageAddrWidth:0]; + // finished + w_tf_d.valid = 1'b0; + w_done = 1'b1; + end + + //-------------------------------------- + // Kill + //-------------------------------------- + if (kill_i) begin + // kill the current state + r_tf_d = '0; + w_tf_d = '0; + r_done = 1'b1; + w_done = 1'b1; + end + + //-------------------------------------- + // Refill + //-------------------------------------- + // new request is taken in if both r and w machines are ready. + if (ready_o & valid_i) begin + + // load all three mutable objects (source, destination, option) + // source or read + r_tf_d = '{ + length: req_i.length, + addr: req_i.src_addr, + valid: 1'b1, + base_addr: req_i.src_addr + }; + // destination or write + w_tf_d = '{ + length: req_i.length, + addr: req_i.dst_addr, + valid: 1'b1, + base_addr: req_i.dst_addr + }; + // options + opt_tf_d = '{ + src_protocol: req_i.opt.src_protocol, + dst_protocol: req_i.opt.dst_protocol, + read_shift: '0, + write_shift: '0, + decouple_rw: req_i.opt.beo.decouple_rw, + decouple_aw: req_i.opt.beo.decouple_aw, + src_max_llen: req_i.opt.beo.src_max_llen, + dst_max_llen: req_i.opt.beo.dst_max_llen, + src_reduce_len: req_i.opt.beo.src_reduce_len, + dst_reduce_len: req_i.opt.beo.dst_reduce_len, + axi_id: req_i.opt.axi_id, + src_axi_opt: req_i.opt.src, + dst_axi_opt: req_i.opt.dst, + super_last: req_i.opt.last + }; + // determine shift amount + if (CombinedShifter) begin + opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0] - req_i.dst_addr[OffsetWidth-1:0]; + opt_tf_d.write_shift = '0; + end else begin + opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0]; + opt_tf_d.write_shift = - req_i.dst_addr[OffsetWidth-1:0]; + end end - endcase end + //-------------------------------------- - // Read Barrel shifter + // Connect outputs //-------------------------------------- - assign buffer_in_shifted = {buffer_in, buffer_in} >> (r_dp_req_i.shift * 8); + // Read meta channel + always_comb begin + r_req_o.ar_req.axi.ar_chan = '{ + id: opt_tf_q.axi_id, + addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, + len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), + size: axi_pkg::size_t'(OffsetWidth), + burst: opt_tf_q.src_axi_opt.burst, + lock: opt_tf_q.src_axi_opt.lock, + cache: opt_tf_q.src_axi_opt.cache, + prot: opt_tf_q.src_axi_opt.prot, + qos: opt_tf_q.src_axi_opt.qos, + region: opt_tf_q.src_axi_opt.region, + user: '0 + }; + + end - //-------------------------------------- - // Buffer - //-------------------------------------- + // assign the signals needed to set-up the read data path + assign r_req_o.r_dp_req = '{ + src_protocol: opt_tf_q.src_protocol, + offset: r_addr_offset, + tailer: OffsetWidth'(r_num_bytes + r_addr_offset), + shift: opt_tf_q.read_shift, + decouple_aw: opt_tf_q.decouple_aw, + is_single: r_num_bytes <= StrbWidth + }; - idma_dataflow_element #( - .BufferDepth ( BufferDepth ), - .StrbWidth ( StrbWidth ), - .PrintFifoInfo ( PrintFifoInfo ), - .strb_t ( strb_t ), - .byte_t ( byte_t ) - ) i_dataflow_element ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .data_i ( buffer_in_shifted ), - .valid_i ( buffer_in_valid ), - .ready_o ( buffer_in_ready ), - .data_o ( buffer_out ), - .valid_o ( buffer_out_valid ), - .ready_i ( buffer_out_ready_shifted ) - ); + // Write meta channel and data path + always_comb begin + w_req_o.aw_req.axi.aw_chan = '{ + id: opt_tf_q.axi_id, + addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, + len: ((w_num_bytes + w_addr_offset - 'd1) >> OffsetWidth), + size: axi_pkg::size_t'(OffsetWidth), + burst: opt_tf_q.dst_axi_opt.burst, + lock: opt_tf_q.dst_axi_opt.lock, + cache: opt_tf_q.dst_axi_opt.cache, + prot: opt_tf_q.dst_axi_opt.prot, + qos: opt_tf_q.dst_axi_opt.qos, + region: opt_tf_q.dst_axi_opt.region, + user: '0, + atop: '0 + }; + + w_req_o.w_dp_req = '{ + dst_protocol: opt_tf_q.dst_protocol, + offset: w_addr_offset, + tailer: OffsetWidth'(w_num_bytes + w_addr_offset), + shift: opt_tf_q.write_shift, + num_beats: w_req_o.aw_req.axi.aw_chan.len, + is_single: w_req_o.aw_req.axi.aw_chan.len == '0 + }; + + end - //-------------------------------------- - // Write Barrel shifter - //-------------------------------------- + // last burst in generic 1D transfer? + assign w_req_o.last = w_done; + + // last burst indicated by midend + assign w_req_o.super_last = opt_tf_q.super_last; + + // assign aw decouple flag + assign w_req_o.decouple_aw = opt_tf_q.decouple_aw; + + // busy output + assign r_busy_o = r_tf_q.valid; + assign w_busy_o = w_tf_q.valid; - assign buffer_out_shifted = {buffer_out, buffer_out} >> (w_dp_req_i.shift*8); - assign buffer_out_valid_shifted = {buffer_out_valid, buffer_out_valid} >> w_dp_req_i.shift; - assign buffer_out_ready_shifted = {buffer_out_ready, buffer_out_ready} >> - w_dp_req_i.shift; //-------------------------------------- - // Write Request Demultiplexer + // Flow Control //-------------------------------------- + // only advance to next state if: + // * rw_coupled: both machines advance + // * rw_decoupled: either machine advances + + always_comb begin : proc_legalizer_flow_control + if ( opt_tf_q.decouple_rw) begin + r_tf_ena = (r_ready_i & !flush_i) | kill_i; + w_tf_ena = (w_ready_i & !flush_i) | kill_i; - // Split write request to write response fifo and write ports - stream_fork #( - .N_OUP ( 2 ) - ) i_write_stream_fork ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( w_dp_valid_i ), - .ready_o ( w_dp_ready_o ), - .valid_o ( { w_resp_fifo_in_valid, w_dp_req_valid } ), - .ready_i ( { w_resp_fifo_in_ready, w_dp_req_ready } ) - ); + r_valid_o = r_tf_q.valid & r_ready_i & !flush_i; + w_valid_o = w_tf_q.valid & w_ready_i & !flush_i; + end else begin + r_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; + w_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; - // Demux write request to correct write port - always_comb begin : gen_write_multiplexer - case(w_dp_req_i.dst_protocol) - idma_pkg::INIT: begin - w_dp_req_ready = init_w_dp_ready; - buffer_out_ready = init_buffer_out_ready; - end - idma_pkg::OBI: begin - w_dp_req_ready = obi_w_dp_ready; - buffer_out_ready = obi_buffer_out_ready; - end - default: begin - w_dp_req_ready = 1'b0; - buffer_out_ready = '0; + r_valid_o = r_tf_q.valid & w_ready_i & r_ready_i & !flush_i; + w_valid_o = w_tf_q.valid & r_ready_i & w_ready_i & !flush_i; end - endcase end + + // load next idma request: if both machines are done! + assign ready_o = r_done & w_done & r_ready_i & w_ready_i & !flush_i; - // Demux write meta channel to correct write port - always_comb begin : gen_write_meta_channel_multiplexer - case(aw_req_i.dst_protocol) - idma_pkg::INIT: aw_ready_o = init_aw_ready; - idma_pkg::OBI: aw_ready_o = obi_aw_ready; - default: aw_ready_o = 1'b0; - endcase - end //-------------------------------------- - // Write Ports + // State //-------------------------------------- + `FF (opt_tf_q, opt_tf_d, '0, clk_i, rst_ni) + `FFL(r_tf_q, r_tf_d, r_tf_ena, '0, clk_i, rst_ni) + `FFL(w_tf_q, w_tf_d, w_tf_ena, '0, clk_i, rst_ni) - idma_init_write #( - .StrbWidth ( StrbWidth ), - .byte_t ( byte_t ), - .data_t ( data_t ), - .strb_t ( strb_t ), - .w_dp_req_t ( w_dp_req_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .write_req_t ( init_req_t ), - .write_rsp_t ( init_rsp_t ) - ) i_idma_init_write ( - .w_dp_req_i ( w_dp_req_i ), - .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::INIT) & w_dp_req_valid ), - .w_dp_ready_o ( init_w_dp_ready ), - .dp_poison_i ( dp_poison_i ), - .w_dp_rsp_o ( init_w_dp_rsp ), - .w_dp_valid_o ( init_w_dp_rsp_valid ), - .w_dp_ready_i ( init_w_dp_rsp_ready ), - .write_meta_req_i ( aw_req_i.aw_req ), - .write_meta_valid_i ( (aw_req_i.dst_protocol == idma_pkg::INIT) & aw_valid_i ), - .write_meta_ready_o ( init_aw_ready ), - .write_req_o ( init_write_req_o ), - .write_rsp_i ( init_write_rsp_i ), - .buffer_out_i ( buffer_out_shifted ), - .buffer_out_valid_i ( buffer_out_valid_shifted ), - .buffer_out_ready_o ( init_buffer_out_ready ) - ); - - idma_obi_write #( - .StrbWidth ( StrbWidth ), - .MaskInvalidData ( MaskInvalidData ), - .byte_t ( byte_t ), - .data_t ( data_t ), - .strb_t ( strb_t ), - .w_dp_req_t ( w_dp_req_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .write_req_t ( obi_req_t ), - .write_rsp_t ( obi_rsp_t ) - ) i_idma_obi_write ( - .w_dp_req_i ( w_dp_req_i ), - .w_dp_valid_i ( (w_dp_req_i.dst_protocol == idma_pkg::OBI) & w_dp_req_valid ), - .w_dp_ready_o ( obi_w_dp_ready ), - .dp_poison_i ( dp_poison_i ), - .w_dp_rsp_o ( obi_w_dp_rsp ), - .w_dp_valid_o ( obi_w_dp_rsp_valid ), - .w_dp_ready_i ( obi_w_dp_rsp_ready ), - .aw_req_i ( aw_req_i.aw_req ), - .aw_valid_i ( (aw_req_i.dst_protocol == idma_pkg::OBI) & aw_valid_i ), - .aw_ready_o ( obi_aw_ready ), - .write_req_o ( obi_write_req_o ), - .write_rsp_i ( obi_write_rsp_i ), - .buffer_out_i ( buffer_out_shifted ), - .buffer_out_valid_i ( buffer_out_valid_shifted ), - .buffer_out_ready_o ( obi_buffer_out_ready ) - ); - - //-------------------------------------- - // Write Response FIFO - //-------------------------------------- - // Needed to be able to route the write reponses properly - // Insert when data write happens - // Remove when write response comes - - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( idma_pkg::protocol_e ), - .PrintInfo ( PrintFifoInfo ) - ) i_write_response_fifo ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_dp_req_i.dst_protocol ), - .valid_i ( w_resp_fifo_in_valid && w_resp_fifo_in_ready ), - .ready_o ( w_resp_fifo_in_ready ), - .data_o ( w_resp_fifo_out_protocol ), - .valid_o ( w_resp_fifo_out_valid ), - .ready_i ( w_resp_fifo_out_ready && w_resp_fifo_out_valid ) - ); - - //-------------------------------------- - // Write Request Demultiplexer - //-------------------------------------- - - // Mux write port responses - always_comb begin : gen_write_reponse_multiplexer - w_dp_rsp_mux = '0; - w_dp_rsp_mux_valid = 1'b0; - init_w_dp_rsp_ready = 1'b0; - obi_w_dp_rsp_ready = 1'b0; - if ( w_resp_fifo_out_valid ) begin - case(w_resp_fifo_out_protocol) - idma_pkg::INIT: begin - w_dp_rsp_mux_valid = init_w_dp_rsp_valid; - w_dp_rsp_mux = init_w_dp_rsp; - init_w_dp_rsp_ready = w_dp_rsp_mux_ready; - end - idma_pkg::OBI: begin - w_dp_rsp_mux_valid = obi_w_dp_rsp_valid; - w_dp_rsp_mux = obi_w_dp_rsp; - obi_w_dp_rsp_ready = w_dp_rsp_mux_ready; - end - default: begin - w_dp_rsp_mux_valid = 1'b0; - w_dp_rsp_mux = '0; - end - endcase - end - end - - // Fall through register for the write response to be ready - fall_through_register #( - .T ( w_dp_rsp_t ) - ) i_write_rsp_channel_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .testmode_i ( testmode_i ), - - .valid_i ( w_dp_rsp_mux_valid ), - .ready_o ( w_dp_rsp_mux_ready ), - .data_i ( w_dp_rsp_mux ), - - .valid_o ( w_dp_rsp_valid ), - .ready_i ( w_dp_rsp_ready ), - .data_o ( w_dp_rsp_o ) - ); - - // Join write response fifo and write port responses - stream_join #( - .N_INP ( 2 ) - ) i_write_stream_join ( - .inp_valid_i ( { w_resp_fifo_out_valid, w_dp_rsp_valid } ), - .inp_ready_o ( { w_resp_fifo_out_ready, w_dp_rsp_ready } ), - - .oup_valid_o ( w_dp_valid_o ), - .oup_ready_i ( w_dp_ready_i ) - ); //-------------------------------------- - // Module Control + // Assertions //-------------------------------------- - assign r_dp_busy_o = r_dp_valid_i; - assign w_dp_busy_o = w_dp_valid_i | w_dp_ready_o; - assign buffer_busy_o = |buffer_out_valid; + // only support the decomposition of incremental bursts + `ASSERT_NEVER(OnlyIncrementalBurstsSRC, (ready_o & valid_i & + req_i.opt.src.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) + `ASSERT_NEVER(OnlyIncrementalBurstsDST, (ready_o & valid_i & + req_i.opt.dst.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) endmodule @@ -2939,7 +2830,7 @@ endmodule /// Legalizes a generic 1D transfer according to the rules given by the /// used protocol. -module idma_legalizer_rw_axi #( +module idma_legalizer_r_obi_w_axi #( /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed @@ -2998,12 +2889,16 @@ module idma_legalizer_rw_axi #( /// Write machine of the legalizer is busy output logic w_busy_o ); + function int unsigned max_size(input int unsigned a, b); + return a > b ? a : b; + endfunction + /// Stobe width localparam int unsigned StrbWidth = DataWidth / 8; /// Offset width localparam int unsigned OffsetWidth = $clog2(StrbWidth); /// The size of a page in byte - localparam int unsigned PageSize = 256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth; + localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, StrbWidth); /// The width of page offset byte addresses localparam int unsigned PageAddrWidth = $clog2(PageSize); @@ -3056,7 +2951,7 @@ module idma_legalizer_rw_axi #( .page_len_t ( page_len_t ), .page_addr_t ( page_addr_t ) ) i_read_page_splitter ( - .not_bursting_i ( 1'b0 ), + .not_bursting_i ( 1'b1 ), .reduce_len_i ( opt_tf_q.src_reduce_len ), .max_llen_i ( opt_tf_q.src_max_llen ), @@ -3077,7 +2972,7 @@ module idma_legalizer_rw_axi #( .page_len_t ( page_len_t ), .page_addr_t ( page_addr_t ) ) i_write_page_splitter ( - .not_bursting_i ( 1'b0 ), + .not_bursting_i ( opt_tf_q.dst_protocol inside { idma_pkg::OBI} ), .reduce_len_i ( opt_tf_q.dst_reduce_len ), .max_llen_i ( opt_tf_q.dst_max_llen ), @@ -3105,7 +3000,8 @@ module idma_legalizer_rw_axi #( r_num_bytes_possible = c_num_bytes_to_pb; w_num_bytes_possible = c_num_bytes_to_pb; - if (opt_tf_q.decouple_rw) begin + if (opt_tf_q.decouple_rw + || (opt_tf_q.src_protocol inside { idma_pkg::OBI })) begin r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end @@ -3231,18 +3127,13 @@ module idma_legalizer_rw_axi #( // Read meta channel always_comb begin - r_req_o.ar_req.axi.ar_chan = '{ - id: opt_tf_q.axi_id, + r_req_o.ar_req.obi.a_chan = '{ addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.src_axi_opt.burst, - lock: opt_tf_q.src_axi_opt.lock, - cache: opt_tf_q.src_axi_opt.cache, - prot: opt_tf_q.src_axi_opt.prot, - qos: opt_tf_q.src_axi_opt.qos, - region: opt_tf_q.src_axi_opt.region, - user: '0 + be: '1, + we: 1'b0, + wdata: '0, + aid: opt_tf_q.axi_id, + a_optional: '0 }; end @@ -3307,7 +3198,8 @@ module idma_legalizer_rw_axi #( // * rw_decoupled: either machine advances always_comb begin : proc_legalizer_flow_control - if ( opt_tf_q.decouple_rw) begin + if ( opt_tf_q.decouple_rw + || (opt_tf_q.src_protocol inside { idma_pkg::OBI })) begin r_tf_ena = (r_ready_i & !flush_i) | kill_i; w_tf_ena = (w_ready_i & !flush_i) | kill_i; @@ -3359,7 +3251,7 @@ endmodule /// Legalizes a generic 1D transfer according to the rules given by the /// used protocol. -module idma_legalizer_r_obi_w_axi #( +module idma_legalizer_r_axi_w_obi #( /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed @@ -3480,7 +3372,7 @@ module idma_legalizer_r_obi_w_axi #( .page_len_t ( page_len_t ), .page_addr_t ( page_addr_t ) ) i_read_page_splitter ( - .not_bursting_i ( 1'b1 ), + .not_bursting_i ( opt_tf_q.src_protocol inside { idma_pkg::OBI} ), .reduce_len_i ( opt_tf_q.src_reduce_len ), .max_llen_i ( opt_tf_q.src_max_llen ), @@ -3501,7 +3393,7 @@ module idma_legalizer_r_obi_w_axi #( .page_len_t ( page_len_t ), .page_addr_t ( page_addr_t ) ) i_write_page_splitter ( - .not_bursting_i ( opt_tf_q.dst_protocol inside { idma_pkg::OBI} ), + .not_bursting_i ( 1'b1 ), .reduce_len_i ( opt_tf_q.dst_reduce_len ), .max_llen_i ( opt_tf_q.dst_max_llen ), @@ -3530,7 +3422,7 @@ module idma_legalizer_r_obi_w_axi #( w_num_bytes_possible = c_num_bytes_to_pb; if (opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end @@ -3656,13 +3548,18 @@ module idma_legalizer_r_obi_w_axi #( // Read meta channel always_comb begin - r_req_o.ar_req.obi.a_chan = '{ + r_req_o.ar_req.axi.ar_chan = '{ + id: opt_tf_q.axi_id, addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - be: '1, - we: 1'b0, - wdata: '0, - aid: opt_tf_q.axi_id, - a_optional: '0 + len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), + size: axi_pkg::size_t'(OffsetWidth), + burst: opt_tf_q.src_axi_opt.burst, + lock: opt_tf_q.src_axi_opt.lock, + cache: opt_tf_q.src_axi_opt.cache, + prot: opt_tf_q.src_axi_opt.prot, + qos: opt_tf_q.src_axi_opt.qos, + region: opt_tf_q.src_axi_opt.region, + user: '0 }; end @@ -3679,30 +3576,23 @@ module idma_legalizer_r_obi_w_axi #( // Write meta channel and data path always_comb begin - w_req_o.aw_req.axi.aw_chan = '{ - id: opt_tf_q.axi_id, + w_req_o.aw_req.obi.a_chan = '{ addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((w_num_bytes + w_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.dst_axi_opt.burst, - lock: opt_tf_q.dst_axi_opt.lock, - cache: opt_tf_q.dst_axi_opt.cache, - prot: opt_tf_q.dst_axi_opt.prot, - qos: opt_tf_q.dst_axi_opt.qos, - region: opt_tf_q.dst_axi_opt.region, - user: '0, - atop: '0 + be: '0, + we: 1, + wdata: '0, + aid: opt_tf_q.axi_id, + a_optional: '0 }; w_req_o.w_dp_req = '{ dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: w_req_o.aw_req.axi.aw_chan.len, - is_single: w_req_o.aw_req.axi.aw_chan.len == '0 + offset: w_addr_offset, + tailer: OffsetWidth'(w_num_bytes + w_addr_offset), + shift: opt_tf_q.write_shift, + num_beats: 'd0, + is_single: 1'b1 }; - end // last burst in generic 1D transfer? @@ -3728,7 +3618,7 @@ module idma_legalizer_r_obi_w_axi #( always_comb begin : proc_legalizer_flow_control if ( opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin r_tf_ena = (r_ready_i & !flush_i) | kill_i; w_tf_ena = (w_ready_i & !flush_i) | kill_i; @@ -3780,7 +3670,7 @@ endmodule /// Legalizes a generic 1D transfer according to the rules given by the /// used protocol. -module idma_legalizer_r_axi_w_obi #( +module idma_legalizer_rw_axi_rw_axis #( /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed @@ -3901,7 +3791,7 @@ module idma_legalizer_r_axi_w_obi #( .page_len_t ( page_len_t ), .page_addr_t ( page_addr_t ) ) i_read_page_splitter ( - .not_bursting_i ( opt_tf_q.src_protocol inside { idma_pkg::OBI} ), + .not_bursting_i ( 1'b1 ), .reduce_len_i ( opt_tf_q.src_reduce_len ), .max_llen_i ( opt_tf_q.src_max_llen ), @@ -3910,7 +3800,13 @@ module idma_legalizer_r_axi_w_obi #( .num_bytes_to_pb_o ( r_page_num_bytes_to_pb ) ); - assign r_num_bytes_to_pb = r_page_num_bytes_to_pb; + always_comb begin : gen_read_num_bytes_to_pb_logic + case (opt_tf_q.src_protocol) + idma_pkg::AXI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; + idma_pkg::AXI_STREAM: r_num_bytes_to_pb = r_page_num_bytes_to_pb; + default: r_num_bytes_to_pb = '0; + endcase + end //-------------------------------------- // write boundary check @@ -3931,7 +3827,13 @@ module idma_legalizer_r_axi_w_obi #( .num_bytes_to_pb_o ( w_page_num_bytes_to_pb ) ); - assign w_num_bytes_to_pb = w_page_num_bytes_to_pb; + always_comb begin : gen_write_num_bytes_to_pb_logic + case (opt_tf_q.dst_protocol) + idma_pkg::AXI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; + idma_pkg::AXI_STREAM: w_num_bytes_to_pb = w_page_num_bytes_to_pb; + default: w_num_bytes_to_pb = '0; + endcase + end //-------------------------------------- // page boundary check @@ -3951,7 +3853,8 @@ module idma_legalizer_r_axi_w_obi #( w_num_bytes_possible = c_num_bytes_to_pb; if (opt_tf_q.decouple_rw - || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::AXI_STREAM }) + || (opt_tf_q.dst_protocol inside { idma_pkg::AXI_STREAM })) begin r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end @@ -4076,21 +3979,32 @@ module idma_legalizer_r_axi_w_obi #( //-------------------------------------- // Read meta channel - always_comb begin - r_req_o.ar_req.axi.ar_chan = '{ - id: opt_tf_q.axi_id, - addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.src_axi_opt.burst, - lock: opt_tf_q.src_axi_opt.lock, - cache: opt_tf_q.src_axi_opt.cache, - prot: opt_tf_q.src_axi_opt.prot, - qos: opt_tf_q.src_axi_opt.qos, - region: opt_tf_q.src_axi_opt.region, - user: '0 - }; - + always_comb begin : gen_read_meta_channel + r_req_o.ar_req = '0; + case(opt_tf_q.src_protocol) + idma_pkg::AXI: begin + r_req_o.ar_req.axi.ar_chan = '{ + id: opt_tf_q.axi_id, + addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, + len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), + size: axi_pkg::size_t'(OffsetWidth), + burst: opt_tf_q.src_axi_opt.burst, + lock: opt_tf_q.src_axi_opt.lock, + cache: opt_tf_q.src_axi_opt.cache, + prot: opt_tf_q.src_axi_opt.prot, + qos: opt_tf_q.src_axi_opt.qos, + region: opt_tf_q.src_axi_opt.region, + user: '0 + }; + + end + idma_pkg::AXI_STREAM: begin + r_req_o.ar_req = '0; + + end + default: + r_req_o.ar_req = '0; + endcase end // assign the signals needed to set-up the read data path @@ -4104,26 +4018,69 @@ module idma_legalizer_r_axi_w_obi #( }; // Write meta channel and data path - always_comb begin - w_req_o.aw_req.obi.a_chan = '{ - addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - be: '0, - we: 1, - wdata: '0, - aid: opt_tf_q.axi_id, - a_optional: '0 - }; - - w_req_o.w_dp_req = '{ - dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: 'd0, - is_single: 1'b1 - }; + always_comb begin : gen_write_meta_channel + w_req_o.aw_req = '0; + case(opt_tf_q.dst_protocol) + idma_pkg::AXI: begin + w_req_o.aw_req.axi.aw_chan = '{ + id: opt_tf_q.axi_id, + addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, + len: ((w_num_bytes + w_addr_offset - 'd1) >> OffsetWidth), + size: axi_pkg::size_t'(OffsetWidth), + burst: opt_tf_q.dst_axi_opt.burst, + lock: opt_tf_q.dst_axi_opt.lock, + cache: opt_tf_q.dst_axi_opt.cache, + prot: opt_tf_q.dst_axi_opt.prot, + qos: opt_tf_q.dst_axi_opt.qos, + region: opt_tf_q.dst_axi_opt.region, + user: '0, + atop: '0 + }; + + end + idma_pkg::AXI_STREAM: begin + w_req_o.aw_req.axis.t_chan = '{ + data: '0, + strb: '1, + keep: '0, + last: w_tf_q.length == w_num_bytes, + id: opt_tf_q.axi_id, + dest: w_tf_q.base_addr[$bits(w_req_o.aw_req.axis.t_chan.dest)-1:0], + user: w_tf_q.base_addr[$bits(w_req_o.aw_req.axis.t_chan.user)-1+:$bits(w_req_o.aw_req.axis.t_chan.dest)] + }; + + end + default: + w_req_o.aw_req = '0; + endcase + end + + // assign the signals needed to set-up the write data path + always_comb begin : gen_write_data_path + case (opt_tf_q.dst_protocol) + idma_pkg::AXI: + w_req_o.w_dp_req = '{ + dst_protocol: opt_tf_q.dst_protocol, + offset: w_addr_offset, + tailer: OffsetWidth'(w_num_bytes + w_addr_offset), + shift: opt_tf_q.write_shift, + num_beats: w_req_o.aw_req.axi.aw_chan.len, + is_single: w_req_o.aw_req.axi.aw_chan.len == '0 + }; + + default: + w_req_o.w_dp_req = '{ + dst_protocol: opt_tf_q.dst_protocol, + offset: w_addr_offset, + tailer: OffsetWidth'(w_num_bytes + w_addr_offset), + shift: opt_tf_q.write_shift, + num_beats: 'd0, + is_single: 1'b1 + }; + endcase end + // last burst in generic 1D transfer? assign w_req_o.last = w_done; @@ -4147,7 +4104,8 @@ module idma_legalizer_r_axi_w_obi #( always_comb begin : proc_legalizer_flow_control if ( opt_tf_q.decouple_rw - || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::AXI_STREAM }) + || (opt_tf_q.dst_protocol inside { idma_pkg::AXI_STREAM })) begin r_tf_ena = (r_ready_i & !flush_i) | kill_i; w_tf_ena = (w_ready_i & !flush_i) | kill_i; @@ -4199,7 +4157,7 @@ endmodule /// Legalizes a generic 1D transfer according to the rules given by the /// used protocol. -module idma_legalizer_rw_axi_rw_axis #( +module idma_legalizer_r_obi_rw_init_w_axi #( /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed @@ -4267,7 +4225,7 @@ module idma_legalizer_rw_axi_rw_axis #( /// Offset width localparam int unsigned OffsetWidth = $clog2(StrbWidth); /// The size of a page in byte - localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, StrbWidth); + localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, max_size(StrbWidth, StrbWidth)); /// The width of page offset byte addresses localparam int unsigned PageAddrWidth = $clog2(PageSize); @@ -4331,8 +4289,8 @@ module idma_legalizer_rw_axi_rw_axis #( always_comb begin : gen_read_num_bytes_to_pb_logic case (opt_tf_q.src_protocol) - idma_pkg::AXI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - idma_pkg::AXI_STREAM: r_num_bytes_to_pb = r_page_num_bytes_to_pb; + idma_pkg::INIT: r_num_bytes_to_pb = r_page_num_bytes_to_pb; + idma_pkg::OBI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; default: r_num_bytes_to_pb = '0; endcase end @@ -4359,7 +4317,7 @@ module idma_legalizer_rw_axi_rw_axis #( always_comb begin : gen_write_num_bytes_to_pb_logic case (opt_tf_q.dst_protocol) idma_pkg::AXI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; - idma_pkg::AXI_STREAM: w_num_bytes_to_pb = w_page_num_bytes_to_pb; + idma_pkg::INIT: w_num_bytes_to_pb = w_page_num_bytes_to_pb; default: w_num_bytes_to_pb = '0; endcase end @@ -4382,8 +4340,8 @@ module idma_legalizer_rw_axi_rw_axis #( w_num_bytes_possible = c_num_bytes_to_pb; if (opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::AXI_STREAM }) - || (opt_tf_q.dst_protocol inside { idma_pkg::AXI_STREAM })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) + || (opt_tf_q.dst_protocol inside { idma_pkg::INIT })) begin r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end @@ -4511,24 +4469,24 @@ module idma_legalizer_rw_axi_rw_axis #( always_comb begin : gen_read_meta_channel r_req_o.ar_req = '0; case(opt_tf_q.src_protocol) - idma_pkg::AXI: begin - r_req_o.ar_req.axi.ar_chan = '{ - id: opt_tf_q.axi_id, - addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.src_axi_opt.burst, - lock: opt_tf_q.src_axi_opt.lock, - cache: opt_tf_q.src_axi_opt.cache, - prot: opt_tf_q.src_axi_opt.prot, - qos: opt_tf_q.src_axi_opt.qos, - region: opt_tf_q.src_axi_opt.region, - user: '0 + idma_pkg::INIT: begin + r_req_o.ar_req.init.req_chan = '{ + cfg: r_tf_q.base_addr, + term: '0, + strb: '0, + id: opt_tf_d.axi_id }; end - idma_pkg::AXI_STREAM: begin - r_req_o.ar_req = '0; + idma_pkg::OBI: begin + r_req_o.ar_req.obi.a_chan = '{ + addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, + be: '1, + we: 1'b0, + wdata: '0, + aid: opt_tf_q.axi_id, + a_optional: '0 + }; end default: @@ -4567,15 +4525,12 @@ module idma_legalizer_rw_axi_rw_axis #( }; end - idma_pkg::AXI_STREAM: begin - w_req_o.aw_req.axis.t_chan = '{ - data: '0, - strb: '1, - keep: '0, - last: w_tf_q.length == w_num_bytes, - id: opt_tf_q.axi_id, - dest: w_tf_q.base_addr[$bits(w_req_o.aw_req.axis.t_chan.dest)-1:0], - user: w_tf_q.base_addr[$bits(w_req_o.aw_req.axis.t_chan.user)-1+:$bits(w_req_o.aw_req.axis.t_chan.dest)] + idma_pkg::INIT: begin + w_req_o.aw_req.init.req_chan = '{ + cfg: w_tf_q.base_addr, + term: '0, + strb: '0, + id: opt_tf_d.axi_id }; end @@ -4633,8 +4588,8 @@ module idma_legalizer_rw_axi_rw_axis #( always_comb begin : proc_legalizer_flow_control if ( opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::AXI_STREAM }) - || (opt_tf_q.dst_protocol inside { idma_pkg::AXI_STREAM })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) + || (opt_tf_q.dst_protocol inside { idma_pkg::INIT })) begin r_tf_ena = (r_ready_i & !flush_i) | kill_i; w_tf_ena = (w_ready_i & !flush_i) | kill_i; @@ -4686,7 +4641,7 @@ endmodule /// Legalizes a generic 1D transfer according to the rules given by the /// used protocol. -module idma_legalizer_rw_axi_rw_obi #( +module idma_legalizer_r_axi_rw_init_rw_obi #( /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed @@ -4754,7 +4709,7 @@ module idma_legalizer_rw_axi_rw_obi #( /// Offset width localparam int unsigned OffsetWidth = $clog2(StrbWidth); /// The size of a page in byte - localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, StrbWidth); + localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, max_size(StrbWidth, StrbWidth)); /// The width of page offset byte addresses localparam int unsigned PageAddrWidth = $clog2(PageSize); @@ -4819,6 +4774,7 @@ module idma_legalizer_rw_axi_rw_obi #( always_comb begin : gen_read_num_bytes_to_pb_logic case (opt_tf_q.src_protocol) idma_pkg::AXI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; + idma_pkg::INIT: r_num_bytes_to_pb = r_page_num_bytes_to_pb; idma_pkg::OBI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; default: r_num_bytes_to_pb = '0; endcase @@ -4845,7 +4801,7 @@ module idma_legalizer_rw_axi_rw_obi #( always_comb begin : gen_write_num_bytes_to_pb_logic case (opt_tf_q.dst_protocol) - idma_pkg::AXI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; + idma_pkg::INIT: w_num_bytes_to_pb = w_page_num_bytes_to_pb; idma_pkg::OBI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; default: w_num_bytes_to_pb = '0; endcase @@ -4869,8 +4825,8 @@ module idma_legalizer_rw_axi_rw_obi #( w_num_bytes_possible = c_num_bytes_to_pb; if (opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) + || (opt_tf_q.dst_protocol inside { idma_pkg::INIT, idma_pkg::OBI })) begin r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end @@ -5013,6 +4969,15 @@ module idma_legalizer_rw_axi_rw_obi #( user: '0 }; + end + idma_pkg::INIT: begin + r_req_o.ar_req.init.req_chan = '{ + cfg: r_tf_q.base_addr, + term: '0, + strb: '0, + id: opt_tf_d.axi_id + }; + end idma_pkg::OBI: begin r_req_o.ar_req.obi.a_chan = '{ @@ -5044,20 +5009,12 @@ module idma_legalizer_rw_axi_rw_obi #( always_comb begin : gen_write_meta_channel w_req_o.aw_req = '0; case(opt_tf_q.dst_protocol) - idma_pkg::AXI: begin - w_req_o.aw_req.axi.aw_chan = '{ - id: opt_tf_q.axi_id, - addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((w_num_bytes + w_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.dst_axi_opt.burst, - lock: opt_tf_q.dst_axi_opt.lock, - cache: opt_tf_q.dst_axi_opt.cache, - prot: opt_tf_q.dst_axi_opt.prot, - qos: opt_tf_q.dst_axi_opt.qos, - region: opt_tf_q.dst_axi_opt.region, - user: '0, - atop: '0 + idma_pkg::INIT: begin + w_req_o.aw_req.init.req_chan = '{ + cfg: w_tf_q.base_addr, + term: '0, + strb: '0, + id: opt_tf_d.axi_id }; end @@ -5080,16 +5037,6 @@ module idma_legalizer_rw_axi_rw_obi #( // assign the signals needed to set-up the write data path always_comb begin : gen_write_data_path case (opt_tf_q.dst_protocol) - idma_pkg::AXI: - w_req_o.w_dp_req = '{ - dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: w_req_o.aw_req.axi.aw_chan.len, - is_single: w_req_o.aw_req.axi.aw_chan.len == '0 - }; - default: w_req_o.w_dp_req = '{ dst_protocol: opt_tf_q.dst_protocol, @@ -5126,8 +5073,8 @@ module idma_legalizer_rw_axi_rw_obi #( always_comb begin : proc_legalizer_flow_control if ( opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::OBI })) begin + || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) + || (opt_tf_q.dst_protocol inside { idma_pkg::INIT, idma_pkg::OBI })) begin r_tf_ena = (r_ready_i & !flush_i) | kill_i; w_tf_ena = (w_ready_i & !flush_i) | kill_i; @@ -5173,479 +5120,698 @@ endmodule // - Thomas Benz // - Tobias Senti -`include "common_cells/registers.svh" -`include "common_cells/assertions.svh" +`include "axi/typedef.svh" `include "idma/guard.svh" -/// Legalizes a generic 1D transfer according to the rules given by the -/// used protocol. -module idma_legalizer_r_obi_rw_init_w_axi #( +/// The iDMA backend implements an arbitrary 1D copy engine +module idma_backend_rw_axi #( + /// Data width + parameter int unsigned DataWidth = 32'd16, + /// Address width + parameter int unsigned AddrWidth = 32'd24, + /// AXI user width + parameter int unsigned UserWidth = 32'd1, + /// AXI ID width + parameter int unsigned AxiIdWidth = 32'd1, + /// Number of transaction that can be in-flight concurrently + parameter int unsigned NumAxInFlight = 32'd2, + /// The depth of the internal reorder buffer: + /// - '2': minimal possible configuration + /// - '3': efficiently handle misaligned transfers (recommended) + parameter int unsigned BufferDepth = 32'd2, + /// With of a transfer: max transfer size is `2**TFLenWidth` bytes + parameter int unsigned TFLenWidth = 32'd24, + /// The depth of the memory system the backend is attached to + parameter int unsigned MemSysDepth = 32'd0, /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Data width - parameter int unsigned DataWidth = 32'd16, - /// Address width - parameter int unsigned AddrWidth = 32'd24, - /// 1D iDMA request type: - /// - `length`: the length of the transfer in bytes - /// - `*_addr`: the source / target byte addresses of the transfer - /// - `opt`: the options field - parameter type idma_req_t = logic, - /// Read request type - parameter type idma_r_req_t = logic, - /// Write request type - parameter type idma_w_req_t = logic, - /// Mutable transfer type - parameter type idma_mut_tf_t = logic, - /// Mutable options type - parameter type idma_mut_tf_opt_t = logic + parameter bit CombinedShifter = 1'b0, + /// Should the `R`-`AW` coupling hardware be present? (recommended) + parameter bit RAWCouplingAvail = 1'b1, + /// Mask invalid data on the manager interface + parameter bit MaskInvalidData = 1'b1, + /// Should hardware legalization be present? (recommended) + /// If not, software legalization is required to ensure the transfers are + /// AXI4-conformal + parameter bit HardwareLegalizer = 1'b1, + /// Reject zero-length transfers + parameter bit RejectZeroTransfers = 1'b1, + /// Should the error handler be present? + parameter idma_pkg::error_cap_e ErrorCap = idma_pkg::NO_ERROR_HANDLING, + /// Print the info of the FIFO configuration + parameter bit PrintFifoInfo = 1'b0, + /// 1D iDMA request type + parameter type idma_req_t = logic, + /// iDMA response type + parameter type idma_rsp_t = logic, + /// Error Handler request type + parameter type idma_eh_req_t = logic, + /// iDMA busy signal + parameter type idma_busy_t = logic, + /// AXI4+ATOP Request and Response channel type + parameter type axi_req_t = logic, + parameter type axi_rsp_t = logic, + /// Address Read Channel type + parameter type read_meta_channel_t = logic, + /// Address Write Channel type + parameter type write_meta_channel_t = logic, + /// Strobe Width (do not override!) + parameter int unsigned StrbWidth = DataWidth / 8, + /// Offset Width (do not override!) + parameter int unsigned OffsetWidth = $clog2(StrbWidth) )( /// Clock input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, + /// Testmode in + input logic testmode_i, - /// 1D request - input idma_req_t req_i, - /// 1D request valid - input logic valid_i, - /// 1D request ready - output logic ready_o, + /// 1D iDMA request + input idma_req_t idma_req_i, + /// 1D iDMA request valid + input logic req_valid_i, + /// 1D iDMA request ready + output logic req_ready_o, - /// Read request; contains datapath and meta information - output idma_r_req_t r_req_o, - /// Read request valid - output logic r_valid_o, - /// Read request ready - input logic r_ready_i, + /// iDMA response + output idma_rsp_t idma_rsp_o, + /// iDMA response valid + output logic rsp_valid_o, + /// iDMA response ready + input logic rsp_ready_i, - /// Write request; contains datapath and meta information - output idma_w_req_t w_req_o, - /// Write request valid - output logic w_valid_o, - /// Write request ready - input logic w_ready_i, + /// Error handler request + input idma_eh_req_t idma_eh_req_i, + /// Error handler request valid + input logic eh_req_valid_i, + /// Error handler request ready + output logic eh_req_ready_o, - /// Invalidate the current burst transfer, stops emission of requests - input logic flush_i, - /// Kill the active 1D transfer; reload a new transfer - input logic kill_i, + /// AXI4+ATOP read request + output axi_req_t axi_read_req_o, + /// AXI4+ATOP read response + input axi_rsp_t axi_read_rsp_i, - /// Read machine of the legalizer is busy - output logic r_busy_o, - /// Write machine of the legalizer is busy - output logic w_busy_o + /// AXI4+ATOP write request + output axi_req_t axi_write_req_o, + /// AXI4+ATOP write response + input axi_rsp_t axi_write_rsp_i, + + /// iDMA busy flags + output idma_busy_t busy_o ); - function int unsigned max_size(input int unsigned a, b); - return a > b ? a : b; - endfunction - /// Stobe width - localparam int unsigned StrbWidth = DataWidth / 8; - /// Offset width - localparam int unsigned OffsetWidth = $clog2(StrbWidth); - /// The size of a page in byte - localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, max_size(StrbWidth, StrbWidth)); - /// The width of page offset byte addresses - localparam int unsigned PageAddrWidth = $clog2(PageSize); + /// The localparam MetaFifoDepth holds the maximum number of transfers that can be + /// in-flight under any circumstances. + localparam int unsigned MetaFifoDepth = BufferDepth + NumAxInFlight + MemSysDepth; - /// Offset type - typedef logic [ OffsetWidth-1:0] offset_t; /// Address type - typedef logic [ AddrWidth-1:0] addr_t; - /// Page address type - typedef logic [PageAddrWidth-1:0] page_addr_t; - /// Page length type - typedef logic [ PageAddrWidth:0] page_len_t; - + typedef logic [AddrWidth-1:0] addr_t; + /// DAta type + typedef logic [DataWidth-1:0] data_t; + /// Strobe type + typedef logic [StrbWidth-1:0] strb_t; + /// User type + typedef logic [UserWidth-1:0] user_t; + /// ID type + typedef logic [AxiIdWidth-1:0] id_t; + /// Offset type + typedef logic [OffsetWidth-1:0] offset_t; + /// Transfer length type + typedef logic [TFLenWidth-1:0] tf_len_t; - // state: internally hold one transfer, this is mutated - idma_mut_tf_t r_tf_d, r_tf_q; - idma_mut_tf_t w_tf_d, w_tf_q; - idma_mut_tf_opt_t opt_tf_d, opt_tf_q; + /// The datapath read request type holds all the information required to configure the read + /// part of the datapath. The type consists of: + /// - `offset`: The bus offset of the read + /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the + /// bus width. + /// - `shift`: The amount the data needs to be shifted + /// - `decouple_aw`: If the transfer has the AW decoupled from the R + /// - `is_single`: Is this transfer just one beat long? `(len == 0)` + typedef struct packed { + idma_pkg::protocol_e src_protocol; + offset_t offset; + offset_t tailer; + offset_t shift; + logic decouple_aw; + logic is_single; + } r_dp_req_t; - // enable signals for next mutable transfer storage - logic r_tf_ena; - logic w_tf_ena; + /// The datapath read response type provides feedback from the read part of the datapath: + /// - `resp`: The response from the R channel of the AXI4 manager interface + /// - `last`: The last flag from the R channel of the AXI4 manager interface + /// - `first`: Is the current item first beat in the burst + typedef struct packed { + axi_pkg::resp_t resp; + logic last; + logic first; + } r_dp_rsp_t; - // page boundaries - page_len_t r_page_num_bytes_to_pb; - page_len_t r_num_bytes_to_pb; - page_len_t w_page_num_bytes_to_pb; - page_len_t w_num_bytes_to_pb; - page_len_t c_num_bytes_to_pb; + /// The datapath write request type holds all the information required to configure the write + /// part of the datapath. The type consists of: + /// - `offset`: The bus offset of the write + /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the + /// bus width. + /// - `shift`: The amount the data needs to be shifted + /// - `num_beats`: The number of beats this burst consist of + /// - `is_single`: Is this transfer just one beat long? `(len == 0)` + typedef struct packed { + idma_pkg::protocol_e dst_protocol; + offset_t offset; + offset_t tailer; + offset_t shift; + axi_pkg::len_t num_beats; + logic is_single; + } w_dp_req_t; - // read process - page_len_t r_num_bytes_possible; - page_len_t r_num_bytes; - offset_t r_addr_offset; - logic r_done; + /// The datapath write response type provides feedback from the write part of the datapath: + /// - `resp`: The response from the B channel of the AXI4 manager interface + /// - `user`: The user field from the B channel of the AXI4 manager interface + typedef struct packed { + axi_pkg::resp_t resp; + user_t user; + } w_dp_rsp_t; - // write process - page_len_t w_num_bytes_possible; - page_len_t w_num_bytes; - offset_t w_addr_offset; - logic w_done; + /// The iDMA read request bundles an `AR` type and a datapath read response type together. + typedef struct packed { + r_dp_req_t r_dp_req; + read_meta_channel_t ar_req; + } idma_r_req_t; + /// The iDMA write request bundles an `AW` type and a datapath write response type together. It + /// has an additional flags: + /// - `last`: indicating the current burst is the last one of the generic 1D transfer currently + /// being processed + /// - `midend_last`: The current transfer is marked by the controlling as last + /// - `decouple_aw`: indicates this is an R-AW decoupled transfer + typedef struct packed { + w_dp_req_t w_dp_req; + write_meta_channel_t aw_req; + logic last; + logic super_last; + logic decouple_aw; + } idma_w_req_t; - //-------------------------------------- - // read boundary check - //-------------------------------------- - idma_legalizer_page_splitter #( - .OffsetWidth ( OffsetWidth ), - .PageAddrWidth ( PageSize ), - .addr_t ( addr_t ), - .page_len_t ( page_len_t ), - .page_addr_t ( page_addr_t ) - ) i_read_page_splitter ( - .not_bursting_i ( 1'b1 ), + /// The mutable transfer options type holds important information that is mutated by the + /// `legalizer` block. + typedef struct packed { + idma_pkg::protocol_e src_protocol; + idma_pkg::protocol_e dst_protocol; + offset_t read_shift; + offset_t write_shift; + logic decouple_rw; + logic decouple_aw; + logic [2:0] src_max_llen; + logic [2:0] dst_max_llen; + logic src_reduce_len; + logic dst_reduce_len; + id_t axi_id; + idma_pkg::axi_options_t src_axi_opt; + idma_pkg::axi_options_t dst_axi_opt; + logic super_last; + } idma_mut_tf_opt_t; - .reduce_len_i ( opt_tf_q.src_reduce_len ), - .max_llen_i ( opt_tf_q.src_max_llen ), - - .addr_i ( r_tf_q.addr ), - .num_bytes_to_pb_o ( r_page_num_bytes_to_pb ) - ); - - always_comb begin : gen_read_num_bytes_to_pb_logic - case (opt_tf_q.src_protocol) - idma_pkg::INIT: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - idma_pkg::OBI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - default: r_num_bytes_to_pb = '0; - endcase - end - - //-------------------------------------- - // write boundary check - //-------------------------------------- - idma_legalizer_page_splitter #( - .OffsetWidth ( OffsetWidth ), - .PageAddrWidth ( PageSize ), - .addr_t ( addr_t ), - .page_len_t ( page_len_t ), - .page_addr_t ( page_addr_t ) - ) i_write_page_splitter ( - .not_bursting_i ( 1'b1 ), + /// The mutable transfer type holds important information that is mutated by the + /// `legalizer` block. + typedef struct packed { + tf_len_t length; + addr_t addr; + logic valid; + addr_t base_addr; + } idma_mut_tf_t; - .reduce_len_i ( opt_tf_q.dst_reduce_len ), - .max_llen_i ( opt_tf_q.dst_max_llen ), - - .addr_i ( w_tf_q.addr ), - .num_bytes_to_pb_o ( w_page_num_bytes_to_pb ) - ); - always_comb begin : gen_write_num_bytes_to_pb_logic - case (opt_tf_q.dst_protocol) - idma_pkg::AXI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; - idma_pkg::INIT: w_num_bytes_to_pb = w_page_num_bytes_to_pb; - default: w_num_bytes_to_pb = '0; - endcase - end + // datapath busy indicates the datapath is actively working on a transfer. It is composed of + // the activity of the buffer as well as both the read and write machines + logic dp_busy; + // blanks invalid data + logic dp_poison; - //-------------------------------------- - // page boundary check - //-------------------------------------- - // how many transfers are remaining when concerning both r/w pages? - // take the boundary that is closer - assign c_num_bytes_to_pb = (r_num_bytes_to_pb > w_num_bytes_to_pb) ? - w_num_bytes_to_pb : r_num_bytes_to_pb; + // read and write requests and their handshaking signals + idma_r_req_t r_req; + idma_w_req_t w_req; + logic r_valid, w_valid; + logic r_ready, w_ready; + // It the current transfer the last burst in the 1D transfer? + logic w_last_burst; + logic w_last_ready; - //-------------------------------------- - // Synchronized R/W process - //-------------------------------------- - always_comb begin : proc_num_bytes_possible - // Default: Coupled - r_num_bytes_possible = c_num_bytes_to_pb; - w_num_bytes_possible = c_num_bytes_to_pb; + // Super last flag: The current transfer is indicated as the last one by the controlling + // unit; e.g. by a midend + logic w_super_last; - if (opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::INIT })) begin - r_num_bytes_possible = r_num_bytes_to_pb; - w_num_bytes_possible = w_num_bytes_to_pb; - end - end + // Datapath FIFO signals -> used to decouple legalizer and datapath + logic r_dp_req_in_ready, w_dp_req_in_ready; + logic r_dp_req_out_valid, w_dp_req_out_valid; + logic r_dp_req_out_ready, w_dp_req_out_ready; + r_dp_req_t r_dp_req_out; + w_dp_req_t w_dp_req_out; - assign r_addr_offset = r_tf_q.addr[OffsetWidth-1:0]; - assign w_addr_offset = w_tf_q.addr[OffsetWidth-1:0]; + // datapah responses + r_dp_rsp_t r_dp_rsp; + w_dp_rsp_t w_dp_rsp; + logic r_dp_rsp_valid, w_dp_rsp_valid; + logic r_dp_rsp_ready, w_dp_rsp_ready; - // legalization process -> read and write is coupled together - always_comb begin : proc_read_write_transaction + // Ax handshaking + logic ar_ready, ar_ready_dp; + logic aw_ready, aw_ready_dp; + logic aw_valid_dp, ar_valid_dp; - // default: keep state - r_tf_d = r_tf_q; - w_tf_d = w_tf_q; - opt_tf_d = opt_tf_q; + // Ax request from R-AW coupler to datapath + write_meta_channel_t aw_req_dp; - // default: not done - r_done = 1'b0; - w_done = 1'b0; + // Ax request from the decoupling stage to the datapath + read_meta_channel_t ar_req_dp; - //-------------------------------------- - // Legalize read transaction - //-------------------------------------- - // more bytes remaining than we can read - if (r_tf_q.length > r_num_bytes_possible) begin - r_num_bytes = r_num_bytes_possible; - // calculate remainder - r_tf_d.length = r_tf_q.length - r_num_bytes_possible; - // next address - r_tf_d.addr = r_tf_q.addr + r_num_bytes; + // flush and preemptively empty the legalizer + logic legalizer_flush, legalizer_kill; - // remaining bytes fit in one burst - end else begin - r_num_bytes = r_tf_q.length[PageAddrWidth:0]; - // finished - r_tf_d.valid = 1'b0; - r_done = 1'b1; - end + /// intermediate signals to reject zero length transfers + logic is_length_zero; + logic req_valid; + idma_rsp_t idma_rsp; + logic rsp_valid; + logic rsp_ready; - //-------------------------------------- - // Legalize write transaction - //-------------------------------------- - // more bytes remaining than we can write - if (w_tf_q.length > w_num_bytes_possible) begin - w_num_bytes = w_num_bytes_possible; - // calculate remainder - w_tf_d.length = w_tf_q.length - w_num_bytes_possible; - // next address - w_tf_d.addr = w_tf_q.addr + w_num_bytes; + // Respone Channel valid and ready -> needed for bursting + logic r_chan_valid; + logic r_chan_ready; - // remaining bytes fit in one burst - end else begin - w_num_bytes = w_tf_q.length[PageAddrWidth:0]; - // finished - w_tf_d.valid = 1'b0; - w_done = 1'b1; - end + //-------------------------------------- + // Reject Zero Length Transfers + //-------------------------------------- + if (RejectZeroTransfers) begin : gen_reject_zero_transfers + // is the current transfer length 0? + assign is_length_zero = idma_req_i.length == '0; - //-------------------------------------- - // Kill - //-------------------------------------- - if (kill_i) begin - // kill the current state - r_tf_d = '0; - w_tf_d = '0; - r_done = 1'b1; - w_done = 1'b1; - end + // bypass valid as long as length is not zero, otherwise suppress it + assign req_valid = is_length_zero ? 1'b0 : req_valid_i; - //-------------------------------------- - // Refill - //-------------------------------------- - // new request is taken in if both r and w machines are ready. - if (ready_o & valid_i) begin + // modify response + always_comb begin : proc_modify_response_zero_length + // default: bypass + idma_rsp_o = idma_rsp; + rsp_ready = rsp_ready_i; + rsp_valid_o = rsp_valid; - // load all three mutable objects (source, destination, option) - // source or read - r_tf_d = '{ - length: req_i.length, - addr: req_i.src_addr, - valid: 1'b1, - base_addr: req_i.src_addr - }; - // destination or write - w_tf_d = '{ - length: req_i.length, - addr: req_i.dst_addr, - valid: 1'b1, - base_addr: req_i.dst_addr - }; - // options - opt_tf_d = '{ - src_protocol: req_i.opt.src_protocol, - dst_protocol: req_i.opt.dst_protocol, - read_shift: '0, - write_shift: '0, - decouple_rw: req_i.opt.beo.decouple_rw, - decouple_aw: req_i.opt.beo.decouple_aw, - src_max_llen: req_i.opt.beo.src_max_llen, - dst_max_llen: req_i.opt.beo.dst_max_llen, - src_reduce_len: req_i.opt.beo.src_reduce_len, - dst_reduce_len: req_i.opt.beo.dst_reduce_len, - axi_id: req_i.opt.axi_id, - src_axi_opt: req_i.opt.src, - dst_axi_opt: req_i.opt.dst, - super_last: req_i.opt.last - }; - // determine shift amount - if (CombinedShifter) begin - opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0] - req_i.dst_addr[OffsetWidth-1:0]; - opt_tf_d.write_shift = '0; - end else begin - opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0]; - opt_tf_d.write_shift = - req_i.dst_addr[OffsetWidth-1:0]; + // a zero transfer happens + if (is_length_zero & req_valid_i & req_ready_o) begin + // block backend + rsp_ready = 1'b0; + // generate new response + rsp_valid_o = 1'b1; + idma_rsp_o = '0; + idma_rsp_o.error = 1'b1; + idma_rsp_o.pld.err_type = idma_pkg::BACKEND; end end + + // just bypass signals + end else begin : gen_bypass_zero_transfers + // bypass + assign req_valid = req_valid_i; + assign idma_rsp_o = idma_rsp; + assign rsp_ready = rsp_ready_i; + assign rsp_valid_o = rsp_valid; end //-------------------------------------- - // Connect outputs + // Legalization //-------------------------------------- + if (HardwareLegalizer) begin : gen_hw_legalizer + // hardware legalizer is present + idma_legalizer_rw_axi #( + .CombinedShifter ( CombinedShifter ), + .DataWidth ( DataWidth ), + .AddrWidth ( AddrWidth ), + .idma_req_t ( idma_req_t ), + .idma_r_req_t ( idma_r_req_t ), + .idma_w_req_t ( idma_w_req_t ), + .idma_mut_tf_t ( idma_mut_tf_t ), + .idma_mut_tf_opt_t ( idma_mut_tf_opt_t ) + ) i_idma_legalizer ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( idma_req_i ), + .valid_i ( req_valid ), + .ready_o ( req_ready_o ), + .r_req_o ( r_req ), + .w_req_o ( w_req ), + .r_valid_o ( r_valid ), + .w_valid_o ( w_valid ), + .r_ready_i ( r_ready ), + .w_ready_i ( w_ready ), + .flush_i ( legalizer_flush ), + .kill_i ( legalizer_kill ), + .r_busy_o ( busy_o.r_leg_busy ), + .w_busy_o ( busy_o.w_leg_busy ) + ); - // Read meta channel - always_comb begin : gen_read_meta_channel - r_req_o.ar_req = '0; - case(opt_tf_q.src_protocol) - idma_pkg::INIT: begin - r_req_o.ar_req.init.req_chan = '{ - cfg: r_tf_q.base_addr, - term: '0, - strb: '0, - id: opt_tf_d.axi_id - }; - - end - idma_pkg::OBI: begin - r_req_o.ar_req.obi.a_chan = '{ - addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - be: '1, - we: 1'b0, - wdata: '0, - aid: opt_tf_q.axi_id, - a_optional: '0 - }; - - end - default: - r_req_o.ar_req = '0; - endcase - end - - // assign the signals needed to set-up the read data path - assign r_req_o.r_dp_req = '{ - src_protocol: opt_tf_q.src_protocol, - offset: r_addr_offset, - tailer: OffsetWidth'(r_num_bytes + r_addr_offset), - shift: opt_tf_q.read_shift, - decouple_aw: opt_tf_q.decouple_aw, - is_single: r_num_bytes <= StrbWidth - }; + end else begin : gen_no_hw_legalizer + // stream fork is used to synchronize the two decoupled channels without the need for a + // FIFO here. + stream_fork #( + .N_OUP ( 32'd2 ) + ) i_stream_fork ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( req_valid ), + .ready_o ( req_ready_o ), + .valid_o ( { r_valid, w_valid } ), + .ready_i ( { r_ready, w_ready } ) + ); - // Write meta channel and data path - always_comb begin : gen_write_meta_channel - w_req_o.aw_req = '0; - case(opt_tf_q.dst_protocol) - idma_pkg::AXI: begin - w_req_o.aw_req.axi.aw_chan = '{ - id: opt_tf_q.axi_id, - addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((w_num_bytes + w_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.dst_axi_opt.burst, - lock: opt_tf_q.dst_axi_opt.lock, - cache: opt_tf_q.dst_axi_opt.cache, - prot: opt_tf_q.dst_axi_opt.prot, - qos: opt_tf_q.dst_axi_opt.qos, - region: opt_tf_q.dst_axi_opt.region, - user: '0, - atop: '0 - }; - - end - idma_pkg::INIT: begin - w_req_o.aw_req.init.req_chan = '{ - cfg: w_tf_q.base_addr, - term: '0, - strb: '0, - id: opt_tf_d.axi_id - }; - - end - default: - w_req_o.aw_req = '0; - endcase - end + // local signal holding the length -> explicitly only doing the computation once + axi_pkg::len_t len; + assign len = ((idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0] - + 'd1) >> OffsetWidth); - // assign the signals needed to set-up the write data path - always_comb begin : gen_write_data_path - case (opt_tf_q.dst_protocol) - idma_pkg::AXI: - w_req_o.w_dp_req = '{ - dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: w_req_o.aw_req.axi.aw_chan.len, - is_single: w_req_o.aw_req.axi.aw_chan.len == '0 - }; - - default: - w_req_o.w_dp_req = '{ - dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: 'd0, - is_single: 1'b1 - }; - endcase - end + // assemble read datapath request + assign r_req.r_dp_req = '{ + src_protocol: idma_req_i.opt.src_protocol, + offset: idma_req_i.src_addr[OffsetWidth-1:0], + tailer: OffsetWidth'(idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0]), + shift: OffsetWidth'(idma_req_i.src_addr[OffsetWidth-1:0]), + decouple_aw: idma_req_i.opt.beo.decouple_aw, + is_single: len == '0 + }; + // assemble write datapath request + assign w_req.w_dp_req = '{ + dst_protocol: idma_req_i.opt.dst_protocol, + offset: idma_req_i.dst_addr[OffsetWidth-1:0], + tailer: OffsetWidth'(idma_req_i.length + idma_req_i.dst_addr[OffsetWidth-1:0]), + shift: OffsetWidth'(- idma_req_i.dst_addr[OffsetWidth-1:0]), + num_beats: len, + is_single: len == '0 + }; - // last burst in generic 1D transfer? - assign w_req_o.last = w_done; + // if the legalizer is bypassed; every burst is the last of the 1D transfer + assign w_req.last = 1'b1; - // last burst indicated by midend - assign w_req_o.super_last = opt_tf_q.super_last; + // assign the last flag of the controlling unit + assign w_req.super_last = idma_req_i.opt.last; - // assign aw decouple flag - assign w_req_o.decouple_aw = opt_tf_q.decouple_aw; + // bypass decouple signal + assign w_req.decouple_aw = idma_req_i.opt.beo.decouple_aw; - // busy output - assign r_busy_o = r_tf_q.valid; - assign w_busy_o = w_tf_q.valid; + // there is no unit to be busy + assign busy_o.r_leg_busy = 1'b0; + assign busy_o.w_leg_busy = 1'b0; + end + + // data path, meta channels, and last queues have to be ready for the legalizer to be ready + assign r_ready = r_dp_req_in_ready & ar_ready; + assign w_ready = w_dp_req_in_ready & aw_ready & w_last_ready; //-------------------------------------- - // Flow Control + // Error handler //-------------------------------------- - // only advance to next state if: - // * rw_coupled: both machines advance - // * rw_decoupled: either machine advances - - always_comb begin : proc_legalizer_flow_control - if ( opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::INIT })) begin - r_tf_ena = (r_ready_i & !flush_i) | kill_i; - w_tf_ena = (w_ready_i & !flush_i) | kill_i; - - r_valid_o = r_tf_q.valid & r_ready_i & !flush_i; - w_valid_o = w_tf_q.valid & w_ready_i & !flush_i; - end else begin - r_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; - w_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; + if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler + idma_error_handler #( + .MetaFifoDepth ( MetaFifoDepth ), + .PrintFifoInfo ( PrintFifoInfo ), + .idma_rsp_t ( idma_rsp_t ), + .idma_eh_req_t ( idma_eh_req_t ), + .addr_t ( addr_t ), + .r_dp_rsp_t ( r_dp_rsp_t ), + .w_dp_rsp_t ( w_dp_rsp_t ) + ) i_idma_error_handler ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .rsp_o ( idma_rsp ), + .rsp_valid_o ( rsp_valid ), + .rsp_ready_i ( rsp_ready ), + .req_valid_i ( req_valid ), + .req_ready_i ( req_ready_o ), + .eh_i ( idma_eh_req_i ), + .eh_valid_i ( eh_req_valid_i ), + .eh_ready_o ( eh_req_ready_o ), + .r_addr_i ( r_req.ar_req.axi.ar_chan.addr ), + .w_addr_i ( w_req.aw_req.axi.aw_chan.addr ), + .r_consume_i ( r_valid & r_ready ), + .w_consume_i ( w_valid & w_ready ), + .legalizer_flush_o ( legalizer_flush ), + .legalizer_kill_o ( legalizer_kill ), + .dp_busy_i ( dp_busy ), + .dp_poison_o ( dp_poison ), + .r_dp_rsp_i ( r_dp_rsp ), + .r_dp_valid_i ( r_dp_rsp_valid ), + .r_dp_ready_o ( r_dp_rsp_ready ), + .w_dp_rsp_i ( w_dp_rsp ), + .w_dp_valid_i ( w_dp_rsp_valid ), + .w_dp_ready_o ( w_dp_rsp_ready ), + .w_last_burst_i ( w_last_burst ), + .w_super_last_i ( w_super_last ), + .fsm_busy_o ( busy_o.eh_fsm_busy ), + .cnt_busy_o ( busy_o.eh_cnt_busy ) + ); + end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler + // bypass the signals, assign their neutral values + assign idma_rsp.error = 1'b0; + assign idma_rsp.pld = 1'b0; + assign idma_rsp.last = w_super_last; + assign rsp_valid = w_dp_rsp_valid & w_last_burst; + assign eh_req_ready_o = 1'b0; + assign legalizer_flush = 1'b0; + assign legalizer_kill = 1'b0; + assign dp_poison = 1'b0; + assign r_dp_rsp_ready = rsp_ready; + assign w_dp_rsp_ready = rsp_ready; + assign busy_o.eh_fsm_busy = 1'b0; + assign busy_o.eh_cnt_busy = 1'b0; - r_valid_o = r_tf_q.valid & w_ready_i & r_ready_i & !flush_i; - w_valid_o = w_tf_q.valid & r_ready_i & w_ready_i & !flush_i; + end else begin : gen_param_error + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Unexpected Error Capability"); end + ) end - - // load next idma request: if both machines are done! - assign ready_o = r_done & w_done & r_ready_i & w_ready_i & !flush_i; //-------------------------------------- - // State + // Datapath busy signal //-------------------------------------- - `FF (opt_tf_q, opt_tf_d, '0, clk_i, rst_ni) - `FFL(r_tf_q, r_tf_d, r_tf_ena, '0, clk_i, rst_ni) - `FFL(w_tf_q, w_tf_d, w_tf_ena, '0, clk_i, rst_ni) + assign dp_busy = busy_o.buffer_busy | + busy_o.r_dp_busy | + busy_o.w_dp_busy; + + + //-------------------------------------- + // Datapath decoupling + //-------------------------------------- + stream_fifo_optimal_wrap #( + .Depth ( NumAxInFlight ), + .type_t ( r_dp_req_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_r_dp_req ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( r_req.r_dp_req ), + .valid_i ( r_valid ), + .ready_o ( r_dp_req_in_ready ), + .data_o ( r_dp_req_out ), + .valid_o ( r_dp_req_out_valid ), + .ready_i ( r_dp_req_out_ready ) + ); + + stream_fifo_optimal_wrap #( + .Depth ( NumAxInFlight ), + .type_t ( w_dp_req_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_w_dp_req ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( w_req.w_dp_req ), + .valid_i ( w_valid ), + .ready_o ( w_dp_req_in_ready ), + .data_o ( w_dp_req_out ), + .valid_o ( w_dp_req_out_valid ), + .ready_i ( w_dp_req_out_ready ) + ); + + // Add fall-through register to allow the input to be ready if the output is not. This + // does not add a cycle of delay + + fall_through_register #( + .T ( read_meta_channel_t ) + ) i_ar_fall_through_register ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .clr_i ( 1'b0 ), + .valid_i ( r_valid ), + .ready_o ( ar_ready ), + .data_i ( r_req.ar_req ), + .valid_o ( ar_valid_dp ), + .ready_i ( ar_ready_dp ), + .data_o ( ar_req_dp ) + ); + + + //-------------------------------------- + // Last flag store + //-------------------------------------- + stream_fifo_optimal_wrap #( + .Depth ( MetaFifoDepth ), + .type_t ( logic [1:0] ), + .PrintInfo ( PrintFifoInfo ) + ) i_w_last ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( {w_req.super_last, w_req.last} ), + .valid_i ( w_valid & w_ready ), + .ready_o ( w_last_ready ), + .data_o ( {w_super_last, w_last_burst} ), + .valid_o ( /* NOT CONNECTED */ ), + .ready_i ( w_dp_rsp_valid & w_dp_rsp_ready ) + ); + + //-------------------------------------- + // Transport Layer / Datapath + //-------------------------------------- + idma_transport_layer_rw_axi #( + .NumAxInFlight ( NumAxInFlight ), + .DataWidth ( DataWidth ), + .BufferDepth ( BufferDepth ), + .MaskInvalidData ( MaskInvalidData ), + .PrintFifoInfo ( PrintFifoInfo ), + .r_dp_req_t ( r_dp_req_t ), + .w_dp_req_t ( w_dp_req_t ), + .r_dp_rsp_t ( r_dp_rsp_t ), + .w_dp_rsp_t ( w_dp_rsp_t ), + .write_meta_channel_t ( write_meta_channel_t ), + .read_meta_channel_t ( read_meta_channel_t ), + .axi_req_t ( axi_req_t ), + .axi_rsp_t ( axi_rsp_t ) + ) i_idma_transport_layer ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .axi_read_req_o ( axi_read_req_o ), + .axi_read_rsp_i ( axi_read_rsp_i ), + .axi_write_req_o ( axi_write_req_o ), + .axi_write_rsp_i ( axi_write_rsp_i ), + .r_dp_req_i ( r_dp_req_out ), + .r_dp_valid_i ( r_dp_req_out_valid ), + .r_dp_ready_o ( r_dp_req_out_ready ), + .r_dp_rsp_o ( r_dp_rsp ), + .r_dp_valid_o ( r_dp_rsp_valid ), + .r_dp_ready_i ( r_dp_rsp_ready ), + .w_dp_req_i ( w_dp_req_out ), + .w_dp_valid_i ( w_dp_req_out_valid ), + .w_dp_ready_o ( w_dp_req_out_ready ), + .w_dp_rsp_o ( w_dp_rsp ), + .w_dp_valid_o ( w_dp_rsp_valid ), + .w_dp_ready_i ( w_dp_rsp_ready ), + .ar_req_i ( ar_req_dp ), + .ar_valid_i ( ar_valid_dp ), + .ar_ready_o ( ar_ready_dp ), + .aw_req_i ( aw_req_dp ), + .aw_valid_i ( aw_valid_dp ), + .aw_ready_o ( aw_ready_dp ), + .dp_poison_i ( dp_poison ), + .r_dp_busy_o ( busy_o.r_dp_busy ), + .w_dp_busy_o ( busy_o.w_dp_busy ), + .buffer_busy_o ( busy_o.buffer_busy ), + .r_chan_ready_o ( r_chan_ready ), + .r_chan_valid_o ( r_chan_valid ) + ); + + //-------------------------------------- + // R-AW channel coupler + //-------------------------------------- + + if (RAWCouplingAvail) begin : gen_r_aw_coupler + // instantiate the channel coupler + idma_channel_coupler #( + .NumAxInFlight ( NumAxInFlight ), + .AddrWidth ( AddrWidth ), + .UserWidth ( UserWidth ), + .AxiIdWidth ( AxiIdWidth ), + .PrintFifoInfo ( PrintFifoInfo ), + .axi_aw_chan_t ( write_meta_channel_t ) + ) i_idma_channel_coupler ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .r_rsp_valid_i ( r_chan_valid ), + .r_rsp_ready_i ( r_chan_ready ), + .r_rsp_first_i ( r_dp_rsp.first ), + .r_decouple_aw_i ( r_dp_req_out.decouple_aw ), + .aw_decouple_aw_i ( w_req.decouple_aw ), + .aw_req_i ( w_req.aw_req ), + .aw_valid_i ( w_valid ), + .aw_ready_o ( aw_ready ), + .aw_req_o ( aw_req_dp ), + .aw_valid_o ( aw_valid_dp ), + .aw_ready_i ( aw_ready_dp ), + .busy_o ( busy_o.raw_coupler_busy ) + ); + end else begin : gen_r_aw_bypass + // Add fall-through register to allow the input to be ready if the output is not. This + // does not add a cycle of delay + fall_through_register #( + .T ( write_meta_channel_t ) + ) i_aw_fall_through_register ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .clr_i ( 1'b0 ), + .valid_i ( w_valid ), + .ready_o ( aw_ready ), + .data_i ( w_req.aw_req ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp ), + .data_o ( aw_req_dp ) + ); + + // no unit: not busy + assign busy_o.raw_coupler_busy = 1'b0; + end //-------------------------------------- // Assertions //-------------------------------------- - // only support the decomposition of incremental bursts - `ASSERT_NEVER(OnlyIncrementalBurstsSRC, (ready_o & valid_i & - req_i.opt.src.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) - `ASSERT_NEVER(OnlyIncrementalBurstsDST, (ready_o & valid_i & - req_i.opt.dst.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) + `IDMA_NONSYNTH_BLOCK( + initial begin : proc_assert_params + axi_addr_width : assert(AddrWidth >= 32'd12) else + $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); + axi_id_width : assert(AxiIdWidth > 32'd0) else + $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); + axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, + 32'd512, 32'd1028}) else + $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); + axi_user_width : assert(UserWidth > 32'd0) else + $fatal(1, "Parameter `UserWidth` has to be > 0!"); + num_ax_in_flight : assert(NumAxInFlight > 32'd1) else + $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); + buffer_depth : assert(BufferDepth > 32'd1) else + $fatal(1, "Parameter `BufferDepth` has to be > 1!"); + tf_len_width : assert(TFLenWidth >= 32'd12) else + $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); + tf_len_width_max : assert(TFLenWidth <= AddrWidth) else + $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); + end + ) endmodule @@ -5657,496 +5823,665 @@ endmodule // - Thomas Benz // - Tobias Senti -`include "common_cells/registers.svh" -`include "common_cells/assertions.svh" +`include "axi/typedef.svh" `include "idma/guard.svh" -/// Legalizes a generic 1D transfer according to the rules given by the -/// used protocol. -module idma_legalizer_r_axi_rw_init_rw_obi #( +/// The iDMA backend implements an arbitrary 1D copy engine +module idma_backend_r_obi_w_axi #( + /// Data width + parameter int unsigned DataWidth = 32'd16, + /// Address width + parameter int unsigned AddrWidth = 32'd24, + /// AXI user width + parameter int unsigned UserWidth = 32'd1, + /// AXI ID width + parameter int unsigned AxiIdWidth = 32'd1, + /// Number of transaction that can be in-flight concurrently + parameter int unsigned NumAxInFlight = 32'd2, + /// The depth of the internal reorder buffer: + /// - '2': minimal possible configuration + /// - '3': efficiently handle misaligned transfers (recommended) + parameter int unsigned BufferDepth = 32'd2, + /// With of a transfer: max transfer size is `2**TFLenWidth` bytes + parameter int unsigned TFLenWidth = 32'd24, + /// The depth of the memory system the backend is attached to + parameter int unsigned MemSysDepth = 32'd0, /// Should both data shifts be done before the dataflow element? /// If this is enabled, then the data inserted into the dataflow element /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Data width - parameter int unsigned DataWidth = 32'd16, - /// Address width - parameter int unsigned AddrWidth = 32'd24, - /// 1D iDMA request type: - /// - `length`: the length of the transfer in bytes - /// - `*_addr`: the source / target byte addresses of the transfer - /// - `opt`: the options field - parameter type idma_req_t = logic, - /// Read request type - parameter type idma_r_req_t = logic, - /// Write request type - parameter type idma_w_req_t = logic, - /// Mutable transfer type - parameter type idma_mut_tf_t = logic, - /// Mutable options type - parameter type idma_mut_tf_opt_t = logic + parameter bit CombinedShifter = 1'b0, + /// Should the `R`-`AW` coupling hardware be present? (recommended) + parameter bit RAWCouplingAvail = 1'b0, + /// Mask invalid data on the manager interface + parameter bit MaskInvalidData = 1'b1, + /// Should hardware legalization be present? (recommended) + /// If not, software legalization is required to ensure the transfers are + /// AXI4-conformal + parameter bit HardwareLegalizer = 1'b1, + /// Reject zero-length transfers + parameter bit RejectZeroTransfers = 1'b1, + /// Should the error handler be present? + parameter idma_pkg::error_cap_e ErrorCap = idma_pkg::NO_ERROR_HANDLING, + /// Print the info of the FIFO configuration + parameter bit PrintFifoInfo = 1'b0, + /// 1D iDMA request type + parameter type idma_req_t = logic, + /// iDMA response type + parameter type idma_rsp_t = logic, + /// Error Handler request type + parameter type idma_eh_req_t = logic, + /// iDMA busy signal + parameter type idma_busy_t = logic, + /// AXI4+ATOP Request and Response channel type + parameter type axi_req_t = logic, + parameter type axi_rsp_t = logic, + /// OBI Request and Response channel type + parameter type obi_req_t = logic, + parameter type obi_rsp_t = logic, + /// Address Read Channel type + parameter type read_meta_channel_t = logic, + /// Address Write Channel type + parameter type write_meta_channel_t = logic, + /// Strobe Width (do not override!) + parameter int unsigned StrbWidth = DataWidth / 8, + /// Offset Width (do not override!) + parameter int unsigned OffsetWidth = $clog2(StrbWidth) )( /// Clock input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, + /// Testmode in + input logic testmode_i, - /// 1D request - input idma_req_t req_i, - /// 1D request valid - input logic valid_i, - /// 1D request ready - output logic ready_o, + /// 1D iDMA request + input idma_req_t idma_req_i, + /// 1D iDMA request valid + input logic req_valid_i, + /// 1D iDMA request ready + output logic req_ready_o, - /// Read request; contains datapath and meta information - output idma_r_req_t r_req_o, - /// Read request valid - output logic r_valid_o, - /// Read request ready - input logic r_ready_i, + /// iDMA response + output idma_rsp_t idma_rsp_o, + /// iDMA response valid + output logic rsp_valid_o, + /// iDMA response ready + input logic rsp_ready_i, - /// Write request; contains datapath and meta information - output idma_w_req_t w_req_o, - /// Write request valid - output logic w_valid_o, - /// Write request ready - input logic w_ready_i, + /// Error handler request + input idma_eh_req_t idma_eh_req_i, + /// Error handler request valid + input logic eh_req_valid_i, + /// Error handler request ready + output logic eh_req_ready_o, - /// Invalidate the current burst transfer, stops emission of requests - input logic flush_i, - /// Kill the active 1D transfer; reload a new transfer - input logic kill_i, + /// OBI read request + output obi_req_t obi_read_req_o, + /// OBI read response + input obi_rsp_t obi_read_rsp_i, - /// Read machine of the legalizer is busy - output logic r_busy_o, - /// Write machine of the legalizer is busy - output logic w_busy_o + /// AXI4+ATOP write request + output axi_req_t axi_write_req_o, + /// AXI4+ATOP write response + input axi_rsp_t axi_write_rsp_i, + + /// iDMA busy flags + output idma_busy_t busy_o ); - function int unsigned max_size(input int unsigned a, b); - return a > b ? a : b; - endfunction - /// Stobe width - localparam int unsigned StrbWidth = DataWidth / 8; - /// Offset width - localparam int unsigned OffsetWidth = $clog2(StrbWidth); - /// The size of a page in byte - localparam int unsigned PageSize = max_size(256 * StrbWidth > 4096 ? 4096 : 256 * StrbWidth, max_size(StrbWidth, StrbWidth)); - /// The width of page offset byte addresses - localparam int unsigned PageAddrWidth = $clog2(PageSize); + /// The localparam MetaFifoDepth holds the maximum number of transfers that can be + /// in-flight under any circumstances. + localparam int unsigned MetaFifoDepth = BufferDepth + NumAxInFlight + MemSysDepth; - /// Offset type - typedef logic [ OffsetWidth-1:0] offset_t; /// Address type - typedef logic [ AddrWidth-1:0] addr_t; - /// Page address type - typedef logic [PageAddrWidth-1:0] page_addr_t; - /// Page length type - typedef logic [ PageAddrWidth:0] page_len_t; + typedef logic [AddrWidth-1:0] addr_t; + /// DAta type + typedef logic [DataWidth-1:0] data_t; + /// Strobe type + typedef logic [StrbWidth-1:0] strb_t; + /// User type + typedef logic [UserWidth-1:0] user_t; + /// ID type + typedef logic [AxiIdWidth-1:0] id_t; + /// Offset type + typedef logic [OffsetWidth-1:0] offset_t; + /// Transfer length type + typedef logic [TFLenWidth-1:0] tf_len_t; + /// The datapath read request type holds all the information required to configure the read + /// part of the datapath. The type consists of: + /// - `offset`: The bus offset of the read + /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the + /// bus width. + /// - `shift`: The amount the data needs to be shifted + /// - `decouple_aw`: If the transfer has the AW decoupled from the R + /// - `is_single`: Is this transfer just one beat long? `(len == 0)` + typedef struct packed { + idma_pkg::protocol_e src_protocol; + offset_t offset; + offset_t tailer; + offset_t shift; + logic decouple_aw; + logic is_single; + } r_dp_req_t; - // state: internally hold one transfer, this is mutated - idma_mut_tf_t r_tf_d, r_tf_q; - idma_mut_tf_t w_tf_d, w_tf_q; - idma_mut_tf_opt_t opt_tf_d, opt_tf_q; + /// The datapath read response type provides feedback from the read part of the datapath: + /// - `resp`: The response from the R channel of the AXI4 manager interface + /// - `last`: The last flag from the R channel of the AXI4 manager interface + /// - `first`: Is the current item first beat in the burst + typedef struct packed { + axi_pkg::resp_t resp; + logic last; + logic first; + } r_dp_rsp_t; - // enable signals for next mutable transfer storage - logic r_tf_ena; - logic w_tf_ena; + /// The datapath write request type holds all the information required to configure the write + /// part of the datapath. The type consists of: + /// - `offset`: The bus offset of the write + /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the + /// bus width. + /// - `shift`: The amount the data needs to be shifted + /// - `num_beats`: The number of beats this burst consist of + /// - `is_single`: Is this transfer just one beat long? `(len == 0)` + typedef struct packed { + idma_pkg::protocol_e dst_protocol; + offset_t offset; + offset_t tailer; + offset_t shift; + axi_pkg::len_t num_beats; + logic is_single; + } w_dp_req_t; - // page boundaries - page_len_t r_page_num_bytes_to_pb; - page_len_t r_num_bytes_to_pb; - page_len_t w_page_num_bytes_to_pb; - page_len_t w_num_bytes_to_pb; - page_len_t c_num_bytes_to_pb; + /// The datapath write response type provides feedback from the write part of the datapath: + /// - `resp`: The response from the B channel of the AXI4 manager interface + /// - `user`: The user field from the B channel of the AXI4 manager interface + typedef struct packed { + axi_pkg::resp_t resp; + user_t user; + } w_dp_rsp_t; - // read process - page_len_t r_num_bytes_possible; - page_len_t r_num_bytes; - offset_t r_addr_offset; - logic r_done; + /// The iDMA read request bundles an `AR` type and a datapath read response type together. + typedef struct packed { + r_dp_req_t r_dp_req; + read_meta_channel_t ar_req; + } idma_r_req_t; - // write process - page_len_t w_num_bytes_possible; - page_len_t w_num_bytes; - offset_t w_addr_offset; - logic w_done; + /// The iDMA write request bundles an `AW` type and a datapath write response type together. It + /// has an additional flags: + /// - `last`: indicating the current burst is the last one of the generic 1D transfer currently + /// being processed + /// - `midend_last`: The current transfer is marked by the controlling as last + /// - `decouple_aw`: indicates this is an R-AW decoupled transfer + typedef struct packed { + w_dp_req_t w_dp_req; + write_meta_channel_t aw_req; + logic last; + logic super_last; + logic decouple_aw; + } idma_w_req_t; + /// The mutable transfer options type holds important information that is mutated by the + /// `legalizer` block. + typedef struct packed { + idma_pkg::protocol_e src_protocol; + idma_pkg::protocol_e dst_protocol; + offset_t read_shift; + offset_t write_shift; + logic decouple_rw; + logic decouple_aw; + logic [2:0] src_max_llen; + logic [2:0] dst_max_llen; + logic src_reduce_len; + logic dst_reduce_len; + id_t axi_id; + idma_pkg::axi_options_t src_axi_opt; + idma_pkg::axi_options_t dst_axi_opt; + logic super_last; + } idma_mut_tf_opt_t; - //-------------------------------------- - // read boundary check - //-------------------------------------- - idma_legalizer_page_splitter #( - .OffsetWidth ( OffsetWidth ), - .PageAddrWidth ( PageSize ), - .addr_t ( addr_t ), - .page_len_t ( page_len_t ), - .page_addr_t ( page_addr_t ) - ) i_read_page_splitter ( - .not_bursting_i ( 1'b1 ), + /// The mutable transfer type holds important information that is mutated by the + /// `legalizer` block. + typedef struct packed { + tf_len_t length; + addr_t addr; + logic valid; + addr_t base_addr; + } idma_mut_tf_t; - .reduce_len_i ( opt_tf_q.src_reduce_len ), - .max_llen_i ( opt_tf_q.src_max_llen ), - - .addr_i ( r_tf_q.addr ), - .num_bytes_to_pb_o ( r_page_num_bytes_to_pb ) - ); - - always_comb begin : gen_read_num_bytes_to_pb_logic - case (opt_tf_q.src_protocol) - idma_pkg::AXI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - idma_pkg::INIT: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - idma_pkg::OBI: r_num_bytes_to_pb = r_page_num_bytes_to_pb; - default: r_num_bytes_to_pb = '0; - endcase - end - - //-------------------------------------- - // write boundary check - //-------------------------------------- - idma_legalizer_page_splitter #( - .OffsetWidth ( OffsetWidth ), - .PageAddrWidth ( PageSize ), - .addr_t ( addr_t ), - .page_len_t ( page_len_t ), - .page_addr_t ( page_addr_t ) - ) i_write_page_splitter ( - .not_bursting_i ( 1'b1 ), - - .reduce_len_i ( opt_tf_q.dst_reduce_len ), - .max_llen_i ( opt_tf_q.dst_max_llen ), - - .addr_i ( w_tf_q.addr ), - .num_bytes_to_pb_o ( w_page_num_bytes_to_pb ) - ); - always_comb begin : gen_write_num_bytes_to_pb_logic - case (opt_tf_q.dst_protocol) - idma_pkg::INIT: w_num_bytes_to_pb = w_page_num_bytes_to_pb; - idma_pkg::OBI: w_num_bytes_to_pb = w_page_num_bytes_to_pb; - default: w_num_bytes_to_pb = '0; - endcase - end + // datapath busy indicates the datapath is actively working on a transfer. It is composed of + // the activity of the buffer as well as both the read and write machines + logic dp_busy; + // blanks invalid data + logic dp_poison; - //-------------------------------------- - // page boundary check - //-------------------------------------- - // how many transfers are remaining when concerning both r/w pages? - // take the boundary that is closer - assign c_num_bytes_to_pb = (r_num_bytes_to_pb > w_num_bytes_to_pb) ? - w_num_bytes_to_pb : r_num_bytes_to_pb; + // read and write requests and their handshaking signals + idma_r_req_t r_req; + idma_w_req_t w_req; + logic r_valid, w_valid; + logic r_ready, w_ready; + // It the current transfer the last burst in the 1D transfer? + logic w_last_burst; + logic w_last_ready; - //-------------------------------------- - // Synchronized R/W process - //-------------------------------------- - always_comb begin : proc_num_bytes_possible - // Default: Coupled - r_num_bytes_possible = c_num_bytes_to_pb; - w_num_bytes_possible = c_num_bytes_to_pb; + // Super last flag: The current transfer is indicated as the last one by the controlling + // unit; e.g. by a midend + logic w_super_last; - if (opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::INIT, idma_pkg::OBI })) begin - r_num_bytes_possible = r_num_bytes_to_pb; - w_num_bytes_possible = w_num_bytes_to_pb; - end - end + // Datapath FIFO signals -> used to decouple legalizer and datapath + logic r_dp_req_in_ready, w_dp_req_in_ready; + logic r_dp_req_out_valid, w_dp_req_out_valid; + logic r_dp_req_out_ready, w_dp_req_out_ready; + r_dp_req_t r_dp_req_out; + w_dp_req_t w_dp_req_out; - assign r_addr_offset = r_tf_q.addr[OffsetWidth-1:0]; - assign w_addr_offset = w_tf_q.addr[OffsetWidth-1:0]; + // datapah responses + r_dp_rsp_t r_dp_rsp; + w_dp_rsp_t w_dp_rsp; + logic r_dp_rsp_valid, w_dp_rsp_valid; + logic r_dp_rsp_ready, w_dp_rsp_ready; - // legalization process -> read and write is coupled together - always_comb begin : proc_read_write_transaction + // Ax handshaking + logic ar_ready, ar_ready_dp; + logic aw_ready, aw_ready_dp; + logic aw_valid_dp, ar_valid_dp; - // default: keep state - r_tf_d = r_tf_q; - w_tf_d = w_tf_q; - opt_tf_d = opt_tf_q; + // Ax request from R-AW coupler to datapath + write_meta_channel_t aw_req_dp; - // default: not done - r_done = 1'b0; - w_done = 1'b0; + // Ax request from the decoupling stage to the datapath + read_meta_channel_t ar_req_dp; - //-------------------------------------- - // Legalize read transaction - //-------------------------------------- - // more bytes remaining than we can read - if (r_tf_q.length > r_num_bytes_possible) begin - r_num_bytes = r_num_bytes_possible; - // calculate remainder - r_tf_d.length = r_tf_q.length - r_num_bytes_possible; - // next address - r_tf_d.addr = r_tf_q.addr + r_num_bytes; + // flush and preemptively empty the legalizer + logic legalizer_flush, legalizer_kill; - // remaining bytes fit in one burst - end else begin - r_num_bytes = r_tf_q.length[PageAddrWidth:0]; - // finished - r_tf_d.valid = 1'b0; - r_done = 1'b1; - end + /// intermediate signals to reject zero length transfers + logic is_length_zero; + logic req_valid; + idma_rsp_t idma_rsp; + logic rsp_valid; + logic rsp_ready; - //-------------------------------------- - // Legalize write transaction - //-------------------------------------- - // more bytes remaining than we can write - if (w_tf_q.length > w_num_bytes_possible) begin - w_num_bytes = w_num_bytes_possible; - // calculate remainder - w_tf_d.length = w_tf_q.length - w_num_bytes_possible; - // next address - w_tf_d.addr = w_tf_q.addr + w_num_bytes; + // Respone Channel valid and ready -> needed for bursting + logic r_chan_valid; + logic r_chan_ready; - // remaining bytes fit in one burst - end else begin - w_num_bytes = w_tf_q.length[PageAddrWidth:0]; - // finished - w_tf_d.valid = 1'b0; - w_done = 1'b1; - end + //-------------------------------------- + // Reject Zero Length Transfers + //-------------------------------------- + if (RejectZeroTransfers) begin : gen_reject_zero_transfers + // is the current transfer length 0? + assign is_length_zero = idma_req_i.length == '0; - //-------------------------------------- - // Kill - //-------------------------------------- - if (kill_i) begin - // kill the current state - r_tf_d = '0; - w_tf_d = '0; - r_done = 1'b1; - w_done = 1'b1; - end + // bypass valid as long as length is not zero, otherwise suppress it + assign req_valid = is_length_zero ? 1'b0 : req_valid_i; - //-------------------------------------- - // Refill - //-------------------------------------- - // new request is taken in if both r and w machines are ready. - if (ready_o & valid_i) begin + // modify response + always_comb begin : proc_modify_response_zero_length + // default: bypass + idma_rsp_o = idma_rsp; + rsp_ready = rsp_ready_i; + rsp_valid_o = rsp_valid; - // load all three mutable objects (source, destination, option) - // source or read - r_tf_d = '{ - length: req_i.length, - addr: req_i.src_addr, - valid: 1'b1, - base_addr: req_i.src_addr - }; - // destination or write - w_tf_d = '{ - length: req_i.length, - addr: req_i.dst_addr, - valid: 1'b1, - base_addr: req_i.dst_addr - }; - // options - opt_tf_d = '{ - src_protocol: req_i.opt.src_protocol, - dst_protocol: req_i.opt.dst_protocol, - read_shift: '0, - write_shift: '0, - decouple_rw: req_i.opt.beo.decouple_rw, - decouple_aw: req_i.opt.beo.decouple_aw, - src_max_llen: req_i.opt.beo.src_max_llen, - dst_max_llen: req_i.opt.beo.dst_max_llen, - src_reduce_len: req_i.opt.beo.src_reduce_len, - dst_reduce_len: req_i.opt.beo.dst_reduce_len, - axi_id: req_i.opt.axi_id, - src_axi_opt: req_i.opt.src, - dst_axi_opt: req_i.opt.dst, - super_last: req_i.opt.last - }; - // determine shift amount - if (CombinedShifter) begin - opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0] - req_i.dst_addr[OffsetWidth-1:0]; - opt_tf_d.write_shift = '0; - end else begin - opt_tf_d.read_shift = req_i.src_addr[OffsetWidth-1:0]; - opt_tf_d.write_shift = - req_i.dst_addr[OffsetWidth-1:0]; + // a zero transfer happens + if (is_length_zero & req_valid_i & req_ready_o) begin + // block backend + rsp_ready = 1'b0; + // generate new response + rsp_valid_o = 1'b1; + idma_rsp_o = '0; + idma_rsp_o.error = 1'b1; + idma_rsp_o.pld.err_type = idma_pkg::BACKEND; end end + + // just bypass signals + end else begin : gen_bypass_zero_transfers + // bypass + assign req_valid = req_valid_i; + assign idma_rsp_o = idma_rsp; + assign rsp_ready = rsp_ready_i; + assign rsp_valid_o = rsp_valid; end //-------------------------------------- - // Connect outputs + // Legalization //-------------------------------------- + if (HardwareLegalizer) begin : gen_hw_legalizer + // hardware legalizer is present + idma_legalizer_r_obi_w_axi #( + .CombinedShifter ( CombinedShifter ), + .DataWidth ( DataWidth ), + .AddrWidth ( AddrWidth ), + .idma_req_t ( idma_req_t ), + .idma_r_req_t ( idma_r_req_t ), + .idma_w_req_t ( idma_w_req_t ), + .idma_mut_tf_t ( idma_mut_tf_t ), + .idma_mut_tf_opt_t ( idma_mut_tf_opt_t ) + ) i_idma_legalizer ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( idma_req_i ), + .valid_i ( req_valid ), + .ready_o ( req_ready_o ), + .r_req_o ( r_req ), + .w_req_o ( w_req ), + .r_valid_o ( r_valid ), + .w_valid_o ( w_valid ), + .r_ready_i ( r_ready ), + .w_ready_i ( w_ready ), + .flush_i ( legalizer_flush ), + .kill_i ( legalizer_kill ), + .r_busy_o ( busy_o.r_leg_busy ), + .w_busy_o ( busy_o.w_leg_busy ) + ); - // Read meta channel - always_comb begin : gen_read_meta_channel - r_req_o.ar_req = '0; - case(opt_tf_q.src_protocol) - idma_pkg::AXI: begin - r_req_o.ar_req.axi.ar_chan = '{ - id: opt_tf_q.axi_id, - addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - len: ((r_num_bytes + r_addr_offset - 'd1) >> OffsetWidth), - size: axi_pkg::size_t'(OffsetWidth), - burst: opt_tf_q.src_axi_opt.burst, - lock: opt_tf_q.src_axi_opt.lock, - cache: opt_tf_q.src_axi_opt.cache, - prot: opt_tf_q.src_axi_opt.prot, - qos: opt_tf_q.src_axi_opt.qos, - region: opt_tf_q.src_axi_opt.region, - user: '0 - }; - - end - idma_pkg::INIT: begin - r_req_o.ar_req.init.req_chan = '{ - cfg: r_tf_q.base_addr, - term: '0, - strb: '0, - id: opt_tf_d.axi_id - }; - - end - idma_pkg::OBI: begin - r_req_o.ar_req.obi.a_chan = '{ - addr: { r_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - be: '1, - we: 1'b0, - wdata: '0, - aid: opt_tf_q.axi_id, - a_optional: '0 - }; - - end - default: - r_req_o.ar_req = '0; - endcase - end - - // assign the signals needed to set-up the read data path - assign r_req_o.r_dp_req = '{ - src_protocol: opt_tf_q.src_protocol, - offset: r_addr_offset, - tailer: OffsetWidth'(r_num_bytes + r_addr_offset), - shift: opt_tf_q.read_shift, - decouple_aw: opt_tf_q.decouple_aw, - is_single: r_num_bytes <= StrbWidth - }; + end else begin : gen_no_hw_legalizer + // stream fork is used to synchronize the two decoupled channels without the need for a + // FIFO here. + stream_fork #( + .N_OUP ( 32'd2 ) + ) i_stream_fork ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( req_valid ), + .ready_o ( req_ready_o ), + .valid_o ( { r_valid, w_valid } ), + .ready_i ( { r_ready, w_ready } ) + ); - // Write meta channel and data path - always_comb begin : gen_write_meta_channel - w_req_o.aw_req = '0; - case(opt_tf_q.dst_protocol) - idma_pkg::INIT: begin - w_req_o.aw_req.init.req_chan = '{ - cfg: w_tf_q.base_addr, - term: '0, - strb: '0, - id: opt_tf_d.axi_id - }; - - end - idma_pkg::OBI: begin - w_req_o.aw_req.obi.a_chan = '{ - addr: { w_tf_q.addr[AddrWidth-1:OffsetWidth], {{OffsetWidth}{1'b0}} }, - be: '0, - we: 1, - wdata: '0, - aid: opt_tf_q.axi_id, - a_optional: '0 - }; - - end - default: - w_req_o.aw_req = '0; - endcase - end + // local signal holding the length -> explicitly only doing the computation once + axi_pkg::len_t len; + assign len = ((idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0] - + 'd1) >> OffsetWidth); - // assign the signals needed to set-up the write data path - always_comb begin : gen_write_data_path - case (opt_tf_q.dst_protocol) - default: - w_req_o.w_dp_req = '{ - dst_protocol: opt_tf_q.dst_protocol, - offset: w_addr_offset, - tailer: OffsetWidth'(w_num_bytes + w_addr_offset), - shift: opt_tf_q.write_shift, - num_beats: 'd0, - is_single: 1'b1 - }; - endcase - end + // assemble read datapath request + assign r_req.r_dp_req = '{ + src_protocol: idma_req_i.opt.src_protocol, + offset: idma_req_i.src_addr[OffsetWidth-1:0], + tailer: OffsetWidth'(idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0]), + shift: OffsetWidth'(idma_req_i.src_addr[OffsetWidth-1:0]), + decouple_aw: idma_req_i.opt.beo.decouple_aw, + is_single: len == '0 + }; + // assemble write datapath request + assign w_req.w_dp_req = '{ + dst_protocol: idma_req_i.opt.dst_protocol, + offset: idma_req_i.dst_addr[OffsetWidth-1:0], + tailer: OffsetWidth'(idma_req_i.length + idma_req_i.dst_addr[OffsetWidth-1:0]), + shift: OffsetWidth'(- idma_req_i.dst_addr[OffsetWidth-1:0]), + num_beats: len, + is_single: len == '0 + }; - // last burst in generic 1D transfer? - assign w_req_o.last = w_done; + // if the legalizer is bypassed; every burst is the last of the 1D transfer + assign w_req.last = 1'b1; - // last burst indicated by midend - assign w_req_o.super_last = opt_tf_q.super_last; + // assign the last flag of the controlling unit + assign w_req.super_last = idma_req_i.opt.last; - // assign aw decouple flag - assign w_req_o.decouple_aw = opt_tf_q.decouple_aw; + // bypass decouple signal + assign w_req.decouple_aw = idma_req_i.opt.beo.decouple_aw; - // busy output - assign r_busy_o = r_tf_q.valid; - assign w_busy_o = w_tf_q.valid; + // there is no unit to be busy + assign busy_o.r_leg_busy = 1'b0; + assign busy_o.w_leg_busy = 1'b0; + end + + // data path, meta channels, and last queues have to be ready for the legalizer to be ready + assign r_ready = r_dp_req_in_ready & ar_ready; + assign w_ready = w_dp_req_in_ready & aw_ready & w_last_ready; //-------------------------------------- - // Flow Control + // Error handler //-------------------------------------- - // only advance to next state if: - // * rw_coupled: both machines advance - // * rw_decoupled: either machine advances - - always_comb begin : proc_legalizer_flow_control - if ( opt_tf_q.decouple_rw - || (opt_tf_q.src_protocol inside { idma_pkg::INIT, idma_pkg::OBI }) - || (opt_tf_q.dst_protocol inside { idma_pkg::INIT, idma_pkg::OBI })) begin - r_tf_ena = (r_ready_i & !flush_i) | kill_i; - w_tf_ena = (w_ready_i & !flush_i) | kill_i; - - r_valid_o = r_tf_q.valid & r_ready_i & !flush_i; - w_valid_o = w_tf_q.valid & w_ready_i & !flush_i; - end else begin - r_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; - w_tf_ena = (r_ready_i & w_ready_i & !flush_i) | kill_i; + if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Error Handling only implemented for AXI to AXI DMA!"); + end + ) + end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler + // bypass the signals, assign their neutral values + assign idma_rsp.error = 1'b0; + assign idma_rsp.pld = 1'b0; + assign idma_rsp.last = w_super_last; + assign rsp_valid = w_dp_rsp_valid & w_last_burst; + assign eh_req_ready_o = 1'b0; + assign legalizer_flush = 1'b0; + assign legalizer_kill = 1'b0; + assign dp_poison = 1'b0; + assign r_dp_rsp_ready = rsp_ready; + assign w_dp_rsp_ready = rsp_ready; + assign busy_o.eh_fsm_busy = 1'b0; + assign busy_o.eh_cnt_busy = 1'b0; - r_valid_o = r_tf_q.valid & w_ready_i & r_ready_i & !flush_i; - w_valid_o = w_tf_q.valid & r_ready_i & w_ready_i & !flush_i; + end else begin : gen_param_error + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Unexpected Error Capability"); end + ) end - - // load next idma request: if both machines are done! - assign ready_o = r_done & w_done & r_ready_i & w_ready_i & !flush_i; //-------------------------------------- - // State + // Datapath busy signal //-------------------------------------- - `FF (opt_tf_q, opt_tf_d, '0, clk_i, rst_ni) - `FFL(r_tf_q, r_tf_d, r_tf_ena, '0, clk_i, rst_ni) - `FFL(w_tf_q, w_tf_d, w_tf_ena, '0, clk_i, rst_ni) + assign dp_busy = busy_o.buffer_busy | + busy_o.r_dp_busy | + busy_o.w_dp_busy; //-------------------------------------- - // Assertions + // Datapath decoupling //-------------------------------------- - // only support the decomposition of incremental bursts - `ASSERT_NEVER(OnlyIncrementalBurstsSRC, (ready_o & valid_i & - req_i.opt.src.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) - `ASSERT_NEVER(OnlyIncrementalBurstsDST, (ready_o & valid_i & - req_i.opt.dst.burst != axi_pkg::BURST_INCR), clk_i, !rst_ni) - -endmodule - -// Copyright 2023 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Authors: -// - Thomas Benz -// - Tobias Senti + stream_fifo_optimal_wrap #( + .Depth ( NumAxInFlight ), + .type_t ( r_dp_req_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_r_dp_req ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( r_req.r_dp_req ), + .valid_i ( r_valid ), + .ready_o ( r_dp_req_in_ready ), + .data_o ( r_dp_req_out ), + .valid_o ( r_dp_req_out_valid ), + .ready_i ( r_dp_req_out_ready ) + ); + + stream_fifo_optimal_wrap #( + .Depth ( NumAxInFlight ), + .type_t ( w_dp_req_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_w_dp_req ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( w_req.w_dp_req ), + .valid_i ( w_valid ), + .ready_o ( w_dp_req_in_ready ), + .data_o ( w_dp_req_out ), + .valid_o ( w_dp_req_out_valid ), + .ready_i ( w_dp_req_out_ready ) + ); + + // Add fall-through register to allow the input to be ready if the output is not. This + // does not add a cycle of delay + + fall_through_register #( + .T ( read_meta_channel_t ) + ) i_ar_fall_through_register ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .clr_i ( 1'b0 ), + .valid_i ( r_valid ), + .ready_o ( ar_ready ), + .data_i ( r_req.ar_req ), + .valid_o ( ar_valid_dp ), + .ready_i ( ar_ready_dp ), + .data_o ( ar_req_dp ) + ); + + + //-------------------------------------- + // Last flag store + //-------------------------------------- + stream_fifo_optimal_wrap #( + .Depth ( MetaFifoDepth ), + .type_t ( logic [1:0] ), + .PrintInfo ( PrintFifoInfo ) + ) i_w_last ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( {w_req.super_last, w_req.last} ), + .valid_i ( w_valid & w_ready ), + .ready_o ( w_last_ready ), + .data_o ( {w_super_last, w_last_burst} ), + .valid_o ( /* NOT CONNECTED */ ), + .ready_i ( w_dp_rsp_valid & w_dp_rsp_ready ) + ); + + //-------------------------------------- + // Transport Layer / Datapath + //-------------------------------------- + idma_transport_layer_r_obi_w_axi #( + .NumAxInFlight ( NumAxInFlight ), + .DataWidth ( DataWidth ), + .BufferDepth ( BufferDepth ), + .MaskInvalidData ( MaskInvalidData ), + .PrintFifoInfo ( PrintFifoInfo ), + .r_dp_req_t ( r_dp_req_t ), + .w_dp_req_t ( w_dp_req_t ), + .r_dp_rsp_t ( r_dp_rsp_t ), + .w_dp_rsp_t ( w_dp_rsp_t ), + .write_meta_channel_t ( write_meta_channel_t ), + .read_meta_channel_t ( read_meta_channel_t ), + .axi_req_t ( axi_req_t ), + .axi_rsp_t ( axi_rsp_t ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ) + ) i_idma_transport_layer ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .obi_read_req_o ( obi_read_req_o ), + .obi_read_rsp_i ( obi_read_rsp_i ), + .axi_write_req_o ( axi_write_req_o ), + .axi_write_rsp_i ( axi_write_rsp_i ), + .r_dp_req_i ( r_dp_req_out ), + .r_dp_valid_i ( r_dp_req_out_valid ), + .r_dp_ready_o ( r_dp_req_out_ready ), + .r_dp_rsp_o ( r_dp_rsp ), + .r_dp_valid_o ( r_dp_rsp_valid ), + .r_dp_ready_i ( r_dp_rsp_ready ), + .w_dp_req_i ( w_dp_req_out ), + .w_dp_valid_i ( w_dp_req_out_valid ), + .w_dp_ready_o ( w_dp_req_out_ready ), + .w_dp_rsp_o ( w_dp_rsp ), + .w_dp_valid_o ( w_dp_rsp_valid ), + .w_dp_ready_i ( w_dp_rsp_ready ), + .ar_req_i ( ar_req_dp ), + .ar_valid_i ( ar_valid_dp ), + .ar_ready_o ( ar_ready_dp ), + .aw_req_i ( aw_req_dp ), + .aw_valid_i ( aw_valid_dp ), + .aw_ready_o ( aw_ready_dp ), + .dp_poison_i ( dp_poison ), + .r_dp_busy_o ( busy_o.r_dp_busy ), + .w_dp_busy_o ( busy_o.w_dp_busy ), + .buffer_busy_o ( busy_o.buffer_busy ), + .r_chan_ready_o ( r_chan_ready ), + .r_chan_valid_o ( r_chan_valid ) + ); + + //-------------------------------------- + // R-AW channel coupler + //-------------------------------------- + + if (RAWCouplingAvail) begin : gen_r_aw_coupler + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); + end + ) + end else begin : gen_r_aw_bypass + // Add fall-through register to allow the input to be ready if the output is not. This + // does not add a cycle of delay + fall_through_register #( + .T ( write_meta_channel_t ) + ) i_aw_fall_through_register ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .clr_i ( 1'b0 ), + .valid_i ( w_valid ), + .ready_o ( aw_ready ), + .data_i ( w_req.aw_req ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp ), + .data_o ( aw_req_dp ) + ); + + // no unit: not busy + assign busy_o.raw_coupler_busy = 1'b0; + end + + + //-------------------------------------- + // Assertions + //-------------------------------------- + `IDMA_NONSYNTH_BLOCK( + initial begin : proc_assert_params + axi_addr_width : assert(AddrWidth >= 32'd12) else + $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); + axi_id_width : assert(AxiIdWidth > 32'd0) else + $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); + axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, + 32'd512, 32'd1028}) else + $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); + axi_user_width : assert(UserWidth > 32'd0) else + $fatal(1, "Parameter `UserWidth` has to be > 0!"); + num_ax_in_flight : assert(NumAxInFlight > 32'd1) else + $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); + buffer_depth : assert(BufferDepth > 32'd1) else + $fatal(1, "Parameter `BufferDepth` has to be > 1!"); + tf_len_width : assert(TFLenWidth >= 32'd12) else + $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); + tf_len_width_max : assert(TFLenWidth <= AddrWidth) else + $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); + end + ) + +endmodule + +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Authors: +// - Thomas Benz +// - Tobias Senti `include "axi/typedef.svh" `include "idma/guard.svh" /// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_rw_axi #( +module idma_backend_r_axi_w_obi #( /// Data width parameter int unsigned DataWidth = 32'd16, /// Address width @@ -6170,7 +6505,7 @@ module idma_backend_rw_axi #( /// will no longer be word aligned, but only a single shifter is needed parameter bit CombinedShifter = 1'b0, /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 1'b1, + parameter bit RAWCouplingAvail = 1'b0, /// Mask invalid data on the manager interface parameter bit MaskInvalidData = 1'b1, /// Should hardware legalization be present? (recommended) @@ -6194,6 +6529,9 @@ module idma_backend_rw_axi #( /// AXI4+ATOP Request and Response channel type parameter type axi_req_t = logic, parameter type axi_rsp_t = logic, + /// OBI Request and Response channel type + parameter type obi_req_t = logic, + parameter type obi_rsp_t = logic, /// Address Read Channel type parameter type read_meta_channel_t = logic, /// Address Write Channel type @@ -6236,10 +6574,10 @@ module idma_backend_rw_axi #( /// AXI4+ATOP read response input axi_rsp_t axi_read_rsp_i, - /// AXI4+ATOP write request - output axi_req_t axi_write_req_o, - /// AXI4+ATOP write response - input axi_rsp_t axi_write_rsp_i, + /// OBI write request + output obi_req_t obi_write_req_o, + /// OBI write response + input obi_rsp_t obi_write_rsp_i, /// iDMA busy flags output idma_busy_t busy_o @@ -6467,7 +6805,7 @@ module idma_backend_rw_axi #( //-------------------------------------- if (HardwareLegalizer) begin : gen_hw_legalizer // hardware legalizer is present - idma_legalizer_rw_axi #( + idma_legalizer_r_axi_w_obi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -6556,45 +6894,11 @@ module idma_backend_rw_axi #( // Error handler //-------------------------------------- if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler - idma_error_handler #( - .MetaFifoDepth ( MetaFifoDepth ), - .PrintFifoInfo ( PrintFifoInfo ), - .idma_rsp_t ( idma_rsp_t ), - .idma_eh_req_t ( idma_eh_req_t ), - .addr_t ( addr_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .w_dp_rsp_t ( w_dp_rsp_t ) - ) i_idma_error_handler ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .rsp_o ( idma_rsp ), - .rsp_valid_o ( rsp_valid ), - .rsp_ready_i ( rsp_ready ), - .req_valid_i ( req_valid ), - .req_ready_i ( req_ready_o ), - .eh_i ( idma_eh_req_i ), - .eh_valid_i ( eh_req_valid_i ), - .eh_ready_o ( eh_req_ready_o ), - .r_addr_i ( r_req.ar_req.axi.ar_chan.addr ), - .w_addr_i ( w_req.aw_req.axi.aw_chan.addr ), - .r_consume_i ( r_valid & r_ready ), - .w_consume_i ( w_valid & w_ready ), - .legalizer_flush_o ( legalizer_flush ), - .legalizer_kill_o ( legalizer_kill ), - .dp_busy_i ( dp_busy ), - .dp_poison_o ( dp_poison ), - .r_dp_rsp_i ( r_dp_rsp ), - .r_dp_valid_i ( r_dp_rsp_valid ), - .r_dp_ready_o ( r_dp_rsp_ready ), - .w_dp_rsp_i ( w_dp_rsp ), - .w_dp_valid_i ( w_dp_rsp_valid ), - .w_dp_ready_o ( w_dp_rsp_ready ), - .w_last_burst_i ( w_last_burst ), - .w_super_last_i ( w_super_last ), - .fsm_busy_o ( busy_o.eh_fsm_busy ), - .cnt_busy_o ( busy_o.eh_cnt_busy ) - ); + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Error Handling only implemented for AXI to AXI DMA!"); + end + ) end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler // bypass the signals, assign their neutral values assign idma_rsp.error = 1'b0; @@ -6709,7 +7013,7 @@ module idma_backend_rw_axi #( //-------------------------------------- // Transport Layer / Datapath //-------------------------------------- - idma_transport_layer_rw_axi #( + idma_transport_layer_r_axi_w_obi #( .NumAxInFlight ( NumAxInFlight ), .DataWidth ( DataWidth ), .BufferDepth ( BufferDepth ), @@ -6722,15 +7026,17 @@ module idma_backend_rw_axi #( .write_meta_channel_t ( write_meta_channel_t ), .read_meta_channel_t ( read_meta_channel_t ), .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ) + .axi_rsp_t ( axi_rsp_t ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ) ) i_idma_transport_layer ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .testmode_i ( testmode_i ), .axi_read_req_o ( axi_read_req_o ), .axi_read_rsp_i ( axi_read_rsp_i ), - .axi_write_req_o ( axi_write_req_o ), - .axi_write_rsp_i ( axi_write_rsp_i ), + .obi_write_req_o ( obi_write_req_o ), + .obi_write_rsp_i ( obi_write_rsp_i ), .r_dp_req_i ( r_dp_req_out ), .r_dp_valid_i ( r_dp_req_out_valid ), .r_dp_ready_o ( r_dp_req_out_ready ), @@ -6762,47 +7068,30 @@ module idma_backend_rw_axi #( //-------------------------------------- if (RAWCouplingAvail) begin : gen_r_aw_coupler - // instantiate the channel coupler - idma_channel_coupler #( - .NumAxInFlight ( NumAxInFlight ), - .AddrWidth ( AddrWidth ), - .UserWidth ( UserWidth ), - .AxiIdWidth ( AxiIdWidth ), - .PrintFifoInfo ( PrintFifoInfo ), - .axi_aw_chan_t ( write_meta_channel_t ) - ) i_idma_channel_coupler ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .r_rsp_valid_i ( r_chan_valid ), - .r_rsp_ready_i ( r_chan_ready ), - .r_rsp_first_i ( r_dp_rsp.first ), - .r_decouple_aw_i ( r_dp_req_out.decouple_aw ), - .aw_decouple_aw_i ( w_req.decouple_aw ), - .aw_req_i ( w_req.aw_req ), - .aw_valid_i ( w_valid ), - .aw_ready_o ( aw_ready ), - .aw_req_o ( aw_req_dp ), - .aw_valid_o ( aw_valid_dp ), - .aw_ready_i ( aw_ready_dp ), - .busy_o ( busy_o.raw_coupler_busy ) - ); + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); + end + ) end else begin : gen_r_aw_bypass - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - fall_through_register #( - .T ( write_meta_channel_t ) - ) i_aw_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( w_valid ), - .ready_o ( aw_ready ), - .data_i ( w_req.aw_req ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp ), - .data_o ( aw_req_dp ) + // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests + // As a write could depend on up to two reads + stream_fifo_optimal_wrap #( + .Depth ( 2 ), + .type_t ( write_meta_channel_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_aw_fifo ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( w_req.aw_req ), + .valid_i ( w_valid && aw_ready ), + .ready_o ( aw_ready ), + .data_o ( aw_req_dp ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp && aw_valid_dp ) ); // no unit: not busy @@ -6849,7 +7138,7 @@ endmodule `include "idma/guard.svh" /// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_r_obi_w_axi #( +module idma_backend_rw_axi_rw_axis #( /// Data width parameter int unsigned DataWidth = 32'd16, /// Address width @@ -6897,9 +7186,9 @@ module idma_backend_r_obi_w_axi #( /// AXI4+ATOP Request and Response channel type parameter type axi_req_t = logic, parameter type axi_rsp_t = logic, - /// OBI Request and Response channel type - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, + /// AXI Stream Request and Response channel type + parameter type axis_req_t = logic, + parameter type axis_rsp_t = logic, /// Address Read Channel type parameter type read_meta_channel_t = logic, /// Address Write Channel type @@ -6937,16 +7226,26 @@ module idma_backend_r_obi_w_axi #( /// Error handler request ready output logic eh_req_ready_o, - /// OBI read request - output obi_req_t obi_read_req_o, - /// OBI read response - input obi_rsp_t obi_read_rsp_i, + /// AXI4+ATOP read request + output axi_req_t axi_read_req_o, + /// AXI4+ATOP read response + input axi_rsp_t axi_read_rsp_i, + + /// AXI Stream read request + input axis_req_t axis_read_req_i, + /// AXI Stream read response + output axis_rsp_t axis_read_rsp_o, /// AXI4+ATOP write request output axi_req_t axi_write_req_o, /// AXI4+ATOP write response input axi_rsp_t axi_write_rsp_i, + /// AXI Stream write request + output axis_req_t axis_write_req_o, + /// AXI Stream write response + input axis_rsp_t axis_write_rsp_i, + /// iDMA busy flags output idma_busy_t busy_o ); @@ -7027,6 +7326,10 @@ module idma_backend_r_obi_w_axi #( r_dp_req_t r_dp_req; read_meta_channel_t ar_req; } idma_r_req_t; + typedef struct packed { + idma_pkg::protocol_e src_protocol; + read_meta_channel_t ar_req; + } read_meta_channel_tagged_t; /// The iDMA write request bundles an `AW` type and a datapath write response type together. It /// has an additional flags: @@ -7041,6 +7344,10 @@ module idma_backend_r_obi_w_axi #( logic super_last; logic decouple_aw; } idma_w_req_t; + typedef struct packed { + idma_pkg::protocol_e dst_protocol; + write_meta_channel_t aw_req; + } write_meta_channel_tagged_t; /// The mutable transfer options type holds important information that is mutated by the /// `legalizer` block. @@ -7082,6 +7389,8 @@ module idma_backend_r_obi_w_axi #( idma_w_req_t w_req; logic r_valid, w_valid; logic r_ready, w_ready; + read_meta_channel_tagged_t r_meta_req_tagged; + write_meta_channel_tagged_t w_meta_req_tagged; // It the current transfer the last burst in the 1D transfer? logic w_last_burst; @@ -7110,10 +7419,10 @@ module idma_backend_r_obi_w_axi #( logic aw_valid_dp, ar_valid_dp; // Ax request from R-AW coupler to datapath - write_meta_channel_t aw_req_dp; + write_meta_channel_tagged_t aw_req_dp; // Ax request from the decoupling stage to the datapath - read_meta_channel_t ar_req_dp; + read_meta_channel_tagged_t ar_req_dp; // flush and preemptively empty the legalizer logic legalizer_flush, legalizer_kill; @@ -7173,7 +7482,7 @@ module idma_backend_r_obi_w_axi #( //-------------------------------------- if (HardwareLegalizer) begin : gen_hw_legalizer // hardware legalizer is present - idma_legalizer_r_obi_w_axi #( + idma_legalizer_rw_axi_rw_axis #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -7340,9 +7649,13 @@ module idma_backend_r_obi_w_axi #( // Add fall-through register to allow the input to be ready if the output is not. This // does not add a cycle of delay + assign r_meta_req_tagged = '{ + src_protocol: r_req.r_dp_req.src_protocol, + ar_req: r_req.ar_req + }; fall_through_register #( - .T ( read_meta_channel_t ) + .T ( read_meta_channel_tagged_t ) ) i_ar_fall_through_register ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -7350,7 +7663,7 @@ module idma_backend_r_obi_w_axi #( .clr_i ( 1'b0 ), .valid_i ( r_valid ), .ready_o ( ar_ready ), - .data_i ( r_req.ar_req ), + .data_i ( r_meta_req_tagged ), .valid_o ( ar_valid_dp ), .ready_i ( ar_ready_dp ), .data_o ( ar_req_dp ) @@ -7381,7 +7694,7 @@ module idma_backend_r_obi_w_axi #( //-------------------------------------- // Transport Layer / Datapath //-------------------------------------- - idma_transport_layer_r_obi_w_axi #( + idma_transport_layer_rw_axi_rw_axis #( .NumAxInFlight ( NumAxInFlight ), .DataWidth ( DataWidth ), .BufferDepth ( BufferDepth ), @@ -7392,19 +7705,25 @@ module idma_backend_r_obi_w_axi #( .r_dp_rsp_t ( r_dp_rsp_t ), .w_dp_rsp_t ( w_dp_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), + .write_meta_channel_tagged_t ( write_meta_channel_tagged_t ), .read_meta_channel_t ( read_meta_channel_t ), + .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ) + .axis_req_t ( axis_req_t ), + .axis_rsp_t ( axis_rsp_t ) ) i_idma_transport_layer ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .testmode_i ( testmode_i ), - .obi_read_req_o ( obi_read_req_o ), - .obi_read_rsp_i ( obi_read_rsp_i ), + .axi_read_req_o ( axi_read_req_o ), + .axi_read_rsp_i ( axi_read_rsp_i ), + .axis_read_req_i ( axis_read_req_i ), + .axis_read_rsp_o ( axis_read_rsp_o ), .axi_write_req_o ( axi_write_req_o ), .axi_write_rsp_i ( axi_write_rsp_i ), + .axis_write_req_o ( axis_write_req_o ), + .axis_write_rsp_i ( axis_write_rsp_i ), .r_dp_req_i ( r_dp_req_out ), .r_dp_valid_i ( r_dp_req_out_valid ), .r_dp_ready_o ( r_dp_req_out_ready ), @@ -7434,6 +7753,10 @@ module idma_backend_r_obi_w_axi #( //-------------------------------------- // R-AW channel coupler //-------------------------------------- + assign w_meta_req_tagged = '{ + dst_protocol: w_req.w_dp_req.dst_protocol, + aw_req: w_req.aw_req + }; if (RAWCouplingAvail) begin : gen_r_aw_coupler `IDMA_NONSYNTH_BLOCK( @@ -7442,21 +7765,24 @@ module idma_backend_r_obi_w_axi #( end ) end else begin : gen_r_aw_bypass - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - fall_through_register #( - .T ( write_meta_channel_t ) - ) i_aw_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( w_valid ), - .ready_o ( aw_ready ), - .data_i ( w_req.aw_req ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp ), - .data_o ( aw_req_dp ) + // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests + // As a write could depend on up to two reads + stream_fifo_optimal_wrap #( + .Depth ( 2 ), + .type_t ( write_meta_channel_tagged_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_aw_fifo ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( w_meta_req_tagged ), + .valid_i ( w_valid && aw_ready ), + .ready_o ( aw_ready ), + .data_o ( aw_req_dp ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp && aw_valid_dp ) ); // no unit: not busy @@ -7503,7 +7829,7 @@ endmodule `include "idma/guard.svh" /// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_r_axi_w_obi #( +module idma_backend_r_obi_rw_init_w_axi #( /// Data width parameter int unsigned DataWidth = 32'd16, /// Address width @@ -7551,6 +7877,9 @@ module idma_backend_r_axi_w_obi #( /// AXI4+ATOP Request and Response channel type parameter type axi_req_t = logic, parameter type axi_rsp_t = logic, + /// Memory Init Request and Response channel type + parameter type init_req_t = logic, + parameter type init_rsp_t = logic, /// OBI Request and Response channel type parameter type obi_req_t = logic, parameter type obi_rsp_t = logic, @@ -7591,15 +7920,25 @@ module idma_backend_r_axi_w_obi #( /// Error handler request ready output logic eh_req_ready_o, - /// AXI4+ATOP read request - output axi_req_t axi_read_req_o, - /// AXI4+ATOP read response - input axi_rsp_t axi_read_rsp_i, + /// Memory Init read request + output init_req_t init_read_req_o, + /// Memory Init read response + input init_rsp_t init_read_rsp_i, - /// OBI write request - output obi_req_t obi_write_req_o, - /// OBI write response - input obi_rsp_t obi_write_rsp_i, + /// OBI read request + output obi_req_t obi_read_req_o, + /// OBI read response + input obi_rsp_t obi_read_rsp_i, + + /// AXI4+ATOP write request + output axi_req_t axi_write_req_o, + /// AXI4+ATOP write response + input axi_rsp_t axi_write_rsp_i, + + /// Memory Init write request + output init_req_t init_write_req_o, + /// Memory Init write response + input init_rsp_t init_write_rsp_i, /// iDMA busy flags output idma_busy_t busy_o @@ -7681,6 +8020,10 @@ module idma_backend_r_axi_w_obi #( r_dp_req_t r_dp_req; read_meta_channel_t ar_req; } idma_r_req_t; + typedef struct packed { + idma_pkg::protocol_e src_protocol; + read_meta_channel_t ar_req; + } read_meta_channel_tagged_t; /// The iDMA write request bundles an `AW` type and a datapath write response type together. It /// has an additional flags: @@ -7695,6 +8038,10 @@ module idma_backend_r_axi_w_obi #( logic super_last; logic decouple_aw; } idma_w_req_t; + typedef struct packed { + idma_pkg::protocol_e dst_protocol; + write_meta_channel_t aw_req; + } write_meta_channel_tagged_t; /// The mutable transfer options type holds important information that is mutated by the /// `legalizer` block. @@ -7736,6 +8083,8 @@ module idma_backend_r_axi_w_obi #( idma_w_req_t w_req; logic r_valid, w_valid; logic r_ready, w_ready; + read_meta_channel_tagged_t r_meta_req_tagged; + write_meta_channel_tagged_t w_meta_req_tagged; // It the current transfer the last burst in the 1D transfer? logic w_last_burst; @@ -7764,10 +8113,10 @@ module idma_backend_r_axi_w_obi #( logic aw_valid_dp, ar_valid_dp; // Ax request from R-AW coupler to datapath - write_meta_channel_t aw_req_dp; + write_meta_channel_tagged_t aw_req_dp; // Ax request from the decoupling stage to the datapath - read_meta_channel_t ar_req_dp; + read_meta_channel_tagged_t ar_req_dp; // flush and preemptively empty the legalizer logic legalizer_flush, legalizer_kill; @@ -7827,7 +8176,7 @@ module idma_backend_r_axi_w_obi #( //-------------------------------------- if (HardwareLegalizer) begin : gen_hw_legalizer // hardware legalizer is present - idma_legalizer_r_axi_w_obi #( + idma_legalizer_r_obi_rw_init_w_axi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -7994,9 +8343,13 @@ module idma_backend_r_axi_w_obi #( // Add fall-through register to allow the input to be ready if the output is not. This // does not add a cycle of delay + assign r_meta_req_tagged = '{ + src_protocol: r_req.r_dp_req.src_protocol, + ar_req: r_req.ar_req + }; fall_through_register #( - .T ( read_meta_channel_t ) + .T ( read_meta_channel_tagged_t ) ) i_ar_fall_through_register ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -8004,7 +8357,7 @@ module idma_backend_r_axi_w_obi #( .clr_i ( 1'b0 ), .valid_i ( r_valid ), .ready_o ( ar_ready ), - .data_i ( r_req.ar_req ), + .data_i ( r_meta_req_tagged ), .valid_o ( ar_valid_dp ), .ready_i ( ar_ready_dp ), .data_o ( ar_req_dp ) @@ -8035,7 +8388,7 @@ module idma_backend_r_axi_w_obi #( //-------------------------------------- // Transport Layer / Datapath //-------------------------------------- - idma_transport_layer_r_axi_w_obi #( + idma_transport_layer_r_obi_rw_init_w_axi #( .NumAxInFlight ( NumAxInFlight ), .DataWidth ( DataWidth ), .BufferDepth ( BufferDepth ), @@ -8046,19 +8399,27 @@ module idma_backend_r_axi_w_obi #( .r_dp_rsp_t ( r_dp_rsp_t ), .w_dp_rsp_t ( w_dp_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), + .write_meta_channel_tagged_t ( write_meta_channel_tagged_t ), .read_meta_channel_t ( read_meta_channel_t ), + .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), + .init_req_t ( init_req_t ), + .init_rsp_t ( init_rsp_t ), .obi_req_t ( obi_req_t ), .obi_rsp_t ( obi_rsp_t ) ) i_idma_transport_layer ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .testmode_i ( testmode_i ), - .axi_read_req_o ( axi_read_req_o ), - .axi_read_rsp_i ( axi_read_rsp_i ), - .obi_write_req_o ( obi_write_req_o ), - .obi_write_rsp_i ( obi_write_rsp_i ), + .init_read_req_o ( init_read_req_o ), + .init_read_rsp_i ( init_read_rsp_i ), + .obi_read_req_o ( obi_read_req_o ), + .obi_read_rsp_i ( obi_read_rsp_i ), + .axi_write_req_o ( axi_write_req_o ), + .axi_write_rsp_i ( axi_write_rsp_i ), + .init_write_req_o ( init_write_req_o ), + .init_write_rsp_i ( init_write_rsp_i ), .r_dp_req_i ( r_dp_req_out ), .r_dp_valid_i ( r_dp_req_out_valid ), .r_dp_ready_o ( r_dp_req_out_ready ), @@ -8088,6 +8449,10 @@ module idma_backend_r_axi_w_obi #( //-------------------------------------- // R-AW channel coupler //-------------------------------------- + assign w_meta_req_tagged = '{ + dst_protocol: w_req.w_dp_req.dst_protocol, + aw_req: w_req.aw_req + }; if (RAWCouplingAvail) begin : gen_r_aw_coupler `IDMA_NONSYNTH_BLOCK( @@ -8096,25 +8461,22 @@ module idma_backend_r_axi_w_obi #( end ) end else begin : gen_r_aw_bypass - // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests - // As a write could depend on up to two reads - stream_fifo_optimal_wrap #( - .Depth ( 2 ), - .type_t ( write_meta_channel_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_aw_fifo ( - .clk_i, - .rst_ni, - .testmode_i, - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_req.aw_req ), - .valid_i ( w_valid && aw_ready ), - .ready_o ( aw_ready ), - .data_o ( aw_req_dp ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp && aw_valid_dp ) - ); + // Add fall-through register to allow the input to be ready if the output is not. This + // does not add a cycle of delay + fall_through_register #( + .T ( write_meta_channel_tagged_t ) + ) i_aw_fall_through_register ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .clr_i ( 1'b0 ), + .valid_i ( w_valid ), + .ready_o ( aw_ready ), + .data_i ( w_meta_req_tagged ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp ), + .data_o ( aw_req_dp ) + ); // no unit: not busy assign busy_o.raw_coupler_busy = 1'b0; @@ -8160,7 +8522,7 @@ endmodule `include "idma/guard.svh" /// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_rw_axi_rw_axis #( +module idma_backend_r_axi_rw_init_rw_obi #( /// Data width parameter int unsigned DataWidth = 32'd16, /// Address width @@ -8208,9 +8570,12 @@ module idma_backend_rw_axi_rw_axis #( /// AXI4+ATOP Request and Response channel type parameter type axi_req_t = logic, parameter type axi_rsp_t = logic, - /// AXI Stream Request and Response channel type - parameter type axis_req_t = logic, - parameter type axis_rsp_t = logic, + /// Memory Init Request and Response channel type + parameter type init_req_t = logic, + parameter type init_rsp_t = logic, + /// OBI Request and Response channel type + parameter type obi_req_t = logic, + parameter type obi_rsp_t = logic, /// Address Read Channel type parameter type read_meta_channel_t = logic, /// Address Write Channel type @@ -8253,20 +8618,25 @@ module idma_backend_rw_axi_rw_axis #( /// AXI4+ATOP read response input axi_rsp_t axi_read_rsp_i, - /// AXI Stream read request - input axis_req_t axis_read_req_i, - /// AXI Stream read response - output axis_rsp_t axis_read_rsp_o, + /// Memory Init read request + output init_req_t init_read_req_o, + /// Memory Init read response + input init_rsp_t init_read_rsp_i, - /// AXI4+ATOP write request - output axi_req_t axi_write_req_o, - /// AXI4+ATOP write response - input axi_rsp_t axi_write_rsp_i, + /// OBI read request + output obi_req_t obi_read_req_o, + /// OBI read response + input obi_rsp_t obi_read_rsp_i, - /// AXI Stream write request - output axis_req_t axis_write_req_o, - /// AXI Stream write response - input axis_rsp_t axis_write_rsp_i, + /// Memory Init write request + output init_req_t init_write_req_o, + /// Memory Init write response + input init_rsp_t init_write_rsp_i, + + /// OBI write request + output obi_req_t obi_write_req_o, + /// OBI write response + input obi_rsp_t obi_write_rsp_i, /// iDMA busy flags output idma_busy_t busy_o @@ -8504,7 +8874,7 @@ module idma_backend_rw_axi_rw_axis #( //-------------------------------------- if (HardwareLegalizer) begin : gen_hw_legalizer // hardware legalizer is present - idma_legalizer_rw_axi_rw_axis #( + idma_legalizer_r_axi_rw_init_rw_obi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -8716,7 +9086,7 @@ module idma_backend_rw_axi_rw_axis #( //-------------------------------------- // Transport Layer / Datapath //-------------------------------------- - idma_transport_layer_rw_axi_rw_axis #( + idma_transport_layer_r_axi_rw_init_rw_obi #( .NumAxInFlight ( NumAxInFlight ), .DataWidth ( DataWidth ), .BufferDepth ( BufferDepth ), @@ -8732,20 +9102,24 @@ module idma_backend_rw_axi_rw_axis #( .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), - .axis_req_t ( axis_req_t ), - .axis_rsp_t ( axis_rsp_t ) + .init_req_t ( init_req_t ), + .init_rsp_t ( init_rsp_t ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ) ) i_idma_transport_layer ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .testmode_i ( testmode_i ), .axi_read_req_o ( axi_read_req_o ), .axi_read_rsp_i ( axi_read_rsp_i ), - .axis_read_req_i ( axis_read_req_i ), - .axis_read_rsp_o ( axis_read_rsp_o ), - .axi_write_req_o ( axi_write_req_o ), - .axi_write_rsp_i ( axi_write_rsp_i ), - .axis_write_req_o ( axis_write_req_o ), - .axis_write_rsp_i ( axis_write_rsp_i ), + .init_read_req_o ( init_read_req_o ), + .init_read_rsp_i ( init_read_rsp_i ), + .obi_read_req_o ( obi_read_req_o ), + .obi_read_rsp_i ( obi_read_rsp_i ), + .init_write_req_o ( init_write_req_o ), + .init_write_rsp_i ( init_write_rsp_i ), + .obi_write_req_o ( obi_write_req_o ), + .obi_write_rsp_i ( obi_write_rsp_i ), .r_dp_req_i ( r_dp_req_out ), .r_dp_valid_i ( r_dp_req_out_valid ), .r_dp_ready_o ( r_dp_req_out_ready ), @@ -8764,2537 +9138,78 @@ module idma_backend_rw_axi_rw_axis #( .aw_req_i ( aw_req_dp ), .aw_valid_i ( aw_valid_dp ), .aw_ready_o ( aw_ready_dp ), - .dp_poison_i ( dp_poison ), - .r_dp_busy_o ( busy_o.r_dp_busy ), - .w_dp_busy_o ( busy_o.w_dp_busy ), - .buffer_busy_o ( busy_o.buffer_busy ), - .r_chan_ready_o ( r_chan_ready ), - .r_chan_valid_o ( r_chan_valid ) - ); - - //-------------------------------------- - // R-AW channel coupler - //-------------------------------------- - assign w_meta_req_tagged = '{ - dst_protocol: w_req.w_dp_req.dst_protocol, - aw_req: w_req.aw_req - }; - - if (RAWCouplingAvail) begin : gen_r_aw_coupler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); - end - ) - end else begin : gen_r_aw_bypass - // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests - // As a write could depend on up to two reads - stream_fifo_optimal_wrap #( - .Depth ( 2 ), - .type_t ( write_meta_channel_tagged_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_aw_fifo ( - .clk_i, - .rst_ni, - .testmode_i, - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_meta_req_tagged ), - .valid_i ( w_valid && aw_ready ), - .ready_o ( aw_ready ), - .data_o ( aw_req_dp ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp && aw_valid_dp ) - ); - - // no unit: not busy - assign busy_o.raw_coupler_busy = 1'b0; - end - - - //-------------------------------------- - // Assertions - //-------------------------------------- - `IDMA_NONSYNTH_BLOCK( - initial begin : proc_assert_params - axi_addr_width : assert(AddrWidth >= 32'd12) else - $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); - axi_id_width : assert(AxiIdWidth > 32'd0) else - $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); - axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, - 32'd512, 32'd1028}) else - $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); - axi_user_width : assert(UserWidth > 32'd0) else - $fatal(1, "Parameter `UserWidth` has to be > 0!"); - num_ax_in_flight : assert(NumAxInFlight > 32'd1) else - $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); - buffer_depth : assert(BufferDepth > 32'd1) else - $fatal(1, "Parameter `BufferDepth` has to be > 1!"); - tf_len_width : assert(TFLenWidth >= 32'd12) else - $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); - tf_len_width_max : assert(TFLenWidth <= AddrWidth) else - $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); - end - ) - -endmodule - -// Copyright 2023 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Authors: -// - Thomas Benz -// - Tobias Senti - -`include "axi/typedef.svh" -`include "idma/guard.svh" - -/// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_rw_axi_rw_obi #( - /// Data width - parameter int unsigned DataWidth = 32'd16, - /// Address width - parameter int unsigned AddrWidth = 32'd24, - /// AXI user width - parameter int unsigned UserWidth = 32'd1, - /// AXI ID width - parameter int unsigned AxiIdWidth = 32'd1, - /// Number of transaction that can be in-flight concurrently - parameter int unsigned NumAxInFlight = 32'd2, - /// The depth of the internal reorder buffer: - /// - '2': minimal possible configuration - /// - '3': efficiently handle misaligned transfers (recommended) - parameter int unsigned BufferDepth = 32'd2, - /// With of a transfer: max transfer size is `2**TFLenWidth` bytes - parameter int unsigned TFLenWidth = 32'd24, - /// The depth of the memory system the backend is attached to - parameter int unsigned MemSysDepth = 32'd0, - /// Should both data shifts be done before the dataflow element? - /// If this is enabled, then the data inserted into the dataflow element - /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 1'b0, - /// Mask invalid data on the manager interface - parameter bit MaskInvalidData = 1'b1, - /// Should hardware legalization be present? (recommended) - /// If not, software legalization is required to ensure the transfers are - /// AXI4-conformal - parameter bit HardwareLegalizer = 1'b1, - /// Reject zero-length transfers - parameter bit RejectZeroTransfers = 1'b1, - /// Should the error handler be present? - parameter idma_pkg::error_cap_e ErrorCap = idma_pkg::NO_ERROR_HANDLING, - /// Print the info of the FIFO configuration - parameter bit PrintFifoInfo = 1'b0, - /// 1D iDMA request type - parameter type idma_req_t = logic, - /// iDMA response type - parameter type idma_rsp_t = logic, - /// Error Handler request type - parameter type idma_eh_req_t = logic, - /// iDMA busy signal - parameter type idma_busy_t = logic, - /// AXI4+ATOP Request and Response channel type - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic, - /// OBI Request and Response channel type - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, - /// Address Read Channel type - parameter type read_meta_channel_t = logic, - /// Address Write Channel type - parameter type write_meta_channel_t = logic, - /// Strobe Width (do not override!) - parameter int unsigned StrbWidth = DataWidth / 8, - /// Offset Width (do not override!) - parameter int unsigned OffsetWidth = $clog2(StrbWidth) -)( - /// Clock - input logic clk_i, - /// Asynchronous reset, active low - input logic rst_ni, - /// Testmode in - input logic testmode_i, - - /// 1D iDMA request - input idma_req_t idma_req_i, - /// 1D iDMA request valid - input logic req_valid_i, - /// 1D iDMA request ready - output logic req_ready_o, - - /// iDMA response - output idma_rsp_t idma_rsp_o, - /// iDMA response valid - output logic rsp_valid_o, - /// iDMA response ready - input logic rsp_ready_i, - - /// Error handler request - input idma_eh_req_t idma_eh_req_i, - /// Error handler request valid - input logic eh_req_valid_i, - /// Error handler request ready - output logic eh_req_ready_o, - - /// AXI4+ATOP read request - output axi_req_t axi_read_req_o, - /// AXI4+ATOP read response - input axi_rsp_t axi_read_rsp_i, - - /// OBI read request - output obi_req_t obi_read_req_o, - /// OBI read response - input obi_rsp_t obi_read_rsp_i, - - /// AXI4+ATOP write request - output axi_req_t axi_write_req_o, - /// AXI4+ATOP write response - input axi_rsp_t axi_write_rsp_i, - - /// OBI write request - output obi_req_t obi_write_req_o, - /// OBI write response - input obi_rsp_t obi_write_rsp_i, - - /// iDMA busy flags - output idma_busy_t busy_o -); - - /// The localparam MetaFifoDepth holds the maximum number of transfers that can be - /// in-flight under any circumstances. - localparam int unsigned MetaFifoDepth = BufferDepth + NumAxInFlight + MemSysDepth; - - /// Address type - typedef logic [AddrWidth-1:0] addr_t; - /// DAta type - typedef logic [DataWidth-1:0] data_t; - /// Strobe type - typedef logic [StrbWidth-1:0] strb_t; - /// User type - typedef logic [UserWidth-1:0] user_t; - /// ID type - typedef logic [AxiIdWidth-1:0] id_t; - /// Offset type - typedef logic [OffsetWidth-1:0] offset_t; - /// Transfer length type - typedef logic [TFLenWidth-1:0] tf_len_t; - - /// The datapath read request type holds all the information required to configure the read - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the read - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `decouple_aw`: If the transfer has the AW decoupled from the R - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e src_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - logic decouple_aw; - logic is_single; - } r_dp_req_t; - - /// The datapath read response type provides feedback from the read part of the datapath: - /// - `resp`: The response from the R channel of the AXI4 manager interface - /// - `last`: The last flag from the R channel of the AXI4 manager interface - /// - `first`: Is the current item first beat in the burst - typedef struct packed { - axi_pkg::resp_t resp; - logic last; - logic first; - } r_dp_rsp_t; - - /// The datapath write request type holds all the information required to configure the write - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the write - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `num_beats`: The number of beats this burst consist of - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - axi_pkg::len_t num_beats; - logic is_single; - } w_dp_req_t; - - /// The datapath write response type provides feedback from the write part of the datapath: - /// - `resp`: The response from the B channel of the AXI4 manager interface - /// - `user`: The user field from the B channel of the AXI4 manager interface - typedef struct packed { - axi_pkg::resp_t resp; - user_t user; - } w_dp_rsp_t; - - /// The iDMA read request bundles an `AR` type and a datapath read response type together. - typedef struct packed { - r_dp_req_t r_dp_req; - read_meta_channel_t ar_req; - } idma_r_req_t; - typedef struct packed { - idma_pkg::protocol_e src_protocol; - read_meta_channel_t ar_req; - } read_meta_channel_tagged_t; - - /// The iDMA write request bundles an `AW` type and a datapath write response type together. It - /// has an additional flags: - /// - `last`: indicating the current burst is the last one of the generic 1D transfer currently - /// being processed - /// - `midend_last`: The current transfer is marked by the controlling as last - /// - `decouple_aw`: indicates this is an R-AW decoupled transfer - typedef struct packed { - w_dp_req_t w_dp_req; - write_meta_channel_t aw_req; - logic last; - logic super_last; - logic decouple_aw; - } idma_w_req_t; - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - write_meta_channel_t aw_req; - } write_meta_channel_tagged_t; - - /// The mutable transfer options type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - idma_pkg::protocol_e src_protocol; - idma_pkg::protocol_e dst_protocol; - offset_t read_shift; - offset_t write_shift; - logic decouple_rw; - logic decouple_aw; - logic [2:0] src_max_llen; - logic [2:0] dst_max_llen; - logic src_reduce_len; - logic dst_reduce_len; - id_t axi_id; - idma_pkg::axi_options_t src_axi_opt; - idma_pkg::axi_options_t dst_axi_opt; - logic super_last; - } idma_mut_tf_opt_t; - - /// The mutable transfer type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - tf_len_t length; - addr_t addr; - logic valid; - addr_t base_addr; - } idma_mut_tf_t; - - - // datapath busy indicates the datapath is actively working on a transfer. It is composed of - // the activity of the buffer as well as both the read and write machines - logic dp_busy; - // blanks invalid data - logic dp_poison; - - // read and write requests and their handshaking signals - idma_r_req_t r_req; - idma_w_req_t w_req; - logic r_valid, w_valid; - logic r_ready, w_ready; - read_meta_channel_tagged_t r_meta_req_tagged; - write_meta_channel_tagged_t w_meta_req_tagged; - - // It the current transfer the last burst in the 1D transfer? - logic w_last_burst; - logic w_last_ready; - - // Super last flag: The current transfer is indicated as the last one by the controlling - // unit; e.g. by a midend - logic w_super_last; - - // Datapath FIFO signals -> used to decouple legalizer and datapath - logic r_dp_req_in_ready, w_dp_req_in_ready; - logic r_dp_req_out_valid, w_dp_req_out_valid; - logic r_dp_req_out_ready, w_dp_req_out_ready; - r_dp_req_t r_dp_req_out; - w_dp_req_t w_dp_req_out; - - // datapah responses - r_dp_rsp_t r_dp_rsp; - w_dp_rsp_t w_dp_rsp; - logic r_dp_rsp_valid, w_dp_rsp_valid; - logic r_dp_rsp_ready, w_dp_rsp_ready; - - // Ax handshaking - logic ar_ready, ar_ready_dp; - logic aw_ready, aw_ready_dp; - logic aw_valid_dp, ar_valid_dp; - - // Ax request from R-AW coupler to datapath - write_meta_channel_tagged_t aw_req_dp; - - // Ax request from the decoupling stage to the datapath - read_meta_channel_tagged_t ar_req_dp; - - // flush and preemptively empty the legalizer - logic legalizer_flush, legalizer_kill; - - /// intermediate signals to reject zero length transfers - logic is_length_zero; - logic req_valid; - idma_rsp_t idma_rsp; - logic rsp_valid; - logic rsp_ready; - - // Respone Channel valid and ready -> needed for bursting - logic r_chan_valid; - logic r_chan_ready; - - //-------------------------------------- - // Reject Zero Length Transfers - //-------------------------------------- - if (RejectZeroTransfers) begin : gen_reject_zero_transfers - // is the current transfer length 0? - assign is_length_zero = idma_req_i.length == '0; - - // bypass valid as long as length is not zero, otherwise suppress it - assign req_valid = is_length_zero ? 1'b0 : req_valid_i; - - // modify response - always_comb begin : proc_modify_response_zero_length - // default: bypass - idma_rsp_o = idma_rsp; - rsp_ready = rsp_ready_i; - rsp_valid_o = rsp_valid; - - // a zero transfer happens - if (is_length_zero & req_valid_i & req_ready_o) begin - // block backend - rsp_ready = 1'b0; - // generate new response - rsp_valid_o = 1'b1; - idma_rsp_o = '0; - idma_rsp_o.error = 1'b1; - idma_rsp_o.pld.err_type = idma_pkg::BACKEND; - end - end - - // just bypass signals - end else begin : gen_bypass_zero_transfers - // bypass - assign req_valid = req_valid_i; - assign idma_rsp_o = idma_rsp; - assign rsp_ready = rsp_ready_i; - assign rsp_valid_o = rsp_valid; - end - - - //-------------------------------------- - // Legalization - //-------------------------------------- - if (HardwareLegalizer) begin : gen_hw_legalizer - // hardware legalizer is present - idma_legalizer_rw_axi_rw_obi #( - .CombinedShifter ( CombinedShifter ), - .DataWidth ( DataWidth ), - .AddrWidth ( AddrWidth ), - .idma_req_t ( idma_req_t ), - .idma_r_req_t ( idma_r_req_t ), - .idma_w_req_t ( idma_w_req_t ), - .idma_mut_tf_t ( idma_mut_tf_t ), - .idma_mut_tf_opt_t ( idma_mut_tf_opt_t ) - ) i_idma_legalizer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .req_i ( idma_req_i ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .r_req_o ( r_req ), - .w_req_o ( w_req ), - .r_valid_o ( r_valid ), - .w_valid_o ( w_valid ), - .r_ready_i ( r_ready ), - .w_ready_i ( w_ready ), - .flush_i ( legalizer_flush ), - .kill_i ( legalizer_kill ), - .r_busy_o ( busy_o.r_leg_busy ), - .w_busy_o ( busy_o.w_leg_busy ) - ); - - end else begin : gen_no_hw_legalizer - // stream fork is used to synchronize the two decoupled channels without the need for a - // FIFO here. - stream_fork #( - .N_OUP ( 32'd2 ) - ) i_stream_fork ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .valid_o ( { r_valid, w_valid } ), - .ready_i ( { r_ready, w_ready } ) - ); - - // local signal holding the length -> explicitly only doing the computation once - axi_pkg::len_t len; - assign len = ((idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0] - - 'd1) >> OffsetWidth); - - // assemble read datapath request - assign r_req.r_dp_req = '{ - src_protocol: idma_req_i.opt.src_protocol, - offset: idma_req_i.src_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(idma_req_i.src_addr[OffsetWidth-1:0]), - decouple_aw: idma_req_i.opt.beo.decouple_aw, - is_single: len == '0 - }; - - // assemble write datapath request - assign w_req.w_dp_req = '{ - dst_protocol: idma_req_i.opt.dst_protocol, - offset: idma_req_i.dst_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.dst_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(- idma_req_i.dst_addr[OffsetWidth-1:0]), - num_beats: len, - is_single: len == '0 - }; - - // if the legalizer is bypassed; every burst is the last of the 1D transfer - assign w_req.last = 1'b1; - - // assign the last flag of the controlling unit - assign w_req.super_last = idma_req_i.opt.last; - - // bypass decouple signal - assign w_req.decouple_aw = idma_req_i.opt.beo.decouple_aw; - - // there is no unit to be busy - assign busy_o.r_leg_busy = 1'b0; - assign busy_o.w_leg_busy = 1'b0; - end - - // data path, meta channels, and last queues have to be ready for the legalizer to be ready - assign r_ready = r_dp_req_in_ready & ar_ready; - assign w_ready = w_dp_req_in_ready & aw_ready & w_last_ready; - - - //-------------------------------------- - // Error handler - //-------------------------------------- - if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Error Handling only implemented for AXI to AXI DMA!"); - end - ) - end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler - // bypass the signals, assign their neutral values - assign idma_rsp.error = 1'b0; - assign idma_rsp.pld = 1'b0; - assign idma_rsp.last = w_super_last; - assign rsp_valid = w_dp_rsp_valid & w_last_burst; - assign eh_req_ready_o = 1'b0; - assign legalizer_flush = 1'b0; - assign legalizer_kill = 1'b0; - assign dp_poison = 1'b0; - assign r_dp_rsp_ready = rsp_ready; - assign w_dp_rsp_ready = rsp_ready; - assign busy_o.eh_fsm_busy = 1'b0; - assign busy_o.eh_cnt_busy = 1'b0; - - end else begin : gen_param_error - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Unexpected Error Capability"); - end - ) - end - - - //-------------------------------------- - // Datapath busy signal - //-------------------------------------- - assign dp_busy = busy_o.buffer_busy | - busy_o.r_dp_busy | - busy_o.w_dp_busy; - - - //-------------------------------------- - // Datapath decoupling - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( r_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_r_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( r_req.r_dp_req ), - .valid_i ( r_valid ), - .ready_o ( r_dp_req_in_ready ), - .data_o ( r_dp_req_out ), - .valid_o ( r_dp_req_out_valid ), - .ready_i ( r_dp_req_out_ready ) - ); - - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( w_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_req.w_dp_req ), - .valid_i ( w_valid ), - .ready_o ( w_dp_req_in_ready ), - .data_o ( w_dp_req_out ), - .valid_o ( w_dp_req_out_valid ), - .ready_i ( w_dp_req_out_ready ) - ); - - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - assign r_meta_req_tagged = '{ - src_protocol: r_req.r_dp_req.src_protocol, - ar_req: r_req.ar_req - }; - - fall_through_register #( - .T ( read_meta_channel_tagged_t ) - ) i_ar_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( r_valid ), - .ready_o ( ar_ready ), - .data_i ( r_meta_req_tagged ), - .valid_o ( ar_valid_dp ), - .ready_i ( ar_ready_dp ), - .data_o ( ar_req_dp ) - ); - - - //-------------------------------------- - // Last flag store - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( MetaFifoDepth ), - .type_t ( logic [1:0] ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_last ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( {w_req.super_last, w_req.last} ), - .valid_i ( w_valid & w_ready ), - .ready_o ( w_last_ready ), - .data_o ( {w_super_last, w_last_burst} ), - .valid_o ( /* NOT CONNECTED */ ), - .ready_i ( w_dp_rsp_valid & w_dp_rsp_ready ) - ); - - //-------------------------------------- - // Transport Layer / Datapath - //-------------------------------------- - idma_transport_layer_rw_axi_rw_obi #( - .NumAxInFlight ( NumAxInFlight ), - .DataWidth ( DataWidth ), - .BufferDepth ( BufferDepth ), - .MaskInvalidData ( MaskInvalidData ), - .PrintFifoInfo ( PrintFifoInfo ), - .r_dp_req_t ( r_dp_req_t ), - .w_dp_req_t ( w_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .write_meta_channel_tagged_t ( write_meta_channel_tagged_t ), - .read_meta_channel_t ( read_meta_channel_t ), - .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), - .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ) - ) i_idma_transport_layer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .axi_read_req_o ( axi_read_req_o ), - .axi_read_rsp_i ( axi_read_rsp_i ), - .obi_read_req_o ( obi_read_req_o ), - .obi_read_rsp_i ( obi_read_rsp_i ), - .axi_write_req_o ( axi_write_req_o ), - .axi_write_rsp_i ( axi_write_rsp_i ), - .obi_write_req_o ( obi_write_req_o ), - .obi_write_rsp_i ( obi_write_rsp_i ), - .r_dp_req_i ( r_dp_req_out ), - .r_dp_valid_i ( r_dp_req_out_valid ), - .r_dp_ready_o ( r_dp_req_out_ready ), - .r_dp_rsp_o ( r_dp_rsp ), - .r_dp_valid_o ( r_dp_rsp_valid ), - .r_dp_ready_i ( r_dp_rsp_ready ), - .w_dp_req_i ( w_dp_req_out ), - .w_dp_valid_i ( w_dp_req_out_valid ), - .w_dp_ready_o ( w_dp_req_out_ready ), - .w_dp_rsp_o ( w_dp_rsp ), - .w_dp_valid_o ( w_dp_rsp_valid ), - .w_dp_ready_i ( w_dp_rsp_ready ), - .ar_req_i ( ar_req_dp ), - .ar_valid_i ( ar_valid_dp ), - .ar_ready_o ( ar_ready_dp ), - .aw_req_i ( aw_req_dp ), - .aw_valid_i ( aw_valid_dp ), - .aw_ready_o ( aw_ready_dp ), - .dp_poison_i ( dp_poison ), - .r_dp_busy_o ( busy_o.r_dp_busy ), - .w_dp_busy_o ( busy_o.w_dp_busy ), - .buffer_busy_o ( busy_o.buffer_busy ), - .r_chan_ready_o ( r_chan_ready ), - .r_chan_valid_o ( r_chan_valid ) - ); - - //-------------------------------------- - // R-AW channel coupler - //-------------------------------------- - assign w_meta_req_tagged = '{ - dst_protocol: w_req.w_dp_req.dst_protocol, - aw_req: w_req.aw_req - }; - - if (RAWCouplingAvail) begin : gen_r_aw_coupler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); - end - ) - end else begin : gen_r_aw_bypass - // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests - // As a write could depend on up to two reads - stream_fifo_optimal_wrap #( - .Depth ( 2 ), - .type_t ( write_meta_channel_tagged_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_aw_fifo ( - .clk_i, - .rst_ni, - .testmode_i, - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_meta_req_tagged ), - .valid_i ( w_valid && aw_ready ), - .ready_o ( aw_ready ), - .data_o ( aw_req_dp ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp && aw_valid_dp ) - ); - - // no unit: not busy - assign busy_o.raw_coupler_busy = 1'b0; - end - - - //-------------------------------------- - // Assertions - //-------------------------------------- - `IDMA_NONSYNTH_BLOCK( - initial begin : proc_assert_params - axi_addr_width : assert(AddrWidth >= 32'd12) else - $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); - axi_id_width : assert(AxiIdWidth > 32'd0) else - $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); - axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, - 32'd512, 32'd1028}) else - $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); - axi_user_width : assert(UserWidth > 32'd0) else - $fatal(1, "Parameter `UserWidth` has to be > 0!"); - num_ax_in_flight : assert(NumAxInFlight > 32'd1) else - $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); - buffer_depth : assert(BufferDepth > 32'd1) else - $fatal(1, "Parameter `BufferDepth` has to be > 1!"); - tf_len_width : assert(TFLenWidth >= 32'd12) else - $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); - tf_len_width_max : assert(TFLenWidth <= AddrWidth) else - $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); - end - ) - -endmodule - -// Copyright 2023 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Authors: -// - Thomas Benz -// - Tobias Senti - -`include "axi/typedef.svh" -`include "idma/guard.svh" - -/// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_r_obi_rw_init_w_axi #( - /// Data width - parameter int unsigned DataWidth = 32'd16, - /// Address width - parameter int unsigned AddrWidth = 32'd24, - /// AXI user width - parameter int unsigned UserWidth = 32'd1, - /// AXI ID width - parameter int unsigned AxiIdWidth = 32'd1, - /// Number of transaction that can be in-flight concurrently - parameter int unsigned NumAxInFlight = 32'd2, - /// The depth of the internal reorder buffer: - /// - '2': minimal possible configuration - /// - '3': efficiently handle misaligned transfers (recommended) - parameter int unsigned BufferDepth = 32'd2, - /// With of a transfer: max transfer size is `2**TFLenWidth` bytes - parameter int unsigned TFLenWidth = 32'd24, - /// The depth of the memory system the backend is attached to - parameter int unsigned MemSysDepth = 32'd0, - /// Should both data shifts be done before the dataflow element? - /// If this is enabled, then the data inserted into the dataflow element - /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 1'b0, - /// Mask invalid data on the manager interface - parameter bit MaskInvalidData = 1'b1, - /// Should hardware legalization be present? (recommended) - /// If not, software legalization is required to ensure the transfers are - /// AXI4-conformal - parameter bit HardwareLegalizer = 1'b1, - /// Reject zero-length transfers - parameter bit RejectZeroTransfers = 1'b1, - /// Should the error handler be present? - parameter idma_pkg::error_cap_e ErrorCap = idma_pkg::NO_ERROR_HANDLING, - /// Print the info of the FIFO configuration - parameter bit PrintFifoInfo = 1'b0, - /// 1D iDMA request type - parameter type idma_req_t = logic, - /// iDMA response type - parameter type idma_rsp_t = logic, - /// Error Handler request type - parameter type idma_eh_req_t = logic, - /// iDMA busy signal - parameter type idma_busy_t = logic, - /// AXI4+ATOP Request and Response channel type - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic, - /// Memory Init Request and Response channel type - parameter type init_req_t = logic, - parameter type init_rsp_t = logic, - /// OBI Request and Response channel type - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, - /// Address Read Channel type - parameter type read_meta_channel_t = logic, - /// Address Write Channel type - parameter type write_meta_channel_t = logic, - /// Strobe Width (do not override!) - parameter int unsigned StrbWidth = DataWidth / 8, - /// Offset Width (do not override!) - parameter int unsigned OffsetWidth = $clog2(StrbWidth) -)( - /// Clock - input logic clk_i, - /// Asynchronous reset, active low - input logic rst_ni, - /// Testmode in - input logic testmode_i, - - /// 1D iDMA request - input idma_req_t idma_req_i, - /// 1D iDMA request valid - input logic req_valid_i, - /// 1D iDMA request ready - output logic req_ready_o, - - /// iDMA response - output idma_rsp_t idma_rsp_o, - /// iDMA response valid - output logic rsp_valid_o, - /// iDMA response ready - input logic rsp_ready_i, - - /// Error handler request - input idma_eh_req_t idma_eh_req_i, - /// Error handler request valid - input logic eh_req_valid_i, - /// Error handler request ready - output logic eh_req_ready_o, - - /// Memory Init read request - output init_req_t init_read_req_o, - /// Memory Init read response - input init_rsp_t init_read_rsp_i, - - /// OBI read request - output obi_req_t obi_read_req_o, - /// OBI read response - input obi_rsp_t obi_read_rsp_i, - - /// AXI4+ATOP write request - output axi_req_t axi_write_req_o, - /// AXI4+ATOP write response - input axi_rsp_t axi_write_rsp_i, - - /// Memory Init write request - output init_req_t init_write_req_o, - /// Memory Init write response - input init_rsp_t init_write_rsp_i, - - /// iDMA busy flags - output idma_busy_t busy_o -); - - /// The localparam MetaFifoDepth holds the maximum number of transfers that can be - /// in-flight under any circumstances. - localparam int unsigned MetaFifoDepth = BufferDepth + NumAxInFlight + MemSysDepth; - - /// Address type - typedef logic [AddrWidth-1:0] addr_t; - /// DAta type - typedef logic [DataWidth-1:0] data_t; - /// Strobe type - typedef logic [StrbWidth-1:0] strb_t; - /// User type - typedef logic [UserWidth-1:0] user_t; - /// ID type - typedef logic [AxiIdWidth-1:0] id_t; - /// Offset type - typedef logic [OffsetWidth-1:0] offset_t; - /// Transfer length type - typedef logic [TFLenWidth-1:0] tf_len_t; - - /// The datapath read request type holds all the information required to configure the read - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the read - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `decouple_aw`: If the transfer has the AW decoupled from the R - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e src_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - logic decouple_aw; - logic is_single; - } r_dp_req_t; - - /// The datapath read response type provides feedback from the read part of the datapath: - /// - `resp`: The response from the R channel of the AXI4 manager interface - /// - `last`: The last flag from the R channel of the AXI4 manager interface - /// - `first`: Is the current item first beat in the burst - typedef struct packed { - axi_pkg::resp_t resp; - logic last; - logic first; - } r_dp_rsp_t; - - /// The datapath write request type holds all the information required to configure the write - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the write - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `num_beats`: The number of beats this burst consist of - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - axi_pkg::len_t num_beats; - logic is_single; - } w_dp_req_t; - - /// The datapath write response type provides feedback from the write part of the datapath: - /// - `resp`: The response from the B channel of the AXI4 manager interface - /// - `user`: The user field from the B channel of the AXI4 manager interface - typedef struct packed { - axi_pkg::resp_t resp; - user_t user; - } w_dp_rsp_t; - - /// The iDMA read request bundles an `AR` type and a datapath read response type together. - typedef struct packed { - r_dp_req_t r_dp_req; - read_meta_channel_t ar_req; - } idma_r_req_t; - typedef struct packed { - idma_pkg::protocol_e src_protocol; - read_meta_channel_t ar_req; - } read_meta_channel_tagged_t; - - /// The iDMA write request bundles an `AW` type and a datapath write response type together. It - /// has an additional flags: - /// - `last`: indicating the current burst is the last one of the generic 1D transfer currently - /// being processed - /// - `midend_last`: The current transfer is marked by the controlling as last - /// - `decouple_aw`: indicates this is an R-AW decoupled transfer - typedef struct packed { - w_dp_req_t w_dp_req; - write_meta_channel_t aw_req; - logic last; - logic super_last; - logic decouple_aw; - } idma_w_req_t; - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - write_meta_channel_t aw_req; - } write_meta_channel_tagged_t; - - /// The mutable transfer options type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - idma_pkg::protocol_e src_protocol; - idma_pkg::protocol_e dst_protocol; - offset_t read_shift; - offset_t write_shift; - logic decouple_rw; - logic decouple_aw; - logic [2:0] src_max_llen; - logic [2:0] dst_max_llen; - logic src_reduce_len; - logic dst_reduce_len; - id_t axi_id; - idma_pkg::axi_options_t src_axi_opt; - idma_pkg::axi_options_t dst_axi_opt; - logic super_last; - } idma_mut_tf_opt_t; - - /// The mutable transfer type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - tf_len_t length; - addr_t addr; - logic valid; - addr_t base_addr; - } idma_mut_tf_t; - - - // datapath busy indicates the datapath is actively working on a transfer. It is composed of - // the activity of the buffer as well as both the read and write machines - logic dp_busy; - // blanks invalid data - logic dp_poison; - - // read and write requests and their handshaking signals - idma_r_req_t r_req; - idma_w_req_t w_req; - logic r_valid, w_valid; - logic r_ready, w_ready; - read_meta_channel_tagged_t r_meta_req_tagged; - write_meta_channel_tagged_t w_meta_req_tagged; - - // It the current transfer the last burst in the 1D transfer? - logic w_last_burst; - logic w_last_ready; - - // Super last flag: The current transfer is indicated as the last one by the controlling - // unit; e.g. by a midend - logic w_super_last; - - // Datapath FIFO signals -> used to decouple legalizer and datapath - logic r_dp_req_in_ready, w_dp_req_in_ready; - logic r_dp_req_out_valid, w_dp_req_out_valid; - logic r_dp_req_out_ready, w_dp_req_out_ready; - r_dp_req_t r_dp_req_out; - w_dp_req_t w_dp_req_out; - - // datapah responses - r_dp_rsp_t r_dp_rsp; - w_dp_rsp_t w_dp_rsp; - logic r_dp_rsp_valid, w_dp_rsp_valid; - logic r_dp_rsp_ready, w_dp_rsp_ready; - - // Ax handshaking - logic ar_ready, ar_ready_dp; - logic aw_ready, aw_ready_dp; - logic aw_valid_dp, ar_valid_dp; - - // Ax request from R-AW coupler to datapath - write_meta_channel_tagged_t aw_req_dp; - - // Ax request from the decoupling stage to the datapath - read_meta_channel_tagged_t ar_req_dp; - - // flush and preemptively empty the legalizer - logic legalizer_flush, legalizer_kill; - - /// intermediate signals to reject zero length transfers - logic is_length_zero; - logic req_valid; - idma_rsp_t idma_rsp; - logic rsp_valid; - logic rsp_ready; - - // Respone Channel valid and ready -> needed for bursting - logic r_chan_valid; - logic r_chan_ready; - - //-------------------------------------- - // Reject Zero Length Transfers - //-------------------------------------- - if (RejectZeroTransfers) begin : gen_reject_zero_transfers - // is the current transfer length 0? - assign is_length_zero = idma_req_i.length == '0; - - // bypass valid as long as length is not zero, otherwise suppress it - assign req_valid = is_length_zero ? 1'b0 : req_valid_i; - - // modify response - always_comb begin : proc_modify_response_zero_length - // default: bypass - idma_rsp_o = idma_rsp; - rsp_ready = rsp_ready_i; - rsp_valid_o = rsp_valid; - - // a zero transfer happens - if (is_length_zero & req_valid_i & req_ready_o) begin - // block backend - rsp_ready = 1'b0; - // generate new response - rsp_valid_o = 1'b1; - idma_rsp_o = '0; - idma_rsp_o.error = 1'b1; - idma_rsp_o.pld.err_type = idma_pkg::BACKEND; - end - end - - // just bypass signals - end else begin : gen_bypass_zero_transfers - // bypass - assign req_valid = req_valid_i; - assign idma_rsp_o = idma_rsp; - assign rsp_ready = rsp_ready_i; - assign rsp_valid_o = rsp_valid; - end - - - //-------------------------------------- - // Legalization - //-------------------------------------- - if (HardwareLegalizer) begin : gen_hw_legalizer - // hardware legalizer is present - idma_legalizer_r_obi_rw_init_w_axi #( - .CombinedShifter ( CombinedShifter ), - .DataWidth ( DataWidth ), - .AddrWidth ( AddrWidth ), - .idma_req_t ( idma_req_t ), - .idma_r_req_t ( idma_r_req_t ), - .idma_w_req_t ( idma_w_req_t ), - .idma_mut_tf_t ( idma_mut_tf_t ), - .idma_mut_tf_opt_t ( idma_mut_tf_opt_t ) - ) i_idma_legalizer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .req_i ( idma_req_i ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .r_req_o ( r_req ), - .w_req_o ( w_req ), - .r_valid_o ( r_valid ), - .w_valid_o ( w_valid ), - .r_ready_i ( r_ready ), - .w_ready_i ( w_ready ), - .flush_i ( legalizer_flush ), - .kill_i ( legalizer_kill ), - .r_busy_o ( busy_o.r_leg_busy ), - .w_busy_o ( busy_o.w_leg_busy ) - ); - - end else begin : gen_no_hw_legalizer - // stream fork is used to synchronize the two decoupled channels without the need for a - // FIFO here. - stream_fork #( - .N_OUP ( 32'd2 ) - ) i_stream_fork ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .valid_o ( { r_valid, w_valid } ), - .ready_i ( { r_ready, w_ready } ) - ); - - // local signal holding the length -> explicitly only doing the computation once - axi_pkg::len_t len; - assign len = ((idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0] - - 'd1) >> OffsetWidth); - - // assemble read datapath request - assign r_req.r_dp_req = '{ - src_protocol: idma_req_i.opt.src_protocol, - offset: idma_req_i.src_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(idma_req_i.src_addr[OffsetWidth-1:0]), - decouple_aw: idma_req_i.opt.beo.decouple_aw, - is_single: len == '0 - }; - - // assemble write datapath request - assign w_req.w_dp_req = '{ - dst_protocol: idma_req_i.opt.dst_protocol, - offset: idma_req_i.dst_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.dst_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(- idma_req_i.dst_addr[OffsetWidth-1:0]), - num_beats: len, - is_single: len == '0 - }; - - // if the legalizer is bypassed; every burst is the last of the 1D transfer - assign w_req.last = 1'b1; - - // assign the last flag of the controlling unit - assign w_req.super_last = idma_req_i.opt.last; - - // bypass decouple signal - assign w_req.decouple_aw = idma_req_i.opt.beo.decouple_aw; - - // there is no unit to be busy - assign busy_o.r_leg_busy = 1'b0; - assign busy_o.w_leg_busy = 1'b0; - end - - // data path, meta channels, and last queues have to be ready for the legalizer to be ready - assign r_ready = r_dp_req_in_ready & ar_ready; - assign w_ready = w_dp_req_in_ready & aw_ready & w_last_ready; - - - //-------------------------------------- - // Error handler - //-------------------------------------- - if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Error Handling only implemented for AXI to AXI DMA!"); - end - ) - end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler - // bypass the signals, assign their neutral values - assign idma_rsp.error = 1'b0; - assign idma_rsp.pld = 1'b0; - assign idma_rsp.last = w_super_last; - assign rsp_valid = w_dp_rsp_valid & w_last_burst; - assign eh_req_ready_o = 1'b0; - assign legalizer_flush = 1'b0; - assign legalizer_kill = 1'b0; - assign dp_poison = 1'b0; - assign r_dp_rsp_ready = rsp_ready; - assign w_dp_rsp_ready = rsp_ready; - assign busy_o.eh_fsm_busy = 1'b0; - assign busy_o.eh_cnt_busy = 1'b0; - - end else begin : gen_param_error - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Unexpected Error Capability"); - end - ) - end - - - //-------------------------------------- - // Datapath busy signal - //-------------------------------------- - assign dp_busy = busy_o.buffer_busy | - busy_o.r_dp_busy | - busy_o.w_dp_busy; - - - //-------------------------------------- - // Datapath decoupling - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( r_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_r_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( r_req.r_dp_req ), - .valid_i ( r_valid ), - .ready_o ( r_dp_req_in_ready ), - .data_o ( r_dp_req_out ), - .valid_o ( r_dp_req_out_valid ), - .ready_i ( r_dp_req_out_ready ) - ); - - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( w_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_req.w_dp_req ), - .valid_i ( w_valid ), - .ready_o ( w_dp_req_in_ready ), - .data_o ( w_dp_req_out ), - .valid_o ( w_dp_req_out_valid ), - .ready_i ( w_dp_req_out_ready ) - ); - - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - assign r_meta_req_tagged = '{ - src_protocol: r_req.r_dp_req.src_protocol, - ar_req: r_req.ar_req - }; - - fall_through_register #( - .T ( read_meta_channel_tagged_t ) - ) i_ar_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( r_valid ), - .ready_o ( ar_ready ), - .data_i ( r_meta_req_tagged ), - .valid_o ( ar_valid_dp ), - .ready_i ( ar_ready_dp ), - .data_o ( ar_req_dp ) - ); - - - //-------------------------------------- - // Last flag store - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( MetaFifoDepth ), - .type_t ( logic [1:0] ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_last ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( {w_req.super_last, w_req.last} ), - .valid_i ( w_valid & w_ready ), - .ready_o ( w_last_ready ), - .data_o ( {w_super_last, w_last_burst} ), - .valid_o ( /* NOT CONNECTED */ ), - .ready_i ( w_dp_rsp_valid & w_dp_rsp_ready ) - ); - - //-------------------------------------- - // Transport Layer / Datapath - //-------------------------------------- - idma_transport_layer_r_obi_rw_init_w_axi #( - .NumAxInFlight ( NumAxInFlight ), - .DataWidth ( DataWidth ), - .BufferDepth ( BufferDepth ), - .MaskInvalidData ( MaskInvalidData ), - .PrintFifoInfo ( PrintFifoInfo ), - .r_dp_req_t ( r_dp_req_t ), - .w_dp_req_t ( w_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .write_meta_channel_tagged_t ( write_meta_channel_tagged_t ), - .read_meta_channel_t ( read_meta_channel_t ), - .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), - .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ), - .init_req_t ( init_req_t ), - .init_rsp_t ( init_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ) - ) i_idma_transport_layer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .init_read_req_o ( init_read_req_o ), - .init_read_rsp_i ( init_read_rsp_i ), - .obi_read_req_o ( obi_read_req_o ), - .obi_read_rsp_i ( obi_read_rsp_i ), - .axi_write_req_o ( axi_write_req_o ), - .axi_write_rsp_i ( axi_write_rsp_i ), - .init_write_req_o ( init_write_req_o ), - .init_write_rsp_i ( init_write_rsp_i ), - .r_dp_req_i ( r_dp_req_out ), - .r_dp_valid_i ( r_dp_req_out_valid ), - .r_dp_ready_o ( r_dp_req_out_ready ), - .r_dp_rsp_o ( r_dp_rsp ), - .r_dp_valid_o ( r_dp_rsp_valid ), - .r_dp_ready_i ( r_dp_rsp_ready ), - .w_dp_req_i ( w_dp_req_out ), - .w_dp_valid_i ( w_dp_req_out_valid ), - .w_dp_ready_o ( w_dp_req_out_ready ), - .w_dp_rsp_o ( w_dp_rsp ), - .w_dp_valid_o ( w_dp_rsp_valid ), - .w_dp_ready_i ( w_dp_rsp_ready ), - .ar_req_i ( ar_req_dp ), - .ar_valid_i ( ar_valid_dp ), - .ar_ready_o ( ar_ready_dp ), - .aw_req_i ( aw_req_dp ), - .aw_valid_i ( aw_valid_dp ), - .aw_ready_o ( aw_ready_dp ), - .dp_poison_i ( dp_poison ), - .r_dp_busy_o ( busy_o.r_dp_busy ), - .w_dp_busy_o ( busy_o.w_dp_busy ), - .buffer_busy_o ( busy_o.buffer_busy ), - .r_chan_ready_o ( r_chan_ready ), - .r_chan_valid_o ( r_chan_valid ) - ); - - //-------------------------------------- - // R-AW channel coupler - //-------------------------------------- - assign w_meta_req_tagged = '{ - dst_protocol: w_req.w_dp_req.dst_protocol, - aw_req: w_req.aw_req - }; - - if (RAWCouplingAvail) begin : gen_r_aw_coupler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); - end - ) - end else begin : gen_r_aw_bypass - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - fall_through_register #( - .T ( write_meta_channel_tagged_t ) - ) i_aw_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( w_valid ), - .ready_o ( aw_ready ), - .data_i ( w_meta_req_tagged ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp ), - .data_o ( aw_req_dp ) - ); - - // no unit: not busy - assign busy_o.raw_coupler_busy = 1'b0; - end - - - //-------------------------------------- - // Assertions - //-------------------------------------- - `IDMA_NONSYNTH_BLOCK( - initial begin : proc_assert_params - axi_addr_width : assert(AddrWidth >= 32'd12) else - $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); - axi_id_width : assert(AxiIdWidth > 32'd0) else - $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); - axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, - 32'd512, 32'd1028}) else - $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); - axi_user_width : assert(UserWidth > 32'd0) else - $fatal(1, "Parameter `UserWidth` has to be > 0!"); - num_ax_in_flight : assert(NumAxInFlight > 32'd1) else - $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); - buffer_depth : assert(BufferDepth > 32'd1) else - $fatal(1, "Parameter `BufferDepth` has to be > 1!"); - tf_len_width : assert(TFLenWidth >= 32'd12) else - $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); - tf_len_width_max : assert(TFLenWidth <= AddrWidth) else - $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); - end - ) - -endmodule - -// Copyright 2023 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Authors: -// - Thomas Benz -// - Tobias Senti - -`include "axi/typedef.svh" -`include "idma/guard.svh" - -/// The iDMA backend implements an arbitrary 1D copy engine -module idma_backend_r_axi_rw_init_rw_obi #( - /// Data width - parameter int unsigned DataWidth = 32'd16, - /// Address width - parameter int unsigned AddrWidth = 32'd24, - /// AXI user width - parameter int unsigned UserWidth = 32'd1, - /// AXI ID width - parameter int unsigned AxiIdWidth = 32'd1, - /// Number of transaction that can be in-flight concurrently - parameter int unsigned NumAxInFlight = 32'd2, - /// The depth of the internal reorder buffer: - /// - '2': minimal possible configuration - /// - '3': efficiently handle misaligned transfers (recommended) - parameter int unsigned BufferDepth = 32'd2, - /// With of a transfer: max transfer size is `2**TFLenWidth` bytes - parameter int unsigned TFLenWidth = 32'd24, - /// The depth of the memory system the backend is attached to - parameter int unsigned MemSysDepth = 32'd0, - /// Should both data shifts be done before the dataflow element? - /// If this is enabled, then the data inserted into the dataflow element - /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 1'b0, - /// Mask invalid data on the manager interface - parameter bit MaskInvalidData = 1'b1, - /// Should hardware legalization be present? (recommended) - /// If not, software legalization is required to ensure the transfers are - /// AXI4-conformal - parameter bit HardwareLegalizer = 1'b1, - /// Reject zero-length transfers - parameter bit RejectZeroTransfers = 1'b1, - /// Should the error handler be present? - parameter idma_pkg::error_cap_e ErrorCap = idma_pkg::NO_ERROR_HANDLING, - /// Print the info of the FIFO configuration - parameter bit PrintFifoInfo = 1'b0, - /// 1D iDMA request type - parameter type idma_req_t = logic, - /// iDMA response type - parameter type idma_rsp_t = logic, - /// Error Handler request type - parameter type idma_eh_req_t = logic, - /// iDMA busy signal - parameter type idma_busy_t = logic, - /// AXI4+ATOP Request and Response channel type - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic, - /// Memory Init Request and Response channel type - parameter type init_req_t = logic, - parameter type init_rsp_t = logic, - /// OBI Request and Response channel type - parameter type obi_req_t = logic, - parameter type obi_rsp_t = logic, - /// Address Read Channel type - parameter type read_meta_channel_t = logic, - /// Address Write Channel type - parameter type write_meta_channel_t = logic, - /// Strobe Width (do not override!) - parameter int unsigned StrbWidth = DataWidth / 8, - /// Offset Width (do not override!) - parameter int unsigned OffsetWidth = $clog2(StrbWidth) -)( - /// Clock - input logic clk_i, - /// Asynchronous reset, active low - input logic rst_ni, - /// Testmode in - input logic testmode_i, - - /// 1D iDMA request - input idma_req_t idma_req_i, - /// 1D iDMA request valid - input logic req_valid_i, - /// 1D iDMA request ready - output logic req_ready_o, - - /// iDMA response - output idma_rsp_t idma_rsp_o, - /// iDMA response valid - output logic rsp_valid_o, - /// iDMA response ready - input logic rsp_ready_i, - - /// Error handler request - input idma_eh_req_t idma_eh_req_i, - /// Error handler request valid - input logic eh_req_valid_i, - /// Error handler request ready - output logic eh_req_ready_o, - - /// AXI4+ATOP read request - output axi_req_t axi_read_req_o, - /// AXI4+ATOP read response - input axi_rsp_t axi_read_rsp_i, - - /// Memory Init read request - output init_req_t init_read_req_o, - /// Memory Init read response - input init_rsp_t init_read_rsp_i, - - /// OBI read request - output obi_req_t obi_read_req_o, - /// OBI read response - input obi_rsp_t obi_read_rsp_i, - - /// Memory Init write request - output init_req_t init_write_req_o, - /// Memory Init write response - input init_rsp_t init_write_rsp_i, - - /// OBI write request - output obi_req_t obi_write_req_o, - /// OBI write response - input obi_rsp_t obi_write_rsp_i, - - /// iDMA busy flags - output idma_busy_t busy_o -); - - /// The localparam MetaFifoDepth holds the maximum number of transfers that can be - /// in-flight under any circumstances. - localparam int unsigned MetaFifoDepth = BufferDepth + NumAxInFlight + MemSysDepth; - - /// Address type - typedef logic [AddrWidth-1:0] addr_t; - /// DAta type - typedef logic [DataWidth-1:0] data_t; - /// Strobe type - typedef logic [StrbWidth-1:0] strb_t; - /// User type - typedef logic [UserWidth-1:0] user_t; - /// ID type - typedef logic [AxiIdWidth-1:0] id_t; - /// Offset type - typedef logic [OffsetWidth-1:0] offset_t; - /// Transfer length type - typedef logic [TFLenWidth-1:0] tf_len_t; - - /// The datapath read request type holds all the information required to configure the read - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the read - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `decouple_aw`: If the transfer has the AW decoupled from the R - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e src_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - logic decouple_aw; - logic is_single; - } r_dp_req_t; - - /// The datapath read response type provides feedback from the read part of the datapath: - /// - `resp`: The response from the R channel of the AXI4 manager interface - /// - `last`: The last flag from the R channel of the AXI4 manager interface - /// - `first`: Is the current item first beat in the burst - typedef struct packed { - axi_pkg::resp_t resp; - logic last; - logic first; - } r_dp_rsp_t; - - /// The datapath write request type holds all the information required to configure the write - /// part of the datapath. The type consists of: - /// - `offset`: The bus offset of the write - /// - `trailer`: How many empty bytes are required to pad the transfer to a multiple of the - /// bus width. - /// - `shift`: The amount the data needs to be shifted - /// - `num_beats`: The number of beats this burst consist of - /// - `is_single`: Is this transfer just one beat long? `(len == 0)` - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - offset_t offset; - offset_t tailer; - offset_t shift; - axi_pkg::len_t num_beats; - logic is_single; - } w_dp_req_t; - - /// The datapath write response type provides feedback from the write part of the datapath: - /// - `resp`: The response from the B channel of the AXI4 manager interface - /// - `user`: The user field from the B channel of the AXI4 manager interface - typedef struct packed { - axi_pkg::resp_t resp; - user_t user; - } w_dp_rsp_t; - - /// The iDMA read request bundles an `AR` type and a datapath read response type together. - typedef struct packed { - r_dp_req_t r_dp_req; - read_meta_channel_t ar_req; - } idma_r_req_t; - typedef struct packed { - idma_pkg::protocol_e src_protocol; - read_meta_channel_t ar_req; - } read_meta_channel_tagged_t; - - /// The iDMA write request bundles an `AW` type and a datapath write response type together. It - /// has an additional flags: - /// - `last`: indicating the current burst is the last one of the generic 1D transfer currently - /// being processed - /// - `midend_last`: The current transfer is marked by the controlling as last - /// - `decouple_aw`: indicates this is an R-AW decoupled transfer - typedef struct packed { - w_dp_req_t w_dp_req; - write_meta_channel_t aw_req; - logic last; - logic super_last; - logic decouple_aw; - } idma_w_req_t; - typedef struct packed { - idma_pkg::protocol_e dst_protocol; - write_meta_channel_t aw_req; - } write_meta_channel_tagged_t; - - /// The mutable transfer options type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - idma_pkg::protocol_e src_protocol; - idma_pkg::protocol_e dst_protocol; - offset_t read_shift; - offset_t write_shift; - logic decouple_rw; - logic decouple_aw; - logic [2:0] src_max_llen; - logic [2:0] dst_max_llen; - logic src_reduce_len; - logic dst_reduce_len; - id_t axi_id; - idma_pkg::axi_options_t src_axi_opt; - idma_pkg::axi_options_t dst_axi_opt; - logic super_last; - } idma_mut_tf_opt_t; - - /// The mutable transfer type holds important information that is mutated by the - /// `legalizer` block. - typedef struct packed { - tf_len_t length; - addr_t addr; - logic valid; - addr_t base_addr; - } idma_mut_tf_t; - - - // datapath busy indicates the datapath is actively working on a transfer. It is composed of - // the activity of the buffer as well as both the read and write machines - logic dp_busy; - // blanks invalid data - logic dp_poison; - - // read and write requests and their handshaking signals - idma_r_req_t r_req; - idma_w_req_t w_req; - logic r_valid, w_valid; - logic r_ready, w_ready; - read_meta_channel_tagged_t r_meta_req_tagged; - write_meta_channel_tagged_t w_meta_req_tagged; - - // It the current transfer the last burst in the 1D transfer? - logic w_last_burst; - logic w_last_ready; - - // Super last flag: The current transfer is indicated as the last one by the controlling - // unit; e.g. by a midend - logic w_super_last; - - // Datapath FIFO signals -> used to decouple legalizer and datapath - logic r_dp_req_in_ready, w_dp_req_in_ready; - logic r_dp_req_out_valid, w_dp_req_out_valid; - logic r_dp_req_out_ready, w_dp_req_out_ready; - r_dp_req_t r_dp_req_out; - w_dp_req_t w_dp_req_out; - - // datapah responses - r_dp_rsp_t r_dp_rsp; - w_dp_rsp_t w_dp_rsp; - logic r_dp_rsp_valid, w_dp_rsp_valid; - logic r_dp_rsp_ready, w_dp_rsp_ready; - - // Ax handshaking - logic ar_ready, ar_ready_dp; - logic aw_ready, aw_ready_dp; - logic aw_valid_dp, ar_valid_dp; - - // Ax request from R-AW coupler to datapath - write_meta_channel_tagged_t aw_req_dp; - - // Ax request from the decoupling stage to the datapath - read_meta_channel_tagged_t ar_req_dp; - - // flush and preemptively empty the legalizer - logic legalizer_flush, legalizer_kill; - - /// intermediate signals to reject zero length transfers - logic is_length_zero; - logic req_valid; - idma_rsp_t idma_rsp; - logic rsp_valid; - logic rsp_ready; - - // Respone Channel valid and ready -> needed for bursting - logic r_chan_valid; - logic r_chan_ready; - - //-------------------------------------- - // Reject Zero Length Transfers - //-------------------------------------- - if (RejectZeroTransfers) begin : gen_reject_zero_transfers - // is the current transfer length 0? - assign is_length_zero = idma_req_i.length == '0; - - // bypass valid as long as length is not zero, otherwise suppress it - assign req_valid = is_length_zero ? 1'b0 : req_valid_i; - - // modify response - always_comb begin : proc_modify_response_zero_length - // default: bypass - idma_rsp_o = idma_rsp; - rsp_ready = rsp_ready_i; - rsp_valid_o = rsp_valid; - - // a zero transfer happens - if (is_length_zero & req_valid_i & req_ready_o) begin - // block backend - rsp_ready = 1'b0; - // generate new response - rsp_valid_o = 1'b1; - idma_rsp_o = '0; - idma_rsp_o.error = 1'b1; - idma_rsp_o.pld.err_type = idma_pkg::BACKEND; - end - end - - // just bypass signals - end else begin : gen_bypass_zero_transfers - // bypass - assign req_valid = req_valid_i; - assign idma_rsp_o = idma_rsp; - assign rsp_ready = rsp_ready_i; - assign rsp_valid_o = rsp_valid; - end - - - //-------------------------------------- - // Legalization - //-------------------------------------- - if (HardwareLegalizer) begin : gen_hw_legalizer - // hardware legalizer is present - idma_legalizer_r_axi_rw_init_rw_obi #( - .CombinedShifter ( CombinedShifter ), - .DataWidth ( DataWidth ), - .AddrWidth ( AddrWidth ), - .idma_req_t ( idma_req_t ), - .idma_r_req_t ( idma_r_req_t ), - .idma_w_req_t ( idma_w_req_t ), - .idma_mut_tf_t ( idma_mut_tf_t ), - .idma_mut_tf_opt_t ( idma_mut_tf_opt_t ) - ) i_idma_legalizer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .req_i ( idma_req_i ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .r_req_o ( r_req ), - .w_req_o ( w_req ), - .r_valid_o ( r_valid ), - .w_valid_o ( w_valid ), - .r_ready_i ( r_ready ), - .w_ready_i ( w_ready ), - .flush_i ( legalizer_flush ), - .kill_i ( legalizer_kill ), - .r_busy_o ( busy_o.r_leg_busy ), - .w_busy_o ( busy_o.w_leg_busy ) - ); - - end else begin : gen_no_hw_legalizer - // stream fork is used to synchronize the two decoupled channels without the need for a - // FIFO here. - stream_fork #( - .N_OUP ( 32'd2 ) - ) i_stream_fork ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( req_valid ), - .ready_o ( req_ready_o ), - .valid_o ( { r_valid, w_valid } ), - .ready_i ( { r_ready, w_ready } ) - ); - - // local signal holding the length -> explicitly only doing the computation once - axi_pkg::len_t len; - assign len = ((idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0] - - 'd1) >> OffsetWidth); - - // assemble read datapath request - assign r_req.r_dp_req = '{ - src_protocol: idma_req_i.opt.src_protocol, - offset: idma_req_i.src_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.src_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(idma_req_i.src_addr[OffsetWidth-1:0]), - decouple_aw: idma_req_i.opt.beo.decouple_aw, - is_single: len == '0 - }; - - // assemble write datapath request - assign w_req.w_dp_req = '{ - dst_protocol: idma_req_i.opt.dst_protocol, - offset: idma_req_i.dst_addr[OffsetWidth-1:0], - tailer: OffsetWidth'(idma_req_i.length + idma_req_i.dst_addr[OffsetWidth-1:0]), - shift: OffsetWidth'(- idma_req_i.dst_addr[OffsetWidth-1:0]), - num_beats: len, - is_single: len == '0 - }; - - // if the legalizer is bypassed; every burst is the last of the 1D transfer - assign w_req.last = 1'b1; - - // assign the last flag of the controlling unit - assign w_req.super_last = idma_req_i.opt.last; - - // bypass decouple signal - assign w_req.decouple_aw = idma_req_i.opt.beo.decouple_aw; - - // there is no unit to be busy - assign busy_o.r_leg_busy = 1'b0; - assign busy_o.w_leg_busy = 1'b0; - end - - // data path, meta channels, and last queues have to be ready for the legalizer to be ready - assign r_ready = r_dp_req_in_ready & ar_ready; - assign w_ready = w_dp_req_in_ready & aw_ready & w_last_ready; - - - //-------------------------------------- - // Error handler - //-------------------------------------- - if (ErrorCap == idma_pkg::ERROR_HANDLING) begin : gen_error_handler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Error Handling only implemented for AXI to AXI DMA!"); - end - ) - end else if (ErrorCap == idma_pkg::NO_ERROR_HANDLING) begin : gen_no_error_handler - // bypass the signals, assign their neutral values - assign idma_rsp.error = 1'b0; - assign idma_rsp.pld = 1'b0; - assign idma_rsp.last = w_super_last; - assign rsp_valid = w_dp_rsp_valid & w_last_burst; - assign eh_req_ready_o = 1'b0; - assign legalizer_flush = 1'b0; - assign legalizer_kill = 1'b0; - assign dp_poison = 1'b0; - assign r_dp_rsp_ready = rsp_ready; - assign w_dp_rsp_ready = rsp_ready; - assign busy_o.eh_fsm_busy = 1'b0; - assign busy_o.eh_cnt_busy = 1'b0; - - end else begin : gen_param_error - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Unexpected Error Capability"); - end - ) - end - - - //-------------------------------------- - // Datapath busy signal - //-------------------------------------- - assign dp_busy = busy_o.buffer_busy | - busy_o.r_dp_busy | - busy_o.w_dp_busy; - - - //-------------------------------------- - // Datapath decoupling - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( r_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_r_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( r_req.r_dp_req ), - .valid_i ( r_valid ), - .ready_o ( r_dp_req_in_ready ), - .data_o ( r_dp_req_out ), - .valid_o ( r_dp_req_out_valid ), - .ready_i ( r_dp_req_out_ready ) - ); - - stream_fifo_optimal_wrap #( - .Depth ( NumAxInFlight ), - .type_t ( w_dp_req_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_dp_req ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_req.w_dp_req ), - .valid_i ( w_valid ), - .ready_o ( w_dp_req_in_ready ), - .data_o ( w_dp_req_out ), - .valid_o ( w_dp_req_out_valid ), - .ready_i ( w_dp_req_out_ready ) - ); - - // Add fall-through register to allow the input to be ready if the output is not. This - // does not add a cycle of delay - assign r_meta_req_tagged = '{ - src_protocol: r_req.r_dp_req.src_protocol, - ar_req: r_req.ar_req - }; - - fall_through_register #( - .T ( read_meta_channel_tagged_t ) - ) i_ar_fall_through_register ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .clr_i ( 1'b0 ), - .valid_i ( r_valid ), - .ready_o ( ar_ready ), - .data_i ( r_meta_req_tagged ), - .valid_o ( ar_valid_dp ), - .ready_i ( ar_ready_dp ), - .data_o ( ar_req_dp ) - ); - - - //-------------------------------------- - // Last flag store - //-------------------------------------- - stream_fifo_optimal_wrap #( - .Depth ( MetaFifoDepth ), - .type_t ( logic [1:0] ), - .PrintInfo ( PrintFifoInfo ) - ) i_w_last ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( {w_req.super_last, w_req.last} ), - .valid_i ( w_valid & w_ready ), - .ready_o ( w_last_ready ), - .data_o ( {w_super_last, w_last_burst} ), - .valid_o ( /* NOT CONNECTED */ ), - .ready_i ( w_dp_rsp_valid & w_dp_rsp_ready ) - ); - - //-------------------------------------- - // Transport Layer / Datapath - //-------------------------------------- - idma_transport_layer_r_axi_rw_init_rw_obi #( - .NumAxInFlight ( NumAxInFlight ), - .DataWidth ( DataWidth ), - .BufferDepth ( BufferDepth ), - .MaskInvalidData ( MaskInvalidData ), - .PrintFifoInfo ( PrintFifoInfo ), - .r_dp_req_t ( r_dp_req_t ), - .w_dp_req_t ( w_dp_req_t ), - .r_dp_rsp_t ( r_dp_rsp_t ), - .w_dp_rsp_t ( w_dp_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .write_meta_channel_tagged_t ( write_meta_channel_tagged_t ), - .read_meta_channel_t ( read_meta_channel_t ), - .read_meta_channel_tagged_t ( read_meta_channel_tagged_t ), - .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ), - .init_req_t ( init_req_t ), - .init_rsp_t ( init_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ) - ) i_idma_transport_layer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( testmode_i ), - .axi_read_req_o ( axi_read_req_o ), - .axi_read_rsp_i ( axi_read_rsp_i ), - .init_read_req_o ( init_read_req_o ), - .init_read_rsp_i ( init_read_rsp_i ), - .obi_read_req_o ( obi_read_req_o ), - .obi_read_rsp_i ( obi_read_rsp_i ), - .init_write_req_o ( init_write_req_o ), - .init_write_rsp_i ( init_write_rsp_i ), - .obi_write_req_o ( obi_write_req_o ), - .obi_write_rsp_i ( obi_write_rsp_i ), - .r_dp_req_i ( r_dp_req_out ), - .r_dp_valid_i ( r_dp_req_out_valid ), - .r_dp_ready_o ( r_dp_req_out_ready ), - .r_dp_rsp_o ( r_dp_rsp ), - .r_dp_valid_o ( r_dp_rsp_valid ), - .r_dp_ready_i ( r_dp_rsp_ready ), - .w_dp_req_i ( w_dp_req_out ), - .w_dp_valid_i ( w_dp_req_out_valid ), - .w_dp_ready_o ( w_dp_req_out_ready ), - .w_dp_rsp_o ( w_dp_rsp ), - .w_dp_valid_o ( w_dp_rsp_valid ), - .w_dp_ready_i ( w_dp_rsp_ready ), - .ar_req_i ( ar_req_dp ), - .ar_valid_i ( ar_valid_dp ), - .ar_ready_o ( ar_ready_dp ), - .aw_req_i ( aw_req_dp ), - .aw_valid_i ( aw_valid_dp ), - .aw_ready_o ( aw_ready_dp ), - .dp_poison_i ( dp_poison ), - .r_dp_busy_o ( busy_o.r_dp_busy ), - .w_dp_busy_o ( busy_o.w_dp_busy ), - .buffer_busy_o ( busy_o.buffer_busy ), - .r_chan_ready_o ( r_chan_ready ), - .r_chan_valid_o ( r_chan_valid ) - ); - - //-------------------------------------- - // R-AW channel coupler - //-------------------------------------- - assign w_meta_req_tagged = '{ - dst_protocol: w_req.w_dp_req.dst_protocol, - aw_req: w_req.aw_req - }; - - if (RAWCouplingAvail) begin : gen_r_aw_coupler - `IDMA_NONSYNTH_BLOCK( - initial begin - $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); - end - ) - end else begin : gen_r_aw_bypass - // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests - // As a write could depend on up to two reads - stream_fifo_optimal_wrap #( - .Depth ( 2 ), - .type_t ( write_meta_channel_tagged_t ), - .PrintInfo ( PrintFifoInfo ) - ) i_aw_fifo ( - .clk_i, - .rst_ni, - .testmode_i, - .flush_i ( 1'b0 ), - .usage_o ( /* NOT CONNECTED */ ), - .data_i ( w_meta_req_tagged ), - .valid_i ( w_valid && aw_ready ), - .ready_o ( aw_ready ), - .data_o ( aw_req_dp ), - .valid_o ( aw_valid_dp ), - .ready_i ( aw_ready_dp && aw_valid_dp ) - ); - - // no unit: not busy - assign busy_o.raw_coupler_busy = 1'b0; - end - - - //-------------------------------------- - // Assertions - //-------------------------------------- - `IDMA_NONSYNTH_BLOCK( - initial begin : proc_assert_params - axi_addr_width : assert(AddrWidth >= 32'd12) else - $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); - axi_id_width : assert(AxiIdWidth > 32'd0) else - $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); - axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, - 32'd512, 32'd1028}) else - $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); - axi_user_width : assert(UserWidth > 32'd0) else - $fatal(1, "Parameter `UserWidth` has to be > 0!"); - num_ax_in_flight : assert(NumAxInFlight > 32'd1) else - $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); - buffer_depth : assert(BufferDepth > 32'd1) else - $fatal(1, "Parameter `BufferDepth` has to be > 1!"); - tf_len_width : assert(TFLenWidth >= 32'd12) else - $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); - tf_len_width_max : assert(TFLenWidth <= AddrWidth) else - $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); - end - ) - -endmodule - -// Copyright 2023 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Authors: -// - Thomas Benz -// - Tobias Senti - -`include "axi/typedef.svh" -`include "axi_stream/typedef.svh" -`include "idma/typedef.svh" -`include "obi/typedef.svh" -`include "tilelink/typedef.svh" - -/// Synthesis wrapper for the iDMA backend. Unpacks all the interfaces to simple logic vectors -module idma_backend_synth_rw_axi #( - /// Data width - parameter int unsigned DataWidth = 32'd32, - /// Address width - parameter int unsigned AddrWidth = 32'd32, - /// AXI user width - parameter int unsigned UserWidth = 32'd1, - /// AXI ID width - parameter int unsigned AxiIdWidth = 32'd1, - /// Number of transaction that can be in-flight concurrently - parameter int unsigned NumAxInFlight = 32'd3, - /// The depth of the internal reorder buffer: - /// - '2': minimal possible configuration - /// - '3': efficiently handle misaligned transfers (recommended) - parameter int unsigned BufferDepth = 32'd3, - /// With of a transfer: max transfer size is `2**TFLenWidth` bytes - parameter int unsigned TFLenWidth = 32'd32, - /// The depth of the memory system the backend is attached to - parameter int unsigned MemSysDepth = 32'd0, - /// Should both data shifts be done before the dataflow element? - /// If this is enabled, then the data inserted into the dataflow element - /// will no longer be word aligned, but only a single shifter is needed - parameter bit CombinedShifter = 1'b0, - /// Mask invalid data on the manager interface - parameter bit MaskInvalidData = 1'b1, - /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 1, - /// Should hardware legalization be present? (recommended) - /// If not, software legalization is required to ensure the transfers are - /// AXI4-conformal - parameter bit HardwareLegalizer = 1'b1, - /// Reject zero-length transfers - parameter bit RejectZeroTransfers = 1'b1, - /// Should the error handler be present? - parameter bit ErrorHandling = 1'b1, - // Dependent parameters; do not override! - /// Strobe Width (do not override!) - parameter int unsigned StrbWidth = DataWidth / 8, - /// Offset Width (do not override!) - parameter int unsigned OffsetWidth = $clog2(StrbWidth), - /// Address type (do not override!) - parameter type addr_t = logic[AddrWidth-1:0], - /// Data type (do not override!) - parameter type data_t = logic[DataWidth-1:0], - /// Strobe type (do not override!) - parameter type strb_t = logic[StrbWidth-1:0], - /// User type (do not override!) - parameter type user_t = logic[UserWidth-1:0], - /// ID type (do not override!) - parameter type id_t = logic[AxiIdWidth-1:0], - /// Transfer length type (do not override!) - parameter type tf_len_t = logic[TFLenWidth-1:0], - /// Offset type (do not override!) - parameter type offset_t = logic[OffsetWidth-1:0] -)( - input logic clk_i, - input logic rst_ni, - input logic test_i, - - input logic req_valid_i, - output logic req_ready_o, - - input tf_len_t req_length_i, - input addr_t req_src_addr_i, - input addr_t req_dst_addr_i, - input idma_pkg::protocol_e req_src_protocol_i, - input idma_pkg::protocol_e req_dst_protocol_i, - input id_t req_axi_id_i, - input axi_pkg::burst_t req_src_burst_i, - input axi_pkg::cache_t req_src_cache_i, - input logic req_src_lock_i, - input axi_pkg::prot_t req_src_prot_i, - input axi_pkg::qos_t req_src_qos_i, - input axi_pkg::region_t req_src_region_i, - input axi_pkg::burst_t req_dst_burst_i, - input axi_pkg::cache_t req_dst_cache_i, - input logic req_dst_lock_i, - input axi_pkg::prot_t req_dst_prot_i, - input axi_pkg::qos_t req_dst_qos_i, - input axi_pkg::region_t req_dst_region_i, - input logic req_decouple_aw_i, - input logic req_decouple_rw_i, - input logic [2:0] req_src_max_llen_i, - input logic [2:0] req_dst_max_llen_i, - input logic req_src_reduce_len_i, - input logic req_dst_reduce_len_i, - input logic req_last_i, - - output logic rsp_valid_o, - input logic rsp_ready_i, - - output axi_pkg::resp_t rsp_cause_o, - output idma_pkg::err_type_t rsp_err_type_o, - output addr_t rsp_burst_addr_o, - output logic rsp_error_o, - output logic rsp_last_o, - - input logic eh_req_valid_i, - output logic eh_req_ready_o, - input idma_pkg::idma_eh_req_t eh_req_i, - - output id_t axi_ar_id_o, - output addr_t axi_ar_addr_o, - output axi_pkg::len_t axi_ar_len_o, - output axi_pkg::size_t axi_ar_size_o, - output axi_pkg::burst_t axi_ar_burst_o, - output logic axi_ar_lock_o, - output axi_pkg::cache_t axi_ar_cache_o, - output axi_pkg::prot_t axi_ar_prot_o, - output axi_pkg::qos_t axi_ar_qos_o, - output axi_pkg::region_t axi_ar_region_o, - output user_t axi_ar_user_o, - output logic axi_ar_valid_o, - input logic axi_ar_ready_i, - input id_t axi_r_id_i, - input data_t axi_r_data_i, - input axi_pkg::resp_t axi_r_resp_i, - input logic axi_r_last_i, - input user_t axi_r_user_i, - input logic axi_r_valid_i, - output logic axi_r_ready_o, - - - output id_t axi_aw_id_o, - output addr_t axi_aw_addr_o, - output axi_pkg::len_t axi_aw_len_o, - output axi_pkg::size_t axi_aw_size_o, - output axi_pkg::burst_t axi_aw_burst_o, - output logic axi_aw_lock_o, - output axi_pkg::cache_t axi_aw_cache_o, - output axi_pkg::prot_t axi_aw_prot_o, - output axi_pkg::qos_t axi_aw_qos_o, - output axi_pkg::region_t axi_aw_region_o, - output axi_pkg::atop_t axi_aw_atop_o, - output user_t axi_aw_user_o, - output logic axi_aw_valid_o, - input logic axi_aw_ready_i, - output data_t axi_w_data_o, - output strb_t axi_w_strb_o, - output logic axi_w_last_o, - output user_t axi_w_user_o, - output logic axi_w_valid_o, - input logic axi_w_ready_i, - input id_t axi_b_id_i, - input axi_pkg::resp_t axi_b_resp_i, - input user_t axi_b_user_i, - input logic axi_b_valid_i, - output logic axi_b_ready_o, - - - output idma_pkg::idma_busy_t idma_busy_o -); - - /// Define the error handling capability - localparam idma_pkg::error_cap_e ErrorCap = ErrorHandling ? idma_pkg::ERROR_HANDLING : - idma_pkg::NO_ERROR_HANDLING; - - // AXI4+ATOP typedefs -`AXI_TYPEDEF_AW_CHAN_T(axi_aw_chan_t, addr_t, id_t, user_t) -`AXI_TYPEDEF_W_CHAN_T(axi_w_chan_t, data_t, strb_t, user_t) -`AXI_TYPEDEF_B_CHAN_T(axi_b_chan_t, id_t, user_t) - -`AXI_TYPEDEF_AR_CHAN_T(axi_ar_chan_t, addr_t, id_t, user_t) -`AXI_TYPEDEF_R_CHAN_T(axi_r_chan_t, data_t, id_t, user_t) - -`AXI_TYPEDEF_REQ_T(axi_req_t, axi_aw_chan_t, axi_w_chan_t, axi_ar_chan_t) -`AXI_TYPEDEF_RESP_T(axi_rsp_t, axi_b_chan_t, axi_r_chan_t) - - - // Meta Channel Widths - localparam int unsigned axi_aw_chan_width = axi_pkg::aw_width(AddrWidth, AxiIdWidth, UserWidth); - localparam int unsigned axi_ar_chan_width = axi_pkg::ar_width(AddrWidth, AxiIdWidth, UserWidth); - - /// Option struct: AXI4 id as well as AXI and backend options - /// - `last`: a flag can be set if this transfer is the last of a set of transfers - `IDMA_TYPEDEF_OPTIONS_T(options_t, id_t) - - /// 1D iDMA request type: - /// - `length`: the length of the transfer in bytes - /// - `*_addr`: the source / target byte addresses of the transfer - /// - `opt`: the options field - `IDMA_TYPEDEF_REQ_T(idma_req_t, tf_len_t, addr_t, options_t) - - /// 1D iDMA response payload: - /// - `cause`: the AXI response - /// - `err_type`: type of the error: read, write, internal, ... - /// - `burst_addr`: the burst address where the issue error occurred - `IDMA_TYPEDEF_ERR_PAYLOAD_T(err_payload_t, addr_t) - - /// 1D iDMA response type: - /// - `last`: the response of the request that was marked with the `opt.last` flag - /// - `error`: 1 if an error occurred - /// - `pld`: the error payload - `IDMA_TYPEDEF_RSP_T(idma_rsp_t, err_payload_t) - - - typedef struct packed { - axi_ar_chan_t ar_chan; - } axi_read_meta_channel_t; - - typedef struct packed { - axi_read_meta_channel_t axi; - } read_meta_channel_t; - - typedef struct packed { - axi_aw_chan_t aw_chan; - } axi_write_meta_channel_t; - - typedef struct packed { - axi_write_meta_channel_t axi; - } write_meta_channel_t; - - // local types - // AXI4+ATOP request and response - axi_req_t axi_read_req; - axi_rsp_t axi_read_rsp; - - axi_req_t axi_write_req; - axi_rsp_t axi_write_rsp; - - idma_req_t idma_req; - idma_rsp_t idma_rsp; - - idma_backend_rw_axi #( - .CombinedShifter ( CombinedShifter ), - .DataWidth ( DataWidth ), - .AddrWidth ( AddrWidth ), - .AxiIdWidth ( AxiIdWidth ), - .UserWidth ( UserWidth ), - .TFLenWidth ( TFLenWidth ), - .MaskInvalidData ( MaskInvalidData ), - .BufferDepth ( BufferDepth ), - .NumAxInFlight ( NumAxInFlight ), - .MemSysDepth ( MemSysDepth ), - .RAWCouplingAvail ( RAWCouplingAvail ), - .HardwareLegalizer ( HardwareLegalizer ), - .RejectZeroTransfers ( RejectZeroTransfers ), - .ErrorCap ( ErrorCap ), - .idma_req_t ( idma_req_t ), - .idma_rsp_t ( idma_rsp_t ), - .idma_eh_req_t ( idma_pkg::idma_eh_req_t ), - .idma_busy_t ( idma_pkg::idma_busy_t ), - .axi_req_t ( axi_req_t ), - .axi_rsp_t ( axi_rsp_t ), - .write_meta_channel_t ( write_meta_channel_t ), - .read_meta_channel_t ( read_meta_channel_t ) - ) i_idma_backend ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( test_i ), - .idma_req_i ( idma_req ), - .req_valid_i ( req_valid_i ), - .req_ready_o ( req_ready_o ), - .idma_rsp_o ( idma_rsp ), - .rsp_valid_o ( rsp_valid_o ), - .rsp_ready_i ( rsp_ready_i ), - .idma_eh_req_i ( eh_req_i ), - .eh_req_valid_i ( eh_req_valid_i ), - .eh_req_ready_o ( eh_req_ready_o ), - .axi_read_req_o ( axi_read_req ), - .axi_read_rsp_i ( axi_read_rsp ), - .axi_write_req_o ( axi_write_req ), - .axi_write_rsp_i ( axi_write_rsp ), - .busy_o ( idma_busy_o ) + .dp_poison_i ( dp_poison ), + .r_dp_busy_o ( busy_o.r_dp_busy ), + .w_dp_busy_o ( busy_o.w_dp_busy ), + .buffer_busy_o ( busy_o.buffer_busy ), + .r_chan_ready_o ( r_chan_ready ), + .r_chan_valid_o ( r_chan_valid ) ); - // flatten structs - assign idma_req.dst_addr = req_dst_addr_i; - assign idma_req.src_addr = req_src_addr_i; - assign idma_req.length = req_length_i; - assign idma_req.opt.src_protocol = req_src_protocol_i; - assign idma_req.opt.dst_protocol = req_dst_protocol_i; - assign idma_req.opt.axi_id = req_axi_id_i; - assign idma_req.opt.dst.cache = req_dst_cache_i; - assign idma_req.opt.dst.burst = req_dst_burst_i; - assign idma_req.opt.dst.qos = req_dst_qos_i; - assign idma_req.opt.dst.lock = req_dst_lock_i; - assign idma_req.opt.dst.prot = req_dst_prot_i; - assign idma_req.opt.dst.region = req_dst_region_i; - assign idma_req.opt.src.cache = req_src_cache_i; - assign idma_req.opt.src.burst = req_src_burst_i; - assign idma_req.opt.src.qos = req_src_qos_i; - assign idma_req.opt.src.lock = req_src_lock_i; - assign idma_req.opt.src.prot = req_src_prot_i; - assign idma_req.opt.src.region = req_src_region_i; - assign idma_req.opt.beo.dst_reduce_len = req_dst_reduce_len_i; - assign idma_req.opt.beo.src_reduce_len = req_src_reduce_len_i; - assign idma_req.opt.beo.dst_max_llen = req_dst_max_llen_i; - assign idma_req.opt.beo.src_max_llen = req_src_max_llen_i; - assign idma_req.opt.beo.decouple_rw = req_decouple_rw_i; - assign idma_req.opt.beo.decouple_aw = req_decouple_aw_i; - assign idma_req.opt.last = req_last_i; - - assign rsp_cause_o = idma_rsp.pld.cause; - assign rsp_err_type_o = idma_rsp.pld.err_type; - assign rsp_burst_addr_o = idma_rsp.pld.burst_addr; - assign rsp_error_o = idma_rsp.error; - assign rsp_last_o = idma_rsp.last; - + //-------------------------------------- + // R-AW channel coupler + //-------------------------------------- + assign w_meta_req_tagged = '{ + dst_protocol: w_req.w_dp_req.dst_protocol, + aw_req: w_req.aw_req + }; - // AXI4+ATOP Read - assign axi_ar_id_o = axi_read_req.ar.id; - assign axi_ar_addr_o = axi_read_req.ar.addr; - assign axi_ar_len_o = axi_read_req.ar.len; - assign axi_ar_size_o = axi_read_req.ar.size; - assign axi_ar_burst_o = axi_read_req.ar.burst; - assign axi_ar_lock_o = axi_read_req.ar.lock; - assign axi_ar_cache_o = axi_read_req.ar.cache; - assign axi_ar_prot_o = axi_read_req.ar.prot; - assign axi_ar_qos_o = axi_read_req.ar.qos; - assign axi_ar_region_o = axi_read_req.ar.region; - assign axi_ar_user_o = axi_read_req.ar.user; - assign axi_ar_valid_o = axi_read_req.ar_valid; - assign axi_r_ready_o = axi_read_req.r_ready; - - assign axi_read_rsp.ar_ready = axi_ar_ready_i; - assign axi_read_rsp.r.id = axi_r_id_i; - assign axi_read_rsp.r.data = axi_r_data_i; - assign axi_read_rsp.r.resp = axi_r_resp_i; - assign axi_read_rsp.r.last = axi_r_last_i; - assign axi_read_rsp.r.user = axi_r_user_i; - assign axi_read_rsp.r_valid = axi_r_valid_i; - + if (RAWCouplingAvail) begin : gen_r_aw_coupler + `IDMA_NONSYNTH_BLOCK( + initial begin + $fatal(1, "Channel Coupler only implemented for AXI DMAs!"); + end + ) + end else begin : gen_r_aw_bypass + // Atleast one write protocol uses combined aw and w -> Need to buffer read meta requests + // As a write could depend on up to two reads + stream_fifo_optimal_wrap #( + .Depth ( 2 ), + .type_t ( write_meta_channel_tagged_t ), + .PrintInfo ( PrintFifoInfo ) + ) i_aw_fifo ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( 1'b0 ), + .usage_o ( /* NOT CONNECTED */ ), + .data_i ( w_meta_req_tagged ), + .valid_i ( w_valid && aw_ready ), + .ready_o ( aw_ready ), + .data_o ( aw_req_dp ), + .valid_o ( aw_valid_dp ), + .ready_i ( aw_ready_dp && aw_valid_dp ) + ); + // no unit: not busy + assign busy_o.raw_coupler_busy = 1'b0; + end - // AXI4+ATOP Write - assign axi_aw_id_o = axi_write_req.aw.id; - assign axi_aw_addr_o = axi_write_req.aw.addr; - assign axi_aw_len_o = axi_write_req.aw.len; - assign axi_aw_size_o = axi_write_req.aw.size; - assign axi_aw_burst_o = axi_write_req.aw.burst; - assign axi_aw_lock_o = axi_write_req.aw.lock; - assign axi_aw_cache_o = axi_write_req.aw.cache; - assign axi_aw_prot_o = axi_write_req.aw.prot; - assign axi_aw_qos_o = axi_write_req.aw.qos; - assign axi_aw_region_o = axi_write_req.aw.region; - assign axi_aw_atop_o = axi_write_req.aw.atop; - assign axi_aw_user_o = axi_write_req.aw.user; - assign axi_aw_valid_o = axi_write_req.aw_valid; - assign axi_w_data_o = axi_write_req.w.data; - assign axi_w_strb_o = axi_write_req.w.strb; - assign axi_w_last_o = axi_write_req.w.last; - assign axi_w_user_o = axi_write_req.w.user; - assign axi_w_valid_o = axi_write_req.w_valid; - assign axi_b_ready_o = axi_write_req.b_ready; - - assign axi_write_rsp.aw_ready = axi_aw_ready_i; - assign axi_write_rsp.w_ready = axi_w_ready_i; - assign axi_write_rsp.b.id = axi_b_id_i; - assign axi_write_rsp.b.resp = axi_b_resp_i; - assign axi_write_rsp.b.user = axi_b_user_i; - assign axi_write_rsp.b_valid = axi_b_valid_i; - + //-------------------------------------- + // Assertions + //-------------------------------------- + `IDMA_NONSYNTH_BLOCK( + initial begin : proc_assert_params + axi_addr_width : assert(AddrWidth >= 32'd12) else + $fatal(1, "Parameter `AddrWidth` has to be >= 12!"); + axi_id_width : assert(AxiIdWidth > 32'd0) else + $fatal(1, "Parameter `AxiIdWidth` has to be > 0!"); + axi_data_width : assert(DataWidth inside {32'd16, 32'd32, 32'd64, 32'd128, 32'd256, + 32'd512, 32'd1028}) else + $fatal(1, "Parameter `DataWidth` has to be at least 16 and inside the AXI4 spec!"); + axi_user_width : assert(UserWidth > 32'd0) else + $fatal(1, "Parameter `UserWidth` has to be > 0!"); + num_ax_in_flight : assert(NumAxInFlight > 32'd1) else + $fatal(1, "Parameter `NumAxInFlight` has to be > 1!"); + buffer_depth : assert(BufferDepth > 32'd1) else + $fatal(1, "Parameter `BufferDepth` has to be > 1!"); + tf_len_width : assert(TFLenWidth >= 32'd12) else + $fatal(1, "Parameter `BufferDepth` has to be >= 12!"); + tf_len_width_max : assert(TFLenWidth <= AddrWidth) else + $fatal(1, "Parameter `TFLenWidth` has to be <= `AddrWidth`!"); + end + ) endmodule @@ -11313,7 +9228,7 @@ endmodule `include "tilelink/typedef.svh" /// Synthesis wrapper for the iDMA backend. Unpacks all the interfaces to simple logic vectors -module idma_backend_synth_r_obi_w_axi #( +module idma_backend_synth_rw_axi #( /// Data width parameter int unsigned DataWidth = 32'd32, /// Address width @@ -11339,7 +9254,7 @@ module idma_backend_synth_r_obi_w_axi #( /// Mask invalid data on the manager interface parameter bit MaskInvalidData = 1'b1, /// Should the `R`-`AW` coupling hardware be present? (recommended) - parameter bit RAWCouplingAvail = 0, + parameter bit RAWCouplingAvail = 1, /// Should hardware legalization be present? (recommended) /// If not, software legalization is required to ensure the transfers are /// AXI4-conformal @@ -11347,7 +9262,7 @@ module idma_backend_synth_r_obi_w_axi #( /// Reject zero-length transfers parameter bit RejectZeroTransfers = 1'b1, /// Should the error handler be present? - parameter bit ErrorHandling = 1'b0, + parameter bit ErrorHandling = 1'b1, // Dependent parameters; do not override! /// Strobe Width (do not override!) parameter int unsigned StrbWidth = DataWidth / 8, @@ -11414,18 +9329,26 @@ module idma_backend_synth_r_obi_w_axi #( output logic eh_req_ready_o, input idma_pkg::idma_eh_req_t eh_req_i, - output logic obi_read_req_a_req_o, - output addr_t obi_read_req_a_addr_o, - output logic obi_read_req_a_we_o, - output strb_t obi_read_req_a_be_o, - output data_t obi_read_req_a_wdata_o, - output logic obi_read_req_r_ready_o, - - input logic obi_read_rsp_a_gnt_i, - input logic obi_read_rsp_r_valid_i, - input data_t obi_read_rsp_r_rdata_i, - input id_t obi_read_rsp_r_rid_i, - input logic obi_read_rsp_r_err_i, + output id_t axi_ar_id_o, + output addr_t axi_ar_addr_o, + output axi_pkg::len_t axi_ar_len_o, + output axi_pkg::size_t axi_ar_size_o, + output axi_pkg::burst_t axi_ar_burst_o, + output logic axi_ar_lock_o, + output axi_pkg::cache_t axi_ar_cache_o, + output axi_pkg::prot_t axi_ar_prot_o, + output axi_pkg::qos_t axi_ar_qos_o, + output axi_pkg::region_t axi_ar_region_o, + output user_t axi_ar_user_o, + output logic axi_ar_valid_o, + input logic axi_ar_ready_i, + input id_t axi_r_id_i, + input data_t axi_r_data_i, + input axi_pkg::resp_t axi_r_resp_i, + input logic axi_r_last_i, + input user_t axi_r_user_i, + input logic axi_r_valid_i, + output logic axi_r_ready_o, output id_t axi_aw_id_o, @@ -11474,20 +9397,9 @@ module idma_backend_synth_r_obi_w_axi #( `AXI_TYPEDEF_RESP_T(axi_rsp_t, axi_b_chan_t, axi_r_chan_t) - // OBI typedefs -`OBI_TYPEDEF_MINIMAL_A_OPTIONAL(a_optional_t) -`OBI_TYPEDEF_MINIMAL_R_OPTIONAL(r_optional_t) - -`OBI_TYPEDEF_TYPE_A_CHAN_T(obi_a_chan_t, addr_t, data_t, strb_t, id_t, a_optional_t) -`OBI_TYPEDEF_TYPE_R_CHAN_T(obi_r_chan_t, data_t, id_t, r_optional_t) - -`OBI_TYPEDEF_REQ_T(obi_req_t, obi_a_chan_t) -`OBI_TYPEDEF_RSP_T(obi_rsp_t, obi_r_chan_t) - - // Meta Channel Widths localparam int unsigned axi_aw_chan_width = axi_pkg::aw_width(AddrWidth, AxiIdWidth, UserWidth); - localparam int unsigned obi_a_chan_width = $bits(obi_a_chan_t); + localparam int unsigned axi_ar_chan_width = axi_pkg::ar_width(AddrWidth, AxiIdWidth, UserWidth); /// Option struct: AXI4 id as well as AXI and backend options /// - `last`: a flag can be set if this transfer is the last of a set of transfers @@ -11513,11 +9425,11 @@ module idma_backend_synth_r_obi_w_axi #( typedef struct packed { - obi_a_chan_t a_chan; - } obi_read_meta_channel_t; + axi_ar_chan_t ar_chan; + } axi_read_meta_channel_t; typedef struct packed { - obi_read_meta_channel_t obi; + axi_read_meta_channel_t axi; } read_meta_channel_t; typedef struct packed { @@ -11530,19 +9442,16 @@ module idma_backend_synth_r_obi_w_axi #( // local types // AXI4+ATOP request and response + axi_req_t axi_read_req; + axi_rsp_t axi_read_rsp; axi_req_t axi_write_req; axi_rsp_t axi_write_rsp; - // OBI request and response - obi_req_t obi_read_req; - obi_rsp_t obi_read_rsp; - - idma_req_t idma_req; idma_rsp_t idma_rsp; - idma_backend_r_obi_w_axi #( + idma_backend_rw_axi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -11563,8 +9472,6 @@ module idma_backend_synth_r_obi_w_axi #( .idma_busy_t ( idma_pkg::idma_busy_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), .read_meta_channel_t ( read_meta_channel_t ) ) i_idma_backend ( @@ -11580,8 +9487,8 @@ module idma_backend_synth_r_obi_w_axi #( .idma_eh_req_i ( eh_req_i ), .eh_req_valid_i ( eh_req_valid_i ), .eh_req_ready_o ( eh_req_ready_o ), - .obi_read_req_o ( obi_read_req ), - .obi_read_rsp_i ( obi_read_rsp ), + .axi_read_req_o ( axi_read_req ), + .axi_read_rsp_i ( axi_read_rsp ), .axi_write_req_o ( axi_write_req ), .axi_write_rsp_i ( axi_write_rsp ), .busy_o ( idma_busy_o ) @@ -11621,19 +9528,28 @@ module idma_backend_synth_r_obi_w_axi #( assign rsp_last_o = idma_rsp.last; - // OBI Read - assign obi_read_req_a_req_o = obi_read_req.req; - assign obi_read_req_a_addr_o = obi_read_req.a.addr; - assign obi_read_req_a_we_o = obi_read_req.a.we; - assign obi_read_req_a_be_o = obi_read_req.a.be; - assign obi_read_req_a_wdata_o = obi_read_req.a.wdata; - assign obi_read_req_r_ready_o = obi_read_req.rready; + // AXI4+ATOP Read + assign axi_ar_id_o = axi_read_req.ar.id; + assign axi_ar_addr_o = axi_read_req.ar.addr; + assign axi_ar_len_o = axi_read_req.ar.len; + assign axi_ar_size_o = axi_read_req.ar.size; + assign axi_ar_burst_o = axi_read_req.ar.burst; + assign axi_ar_lock_o = axi_read_req.ar.lock; + assign axi_ar_cache_o = axi_read_req.ar.cache; + assign axi_ar_prot_o = axi_read_req.ar.prot; + assign axi_ar_qos_o = axi_read_req.ar.qos; + assign axi_ar_region_o = axi_read_req.ar.region; + assign axi_ar_user_o = axi_read_req.ar.user; + assign axi_ar_valid_o = axi_read_req.ar_valid; + assign axi_r_ready_o = axi_read_req.r_ready; - assign obi_read_rsp.gnt = obi_read_rsp_a_gnt_i; - assign obi_read_rsp.rvalid = obi_read_rsp_r_valid_i; - assign obi_read_rsp.r.rdata = obi_read_rsp_r_rdata_i; - assign obi_read_rsp.r.rid = obi_read_rsp_r_rid_i; - assign obi_read_rsp.r.err = obi_read_rsp_r_err_i; + assign axi_read_rsp.ar_ready = axi_ar_ready_i; + assign axi_read_rsp.r.id = axi_r_id_i; + assign axi_read_rsp.r.data = axi_r_data_i; + assign axi_read_rsp.r.resp = axi_r_resp_i; + assign axi_read_rsp.r.last = axi_r_last_i; + assign axi_read_rsp.r.user = axi_r_user_i; + assign axi_read_rsp.r_valid = axi_r_valid_i; @@ -11684,7 +9600,7 @@ endmodule `include "tilelink/typedef.svh" /// Synthesis wrapper for the iDMA backend. Unpacks all the interfaces to simple logic vectors -module idma_backend_synth_r_axi_w_obi #( +module idma_backend_synth_r_obi_w_axi #( /// Data width parameter int unsigned DataWidth = 32'd32, /// Address width @@ -11785,39 +9701,45 @@ module idma_backend_synth_r_axi_w_obi #( output logic eh_req_ready_o, input idma_pkg::idma_eh_req_t eh_req_i, - output id_t axi_ar_id_o, - output addr_t axi_ar_addr_o, - output axi_pkg::len_t axi_ar_len_o, - output axi_pkg::size_t axi_ar_size_o, - output axi_pkg::burst_t axi_ar_burst_o, - output logic axi_ar_lock_o, - output axi_pkg::cache_t axi_ar_cache_o, - output axi_pkg::prot_t axi_ar_prot_o, - output axi_pkg::qos_t axi_ar_qos_o, - output axi_pkg::region_t axi_ar_region_o, - output user_t axi_ar_user_o, - output logic axi_ar_valid_o, - input logic axi_ar_ready_i, - input id_t axi_r_id_i, - input data_t axi_r_data_i, - input axi_pkg::resp_t axi_r_resp_i, - input logic axi_r_last_i, - input user_t axi_r_user_i, - input logic axi_r_valid_i, - output logic axi_r_ready_o, + output logic obi_read_req_a_req_o, + output addr_t obi_read_req_a_addr_o, + output logic obi_read_req_a_we_o, + output strb_t obi_read_req_a_be_o, + output data_t obi_read_req_a_wdata_o, + output logic obi_read_req_r_ready_o, - - output logic obi_write_req_a_req_o, - output addr_t obi_write_req_a_addr_o, - output logic obi_write_req_a_we_o, - output strb_t obi_write_req_a_be_o, - output data_t obi_write_req_a_wdata_o, - output id_t obi_write_req_a_aid_o, - output logic obi_write_req_r_ready_o, + input logic obi_read_rsp_a_gnt_i, + input logic obi_read_rsp_r_valid_i, + input data_t obi_read_rsp_r_rdata_i, + input id_t obi_read_rsp_r_rid_i, + input logic obi_read_rsp_r_err_i, - input logic obi_write_rsp_a_gnt_i, - input logic obi_write_rsp_r_valid_i, - input data_t obi_write_rsp_r_rdata_i, + + output id_t axi_aw_id_o, + output addr_t axi_aw_addr_o, + output axi_pkg::len_t axi_aw_len_o, + output axi_pkg::size_t axi_aw_size_o, + output axi_pkg::burst_t axi_aw_burst_o, + output logic axi_aw_lock_o, + output axi_pkg::cache_t axi_aw_cache_o, + output axi_pkg::prot_t axi_aw_prot_o, + output axi_pkg::qos_t axi_aw_qos_o, + output axi_pkg::region_t axi_aw_region_o, + output axi_pkg::atop_t axi_aw_atop_o, + output user_t axi_aw_user_o, + output logic axi_aw_valid_o, + input logic axi_aw_ready_i, + output data_t axi_w_data_o, + output strb_t axi_w_strb_o, + output logic axi_w_last_o, + output user_t axi_w_user_o, + output logic axi_w_valid_o, + input logic axi_w_ready_i, + input id_t axi_b_id_i, + input axi_pkg::resp_t axi_b_resp_i, + input user_t axi_b_user_i, + input logic axi_b_valid_i, + output logic axi_b_ready_o, output idma_pkg::idma_busy_t idma_busy_o @@ -11851,7 +9773,7 @@ module idma_backend_synth_r_axi_w_obi #( // Meta Channel Widths - localparam int unsigned axi_ar_chan_width = axi_pkg::ar_width(AddrWidth, AxiIdWidth, UserWidth); + localparam int unsigned axi_aw_chan_width = axi_pkg::aw_width(AddrWidth, AxiIdWidth, UserWidth); localparam int unsigned obi_a_chan_width = $bits(obi_a_chan_t); /// Option struct: AXI4 id as well as AXI and backend options @@ -11878,36 +9800,36 @@ module idma_backend_synth_r_axi_w_obi #( typedef struct packed { - axi_ar_chan_t ar_chan; - } axi_read_meta_channel_t; + obi_a_chan_t a_chan; + } obi_read_meta_channel_t; typedef struct packed { - axi_read_meta_channel_t axi; + obi_read_meta_channel_t obi; } read_meta_channel_t; typedef struct packed { - obi_a_chan_t a_chan; - } obi_write_meta_channel_t; + axi_aw_chan_t aw_chan; + } axi_write_meta_channel_t; typedef struct packed { - obi_write_meta_channel_t obi; + axi_write_meta_channel_t axi; } write_meta_channel_t; // local types // AXI4+ATOP request and response - axi_req_t axi_read_req; - axi_rsp_t axi_read_rsp; + axi_req_t axi_write_req; + axi_rsp_t axi_write_rsp; // OBI request and response + obi_req_t obi_read_req; + obi_rsp_t obi_read_rsp; - obi_req_t obi_write_req; - obi_rsp_t obi_write_rsp; idma_req_t idma_req; idma_rsp_t idma_rsp; - idma_backend_r_axi_w_obi #( + idma_backend_r_obi_w_axi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -11945,10 +9867,10 @@ module idma_backend_synth_r_axi_w_obi #( .idma_eh_req_i ( eh_req_i ), .eh_req_valid_i ( eh_req_valid_i ), .eh_req_ready_o ( eh_req_ready_o ), - .axi_read_req_o ( axi_read_req ), - .axi_read_rsp_i ( axi_read_rsp ), - .obi_write_req_o ( obi_write_req ), - .obi_write_rsp_i ( obi_write_rsp ), + .obi_read_req_o ( obi_read_req ), + .obi_read_rsp_i ( obi_read_rsp ), + .axi_write_req_o ( axi_write_req ), + .axi_write_rsp_i ( axi_write_rsp ), .busy_o ( idma_busy_o ) ); @@ -11986,43 +9908,49 @@ module idma_backend_synth_r_axi_w_obi #( assign rsp_last_o = idma_rsp.last; - // AXI4+ATOP Read - assign axi_ar_id_o = axi_read_req.ar.id; - assign axi_ar_addr_o = axi_read_req.ar.addr; - assign axi_ar_len_o = axi_read_req.ar.len; - assign axi_ar_size_o = axi_read_req.ar.size; - assign axi_ar_burst_o = axi_read_req.ar.burst; - assign axi_ar_lock_o = axi_read_req.ar.lock; - assign axi_ar_cache_o = axi_read_req.ar.cache; - assign axi_ar_prot_o = axi_read_req.ar.prot; - assign axi_ar_qos_o = axi_read_req.ar.qos; - assign axi_ar_region_o = axi_read_req.ar.region; - assign axi_ar_user_o = axi_read_req.ar.user; - assign axi_ar_valid_o = axi_read_req.ar_valid; - assign axi_r_ready_o = axi_read_req.r_ready; + // OBI Read + assign obi_read_req_a_req_o = obi_read_req.req; + assign obi_read_req_a_addr_o = obi_read_req.a.addr; + assign obi_read_req_a_we_o = obi_read_req.a.we; + assign obi_read_req_a_be_o = obi_read_req.a.be; + assign obi_read_req_a_wdata_o = obi_read_req.a.wdata; + assign obi_read_req_r_ready_o = obi_read_req.rready; - assign axi_read_rsp.ar_ready = axi_ar_ready_i; - assign axi_read_rsp.r.id = axi_r_id_i; - assign axi_read_rsp.r.data = axi_r_data_i; - assign axi_read_rsp.r.resp = axi_r_resp_i; - assign axi_read_rsp.r.last = axi_r_last_i; - assign axi_read_rsp.r.user = axi_r_user_i; - assign axi_read_rsp.r_valid = axi_r_valid_i; + assign obi_read_rsp.gnt = obi_read_rsp_a_gnt_i; + assign obi_read_rsp.rvalid = obi_read_rsp_r_valid_i; + assign obi_read_rsp.r.rdata = obi_read_rsp_r_rdata_i; + assign obi_read_rsp.r.rid = obi_read_rsp_r_rid_i; + assign obi_read_rsp.r.err = obi_read_rsp_r_err_i; - // OBI Write - assign obi_write_req_a_req_o = obi_write_req.req; - assign obi_write_req_a_addr_o = obi_write_req.a.addr; - assign obi_write_req_a_we_o = obi_write_req.a.we; - assign obi_write_req_a_be_o = obi_write_req.a.be; - assign obi_write_req_a_wdata_o = obi_write_req.a.wdata; - assign obi_write_req_a_aid_o = obi_write_req.a.aid; - assign obi_write_req_r_ready_o = obi_write_req.rready; + // AXI4+ATOP Write + assign axi_aw_id_o = axi_write_req.aw.id; + assign axi_aw_addr_o = axi_write_req.aw.addr; + assign axi_aw_len_o = axi_write_req.aw.len; + assign axi_aw_size_o = axi_write_req.aw.size; + assign axi_aw_burst_o = axi_write_req.aw.burst; + assign axi_aw_lock_o = axi_write_req.aw.lock; + assign axi_aw_cache_o = axi_write_req.aw.cache; + assign axi_aw_prot_o = axi_write_req.aw.prot; + assign axi_aw_qos_o = axi_write_req.aw.qos; + assign axi_aw_region_o = axi_write_req.aw.region; + assign axi_aw_atop_o = axi_write_req.aw.atop; + assign axi_aw_user_o = axi_write_req.aw.user; + assign axi_aw_valid_o = axi_write_req.aw_valid; + assign axi_w_data_o = axi_write_req.w.data; + assign axi_w_strb_o = axi_write_req.w.strb; + assign axi_w_last_o = axi_write_req.w.last; + assign axi_w_user_o = axi_write_req.w.user; + assign axi_w_valid_o = axi_write_req.w_valid; + assign axi_b_ready_o = axi_write_req.b_ready; - assign obi_write_rsp.gnt = obi_write_rsp_a_gnt_i; - assign obi_write_rsp.rvalid = obi_write_rsp_r_valid_i; - assign obi_write_rsp.r.rdata = obi_write_rsp_r_rdata_i; + assign axi_write_rsp.aw_ready = axi_aw_ready_i; + assign axi_write_rsp.w_ready = axi_w_ready_i; + assign axi_write_rsp.b.id = axi_b_id_i; + assign axi_write_rsp.b.resp = axi_b_resp_i; + assign axi_write_rsp.b.user = axi_b_user_i; + assign axi_write_rsp.b_valid = axi_b_valid_i; @@ -12043,7 +9971,7 @@ endmodule `include "tilelink/typedef.svh" /// Synthesis wrapper for the iDMA backend. Unpacks all the interfaces to simple logic vectors -module idma_backend_synth_rw_axi_rw_axis #( +module idma_backend_synth_r_axi_w_obi #( /// Data width parameter int unsigned DataWidth = 32'd32, /// Address width @@ -12166,55 +10094,17 @@ module idma_backend_synth_rw_axi_rw_axis #( output logic axi_r_ready_o, - input data_t axis_read_data_i, - input strb_t axis_read_strb_i, - input strb_t axis_read_keep_i, - input logic axis_read_last_i, - input id_t axis_read_id_i, - input id_t axis_read_dest_i, - input user_t axis_read_user_i, - input logic axis_read_tvalid_i, - - output logic axis_read_tready_o, - - - output id_t axi_aw_id_o, - output addr_t axi_aw_addr_o, - output axi_pkg::len_t axi_aw_len_o, - output axi_pkg::size_t axi_aw_size_o, - output axi_pkg::burst_t axi_aw_burst_o, - output logic axi_aw_lock_o, - output axi_pkg::cache_t axi_aw_cache_o, - output axi_pkg::prot_t axi_aw_prot_o, - output axi_pkg::qos_t axi_aw_qos_o, - output axi_pkg::region_t axi_aw_region_o, - output axi_pkg::atop_t axi_aw_atop_o, - output user_t axi_aw_user_o, - output logic axi_aw_valid_o, - input logic axi_aw_ready_i, - output data_t axi_w_data_o, - output strb_t axi_w_strb_o, - output logic axi_w_last_o, - output user_t axi_w_user_o, - output logic axi_w_valid_o, - input logic axi_w_ready_i, - input id_t axi_b_id_i, - input axi_pkg::resp_t axi_b_resp_i, - input user_t axi_b_user_i, - input logic axi_b_valid_i, - output logic axi_b_ready_o, - - - output data_t axis_write_data_o, - output strb_t axis_write_strb_o, - output strb_t axis_write_keep_o, - output logic axis_write_last_o, - output id_t axis_write_id_o, - output id_t axis_write_dest_o, - output user_t axis_write_user_o, - output logic axis_write_tvalid_o, + output logic obi_write_req_a_req_o, + output addr_t obi_write_req_a_addr_o, + output logic obi_write_req_a_we_o, + output strb_t obi_write_req_a_be_o, + output data_t obi_write_req_a_wdata_o, + output id_t obi_write_req_a_aid_o, + output logic obi_write_req_r_ready_o, - input logic axis_write_tready_i, + input logic obi_write_rsp_a_gnt_i, + input logic obi_write_rsp_r_valid_i, + input data_t obi_write_rsp_r_rdata_i, output idma_pkg::idma_busy_t idma_busy_o @@ -12236,17 +10126,20 @@ module idma_backend_synth_rw_axi_rw_axis #( `AXI_TYPEDEF_RESP_T(axi_rsp_t, axi_b_chan_t, axi_r_chan_t) - // AXI Stream typedefs -`AXI_STREAM_TYPEDEF_S_CHAN_T(axis_t_chan_t, data_t, strb_t, strb_t, id_t, id_t, user_t) + // OBI typedefs +`OBI_TYPEDEF_MINIMAL_A_OPTIONAL(a_optional_t) +`OBI_TYPEDEF_MINIMAL_R_OPTIONAL(r_optional_t) -`AXI_STREAM_TYPEDEF_REQ_T(axis_req_t, axis_t_chan_t) -`AXI_STREAM_TYPEDEF_RSP_T(axis_rsp_t) +`OBI_TYPEDEF_TYPE_A_CHAN_T(obi_a_chan_t, addr_t, data_t, strb_t, id_t, a_optional_t) +`OBI_TYPEDEF_TYPE_R_CHAN_T(obi_r_chan_t, data_t, id_t, r_optional_t) + +`OBI_TYPEDEF_REQ_T(obi_req_t, obi_a_chan_t) +`OBI_TYPEDEF_RSP_T(obi_rsp_t, obi_r_chan_t) // Meta Channel Widths - localparam int unsigned axi_aw_chan_width = axi_pkg::aw_width(AddrWidth, AxiIdWidth, UserWidth); localparam int unsigned axi_ar_chan_width = axi_pkg::ar_width(AddrWidth, AxiIdWidth, UserWidth); - localparam int unsigned axis_t_chan_width = $bits(axis_t_chan_t); + localparam int unsigned obi_a_chan_width = $bits(obi_a_chan_t); /// Option struct: AXI4 id as well as AXI and backend options /// - `last`: a flag can be set if this transfer is the last of a set of transfers @@ -12270,38 +10163,21 @@ module idma_backend_synth_rw_axi_rw_axis #( /// - `pld`: the error payload `IDMA_TYPEDEF_RSP_T(idma_rsp_t, err_payload_t) - function int unsigned max_width(input int unsigned a, b); - return (a > b) ? a : b; - endfunction typedef struct packed { axi_ar_chan_t ar_chan; - logic[max_width(axi_ar_chan_width, axis_t_chan_width)-axi_ar_chan_width:0] padding; - } axi_read_ar_chan_padded_t; - - typedef struct packed { - axis_t_chan_t t_chan; - logic[max_width(axi_ar_chan_width, axis_t_chan_width)-axis_t_chan_width:0] padding; - } axis_read_t_chan_padded_t; + } axi_read_meta_channel_t; - typedef union packed { - axi_read_ar_chan_padded_t axi; - axis_read_t_chan_padded_t axis; + typedef struct packed { + axi_read_meta_channel_t axi; } read_meta_channel_t; typedef struct packed { - axi_aw_chan_t aw_chan; - logic[max_width(axi_aw_chan_width, axis_t_chan_width)-axi_aw_chan_width:0] padding; - } axi_write_aw_chan_padded_t; + obi_a_chan_t a_chan; + } obi_write_meta_channel_t; typedef struct packed { - axis_t_chan_t t_chan; - logic[max_width(axi_aw_chan_width, axis_t_chan_width)-axis_t_chan_width:0] padding; - } axis_write_t_chan_padded_t; - - typedef union packed { - axi_write_aw_chan_padded_t axi; - axis_write_t_chan_padded_t axis; + obi_write_meta_channel_t obi; } write_meta_channel_t; // local types @@ -12309,20 +10185,16 @@ module idma_backend_synth_rw_axi_rw_axis #( axi_req_t axi_read_req; axi_rsp_t axi_read_rsp; - axi_req_t axi_write_req; - axi_rsp_t axi_write_rsp; - // AXI Stream request and response - axis_req_t axis_read_req; - axis_rsp_t axis_read_rsp; + // OBI request and response - axis_req_t axis_write_req; - axis_rsp_t axis_write_rsp; + obi_req_t obi_write_req; + obi_rsp_t obi_write_rsp; idma_req_t idma_req; idma_rsp_t idma_rsp; - idma_backend_rw_axi_rw_axis #( + idma_backend_r_axi_w_obi #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -12343,8 +10215,8 @@ module idma_backend_synth_rw_axi_rw_axis #( .idma_busy_t ( idma_pkg::idma_busy_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), - .axis_req_t ( axis_req_t ), - .axis_rsp_t ( axis_rsp_t ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), .read_meta_channel_t ( read_meta_channel_t ) ) i_idma_backend ( @@ -12362,12 +10234,8 @@ module idma_backend_synth_rw_axi_rw_axis #( .eh_req_ready_o ( eh_req_ready_o ), .axi_read_req_o ( axi_read_req ), .axi_read_rsp_i ( axi_read_rsp ), - .axis_read_req_i ( axis_read_req ), - .axis_read_rsp_o ( axis_read_rsp ), - .axi_write_req_o ( axi_write_req ), - .axi_write_rsp_i ( axi_write_rsp ), - .axis_write_req_o ( axis_write_req ), - .axis_write_rsp_i ( axis_write_rsp ), + .obi_write_req_o ( obi_write_req ), + .obi_write_rsp_i ( obi_write_rsp ), .busy_o ( idma_busy_o ) ); @@ -12430,61 +10298,18 @@ module idma_backend_synth_rw_axi_rw_axis #( - // AXI Stream Read - assign axis_read_req.t.data = axis_read_data_i; - assign axis_read_req.t.strb = axis_read_strb_i; - assign axis_read_req.t.keep = axis_read_keep_i; - assign axis_read_req.t.last = axis_read_last_i; - assign axis_read_req.t.id = axis_read_id_i; - assign axis_read_req.t.dest = axis_read_dest_i; - assign axis_read_req.t.user = axis_read_user_i; - assign axis_read_req.tvalid = axis_read_tvalid_i; - - assign axis_read_tready_o = axis_read_rsp.tready; - - - - // AXI4+ATOP Write - assign axi_aw_id_o = axi_write_req.aw.id; - assign axi_aw_addr_o = axi_write_req.aw.addr; - assign axi_aw_len_o = axi_write_req.aw.len; - assign axi_aw_size_o = axi_write_req.aw.size; - assign axi_aw_burst_o = axi_write_req.aw.burst; - assign axi_aw_lock_o = axi_write_req.aw.lock; - assign axi_aw_cache_o = axi_write_req.aw.cache; - assign axi_aw_prot_o = axi_write_req.aw.prot; - assign axi_aw_qos_o = axi_write_req.aw.qos; - assign axi_aw_region_o = axi_write_req.aw.region; - assign axi_aw_atop_o = axi_write_req.aw.atop; - assign axi_aw_user_o = axi_write_req.aw.user; - assign axi_aw_valid_o = axi_write_req.aw_valid; - assign axi_w_data_o = axi_write_req.w.data; - assign axi_w_strb_o = axi_write_req.w.strb; - assign axi_w_last_o = axi_write_req.w.last; - assign axi_w_user_o = axi_write_req.w.user; - assign axi_w_valid_o = axi_write_req.w_valid; - assign axi_b_ready_o = axi_write_req.b_ready; - - assign axi_write_rsp.aw_ready = axi_aw_ready_i; - assign axi_write_rsp.w_ready = axi_w_ready_i; - assign axi_write_rsp.b.id = axi_b_id_i; - assign axi_write_rsp.b.resp = axi_b_resp_i; - assign axi_write_rsp.b.user = axi_b_user_i; - assign axi_write_rsp.b_valid = axi_b_valid_i; - - - - // AXI Stream Write - assign axis_write_data_o = axis_write_req.t.data; - assign axis_write_strb_o = axis_write_req.t.strb; - assign axis_write_keep_o = axis_write_req.t.keep; - assign axis_write_last_o = axis_write_req.t.last; - assign axis_write_id_o = axis_write_req.t.id; - assign axis_write_dest_o = axis_write_req.t.dest; - assign axis_write_user_o = axis_write_req.t.user; - assign axis_write_tvalid_o = axis_write_req.tvalid; + // OBI Write + assign obi_write_req_a_req_o = obi_write_req.req; + assign obi_write_req_a_addr_o = obi_write_req.a.addr; + assign obi_write_req_a_we_o = obi_write_req.a.we; + assign obi_write_req_a_be_o = obi_write_req.a.be; + assign obi_write_req_a_wdata_o = obi_write_req.a.wdata; + assign obi_write_req_a_aid_o = obi_write_req.a.aid; + assign obi_write_req_r_ready_o = obi_write_req.rready; - assign axis_write_rsp.tready = axis_write_tready_i; + assign obi_write_rsp.gnt = obi_write_rsp_a_gnt_i; + assign obi_write_rsp.rvalid = obi_write_rsp_r_valid_i; + assign obi_write_rsp.r.rdata = obi_write_rsp_r_rdata_i; @@ -12505,7 +10330,7 @@ endmodule `include "tilelink/typedef.svh" /// Synthesis wrapper for the iDMA backend. Unpacks all the interfaces to simple logic vectors -module idma_backend_synth_rw_axi_rw_obi #( +module idma_backend_synth_rw_axi_rw_axis #( /// Data width parameter int unsigned DataWidth = 32'd32, /// Address width @@ -12628,18 +10453,16 @@ module idma_backend_synth_rw_axi_rw_obi #( output logic axi_r_ready_o, - output logic obi_read_req_a_req_o, - output addr_t obi_read_req_a_addr_o, - output logic obi_read_req_a_we_o, - output strb_t obi_read_req_a_be_o, - output data_t obi_read_req_a_wdata_o, - output logic obi_read_req_r_ready_o, + input data_t axis_read_data_i, + input strb_t axis_read_strb_i, + input strb_t axis_read_keep_i, + input logic axis_read_last_i, + input id_t axis_read_id_i, + input id_t axis_read_dest_i, + input user_t axis_read_user_i, + input logic axis_read_tvalid_i, - input logic obi_read_rsp_a_gnt_i, - input logic obi_read_rsp_r_valid_i, - input data_t obi_read_rsp_r_rdata_i, - input id_t obi_read_rsp_r_rid_i, - input logic obi_read_rsp_r_err_i, + output logic axis_read_tready_o, output id_t axi_aw_id_o, @@ -12669,17 +10492,16 @@ module idma_backend_synth_rw_axi_rw_obi #( output logic axi_b_ready_o, - output logic obi_write_req_a_req_o, - output addr_t obi_write_req_a_addr_o, - output logic obi_write_req_a_we_o, - output strb_t obi_write_req_a_be_o, - output data_t obi_write_req_a_wdata_o, - output id_t obi_write_req_a_aid_o, - output logic obi_write_req_r_ready_o, + output data_t axis_write_data_o, + output strb_t axis_write_strb_o, + output strb_t axis_write_keep_o, + output logic axis_write_last_o, + output id_t axis_write_id_o, + output id_t axis_write_dest_o, + output user_t axis_write_user_o, + output logic axis_write_tvalid_o, - input logic obi_write_rsp_a_gnt_i, - input logic obi_write_rsp_r_valid_i, - input data_t obi_write_rsp_r_rdata_i, + input logic axis_write_tready_i, output idma_pkg::idma_busy_t idma_busy_o @@ -12701,21 +10523,17 @@ module idma_backend_synth_rw_axi_rw_obi #( `AXI_TYPEDEF_RESP_T(axi_rsp_t, axi_b_chan_t, axi_r_chan_t) - // OBI typedefs -`OBI_TYPEDEF_MINIMAL_A_OPTIONAL(a_optional_t) -`OBI_TYPEDEF_MINIMAL_R_OPTIONAL(r_optional_t) - -`OBI_TYPEDEF_TYPE_A_CHAN_T(obi_a_chan_t, addr_t, data_t, strb_t, id_t, a_optional_t) -`OBI_TYPEDEF_TYPE_R_CHAN_T(obi_r_chan_t, data_t, id_t, r_optional_t) + // AXI Stream typedefs +`AXI_STREAM_TYPEDEF_S_CHAN_T(axis_t_chan_t, data_t, strb_t, strb_t, id_t, id_t, user_t) -`OBI_TYPEDEF_REQ_T(obi_req_t, obi_a_chan_t) -`OBI_TYPEDEF_RSP_T(obi_rsp_t, obi_r_chan_t) +`AXI_STREAM_TYPEDEF_REQ_T(axis_req_t, axis_t_chan_t) +`AXI_STREAM_TYPEDEF_RSP_T(axis_rsp_t) // Meta Channel Widths localparam int unsigned axi_aw_chan_width = axi_pkg::aw_width(AddrWidth, AxiIdWidth, UserWidth); localparam int unsigned axi_ar_chan_width = axi_pkg::ar_width(AddrWidth, AxiIdWidth, UserWidth); - localparam int unsigned obi_a_chan_width = $bits(obi_a_chan_t); + localparam int unsigned axis_t_chan_width = $bits(axis_t_chan_t); /// Option struct: AXI4 id as well as AXI and backend options /// - `last`: a flag can be set if this transfer is the last of a set of transfers @@ -12745,32 +10563,32 @@ module idma_backend_synth_rw_axi_rw_obi #( typedef struct packed { axi_ar_chan_t ar_chan; - logic[max_width(axi_ar_chan_width, obi_a_chan_width)-axi_ar_chan_width:0] padding; + logic[max_width(axi_ar_chan_width, axis_t_chan_width)-axi_ar_chan_width:0] padding; } axi_read_ar_chan_padded_t; typedef struct packed { - obi_a_chan_t a_chan; - logic[max_width(axi_ar_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; - } obi_read_a_chan_padded_t; + axis_t_chan_t t_chan; + logic[max_width(axi_ar_chan_width, axis_t_chan_width)-axis_t_chan_width:0] padding; + } axis_read_t_chan_padded_t; typedef union packed { axi_read_ar_chan_padded_t axi; - obi_read_a_chan_padded_t obi; + axis_read_t_chan_padded_t axis; } read_meta_channel_t; typedef struct packed { axi_aw_chan_t aw_chan; - logic[max_width(axi_aw_chan_width, obi_a_chan_width)-axi_aw_chan_width:0] padding; + logic[max_width(axi_aw_chan_width, axis_t_chan_width)-axi_aw_chan_width:0] padding; } axi_write_aw_chan_padded_t; typedef struct packed { - obi_a_chan_t a_chan; - logic[max_width(axi_aw_chan_width, obi_a_chan_width)-obi_a_chan_width:0] padding; - } obi_write_a_chan_padded_t; + axis_t_chan_t t_chan; + logic[max_width(axi_aw_chan_width, axis_t_chan_width)-axis_t_chan_width:0] padding; + } axis_write_t_chan_padded_t; typedef union packed { axi_write_aw_chan_padded_t axi; - obi_write_a_chan_padded_t obi; + axis_write_t_chan_padded_t axis; } write_meta_channel_t; // local types @@ -12781,17 +10599,17 @@ module idma_backend_synth_rw_axi_rw_obi #( axi_req_t axi_write_req; axi_rsp_t axi_write_rsp; - // OBI request and response - obi_req_t obi_read_req; - obi_rsp_t obi_read_rsp; + // AXI Stream request and response + axis_req_t axis_read_req; + axis_rsp_t axis_read_rsp; - obi_req_t obi_write_req; - obi_rsp_t obi_write_rsp; + axis_req_t axis_write_req; + axis_rsp_t axis_write_rsp; idma_req_t idma_req; idma_rsp_t idma_rsp; - idma_backend_rw_axi_rw_obi #( + idma_backend_rw_axi_rw_axis #( .CombinedShifter ( CombinedShifter ), .DataWidth ( DataWidth ), .AddrWidth ( AddrWidth ), @@ -12812,8 +10630,8 @@ module idma_backend_synth_rw_axi_rw_obi #( .idma_busy_t ( idma_pkg::idma_busy_t ), .axi_req_t ( axi_req_t ), .axi_rsp_t ( axi_rsp_t ), - .obi_req_t ( obi_req_t ), - .obi_rsp_t ( obi_rsp_t ), + .axis_req_t ( axis_req_t ), + .axis_rsp_t ( axis_rsp_t ), .write_meta_channel_t ( write_meta_channel_t ), .read_meta_channel_t ( read_meta_channel_t ) ) i_idma_backend ( @@ -12831,12 +10649,12 @@ module idma_backend_synth_rw_axi_rw_obi #( .eh_req_ready_o ( eh_req_ready_o ), .axi_read_req_o ( axi_read_req ), .axi_read_rsp_i ( axi_read_rsp ), - .obi_read_req_o ( obi_read_req ), - .obi_read_rsp_i ( obi_read_rsp ), + .axis_read_req_i ( axis_read_req ), + .axis_read_rsp_o ( axis_read_rsp ), .axi_write_req_o ( axi_write_req ), .axi_write_rsp_i ( axi_write_rsp ), - .obi_write_req_o ( obi_write_req ), - .obi_write_rsp_i ( obi_write_rsp ), + .axis_write_req_o ( axis_write_req ), + .axis_write_rsp_i ( axis_write_rsp ), .busy_o ( idma_busy_o ) ); @@ -12899,19 +10717,17 @@ module idma_backend_synth_rw_axi_rw_obi #( - // OBI Read - assign obi_read_req_a_req_o = obi_read_req.req; - assign obi_read_req_a_addr_o = obi_read_req.a.addr; - assign obi_read_req_a_we_o = obi_read_req.a.we; - assign obi_read_req_a_be_o = obi_read_req.a.be; - assign obi_read_req_a_wdata_o = obi_read_req.a.wdata; - assign obi_read_req_r_ready_o = obi_read_req.rready; + // AXI Stream Read + assign axis_read_req.t.data = axis_read_data_i; + assign axis_read_req.t.strb = axis_read_strb_i; + assign axis_read_req.t.keep = axis_read_keep_i; + assign axis_read_req.t.last = axis_read_last_i; + assign axis_read_req.t.id = axis_read_id_i; + assign axis_read_req.t.dest = axis_read_dest_i; + assign axis_read_req.t.user = axis_read_user_i; + assign axis_read_req.tvalid = axis_read_tvalid_i; - assign obi_read_rsp.gnt = obi_read_rsp_a_gnt_i; - assign obi_read_rsp.rvalid = obi_read_rsp_r_valid_i; - assign obi_read_rsp.r.rdata = obi_read_rsp_r_rdata_i; - assign obi_read_rsp.r.rid = obi_read_rsp_r_rid_i; - assign obi_read_rsp.r.err = obi_read_rsp_r_err_i; + assign axis_read_tready_o = axis_read_rsp.tready; @@ -12945,18 +10761,17 @@ module idma_backend_synth_rw_axi_rw_obi #( - // OBI Write - assign obi_write_req_a_req_o = obi_write_req.req; - assign obi_write_req_a_addr_o = obi_write_req.a.addr; - assign obi_write_req_a_we_o = obi_write_req.a.we; - assign obi_write_req_a_be_o = obi_write_req.a.be; - assign obi_write_req_a_wdata_o = obi_write_req.a.wdata; - assign obi_write_req_a_aid_o = obi_write_req.a.aid; - assign obi_write_req_r_ready_o = obi_write_req.rready; + // AXI Stream Write + assign axis_write_data_o = axis_write_req.t.data; + assign axis_write_strb_o = axis_write_req.t.strb; + assign axis_write_keep_o = axis_write_req.t.keep; + assign axis_write_last_o = axis_write_req.t.last; + assign axis_write_id_o = axis_write_req.t.id; + assign axis_write_dest_o = axis_write_req.t.dest; + assign axis_write_user_o = axis_write_req.t.user; + assign axis_write_tvalid_o = axis_write_req.tvalid; - assign obi_write_rsp.gnt = obi_write_rsp_a_gnt_i; - assign obi_write_rsp.rvalid = obi_write_rsp_r_valid_i; - assign obi_write_rsp.r.rdata = obi_write_rsp_r_rdata_i; + assign axis_write_rsp.tready = axis_write_tready_i; @@ -21602,6 +19417,17 @@ module idma_reg32_3d #( // register signals reg_rsp_t [NumRegs-1:0] dma_ctrl_rsp; + always_comb begin + stream_idx_o = '0; + for (int r = 0; r < NumRegs; r++) begin + for (int c = 0; c < NumStreams; c++) begin + if (dma_reg2hw[r].next_id[c].re) begin + stream_idx_o = c; + end + end + end + end + // generate the registers for (genvar i = 0; i < NumRegs; i++) begin : gen_core_regs @@ -21629,12 +19455,8 @@ module idma_reg32_3d #( logic read_happens; always_comb begin : proc_launch read_happens = 1'b0; - stream_idx_o = '0; for (int c = 0; c < NumStreams; c++) begin read_happens |= dma_reg2hw[i].next_id[c].re; - if (dma_reg2hw[i].next_id[c].re) begin - stream_idx_o = c; - end end arb_valid[i] = read_happens; end @@ -21650,8 +19472,8 @@ module idma_reg32_3d #( arb_dma_req[i].burst_req.dst_addr = dma_reg2hw[i].dst_addr_low.q; // Protocols - arb_dma_req[i].burst_req.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); - arb_dma_req[i].burst_req.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); + arb_dma_req[i].burst_req.opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); + arb_dma_req[i].burst_req.opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); // Current backend only supports incremental burst arb_dma_req[i].burst_req.opt.src.burst = axi_pkg::BURST_INCR; @@ -21787,6 +19609,17 @@ module idma_reg64_2d #( // register signals reg_rsp_t [NumRegs-1:0] dma_ctrl_rsp; + always_comb begin + stream_idx_o = '0; + for (int r = 0; r < NumRegs; r++) begin + for (int c = 0; c < NumStreams; c++) begin + if (dma_reg2hw[r].next_id[c].re) begin + stream_idx_o = c; + end + end + end + end + // generate the registers for (genvar i = 0; i < NumRegs; i++) begin : gen_core_regs @@ -21814,12 +19647,8 @@ module idma_reg64_2d #( logic read_happens; always_comb begin : proc_launch read_happens = 1'b0; - stream_idx_o = '0; for (int c = 0; c < NumStreams; c++) begin read_happens |= dma_reg2hw[i].next_id[c].re; - if (dma_reg2hw[i].next_id[c].re) begin - stream_idx_o = c; - end end arb_valid[i] = read_happens; end @@ -21835,8 +19664,8 @@ module idma_reg64_2d #( arb_dma_req[i].burst_req.dst_addr = {dma_reg2hw[i].dst_addr_high.q, dma_reg2hw[i].dst_addr_low.q}; // Protocols - arb_dma_req[i].burst_req.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); - arb_dma_req[i].burst_req.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); + arb_dma_req[i].burst_req.opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); + arb_dma_req[i].burst_req.opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); // Current backend only supports incremental burst arb_dma_req[i].burst_req.opt.src.burst = axi_pkg::BURST_INCR; @@ -21968,6 +19797,17 @@ module idma_reg64_1d #( // register signals reg_rsp_t [NumRegs-1:0] dma_ctrl_rsp; + always_comb begin + stream_idx_o = '0; + for (int r = 0; r < NumRegs; r++) begin + for (int c = 0; c < NumStreams; c++) begin + if (dma_reg2hw[r].next_id[c].re) begin + stream_idx_o = c; + end + end + end + end + // generate the registers for (genvar i = 0; i < NumRegs; i++) begin : gen_core_regs @@ -21995,12 +19835,8 @@ module idma_reg64_1d #( logic read_happens; always_comb begin : proc_launch read_happens = 1'b0; - stream_idx_o = '0; for (int c = 0; c < NumStreams; c++) begin read_happens |= dma_reg2hw[i].next_id[c].re; - if (dma_reg2hw[i].next_id[c].re) begin - stream_idx_o = c; - end end arb_valid[i] = read_happens; end @@ -22016,8 +19852,8 @@ module idma_reg64_1d #( arb_dma_req[i].dst_addr = {dma_reg2hw[i].dst_addr_high.q, dma_reg2hw[i].dst_addr_low.q}; // Protocols - arb_dma_req[i].src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); - arb_dma_req[i].dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); + arb_dma_req[i].opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol); + arb_dma_req[i].opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol); // Current backend only supports incremental burst arb_dma_req[i].opt.src.burst = axi_pkg::BURST_INCR;