rtl: rework dma AXIS cmd&status
This commit is contained in:
@ -1,19 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// AXIS compat wrapper above axi_dma_if_wrapper.
|
||||
//
|
||||
// Compatibility wrapper over axi_dma_if_wrapper.
|
||||
//
|
||||
// Uses 4 axis_if channels for statuses and descs
|
||||
// s_axis_desc_cmd = one-beat command stream carrying read + write desc
|
||||
// m_axis_desc_status = one-beat status stream carrying read + write status
|
||||
//
|
||||
// payload packing is LSB-first and one descriptor/status occupies one AXIS beat.
|
||||
// tkeep/tstrb/tlast/id/dest/user on descriptor inputs are ignored.
|
||||
// status outputs drive tkeep/tstrb to all ones, tlast to 1, and id/dest/user to 0.
|
||||
//
|
||||
// !!!!!: the original alexforencich axi_dma status outputs have
|
||||
// no ready/backpressure signal. This wrapper adds a oneentry holding register
|
||||
// for each status axis output, but if a downstream is not ready long enough for a
|
||||
// second status to arrive while the first one is still pending, the core cannot
|
||||
// be backpressured. In normal use keep status sinks ready, or add an external
|
||||
// FIFO if long stalls are possible.
|
||||
// read_enable and write_enable select which descriptor is used
|
||||
|
||||
`default_nettype none
|
||||
|
||||
@ -41,102 +32,83 @@ module axi_dma_axis_compat #(
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
// Payload widths for descriptor/status AXIS streams.
|
||||
parameter int unsigned READ_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH,
|
||||
parameter int unsigned READ_DESC_AXIS_DATA_WIDTH = ((READ_DESC_PAYLOAD_WIDTH + 7) / 8) * 8,
|
||||
parameter int unsigned READ_DESC_STATUS_PAYLOAD_WIDTH = TAG_WIDTH + 4,
|
||||
parameter int unsigned READ_DESC_STATUS_AXIS_DATA_WIDTH = ((READ_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8,
|
||||
parameter int unsigned WRITE_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH,
|
||||
parameter int unsigned WRITE_DESC_AXIS_DATA_WIDTH = ((WRITE_DESC_PAYLOAD_WIDTH + 7) / 8) * 8,
|
||||
parameter int unsigned WRITE_DESC_STATUS_PAYLOAD_WIDTH = LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4,
|
||||
parameter int unsigned WRITE_DESC_STATUS_AXIS_DATA_WIDTH = ((WRITE_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8
|
||||
// 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,
|
||||
|
||||
/*
|
||||
* AXI read descriptor input, encoded as one AXIS beat.
|
||||
* tdata layout, LSB first:
|
||||
* addr | len | tag | id | dest | user
|
||||
*/
|
||||
axis_if.slave s_axis_read_desc,
|
||||
// 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,
|
||||
|
||||
/*
|
||||
* AXI read descriptor status output, encoded as one AXIS beat.
|
||||
* tdata layout, LSB first:
|
||||
* tag | error
|
||||
*/
|
||||
axis_if.master m_axis_read_desc_status,
|
||||
// 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,
|
||||
|
||||
/*
|
||||
* AXI stream read data output.
|
||||
*/
|
||||
// Original DMA data streams and AXI memory master, still exposed as normal
|
||||
// generic interfaces.
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
/*
|
||||
* AXI write descriptor input, encoded as one AXIS beat.
|
||||
* tdata layout, LSB first:
|
||||
* addr | len | tag
|
||||
*/
|
||||
axis_if.slave s_axis_write_desc,
|
||||
|
||||
/*
|
||||
* AXI write descriptor status output, encoded as one AXIS beat.
|
||||
* tdata layout, LSB first:
|
||||
* len | tag | id | dest | user | error
|
||||
*/
|
||||
axis_if.master m_axis_write_desc_status,
|
||||
|
||||
/*
|
||||
* AXI stream write data input.
|
||||
*/
|
||||
axis_if.slave s_axis_write_data,
|
||||
|
||||
/*
|
||||
* AXI memory master interface.
|
||||
*/
|
||||
axi4_if.master m_axi,
|
||||
|
||||
/*
|
||||
* Configuration.
|
||||
*/
|
||||
input logic read_enable,
|
||||
input logic write_enable,
|
||||
input logic write_abort
|
||||
);
|
||||
|
||||
localparam int unsigned RD_ADDR_LSB = 0;
|
||||
localparam int unsigned RD_LEN_LSB = RD_ADDR_LSB + AXI_ADDR_WIDTH;
|
||||
localparam int unsigned RD_TAG_LSB = RD_LEN_LSB + LEN_WIDTH;
|
||||
localparam int unsigned RD_ID_LSB = RD_TAG_LSB + TAG_WIDTH;
|
||||
localparam int unsigned RD_DEST_LSB = RD_ID_LSB + AXIS_ID_WIDTH;
|
||||
localparam int unsigned RD_USER_LSB = RD_DEST_LSB + AXIS_DEST_WIDTH;
|
||||
// --------------------------------------------------------------------------
|
||||
// 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 RDS_TAG_LSB = 0;
|
||||
localparam int unsigned RDS_ERROR_LSB = RDS_TAG_LSB + TAG_WIDTH;
|
||||
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 WD_ADDR_LSB = 0;
|
||||
localparam int unsigned WD_LEN_LSB = WD_ADDR_LSB + AXI_ADDR_WIDTH;
|
||||
localparam int unsigned WD_TAG_LSB = WD_LEN_LSB + LEN_WIDTH;
|
||||
localparam int unsigned 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 WDS_LEN_LSB = 0;
|
||||
localparam int unsigned WDS_TAG_LSB = WDS_LEN_LSB + LEN_WIDTH;
|
||||
localparam int unsigned WDS_ID_LSB = WDS_TAG_LSB + TAG_WIDTH;
|
||||
localparam int unsigned WDS_DEST_LSB = WDS_ID_LSB + AXIS_ID_WIDTH;
|
||||
localparam int unsigned WDS_USER_LSB = WDS_DEST_LSB + AXIS_DEST_WIDTH;
|
||||
localparam int unsigned WDS_ERROR_LSB = WDS_USER_LSB + AXIS_USER_WIDTH;
|
||||
localparam int unsigned RD_STS_TAG_LSB = 0;
|
||||
localparam int unsigned RD_STS_ERROR_LSB = RD_STS_TAG_LSB + TAG_WIDTH;
|
||||
|
||||
localparam int unsigned READ_DESC_AXIS_KEEP_WIDTH = READ_DESC_AXIS_DATA_WIDTH / 8;
|
||||
localparam int unsigned READ_DESC_STATUS_AXIS_KEEP_WIDTH = READ_DESC_STATUS_AXIS_DATA_WIDTH / 8;
|
||||
localparam int unsigned WRITE_DESC_AXIS_KEEP_WIDTH = WRITE_DESC_AXIS_DATA_WIDTH / 8;
|
||||
localparam int unsigned WRITE_DESC_STATUS_AXIS_KEEP_WIDTH = WRITE_DESC_STATUS_AXIS_DATA_WIDTH / 8;
|
||||
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;
|
||||
|
||||
logic rstn;
|
||||
assign rstn = ~rst;
|
||||
wire rstn = ~rst;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Internal DMA-specific descriptor/status interfaces expected by
|
||||
// axi_dma_if_wrapper.
|
||||
// Internal DMA-specific descriptor/status interfaces
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
axi_dma_read_desc_if #(
|
||||
@ -179,125 +151,33 @@ module axi_dma_axis_compat #(
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// AXIS read descriptor input -> DMA-specific read descriptor interface.
|
||||
// Command AXIS -> read/write descriptors
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
assign read_desc_if.req.addr = s_axis_read_desc.req.t.data[RD_ADDR_LSB +: AXI_ADDR_WIDTH];
|
||||
assign read_desc_if.req.len = s_axis_read_desc.req.t.data[RD_LEN_LSB +: LEN_WIDTH];
|
||||
assign read_desc_if.req.tag = s_axis_read_desc.req.t.data[RD_TAG_LSB +: TAG_WIDTH];
|
||||
assign read_desc_if.req.id = s_axis_read_desc.req.t.data[RD_ID_LSB +: AXIS_ID_WIDTH];
|
||||
assign read_desc_if.req.dest = s_axis_read_desc.req.t.data[RD_DEST_LSB +: AXIS_DEST_WIDTH];
|
||||
assign read_desc_if.req.user = s_axis_read_desc.req.t.data[RD_USER_LSB +: AXIS_USER_WIDTH];
|
||||
assign read_desc_if.req.valid = s_axis_read_desc.req.t.valid;
|
||||
assign s_axis_read_desc.resp.ready = read_desc_if.resp.ready;
|
||||
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];
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// AXIS write descriptor input -> DMA-specific write descriptor interface.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
assign write_desc_if.req.addr = s_axis_write_desc.req.t.data[WD_ADDR_LSB +: AXI_ADDR_WIDTH];
|
||||
assign write_desc_if.req.len = s_axis_write_desc.req.t.data[WD_LEN_LSB +: LEN_WIDTH];
|
||||
assign write_desc_if.req.tag = s_axis_write_desc.req.t.data[WD_TAG_LSB +: TAG_WIDTH];
|
||||
assign write_desc_if.req.valid = s_axis_write_desc.req.t.valid;
|
||||
assign s_axis_write_desc.resp.ready = write_desc_if.resp.ready;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// DMA-specific read status -> AXIS read status output.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
logic [READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] read_status_payload;
|
||||
logic [READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] read_status_data_q;
|
||||
logic read_status_valid_q;
|
||||
|
||||
always_comb begin
|
||||
read_status_payload = '0;
|
||||
read_status_payload[RDS_TAG_LSB +: TAG_WIDTH] = read_desc_status_if.req.tag;
|
||||
read_status_payload[RDS_ERROR_LSB +: 4] = read_desc_status_if.req.error;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst) begin
|
||||
read_status_valid_q <= 1'b0;
|
||||
read_status_data_q <= '0;
|
||||
end else begin
|
||||
if (!read_status_valid_q || m_axis_read_desc_status.resp.ready) begin
|
||||
read_status_valid_q <= read_desc_status_if.req.valid;
|
||||
if (read_desc_status_if.req.valid) begin
|
||||
read_status_data_q <= read_status_payload;
|
||||
end else begin
|
||||
read_status_data_q <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_axis_read_desc_status.req.t.data = '0;
|
||||
m_axis_read_desc_status.req.t.keep = '0;
|
||||
m_axis_read_desc_status.req.t.strb = '0;
|
||||
m_axis_read_desc_status.req.t.last = read_status_valid_q;
|
||||
m_axis_read_desc_status.req.t.id = '0;
|
||||
m_axis_read_desc_status.req.t.dest = '0;
|
||||
m_axis_read_desc_status.req.t.user = '0;
|
||||
m_axis_read_desc_status.req.t.valid = read_status_valid_q;
|
||||
|
||||
m_axis_read_desc_status.req.t.data[READ_DESC_STATUS_AXIS_DATA_WIDTH-1:0] = read_status_data_q;
|
||||
m_axis_read_desc_status.req.t.keep[READ_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {READ_DESC_STATUS_AXIS_KEEP_WIDTH{read_status_valid_q}};
|
||||
m_axis_read_desc_status.req.t.strb[READ_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {READ_DESC_STATUS_AXIS_KEEP_WIDTH{read_status_valid_q}};
|
||||
end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// DMA-specific write status -> AXIS write status output.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
logic [WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] write_status_payload;
|
||||
logic [WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] write_status_data_q;
|
||||
logic write_status_valid_q;
|
||||
|
||||
always_comb begin
|
||||
write_status_payload = '0;
|
||||
write_status_payload[WDS_LEN_LSB +: LEN_WIDTH] = write_desc_status_if.req.len;
|
||||
write_status_payload[WDS_TAG_LSB +: TAG_WIDTH] = write_desc_status_if.req.tag;
|
||||
write_status_payload[WDS_ID_LSB +: AXIS_ID_WIDTH] = write_desc_status_if.req.id;
|
||||
write_status_payload[WDS_DEST_LSB +: AXIS_DEST_WIDTH] = write_desc_status_if.req.dest;
|
||||
write_status_payload[WDS_USER_LSB +: AXIS_USER_WIDTH] = write_desc_status_if.req.user;
|
||||
write_status_payload[WDS_ERROR_LSB +: 4] = write_desc_status_if.req.error;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst) begin
|
||||
write_status_valid_q <= 1'b0;
|
||||
write_status_data_q <= '0;
|
||||
end else begin
|
||||
if (!write_status_valid_q || m_axis_write_desc_status.resp.ready) begin
|
||||
write_status_valid_q <= write_desc_status_if.req.valid;
|
||||
if (write_desc_status_if.req.valid) begin
|
||||
write_status_data_q <= write_status_payload;
|
||||
end else begin
|
||||
write_status_data_q <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_axis_write_desc_status.req.t.data = '0;
|
||||
m_axis_write_desc_status.req.t.keep = '0;
|
||||
m_axis_write_desc_status.req.t.strb = '0;
|
||||
m_axis_write_desc_status.req.t.last = write_status_valid_q;
|
||||
m_axis_write_desc_status.req.t.id = '0;
|
||||
m_axis_write_desc_status.req.t.dest = '0;
|
||||
m_axis_write_desc_status.req.t.user = '0;
|
||||
m_axis_write_desc_status.req.t.valid = write_status_valid_q;
|
||||
|
||||
m_axis_write_desc_status.req.t.data[WRITE_DESC_STATUS_AXIS_DATA_WIDTH-1:0] = write_status_data_q;
|
||||
m_axis_write_desc_status.req.t.keep[WRITE_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {WRITE_DESC_STATUS_AXIS_KEEP_WIDTH{write_status_valid_q}};
|
||||
m_axis_write_desc_status.req.t.strb[WRITE_DESC_STATUS_AXIS_KEEP_WIDTH-1:0] = {WRITE_DESC_STATUS_AXIS_KEEP_WIDTH{write_status_valid_q}};
|
||||
end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Lower-level wrapper: DMA-specific descriptor/status interfaces inside,
|
||||
// ordinary AXIS data and AXI memory interfaces unchanged.
|
||||
// Lower DMA wrapper
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
axi_dma_if_wrapper #(
|
||||
@ -307,6 +187,7 @@ module axi_dma_axis_compat #(
|
||||
.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),
|
||||
@ -317,29 +198,134 @@ module axi_dma_axis_compat #(
|
||||
.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),
|
||||
.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_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),
|
||||
.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),
|
||||
.m_axi (m_axi),
|
||||
|
||||
.read_enable (read_enable),
|
||||
.write_enable (write_enable),
|
||||
.write_abort (write_abort)
|
||||
.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
|
||||
|
||||
@ -24,214 +24,143 @@ module tb_axi_dma_axis_compat #(
|
||||
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 ENABLE_UNALIGNED = 0,
|
||||
|
||||
// cocotb drives these directly
|
||||
logic clk;
|
||||
logic rst;
|
||||
logic rstn;
|
||||
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,
|
||||
|
||||
assign rstn = ~rst;
|
||||
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,
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Descriptor/status payload widths and tdata layouts.
|
||||
// --------------------------------------------------------------------------
|
||||
input logic read_enable,
|
||||
input logic write_enable,
|
||||
input logic write_abort,
|
||||
|
||||
localparam int unsigned READ_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH;
|
||||
localparam int unsigned READ_DESC_AXIS_DATA_WIDTH = ((READ_DESC_PAYLOAD_WIDTH + 7) / 8) * 8;
|
||||
localparam int unsigned READ_DESC_AXIS_KEEP_WIDTH = READ_DESC_AXIS_DATA_WIDTH / 8;
|
||||
// Unified descriptor command AXIS, flat for cocotb
|
||||
input logic [DESC_CMD_DATA_WIDTH-1:0] s_axis_desc_cmd_tdata,
|
||||
input logic [DESC_CMD_KEEP_WIDTH-1:0] s_axis_desc_cmd_tkeep,
|
||||
input logic [DESC_CMD_KEEP_WIDTH-1:0] s_axis_desc_cmd_tstrb,
|
||||
input logic s_axis_desc_cmd_tlast,
|
||||
input logic s_axis_desc_cmd_tid,
|
||||
input logic s_axis_desc_cmd_tdest,
|
||||
input logic s_axis_desc_cmd_tuser,
|
||||
input logic s_axis_desc_cmd_tvalid,
|
||||
output logic s_axis_desc_cmd_tready,
|
||||
|
||||
localparam int unsigned READ_DESC_STATUS_PAYLOAD_WIDTH = TAG_WIDTH + 4;
|
||||
localparam int unsigned READ_DESC_STATUS_AXIS_DATA_WIDTH = ((READ_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8;
|
||||
localparam int unsigned READ_DESC_STATUS_AXIS_KEEP_WIDTH = READ_DESC_STATUS_AXIS_DATA_WIDTH / 8;
|
||||
// Unified descriptor status AXIS, flat for cocotb
|
||||
output logic [DESC_STATUS_DATA_WIDTH-1:0] m_axis_desc_status_tdata,
|
||||
output logic [DESC_STATUS_KEEP_WIDTH-1:0] m_axis_desc_status_tkeep,
|
||||
output logic [DESC_STATUS_KEEP_WIDTH-1:0] m_axis_desc_status_tstrb,
|
||||
output logic m_axis_desc_status_tlast,
|
||||
output logic m_axis_desc_status_tid,
|
||||
output logic m_axis_desc_status_tdest,
|
||||
output logic [DESC_STATUS_USER_WIDTH-1:0] m_axis_desc_status_tuser,
|
||||
output logic m_axis_desc_status_tvalid,
|
||||
input logic m_axis_desc_status_tready,
|
||||
|
||||
localparam int unsigned WRITE_DESC_PAYLOAD_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH;
|
||||
localparam int unsigned WRITE_DESC_AXIS_DATA_WIDTH = ((WRITE_DESC_PAYLOAD_WIDTH + 7) / 8) * 8;
|
||||
localparam int unsigned WRITE_DESC_AXIS_KEEP_WIDTH = WRITE_DESC_AXIS_DATA_WIDTH / 8;
|
||||
// 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,
|
||||
|
||||
localparam int unsigned WRITE_DESC_STATUS_PAYLOAD_WIDTH = LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4;
|
||||
localparam int unsigned WRITE_DESC_STATUS_AXIS_DATA_WIDTH = ((WRITE_DESC_STATUS_PAYLOAD_WIDTH + 7) / 8) * 8;
|
||||
localparam int unsigned WRITE_DESC_STATUS_AXIS_KEEP_WIDTH = WRITE_DESC_STATUS_AXIS_DATA_WIDTH / 8;
|
||||
// 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,
|
||||
|
||||
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;
|
||||
// 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,
|
||||
|
||||
localparam int unsigned RDS_TAG_LSB = 0;
|
||||
localparam int unsigned RDS_ERROR_LSB = RDS_TAG_LSB + TAG_WIDTH;
|
||||
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,
|
||||
|
||||
localparam int unsigned WD_ADDR_LSB = 0;
|
||||
localparam int unsigned WD_LEN_LSB = WD_ADDR_LSB + AXI_ADDR_WIDTH;
|
||||
localparam int unsigned WD_TAG_LSB = WD_LEN_LSB + LEN_WIDTH;
|
||||
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,
|
||||
|
||||
localparam int unsigned WDS_LEN_LSB = 0;
|
||||
localparam int unsigned WDS_TAG_LSB = WDS_LEN_LSB + LEN_WIDTH;
|
||||
localparam int unsigned WDS_ID_LSB = WDS_TAG_LSB + TAG_WIDTH;
|
||||
localparam int unsigned WDS_DEST_LSB = WDS_ID_LSB + AXIS_ID_WIDTH;
|
||||
localparam int unsigned WDS_USER_LSB = WDS_DEST_LSB + AXIS_DEST_WIDTH;
|
||||
localparam int unsigned WDS_ERROR_LSB = WDS_USER_LSB + AXIS_USER_WIDTH;
|
||||
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,
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Flat descriptor/status ports visible to cocotb.
|
||||
// --------------------------------------------------------------------------
|
||||
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
|
||||
);
|
||||
|
||||
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.
|
||||
// --------------------------------------------------------------------------
|
||||
wire rstn = ~rst;
|
||||
|
||||
axis_if #(
|
||||
.DATA_W (READ_DESC_AXIS_DATA_WIDTH),
|
||||
.KEEP_W (READ_DESC_AXIS_KEEP_WIDTH),
|
||||
.DATA_W (DESC_CMD_DATA_WIDTH),
|
||||
.KEEP_W (DESC_CMD_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (1)
|
||||
) s_axis_read_desc_axis_if (
|
||||
) desc_cmd_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W (READ_DESC_STATUS_AXIS_DATA_WIDTH),
|
||||
.KEEP_W (READ_DESC_STATUS_AXIS_KEEP_WIDTH),
|
||||
.DATA_W (DESC_STATUS_DATA_WIDTH),
|
||||
.KEEP_W (DESC_STATUS_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (1)
|
||||
) m_axis_read_desc_status_axis_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W (WRITE_DESC_AXIS_DATA_WIDTH),
|
||||
.KEEP_W (WRITE_DESC_AXIS_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (1)
|
||||
) s_axis_write_desc_axis_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W (WRITE_DESC_STATUS_AXIS_DATA_WIDTH),
|
||||
.KEEP_W (WRITE_DESC_STATUS_AXIS_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (1)
|
||||
) m_axis_write_desc_status_axis_if (
|
||||
.USER_W (DESC_STATUS_USER_WIDTH)
|
||||
) desc_status_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
@ -242,7 +171,7 @@ module tb_axi_dma_axis_compat #(
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) m_axis_read_data_if (
|
||||
) read_data_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
@ -253,7 +182,7 @@ module tb_axi_dma_axis_compat #(
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) s_axis_write_data_if (
|
||||
) write_data_if (
|
||||
.aclk (clk),
|
||||
.aresetn (rstn)
|
||||
);
|
||||
@ -268,99 +197,52 @@ module tb_axi_dma_axis_compat #(
|
||||
.aresetn (rstn)
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Flat descriptor/status <-> AXIS descriptor/status packing.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
s_axis_read_desc_axis_if.req.t.data = '0;
|
||||
s_axis_read_desc_axis_if.req.t.keep = {READ_DESC_AXIS_KEEP_WIDTH{s_axis_read_desc_valid}};
|
||||
s_axis_read_desc_axis_if.req.t.strb = {READ_DESC_AXIS_KEEP_WIDTH{s_axis_read_desc_valid}};
|
||||
s_axis_read_desc_axis_if.req.t.last = s_axis_read_desc_valid;
|
||||
s_axis_read_desc_axis_if.req.t.id = '0;
|
||||
s_axis_read_desc_axis_if.req.t.dest = '0;
|
||||
s_axis_read_desc_axis_if.req.t.user = '0;
|
||||
s_axis_read_desc_axis_if.req.t.valid = s_axis_read_desc_valid;
|
||||
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_ADDR_LSB +: AXI_ADDR_WIDTH] = s_axis_read_desc_addr;
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_LEN_LSB +: LEN_WIDTH] = s_axis_read_desc_len;
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_TAG_LSB +: TAG_WIDTH] = s_axis_read_desc_tag;
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_ID_LSB +: AXIS_ID_WIDTH] = s_axis_read_desc_id;
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_DEST_LSB +: AXIS_DEST_WIDTH] = s_axis_read_desc_dest;
|
||||
s_axis_read_desc_axis_if.req.t.data[RD_USER_LSB +: AXIS_USER_WIDTH] = s_axis_read_desc_user;
|
||||
end
|
||||
|
||||
assign s_axis_read_desc_ready = s_axis_read_desc_axis_if.resp.ready;
|
||||
|
||||
always_comb begin
|
||||
m_axis_read_desc_status_tag = m_axis_read_desc_status_axis_if.req.t.data[RDS_TAG_LSB +: TAG_WIDTH];
|
||||
m_axis_read_desc_status_error = m_axis_read_desc_status_axis_if.req.t.data[RDS_ERROR_LSB +: 4];
|
||||
m_axis_read_desc_status_valid = m_axis_read_desc_status_axis_if.req.t.valid;
|
||||
end
|
||||
|
||||
assign m_axis_read_desc_status_axis_if.resp.ready = 1'b1;
|
||||
|
||||
always_comb begin
|
||||
s_axis_write_desc_axis_if.req.t.data = '0;
|
||||
s_axis_write_desc_axis_if.req.t.keep = {WRITE_DESC_AXIS_KEEP_WIDTH{s_axis_write_desc_valid}};
|
||||
s_axis_write_desc_axis_if.req.t.strb = {WRITE_DESC_AXIS_KEEP_WIDTH{s_axis_write_desc_valid}};
|
||||
s_axis_write_desc_axis_if.req.t.last = s_axis_write_desc_valid;
|
||||
s_axis_write_desc_axis_if.req.t.id = '0;
|
||||
s_axis_write_desc_axis_if.req.t.dest = '0;
|
||||
s_axis_write_desc_axis_if.req.t.user = '0;
|
||||
s_axis_write_desc_axis_if.req.t.valid = s_axis_write_desc_valid;
|
||||
|
||||
s_axis_write_desc_axis_if.req.t.data[WD_ADDR_LSB +: AXI_ADDR_WIDTH] = s_axis_write_desc_addr;
|
||||
s_axis_write_desc_axis_if.req.t.data[WD_LEN_LSB +: LEN_WIDTH] = s_axis_write_desc_len;
|
||||
s_axis_write_desc_axis_if.req.t.data[WD_TAG_LSB +: TAG_WIDTH] = s_axis_write_desc_tag;
|
||||
end
|
||||
|
||||
assign s_axis_write_desc_ready = s_axis_write_desc_axis_if.resp.ready;
|
||||
|
||||
always_comb begin
|
||||
m_axis_write_desc_status_len = m_axis_write_desc_status_axis_if.req.t.data[WDS_LEN_LSB +: LEN_WIDTH];
|
||||
m_axis_write_desc_status_tag = m_axis_write_desc_status_axis_if.req.t.data[WDS_TAG_LSB +: TAG_WIDTH];
|
||||
m_axis_write_desc_status_id = m_axis_write_desc_status_axis_if.req.t.data[WDS_ID_LSB +: AXIS_ID_WIDTH];
|
||||
m_axis_write_desc_status_dest = m_axis_write_desc_status_axis_if.req.t.data[WDS_DEST_LSB +: AXIS_DEST_WIDTH];
|
||||
m_axis_write_desc_status_user = m_axis_write_desc_status_axis_if.req.t.data[WDS_USER_LSB +: AXIS_USER_WIDTH];
|
||||
m_axis_write_desc_status_error = m_axis_write_desc_status_axis_if.req.t.data[WDS_ERROR_LSB +: 4];
|
||||
m_axis_write_desc_status_valid = m_axis_write_desc_status_axis_if.req.t.valid;
|
||||
end
|
||||
|
||||
assign m_axis_write_desc_status_axis_if.resp.ready = 1'b1;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 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)
|
||||
.DATA_W (DESC_CMD_DATA_WIDTH),
|
||||
.KEEP_W (DESC_CMD_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (1)
|
||||
) u_desc_cmd_flat_to_if (
|
||||
.s_axis_tdata (s_axis_desc_cmd_tdata),
|
||||
.s_axis_tkeep (s_axis_desc_cmd_tkeep),
|
||||
.s_axis_tstrb (s_axis_desc_cmd_tstrb),
|
||||
.s_axis_tlast (s_axis_desc_cmd_tlast),
|
||||
.s_axis_tid (s_axis_desc_cmd_tid),
|
||||
.s_axis_tdest (s_axis_desc_cmd_tdest),
|
||||
.s_axis_tuser (s_axis_desc_cmd_tuser),
|
||||
.s_axis_tvalid (s_axis_desc_cmd_tvalid),
|
||||
.s_axis_tready (s_axis_desc_cmd_tready),
|
||||
.m_axis (desc_cmd_if)
|
||||
);
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (DESC_STATUS_DATA_WIDTH),
|
||||
.KEEP_W (DESC_STATUS_KEEP_WIDTH),
|
||||
.ID_W (1),
|
||||
.DEST_W (1),
|
||||
.USER_W (DESC_STATUS_USER_WIDTH)
|
||||
) u_desc_status_if_to_flat (
|
||||
.s_axis (desc_status_if),
|
||||
.m_axis_tdata (m_axis_desc_status_tdata),
|
||||
.m_axis_tkeep (m_axis_desc_status_tkeep),
|
||||
.m_axis_tstrb (m_axis_desc_status_tstrb),
|
||||
.m_axis_tlast (m_axis_desc_status_tlast),
|
||||
.m_axis_tid (m_axis_desc_status_tid),
|
||||
.m_axis_tdest (m_axis_desc_status_tdest),
|
||||
.m_axis_tuser (m_axis_desc_status_tuser),
|
||||
.m_axis_tvalid (m_axis_desc_status_tvalid),
|
||||
.m_axis_tready (m_axis_desc_status_tready)
|
||||
);
|
||||
|
||||
// Wrapper read stream interface -> 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),
|
||||
) 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),
|
||||
@ -372,63 +254,23 @@ module tb_axi_dma_axis_compat #(
|
||||
.m_axis_tready (m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
// Wrapper AXI interface -> 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)
|
||||
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_axis_compat #(
|
||||
@ -451,25 +293,74 @@ module tb_axi_dma_axis_compat #(
|
||||
.LEN_WIDTH (LEN_WIDTH),
|
||||
.TAG_WIDTH (TAG_WIDTH),
|
||||
.ENABLE_SG (ENABLE_SG),
|
||||
.ENABLE_UNALIGNED (ENABLE_UNALIGNED)
|
||||
.ENABLE_UNALIGNED (ENABLE_UNALIGNED),
|
||||
.DESC_CMD_DATA_WIDTH (DESC_CMD_DATA_WIDTH),
|
||||
.DESC_STATUS_DATA_WIDTH (DESC_STATUS_DATA_WIDTH),
|
||||
.DESC_STATUS_USER_WIDTH (DESC_STATUS_USER_WIDTH)
|
||||
) u_dut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
.s_axis_desc_cmd (desc_cmd_if),
|
||||
.m_axis_desc_status (desc_status_if),
|
||||
.m_axis_read_data (read_data_if),
|
||||
.s_axis_write_data (write_data_if),
|
||||
.m_axi (m_axi_if),
|
||||
.read_enable (read_enable),
|
||||
.write_enable (write_enable),
|
||||
.write_abort (write_abort)
|
||||
);
|
||||
|
||||
.s_axis_read_desc (s_axis_read_desc_axis_if),
|
||||
.m_axis_read_desc_status (m_axis_read_desc_status_axis_if),
|
||||
|
||||
.m_axis_read_data (m_axis_read_data_if),
|
||||
|
||||
.s_axis_write_desc (s_axis_write_desc_axis_if),
|
||||
.m_axis_write_desc_status (m_axis_write_desc_status_axis_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)
|
||||
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
|
||||
|
||||
@ -1,33 +1,127 @@
|
||||
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 cocotb.triggers import RisingEdge, Combine
|
||||
|
||||
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"],
|
||||
)
|
||||
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"))
|
||||
|
||||
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream(
|
||||
"DescStatus",
|
||||
signals=["tag", "error", "valid"],
|
||||
optional_signals=["len", "id", "dest", "user"],
|
||||
)
|
||||
READ_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + \
|
||||
AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH
|
||||
WRITE_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH
|
||||
DESC_CMD_RAW_WIDTH = READ_DESC_WIDTH + WRITE_DESC_WIDTH
|
||||
DESC_CMD_DATA_WIDTH = ((DESC_CMD_RAW_WIDTH + 7) // 8) * 8
|
||||
DESC_CMD_BYTES = DESC_CMD_DATA_WIDTH // 8
|
||||
|
||||
READ_STATUS_WIDTH = TAG_WIDTH + 4
|
||||
WRITE_STATUS_WIDTH = LEN_WIDTH + TAG_WIDTH + \
|
||||
AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4
|
||||
DESC_STATUS_RAW_WIDTH = READ_STATUS_WIDTH + WRITE_STATUS_WIDTH
|
||||
DESC_STATUS_DATA_WIDTH = ((DESC_STATUS_RAW_WIDTH + 7) // 8) * 8
|
||||
DESC_STATUS_BYTES = DESC_STATUS_DATA_WIDTH // 8
|
||||
|
||||
RD_ADDR_LSB = 0
|
||||
RD_LEN_LSB = RD_ADDR_LSB + AXI_ADDR_WIDTH
|
||||
RD_TAG_LSB = RD_LEN_LSB + LEN_WIDTH
|
||||
RD_ID_LSB = RD_TAG_LSB + TAG_WIDTH
|
||||
RD_DEST_LSB = RD_ID_LSB + AXIS_ID_WIDTH
|
||||
RD_USER_LSB = RD_DEST_LSB + AXIS_DEST_WIDTH
|
||||
|
||||
WR_BASE_LSB = READ_DESC_WIDTH
|
||||
WR_ADDR_LSB = WR_BASE_LSB
|
||||
WR_LEN_LSB = WR_ADDR_LSB + AXI_ADDR_WIDTH
|
||||
WR_TAG_LSB = WR_LEN_LSB + LEN_WIDTH
|
||||
|
||||
RD_STS_TAG_LSB = 0
|
||||
RD_STS_ERROR_LSB = RD_STS_TAG_LSB + TAG_WIDTH
|
||||
|
||||
WR_STS_BASE_LSB = READ_STATUS_WIDTH
|
||||
WR_STS_LEN_LSB = WR_STS_BASE_LSB
|
||||
WR_STS_TAG_LSB = WR_STS_LEN_LSB + LEN_WIDTH
|
||||
WR_STS_ID_LSB = WR_STS_TAG_LSB + TAG_WIDTH
|
||||
WR_STS_DEST_LSB = WR_STS_ID_LSB + AXIS_ID_WIDTH
|
||||
WR_STS_USER_LSB = WR_STS_DEST_LSB + AXIS_DEST_WIDTH
|
||||
WR_STS_ERROR_LSB = WR_STS_USER_LSB + AXIS_USER_WIDTH
|
||||
|
||||
|
||||
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_desc_cmd(
|
||||
*,
|
||||
read_addr=0,
|
||||
read_len=0,
|
||||
read_tag=0,
|
||||
read_id=0,
|
||||
read_dest=0,
|
||||
read_user=0,
|
||||
write_addr=0,
|
||||
write_len=0,
|
||||
write_tag=0,
|
||||
):
|
||||
value = 0
|
||||
value = put(value, RD_ADDR_LSB, AXI_ADDR_WIDTH, read_addr)
|
||||
value = put(value, RD_LEN_LSB, LEN_WIDTH, read_len)
|
||||
value = put(value, RD_TAG_LSB, TAG_WIDTH, read_tag)
|
||||
value = put(value, RD_ID_LSB, AXIS_ID_WIDTH, read_id)
|
||||
value = put(value, RD_DEST_LSB, AXIS_DEST_WIDTH, read_dest)
|
||||
value = put(value, RD_USER_LSB, AXIS_USER_WIDTH, read_user)
|
||||
|
||||
value = put(value, WR_ADDR_LSB, AXI_ADDR_WIDTH, write_addr)
|
||||
value = put(value, WR_LEN_LSB, LEN_WIDTH, write_len)
|
||||
value = put(value, WR_TAG_LSB, TAG_WIDTH, write_tag)
|
||||
|
||||
return value.to_bytes(DESC_CMD_BYTES, byteorder="little")
|
||||
|
||||
|
||||
def frame_to_int(frame):
|
||||
return int.from_bytes(bytes(frame.tdata), byteorder="little")
|
||||
|
||||
|
||||
def frame_tuser(frame):
|
||||
try:
|
||||
return int(frame.tuser)
|
||||
except TypeError:
|
||||
return int(frame.tuser[0]) if frame.tuser else 0
|
||||
|
||||
|
||||
def unpack_status(frame):
|
||||
value = frame_to_int(frame)
|
||||
tuser = frame_tuser(frame)
|
||||
|
||||
return {
|
||||
"read_valid": bool(tuser & 0x1),
|
||||
"write_valid": bool(tuser & 0x2),
|
||||
"read_tag": get(value, RD_STS_TAG_LSB, TAG_WIDTH),
|
||||
"read_error": get(value, RD_STS_ERROR_LSB, 4),
|
||||
"write_len": get(value, WR_STS_LEN_LSB, LEN_WIDTH),
|
||||
"write_tag": get(value, WR_STS_TAG_LSB, TAG_WIDTH),
|
||||
"write_id": get(value, WR_STS_ID_LSB, AXIS_ID_WIDTH),
|
||||
"write_dest": get(value, WR_STS_DEST_LSB, AXIS_DEST_WIDTH),
|
||||
"write_user": get(value, WR_STS_USER_LSB, AXIS_USER_WIDTH),
|
||||
"write_error": get(value, WR_STS_ERROR_LSB, 4),
|
||||
}
|
||||
|
||||
|
||||
class TB:
|
||||
@ -38,25 +132,14 @@ class TB:
|
||||
|
||||
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
|
||||
|
||||
# Cocotb still uses the original flat Forencich descriptor/status prefixes;
|
||||
# the SV top packs/unpacks these into ordinary axis_if streams.
|
||||
self.read_desc_source = DescSource(
|
||||
DescBus.from_prefix(dut, "s_axis_read_desc"), dut.clk, dut.rst
|
||||
self.desc_cmd_source = AxiStreamSource(
|
||||
AxiStreamBus.from_prefix(dut, "s_axis_desc_cmd"), 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
|
||||
self.desc_status_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(
|
||||
dut, "m_axis_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
|
||||
)
|
||||
@ -65,7 +148,6 @@ class TB:
|
||||
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)
|
||||
|
||||
@ -73,22 +155,7 @@ class TB:
|
||||
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):
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
@ -99,264 +166,149 @@ class TB:
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
async def send_desc_cmd(self, payload):
|
||||
await self.desc_cmd_source.send(AxiStreamFrame(payload))
|
||||
|
||||
async def 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."""
|
||||
|
||||
@cocotb.test()
|
||||
async def test_axis_compat_write_path(dut):
|
||||
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)
|
||||
await tb.reset()
|
||||
|
||||
dut.write_enable.value = 1
|
||||
dut.read_enable.value = 0
|
||||
|
||||
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))
|
||||
addr = 0x1000
|
||||
tag = 0x12
|
||||
data = bytes(range(1, 33))
|
||||
|
||||
for offset in offsets:
|
||||
for diff in [-8, -2, -1, 0, 1, 2, 8]:
|
||||
if length + diff < 1:
|
||||
continue
|
||||
tb.axi_ram.write(addr - 16, b"\xaa" * (len(data) + 32))
|
||||
|
||||
tb.log.info("write: length=%d offset=%d diff=%d",
|
||||
length, offset, diff)
|
||||
cmd = pack_desc_cmd(write_addr=addr, write_len=len(data), write_tag=tag)
|
||||
|
||||
addr = offset + 0x1000
|
||||
expected_data = bytearray([x % 256 for x in range(length)])
|
||||
stream_data = bytearray(
|
||||
[x % 256 for x in range(length + diff)])
|
||||
cmd_task = cocotb.start_soon(tb.send_desc_cmd(cmd))
|
||||
data_task = cocotb.start_soon(
|
||||
tb.write_data_source.send(AxiStreamFrame(data, tid=tag))
|
||||
)
|
||||
|
||||
tb.axi_ram.write(addr - 128, b"\xaa" *
|
||||
(len(expected_data) + 256))
|
||||
await cmd_task
|
||||
await data_task
|
||||
|
||||
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_frame = await tb.desc_status_sink.recv()
|
||||
status = unpack_status(status_frame)
|
||||
|
||||
status = await tb.write_desc_status_sink.recv()
|
||||
tb.log.info("write status: %s", status)
|
||||
assert not status["read_valid"]
|
||||
assert status["write_valid"]
|
||||
assert status["write_tag"] == tag
|
||||
assert status["write_len"] == len(data)
|
||||
assert status["write_id"] == tag
|
||||
assert status["write_error"] == 0
|
||||
|
||||
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)
|
||||
assert tb.axi_ram.read(addr - 8, len(data) +
|
||||
16) == b"\xaa" * 8 + data + b"\xaa" * 8
|
||||
|
||||
|
||||
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."""
|
||||
@cocotb.test()
|
||||
async def test_axis_compat_read_path(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
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.write_enable.value = 0
|
||||
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))
|
||||
addr = 0x1100
|
||||
tag = 0x34
|
||||
data = bytes((x * 3) % 256 for x in range(48))
|
||||
|
||||
for offset in offsets:
|
||||
tb.log.info("read: length=%d offset=%d", length, offset)
|
||||
tb.axi_ram.write(addr, data)
|
||||
|
||||
addr = offset + 0x1000
|
||||
test_data = bytearray([x % 256 for x in range(length)])
|
||||
cmd = pack_desc_cmd(
|
||||
read_addr=addr,
|
||||
read_len=len(data),
|
||||
read_tag=tag,
|
||||
read_id=tag,
|
||||
read_dest=0,
|
||||
read_user=0,
|
||||
)
|
||||
|
||||
tb.axi_ram.write(addr - 128, b"\xaa" * (len(test_data) + 256))
|
||||
tb.axi_ram.write(addr, test_data)
|
||||
await tb.send_desc_cmd(cmd)
|
||||
|
||||
tb.log.debug(
|
||||
"%s",
|
||||
tb.axi_ram.hexdump_str(
|
||||
(addr & ~0xF) - 16,
|
||||
(((addr & 0xF) + length - 1) & ~0xF) + 48,
|
||||
),
|
||||
)
|
||||
data_frame = await tb.read_data_sink.recv()
|
||||
assert bytes(data_frame.tdata) == data
|
||||
assert int(data_frame.tid) == tag
|
||||
|
||||
await tb.read_desc_source.send(
|
||||
DescTransaction(addr=addr, len=len(
|
||||
test_data), tag=cur_tag, id=cur_tag)
|
||||
)
|
||||
status_frame = await tb.desc_status_sink.recv()
|
||||
status = unpack_status(status_frame)
|
||||
|
||||
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)
|
||||
assert status["read_valid"]
|
||||
assert not status["write_valid"]
|
||||
assert status["read_tag"] == tag
|
||||
assert status["read_error"] == 0
|
||||
|
||||
|
||||
def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
@cocotb.test()
|
||||
async def test_axis_compat_read_and_write_same_command(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
dut.write_enable.value = 1
|
||||
dut.read_enable.value = 1
|
||||
|
||||
# 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()
|
||||
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))
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Optional pytest entrypoint via cocotb-test.
|
||||
# Run from this directory with: pytest -q test_axi_dma_axis_compat.py
|
||||
# -----------------------------------------------------------------------------
|
||||
cmd = pack_desc_cmd(
|
||||
read_addr=read_addr,
|
||||
read_len=len(read_data),
|
||||
read_tag=read_tag,
|
||||
read_id=read_tag,
|
||||
write_addr=write_addr,
|
||||
write_len=len(write_data),
|
||||
write_tag=write_tag,
|
||||
)
|
||||
|
||||
cmd_task = cocotb.start_soon(tb.send_desc_cmd(cmd))
|
||||
data_task = cocotb.start_soon(
|
||||
tb.write_data_source.send(AxiStreamFrame(write_data, tid=write_tag))
|
||||
)
|
||||
|
||||
def _sanitize_node_name(name):
|
||||
return name.replace("[", "-").replace("]", "").replace("/", "_")
|
||||
await cmd_task
|
||||
await data_task
|
||||
|
||||
data_frame = await tb.read_data_sink.recv()
|
||||
assert bytes(data_frame.tdata) == read_data
|
||||
assert int(data_frame.tid) == read_tag
|
||||
|
||||
if pytest is not None:
|
||||
@pytest.mark.parametrize("axi_data_width", [8, 16, 32])
|
||||
@pytest.mark.parametrize("unaligned", [0, 1])
|
||||
def test_axi_dma_axis_compat_pytest(request, axi_data_width, unaligned):
|
||||
import cocotb_test.simulator
|
||||
# status might be in 2 beats, depending on timings
|
||||
seen_read = False
|
||||
seen_write = False
|
||||
|
||||
tests_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
project_root = os.path.abspath(os.path.join(tests_dir, "..", ".."))
|
||||
for _ in range(2):
|
||||
status_frame = await tb.desc_status_sink.recv()
|
||||
status = unpack_status(status_frame)
|
||||
|
||||
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"),
|
||||
)
|
||||
if status["read_valid"]:
|
||||
assert status["read_tag"] == read_tag
|
||||
assert status["read_error"] == 0
|
||||
seen_read = True
|
||||
|
||||
dut = "tb_axi_dma_axis_compat"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
if status["write_valid"]:
|
||||
assert status["write_tag"] == write_tag
|
||||
assert status["write_len"] == len(write_data)
|
||||
assert status["write_error"] == 0
|
||||
seen_write = True
|
||||
|
||||
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,
|
||||
}
|
||||
if seen_read and seen_write:
|
||||
break
|
||||
|
||||
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(wrapper_rtl_dir, "axi_dma_axis_compat.sv"),
|
||||
os.path.join(tests_dir, "tb_axi_dma_axis_compat.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,
|
||||
)
|
||||
assert seen_read
|
||||
assert seen_write
|
||||
assert tb.axi_ram.read(write_addr - 8, len(write_data) +
|
||||
16) == b"\xaa" * 8 + write_data + b"\xaa" * 8
|
||||
|
||||
Reference in New Issue
Block a user