Compare commits

..

19 Commits

Author SHA1 Message Date
Alex Forencich
32b073ade9 cndm: Fix widths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 14:02:39 -08:00
Alex Forencich
e27b5c0b94 cndm: Initial implementation of command interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 13:16:24 -08:00
Alex Forencich
0ff8e5fb9e prim: Add RAM primitives
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 22:08:14 -08:00
Alex Forencich
901606a64d dma: Use SV enums in DMA components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 20:12:47 -08:00
Alex Forencich
ee204d1665 axi: Fix width
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 18:11:55 -08:00
Alex Forencich
f8d2c26663 zircon: Fix types
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:16:04 -08:00
Alex Forencich
aee0483835 axi: Use SV enums in AXI components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:12:21 -08:00
Alex Forencich
1530f8cecf axis: Use SV enums in AXI stream components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:11:30 -08:00
Alex Forencich
450960c564 apb: Use SV enums in APB components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:11:22 -08:00
Alex Forencich
d055cb7857 xfcp: Use SV enums in XFCP
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:13:16 -08:00
Alex Forencich
b7aa9623c4 zircon: Use SV enums in zircon
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:08:57 -08:00
Alex Forencich
08f6586c2e lss: Use SV enums in low-speed serial logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:05:06 -08:00
Alex Forencich
bc0f8c0df2 stats: Use SV enums in statistics logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:57:05 -08:00
Alex Forencich
6cf03d6435 pcie: Use SV enums in PCIe logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:55:34 -08:00
Alex Forencich
1740e09a8a hip: Use SV enums in transceiver support logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:45:22 -08:00
Alex Forencich
5df2aa3cfd eth: Use SV enums in MAC logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:04:08 -08:00
Alex Forencich
8d7cdaa689 pcie: Fix parametrization issues in MSI-X modules
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 10:42:07 -08:00
Alex Forencich
a39c62f85a pcie: Add MSI-X module with APB interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 00:06:42 -08:00
Alex Forencich
896dff2fd1 pcie: Add MSI-X module with AXI lite interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 00:06:20 -08:00
94 changed files with 4948 additions and 976 deletions

View File

@@ -183,6 +183,8 @@ The Taxi transport library contains many smaller components that can be composed
* PCIe AXI lite master
* PCIe AXI lite master for Xilinx UltraScale
* MSI shim for Xilinx UltraScale
* MSI-X with AXI lite control interface
* MSI-X with APB control interface
* Primitives
* Arbiter
* Priority encoder

View File

@@ -93,11 +93,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [S_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -232,11 +233,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -91,11 +91,12 @@ if (m_axil_wr.DATA_W != m_axil_rd.DATA_W)
if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
// same width; translate
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -243,11 +244,12 @@ if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -406,11 +408,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -115,13 +115,14 @@ end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_READ = 2'd2,
STATE_DATA_SPLIT = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_READ,
STATE_DATA_SPLIT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -480,11 +481,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -122,13 +122,14 @@ end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_2 = 2'd2,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_2,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -505,13 +506,14 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_2 = 2'd2,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_2,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -89,11 +89,12 @@ if (AXIL_BYTE_LANES == AXI_BYTE_LANES) begin : translate
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -251,13 +252,14 @@ end else if (AXIL_BYTE_LANES > AXI_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_READ = 2'd2,
STATE_DATA_SPLIT = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_READ,
STATE_DATA_SPLIT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -483,11 +485,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -91,12 +91,13 @@ if (AXIL_BYTE_LANES == AXI_BYTE_LANES) begin : translate
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_RESP = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -295,13 +296,14 @@ end else if (AXIL_BYTE_LANES > AXI_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_2 = 2'd2,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_2,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -547,13 +549,14 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_DATA_2 = 2'd2,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_DATA_2,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -213,11 +213,12 @@ initial begin
end
end
localparam logic [0:0]
STATE_IDLE = 1'd0,
STATE_DECODE = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DECODE
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axi_aready_reg = 1'b0, s_axi_aready_next;

View File

@@ -100,11 +100,12 @@ if (FIFO_DELAY) begin
localparam COUNT_W = (FIFO_AW > 8 ? FIFO_AW : 8) + 1;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_WAIT = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_WAIT
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [COUNT_W-1:0] count_reg = 0, count_next;

View File

@@ -99,12 +99,13 @@ if (WUSER_EN) assign s_axi_w[WUSER_OFFSET +: WUSER_W] = s_axi_wr.wuser;
if (FIFO_DELAY) begin
// store AW channel value until W channel burst is stored in FIFO or FIFO is full
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_TRANSFER_IN = 2'd1,
STATE_TRANSFER_OUT = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_TRANSFER_IN,
STATE_TRANSFER_OUT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic hold_reg = 1'b1, hold_next;
logic [8:0] count_reg = 9'd0, count_next;

View File

@@ -182,14 +182,15 @@ initial begin
end
end
localparam logic [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1,
STATE_READ = 3'd2,
STATE_READ_DROP = 3'd3,
STATE_WAIT_IDLE = 3'd4;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_DECODE,
STATE_READ,
STATE_READ_DROP,
STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic match;

View File

@@ -186,15 +186,16 @@ initial begin
end
end
localparam logic [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1,
STATE_WRITE = 3'd2,
STATE_WRITE_RESP = 3'd3,
STATE_WRITE_DROP = 3'd4,
STATE_WAIT_IDLE = 3'd5;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_DECODE,
STATE_WRITE,
STATE_WRITE_RESP,
STATE_WRITE_DROP,
STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic match;

View File

@@ -56,18 +56,20 @@ if (s_axi_wr.DATA_W != s_axi_rd.DATA_W)
if (s_axi_wr.ADDR_W < ADDR_W || s_axi_rd.ADDR_W < ADDR_W)
$fatal(0, "Error: AXI address width is insufficient (instance %m)");
localparam [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_BURST = 1'd1;
typedef enum logic [0:0] {
READ_STATE_IDLE,
READ_STATE_BURST
} read_state_t;
logic [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam [1:0]
WRITE_STATE_IDLE = 2'd0,
WRITE_STATE_BURST = 2'd1,
WRITE_STATE_RESP = 2'd2;
typedef enum logic [1:0] {
WRITE_STATE_IDLE,
WRITE_STATE_BURST,
WRITE_STATE_RESP
} write_state_t;
logic [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next;
write_state_t write_state_reg = WRITE_STATE_IDLE, write_state_next;
logic mem_wr_en;
logic mem_rd_en;

View File

@@ -86,11 +86,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [S_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
@@ -203,11 +204,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next;

View File

@@ -93,11 +93,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
@@ -220,12 +221,13 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -96,11 +96,12 @@ localparam [1:0]
if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate
// same width; translate
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next;
@@ -294,11 +295,12 @@ if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate
end else if (APB_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next;
@@ -503,11 +505,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next;

View File

@@ -95,11 +95,12 @@ if (AXI_BYTE_LANES == AXIL_BYTE_LANES) begin : bypass
end else if (AXI_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
@@ -220,11 +221,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next;

View File

@@ -103,11 +103,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
@@ -239,12 +240,13 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_RESP = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DATA,
STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -189,11 +189,12 @@ initial begin
end
end
localparam logic [0:0]
STATE_IDLE = 1'd0,
STATE_DECODE = 1'd1;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DECODE
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic s_axil_aready_reg = 1'b0, s_axil_aready_next;

View File

@@ -177,13 +177,14 @@ initial begin
end
end
localparam logic [1:0]
STATE_IDLE = 2'd0,
STATE_DECODE = 2'd1,
STATE_READ = 2'd2,
STATE_WAIT_IDLE = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_DECODE,
STATE_READ,
STATE_WAIT_IDLE
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic match;

View File

@@ -179,15 +179,16 @@ initial begin
end
end
localparam logic [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1,
STATE_WRITE = 3'd2,
STATE_WRITE_RESP = 3'd3,
STATE_WRITE_DROP = 3'd4,
STATE_WAIT_IDLE = 3'd5;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_DECODE,
STATE_WRITE,
STATE_WRITE_RESP,
STATE_WRITE_DROP,
STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic match;

View File

@@ -36,12 +36,13 @@ if (m_axis.DATA_W != 8 || s_axis.DATA_W != 8)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_SEGMENT = 2'd1,
STATE_NEXT_SEGMENT = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_SEGMENT,
STATE_NEXT_SEGMENT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = 8'd0, count_next;
logic suppress_zero_reg = 1'b0, suppress_zero_next;

View File

@@ -40,19 +40,21 @@ if (m_axis.DATA_W != 8 || s_axis.DATA_W != 8)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register
localparam [1:0]
INPUT_STATE_IDLE = 2'd0,
INPUT_STATE_SEGMENT = 2'd1,
INPUT_STATE_FINAL_ZERO = 2'd2,
INPUT_STATE_APPEND_ZERO = 2'd3;
typedef enum logic [1:0] {
INPUT_STATE_IDLE,
INPUT_STATE_SEGMENT,
INPUT_STATE_FINAL_ZERO,
INPUT_STATE_APPEND_ZERO
} input_state_t;
logic [1:0] input_state_reg = INPUT_STATE_IDLE, input_state_next;
input_state_t input_state_reg = INPUT_STATE_IDLE, input_state_next;
localparam [0:0]
OUTPUT_STATE_IDLE = 1'd0,
OUTPUT_STATE_SEGMENT = 1'd1;
typedef enum logic [0:0] {
OUTPUT_STATE_IDLE,
OUTPUT_STATE_SEGMENT
} output_state_t;
logic [0:0] output_state_reg = OUTPUT_STATE_IDLE, output_state_next;
output_state_t output_state_reg = OUTPUT_STATE_IDLE, output_state_next;
logic [7:0] input_count_reg = 8'd0, input_count_next;
logic [7:0] output_count_reg = 8'd0, output_count_next;

View File

@@ -7,6 +7,7 @@ obj-m += cndm.o
cndm-y += cndm_main.o
cndm-y += cndm_devlink.o
cndm-y += cndm_irq.o
cndm-y += cndm_cmd.o
cndm-y += cndm_dev.o
cndm-y += cndm_netdev.o
cndm-y += cndm_ethtool.o

View File

@@ -20,6 +20,8 @@ Authors:
#include <linux/ptp_clock_kernel.h>
#include <net/devlink.h>
#include "cndm_hw.h"
#define DRIVER_VERSION "0.1"
#define CNDM_MAX_IRQ 256
@@ -105,6 +107,7 @@ struct cndm_priv {
u32 txq_mask;
u32 txq_prod;
u32 txq_cons;
u32 txq_db_offs;
size_t rxq_region_len;
void *rxq_region;
@@ -115,6 +118,7 @@ struct cndm_priv {
u32 rxq_mask;
u32 rxq_prod;
u32 rxq_cons;
u32 rxq_db_offs;
size_t txcq_region_len;
void *txcq_region;
@@ -137,20 +141,9 @@ struct cndm_priv {
u32 rxcq_cons;
};
struct cndm_desc {
__u8 rsvd[4];
__le32 len;
__le64 addr;
};
struct cndm_cpl {
__u8 rsvd[4];
__le32 len;
__le32 ts_ns;
__le16 ts_fns;
__u8 ts_s;
__u8 phase;
};
// cndm_cmd.c
int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp);
int cndm_exec_cmd(struct cndm_dev *cdev, void *cmd, void *rsp);
// cndm_devlink.c
struct devlink *cndm_devlink_alloc(struct device *dev);
@@ -161,7 +154,7 @@ int cndm_irq_init_pcie(struct cndm_dev *cdev);
void cndm_irq_deinit_pcie(struct cndm_dev *cdev);
// cndm_netdev.c
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __iomem *hw_addr);
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port);
void cndm_destroy_netdev(struct net_device *ndev);
// cndm_dev.c

View File

@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
#include "cndm.h"
int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp)
{
int k;
if (!cmd || !rsp)
return -EINVAL;
// write command to mailbox
for (k = 0; k < 16; k++) {
iowrite32(*((u32 *)(cmd + k*4)), cdev->hw_addr + 0x10000 + k*4);
}
// execute it
iowrite32(0x00000001, cdev->hw_addr + 0x0200);
// wait for completion
for (k = 0; k < 10; k++) {
if ((ioread32(cdev->hw_addr + 0x0200) & 0x00000001) == 0) {
break;
}
udelay(100);
}
// read response from mailbox
for (k = 0; k < 16; k++) {
*((u32 *)(rsp + k*4)) = ioread32(cdev->hw_addr + 0x10000 + 0x40 + k*4);
}
return 0;
}
int cndm_exec_cmd(struct cndm_dev *cdev, void *cmd, void *rsp)
{
return cndm_exec_mbox_cmd(cdev, cmd, rsp);
}

View File

@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL */
/*
Copyright (c) 2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
#ifndef CNDM_HW_H
#define CNDM_HW_H
#include <linux/types.h>
#define CNDM_CMD_OP_NOP 0x0000
#define CNDM_CMD_OP_CREATE_EQ 0x0200
#define CNDM_CMD_OP_MODIFY_EQ 0x0201
#define CNDM_CMD_OP_QUERY_EQ 0x0202
#define CNDM_CMD_OP_DESTROY_EQ 0x0203
#define CNDM_CMD_OP_CREATE_CQ 0x0210
#define CNDM_CMD_OP_MODIFY_CQ 0x0211
#define CNDM_CMD_OP_QUERY_CQ 0x0212
#define CNDM_CMD_OP_DESTROY_CQ 0x0213
#define CNDM_CMD_OP_CREATE_SQ 0x0220
#define CNDM_CMD_OP_MODIFY_SQ 0x0221
#define CNDM_CMD_OP_QUERY_SQ 0x0222
#define CNDM_CMD_OP_DESTROY_SQ 0x0223
#define CNDM_CMD_OP_CREATE_RQ 0x0230
#define CNDM_CMD_OP_MODIFY_RQ 0x0231
#define CNDM_CMD_OP_QUERY_RQ 0x0232
#define CNDM_CMD_OP_DESTROY_RQ 0x0233
#define CNDM_CMD_OP_CREATE_QP 0x0240
#define CNDM_CMD_OP_MODIFY_QP 0x0241
#define CNDM_CMD_OP_QUERY_QP 0x0242
#define CNDM_CMD_OP_DESTROY_QP 0x0243
struct cndm_cmd {
__le16 rsvd;
union {
__le16 opcode;
__le16 status;
};
__le32 flags;
__le32 port;
__le32 qn;
__le32 qn2;
__le32 pd;
__le32 size;
__le32 dboffs;
__le64 ptr1;
__le64 ptr2;
__le32 dw12;
__le32 dw13;
__le32 dw14;
__le32 dw15;
};
struct cndm_desc {
__le16 rsvd0;
union {
struct {
__le16 csum_cmd;
} tx;
struct {
__le16 rsvd0;
} rx;
};
__le32 len;
__le64 addr;
};
struct cndm_cpl {
__u8 rsvd[4];
__le32 len;
__le32 ts_ns;
__le16 ts_fns;
__u8 ts_s;
__u8 phase;
};
struct cndm_event {
__le16 type;
__le16 source;
__le32 rsvd0;
__le32 rsvd1;
__le32 rsvd2;
__le32 rsvd3;
__le32 rsvd4;
__le32 rsvd5;
__le32 phase;
};
#endif

View File

@@ -9,6 +9,7 @@ Authors:
*/
#include "cndm.h"
#include "cndm_hw.h"
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/version.h>
@@ -68,7 +69,7 @@ static int cndm_common_probe(struct cndm_dev *cdev)
for (k = 0; k < cdev->port_count; k++) {
struct net_device *ndev;
ndev = cndm_create_netdev(cdev, k, cdev->hw_addr + cdev->port_offset + (cdev->port_stride*k));
ndev = cndm_create_netdev(cdev, k);
if (IS_ERR_OR_NULL(ndev)) {
ret = PTR_ERR(ndev);
goto fail_netdev;

View File

@@ -9,6 +9,7 @@ Authors:
*/
#include "cndm.h"
#include "cndm_hw.h"
#include <linux/version.h>
@@ -170,13 +171,16 @@ static int cndm_netdev_irq(struct notifier_block *nb, unsigned long action, void
return NOTIFY_DONE;
}
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __iomem *hw_addr)
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
{
struct device *dev = cdev->dev;
struct net_device *ndev;
struct cndm_priv *priv;
int ret = 0;
struct cndm_cmd cmd;
struct cndm_cmd rsp;
ndev = alloc_etherdev_mqs(sizeof(*priv), 1, 1);
if (!ndev) {
dev_err(dev, "Failed to allocate net_device");
@@ -193,7 +197,7 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __io
priv->ndev = ndev;
priv->cdev = cdev;
priv->hw_addr = hw_addr;
priv->hw_addr = cdev->hw_addr;
netif_set_real_num_tx_queues(ndev, 1);
netif_set_real_num_rx_queues(ndev, 1);
@@ -281,27 +285,61 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __io
goto fail;
}
iowrite32(0x00000000, priv->hw_addr + 0x200);
iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + 0x204);
iowrite32(priv->rxq_region_addr & 0xffffffff, priv->hw_addr + 0x208);
iowrite32(priv->rxq_region_addr >> 32, priv->hw_addr + 0x20c);
iowrite32(0x00000001 | (priv->rxq_log_size << 16), priv->hw_addr + 0x200);
cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
cmd.flags = 0x00000000;
cmd.port = port;
cmd.qn = 0;
cmd.qn2 = 0;
cmd.pd = 0;
cmd.size = priv->rxcq_log_size;
cmd.dboffs = 0;
cmd.ptr1 = priv->rxcq_region_addr;
cmd.ptr2 = 0;
iowrite32(0x00000000, priv->hw_addr + 0x100);
iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + 0x104);
iowrite32(priv->txq_region_addr & 0xffffffff, priv->hw_addr + 0x108);
iowrite32(priv->txq_region_addr >> 32, priv->hw_addr + 0x10c);
iowrite32(0x00000001 | (priv->txq_log_size << 16), priv->hw_addr + 0x100);
cndm_exec_cmd(cdev, &cmd, &rsp);
iowrite32(0x00000000, priv->hw_addr + 0x400);
iowrite32(priv->rxcq_region_addr & 0xffffffff, priv->hw_addr + 0x408);
iowrite32(priv->rxcq_region_addr >> 32, priv->hw_addr + 0x40c);
iowrite32(0x00000001 | (priv->rxcq_log_size << 16), priv->hw_addr + 0x400);
cmd.opcode = CNDM_CMD_OP_CREATE_RQ;
cmd.flags = 0x00000000;
cmd.port = port;
cmd.qn = 0;
cmd.qn2 = 0;
cmd.pd = 0;
cmd.size = priv->rxq_log_size;
cmd.dboffs = 0;
cmd.ptr1 = priv->rxq_region_addr;
cmd.ptr2 = 0;
iowrite32(0x00000000, priv->hw_addr + 0x300);
iowrite32(priv->txcq_region_addr & 0xffffffff, priv->hw_addr + 0x308);
iowrite32(priv->txcq_region_addr >> 32, priv->hw_addr + 0x30c);
iowrite32(0x00000001 | (priv->txcq_log_size << 16), priv->hw_addr + 0x300);
cndm_exec_cmd(cdev, &cmd, &rsp);
priv->rxq_db_offs = rsp.dboffs;
cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
cmd.flags = 0x00000000;
cmd.port = port;
cmd.qn = 1;
cmd.qn2 = 0;
cmd.pd = 0;
cmd.size = priv->txcq_log_size;
cmd.dboffs = 0;
cmd.ptr1 = priv->txcq_region_addr;
cmd.ptr2 = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
cmd.opcode = CNDM_CMD_OP_CREATE_SQ;
cmd.flags = 0x00000000;
cmd.port = port;
cmd.qn = 0;
cmd.qn2 = 0;
cmd.pd = 0;
cmd.size = priv->txq_log_size;
cmd.dboffs = 0;
cmd.ptr1 = priv->txq_region_addr;
cmd.ptr2 = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
priv->txq_db_offs = rsp.dboffs;
netif_carrier_off(ndev);
@@ -332,12 +370,41 @@ fail:
void cndm_destroy_netdev(struct net_device *ndev)
{
struct cndm_priv *priv = netdev_priv(ndev);
struct cndm_dev *cdev = priv->cdev;
struct device *dev = priv->dev;
iowrite32(0x00000000, priv->hw_addr + 0x200);
iowrite32(0x00000000, priv->hw_addr + 0x100);
iowrite32(0x00000000, priv->hw_addr + 0x400);
iowrite32(0x00000000, priv->hw_addr + 0x300);
struct cndm_cmd cmd;
struct cndm_cmd rsp;
cmd.opcode = CNDM_CMD_OP_DESTROY_CQ;
cmd.flags = 0x00000000;
cmd.port = ndev->dev_port;
cmd.qn = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
cmd.opcode = CNDM_CMD_OP_DESTROY_RQ;
cmd.flags = 0x00000000;
cmd.port = ndev->dev_port;
cmd.qn = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
priv->rxq_db_offs = rsp.dboffs;
cmd.opcode = CNDM_CMD_OP_DESTROY_CQ;
cmd.flags = 0x00000000;
cmd.port = ndev->dev_port;
cmd.qn = 1;
cndm_exec_cmd(cdev, &cmd, &rsp);
cmd.opcode = CNDM_CMD_OP_DESTROY_SQ;
cmd.flags = 0x00000000;
cmd.port = ndev->dev_port;
cmd.qn = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
if (priv->irq)
atomic_notifier_chain_unregister(&priv->irq->nh, &priv->irq_nb);

View File

@@ -148,12 +148,12 @@ void cndm_register_phc(struct cndm_dev *cdev)
}
// TODO
if (cdev->port_offset == 0x10000) {
if (cdev->port_offset == 0x20000) {
dev_info(cdev->dev, "PTP clock not present");
return;
}
cdev->phc_regs = cdev->hw_addr + 0x10000; // TODO
cdev->phc_regs = cdev->hw_addr + 0x20000; // TODO
cdev->ptp_clock_info.owner = THIS_MODULE;
snprintf(cdev->ptp_clock_info.name, sizeof(cdev->ptp_clock_info.name), "%s_phc", cdev->name);

View File

@@ -92,7 +92,7 @@ int cndm_refill_rx_buffers(struct cndm_priv *priv)
}
dma_wmb();
iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + 0x204);
iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + priv->rxq_db_offs);
return ret;
}

View File

@@ -170,7 +170,7 @@ int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
dma_wmb();
iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + 0x104);
iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + priv->txq_db_offs);
return NETDEV_TX_OK;

View File

@@ -0,0 +1,265 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Command mailbox
*/
module cndm_micro_cmd_mbox
(
input wire logic clk,
input wire logic rst,
/*
* AXI lite interface
*/
taxi_axil_if.wr_slv s_axil_wr,
taxi_axil_if.rd_slv s_axil_rd,
/*
* Control
*/
input wire logic start,
output wire logic busy,
/*
* Command interface
*/
taxi_axis_if.src m_axis_cmd,
taxi_axis_if.snk s_axis_rsp
);
localparam ADDR_W = 7;
// extract parameters
localparam DATA_W = s_axil_wr.DATA_W;
localparam STRB_W = s_axil_wr.STRB_W;
localparam VALID_ADDR_W = ADDR_W - $clog2(STRB_W);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: AXI data width not evenly divisible (instance %m)");
if (2**$clog2(BYTE_LANES) != BYTE_LANES)
$fatal(0, "Error: AXI word width must be even power of two (instance %m)");
if (s_axil_rd.DATA_W != DATA_W)
$fatal(0, "Error: AXI interface configuration mismatch (instance %m)");
if (s_axil_wr.ADDR_W < ADDR_W || s_axil_wr.ADDR_W < ADDR_W)
$fatal(0, "Error: AXI address width is insufficient (instance %m)");
logic read_eligible;
logic write_eligible;
logic axil_mem_wr_en;
logic axil_mem_rd_en;
logic [4:0] axil_mem_addr;
logic cmd_mem_wr_en;
logic cmd_mem_rd_en;
logic [4:0] cmd_mem_addr;
logic last_read_reg = 1'b0, last_read_next;
logic [3:0] rd_ptr_reg = '0, rd_ptr_next;
logic [3:0] wr_ptr_reg = '0, wr_ptr_next;
logic busy_reg = 1'b0, busy_next;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
logic s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
// logic [DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
logic s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next;
// logic [31:0] m_axis_cmd_tdata_reg = '0;
logic m_axis_cmd_tvalid_reg = 1'b0, m_axis_cmd_tvalid_next;
logic m_axis_cmd_tlast_reg = 1'b0, m_axis_cmd_tlast_next;
logic s_axis_rsp_tready_reg = 1'b0, s_axis_rsp_tready_next;
wire [VALID_ADDR_W-1:0] s_axil_awaddr_valid = VALID_ADDR_W'(s_axil_wr.awaddr >> (ADDR_W - VALID_ADDR_W));
wire [VALID_ADDR_W-1:0] s_axil_araddr_valid = VALID_ADDR_W'(s_axil_rd.araddr >> (ADDR_W - VALID_ADDR_W));
assign s_axil_wr.awready = s_axil_awready_reg;
assign s_axil_wr.wready = s_axil_wready_reg;
assign s_axil_wr.bresp = 2'b00;
assign s_axil_wr.buser = '0;
assign s_axil_wr.bvalid = s_axil_bvalid_reg;
assign s_axil_rd.arready = s_axil_arready_reg;
// assign s_axil_rd.rdata = s_axil_rdata_reg;
assign s_axil_rd.rresp = 2'b00;
assign s_axil_rd.ruser = '0;
assign s_axil_rd.rvalid = s_axil_rvalid_reg;
// assign m_axis_cmd.tdata = m_axis_cmd_tdata_reg;
assign m_axis_cmd.tkeep = '1;
assign m_axis_cmd.tstrb = m_axis_cmd.tkeep;
assign m_axis_cmd.tvalid = m_axis_cmd_tvalid_reg;
assign m_axis_cmd.tlast = m_axis_cmd_tlast_reg;
assign m_axis_cmd.tid = '0;
assign m_axis_cmd.tdest = '0;
assign m_axis_cmd.tuser = '0;
assign s_axis_rsp.tready = s_axis_rsp_tready_reg;
assign busy = busy_reg;
taxi_ram_2rw_1c #(
.ADDR_W(5),
.DATA_W(32),
.STRB_EN(1'b1),
.STRB_W(4)
)
ram_inst (
.clk(clk),
.a_en(axil_mem_wr_en || axil_mem_rd_en),
.a_addr(axil_mem_addr),
.a_wr_en(axil_mem_wr_en),
.a_wr_data(s_axil_wr.wdata),
.a_wr_strb(s_axil_wr.wstrb),
.a_rd_data(s_axil_rd.rdata),
.b_en(cmd_mem_wr_en || cmd_mem_rd_en),
.b_addr(cmd_mem_addr),
.b_wr_en(cmd_mem_wr_en),
.b_wr_data(s_axis_rsp.tdata),
.b_wr_strb('1),
.b_rd_data(m_axis_cmd.tdata)
);
// Register interface
always_comb begin
axil_mem_wr_en = 1'b0;
axil_mem_rd_en = 1'b0;
axil_mem_addr = s_axil_araddr_valid;
last_read_next = last_read_reg;
s_axil_awready_next = 1'b0;
s_axil_wready_next = 1'b0;
s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_wr.bready;
s_axil_arready_next = 1'b0;
s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rd.rready;
write_eligible = s_axil_wr.awvalid && s_axil_wr.wvalid && (!s_axil_wr.bvalid || s_axil_wr.bready) && (!s_axil_wr.awready && !s_axil_wr.wready);
read_eligible = s_axil_rd.arvalid && (!s_axil_rd.rvalid || s_axil_rd.rready) && (!s_axil_rd.arready);
if (write_eligible && (!read_eligible || last_read_reg)) begin
last_read_next = 1'b0;
s_axil_awready_next = 1'b1;
s_axil_wready_next = 1'b1;
s_axil_bvalid_next = 1'b1;
axil_mem_wr_en = 1'b1;
axil_mem_addr = s_axil_awaddr_valid;
end else if (read_eligible) begin
last_read_next = 1'b1;
s_axil_arready_next = 1'b1;
s_axil_rvalid_next = 1'b1;
axil_mem_rd_en = 1'b1;
axil_mem_addr = s_axil_araddr_valid;
end
end
always_ff @(posedge clk) begin
last_read_reg <= last_read_next;
s_axil_awready_reg <= s_axil_awready_next;
s_axil_wready_reg <= s_axil_wready_next;
s_axil_bvalid_reg <= s_axil_bvalid_next;
s_axil_arready_reg <= s_axil_arready_next;
s_axil_rvalid_reg <= s_axil_rvalid_next;
if (rst) begin
last_read_reg <= 1'b0;
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= 1'b0;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= 1'b0;
end
end
// Command interface
always_comb begin
cmd_mem_rd_en = 1'b0;
cmd_mem_wr_en = 1'b0;
cmd_mem_addr = {1'b0, rd_ptr_reg};
rd_ptr_next = rd_ptr_reg;
wr_ptr_next = wr_ptr_reg;
busy_next = busy_reg;
m_axis_cmd_tvalid_next = m_axis_cmd_tvalid_reg && !m_axis_cmd.tready;
m_axis_cmd_tlast_next = m_axis_cmd_tlast_reg;
s_axis_rsp_tready_next = 1'b0;
if ((!m_axis_cmd_tvalid_reg || m_axis_cmd.tready) && (rd_ptr_reg != 0 || start)) begin
cmd_mem_rd_en = 1'b1;
cmd_mem_addr = {1'b0, rd_ptr_reg};
m_axis_cmd_tvalid_next = 1'b1;
m_axis_cmd_tlast_next = &rd_ptr_reg;
rd_ptr_next = rd_ptr_reg + 1;
busy_next = 1'b1;
end else if (s_axis_rsp.tvalid && !s_axis_rsp_tready_reg) begin
cmd_mem_wr_en = 1'b1;
cmd_mem_addr = {1'b1, wr_ptr_reg};
s_axis_rsp_tready_next = 1'b1;
if (s_axis_rsp.tlast) begin
wr_ptr_next = '0;
busy_next = 1'b0;
end else begin
wr_ptr_next = wr_ptr_reg + 1;
end
end
end
always_ff @(posedge clk) begin
rd_ptr_reg <= rd_ptr_next;
wr_ptr_reg <= wr_ptr_next;
busy_reg <= busy_next;
m_axis_cmd_tvalid_reg <= m_axis_cmd_tvalid_next;
m_axis_cmd_tlast_reg <= m_axis_cmd_tlast_next;
s_axis_rsp_tready_reg <= s_axis_rsp_tready_next;
if (rst) begin
rd_ptr_reg <= '0;
wr_ptr_reg <= '0;
busy_reg <= 1'b0;
m_axis_cmd_tvalid_reg <= 1'b0;
s_axis_rsp_tready_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -1,13 +1,18 @@
cndm_micro_core.sv
cndm_micro_cmd_mbox.sv
cndm_micro_dp_mgr.sv
cndm_micro_port.sv
cndm_micro_rx.sv
cndm_micro_tx.sv
cndm_micro_desc_rd.sv
cndm_micro_cpl_wr.sv
../lib/taxi/src/prim/rtl/taxi_ram_2rw_1c.sv
../lib/taxi/src/dma/rtl/taxi_dma_client_axis_source.sv
../lib/taxi/src/dma/rtl/taxi_dma_client_axis_sink.sv
../lib/taxi/src/dma/rtl/taxi_dma_if_mux.f
../lib/taxi/src/dma/rtl/taxi_dma_psdpram.sv
../lib/taxi/src/apb/rtl/taxi_apb_if.sv
../lib/taxi/src/apb/rtl/taxi_apb_interconnect.sv
../lib/taxi/src/axi/rtl/taxi_axil_interconnect_1s.f
../lib/taxi/src/axis/rtl/taxi_axis_async_fifo.f
../lib/taxi/src/axis/rtl/taxi_axis_arb_mux.f

View File

@@ -49,8 +49,8 @@ module cndm_micro_core #(
/*
* Control register interface
*/
taxi_axil_if.wr_slv s_axil_wr,
taxi_axil_if.rd_slv s_axil_rd,
taxi_axil_if.wr_slv s_axil_ctrl_wr,
taxi_axil_if.rd_slv s_axil_ctrl_rd,
/*
* DMA
@@ -97,8 +97,8 @@ module cndm_micro_core #(
localparam CL_PORTS = $clog2(PORTS);
localparam AXIL_ADDR_W = s_axil_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_wr.DATA_W;
localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
localparam RAM_SEGS = dma_ram_wr.SEGS;
localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W;
@@ -106,32 +106,33 @@ localparam RAM_SEG_DATA_W = dma_ram_wr.SEG_DATA_W;
localparam RAM_SEG_BE_W = dma_ram_wr.SEG_BE_W;
localparam RAM_SEL_W = dma_ram_wr.SEL_W;
localparam PORT_OFFSET = PTP_TS_EN ? 2 : 1;
localparam PORT_OFFSET = PTP_TS_EN ? 3 : 2;
localparam PORT_BASE_ADDR = PTP_TS_EN ? 32'h00030000 : 32'h00020000;
taxi_axil_if #(
.DATA_W(s_axil_wr.DATA_W),
.DATA_W(s_axil_ctrl_wr.DATA_W),
.ADDR_W(16),
.STRB_W(s_axil_wr.STRB_W),
.AWUSER_EN(s_axil_wr.AWUSER_EN),
.AWUSER_W(s_axil_wr.AWUSER_W),
.WUSER_EN(s_axil_wr.WUSER_EN),
.WUSER_W(s_axil_wr.WUSER_W),
.BUSER_EN(s_axil_wr.BUSER_EN),
.BUSER_W(s_axil_wr.BUSER_W),
.ARUSER_EN(s_axil_wr.ARUSER_EN),
.ARUSER_W(s_axil_wr.ARUSER_W),
.RUSER_EN(s_axil_wr.RUSER_EN),
.RUSER_W(s_axil_wr.RUSER_W)
.STRB_W(s_axil_ctrl_wr.STRB_W),
.AWUSER_EN(s_axil_ctrl_wr.AWUSER_EN),
.AWUSER_W(s_axil_ctrl_wr.AWUSER_W),
.WUSER_EN(s_axil_ctrl_wr.WUSER_EN),
.WUSER_W(s_axil_ctrl_wr.WUSER_W),
.BUSER_EN(s_axil_ctrl_wr.BUSER_EN),
.BUSER_W(s_axil_ctrl_wr.BUSER_W),
.ARUSER_EN(s_axil_ctrl_wr.ARUSER_EN),
.ARUSER_W(s_axil_ctrl_wr.ARUSER_W),
.RUSER_EN(s_axil_ctrl_wr.RUSER_EN),
.RUSER_W(s_axil_ctrl_wr.RUSER_W)
)
s_axil_ctrl[PORTS+PORT_OFFSET]();
axil_ctrl[PORTS+PORT_OFFSET]();
taxi_axil_interconnect_1s #(
.M_COUNT($size(s_axil_ctrl)),
.ADDR_W(s_axil_wr.ADDR_W),
.M_COUNT($size(axil_ctrl)),
.ADDR_W(s_axil_ctrl_wr.ADDR_W),
.M_REGIONS(1),
.M_BASE_ADDR('0),
.M_ADDR_W({$size(s_axil_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(s_axil_ctrl){1'b0}})
.M_ADDR_W({$size(axil_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(axil_ctrl){1'b0}})
)
port_intercon_inst (
.clk(clk),
@@ -140,14 +141,14 @@ port_intercon_inst (
/*
* AXI4-lite slave interface
*/
.s_axil_wr(s_axil_wr),
.s_axil_rd(s_axil_rd),
.s_axil_wr(s_axil_ctrl_wr),
.s_axil_rd(s_axil_ctrl_rd),
/*
* AXI4-lite master interfaces
*/
.m_axil_wr(s_axil_ctrl),
.m_axil_rd(s_axil_ctrl)
.m_axil_wr(axil_ctrl),
.m_axil_rd(axil_ctrl)
);
logic s_axil_awready_reg = 1'b0;
@@ -158,53 +159,64 @@ logic s_axil_arready_reg = 1'b0;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0;
logic s_axil_rvalid_reg = 1'b0;
assign s_axil_ctrl[0].awready = s_axil_awready_reg;
assign s_axil_ctrl[0].wready = s_axil_wready_reg;
assign s_axil_ctrl[0].bresp = '0;
assign s_axil_ctrl[0].buser = '0;
assign s_axil_ctrl[0].bvalid = s_axil_bvalid_reg;
assign axil_ctrl[0].awready = s_axil_awready_reg;
assign axil_ctrl[0].wready = s_axil_wready_reg;
assign axil_ctrl[0].bresp = '0;
assign axil_ctrl[0].buser = '0;
assign axil_ctrl[0].bvalid = s_axil_bvalid_reg;
assign s_axil_ctrl[0].arready = s_axil_arready_reg;
assign s_axil_ctrl[0].rdata = s_axil_rdata_reg;
assign s_axil_ctrl[0].rresp = '0;
assign s_axil_ctrl[0].ruser = '0;
assign s_axil_ctrl[0].rvalid = s_axil_rvalid_reg;
assign axil_ctrl[0].arready = s_axil_arready_reg;
assign axil_ctrl[0].rdata = s_axil_rdata_reg;
assign axil_ctrl[0].rresp = '0;
assign axil_ctrl[0].ruser = '0;
assign axil_ctrl[0].rvalid = s_axil_rvalid_reg;
logic cmd_mbox_start_reg = 1'b0;
wire cmd_mbox_busy;
always_ff @(posedge clk) begin
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= s_axil_bvalid_reg && !s_axil_ctrl[0].bready;
s_axil_bvalid_reg <= s_axil_bvalid_reg && !axil_ctrl[0].bready;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= s_axil_rvalid_reg && !s_axil_ctrl[0].rready;
s_axil_rvalid_reg <= s_axil_rvalid_reg && !axil_ctrl[0].rready;
if (s_axil_ctrl[0].awvalid && s_axil_ctrl[0].wvalid && !s_axil_bvalid_reg) begin
cmd_mbox_start_reg <= 1'b0;
if (axil_ctrl[0].awvalid && axil_ctrl[0].wvalid && !s_axil_bvalid_reg) begin
s_axil_awready_reg <= 1'b1;
s_axil_wready_reg <= 1'b1;
s_axil_bvalid_reg <= 1'b1;
case ({s_axil_ctrl[0].awaddr[15:2], 2'b00})
case ({axil_ctrl[0].awaddr[15:2], 2'b00})
// 16'h0100: begin
// txq_en_reg <= s_axil_ctrl[0].wdata[0];
// txq_size_reg <= s_axil_ctrl[0].wdata[19:16];
// txq_en_reg <= axil_ctrl[0].wdata[0];
// txq_size_reg <= axil_ctrl[0].wdata[19:16];
// end
// 16'h0104: txq_prod_reg <= s_axil_ctrl[0].wdata[15:0];
// 16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl[0].wdata;
// 16'h010c: txq_base_addr_reg[63:32] <= s_axil_ctrl[0].wdata;
// 16'h0104: txq_prod_reg <= axil_ctrl[0].wdata[15:0];
// 16'h0108: txq_base_addr_reg[31:0] <= axil_ctrl[0].wdata;
// 16'h010c: txq_base_addr_reg[63:32] <= axil_ctrl[0].wdata;
16'h0200: begin
cmd_mbox_start_reg <= axil_ctrl[0].wdata[0];
end
default: begin end
endcase
end
if (s_axil_ctrl[0].arvalid && !s_axil_rvalid_reg) begin
if (axil_ctrl[0].arvalid && !s_axil_rvalid_reg) begin
s_axil_rdata_reg <= '0;
s_axil_arready_reg <= 1'b1;
s_axil_rvalid_reg <= 1'b1;
case ({s_axil_ctrl[0].araddr[15:2], 2'b00})
case ({axil_ctrl[0].araddr[15:2], 2'b00})
16'h0100: s_axil_rdata_reg <= PORTS; // port count
16'h0104: s_axil_rdata_reg <= PTP_TS_EN ? 32'h00020000 : 32'h00010000; // port offset
16'h0104: s_axil_rdata_reg <= PORT_BASE_ADDR; // port offset
16'h0108: s_axil_rdata_reg <= 32'h00010000; // port stride
16'h0200: begin
s_axil_rdata_reg[0] <= cmd_mbox_busy;
end
default: begin end
endcase
end
@@ -219,6 +231,106 @@ always_ff @(posedge clk) begin
end
end
// command mailbox
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.LAST_EN(1),
.ID_EN(0),
.DEST_EN(0),
.USER_EN(0)
) axis_cmd();
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.LAST_EN(1),
.ID_EN(0),
.DEST_EN(0),
.USER_EN(0)
) axis_rsp();
cndm_micro_cmd_mbox
cmd_mbox_inst (
.clk(clk),
.rst(rst),
/*
* AXI lite interface
*/
.s_axil_wr(axil_ctrl[1]),
.s_axil_rd(axil_ctrl[1]),
/*
* Control
*/
.start(cmd_mbox_start_reg),
.busy(cmd_mbox_busy),
/*
* Command interface
*/
.m_axis_cmd(axis_cmd),
.s_axis_rsp(axis_rsp)
);
// datapath manager
taxi_apb_if #(
.DATA_W(32),
.ADDR_W(16+CL_PORTS)
)
apb_dp_ctrl();
cndm_micro_dp_mgr #(
.PORTS(PORTS),
.PORT_BASE_ADDR(PORT_BASE_ADDR)
)
dp_mgr_inst (
.clk(clk),
.rst(rst),
/*
* Command interface
*/
.s_axis_cmd(axis_cmd),
.m_axis_rsp(axis_rsp),
/*
* APB master interface (datapath control)
*/
.m_apb_dp_ctrl(apb_dp_ctrl)
);
taxi_apb_if #(
.DATA_W(32),
.ADDR_W(16)
)
apb_port_dp_ctrl[PORTS]();
taxi_apb_interconnect #(
.M_CNT($size(apb_port_dp_ctrl)),
.ADDR_W(apb_dp_ctrl.ADDR_W),
.M_REGIONS(1),
.M_BASE_ADDR('0),
.M_ADDR_W({$size(apb_port_dp_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(apb_port_dp_ctrl){1'b0}})
)
port_dp_intercon_inst (
.clk(clk),
.rst(rst),
/*
* APB slave interface
*/
.s_apb(apb_dp_ctrl),
/*
* APB master interfaces
*/
.m_apb(apb_port_dp_ctrl)
);
if (PTP_TS_EN) begin : ptp
taxi_ptp_td_phc_axil #(
@@ -232,8 +344,8 @@ if (PTP_TS_EN) begin : ptp
/*
* Control register interface
*/
.s_axil_wr(s_axil_ctrl[1]),
.s_axil_rd(s_axil_ctrl[1]),
.s_axil_wr(axil_ctrl[2]),
.s_axil_rd(axil_ctrl[2]),
/*
* PTP
@@ -362,8 +474,13 @@ for (genvar p = 0; p < PORTS; p = p + 1) begin : port
/*
* Control register interface
*/
.s_axil_wr(s_axil_ctrl[PORT_OFFSET+p]),
.s_axil_rd(s_axil_ctrl[PORT_OFFSET+p]),
.s_axil_ctrl_wr(axil_ctrl[PORT_OFFSET+p]),
.s_axil_ctrl_rd(axil_ctrl[PORT_OFFSET+p]),
/*
* Datapath control register interface
*/
.s_apb_dp_ctrl(apb_port_dp_ctrl[p]),
/*
* DMA

View File

@@ -0,0 +1,546 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Datapath manager
*/
module cndm_micro_dp_mgr #
(
parameter PORTS = 2,
parameter PORT_BASE_ADDR = 0
)
(
input wire logic clk,
input wire logic rst,
/*
* Command interface
*/
taxi_axis_if.snk s_axis_cmd,
taxi_axis_if.src m_axis_rsp,
/*
* APB master interface (datapath control)
*/
taxi_apb_if.mst m_apb_dp_ctrl
);
// extract parameters
localparam DP_APB_ADDR_W = m_apb_dp_ctrl.ADDR_W;
localparam DP_APB_DATA_W = m_apb_dp_ctrl.DATA_W;
localparam DP_APB_STRB_W = m_apb_dp_ctrl.STRB_W;
typedef enum logic [15:0] {
CMD_OP_NOP = 16'h0000,
CMD_OP_CREATE_EQ = 16'h0200,
CMD_OP_MODIFY_EQ = 16'h0201,
CMD_OP_QUERY_EQ = 16'h0202,
CMD_OP_DESTROY_EQ = 16'h0203,
CMD_OP_CREATE_CQ = 16'h0210,
CMD_OP_MODIFY_CQ = 16'h0211,
CMD_OP_QUERY_CQ = 16'h0212,
CMD_OP_DESTROY_CQ = 16'h0213,
CMD_OP_CREATE_SQ = 16'h0220,
CMD_OP_MODIFY_SQ = 16'h0221,
CMD_OP_QUERY_SQ = 16'h0222,
CMD_OP_DESTROY_SQ = 16'h0223,
CMD_OP_CREATE_RQ = 16'h0230,
CMD_OP_MODIFY_RQ = 16'h0231,
CMD_OP_QUERY_RQ = 16'h0232,
CMD_OP_DESTROY_RQ = 16'h0233,
CMD_OP_CREATE_QP = 16'h0240,
CMD_OP_MODIFY_QP = 16'h0241,
CMD_OP_QUERY_QP = 16'h0242,
CMD_OP_DESTROY_QP = 16'h0243
} cmd_opcode_t;
typedef enum logic [4:0] {
STATE_IDLE,
STATE_START,
STATE_Q_RESET_1,
STATE_Q_RESET_2,
STATE_Q_SET_BASE_L,
STATE_Q_SET_BASE_H,
STATE_Q_ENABLE,
STATE_Q_DISABLE,
STATE_SEND_RSP,
STATE_PAD_RSP
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic s_axis_cmd_tready_reg = 1'b0, s_axis_cmd_tready_next;
logic [31:0] m_axis_rsp_tdata_reg = '0, m_axis_rsp_tdata_next;
logic m_axis_rsp_tvalid_reg = 1'b0, m_axis_rsp_tvalid_next;
logic m_axis_rsp_tlast_reg = 1'b0, m_axis_rsp_tlast_next;
logic [DP_APB_ADDR_W-1:0] m_apb_dp_ctrl_paddr_reg = '0, m_apb_dp_ctrl_paddr_next;
logic m_apb_dp_ctrl_psel_reg = 1'b0, m_apb_dp_ctrl_psel_next;
logic m_apb_dp_ctrl_penable_reg = 1'b0, m_apb_dp_ctrl_penable_next;
logic m_apb_dp_ctrl_pwrite_reg = 1'b0, m_apb_dp_ctrl_pwrite_next;
logic [DP_APB_DATA_W-1:0] m_apb_dp_ctrl_pwdata_reg = '0, m_apb_dp_ctrl_pwdata_next;
logic [DP_APB_STRB_W-1:0] m_apb_dp_ctrl_pstrb_reg = '0, m_apb_dp_ctrl_pstrb_next;
// command RAM
localparam CMD_AW = 4;
logic [31:0] cmd_ram[2**CMD_AW];
logic [31:0] cmd_ram_wr_data;
logic [CMD_AW-1:0] cmd_ram_wr_addr;
logic cmd_ram_wr_en;
logic [CMD_AW-1:0] cmd_ram_rd_addr;
wire [31:0] cmd_ram_rd_data = cmd_ram[cmd_ram_rd_addr];
assign s_axis_cmd.tready = s_axis_cmd_tready_reg;
assign m_axis_rsp.tdata = m_axis_rsp_tdata_reg;
assign m_axis_rsp.tkeep = '1;
assign m_axis_rsp.tstrb = m_axis_rsp.tkeep;
assign m_axis_rsp.tvalid = m_axis_rsp_tvalid_reg;
assign m_axis_rsp.tlast = m_axis_rsp_tlast_reg;
assign m_axis_rsp.tid = '0;
assign m_axis_rsp.tdest = '0;
assign m_axis_rsp.tuser = '0;
assign m_apb_dp_ctrl.paddr = m_apb_dp_ctrl_paddr_reg;
assign m_apb_dp_ctrl.pprot = 3'b010;
assign m_apb_dp_ctrl.psel = m_apb_dp_ctrl_psel_reg;
assign m_apb_dp_ctrl.penable = m_apb_dp_ctrl_penable_reg;
assign m_apb_dp_ctrl.pwrite = m_apb_dp_ctrl_pwrite_reg;
assign m_apb_dp_ctrl.pwdata = m_apb_dp_ctrl_pwdata_reg;
assign m_apb_dp_ctrl.pstrb = m_apb_dp_ctrl_pstrb_reg;
assign m_apb_dp_ctrl.pauser = '0;
assign m_apb_dp_ctrl.pwuser = '0;
logic cmd_frame_reg = 1'b0, cmd_frame_next;
logic [3:0] cmd_ptr_reg = '0, cmd_ptr_next;
logic rsp_frame_reg = 1'b0, rsp_frame_next;
logic [3:0] rsp_ptr_reg = '0, rsp_ptr_next;
logic drop_cmd_reg = 1'b0, drop_cmd_next;
logic [15:0] opcode_reg = '0, opcode_next;
logic [31:0] flags_reg = '0, flags_next;
logic [15:0] port_reg = '0, port_next;
logic [23:0] qn_reg = '0, qn_next;
logic [DP_APB_ADDR_W-1:0] block_base_addr_reg = '0, block_base_addr_next;
always_comb begin
state_next = STATE_IDLE;
s_axis_cmd_tready_next = 1'b0;
m_axis_rsp_tdata_next = m_axis_rsp_tdata_reg;
m_axis_rsp_tvalid_next = m_axis_rsp_tvalid_reg && !m_axis_rsp.tready;
m_axis_rsp_tlast_next = m_axis_rsp_tlast_reg;
m_apb_dp_ctrl_paddr_next = m_apb_dp_ctrl_paddr_reg;
m_apb_dp_ctrl_psel_next = m_apb_dp_ctrl_psel_reg && !m_apb_dp_ctrl.pready;
m_apb_dp_ctrl_penable_next = m_apb_dp_ctrl_psel_reg && !m_apb_dp_ctrl.pready;
m_apb_dp_ctrl_pwrite_next = m_apb_dp_ctrl_pwrite_reg;
m_apb_dp_ctrl_pwdata_next = m_apb_dp_ctrl_pwdata_reg;
m_apb_dp_ctrl_pstrb_next = m_apb_dp_ctrl_pstrb_reg;
cmd_ram_wr_data = s_axis_cmd.tdata;
cmd_ram_wr_addr = cmd_ptr_reg;
cmd_ram_wr_en = 1'b0;
cmd_ram_rd_addr = '0;
cmd_frame_next = cmd_frame_reg;
cmd_ptr_next = cmd_ptr_reg;
rsp_frame_next = rsp_frame_reg;
rsp_ptr_next = rsp_ptr_reg;
drop_cmd_next = drop_cmd_reg;
opcode_next = opcode_reg;
flags_next = flags_reg;
port_next = port_reg;
qn_next = qn_reg;
block_base_addr_next = block_base_addr_reg;
if (s_axis_cmd.tready && s_axis_cmd.tvalid) begin
if (s_axis_cmd.tlast) begin
cmd_frame_next = 1'b0;
cmd_ptr_next = '0;
end else begin
cmd_ptr_next = cmd_ptr_reg + 1;
cmd_frame_next = 1'b1;
end
end
case (state_reg)
STATE_IDLE: begin
s_axis_cmd_tready_next = !m_axis_rsp_tvalid_reg && !rsp_frame_reg;
cmd_ram_wr_data = s_axis_cmd.tdata;
cmd_ram_wr_addr = cmd_ptr_reg;
cmd_ram_wr_en = 1'b1;
// save some important fields
case (cmd_ptr_reg)
4'd0: opcode_next = s_axis_cmd.tdata[31:16];
4'd1: flags_next = s_axis_cmd.tdata;
4'd2: port_next = s_axis_cmd.tdata[15:0];
4'd3: qn_next = s_axis_cmd.tdata[23:0];
default: begin end
endcase
if (s_axis_cmd.tready && s_axis_cmd.tvalid && !drop_cmd_reg) begin
if (s_axis_cmd.tlast || &cmd_ptr_reg) begin
drop_cmd_next = !s_axis_cmd.tlast;
state_next = STATE_START;
end else begin
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_START: begin
// determine block base address
case (opcode_reg)
CMD_OP_CREATE_EQ,
CMD_OP_MODIFY_EQ,
CMD_OP_QUERY_EQ,
CMD_OP_DESTROY_EQ:
begin
// EQ
block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0000);
end
CMD_OP_CREATE_CQ,
CMD_OP_MODIFY_CQ,
CMD_OP_QUERY_CQ,
CMD_OP_DESTROY_CQ:
begin
// CQ
if (qn_reg[0]) begin
block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0300);
end else begin
block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0400);
end
end
CMD_OP_CREATE_SQ,
CMD_OP_MODIFY_SQ,
CMD_OP_QUERY_SQ,
CMD_OP_DESTROY_SQ:
begin
// SQ
block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0100);
end
CMD_OP_CREATE_RQ,
CMD_OP_MODIFY_RQ,
CMD_OP_QUERY_RQ,
CMD_OP_DESTROY_RQ:
begin
// RQ
block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0200);
end
default: begin end
endcase
case (opcode_reg)
16'h0000: begin
// NOP
m_axis_rsp_tdata_next = '0; // TODO
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
state_next = STATE_SEND_RSP;
end
CMD_OP_CREATE_EQ,
CMD_OP_CREATE_CQ,
CMD_OP_CREATE_SQ,
CMD_OP_CREATE_RQ:
begin
// create queue operation
state_next = STATE_Q_RESET_1;
end
CMD_OP_MODIFY_EQ,
CMD_OP_MODIFY_CQ,
CMD_OP_MODIFY_SQ,
CMD_OP_MODIFY_RQ:
begin
// modify queue operation
m_axis_rsp_tdata_next = '0; // TODO
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
// determine base address
state_next = STATE_PAD_RSP;
end
CMD_OP_QUERY_EQ,
CMD_OP_QUERY_CQ,
CMD_OP_QUERY_SQ,
CMD_OP_QUERY_RQ:
begin
// query queue operation
m_axis_rsp_tdata_next = '0; // TODO
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
// determine base address
state_next = STATE_PAD_RSP;
end
CMD_OP_DESTROY_EQ,
CMD_OP_DESTROY_CQ,
CMD_OP_DESTROY_SQ,
CMD_OP_DESTROY_RQ:
begin
// destroy queue operation
state_next = STATE_Q_DISABLE;
end
default: begin
// unknown opcode
m_axis_rsp_tdata_next = '0; // TODO error code
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
state_next = STATE_PAD_RSP;
end
endcase
end
STATE_Q_RESET_1: begin
// reset queue 1
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h0000;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
m_apb_dp_ctrl_pstrb_next = '1;
state_next = STATE_Q_RESET_2;
end else begin
state_next = STATE_Q_RESET_1;
end
end
STATE_Q_RESET_2: begin
// reset queue 2
cmd_ram_wr_data = 32'(block_base_addr_reg + 'h0004) + PORT_BASE_ADDR;
cmd_ram_wr_addr = 7;
cmd_ram_wr_en = 1'b1;
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h0004;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
m_apb_dp_ctrl_pstrb_next = '1;
state_next = STATE_Q_SET_BASE_L;
end else begin
state_next = STATE_Q_RESET_2;
end
end
STATE_Q_SET_BASE_L: begin
// set queue base addr (LSB)
cmd_ram_rd_addr = 8;
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h0008;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data;
m_apb_dp_ctrl_pstrb_next = '1;
state_next = STATE_Q_SET_BASE_H;
end else begin
state_next = STATE_Q_SET_BASE_L;
end
end
STATE_Q_SET_BASE_H: begin
// set queue base addr (MSB)
cmd_ram_rd_addr = 9;
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h000C;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data;
m_apb_dp_ctrl_pstrb_next = '1;
state_next = STATE_Q_ENABLE;
end else begin
state_next = STATE_Q_SET_BASE_H;
end
end
STATE_Q_ENABLE: begin
// enable queue
cmd_ram_rd_addr = 6;
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h0000;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = '0;
m_apb_dp_ctrl_pwdata_next[19:16] = cmd_ram_rd_data[3:0];
m_apb_dp_ctrl_pwdata_next[0] = 1'b1;
m_apb_dp_ctrl_pstrb_next = '1;
m_axis_rsp_tdata_next = '0; // TODO
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
state_next = STATE_SEND_RSP;
end else begin
state_next = STATE_Q_ENABLE;
end
end
STATE_Q_DISABLE: begin
// disable queue
if (!m_apb_dp_ctrl_psel_reg) begin
m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 'h0000;
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = 1'b1;
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
m_apb_dp_ctrl_pstrb_next = '1;
m_axis_rsp_tdata_next = '0; // TODO
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = 1'b0;
state_next = STATE_SEND_RSP;
end else begin
state_next = STATE_Q_DISABLE;
end
end
STATE_SEND_RSP: begin
// send response in the form of an edited command
cmd_ram_rd_addr = rsp_ptr_reg;
if (m_axis_rsp.tready || !m_axis_rsp.tvalid) begin
m_axis_rsp_tdata_next = cmd_ram_rd_data;
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = &rsp_ptr_reg;
if (&rsp_ptr_reg) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_SEND_RSP;
end
end else begin
state_next = STATE_SEND_RSP;
end
end
STATE_PAD_RSP: begin
// zero pad response
if (m_axis_rsp.tready || !m_axis_rsp.tvalid) begin
m_axis_rsp_tdata_next = '0;
m_axis_rsp_tvalid_next = 1'b1;
m_axis_rsp_tlast_next = &rsp_ptr_reg;
if (&rsp_ptr_reg) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_PAD_RSP;
end
end else begin
state_next = STATE_PAD_RSP;
end
end
default: begin
// unknown state; return to idle
state_next = STATE_IDLE;
end
endcase
if (drop_cmd_reg) begin
s_axis_cmd_tready_next = 1'b1;
if (s_axis_cmd.tready && s_axis_cmd.tvalid) begin
drop_cmd_next = !s_axis_cmd.tlast;
end
end
if (m_axis_rsp_tvalid_next && (!m_axis_rsp_tvalid_reg || m_axis_rsp.tready)) begin
if (m_axis_rsp_tlast_next) begin
rsp_ptr_next = '0;
end else begin
rsp_ptr_next = rsp_ptr_reg + 1;
rsp_frame_next = 1'b1;
end
end
if (m_axis_rsp.tready && m_axis_rsp.tvalid) begin
if (m_axis_rsp.tlast) begin
rsp_frame_next = 1'b0;
rsp_ptr_next = '0;
end
end
end
always_ff @(posedge clk) begin
if (cmd_ram_wr_en) begin
cmd_ram[cmd_ram_wr_addr] = cmd_ram_wr_data;
end
end
always_ff @(posedge clk) begin
state_reg <= state_next;
s_axis_cmd_tready_reg <= s_axis_cmd_tready_next;
m_axis_rsp_tdata_reg <= m_axis_rsp_tdata_next;
m_axis_rsp_tvalid_reg <= m_axis_rsp_tvalid_next;
m_axis_rsp_tlast_reg <= m_axis_rsp_tlast_next;
m_apb_dp_ctrl_paddr_reg <= m_apb_dp_ctrl_paddr_next;
m_apb_dp_ctrl_psel_reg <= m_apb_dp_ctrl_psel_next;
m_apb_dp_ctrl_penable_reg <= m_apb_dp_ctrl_penable_next;
m_apb_dp_ctrl_pwrite_reg <= m_apb_dp_ctrl_pwrite_next;
m_apb_dp_ctrl_pwdata_reg <= m_apb_dp_ctrl_pwdata_next;
m_apb_dp_ctrl_pstrb_reg <= m_apb_dp_ctrl_pstrb_next;
cmd_frame_reg <= cmd_frame_next;
cmd_ptr_reg <= cmd_ptr_next;
rsp_frame_reg <= rsp_frame_next;
rsp_ptr_reg <= rsp_ptr_next;
drop_cmd_reg <= drop_cmd_next;
opcode_reg <= opcode_next;
flags_reg <= flags_next;
port_reg <= port_next;
qn_reg <= qn_next;
block_base_addr_reg <= block_base_addr_next;
if (rst) begin
state_reg <= STATE_IDLE;
s_axis_cmd_tready_reg <= 1'b0;
m_axis_rsp_tvalid_reg <= 1'b0;
m_apb_dp_ctrl_psel_reg <= 1'b0;
m_apb_dp_ctrl_penable_reg <= 1'b0;
cmd_frame_reg <= 1'b0;
cmd_ptr_reg <= '0;
rsp_frame_reg <= 1'b0;
rsp_ptr_reg <= '0;
drop_cmd_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -523,8 +523,8 @@ core_inst (
/*
* Control register interface
*/
.s_axil_wr(axil_ctrl_bar),
.s_axil_rd(axil_ctrl_bar),
.s_axil_ctrl_wr(axil_ctrl_bar),
.s_axil_ctrl_rd(axil_ctrl_bar),
/*
* DMA

View File

@@ -26,8 +26,13 @@ module cndm_micro_port #(
/*
* Control register interface
*/
taxi_axil_if.wr_slv s_axil_wr,
taxi_axil_if.rd_slv s_axil_rd,
taxi_axil_if.wr_slv s_axil_ctrl_wr,
taxi_axil_if.rd_slv s_axil_ctrl_rd,
/*
* Datapath control register interface
*/
taxi_apb_if.slv s_apb_dp_ctrl,
/*
* DMA
@@ -61,8 +66,8 @@ module cndm_micro_port #(
taxi_axis_if.snk mac_axis_rx
);
localparam AXIL_ADDR_W = s_axil_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_wr.DATA_W;
localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
localparam RAM_SEGS = dma_ram_wr.SEGS;
localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W;
@@ -90,128 +95,222 @@ logic [3:0] rxcq_size_reg = '0;
logic [63:0] rxcq_base_addr_reg = '0;
wire [15:0] rxcq_prod;
logic s_axil_awready_reg = 1'b0;
logic s_axil_wready_reg = 1'b0;
logic s_axil_bvalid_reg = 1'b0;
logic s_axil_ctrl_awready_reg = 1'b0;
logic s_axil_ctrl_wready_reg = 1'b0;
logic s_axil_ctrl_bvalid_reg = 1'b0;
logic s_axil_arready_reg = 1'b0;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0;
logic s_axil_rvalid_reg = 1'b0;
logic s_axil_ctrl_arready_reg = 1'b0;
logic [AXIL_DATA_W-1:0] s_axil_ctrl_rdata_reg = '0;
logic s_axil_ctrl_rvalid_reg = 1'b0;
assign s_axil_wr.awready = s_axil_awready_reg;
assign s_axil_wr.wready = s_axil_wready_reg;
assign s_axil_wr.bresp = '0;
assign s_axil_wr.buser = '0;
assign s_axil_wr.bvalid = s_axil_bvalid_reg;
assign s_axil_ctrl_wr.awready = s_axil_ctrl_awready_reg;
assign s_axil_ctrl_wr.wready = s_axil_ctrl_wready_reg;
assign s_axil_ctrl_wr.bresp = '0;
assign s_axil_ctrl_wr.buser = '0;
assign s_axil_ctrl_wr.bvalid = s_axil_ctrl_bvalid_reg;
assign s_axil_rd.arready = s_axil_arready_reg;
assign s_axil_rd.rdata = s_axil_rdata_reg;
assign s_axil_rd.rresp = '0;
assign s_axil_rd.ruser = '0;
assign s_axil_rd.rvalid = s_axil_rvalid_reg;
assign s_axil_ctrl_rd.arready = s_axil_ctrl_arready_reg;
assign s_axil_ctrl_rd.rdata = s_axil_ctrl_rdata_reg;
assign s_axil_ctrl_rd.rresp = '0;
assign s_axil_ctrl_rd.ruser = '0;
assign s_axil_ctrl_rd.rvalid = s_axil_ctrl_rvalid_reg;
logic s_apb_dp_ctrl_pready_reg = 1'b0;
logic [AXIL_DATA_W-1:0] s_apb_dp_ctrl_prdata_reg = '0;
assign s_apb_dp_ctrl.pready = s_apb_dp_ctrl_pready_reg;
assign s_apb_dp_ctrl.prdata = s_apb_dp_ctrl_prdata_reg;
assign s_apb_dp_ctrl.pslverr = 1'b0;
assign s_apb_dp_ctrl.pruser = '0;
assign s_apb_dp_ctrl.pbuser = '0;
always_ff @(posedge clk) begin
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= s_axil_bvalid_reg && !s_axil_wr.bready;
s_axil_ctrl_awready_reg <= 1'b0;
s_axil_ctrl_wready_reg <= 1'b0;
s_axil_ctrl_bvalid_reg <= s_axil_ctrl_bvalid_reg && !s_axil_ctrl_wr.bready;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= s_axil_rvalid_reg && !s_axil_rd.rready;
s_axil_ctrl_arready_reg <= 1'b0;
s_axil_ctrl_rvalid_reg <= s_axil_ctrl_rvalid_reg && !s_axil_ctrl_rd.rready;
if (s_axil_wr.awvalid && s_axil_wr.wvalid && !s_axil_bvalid_reg) begin
s_axil_awready_reg <= 1'b1;
s_axil_wready_reg <= 1'b1;
s_axil_bvalid_reg <= 1'b1;
s_apb_dp_ctrl_pready_reg <= 1'b0;
case ({s_axil_wr.awaddr[15:2], 2'b00})
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
s_axil_ctrl_awready_reg <= 1'b1;
s_axil_ctrl_wready_reg <= 1'b1;
s_axil_ctrl_bvalid_reg <= 1'b1;
case ({s_axil_ctrl_wr.awaddr[15:2], 2'b00})
16'h0100: begin
txq_en_reg <= s_axil_wr.wdata[0];
txq_size_reg <= s_axil_wr.wdata[19:16];
txq_en_reg <= s_axil_ctrl_wr.wdata[0];
txq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
end
16'h0104: txq_prod_reg <= s_axil_wr.wdata[15:0];
16'h0108: txq_base_addr_reg[31:0] <= s_axil_wr.wdata;
16'h010c: txq_base_addr_reg[63:32] <= s_axil_wr.wdata;
16'h0104: txq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
16'h010c: txq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
16'h0200: begin
rxq_en_reg <= s_axil_wr.wdata[0];
rxq_size_reg <= s_axil_wr.wdata[19:16];
rxq_en_reg <= s_axil_ctrl_wr.wdata[0];
rxq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
end
16'h0204: rxq_prod_reg <= s_axil_wr.wdata[15:0];
16'h0208: rxq_base_addr_reg[31:0] <= s_axil_wr.wdata;
16'h020c: rxq_base_addr_reg[63:32] <= s_axil_wr.wdata;
16'h0204: rxq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
16'h0208: rxq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
16'h020c: rxq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
16'h0300: begin
txcq_en_reg <= s_axil_wr.wdata[0];
txcq_size_reg <= s_axil_wr.wdata[19:16];
txcq_en_reg <= s_axil_ctrl_wr.wdata[0];
txcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
end
16'h0308: txcq_base_addr_reg[31:0] <= s_axil_wr.wdata;
16'h030c: txcq_base_addr_reg[63:32] <= s_axil_wr.wdata;
16'h0308: txcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
16'h030c: txcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
16'h0400: begin
rxcq_en_reg <= s_axil_wr.wdata[0];
rxcq_size_reg <= s_axil_wr.wdata[19:16];
rxcq_en_reg <= s_axil_ctrl_wr.wdata[0];
rxcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
end
16'h0408: rxcq_base_addr_reg[31:0] <= s_axil_wr.wdata;
16'h040c: rxcq_base_addr_reg[63:32] <= s_axil_wr.wdata;
16'h0408: rxcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
16'h040c: rxcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
default: begin end
endcase
end
if (s_axil_rd.arvalid && !s_axil_rvalid_reg) begin
s_axil_rdata_reg <= '0;
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
s_axil_ctrl_rdata_reg <= '0;
s_axil_arready_reg <= 1'b1;
s_axil_rvalid_reg <= 1'b1;
s_axil_ctrl_arready_reg <= 1'b1;
s_axil_ctrl_rvalid_reg <= 1'b1;
case ({s_axil_rd.araddr[15:2], 2'b00})
case ({s_axil_ctrl_rd.araddr[15:2], 2'b00})
16'h0100: begin
s_axil_rdata_reg[0] <= txq_en_reg;
s_axil_rdata_reg[19:16] <= txq_size_reg;
s_axil_ctrl_rdata_reg[0] <= txq_en_reg;
s_axil_ctrl_rdata_reg[19:16] <= txq_size_reg;
end
16'h0104: begin
s_axil_rdata_reg[15:0] <= txq_prod_reg;
s_axil_rdata_reg[31:16] <= txq_cons;
s_axil_ctrl_rdata_reg[15:0] <= txq_prod_reg;
s_axil_ctrl_rdata_reg[31:16] <= txq_cons;
end
16'h0108: s_axil_rdata_reg <= txq_base_addr_reg[31:0];
16'h010c: s_axil_rdata_reg <= txq_base_addr_reg[63:32];
16'h0108: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[31:0];
16'h010c: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[63:32];
16'h0200: begin
s_axil_rdata_reg[0] <= rxq_en_reg;
s_axil_rdata_reg[19:16] <= rxq_size_reg;
s_axil_ctrl_rdata_reg[0] <= rxq_en_reg;
s_axil_ctrl_rdata_reg[19:16] <= rxq_size_reg;
end
16'h0204: begin
s_axil_rdata_reg[15:0] <= rxq_prod_reg;
s_axil_rdata_reg[31:16] <= rxq_cons;
s_axil_ctrl_rdata_reg[15:0] <= rxq_prod_reg;
s_axil_ctrl_rdata_reg[31:16] <= rxq_cons;
end
16'h0208: s_axil_rdata_reg <= rxq_base_addr_reg[31:0];
16'h020c: s_axil_rdata_reg <= rxq_base_addr_reg[63:32];
16'h0208: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[31:0];
16'h020c: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[63:32];
16'h0300: begin
s_axil_rdata_reg[0] <= txcq_en_reg;
s_axil_rdata_reg[19:16] <= txcq_size_reg;
s_axil_ctrl_rdata_reg[0] <= txcq_en_reg;
s_axil_ctrl_rdata_reg[19:16] <= txcq_size_reg;
end
16'h0304: s_axil_rdata_reg[15:0] <= txcq_prod;
16'h0308: s_axil_rdata_reg <= txcq_base_addr_reg[31:0];
16'h030c: s_axil_rdata_reg <= txcq_base_addr_reg[63:32];
16'h0304: s_axil_ctrl_rdata_reg[15:0] <= txcq_prod;
16'h0308: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[31:0];
16'h030c: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[63:32];
16'h0400: begin
s_axil_rdata_reg[0] <= rxcq_en_reg;
s_axil_rdata_reg[19:16] <= rxcq_size_reg;
s_axil_ctrl_rdata_reg[0] <= rxcq_en_reg;
s_axil_ctrl_rdata_reg[19:16] <= rxcq_size_reg;
end
16'h0404: s_axil_rdata_reg[15:0] <= rxcq_prod;
16'h0408: s_axil_rdata_reg <= rxcq_base_addr_reg[31:0];
16'h040c: s_axil_rdata_reg <= rxcq_base_addr_reg[63:32];
16'h0404: s_axil_ctrl_rdata_reg[15:0] <= rxcq_prod;
16'h0408: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[31:0];
16'h040c: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[63:32];
default: begin end
endcase
end
if (s_apb_dp_ctrl.penable && s_apb_dp_ctrl.psel && !s_apb_dp_ctrl_pready_reg) begin
s_apb_dp_ctrl_pready_reg <= 1'b1;
s_apb_dp_ctrl_prdata_reg <= '0;
if (s_apb_dp_ctrl.pwrite) begin
case ({s_apb_dp_ctrl.paddr[15:2], 2'b00})
16'h0100: begin
txq_en_reg <= s_apb_dp_ctrl.pwdata[0];
txq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
end
16'h0104: txq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
16'h0108: txq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
16'h010c: txq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
16'h0200: begin
rxq_en_reg <= s_apb_dp_ctrl.pwdata[0];
rxq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
end
16'h0204: rxq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
16'h0208: rxq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
16'h020c: rxq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
16'h0300: begin
txcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
txcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
end
16'h0308: txcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
16'h030c: txcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
16'h0400: begin
rxcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
rxcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
end
16'h0408: rxcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
16'h040c: rxcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
default: begin end
endcase
end
case ({s_apb_dp_ctrl.paddr[15:2], 2'b00})
16'h0100: begin
s_apb_dp_ctrl_prdata_reg[0] <= txq_en_reg;
s_apb_dp_ctrl_prdata_reg[19:16] <= txq_size_reg;
end
16'h0104: begin
s_apb_dp_ctrl_prdata_reg[15:0] <= txq_prod_reg;
s_apb_dp_ctrl_prdata_reg[31:16] <= txq_cons;
end
16'h0108: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[31:0];
16'h010c: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[63:32];
16'h0200: begin
s_apb_dp_ctrl_prdata_reg[0] <= rxq_en_reg;
s_apb_dp_ctrl_prdata_reg[19:16] <= rxq_size_reg;
end
16'h0204: begin
s_apb_dp_ctrl_prdata_reg[15:0] <= rxq_prod_reg;
s_apb_dp_ctrl_prdata_reg[31:16] <= rxq_cons;
end
16'h0208: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[31:0];
16'h020c: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[63:32];
16'h0300: begin
s_apb_dp_ctrl_prdata_reg[0] <= txcq_en_reg;
s_apb_dp_ctrl_prdata_reg[19:16] <= txcq_size_reg;
end
16'h0304: s_apb_dp_ctrl_prdata_reg[15:0] <= txcq_prod;
16'h0308: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[31:0];
16'h030c: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[63:32];
16'h0400: begin
s_apb_dp_ctrl_prdata_reg[0] <= rxcq_en_reg;
s_apb_dp_ctrl_prdata_reg[19:16] <= rxcq_size_reg;
end
16'h0404: s_apb_dp_ctrl_prdata_reg[15:0] <= rxcq_prod;
16'h0408: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[31:0];
16'h040c: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[63:32];
default: begin end
endcase
end
if (rst) begin
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= 1'b0;
s_axil_ctrl_awready_reg <= 1'b0;
s_axil_ctrl_wready_reg <= 1'b0;
s_axil_ctrl_bvalid_reg <= 1'b0;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= 1'b0;
s_axil_ctrl_arready_reg <= 1'b0;
s_axil_ctrl_rvalid_reg <= 1'b0;
s_apb_dp_ctrl_pready_reg <= 1'b0;
end
end

View File

@@ -8,18 +8,49 @@ Authors:
"""
import array
import logging
import struct
from collections import deque
from cocotb.queue import Queue
# Command opcodes
CNDM_CMD_OP_NOP = 0x0000
CNDM_CMD_OP_CREATE_EQ = 0x0200
CNDM_CMD_OP_MODIFY_EQ = 0x0201
CNDM_CMD_OP_QUERY_EQ = 0x0202
CNDM_CMD_OP_DESTROY_EQ = 0x0203
CNDM_CMD_OP_CREATE_CQ = 0x0210
CNDM_CMD_OP_MODIFY_CQ = 0x0211
CNDM_CMD_OP_QUERY_CQ = 0x0212
CNDM_CMD_OP_DESTROY_CQ = 0x0213
CNDM_CMD_OP_CREATE_SQ = 0x0220
CNDM_CMD_OP_MODIFY_SQ = 0x0221
CNDM_CMD_OP_QUERY_SQ = 0x0222
CNDM_CMD_OP_DESTROY_SQ = 0x0223
CNDM_CMD_OP_CREATE_RQ = 0x0230
CNDM_CMD_OP_MODIFY_RQ = 0x0231
CNDM_CMD_OP_QUERY_RQ = 0x0232
CNDM_CMD_OP_DESTROY_RQ = 0x0233
CNDM_CMD_OP_CREATE_QP = 0x0240
CNDM_CMD_OP_MODIFY_QP = 0x0241
CNDM_CMD_OP_QUERY_QP = 0x0242
CNDM_CMD_OP_DESTROY_QP = 0x0243
class Port:
def __init__(self, driver, index, hw_regs):
def __init__(self, driver, index):
self.driver = driver
self.log = driver.log
self.index = index
self.hw_regs = hw_regs
self.hw_regs = driver.hw_regs
self.rxq_log_size = (256).bit_length()-1
self.rxq_size = 2**self.rxq_log_size
@@ -27,6 +58,8 @@ class Port:
self.rxq = None
self.rxq_prod = 0
self.rxq_cons = 0
self.rx_rqn = 0
self.rxq_db_offs = 0
self.rx_info = [None] * self.rxq_size
@@ -36,6 +69,7 @@ class Port:
self.rxcq = None
self.rxcq_prod = 0
self.rxcq_cons = 0
self.rx_cqn = 0
self.txq_log_size = (256).bit_length()-1
self.txq_size = 2**self.txq_log_size
@@ -43,6 +77,8 @@ class Port:
self.txq = None
self.txq_prod = 0
self.txq_cons = 0
self.tx_sqn = 0
self.txq_db_offs = 0
self.tx_info = [None] * self.txq_size
@@ -52,43 +88,103 @@ class Port:
self.txcq = None
self.txcq_prod = 0
self.txcq_cons = 0
self.tx_cqn = 0
self.rx_queue = Queue()
async def init(self):
self.rxq = self.driver.pool.alloc_region(self.rxq_size*16)
addr = self.rxq.get_absolute_address(0)
await self.hw_regs.write_dword(0x0200, 0x00000000)
await self.hw_regs.write_dword(0x0204, 0x00000000)
await self.hw_regs.write_dword(0x0208, addr & 0xffffffff)
await self.hw_regs.write_dword(0x020c, addr >> 32)
await self.hw_regs.write_dword(0x0200, 0x00000001 | (self.rxq_log_size << 16))
self.rxcq = self.driver.pool.alloc_region(self.rxcq_size*16)
addr = self.rxcq.get_absolute_address(0)
await self.hw_regs.write_dword(0x0400, 0x00000000)
await self.hw_regs.write_dword(0x0408, addr & 0xffffffff)
await self.hw_regs.write_dword(0x040c, addr >> 32)
await self.hw_regs.write_dword(0x0400, 0x00000001 | (self.rxcq_log_size << 16))
self.txq = self.driver.pool.alloc_region(self.txq_size*16)
addr = self.txq.get_absolute_address(0)
await self.hw_regs.write_dword(0x0100, 0x00000000)
await self.hw_regs.write_dword(0x0104, 0x00000000)
await self.hw_regs.write_dword(0x0108, addr & 0xffffffff)
await self.hw_regs.write_dword(0x010c, addr >> 32)
await self.hw_regs.write_dword(0x0100, 0x00000001 | (self.txq_log_size << 16))
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_CQ, # opcode
0x00000000, # flags
self.index, # port
0, # cqn
0, # eqn
0, # pd
self.rxcq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.rxq = self.driver.pool.alloc_region(self.rxq_size*16)
addr = self.rxq.get_absolute_address(0)
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_RQ, # opcode
0x00000000, # flags
self.index, # port
0, # rqn
0, # cqn
0, # pd
self.rxq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.rxq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
self.txcq = self.driver.pool.alloc_region(self.txcq_size*16)
addr = self.txcq.get_absolute_address(0)
await self.hw_regs.write_dword(0x0300, 0x00000000)
await self.hw_regs.write_dword(0x0308, addr & 0xffffffff)
await self.hw_regs.write_dword(0x030c, addr >> 32)
await self.hw_regs.write_dword(0x0300, 0x00000001 | (self.txcq_log_size << 16))
# wait for writes to complete
await self.hw_regs.read_dword(0)
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_CQ, # opcode
0x00000000, # flags
self.index, # port
1, # cqn
0, # eqn
0, # pd
self.txcq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.txq = self.driver.pool.alloc_region(self.txq_size*16)
addr = self.txq.get_absolute_address(0)
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_SQ, # opcode
0x00000000, # flags
self.index, # port
0, # sqn
1, # cqn
0, # pd
self.txq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.txq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
await self.refill_rx_buffers()
@@ -101,7 +197,7 @@ class Port:
struct.pack_into('<xxxxLQ', self.txq.mem, 16*index, len(data), ptr+headroom)
self.tx_info[index] = tx_buf
self.txq_prod += 1
await self.hw_regs.write_dword(0x0104, self.txq_prod & 0xffff)
await self.hw_regs.write_dword(self.txq_db_offs, self.txq_prod & 0xffff)
async def recv(self):
return await self.rx_queue.get()
@@ -177,7 +273,7 @@ class Port:
self.prepare_rx_desc(self.rxq_prod & self.rxq_mask)
self.rxq_prod += 1
await self.hw_regs.write_dword(0x0204, self.rxq_prod & 0xffff)
await self.hw_regs.write_dword(self.rxq_db_offs, self.rxq_prod & 0xffff)
async def process_rx_cq(self):
@@ -229,6 +325,8 @@ class Driver:
self.pool = None
self.hw_regs = None
self.port_count = None
self.ports = []
self.free_packets = deque()
@@ -256,12 +354,40 @@ class Driver:
self.log.info("Port stride: 0x%x", self.port_stride)
for k in range(self.port_count):
port = Port(self, k, self.hw_regs.create_window(self.port_offset + self.port_stride*k))
port = Port(self, k)
await port.init()
self.dev.request_irq(k, port.interrupt_handler)
self.ports.append(port)
async def exec_cmd(self, cmd):
return await self.exec_mbox_cmd(cmd)
async def exec_mbox_cmd(self, cmd):
cmd = bytes(cmd)
cmd = cmd.ljust(64, b'\x00')
if len(cmd) != 64:
raise ValueError("Invalid command length")
# write command to mailbox
a = array.array("I")
a.frombytes(cmd)
for k, dw in enumerate(a):
await self.hw_regs.write_dword(0x10000+k*4, dw)
# execute it
await self.hw_regs.write_dword(0x0200, 0x00000001)
# wait for completion
while await self.hw_regs.read_dword(0x0200) & 0x00000001:
pass
# read response from mailbox
for k in range(16):
a[k] = await self.hw_regs.read_dword(0x10040+k*4)
return a.tobytes()
def alloc_pkt(self):
if self.free_packets:
return self.free_packets.popleft()

View File

@@ -80,13 +80,14 @@ if (AXI_MAX_BURST_LEN_INT < 1 || AXI_MAX_BURST_LEN_INT > 256)
if (desc_req.SRC_ADDR_W < AXI_ADDR_W || desc_req.DST_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
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_DECERR = 2'b11
} axi_resp_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
@@ -97,20 +98,23 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11
} dma_error_t;
localparam logic [1:0]
READ_STATE_IDLE = 2'd0,
READ_STATE_START = 2'd1,
READ_STATE_REQ = 2'd2;
typedef enum logic [1:0] {
READ_STATE_IDLE,
READ_STATE_START,
READ_STATE_REQ
} read_state_t;
logic [1:0] read_state_reg = READ_STATE_IDLE, read_state_next;
read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam logic [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_WRITE = 1'd1;
typedef enum logic [0:0] {
AXI_STATE_IDLE,
AXI_STATE_WRITE
} axi_state_t;
logic [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
axi_state_t axi_state_reg = AXI_STATE_IDLE, axi_state_next;
// datapath control signals
logic transfer_in_save;

View File

@@ -107,13 +107,14 @@ if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256)
if (rd_desc_req.SRC_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
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_DECERR = 2'b11
} axi_resp_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
@@ -124,19 +125,22 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11
} dma_error_t;
localparam logic [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_START = 1'd1;
typedef enum logic [0:0] {
AXI_STATE_IDLE,
AXI_STATE_START
} axi_state_t;
logic [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
axi_state_t axi_state_reg = AXI_STATE_IDLE, axi_state_next;
localparam logic [0:0]
AXIS_STATE_IDLE = 1'd0,
AXIS_STATE_READ = 1'd1;
typedef enum logic [0:0] {
AXIS_STATE_IDLE,
AXIS_STATE_READ
} axis_state_t;
logic [0:0] axis_state_reg = AXIS_STATE_IDLE, axis_state_next;
axis_state_t axis_state_reg = AXIS_STATE_IDLE, axis_state_next;
// datapath control signals
logic transfer_in_save;

View File

@@ -109,13 +109,14 @@ if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256)
if (wr_desc_req.DST_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
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_DECERR = 2'b11
} axi_resp_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
@@ -126,16 +127,18 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11
} dma_error_t;
localparam logic [2:0]
STATE_IDLE = 3'd0,
STATE_START = 3'd1,
STATE_WRITE = 3'd2,
STATE_FINISH_BURST = 3'd3,
STATE_DROP_DATA = 3'd4;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_START,
STATE_WRITE,
STATE_FINISH_BURST,
STATE_DROP_DATA
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic transfer_in_save;

View File

@@ -110,12 +110,13 @@ if (AXIS_DATA_W*2**$clog2(PART_COUNT) != RAM_SEGS*RAM_SEG_DATA_W)
if (desc_req.DST_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
STATE_IDLE = 2'd0,
STATE_WRITE = 2'd1,
STATE_DROP_DATA = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_WRITE,
STATE_DROP_DATA
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [OFFSET_W:0] cycle_size;

View File

@@ -109,17 +109,19 @@ if (AXIS_DATA_W*2**$clog2(PART_COUNT) != RAM_SEGS*RAM_SEG_DATA_W)
if (desc_req.SRC_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_READ = 1'd1;
typedef enum logic [0:0] {
READ_STATE_IDLE,
READ_STATE_READ
} read_state_t;
logic [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam logic [0:0]
AXIS_STATE_IDLE = 1'd0,
AXIS_STATE_READ = 1'd1;
typedef enum logic [0:0] {
AXIS_STATE_IDLE,
AXIS_STATE_READ
} axis_state_t;
logic [0:0] axis_state_reg = AXIS_STATE_IDLE, axis_state_next;
axis_state_t axis_state_reg = AXIS_STATE_IDLE, axis_state_next;
// datapath control signals
logic axis_cmd_ready;

View File

@@ -142,13 +142,14 @@ if (OP_TBL_SIZE > 2**AXI_ID_W)
if (rd_desc_req.SRC_ADDR_W < AXI_ADDR_W || rd_desc_req.DST_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
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_DECERR = 2'b11
} axi_resp_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
@@ -159,19 +160,22 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11
} dma_error_t;
localparam logic [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_START = 1'd1;
typedef enum logic [0:0] {
REQ_STATE_IDLE,
REQ_STATE_START
} req_state_t;
logic [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam logic [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_WRITE = 1'd1;
typedef enum logic [0:0] {
AXI_STATE_IDLE,
AXI_STATE_WRITE
} axi_state_t;
logic [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
axi_state_t axi_state_reg = AXI_STATE_IDLE, axi_state_next;
logic [AXI_ADDR_W-1:0] req_axi_addr_reg = '0, req_axi_addr_next;
logic [RAM_SEL_W-1:0] req_ram_sel_reg = '0, req_ram_sel_next;

View File

@@ -146,13 +146,14 @@ if (IMM_EN && IMM_W > AXI_DATA_W)
if (wr_desc_req.SRC_ADDR_W < RAM_ADDR_W || wr_desc_req.DST_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0]
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_DECERR = 2'b11
} axi_resp_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
@@ -163,25 +164,29 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11
} dma_error_t;
localparam logic [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_START = 1'd1;
typedef enum logic [0:0] {
REQ_STATE_IDLE,
REQ_STATE_START
} req_state_t;
logic [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam logic [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_READ = 1'd1;
typedef enum logic [0:0] {
READ_STATE_IDLE,
READ_STATE_READ
} read_state_t;
logic [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam logic [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_TRANSFER = 1'd1;
typedef enum logic [0:0] {
AXI_STATE_IDLE,
AXI_STATE_TRANSFER
} axi_state_t;
logic [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
axi_state_t axi_state_reg = AXI_STATE_IDLE, axi_state_next;
// datapath control signals
logic mask_fifo_we;

View File

@@ -213,7 +213,7 @@ if (PCIE_TAG_CNT < 1 || PCIE_TAG_CNT > 256)
if (rd_desc_req.SRC_ADDR_W < PCIE_ADDR_W || rd_desc_req.DST_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [3:0]
typedef enum logic [3:0] {
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
@@ -221,22 +221,24 @@ localparam logic [3:0]
REQ_MEM_FETCH_ADD = 4'b0100,
REQ_MEM_SWAP = 4'b0101,
REQ_MEM_CAS = 4'b0110,
REQ_MEM_RD_LOCKED = 4'b0111,
REQ_CFG_RD_0 = 4'b1000,
REQ_CFG_RD_1 = 4'b1001,
REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
REQ_MSG_ATS = 4'b1110
} req_type_t;
localparam logic [2:0]
typedef enum logic [2:0] {
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
CPL_STATUS_CA = 3'b100 // completer abort
} cpl_status_t;
localparam logic [3:0]
typedef enum logic [3:0] {
RC_ERR_NORMAL_TERM = 4'b0000,
RC_ERR_POISONED = 4'b0001,
RC_ERR_BAD_STATUS = 4'b0010,
@@ -245,9 +247,10 @@ localparam logic [3:0]
RC_ERR_INVALID_ADDR = 4'b0101,
RC_ERR_INVALID_TAG = 4'b0110,
RC_ERR_TIMEOUT = 4'b1001,
RC_ERR_FLR = 4'b1000;
RC_ERR_FLR = 4'b1000
} rc_err_t;
localparam logic [3:0]
typedef enum logic [3:0] {
DMA_ERR_NONE = 4'd0,
DMA_ERR_TIMEOUT = 4'd1,
DMA_ERR_PARITY = 4'd2,
@@ -258,22 +261,25 @@ localparam logic [3:0]
DMA_ERR_PCIE_FLR = 4'd8,
DMA_ERR_PCIE_CPL_POISONED = 4'd9,
DMA_ERR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERR_PCIE_CPL_STATUS_CA = 4'd11;
DMA_ERR_PCIE_CPL_STATUS_CA = 4'd11
} dma_err_t;
localparam logic [1:0]
REQ_STATE_IDLE = 2'd0,
REQ_STATE_START = 2'd1,
REQ_STATE_HEADER = 2'd2;
typedef enum logic [1:0] {
REQ_STATE_IDLE,
REQ_STATE_START,
REQ_STATE_HEADER
} req_state_t;
logic [1:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam logic [1:0]
typedef enum logic [1:0] {
TLP_STATE_IDLE = 2'd0,
TLP_STATE_HEADER = 2'd1,
TLP_STATE_WRITE = 2'd2,
TLP_STATE_WAIT_END = 2'd3;
TLP_STATE_WAIT_END = 2'd3
} tlp_state_t;
logic [1:0] tlp_state_reg = TLP_STATE_IDLE, tlp_state_next;
tlp_state_t tlp_state_reg = TLP_STATE_IDLE, tlp_state_next;
// datapath control signals
logic last_cycle;

View File

@@ -182,7 +182,7 @@ if (2**$clog2(RAM_BYTE_LANES) != RAM_BYTE_LANES)
if (wr_desc_req.SRC_ADDR_W < RAM_ADDR_W || wr_desc_req.DST_ADDR_W < PCIE_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [3:0]
typedef enum logic [3:0] {
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
@@ -193,44 +193,50 @@ localparam logic [3:0]
REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WR_0 = 4'b1010,
REQ_CFG_WR_1 = 4'b1011,
REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
REQ_MSG_ATS = 4'b1110
} req_type_t;
localparam logic [2:0]
typedef enum logic [2:0] {
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
CPL_STATUS_CA = 3'b100 // completer abort
} cpl_status_t;
localparam logic [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_START = 1'd1;
typedef enum logic [0:0] {
REQ_STATE_IDLE,
REQ_STATE_START
} req_state_t;
logic [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam logic [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_READ = 1'd1;
typedef enum logic [0:0] {
READ_STATE_IDLE,
READ_STATE_READ
} read_state_t;
logic [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam logic [1:0]
TLP_STATE_IDLE = 2'd0,
TLP_STATE_HEADER = 2'd1,
TLP_STATE_TRANSFER = 2'd2;
typedef enum logic [1:0] {
TLP_STATE_IDLE,
TLP_STATE_HEADER,
TLP_STATE_TRANSFER
} tlp_state_t;
logic [1:0] tlp_state_reg = TLP_STATE_IDLE, tlp_state_next;
tlp_state_t tlp_state_reg = TLP_STATE_IDLE, tlp_state_next;
localparam logic [1:0]
TLP_OUTPUT_STATE_IDLE = 2'd0,
TLP_OUTPUT_STATE_HEADER = 2'd1,
TLP_OUTPUT_STATE_PAYLOAD = 2'd2,
TLP_OUTPUT_STATE_PASSTHROUGH = 2'd3;
typedef enum logic [1:0] {
TLP_OUTPUT_STATE_IDLE,
TLP_OUTPUT_STATE_HEADER,
TLP_OUTPUT_STATE_PAYLOAD,
TLP_OUTPUT_STATE_PASSTHROUGH
} tlp_output_state_t;
logic [1:0] tlp_output_state_reg = TLP_OUTPUT_STATE_IDLE, tlp_output_state_next;
tlp_output_state_t tlp_output_state_reg = TLP_OUTPUT_STATE_IDLE, tlp_output_state_next;
// datapath control signals
logic mask_fifo_we;

View File

@@ -92,11 +92,12 @@ if (m_axis_rx.DATA_W != DATA_W)
if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -105,17 +106,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -130,15 +134,17 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PREAMBLE = 2'd1,
STATE_PAYLOAD = 2'd2,
STATE_LAST = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_PAYLOAD,
STATE_LAST
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;

View File

@@ -93,11 +93,12 @@ if (m_axis_rx.DATA_W != DATA_W)
if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -106,17 +107,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -131,14 +135,16 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PAYLOAD = 2'd1,
STATE_LAST = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PAYLOAD,
STATE_LAST
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic lanes_swapped_reg = 1'b0;
logic lanes_swapped_d1_reg = 1'b0;

View File

@@ -102,11 +102,12 @@ if (s_axis_tx.DATA_W != DATA_W)
if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -115,17 +116,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -140,9 +144,10 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
localparam [2:0]
typedef enum logic [2:0] {
OUTPUT_TYPE_IDLE = 3'd0,
OUTPUT_TYPE_ERROR = 3'd1,
OUTPUT_TYPE_START = 3'd2,
@@ -150,20 +155,22 @@ localparam [2:0]
OUTPUT_TYPE_TERM_0 = 3'd4,
OUTPUT_TYPE_TERM_1 = 3'd5,
OUTPUT_TYPE_TERM_2 = 3'd6,
OUTPUT_TYPE_TERM_3 = 3'd7;
OUTPUT_TYPE_TERM_3 = 3'd7
} out_type_t;
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_PREAMBLE = 4'd1,
STATE_PAYLOAD = 4'd2,
STATE_PAD = 4'd3,
STATE_FCS_1 = 4'd4,
STATE_FCS_2 = 4'd5,
STATE_FCS_3 = 4'd6,
STATE_ERR = 4'd7,
STATE_IFG = 4'd8;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_PAYLOAD,
STATE_PAD,
STATE_FCS_1,
STATE_FCS_2,
STATE_FCS_3,
STATE_ERR,
STATE_IFG
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;
@@ -174,8 +181,8 @@ logic [EMPTY_W-1:0] s_empty_reg = '0, s_empty_next;
logic [DATA_W-1:0] fcs_output_data_0;
logic [DATA_W-1:0] fcs_output_data_1;
logic [2:0] fcs_output_type_0;
logic [2:0] fcs_output_type_1;
out_type_t fcs_output_type_0;
out_type_t fcs_output_type_1;
logic [7:0] ifg_offset;
@@ -216,7 +223,7 @@ logic [GBX_CNT-1:0] tx_gbx_sync_reg = '0;
logic [DATA_W-1:0] output_data_reg = '0, output_data_next;
logic [DATA_W-1:0] output_data_d1_reg = '0;
logic [2:0] output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
out_type_t output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
logic start_packet_reg = 1'b0, start_packet_next;

View File

@@ -103,11 +103,12 @@ if (s_axis_tx.DATA_W != DATA_W)
if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -116,17 +117,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -141,9 +145,10 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
localparam [3:0]
typedef enum logic [3:0] {
OUTPUT_TYPE_IDLE = 4'd0,
OUTPUT_TYPE_ERROR = 4'd1,
OUTPUT_TYPE_START_0 = 4'd2,
@@ -156,18 +161,20 @@ localparam [3:0]
OUTPUT_TYPE_TERM_4 = 4'd12,
OUTPUT_TYPE_TERM_5 = 4'd13,
OUTPUT_TYPE_TERM_6 = 4'd14,
OUTPUT_TYPE_TERM_7 = 4'd15;
OUTPUT_TYPE_TERM_7 = 4'd15
} out_type_t;
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_PAYLOAD = 3'd1,
STATE_PAD = 3'd2,
STATE_FCS_1 = 3'd3,
STATE_FCS_2 = 3'd4,
STATE_ERR = 3'd5,
STATE_IFG = 3'd6;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_PAYLOAD,
STATE_PAD,
STATE_FCS_1,
STATE_FCS_2,
STATE_ERR,
STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;
@@ -184,8 +191,8 @@ logic [EMPTY_W-1:0] s_empty_reg = '0, s_empty_next;
logic [DATA_W-1:0] fcs_output_data_0;
logic [DATA_W-1:0] fcs_output_data_1;
logic [3:0] fcs_output_type_0;
logic [3:0] fcs_output_type_1;
out_type_t fcs_output_type_0;
out_type_t fcs_output_type_1;
logic [7:0] ifg_offset;
@@ -226,7 +233,7 @@ logic encoded_tx_hdr_valid_reg = 1'b0;
logic [GBX_CNT-1:0] tx_gbx_sync_reg = '0;
logic [DATA_W-1:0] output_data_reg = '0, output_data_next;
logic [3:0] output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
out_type_t output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
logic [1:0] start_packet_reg = 2'b00;

View File

@@ -87,16 +87,18 @@ if (m_axis_rx.DATA_W != DATA_W)
if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PIPE = 2'd1,
STATE_PAYLOAD = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PIPE,
STATE_PAYLOAD
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;

View File

@@ -91,20 +91,22 @@ if (s_axis_tx.DATA_W != DATA_W)
if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_PREAMBLE = 3'd1,
STATE_PAYLOAD = 3'd2,
STATE_LAST = 3'd3,
STATE_PAD = 3'd4,
STATE_FCS = 3'd5,
STATE_IFG = 3'd6;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_PAYLOAD,
STATE_LAST,
STATE_PAD,
STATE_FCS,
STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;

View File

@@ -88,23 +88,35 @@ if (m_axis_rx.DATA_W != DATA_W)
if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0]
XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe;
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe,
XGMII_SEQ_OS = 8'h9c,
XGMII_RES_0 = 8'h1c,
XGMII_RES_1 = 8'h3c,
XGMII_RES_2 = 8'h7c,
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PREAMBLE = 2'd1,
STATE_PAYLOAD = 2'd2,
STATE_LAST = 2'd3;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_PAYLOAD,
STATE_LAST
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic term_present_reg = 1'b0;
logic term_first_cycle_reg = 1'b0;

View File

@@ -89,22 +89,34 @@ if (m_axis_rx.DATA_W != DATA_W)
if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0]
XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe;
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe,
XGMII_SEQ_OS = 8'h9c,
XGMII_RES_0 = 8'h1c,
XGMII_RES_1 = 8'h3c,
XGMII_RES_2 = 8'h7c,
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PAYLOAD = 2'd1,
STATE_LAST = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PAYLOAD,
STATE_LAST
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic lanes_swapped_reg = 1'b0;
logic lanes_swapped_d1_reg = 1'b0;
@@ -120,7 +132,6 @@ logic framing_error_reg = 1'b0, framing_error_d0_reg = 1'b0;
logic [DATA_W-1:0] xgmii_rxd_d0_reg = '0;
logic [DATA_W-1:0] xgmii_rxd_d1_reg = '0;
logic xgmii_start_swap_reg = 1'b0;
logic xgmii_start_d0_reg = 1'b0;
logic xgmii_start_d1_reg = 1'b0;

View File

@@ -98,28 +98,40 @@ if (s_axis_tx.DATA_W != DATA_W)
if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0]
XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe;
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe,
XGMII_SEQ_OS = 8'h9c,
XGMII_RES_0 = 8'h1c,
XGMII_RES_1 = 8'h3c,
XGMII_RES_2 = 8'h7c,
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_PREAMBLE = 4'd1,
STATE_PAYLOAD = 4'd2,
STATE_PAD = 4'd3,
STATE_FCS_1 = 4'd4,
STATE_FCS_2 = 4'd5,
STATE_FCS_3 = 4'd6,
STATE_ERR = 4'd7,
STATE_IFG = 4'd8;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_PAYLOAD,
STATE_PAD,
STATE_FCS_1,
STATE_FCS_2,
STATE_FCS_3,
STATE_ERR,
STATE_IFG
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;

View File

@@ -99,26 +99,38 @@ if (s_axis_tx.DATA_W != DATA_W)
if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0]
typedef enum logic [7:0] {
ETH_PRE = 8'h55,
ETH_SFD = 8'hD5;
ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0]
XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe;
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe,
XGMII_SEQ_OS = 8'h9c,
XGMII_RES_0 = 8'h1c,
XGMII_RES_1 = 8'h3c,
XGMII_RES_2 = 8'h7c,
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_PAYLOAD = 3'd1,
STATE_PAD = 3'd2,
STATE_FCS_1 = 3'd3,
STATE_FCS_2 = 3'd4,
STATE_ERR = 3'd5,
STATE_IFG = 3'd6;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_PAYLOAD,
STATE_PAD,
STATE_FCS_1,
STATE_FCS_2,
STATE_ERR,
STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
// datapath control signals
logic reset_crc;

View File

@@ -63,7 +63,7 @@ if (CTRL_W * 8 != DATA_W)
if (HDR_W != 2)
$fatal(0, "Error: HDR_W must be 2");
localparam [7:0]
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
@@ -76,9 +76,10 @@ localparam [7:0]
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c;
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -87,17 +88,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -112,7 +116,8 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
wire [DATA_W_INT-1:0] encoded_rx_data_int;
wire encoded_rx_data_valid_int;

View File

@@ -67,7 +67,7 @@ if (CTRL_W * 8 != DATA_W)
if (HDR_W != 2)
$fatal(0, "Error: HDR_W must be 2");
localparam [7:0]
typedef enum logic [7:0] {
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
@@ -80,9 +80,10 @@ localparam [7:0]
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c;
XGMII_SIG_OS = 8'h5c
} xgmii_ctrl_t;
localparam [6:0]
typedef enum logic [6:0] {
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
@@ -91,17 +92,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
CTRL_RES_5 = 7'h78
} baser_ctrl_t;
localparam [3:0]
typedef enum logic [3:0] {
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
O_SIG_OS = 4'hf
} baser_o_t;
localparam [1:0]
typedef enum logic [1:0] {
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
SYNC_CTRL = 2'b01
} baser_sync_t;
localparam [7:0]
typedef enum logic [7:0] {
BLOCK_TYPE_CTRL = 8'h1e, // C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4 = 8'h2d, // D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4 = 8'h33, // D7 D6 D5 C3 C2 C1 C0 BT
@@ -116,7 +120,8 @@ localparam [7:0]
BLOCK_TYPE_TERM_4 = 8'hcc, // C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5 = 8'hd2, // C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6 = 8'he1, // C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff; // D6 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7 = 8'hff // D6 D5 D4 D3 D2 D1 D0 BT
} baser_block_type_t;
wire [DATA_W_INT-1:0] xgmii_txd_int;
wire [CTRL_W_INT-1:0] xgmii_txc_int;

View File

@@ -116,14 +116,16 @@ reset_sync_inst (
.out(rx_reset_sync)
);
localparam [2:0]
STATE_RESET = 3'd0,
STATE_WAIT_LOCK = 3'd1,
STATE_WAIT_CDR = 3'd2,
STATE_WAIT_USRCLK = 3'd3,
STATE_DONE = 3'd4;
typedef enum logic [2:0] {
STATE_RESET,
STATE_WAIT_LOCK,
STATE_WAIT_CDR,
STATE_WAIT_USRCLK,
STATE_DONE
} state_t;
state_t state_reg = STATE_RESET, state_next;
logic [2:0] state_reg = STATE_RESET;
logic [CNT_W-1:0] rx_reset_cnt_reg = '0;
logic [CDR_CNT_W-1:0] rx_reset_cdr_cnt_reg = '0;
logic rx_reset_done_reg = 1'b0;

View File

@@ -103,13 +103,15 @@ reset_sync_inst (
.out(tx_reset_sync)
);
localparam [1:0]
STATE_RESET = 2'd0,
STATE_WAIT_LOCK = 2'd1,
STATE_WAIT_USRCLK = 2'd2,
STATE_DONE = 2'd3;
typedef enum logic [1:0] {
STATE_RESET,
STATE_WAIT_LOCK,
STATE_WAIT_USRCLK,
STATE_DONE
} state_t;
state_t state_reg = STATE_RESET, state_next;
logic [1:0] state_reg = STATE_RESET;
logic [CNT_W-1:0] tx_reset_cnt_reg = '0;
logic tx_reset_done_reg = 1'b0;

View File

@@ -189,14 +189,15 @@ initial begin
init_data[21] = cmd_halt(); // halt
end
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_RUN = 3'd1,
STATE_TABLE_1 = 3'd2,
STATE_TABLE_2 = 3'd3,
STATE_TABLE_3 = 3'd4;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_RUN,
STATE_TABLE_1,
STATE_TABLE_2,
STATE_TABLE_3
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
localparam AW = $clog2(INIT_DATA_LEN);

View File

@@ -158,41 +158,43 @@ if (s_axis_cmd.DATA_W < 12)
if (s_axis_tx.DATA_W != 8 || m_axis_rx.DATA_W != 8)
$fatal(0, "Data interface width must be 8 bits (instance %m)");
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_ACTIVE_WRITE = 4'd1,
STATE_ACTIVE_READ = 4'd2,
STATE_START_WAIT = 4'd3,
STATE_START = 4'd4,
STATE_ADDRESS_1 = 4'd5,
STATE_ADDRESS_2 = 4'd6,
STATE_WRITE_1 = 4'd7,
STATE_WRITE_2 = 4'd8,
STATE_WRITE_3 = 4'd9,
STATE_READ = 4'd10,
STATE_STOP = 4'd11;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_ACTIVE_WRITE,
STATE_ACTIVE_READ,
STATE_START_WAIT,
STATE_START,
STATE_ADDRESS_1,
STATE_ADDRESS_2,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_WRITE_3,
STATE_READ,
STATE_STOP
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
localparam [3:0]
PHY_STATE_IDLE = 4'd0,
PHY_STATE_ACTIVE = 4'd1,
PHY_STATE_REPEATED_START_1 = 4'd2,
PHY_STATE_REPEATED_START_2 = 4'd3,
PHY_STATE_START_1 = 4'd4,
PHY_STATE_START_2 = 4'd5,
PHY_STATE_WRITE_BIT_1 = 4'd6,
PHY_STATE_WRITE_BIT_2 = 4'd7,
PHY_STATE_WRITE_BIT_3 = 4'd8,
PHY_STATE_READ_BIT_1 = 4'd9,
PHY_STATE_READ_BIT_2 = 4'd10,
PHY_STATE_READ_BIT_3 = 4'd11,
PHY_STATE_READ_BIT_4 = 4'd12,
PHY_STATE_STOP_1 = 4'd13,
PHY_STATE_STOP_2 = 4'd14,
PHY_STATE_STOP_3 = 4'd15;
typedef enum logic [3:0] {
PHY_STATE_IDLE,
PHY_STATE_ACTIVE,
PHY_STATE_REPEATED_START_1,
PHY_STATE_REPEATED_START_2,
PHY_STATE_START_1,
PHY_STATE_START_2,
PHY_STATE_WRITE_BIT_1,
PHY_STATE_WRITE_BIT_2,
PHY_STATE_WRITE_BIT_3,
PHY_STATE_READ_BIT_1,
PHY_STATE_READ_BIT_2,
PHY_STATE_READ_BIT_3,
PHY_STATE_READ_BIT_4,
PHY_STATE_STOP_1,
PHY_STATE_STOP_2,
PHY_STATE_STOP_3
} phy_state_t;
logic [3:0] phy_state_reg = STATE_IDLE, phy_state_next;
phy_state_t phy_state_reg = PHY_STATE_IDLE, phy_state_next;
logic phy_start_bit;
logic phy_stop_bit;
@@ -359,7 +361,7 @@ always_comb begin
mode_stop_next = s_axis_cmd_stop;
s_axis_cmd_ready_next = 1'b0;
if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin
// address or mode mismatch or forced start - repeated start
@@ -406,7 +408,7 @@ always_comb begin
mode_stop_next = s_axis_cmd_stop;
s_axis_cmd_ready_next = 1'b0;
if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin
// address or mode mismatch or forced start - repeated start

View File

@@ -39,17 +39,18 @@ module taxi_i2c_single_reg #(
output wire logic [7:0] data_out
);
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_ADDRESS = 3'd1,
STATE_ACK = 3'd2,
STATE_WRITE_1 = 3'd3,
STATE_WRITE_2 = 3'd4,
STATE_READ_1 = 3'd5,
STATE_READ_2 = 3'd6,
STATE_READ_3 = 3'd7;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_ADDRESS,
STATE_ACK,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_READ_1,
STATE_READ_2,
STATE_READ_3
} state_t;
logic [2:0] state_reg = STATE_IDLE;
state_t state_reg = STATE_IDLE;
logic [7:0] data_reg = '0;
logic [7:0] shift_reg = '0;

View File

@@ -75,7 +75,7 @@ This module translates I2C read and write operations into AXI stream transfers.
Bytes written over I2C will be delayed by one byte time so that the last byte
in a write operation can be accurately marked. When reading, the module will
stretch SCL by holding it low until a data byte is presented at the AXI stream
input.
input.
Control:
@@ -139,17 +139,18 @@ I/O pin. This would prevent devices from stretching the clock period.
if (s_axis_tx.DATA_W != 8 || m_axis_rx.DATA_W != 8)
$fatal(0, "Data interface width must be 8 bits (instance %m)");
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_ADDRESS = 3'd1,
STATE_ACK = 3'd2,
STATE_WRITE_1 = 3'd3,
STATE_WRITE_2 = 3'd4,
STATE_READ_1 = 3'd5,
STATE_READ_2 = 3'd6,
STATE_READ_3 = 3'd7;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_ADDRESS,
STATE_ACK,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_READ_1,
STATE_READ_2,
STATE_READ_3
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [6:0] addr_reg = '0, addr_next;
logic [7:0] data_reg = '0, data_next;

View File

@@ -178,15 +178,16 @@ if (2**$clog2(BYTE_LANES) != BYTE_LANES)
if (8*2**$clog2(BYTE_SIZE/8) != BYTE_SIZE)
$fatal(0, "Error: AXI word size must be a power of two multiple of 8 bits (instance %m)");
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_ADDRESS = 3'd1,
STATE_READ_1 = 3'd2,
STATE_READ_2 = 3'd3,
STATE_WRITE_1 = 3'd4,
STATE_WRITE_2 = 3'd5;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_ADDRESS,
STATE_READ_1,
STATE_READ_2,
STATE_WRITE_1,
STATE_WRITE_2
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = '0, count_next;
logic last_cycle_reg = 1'b0;

View File

@@ -181,15 +181,16 @@ if (2**$clog2(BYTE_LANES) != BYTE_LANES)
if (8*2**$clog2(BYTE_SIZE/8) != BYTE_SIZE)
$fatal(0, "Error: AXI word size must be a power of two multiple of 8 bits (instance %m)");
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_ADDRESS = 3'd1,
STATE_READ_1 = 3'd2,
STATE_READ_2 = 3'd3,
STATE_WRITE_1 = 3'd4,
STATE_WRITE_2 = 3'd5;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_ADDRESS,
STATE_READ_1,
STATE_READ_2,
STATE_WRITE_1,
STATE_WRITE_2
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = '0, count_next;
logic last_cycle_reg = 1'b0;

View File

@@ -44,12 +44,13 @@ module taxi_mdio_master (
input wire logic [7:0] prescale
);
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_PREAMBLE = 2'd1,
STATE_TRANSFER = 2'd2;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_PREAMBLE,
STATE_TRANSFER
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = '0, count_next;
logic [5:0] bit_count_reg = '0, bit_count_next;

View File

@@ -89,36 +89,40 @@ if (AXIL_DATA_W != 32)
if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface requires byte (8-bit) granularity (instance %m)");
localparam [2:0]
typedef enum logic [2:0] {
TLP_FMT_3DW = 3'b000,
TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011,
TLP_FMT_PREFIX = 3'b100;
TLP_FMT_PREFIX = 3'b100
} tlp_fmt_t;
localparam [2:0]
typedef enum logic [2:0] {
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
CPL_STATUS_CA = 3'b100 // completer abort
} cpl_status_t;
localparam [2:0]
REQ_STATE_IDLE = 3'd0,
REQ_STATE_READ_1 = 3'd1,
REQ_STATE_READ_2 = 3'd2,
REQ_STATE_WRITE_1 = 3'd3,
REQ_STATE_WRITE_2 = 3'd4,
REQ_STATE_WAIT_END = 3'd5;
typedef enum logic [2:0] {
REQ_STATE_IDLE,
REQ_STATE_READ_1,
REQ_STATE_READ_2,
REQ_STATE_WRITE_1,
REQ_STATE_WRITE_2,
REQ_STATE_WAIT_END
} req_state_t;
logic [2:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam [1:0]
RESP_STATE_IDLE = 2'd0,
RESP_STATE_READ = 2'd1,
RESP_STATE_WRITE = 2'd2,
RESP_STATE_CPL = 2'd3;
typedef enum logic [1:0] {
RESP_STATE_IDLE,
RESP_STATE_READ,
RESP_STATE_WRITE,
RESP_STATE_CPL
} resp_state_t;
logic [1:0] resp_state_reg = RESP_STATE_IDLE, resp_state_next;
resp_state_t resp_state_reg = RESP_STATE_IDLE, resp_state_next;
logic [AXIL_ADDR_W-1:0] req_addr_reg = '0, req_addr_next;
logic [TLP_DATA_W-1:0] req_data_reg = '0, req_data_next;

View File

@@ -87,32 +87,36 @@ if (AXIL_DATA_W != 32)
if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface requires byte (8-bit) granularity (instance %m)");
localparam [2:0]
typedef enum logic [2:0] {
TLP_FMT_3DW = 3'b000,
TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011,
TLP_FMT_PREFIX = 3'b100;
TLP_FMT_PREFIX = 3'b100
} tlp_fmt_t;
localparam [2:0]
typedef enum logic [2:0] {
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
CPL_STATUS_CA = 3'b100 // completer abort
} cpl_status_t;
localparam [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_WAIT_END = 1'd1;
typedef enum logic [0:0] {
REQ_STATE_IDLE,
REQ_STATE_WAIT_END
} req_state_t;
logic [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
req_state_t req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam [1:0]
RESP_STATE_IDLE = 2'd0,
RESP_STATE_READ = 2'd1,
RESP_STATE_WRITE = 2'd2,
RESP_STATE_CPL = 2'd3;
typedef enum logic [1:0] {
RESP_STATE_IDLE,
RESP_STATE_READ,
RESP_STATE_WRITE,
RESP_STATE_CPL
} resp_state_t;
logic [1:0] resp_state_reg = RESP_STATE_IDLE, resp_state_next;
resp_state_t resp_state_reg = RESP_STATE_IDLE, resp_state_next;
logic [2:0] rx_req_tlp_hdr_fmt;
logic [4:0] rx_req_tlp_hdr_type;

View File

@@ -0,0 +1,469 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2022-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe MSI-X module with APB interface
*/
module taxi_pcie_msix_apb #
(
// TLP interface configuration
parameter logic TLP_FORCE_64_BIT_ADDR = 1'b0
)
(
input wire logic clk,
input wire logic rst,
/*
* APB interface for MSI-X tables
*/
taxi_apb_if.slv s_apb,
/*
* Interrupt request input
*/
taxi_axis_if.snk s_axis_irq,
/*
* Memory write TLP output
*/
taxi_pcie_tlp_if.src tx_wr_req_tlp,
/*
* Configuration
*/
input wire logic [7:0] bus_num,
input wire logic [7:0] func_num,
input wire logic msix_enable,
input wire logic msix_mask
);
// extract parameters
localparam TLP_SEGS = tx_wr_req_tlp.SEGS;
localparam TLP_SEG_DATA_W = tx_wr_req_tlp.SEG_DATA_W;
localparam TLP_SEG_EMPTY_W = tx_wr_req_tlp.SEG_EMPTY_W;
localparam TLP_DATA_W = TLP_SEGS*TLP_SEG_DATA_W;
localparam TLP_HDR_W = tx_wr_req_tlp.HDR_W;
localparam FUNC_NUM_W = tx_wr_req_tlp.FUNC_NUM_W;
localparam APB_DATA_W = s_apb.DATA_W;
localparam APB_ADDR_W = s_apb.ADDR_W;
localparam APB_STRB_W = s_apb.STRB_W;
localparam IRQ_INDEX_W = s_axis_irq.DATA_W;
localparam TLP_DATA_W_B = TLP_DATA_W/8;
localparam TLP_DATA_W_DW = TLP_DATA_W/32;
localparam TBL_ADDR_W = IRQ_INDEX_W+1;
localparam PBA_ADDR_W = IRQ_INDEX_W > 6 ? IRQ_INDEX_W-6 : 0;
localparam PBA_ADDR_W_INT = PBA_ADDR_W > 0 ? PBA_ADDR_W : 1;
localparam INDEX_SHIFT = $clog2(64/8);
localparam WORD_SELECT_SHIFT = $clog2(APB_DATA_W/8);
localparam WORD_SELECT_W = 64 > APB_DATA_W ? $clog2((64+7)/8) - $clog2(APB_DATA_W/8) : 1;
localparam RATIO = 64/APB_DATA_W;
// bus width assertions
if (APB_STRB_W * 8 != APB_DATA_W)
$fatal(0, "Error: APB interface requires byte (8-bit) granularity (instance %m)");
if (APB_DATA_W > 64)
$fatal(0, "Error: APB data width must be 64 or less (instance %m)");
if (APB_ADDR_W < IRQ_INDEX_W+5)
$fatal(0, "Error: APB address width too narrow (instance %m)");
if (IRQ_INDEX_W > 11)
$fatal(0, "Error: IRQ index width must be 11 or less (instance %m)");
typedef enum logic [2:0] {
TLP_FMT_3DW = 3'b000,
TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011,
TLP_FMT_PREFIX = 3'b100
} tlp_fmt_t;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_READ_TBL_1,
STATE_READ_TBL_2,
STATE_SEND_TLP
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic [IRQ_INDEX_W-1:0] irq_index_reg = '0, irq_index_next;
logic [63:0] vec_addr_reg = '0, vec_addr_next;
logic [31:0] vec_data_reg = '0, vec_data_next;
logic vec_mask_reg = 1'b0, vec_mask_next;
logic [127:0] tlp_hdr;
logic tbl_apb_mem_rd_en;
logic tbl_apb_mem_wr_en;
logic [7:0] tbl_apb_mem_wr_be;
logic [63:0] tbl_apb_mem_wr_data;
logic pba_apb_mem_rd_en;
logic tbl_mem_rd_en;
logic [TBL_ADDR_W-1:0] tbl_mem_addr;
logic pba_mem_rd_en;
logic pba_mem_wr_en;
logic [PBA_ADDR_W-1:0] pba_mem_addr;
logic [63:0] pba_mem_wr_data;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic irq_ready_reg = 1'b0, irq_ready_next;
logic [31:0] tx_wr_req_tlp_data_reg = '0, tx_wr_req_tlp_data_next;
logic [TLP_HDR_W-1:0] tx_wr_req_tlp_hdr_reg = '0, tx_wr_req_tlp_hdr_next;
logic tx_wr_req_tlp_valid_reg = 0, tx_wr_req_tlp_valid_next;
logic msix_enable_reg = 1'b0;
logic msix_mask_reg = 1'b0;
// MSI-X table
(* ramstyle = "no_rw_check, mlab" *)
logic [63:0] tbl_mem[2**TBL_ADDR_W];
// MSI-X PBA
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [63:0] pba_mem[2**PBA_ADDR_W];
logic tbl_rd_data_valid_reg = 1'b0, tbl_rd_data_valid_next;
logic pba_rd_data_valid_reg = 1'b0, pba_rd_data_valid_next;
logic [WORD_SELECT_W-1:0] rd_data_shift_reg = '0, rd_data_shift_next;
logic [63:0] tbl_mem_rd_data_reg = '0;
logic [63:0] pba_mem_rd_data_reg = '0;
logic [63:0] tbl_apb_mem_rd_data_reg = '0;
logic [63:0] pba_apb_mem_rd_data_reg = '0;
wire [TBL_ADDR_W-1:0] s_apb_paddr_index = s_apb.paddr[INDEX_SHIFT +: TBL_ADDR_W];
wire [WORD_SELECT_W-1:0] s_apb_paddr_word = APB_DATA_W < 64 ? s_apb.paddr[WORD_SELECT_SHIFT +: WORD_SELECT_W] : 0;
assign s_apb.pready = s_apb_pready_reg;
assign s_apb.prdata = s_apb_prdata_reg;
assign s_apb.pslverr = 1'b0;
assign s_apb.pruser = '0;
assign s_apb.pbuser = '0;
assign s_axis_irq.tready = irq_ready_reg;
assign tx_wr_req_tlp.data = TLP_DATA_W'(tx_wr_req_tlp_data_reg);
assign tx_wr_req_tlp.empty = '1;
assign tx_wr_req_tlp.hdr = tx_wr_req_tlp_hdr_reg;
assign tx_wr_req_tlp.seq = '0;
assign tx_wr_req_tlp.bar_id = '0;
assign tx_wr_req_tlp.func_num = '0;
assign tx_wr_req_tlp.error = '0;
assign tx_wr_req_tlp.valid = tx_wr_req_tlp_valid_reg;
assign tx_wr_req_tlp.sop = 1'b1;
assign tx_wr_req_tlp.eop = 1'b1;
initial begin
for (integer i = 0; i < 2**TBL_ADDR_W; i = i + 1) begin
tbl_mem[i] = '0;
end
for (integer i = 0; i < 2**PBA_ADDR_W; i = i + 1) begin
pba_mem[i] = '0;
end
end
always_comb begin
state_next = STATE_IDLE;
tbl_mem_rd_en = 1'b0;
tbl_mem_addr = {irq_index_reg, 1'b0};
pba_mem_rd_en = 1'b0;
pba_mem_wr_en = 1'b0;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_reg >> 6);
pba_mem_wr_data = '0;
irq_index_next = irq_index_reg;
vec_addr_next = vec_addr_reg;
vec_data_next = vec_data_reg;
vec_mask_next = vec_mask_reg;
irq_ready_next = 1'b0;
tx_wr_req_tlp_data_next = tx_wr_req_tlp_data_reg;
tx_wr_req_tlp_hdr_next = tx_wr_req_tlp_hdr_reg;
tx_wr_req_tlp_valid_next = tx_wr_req_tlp_valid_reg && !tx_wr_req_tlp.ready;
// TLP header
// DW 0
if (((vec_addr_reg[63:2] >> 30) != 0) || TLP_FORCE_64_BIT_ADDR) begin
tlp_hdr[127:125] = TLP_FMT_4DW_DATA; // fmt - 4DW with data
end else begin
tlp_hdr[127:125] = TLP_FMT_3DW_DATA; // fmt - 3DW with data
end
tlp_hdr[124:120] = 5'b00000; // type - write
tlp_hdr[119] = 1'b0; // T9
tlp_hdr[118:116] = 3'b000; // TC
tlp_hdr[115] = 1'b0; // T8
tlp_hdr[114] = 1'b0; // attr
tlp_hdr[113] = 1'b0; // LN
tlp_hdr[112] = 1'b0; // TH
tlp_hdr[111] = 1'b0; // TD
tlp_hdr[110] = 1'b0; // EP
tlp_hdr[109:108] = 2'b00; // attr
tlp_hdr[107:106] = 2'b00; // AT
tlp_hdr[105:96] = 10'd1; // length
// DW 1
tlp_hdr[95:88] = bus_num; // requester ID (bus number)
tlp_hdr[87:80] = func_num; // requester ID (device/function number)
tlp_hdr[79:72] = 8'd0; // tag
tlp_hdr[71:68] = 4'b0000; // last BE
tlp_hdr[67:64] = 4'b1111; // first BE
if ((vec_addr_reg[63:32] != 0) || TLP_FORCE_64_BIT_ADDR) begin
// DW 2+3
tlp_hdr[63:2] = vec_addr_reg[63:2]; // address
tlp_hdr[1:0] = 2'b00; // PH
end else begin
// DW 2
tlp_hdr[63:34] = vec_addr_reg[31:2]; // address
tlp_hdr[33:32] = 2'b00; // PH
// DW 3
tlp_hdr[31:0] = 32'd0;
end
case (state_reg)
STATE_IDLE: begin
irq_ready_next = 1'b1;
if (s_axis_irq.tvalid && s_axis_irq.tready) begin
// new request
irq_ready_next = 1'b0;
irq_index_next = s_axis_irq.tdata;
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_next, 1'b0};
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_READ_TBL_1;
end else if (!s_axis_irq.tvalid && msix_enable_reg && !msix_mask_reg) begin
// no new request waiting, scan PBA for masked requests
if (pba_mem_rd_data_reg[6'(irq_index_reg)] != 0) begin
// PBA bit for current index is set, try issuing it
irq_ready_next = 1'b0;
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_next, 1'b0};
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_READ_TBL_1;
end else begin
// PBA bit for current index is not set
if (pba_mem_rd_data_reg != 0) begin
// at least one bit set in current group, move to next index
irq_index_next = irq_index_reg + 1;
end else begin
// no bits set in current group, move to next group
irq_index_next = (irq_index_reg & ({IRQ_INDEX_W{1'b1}} << 6)) + 'd64;
end
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_TBL_1: begin
// handle first table read
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_reg, 1'b1};
vec_addr_next = {tbl_mem_rd_data_reg[63:2], 2'b00};
state_next = STATE_READ_TBL_2;
end
STATE_READ_TBL_2: begin
// handle second table read
vec_data_next = tbl_mem_rd_data_reg[31:0];
vec_mask_next = tbl_mem_rd_data_reg[32];
if (msix_enable_reg && !msix_mask_reg && !vec_mask_next) begin
// send TLP
state_next = STATE_SEND_TLP;
end else begin
// set PBA bit
pba_mem_wr_en = 1'b1;
pba_mem_wr_data = pba_mem_rd_data_reg | (1 << 6'(irq_index_reg));
irq_ready_next = 1'b1;
state_next = STATE_IDLE;
end
end
STATE_SEND_TLP: begin
if (!tx_wr_req_tlp.valid || tx_wr_req_tlp.ready) begin
// send TLP
tx_wr_req_tlp_data_next = vec_data_reg;
tx_wr_req_tlp_hdr_next = tlp_hdr;
tx_wr_req_tlp_valid_next = 1'b1;
// clear PBA bit
pba_mem_wr_en = 1'b1;
pba_mem_wr_data = pba_mem_rd_data_reg & ~(1 << 6'(irq_index_reg));
// increment index so we don't check the same PBA bit immediately
irq_index_next = irq_index_reg + 1;
irq_ready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_SEND_TLP;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
irq_index_reg <= irq_index_next;
vec_addr_reg <= vec_addr_next;
vec_data_reg <= vec_data_next;
vec_mask_reg <= vec_mask_next;
irq_ready_reg <= irq_ready_next;
tx_wr_req_tlp_data_reg <= tx_wr_req_tlp_data_next;
tx_wr_req_tlp_hdr_reg <= tx_wr_req_tlp_hdr_next;
tx_wr_req_tlp_valid_reg <= tx_wr_req_tlp_valid_next;
msix_enable_reg <= msix_enable;
msix_mask_reg <= msix_mask;
if (tbl_mem_rd_en) begin
tbl_mem_rd_data_reg <= tbl_mem[tbl_mem_addr];
end
if (pba_mem_wr_en) begin
pba_mem[pba_mem_addr] <= pba_mem_wr_data;
end else if (pba_mem_rd_en) begin
pba_mem_rd_data_reg <= pba_mem[pba_mem_addr];
end
if (rst) begin
state_reg <= STATE_IDLE;
irq_ready_reg <= 1'b0;
tx_wr_req_tlp_valid_reg <= 1'b0;
end
end
// APB interface
always_comb begin
tbl_apb_mem_rd_en = 1'b0;
tbl_apb_mem_wr_en = 1'b0;
tbl_apb_mem_wr_be = 8'(s_apb.pstrb << (s_apb_paddr_word * APB_STRB_W));
tbl_apb_mem_wr_data = {RATIO{s_apb.pwdata}};
pba_apb_mem_rd_en = 1'b0;
tbl_rd_data_valid_next = 1'b0;
pba_rd_data_valid_next = 1'b0;
rd_data_shift_next = rd_data_shift_reg;
s_apb_pready_next = 1'b0;
s_apb_prdata_next = s_apb_prdata_reg;
if (tbl_rd_data_valid_reg || pba_rd_data_valid_reg) begin
s_apb_pready_next = !s_apb_pready_reg;
tbl_rd_data_valid_next = 1'b0;
pba_rd_data_valid_next = 1'b0;
if (tbl_rd_data_valid_reg) begin
if (APB_DATA_W < 64) begin
s_apb_prdata_next = APB_DATA_W'(tbl_apb_mem_rd_data_reg >> rd_data_shift_reg*APB_DATA_W);
end else begin
s_apb_prdata_next = APB_DATA_W'(tbl_apb_mem_rd_data_reg);
end
end else begin
if (APB_DATA_W < 64) begin
s_apb_prdata_next = APB_DATA_W'(pba_apb_mem_rd_data_reg >> rd_data_shift_reg*APB_DATA_W);
end else begin
s_apb_prdata_next = APB_DATA_W'(pba_apb_mem_rd_data_reg);
end
end
end
if (s_apb.psel && s_apb.penable) begin
rd_data_shift_next = s_apb_paddr_word;
if (s_apb.pwrite) begin
s_apb_pready_next = !s_apb_pready_reg;
if (s_apb.paddr[IRQ_INDEX_W+5-1] == 0) begin
tbl_apb_mem_wr_en = !s_apb_pready_reg;
end
end else begin
if (s_apb.paddr[IRQ_INDEX_W+5-1] == 0) begin
tbl_apb_mem_rd_en = 1'b1;
tbl_rd_data_valid_next = !s_apb_pready_reg;
end else begin
pba_apb_mem_rd_en = 1'b1;
pba_rd_data_valid_next = !s_apb_pready_reg;
end
end
end
end
always_ff @(posedge clk) begin
tbl_rd_data_valid_reg <= tbl_rd_data_valid_next;
pba_rd_data_valid_reg <= pba_rd_data_valid_next;
rd_data_shift_reg <= rd_data_shift_next;
s_apb_pready_reg <= s_apb_pready_next;
s_apb_prdata_reg <= s_apb_prdata_next;
if (tbl_apb_mem_rd_en) begin
tbl_apb_mem_rd_data_reg <= tbl_mem[s_apb_paddr_index];
end else begin
for (integer i = 0; i < 8; i = i + 1) begin
if (tbl_apb_mem_wr_en && tbl_apb_mem_wr_be[i]) begin
tbl_mem[s_apb_paddr_index][8*i +: 8] <= tbl_apb_mem_wr_data[8*i +: 8];
end
end
end
if (pba_apb_mem_rd_en) begin
pba_apb_mem_rd_data_reg <= pba_mem[s_apb_paddr_index[PBA_ADDR_W-1:0]];
end
if (rst) begin
tbl_rd_data_valid_reg <= 1'b0;
pba_rd_data_valid_reg <= 1'b0;
s_apb_pready_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -0,0 +1,517 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2022-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe MSI-X module with AXI lite interface
*/
module taxi_pcie_msix_axil #
(
// TLP interface configuration
parameter logic TLP_FORCE_64_BIT_ADDR = 1'b0
)
(
input wire logic clk,
input wire logic rst,
/*
* AXI lite interface for MSI-X tables
*/
taxi_axil_if.wr_slv s_axil_wr,
taxi_axil_if.rd_slv s_axil_rd,
/*
* Interrupt request input
*/
taxi_axis_if.snk s_axis_irq,
/*
* Memory write TLP output
*/
taxi_pcie_tlp_if.src tx_wr_req_tlp,
/*
* Configuration
*/
input wire logic [7:0] bus_num,
input wire logic [7:0] func_num,
input wire logic msix_enable,
input wire logic msix_mask
);
// extract parameters
localparam TLP_SEGS = tx_wr_req_tlp.SEGS;
localparam TLP_SEG_DATA_W = tx_wr_req_tlp.SEG_DATA_W;
localparam TLP_SEG_EMPTY_W = tx_wr_req_tlp.SEG_EMPTY_W;
localparam TLP_DATA_W = TLP_SEGS*TLP_SEG_DATA_W;
localparam TLP_HDR_W = tx_wr_req_tlp.HDR_W;
localparam FUNC_NUM_W = tx_wr_req_tlp.FUNC_NUM_W;
localparam AXIL_DATA_W = s_axil_wr.DATA_W;
localparam AXIL_ADDR_W = s_axil_wr.ADDR_W;
localparam AXIL_STRB_W = s_axil_wr.STRB_W;
localparam IRQ_INDEX_W = s_axis_irq.DATA_W;
localparam TLP_DATA_W_B = TLP_DATA_W/8;
localparam TLP_DATA_W_DW = TLP_DATA_W/32;
localparam TBL_ADDR_W = IRQ_INDEX_W+1;
localparam PBA_ADDR_W = IRQ_INDEX_W > 6 ? IRQ_INDEX_W-6 : 0;
localparam PBA_ADDR_W_INT = PBA_ADDR_W > 0 ? PBA_ADDR_W : 1;
localparam INDEX_SHIFT = $clog2(64/8);
localparam WORD_SELECT_SHIFT = $clog2(AXIL_DATA_W/8);
localparam WORD_SELECT_W = 64 > AXIL_DATA_W ? $clog2((64+7)/8) - $clog2(AXIL_DATA_W/8) : 1;
localparam RATIO = 64/AXIL_DATA_W;
// bus width assertions
if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface requires byte (8-bit) granularity (instance %m)");
if (AXIL_DATA_W > 64)
$fatal(0, "Error: AXI lite data width must be 64 or less (instance %m)");
if (AXIL_ADDR_W < IRQ_INDEX_W+5)
$fatal(0, "Error: AXI lite address width too narrow (instance %m)");
if (IRQ_INDEX_W > 11)
$fatal(0, "Error: IRQ index width must be 11 or less (instance %m)");
typedef enum logic [2:0] {
TLP_FMT_3DW = 3'b000,
TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011,
TLP_FMT_PREFIX = 3'b100
} tlp_fmt_t;
typedef enum logic [1:0] {
STATE_IDLE,
STATE_READ_TBL_1,
STATE_READ_TBL_2,
STATE_SEND_TLP
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic [IRQ_INDEX_W-1:0] irq_index_reg = '0, irq_index_next;
logic [63:0] vec_addr_reg = '0, vec_addr_next;
logic [31:0] vec_data_reg = '0, vec_data_next;
logic vec_mask_reg = 1'b0, vec_mask_next;
logic last_read_reg = 1'b0, last_read_next;
logic [127:0] tlp_hdr;
logic read_eligible;
logic write_eligible;
logic tbl_axil_mem_rd_en;
logic tbl_axil_mem_wr_en;
logic [7:0] tbl_axil_mem_wr_be;
logic [63:0] tbl_axil_mem_wr_data;
logic pba_axil_mem_rd_en;
logic tbl_mem_rd_en;
logic [TBL_ADDR_W-1:0] tbl_mem_addr;
logic pba_mem_rd_en;
logic pba_mem_wr_en;
logic [PBA_ADDR_W-1:0] pba_mem_addr;
logic [63:0] pba_mem_wr_data;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
logic s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
logic s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next;
logic irq_ready_reg = 1'b0, irq_ready_next;
logic [31:0] tx_wr_req_tlp_data_reg = '0, tx_wr_req_tlp_data_next;
logic [TLP_HDR_W-1:0] tx_wr_req_tlp_hdr_reg = '0, tx_wr_req_tlp_hdr_next;
logic tx_wr_req_tlp_valid_reg = 0, tx_wr_req_tlp_valid_next;
logic msix_enable_reg = 1'b0;
logic msix_mask_reg = 1'b0;
// MSI-X table
(* ramstyle = "no_rw_check, mlab" *)
logic [63:0] tbl_mem[2**TBL_ADDR_W];
// MSI-X PBA
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [63:0] pba_mem[2**PBA_ADDR_W];
logic tbl_rd_data_valid_reg = 1'b0, tbl_rd_data_valid_next;
logic pba_rd_data_valid_reg = 1'b0, pba_rd_data_valid_next;
logic [WORD_SELECT_W-1:0] rd_data_shift_reg = '0, rd_data_shift_next;
logic [63:0] tbl_mem_rd_data_reg = '0;
logic [63:0] pba_mem_rd_data_reg = '0;
logic [63:0] tbl_axil_mem_rd_data_reg = '0;
logic [63:0] pba_axil_mem_rd_data_reg = '0;
wire [TBL_ADDR_W-1:0] s_axil_awaddr_index = s_axil_wr.awaddr[INDEX_SHIFT +: TBL_ADDR_W];
wire [WORD_SELECT_W-1:0] s_axil_awaddr_word = AXIL_DATA_W < 64 ? s_axil_wr.awaddr[WORD_SELECT_SHIFT +: WORD_SELECT_W] : 0;
wire [TBL_ADDR_W-1:0] s_axil_araddr_index = s_axil_rd.araddr[INDEX_SHIFT +: TBL_ADDR_W];
wire [WORD_SELECT_W-1:0] s_axil_araddr_word = AXIL_DATA_W < 64 ? s_axil_rd.araddr[WORD_SELECT_SHIFT +: WORD_SELECT_W] : 0;
assign s_axil_wr.awready = s_axil_awready_reg;
assign s_axil_wr.wready = s_axil_wready_reg;
assign s_axil_wr.bresp = 2'b00;
assign s_axil_wr.buser = '0;
assign s_axil_wr.bvalid = s_axil_bvalid_reg;
assign s_axil_rd.arready = s_axil_arready_reg;
assign s_axil_rd.rdata = s_axil_rdata_reg;
assign s_axil_rd.rresp = 2'b00;
assign s_axil_rd.ruser = '0;
assign s_axil_rd.rvalid = s_axil_rvalid_reg;
assign s_axis_irq.tready = irq_ready_reg;
assign tx_wr_req_tlp.data = TLP_DATA_W'(tx_wr_req_tlp_data_reg);
assign tx_wr_req_tlp.empty = '1;
assign tx_wr_req_tlp.hdr = tx_wr_req_tlp_hdr_reg;
assign tx_wr_req_tlp.seq = '0;
assign tx_wr_req_tlp.bar_id = '0;
assign tx_wr_req_tlp.func_num = '0;
assign tx_wr_req_tlp.error = '0;
assign tx_wr_req_tlp.valid = tx_wr_req_tlp_valid_reg;
assign tx_wr_req_tlp.sop = 1'b1;
assign tx_wr_req_tlp.eop = 1'b1;
initial begin
for (integer i = 0; i < 2**TBL_ADDR_W; i = i + 1) begin
tbl_mem[i] = '0;
end
for (integer i = 0; i < 2**PBA_ADDR_W; i = i + 1) begin
pba_mem[i] = '0;
end
end
always_comb begin
state_next = STATE_IDLE;
tbl_mem_rd_en = 1'b0;
tbl_mem_addr = {irq_index_reg, 1'b0};
pba_mem_rd_en = 1'b0;
pba_mem_wr_en = 1'b0;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_reg >> 6);
pba_mem_wr_data = '0;
irq_index_next = irq_index_reg;
vec_addr_next = vec_addr_reg;
vec_data_next = vec_data_reg;
vec_mask_next = vec_mask_reg;
irq_ready_next = 1'b0;
tx_wr_req_tlp_data_next = tx_wr_req_tlp_data_reg;
tx_wr_req_tlp_hdr_next = tx_wr_req_tlp_hdr_reg;
tx_wr_req_tlp_valid_next = tx_wr_req_tlp_valid_reg && !tx_wr_req_tlp.ready;
// TLP header
// DW 0
if (((vec_addr_reg[63:2] >> 30) != 0) || TLP_FORCE_64_BIT_ADDR) begin
tlp_hdr[127:125] = TLP_FMT_4DW_DATA; // fmt - 4DW with data
end else begin
tlp_hdr[127:125] = TLP_FMT_3DW_DATA; // fmt - 3DW with data
end
tlp_hdr[124:120] = 5'b00000; // type - write
tlp_hdr[119] = 1'b0; // T9
tlp_hdr[118:116] = 3'b000; // TC
tlp_hdr[115] = 1'b0; // T8
tlp_hdr[114] = 1'b0; // attr
tlp_hdr[113] = 1'b0; // LN
tlp_hdr[112] = 1'b0; // TH
tlp_hdr[111] = 1'b0; // TD
tlp_hdr[110] = 1'b0; // EP
tlp_hdr[109:108] = 2'b00; // attr
tlp_hdr[107:106] = 2'b00; // AT
tlp_hdr[105:96] = 10'd1; // length
// DW 1
tlp_hdr[95:88] = bus_num; // requester ID (bus number)
tlp_hdr[87:80] = func_num; // requester ID (device/function number)
tlp_hdr[79:72] = 8'd0; // tag
tlp_hdr[71:68] = 4'b0000; // last BE
tlp_hdr[67:64] = 4'b1111; // first BE
if ((vec_addr_reg[63:32] != 0) || TLP_FORCE_64_BIT_ADDR) begin
// DW 2+3
tlp_hdr[63:2] = vec_addr_reg[63:2]; // address
tlp_hdr[1:0] = 2'b00; // PH
end else begin
// DW 2
tlp_hdr[63:34] = vec_addr_reg[31:2]; // address
tlp_hdr[33:32] = 2'b00; // PH
// DW 3
tlp_hdr[31:0] = 32'd0;
end
case (state_reg)
STATE_IDLE: begin
irq_ready_next = 1'b1;
if (s_axis_irq.tvalid && s_axis_irq.tready) begin
// new request
irq_ready_next = 1'b0;
irq_index_next = s_axis_irq.tdata;
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_next, 1'b0};
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_READ_TBL_1;
end else if (!s_axis_irq.tvalid && msix_enable_reg && !msix_mask_reg) begin
// no new request waiting, scan PBA for masked requests
if (pba_mem_rd_data_reg[6'(irq_index_reg)] != 0) begin
// PBA bit for current index is set, try issuing it
irq_ready_next = 1'b0;
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_next, 1'b0};
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_READ_TBL_1;
end else begin
// PBA bit for current index is not set
if (pba_mem_rd_data_reg != 0) begin
// at least one bit set in current group, move to next index
irq_index_next = irq_index_reg + 1;
end else begin
// no bits set in current group, move to next group
irq_index_next = (irq_index_reg & ({IRQ_INDEX_W{1'b1}} << 6)) + 'd64;
end
pba_mem_rd_en = 1'b1;
pba_mem_addr = PBA_ADDR_W_INT'(irq_index_next >> 6);
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_TBL_1: begin
// handle first table read
tbl_mem_rd_en = 1'b1;
tbl_mem_addr = {irq_index_reg, 1'b1};
vec_addr_next = {tbl_mem_rd_data_reg[63:2], 2'b00};
state_next = STATE_READ_TBL_2;
end
STATE_READ_TBL_2: begin
// handle second table read
vec_data_next = tbl_mem_rd_data_reg[31:0];
vec_mask_next = tbl_mem_rd_data_reg[32];
if (msix_enable_reg && !msix_mask_reg && !vec_mask_next) begin
// send TLP
state_next = STATE_SEND_TLP;
end else begin
// set PBA bit
pba_mem_wr_en = 1'b1;
pba_mem_wr_data = pba_mem_rd_data_reg | (1 << 6'(irq_index_reg));
irq_ready_next = 1'b1;
state_next = STATE_IDLE;
end
end
STATE_SEND_TLP: begin
if (!tx_wr_req_tlp.valid || tx_wr_req_tlp.ready) begin
// send TLP
tx_wr_req_tlp_data_next = vec_data_reg;
tx_wr_req_tlp_hdr_next = tlp_hdr;
tx_wr_req_tlp_valid_next = 1'b1;
// clear PBA bit
pba_mem_wr_en = 1'b1;
pba_mem_wr_data = pba_mem_rd_data_reg & ~(1 << 6'(irq_index_reg));
// increment index so we don't check the same PBA bit immediately
irq_index_next = irq_index_reg + 1;
irq_ready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_SEND_TLP;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
irq_index_reg <= irq_index_next;
vec_addr_reg <= vec_addr_next;
vec_data_reg <= vec_data_next;
vec_mask_reg <= vec_mask_next;
irq_ready_reg <= irq_ready_next;
tx_wr_req_tlp_data_reg <= tx_wr_req_tlp_data_next;
tx_wr_req_tlp_hdr_reg <= tx_wr_req_tlp_hdr_next;
tx_wr_req_tlp_valid_reg <= tx_wr_req_tlp_valid_next;
msix_enable_reg <= msix_enable;
msix_mask_reg <= msix_mask;
if (tbl_mem_rd_en) begin
tbl_mem_rd_data_reg <= tbl_mem[tbl_mem_addr];
end
if (pba_mem_wr_en) begin
pba_mem[pba_mem_addr] <= pba_mem_wr_data;
end else if (pba_mem_rd_en) begin
pba_mem_rd_data_reg <= pba_mem[pba_mem_addr];
end
if (rst) begin
state_reg <= STATE_IDLE;
irq_ready_reg <= 1'b0;
tx_wr_req_tlp_valid_reg <= 1'b0;
end
end
// AXI lite interface
always_comb begin
tbl_axil_mem_rd_en = 1'b0;
tbl_axil_mem_wr_en = 1'b0;
tbl_axil_mem_wr_be = 8'(s_axil_wr.wstrb << (s_axil_awaddr_word * AXIL_STRB_W));
tbl_axil_mem_wr_data = {RATIO{s_axil_wr.wdata}};
pba_axil_mem_rd_en = 1'b0;
tbl_rd_data_valid_next = tbl_rd_data_valid_reg;
pba_rd_data_valid_next = pba_rd_data_valid_reg;
rd_data_shift_next = rd_data_shift_reg;
last_read_next = last_read_reg;
s_axil_awready_next = 1'b0;
s_axil_wready_next = 1'b0;
s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_wr.bready;
s_axil_arready_next = 1'b0;
s_axil_rdata_next = s_axil_rdata_reg;
s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rd.rready;
write_eligible = s_axil_wr.awvalid && s_axil_wr.wvalid && (!s_axil_wr.bvalid || s_axil_wr.bready) && (!s_axil_wr.awready && !s_axil_wr.wready);
read_eligible = s_axil_rd.arvalid && (!s_axil_rd.rvalid || s_axil_rd.rready || !(tbl_rd_data_valid_reg || pba_rd_data_valid_reg)) && (!s_axil_rd.arready);
if ((tbl_rd_data_valid_reg || pba_rd_data_valid_reg) && (!s_axil_rd.rvalid || s_axil_rd.rready)) begin
s_axil_rvalid_next = 1'b1;
tbl_rd_data_valid_next = 1'b0;
pba_rd_data_valid_next = 1'b0;
if (tbl_rd_data_valid_reg) begin
if (AXIL_DATA_W < 64) begin
s_axil_rdata_next = AXIL_DATA_W'(tbl_axil_mem_rd_data_reg >> rd_data_shift_reg*AXIL_DATA_W);
end else begin
s_axil_rdata_next = AXIL_DATA_W'(tbl_axil_mem_rd_data_reg);
end
end else begin
if (AXIL_DATA_W < 64) begin
s_axil_rdata_next = AXIL_DATA_W'(pba_axil_mem_rd_data_reg >> rd_data_shift_reg*AXIL_DATA_W);
end else begin
s_axil_rdata_next = AXIL_DATA_W'(pba_axil_mem_rd_data_reg);
end
end
end
if (write_eligible && (!read_eligible || last_read_reg)) begin
last_read_next = 1'b0;
s_axil_awready_next = 1'b1;
s_axil_wready_next = 1'b1;
s_axil_bvalid_next = 1'b1;
if (s_axil_wr.awaddr[IRQ_INDEX_W+5-1] == 0) begin
tbl_axil_mem_wr_en = 1'b1;
end
end else if (read_eligible) begin
last_read_next = 1'b1;
s_axil_arready_next = 1'b1;
rd_data_shift_next = s_axil_araddr_word;
if (s_axil_rd.araddr[IRQ_INDEX_W+5-1] == 0) begin
tbl_axil_mem_rd_en = 1'b1;
tbl_rd_data_valid_next = 1'b1;
end else begin
pba_axil_mem_rd_en = 1'b1;
pba_rd_data_valid_next = 1'b1;
end
end
end
always_ff @(posedge clk) begin
tbl_rd_data_valid_reg <= tbl_rd_data_valid_next;
pba_rd_data_valid_reg <= pba_rd_data_valid_next;
rd_data_shift_reg <= rd_data_shift_next;
last_read_reg <= last_read_next;
s_axil_awready_reg <= s_axil_awready_next;
s_axil_wready_reg <= s_axil_wready_next;
s_axil_bvalid_reg <= s_axil_bvalid_next;
s_axil_arready_reg <= s_axil_arready_next;
s_axil_rdata_reg <= s_axil_rdata_next;
s_axil_rvalid_reg <= s_axil_rvalid_next;
if (tbl_axil_mem_rd_en) begin
tbl_axil_mem_rd_data_reg <= tbl_mem[s_axil_araddr_index];
end else begin
for (integer i = 0; i < 8; i = i + 1) begin
if (tbl_axil_mem_wr_en && tbl_axil_mem_wr_be[i]) begin
tbl_mem[s_axil_awaddr_index][8*i +: 8] <= tbl_axil_mem_wr_data[8*i +: 8];
end
end
end
if (pba_axil_mem_rd_en) begin
pba_axil_mem_rd_data_reg <= pba_mem[s_axil_araddr_index[PBA_ADDR_W-1:0]];
end
if (rst) begin
tbl_rd_data_valid_reg <= 1'b0;
pba_rd_data_valid_reg <= 1'b0;
last_read_reg <= 1'b0;
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= 1'b0;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -81,7 +81,7 @@ if (AXIL_DATA_W != 32)
if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI interface requires byte (8-bit) granularity (instance %m)");
localparam [3:0]
typedef enum logic [3:0] {
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
@@ -96,23 +96,26 @@ localparam [3:0]
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
REQ_MSG_ATS = 4'b1110
} req_type_t;
localparam [2:0]
typedef enum logic [2:0] {
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
CPL_STATUS_CA = 3'b100 // completer abort
} cpl_status_t;
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_HEADER = 3'd1,
STATE_READ = 3'd2,
STATE_WRITE_1 = 3'd3,
STATE_WRITE_2 = 3'd4,
STATE_WAIT_END = 3'd5,
STATE_CPL_1 = 3'd6,
STATE_CPL_2 = 3'd7;
typedef enum logic [2:0] {
STATE_IDLE,
STATE_HEADER,
STATE_READ,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_WAIT_END,
STATE_CPL_1,
STATE_CPL_2
} state_t;
wire [63:0] req_tlp_hdr_addr;
wire [10:0] req_tlp_hdr_length;
@@ -161,7 +164,7 @@ logic [95:0] cpl_tlp_hdr;
logic [32:0] cpl_tuser_1;
logic [80:0] cpl_tuser_2;
logic [2:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [10:0] dword_count_reg = '0, dword_count_next;
logic [3:0] type_reg = '0, type_next;

View File

@@ -0,0 +1,56 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0
#
# Copyright (c) 2021-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = taxi_pcie_msix_apb
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(RTL_DIR)/taxi_pcie_tlp_if.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_if.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/apb/rtl/taxi_apb_if.sv
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_IRQ_INDEX_W := 11
export PARAM_APB_DATA_W := 32
export PARAM_APB_ADDR_W := $(shell expr $(PARAM_IRQ_INDEX_W) + 5 )
export PARAM_TLP_FORCE_64_BIT_ADDR := 0
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1 @@
../pcie_if.py

View File

@@ -0,0 +1,349 @@
#!/usr/bin/env python
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2022-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import re
import sys
from contextlib import contextmanager
import cocotb_test.simulator
import pytest
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.regression import TestFactory
from cocotbext.axi import ApbBus, ApbMaster
from cocotbext.axi import AxiStreamBus, AxiStreamSource
try:
from pcie_if import PcieIfSink, PcieIfTxBus
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from pcie_if import PcieIfSink, PcieIfTxBus
finally:
del sys.path[0]
@contextmanager
def assert_raises(exc_type, pattern=None):
try:
yield
except exc_type as e:
if pattern:
assert re.match(pattern, str(e)), \
"Correct exception type caught, but message did not match pattern"
pass
else:
raise AssertionError("{} was not raised".format(exc_type.__name__))
class TB(object):
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.clk, 4, units="ns").start())
self.apb_master = ApbMaster(ApbBus.from_entity(dut.s_apb), dut.clk, dut.rst)
self.irq_source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_irq), dut.clk, dut.rst)
self.tlp_sink = PcieIfSink(PcieIfTxBus.from_entity(dut.tx_wr_req_tlp), dut.clk, dut.rst)
dut.bus_num.setimmediatevalue(0)
dut.func_num.setimmediatevalue(0)
dut.msix_enable.setimmediatevalue(0)
dut.msix_mask.setimmediatevalue(0)
def set_idle_generator(self, generator=None):
if generator:
self.apb_master.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
self.tlp_sink.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_table_write(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes*4):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
addr = offset+0x100
test_data = bytearray([x % 256 for x in range(length)])
await tb.apb_master.write(addr-4, b'\xaa'*(length+8))
await tb.apb_master.write(addr, test_data)
data = await tb.apb_master.read(addr-1, length+2)
assert data.data == b'\xaa'+test_data+b'\xaa'
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_table_read(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes*4):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
addr = offset+0x100
test_data = bytearray([x % 256 for x in range(length)])
await tb.apb_master.write(addr, test_data)
data = await tb.apb_master.read(addr, length)
assert data.data == test_data
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_msix(dut, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
tbl_offset = 0
pba_offset = 2**(tb.apb_master.address_width-1)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
dut.msix_enable.value = 1
tb.log.info("Init table")
for k in range(2**len(dut.s_axis_irq.tdata)):
await tb.apb_master.write_qword(tbl_offset+k*16+0, 0x1234567800000000 + k*4)
await tb.apb_master.write_dword(tbl_offset+k*16+8, k)
await tb.apb_master.write_dword(tbl_offset+k*16+12, 0)
tb.log.info("Test unmasked interrupts")
for k in range(8):
await tb.irq_source.send([k])
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.apb_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
tb.log.info("Test global mask")
dut.msix_mask.value = 1
for k in range(8):
await tb.irq_source.send([k])
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
while int(dut.s_axis_irq.tvalid.value):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
val = await tb.apb_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0xff
dut.msix_mask.value = 0
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.apb_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
tb.log.info("Test vector masks")
for k in range(8):
await tb.apb_master.write_dword(tbl_offset+k*16+12, 1)
for k in range(8):
await tb.irq_source.send([k])
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
while int(dut.s_axis_irq.tvalid.value):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
val = await tb.apb_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0xff
for k in range(8):
await tb.apb_master.write_dword(tbl_offset+k*16+12, 0)
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.apb_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
def cycle_pause():
return itertools.cycle([1, 1, 1, 0])
if getattr(cocotb, 'top', None) is not None:
for test in [
run_test_table_write,
run_test_table_read,
run_test_msix
]:
factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == '.f':
with open(f, 'r') as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
@pytest.mark.parametrize("apb_data_w", [32, 64])
def test_taxi_pcie_msix_apb(request, apb_data_w):
dut = "taxi_pcie_msix_apb"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(rtl_dir, "taxi_pcie_tlp_if.sv"),
os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_if.sv"),
os.path.join(taxi_src_dir, "apb", "rtl", "taxi_apb_if.sv"),
]
parameters = {}
parameters['IRQ_INDEX_W'] = 11
parameters['APB_DATA_W'] = apb_data_w
parameters['APB_ADDR_W'] = parameters['IRQ_INDEX_W']+5
parameters['TLP_FORCE_64_BIT_ADDR'] = 0
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe MSI-X module testbench
*/
module test_taxi_pcie_msix_apb #
(
/* verilator lint_off WIDTHTRUNC */
parameter IRQ_INDEX_W = 11,
parameter TLP_SEG_DATA_W = 64,
parameter TLP_SEGS = 1,
parameter APB_DATA_W = 32,
parameter APB_ADDR_W = IRQ_INDEX_W+5,
parameter logic TLP_FORCE_64_BIT_ADDR = 1'b0
/* verilator lint_on WIDTHTRUNC */
)
();
logic clk;
logic rst;
taxi_apb_if #(
.DATA_W(APB_DATA_W),
.ADDR_W(APB_ADDR_W),
.PAUSER_EN(1'b0),
.PWUSER_EN(1'b0),
.PBUSER_EN(1'b0),
.PRUSER_EN(1'b0)
) s_apb();
taxi_axis_if #(
.DATA_W(IRQ_INDEX_W),
.KEEP_EN(0),
.KEEP_W(1)
) s_axis_irq();
taxi_pcie_tlp_if #(
.SEGS(TLP_SEGS),
.SEG_DATA_W(TLP_SEG_DATA_W),
.FUNC_NUM_W(8)
) tx_wr_req_tlp();
logic [7:0] bus_num;
logic [7:0] func_num;
logic msix_enable;
logic msix_mask;
taxi_pcie_msix_apb #(
.TLP_FORCE_64_BIT_ADDR(TLP_FORCE_64_BIT_ADDR)
)
uut (
.clk(clk),
.rst(rst),
/*
* APB interface for MSI-X tables
*/
.s_apb(s_apb),
/*
* Interrupt request input
*/
.s_axis_irq(s_axis_irq),
/*
* Memory write TLP output
*/
.tx_wr_req_tlp(tx_wr_req_tlp),
/*
* Configuration
*/
.bus_num(bus_num),
.func_num(func_num),
.msix_enable(msix_enable),
.msix_mask(msix_mask)
);
endmodule
`resetall

View File

@@ -0,0 +1,56 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0
#
# Copyright (c) 2021-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = taxi_pcie_msix_axil
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(RTL_DIR)/taxi_pcie_tlp_if.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_if.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axi/rtl/taxi_axil_if.sv
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_IRQ_INDEX_W := 11
export PARAM_AXIL_DATA_W := 32
export PARAM_AXIL_ADDR_W := $(shell expr $(PARAM_IRQ_INDEX_W) + 5 )
export PARAM_TLP_FORCE_64_BIT_ADDR := 0
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1 @@
../pcie_if.py

View File

@@ -0,0 +1,353 @@
#!/usr/bin/env python
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2022-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import re
import sys
from contextlib import contextmanager
import cocotb_test.simulator
import pytest
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.regression import TestFactory
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
from cocotbext.axi import AxiStreamBus, AxiStreamSource
try:
from pcie_if import PcieIfSink, PcieIfTxBus
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from pcie_if import PcieIfSink, PcieIfTxBus
finally:
del sys.path[0]
@contextmanager
def assert_raises(exc_type, pattern=None):
try:
yield
except exc_type as e:
if pattern:
assert re.match(pattern, str(e)), \
"Correct exception type caught, but message did not match pattern"
pass
else:
raise AssertionError("{} was not raised".format(exc_type.__name__))
class TB(object):
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.clk, 4, units="ns").start())
self.axil_master = AxiLiteMaster(AxiLiteBus.from_entity(dut.s_axil), dut.clk, dut.rst)
self.irq_source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_irq), dut.clk, dut.rst)
self.tlp_sink = PcieIfSink(PcieIfTxBus.from_entity(dut.tx_wr_req_tlp), dut.clk, dut.rst)
dut.bus_num.setimmediatevalue(0)
dut.func_num.setimmediatevalue(0)
dut.msix_enable.setimmediatevalue(0)
dut.msix_mask.setimmediatevalue(0)
def set_idle_generator(self, generator=None):
if generator:
self.axil_master.write_if.aw_channel.set_pause_generator(generator())
self.axil_master.write_if.w_channel.set_pause_generator(generator())
self.axil_master.read_if.ar_channel.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
self.axil_master.write_if.b_channel.set_pause_generator(generator())
self.axil_master.read_if.r_channel.set_pause_generator(generator())
self.tlp_sink.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_table_write(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
byte_lanes = tb.axil_master.write_if.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes*4):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
addr = offset+0x100
test_data = bytearray([x % 256 for x in range(length)])
await tb.axil_master.write(addr-4, b'\xaa'*(length+8))
await tb.axil_master.write(addr, test_data)
data = await tb.axil_master.read(addr-1, length+2)
assert data.data == b'\xaa'+test_data+b'\xaa'
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_table_read(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
byte_lanes = tb.axil_master.write_if.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes*4):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
addr = offset+0x100
test_data = bytearray([x % 256 for x in range(length)])
await tb.axil_master.write(addr, test_data)
data = await tb.axil_master.read(addr, length)
assert data.data == test_data
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_msix(dut, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
tbl_offset = 0
pba_offset = 2**(tb.axil_master.write_if.address_width-1)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
dut.msix_enable.value = 1
tb.log.info("Init table")
for k in range(2**len(dut.s_axis_irq.tdata)):
await tb.axil_master.write_qword(tbl_offset+k*16+0, 0x1234567800000000 + k*4)
await tb.axil_master.write_dword(tbl_offset+k*16+8, k)
await tb.axil_master.write_dword(tbl_offset+k*16+12, 0)
tb.log.info("Test unmasked interrupts")
for k in range(8):
await tb.irq_source.send([k])
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.axil_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
tb.log.info("Test global mask")
dut.msix_mask.value = 1
for k in range(8):
await tb.irq_source.send([k])
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
while int(dut.s_axis_irq.tvalid.value):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
val = await tb.axil_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0xff
dut.msix_mask.value = 0
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.axil_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
tb.log.info("Test vector masks")
for k in range(8):
await tb.axil_master.write_dword(tbl_offset+k*16+12, 1)
for k in range(8):
await tb.irq_source.send([k])
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
while int(dut.s_axis_irq.tvalid.value):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
val = await tb.axil_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0xff
for k in range(8):
await tb.axil_master.write_dword(tbl_offset+k*16+12, 0)
for k in range(8):
frame = await tb.tlp_sink.recv()
tlp = frame.to_tlp()
tb.log.info("TLP: %s", tlp)
assert tlp.address == 0x1234567800000000 + k*4
assert tlp.data == k.to_bytes(4, 'little')
assert tlp.first_be == 0xf
val = await tb.axil_master.read_dword(pba_offset+0)
tb.log.info("PBA value: 0x%02x", val)
assert val == 0x00
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
def cycle_pause():
return itertools.cycle([1, 1, 1, 0])
if getattr(cocotb, 'top', None) is not None:
for test in [
run_test_table_write,
run_test_table_read,
run_test_msix
]:
factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == '.f':
with open(f, 'r') as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
@pytest.mark.parametrize("axil_data_w", [32, 64])
def test_taxi_pcie_msix_axil(request, axil_data_w):
dut = "taxi_pcie_msix_axil"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(rtl_dir, "taxi_pcie_tlp_if.sv"),
os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_if.sv"),
os.path.join(taxi_src_dir, "axi", "rtl", "taxi_axil_if.sv"),
]
parameters = {}
parameters['IRQ_INDEX_W'] = 11
parameters['AXIL_DATA_W'] = axil_data_w
parameters['AXIL_ADDR_W'] = parameters['IRQ_INDEX_W']+5
parameters['TLP_FORCE_64_BIT_ADDR'] = 0
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe MSI-X module testbench
*/
module test_taxi_pcie_msix_axil #
(
/* verilator lint_off WIDTHTRUNC */
parameter IRQ_INDEX_W = 11,
parameter TLP_SEG_DATA_W = 64,
parameter TLP_SEGS = 1,
parameter AXIL_DATA_W = 32,
parameter AXIL_ADDR_W = IRQ_INDEX_W+5,
parameter logic TLP_FORCE_64_BIT_ADDR = 1'b0
/* verilator lint_on WIDTHTRUNC */
)
();
logic clk;
logic rst;
taxi_axil_if #(
.DATA_W(AXIL_DATA_W),
.ADDR_W(AXIL_ADDR_W),
.AWUSER_EN(1'b0),
.WUSER_EN(1'b0),
.BUSER_EN(1'b0),
.ARUSER_EN(1'b0),
.RUSER_EN(1'b0)
) s_axil();
taxi_axis_if #(
.DATA_W(IRQ_INDEX_W),
.KEEP_EN(0),
.KEEP_W(1)
) s_axis_irq();
taxi_pcie_tlp_if #(
.SEGS(TLP_SEGS),
.SEG_DATA_W(TLP_SEG_DATA_W),
.FUNC_NUM_W(8)
) tx_wr_req_tlp();
logic [7:0] bus_num;
logic [7:0] func_num;
logic msix_enable;
logic msix_mask;
taxi_pcie_msix_axil #(
.TLP_FORCE_64_BIT_ADDR(TLP_FORCE_64_BIT_ADDR)
)
uut (
.clk(clk),
.rst(rst),
/*
* AXI lite interface for MSI-X tables
*/
.s_axil_wr(s_axil),
.s_axil_rd(s_axil),
/*
* Interrupt request input
*/
.s_axis_irq(s_axis_irq),
/*
* Memory write TLP output
*/
.tx_wr_req_tlp(tx_wr_req_tlp),
/*
* Configuration
*/
.bus_num(bus_num),
.func_num(func_num),
.msix_enable(msix_enable),
.msix_mask(msix_mask)
);
endmodule
`resetall

View File

@@ -0,0 +1,72 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Simple dual-port RAM
*/
module taxi_ram_1r1w_1c #
(
parameter ADDR_W = 16,
parameter DATA_W = 16,
parameter logic STRB_EN = 1'b1,
parameter STRB_W = DATA_W/8
)
(
input wire logic clk,
input wire logic wr_en,
input wire logic [ADDR_W-1:0] wr_addr,
input wire logic [DATA_W-1:0] wr_data,
input wire logic [STRB_W-1:0] wr_strb = '1,
input wire logic rd_en,
input wire logic [ADDR_W-1:0] rd_addr,
output wire logic [DATA_W-1:0] rd_data
);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (STRB_EN && BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: Data width not evenly divisible (instance %m)");
reg [DATA_W-1:0] rd_data_reg = '0;
assign rd_data = rd_data_reg;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0};
always_ff @(posedge clk) begin
if (wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (wr_strb[i]) begin
mem[wr_addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[wr_addr] <= wr_data;
end
end
if (rd_en) begin
rd_data_reg <= mem[rd_addr];
end
end
endmodule
`resetall

View File

@@ -0,0 +1,74 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Simple dual-port, dual-clock RAM
*/
module taxi_ram_1r1w_2c #
(
parameter ADDR_W = 16,
parameter DATA_W = 16,
parameter logic STRB_EN = 1'b1,
parameter STRB_W = DATA_W/8
)
(
input wire logic wr_clk,
input wire logic wr_en,
input wire logic [ADDR_W-1:0] wr_addr,
input wire logic [DATA_W-1:0] wr_data,
input wire logic [STRB_W-1:0] wr_strb = '1,
input wire logic rd_clk,
input wire logic rd_en,
input wire logic [ADDR_W-1:0] rd_addr,
output wire logic [DATA_W-1:0] rd_data
);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (STRB_EN && BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: Data width not evenly divisible (instance %m)");
reg [DATA_W-1:0] rd_data_reg = '0;
assign rd_data = rd_data_reg;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0};
always_ff @(posedge wr_clk) begin
if (wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (wr_strb[i]) begin
mem[wr_addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[wr_addr] <= wr_data;
end
end
end
always_ff @(posedge rd_clk) begin
if (rd_en) begin
rd_data_reg <= mem[rd_addr];
end
end
endmodule
`resetall

View File

@@ -0,0 +1,70 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Single-port RAM
*/
module taxi_ram_1rw #
(
parameter ADDR_W = 16,
parameter DATA_W = 16,
parameter logic STRB_EN = 1'b1,
parameter STRB_W = DATA_W/8
)
(
input wire logic clk,
input wire logic en,
input wire logic [ADDR_W-1:0] addr,
input wire logic wr_en,
input wire logic [DATA_W-1:0] wr_data,
input wire logic [STRB_W-1:0] wr_strb = '0,
output wire logic [DATA_W-1:0] rd_data
);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (STRB_EN && BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: Data width not evenly divisible (instance %m)");
reg [DATA_W-1:0] rd_data_reg = '0;
assign rd_data = rd_data_reg;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0};
always_ff @(posedge clk) begin
if (en) begin
if (wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (wr_strb[i]) begin
mem[addr][BYTE_W*i +: BYTE_W] <= wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[addr] <= wr_data;
end
end else begin
rd_data_reg <= mem[addr];
end
end
end
endmodule
`resetall

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* True dual-port RAM
*/
module taxi_ram_2rw_1c #
(
parameter ADDR_W = 16,
parameter DATA_W = 16,
parameter logic STRB_EN = 1'b1,
parameter STRB_W = DATA_W/8
)
(
input wire logic clk,
input wire logic a_en,
input wire logic [ADDR_W-1:0] a_addr,
input wire logic a_wr_en,
input wire logic [DATA_W-1:0] a_wr_data,
input wire logic [STRB_W-1:0] a_wr_strb = '1,
output wire logic [DATA_W-1:0] a_rd_data,
input wire logic b_en,
input wire logic [ADDR_W-1:0] b_addr,
input wire logic b_wr_en,
input wire logic [DATA_W-1:0] b_wr_data,
input wire logic [STRB_W-1:0] b_wr_strb = '1,
output wire logic [DATA_W-1:0] b_rd_data
);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (STRB_EN && BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: Data width not evenly divisible (instance %m)");
reg [DATA_W-1:0] a_rd_data_reg = '0;
reg [DATA_W-1:0] b_rd_data_reg = '0;
assign a_rd_data = a_rd_data_reg;
assign b_rd_data = b_rd_data_reg;
// verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN
always_ff @(posedge clk) begin
if (a_en) begin
if (a_wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (a_wr_strb[i]) begin
mem[a_addr][BYTE_W*i +: BYTE_W] <= a_wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[a_addr] <= a_wr_data;
end
end else begin
a_rd_data_reg <= mem[a_addr];
end
end
if (b_en) begin
if (b_wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (b_wr_strb[i]) begin
mem[b_addr][BYTE_W*i +: BYTE_W] <= b_wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[b_addr] <= b_wr_data;
end
end else begin
b_rd_data_reg <= mem[b_addr];
end
end
end
endmodule
`resetall

View File

@@ -0,0 +1,99 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* True dual-port, dual-clock RAM
*/
module taxi_ram_2rw_2c #
(
parameter ADDR_W = 16,
parameter DATA_W = 16,
parameter logic STRB_EN = 1'b1,
parameter STRB_W = DATA_W/8
)
(
input wire logic a_clk,
input wire logic a_en,
input wire logic [ADDR_W-1:0] a_addr,
input wire logic a_wr_en,
input wire logic [DATA_W-1:0] a_wr_data,
input wire logic [STRB_W-1:0] a_wr_strb = '1,
output wire logic [DATA_W-1:0] a_rd_data,
input wire logic b_clk,
input wire logic b_en,
input wire logic [ADDR_W-1:0] b_addr,
input wire logic b_wr_en,
input wire logic [DATA_W-1:0] b_wr_data,
input wire logic [STRB_W-1:0] b_wr_strb = '1,
output wire logic [DATA_W-1:0] b_rd_data
);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (STRB_EN && BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: Data width not evenly divisible (instance %m)");
reg [DATA_W-1:0] a_rd_data_reg = '0;
reg [DATA_W-1:0] b_rd_data_reg = '0;
assign a_rd_data = a_rd_data_reg;
assign b_rd_data = b_rd_data_reg;
// verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN
always_ff @(posedge a_clk) begin
if (a_en) begin
if (a_wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (a_wr_strb[i]) begin
mem[a_addr][BYTE_W*i +: BYTE_W] <= a_wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[a_addr] <= a_wr_data;
end
end else begin
a_rd_data_reg <= mem[a_addr];
end
end
end
always_ff @(posedge b_clk) begin
if (b_en) begin
if (b_wr_en) begin
if (STRB_EN) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (b_wr_strb[i]) begin
mem[b_addr][BYTE_W*i +: BYTE_W] <= b_wr_data[BYTE_W*i +: BYTE_W];
end
end
end else begin
mem[b_addr] <= b_wr_data;
end
end else begin
b_rd_data_reg <= mem[b_addr];
end
end
end
endmodule
`resetall

View File

@@ -71,11 +71,12 @@ localparam CNT_W = $clog2(CNT);
localparam PERIOD_CNT_W = $clog2(UPDATE_PERIOD+1);
localparam ACC_W = INC_W+CNT_W+1;
localparam [0:0]
STATE_READ = 1'd0,
STATE_WRITE = 1'd1;
typedef enum logic [0:0] {
STATE_READ,
STATE_WRITE
} state_t;
logic [0:0] state_reg = STATE_READ, state_next;
state_t state_reg = STATE_READ, state_next;
logic [STAT_INC_W-1:0] m_axis_stat_tdata_reg = '0, m_axis_stat_tdata_next;
logic [STAT_ID_W-1:0] m_axis_stat_tid_reg = '0, m_axis_stat_tid_next;

View File

@@ -143,19 +143,20 @@ initial begin
end
end
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_HEADER_1 = 4'd1,
STATE_HEADER_2 = 4'd2,
STATE_HEADER_3 = 4'd3,
STATE_READ_1 = 4'd4,
STATE_READ_2 = 4'd5,
STATE_WRITE_1 = 4'd6,
STATE_WRITE_2 = 4'd7,
STATE_WAIT_LAST = 4'd8,
STATE_ID = 4'd9;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_HEADER_1,
STATE_HEADER_2,
STATE_HEADER_3,
STATE_READ_1,
STATE_READ_2,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_WAIT_LAST,
STATE_ID
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [COUNT_SIZE-1:0] ptr_reg = '0, ptr_next;
logic [7:0] count_reg = 8'd0, count_next;

View File

@@ -144,19 +144,20 @@ initial begin
end
end
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_HEADER_1 = 4'd1,
STATE_HEADER_2 = 4'd2,
STATE_HEADER_3 = 4'd3,
STATE_READ_1 = 4'd4,
STATE_READ_2 = 4'd5,
STATE_WRITE_1 = 4'd6,
STATE_WRITE_2 = 4'd7,
STATE_WAIT_LAST = 4'd8,
STATE_ID = 4'd9;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_HEADER_1,
STATE_HEADER_2,
STATE_HEADER_3,
STATE_READ_1,
STATE_READ_2,
STATE_WRITE_1,
STATE_WRITE_2,
STATE_WAIT_LAST,
STATE_ID
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [COUNT_SIZE-1:0] ptr_reg = '0, ptr_next;
logic [7:0] count_reg = 8'd0, count_next;
@@ -621,7 +622,7 @@ always_comb begin
store_xfcp_usp_us_int_to_output = 1'b0;
store_xfcp_usp_us_int_to_temp = 1'b0;
store_xfcp_usp_us_temp_to_output = 1'b0;
if (xfcp_usp_us_tready_int_reg) begin
// input is ready
if (xfcp_usp_us.tready || !xfcp_usp_us_tvalid_reg) begin
@@ -667,7 +668,7 @@ always_ff @(posedge clk) begin
xfcp_usp_us_tvalid_reg <= 1'b0;
xfcp_usp_us_tready_int_reg <= 1'b0;
temp_xfcp_usp_us_tvalid_reg <= 1'b0;
end
end
end
endmodule

View File

@@ -105,22 +105,23 @@ initial begin
end
end
localparam [3:0]
STATE_IDLE = 4'd0,
STATE_HEADER_1 = 4'd1,
STATE_HEADER_2 = 4'd2,
STATE_PROCESS = 4'd3,
STATE_STATUS = 4'd4,
STATE_PRESCALE_L = 4'd5,
STATE_PRESCALE_H = 4'd6,
STATE_COUNT = 4'd7,
STATE_NEXT_CMD= 4'd8,
STATE_WRITE_DATA = 4'd9,
STATE_READ_DATA = 4'd10,
STATE_WAIT_LAST = 4'd11,
STATE_ID = 4'd12;
typedef enum logic [3:0] {
STATE_IDLE,
STATE_HEADER_1,
STATE_HEADER_2,
STATE_PROCESS,
STATE_STATUS,
STATE_PRESCALE_L,
STATE_PRESCALE_H,
STATE_COUNT,
STATE_NEXT_CMD,
STATE_WRITE_DATA,
STATE_READ_DATA,
STATE_WAIT_LAST,
STATE_ID
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = 8'd0, count_next;
@@ -201,9 +202,9 @@ always_comb begin
i2c_wr_data_next = i2c_wr_data_reg;
i2c_wr_data_valid_next = i2c_wr_data_valid_reg && !i2c_wr_data.tready;
i2c_wr_data_last_next = i2c_wr_data_last_reg;
i2c_rd_data_ready_next = 1'b0;
prescale_next = prescale_reg;
stop_on_idle_next = stop_on_idle_reg;
@@ -726,7 +727,7 @@ always_comb begin
store_up_xfcp_int_to_output = 1'b0;
store_up_xfcp_int_to_temp = 1'b0;
store_up_xfcp_temp_to_output = 1'b0;
if (xfcp_usp_us_tready_int_reg) begin
// input is ready
if (xfcp_usp_us.tready || !xfcp_usp_us_tvalid_reg) begin

View File

@@ -108,20 +108,22 @@ initial begin
end
end
localparam [2:0]
DN_STATE_IDLE = 3'd0,
DN_STATE_TRANSFER = 3'd1,
DN_STATE_HEADER = 3'd2,
DN_STATE_PKT = 3'd3,
DN_STATE_ID = 3'd4;
typedef enum logic [2:0] {
DN_STATE_IDLE,
DN_STATE_TRANSFER,
DN_STATE_HEADER,
DN_STATE_PKT,
DN_STATE_ID
} dn_state_t;
logic [2:0] dn_state_reg = DN_STATE_IDLE, dn_state_next;
dn_state_t dn_state_reg = DN_STATE_IDLE, dn_state_next;
localparam [0:0]
UP_STATE_IDLE = 1'd0,
UP_STATE_TRANSFER = 1'd1;
typedef enum logic [0:0] {
UP_STATE_IDLE,
UP_STATE_TRANSFER
} up_state_t;
logic [0:0] up_state_reg = UP_STATE_IDLE, up_state_next;
up_state_t up_state_reg = UP_STATE_IDLE, up_state_next;
logic [CL_PORTS-1:0] dn_select_reg = '0, dn_select_next;
logic dn_frame_reg = 1'b0, dn_frame_next;
@@ -143,14 +145,14 @@ logic xfcp_usp_us_tvalid_int;
logic xfcp_usp_us_tready_int_reg = 1'b0;
logic xfcp_usp_us_tlast_int;
logic xfcp_usp_us_tuser_int;
wire xfcp_usp_us_tready_int_early;
wire xfcp_usp_us_tready_int_early;
logic [7:0] xfcp_dsp_ds_tdata_int;
logic [PORTS-1:0] xfcp_dsp_ds_tvalid_int;
logic xfcp_dsp_ds_tready_int_reg = 1'b0;
logic xfcp_dsp_ds_tlast_int;
logic xfcp_dsp_ds_tuser_int;
wire xfcp_dsp_ds_tready_int_early;
wire xfcp_dsp_ds_tready_int_early;
logic [7:0] int_loop_tdata_reg = 8'd0, int_loop_tdata_next;
logic int_loop_tvalid_reg = 1'b0, int_loop_tvalid_next;

View File

@@ -69,7 +69,7 @@ if (META_W != 64)
if (m_axis_meta.KEEP_W * 8 != META_W)
$fatal(0, "Error: Interface requires byte (8-bit) granularity (instance %m)");
localparam [15:0]
typedef enum logic [15:0] {
ETHERTYPE_IPV4 = 16'h0800,
ETHERTYPE_ARP = 16'h0806,
ETHERTYPE_VLAN_C = 16'h8100,
@@ -77,9 +77,10 @@ localparam [15:0]
ETHERTYPE_IPV6 = 16'h86DD,
ETHERTYPE_PBB = 16'h88E7,
ETHERTYPE_PTP = 16'h88F7,
ETHERTYPE_ROCE = 16'h8915;
ETHERTYPE_ROCE = 16'h8915
} ethertype_t;
localparam [7:0]
typedef enum logic [7:0] {
PROTO_IPV6_HOPOPT = 8'd0,
PROTO_ICMP = 8'd1,
PROTO_IGMP = 8'd2,
@@ -98,7 +99,8 @@ localparam [7:0]
PROTO_HIP = 8'd139,
PROTO_SHIM6 = 8'd140,
PROTO_253 = 8'd253,
PROTO_254 = 8'd254;
PROTO_254 = 8'd254
} proto_t;
localparam
FLG_VLAN_S = 1,
@@ -118,41 +120,42 @@ localparam
FLG_L4_BAD_LEN = 25,
FLG_PARSE_DONE = 31;
localparam [4:0]
STATE_IDLE = 5'd0,
STATE_ETH_1 = 5'd1,
STATE_ETH_2 = 5'd2,
STATE_ETH_3 = 5'd3,
STATE_VLAN_1 = 5'd4,
STATE_VLAN_2 = 5'd5,
STATE_IPV4_1 = 5'd6,
STATE_IPV4_2 = 5'd7,
STATE_IPV4_3 = 5'd8,
STATE_IPV4_4 = 5'd9,
STATE_IPV4_5 = 5'd10,
STATE_IPV4_6 = 5'd11,
STATE_IPV6_1 = 5'd12,
STATE_IPV6_2 = 5'd13,
STATE_IPV6_3 = 5'd14,
STATE_IPV6_4 = 5'd15,
STATE_IPV6_5 = 5'd16,
STATE_IPV6_6 = 5'd17,
STATE_IPV6_7 = 5'd18,
STATE_IPV6_8 = 5'd19,
STATE_IPV6_9 = 5'd20,
STATE_IPV6_10 = 5'd21,
STATE_EXT_HDR_1 = 5'd22,
STATE_TCP_1 = 5'd23,
STATE_TCP_2 = 5'd24,
STATE_TCP_3 = 5'd25,
STATE_TCP_4 = 5'd26,
STATE_TCP_5 = 5'd27,
STATE_UDP_1 = 5'd28,
STATE_UDP_2 = 5'd29,
STATE_FINISH_1 = 5'd30,
STATE_FINISH_2 = 5'd31;
typedef enum logic [4:0] {
STATE_IDLE,
STATE_ETH_1,
STATE_ETH_2,
STATE_ETH_3,
STATE_VLAN_1,
STATE_VLAN_2,
STATE_IPV4_1,
STATE_IPV4_2,
STATE_IPV4_3,
STATE_IPV4_4,
STATE_IPV4_5,
STATE_IPV4_6,
STATE_IPV6_1,
STATE_IPV6_2,
STATE_IPV6_3,
STATE_IPV6_4,
STATE_IPV6_5,
STATE_IPV6_6,
STATE_IPV6_7,
STATE_IPV6_8,
STATE_IPV6_9,
STATE_IPV6_10,
STATE_EXT_HDR_1,
STATE_TCP_1,
STATE_TCP_2,
STATE_TCP_3,
STATE_TCP_4,
STATE_TCP_5,
STATE_UDP_1,
STATE_UDP_2,
STATE_FINISH_1,
STATE_FINISH_2
} state_t;
logic [4:0] state_reg = STATE_IDLE, state_next;
state_t state_reg = STATE_IDLE, state_next;
logic frame_reg = 1'b0, frame_next;
logic run_reg = 1'b0, run_next;
@@ -273,11 +276,12 @@ end else begin
end
// handle ethertype
logic [4:0] eth_type_state;
state_t eth_type_state;
logic [31:0] eth_type_flags;
always_comb begin
eth_type_flags = '0;
eth_type_state = STATE_FINISH_1;
if (pkt_data_be[15:0] == ETHERTYPE_VLAN_S) begin
// S-tag
eth_type_state = STATE_VLAN_1;
@@ -300,11 +304,12 @@ always_comb begin
end
// handle next header
logic [4:0] next_hdr_state;
state_t next_hdr_state;
logic [31:0] next_hdr_flags;
always_comb begin
next_hdr_flags = '0;
next_hdr_state = STATE_FINISH_1;
case (next_hdr_reg)
PROTO_IPV6_HOPOPT: begin
next_hdr_flags[FLG_L3_OPT_PRSNT] = 1'b1;

View File

@@ -86,7 +86,7 @@ function [31:0] swab32(input [31:0] data);
end
endfunction
localparam [15:0]
typedef enum logic [15:0] {
ETHERTYPE_IPV4 = 16'h0800,
ETHERTYPE_ARP = 16'h0806,
ETHERTYPE_VLAN_C = 16'h8100,
@@ -94,9 +94,10 @@ localparam [15:0]
ETHERTYPE_IPV6 = 16'h86DD,
ETHERTYPE_PBB = 16'h88E7,
ETHERTYPE_PTP = 16'h88F7,
ETHERTYPE_ROCE = 16'h8915;
ETHERTYPE_ROCE = 16'h8915
} ethertype_t;
localparam [7:0]
typedef enum logic [7:0] {
PROTO_IPV6_HOPOPT = 8'd0,
PROTO_ICMP = 8'd1,
PROTO_IGMP = 8'd2,
@@ -115,7 +116,8 @@ localparam [7:0]
PROTO_HIP = 8'd139,
PROTO_SHIM6 = 8'd140,
PROTO_253 = 8'd253,
PROTO_254 = 8'd254;
PROTO_254 = 8'd254
} proto_t;
localparam
FLG_VLAN_S = 1,
@@ -130,39 +132,40 @@ localparam
FLG_ESP = 11,
FLG_EN = 31;
localparam [4:0]
PKT_STATE_IDLE = 5'd0,
PKT_STATE_ETH_1 = 5'd1,
PKT_STATE_ETH_2 = 5'd2,
PKT_STATE_ETH_3 = 5'd3,
PKT_STATE_VLAN_1 = 5'd4,
PKT_STATE_VLAN_2 = 5'd5,
PKT_STATE_IPV4_1 = 5'd6,
PKT_STATE_IPV4_2 = 5'd7,
PKT_STATE_IPV4_3 = 5'd8,
PKT_STATE_IPV4_4 = 5'd9,
PKT_STATE_IPV4_5 = 5'd10,
PKT_STATE_IPV4_6 = 5'd11,
PKT_STATE_IPV6_1 = 5'd12,
PKT_STATE_IPV6_2 = 5'd13,
PKT_STATE_IPV6_3 = 5'd14,
PKT_STATE_IPV6_4 = 5'd15,
PKT_STATE_IPV6_5 = 5'd16,
PKT_STATE_IPV6_6 = 5'd17,
PKT_STATE_IPV6_7 = 5'd18,
PKT_STATE_IPV6_8 = 5'd19,
PKT_STATE_IPV6_9 = 5'd20,
PKT_STATE_IPV6_10 = 5'd21,
PKT_STATE_TCP_1 = 5'd23,
PKT_STATE_TCP_2 = 5'd24,
PKT_STATE_TCP_3 = 5'd25,
PKT_STATE_TCP_4 = 5'd26,
PKT_STATE_TCP_5 = 5'd27,
PKT_STATE_UDP_1 = 5'd28,
PKT_STATE_UDP_2 = 5'd29,
PKT_STATE_FINISH_1 = 5'd30;
typedef enum logic [4:0] {
PKT_STATE_IDLE,
PKT_STATE_ETH_1,
PKT_STATE_ETH_2,
PKT_STATE_ETH_3,
PKT_STATE_VLAN_1,
PKT_STATE_VLAN_2,
PKT_STATE_IPV4_1,
PKT_STATE_IPV4_2,
PKT_STATE_IPV4_3,
PKT_STATE_IPV4_4,
PKT_STATE_IPV4_5,
PKT_STATE_IPV4_6,
PKT_STATE_IPV6_1,
PKT_STATE_IPV6_2,
PKT_STATE_IPV6_3,
PKT_STATE_IPV6_4,
PKT_STATE_IPV6_5,
PKT_STATE_IPV6_6,
PKT_STATE_IPV6_7,
PKT_STATE_IPV6_8,
PKT_STATE_IPV6_9,
PKT_STATE_IPV6_10,
PKT_STATE_TCP_1,
PKT_STATE_TCP_2,
PKT_STATE_TCP_3,
PKT_STATE_TCP_4,
PKT_STATE_TCP_5,
PKT_STATE_UDP_1,
PKT_STATE_UDP_2,
PKT_STATE_FINISH_1
} pkt_state_t;
logic [4:0] pkt_state_reg = PKT_STATE_IDLE, pkt_state_next;
pkt_state_t pkt_state_reg = PKT_STATE_IDLE, pkt_state_next;
logic [31:0] meta_flag_reg = '0, meta_flag_next;
logic [15:0] meta_payload_len_reg = '0, meta_payload_len_next;