Intermediate tests and updates to the AXI modules.

This commit is contained in:
otroubi
2026-09-03 15:52:16 +03:00
parent 136b69dd9f
commit d7c826406d
36 changed files with 7073 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
**sim_build**
**pycache**
dump.vcd
results.xml
+3
View File
@@ -0,0 +1,3 @@
[submodule "external/verilog-axi"]
path = external/verilog-axi
url = https://github.com/alexforencich/verilog-axi
+3
View File
@@ -0,0 +1,3 @@
# RTL Libs
## AXI Defines
+213
View File
@@ -0,0 +1,213 @@
module axi4l_reg_map #(
parameter int unsigned ADDR_W = 16,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1,
parameter int unsigned N_REGS = 4,
parameter logic [N_REGS-1:0][31:0][2:0] REG_MODE = '{default:'0},
parameter logic [N_REGS-1:0][31:0] REG_RST = '{default:'0}
)(
input logic clk,
input logic rst_n,
axi4l_if.slave s_axil,
input logic [N_REGS-1:0][31:0] reg_i,
output logic [N_REGS-1:0][31:0] reg_o,
output logic [N_REGS-1:0][31:0] reg_pulse
);
import axi_pkg::*;
typedef enum logic [2:0] {
REG_BIT_RSVD = 3'd0,
REG_BIT_RO = 3'd1,
REG_BIT_RW = 3'd2,
REG_BIT_W1S = 3'd3,
REG_BIT_W1C = 3'd4
} reg_bit_mode_t;
localparam int unsigned STRB_W = DATA_W/8;
localparam int unsigned ADDR_LSB = $clog2(DATA_W/8);
localparam int unsigned REG_INDEX_W = (N_REGS <= 1) ? 1 : $clog2(N_REGS);
logic [ADDR_W-1:0] awaddr_q;
logic aw_seen_q;
logic [DATA_W-1:0] wdata_q;
logic [STRB_W-1:0] wstrb_q;
logic w_seen_q;
logic bvalid_q;
logic [1:0] bresp_q;
logic rvalid_q;
logic [1:0] rresp_q;
logic [DATA_W-1:0] rdata_q;
logic [REG_INDEX_W-1:0] wr_idx;
logic [REG_INDEX_W-1:0] rd_idx;
logic wr_addr_valid;
logic rd_addr_valid;
integer b;
logic [31:0] wr_mask;
logic [31:0] wr_data32;
logic [31:0] rw_cur;
logic [31:0] rw_new;
logic [31:0] rd_word;
always_comb begin
wr_idx = '0;
rd_idx = '0;
wr_addr_valid = 1'b0;
rd_addr_valid = 1'b0;
if (awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
wr_idx = awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
wr_addr_valid = 1'b1;
end
if (s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
rd_idx = s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
rd_addr_valid = 1'b1;
end
end
always_comb begin
wr_mask = '0;
for (int k = 0; k < STRB_W; k++) begin
wr_mask[k*8 +: 8] = {8{wstrb_q[k]}};
end
wr_data32 = wdata_q[31:0];
end
assign s_axil.resp.aw_ready = !aw_seen_q && !bvalid_q;
assign s_axil.resp.w_ready = !w_seen_q && !bvalid_q;
assign s_axil.resp.ar_ready = !rvalid_q;
assign s_axil.resp.b.valid = bvalid_q;
assign s_axil.resp.b.resp = axi_resp_t'(bresp_q);
assign s_axil.resp.b.user = '0;
assign s_axil.resp.r.valid = rvalid_q;
assign s_axil.resp.r.resp = axi_resp_t'(rresp_q);
assign s_axil.resp.r.data = rdata_q;
assign s_axil.resp.r.user = '0;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
awaddr_q <= '0;
aw_seen_q <= 1'b0;
wdata_q <= '0;
wstrb_q <= '0;
w_seen_q <= 1'b0;
bvalid_q <= 1'b0;
bresp_q <= 2'b00;
rvalid_q <= 1'b0;
rresp_q <= 2'b00;
rdata_q <= '0;
reg_o <= REG_RST;
end else begin
reg_pulse <= '0;
for (int r = 0; r < N_REGS; r++) begin
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
if (reg_bit_mode_t'(REG_MODE[r][bit_idx]) == REG_BIT_W1S)
reg_o[r][bit_idx] <= 1'b0;
end
end
if (s_axil.req.aw.valid && s_axil.resp.aw_ready) begin
awaddr_q <= s_axil.req.aw.addr;
aw_seen_q <= 1'b1;
end
if (s_axil.req.w.valid && s_axil.resp.w_ready) begin
wdata_q <= s_axil.req.w.data;
wstrb_q <= s_axil.req.w.strb;
w_seen_q <= 1'b1;
end
if (aw_seen_q && w_seen_q && !bvalid_q) begin
bvalid_q <= 1'b1;
bresp_q <= 2'b00;
if (!wr_addr_valid) begin
bresp_q <= 2'b10;
end else begin
rw_cur = reg_o[wr_idx];
rw_new = rw_cur;
for (b = 0; b < 32; b = b + 1) begin
if (wr_mask[b]) begin
unique case (reg_bit_mode_t'(REG_MODE[wr_idx][b]))
REG_BIT_RSVD: begin
end
REG_BIT_RO: begin
bresp_q <= 2'b10;
end
REG_BIT_RW: begin
rw_new[b] = wr_data32[b];
end
REG_BIT_W1S: begin
if (wr_data32[b]) begin
rw_new[b] = 1'b1;
reg_pulse[wr_idx][b] <= 1'b1;
end
end
REG_BIT_W1C: begin
if (wr_data32[b]) begin
rw_new[b] = 1'b0;
reg_pulse[wr_idx][b] <= 1'b1;
end
end
default: begin
end
endcase
end
end
reg_o[wr_idx] <= rw_new;
end
aw_seen_q <= 1'b0;
w_seen_q <= 1'b0;
end
if (bvalid_q && s_axil.req.b_ready) begin
bvalid_q <= 1'b0;
end
if (s_axil.req.ar.valid && s_axil.resp.ar_ready) begin
rvalid_q <= 1'b1;
rresp_q <= 2'b00;
rd_word = '0;
if (!rd_addr_valid) begin
rresp_q <= 2'b10;
end else begin
for (b = 0; b < 32; b = b + 1) begin
unique case (reg_bit_mode_t'(REG_MODE[rd_idx][b]))
REG_BIT_RSVD: rd_word[b] = 1'b0;
REG_BIT_RO : rd_word[b] = reg_i[rd_idx][b];
REG_BIT_RW : rd_word[b] = reg_o[rd_idx][b];
REG_BIT_W1S : rd_word[b] = 1'b0;
REG_BIT_W1C : rd_word[b] = reg_o[rd_idx][b];
default : rd_word[b] = 1'b0;
endcase
end
end
rdata_q <= rd_word;
end
if (rvalid_q && s_axil.req.r_ready) begin
rvalid_q <= 1'b0;
end
end
end
endmodule
@@ -0,0 +1,67 @@
module axi4l_reg_map_example #(
parameter int unsigned ADDR_W = 16,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1
)(
input logic clk,
input logic rst_n,
axi4l_if.slave s_axil,
output logic start_o,
output logic soft_reset_o,
output logic enable_o,
output logic irq_enable_o,
output logic [31:0] config_o,
input logic busy_i,
input logic done_i,
input logic error_i,
input logic [7:0] error_code_i
);
import axi4l_reg_map_example_pkg::*;
localparam int unsigned N_REGS = AXI4L_REG_MAP_EXAMPLE_N_REGS;
logic [N_REGS-1:0][31:0] reg_i;
logic [N_REGS-1:0][31:0] reg_o;
logic [N_REGS-1:0][31:0] reg_pulse;
axi4l_reg_map #(
.ADDR_W (ADDR_W),
.DATA_W (DATA_W),
.USER_W (USER_W),
.N_REGS (N_REGS),
.REG_MODE (AXI4L_REG_MAP_EXAMPLE_REG_MODE),
.REG_RST (AXI4L_REG_MAP_EXAMPLE_REG_RST)
) u_reg_map (
.clk (clk),
.rst_n (rst_n),
.s_axil (s_axil),
.reg_i (reg_i),
.reg_o (reg_o),
.reg_pulse (reg_pulse)
);
always_comb begin
reg_i = '0;
// REG_STATUS @ 0x04
reg_i[REG_STATUS][STATUS_BUSY_BIT] = busy_i;
reg_i[REG_STATUS][STATUS_DONE_BIT] = done_i;
reg_i[REG_STATUS][STATUS_ERROR_BIT] = error_i;
reg_i[REG_STATUS][STATUS_ERROR_CODE_MSB:STATUS_ERROR_CODE_LSB] = error_code_i;
// REG_VERSION @ 0x0c
reg_i[REG_VERSION] = VERSION_VAL;
end
// REG_CTRL @ 0x00
assign start_o = reg_pulse[REG_CTRL][CTRL_START_BIT];
assign soft_reset_o = reg_pulse[REG_CTRL][CTRL_SOFT_RESET_BIT];
assign enable_o = reg_o[REG_CTRL][CTRL_ENABLE_BIT];
assign irq_enable_o = reg_o[REG_CTRL][CTRL_IRQ_ENABLE_BIT];
// REG_CONFIG @ 0x08
assign config_o = reg_o[REG_CONFIG];
endmodule : axi4l_reg_map_example
@@ -0,0 +1,68 @@
package axi4l_reg_map_example_pkg;
import axi4l_reg_map_pkg::*;
localparam int unsigned AXI4L_REG_MAP_EXAMPLE_N_REGS = 4;
localparam int unsigned REG_CTRL = 0;
localparam int unsigned REG_STATUS = 1;
localparam int unsigned REG_CONFIG = 2;
localparam int unsigned REG_VERSION = 3;
localparam logic [15:0] REG_CTRL_ADDR = 16'h0000;
localparam logic [15:0] REG_STATUS_ADDR = 16'h0004;
localparam logic [15:0] REG_CONFIG_ADDR = 16'h0008;
localparam logic [15:0] REG_VERSION_ADDR = 16'h000c;
localparam int unsigned CTRL_START_BIT = 0;
localparam int unsigned CTRL_SOFT_RESET_BIT = 1;
localparam int unsigned CTRL_ENABLE_BIT = 2;
localparam int unsigned CTRL_IRQ_ENABLE_BIT = 3;
localparam int unsigned STATUS_BUSY_BIT = 0;
localparam int unsigned STATUS_DONE_BIT = 1;
localparam int unsigned STATUS_ERROR_BIT = 2;
localparam int unsigned STATUS_ERROR_CODE_LSB = 8;
localparam int unsigned STATUS_ERROR_CODE_MSB = 15;
localparam logic [31:0] CONFIG_RST = 32'h0000_0001;
localparam logic [31:0] VERSION_VAL = 32'h0001_0000;
localparam logic [AXI4L_REG_MAP_EXAMPLE_N_REGS-1:0][31:0][2:0] AXI4L_REG_MAP_EXAMPLE_REG_MODE = '{
REG_CTRL: '{
CTRL_START_BIT : REG_BIT_W1S,
CTRL_SOFT_RESET_BIT : REG_BIT_W1S,
CTRL_ENABLE_BIT : REG_BIT_RW,
CTRL_IRQ_ENABLE_BIT : REG_BIT_RW,
default : REG_BIT_RSVD
},
REG_STATUS: '{
STATUS_BUSY_BIT : REG_BIT_RO,
STATUS_DONE_BIT : REG_BIT_RO,
STATUS_ERROR_BIT : REG_BIT_RO,
STATUS_ERROR_CODE_LSB : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+1 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+2 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+3 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+4 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+5 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+6 : REG_BIT_RO,
STATUS_ERROR_CODE_LSB+7 : REG_BIT_RO,
default : REG_BIT_RSVD
},
REG_CONFIG: '{
default: REG_BIT_RW
},
REG_VERSION: '{
default: REG_BIT_RO
}
};
localparam logic [AXI4L_REG_MAP_EXAMPLE_N_REGS-1:0][31:0] AXI4L_REG_MAP_EXAMPLE_REG_RST = '{
REG_CTRL : 32'h0000_0000,
REG_STATUS : 32'h0000_0000,
REG_CONFIG : CONFIG_RST,
REG_VERSION : 32'h0000_0000
};
endpackage : axi4l_reg_map_example_pkg
@@ -0,0 +1,64 @@
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 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;
typedef logic [DMA_AXIL_REG_MAP_N_REGS-1:0][31:0][2:0] reg_mode_map_t;
function automatic reg_mode_map_t make_dma_reg_mode();
reg_mode_map_t mode;
mode = '0;
// По умолчанию всё 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();
endpackage
+97
View File
@@ -0,0 +1,97 @@
module axi4_flat_to_if #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 64,
parameter int unsigned ID_W = 4,
parameter int unsigned USER_W = 1
)(
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,
axi4_if.master m_axi
);
assign m_axi.req.aw.id = s_axi_awid;
assign m_axi.req.aw.addr = s_axi_awaddr;
assign m_axi.req.aw.len = s_axi_awlen;
assign m_axi.req.aw.size = s_axi_awsize;
assign m_axi.req.aw.burst = axi_pkg::axi_burst_t'(s_axi_awburst);
assign m_axi.req.aw.lock = s_axi_awlock;
assign m_axi.req.aw.cache = s_axi_awcache;
assign m_axi.req.aw.prot = s_axi_awprot;
assign m_axi.req.aw.qos = s_axi_awqos;
assign m_axi.req.aw.region = s_axi_awregion;
assign m_axi.req.aw.user = s_axi_awuser;
assign m_axi.req.aw.valid = s_axi_awvalid;
assign s_axi_awready = m_axi.resp.aw_ready;
assign m_axi.req.w.data = s_axi_wdata;
assign m_axi.req.w.strb = s_axi_wstrb;
assign m_axi.req.w.last = s_axi_wlast;
assign m_axi.req.w.user = s_axi_wuser;
assign m_axi.req.w.valid = s_axi_wvalid;
assign s_axi_wready = m_axi.resp.w_ready;
assign s_axi_bid = m_axi.resp.b.id;
assign s_axi_bresp = m_axi.resp.b.resp;
assign s_axi_buser = m_axi.resp.b.user;
assign s_axi_bvalid = m_axi.resp.b.valid;
assign m_axi.req.b_ready = s_axi_bready;
assign m_axi.req.ar.id = s_axi_arid;
assign m_axi.req.ar.addr = s_axi_araddr;
assign m_axi.req.ar.len = s_axi_arlen;
assign m_axi.req.ar.size = s_axi_arsize;
assign m_axi.req.ar.burst = axi_pkg::axi_burst_t'(s_axi_arburst);
assign m_axi.req.ar.lock = s_axi_arlock;
assign m_axi.req.ar.cache = s_axi_arcache;
assign m_axi.req.ar.prot = s_axi_arprot;
assign m_axi.req.ar.qos = s_axi_arqos;
assign m_axi.req.ar.region = s_axi_arregion;
assign m_axi.req.ar.user = s_axi_aruser;
assign m_axi.req.ar.valid = s_axi_arvalid;
assign s_axi_arready = m_axi.resp.ar_ready;
assign s_axi_rid = m_axi.resp.r.id;
assign s_axi_rdata = m_axi.resp.r.data;
assign s_axi_rresp = m_axi.resp.r.resp;
assign s_axi_rlast = m_axi.resp.r.last;
assign s_axi_ruser = m_axi.resp.r.user;
assign s_axi_rvalid = m_axi.resp.r.valid;
assign m_axi.req.r_ready = s_axi_rready;
endmodule
+97
View File
@@ -0,0 +1,97 @@
module axi4_if_to_flat #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 64,
parameter int unsigned ID_W = 4,
parameter int unsigned USER_W = 1
)(
axi4_if.slave s_axi,
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
);
assign m_axi_awid = s_axi.req.aw.id;
assign m_axi_awaddr = s_axi.req.aw.addr;
assign m_axi_awlen = s_axi.req.aw.len;
assign m_axi_awsize = s_axi.req.aw.size;
assign m_axi_awburst = s_axi.req.aw.burst;
assign m_axi_awlock = s_axi.req.aw.lock;
assign m_axi_awcache = s_axi.req.aw.cache;
assign m_axi_awprot = s_axi.req.aw.prot;
assign m_axi_awqos = s_axi.req.aw.qos;
assign m_axi_awregion = s_axi.req.aw.region;
assign m_axi_awuser = s_axi.req.aw.user;
assign m_axi_awvalid = s_axi.req.aw.valid;
assign s_axi.resp.aw_ready = m_axi_awready;
assign m_axi_wdata = s_axi.req.w.data;
assign m_axi_wstrb = s_axi.req.w.strb;
assign m_axi_wlast = s_axi.req.w.last;
assign m_axi_wuser = s_axi.req.w.user;
assign m_axi_wvalid = s_axi.req.w.valid;
assign s_axi.resp.w_ready = m_axi_wready;
assign s_axi.resp.b.id = m_axi_bid;
assign s_axi.resp.b.resp = axi_pkg::axi_resp_t'(m_axi_bresp);
assign s_axi.resp.b.user = m_axi_buser;
assign s_axi.resp.b.valid= m_axi_bvalid;
assign m_axi_bready = s_axi.req.b_ready;
assign m_axi_arid = s_axi.req.ar.id;
assign m_axi_araddr = s_axi.req.ar.addr;
assign m_axi_arlen = s_axi.req.ar.len;
assign m_axi_arsize = s_axi.req.ar.size;
assign m_axi_arburst = s_axi.req.ar.burst;
assign m_axi_arlock = s_axi.req.ar.lock;
assign m_axi_arcache = s_axi.req.ar.cache;
assign m_axi_arprot = s_axi.req.ar.prot;
assign m_axi_arqos = s_axi.req.ar.qos;
assign m_axi_arregion = s_axi.req.ar.region;
assign m_axi_aruser = s_axi.req.ar.user;
assign m_axi_arvalid = s_axi.req.ar.valid;
assign s_axi.resp.ar_ready = m_axi_arready;
assign s_axi.resp.r.id = m_axi_rid;
assign s_axi.resp.r.data = m_axi_rdata;
assign s_axi.resp.r.resp = axi_pkg::axi_resp_t'(m_axi_rresp);
assign s_axi.resp.r.last = m_axi_rlast;
assign s_axi.resp.r.user = m_axi_ruser;
assign s_axi.resp.r.valid= m_axi_rvalid;
assign m_axi_rready = s_axi.req.r_ready;
endmodule
+58
View File
@@ -0,0 +1,58 @@
module axi4l_flat_to_if #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn,
input logic [ADDR_W-1:0] s_axil_awaddr,
input logic [2:0] s_axil_awprot,
input logic [USER_W-1:0] s_axil_awuser,
input logic s_axil_awvalid,
output logic s_axil_awready,
input logic [DATA_W-1:0] s_axil_wdata,
input logic [DATA_W/8-1:0] s_axil_wstrb,
input logic [USER_W-1:0] s_axil_wuser,
input logic s_axil_wvalid,
output logic s_axil_wready,
output logic [1:0] s_axil_bresp,
output logic [USER_W-1:0] s_axil_buser,
output logic s_axil_bvalid,
input logic s_axil_bready,
input logic [ADDR_W-1:0] s_axil_araddr,
input logic [2:0] s_axil_arprot,
input logic [USER_W-1:0] s_axil_aruser,
input logic s_axil_arvalid,
output logic s_axil_arready,
output logic [DATA_W-1:0] s_axil_rdata,
output logic [1:0] s_axil_rresp,
output logic [USER_W-1:0] s_axil_ruser,
output logic s_axil_rvalid,
input logic s_axil_rready,
axi4l_if.master m_axil
);
assign m_axil.req.aw.addr = s_axil_awaddr;
assign m_axil.req.aw.prot = s_axil_awprot;
assign m_axil.req.aw.user = s_axil_awuser;
assign m_axil.req.aw.valid = s_axil_awvalid;
assign s_axil_awready = m_axil.resp.aw_ready;
assign m_axil.req.w.data = s_axil_wdata;
assign m_axil.req.w.strb = s_axil_wstrb;
assign m_axil.req.w.user = s_axil_wuser;
assign m_axil.req.w.valid = s_axil_wvalid;
assign s_axil_wready = m_axil.resp.w_ready;
assign s_axil_bresp = m_axil.resp.b.resp;
assign s_axil_buser = m_axil.resp.b.user;
assign s_axil_bvalid = m_axil.resp.b.valid;
assign m_axil.req.b_ready = s_axil_bready;
assign m_axil.req.ar.addr = s_axil_araddr;
assign m_axil.req.ar.prot = s_axil_arprot;
assign m_axil.req.ar.user = s_axil_aruser;
assign m_axil.req.ar.valid = s_axil_arvalid;
assign s_axil_arready = m_axil.resp.ar_ready;
assign s_axil_rdata = m_axil.resp.r.data;
assign s_axil_rresp = m_axil.resp.r.resp;
assign s_axil_ruser = m_axil.resp.r.user;
assign s_axil_rvalid = m_axil.resp.r.valid;
assign m_axil.req.r_ready = s_axil_rready;
endmodule
+56
View File
@@ -0,0 +1,56 @@
module axi4l_if_to_flat #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1
)(
axi4l_if.slave s_axil,
output logic [ADDR_W-1:0] m_axil_awaddr,
output logic [2:0] m_axil_awprot,
output logic [USER_W-1:0] m_axil_awuser,
output logic m_axil_awvalid,
input logic m_axil_awready,
output logic [DATA_W-1:0] m_axil_wdata,
output logic [DATA_W/8-1:0] m_axil_wstrb,
output logic [USER_W-1:0] m_axil_wuser,
output logic m_axil_wvalid,
input logic m_axil_wready,
input logic [1:0] m_axil_bresp,
input logic [USER_W-1:0] m_axil_buser,
input logic m_axil_bvalid,
output logic m_axil_bready,
output logic [ADDR_W-1:0] m_axil_araddr,
output logic [2:0] m_axil_arprot,
output logic [USER_W-1:0] m_axil_aruser,
output logic m_axil_arvalid,
input logic m_axil_arready,
input logic [DATA_W-1:0] m_axil_rdata,
input logic [1:0] m_axil_rresp,
input logic [USER_W-1:0] m_axil_ruser,
input logic m_axil_rvalid,
output logic m_axil_rready
);
assign m_axil_awaddr = s_axil.req.aw.addr;
assign m_axil_awprot = s_axil.req.aw.prot;
assign m_axil_awuser = s_axil.req.aw.user;
assign m_axil_awvalid = s_axil.req.aw.valid;
assign s_axil.resp.aw_ready = m_axil_awready;
assign m_axil_wdata = s_axil.req.w.data;
assign m_axil_wstrb = s_axil.req.w.strb;
assign m_axil_wuser = s_axil.req.w.user;
assign m_axil_wvalid = s_axil.req.w.valid;
assign s_axil.resp.w_ready = m_axil_wready;
assign s_axil.resp.b.resp = axi_pkg::axi_resp_t'(m_axil_bresp);
assign s_axil.resp.b.user = m_axil_buser;
assign s_axil.resp.b.valid = m_axil_bvalid;
assign m_axil_bready = s_axil.req.b_ready;
assign m_axil_araddr = s_axil.req.ar.addr;
assign m_axil_arprot = s_axil.req.ar.prot;
assign m_axil_aruser = s_axil.req.ar.user;
assign m_axil_arvalid = s_axil.req.ar.valid;
assign s_axil.resp.ar_ready = m_axil_arready;
assign s_axil.resp.r.data = m_axil_rdata;
assign s_axil.resp.r.resp = axi_pkg::axi_resp_t'(m_axil_rresp);
assign s_axil.resp.r.user = m_axil_ruser;
assign s_axil.resp.r.valid = m_axil_rvalid;
assign m_axil_rready = s_axil.req.r_ready;
endmodule
+189
View File
@@ -0,0 +1,189 @@
module axi4l_reg_map #(
parameter int unsigned ADDR_W = 16,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1,
parameter int unsigned N_REGS = 4,
parameter logic [N_REGS-1:0][31:0][2:0] REG_MODE = '{default:'0},
parameter logic [N_REGS-1:0][31:0] REG_RST = '{default:'0}
)(
input logic clk,
input logic rst_n,
axi4l_if.slave s_axil,
input logic [N_REGS-1:0][31:0] reg_i,
output logic [N_REGS-1:0][31:0] reg_o
);
import axi_pkg::*;
typedef enum logic [2:0] {
REG_BIT_RSVD = 3'd0,
REG_BIT_RO = 3'd1,
REG_BIT_RW = 3'd2,
REG_BIT_W1S = 3'd3,
REG_BIT_W1C = 3'd4
} reg_bit_mode_t;
localparam int unsigned STRB_W = DATA_W/8;
localparam int unsigned ADDR_LSB = $clog2(DATA_W/8);
localparam int unsigned REG_INDEX_W = (N_REGS <= 1) ? 1 : $clog2(N_REGS);
logic [ADDR_W-1:0] awaddr_q;
logic aw_seen_q;
logic [DATA_W-1:0] wdata_q;
logic [STRB_W-1:0] wstrb_q;
logic w_seen_q;
logic bvalid_q;
logic [1:0] bresp_q;
logic rvalid_q;
logic [1:0] rresp_q;
logic [DATA_W-1:0] rdata_q;
logic [REG_INDEX_W-1:0] wr_idx;
logic [REG_INDEX_W-1:0] rd_idx;
logic wr_addr_valid;
logic rd_addr_valid;
integer b;
logic [31:0] wr_mask;
logic [31:0] wr_data32;
logic [31:0] rw_cur;
logic [31:0] rw_new;
logic [31:0] rd_word;
always_comb begin
wr_idx = '0;
rd_idx = '0;
wr_addr_valid = 1'b0;
rd_addr_valid = 1'b0;
if (awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
wr_idx = awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
wr_addr_valid = 1'b1;
end
if (s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
rd_idx = s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
rd_addr_valid = 1'b1;
end
end
always_comb begin
wr_mask = '0;
for (int k = 0; k < STRB_W; k++) begin
wr_mask[k*8 +: 8] = {8{wstrb_q[k]}};
end
wr_data32 = wdata_q[31:0];
end
assign s_axil.resp.aw_ready = !aw_seen_q && !bvalid_q;
assign s_axil.resp.w_ready = !w_seen_q && !bvalid_q;
assign s_axil.resp.ar_ready = !rvalid_q;
assign s_axil.resp.b.valid = bvalid_q;
assign s_axil.resp.b.resp = axi_resp_t'(bresp_q);
assign s_axil.resp.b.user = '0;
assign s_axil.resp.r.valid = rvalid_q;
assign s_axil.resp.r.resp = axi_resp_t'(rresp_q);
assign s_axil.resp.r.data = rdata_q;
assign s_axil.resp.r.user = '0;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
awaddr_q <= '0;
aw_seen_q <= 1'b0;
wdata_q <= '0;
wstrb_q <= '0;
w_seen_q <= 1'b0;
bvalid_q <= 1'b0;
bresp_q <= 2'b00;
rvalid_q <= 1'b0;
rresp_q <= 2'b00;
rdata_q <= '0;
reg_o <= REG_RST;
end else begin
for (int r = 0; r < N_REGS; r++) begin
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
if (reg_bit_mode_t'(REG_MODE[r][bit_idx]) == REG_BIT_W1S)
reg_o[r][bit_idx] <= 1'b0;
end
end
if (s_axil.req.aw.valid && s_axil.resp.aw_ready) begin
awaddr_q <= s_axil.req.aw.addr;
aw_seen_q <= 1'b1;
end
if (s_axil.req.w.valid && s_axil.resp.w_ready) begin
wdata_q <= s_axil.req.w.data;
wstrb_q <= s_axil.req.w.strb;
w_seen_q <= 1'b1;
end
if (aw_seen_q && w_seen_q && !bvalid_q) begin
bvalid_q <= 1'b1;
bresp_q <= 2'b00;
if (!wr_addr_valid) begin
bresp_q <= 2'b10;
end else begin
rw_cur = reg_o[wr_idx];
rw_new = rw_cur;
for (b = 0; b < 32; b = b + 1) begin
if (wr_mask[b]) begin
unique case (reg_bit_mode_t'(REG_MODE[wr_idx][b]))
REG_BIT_RSVD: begin end
REG_BIT_RO : begin bresp_q <= 2'b10; end
REG_BIT_RW : rw_new[b] = wr_data32[b];
REG_BIT_W1S : if (wr_data32[b]) rw_new[b] = 1'b1;
REG_BIT_W1C : if (wr_data32[b]) rw_new[b] = 1'b0;
default : begin end
endcase
end
end
reg_o[wr_idx] <= rw_new;
end
aw_seen_q <= 1'b0;
w_seen_q <= 1'b0;
end
if (bvalid_q && s_axil.req.b_ready) begin
bvalid_q <= 1'b0;
end
if (s_axil.req.ar.valid && s_axil.resp.ar_ready) begin
rvalid_q <= 1'b1;
rresp_q <= 2'b00;
rd_word = '0;
if (!rd_addr_valid) begin
rresp_q <= 2'b10;
end else begin
for (b = 0; b < 32; b = b + 1) begin
unique case (reg_bit_mode_t'(REG_MODE[rd_idx][b]))
REG_BIT_RSVD: rd_word[b] = 1'b0;
REG_BIT_RO : rd_word[b] = reg_i[rd_idx][b];
REG_BIT_RW : rd_word[b] = reg_o[rd_idx][b];
REG_BIT_W1S : rd_word[b] = 1'b0;
REG_BIT_W1C : rd_word[b] = reg_o[rd_idx][b];
default : rd_word[b] = 1'b0;
endcase
end
end
rdata_q <= rd_word;
end
if (rvalid_q && s_axil.req.r_ready) begin
rvalid_q <= 1'b0;
end
end
end
endmodule
+59
View File
@@ -0,0 +1,59 @@
module axi4l_to_axi4 #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned ID_W = 4,
parameter int unsigned USER_W = 1,
parameter logic [ID_W-1:0] AXI_ID_CONST = '0,
parameter logic [3:0] AXI_CACHE_CONST = 4'b0000,
parameter logic [3:0] AXI_QOS_CONST = 4'b0000,
parameter logic [3:0] AXI_REGION_CONST = 4'b0000
)(
axi4l_if.slave s_axil,
axi4_if.master m_axi
);
assign m_axi.req.aw.id = AXI_ID_CONST;
assign m_axi.req.aw.addr = s_axil.req.aw.addr;
assign m_axi.req.aw.len = 8'd0;
assign m_axi.req.aw.size = axi_pkg::axi_size_from_bytes(DATA_W/8);
assign m_axi.req.aw.burst = axi_pkg::AXI_BURST_INCR;
assign m_axi.req.aw.lock = 1'b0;
assign m_axi.req.aw.cache = AXI_CACHE_CONST;
assign m_axi.req.aw.prot = s_axil.req.aw.prot;
assign m_axi.req.aw.qos = AXI_QOS_CONST;
assign m_axi.req.aw.region = AXI_REGION_CONST;
assign m_axi.req.aw.user = s_axil.req.aw.user;
assign m_axi.req.aw.valid = s_axil.req.aw.valid;
assign s_axil.resp.aw_ready = m_axi.resp.aw_ready;
assign m_axi.req.w.data = s_axil.req.w.data;
assign m_axi.req.w.strb = s_axil.req.w.strb;
assign m_axi.req.w.last = 1'b1;
assign m_axi.req.w.user = s_axil.req.w.user;
assign m_axi.req.w.valid = s_axil.req.w.valid;
assign s_axil.resp.w_ready = m_axi.resp.w_ready;
assign s_axil.resp.b.resp = m_axi.resp.b.resp;
assign s_axil.resp.b.user = m_axi.resp.b.user;
assign s_axil.resp.b.valid = m_axi.resp.b.valid;
assign m_axi.req.b_ready = s_axil.req.b_ready;
assign m_axi.req.ar.id = AXI_ID_CONST;
assign m_axi.req.ar.addr = s_axil.req.ar.addr;
assign m_axi.req.ar.len = 8'd0;
assign m_axi.req.ar.size = axi_pkg::axi_size_from_bytes(DATA_W/8);
assign m_axi.req.ar.burst = axi_pkg::AXI_BURST_INCR;
assign m_axi.req.ar.lock = 1'b0;
assign m_axi.req.ar.cache = AXI_CACHE_CONST;
assign m_axi.req.ar.prot = s_axil.req.ar.prot;
assign m_axi.req.ar.qos = AXI_QOS_CONST;
assign m_axi.req.ar.region = AXI_REGION_CONST;
assign m_axi.req.ar.user = s_axil.req.ar.user;
assign m_axi.req.ar.valid = s_axil.req.ar.valid;
assign s_axil.resp.ar_ready = m_axi.resp.ar_ready;
assign s_axil.resp.r.data = m_axi.resp.r.data;
assign s_axil.resp.r.resp = m_axi.resp.r.resp;
assign s_axil.resp.r.user = m_axi.resp.r.user;
assign s_axil.resp.r.valid = m_axi.resp.r.valid;
assign m_axi.req.r_ready = s_axil.req.r_ready;
endmodule
@@ -0,0 +1,654 @@
/*
Copyright (c) 2020 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 3x3 crossbar (wrapper)
*/
module axi_crossbar_core_wrapper #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Input ID field width (from AXI masters)
parameter S_ID_WIDTH = 8,
// Output ID field width (towards AXI slaves)
// Additional bits required for response routing
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT),
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Number of concurrent unique IDs
parameter S00_THREADS = 2,
// Number of concurrent operations
parameter S00_ACCEPT = 16,
// Number of concurrent unique IDs
parameter S01_THREADS = 2,
// Number of concurrent operations
parameter S01_ACCEPT = 16,
// Number of concurrent unique IDs
parameter S02_THREADS = 2,
// Number of concurrent operations
parameter S02_ACCEPT = 16,
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_REGIONS concatenated fields of ADDR_WIDTH bits
parameter M00_BASE_ADDR = 0,
// Master interface address widths
// M_REGIONS concatenated fields of 32 bits
parameter M00_ADDR_WIDTH = {M_REGIONS{32'd24}},
// Read connections between interfaces
// S_COUNT bits
parameter M00_CONNECT_READ = 3'b111,
// Write connections between interfaces
// S_COUNT bits
parameter M00_CONNECT_WRITE = 3'b111,
// Number of concurrent operations for each master interface
parameter M00_ISSUE = 4,
// Secure master (fail operations based on awprot/arprot)
parameter M00_SECURE = 0,
// Master interface base addresses
// M_REGIONS concatenated fields of ADDR_WIDTH bits
parameter M01_BASE_ADDR = 0,
// Master interface address widths
// M_REGIONS concatenated fields of 32 bits
parameter M01_ADDR_WIDTH = {M_REGIONS{32'd24}},
// Read connections between interfaces
// S_COUNT bits
parameter M01_CONNECT_READ = 3'b111,
// Write connections between interfaces
// S_COUNT bits
parameter M01_CONNECT_WRITE = 3'b111,
// Number of concurrent operations for each master interface
parameter M01_ISSUE = 4,
// Secure master (fail operations based on awprot/arprot)
parameter M01_SECURE = 0,
// Master interface base addresses
// M_REGIONS concatenated fields of ADDR_WIDTH bits
parameter M02_BASE_ADDR = 0,
// Master interface address widths
// M_REGIONS concatenated fields of 32 bits
parameter M02_ADDR_WIDTH = {M_REGIONS{32'd24}},
// Read connections between interfaces
// S_COUNT bits
parameter M02_CONNECT_READ = 3'b111,
// Write connections between interfaces
// S_COUNT bits
parameter M02_CONNECT_WRITE = 3'b111,
// Number of concurrent operations for each master interface
parameter M02_ISSUE = 4,
// Secure master (fail operations based on awprot/arprot)
parameter M02_SECURE = 0,
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S00_AW_REG_TYPE = 0,
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S00_W_REG_TYPE = 0,
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S00_B_REG_TYPE = 1,
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S00_AR_REG_TYPE = 0,
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S00_R_REG_TYPE = 2,
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S01_AW_REG_TYPE = 0,
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S01_W_REG_TYPE = 0,
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S01_B_REG_TYPE = 1,
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S01_AR_REG_TYPE = 0,
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S01_R_REG_TYPE = 2,
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S02_AW_REG_TYPE = 0,
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S02_W_REG_TYPE = 0,
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S02_B_REG_TYPE = 1,
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S02_AR_REG_TYPE = 0,
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S02_R_REG_TYPE = 2,
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M00_AW_REG_TYPE = 1,
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M00_W_REG_TYPE = 2,
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M00_B_REG_TYPE = 0,
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M00_AR_REG_TYPE = 1,
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M00_R_REG_TYPE = 0,
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M01_AW_REG_TYPE = 1,
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M01_W_REG_TYPE = 2,
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M01_B_REG_TYPE = 0,
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M01_AR_REG_TYPE = 1,
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M01_R_REG_TYPE = 0,
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M02_AW_REG_TYPE = 1,
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M02_W_REG_TYPE = 2,
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M02_B_REG_TYPE = 0,
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M02_AR_REG_TYPE = 1,
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M02_R_REG_TYPE = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [S_ID_WIDTH-1:0] s00_axi_awid,
input wire [ADDR_WIDTH-1:0] s00_axi_awaddr,
input wire [7:0] s00_axi_awlen,
input wire [2:0] s00_axi_awsize,
input wire [1:0] s00_axi_awburst,
input wire s00_axi_awlock,
input wire [3:0] s00_axi_awcache,
input wire [2:0] s00_axi_awprot,
input wire [3:0] s00_axi_awqos,
input wire [AWUSER_WIDTH-1:0] s00_axi_awuser,
input wire s00_axi_awvalid,
output wire s00_axi_awready,
input wire [DATA_WIDTH-1:0] s00_axi_wdata,
input wire [STRB_WIDTH-1:0] s00_axi_wstrb,
input wire s00_axi_wlast,
input wire [WUSER_WIDTH-1:0] s00_axi_wuser,
input wire s00_axi_wvalid,
output wire s00_axi_wready,
output wire [S_ID_WIDTH-1:0] s00_axi_bid,
output wire [1:0] s00_axi_bresp,
output wire [BUSER_WIDTH-1:0] s00_axi_buser,
output wire s00_axi_bvalid,
input wire s00_axi_bready,
input wire [S_ID_WIDTH-1:0] s00_axi_arid,
input wire [ADDR_WIDTH-1:0] s00_axi_araddr,
input wire [7:0] s00_axi_arlen,
input wire [2:0] s00_axi_arsize,
input wire [1:0] s00_axi_arburst,
input wire s00_axi_arlock,
input wire [3:0] s00_axi_arcache,
input wire [2:0] s00_axi_arprot,
input wire [3:0] s00_axi_arqos,
input wire [ARUSER_WIDTH-1:0] s00_axi_aruser,
input wire s00_axi_arvalid,
output wire s00_axi_arready,
output wire [S_ID_WIDTH-1:0] s00_axi_rid,
output wire [DATA_WIDTH-1:0] s00_axi_rdata,
output wire [1:0] s00_axi_rresp,
output wire s00_axi_rlast,
output wire [RUSER_WIDTH-1:0] s00_axi_ruser,
output wire s00_axi_rvalid,
input wire s00_axi_rready,
input wire [S_ID_WIDTH-1:0] s01_axi_awid,
input wire [ADDR_WIDTH-1:0] s01_axi_awaddr,
input wire [7:0] s01_axi_awlen,
input wire [2:0] s01_axi_awsize,
input wire [1:0] s01_axi_awburst,
input wire s01_axi_awlock,
input wire [3:0] s01_axi_awcache,
input wire [2:0] s01_axi_awprot,
input wire [3:0] s01_axi_awqos,
input wire [AWUSER_WIDTH-1:0] s01_axi_awuser,
input wire s01_axi_awvalid,
output wire s01_axi_awready,
input wire [DATA_WIDTH-1:0] s01_axi_wdata,
input wire [STRB_WIDTH-1:0] s01_axi_wstrb,
input wire s01_axi_wlast,
input wire [WUSER_WIDTH-1:0] s01_axi_wuser,
input wire s01_axi_wvalid,
output wire s01_axi_wready,
output wire [S_ID_WIDTH-1:0] s01_axi_bid,
output wire [1:0] s01_axi_bresp,
output wire [BUSER_WIDTH-1:0] s01_axi_buser,
output wire s01_axi_bvalid,
input wire s01_axi_bready,
input wire [S_ID_WIDTH-1:0] s01_axi_arid,
input wire [ADDR_WIDTH-1:0] s01_axi_araddr,
input wire [7:0] s01_axi_arlen,
input wire [2:0] s01_axi_arsize,
input wire [1:0] s01_axi_arburst,
input wire s01_axi_arlock,
input wire [3:0] s01_axi_arcache,
input wire [2:0] s01_axi_arprot,
input wire [3:0] s01_axi_arqos,
input wire [ARUSER_WIDTH-1:0] s01_axi_aruser,
input wire s01_axi_arvalid,
output wire s01_axi_arready,
output wire [S_ID_WIDTH-1:0] s01_axi_rid,
output wire [DATA_WIDTH-1:0] s01_axi_rdata,
output wire [1:0] s01_axi_rresp,
output wire s01_axi_rlast,
output wire [RUSER_WIDTH-1:0] s01_axi_ruser,
output wire s01_axi_rvalid,
input wire s01_axi_rready,
input wire [S_ID_WIDTH-1:0] s02_axi_awid,
input wire [ADDR_WIDTH-1:0] s02_axi_awaddr,
input wire [7:0] s02_axi_awlen,
input wire [2:0] s02_axi_awsize,
input wire [1:0] s02_axi_awburst,
input wire s02_axi_awlock,
input wire [3:0] s02_axi_awcache,
input wire [2:0] s02_axi_awprot,
input wire [3:0] s02_axi_awqos,
input wire [AWUSER_WIDTH-1:0] s02_axi_awuser,
input wire s02_axi_awvalid,
output wire s02_axi_awready,
input wire [DATA_WIDTH-1:0] s02_axi_wdata,
input wire [STRB_WIDTH-1:0] s02_axi_wstrb,
input wire s02_axi_wlast,
input wire [WUSER_WIDTH-1:0] s02_axi_wuser,
input wire s02_axi_wvalid,
output wire s02_axi_wready,
output wire [S_ID_WIDTH-1:0] s02_axi_bid,
output wire [1:0] s02_axi_bresp,
output wire [BUSER_WIDTH-1:0] s02_axi_buser,
output wire s02_axi_bvalid,
input wire s02_axi_bready,
input wire [S_ID_WIDTH-1:0] s02_axi_arid,
input wire [ADDR_WIDTH-1:0] s02_axi_araddr,
input wire [7:0] s02_axi_arlen,
input wire [2:0] s02_axi_arsize,
input wire [1:0] s02_axi_arburst,
input wire s02_axi_arlock,
input wire [3:0] s02_axi_arcache,
input wire [2:0] s02_axi_arprot,
input wire [3:0] s02_axi_arqos,
input wire [ARUSER_WIDTH-1:0] s02_axi_aruser,
input wire s02_axi_arvalid,
output wire s02_axi_arready,
output wire [S_ID_WIDTH-1:0] s02_axi_rid,
output wire [DATA_WIDTH-1:0] s02_axi_rdata,
output wire [1:0] s02_axi_rresp,
output wire s02_axi_rlast,
output wire [RUSER_WIDTH-1:0] s02_axi_ruser,
output wire s02_axi_rvalid,
input wire s02_axi_rready,
/*
* AXI master interface
*/
output wire [M_ID_WIDTH-1:0] m00_axi_awid,
output wire [ADDR_WIDTH-1:0] m00_axi_awaddr,
output wire [7:0] m00_axi_awlen,
output wire [2:0] m00_axi_awsize,
output wire [1:0] m00_axi_awburst,
output wire m00_axi_awlock,
output wire [3:0] m00_axi_awcache,
output wire [2:0] m00_axi_awprot,
output wire [3:0] m00_axi_awqos,
output wire [3:0] m00_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m00_axi_awuser,
output wire m00_axi_awvalid,
input wire m00_axi_awready,
output wire [DATA_WIDTH-1:0] m00_axi_wdata,
output wire [STRB_WIDTH-1:0] m00_axi_wstrb,
output wire m00_axi_wlast,
output wire [WUSER_WIDTH-1:0] m00_axi_wuser,
output wire m00_axi_wvalid,
input wire m00_axi_wready,
input wire [M_ID_WIDTH-1:0] m00_axi_bid,
input wire [1:0] m00_axi_bresp,
input wire [BUSER_WIDTH-1:0] m00_axi_buser,
input wire m00_axi_bvalid,
output wire m00_axi_bready,
output wire [M_ID_WIDTH-1:0] m00_axi_arid,
output wire [ADDR_WIDTH-1:0] m00_axi_araddr,
output wire [7:0] m00_axi_arlen,
output wire [2:0] m00_axi_arsize,
output wire [1:0] m00_axi_arburst,
output wire m00_axi_arlock,
output wire [3:0] m00_axi_arcache,
output wire [2:0] m00_axi_arprot,
output wire [3:0] m00_axi_arqos,
output wire [3:0] m00_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m00_axi_aruser,
output wire m00_axi_arvalid,
input wire m00_axi_arready,
input wire [M_ID_WIDTH-1:0] m00_axi_rid,
input wire [DATA_WIDTH-1:0] m00_axi_rdata,
input wire [1:0] m00_axi_rresp,
input wire m00_axi_rlast,
input wire [RUSER_WIDTH-1:0] m00_axi_ruser,
input wire m00_axi_rvalid,
output wire m00_axi_rready,
output wire [M_ID_WIDTH-1:0] m01_axi_awid,
output wire [ADDR_WIDTH-1:0] m01_axi_awaddr,
output wire [7:0] m01_axi_awlen,
output wire [2:0] m01_axi_awsize,
output wire [1:0] m01_axi_awburst,
output wire m01_axi_awlock,
output wire [3:0] m01_axi_awcache,
output wire [2:0] m01_axi_awprot,
output wire [3:0] m01_axi_awqos,
output wire [3:0] m01_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m01_axi_awuser,
output wire m01_axi_awvalid,
input wire m01_axi_awready,
output wire [DATA_WIDTH-1:0] m01_axi_wdata,
output wire [STRB_WIDTH-1:0] m01_axi_wstrb,
output wire m01_axi_wlast,
output wire [WUSER_WIDTH-1:0] m01_axi_wuser,
output wire m01_axi_wvalid,
input wire m01_axi_wready,
input wire [M_ID_WIDTH-1:0] m01_axi_bid,
input wire [1:0] m01_axi_bresp,
input wire [BUSER_WIDTH-1:0] m01_axi_buser,
input wire m01_axi_bvalid,
output wire m01_axi_bready,
output wire [M_ID_WIDTH-1:0] m01_axi_arid,
output wire [ADDR_WIDTH-1:0] m01_axi_araddr,
output wire [7:0] m01_axi_arlen,
output wire [2:0] m01_axi_arsize,
output wire [1:0] m01_axi_arburst,
output wire m01_axi_arlock,
output wire [3:0] m01_axi_arcache,
output wire [2:0] m01_axi_arprot,
output wire [3:0] m01_axi_arqos,
output wire [3:0] m01_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m01_axi_aruser,
output wire m01_axi_arvalid,
input wire m01_axi_arready,
input wire [M_ID_WIDTH-1:0] m01_axi_rid,
input wire [DATA_WIDTH-1:0] m01_axi_rdata,
input wire [1:0] m01_axi_rresp,
input wire m01_axi_rlast,
input wire [RUSER_WIDTH-1:0] m01_axi_ruser,
input wire m01_axi_rvalid,
output wire m01_axi_rready,
output wire [M_ID_WIDTH-1:0] m02_axi_awid,
output wire [ADDR_WIDTH-1:0] m02_axi_awaddr,
output wire [7:0] m02_axi_awlen,
output wire [2:0] m02_axi_awsize,
output wire [1:0] m02_axi_awburst,
output wire m02_axi_awlock,
output wire [3:0] m02_axi_awcache,
output wire [2:0] m02_axi_awprot,
output wire [3:0] m02_axi_awqos,
output wire [3:0] m02_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m02_axi_awuser,
output wire m02_axi_awvalid,
input wire m02_axi_awready,
output wire [DATA_WIDTH-1:0] m02_axi_wdata,
output wire [STRB_WIDTH-1:0] m02_axi_wstrb,
output wire m02_axi_wlast,
output wire [WUSER_WIDTH-1:0] m02_axi_wuser,
output wire m02_axi_wvalid,
input wire m02_axi_wready,
input wire [M_ID_WIDTH-1:0] m02_axi_bid,
input wire [1:0] m02_axi_bresp,
input wire [BUSER_WIDTH-1:0] m02_axi_buser,
input wire m02_axi_bvalid,
output wire m02_axi_bready,
output wire [M_ID_WIDTH-1:0] m02_axi_arid,
output wire [ADDR_WIDTH-1:0] m02_axi_araddr,
output wire [7:0] m02_axi_arlen,
output wire [2:0] m02_axi_arsize,
output wire [1:0] m02_axi_arburst,
output wire m02_axi_arlock,
output wire [3:0] m02_axi_arcache,
output wire [2:0] m02_axi_arprot,
output wire [3:0] m02_axi_arqos,
output wire [3:0] m02_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m02_axi_aruser,
output wire m02_axi_arvalid,
input wire m02_axi_arready,
input wire [M_ID_WIDTH-1:0] m02_axi_rid,
input wire [DATA_WIDTH-1:0] m02_axi_rdata,
input wire [1:0] m02_axi_rresp,
input wire m02_axi_rlast,
input wire [RUSER_WIDTH-1:0] m02_axi_ruser,
input wire m02_axi_rvalid,
output wire m02_axi_rready
);
localparam S_COUNT = 3;
localparam M_COUNT = 3;
// parameter sizing helpers
function [ADDR_WIDTH*M_REGIONS-1:0] w_a_r(input [ADDR_WIDTH*M_REGIONS-1:0] val);
w_a_r = val;
endfunction
function [32*M_REGIONS-1:0] w_32_r(input [32*M_REGIONS-1:0] val);
w_32_r = val;
endfunction
function [S_COUNT-1:0] w_s(input [S_COUNT-1:0] val);
w_s = val;
endfunction
function [31:0] w_32(input [31:0] val);
w_32 = val;
endfunction
function [1:0] w_2(input [1:0] val);
w_2 = val;
endfunction
function w_1(input val);
w_1 = val;
endfunction
axi_crossbar #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ID_WIDTH(S_ID_WIDTH),
.M_ID_WIDTH(M_ID_WIDTH),
.AWUSER_ENABLE(AWUSER_ENABLE),
.AWUSER_WIDTH(AWUSER_WIDTH),
.WUSER_ENABLE(WUSER_ENABLE),
.WUSER_WIDTH(WUSER_WIDTH),
.BUSER_ENABLE(BUSER_ENABLE),
.BUSER_WIDTH(BUSER_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.S_THREADS({ w_32(S02_THREADS), w_32(S01_THREADS), w_32(S00_THREADS) }),
.S_ACCEPT({ w_32(S02_ACCEPT), w_32(S01_ACCEPT), w_32(S00_ACCEPT) }),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR({ w_a_r(M02_BASE_ADDR), w_a_r(M01_BASE_ADDR), w_a_r(M00_BASE_ADDR) }),
.M_ADDR_WIDTH({ w_32_r(M02_ADDR_WIDTH), w_32_r(M01_ADDR_WIDTH), w_32_r(M00_ADDR_WIDTH) }),
.M_CONNECT_READ({ w_s(M02_CONNECT_READ), w_s(M01_CONNECT_READ), w_s(M00_CONNECT_READ) }),
.M_CONNECT_WRITE({ w_s(M02_CONNECT_WRITE), w_s(M01_CONNECT_WRITE), w_s(M00_CONNECT_WRITE) }),
.M_ISSUE({ w_32(M02_ISSUE), w_32(M01_ISSUE), w_32(M00_ISSUE) }),
.M_SECURE({ w_1(M02_SECURE), w_1(M01_SECURE), w_1(M00_SECURE) }),
.S_AR_REG_TYPE({ w_2(S02_AR_REG_TYPE), w_2(S01_AR_REG_TYPE), w_2(S00_AR_REG_TYPE) }),
.S_R_REG_TYPE({ w_2(S02_R_REG_TYPE), w_2(S01_R_REG_TYPE), w_2(S00_R_REG_TYPE) }),
.S_AW_REG_TYPE({ w_2(S02_AW_REG_TYPE), w_2(S01_AW_REG_TYPE), w_2(S00_AW_REG_TYPE) }),
.S_W_REG_TYPE({ w_2(S02_W_REG_TYPE), w_2(S01_W_REG_TYPE), w_2(S00_W_REG_TYPE) }),
.S_B_REG_TYPE({ w_2(S02_B_REG_TYPE), w_2(S01_B_REG_TYPE), w_2(S00_B_REG_TYPE) }),
.M_AR_REG_TYPE({ w_2(M02_AR_REG_TYPE), w_2(M01_AR_REG_TYPE), w_2(M00_AR_REG_TYPE) }),
.M_R_REG_TYPE({ w_2(M02_R_REG_TYPE), w_2(M01_R_REG_TYPE), w_2(M00_R_REG_TYPE) }),
.M_AW_REG_TYPE({ w_2(M02_AW_REG_TYPE), w_2(M01_AW_REG_TYPE), w_2(M00_AW_REG_TYPE) }),
.M_W_REG_TYPE({ w_2(M02_W_REG_TYPE), w_2(M01_W_REG_TYPE), w_2(M00_W_REG_TYPE) }),
.M_B_REG_TYPE({ w_2(M02_B_REG_TYPE), w_2(M01_B_REG_TYPE), w_2(M00_B_REG_TYPE) })
)
axi_crossbar_inst (
.clk(clk),
.rst(rst),
.s_axi_awid({ s02_axi_awid, s01_axi_awid, s00_axi_awid }),
.s_axi_awaddr({ s02_axi_awaddr, s01_axi_awaddr, s00_axi_awaddr }),
.s_axi_awlen({ s02_axi_awlen, s01_axi_awlen, s00_axi_awlen }),
.s_axi_awsize({ s02_axi_awsize, s01_axi_awsize, s00_axi_awsize }),
.s_axi_awburst({ s02_axi_awburst, s01_axi_awburst, s00_axi_awburst }),
.s_axi_awlock({ s02_axi_awlock, s01_axi_awlock, s00_axi_awlock }),
.s_axi_awcache({ s02_axi_awcache, s01_axi_awcache, s00_axi_awcache }),
.s_axi_awprot({ s02_axi_awprot, s01_axi_awprot, s00_axi_awprot }),
.s_axi_awqos({ s02_axi_awqos, s01_axi_awqos, s00_axi_awqos }),
.s_axi_awuser({ s02_axi_awuser, s01_axi_awuser, s00_axi_awuser }),
.s_axi_awvalid({ s02_axi_awvalid, s01_axi_awvalid, s00_axi_awvalid }),
.s_axi_awready({ s02_axi_awready, s01_axi_awready, s00_axi_awready }),
.s_axi_wdata({ s02_axi_wdata, s01_axi_wdata, s00_axi_wdata }),
.s_axi_wstrb({ s02_axi_wstrb, s01_axi_wstrb, s00_axi_wstrb }),
.s_axi_wlast({ s02_axi_wlast, s01_axi_wlast, s00_axi_wlast }),
.s_axi_wuser({ s02_axi_wuser, s01_axi_wuser, s00_axi_wuser }),
.s_axi_wvalid({ s02_axi_wvalid, s01_axi_wvalid, s00_axi_wvalid }),
.s_axi_wready({ s02_axi_wready, s01_axi_wready, s00_axi_wready }),
.s_axi_bid({ s02_axi_bid, s01_axi_bid, s00_axi_bid }),
.s_axi_bresp({ s02_axi_bresp, s01_axi_bresp, s00_axi_bresp }),
.s_axi_buser({ s02_axi_buser, s01_axi_buser, s00_axi_buser }),
.s_axi_bvalid({ s02_axi_bvalid, s01_axi_bvalid, s00_axi_bvalid }),
.s_axi_bready({ s02_axi_bready, s01_axi_bready, s00_axi_bready }),
.s_axi_arid({ s02_axi_arid, s01_axi_arid, s00_axi_arid }),
.s_axi_araddr({ s02_axi_araddr, s01_axi_araddr, s00_axi_araddr }),
.s_axi_arlen({ s02_axi_arlen, s01_axi_arlen, s00_axi_arlen }),
.s_axi_arsize({ s02_axi_arsize, s01_axi_arsize, s00_axi_arsize }),
.s_axi_arburst({ s02_axi_arburst, s01_axi_arburst, s00_axi_arburst }),
.s_axi_arlock({ s02_axi_arlock, s01_axi_arlock, s00_axi_arlock }),
.s_axi_arcache({ s02_axi_arcache, s01_axi_arcache, s00_axi_arcache }),
.s_axi_arprot({ s02_axi_arprot, s01_axi_arprot, s00_axi_arprot }),
.s_axi_arqos({ s02_axi_arqos, s01_axi_arqos, s00_axi_arqos }),
.s_axi_aruser({ s02_axi_aruser, s01_axi_aruser, s00_axi_aruser }),
.s_axi_arvalid({ s02_axi_arvalid, s01_axi_arvalid, s00_axi_arvalid }),
.s_axi_arready({ s02_axi_arready, s01_axi_arready, s00_axi_arready }),
.s_axi_rid({ s02_axi_rid, s01_axi_rid, s00_axi_rid }),
.s_axi_rdata({ s02_axi_rdata, s01_axi_rdata, s00_axi_rdata }),
.s_axi_rresp({ s02_axi_rresp, s01_axi_rresp, s00_axi_rresp }),
.s_axi_rlast({ s02_axi_rlast, s01_axi_rlast, s00_axi_rlast }),
.s_axi_ruser({ s02_axi_ruser, s01_axi_ruser, s00_axi_ruser }),
.s_axi_rvalid({ s02_axi_rvalid, s01_axi_rvalid, s00_axi_rvalid }),
.s_axi_rready({ s02_axi_rready, s01_axi_rready, s00_axi_rready }),
.m_axi_awid({ m02_axi_awid, m01_axi_awid, m00_axi_awid }),
.m_axi_awaddr({ m02_axi_awaddr, m01_axi_awaddr, m00_axi_awaddr }),
.m_axi_awlen({ m02_axi_awlen, m01_axi_awlen, m00_axi_awlen }),
.m_axi_awsize({ m02_axi_awsize, m01_axi_awsize, m00_axi_awsize }),
.m_axi_awburst({ m02_axi_awburst, m01_axi_awburst, m00_axi_awburst }),
.m_axi_awlock({ m02_axi_awlock, m01_axi_awlock, m00_axi_awlock }),
.m_axi_awcache({ m02_axi_awcache, m01_axi_awcache, m00_axi_awcache }),
.m_axi_awprot({ m02_axi_awprot, m01_axi_awprot, m00_axi_awprot }),
.m_axi_awqos({ m02_axi_awqos, m01_axi_awqos, m00_axi_awqos }),
.m_axi_awregion({ m02_axi_awregion, m01_axi_awregion, m00_axi_awregion }),
.m_axi_awuser({ m02_axi_awuser, m01_axi_awuser, m00_axi_awuser }),
.m_axi_awvalid({ m02_axi_awvalid, m01_axi_awvalid, m00_axi_awvalid }),
.m_axi_awready({ m02_axi_awready, m01_axi_awready, m00_axi_awready }),
.m_axi_wdata({ m02_axi_wdata, m01_axi_wdata, m00_axi_wdata }),
.m_axi_wstrb({ m02_axi_wstrb, m01_axi_wstrb, m00_axi_wstrb }),
.m_axi_wlast({ m02_axi_wlast, m01_axi_wlast, m00_axi_wlast }),
.m_axi_wuser({ m02_axi_wuser, m01_axi_wuser, m00_axi_wuser }),
.m_axi_wvalid({ m02_axi_wvalid, m01_axi_wvalid, m00_axi_wvalid }),
.m_axi_wready({ m02_axi_wready, m01_axi_wready, m00_axi_wready }),
.m_axi_bid({ m02_axi_bid, m01_axi_bid, m00_axi_bid }),
.m_axi_bresp({ m02_axi_bresp, m01_axi_bresp, m00_axi_bresp }),
.m_axi_buser({ m02_axi_buser, m01_axi_buser, m00_axi_buser }),
.m_axi_bvalid({ m02_axi_bvalid, m01_axi_bvalid, m00_axi_bvalid }),
.m_axi_bready({ m02_axi_bready, m01_axi_bready, m00_axi_bready }),
.m_axi_arid({ m02_axi_arid, m01_axi_arid, m00_axi_arid }),
.m_axi_araddr({ m02_axi_araddr, m01_axi_araddr, m00_axi_araddr }),
.m_axi_arlen({ m02_axi_arlen, m01_axi_arlen, m00_axi_arlen }),
.m_axi_arsize({ m02_axi_arsize, m01_axi_arsize, m00_axi_arsize }),
.m_axi_arburst({ m02_axi_arburst, m01_axi_arburst, m00_axi_arburst }),
.m_axi_arlock({ m02_axi_arlock, m01_axi_arlock, m00_axi_arlock }),
.m_axi_arcache({ m02_axi_arcache, m01_axi_arcache, m00_axi_arcache }),
.m_axi_arprot({ m02_axi_arprot, m01_axi_arprot, m00_axi_arprot }),
.m_axi_arqos({ m02_axi_arqos, m01_axi_arqos, m00_axi_arqos }),
.m_axi_arregion({ m02_axi_arregion, m01_axi_arregion, m00_axi_arregion }),
.m_axi_aruser({ m02_axi_aruser, m01_axi_aruser, m00_axi_aruser }),
.m_axi_arvalid({ m02_axi_arvalid, m01_axi_arvalid, m00_axi_arvalid }),
.m_axi_arready({ m02_axi_arready, m01_axi_arready, m00_axi_arready }),
.m_axi_rid({ m02_axi_rid, m01_axi_rid, m00_axi_rid }),
.m_axi_rdata({ m02_axi_rdata, m01_axi_rdata, m00_axi_rdata }),
.m_axi_rresp({ m02_axi_rresp, m01_axi_rresp, m00_axi_rresp }),
.m_axi_rlast({ m02_axi_rlast, m01_axi_rlast, m00_axi_rlast }),
.m_axi_ruser({ m02_axi_ruser, m01_axi_ruser, m00_axi_ruser }),
.m_axi_rvalid({ m02_axi_rvalid, m01_axi_rvalid, m00_axi_rvalid }),
.m_axi_rready({ m02_axi_rready, m01_axi_rready, m00_axi_rready })
);
endmodule
`resetall
File diff suppressed because it is too large Load Diff
+331
View File
@@ -0,0 +1,331 @@
// AXIS compat wrapper above axi_dma_if_wrapper.
//
//
// s_axis_desc_cmd = one-beat command stream carrying read + write desc
// m_axis_desc_status = one-beat status stream carrying read + write status
//
// read_enable and write_enable select which descriptor is used
`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,
// Raw packed command/status widths. rounded up to full bytes
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
)(
input logic clk,
input logic rst,
// Unified command stream. One beat carries both read and write descriptors.
// Which parts are used is selected by read_enable/write_enable.
axis_if.slave s_axis_desc_cmd,
// Unified status stream. One beat can carry read status, write status, or both.
// m_axis_desc_status.tuser[0] = read status valid in this beat
// m_axis_desc_status.tuser[1] = write status valid in this beat
axis_if.master m_axis_desc_status,
// Original DMA data streams and AXI memory master, still exposed as normal
// generic interfaces.
axis_if.master m_axis_read_data,
axis_if.slave s_axis_write_data,
axi4_if.master m_axi,
input logic read_enable,
input logic write_enable,
input logic write_abort
);
// --------------------------------------------------------------------------
// packing layout
// --------------------------------------------------------------------------
// s_axis_desc_cmd.tdata:
// [READ_DESC_*] read descriptor
// [WRITE_DESC_*] write descriptor
//
// m_axis_desc_status.tdata:
// [READ_STATUS_*] read descriptor status
// [WRITE_STATUS_*] write descriptor status
//
// offsets are LSB-first. padding in upper bits (if required)
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 WR_BASE_LSB = READ_DESC_WIDTH;
localparam int unsigned WR_ADDR_LSB = WR_BASE_LSB;
localparam int unsigned WR_LEN_LSB = WR_ADDR_LSB + AXI_ADDR_WIDTH;
localparam int unsigned WR_TAG_LSB = WR_LEN_LSB + LEN_WIDTH;
localparam int unsigned RD_STS_TAG_LSB = 0;
localparam int unsigned RD_STS_ERROR_LSB = RD_STS_TAG_LSB + TAG_WIDTH;
localparam int unsigned WR_STS_BASE_LSB = READ_STATUS_WIDTH;
localparam int unsigned WR_STS_LEN_LSB = WR_STS_BASE_LSB;
localparam int unsigned WR_STS_TAG_LSB = WR_STS_LEN_LSB + LEN_WIDTH;
localparam int unsigned WR_STS_ID_LSB = WR_STS_TAG_LSB + TAG_WIDTH;
localparam int unsigned WR_STS_DEST_LSB = WR_STS_ID_LSB + AXIS_ID_WIDTH;
localparam int unsigned WR_STS_USER_LSB = WR_STS_DEST_LSB + AXIS_DEST_WIDTH;
localparam int unsigned WR_STS_ERROR_LSB = WR_STS_USER_LSB + AXIS_USER_WIDTH;
wire rstn = ~rst;
// --------------------------------------------------------------------------
// Internal DMA-specific descriptor/status interfaces
// --------------------------------------------------------------------------
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)
);
// --------------------------------------------------------------------------
// Command AXIS -> read/write descriptors
// --------------------------------------------------------------------------
wire cmd_valid = s_axis_desc_cmd.req.t.valid;
wire cmd_ready = (!read_enable || read_desc_if.resp.ready) &&
(!write_enable || write_desc_if.resp.ready);
// Only assert a descriptor valid when the complete command can be accepted.
// This prevents partial consumption when both read and write are enabled.
assign read_desc_if.req.valid = cmd_valid && read_enable && (!write_enable || write_desc_if.resp.ready);
assign write_desc_if.req.valid = cmd_valid && write_enable && (!read_enable || read_desc_if.resp.ready);
assign s_axis_desc_cmd.resp.ready = cmd_ready;
assign read_desc_if.req.addr = s_axis_desc_cmd.req.t.data[RD_ADDR_LSB +: AXI_ADDR_WIDTH];
assign read_desc_if.req.len = s_axis_desc_cmd.req.t.data[RD_LEN_LSB +: LEN_WIDTH];
assign read_desc_if.req.tag = s_axis_desc_cmd.req.t.data[RD_TAG_LSB +: TAG_WIDTH];
assign read_desc_if.req.id = s_axis_desc_cmd.req.t.data[RD_ID_LSB +: AXIS_ID_WIDTH];
assign read_desc_if.req.dest = s_axis_desc_cmd.req.t.data[RD_DEST_LSB +: AXIS_DEST_WIDTH];
assign read_desc_if.req.user = s_axis_desc_cmd.req.t.data[RD_USER_LSB +: AXIS_USER_WIDTH];
assign write_desc_if.req.addr = s_axis_desc_cmd.req.t.data[WR_ADDR_LSB +: AXI_ADDR_WIDTH];
assign write_desc_if.req.len = s_axis_desc_cmd.req.t.data[WR_LEN_LSB +: LEN_WIDTH];
assign write_desc_if.req.tag = s_axis_desc_cmd.req.t.data[WR_TAG_LSB +: TAG_WIDTH];
// --------------------------------------------------------------------------
// Lower DMA wrapper
// --------------------------------------------------------------------------
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)
);
// --------------------------------------------------------------------------
// Status capture and unified AXIS output
// --------------------------------------------------------------------------
// Forencich descriptor status channels have valid but no ready. A regular
// AXI-Stream output can be stalled
// this wrapper stores one pending read status and one pending write status.
// if you need more, please attack a fifo
logic rd_status_pending;
logic [TAG_WIDTH-1:0] rd_status_tag_q;
logic [3:0] rd_status_error_q;
logic wr_status_pending;
logic [LEN_WIDTH-1:0] wr_status_len_q;
logic [TAG_WIDTH-1:0] wr_status_tag_q;
logic [AXIS_ID_WIDTH-1:0] wr_status_id_q;
logic [AXIS_DEST_WIDTH-1:0] wr_status_dest_q;
logic [AXIS_USER_WIDTH-1:0] wr_status_user_q;
logic [3:0] wr_status_error_q;
wire status_valid = rd_status_pending || wr_status_pending;
wire status_fire = status_valid && m_axis_desc_status.resp.ready;
always_ff @(posedge clk) begin
if (rst) begin
rd_status_pending <= 1'b0;
wr_status_pending <= 1'b0;
rd_status_tag_q <= '0;
rd_status_error_q <= '0;
wr_status_len_q <= '0;
wr_status_tag_q <= '0;
wr_status_id_q <= '0;
wr_status_dest_q <= '0;
wr_status_user_q <= '0;
wr_status_error_q <= '0;
end else begin
if (status_fire) begin
rd_status_pending <= 1'b0;
wr_status_pending <= 1'b0;
end
if (read_desc_status_if.req.valid) begin
`ifndef SYNTHESIS
if (rd_status_pending && !status_fire) begin
$error("axi_dma_axis_compat: read status overflow; add a FIFO or do not backpressure status output");
end
`endif
rd_status_pending <= 1'b1;
rd_status_tag_q <= read_desc_status_if.req.tag;
rd_status_error_q <= read_desc_status_if.req.error;
end
if (write_desc_status_if.req.valid) begin
`ifndef SYNTHESIS
if (wr_status_pending && !status_fire) begin
$error("axi_dma_axis_compat: write status overflow; add a FIFO or do not backpressure status output");
end
`endif
wr_status_pending <= 1'b1;
wr_status_len_q <= write_desc_status_if.req.len;
wr_status_tag_q <= write_desc_status_if.req.tag;
wr_status_id_q <= write_desc_status_if.req.id;
wr_status_dest_q <= write_desc_status_if.req.dest;
wr_status_user_q <= write_desc_status_if.req.user;
wr_status_error_q <= write_desc_status_if.req.error;
end
end
end
logic [DESC_STATUS_DATA_WIDTH-1:0] status_tdata;
logic [DESC_STATUS_USER_WIDTH-1:0] status_tuser;
always_comb begin
status_tdata = '0;
status_tuser = '0;
if (rd_status_pending) begin
status_tdata[RD_STS_TAG_LSB +: TAG_WIDTH] = rd_status_tag_q;
status_tdata[RD_STS_ERROR_LSB +: 4] = rd_status_error_q;
status_tuser[0] = 1'b1;
end
if (wr_status_pending) begin
status_tdata[WR_STS_LEN_LSB +: LEN_WIDTH] = wr_status_len_q;
status_tdata[WR_STS_TAG_LSB +: TAG_WIDTH] = wr_status_tag_q;
status_tdata[WR_STS_ID_LSB +: AXIS_ID_WIDTH] = wr_status_id_q;
status_tdata[WR_STS_DEST_LSB +: AXIS_DEST_WIDTH] = wr_status_dest_q;
status_tdata[WR_STS_USER_LSB +: AXIS_USER_WIDTH] = wr_status_user_q;
status_tdata[WR_STS_ERROR_LSB +: 4] = wr_status_error_q;
status_tuser[1] = 1'b1;
end
end
assign m_axis_desc_status.req.t.data = status_tdata;
assign m_axis_desc_status.req.t.keep = {DESC_STATUS_KEEP_WIDTH{1'b1}};
assign m_axis_desc_status.req.t.strb = {DESC_STATUS_KEEP_WIDTH{1'b1}};
assign m_axis_desc_status.req.t.last = 1'b1;
assign m_axis_desc_status.req.t.id = '0;
assign m_axis_desc_status.req.t.dest = '0;
assign m_axis_desc_status.req.t.user = status_tuser;
assign m_axis_desc_status.req.t.valid = status_valid;
endmodule : axi_dma_axis_compat
`default_nettype wire
+109
View File
@@ -0,0 +1,109 @@
`default_nettype none
interface axi_dma_read_desc_if #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn
);
typedef struct packed {
logic [ADDR_W-1:0] addr;
logic [LEN_W-1:0] len;
logic [TAG_W-1:0] tag;
logic [ID_W-1:0] id;
logic [DEST_W-1:0] dest;
logic [USER_W-1:0] user;
logic valid;
} req_t;
typedef struct packed {
logic ready;
} resp_t;
req_t req;
resp_t resp;
modport master (input aclk, aresetn, output req, input resp);
modport slave (input aclk, aresetn, input req, output resp);
modport monitor (input aclk, aresetn, input req, input resp);
endinterface : axi_dma_read_desc_if
interface axi_dma_read_desc_status_if #(
parameter int unsigned TAG_W = 8
)(
input logic aclk,
input logic aresetn
);
typedef struct packed {
logic [TAG_W-1:0] tag;
logic [3:0] error;
logic valid;
} req_t;
req_t req;
modport master (input aclk, aresetn, output req);
modport slave (input aclk, aresetn, input req);
modport monitor (input aclk, aresetn, input req);
endinterface : axi_dma_read_desc_status_if
interface axi_dma_write_desc_if #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8
)(
input logic aclk,
input logic aresetn
);
typedef struct packed {
logic [ADDR_W-1:0] addr;
logic [LEN_W-1:0] len;
logic [TAG_W-1:0] tag;
logic valid;
} req_t;
typedef struct packed {
logic ready;
} resp_t;
req_t req;
resp_t resp;
modport master (input aclk, aresetn, output req, input resp);
modport slave (input aclk, aresetn, input req, output resp);
modport monitor (input aclk, aresetn, input req, input resp);
endinterface : axi_dma_write_desc_if
interface axi_dma_write_desc_status_if #(
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn
);
typedef struct packed {
logic [LEN_W-1:0] len;
logic [TAG_W-1:0] tag;
logic [ID_W-1:0] id;
logic [DEST_W-1:0] dest;
logic [USER_W-1:0] user;
logic [3:0] error;
logic valid;
} req_t;
req_t req;
modport master (input aclk, aresetn, output req);
modport slave (input aclk, aresetn, input req);
modport monitor (input aclk, aresetn, input req);
endinterface : axi_dma_write_desc_status_if
`default_nettype wire
+643
View File
@@ -0,0 +1,643 @@
// 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_read_desc_flat_to_if #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic [ADDR_W-1:0] s_axis_read_desc_addr,
input logic [LEN_W-1:0] s_axis_read_desc_len,
input logic [TAG_W-1:0] s_axis_read_desc_tag,
input logic [ID_W-1:0] s_axis_read_desc_id,
input logic [DEST_W-1:0] s_axis_read_desc_dest,
input logic [USER_W-1:0] s_axis_read_desc_user,
input logic s_axis_read_desc_valid,
output logic s_axis_read_desc_ready,
axi_dma_read_desc_if.master m_axis_read_desc
);
assign m_axis_read_desc.req.addr = s_axis_read_desc_addr;
assign m_axis_read_desc.req.len = s_axis_read_desc_len;
assign m_axis_read_desc.req.tag = s_axis_read_desc_tag;
assign m_axis_read_desc.req.id = s_axis_read_desc_id;
assign m_axis_read_desc.req.dest = s_axis_read_desc_dest;
assign m_axis_read_desc.req.user = s_axis_read_desc_user;
assign m_axis_read_desc.req.valid = s_axis_read_desc_valid;
assign s_axis_read_desc_ready = m_axis_read_desc.resp.ready;
endmodule : axi_dma_read_desc_flat_to_if
module axi_dma_read_desc_if_to_flat #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
axi_dma_read_desc_if.slave s_axis_read_desc,
output logic [ADDR_W-1:0] m_axis_read_desc_addr,
output logic [LEN_W-1:0] m_axis_read_desc_len,
output logic [TAG_W-1:0] m_axis_read_desc_tag,
output logic [ID_W-1:0] m_axis_read_desc_id,
output logic [DEST_W-1:0] m_axis_read_desc_dest,
output logic [USER_W-1:0] m_axis_read_desc_user,
output logic m_axis_read_desc_valid,
input logic m_axis_read_desc_ready
);
assign m_axis_read_desc_addr = s_axis_read_desc.req.addr;
assign m_axis_read_desc_len = s_axis_read_desc.req.len;
assign m_axis_read_desc_tag = s_axis_read_desc.req.tag;
assign m_axis_read_desc_id = s_axis_read_desc.req.id;
assign m_axis_read_desc_dest = s_axis_read_desc.req.dest;
assign m_axis_read_desc_user = s_axis_read_desc.req.user;
assign m_axis_read_desc_valid = s_axis_read_desc.req.valid;
assign s_axis_read_desc.resp.ready = m_axis_read_desc_ready;
endmodule : axi_dma_read_desc_if_to_flat
module axi_dma_read_desc_status_flat_to_if #(
parameter int unsigned TAG_W = 8
)(
input logic [TAG_W-1:0] m_axis_read_desc_status_tag,
input logic [3:0] m_axis_read_desc_status_error,
input logic m_axis_read_desc_status_valid,
axi_dma_read_desc_status_if.master m_axis_read_desc_status
);
assign m_axis_read_desc_status.req.tag = m_axis_read_desc_status_tag;
assign m_axis_read_desc_status.req.error = m_axis_read_desc_status_error;
assign m_axis_read_desc_status.req.valid = m_axis_read_desc_status_valid;
endmodule : axi_dma_read_desc_status_flat_to_if
module axi_dma_read_desc_status_if_to_flat #(
parameter int unsigned TAG_W = 8
)(
axi_dma_read_desc_status_if.slave s_axis_read_desc_status,
output logic [TAG_W-1:0] m_axis_read_desc_status_tag,
output logic [3:0] m_axis_read_desc_status_error,
output logic m_axis_read_desc_status_valid
);
assign m_axis_read_desc_status_tag = s_axis_read_desc_status.req.tag;
assign m_axis_read_desc_status_error = s_axis_read_desc_status.req.error;
assign m_axis_read_desc_status_valid = s_axis_read_desc_status.req.valid;
endmodule : axi_dma_read_desc_status_if_to_flat
module axi_dma_write_desc_flat_to_if #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8
)(
input logic [ADDR_W-1:0] s_axis_write_desc_addr,
input logic [LEN_W-1:0] s_axis_write_desc_len,
input logic [TAG_W-1:0] s_axis_write_desc_tag,
input logic s_axis_write_desc_valid,
output logic s_axis_write_desc_ready,
axi_dma_write_desc_if.master m_axis_write_desc
);
assign m_axis_write_desc.req.addr = s_axis_write_desc_addr;
assign m_axis_write_desc.req.len = s_axis_write_desc_len;
assign m_axis_write_desc.req.tag = s_axis_write_desc_tag;
assign m_axis_write_desc.req.valid = s_axis_write_desc_valid;
assign s_axis_write_desc_ready = m_axis_write_desc.resp.ready;
endmodule : axi_dma_write_desc_flat_to_if
module axi_dma_write_desc_if_to_flat #(
parameter int unsigned ADDR_W = 64,
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8
)(
axi_dma_write_desc_if.slave s_axis_write_desc,
output logic [ADDR_W-1:0] m_axis_write_desc_addr,
output logic [LEN_W-1:0] m_axis_write_desc_len,
output logic [TAG_W-1:0] m_axis_write_desc_tag,
output logic m_axis_write_desc_valid,
input logic m_axis_write_desc_ready
);
assign m_axis_write_desc_addr = s_axis_write_desc.req.addr;
assign m_axis_write_desc_len = s_axis_write_desc.req.len;
assign m_axis_write_desc_tag = s_axis_write_desc.req.tag;
assign m_axis_write_desc_valid = s_axis_write_desc.req.valid;
assign s_axis_write_desc.resp.ready = m_axis_write_desc_ready;
endmodule : axi_dma_write_desc_if_to_flat
module axi_dma_write_desc_status_flat_to_if #(
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic [LEN_W-1:0] m_axis_write_desc_status_len,
input logic [TAG_W-1:0] m_axis_write_desc_status_tag,
input logic [ID_W-1:0] m_axis_write_desc_status_id,
input logic [DEST_W-1:0] m_axis_write_desc_status_dest,
input logic [USER_W-1:0] m_axis_write_desc_status_user,
input logic [3:0] m_axis_write_desc_status_error,
input logic m_axis_write_desc_status_valid,
axi_dma_write_desc_status_if.master m_axis_write_desc_status
);
assign m_axis_write_desc_status.req.len = m_axis_write_desc_status_len;
assign m_axis_write_desc_status.req.tag = m_axis_write_desc_status_tag;
assign m_axis_write_desc_status.req.id = m_axis_write_desc_status_id;
assign m_axis_write_desc_status.req.dest = m_axis_write_desc_status_dest;
assign m_axis_write_desc_status.req.user = m_axis_write_desc_status_user;
assign m_axis_write_desc_status.req.error = m_axis_write_desc_status_error;
assign m_axis_write_desc_status.req.valid = m_axis_write_desc_status_valid;
endmodule : axi_dma_write_desc_status_flat_to_if
module axi_dma_write_desc_status_if_to_flat #(
parameter int unsigned LEN_W = 20,
parameter int unsigned TAG_W = 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
axi_dma_write_desc_status_if.slave s_axis_write_desc_status,
output logic [LEN_W-1:0] m_axis_write_desc_status_len,
output logic [TAG_W-1:0] m_axis_write_desc_status_tag,
output logic [ID_W-1:0] m_axis_write_desc_status_id,
output logic [DEST_W-1:0] m_axis_write_desc_status_dest,
output logic [USER_W-1:0] m_axis_write_desc_status_user,
output logic [3:0] m_axis_write_desc_status_error,
output logic m_axis_write_desc_status_valid
);
assign m_axis_write_desc_status_len = s_axis_write_desc_status.req.len;
assign m_axis_write_desc_status_tag = s_axis_write_desc_status.req.tag;
assign m_axis_write_desc_status_id = s_axis_write_desc_status.req.id;
assign m_axis_write_desc_status_dest = s_axis_write_desc_status.req.dest;
assign m_axis_write_desc_status_user = s_axis_write_desc_status.req.user;
assign m_axis_write_desc_status_error = s_axis_write_desc_status.req.error;
assign m_axis_write_desc_status_valid = s_axis_write_desc_status.req.valid;
endmodule : axi_dma_write_desc_status_if_to_flat
module axi_dma_if_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,
/*
* AXI read descriptor input.
*/
axi_dma_read_desc_if.slave s_axis_read_desc,
/*
* AXI read descriptor status output.
*/
axi_dma_read_desc_status_if.master m_axis_read_desc_status,
/*
* AXI stream read data output.
*/
axis_if.master m_axis_read_data,
/*
* AXI write descriptor input.
*/
axi_dma_write_desc_if.slave s_axis_write_desc,
/*
* AXI write descriptor status output.
*/
axi_dma_write_desc_status_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
);
// --------------------------------------------------------------------------
// 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)
) u_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
axi_dma_read_desc_if_to_flat #(
.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)
) u_s_axis_read_desc_if_to_flat (
.s_axis_read_desc (s_axis_read_desc),
.m_axis_read_desc_addr (dma_s_axis_read_desc_addr),
.m_axis_read_desc_len (dma_s_axis_read_desc_len),
.m_axis_read_desc_tag (dma_s_axis_read_desc_tag),
.m_axis_read_desc_id (dma_s_axis_read_desc_id),
.m_axis_read_desc_dest (dma_s_axis_read_desc_dest),
.m_axis_read_desc_user (dma_s_axis_read_desc_user),
.m_axis_read_desc_valid (dma_s_axis_read_desc_valid),
.m_axis_read_desc_ready (dma_s_axis_read_desc_ready)
);
// DMA read descriptor status flat output -> local status interface
axi_dma_read_desc_status_flat_to_if #(
.TAG_W (TAG_WIDTH)
) u_m_axis_read_desc_status_flat_to_if (
.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_desc_status (m_axis_read_desc_status)
);
// local write descriptor interface -> DMA flat input
axi_dma_write_desc_if_to_flat #(
.ADDR_W (AXI_ADDR_WIDTH),
.LEN_W (LEN_WIDTH),
.TAG_W (TAG_WIDTH)
) u_s_axis_write_desc_if_to_flat (
.s_axis_write_desc (s_axis_write_desc),
.m_axis_write_desc_addr (dma_s_axis_write_desc_addr),
.m_axis_write_desc_len (dma_s_axis_write_desc_len),
.m_axis_write_desc_tag (dma_s_axis_write_desc_tag),
.m_axis_write_desc_valid (dma_s_axis_write_desc_valid),
.m_axis_write_desc_ready (dma_s_axis_write_desc_ready)
);
// DMA write descriptor status flat output -> local status interface
axi_dma_write_desc_status_flat_to_if #(
.LEN_W (LEN_WIDTH),
.TAG_W (TAG_WIDTH),
.ID_W (AXIS_ID_WIDTH),
.DEST_W (AXIS_DEST_WIDTH),
.USER_W (AXIS_USER_WIDTH)
) u_m_axis_write_desc_status_flat_to_if (
.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),
.m_axis_write_desc_status (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
+453
View 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 (AXIS_KEEP_WIDTH),
.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_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)
);
// DMA read descriptor status flat output -> local status interface
axis_flat_to_if #(
.DATA_W (TAG_WIDTH + 4),
.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 (),
.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 (AXIS_KEEP_WIDTH),
.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 (),
.m_axis_tdest (),
.m_axis_tuser (),
.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 (AXIS_KEEP_WIDTH),
.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_wrapper
`default_nettype wire
+43
View File
@@ -0,0 +1,43 @@
interface axi4_if #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned ID_W = 4,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn
);
import axi_pkg::*;
typedef logic [ADDR_W-1:0] addr_t;
typedef logic [DATA_W-1:0] data_t;
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);
axi_req_t req;
axi_resp_t resp;
modport master (input aclk, aresetn, output req, input resp);
modport slave (input aclk, aresetn, input req, output resp);
modport monitor(input aclk, aresetn, input req, input resp);
endinterface : axi4_if
interface axi4l_if #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn
);
import axi_pkg::*;
typedef logic [ADDR_W-1:0] addr_t;
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);
axil_req_t req;
axil_resp_t resp;
modport master (input aclk, aresetn, output req, input resp);
modport slave (input aclk, aresetn, input req, output resp);
modport monitor(input aclk, aresetn, input req, input resp);
endinterface : axi4l_if
+140
View File
@@ -0,0 +1,140 @@
package axi_pkg;
typedef enum logic [1:0] {
AXI_BURST_FIXED = 2'b00,
AXI_BURST_INCR = 2'b01,
AXI_BURST_WRAP = 2'b10
} axi_burst_t;
typedef enum logic [1:0] {
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11
} axi_resp_t;
function automatic logic [2:0] axi_size_from_bytes(input int unsigned nbytes);
case (nbytes)
1 : return 3'd0;
2 : return 3'd1;
4 : return 3'd2;
8 : return 3'd3;
16 : return 3'd4;
32 : return 3'd5;
64 : return 3'd6;
128 : return 3'd7;
default: return 3'd0;
endcase
endfunction
endpackage : axi_pkg
`define AXI4_TYPEDEF_ALL(__name, __addr_t, __data_t, __strb_t, __id_t, __user_t) \
typedef struct packed { \
__id_t id; \
__addr_t addr; \
logic [7:0] len; \
logic [2:0] size; \
axi_pkg::axi_burst_t burst; \
logic lock; \
logic [3:0] cache; \
logic [2:0] prot; \
logic [3:0] qos; \
logic [3:0] region; \
__user_t user; \
logic valid; \
} __name``_aw_chan_t; \
typedef struct packed { \
__data_t data; \
__strb_t strb; \
logic last; \
__user_t user; \
logic valid; \
} __name``_w_chan_t; \
typedef struct packed { \
__id_t id; \
axi_pkg::axi_resp_t resp; \
__user_t user; \
logic valid; \
} __name``_b_chan_t; \
typedef struct packed { \
__id_t id; \
__addr_t addr; \
logic [7:0] len; \
logic [2:0] size; \
axi_pkg::axi_burst_t burst; \
logic lock; \
logic [3:0] cache; \
logic [2:0] prot; \
logic [3:0] qos; \
logic [3:0] region; \
__user_t user; \
logic valid; \
} __name``_ar_chan_t; \
typedef struct packed { \
__id_t id; \
__data_t data; \
axi_pkg::axi_resp_t resp; \
logic last; \
__user_t user; \
logic valid; \
} __name``_r_chan_t; \
typedef struct packed { \
__name``_aw_chan_t aw; \
__name``_w_chan_t w; \
logic b_ready; \
__name``_ar_chan_t ar; \
logic r_ready; \
} __name``_req_t; \
typedef struct packed { \
logic aw_ready; \
logic w_ready; \
__name``_b_chan_t b; \
logic ar_ready; \
__name``_r_chan_t r; \
} __name``_resp_t;
`define AXI4L_TYPEDEF_ALL(__name, __addr_t, __data_t, __strb_t, __user_t) \
typedef struct packed { \
__addr_t addr; \
logic [2:0] prot; \
__user_t user; \
logic valid; \
} __name``_aw_chan_t; \
typedef struct packed { \
__data_t data; \
__strb_t strb; \
__user_t user; \
logic valid; \
} __name``_w_chan_t; \
typedef struct packed { \
axi_pkg::axi_resp_t resp; \
__user_t user; \
logic valid; \
} __name``_b_chan_t; \
typedef struct packed { \
__addr_t addr; \
logic [2:0] prot; \
__user_t user; \
logic valid; \
} __name``_ar_chan_t; \
typedef struct packed { \
__data_t data; \
axi_pkg::axi_resp_t resp; \
__user_t user; \
logic valid; \
} __name``_r_chan_t; \
typedef struct packed { \
__name``_aw_chan_t aw; \
__name``_w_chan_t w; \
logic b_ready; \
__name``_ar_chan_t ar; \
logic r_ready; \
} __name``_req_t; \
typedef struct packed { \
logic aw_ready; \
logic w_ready; \
__name``_b_chan_t b; \
logic ar_ready; \
__name``_r_chan_t r; \
} __name``_resp_t;
+146
View File
@@ -0,0 +1,146 @@
module axi_ram_wrapper #(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 16,
parameter ID_WIDTH = 8,
parameter PIPELINE_OUTPUT = 0
)(
input wire clk,
input wire rst,
axi4_if.slaver s_axi
);
wire [ID_WIDTH-1:0] ram_s_axi_awid;
wire [ADDR_WIDTH-1:0] ram_s_axi_awaddr;
wire [7:0] ram_s_axi_awlen;
wire [2:0] ram_s_axi_awsize;
wire [1:0] ram_s_axi_awburst;
wire ram_s_axi_awlock;
wire [3:0] ram_s_axi_awcache;
wire [2:0] ram_s_axi_awprot;
wire ram_s_axi_awvalid;
wire ram_s_axi_awready;
wire [DATA_WIDTH-1:0] ram_s_axi_wdata;
wire [STRB_WIDTH-1:0] ram_s_axi_wstrb;
wire ram_s_axi_wlast;
wire ram_s_axi_wvalid;
wire ram_s_axi_wready;
wire [ID_WIDTH-1:0] ram_s_axi_bid;
wire [1:0] ram_s_axi_bresp;
wire ram_s_axi_bvalid;
wire ram_s_axi_bready;
wire [ID_WIDTH-1:0] ram_s_axi_arid;
wire [ADDR_WIDTH-1:0] ram_s_axi_araddr;
wire [7:0] ram_s_axi_arlen;
wire [2:0] ram_s_axi_arsize;
wire [1:0] ram_s_axi_arburst;
wire ram_s_axi_arlock;
wire [3:0] ram_s_axi_arcache;
wire [2:0] ram_s_axi_arprot;
wire ram_s_axi_arvalid;
wire ram_s_axi_arready;
wire [ID_WIDTH-1:0] ram_s_axi_rid;
wire [DATA_WIDTH-1:0] ram_s_axi_rdata;
wire [1:0] ram_s_axi_rresp;
wire ram_s_axi_rlast;
wire ram_s_axi_rvalid;
wire ram_s_axi_rready;
axi4_if_to_flat #(
.ADDR_W (ADDR_WIDTH),
.DATA_W (DATA_WIDTH)
) i_axi4_if_to_flat (
.s_axi (s_axi),
.m_axi_awid (ram_s_axi_awid),
.m_axi_awaddr (ram_s_axi_awaddr),
.m_axi_awlen (ram_s_axi_awlen),
.m_axi_awsize (ram_s_axi_awsize),
.m_axi_awburst (ram_s_axi_awburst),
.m_axi_awlock (ram_s_axi_awlock),
.m_axi_awcache (ram_s_axi_awcache),
.m_axi_awprot (ram_s_axi_awprot),
.m_axi_awqos (ram_s_axi_awqos),
.m_axi_awregion (ram_s_axi_awregion),
.m_axi_awuser (ram_s_axi_awuser),
.m_axi_awvalid (ram_s_axi_awvalid),
.m_axi_awready (ram_s_axi_awready),
.m_axi_wdata (ram_s_axi_wdata),
.m_axi_wstrb (ram_s_axi_wstrb),
.m_axi_wlast (ram_s_axi_wlast),
.m_axi_wuser (ram_s_axi_wuser),
.m_axi_wvalid (ram_s_axi_wvalid),
.m_axi_wready (ram_s_axi_wready),
.m_axi_bid (ram_s_axi_bid),
.m_axi_bresp (ram_s_axi_bresp),
.m_axi_buser (ram_s_axi_buser),
.m_axi_bvalid (ram_s_axi_bvalid),
.m_axi_bready (ram_s_axi_bready),
.m_axi_arid (ram_s_axi_arid),
.m_axi_araddr (ram_s_axi_araddr),
.m_axi_arlen (ram_s_axi_arlen),
.m_axi_arsize (ram_s_axi_arsize),
.m_axi_arburst (ram_s_axi_arburst),
.m_axi_arlock (ram_s_axi_arlock),
.m_axi_arcache (ram_s_axi_arcache),
.m_axi_arprot (ram_s_axi_arprot),
.m_axi_arqos (ram_s_axi_arqos),
.m_axi_arregion (ram_s_axi_arregion),
.m_axi_aruser (ram_s_axi_aruser),
.m_axi_arvalid (ram_s_axi_arvalid),
.m_axi_arready (ram_s_axi_arready),
.m_axi_rid (ram_s_axi_rid),
.m_axi_rdata (ram_s_axi_rdata),
.m_axi_rresp (ram_s_axi_rresp),
.m_axi_rlast (ram_s_axi_rlast),
.m_axi_ruser (ram_s_axi_ruser),
.m_axi_rvalid (ram_s_axi_rvalid),
.m_axi_rready (ram_s_axi_rready)
);
axi_ram #
(
.DATA_WIDTH (DATA_WIDTH),
.ADDR_WIDTH (ADDR_WIDTH),
.ID_WIDTH (ID_WIDTH),
.PIPELINE_OUTPUT (PIPELINE_OUTPUT)
) i_axi_ram (
.clk (clk),
.rst (rst),
.s_axi_awid (ram_s_axi_awid),
.s_axi_awaddr (ram_s_axi_awaddr),
.s_axi_awlen (ram_s_axi_awlen),
.s_axi_awsize (ram_s_axi_awsize),
.s_axi_awburst (ram_s_axi_awburst),
.s_axi_awlock (ram_s_axi_awlock),
.s_axi_awcache (ram_s_axi_awcache),
.s_axi_awprot (ram_s_axi_awprot),
.s_axi_awvalid (ram_s_axi_awvalid),
.s_axi_awready (ram_s_axi_awready),
.s_axi_wdata (ram_s_axi_wdata),
.s_axi_wstrb (ram_s_axi_wstrb),
.s_axi_wlast (ram_s_axi_wlast),
.s_axi_wvalid (ram_s_axi_wvalid),
.s_axi_wready (ram_s_axi_wready),
.s_axi_bid (ram_s_axi_bid),
.s_axi_bresp (ram_s_axi_bresp),
.s_axi_bvalid (ram_s_axi_bvalid),
.s_axi_bready (ram_s_axi_bready),
.s_axi_arid (ram_s_axi_arid),
.s_axi_araddr (ram_s_axi_araddr),
.s_axi_arlen (ram_s_axi_arlen),
.s_axi_arsize (ram_s_axi_arsize),
.s_axi_arburst (ram_s_axi_arburst),
.s_axi_arlock (ram_s_axi_arlock),
.s_axi_arcache (ram_s_axi_arcache),
.s_axi_arprot (ram_s_axi_arprot),
.s_axi_arvalid (ram_s_axi_arvalid),
.s_axi_arready (ram_s_axi_arready),
.s_axi_rid (ram_s_axi_rid),
.s_axi_rdata (ram_s_axi_rdata),
.s_axi_rresp (ram_s_axi_rresp),
.s_axi_rlast (ram_s_axi_rlast),
.s_axi_rvalid (ram_s_axi_rvalid),
.s_axi_rready (ram_s_axi_rready)
);
endmodule
+165
View File
@@ -0,0 +1,165 @@
module axil_cdc_wrapper #(
parameter int ADDR_WIDTH = 32,
parameter int DATA_WIDTH = 32
)(
input wire s_clk,
input wire s_rst,
axi4l_if.slave s_axi,
input wire m_clk,
input wire m_rst,
axi4l_if.master m_axi
);
localparam int STRB_WIDTH = (DATA_WIDTH/8);
wire [ADDR_WIDTH-1:0] cdc_s_axil_awaddr;
wire [2:0] cdc_s_axil_awprot;
wire cdc_s_axil_awvalid;
wire cdc_s_axil_awready;
wire [DATA_WIDTH-1:0] cdc_s_axil_wdata;
wire [STRB_WIDTH-1:0] cdc_s_axil_wstrb;
wire cdc_s_axil_wvalid;
wire cdc_s_axil_wready;
wire [1:0] cdc_s_axil_bresp;
wire cdc_s_axil_bvalid;
wire cdc_s_axil_bready;
wire [ADDR_WIDTH-1:0] cdc_s_axil_araddr;
wire [2:0] cdc_s_axil_arprot;
wire cdc_s_axil_arvalid;
wire cdc_s_axil_arready;
wire [DATA_WIDTH-1:0] cdc_s_axil_rdata;
wire [1:0] cdc_s_axil_rresp;
wire cdc_s_axil_rvalid;
wire cdc_s_axil_rready;
wire [ADDR_WIDTH-1:0] cdc_m_axil_awaddr;
wire [2:0] cdc_m_axil_awprot;
wire cdc_m_axil_awvalid;
wire cdc_m_axil_awready;
wire [DATA_WIDTH-1:0] cdc_m_axil_wdata;
wire [STRB_WIDTH-1:0] cdc_m_axil_wstrb;
wire cdc_m_axil_wvalid;
wire cdc_m_axil_wready;
wire [1:0] cdc_m_axil_bresp;
wire cdc_m_axil_bvalid;
wire cdc_m_axil_bready;
wire [ADDR_WIDTH-1:0] cdc_m_axil_araddr;
wire [2:0] cdc_m_axil_arprot;
wire cdc_m_axil_arvalid;
wire cdc_m_axil_arready;
wire [DATA_WIDTH-1:0] cdc_m_axil_rdata;
wire [1:0] cdc_m_axil_rresp;
wire cdc_m_axil_rvalid;
wire cdc_m_axil_rready;
axi4l_if_to_flat #(
.ADDR_W (ADDR_WIDTH),
.DATA_W (DATA_WIDTH)
) i_axi4l_if_to_flat (
.s_axil (s_axi),
.m_axil_awaddr (cdc_m_axil_awaddr),
.m_axil_awprot (cdc_m_axil_awprot),
.m_axil_awuser (cdc_m_axil_awuser),
.m_axil_awvalid (cdc_m_axil_awvalid),
.m_axil_awready (cdc_m_axil_awready),
.m_axil_wdata (cdc_m_axil_wdata),
.m_axil_wstrb (cdc_m_axil_wstrb),
.m_axil_wuser (cdc_m_axil_wuser),
.m_axil_wvalid (cdc_m_axil_wvalid),
.m_axil_wready (cdc_m_axil_wready),
.m_axil_bresp (cdc_m_axil_bresp),
.m_axil_buser (cdc_m_axil_buser),
.m_axil_bvalid (cdc_m_axil_bvalid),
.m_axil_bready (cdc_m_axil_bready),
.m_axil_araddr (cdc_m_axil_araddr),
.m_axil_arprot (cdc_m_axil_arprot),
.m_axil_aruser (cdc_m_axil_aruser),
.m_axil_arvalid (cdc_m_axil_arvalid),
.m_axil_arready (cdc_m_axil_arready),
.m_axil_rdata (cdc_m_axil_rdata),
.m_axil_rresp (cdc_m_axil_rresp),
.m_axil_ruser (cdc_m_axil_ruser),
.m_axil_rvalid (cdc_m_axil_rvalid),
.m_axil_rready (cdc_m_axil_rready)
);
axil_cdc #(
.ADDR_WIDTH (ADDR_WIDTH),
.DATA_WIDTH (DATA_WIDTH)
) i_axil_cdc (
.s_clk (s_clk),
.s_rst (s_rst),
.s_axil_awaddr (cdc_m_axil_awaddr),
.s_axil_awprot (cdc_m_axil_awprot),
.s_axil_awvalid (cdc_m_axil_awvalid),
.s_axil_awready (cdc_m_axil_awready),
.s_axil_wdata (cdc_m_axil_wdata),
.s_axil_wstrb (cdc_m_axil_wstrb),
.s_axil_wvalid (cdc_m_axil_wvalid),
.s_axil_wready (cdc_m_axil_wready),
.s_axil_bresp (cdc_m_axil_bresp),
.s_axil_bvalid (cdc_m_axil_bvalid),
.s_axil_bready (cdc_m_axil_bready),
.s_axil_araddr (cdc_m_axil_araddr),
.s_axil_arprot (cdc_m_axil_arprot),
.s_axil_arvalid (cdc_m_axil_arvalid),
.s_axil_arready (cdc_m_axil_arready),
.s_axil_rdata (cdc_m_axil_rdata),
.s_axil_rresp (cdc_m_axil_rresp),
.s_axil_rvalid (cdc_m_axil_rvalid),
.s_axil_rready (cdc_m_axil_rready),
.m_clk (m_clk),
.m_rst (m_rst),
.m_axil_awaddr (cdc_s_axil_awaddr),
.m_axil_awprot (cdc_s_axil_awprot),
.m_axil_awvalid (cdc_s_axil_awvalid),
.m_axil_awready (cdc_s_axil_awready),
.m_axil_wdata (cdc_s_axil_wdata),
.m_axil_wstrb (cdc_s_axil_wstrb),
.m_axil_wvalid (cdc_s_axil_wvalid),
.m_axil_wready (cdc_s_axil_wready),
.m_axil_bresp (cdc_s_axil_bresp),
.m_axil_bvalid (cdc_s_axil_bvalid),
.m_axil_bready (cdc_s_axil_bready),
.m_axil_araddr (cdc_s_axil_araddr),
.m_axil_arprot (cdc_s_axil_arprot),
.m_axil_arvalid (cdc_s_axil_arvalid),
.m_axil_arready (cdc_s_axil_arready),
.m_axil_rdata (cdc_s_axil_rdata),
.m_axil_rresp (cdc_s_axil_rresp),
.m_axil_rvalid (cdc_s_axil_rvalid),
.m_axil_rready (cdc_s_axil_rready)
);
axi4l_flat_to_if #(
.ADDR_W (ADDR_WIDTH),
.DATA_W (DATA_WIDTH)
) i_axi4l_flat_to_if (
.s_axil_awaddr (cdc_s_axil_awaddr),
.s_axil_awprot (cdc_s_axil_awprot),
.s_axil_awuser (cdc_s_axil_awuser),
.s_axil_awvalid (cdc_s_axil_awvalid),
.s_axil_awready (cdc_s_axil_awready),
.s_axil_wdata (cdc_s_axil_wdata),
.s_axil_wstrb (cdc_s_axil_wstrb),
.s_axil_wuser (cdc_s_axil_wuser),
.s_axil_wvalid (cdc_s_axil_wvalid),
.s_axil_wready (cdc_s_axil_wready),
.s_axil_bresp (cdc_s_axil_bresp),
.s_axil_buser (cdc_s_axil_buser),
.s_axil_bvalid (cdc_s_axil_bvalid),
.s_axil_bready (cdc_s_axil_bready),
.s_axil_araddr (cdc_s_axil_araddr),
.s_axil_arprot (cdc_s_axil_arprot),
.s_axil_aruser (cdc_s_axil_aruser),
.s_axil_arvalid (cdc_s_axil_arvalid),
.s_axil_arready (cdc_s_axil_arready),
.s_axil_rdata (cdc_s_axil_rdata),
.s_axil_rresp (cdc_s_axil_rresp),
.s_axil_ruser (cdc_s_axil_ruser),
.s_axil_rvalid (cdc_s_axil_rvalid),
.s_axil_rready (cdc_s_axil_rready),
.m_axil (m_axil)
);
endmodule
+30
View File
@@ -0,0 +1,30 @@
module axis_flat_to_if #(
parameter int unsigned DATA_W = 64,
parameter int unsigned KEEP_W = DATA_W / 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic [DATA_W-1:0] s_axis_tdata,
input logic [KEEP_W-1:0] s_axis_tkeep,
input logic [KEEP_W-1:0] s_axis_tstrb,
input logic s_axis_tlast,
input logic [ID_W-1:0] s_axis_tid,
input logic [DEST_W-1:0] s_axis_tdest,
input logic [USER_W-1:0] s_axis_tuser,
input logic s_axis_tvalid,
output logic s_axis_tready,
axis_if.master m_axis
);
assign m_axis.req.t.data = s_axis_tdata;
assign m_axis.req.t.keep = s_axis_tkeep;
assign m_axis.req.t.strb = s_axis_tstrb;
assign m_axis.req.t.last = s_axis_tlast;
assign m_axis.req.t.id = s_axis_tid;
assign m_axis.req.t.dest = s_axis_tdest;
assign m_axis.req.t.user = s_axis_tuser;
assign m_axis.req.t.valid = s_axis_tvalid;
assign s_axis_tready = m_axis.resp.ready;
endmodule : axis_flat_to_if
+47
View File
@@ -0,0 +1,47 @@
`define AXIS_TYPEDEF_ALL(__name, __data_t, __keep_t, __strb_t, __id_t, __dest_t, __user_t) \
typedef struct packed { \
__data_t data; \
__keep_t keep; \
__strb_t strb; \
logic last; \
__id_t id; \
__dest_t dest; \
__user_t user; \
logic valid; \
} __name``_chan_t; \
typedef struct packed { \
__name``_chan_t t; \
} __name``_req_t; \
typedef struct packed { \
logic ready; \
} __name``_resp_t;
interface axis_if #(
parameter int unsigned DATA_W = 64,
parameter int unsigned KEEP_W = DATA_W / 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
input logic aclk,
input logic aresetn
);
typedef logic [DATA_W-1:0] data_t;
typedef logic [KEEP_W-1:0] keep_t;
typedef logic [KEEP_W-1:0] strb_t;
typedef logic [ID_W-1:0] id_t;
typedef logic [DEST_W-1:0] dest_t;
typedef logic [USER_W-1:0] user_t;
`AXIS_TYPEDEF_ALL(axis, data_t, keep_t, strb_t, id_t, dest_t, user_t)
axis_req_t req;
axis_resp_t resp;
modport master (input aclk, aresetn, output req, input resp);
modport slave (input aclk, aresetn, input req, output resp);
modport monitor (input aclk, aresetn, input req, input resp);
endinterface : axis_if
+30
View File
@@ -0,0 +1,30 @@
module axis_if_to_flat #(
parameter int unsigned DATA_W = 64,
parameter int unsigned KEEP_W = DATA_W / 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
axis_if.slave s_axis,
output logic [DATA_W-1:0] m_axis_tdata,
output logic [KEEP_W-1:0] m_axis_tkeep,
output logic [KEEP_W-1:0] m_axis_tstrb,
output logic m_axis_tlast,
output logic [ID_W-1:0] m_axis_tid,
output logic [DEST_W-1:0] m_axis_tdest,
output logic [USER_W-1:0] m_axis_tuser,
output logic m_axis_tvalid,
input logic m_axis_tready
);
assign m_axis_tdata = s_axis.req.t.data;
assign m_axis_tkeep = s_axis.req.t.keep;
assign m_axis_tstrb = s_axis.req.t.strb;
assign m_axis_tlast = s_axis.req.t.last;
assign m_axis_tid = s_axis.req.t.id;
assign m_axis_tdest = s_axis.req.t.dest;
assign m_axis_tuser = s_axis.req.t.user;
assign m_axis_tvalid = s_axis.req.t.valid;
assign s_axis.resp.ready = m_axis_tready;
endmodule : axis_if_to_flat
@@ -0,0 +1,84 @@
# Simple cocotb makefile for tb_axi_dma_axis_compat
TOPLEVEL_LANG = verilog
SIM ?= verilator
PWD := $(shell pwd)
PROJECT_ROOT ?= $(abspath $(PWD)/../../..)
AXI_IF_RTL_DIR ?= $(PROJECT_ROOT)/axi/rtl
FORENCICH_AXI_RTL_DIR ?= $(PROJECT_ROOT)/external/verilog-axi/rtl
TB_DIR ?= $(PWD)
TOPLEVEL = tb_axi_dma_axis_compat
MODULE = test_axi_dma_axis_compat
export PYTHONPATH := $(TB_DIR):$(PYTHONPATH)
AXI_DATA_WIDTH ?= 32
AXI_ADDR_WIDTH ?= 16
AXI_ID_WIDTH ?= 8
AXI_USER_WIDTH ?= 1
AXI_MAX_BURST_LEN ?= 16
ENABLE_UNALIGNED ?= 0
AXI_STRB_WIDTH := $(shell expr $(AXI_DATA_WIDTH) / 8)
AXIS_DATA_WIDTH ?= $(AXI_DATA_WIDTH)
AXIS_KEEP_WIDTH := $(shell expr $(AXIS_DATA_WIDTH) / 8)
AXIS_KEEP_ENABLE := $(shell [ $(AXIS_DATA_WIDTH) -gt 8 ] && echo 1 || echo 0)
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_pkg.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi4_flat_to_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi4_if_to_flat.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_flat_to_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_if_to_flat.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_dma_desc_if.sv
VERILOG_SOURCES += $(FORENCICH_AXI_RTL_DIR)/axi_dma.v
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_wrapper.sv
VERILOG_SOURCES += $(TB_DIR)/tb_axi_dma_axis_compat.sv
COMPILE_ARGS += -I$(AXI_IF_RTL_DIR)
COMPILE_ARGS += -I$(FORENCICH_AXI_RTL_DIR)
# took this from forencich to silence 100+ warnings
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH -Wno-CASEINCOMPLETE
ifeq ($(SIM),verilator)
EXTRA_ARGS += --trace
EXTRA_ARGS += --trace-structs
EXTRA_ARGS += -GAXI_DATA_WIDTH=$(AXI_DATA_WIDTH)
EXTRA_ARGS += -GAXI_ADDR_WIDTH=$(AXI_ADDR_WIDTH)
EXTRA_ARGS += -GAXI_STRB_WIDTH=$(AXI_STRB_WIDTH)
EXTRA_ARGS += -GAXI_ID_WIDTH=$(AXI_ID_WIDTH)
EXTRA_ARGS += -GAXI_USER_WIDTH=$(AXI_USER_WIDTH)
EXTRA_ARGS += -GAXI_MAX_BURST_LEN=$(AXI_MAX_BURST_LEN)
EXTRA_ARGS += -GAXIS_DATA_WIDTH=$(AXIS_DATA_WIDTH)
EXTRA_ARGS += -GAXIS_KEEP_ENABLE=$(AXIS_KEEP_ENABLE)
EXTRA_ARGS += -GAXIS_KEEP_WIDTH=$(AXIS_KEEP_WIDTH)
EXTRA_ARGS += -GAXIS_LAST_ENABLE=1
EXTRA_ARGS += -GAXIS_ID_ENABLE=1
EXTRA_ARGS += -GAXIS_ID_WIDTH=8
EXTRA_ARGS += -GAXIS_DEST_ENABLE=0
EXTRA_ARGS += -GAXIS_DEST_WIDTH=8
EXTRA_ARGS += -GAXIS_USER_ENABLE=1
EXTRA_ARGS += -GAXIS_USER_WIDTH=1
EXTRA_ARGS += -GLEN_WIDTH=20
EXTRA_ARGS += -GTAG_WIDTH=8
EXTRA_ARGS += -GENABLE_SG=0
EXTRA_ARGS += -GENABLE_UNALIGNED=$(ENABLE_UNALIGNED)
endif
export PARAM_AXI_DATA_WIDTH=$(AXI_DATA_WIDTH)
export PARAM_ENABLE_UNALIGNED=$(ENABLE_UNALIGNED)
include $(shell cocotb-config --makefiles)/Makefile.sim
@@ -0,0 +1,431 @@
// another wrapper...
`default_nettype none
module tb_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,
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,
input logic read_enable,
input logic write_enable,
input logic write_abort,
// 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,
// 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,
output logic [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
output logic [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tstrb,
output logic m_axis_read_data_tlast,
output logic [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
output logic [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
output logic [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
output logic m_axis_read_data_tvalid,
input logic m_axis_read_data_tready,
// Write data AXIS input
input logic [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata,
input logic [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep,
input logic [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tstrb,
input logic s_axis_write_data_tlast,
input logic [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid,
input logic [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest,
input logic [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser,
input logic s_axis_write_data_tvalid,
output logic s_axis_write_data_tready,
// AXI memory master, flat for cocotb AxiRam
output logic [AXI_ID_WIDTH-1:0] m_axi_awid,
output logic [AXI_ADDR_WIDTH-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 [AXI_USER_WIDTH-1:0] m_axi_awuser,
output logic m_axi_awvalid,
input logic m_axi_awready,
output logic [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output logic [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output logic m_axi_wlast,
output logic [AXI_USER_WIDTH-1:0] m_axi_wuser,
output logic m_axi_wvalid,
input logic m_axi_wready,
input logic [AXI_ID_WIDTH-1:0] m_axi_bid,
input logic [1:0] m_axi_bresp,
input logic [AXI_USER_WIDTH-1:0] m_axi_buser,
input logic m_axi_bvalid,
output logic m_axi_bready,
output logic [AXI_ID_WIDTH-1:0] m_axi_arid,
output logic [AXI_ADDR_WIDTH-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 [AXI_USER_WIDTH-1:0] m_axi_aruser,
output logic m_axi_arvalid,
input logic m_axi_arready,
input logic [AXI_ID_WIDTH-1:0] m_axi_rid,
input logic [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input logic [1:0] m_axi_rresp,
input logic m_axi_rlast,
input logic [AXI_USER_WIDTH-1:0] m_axi_ruser,
input logic m_axi_rvalid,
output logic m_axi_rready
);
wire rstn = ~rst;
axis_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 (READ_STATUS_DATA_WIDTH),
.KEEP_W (READ_STATUS_DATA_WIDTH / 8),
.ID_W (1),
.DEST_W (1),
.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)
);
axis_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)
) read_data_if (
.aclk (clk),
.aresetn (rstn)
);
axis_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)
) write_data_if (
.aclk (clk),
.aresetn (rstn)
);
axi4_if #(
.ADDR_W (AXI_ADDR_WIDTH),
.DATA_W (AXI_DATA_WIDTH),
.ID_W (AXI_ID_WIDTH),
.USER_W (AXI_USER_WIDTH)
) m_axi_if (
.aclk (clk),
.aresetn (rstn)
);
axis_flat_to_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 (READ_STATUS_DATA_WIDTH),
.KEEP_W (READ_STATUS_DATA_WIDTH / 8),
.ID_W (1),
.DEST_W (1),
.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 #(
.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_read_data_if_to_flat (
.s_axis (read_data_if),
.m_axis_tdata (m_axis_read_data_tdata),
.m_axis_tkeep (m_axis_read_data_tkeep),
.m_axis_tstrb (m_axis_read_data_tstrb),
.m_axis_tlast (m_axis_read_data_tlast),
.m_axis_tid (m_axis_read_data_tid),
.m_axis_tdest (m_axis_read_data_tdest),
.m_axis_tuser (m_axis_read_data_tuser),
.m_axis_tvalid (m_axis_read_data_tvalid),
.m_axis_tready (m_axis_read_data_tready)
);
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_write_data_flat_to_if (
.s_axis_tdata (s_axis_write_data_tdata),
.s_axis_tkeep (s_axis_write_data_tkeep),
.s_axis_tstrb (s_axis_write_data_tstrb),
.s_axis_tlast (s_axis_write_data_tlast),
.s_axis_tid (s_axis_write_data_tid),
.s_axis_tdest (s_axis_write_data_tdest),
.s_axis_tuser (s_axis_write_data_tuser),
.s_axis_tvalid (s_axis_write_data_tvalid),
.s_axis_tready (s_axis_write_data_tready),
.m_axis (write_data_if)
);
axi_dma_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_dut (
.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 #(
.ADDR_W (AXI_ADDR_WIDTH),
.DATA_W (AXI_DATA_WIDTH),
.ID_W (AXI_ID_WIDTH),
.USER_W (AXI_USER_WIDTH)
) u_m_axi_if_to_flat (
.s_axi (m_axi_if),
.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 : tb_axi_dma_axis_compat
`default_nettype wire
@@ -0,0 +1,317 @@
import logging
import os
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotbext.axi import AxiBus, AxiRam
from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink
AXI_ADDR_WIDTH = int(os.getenv("PARAM_AXI_ADDR_WIDTH", "16"))
LEN_WIDTH = int(os.getenv("PARAM_LEN_WIDTH", "20"))
TAG_WIDTH = int(os.getenv("PARAM_TAG_WIDTH", "8"))
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_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
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
READ_STATUS_RAW_WIDTH = TAG_WIDTH + 4
READ_STATUS_DATA_WIDTH = ((READ_STATUS_RAW_WIDTH + 7) // 8) * 8
WRITE_STATUS_RAW_WIDTH = LEN_WIDTH + TAG_WIDTH + 4
WRITE_STATUS_DATA_WIDTH = ((WRITE_STATUS_RAW_WIDTH + 7) // 8) * 8
# 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
# 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):
return (1 << width) - 1
def put(value, lsb, width, field):
value &= ~(mask(width) << lsb)
value |= (int(field) & mask(width)) << lsb
return value
def get(value, lsb, width):
return (int(value) >> lsb) & mask(width)
def pack_read_desc(*, addr, length, tag, axis_id=0, dest=0, user=0):
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(READ_DESC_BYTES, byteorder="little"),
tid=axis_id,
tdest=dest,
tuser=user,
)
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_sideband(frame, name):
value = getattr(frame, name)
try:
return int(value)
except TypeError:
return int(value[0]) if value else 0
def unpack_read_status(frame):
value = frame_to_int(frame)
return {
"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"),
}
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
self.read_desc_source = AxiStreamSource(
AxiStreamBus.from_prefix(dut, "s_axis_read_desc"),
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,
)
self.write_data_source = AxiStreamSource(
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**AXI_ADDR_WIDTH,
)
dut.read_enable.setimmediatevalue(0)
dut.write_enable.setimmediatevalue(0)
dut.write_abort.setimmediatevalue(0)
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)
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()
async def test_axis_compat_write_path(dut):
tb = TB(dut)
await tb.reset()
dut.write_enable.value = 1
dut.read_enable.value = 0
addr = 0x1000
tag = 0x12
data = bytes(range(1, 33))
tb.axi_ram.write(addr - 16, b"\xaa" * (len(data) + 32))
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 desc_task
await data_task
status = unpack_write_status(await tb.write_desc_status_sink.recv())
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
)
@cocotb.test()
async def test_axis_compat_read_path(dut):
tb = TB(dut)
await tb.reset()
dut.write_enable.value = 0
dut.read_enable.value = 1
addr = 0x1100
tag = 0x34
data = bytes((x * 3) % 256 for x in range(48))
tb.axi_ram.write(addr, data)
await tb.send_read_desc(
addr=addr,
length=len(data),
tag=tag,
axis_id=tag,
dest=0,
user=0,
)
data_frame = await tb.read_data_sink.recv()
assert bytes(data_frame.tdata) == data
assert frame_sideband(data_frame, "tid") == tag
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_independent_desc_ports(dut):
tb = TB(dut)
await tb.reset()
dut.write_enable.value = 1
dut.read_enable.value = 1
read_addr = 0x1200
write_addr = 0x1300
read_tag = 0x41
write_tag = 0x42
read_data = bytes((x + 7) % 256 for x in range(24))
write_data = bytes((x + 100) % 256 for x in range(24))
tb.axi_ram.write(read_addr, read_data)
tb.axi_ram.write(write_addr - 8, b"\xaa" * (len(write_data) + 16))
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,
)
)
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 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 frame_sideband(data_frame, "tid") == read_tag
read_status = unpack_read_status(await tb.read_desc_status_sink.recv())
write_status = unpack_write_status(await tb.write_desc_status_sink.recv())
assert read_status["tag"] == read_tag
assert read_status["error"] == 0
assert write_status["tag"] == write_tag
assert write_status["len"] == len(write_data)
assert write_status["id"] == write_tag
assert write_status["error"] == 0
assert tb.axi_ram.read(write_addr - 8, len(write_data) + 16) == (
b"\xaa" * 8 + write_data + b"\xaa" * 8
)
@@ -0,0 +1,84 @@
TOPLEVEL_LANG = verilog
SIM ?= verilator
PWD := $(shell pwd)
PROJECT_ROOT ?= $(abspath $(PWD)/../../..)
AXI_IF_RTL_DIR ?= $(PROJECT_ROOT)/axi/rtl
FORENCICH_AXI_RTL_DIR ?= $(PROJECT_ROOT)/external/verilog-axi/rtl
TB_DIR ?= $(PWD)
TOPLEVEL = tb_axi_dma_wrapper
MODULE = test_axi_dma_wrapper
export PYTHONPATH := $(TB_DIR):$(PYTHONPATH)
# Parameters for a quick make-based run. The pytest entrypoint can be used for
# wider parameter sweeps.
AXI_DATA_WIDTH ?= 32
AXI_ADDR_WIDTH ?= 16
AXI_ID_WIDTH ?= 8
AXI_USER_WIDTH ?= 1
AXI_MAX_BURST_LEN ?= 16
ENABLE_UNALIGNED ?= 0
AXI_STRB_WIDTH := $(shell expr $(AXI_DATA_WIDTH) / 8)
AXIS_DATA_WIDTH ?= $(AXI_DATA_WIDTH)
AXIS_KEEP_WIDTH := $(shell expr $(AXIS_DATA_WIDTH) / 8)
AXIS_KEEP_ENABLE := $(shell [ $(AXIS_DATA_WIDTH) -gt 8 ] && echo 1 || echo 0)
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_pkg.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi4_flat_to_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi4_if_to_flat.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_flat_to_if.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axis_if_to_flat.sv
VERILOG_SOURCES += $(AXI_IF_RTL_DIR)/axi_dma_desc_if.sv
VERILOG_SOURCES += $(FORENCICH_AXI_RTL_DIR)/axi_dma.v
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 += $(TB_DIR)/tb_axi_dma_wrapper.sv
COMPILE_ARGS += -I$(AXI_IF_RTL_DIR)
COMPILE_ARGS += -I$(WRAPPER_RTL_DIR)
COMPILE_ARGS += -I$(FORENCICH_AXI_RTL_DIR)
# took this from forencich to silence 100+ warnings
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH -Wno-CASEINCOMPLETE
ifeq ($(SIM),verilator)
EXTRA_ARGS += --trace
EXTRA_ARGS += --trace-structs
EXTRA_ARGS += -GAXI_DATA_WIDTH=$(AXI_DATA_WIDTH)
EXTRA_ARGS += -GAXI_ADDR_WIDTH=$(AXI_ADDR_WIDTH)
EXTRA_ARGS += -GAXI_STRB_WIDTH=$(AXI_STRB_WIDTH)
EXTRA_ARGS += -GAXI_ID_WIDTH=$(AXI_ID_WIDTH)
EXTRA_ARGS += -GAXI_USER_WIDTH=$(AXI_USER_WIDTH)
EXTRA_ARGS += -GAXI_MAX_BURST_LEN=$(AXI_MAX_BURST_LEN)
EXTRA_ARGS += -GAXIS_DATA_WIDTH=$(AXIS_DATA_WIDTH)
EXTRA_ARGS += -GAXIS_KEEP_ENABLE=$(AXIS_KEEP_ENABLE)
EXTRA_ARGS += -GAXIS_KEEP_WIDTH=$(AXIS_KEEP_WIDTH)
EXTRA_ARGS += -GAXIS_LAST_ENABLE=1
EXTRA_ARGS += -GAXIS_ID_ENABLE=1
EXTRA_ARGS += -GAXIS_ID_WIDTH=8
EXTRA_ARGS += -GAXIS_DEST_ENABLE=0
EXTRA_ARGS += -GAXIS_DEST_WIDTH=8
EXTRA_ARGS += -GAXIS_USER_ENABLE=1
EXTRA_ARGS += -GAXIS_USER_WIDTH=1
EXTRA_ARGS += -GLEN_WIDTH=20
EXTRA_ARGS += -GTAG_WIDTH=8
EXTRA_ARGS += -GENABLE_SG=0
EXTRA_ARGS += -GENABLE_UNALIGNED=$(ENABLE_UNALIGNED)
endif
export PARAM_AXI_DATA_WIDTH=$(AXI_DATA_WIDTH)
export PARAM_ENABLE_UNALIGNED=$(ENABLE_UNALIGNED)
include $(shell cocotb-config --makefiles)/Makefile.sim
@@ -0,0 +1,429 @@
// Cocotb still sees flat Forencich-style signal names
// this top converts those flat signals to local interfaces
`default_nettype none
module tb_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
)();
// cocotb drives these directly
logic clk;
logic rst;
logic rstn;
assign rstn = ~rst;
// --------------------------------------------------------------------------
// Flat descriptor/status ports visible to cocotb
// --------------------------------------------------------------------------
logic [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_addr;
logic [LEN_WIDTH-1:0] s_axis_read_desc_len;
logic [TAG_WIDTH-1:0] s_axis_read_desc_tag;
logic [AXIS_ID_WIDTH-1:0] s_axis_read_desc_id;
logic [AXIS_DEST_WIDTH-1:0] s_axis_read_desc_dest;
logic [AXIS_USER_WIDTH-1:0] s_axis_read_desc_user;
logic s_axis_read_desc_valid;
logic s_axis_read_desc_ready;
logic [TAG_WIDTH-1:0] m_axis_read_desc_status_tag;
logic [3:0] m_axis_read_desc_status_error;
logic m_axis_read_desc_status_valid;
logic [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_addr;
logic [LEN_WIDTH-1:0] s_axis_write_desc_len;
logic [TAG_WIDTH-1:0] s_axis_write_desc_tag;
logic s_axis_write_desc_valid;
logic s_axis_write_desc_ready;
logic [LEN_WIDTH-1:0] m_axis_write_desc_status_len;
logic [TAG_WIDTH-1:0] m_axis_write_desc_status_tag;
logic [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id;
logic [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest;
logic [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user;
logic [3:0] m_axis_write_desc_status_error;
logic m_axis_write_desc_status_valid;
// --------------------------------------------------------------------------
// Flat AXIS data ports visible to cocotb
// --------------------------------------------------------------------------
logic [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata;
logic [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep;
logic [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tstrb;
logic m_axis_read_data_tvalid;
logic m_axis_read_data_tready;
logic m_axis_read_data_tlast;
logic [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid;
logic [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest;
logic [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser;
logic [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata;
logic [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep;
logic [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tstrb;
logic s_axis_write_data_tvalid;
logic s_axis_write_data_tready;
logic s_axis_write_data_tlast;
logic [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid;
logic [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest;
logic [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser;
// --------------------------------------------------------------------------
// Flat AXI memory master ports visible to cocotb AxiRam
// --------------------------------------------------------------------------
logic [AXI_ID_WIDTH-1:0] m_axi_awid;
logic [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
logic [7:0] m_axi_awlen;
logic [2:0] m_axi_awsize;
logic [1:0] m_axi_awburst;
logic m_axi_awlock;
logic [3:0] m_axi_awcache;
logic [2:0] m_axi_awprot;
logic [3:0] m_axi_awqos;
logic [3:0] m_axi_awregion;
logic [AXI_USER_WIDTH-1:0] m_axi_awuser;
logic m_axi_awvalid;
logic m_axi_awready;
logic [AXI_DATA_WIDTH-1:0] m_axi_wdata;
logic [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
logic m_axi_wlast;
logic [AXI_USER_WIDTH-1:0] m_axi_wuser;
logic m_axi_wvalid;
logic m_axi_wready;
logic [AXI_ID_WIDTH-1:0] m_axi_bid;
logic [1:0] m_axi_bresp;
logic [AXI_USER_WIDTH-1:0] m_axi_buser;
logic m_axi_bvalid;
logic m_axi_bready;
logic [AXI_ID_WIDTH-1:0] m_axi_arid;
logic [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
logic [7:0] m_axi_arlen;
logic [2:0] m_axi_arsize;
logic [1:0] m_axi_arburst;
logic m_axi_arlock;
logic [3:0] m_axi_arcache;
logic [2:0] m_axi_arprot;
logic [3:0] m_axi_arqos;
logic [3:0] m_axi_arregion;
logic [AXI_USER_WIDTH-1:0] m_axi_aruser;
logic m_axi_arvalid;
logic m_axi_arready;
logic [AXI_ID_WIDTH-1:0] m_axi_rid;
logic [AXI_DATA_WIDTH-1:0] m_axi_rdata;
logic [1:0] m_axi_rresp;
logic m_axi_rlast;
logic [AXI_USER_WIDTH-1:0] m_axi_ruser;
logic m_axi_rvalid;
logic m_axi_rready;
// Configuration visible to cocotb
logic read_enable;
logic write_enable;
logic write_abort;
// --------------------------------------------------------------------------
// Local interface instances
// --------------------------------------------------------------------------
axis_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)
) m_axis_read_data_if (
.aclk (clk),
.aresetn (rstn)
);
axis_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)
) s_axis_write_data_if (
.aclk (clk),
.aresetn (rstn)
);
axi4_if #(
.ADDR_W (AXI_ADDR_WIDTH),
.DATA_W (AXI_DATA_WIDTH),
.ID_W (AXI_ID_WIDTH),
.USER_W (AXI_USER_WIDTH)
) m_axi_if (
.aclk (clk),
.aresetn (rstn)
);
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)
) s_axis_read_desc_if (
.aclk (clk),
.aresetn (rstn)
);
axi_dma_read_desc_status_if #(
.TAG_W (TAG_WIDTH)
) m_axis_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)
) s_axis_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)
) m_axis_write_desc_status_if (
.aclk (clk),
.aresetn (rstn)
);
// cocotb flat read descriptor -> interface
axi_dma_read_desc_flat_to_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)
) u_s_axis_read_desc_flat_to_if (
.s_axis_read_desc_addr (s_axis_read_desc_addr),
.s_axis_read_desc_len (s_axis_read_desc_len),
.s_axis_read_desc_tag (s_axis_read_desc_tag),
.s_axis_read_desc_id (s_axis_read_desc_id),
.s_axis_read_desc_dest (s_axis_read_desc_dest),
.s_axis_read_desc_user (s_axis_read_desc_user),
.s_axis_read_desc_valid (s_axis_read_desc_valid),
.s_axis_read_desc_ready (s_axis_read_desc_ready),
.m_axis_read_desc (s_axis_read_desc_if)
);
// wrapper read descriptor status interface -> cocotb flat status
axi_dma_read_desc_status_if_to_flat #(
.TAG_W (TAG_WIDTH)
) u_m_axis_read_desc_status_if_to_flat (
.s_axis_read_desc_status (m_axis_read_desc_status_if),
.m_axis_read_desc_status_tag (m_axis_read_desc_status_tag),
.m_axis_read_desc_status_error (m_axis_read_desc_status_error),
.m_axis_read_desc_status_valid (m_axis_read_desc_status_valid)
);
// cocotb flat write descriptor -> interface
axi_dma_write_desc_flat_to_if #(
.ADDR_W (AXI_ADDR_WIDTH),
.LEN_W (LEN_WIDTH),
.TAG_W (TAG_WIDTH)
) u_s_axis_write_desc_flat_to_if (
.s_axis_write_desc_addr (s_axis_write_desc_addr),
.s_axis_write_desc_len (s_axis_write_desc_len),
.s_axis_write_desc_tag (s_axis_write_desc_tag),
.s_axis_write_desc_valid (s_axis_write_desc_valid),
.s_axis_write_desc_ready (s_axis_write_desc_ready),
.m_axis_write_desc (s_axis_write_desc_if)
);
// wrapper write descriptor status interface -> cocotb flat status
axi_dma_write_desc_status_if_to_flat #(
.LEN_W (LEN_WIDTH),
.TAG_W (TAG_WIDTH),
.ID_W (AXIS_ID_WIDTH),
.DEST_W (AXIS_DEST_WIDTH),
.USER_W (AXIS_USER_WIDTH)
) u_m_axis_write_desc_status_if_to_flat (
.s_axis_write_desc_status (m_axis_write_desc_status_if),
.m_axis_write_desc_status_len (m_axis_write_desc_status_len),
.m_axis_write_desc_status_tag (m_axis_write_desc_status_tag),
.m_axis_write_desc_status_id (m_axis_write_desc_status_id),
.m_axis_write_desc_status_dest (m_axis_write_desc_status_dest),
.m_axis_write_desc_status_user (m_axis_write_desc_status_user),
.m_axis_write_desc_status_error (m_axis_write_desc_status_error),
.m_axis_write_desc_status_valid (m_axis_write_desc_status_valid)
);
// cocotb flat write stream -> interface
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_s_axis_write_data_flat_to_if (
.s_axis_tdata (s_axis_write_data_tdata),
.s_axis_tkeep (s_axis_write_data_tkeep),
.s_axis_tstrb (s_axis_write_data_tstrb),
.s_axis_tlast (s_axis_write_data_tlast),
.s_axis_tid (s_axis_write_data_tid),
.s_axis_tdest (s_axis_write_data_tdest),
.s_axis_tuser (s_axis_write_data_tuser),
.s_axis_tvalid (s_axis_write_data_tvalid),
.s_axis_tready (s_axis_write_data_tready),
.m_axis (s_axis_write_data_if)
);
// wrapper read stream interface -> cocotb flat stream
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_m_axis_read_data_if_to_flat (
.s_axis (m_axis_read_data_if),
.m_axis_tdata (m_axis_read_data_tdata),
.m_axis_tkeep (m_axis_read_data_tkeep),
.m_axis_tstrb (m_axis_read_data_tstrb),
.m_axis_tlast (m_axis_read_data_tlast),
.m_axis_tid (m_axis_read_data_tid),
.m_axis_tdest (m_axis_read_data_tdest),
.m_axis_tuser (m_axis_read_data_tuser),
.m_axis_tvalid (m_axis_read_data_tvalid),
.m_axis_tready (m_axis_read_data_tready)
);
// wrapper AXI interface -> cocotb flat AXI memory bus
axi4_if_to_flat #(
.ADDR_W (AXI_ADDR_WIDTH),
.DATA_W (AXI_DATA_WIDTH),
.ID_W (AXI_ID_WIDTH),
.USER_W (AXI_USER_WIDTH)
) u_m_axi_if_to_flat (
.s_axi (m_axi_if),
.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)
);
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_dut (
.clk (clk),
.rst (rst),
.s_axis_read_desc (s_axis_read_desc_if),
.m_axis_read_desc_status (m_axis_read_desc_status_if),
.m_axis_read_data (m_axis_read_data_if),
.s_axis_write_desc (s_axis_write_desc_if),
.m_axis_write_desc_status (m_axis_write_desc_status_if),
.s_axis_write_data (s_axis_write_data_if),
.m_axi (m_axi_if),
.read_enable (read_enable),
.write_enable (write_enable),
.write_abort (write_abort)
);
endmodule : tb_axi_dma_wrapper
`default_nettype wire
@@ -0,0 +1,392 @@
# SPDX-License-Identifier: MIT
"""
Adapted cocotb/pytest tests for tb_axi_dma_wrapper.
This file is based on alexforencich/verilog-axi/tb/axi_dma/test_axi_dma.py
and keeps the same cocotb-facing flat prefixes. The SystemVerilog test top
routes these flat signals through local axi4_if/axis_if converters and then
through axi_dma_if_wrapper.
Original copyright:
Copyright (c) 2020 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import itertools
import logging
import os
import cocotb
try:
import pytest
except ImportError: # pytest is only needed for the optional cocotb-test entrypoint
pytest = None
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.regression import TestFactory
from cocotbext.axi import AxiBus, AxiRam
from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink
from cocotbext.axi.stream import define_stream
DescBus, DescTransaction, DescSource, DescSink, DescMonitor = define_stream(
"Desc",
signals=["addr", "len", "tag", "valid", "ready"],
optional_signals=["id", "dest", "user"],
)
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream(
"DescStatus",
signals=["tag", "error", "valid"],
optional_signals=["len", "id", "dest", "user"],
)
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
# Descriptor/status streams remain flat on purpose: they are specific
# to Forencich DMA, not generic AXIS interfaces in our library.
self.read_desc_source = DescSource(
DescBus.from_prefix(dut, "s_axis_read_desc"), dut.clk, dut.rst
)
self.read_desc_status_sink = DescStatusSink(
DescStatusBus.from_prefix(
dut, "m_axis_read_desc_status"), dut.clk, dut.rst
)
self.write_desc_source = DescSource(
DescBus.from_prefix(dut, "s_axis_write_desc"), dut.clk, dut.rst
)
self.write_desc_status_sink = DescStatusSink(
DescStatusBus.from_prefix(
dut, "m_axis_write_desc_status"), dut.clk, dut.rst
)
# Data streams are flat from cocotb's point of view, but the SV top
# sends them through axis_flat_to_if/axis_if_to_flat before/after DUT.
self.read_data_sink = AxiStreamSink(
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
)
# AXI memory model. The SV top routes this through the axi4_if adapters.
self.axi_ram = AxiRam(AxiBus.from_prefix(
dut, "m_axi"), dut.clk, dut.rst, size=2**16)
dut.read_enable.setimmediatevalue(0)
dut.write_enable.setimmediatevalue(0)
dut.write_abort.setimmediatevalue(0)
def set_idle_generator(self, generator=None):
if generator:
self.write_desc_source.set_pause_generator(generator())
self.write_data_source.set_pause_generator(generator())
self.read_desc_source.set_pause_generator(generator())
self.axi_ram.write_if.b_channel.set_pause_generator(generator())
self.axi_ram.read_if.r_channel.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
self.read_data_sink.set_pause_generator(generator())
self.axi_ram.write_if.aw_channel.set_pause_generator(generator())
self.axi_ram.write_if.w_channel.set_pause_generator(generator())
self.axi_ram.read_if.ar_channel.set_pause_generator(generator())
async def cycle_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)
async def run_test_write(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
"""DMA write path stress test adapted from Forencich's axi_dma test."""
tb = TB(dut)
byte_lanes = tb.axi_ram.write_if.byte_lanes
step_size = 1 if int(
os.getenv("PARAM_ENABLE_UNALIGNED", "0")) else byte_lanes
tag_count = 2 ** len(tb.write_desc_source.bus.tag)
cur_tag = 1
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
dut.write_enable.value = 1
for length in list(range(1, byte_lanes * 4 + 1)) + [128]:
offsets = list(range(0, byte_lanes * 2, step_size))
offsets += list(range(4096 - byte_lanes * 2, 4096, step_size))
for offset in offsets:
for diff in [-8, -2, -1, 0, 1, 2, 8]:
if length + diff < 1:
continue
tb.log.info("write: length=%d offset=%d diff=%d",
length, offset, diff)
addr = offset + 0x1000
expected_data = bytearray([x % 256 for x in range(length)])
stream_data = bytearray(
[x % 256 for x in range(length + diff)])
tb.axi_ram.write(addr - 128, b"\xaa" *
(len(expected_data) + 256))
await tb.write_desc_source.send(
DescTransaction(addr=addr, len=len(
expected_data), tag=cur_tag)
)
await tb.write_data_source.send(AxiStreamFrame(stream_data, tid=cur_tag))
status = await tb.write_desc_status_sink.recv()
tb.log.info("write status: %s", status)
transferred_len = min(len(expected_data), len(stream_data))
assert int(status.len) == transferred_len
assert int(status.tag) == cur_tag
assert int(status.id) == cur_tag
assert int(status.error) == 0
tb.log.debug(
"%s",
tb.axi_ram.hexdump_str(
(addr & ~0xF) - 16,
(((addr & 0xF) + length - 1) & ~0xF) + 48,
),
)
if len(expected_data) <= len(stream_data):
assert tb.axi_ram.read(addr - 8, len(expected_data) + 16) == (
b"\xaa" * 8 + expected_data + b"\xaa" * 8
)
else:
assert tb.axi_ram.read(addr - 8, len(stream_data) + 16) == (
b"\xaa" * 8 + stream_data + b"\xaa" * 8
)
cur_tag = (cur_tag + 1) % tag_count
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_read(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
"""DMA read path stress test adapted from Forencich's axi_dma test."""
tb = TB(dut)
byte_lanes = tb.axi_ram.read_if.byte_lanes
step_size = 1 if int(
os.getenv("PARAM_ENABLE_UNALIGNED", "0")) else byte_lanes
tag_count = 2 ** len(tb.read_desc_source.bus.tag)
cur_tag = 1
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
dut.read_enable.value = 1
for length in list(range(1, byte_lanes * 4 + 1)) + [128]:
offsets = list(range(0, byte_lanes * 2, step_size))
offsets += list(range(4096 - byte_lanes * 2, 4096, step_size))
for offset in offsets:
tb.log.info("read: length=%d offset=%d", length, offset)
addr = offset + 0x1000
test_data = bytearray([x % 256 for x in range(length)])
tb.axi_ram.write(addr - 128, b"\xaa" * (len(test_data) + 256))
tb.axi_ram.write(addr, test_data)
tb.log.debug(
"%s",
tb.axi_ram.hexdump_str(
(addr & ~0xF) - 16,
(((addr & 0xF) + length - 1) & ~0xF) + 48,
),
)
await tb.read_desc_source.send(
DescTransaction(addr=addr, len=len(
test_data), tag=cur_tag, id=cur_tag)
)
status = await tb.read_desc_status_sink.recv()
read_data = await tb.read_data_sink.recv()
tb.log.info("read status: %s", status)
tb.log.info("read data: %s", read_data)
assert int(status.tag) == cur_tag
assert int(status.error) == 0
assert read_data.tdata == test_data
assert int(read_data.tid) == cur_tag
cur_tag = (cur_tag + 1) % tag_count
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
def cycle_pause():
return itertools.cycle([1, 1, 1, 0])
# When imported by cocotb inside a simulator, generate the actual cocotb tests.
if cocotb.SIM_NAME:
for test in [run_test_write, run_test_read]:
factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
# -----------------------------------------------------------------------------
# Optional pytest entrypoint via cocotb-test.
# Run from this directory with: pytest -q test_axi_dma_wrapper.py
# -----------------------------------------------------------------------------
def _sanitize_node_name(name):
return name.replace("[", "-").replace("]", "").replace("/", "_")
if pytest is not None:
@pytest.mark.parametrize("axi_data_width", [8, 16, 32])
@pytest.mark.parametrize("unaligned", [0, 1])
def test_axi_dma_wrapper_pytest(request, axi_data_width, unaligned):
import cocotb_test.simulator
tests_dir = os.path.abspath(os.path.dirname(__file__))
project_root = os.path.abspath(os.path.join(tests_dir, "..", ".."))
axi_if_rtl_dir = os.environ.get(
"AXI_IF_RTL_DIR", os.path.join(project_root, "rtl", "axi")
)
dma_if_rtl_dir = os.environ.get(
"DMA_IF_RTL_DIR", os.path.join(project_root, "rtl", "dma")
)
wrapper_rtl_dir = os.environ.get(
"WRAPPER_RTL_DIR", os.path.join(project_root, "rtl", "wrappers")
)
forencich_rtl_dir = os.environ.get(
"FORENCICH_AXI_RTL_DIR",
os.path.join(project_root, "external", "verilog-axi", "rtl"),
)
dut = "tb_axi_dma_wrapper"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut
parameters = {
"AXI_DATA_WIDTH": axi_data_width,
"AXI_ADDR_WIDTH": 16,
"AXI_ID_WIDTH": 8,
"AXI_USER_WIDTH": 1,
"AXI_MAX_BURST_LEN": 16,
"AXIS_ID_ENABLE": 1,
"AXIS_ID_WIDTH": 8,
"AXIS_DEST_ENABLE": 0,
"AXIS_DEST_WIDTH": 8,
"AXIS_USER_ENABLE": 1,
"AXIS_USER_WIDTH": 1,
"LEN_WIDTH": 20,
"TAG_WIDTH": 8,
"ENABLE_SG": 0,
"ENABLE_UNALIGNED": unaligned,
}
parameters["AXI_STRB_WIDTH"] = parameters["AXI_DATA_WIDTH"] // 8
parameters["AXIS_DATA_WIDTH"] = parameters["AXI_DATA_WIDTH"]
parameters["AXIS_KEEP_ENABLE"] = int(parameters["AXIS_DATA_WIDTH"] > 8)
parameters["AXIS_KEEP_WIDTH"] = parameters["AXIS_DATA_WIDTH"] // 8
parameters["AXIS_LAST_ENABLE"] = 1
verilog_sources = [
os.path.join(axi_if_rtl_dir, "axi_pkg.sv"),
os.path.join(axi_if_rtl_dir, "axi_if.sv"),
os.path.join(axi_if_rtl_dir, "axis_if.sv"),
os.path.join(axi_if_rtl_dir, "axi4_flat_to_if.sv"),
os.path.join(axi_if_rtl_dir, "axi4_if_to_flat.sv"),
os.path.join(axi_if_rtl_dir, "axis_flat_to_if.sv"),
os.path.join(axi_if_rtl_dir, "axis_if_to_flat.sv"),
os.path.join(dma_if_rtl_dir, "axi_dma_desc_if.sv"),
os.path.join(dma_if_rtl_dir, "axi_dma_read_desc_flat_to_if.sv"),
os.path.join(dma_if_rtl_dir, "axi_dma_read_desc_if_to_flat.sv"),
os.path.join(dma_if_rtl_dir,
"axi_dma_read_desc_status_flat_to_if.sv"),
os.path.join(dma_if_rtl_dir,
"axi_dma_read_desc_status_if_to_flat.sv"),
os.path.join(dma_if_rtl_dir, "axi_dma_write_desc_flat_to_if.sv"),
os.path.join(dma_if_rtl_dir, "axi_dma_write_desc_if_to_flat.sv"),
os.path.join(dma_if_rtl_dir,
"axi_dma_write_desc_status_flat_to_if.sv"),
os.path.join(dma_if_rtl_dir,
"axi_dma_write_desc_status_if_to_flat.sv"),
os.path.join(forencich_rtl_dir, "axi_dma.v"),
os.path.join(forencich_rtl_dir, "axi_dma_rd.v"),
os.path.join(forencich_rtl_dir, "axi_dma_wr.v"),
os.path.join(wrapper_rtl_dir, "axi_dma_if_wrapper.sv"),
os.path.join(tests_dir, "tb_axi_dma_wrapper.sv"),
]
extra_env = {f"PARAM_{k}": str(v) for k, v in parameters.items()}
sim_build = os.path.join(
tests_dir, "sim_build", _sanitize_node_name(request.node.name))
extra_args = []
if os.getenv("SIM", "verilator") == "verilator":
extra_args += ["--trace-structs"]
cocotb_test.simulator.run(
python_search=[tests_dir],
verilog_sources=verilog_sources,
includes=[axi_if_rtl_dir, dma_if_rtl_dir,
wrapper_rtl_dir, forencich_rtl_dir],
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
waves=bool(int(os.getenv("WAVES", "0"))),
extra_args=extra_args,
)
@@ -0,0 +1,34 @@
# SPDX-License-Identifier: MIT
TOPLEVEL_LANG = verilog
SIM ?= verilator
PWD := $(shell pwd)
# Directory with axi_pkg.sv, axi_if.sv and axi4l_reg_map.sv.
# Override it from command line if your tree is different:
# make SIM=verilator RTL_DIR=/path/to/rtl_libs/axi
RTL_DIR ?= $(PWD)/../../../axi
TB_DIR ?= $(PWD)
TOPLEVEL = tb_axi4l_reg_map
MODULE = test_axi4l_reg_map
export PYTHONPATH := $(TB_DIR):$(PYTHONPATH)
VERILOG_SOURCES += $(RTL_DIR)/rtl/axi_pkg.sv
VERILOG_SOURCES += $(RTL_DIR)/rtl/axi_if.sv
VERILOG_SOURCES += $(RTL_DIR)/axi_reg/axi4l_reg_map.sv
VERILOG_SOURCES += $(TB_DIR)/tb_axi4l_reg_map.sv
COMPILE_ARGS += -I$(RTL_DIR)
ifeq ($(SIM),verilator)
EXTRA_ARGS += --trace
EXTRA_ARGS += --trace-structs
EXTRA_ARGS += --public-flat-rw
EXTRA_ARGS += -Wno-fatal
EXTRA_ARGS += --timing
endif
include $(shell cocotb-config --makefiles)/Makefile.sim
@@ -0,0 +1,165 @@
module tb_axi4l_reg_map;
localparam int unsigned ADDR_W = 16;
localparam int unsigned DATA_W = 32;
localparam int unsigned USER_W = 1;
localparam int unsigned N_REGS = 3;
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;
function automatic logic [N_REGS-1:0][31:0][2:0] make_reg_mode();
logic [N_REGS-1:0][31:0][2:0] mode;
mode = '{default: REG_BIT_RSVD};
// REG0 - 0x00: mixed control register
// bit 0 : W1S
// bit 1 : RW
// bit 2 : W1C
mode[0][0] = REG_BIT_W1S;
mode[0][1] = REG_BIT_RW;
mode[0][2] = REG_BIT_W1C;
// REG1 - 0x04: status register
// bit 0 : RO busy
// bits 15:8 : RO error_code
mode[1][0] = REG_BIT_RO;
for (int i = 8; i < 16; i++) begin
mode[1][i] = REG_BIT_RO;
end
// REG2 - 0x08: full RW config register
for (int i = 0; i < 32; i++) begin
mode[2][i] = REG_BIT_RW;
end
return mode;
endfunction
function automatic logic [N_REGS-1:0][31:0] make_reg_rst();
logic [N_REGS-1:0][31:0] rst;
rst = '{default: 32'h0000_0000};
rst[0] = 32'h0000_0004; // W1C sticky bit starts set
rst[2] = 32'h1234_5678; // RW config reset value
return rst;
endfunction
localparam logic [N_REGS-1:0][31:0][2:0] REG_MODE = make_reg_mode();
localparam logic [N_REGS-1:0][31:0] REG_RST = make_reg_rst();
logic clk = 1'b0;
logic rst = 1'b0;
logic rst_n;
assign rst_n = ~rst;
always #5ns clk = ~clk;
// flat axil
logic [ADDR_W-1:0] s_axil_awaddr;
logic [2:0] s_axil_awprot;
logic s_axil_awvalid;
logic s_axil_awready;
logic [DATA_W-1:0] s_axil_wdata;
logic [DATA_W/8-1:0] s_axil_wstrb;
logic s_axil_wvalid;
logic s_axil_wready;
logic [1:0] s_axil_bresp;
logic s_axil_bvalid;
logic s_axil_bready;
logic [ADDR_W-1:0] s_axil_araddr;
logic [2:0] s_axil_arprot;
logic s_axil_arvalid;
logic s_axil_arready;
logic [DATA_W-1:0] s_axil_rdata;
logic [1:0] s_axil_rresp;
logic s_axil_rvalid;
logic s_axil_rready;
// simple external status inputs driven from cocotb
logic busy_i;
logic [7:0] error_code_i;
logic [N_REGS-1:0][31:0] reg_i;
logic [N_REGS-1:0][31:0] reg_o;
logic [N_REGS-1:0][31:0] reg_pulse;
// debug probes visible from cocotb. they are useful for checking W1S pulse-like behavior
logic [31:0] reg0_o;
logic [31:0] reg1_o;
logic [31:0] reg2_o;
assign reg0_o = reg_o[0];
assign reg1_o = reg_o[1];
assign reg2_o = reg_o[2];
always_comb begin
reg_i = '0;
reg_i[1][0] = busy_i;
reg_i[1][15:8] = error_code_i;
end
axi4l_if #(
.ADDR_W(ADDR_W),
.DATA_W(DATA_W),
.USER_W(USER_W)
) s_axil_if (
.aclk (clk),
.aresetn (rst_n)
);
assign s_axil_if.req.aw.addr = s_axil_awaddr;
assign s_axil_if.req.aw.prot = s_axil_awprot;
assign s_axil_if.req.aw.user = '0;
assign s_axil_if.req.aw.valid = s_axil_awvalid;
assign s_axil_awready = s_axil_if.resp.aw_ready;
assign s_axil_if.req.w.data = s_axil_wdata;
assign s_axil_if.req.w.strb = s_axil_wstrb;
assign s_axil_if.req.w.user = '0;
assign s_axil_if.req.w.valid = s_axil_wvalid;
assign s_axil_wready = s_axil_if.resp.w_ready;
assign s_axil_bresp = s_axil_if.resp.b.resp;
assign s_axil_bvalid = s_axil_if.resp.b.valid;
assign s_axil_if.req.b_ready = s_axil_bready;
assign s_axil_if.req.ar.addr = s_axil_araddr;
assign s_axil_if.req.ar.prot = s_axil_arprot;
assign s_axil_if.req.ar.user = '0;
assign s_axil_if.req.ar.valid = s_axil_arvalid;
assign s_axil_arready = s_axil_if.resp.ar_ready;
assign s_axil_rdata = s_axil_if.resp.r.data;
assign s_axil_rresp = s_axil_if.resp.r.resp;
assign s_axil_rvalid = s_axil_if.resp.r.valid;
assign s_axil_if.req.r_ready = s_axil_rready;
axi4l_reg_map #(
.ADDR_W (ADDR_W),
.DATA_W (DATA_W),
.USER_W (USER_W),
.N_REGS (N_REGS),
.REG_MODE(REG_MODE),
.REG_RST (REG_RST)
) u_reg_map (
.clk (clk),
.rst_n (rst_n),
.s_axil (s_axil_if.slave),
.reg_i (reg_i),
.reg_o (reg_o),
.reg_pulse(reg_pulse)
);
endmodule
@@ -0,0 +1,310 @@
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import ReadOnly, RisingEdge
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
OKAY = 0
SLVERR = 2
REG0_CTRL = 0x00
REG1_STATUS = 0x04
REG2_CONFIG = 0x08
REG_INVALID = 0x0C # N_REGS=3, so index 3 is bad
def _resp_code(resp):
"""Return integer AXI response code from a cocotbext-axi response object."""
if resp is None:
return OKAY
value = getattr(resp, "resp", OKAY)
# common guards
try:
return int(value)
except TypeError:
return int(value.integer)
def _read_data(resp):
return int.from_bytes(bytes(resp.data), "little")
class TB:
def __init__(self, dut):
self.dut = dut
self.axil = AxiLiteMaster(AxiLiteBus.from_prefix(
dut, "s_axil"), dut.clk, dut.rst)
async def reset(self):
self.dut.rst.value = 1
self.dut.busy_i.value = 0
self.dut.error_code_i.value = 0
for _ in range(5):
await RisingEdge(self.dut.clk)
self.dut.rst.value = 0
for _ in range(5):
await RisingEdge(self.dut.clk)
# shortcuts sorta
async def write32(self, addr, value, expected_resp=OKAY):
resp = await self.axil.write(addr, value.to_bytes(4, "little"))
assert _resp_code(resp) == expected_resp, (
f"write addr=0x{addr:08x}: expected resp {expected_resp}, got {_resp_code(resp)}"
)
return resp
async def read32(self, addr, expected_resp=OKAY):
resp = await self.axil.read(addr, 4)
assert _resp_code(resp) == expected_resp, (
f"read addr=0x{addr:08x}: expected resp {expected_resp}, got {_resp_code(resp)}"
)
return _read_data(resp)
@cocotb.test()
async def test_reset_and_basic_reads(dut):
"""Check reset values and RO status path via reg_i."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
# REG0 reset: W1C sticky bit set. W1S reads as 0, RW reads from reg_o
assert await tb.read32(REG0_CTRL) == 0x00000004
# REG2 is a normal RW config register with non-zero reset value
assert await tb.read32(REG2_CONFIG) == 0x12345678
# Drive external status and read it through RO bits
dut.busy_i.value = 1
dut.error_code_i.value = 0x5A
await RisingEdge(dut.clk)
assert await tb.read32(REG1_STATUS) == 0x00005A01
@cocotb.test()
async def test_rw_and_w1c_bits(dut):
"""Check RW bit update and W1C sticky clear behavior."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
# Initial REG0: bit2 W1C is set, bit1 RW is clear, bit0 W1S reads as 0
assert await tb.read32(REG0_CTRL) == 0x00000004
# Set RW bit1 while preserving W1C bit2
await tb.write32(REG0_CTRL, 0x00000002)
assert await tb.read32(REG0_CTRL) == 0x00000006
# Write 1 to W1C bit2, keep RW bit1 set
await tb.write32(REG0_CTRL, 0x00000006)
assert await tb.read32(REG0_CTRL) == 0x00000002
# Write zero clears the RW bit because REG0 is a normal word write for RW fields
await tb.write32(REG0_CTRL, 0x00000000)
assert await tb.read32(REG0_CTRL) == 0x00000000
# Full RW register write/read
await tb.write32(REG2_CONFIG, 0xDEADBEEF)
assert await tb.read32(REG2_CONFIG) == 0xDEADBEEF
def _reg0_pulse_value(dut):
"""Return REG0 pulse bits regardless of how the test wrapper exposes them."""
if hasattr(dut, "reg0_pulse"):
return int(dut.reg0_pulse.value)
if hasattr(dut, "reg_pulse"):
# Packed SystemVerilog array [N_REGS-1:0][31:0]: REG0 occupies bits 31:0.
return int(dut.reg_pulse.value) & 0xFFFF_FFFF
raise AssertionError(
"DUT must expose either reg0_pulse[31:0] or packed reg_pulse"
)
async def _sample_reg0_pulse_cycles(dut, cycles):
"""Sample REG0 pulse output after each active clock edge."""
samples = []
for _ in range(cycles):
await RisingEdge(dut.clk)
await ReadOnly()
samples.append(_reg0_pulse_value(dut))
return samples
def _assert_single_cycle_bit_pulse(samples, bit, name):
"""Check that one selected bit was high for exactly one sampled cycle."""
high_cycles = [
index for index, value in enumerate(samples)
if value & (1 << bit)
]
assert len(high_cycles) == 1, (
f"{name}: expected one high cycle, got {len(high_cycles)}; "
f"samples={[f'0x{value:08x}' for value in samples]}"
)
return high_cycles[0]
@cocotb.test()
async def test_reg_pulse_is_zero_after_reset(dut):
"""No W1 event may be reported after reset without a write."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
samples = await _sample_reg0_pulse_cycles(dut, 4)
assert not any(samples), (
"reg_pulse was asserted without a W1 write: "
f"{[f'0x{value:08x}' for value in samples]}"
)
@cocotb.test()
async def test_w1s_generates_single_cycle_reg_pulse(dut):
"""Writing 1 to REG0[0] W1S must pulse REG0 pulse bit 0 once."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
monitor = cocotb.start_soon(_sample_reg0_pulse_cycles(dut, 20))
await tb.write32(REG0_CTRL, 0x00000001)
samples = await monitor
_assert_single_cycle_bit_pulse(samples, bit=0, name="reg_pulse[0][0]")
# No unrelated W1 bit may pulse.
assert not any(value & (1 << 2) for value in samples)
# W1S is a command bit and is not returned by reads.
assert await tb.read32(REG0_CTRL) == 0x00000004
@cocotb.test()
async def test_w1c_generates_single_cycle_reg_pulse(dut):
"""Writing 1 to REG0[2] W1C must pulse bit 2 once and clear state."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
assert await tb.read32(REG0_CTRL) == 0x00000004
monitor = cocotb.start_soon(_sample_reg0_pulse_cycles(dut, 20))
await tb.write32(REG0_CTRL, 0x00000004)
samples = await monitor
_assert_single_cycle_bit_pulse(samples, bit=2, name="reg_pulse[0][2]")
# No unrelated W1 bit may pulse.
assert not any(value & (1 << 0) for value in samples)
assert await tb.read32(REG0_CTRL) == 0x00000000
@cocotb.test()
async def test_zero_to_w1_and_rw_write_do_not_generate_reg_pulse(dut):
"""Only written ones in W1 fields may create reg_pulse."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
monitor = cocotb.start_soon(_sample_reg0_pulse_cycles(dut, 20))
# bit1 is RW; both W1 fields receive zero.
await tb.write32(REG0_CTRL, 0x00000002)
samples = await monitor
assert not any(samples), (
"RW write or zero written to W1 fields generated reg_pulse: "
f"{[f'0x{value:08x}' for value in samples]}"
)
assert await tb.read32(REG0_CTRL) == 0x00000006
@cocotb.test()
async def test_w1s_and_w1c_pulse_together(dut):
"""W1S and W1C ones in one AXI write must pulse on the same cycle."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
monitor = cocotb.start_soon(_sample_reg0_pulse_cycles(dut, 20))
await tb.write32(REG0_CTRL, 0x00000005)
samples = await monitor
w1s_cycle = _assert_single_cycle_bit_pulse(
samples, bit=0, name="reg_pulse[0][0]"
)
w1c_cycle = _assert_single_cycle_bit_pulse(
samples, bit=2, name="reg_pulse[0][2]"
)
assert w1s_cycle == w1c_cycle, (
"W1 bits written by one transaction pulsed on different cycles: "
f"W1S={w1s_cycle}, W1C={w1c_cycle}"
)
# Only bits 0 and 2 are allowed to pulse.
assert samples[w1s_cycle] == 0x00000005
assert await tb.read32(REG0_CTRL) == 0x00000000
@cocotb.test()
async def test_each_w1_write_creates_a_new_pulse(dut):
"""Two separate W1 writes must create two separate one-cycle pulses."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
monitor = cocotb.start_soon(_sample_reg0_pulse_cycles(dut, 40))
await tb.write32(REG0_CTRL, 0x00000001)
for _ in range(3):
await RisingEdge(dut.clk)
await tb.write32(REG0_CTRL, 0x00000001)
samples = await monitor
high_cycles = [
index for index, value in enumerate(samples)
if value & 0x1
]
assert len(high_cycles) == 2, (
f"expected two W1S pulses, got cycles {high_cycles}; "
f"samples={[f'0x{value:08x}' for value in samples]}"
)
assert high_cycles[1] > high_cycles[0] + 1, (
f"separate writes did not produce separate pulses: {high_cycles}"
)
@cocotb.test()
async def test_write_to_ro_returns_slverr(dut):
"""Writing a RO bit should return SLVERR and should not change status."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
dut.busy_i.value = 1
dut.error_code_i.value = 0x33
await RisingEdge(dut.clk)
await tb.write32(REG1_STATUS, 0x00000101, expected_resp=SLVERR)
assert await tb.read32(REG1_STATUS) == 0x00003301
@cocotb.test()
async def test_invalid_address_returns_slverr(dut):
"""N_REGS=3, so address 0x0C selects index 3 and must fail."""
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
tb = TB(dut)
await tb.reset()
await tb.write32(REG_INVALID, 0x11223344, expected_resp=SLVERR)
assert await tb.read32(REG_INVALID, expected_resp=SLVERR) == 0x00000000
@@ -0,0 +1,13 @@
module axis_loopback #(
parameter int unsigned DATA_W = 64,
parameter int unsigned KEEP_W = DATA_W / 8,
parameter int unsigned ID_W = 8,
parameter int unsigned DEST_W = 8,
parameter int unsigned USER_W = 1
)(
axis_if.slave s_axis,
axis_if.master m_axis
);
assign m_axis.req = s_axis.req;
assign s_axis.resp = m_axis.resp;
endmodule : axis_loopback