From a0a7137064fc2b4e211e9117a96e42f5ad13682f Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 10 Jul 2026 18:59:50 +0300 Subject: [PATCH] fix: axi dma wrapper --- axi/rtl/axi_dma_wrapper.sv | 24 +- axi/tb/axi_dma_axis_compat/Makefile | 4 +- .../tb_axi_dma_axis_compat.sv | 237 +++++++++----- .../test_axi_dma_axis_compat.py | 305 +++++++++--------- 4 files changed, 318 insertions(+), 252 deletions(-) diff --git a/axi/rtl/axi_dma_wrapper.sv b/axi/rtl/axi_dma_wrapper.sv index adeac8b..d9c20ef 100644 --- a/axi/rtl/axi_dma_wrapper.sv +++ b/axi/rtl/axi_dma_wrapper.sv @@ -271,7 +271,7 @@ module axi_dma_wrapper #( // local read descriptor interface -> DMA flat input axis_if_to_flat #( .DATA_W (AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH), - .KEEP_W ('0), + .KEEP_W (AXIS_KEEP_WIDTH), .ID_W (AXIS_ID_WIDTH), .DEST_W (AXIS_DEST_WIDTH), .USER_W (AXIS_USER_WIDTH) @@ -282,7 +282,7 @@ module axi_dma_wrapper #( .m_axis_tstrb (), .m_axis_tlast (), .m_axis_tid (dma_s_axis_read_desc_id), - .m_axis_tdest (dma_s_axis_read_desc_tdest), + .m_axis_tdest (dma_s_axis_read_desc_dest), .m_axis_tuser (dma_s_axis_read_desc_user), .m_axis_tvalid (dma_s_axis_read_desc_valid), .m_axis_tready (dma_s_axis_read_desc_ready) @@ -291,10 +291,10 @@ module axi_dma_wrapper #( // DMA read descriptor status flat output -> local status interface axis_flat_to_if #( .DATA_W (TAG_WIDTH + 4), - .KEEP_W ('0), - .ID_W ('0), - .DEST_W ('0), - .USER_W ('0) + .KEEP_W (AXIS_KEEP_WIDTH), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) ) i_read_desc_status_f2i( .s_axis_tdata ({dma_m_axis_read_desc_status_tag, dma_m_axis_read_desc_status_error}), .s_axis_tkeep (), @@ -311,7 +311,7 @@ module axi_dma_wrapper #( // local write descriptor interface -> DMA flat input axis_if_to_flat #( .DATA_W (AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH), - .KEEP_W ('0), + .KEEP_W (AXIS_KEEP_WIDTH), .ID_W (AXIS_ID_WIDTH), .DEST_W (AXIS_DEST_WIDTH), .USER_W (AXIS_USER_WIDTH) @@ -321,9 +321,9 @@ module axi_dma_wrapper #( .m_axis_tkeep (), .m_axis_tstrb (), .m_axis_tlast (), - .m_axis_tid (dma_s_axis_write_desc_id), - .m_axis_tdest (dma_s_axis_write_desc_tdest), - .m_axis_tuser (dma_s_axis_write_desc_user), + .m_axis_tid (), + .m_axis_tdest (), + .m_axis_tuser (), .m_axis_tvalid (dma_s_axis_write_desc_valid), .m_axis_tready (dma_s_axis_write_desc_ready) ); @@ -332,7 +332,7 @@ module axi_dma_wrapper #( // DMA write descriptor status flat output -> local status interface axis_flat_to_if #( .DATA_W (TAG_WIDTH + LEN_WIDTH + 4), - .KEEP_W ('0), + .KEEP_W (AXIS_KEEP_WIDTH), .ID_W (AXIS_ID_WIDTH), .DEST_W (AXIS_DEST_WIDTH), .USER_W (AXIS_USER_WIDTH) @@ -448,6 +448,6 @@ module axi_dma_wrapper #( .m_axi (m_axi) ); -endmodule : axi_dma_if_wrapper +endmodule : axi_dma_wrapper `default_nettype wire diff --git a/axi/tb/axi_dma_axis_compat/Makefile b/axi/tb/axi_dma_axis_compat/Makefile index b1b303d..3bc4e57 100644 --- a/axi/tb/axi_dma_axis_compat/Makefile +++ b/axi/tb/axi_dma_axis_compat/Makefile @@ -44,8 +44,8 @@ VERILOG_SOURCES += $(FORENCICH_AXI_RTL_DIR)/axi_dma_rd.v VERILOG_SOURCES += $(FORENCICH_AXI_RTL_DIR)/axi_dma_wr.v -VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_dma_if_wrapper.sv -VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_dma_compat.sv +VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_dma_wrapper.sv + VERILOG_SOURCES += $(TB_DIR)/tb_axi_dma_axis_compat.sv COMPILE_ARGS += -I$(AXI_IF_RTL_DIR) diff --git a/axi/tb/axi_dma_axis_compat/tb_axi_dma_axis_compat.sv b/axi/tb/axi_dma_axis_compat/tb_axi_dma_axis_compat.sv index b7269f3..7ce92d3 100644 --- a/axi/tb/axi_dma_axis_compat/tb_axi_dma_axis_compat.sv +++ b/axi/tb/axi_dma_axis_compat/tb_axi_dma_axis_compat.sv @@ -26,18 +26,14 @@ module tb_axi_dma_axis_compat #( parameter int unsigned ENABLE_SG = 0, parameter int unsigned ENABLE_UNALIGNED = 0, - parameter int unsigned READ_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH, - parameter int unsigned WRITE_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH, - parameter int unsigned DESC_CMD_RAW_WIDTH = READ_DESC_WIDTH + WRITE_DESC_WIDTH, - parameter int unsigned DESC_CMD_DATA_WIDTH = ((DESC_CMD_RAW_WIDTH + 7) / 8) * 8, - parameter int unsigned DESC_CMD_KEEP_WIDTH = DESC_CMD_DATA_WIDTH / 8, - - parameter int unsigned READ_STATUS_WIDTH = TAG_WIDTH + 4, - parameter int unsigned WRITE_STATUS_WIDTH = LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4, - parameter int unsigned DESC_STATUS_RAW_WIDTH = READ_STATUS_WIDTH + WRITE_STATUS_WIDTH, - parameter int unsigned DESC_STATUS_DATA_WIDTH = ((DESC_STATUS_RAW_WIDTH + 7) / 8) * 8, - parameter int unsigned DESC_STATUS_KEEP_WIDTH = DESC_STATUS_DATA_WIDTH / 8, - parameter int unsigned DESC_STATUS_USER_WIDTH = 2 + parameter int unsigned READ_DESC_RAW_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH, + parameter int unsigned READ_DESC_DATA_WIDTH = ((READ_DESC_RAW_WIDTH + 7) / 8) * 8, + parameter int unsigned WRITE_DESC_RAW_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH, + parameter int unsigned WRITE_DESC_DATA_WIDTH = ((WRITE_DESC_RAW_WIDTH + 7) / 8) * 8, + parameter int unsigned READ_STATUS_RAW_WIDTH = TAG_WIDTH + 4, + parameter int unsigned READ_STATUS_DATA_WIDTH = ((READ_STATUS_RAW_WIDTH + 7) / 8) * 8, + parameter int unsigned WRITE_STATUS_RAW_WIDTH = LEN_WIDTH + TAG_WIDTH + 4, + parameter int unsigned WRITE_STATUS_DATA_WIDTH = ((WRITE_STATUS_RAW_WIDTH + 7) / 8) * 8 )( input logic clk, input logic rst, @@ -46,27 +42,35 @@ module tb_axi_dma_axis_compat #( input logic write_enable, input logic write_abort, - // Unified descriptor command AXIS, flat for cocotb - input logic [DESC_CMD_DATA_WIDTH-1:0] s_axis_desc_cmd_tdata, - input logic [DESC_CMD_KEEP_WIDTH-1:0] s_axis_desc_cmd_tkeep, - input logic [DESC_CMD_KEEP_WIDTH-1:0] s_axis_desc_cmd_tstrb, - input logic s_axis_desc_cmd_tlast, - input logic s_axis_desc_cmd_tid, - input logic s_axis_desc_cmd_tdest, - input logic s_axis_desc_cmd_tuser, - input logic s_axis_desc_cmd_tvalid, - output logic s_axis_desc_cmd_tready, + // Read descriptor AXIS input, flat for cocotb. + // tdata layout: {addr, len, tag}; id/dest/user use AXIS sidebands. + input logic [READ_DESC_DATA_WIDTH-1:0] s_axis_read_desc_tdata, + input logic [AXIS_ID_WIDTH-1:0] s_axis_read_desc_tid, + input logic [AXIS_DEST_WIDTH-1:0] s_axis_read_desc_tdest, + input logic [AXIS_USER_WIDTH-1:0] s_axis_read_desc_tuser, + input logic s_axis_read_desc_tvalid, + output logic s_axis_read_desc_tready, - // Unified descriptor status AXIS, flat for cocotb - output logic [DESC_STATUS_DATA_WIDTH-1:0] m_axis_desc_status_tdata, - output logic [DESC_STATUS_KEEP_WIDTH-1:0] m_axis_desc_status_tkeep, - output logic [DESC_STATUS_KEEP_WIDTH-1:0] m_axis_desc_status_tstrb, - output logic m_axis_desc_status_tlast, - output logic m_axis_desc_status_tid, - output logic m_axis_desc_status_tdest, - output logic [DESC_STATUS_USER_WIDTH-1:0] m_axis_desc_status_tuser, - output logic m_axis_desc_status_tvalid, - input logic m_axis_desc_status_tready, + // Read descriptor status AXIS output. + // tdata layout: {tag, error}. + output logic [READ_STATUS_DATA_WIDTH-1:0] m_axis_read_desc_status_tdata, + output logic m_axis_read_desc_status_tvalid, + input logic m_axis_read_desc_status_tready, + + // Write descriptor AXIS input. + // tdata layout: {addr, len, tag}. + input logic [WRITE_DESC_DATA_WIDTH-1:0] s_axis_write_desc_tdata, + input logic s_axis_write_desc_tvalid, + output logic s_axis_write_desc_tready, + + // Write descriptor status AXIS output. + // tdata layout: {len, tag, error}; id/dest/user use AXIS sidebands. + output logic [WRITE_STATUS_DATA_WIDTH-1:0] m_axis_write_desc_status_tdata, + output logic [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_tid, + output logic [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_tdest, + output logic [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_tuser, + output logic m_axis_write_desc_status_tvalid, + input logic m_axis_write_desc_status_tready, // Read data AXIS output output logic [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata, @@ -144,23 +148,45 @@ module tb_axi_dma_axis_compat #( wire rstn = ~rst; axis_if #( - .DATA_W (DESC_CMD_DATA_WIDTH), - .KEEP_W (DESC_CMD_KEEP_WIDTH), - .ID_W (1), - .DEST_W (1), - .USER_W (1) - ) desc_cmd_if ( + .DATA_W (READ_DESC_DATA_WIDTH), + .KEEP_W (READ_DESC_DATA_WIDTH / 8), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) read_desc_if ( .aclk (clk), .aresetn (rstn) ); axis_if #( - .DATA_W (DESC_STATUS_DATA_WIDTH), - .KEEP_W (DESC_STATUS_KEEP_WIDTH), + .DATA_W (READ_STATUS_DATA_WIDTH), + .KEEP_W (READ_STATUS_DATA_WIDTH / 8), .ID_W (1), .DEST_W (1), - .USER_W (DESC_STATUS_USER_WIDTH) - ) desc_status_if ( + .USER_W (1) + ) read_desc_status_if ( + .aclk (clk), + .aresetn (rstn) + ); + + axis_if #( + .DATA_W (WRITE_DESC_DATA_WIDTH), + .KEEP_W (WRITE_DESC_DATA_WIDTH / 8), + .ID_W (1), + .DEST_W (1), + .USER_W (1) + ) write_desc_if ( + .aclk (clk), + .aresetn (rstn) + ); + + axis_if #( + .DATA_W (WRITE_STATUS_DATA_WIDTH), + .KEEP_W (WRITE_STATUS_DATA_WIDTH / 8), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) write_desc_status_if ( .aclk (clk), .aresetn (rstn) ); @@ -198,41 +224,79 @@ module tb_axi_dma_axis_compat #( ); axis_flat_to_if #( - .DATA_W (DESC_CMD_DATA_WIDTH), - .KEEP_W (DESC_CMD_KEEP_WIDTH), - .ID_W (1), - .DEST_W (1), - .USER_W (1) - ) u_desc_cmd_flat_to_if ( - .s_axis_tdata (s_axis_desc_cmd_tdata), - .s_axis_tkeep (s_axis_desc_cmd_tkeep), - .s_axis_tstrb (s_axis_desc_cmd_tstrb), - .s_axis_tlast (s_axis_desc_cmd_tlast), - .s_axis_tid (s_axis_desc_cmd_tid), - .s_axis_tdest (s_axis_desc_cmd_tdest), - .s_axis_tuser (s_axis_desc_cmd_tuser), - .s_axis_tvalid (s_axis_desc_cmd_tvalid), - .s_axis_tready (s_axis_desc_cmd_tready), - .m_axis (desc_cmd_if) + .DATA_W (READ_DESC_DATA_WIDTH), + .KEEP_W (READ_DESC_DATA_WIDTH / 8), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) u_read_desc_flat_to_if ( + .s_axis_tdata (s_axis_read_desc_tdata), + .s_axis_tkeep ({(READ_DESC_DATA_WIDTH/8){1'b1}}), + .s_axis_tstrb ({(READ_DESC_DATA_WIDTH/8){1'b1}}), + .s_axis_tlast (1'b1), + .s_axis_tid (s_axis_read_desc_tid), + .s_axis_tdest (s_axis_read_desc_tdest), + .s_axis_tuser (s_axis_read_desc_tuser), + .s_axis_tvalid (s_axis_read_desc_tvalid), + .s_axis_tready (s_axis_read_desc_tready), + .m_axis (read_desc_if) ); axis_if_to_flat #( - .DATA_W (DESC_STATUS_DATA_WIDTH), - .KEEP_W (DESC_STATUS_KEEP_WIDTH), + .DATA_W (READ_STATUS_DATA_WIDTH), + .KEEP_W (READ_STATUS_DATA_WIDTH / 8), .ID_W (1), .DEST_W (1), - .USER_W (DESC_STATUS_USER_WIDTH) - ) u_desc_status_if_to_flat ( - .s_axis (desc_status_if), - .m_axis_tdata (m_axis_desc_status_tdata), - .m_axis_tkeep (m_axis_desc_status_tkeep), - .m_axis_tstrb (m_axis_desc_status_tstrb), - .m_axis_tlast (m_axis_desc_status_tlast), - .m_axis_tid (m_axis_desc_status_tid), - .m_axis_tdest (m_axis_desc_status_tdest), - .m_axis_tuser (m_axis_desc_status_tuser), - .m_axis_tvalid (m_axis_desc_status_tvalid), - .m_axis_tready (m_axis_desc_status_tready) + .USER_W (1) + ) u_read_desc_status_if_to_flat ( + .s_axis (read_desc_status_if), + .m_axis_tdata (m_axis_read_desc_status_tdata), + .m_axis_tkeep (), + .m_axis_tstrb (), + .m_axis_tlast (), + .m_axis_tid (), + .m_axis_tdest (), + .m_axis_tuser (), + .m_axis_tvalid (m_axis_read_desc_status_tvalid), + .m_axis_tready (m_axis_read_desc_status_tready) + ); + + axis_flat_to_if #( + .DATA_W (WRITE_DESC_DATA_WIDTH), + .KEEP_W (WRITE_DESC_DATA_WIDTH / 8), + .ID_W (1), + .DEST_W (1), + .USER_W (1) + ) u_write_desc_flat_to_if ( + .s_axis_tdata (s_axis_write_desc_tdata), + .s_axis_tkeep ({(WRITE_DESC_DATA_WIDTH/8){1'b1}}), + .s_axis_tstrb ({(WRITE_DESC_DATA_WIDTH/8){1'b1}}), + .s_axis_tlast (1'b1), + .s_axis_tid (1'b0), + .s_axis_tdest (1'b0), + .s_axis_tuser (1'b0), + .s_axis_tvalid (s_axis_write_desc_tvalid), + .s_axis_tready (s_axis_write_desc_tready), + .m_axis (write_desc_if) + ); + + axis_if_to_flat #( + .DATA_W (WRITE_STATUS_DATA_WIDTH), + .KEEP_W (WRITE_STATUS_DATA_WIDTH / 8), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) u_write_desc_status_if_to_flat ( + .s_axis (write_desc_status_if), + .m_axis_tdata (m_axis_write_desc_status_tdata), + .m_axis_tkeep (), + .m_axis_tstrb (), + .m_axis_tlast (), + .m_axis_tid (m_axis_write_desc_status_tid), + .m_axis_tdest (m_axis_write_desc_status_tdest), + .m_axis_tuser (m_axis_write_desc_status_tuser), + .m_axis_tvalid (m_axis_write_desc_status_tvalid), + .m_axis_tready (m_axis_write_desc_status_tready) ); axis_if_to_flat #( @@ -273,7 +337,7 @@ module tb_axi_dma_axis_compat #( .m_axis (write_data_if) ); - axi_dma_axis_compat #( + axi_dma_wrapper #( .AXI_DATA_WIDTH (AXI_DATA_WIDTH), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH), .AXI_STRB_WIDTH (AXI_STRB_WIDTH), @@ -293,21 +357,20 @@ module tb_axi_dma_axis_compat #( .LEN_WIDTH (LEN_WIDTH), .TAG_WIDTH (TAG_WIDTH), .ENABLE_SG (ENABLE_SG), - .ENABLE_UNALIGNED (ENABLE_UNALIGNED), - .DESC_CMD_DATA_WIDTH (DESC_CMD_DATA_WIDTH), - .DESC_STATUS_DATA_WIDTH (DESC_STATUS_DATA_WIDTH), - .DESC_STATUS_USER_WIDTH (DESC_STATUS_USER_WIDTH) + .ENABLE_UNALIGNED (ENABLE_UNALIGNED) ) u_dut ( - .clk (clk), - .rst (rst), - .s_axis_desc_cmd (desc_cmd_if), - .m_axis_desc_status (desc_status_if), - .m_axis_read_data (read_data_if), - .s_axis_write_data (write_data_if), - .m_axi (m_axi_if), - .read_enable (read_enable), - .write_enable (write_enable), - .write_abort (write_abort) + .clk (clk), + .rst (rst), + .s_axis_read_desc (read_desc_if), + .m_axis_read_desc_status (read_desc_status_if), + .m_axis_read_data (read_data_if), + .s_axis_write_desc (write_desc_if), + .m_axis_write_desc_status (write_desc_status_if), + .s_axis_write_data (write_data_if), + .m_axi (m_axi_if), + .read_enable (read_enable), + .write_enable (write_enable), + .write_abort (write_abort) ); axi4_if_to_flat #( diff --git a/axi/tb/axi_dma_axis_compat/test_axi_dma_axis_compat.py b/axi/tb/axi_dma_axis_compat/test_axi_dma_axis_compat.py index 15c891c..4484d47 100644 --- a/axi/tb/axi_dma_axis_compat/test_axi_dma_axis_compat.py +++ b/axi/tb/axi_dma_axis_compat/test_axi_dma_axis_compat.py @@ -3,7 +3,7 @@ import os import cocotb from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, Combine +from cocotb.triggers import RisingEdge from cocotbext.axi import AxiBus, AxiRam from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink @@ -16,42 +16,33 @@ AXIS_ID_WIDTH = int(os.getenv("PARAM_AXIS_ID_WIDTH", "8")) AXIS_DEST_WIDTH = int(os.getenv("PARAM_AXIS_DEST_WIDTH", "8")) AXIS_USER_WIDTH = int(os.getenv("PARAM_AXIS_USER_WIDTH", "1")) -READ_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + \ - AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH -WRITE_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH -DESC_CMD_RAW_WIDTH = READ_DESC_WIDTH + WRITE_DESC_WIDTH -DESC_CMD_DATA_WIDTH = ((DESC_CMD_RAW_WIDTH + 7) // 8) * 8 -DESC_CMD_BYTES = DESC_CMD_DATA_WIDTH // 8 +READ_DESC_RAW_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH +READ_DESC_DATA_WIDTH = ((READ_DESC_RAW_WIDTH + 7) // 8) * 8 +READ_DESC_BYTES = READ_DESC_DATA_WIDTH // 8 -READ_STATUS_WIDTH = TAG_WIDTH + 4 -WRITE_STATUS_WIDTH = LEN_WIDTH + TAG_WIDTH + \ - AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4 -DESC_STATUS_RAW_WIDTH = READ_STATUS_WIDTH + WRITE_STATUS_WIDTH -DESC_STATUS_DATA_WIDTH = ((DESC_STATUS_RAW_WIDTH + 7) // 8) * 8 -DESC_STATUS_BYTES = DESC_STATUS_DATA_WIDTH // 8 +WRITE_DESC_RAW_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH +WRITE_DESC_DATA_WIDTH = ((WRITE_DESC_RAW_WIDTH + 7) // 8) * 8 +WRITE_DESC_BYTES = WRITE_DESC_DATA_WIDTH // 8 -RD_ADDR_LSB = 0 -RD_LEN_LSB = RD_ADDR_LSB + AXI_ADDR_WIDTH -RD_TAG_LSB = RD_LEN_LSB + LEN_WIDTH -RD_ID_LSB = RD_TAG_LSB + TAG_WIDTH -RD_DEST_LSB = RD_ID_LSB + AXIS_ID_WIDTH -RD_USER_LSB = RD_DEST_LSB + AXIS_DEST_WIDTH +READ_STATUS_RAW_WIDTH = TAG_WIDTH + 4 +READ_STATUS_DATA_WIDTH = ((READ_STATUS_RAW_WIDTH + 7) // 8) * 8 -WR_BASE_LSB = READ_DESC_WIDTH -WR_ADDR_LSB = WR_BASE_LSB -WR_LEN_LSB = WR_ADDR_LSB + AXI_ADDR_WIDTH -WR_TAG_LSB = WR_LEN_LSB + LEN_WIDTH +WRITE_STATUS_RAW_WIDTH = LEN_WIDTH + TAG_WIDTH + 4 +WRITE_STATUS_DATA_WIDTH = ((WRITE_STATUS_RAW_WIDTH + 7) // 8) * 8 -RD_STS_TAG_LSB = 0 -RD_STS_ERROR_LSB = RD_STS_TAG_LSB + TAG_WIDTH +# axi_dma_wrapper maps descriptor tdata as {addr, len, tag}. +DESC_TAG_LSB = 0 +DESC_LEN_LSB = DESC_TAG_LSB + TAG_WIDTH +DESC_ADDR_LSB = DESC_LEN_LSB + LEN_WIDTH -WR_STS_BASE_LSB = READ_STATUS_WIDTH -WR_STS_LEN_LSB = WR_STS_BASE_LSB -WR_STS_TAG_LSB = WR_STS_LEN_LSB + LEN_WIDTH -WR_STS_ID_LSB = WR_STS_TAG_LSB + TAG_WIDTH -WR_STS_DEST_LSB = WR_STS_ID_LSB + AXIS_ID_WIDTH -WR_STS_USER_LSB = WR_STS_DEST_LSB + AXIS_DEST_WIDTH -WR_STS_ERROR_LSB = WR_STS_USER_LSB + AXIS_USER_WIDTH +# Read status tdata is {tag, error}. +READ_STATUS_ERROR_LSB = 0 +READ_STATUS_TAG_LSB = READ_STATUS_ERROR_LSB + 4 + +# Write status tdata is {len, tag, error}. +WRITE_STATUS_ERROR_LSB = 0 +WRITE_STATUS_TAG_LSB = WRITE_STATUS_ERROR_LSB + 4 +WRITE_STATUS_LEN_LSB = WRITE_STATUS_TAG_LSB + TAG_WIDTH def mask(width): @@ -68,59 +59,60 @@ def get(value, lsb, width): return (int(value) >> lsb) & mask(width) -def pack_desc_cmd( - *, - read_addr=0, - read_len=0, - read_tag=0, - read_id=0, - read_dest=0, - read_user=0, - write_addr=0, - write_len=0, - write_tag=0, -): +def pack_read_desc(*, addr, length, tag, axis_id=0, dest=0, user=0): value = 0 - value = put(value, RD_ADDR_LSB, AXI_ADDR_WIDTH, read_addr) - value = put(value, RD_LEN_LSB, LEN_WIDTH, read_len) - value = put(value, RD_TAG_LSB, TAG_WIDTH, read_tag) - value = put(value, RD_ID_LSB, AXIS_ID_WIDTH, read_id) - value = put(value, RD_DEST_LSB, AXIS_DEST_WIDTH, read_dest) - value = put(value, RD_USER_LSB, AXIS_USER_WIDTH, read_user) + value = put(value, DESC_TAG_LSB, TAG_WIDTH, tag) + value = put(value, DESC_LEN_LSB, LEN_WIDTH, length) + value = put(value, DESC_ADDR_LSB, AXI_ADDR_WIDTH, addr) - value = put(value, WR_ADDR_LSB, AXI_ADDR_WIDTH, write_addr) - value = put(value, WR_LEN_LSB, LEN_WIDTH, write_len) - value = put(value, WR_TAG_LSB, TAG_WIDTH, write_tag) + return AxiStreamFrame( + value.to_bytes(READ_DESC_BYTES, byteorder="little"), + tid=axis_id, + tdest=dest, + tuser=user, + ) - return value.to_bytes(DESC_CMD_BYTES, byteorder="little") + +def pack_write_desc(*, addr, length, tag): + value = 0 + value = put(value, DESC_TAG_LSB, TAG_WIDTH, tag) + value = put(value, DESC_LEN_LSB, LEN_WIDTH, length) + value = put(value, DESC_ADDR_LSB, AXI_ADDR_WIDTH, addr) + + return AxiStreamFrame( + value.to_bytes(WRITE_DESC_BYTES, byteorder="little") + ) def frame_to_int(frame): return int.from_bytes(bytes(frame.tdata), byteorder="little") -def frame_tuser(frame): +def frame_sideband(frame, name): + value = getattr(frame, name) try: - return int(frame.tuser) + return int(value) except TypeError: - return int(frame.tuser[0]) if frame.tuser else 0 + return int(value[0]) if value else 0 -def unpack_status(frame): +def unpack_read_status(frame): value = frame_to_int(frame) - tuser = frame_tuser(frame) - return { - "read_valid": bool(tuser & 0x1), - "write_valid": bool(tuser & 0x2), - "read_tag": get(value, RD_STS_TAG_LSB, TAG_WIDTH), - "read_error": get(value, RD_STS_ERROR_LSB, 4), - "write_len": get(value, WR_STS_LEN_LSB, LEN_WIDTH), - "write_tag": get(value, WR_STS_TAG_LSB, TAG_WIDTH), - "write_id": get(value, WR_STS_ID_LSB, AXIS_ID_WIDTH), - "write_dest": get(value, WR_STS_DEST_LSB, AXIS_DEST_WIDTH), - "write_user": get(value, WR_STS_USER_LSB, AXIS_USER_WIDTH), - "write_error": get(value, WR_STS_ERROR_LSB, 4), + "tag": get(value, READ_STATUS_TAG_LSB, TAG_WIDTH), + "error": get(value, READ_STATUS_ERROR_LSB, 4), + } + + +def unpack_write_status(frame): + value = frame_to_int(frame) + return { + "len": get(value, WRITE_STATUS_LEN_LSB, LEN_WIDTH), + "tag": get(value, WRITE_STATUS_TAG_LSB, TAG_WIDTH), + "error": get(value, WRITE_STATUS_ERROR_LSB, 4), + "id": frame_sideband(frame, "tid"), + "dest": frame_sideband(frame, "tdest"), + "user": frame_sideband(frame, "tuser"), } @@ -132,24 +124,45 @@ class TB: cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) - self.desc_cmd_source = AxiStreamSource( - AxiStreamBus.from_prefix(dut, "s_axis_desc_cmd"), dut.clk, dut.rst + self.read_desc_source = AxiStreamSource( + AxiStreamBus.from_prefix(dut, "s_axis_read_desc"), + dut.clk, + dut.rst, ) - self.desc_status_sink = AxiStreamSink( - AxiStreamBus.from_prefix( - dut, "m_axis_desc_status"), dut.clk, dut.rst + self.read_desc_status_sink = AxiStreamSink( + AxiStreamBus.from_prefix(dut, "m_axis_read_desc_status"), + dut.clk, + dut.rst, + ) + + self.write_desc_source = AxiStreamSource( + AxiStreamBus.from_prefix(dut, "s_axis_write_desc"), + dut.clk, + dut.rst, + ) + self.write_desc_status_sink = AxiStreamSink( + AxiStreamBus.from_prefix(dut, "m_axis_write_desc_status"), + dut.clk, + dut.rst, ) self.read_data_sink = AxiStreamSink( - AxiStreamBus.from_prefix(dut, "m_axis_read_data"), dut.clk, dut.rst + AxiStreamBus.from_prefix(dut, "m_axis_read_data"), + dut.clk, + dut.rst, ) self.write_data_source = AxiStreamSource( - AxiStreamBus.from_prefix( - dut, "s_axis_write_data"), dut.clk, dut.rst + AxiStreamBus.from_prefix(dut, "s_axis_write_data"), + dut.clk, + dut.rst, ) - self.axi_ram = AxiRam(AxiBus.from_prefix( - dut, "m_axi"), dut.clk, dut.rst, size=2**16) + self.axi_ram = AxiRam( + AxiBus.from_prefix(dut, "m_axi"), + dut.clk, + dut.rst, + size=2**AXI_ADDR_WIDTH, + ) dut.read_enable.setimmediatevalue(0) dut.write_enable.setimmediatevalue(0) @@ -166,8 +179,11 @@ class TB: await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) - async def send_desc_cmd(self, payload): - await self.desc_cmd_source.send(AxiStreamFrame(payload)) + async def send_read_desc(self, **kwargs): + await self.read_desc_source.send(pack_read_desc(**kwargs)) + + async def send_write_desc(self, **kwargs): + await self.write_desc_source.send(pack_write_desc(**kwargs)) @cocotb.test() @@ -184,28 +200,26 @@ async def test_axis_compat_write_path(dut): tb.axi_ram.write(addr - 16, b"\xaa" * (len(data) + 32)) - cmd = pack_desc_cmd(write_addr=addr, write_len=len(data), write_tag=tag) - - cmd_task = cocotb.start_soon(tb.send_desc_cmd(cmd)) + desc_task = cocotb.start_soon( + tb.send_write_desc(addr=addr, length=len(data), tag=tag) + ) data_task = cocotb.start_soon( tb.write_data_source.send(AxiStreamFrame(data, tid=tag)) ) - await cmd_task + await desc_task await data_task - status_frame = await tb.desc_status_sink.recv() - status = unpack_status(status_frame) + status = unpack_write_status(await tb.write_desc_status_sink.recv()) - assert not status["read_valid"] - assert status["write_valid"] - assert status["write_tag"] == tag - assert status["write_len"] == len(data) - assert status["write_id"] == tag - assert status["write_error"] == 0 + assert status["tag"] == tag + assert status["len"] == len(data) + assert status["id"] == tag + assert status["error"] == 0 - assert tb.axi_ram.read(addr - 8, len(data) + - 16) == b"\xaa" * 8 + data + b"\xaa" * 8 + assert tb.axi_ram.read(addr - 8, len(data) + 16) == ( + b"\xaa" * 8 + data + b"\xaa" * 8 + ) @cocotb.test() @@ -222,32 +236,26 @@ async def test_axis_compat_read_path(dut): tb.axi_ram.write(addr, data) - cmd = pack_desc_cmd( - read_addr=addr, - read_len=len(data), - read_tag=tag, - read_id=tag, - read_dest=0, - read_user=0, + await tb.send_read_desc( + addr=addr, + length=len(data), + tag=tag, + axis_id=tag, + dest=0, + user=0, ) - await tb.send_desc_cmd(cmd) - data_frame = await tb.read_data_sink.recv() assert bytes(data_frame.tdata) == data - assert int(data_frame.tid) == tag + assert frame_sideband(data_frame, "tid") == tag - status_frame = await tb.desc_status_sink.recv() - status = unpack_status(status_frame) - - assert status["read_valid"] - assert not status["write_valid"] - assert status["read_tag"] == tag - assert status["read_error"] == 0 + status = unpack_read_status(await tb.read_desc_status_sink.recv()) + assert status["tag"] == tag + assert status["error"] == 0 @cocotb.test() -async def test_axis_compat_read_and_write_same_command(dut): +async def test_axis_compat_read_and_write_independent_desc_ports(dut): tb = TB(dut) await tb.reset() @@ -264,51 +272,46 @@ async def test_axis_compat_read_and_write_same_command(dut): tb.axi_ram.write(read_addr, read_data) tb.axi_ram.write(write_addr - 8, b"\xaa" * (len(write_data) + 16)) - cmd = pack_desc_cmd( - read_addr=read_addr, - read_len=len(read_data), - read_tag=read_tag, - read_id=read_tag, - write_addr=write_addr, - write_len=len(write_data), - write_tag=write_tag, + read_desc_task = cocotb.start_soon( + tb.send_read_desc( + addr=read_addr, + length=len(read_data), + tag=read_tag, + axis_id=read_tag, + dest=0, + user=0, + ) ) - - cmd_task = cocotb.start_soon(tb.send_desc_cmd(cmd)) - data_task = cocotb.start_soon( + write_desc_task = cocotb.start_soon( + tb.send_write_desc( + addr=write_addr, + length=len(write_data), + tag=write_tag, + ) + ) + write_data_task = cocotb.start_soon( tb.write_data_source.send(AxiStreamFrame(write_data, tid=write_tag)) ) - await cmd_task - await data_task + await read_desc_task + await write_desc_task + await write_data_task data_frame = await tb.read_data_sink.recv() assert bytes(data_frame.tdata) == read_data - assert int(data_frame.tid) == read_tag + assert frame_sideband(data_frame, "tid") == read_tag - # status might be in 2 beats, depending on timings - seen_read = False - seen_write = False + read_status = unpack_read_status(await tb.read_desc_status_sink.recv()) + write_status = unpack_write_status(await tb.write_desc_status_sink.recv()) - for _ in range(2): - status_frame = await tb.desc_status_sink.recv() - status = unpack_status(status_frame) + assert read_status["tag"] == read_tag + assert read_status["error"] == 0 - if status["read_valid"]: - assert status["read_tag"] == read_tag - assert status["read_error"] == 0 - seen_read = True + assert write_status["tag"] == write_tag + assert write_status["len"] == len(write_data) + assert write_status["id"] == write_tag + assert write_status["error"] == 0 - if status["write_valid"]: - assert status["write_tag"] == write_tag - assert status["write_len"] == len(write_data) - assert status["write_error"] == 0 - seen_write = True - - if seen_read and seen_write: - break - - assert seen_read - assert seen_write - assert tb.axi_ram.read(write_addr - 8, len(write_data) + - 16) == b"\xaa" * 8 + write_data + b"\xaa" * 8 + assert tb.axi_ram.read(write_addr - 8, len(write_data) + 16) == ( + b"\xaa" * 8 + write_data + b"\xaa" * 8 + )