Compare commits
2 Commits
8cadd5a02f
...
cocotb_pro
| Author | SHA1 | Date | |
|---|---|---|---|
| 4dac1789c8 | |||
| f3450cb22a |
@ -1,64 +1,37 @@
|
||||
package dma_axil_reg_map_pkg;
|
||||
|
||||
localparam int unsigned DMA_AXIL_REG_MAP_N_REGS = 6;
|
||||
|
||||
localparam int unsigned DMA_WRITE_DESC_CONTROL_REG = 0;
|
||||
localparam int unsigned DMA_WRITE_DESC_ADDR_REG = 1;
|
||||
localparam int unsigned DMA_WRITE_DESC_LEN_REG = 2;
|
||||
localparam int unsigned DMA_READ_DESC_CONTROL_REG = 3;
|
||||
localparam int unsigned DMA_READ_DESC_ADDR_REG = 4;
|
||||
localparam int unsigned DMA_READ_DESC_LEN_REG = 5;
|
||||
localparam int unsigned DMA_AXIL_REG_MAP_N_REGS = 4;
|
||||
|
||||
localparam logic [2:0] REG_BIT_RSVD = 3'd0;
|
||||
localparam logic [2:0] REG_BIT_RO = 3'd1;
|
||||
localparam logic [2:0] REG_BIT_RW = 3'd2;
|
||||
localparam logic [2:0] REG_BIT_W1S = 3'd3;
|
||||
localparam logic [2:0] REG_BIT_W1C = 3'd4;
|
||||
|
||||
typedef logic [DMA_AXIL_REG_MAP_N_REGS-1:0][31:0][2:0] reg_mode_map_t;
|
||||
localparam DMA_WRITE_DESC_CONTROL_REG = 0;
|
||||
localparam DMA_WRITE_DESC_ADDR_REG = 1;
|
||||
localparam DMA_WRITE_DESC_LEN_REG = 2;
|
||||
localparam DMA_READ_DESC_CONTROL_REG = 3;
|
||||
localparam DMA_READ_DESC_ADDR_REG = 4;
|
||||
localparam DMA_READ_DESC_LEN_REG = 5;
|
||||
|
||||
function automatic reg_mode_map_t make_dma_reg_mode();
|
||||
reg_mode_map_t mode;
|
||||
localparam logic [DMA_AXIL_REG_MAP_N_REGS-1:0][31:0][2:0] DMA_AXIL_REG_MAP_REG_MODE = '{
|
||||
|
||||
mode = '0;
|
||||
'{REG_BIT_RO, REG_BIT_W1S, default: REG_BIT_RSVD},
|
||||
'{32{REG_BIT_RW}, default: REG_BIT_RSVD},
|
||||
'{32{REG_BIT_RW}, default: REG_BIT_RSVD},
|
||||
'{REG_BIT_RO, REG_BIT_W1S, default: REG_BIT_RSVD},
|
||||
'{32{REG_BIT_RW}, default: REG_BIT_RSVD},
|
||||
'{32{REG_BIT_RW}, default: REG_BIT_RSVD}
|
||||
};
|
||||
|
||||
// По умолчанию всё reserved
|
||||
for (int reg_idx = 0; reg_idx < DMA_AXIL_REG_MAP_N_REGS; reg_idx++) begin
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[reg_idx][bit_idx] = REG_BIT_RSVD;
|
||||
end
|
||||
end
|
||||
|
||||
// WRITE CONTROL
|
||||
mode[DMA_WRITE_DESC_CONTROL_REG][0] = REG_BIT_RO;
|
||||
mode[DMA_WRITE_DESC_CONTROL_REG][1] = REG_BIT_W1S;
|
||||
|
||||
// WRITE ADDR
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_WRITE_DESC_ADDR_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// WRITE LEN
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_WRITE_DESC_LEN_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// READ CONTROL
|
||||
mode[DMA_READ_DESC_CONTROL_REG][0] = REG_BIT_RO;
|
||||
mode[DMA_READ_DESC_CONTROL_REG][1] = REG_BIT_W1S;
|
||||
|
||||
// READ ADDR
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_READ_DESC_ADDR_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// READ LEN
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_READ_DESC_LEN_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
return mode;
|
||||
endfunction
|
||||
|
||||
localparam reg_mode_map_t DMA_AXIL_REG_MAP_REG_MODE = make_dma_reg_mode();
|
||||
localparam logic [DMA_AXIL_REG_MAP_N_REGS-1:0][31:0] DMA_AXIL_REG_MAP_REG_RST = '{
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000
|
||||
};
|
||||
|
||||
endpackage
|
||||
@ -2,7 +2,7 @@ module axi_crossbar_wrapper #(
|
||||
parameter int SLAVE_QTY = 3,
|
||||
parameter int MASTER_QTY = 3,
|
||||
parameter int ADDR_WIDTH = 32,
|
||||
parameter int DATA_WIDTH = 32,
|
||||
parameter int DATA_WIDTH = 32
|
||||
parameter int STRB_WIDTH = (DATA_WIDTH/8)
|
||||
)(
|
||||
input wire clk,
|
||||
|
||||
453
axi/rtl/axi_dma_wrapper.sv
Normal file
453
axi/rtl/axi_dma_wrapper.sv
Normal file
@ -0,0 +1,453 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// SystemVerilog interface wrapper around alexforencich/verilog-axi axi_dma.v.
|
||||
//
|
||||
// AXI memory, AXI-Stream data, DMA descriptor, and DMA status channels are all
|
||||
// exposed through compact interfaces. The original Forencich core remains
|
||||
// untouched and is connected through local flat wires.
|
||||
|
||||
`default_nettype none
|
||||
|
||||
// DMA Specific wrappers & converters
|
||||
module axi_dma_wrapper #(
|
||||
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
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
axis_if.slave s_axis_read_desc,
|
||||
|
||||
axis_if.master m_axis_read_desc_status,
|
||||
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
axis_if.slave s_axis_write_desc,
|
||||
|
||||
axis_if.master m_axis_write_desc_status,
|
||||
|
||||
axis_if.slave s_axis_write_data,
|
||||
|
||||
axi4_if.master m_axi,
|
||||
|
||||
/*
|
||||
* Configuration.
|
||||
*/
|
||||
input logic read_enable,
|
||||
input logic write_enable,
|
||||
input logic write_abort
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Flat wires connected to original alexforencich axi_dma.v
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
logic [AXI_ADDR_WIDTH-1:0] dma_s_axis_read_desc_addr;
|
||||
logic [LEN_WIDTH-1:0] dma_s_axis_read_desc_len;
|
||||
logic [TAG_WIDTH-1:0] dma_s_axis_read_desc_tag;
|
||||
logic [AXIS_ID_WIDTH-1:0] dma_s_axis_read_desc_id;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dma_s_axis_read_desc_dest;
|
||||
logic [AXIS_USER_WIDTH-1:0] dma_s_axis_read_desc_user;
|
||||
logic dma_s_axis_read_desc_valid;
|
||||
logic dma_s_axis_read_desc_ready;
|
||||
|
||||
logic [TAG_WIDTH-1:0] dma_m_axis_read_desc_status_tag;
|
||||
logic [3:0] dma_m_axis_read_desc_status_error;
|
||||
logic dma_m_axis_read_desc_status_valid;
|
||||
|
||||
logic [AXI_ADDR_WIDTH-1:0] dma_s_axis_write_desc_addr;
|
||||
logic [LEN_WIDTH-1:0] dma_s_axis_write_desc_len;
|
||||
logic [TAG_WIDTH-1:0] dma_s_axis_write_desc_tag;
|
||||
logic dma_s_axis_write_desc_valid;
|
||||
logic dma_s_axis_write_desc_ready;
|
||||
|
||||
logic [LEN_WIDTH-1:0] dma_m_axis_write_desc_status_len;
|
||||
logic [TAG_WIDTH-1:0] dma_m_axis_write_desc_status_tag;
|
||||
logic [AXIS_ID_WIDTH-1:0] dma_m_axis_write_desc_status_id;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dma_m_axis_write_desc_status_dest;
|
||||
logic [AXIS_USER_WIDTH-1:0] dma_m_axis_write_desc_status_user;
|
||||
logic [3:0] dma_m_axis_write_desc_status_error;
|
||||
logic dma_m_axis_write_desc_status_valid;
|
||||
|
||||
logic [AXIS_DATA_WIDTH-1:0] dma_m_axis_read_data_tdata;
|
||||
logic [AXIS_KEEP_WIDTH-1:0] dma_m_axis_read_data_tkeep;
|
||||
logic dma_m_axis_read_data_tvalid;
|
||||
logic dma_m_axis_read_data_tready;
|
||||
logic dma_m_axis_read_data_tlast;
|
||||
logic [AXIS_ID_WIDTH-1:0] dma_m_axis_read_data_tid;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dma_m_axis_read_data_tdest;
|
||||
logic [AXIS_USER_WIDTH-1:0] dma_m_axis_read_data_tuser;
|
||||
|
||||
logic [AXIS_DATA_WIDTH-1:0] dma_s_axis_write_data_tdata;
|
||||
logic [AXIS_KEEP_WIDTH-1:0] dma_s_axis_write_data_tkeep;
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_s_axis_write_data_tstrb;
|
||||
logic dma_s_axis_write_data_tvalid;
|
||||
logic dma_s_axis_write_data_tready;
|
||||
logic dma_s_axis_write_data_tlast;
|
||||
logic [AXIS_ID_WIDTH-1:0] dma_s_axis_write_data_tid;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dma_s_axis_write_data_tdest;
|
||||
logic [AXIS_USER_WIDTH-1:0] dma_s_axis_write_data_tuser;
|
||||
|
||||
logic [AXI_ID_WIDTH-1:0] dma_m_axi_awid;
|
||||
logic [AXI_ADDR_WIDTH-1:0] dma_m_axi_awaddr;
|
||||
logic [7:0] dma_m_axi_awlen;
|
||||
logic [2:0] dma_m_axi_awsize;
|
||||
logic [1:0] dma_m_axi_awburst;
|
||||
logic dma_m_axi_awlock;
|
||||
logic [3:0] dma_m_axi_awcache;
|
||||
logic [2:0] dma_m_axi_awprot;
|
||||
logic dma_m_axi_awvalid;
|
||||
logic dma_m_axi_awready;
|
||||
|
||||
logic [AXI_DATA_WIDTH-1:0] dma_m_axi_wdata;
|
||||
logic [AXI_STRB_WIDTH-1:0] dma_m_axi_wstrb;
|
||||
logic dma_m_axi_wlast;
|
||||
logic dma_m_axi_wvalid;
|
||||
logic dma_m_axi_wready;
|
||||
|
||||
logic [AXI_ID_WIDTH-1:0] dma_m_axi_bid;
|
||||
logic [1:0] dma_m_axi_bresp;
|
||||
logic dma_m_axi_bvalid;
|
||||
logic dma_m_axi_bready;
|
||||
|
||||
logic [AXI_ID_WIDTH-1:0] dma_m_axi_arid;
|
||||
logic [AXI_ADDR_WIDTH-1:0] dma_m_axi_araddr;
|
||||
logic [7:0] dma_m_axi_arlen;
|
||||
logic [2:0] dma_m_axi_arsize;
|
||||
logic [1:0] dma_m_axi_arburst;
|
||||
logic dma_m_axi_arlock;
|
||||
logic [3:0] dma_m_axi_arcache;
|
||||
logic [2:0] dma_m_axi_arprot;
|
||||
logic dma_m_axi_arvalid;
|
||||
logic dma_m_axi_arready;
|
||||
|
||||
logic [AXI_ID_WIDTH-1:0] dma_m_axi_rid;
|
||||
logic [AXI_DATA_WIDTH-1:0] dma_m_axi_rdata;
|
||||
logic [1:0] dma_m_axi_rresp;
|
||||
logic dma_m_axi_rlast;
|
||||
logic dma_m_axi_rvalid;
|
||||
logic dma_m_axi_rready;
|
||||
|
||||
logic [AXI_USER_WIDTH-1:0] unused_m_axi_buser;
|
||||
logic [AXI_USER_WIDTH-1:0] unused_m_axi_ruser;
|
||||
|
||||
// Original DMA: flat ports only.
|
||||
axi_dma #(
|
||||
.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_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)
|
||||
) i_axi_dma (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.s_axis_read_desc_addr (dma_s_axis_read_desc_addr),
|
||||
.s_axis_read_desc_len (dma_s_axis_read_desc_len),
|
||||
.s_axis_read_desc_tag (dma_s_axis_read_desc_tag),
|
||||
.s_axis_read_desc_id (dma_s_axis_read_desc_id),
|
||||
.s_axis_read_desc_dest (dma_s_axis_read_desc_dest),
|
||||
.s_axis_read_desc_user (dma_s_axis_read_desc_user),
|
||||
.s_axis_read_desc_valid (dma_s_axis_read_desc_valid),
|
||||
.s_axis_read_desc_ready (dma_s_axis_read_desc_ready),
|
||||
|
||||
.m_axis_read_desc_status_tag (dma_m_axis_read_desc_status_tag),
|
||||
.m_axis_read_desc_status_error (dma_m_axis_read_desc_status_error),
|
||||
.m_axis_read_desc_status_valid (dma_m_axis_read_desc_status_valid),
|
||||
|
||||
.m_axis_read_data_tdata (dma_m_axis_read_data_tdata),
|
||||
.m_axis_read_data_tkeep (dma_m_axis_read_data_tkeep),
|
||||
.m_axis_read_data_tvalid (dma_m_axis_read_data_tvalid),
|
||||
.m_axis_read_data_tready (dma_m_axis_read_data_tready),
|
||||
.m_axis_read_data_tlast (dma_m_axis_read_data_tlast),
|
||||
.m_axis_read_data_tid (dma_m_axis_read_data_tid),
|
||||
.m_axis_read_data_tdest (dma_m_axis_read_data_tdest),
|
||||
.m_axis_read_data_tuser (dma_m_axis_read_data_tuser),
|
||||
|
||||
.s_axis_write_desc_addr (dma_s_axis_write_desc_addr),
|
||||
.s_axis_write_desc_len (dma_s_axis_write_desc_len),
|
||||
.s_axis_write_desc_tag (dma_s_axis_write_desc_tag),
|
||||
.s_axis_write_desc_valid (dma_s_axis_write_desc_valid),
|
||||
.s_axis_write_desc_ready (dma_s_axis_write_desc_ready),
|
||||
|
||||
.m_axis_write_desc_status_len (dma_m_axis_write_desc_status_len),
|
||||
.m_axis_write_desc_status_tag (dma_m_axis_write_desc_status_tag),
|
||||
.m_axis_write_desc_status_id (dma_m_axis_write_desc_status_id),
|
||||
.m_axis_write_desc_status_dest (dma_m_axis_write_desc_status_dest),
|
||||
.m_axis_write_desc_status_user (dma_m_axis_write_desc_status_user),
|
||||
.m_axis_write_desc_status_error (dma_m_axis_write_desc_status_error),
|
||||
.m_axis_write_desc_status_valid (dma_m_axis_write_desc_status_valid),
|
||||
|
||||
.s_axis_write_data_tdata (dma_s_axis_write_data_tdata),
|
||||
.s_axis_write_data_tkeep (dma_s_axis_write_data_tkeep),
|
||||
.s_axis_write_data_tvalid (dma_s_axis_write_data_tvalid),
|
||||
.s_axis_write_data_tready (dma_s_axis_write_data_tready),
|
||||
.s_axis_write_data_tlast (dma_s_axis_write_data_tlast),
|
||||
.s_axis_write_data_tid (dma_s_axis_write_data_tid),
|
||||
.s_axis_write_data_tdest (dma_s_axis_write_data_tdest),
|
||||
.s_axis_write_data_tuser (dma_s_axis_write_data_tuser),
|
||||
|
||||
.m_axi_awid (dma_m_axi_awid),
|
||||
.m_axi_awaddr (dma_m_axi_awaddr),
|
||||
.m_axi_awlen (dma_m_axi_awlen),
|
||||
.m_axi_awsize (dma_m_axi_awsize),
|
||||
.m_axi_awburst (dma_m_axi_awburst),
|
||||
.m_axi_awlock (dma_m_axi_awlock),
|
||||
.m_axi_awcache (dma_m_axi_awcache),
|
||||
.m_axi_awprot (dma_m_axi_awprot),
|
||||
.m_axi_awvalid (dma_m_axi_awvalid),
|
||||
.m_axi_awready (dma_m_axi_awready),
|
||||
|
||||
.m_axi_wdata (dma_m_axi_wdata),
|
||||
.m_axi_wstrb (dma_m_axi_wstrb),
|
||||
.m_axi_wlast (dma_m_axi_wlast),
|
||||
.m_axi_wvalid (dma_m_axi_wvalid),
|
||||
.m_axi_wready (dma_m_axi_wready),
|
||||
|
||||
.m_axi_bid (dma_m_axi_bid),
|
||||
.m_axi_bresp (dma_m_axi_bresp),
|
||||
.m_axi_bvalid (dma_m_axi_bvalid),
|
||||
.m_axi_bready (dma_m_axi_bready),
|
||||
|
||||
.m_axi_arid (dma_m_axi_arid),
|
||||
.m_axi_araddr (dma_m_axi_araddr),
|
||||
.m_axi_arlen (dma_m_axi_arlen),
|
||||
.m_axi_arsize (dma_m_axi_arsize),
|
||||
.m_axi_arburst (dma_m_axi_arburst),
|
||||
.m_axi_arlock (dma_m_axi_arlock),
|
||||
.m_axi_arcache (dma_m_axi_arcache),
|
||||
.m_axi_arprot (dma_m_axi_arprot),
|
||||
.m_axi_arvalid (dma_m_axi_arvalid),
|
||||
.m_axi_arready (dma_m_axi_arready),
|
||||
|
||||
.m_axi_rid (dma_m_axi_rid),
|
||||
.m_axi_rdata (dma_m_axi_rdata),
|
||||
.m_axi_rresp (dma_m_axi_rresp),
|
||||
.m_axi_rlast (dma_m_axi_rlast),
|
||||
.m_axi_rvalid (dma_m_axi_rvalid),
|
||||
.m_axi_rready (dma_m_axi_rready),
|
||||
|
||||
.read_enable (read_enable),
|
||||
.write_enable (write_enable),
|
||||
.write_abort (write_abort)
|
||||
);
|
||||
|
||||
|
||||
|
||||
// local read descriptor interface -> DMA flat input
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH),
|
||||
.KEEP_W ('0),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) i_read_desc_cmd_i2f (
|
||||
.s_axis (s_axis_read_desc),
|
||||
.m_axis_tdata ({dma_s_axis_read_desc_addr, dma_s_axis_read_desc_len, dma_s_axis_read_desc_tag}),
|
||||
.m_axis_tkeep (),
|
||||
.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_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)
|
||||
);
|
||||
|
||||
// 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)
|
||||
) 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 (),
|
||||
.s_axis_tstrb (),
|
||||
.s_axis_tlast (),
|
||||
.s_axis_tid (),
|
||||
.s_axis_tdest (),
|
||||
.s_axis_tuser (),
|
||||
.s_axis_tvalid (dma_m_axis_read_desc_status_valid),
|
||||
.s_axis_tready (),
|
||||
.m_axis (m_axis_read_desc_status)
|
||||
);
|
||||
|
||||
// local write descriptor interface -> DMA flat input
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH),
|
||||
.KEEP_W ('0),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) i_write_desc_cmd_i2f (
|
||||
.s_axis (s_axis_write_desc),
|
||||
.m_axis_tdata ({dma_s_axis_write_desc_addr, dma_s_axis_write_desc_len, dma_s_axis_write_desc_tag}),
|
||||
.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_tvalid (dma_s_axis_write_desc_valid),
|
||||
.m_axis_tready (dma_s_axis_write_desc_ready)
|
||||
);
|
||||
|
||||
|
||||
// DMA write descriptor status flat output -> local status interface
|
||||
axis_flat_to_if #(
|
||||
.DATA_W (TAG_WIDTH + LEN_WIDTH + 4),
|
||||
.KEEP_W ('0),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) i_write_desc_status_f2i(
|
||||
.s_axis_tdata ({dma_m_axis_write_desc_status_len, dma_m_axis_write_desc_status_tag, dma_m_axis_write_desc_status_error}),
|
||||
.s_axis_tkeep (),
|
||||
.s_axis_tstrb (),
|
||||
.s_axis_tlast (),
|
||||
.s_axis_tid (dma_m_axis_write_desc_status_id),
|
||||
.s_axis_tdest (dma_m_axis_write_desc_status_dest),
|
||||
.s_axis_tuser (dma_m_axis_write_desc_status_user),
|
||||
.s_axis_tvalid (dma_m_axis_write_desc_status_valid),
|
||||
.s_axis_tready (),
|
||||
.m_axis (m_axis_write_desc_status)
|
||||
);
|
||||
|
||||
// DMA read data flat output -> local axis_if.master
|
||||
axis_flat_to_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) u_m_axis_read_data_flat_to_if (
|
||||
.s_axis_tdata (dma_m_axis_read_data_tdata),
|
||||
.s_axis_tkeep (dma_m_axis_read_data_tkeep),
|
||||
.s_axis_tstrb (dma_m_axis_read_data_tkeep), // axi_dma has no tstrb; mirror tkeep
|
||||
.s_axis_tlast (dma_m_axis_read_data_tlast),
|
||||
.s_axis_tid (dma_m_axis_read_data_tid),
|
||||
.s_axis_tdest (dma_m_axis_read_data_tdest),
|
||||
.s_axis_tuser (dma_m_axis_read_data_tuser),
|
||||
.s_axis_tvalid (dma_m_axis_read_data_tvalid),
|
||||
.s_axis_tready (dma_m_axis_read_data_tready),
|
||||
.m_axis (m_axis_read_data)
|
||||
);
|
||||
|
||||
// local axis_if.slave -> DMA write data flat input
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) u_s_axis_write_data_if_to_flat (
|
||||
.s_axis (s_axis_write_data),
|
||||
.m_axis_tdata (dma_s_axis_write_data_tdata),
|
||||
.m_axis_tkeep (dma_s_axis_write_data_tkeep),
|
||||
.m_axis_tstrb (unused_s_axis_write_data_tstrb),
|
||||
.m_axis_tlast (dma_s_axis_write_data_tlast),
|
||||
.m_axis_tid (dma_s_axis_write_data_tid),
|
||||
.m_axis_tdest (dma_s_axis_write_data_tdest),
|
||||
.m_axis_tuser (dma_s_axis_write_data_tuser),
|
||||
.m_axis_tvalid(dma_s_axis_write_data_tvalid),
|
||||
.m_axis_tready(dma_s_axis_write_data_tready)
|
||||
);
|
||||
|
||||
// DMA AXI master flat output -> local axi4_if.master
|
||||
axi4_flat_to_if #(
|
||||
.ADDR_W (AXI_ADDR_WIDTH),
|
||||
.DATA_W (AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W (AXI_USER_WIDTH)
|
||||
) u_m_axi_flat_to_if (
|
||||
.s_axi_awid (dma_m_axi_awid),
|
||||
.s_axi_awaddr (dma_m_axi_awaddr),
|
||||
.s_axi_awlen (dma_m_axi_awlen),
|
||||
.s_axi_awsize (dma_m_axi_awsize),
|
||||
.s_axi_awburst (dma_m_axi_awburst),
|
||||
.s_axi_awlock (dma_m_axi_awlock),
|
||||
.s_axi_awcache (dma_m_axi_awcache),
|
||||
.s_axi_awprot (dma_m_axi_awprot),
|
||||
.s_axi_awqos (4'd0),
|
||||
.s_axi_awregion (4'd0),
|
||||
.s_axi_awuser ({AXI_USER_WIDTH{1'b0}}),
|
||||
.s_axi_awvalid (dma_m_axi_awvalid),
|
||||
.s_axi_awready (dma_m_axi_awready),
|
||||
|
||||
.s_axi_wdata (dma_m_axi_wdata),
|
||||
.s_axi_wstrb (dma_m_axi_wstrb),
|
||||
.s_axi_wlast (dma_m_axi_wlast),
|
||||
.s_axi_wuser ({AXI_USER_WIDTH{1'b0}}),
|
||||
.s_axi_wvalid (dma_m_axi_wvalid),
|
||||
.s_axi_wready (dma_m_axi_wready),
|
||||
|
||||
.s_axi_bid (dma_m_axi_bid),
|
||||
.s_axi_bresp (dma_m_axi_bresp),
|
||||
.s_axi_buser (unused_m_axi_buser),
|
||||
.s_axi_bvalid (dma_m_axi_bvalid),
|
||||
.s_axi_bready (dma_m_axi_bready),
|
||||
|
||||
.s_axi_arid (dma_m_axi_arid),
|
||||
.s_axi_araddr (dma_m_axi_araddr),
|
||||
.s_axi_arlen (dma_m_axi_arlen),
|
||||
.s_axi_arsize (dma_m_axi_arsize),
|
||||
.s_axi_arburst (dma_m_axi_arburst),
|
||||
.s_axi_arlock (dma_m_axi_arlock),
|
||||
.s_axi_arcache (dma_m_axi_arcache),
|
||||
.s_axi_arprot (dma_m_axi_arprot),
|
||||
.s_axi_arqos (4'd0),
|
||||
.s_axi_arregion (4'd0),
|
||||
.s_axi_aruser ({AXI_USER_WIDTH{1'b0}}),
|
||||
.s_axi_arvalid (dma_m_axi_arvalid),
|
||||
.s_axi_arready (dma_m_axi_arready),
|
||||
|
||||
.s_axi_rid (dma_m_axi_rid),
|
||||
.s_axi_rdata (dma_m_axi_rdata),
|
||||
.s_axi_rresp (dma_m_axi_rresp),
|
||||
.s_axi_rlast (dma_m_axi_rlast),
|
||||
.s_axi_ruser (unused_m_axi_ruser),
|
||||
.s_axi_rvalid (dma_m_axi_rvalid),
|
||||
.s_axi_rready (dma_m_axi_rready),
|
||||
|
||||
.m_axi (m_axi)
|
||||
);
|
||||
|
||||
endmodule : axi_dma_if_wrapper
|
||||
|
||||
`default_nettype wire
|
||||
@ -13,7 +13,7 @@ interface axi4_if #(
|
||||
typedef logic [DATA_W/8-1:0] strb_t;
|
||||
typedef logic [ID_W-1:0] id_t;
|
||||
typedef logic [USER_W-1:0] user_t;
|
||||
`AXI4_TYPEDEF_ALL(axi, addr_t, data_t, strb_t, id_t, user_t);
|
||||
`AXI4_TYPEDEF_ALL(axi, addr_t, data_t, strb_t, id_t, user_t)
|
||||
axi_req_t req;
|
||||
axi_resp_t resp;
|
||||
modport master (input aclk, aresetn, output req, input resp);
|
||||
@ -34,7 +34,7 @@ interface axi4l_if #(
|
||||
typedef logic [DATA_W-1:0] data_t;
|
||||
typedef logic [DATA_W/8-1:0] strb_t;
|
||||
typedef logic [USER_W-1:0] user_t;
|
||||
`AXI4L_TYPEDEF_ALL(axil, addr_t, data_t, strb_t, user_t);
|
||||
`AXI4L_TYPEDEF_ALL(axil, addr_t, data_t, strb_t, user_t)
|
||||
axil_req_t req;
|
||||
axil_resp_t resp;
|
||||
modport master (input aclk, aresetn, output req, input resp);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
module axil_cdc_wrapper #(
|
||||
parameter int ADDR_WIDTH = 32,
|
||||
parameter int DATA_WIDTH = 32
|
||||
parameter int ADDR_WIDTH = 32
|
||||
parameter int DATA_WIDTH = 32,
|
||||
)(
|
||||
input wire s_clk,
|
||||
input wire s_rst,
|
||||
@ -83,8 +83,8 @@ module axil_cdc_wrapper #(
|
||||
);
|
||||
|
||||
axil_cdc #(
|
||||
.ADDR_WIDTH (ADDR_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH)
|
||||
.ADDR_WIDTH (ADDR_WIDTH)
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
) i_axil_cdc (
|
||||
.s_clk (s_clk),
|
||||
.s_rst (s_rst),
|
||||
|
||||
430
axi/tb/axi_cocotb_loopback_test/axi4_proxy.py
Normal file
430
axi/tb/axi_cocotb_loopback_test/axi4_proxy.py
Normal file
@ -0,0 +1,430 @@
|
||||
# proxy to match cocotb and custom axi4_if
|
||||
|
||||
import logging
|
||||
|
||||
from cocotb.types import LogicArray
|
||||
|
||||
from cocotbext.axi.axi_channels import (
|
||||
AxiAWBus,
|
||||
AxiWBus,
|
||||
AxiBBus,
|
||||
AxiARBus,
|
||||
AxiRBus,
|
||||
AxiBus,
|
||||
)
|
||||
|
||||
|
||||
def install_cocotbext_axi_slice_compat():
|
||||
"""
|
||||
cocotbext-axi StreamMonitor uses RisingEdge(self.valid/self.ready).
|
||||
That works only for real cocotb LogicObject handles.
|
||||
|
||||
Our SliceSignal is a Python proxy over packed req/resp vector, so
|
||||
RisingEdge(SliceSignal) fails in cocotb 2.x.
|
||||
|
||||
This patch makes StreamMonitor wake on signal.value_change instead.
|
||||
For SliceSignal this should return parent packed vector value_change.
|
||||
"""
|
||||
|
||||
# this sucks...
|
||||
from cocotbext.axi import stream as axi_stream
|
||||
|
||||
async def _run_valid_monitor_value_change(self):
|
||||
while True:
|
||||
await self.valid.value_change
|
||||
self.wake_event.set()
|
||||
|
||||
async def _run_ready_monitor_value_change(self):
|
||||
while True:
|
||||
await self.ready.value_change
|
||||
self.wake_event.set()
|
||||
|
||||
axi_stream.StreamMonitor._run_valid_monitor = _run_valid_monitor_value_change
|
||||
axi_stream.StreamMonitor._run_ready_monitor = _run_ready_monitor_value_change
|
||||
|
||||
|
||||
def _safe_int(value) -> int:
|
||||
try:
|
||||
return int(value)
|
||||
except Exception:
|
||||
|
||||
s = str(value).upper()
|
||||
bits = []
|
||||
|
||||
for ch in s:
|
||||
if ch in "01":
|
||||
bits.append(ch)
|
||||
elif ch in "XZUW-":
|
||||
bits.append("0")
|
||||
|
||||
if not bits:
|
||||
return 0
|
||||
|
||||
return int("".join(bits), 2)
|
||||
|
||||
|
||||
def _logic_array(value: int, width: int):
|
||||
value &= (1 << width) - 1
|
||||
return LogicArray.from_unsigned(value, width)
|
||||
|
||||
|
||||
def _param_int(obj, name: str, override):
|
||||
if override is not None:
|
||||
return int(override)
|
||||
|
||||
p = getattr(obj, name)
|
||||
|
||||
try:
|
||||
return int(p)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
return int(p.value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
raise RuntimeError(f"Cannot read parameter {name} from {obj!r}")
|
||||
|
||||
|
||||
def _packed_offsets(fields):
|
||||
"""
|
||||
de-construct SV signal order.
|
||||
"""
|
||||
total = sum(width for _, width in fields)
|
||||
pos = total
|
||||
offsets = {}
|
||||
|
||||
for name, width in fields:
|
||||
pos -= width
|
||||
offsets[name] = (pos, width)
|
||||
|
||||
return total, offsets
|
||||
|
||||
|
||||
class PackedVector:
|
||||
def __init__(self, handle, name=None):
|
||||
self.handle = handle
|
||||
self.name = name or getattr(handle, "_path", repr(handle))
|
||||
self.width = len(handle)
|
||||
self.mask = (1 << self.width) - 1
|
||||
|
||||
self.shadow = _safe_int(handle.value) & self.mask
|
||||
self.dirty = False
|
||||
|
||||
def read(self, lo: int, width: int) -> int:
|
||||
src = self.shadow if self.dirty else (
|
||||
_safe_int(self.handle.value) & self.mask)
|
||||
return (src >> lo) & ((1 << width) - 1)
|
||||
|
||||
def write(self, lo: int, width: int, value, immediate=False):
|
||||
value = _safe_int(value)
|
||||
field_mask = ((1 << width) - 1) << lo
|
||||
|
||||
self.shadow &= ~field_mask
|
||||
self.shadow |= (value << lo) & field_mask
|
||||
self.shadow &= self.mask
|
||||
self.dirty = True
|
||||
|
||||
v = _logic_array(self.shadow, self.width)
|
||||
|
||||
if immediate:
|
||||
self.handle.setimmediatevalue(v)
|
||||
else:
|
||||
self.handle.value = v
|
||||
|
||||
|
||||
class SliceSignal:
|
||||
"""
|
||||
cocotbext-axi proxy
|
||||
|
||||
looks like:
|
||||
sig.value
|
||||
sig.value = ...
|
||||
sig.setimmediatevalue(...)
|
||||
len(sig)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, parent: PackedVector, lo: int, width: int):
|
||||
self._name = name
|
||||
self._path = name
|
||||
self._log = logging.getLogger(f"cocotb.{name}")
|
||||
|
||||
self.parent = parent
|
||||
self.lo = lo
|
||||
self.width = width
|
||||
|
||||
def __len__(self):
|
||||
return self.width
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SliceSignal {self._path}[{self.lo + self.width - 1}:{self.lo}]>"
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return _logic_array(self.parent.read(self.lo, self.width), self.width)
|
||||
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
self.parent.write(self.lo, self.width, value, immediate=False)
|
||||
|
||||
def setimmediatevalue(self, value):
|
||||
self.parent.write(self.lo, self.width, value, immediate=True)
|
||||
|
||||
def set(self, value):
|
||||
self.value = value
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def value_change(self):
|
||||
# dirty
|
||||
return self.parent.handle.value_change
|
||||
|
||||
|
||||
class ProxyEntity:
|
||||
def __init__(self, name: str, **signals):
|
||||
self._name = name
|
||||
self._path = name
|
||||
self._log = logging.getLogger(f"cocotb.{name}")
|
||||
self.__dict__.update(signals)
|
||||
|
||||
def __dir__(self):
|
||||
return list(self.__dict__.keys())
|
||||
|
||||
|
||||
def _sig(name, parent, base_lo, layout, field):
|
||||
lo, width = layout[field]
|
||||
return SliceSignal(name, parent, base_lo + lo, width)
|
||||
|
||||
|
||||
def axi4_bus_from_packed_if(
|
||||
iface,
|
||||
name="axi",
|
||||
*,
|
||||
addr_width=None,
|
||||
data_width=None,
|
||||
id_width=None,
|
||||
user_width=None,
|
||||
):
|
||||
"""
|
||||
Build cocotbext-axi AxiBus from custom packed axi4_if.
|
||||
|
||||
iface should be instance axi4_if:
|
||||
dut.axi_in
|
||||
dut.axi_out
|
||||
|
||||
example:
|
||||
master = AxiMaster(
|
||||
axi4_bus_from_packed_if(dut.axi_in, "s_axi"),
|
||||
dut.clk,
|
||||
dut.rst,
|
||||
)
|
||||
|
||||
ram = AxiRam(
|
||||
axi4_bus_from_packed_if(dut.axi_out, "m_axi"),
|
||||
dut.clk,
|
||||
dut.rst,
|
||||
size=2**20,
|
||||
)
|
||||
"""
|
||||
|
||||
ADDR_W = _param_int(iface, "ADDR_W", addr_width)
|
||||
DATA_W = _param_int(iface, "DATA_W", data_width)
|
||||
ID_W = _param_int(iface, "ID_W", id_width)
|
||||
USER_W = _param_int(iface, "USER_W", user_width)
|
||||
|
||||
if DATA_W % 8 != 0:
|
||||
raise ValueError(f"AXI DATA_W must be divisible by 8, got {DATA_W}")
|
||||
|
||||
STRB_W = DATA_W // 8
|
||||
|
||||
aw_total, aw_layout = _packed_offsets([
|
||||
("id", ID_W),
|
||||
("addr", ADDR_W),
|
||||
("len", 8),
|
||||
("size", 3),
|
||||
("burst", 2),
|
||||
("lock", 1),
|
||||
("cache", 4),
|
||||
("prot", 3),
|
||||
("qos", 4),
|
||||
("region", 4),
|
||||
("user", USER_W),
|
||||
("valid", 1),
|
||||
])
|
||||
|
||||
w_total, w_layout = _packed_offsets([
|
||||
("data", DATA_W),
|
||||
("strb", STRB_W),
|
||||
("last", 1),
|
||||
("user", USER_W),
|
||||
("valid", 1),
|
||||
])
|
||||
|
||||
b_total, b_layout = _packed_offsets([
|
||||
("id", ID_W),
|
||||
("resp", 2),
|
||||
("user", USER_W),
|
||||
("valid", 1),
|
||||
])
|
||||
|
||||
ar_total, ar_layout = _packed_offsets([
|
||||
("id", ID_W),
|
||||
("addr", ADDR_W),
|
||||
("len", 8),
|
||||
("size", 3),
|
||||
("burst", 2),
|
||||
("lock", 1),
|
||||
("cache", 4),
|
||||
("prot", 3),
|
||||
("qos", 4),
|
||||
("region", 4),
|
||||
("user", USER_W),
|
||||
("valid", 1),
|
||||
])
|
||||
|
||||
r_total, r_layout = _packed_offsets([
|
||||
("id", ID_W),
|
||||
("data", DATA_W),
|
||||
("resp", 2),
|
||||
("last", 1),
|
||||
("user", USER_W),
|
||||
("valid", 1),
|
||||
])
|
||||
|
||||
req_total, req_layout = _packed_offsets([
|
||||
("aw", aw_total),
|
||||
("w", w_total),
|
||||
("b_ready", 1),
|
||||
("ar", ar_total),
|
||||
("r_ready", 1),
|
||||
])
|
||||
|
||||
resp_total, resp_layout = _packed_offsets([
|
||||
("aw_ready", 1),
|
||||
("w_ready", 1),
|
||||
("b", b_total),
|
||||
("ar_ready", 1),
|
||||
("r", r_total),
|
||||
])
|
||||
|
||||
req = PackedVector(iface.req, f"{name}.req")
|
||||
resp = PackedVector(iface.resp, f"{name}.resp")
|
||||
|
||||
if req_total != req.width:
|
||||
raise RuntimeError(
|
||||
f"{name}.req layout mismatch: calculated {req_total} bits, "
|
||||
f"simulator has {req.width} bits"
|
||||
)
|
||||
|
||||
if resp_total != resp.width:
|
||||
raise RuntimeError(
|
||||
f"{name}.resp layout mismatch: calculated {resp_total} bits, "
|
||||
f"simulator has {resp.width} bits"
|
||||
)
|
||||
|
||||
aw_lo, _ = req_layout["aw"]
|
||||
w_lo, _ = req_layout["w"]
|
||||
ar_lo, _ = req_layout["ar"]
|
||||
|
||||
b_lo, _ = resp_layout["b"]
|
||||
r_lo, _ = resp_layout["r"]
|
||||
|
||||
aw = AxiAWBus.from_entity(ProxyEntity(
|
||||
f"{name}_aw",
|
||||
|
||||
awid=_sig(f"{name}_awid", req, aw_lo, aw_layout, "id"),
|
||||
awaddr=_sig(f"{name}_awaddr", req, aw_lo, aw_layout, "addr"),
|
||||
awlen=_sig(f"{name}_awlen", req, aw_lo, aw_layout, "len"),
|
||||
awsize=_sig(f"{name}_awsize", req, aw_lo, aw_layout, "size"),
|
||||
awburst=_sig(f"{name}_awburst", req, aw_lo, aw_layout, "burst"),
|
||||
awlock=_sig(f"{name}_awlock", req, aw_lo, aw_layout, "lock"),
|
||||
awcache=_sig(f"{name}_awcache", req, aw_lo, aw_layout, "cache"),
|
||||
awprot=_sig(f"{name}_awprot", req, aw_lo, aw_layout, "prot"),
|
||||
awqos=_sig(f"{name}_awqos", req, aw_lo, aw_layout, "qos"),
|
||||
awregion=_sig(f"{name}_awregion", req, aw_lo, aw_layout, "region"),
|
||||
awuser=_sig(f"{name}_awuser", req, aw_lo, aw_layout, "user"),
|
||||
awvalid=_sig(f"{name}_awvalid", req, aw_lo, aw_layout, "valid"),
|
||||
|
||||
awready=SliceSignal(
|
||||
f"{name}_awready",
|
||||
resp,
|
||||
*resp_layout["aw_ready"],
|
||||
),
|
||||
))
|
||||
|
||||
w = AxiWBus.from_entity(ProxyEntity(
|
||||
f"{name}_w",
|
||||
|
||||
wdata=_sig(f"{name}_wdata", req, w_lo, w_layout, "data"),
|
||||
wstrb=_sig(f"{name}_wstrb", req, w_lo, w_layout, "strb"),
|
||||
wlast=_sig(f"{name}_wlast", req, w_lo, w_layout, "last"),
|
||||
wuser=_sig(f"{name}_wuser", req, w_lo, w_layout, "user"),
|
||||
wvalid=_sig(f"{name}_wvalid", req, w_lo, w_layout, "valid"),
|
||||
|
||||
wready=SliceSignal(
|
||||
f"{name}_wready",
|
||||
resp,
|
||||
*resp_layout["w_ready"],
|
||||
),
|
||||
))
|
||||
|
||||
b = AxiBBus.from_entity(ProxyEntity(
|
||||
f"{name}_b",
|
||||
|
||||
bid=_sig(f"{name}_bid", resp, b_lo, b_layout, "id"),
|
||||
bresp=_sig(f"{name}_bresp", resp, b_lo, b_layout, "resp"),
|
||||
buser=_sig(f"{name}_buser", resp, b_lo, b_layout, "user"),
|
||||
bvalid=_sig(f"{name}_bvalid", resp, b_lo, b_layout, "valid"),
|
||||
|
||||
bready=SliceSignal(
|
||||
f"{name}_bready",
|
||||
req,
|
||||
*req_layout["b_ready"],
|
||||
),
|
||||
))
|
||||
|
||||
ar = AxiARBus.from_entity(ProxyEntity(
|
||||
f"{name}_ar",
|
||||
|
||||
arid=_sig(f"{name}_arid", req, ar_lo, ar_layout, "id"),
|
||||
araddr=_sig(f"{name}_araddr", req, ar_lo, ar_layout, "addr"),
|
||||
arlen=_sig(f"{name}_arlen", req, ar_lo, ar_layout, "len"),
|
||||
arsize=_sig(f"{name}_arsize", req, ar_lo, ar_layout, "size"),
|
||||
arburst=_sig(f"{name}_arburst", req, ar_lo, ar_layout, "burst"),
|
||||
arlock=_sig(f"{name}_arlock", req, ar_lo, ar_layout, "lock"),
|
||||
arcache=_sig(f"{name}_arcache", req, ar_lo, ar_layout, "cache"),
|
||||
arprot=_sig(f"{name}_arprot", req, ar_lo, ar_layout, "prot"),
|
||||
arqos=_sig(f"{name}_arqos", req, ar_lo, ar_layout, "qos"),
|
||||
arregion=_sig(f"{name}_arregion", req, ar_lo, ar_layout, "region"),
|
||||
aruser=_sig(f"{name}_aruser", req, ar_lo, ar_layout, "user"),
|
||||
arvalid=_sig(f"{name}_arvalid", req, ar_lo, ar_layout, "valid"),
|
||||
|
||||
arready=SliceSignal(
|
||||
f"{name}_arready",
|
||||
resp,
|
||||
*resp_layout["ar_ready"],
|
||||
),
|
||||
))
|
||||
|
||||
r = AxiRBus.from_entity(ProxyEntity(
|
||||
f"{name}_r",
|
||||
|
||||
rid=_sig(f"{name}_rid", resp, r_lo, r_layout, "id"),
|
||||
rdata=_sig(f"{name}_rdata", resp, r_lo, r_layout, "data"),
|
||||
rresp=_sig(f"{name}_rresp", resp, r_lo, r_layout, "resp"),
|
||||
rlast=_sig(f"{name}_rlast", resp, r_lo, r_layout, "last"),
|
||||
ruser=_sig(f"{name}_ruser", resp, r_lo, r_layout, "user"),
|
||||
rvalid=_sig(f"{name}_rvalid", resp, r_lo, r_layout, "valid"),
|
||||
|
||||
rready=SliceSignal(
|
||||
f"{name}_rready",
|
||||
req,
|
||||
*req_layout["r_ready"],
|
||||
),
|
||||
))
|
||||
|
||||
return AxiBus.from_channels(aw, w, b, ar, r)
|
||||
@ -1,5 +1,3 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_axi4_loopback #(
|
||||
parameter int unsigned ADDR_W = 32,
|
||||
parameter int unsigned DATA_W = 64,
|
||||
@ -7,107 +5,7 @@ module tb_axi4_loopback #(
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
// slave-side flat AXI port (cocotb driven)
|
||||
input logic [ID_W-1:0] s_axi_awid,
|
||||
input logic [ADDR_W-1:0] s_axi_awaddr,
|
||||
input logic [7:0] s_axi_awlen,
|
||||
input logic [2:0] s_axi_awsize,
|
||||
input logic [1:0] s_axi_awburst,
|
||||
input logic s_axi_awlock,
|
||||
input logic [3:0] s_axi_awcache,
|
||||
input logic [2:0] s_axi_awprot,
|
||||
input logic [3:0] s_axi_awqos,
|
||||
input logic [3:0] s_axi_awregion,
|
||||
input logic [USER_W-1:0] s_axi_awuser,
|
||||
input logic s_axi_awvalid,
|
||||
output logic s_axi_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axi_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axi_wstrb,
|
||||
input logic s_axi_wlast,
|
||||
input logic [USER_W-1:0] s_axi_wuser,
|
||||
input logic s_axi_wvalid,
|
||||
output logic s_axi_wready,
|
||||
|
||||
output logic [ID_W-1:0] s_axi_bid,
|
||||
output logic [1:0] s_axi_bresp,
|
||||
output logic [USER_W-1:0] s_axi_buser,
|
||||
output logic s_axi_bvalid,
|
||||
input logic s_axi_bready,
|
||||
|
||||
input logic [ID_W-1:0] s_axi_arid,
|
||||
input logic [ADDR_W-1:0] s_axi_araddr,
|
||||
input logic [7:0] s_axi_arlen,
|
||||
input logic [2:0] s_axi_arsize,
|
||||
input logic [1:0] s_axi_arburst,
|
||||
input logic s_axi_arlock,
|
||||
input logic [3:0] s_axi_arcache,
|
||||
input logic [2:0] s_axi_arprot,
|
||||
input logic [3:0] s_axi_arqos,
|
||||
input logic [3:0] s_axi_arregion,
|
||||
input logic [USER_W-1:0] s_axi_aruser,
|
||||
input logic s_axi_arvalid,
|
||||
output logic s_axi_arready,
|
||||
|
||||
output logic [ID_W-1:0] s_axi_rid,
|
||||
output logic [DATA_W-1:0] s_axi_rdata,
|
||||
output logic [1:0] s_axi_rresp,
|
||||
output logic s_axi_rlast,
|
||||
output logic [USER_W-1:0] s_axi_ruser,
|
||||
output logic s_axi_rvalid,
|
||||
input logic s_axi_rready,
|
||||
|
||||
// master-side flat AXI port for coco-tb
|
||||
output logic [ID_W-1:0] m_axi_awid,
|
||||
output logic [ADDR_W-1:0] m_axi_awaddr,
|
||||
output logic [7:0] m_axi_awlen,
|
||||
output logic [2:0] m_axi_awsize,
|
||||
output logic [1:0] m_axi_awburst,
|
||||
output logic m_axi_awlock,
|
||||
output logic [3:0] m_axi_awcache,
|
||||
output logic [2:0] m_axi_awprot,
|
||||
output logic [3:0] m_axi_awqos,
|
||||
output logic [3:0] m_axi_awregion,
|
||||
output logic [USER_W-1:0] m_axi_awuser,
|
||||
output logic m_axi_awvalid,
|
||||
input logic m_axi_awready,
|
||||
|
||||
output logic [DATA_W-1:0] m_axi_wdata,
|
||||
output logic [DATA_W/8-1:0] m_axi_wstrb,
|
||||
output logic m_axi_wlast,
|
||||
output logic [USER_W-1:0] m_axi_wuser,
|
||||
output logic m_axi_wvalid,
|
||||
input logic m_axi_wready,
|
||||
|
||||
input logic [ID_W-1:0] m_axi_bid,
|
||||
input logic [1:0] m_axi_bresp,
|
||||
input logic [USER_W-1:0] m_axi_buser,
|
||||
input logic m_axi_bvalid,
|
||||
output logic m_axi_bready,
|
||||
|
||||
output logic [ID_W-1:0] m_axi_arid,
|
||||
output logic [ADDR_W-1:0] m_axi_araddr,
|
||||
output logic [7:0] m_axi_arlen,
|
||||
output logic [2:0] m_axi_arsize,
|
||||
output logic [1:0] m_axi_arburst,
|
||||
output logic m_axi_arlock,
|
||||
output logic [3:0] m_axi_arcache,
|
||||
output logic [2:0] m_axi_arprot,
|
||||
output logic [3:0] m_axi_arqos,
|
||||
output logic [3:0] m_axi_arregion,
|
||||
output logic [USER_W-1:0] m_axi_aruser,
|
||||
output logic m_axi_arvalid,
|
||||
input logic m_axi_arready,
|
||||
|
||||
input logic [ID_W-1:0] m_axi_rid,
|
||||
input logic [DATA_W-1:0] m_axi_rdata,
|
||||
input logic [1:0] m_axi_rresp,
|
||||
input logic m_axi_rlast,
|
||||
input logic [USER_W-1:0] m_axi_ruser,
|
||||
input logic m_axi_rvalid,
|
||||
output logic m_axi_rready
|
||||
input logic rst
|
||||
);
|
||||
|
||||
logic aresetn;
|
||||
@ -133,120 +31,9 @@ module tb_axi4_loopback #(
|
||||
.aresetn(aresetn)
|
||||
);
|
||||
|
||||
axi4_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.ID_W(ID_W),
|
||||
.USER_W(USER_W)
|
||||
) u_flat_to_if (
|
||||
.s_axi_awid (s_axi_awid),
|
||||
.s_axi_awaddr (s_axi_awaddr),
|
||||
.s_axi_awlen (s_axi_awlen),
|
||||
.s_axi_awsize (s_axi_awsize),
|
||||
.s_axi_awburst (s_axi_awburst),
|
||||
.s_axi_awlock (s_axi_awlock),
|
||||
.s_axi_awcache (s_axi_awcache),
|
||||
.s_axi_awprot (s_axi_awprot),
|
||||
.s_axi_awqos (s_axi_awqos),
|
||||
.s_axi_awregion (s_axi_awregion),
|
||||
.s_axi_awuser (s_axi_awuser),
|
||||
.s_axi_awvalid (s_axi_awvalid),
|
||||
.s_axi_awready (s_axi_awready),
|
||||
.s_axi_wdata (s_axi_wdata),
|
||||
.s_axi_wstrb (s_axi_wstrb),
|
||||
.s_axi_wlast (s_axi_wlast),
|
||||
.s_axi_wuser (s_axi_wuser),
|
||||
.s_axi_wvalid (s_axi_wvalid),
|
||||
.s_axi_wready (s_axi_wready),
|
||||
.s_axi_bid (s_axi_bid),
|
||||
.s_axi_bresp (s_axi_bresp),
|
||||
.s_axi_buser (s_axi_buser),
|
||||
.s_axi_bvalid (s_axi_bvalid),
|
||||
.s_axi_bready (s_axi_bready),
|
||||
.s_axi_arid (s_axi_arid),
|
||||
.s_axi_araddr (s_axi_araddr),
|
||||
.s_axi_arlen (s_axi_arlen),
|
||||
.s_axi_arsize (s_axi_arsize),
|
||||
.s_axi_arburst (s_axi_arburst),
|
||||
.s_axi_arlock (s_axi_arlock),
|
||||
.s_axi_arcache (s_axi_arcache),
|
||||
.s_axi_arprot (s_axi_arprot),
|
||||
.s_axi_arqos (s_axi_arqos),
|
||||
.s_axi_arregion (s_axi_arregion),
|
||||
.s_axi_aruser (s_axi_aruser),
|
||||
.s_axi_arvalid (s_axi_arvalid),
|
||||
.s_axi_arready (s_axi_arready),
|
||||
.s_axi_rid (s_axi_rid),
|
||||
.s_axi_rdata (s_axi_rdata),
|
||||
.s_axi_rresp (s_axi_rresp),
|
||||
.s_axi_rlast (s_axi_rlast),
|
||||
.s_axi_ruser (s_axi_ruser),
|
||||
.s_axi_rvalid (s_axi_rvalid),
|
||||
.s_axi_rready (s_axi_rready),
|
||||
.m_axi (axi_in)
|
||||
);
|
||||
|
||||
axi4_loopback #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.ID_W(ID_W),
|
||||
.USER_W(USER_W)
|
||||
) dut (
|
||||
axi4_loopback dut (
|
||||
.s_axi(axi_in),
|
||||
.m_axi(axi_out)
|
||||
);
|
||||
|
||||
axi4_if_to_flat #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.ID_W(ID_W),
|
||||
.USER_W(USER_W)
|
||||
) u_if_to_flat (
|
||||
.s_axi (axi_out),
|
||||
.m_axi_awid (m_axi_awid),
|
||||
.m_axi_awaddr (m_axi_awaddr),
|
||||
.m_axi_awlen (m_axi_awlen),
|
||||
.m_axi_awsize (m_axi_awsize),
|
||||
.m_axi_awburst (m_axi_awburst),
|
||||
.m_axi_awlock (m_axi_awlock),
|
||||
.m_axi_awcache (m_axi_awcache),
|
||||
.m_axi_awprot (m_axi_awprot),
|
||||
.m_axi_awqos (m_axi_awqos),
|
||||
.m_axi_awregion (m_axi_awregion),
|
||||
.m_axi_awuser (m_axi_awuser),
|
||||
.m_axi_awvalid (m_axi_awvalid),
|
||||
.m_axi_awready (m_axi_awready),
|
||||
.m_axi_wdata (m_axi_wdata),
|
||||
.m_axi_wstrb (m_axi_wstrb),
|
||||
.m_axi_wlast (m_axi_wlast),
|
||||
.m_axi_wuser (m_axi_wuser),
|
||||
.m_axi_wvalid (m_axi_wvalid),
|
||||
.m_axi_wready (m_axi_wready),
|
||||
.m_axi_bid (m_axi_bid),
|
||||
.m_axi_bresp (m_axi_bresp),
|
||||
.m_axi_buser (m_axi_buser),
|
||||
.m_axi_bvalid (m_axi_bvalid),
|
||||
.m_axi_bready (m_axi_bready),
|
||||
.m_axi_arid (m_axi_arid),
|
||||
.m_axi_araddr (m_axi_araddr),
|
||||
.m_axi_arlen (m_axi_arlen),
|
||||
.m_axi_arsize (m_axi_arsize),
|
||||
.m_axi_arburst (m_axi_arburst),
|
||||
.m_axi_arlock (m_axi_arlock),
|
||||
.m_axi_arcache (m_axi_arcache),
|
||||
.m_axi_arprot (m_axi_arprot),
|
||||
.m_axi_arqos (m_axi_arqos),
|
||||
.m_axi_arregion (m_axi_arregion),
|
||||
.m_axi_aruser (m_axi_aruser),
|
||||
.m_axi_arvalid (m_axi_arvalid),
|
||||
.m_axi_arready (m_axi_arready),
|
||||
.m_axi_rid (m_axi_rid),
|
||||
.m_axi_rdata (m_axi_rdata),
|
||||
.m_axi_rresp (m_axi_rresp),
|
||||
.m_axi_rlast (m_axi_rlast),
|
||||
.m_axi_ruser (m_axi_ruser),
|
||||
.m_axi_rvalid (m_axi_rvalid),
|
||||
.m_axi_rready (m_axi_rready)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@ -3,7 +3,12 @@ import itertools
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotbext.axi import AxiBus, AxiMaster, AxiRam
|
||||
from cocotbext.axi import AxiMaster, AxiRam
|
||||
|
||||
from cocotbext.axi import AxiMaster, AxiRam
|
||||
from axi4_proxy import axi4_bus_from_packed_if, install_cocotbext_axi_slice_compat
|
||||
|
||||
install_cocotbext_axi_slice_compat()
|
||||
|
||||
|
||||
class TB:
|
||||
@ -12,21 +17,28 @@ class TB:
|
||||
|
||||
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
|
||||
|
||||
# Forencich-style connection:
|
||||
# s_axi: cocotb AXI master -> flat_to_if -> compact AXI interface
|
||||
# m_axi: compact AXI interface -> if_to_flat -> cocotb AXI RAM
|
||||
self.master = AxiMaster(AxiBus.from_prefix(
|
||||
dut, "s_axi"), dut.clk, dut.rst)
|
||||
self.ram = AxiRam(AxiBus.from_prefix(dut, "m_axi"),
|
||||
dut.clk, dut.rst, size=2**20)
|
||||
self.master = AxiMaster(
|
||||
axi4_bus_from_packed_if(dut.axi_in, "s_axi"),
|
||||
dut.clk,
|
||||
dut.rst,
|
||||
)
|
||||
|
||||
self.ram = AxiRam(
|
||||
axi4_bus_from_packed_if(dut.axi_out, "m_axi"),
|
||||
dut.clk,
|
||||
dut.rst,
|
||||
size=2**20,
|
||||
)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
self.dut.rst.value = 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
self.dut.rst.value = 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
@ -36,6 +48,13 @@ def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def inspect_axi_if(dut):
|
||||
dut._log.info("axi_in fields: %s", dir(dut.axi_in))
|
||||
dut._log.info("axi_in.req fields: %s", dir(dut.axi_in.req))
|
||||
dut._log.info("axi_in.resp fields: %s", dir(dut.axi_in.resp))
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_basic_write_read_test(dut):
|
||||
# simple loopback test..
|
||||
|
||||
Reference in New Issue
Block a user