// SPDX-License-Identifier: MIT // // Compatibility wrapper over axi_dma_if_wrapper. // // Uses 4 axis_if channels for statuses and descs // // payload packing is LSB-first and one descriptor/status occupies one AXIS beat. // tkeep/tstrb/tlast/id/dest/user on descriptor inputs are ignored. // status outputs drive tkeep/tstrb to all ones, tlast to 1, and id/dest/user to 0. // // !!!!!: the original alexforencich axi_dma status outputs have // no ready/backpressure signal. This wrapper adds a oneentry holding register // for each status axis output, but if a downstream is not ready long enough for a // second status to arrive while the first one is still pending, the core cannot // be backpressured. In normal use keep status sinks ready, or add an external // FIFO if long stalls are possible. `default_nettype none module axi_dma_axis_compat #( parameter int unsigned AXI_DATA_WIDTH = 32, parameter int unsigned AXI_ADDR_WIDTH = 16, parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8, parameter int unsigned AXI_ID_WIDTH = 8, parameter int unsigned AXI_USER_WIDTH = 1, parameter int unsigned AXI_MAX_BURST_LEN = 16, parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH, parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8, parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8, parameter int unsigned AXIS_LAST_ENABLE = 1, parameter int unsigned AXIS_ID_ENABLE = 1, parameter int unsigned AXIS_ID_WIDTH = 8, parameter int unsigned AXIS_DEST_ENABLE = 0, parameter int unsigned AXIS_DEST_WIDTH = 8, parameter int unsigned AXIS_USER_ENABLE = 1, parameter int unsigned AXIS_USER_WIDTH = 1, parameter int unsigned LEN_WIDTH = 20, parameter int unsigned TAG_WIDTH = 8, parameter int unsigned ENABLE_SG = 0, parameter int unsigned ENABLE_UNALIGNED = 0, // Payload widths for descriptor/status AXIS streams. parameter int unsigned READ_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH, parameter int unsigned READ_DESC_AXIS_DATA_WIDTH = ((READ_DESC_PAYLOAD_WIDTH + 7) / 8) * 8, parameter int unsigned READ_DESC_STATUS_PAYLOAD_WIDTH = TAG_WIDTH + 4, parameter int unsigned READ_DESC_STATUS_AXIS_DATA_WIDTH = ((READ_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8, parameter int unsigned WRITE_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH, parameter int unsigned WRITE_DESC_AXIS_DATA_WIDTH = ((WRITE_DESC_PAYLOAD_WIDTH + 7) / 8) * 8, parameter int unsigned WRITE_DESC_STATUS_PAYLOAD_WIDTH = LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4, parameter int unsigned WRITE_DESC_STATUS_AXIS_DATA_WIDTH = ((WRITE_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8 )( input logic clk, input logic rst, /* * AXI read descriptor input, encoded as one AXIS beat. * tdata layout, LSB first: * addr | len | tag | id | dest | user */ axis_if.slave s_axis_read_desc, /* * AXI read descriptor status output, encoded as one AXIS beat. * tdata layout, LSB first: * tag | error */ axis_if.master m_axis_read_desc_status, /* * AXI stream read data output. */ axis_if.master m_axis_read_data, /* * AXI write descriptor input, encoded as one AXIS beat. * tdata layout, LSB first: * addr | len | tag */ axis_if.slave s_axis_write_desc, /* * AXI write descriptor status output, encoded as one AXIS beat. * tdata layout, LSB first: * len | tag | id | dest | user | error */ axis_if.master m_axis_write_desc_status, /* * AXI stream write data input. */ axis_if.slave s_axis_write_data, /* * AXI memory master interface. */ axi4_if.master m_axi, /* * Configuration. */ input logic read_enable, input logic write_enable, input logic write_abort ); localparam int unsigned RD_ADDR_LSB = 0; localparam int unsigned RD_LEN_LSB = RD_ADDR_LSB + AXI_ADDR_WIDTH; localparam int unsigned RD_TAG_LSB = RD_LEN_LSB + LEN_WIDTH; localparam int unsigned RD_ID_LSB = RD_TAG_LSB + TAG_WIDTH; localparam int unsigned RD_DEST_LSB = RD_ID_LSB + AXIS_ID_WIDTH; localparam int unsigned RD_USER_LSB = RD_DEST_LSB + AXIS_DEST_WIDTH; localparam int unsigned RDS_TAG_LSB = 0; localparam int unsigned RDS_ERROR_LSB = RDS_TAG_LSB + TAG_WIDTH; localparam int unsigned WD_ADDR_LSB = 0; localparam int unsigned WD_LEN_LSB = WD_ADDR_LSB + AXI_ADDR_WIDTH; localparam int unsigned WD_TAG_LSB = WD_LEN_LSB + LEN_WIDTH; localparam int unsigned WDS_LEN_LSB = 0; localparam int unsigned WDS_TAG_LSB = WDS_LEN_LSB + LEN_WIDTH; localparam int unsigned WDS_ID_LSB = WDS_TAG_LSB + TAG_WIDTH; localparam int unsigned WDS_DEST_LSB = WDS_ID_LSB + AXIS_ID_WIDTH; localparam int unsigned WDS_USER_LSB = WDS_DEST_LSB + AXIS_DEST_WIDTH; localparam int unsigned WDS_ERROR_LSB = WDS_USER_LSB + AXIS_USER_WIDTH; localparam int unsigned READ_DESC_AXIS_KEEP_WIDTH = READ_DESC_AXIS_DATA_WIDTH / 8; localparam int unsigned READ_DESC_STATUS_AXIS_KEEP_WIDTH = READ_DESC_STATUS_AXIS_DATA_WIDTH / 8; localparam int unsigned WRITE_DESC_AXIS_KEEP_WIDTH = WRITE_DESC_AXIS_DATA_WIDTH / 8; localparam int unsigned WRITE_DESC_STATUS_AXIS_KEEP_WIDTH = WRITE_DESC_STATUS_AXIS_DATA_WIDTH / 8; logic rstn; assign rstn = ~rst; // -------------------------------------------------------------------------- // Internal DMA-specific descriptor/status interfaces expected by // axi_dma_if_wrapper. // -------------------------------------------------------------------------- axi_dma_read_desc_if #( .ADDR_W (AXI_ADDR_WIDTH), .LEN_W (LEN_WIDTH), .TAG_W (TAG_WIDTH), .ID_W (AXIS_ID_WIDTH), .DEST_W (AXIS_DEST_WIDTH), .USER_W (AXIS_USER_WIDTH) ) read_desc_if ( .aclk (clk), .aresetn (rstn) ); axi_dma_read_desc_status_if #( .TAG_W (TAG_WIDTH) ) read_desc_status_if ( .aclk (clk), .aresetn (rstn) ); axi_dma_write_desc_if #( .ADDR_W (AXI_ADDR_WIDTH), .LEN_W (LEN_WIDTH), .TAG_W (TAG_WIDTH) ) write_desc_if ( .aclk (clk), .aresetn (rstn) ); axi_dma_write_desc_status_if #( .LEN_W (LEN_WIDTH), .TAG_W (TAG_WIDTH), .ID_W (AXIS_ID_WIDTH), .DEST_W (AXIS_DEST_WIDTH), .USER_W (AXIS_USER_WIDTH) ) write_desc_status_if ( .aclk (clk), .aresetn (rstn) ); // -------------------------------------------------------------------------- // AXIS read descriptor input -> DMA-specific read descriptor interface. // -------------------------------------------------------------------------- assign read_desc_if.req.addr = s_axis_read_desc.req.t.data[RD_ADDR_LSB +: AXI_ADDR_WIDTH]; assign read_desc_if.req.len = s_axis_read_desc.req.t.data[RD_LEN_LSB +: LEN_WIDTH]; assign read_desc_if.req.tag = s_axis_read_desc.req.t.data[RD_TAG_LSB +: TAG_WIDTH]; assign read_desc_if.req.id = s_axis_read_desc.req.t.data[RD_ID_LSB +: AXIS_ID_WIDTH]; assign read_desc_if.req.dest = s_axis_read_desc.req.t.data[RD_DEST_LSB +: AXIS_DEST_WIDTH]; assign read_desc_if.req.user = s_axis_read_desc.req.t.data[RD_USER_LSB +: AXIS_USER_WIDTH]; assign read_desc_if.req.valid = s_axis_read_desc.req.t.valid; assign s_axis_read_desc.resp.ready = read_desc_if.resp.ready; // -------------------------------------------------------------------------- // AXIS write descriptor input -> DMA-specific write descriptor interface. // -------------------------------------------------------------------------- assign write_desc_if.req.addr = s_axis_write_desc.req.t.data[WD_ADDR_LSB +: AXI_ADDR_WIDTH]; assign write_desc_if.req.len = s_axis_write_desc.req.t.data[WD_LEN_LSB +: LEN_WIDTH]; assign write_desc_if.req.tag = s_axis_write_desc.req.t.data[WD_TAG_LSB +: TAG_WIDTH]; assign write_desc_if.req.valid = s_axis_write_desc.req.t.valid; assign s_axis_write_desc.resp.ready = write_desc_if.resp.ready; // -------------------------------------------------------------------------- // DMA-specific read status -> AXIS read status output. // -------------------------------------------------------------------------- logic [READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] read_status_payload; logic [READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] read_status_data_q; logic read_status_valid_q; always_comb begin read_status_payload = '0; read_status_payload[RDS_TAG_LSB +: TAG_WIDTH] = read_desc_status_if.req.tag; read_status_payload[RDS_ERROR_LSB +: 4] = read_desc_status_if.req.error; end always_ff @(posedge clk) begin if (rst) begin read_status_valid_q <= 1'b0; read_status_data_q <= '0; end else begin if (!read_status_valid_q || m_axis_read_desc_status.resp.ready) begin read_status_valid_q <= read_desc_status_if.req.valid; if (read_desc_status_if.req.valid) begin read_status_data_q <= read_status_payload; end else begin read_status_data_q <= '0; end end end end always_comb begin m_axis_read_desc_status.req.t.data = '0; m_axis_read_desc_status.req.t.keep = '0; m_axis_read_desc_status.req.t.strb = '0; m_axis_read_desc_status.req.t.last = read_status_valid_q; m_axis_read_desc_status.req.t.id = '0; m_axis_read_desc_status.req.t.dest = '0; m_axis_read_desc_status.req.t.user = '0; m_axis_read_desc_status.req.t.valid = read_status_valid_q; m_axis_read_desc_status.req.t.data[READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] = read_status_data_q; m_axis_read_desc_status.req.t.keep[READ_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {READ_DESC_STATUS_AXIS_KEEP_WIDTH{read_status_valid_q}}; m_axis_read_desc_status.req.t.strb[READ_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {READ_DESC_STATUS_AXIS_KEEP_WIDTH{read_status_valid_q}}; end // -------------------------------------------------------------------------- // DMA-specific write status -> AXIS write status output. // -------------------------------------------------------------------------- logic [WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] write_status_payload; logic [WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] write_status_data_q; logic write_status_valid_q; always_comb begin write_status_payload = '0; write_status_payload[WDS_LEN_LSB +: LEN_WIDTH] = write_desc_status_if.req.len; write_status_payload[WDS_TAG_LSB +: TAG_WIDTH] = write_desc_status_if.req.tag; write_status_payload[WDS_ID_LSB +: AXIS_ID_WIDTH] = write_desc_status_if.req.id; write_status_payload[WDS_DEST_LSB +: AXIS_DEST_WIDTH] = write_desc_status_if.req.dest; write_status_payload[WDS_USER_LSB +: AXIS_USER_WIDTH] = write_desc_status_if.req.user; write_status_payload[WDS_ERROR_LSB +: 4] = write_desc_status_if.req.error; end always_ff @(posedge clk) begin if (rst) begin write_status_valid_q <= 1'b0; write_status_data_q <= '0; end else begin if (!write_status_valid_q || m_axis_write_desc_status.resp.ready) begin write_status_valid_q <= write_desc_status_if.req.valid; if (write_desc_status_if.req.valid) begin write_status_data_q <= write_status_payload; end else begin write_status_data_q <= '0; end end end end always_comb begin m_axis_write_desc_status.req.t.data = '0; m_axis_write_desc_status.req.t.keep = '0; m_axis_write_desc_status.req.t.strb = '0; m_axis_write_desc_status.req.t.last = write_status_valid_q; m_axis_write_desc_status.req.t.id = '0; m_axis_write_desc_status.req.t.dest = '0; m_axis_write_desc_status.req.t.user = '0; m_axis_write_desc_status.req.t.valid = write_status_valid_q; m_axis_write_desc_status.req.t.data[WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] = write_status_data_q; m_axis_write_desc_status.req.t.keep[WRITE_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {WRITE_DESC_STATUS_AXIS_KEEP_WIDTH{write_status_valid_q}}; m_axis_write_desc_status.req.t.strb[WRITE_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {WRITE_DESC_STATUS_AXIS_KEEP_WIDTH{write_status_valid_q}}; end // -------------------------------------------------------------------------- // Lower-level wrapper: DMA-specific descriptor/status interfaces inside, // ordinary AXIS data and AXI memory interfaces unchanged. // -------------------------------------------------------------------------- axi_dma_if_wrapper #( .AXI_DATA_WIDTH (AXI_DATA_WIDTH), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH), .AXI_STRB_WIDTH (AXI_STRB_WIDTH), .AXI_ID_WIDTH (AXI_ID_WIDTH), .AXI_USER_WIDTH (AXI_USER_WIDTH), .AXI_MAX_BURST_LEN (AXI_MAX_BURST_LEN), .AXIS_DATA_WIDTH (AXIS_DATA_WIDTH), .AXIS_KEEP_ENABLE (AXIS_KEEP_ENABLE), .AXIS_KEEP_WIDTH (AXIS_KEEP_WIDTH), .AXIS_LAST_ENABLE (AXIS_LAST_ENABLE), .AXIS_ID_ENABLE (AXIS_ID_ENABLE), .AXIS_ID_WIDTH (AXIS_ID_WIDTH), .AXIS_DEST_ENABLE (AXIS_DEST_ENABLE), .AXIS_DEST_WIDTH (AXIS_DEST_WIDTH), .AXIS_USER_ENABLE (AXIS_USER_ENABLE), .AXIS_USER_WIDTH (AXIS_USER_WIDTH), .LEN_WIDTH (LEN_WIDTH), .TAG_WIDTH (TAG_WIDTH), .ENABLE_SG (ENABLE_SG), .ENABLE_UNALIGNED (ENABLE_UNALIGNED) ) u_axi_dma_if_wrapper ( .clk (clk), .rst (rst), .s_axis_read_desc (read_desc_if), .m_axis_read_desc_status (read_desc_status_if), .m_axis_read_data (m_axis_read_data), .s_axis_write_desc (write_desc_if), .m_axis_write_desc_status (write_desc_status_if), .s_axis_write_data (s_axis_write_data), .m_axi (m_axi), .read_enable (read_enable), .write_enable (write_enable), .write_abort (write_abort) ); endmodule : axi_dma_axis_compat `default_nettype wire