Intermediate tests and updates to the AXI modules.
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
**sim_build**
|
||||||
|
**pycache**
|
||||||
|
dump.vcd
|
||||||
|
results.xml
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "external/verilog-axi"]
|
||||||
|
path = external/verilog-axi
|
||||||
|
url = https://github.com/alexforencich/verilog-axi
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# RTL Libs
|
||||||
|
|
||||||
|
## AXI Defines
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
+431
@@ -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
|
||||||
+317
@@ -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
|
||||||
Reference in New Issue
Block a user