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
* PCIe AXI lite master for Xilinx UltraScale * PCIe AXI lite master for Xilinx UltraScale
* MSI shim for Xilinx UltraScale * MSI shim for Xilinx UltraScale
* MSI-X with AXI lite control interface
* MSI-X with APB control interface
* Primitives * Primitives
* Arbiter * Arbiter
* Priority encoder * 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 end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [S_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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 [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_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 if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
// same width; translate // same width; translate
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_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 [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 end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_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 [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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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 [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_READ = 2'd2, STATE_DATA_READ,
STATE_DATA_SPLIT = 2'd3; 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 [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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 [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; 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 [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; 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 [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_READ = 2'd2, STATE_DATA_READ,
STATE_DATA_SPLIT = 2'd3; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd2; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; 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 [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -213,11 +213,12 @@ initial begin
end end
end end
localparam logic [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DECODE = 1'd1; 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; 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 COUNT_W = (FIFO_AW > 8 ? FIFO_AW : 8) + 1;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_WAIT = 1'd1; 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; 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 if (FIFO_DELAY) begin
// store AW channel value until W channel burst is stored in FIFO or FIFO is full // store AW channel value until W channel burst is stored in FIFO or FIFO is full
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_TRANSFER_IN = 2'd1, STATE_TRANSFER_IN,
STATE_TRANSFER_OUT = 2'd2; 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 hold_reg = 1'b1, hold_next;
logic [8:0] count_reg = 9'd0, count_next; logic [8:0] count_reg = 9'd0, count_next;

View File

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

View File

@@ -186,15 +186,16 @@ initial begin
end end
end end
localparam logic [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_DECODE = 3'd1, STATE_DECODE,
STATE_WRITE = 3'd2, STATE_WRITE,
STATE_WRITE_RESP = 3'd3, STATE_WRITE_RESP,
STATE_WRITE_DROP = 3'd4, STATE_WRITE_DROP,
STATE_WAIT_IDLE = 3'd5; STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; 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) 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)"); $fatal(0, "Error: AXI address width is insufficient (instance %m)");
localparam [0:0] typedef enum logic [0:0] {
READ_STATE_IDLE = 1'd0, READ_STATE_IDLE,
READ_STATE_BURST = 1'd1; 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] typedef enum logic [1:0] {
WRITE_STATE_IDLE = 2'd0, WRITE_STATE_IDLE,
WRITE_STATE_BURST = 2'd1, WRITE_STATE_BURST,
WRITE_STATE_RESP = 2'd2; 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_wr_en;
logic mem_rd_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 end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [S_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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; 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 end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd3; 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 [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_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 if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate
// same width; translate // same width; translate
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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; 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 end else if (APB_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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; 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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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; 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 end else if (AXI_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_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 [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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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; 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 end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; 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_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_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_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd3; 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 [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next; logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -189,11 +189,12 @@ initial begin
end end
end end
localparam logic [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DECODE = 1'd1; 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; logic s_axil_aready_reg = 1'b0, s_axil_aready_next;

View File

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

View File

@@ -179,15 +179,16 @@ initial begin
end end
end end
localparam logic [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_DECODE = 3'd1, STATE_DECODE,
STATE_WRITE = 3'd2, STATE_WRITE,
STATE_WRITE_RESP = 3'd3, STATE_WRITE_RESP,
STATE_WRITE_DROP = 3'd4, STATE_WRITE_DROP,
STATE_WAIT_IDLE = 3'd5; STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; 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)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register // state register
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_SEGMENT = 2'd1, STATE_SEGMENT,
STATE_NEXT_SEGMENT = 2'd2; 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 [7:0] count_reg = 8'd0, count_next;
logic suppress_zero_reg = 1'b0, suppress_zero_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)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register // state register
localparam [1:0] typedef enum logic [1:0] {
INPUT_STATE_IDLE = 2'd0, INPUT_STATE_IDLE,
INPUT_STATE_SEGMENT = 2'd1, INPUT_STATE_SEGMENT,
INPUT_STATE_FINAL_ZERO = 2'd2, INPUT_STATE_FINAL_ZERO,
INPUT_STATE_APPEND_ZERO = 2'd3; 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] typedef enum logic [0:0] {
OUTPUT_STATE_IDLE = 1'd0, OUTPUT_STATE_IDLE,
OUTPUT_STATE_SEGMENT = 1'd1; 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] input_count_reg = 8'd0, input_count_next;
logic [7:0] output_count_reg = 8'd0, output_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_main.o
cndm-y += cndm_devlink.o cndm-y += cndm_devlink.o
cndm-y += cndm_irq.o cndm-y += cndm_irq.o
cndm-y += cndm_cmd.o
cndm-y += cndm_dev.o cndm-y += cndm_dev.o
cndm-y += cndm_netdev.o cndm-y += cndm_netdev.o
cndm-y += cndm_ethtool.o cndm-y += cndm_ethtool.o

View File

@@ -20,6 +20,8 @@ Authors:
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <net/devlink.h> #include <net/devlink.h>
#include "cndm_hw.h"
#define DRIVER_VERSION "0.1" #define DRIVER_VERSION "0.1"
#define CNDM_MAX_IRQ 256 #define CNDM_MAX_IRQ 256
@@ -105,6 +107,7 @@ struct cndm_priv {
u32 txq_mask; u32 txq_mask;
u32 txq_prod; u32 txq_prod;
u32 txq_cons; u32 txq_cons;
u32 txq_db_offs;
size_t rxq_region_len; size_t rxq_region_len;
void *rxq_region; void *rxq_region;
@@ -115,6 +118,7 @@ struct cndm_priv {
u32 rxq_mask; u32 rxq_mask;
u32 rxq_prod; u32 rxq_prod;
u32 rxq_cons; u32 rxq_cons;
u32 rxq_db_offs;
size_t txcq_region_len; size_t txcq_region_len;
void *txcq_region; void *txcq_region;
@@ -137,20 +141,9 @@ struct cndm_priv {
u32 rxcq_cons; u32 rxcq_cons;
}; };
struct cndm_desc { // cndm_cmd.c
__u8 rsvd[4]; int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp);
__le32 len; int cndm_exec_cmd(struct cndm_dev *cdev, void *cmd, void *rsp);
__le64 addr;
};
struct cndm_cpl {
__u8 rsvd[4];
__le32 len;
__le32 ts_ns;
__le16 ts_fns;
__u8 ts_s;
__u8 phase;
};
// cndm_devlink.c // cndm_devlink.c
struct devlink *cndm_devlink_alloc(struct device *dev); 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); void cndm_irq_deinit_pcie(struct cndm_dev *cdev);
// cndm_netdev.c // 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); void cndm_destroy_netdev(struct net_device *ndev);
// cndm_dev.c // 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.h"
#include "cndm_hw.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/version.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++) { for (k = 0; k < cdev->port_count; k++) {
struct net_device *ndev; 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)) { if (IS_ERR_OR_NULL(ndev)) {
ret = PTR_ERR(ndev); ret = PTR_ERR(ndev);
goto fail_netdev; goto fail_netdev;

View File

@@ -9,6 +9,7 @@ Authors:
*/ */
#include "cndm.h" #include "cndm.h"
#include "cndm_hw.h"
#include <linux/version.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; 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 device *dev = cdev->dev;
struct net_device *ndev; struct net_device *ndev;
struct cndm_priv *priv; struct cndm_priv *priv;
int ret = 0; int ret = 0;
struct cndm_cmd cmd;
struct cndm_cmd rsp;
ndev = alloc_etherdev_mqs(sizeof(*priv), 1, 1); ndev = alloc_etherdev_mqs(sizeof(*priv), 1, 1);
if (!ndev) { if (!ndev) {
dev_err(dev, "Failed to allocate net_device"); 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->ndev = ndev;
priv->cdev = cdev; 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_tx_queues(ndev, 1);
netif_set_real_num_rx_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; goto fail;
} }
iowrite32(0x00000000, priv->hw_addr + 0x200); cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + 0x204); cmd.flags = 0x00000000;
iowrite32(priv->rxq_region_addr & 0xffffffff, priv->hw_addr + 0x208); cmd.port = port;
iowrite32(priv->rxq_region_addr >> 32, priv->hw_addr + 0x20c); cmd.qn = 0;
iowrite32(0x00000001 | (priv->rxq_log_size << 16), priv->hw_addr + 0x200); 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); cndm_exec_cmd(cdev, &cmd, &rsp);
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);
iowrite32(0x00000000, priv->hw_addr + 0x400); cmd.opcode = CNDM_CMD_OP_CREATE_RQ;
iowrite32(priv->rxcq_region_addr & 0xffffffff, priv->hw_addr + 0x408); cmd.flags = 0x00000000;
iowrite32(priv->rxcq_region_addr >> 32, priv->hw_addr + 0x40c); cmd.port = port;
iowrite32(0x00000001 | (priv->rxcq_log_size << 16), priv->hw_addr + 0x400); 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); cndm_exec_cmd(cdev, &cmd, &rsp);
iowrite32(priv->txcq_region_addr & 0xffffffff, priv->hw_addr + 0x308);
iowrite32(priv->txcq_region_addr >> 32, priv->hw_addr + 0x30c); priv->rxq_db_offs = rsp.dboffs;
iowrite32(0x00000001 | (priv->txcq_log_size << 16), priv->hw_addr + 0x300);
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); netif_carrier_off(ndev);
@@ -332,12 +370,41 @@ fail:
void cndm_destroy_netdev(struct net_device *ndev) void cndm_destroy_netdev(struct net_device *ndev)
{ {
struct cndm_priv *priv = netdev_priv(ndev); struct cndm_priv *priv = netdev_priv(ndev);
struct cndm_dev *cdev = priv->cdev;
struct device *dev = priv->dev; struct device *dev = priv->dev;
iowrite32(0x00000000, priv->hw_addr + 0x200); struct cndm_cmd cmd;
iowrite32(0x00000000, priv->hw_addr + 0x100); struct cndm_cmd rsp;
iowrite32(0x00000000, priv->hw_addr + 0x400);
iowrite32(0x00000000, priv->hw_addr + 0x300); 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) if (priv->irq)
atomic_notifier_chain_unregister(&priv->irq->nh, &priv->irq_nb); 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 // TODO
if (cdev->port_offset == 0x10000) { if (cdev->port_offset == 0x20000) {
dev_info(cdev->dev, "PTP clock not present"); dev_info(cdev->dev, "PTP clock not present");
return; return;
} }
cdev->phc_regs = cdev->hw_addr + 0x10000; // TODO cdev->phc_regs = cdev->hw_addr + 0x20000; // TODO
cdev->ptp_clock_info.owner = THIS_MODULE; cdev->ptp_clock_info.owner = THIS_MODULE;
snprintf(cdev->ptp_clock_info.name, sizeof(cdev->ptp_clock_info.name), "%s_phc", cdev->name); 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(); 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; return ret;
} }

View File

@@ -170,7 +170,7 @@ int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} }
dma_wmb(); 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; 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_core.sv
cndm_micro_cmd_mbox.sv
cndm_micro_dp_mgr.sv
cndm_micro_port.sv cndm_micro_port.sv
cndm_micro_rx.sv cndm_micro_rx.sv
cndm_micro_tx.sv cndm_micro_tx.sv
cndm_micro_desc_rd.sv cndm_micro_desc_rd.sv
cndm_micro_cpl_wr.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_source.sv
../lib/taxi/src/dma/rtl/taxi_dma_client_axis_sink.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_if_mux.f
../lib/taxi/src/dma/rtl/taxi_dma_psdpram.sv ../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/axi/rtl/taxi_axil_interconnect_1s.f
../lib/taxi/src/axis/rtl/taxi_axis_async_fifo.f ../lib/taxi/src/axis/rtl/taxi_axis_async_fifo.f
../lib/taxi/src/axis/rtl/taxi_axis_arb_mux.f ../lib/taxi/src/axis/rtl/taxi_axis_arb_mux.f

View File

@@ -49,8 +49,8 @@ module cndm_micro_core #(
/* /*
* Control register interface * Control register interface
*/ */
taxi_axil_if.wr_slv s_axil_wr, taxi_axil_if.wr_slv s_axil_ctrl_wr,
taxi_axil_if.rd_slv s_axil_rd, taxi_axil_if.rd_slv s_axil_ctrl_rd,
/* /*
* DMA * DMA
@@ -97,8 +97,8 @@ module cndm_micro_core #(
localparam CL_PORTS = $clog2(PORTS); localparam CL_PORTS = $clog2(PORTS);
localparam AXIL_ADDR_W = s_axil_wr.ADDR_W; localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_wr.DATA_W; localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
localparam RAM_SEGS = dma_ram_wr.SEGS; localparam RAM_SEGS = dma_ram_wr.SEGS;
localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W; 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_SEG_BE_W = dma_ram_wr.SEG_BE_W;
localparam RAM_SEL_W = dma_ram_wr.SEL_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 #( taxi_axil_if #(
.DATA_W(s_axil_wr.DATA_W), .DATA_W(s_axil_ctrl_wr.DATA_W),
.ADDR_W(16), .ADDR_W(16),
.STRB_W(s_axil_wr.STRB_W), .STRB_W(s_axil_ctrl_wr.STRB_W),
.AWUSER_EN(s_axil_wr.AWUSER_EN), .AWUSER_EN(s_axil_ctrl_wr.AWUSER_EN),
.AWUSER_W(s_axil_wr.AWUSER_W), .AWUSER_W(s_axil_ctrl_wr.AWUSER_W),
.WUSER_EN(s_axil_wr.WUSER_EN), .WUSER_EN(s_axil_ctrl_wr.WUSER_EN),
.WUSER_W(s_axil_wr.WUSER_W), .WUSER_W(s_axil_ctrl_wr.WUSER_W),
.BUSER_EN(s_axil_wr.BUSER_EN), .BUSER_EN(s_axil_ctrl_wr.BUSER_EN),
.BUSER_W(s_axil_wr.BUSER_W), .BUSER_W(s_axil_ctrl_wr.BUSER_W),
.ARUSER_EN(s_axil_wr.ARUSER_EN), .ARUSER_EN(s_axil_ctrl_wr.ARUSER_EN),
.ARUSER_W(s_axil_wr.ARUSER_W), .ARUSER_W(s_axil_ctrl_wr.ARUSER_W),
.RUSER_EN(s_axil_wr.RUSER_EN), .RUSER_EN(s_axil_ctrl_wr.RUSER_EN),
.RUSER_W(s_axil_wr.RUSER_W) .RUSER_W(s_axil_ctrl_wr.RUSER_W)
) )
s_axil_ctrl[PORTS+PORT_OFFSET](); axil_ctrl[PORTS+PORT_OFFSET]();
taxi_axil_interconnect_1s #( taxi_axil_interconnect_1s #(
.M_COUNT($size(s_axil_ctrl)), .M_COUNT($size(axil_ctrl)),
.ADDR_W(s_axil_wr.ADDR_W), .ADDR_W(s_axil_ctrl_wr.ADDR_W),
.M_REGIONS(1), .M_REGIONS(1),
.M_BASE_ADDR('0), .M_BASE_ADDR('0),
.M_ADDR_W({$size(s_axil_ctrl){{1{32'd16}}}}), .M_ADDR_W({$size(axil_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(s_axil_ctrl){1'b0}}) .M_SECURE({$size(axil_ctrl){1'b0}})
) )
port_intercon_inst ( port_intercon_inst (
.clk(clk), .clk(clk),
@@ -140,14 +141,14 @@ port_intercon_inst (
/* /*
* AXI4-lite slave interface * AXI4-lite slave interface
*/ */
.s_axil_wr(s_axil_wr), .s_axil_wr(s_axil_ctrl_wr),
.s_axil_rd(s_axil_rd), .s_axil_rd(s_axil_ctrl_rd),
/* /*
* AXI4-lite master interfaces * AXI4-lite master interfaces
*/ */
.m_axil_wr(s_axil_ctrl), .m_axil_wr(axil_ctrl),
.m_axil_rd(s_axil_ctrl) .m_axil_rd(axil_ctrl)
); );
logic s_axil_awready_reg = 1'b0; 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 [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0;
logic s_axil_rvalid_reg = 1'b0; logic s_axil_rvalid_reg = 1'b0;
assign s_axil_ctrl[0].awready = s_axil_awready_reg; assign axil_ctrl[0].awready = s_axil_awready_reg;
assign s_axil_ctrl[0].wready = s_axil_wready_reg; assign axil_ctrl[0].wready = s_axil_wready_reg;
assign s_axil_ctrl[0].bresp = '0; assign axil_ctrl[0].bresp = '0;
assign s_axil_ctrl[0].buser = '0; assign axil_ctrl[0].buser = '0;
assign s_axil_ctrl[0].bvalid = s_axil_bvalid_reg; assign axil_ctrl[0].bvalid = s_axil_bvalid_reg;
assign s_axil_ctrl[0].arready = s_axil_arready_reg; assign axil_ctrl[0].arready = s_axil_arready_reg;
assign s_axil_ctrl[0].rdata = s_axil_rdata_reg; assign axil_ctrl[0].rdata = s_axil_rdata_reg;
assign s_axil_ctrl[0].rresp = '0; assign axil_ctrl[0].rresp = '0;
assign s_axil_ctrl[0].ruser = '0; assign axil_ctrl[0].ruser = '0;
assign s_axil_ctrl[0].rvalid = s_axil_rvalid_reg; 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 always_ff @(posedge clk) begin
s_axil_awready_reg <= 1'b0; s_axil_awready_reg <= 1'b0;
s_axil_wready_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_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_awready_reg <= 1'b1;
s_axil_wready_reg <= 1'b1; s_axil_wready_reg <= 1'b1;
s_axil_bvalid_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 // 16'h0100: begin
// txq_en_reg <= s_axil_ctrl[0].wdata[0]; // txq_en_reg <= axil_ctrl[0].wdata[0];
// txq_size_reg <= s_axil_ctrl[0].wdata[19:16]; // txq_size_reg <= axil_ctrl[0].wdata[19:16];
// end // end
// 16'h0104: txq_prod_reg <= s_axil_ctrl[0].wdata[15:0]; // 16'h0104: txq_prod_reg <= axil_ctrl[0].wdata[15:0];
// 16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl[0].wdata; // 16'h0108: txq_base_addr_reg[31:0] <= axil_ctrl[0].wdata;
// 16'h010c: txq_base_addr_reg[63:32] <= s_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 default: begin end
endcase endcase
end 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_rdata_reg <= '0;
s_axil_arready_reg <= 1'b1; s_axil_arready_reg <= 1'b1;
s_axil_rvalid_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'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'h0108: s_axil_rdata_reg <= 32'h00010000; // port stride
16'h0200: begin
s_axil_rdata_reg[0] <= cmd_mbox_busy;
end
default: begin end default: begin end
endcase endcase
end end
@@ -219,6 +231,106 @@ always_ff @(posedge clk) begin
end end
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 if (PTP_TS_EN) begin : ptp
taxi_ptp_td_phc_axil #( taxi_ptp_td_phc_axil #(
@@ -232,8 +344,8 @@ if (PTP_TS_EN) begin : ptp
/* /*
* Control register interface * Control register interface
*/ */
.s_axil_wr(s_axil_ctrl[1]), .s_axil_wr(axil_ctrl[2]),
.s_axil_rd(s_axil_ctrl[1]), .s_axil_rd(axil_ctrl[2]),
/* /*
* PTP * PTP
@@ -362,8 +474,13 @@ for (genvar p = 0; p < PORTS; p = p + 1) begin : port
/* /*
* Control register interface * Control register interface
*/ */
.s_axil_wr(s_axil_ctrl[PORT_OFFSET+p]), .s_axil_ctrl_wr(axil_ctrl[PORT_OFFSET+p]),
.s_axil_rd(s_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 * 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 * Control register interface
*/ */
.s_axil_wr(axil_ctrl_bar), .s_axil_ctrl_wr(axil_ctrl_bar),
.s_axil_rd(axil_ctrl_bar), .s_axil_ctrl_rd(axil_ctrl_bar),
/* /*
* DMA * DMA

View File

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

View File

@@ -8,18 +8,49 @@ Authors:
""" """
import array
import logging import logging
import struct import struct
from collections import deque from collections import deque
from cocotb.queue import Queue 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: class Port:
def __init__(self, driver, index, hw_regs): def __init__(self, driver, index):
self.driver = driver self.driver = driver
self.log = driver.log self.log = driver.log
self.index = index self.index = index
self.hw_regs = hw_regs self.hw_regs = driver.hw_regs
self.rxq_log_size = (256).bit_length()-1 self.rxq_log_size = (256).bit_length()-1
self.rxq_size = 2**self.rxq_log_size self.rxq_size = 2**self.rxq_log_size
@@ -27,6 +58,8 @@ class Port:
self.rxq = None self.rxq = None
self.rxq_prod = 0 self.rxq_prod = 0
self.rxq_cons = 0 self.rxq_cons = 0
self.rx_rqn = 0
self.rxq_db_offs = 0
self.rx_info = [None] * self.rxq_size self.rx_info = [None] * self.rxq_size
@@ -36,6 +69,7 @@ class Port:
self.rxcq = None self.rxcq = None
self.rxcq_prod = 0 self.rxcq_prod = 0
self.rxcq_cons = 0 self.rxcq_cons = 0
self.rx_cqn = 0
self.txq_log_size = (256).bit_length()-1 self.txq_log_size = (256).bit_length()-1
self.txq_size = 2**self.txq_log_size self.txq_size = 2**self.txq_log_size
@@ -43,6 +77,8 @@ class Port:
self.txq = None self.txq = None
self.txq_prod = 0 self.txq_prod = 0
self.txq_cons = 0 self.txq_cons = 0
self.tx_sqn = 0
self.txq_db_offs = 0
self.tx_info = [None] * self.txq_size self.tx_info = [None] * self.txq_size
@@ -52,43 +88,103 @@ class Port:
self.txcq = None self.txcq = None
self.txcq_prod = 0 self.txcq_prod = 0
self.txcq_cons = 0 self.txcq_cons = 0
self.tx_cqn = 0
self.rx_queue = Queue() self.rx_queue = Queue()
async def init(self): 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) self.rxcq = self.driver.pool.alloc_region(self.rxcq_size*16)
addr = self.rxcq.get_absolute_address(0) 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) rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
addr = self.txq.get_absolute_address(0) 0, # rsvd
await self.hw_regs.write_dword(0x0100, 0x00000000) CNDM_CMD_OP_CREATE_CQ, # opcode
await self.hw_regs.write_dword(0x0104, 0x00000000) 0x00000000, # flags
await self.hw_regs.write_dword(0x0108, addr & 0xffffffff) self.index, # port
await self.hw_regs.write_dword(0x010c, addr >> 32) 0, # cqn
await self.hw_regs.write_dword(0x0100, 0x00000001 | (self.txq_log_size << 16)) 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) self.txcq = self.driver.pool.alloc_region(self.txcq_size*16)
addr = self.txcq.get_absolute_address(0) 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 rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
await self.hw_regs.read_dword(0) 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() await self.refill_rx_buffers()
@@ -101,7 +197,7 @@ class Port:
struct.pack_into('<xxxxLQ', self.txq.mem, 16*index, len(data), ptr+headroom) struct.pack_into('<xxxxLQ', self.txq.mem, 16*index, len(data), ptr+headroom)
self.tx_info[index] = tx_buf self.tx_info[index] = tx_buf
self.txq_prod += 1 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): async def recv(self):
return await self.rx_queue.get() return await self.rx_queue.get()
@@ -177,7 +273,7 @@ class Port:
self.prepare_rx_desc(self.rxq_prod & self.rxq_mask) self.prepare_rx_desc(self.rxq_prod & self.rxq_mask)
self.rxq_prod += 1 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): async def process_rx_cq(self):
@@ -229,6 +325,8 @@ class Driver:
self.pool = None self.pool = None
self.hw_regs = None self.hw_regs = None
self.port_count = None
self.ports = [] self.ports = []
self.free_packets = deque() self.free_packets = deque()
@@ -256,12 +354,40 @@ class Driver:
self.log.info("Port stride: 0x%x", self.port_stride) self.log.info("Port stride: 0x%x", self.port_stride)
for k in range(self.port_count): 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() await port.init()
self.dev.request_irq(k, port.interrupt_handler) self.dev.request_irq(k, port.interrupt_handler)
self.ports.append(port) 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): def alloc_pkt(self):
if self.free_packets: if self.free_packets:
return self.free_packets.popleft() 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) 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)"); $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_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01, AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10, 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_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1, DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2, DMA_ERROR_PARITY = 4'd2,
@@ -97,20 +98,23 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8, DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9, DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [1:0] {
READ_STATE_IDLE = 2'd0, READ_STATE_IDLE,
READ_STATE_START = 2'd1, READ_STATE_START,
READ_STATE_REQ = 2'd2; 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] typedef enum logic [0:0] {
AXI_STATE_IDLE = 1'd0, AXI_STATE_IDLE,
AXI_STATE_WRITE = 1'd1; 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 // datapath control signals
logic transfer_in_save; 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) if (rd_desc_req.SRC_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)"); $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_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01, AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10, 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_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1, DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2, DMA_ERROR_PARITY = 4'd2,
@@ -124,19 +125,22 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8, DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9, DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [0:0] {
AXI_STATE_IDLE = 1'd0, AXI_STATE_IDLE,
AXI_STATE_START = 1'd1; 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] typedef enum logic [0:0] {
AXIS_STATE_IDLE = 1'd0, AXIS_STATE_IDLE,
AXIS_STATE_READ = 1'd1; 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 // datapath control signals
logic transfer_in_save; 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) if (wr_desc_req.DST_ADDR_W < AXI_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)"); $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_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01, AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10, 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_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1, DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2, DMA_ERROR_PARITY = 4'd2,
@@ -126,16 +127,18 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8, DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9, DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_START = 3'd1, STATE_START,
STATE_WRITE = 3'd2, STATE_WRITE,
STATE_FINISH_BURST = 3'd3, STATE_FINISH_BURST,
STATE_DROP_DATA = 3'd4; 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 // datapath control signals
logic transfer_in_save; 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) if (desc_req.DST_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)"); $fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_WRITE = 2'd1, STATE_WRITE,
STATE_DROP_DATA = 2'd2; 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; 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) if (desc_req.SRC_ADDR_W < RAM_ADDR_W)
$fatal(0, "Error: Descriptor address width is not sufficient (instance %m)"); $fatal(0, "Error: Descriptor address width is not sufficient (instance %m)");
localparam logic [0:0] typedef enum logic [0:0] {
READ_STATE_IDLE = 1'd0, READ_STATE_IDLE,
READ_STATE_READ = 1'd1; 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] typedef enum logic [0:0] {
AXIS_STATE_IDLE = 1'd0, AXIS_STATE_IDLE,
AXIS_STATE_READ = 1'd1; 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 // datapath control signals
logic axis_cmd_ready; 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) 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)"); $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_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01, AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10, 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_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1, DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2, DMA_ERROR_PARITY = 4'd2,
@@ -159,19 +160,22 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8, DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9, DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [0:0] {
REQ_STATE_IDLE = 1'd0, REQ_STATE_IDLE,
REQ_STATE_START = 1'd1; 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] typedef enum logic [0:0] {
AXI_STATE_IDLE = 1'd0, AXI_STATE_IDLE,
AXI_STATE_WRITE = 1'd1; 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 [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; 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) 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)"); $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_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01, AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10, 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_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1, DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2, DMA_ERROR_PARITY = 4'd2,
@@ -163,25 +164,29 @@ localparam logic [3:0]
DMA_ERROR_PCIE_FLR = 4'd8, DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9, DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [0:0] {
REQ_STATE_IDLE = 1'd0, REQ_STATE_IDLE,
REQ_STATE_START = 1'd1; 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] typedef enum logic [0:0] {
READ_STATE_IDLE = 1'd0, READ_STATE_IDLE,
READ_STATE_READ = 1'd1; 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] typedef enum logic [0:0] {
AXI_STATE_IDLE = 1'd0, AXI_STATE_IDLE,
AXI_STATE_TRANSFER = 1'd1; 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 // datapath control signals
logic mask_fifo_we; 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) 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)"); $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_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001, REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010, REQ_IO_READ = 4'b0010,
@@ -221,22 +221,24 @@ localparam logic [3:0]
REQ_MEM_FETCH_ADD = 4'b0100, REQ_MEM_FETCH_ADD = 4'b0100,
REQ_MEM_SWAP = 4'b0101, REQ_MEM_SWAP = 4'b0101,
REQ_MEM_CAS = 4'b0110, REQ_MEM_CAS = 4'b0110,
REQ_MEM_RD_LOCKED = 4'b0111, REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_RD_0 = 4'b1000, REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_RD_1 = 4'b1001, REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WRITE_0 = 4'b1010, REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011, REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100, REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101, 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_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status 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_NORMAL_TERM = 4'b0000,
RC_ERR_POISONED = 4'b0001, RC_ERR_POISONED = 4'b0001,
RC_ERR_BAD_STATUS = 4'b0010, RC_ERR_BAD_STATUS = 4'b0010,
@@ -245,9 +247,10 @@ localparam logic [3:0]
RC_ERR_INVALID_ADDR = 4'b0101, RC_ERR_INVALID_ADDR = 4'b0101,
RC_ERR_INVALID_TAG = 4'b0110, RC_ERR_INVALID_TAG = 4'b0110,
RC_ERR_TIMEOUT = 4'b1001, 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_NONE = 4'd0,
DMA_ERR_TIMEOUT = 4'd1, DMA_ERR_TIMEOUT = 4'd1,
DMA_ERR_PARITY = 4'd2, DMA_ERR_PARITY = 4'd2,
@@ -258,22 +261,25 @@ localparam logic [3:0]
DMA_ERR_PCIE_FLR = 4'd8, DMA_ERR_PCIE_FLR = 4'd8,
DMA_ERR_PCIE_CPL_POISONED = 4'd9, DMA_ERR_PCIE_CPL_POISONED = 4'd9,
DMA_ERR_PCIE_CPL_STATUS_UR = 4'd10, 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] typedef enum logic [1:0] {
REQ_STATE_IDLE = 2'd0, REQ_STATE_IDLE,
REQ_STATE_START = 2'd1, REQ_STATE_START,
REQ_STATE_HEADER = 2'd2; 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_IDLE = 2'd0,
TLP_STATE_HEADER = 2'd1, TLP_STATE_HEADER = 2'd1,
TLP_STATE_WRITE = 2'd2, 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 // datapath control signals
logic last_cycle; 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) 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)"); $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_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001, REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010, REQ_IO_READ = 4'b0010,
@@ -193,44 +193,50 @@ localparam logic [3:0]
REQ_MEM_READ_LOCKED = 4'b0111, REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000, REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001, REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WR_0 = 4'b1010, REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WR_1 = 4'b1011, REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100, REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101, 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_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status 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] typedef enum logic [0:0] {
REQ_STATE_IDLE = 1'd0, REQ_STATE_IDLE,
REQ_STATE_START = 1'd1; 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] typedef enum logic [0:0] {
READ_STATE_IDLE = 1'd0, READ_STATE_IDLE,
READ_STATE_READ = 1'd1; 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] typedef enum logic [1:0] {
TLP_STATE_IDLE = 2'd0, TLP_STATE_IDLE,
TLP_STATE_HEADER = 2'd1, TLP_STATE_HEADER,
TLP_STATE_TRANSFER = 2'd2; 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] typedef enum logic [1:0] {
TLP_OUTPUT_STATE_IDLE = 2'd0, TLP_OUTPUT_STATE_IDLE,
TLP_OUTPUT_STATE_HEADER = 2'd1, TLP_OUTPUT_STATE_HEADER,
TLP_OUTPUT_STATE_PAYLOAD = 2'd2, TLP_OUTPUT_STATE_PAYLOAD,
TLP_OUTPUT_STATE_PASSTHROUGH = 2'd3; 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 // datapath control signals
logic mask_fifo_we; 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) if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -105,17 +106,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PREAMBLE = 2'd1, STATE_PREAMBLE,
STATE_PAYLOAD = 2'd2, STATE_PAYLOAD,
STATE_LAST = 2'd3; STATE_LAST
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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) if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -106,17 +107,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PAYLOAD = 2'd1, STATE_PAYLOAD,
STATE_LAST = 2'd2; 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_reg = 1'b0;
logic lanes_swapped_d1_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) if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -115,17 +116,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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_IDLE = 3'd0,
OUTPUT_TYPE_ERROR = 3'd1, OUTPUT_TYPE_ERROR = 3'd1,
OUTPUT_TYPE_START = 3'd2, OUTPUT_TYPE_START = 3'd2,
@@ -150,20 +155,22 @@ localparam [2:0]
OUTPUT_TYPE_TERM_0 = 3'd4, OUTPUT_TYPE_TERM_0 = 3'd4,
OUTPUT_TYPE_TERM_1 = 3'd5, OUTPUT_TYPE_TERM_1 = 3'd5,
OUTPUT_TYPE_TERM_2 = 3'd6, OUTPUT_TYPE_TERM_2 = 3'd6,
OUTPUT_TYPE_TERM_3 = 3'd7; OUTPUT_TYPE_TERM_3 = 3'd7
} out_type_t;
localparam [3:0] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_PREAMBLE = 4'd1, STATE_PREAMBLE,
STATE_PAYLOAD = 4'd2, STATE_PAYLOAD,
STATE_PAD = 4'd3, STATE_PAD,
STATE_FCS_1 = 4'd4, STATE_FCS_1,
STATE_FCS_2 = 4'd5, STATE_FCS_2,
STATE_FCS_3 = 4'd6, STATE_FCS_3,
STATE_ERR = 4'd7, STATE_ERR,
STATE_IFG = 4'd8; STATE_IFG
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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_0;
logic [DATA_W-1:0] fcs_output_data_1; logic [DATA_W-1:0] fcs_output_data_1;
logic [2:0] fcs_output_type_0; out_type_t fcs_output_type_0;
logic [2:0] fcs_output_type_1; out_type_t fcs_output_type_1;
logic [7:0] ifg_offset; 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_reg = '0, output_data_next;
logic [DATA_W-1:0] output_data_d1_reg = '0; 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; 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) if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -116,17 +117,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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_IDLE = 4'd0,
OUTPUT_TYPE_ERROR = 4'd1, OUTPUT_TYPE_ERROR = 4'd1,
OUTPUT_TYPE_START_0 = 4'd2, OUTPUT_TYPE_START_0 = 4'd2,
@@ -156,18 +161,20 @@ localparam [3:0]
OUTPUT_TYPE_TERM_4 = 4'd12, OUTPUT_TYPE_TERM_4 = 4'd12,
OUTPUT_TYPE_TERM_5 = 4'd13, OUTPUT_TYPE_TERM_5 = 4'd13,
OUTPUT_TYPE_TERM_6 = 4'd14, OUTPUT_TYPE_TERM_6 = 4'd14,
OUTPUT_TYPE_TERM_7 = 4'd15; OUTPUT_TYPE_TERM_7 = 4'd15
} out_type_t;
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_PAYLOAD = 3'd1, STATE_PAYLOAD,
STATE_PAD = 3'd2, STATE_PAD,
STATE_FCS_1 = 3'd3, STATE_FCS_1,
STATE_FCS_2 = 3'd4, STATE_FCS_2,
STATE_ERR = 3'd5, STATE_ERR,
STATE_IFG = 3'd6; STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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_0;
logic [DATA_W-1:0] fcs_output_data_1; logic [DATA_W-1:0] fcs_output_data_1;
logic [3:0] fcs_output_type_0; out_type_t fcs_output_type_0;
logic [3:0] fcs_output_type_1; out_type_t fcs_output_type_1;
logic [7:0] ifg_offset; 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 [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_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; 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) if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PIPE = 2'd1, STATE_PIPE,
STATE_PAYLOAD = 2'd2; STATE_PAYLOAD
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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) if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_PREAMBLE = 3'd1, STATE_PREAMBLE,
STATE_PAYLOAD = 3'd2, STATE_PAYLOAD,
STATE_LAST = 3'd3, STATE_LAST,
STATE_PAD = 3'd4, STATE_PAD,
STATE_FCS = 3'd5, STATE_FCS,
STATE_IFG = 3'd6; STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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) if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb, XGMII_LPI = 8'h06,
XGMII_TERM = 8'hfd, XGMII_START = 8'hfb,
XGMII_ERROR = 8'hfe; 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] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PREAMBLE = 2'd1, STATE_PREAMBLE,
STATE_PAYLOAD = 2'd2, STATE_PAYLOAD,
STATE_LAST = 2'd3; 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_present_reg = 1'b0;
logic term_first_cycle_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) if (m_axis_rx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb, XGMII_LPI = 8'h06,
XGMII_TERM = 8'hfd, XGMII_START = 8'hfb,
XGMII_ERROR = 8'hfe; 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] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PAYLOAD = 2'd1, STATE_PAYLOAD,
STATE_LAST = 2'd2; 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_reg = 1'b0;
logic lanes_swapped_d1_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_d0_reg = '0;
logic [DATA_W-1:0] xgmii_rxd_d1_reg = '0; logic [DATA_W-1:0] xgmii_rxd_d1_reg = '0;
logic xgmii_start_swap_reg = 1'b0; logic xgmii_start_swap_reg = 1'b0;
logic xgmii_start_d0_reg = 1'b0; logic xgmii_start_d0_reg = 1'b0;
logic xgmii_start_d1_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) if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb, XGMII_LPI = 8'h06,
XGMII_TERM = 8'hfd, XGMII_START = 8'hfb,
XGMII_ERROR = 8'hfe; 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] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_PREAMBLE = 4'd1, STATE_PREAMBLE,
STATE_PAYLOAD = 4'd2, STATE_PAYLOAD,
STATE_PAD = 4'd3, STATE_PAD,
STATE_FCS_1 = 4'd4, STATE_FCS_1,
STATE_FCS_2 = 4'd5, STATE_FCS_2,
STATE_FCS_3 = 4'd6, STATE_FCS_3,
STATE_ERR = 4'd7, STATE_ERR,
STATE_IFG = 4'd8; STATE_IFG
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; 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) if (s_axis_tx.USER_W != USER_W)
$fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface USER_W parameter mismatch (instance %m)");
localparam [7:0] typedef enum logic [7:0] {
ETH_PRE = 8'h55, ETH_PRE = 8'h55,
ETH_SFD = 8'hD5; ETH_SFD = 8'hD5
} eth_pre_t;
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_START = 8'hfb, XGMII_LPI = 8'h06,
XGMII_TERM = 8'hfd, XGMII_START = 8'hfb,
XGMII_ERROR = 8'hfe; 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] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_PAYLOAD = 3'd1, STATE_PAYLOAD,
STATE_PAD = 3'd2, STATE_PAD,
STATE_FCS_1 = 3'd3, STATE_FCS_1,
STATE_FCS_2 = 3'd4, STATE_FCS_2,
STATE_ERR = 3'd5, STATE_ERR,
STATE_IFG = 3'd6; STATE_IFG
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
logic reset_crc; logic reset_crc;

View File

@@ -63,7 +63,7 @@ if (CTRL_W * 8 != DATA_W)
if (HDR_W != 2) if (HDR_W != 2)
$fatal(0, "Error: HDR_W must be 2"); $fatal(0, "Error: HDR_W must be 2");
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06, XGMII_LPI = 8'h06,
XGMII_START = 8'hfb, XGMII_START = 8'hfb,
@@ -76,9 +76,10 @@ localparam [7:0]
XGMII_RES_3 = 8'hbc, XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc, XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -87,17 +88,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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 [DATA_W_INT-1:0] encoded_rx_data_int;
wire encoded_rx_data_valid_int; wire encoded_rx_data_valid_int;

View File

@@ -67,7 +67,7 @@ if (CTRL_W * 8 != DATA_W)
if (HDR_W != 2) if (HDR_W != 2)
$fatal(0, "Error: HDR_W must be 2"); $fatal(0, "Error: HDR_W must be 2");
localparam [7:0] typedef enum logic [7:0] {
XGMII_IDLE = 8'h07, XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06, XGMII_LPI = 8'h06,
XGMII_START = 8'hfb, XGMII_START = 8'hfb,
@@ -80,9 +80,10 @@ localparam [7:0]
XGMII_RES_3 = 8'hbc, XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc, XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7, 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_IDLE = 7'h00,
CTRL_LPI = 7'h06, CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e, CTRL_ERROR = 7'h1e,
@@ -91,17 +92,20 @@ localparam [6:0]
CTRL_RES_2 = 7'h4b, CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55, CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66, 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_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_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_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_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 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_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_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_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 [DATA_W_INT-1:0] xgmii_txd_int;
wire [CTRL_W_INT-1:0] xgmii_txc_int; wire [CTRL_W_INT-1:0] xgmii_txc_int;

View File

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

View File

@@ -103,13 +103,15 @@ reset_sync_inst (
.out(tx_reset_sync) .out(tx_reset_sync)
); );
localparam [1:0] typedef enum logic [1:0] {
STATE_RESET = 2'd0, STATE_RESET,
STATE_WAIT_LOCK = 2'd1, STATE_WAIT_LOCK,
STATE_WAIT_USRCLK = 2'd2, STATE_WAIT_USRCLK,
STATE_DONE = 2'd3; 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 [CNT_W-1:0] tx_reset_cnt_reg = '0;
logic tx_reset_done_reg = 1'b0; logic tx_reset_done_reg = 1'b0;

View File

@@ -189,14 +189,15 @@ initial begin
init_data[21] = cmd_halt(); // halt init_data[21] = cmd_halt(); // halt
end end
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_RUN = 3'd1, STATE_RUN,
STATE_TABLE_1 = 3'd2, STATE_TABLE_1,
STATE_TABLE_2 = 3'd3, STATE_TABLE_2,
STATE_TABLE_3 = 3'd4; 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); 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) if (s_axis_tx.DATA_W != 8 || m_axis_rx.DATA_W != 8)
$fatal(0, "Data interface width must be 8 bits (instance %m)"); $fatal(0, "Data interface width must be 8 bits (instance %m)");
localparam [3:0] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_ACTIVE_WRITE = 4'd1, STATE_ACTIVE_WRITE,
STATE_ACTIVE_READ = 4'd2, STATE_ACTIVE_READ,
STATE_START_WAIT = 4'd3, STATE_START_WAIT,
STATE_START = 4'd4, STATE_START,
STATE_ADDRESS_1 = 4'd5, STATE_ADDRESS_1,
STATE_ADDRESS_2 = 4'd6, STATE_ADDRESS_2,
STATE_WRITE_1 = 4'd7, STATE_WRITE_1,
STATE_WRITE_2 = 4'd8, STATE_WRITE_2,
STATE_WRITE_3 = 4'd9, STATE_WRITE_3,
STATE_READ = 4'd10, STATE_READ,
STATE_STOP = 4'd11; STATE_STOP
} state_t;
logic [3:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
localparam [3:0] typedef enum logic [3:0] {
PHY_STATE_IDLE = 4'd0, PHY_STATE_IDLE,
PHY_STATE_ACTIVE = 4'd1, PHY_STATE_ACTIVE,
PHY_STATE_REPEATED_START_1 = 4'd2, PHY_STATE_REPEATED_START_1,
PHY_STATE_REPEATED_START_2 = 4'd3, PHY_STATE_REPEATED_START_2,
PHY_STATE_START_1 = 4'd4, PHY_STATE_START_1,
PHY_STATE_START_2 = 4'd5, PHY_STATE_START_2,
PHY_STATE_WRITE_BIT_1 = 4'd6, PHY_STATE_WRITE_BIT_1,
PHY_STATE_WRITE_BIT_2 = 4'd7, PHY_STATE_WRITE_BIT_2,
PHY_STATE_WRITE_BIT_3 = 4'd8, PHY_STATE_WRITE_BIT_3,
PHY_STATE_READ_BIT_1 = 4'd9, PHY_STATE_READ_BIT_1,
PHY_STATE_READ_BIT_2 = 4'd10, PHY_STATE_READ_BIT_2,
PHY_STATE_READ_BIT_3 = 4'd11, PHY_STATE_READ_BIT_3,
PHY_STATE_READ_BIT_4 = 4'd12, PHY_STATE_READ_BIT_4,
PHY_STATE_STOP_1 = 4'd13, PHY_STATE_STOP_1,
PHY_STATE_STOP_2 = 4'd14, PHY_STATE_STOP_2,
PHY_STATE_STOP_3 = 4'd15; 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_start_bit;
logic phy_stop_bit; logic phy_stop_bit;
@@ -359,7 +361,7 @@ always_comb begin
mode_stop_next = s_axis_cmd_stop; mode_stop_next = s_axis_cmd_stop;
s_axis_cmd_ready_next = 1'b0; s_axis_cmd_ready_next = 1'b0;
if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin 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 // address or mode mismatch or forced start - repeated start
@@ -406,7 +408,7 @@ always_comb begin
mode_stop_next = s_axis_cmd_stop; mode_stop_next = s_axis_cmd_stop;
s_axis_cmd_ready_next = 1'b0; s_axis_cmd_ready_next = 1'b0;
if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin 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 // 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 output wire logic [7:0] data_out
); );
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_ADDRESS = 3'd1, STATE_ADDRESS,
STATE_ACK = 3'd2, STATE_ACK,
STATE_WRITE_1 = 3'd3, STATE_WRITE_1,
STATE_WRITE_2 = 3'd4, STATE_WRITE_2,
STATE_READ_1 = 3'd5, STATE_READ_1,
STATE_READ_2 = 3'd6, STATE_READ_2,
STATE_READ_3 = 3'd7; 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] data_reg = '0;
logic [7:0] shift_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 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 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 stretch SCL by holding it low until a data byte is presented at the AXI stream
input. input.
Control: 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) if (s_axis_tx.DATA_W != 8 || m_axis_rx.DATA_W != 8)
$fatal(0, "Data interface width must be 8 bits (instance %m)"); $fatal(0, "Data interface width must be 8 bits (instance %m)");
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_ADDRESS = 3'd1, STATE_ADDRESS,
STATE_ACK = 3'd2, STATE_ACK,
STATE_WRITE_1 = 3'd3, STATE_WRITE_1,
STATE_WRITE_2 = 3'd4, STATE_WRITE_2,
STATE_READ_1 = 3'd5, STATE_READ_1,
STATE_READ_2 = 3'd6, STATE_READ_2,
STATE_READ_3 = 3'd7; 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 [6:0] addr_reg = '0, addr_next;
logic [7:0] data_reg = '0, data_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) 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)"); $fatal(0, "Error: AXI word size must be a power of two multiple of 8 bits (instance %m)");
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_ADDRESS = 3'd1, STATE_ADDRESS,
STATE_READ_1 = 3'd2, STATE_READ_1,
STATE_READ_2 = 3'd3, STATE_READ_2,
STATE_WRITE_1 = 3'd4, STATE_WRITE_1,
STATE_WRITE_2 = 3'd5; 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 [7:0] count_reg = '0, count_next;
logic last_cycle_reg = 1'b0; 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) 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)"); $fatal(0, "Error: AXI word size must be a power of two multiple of 8 bits (instance %m)");
localparam [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_ADDRESS = 3'd1, STATE_ADDRESS,
STATE_READ_1 = 3'd2, STATE_READ_1,
STATE_READ_2 = 3'd3, STATE_READ_2,
STATE_WRITE_1 = 3'd4, STATE_WRITE_1,
STATE_WRITE_2 = 3'd5; 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 [7:0] count_reg = '0, count_next;
logic last_cycle_reg = 1'b0; logic last_cycle_reg = 1'b0;

View File

@@ -44,12 +44,13 @@ module taxi_mdio_master (
input wire logic [7:0] prescale input wire logic [7:0] prescale
); );
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_PREAMBLE = 2'd1, STATE_PREAMBLE,
STATE_TRANSFER = 2'd2; 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 [7:0] count_reg = '0, count_next;
logic [5:0] bit_count_reg = '0, bit_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) if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface requires byte (8-bit) granularity (instance %m)"); $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_3DW = 3'b000,
TLP_FMT_4DW = 3'b001, TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010, TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011, 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_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status 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] typedef enum logic [2:0] {
REQ_STATE_IDLE = 3'd0, REQ_STATE_IDLE,
REQ_STATE_READ_1 = 3'd1, REQ_STATE_READ_1,
REQ_STATE_READ_2 = 3'd2, REQ_STATE_READ_2,
REQ_STATE_WRITE_1 = 3'd3, REQ_STATE_WRITE_1,
REQ_STATE_WRITE_2 = 3'd4, REQ_STATE_WRITE_2,
REQ_STATE_WAIT_END = 3'd5; 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] typedef enum logic [1:0] {
RESP_STATE_IDLE = 2'd0, RESP_STATE_IDLE,
RESP_STATE_READ = 2'd1, RESP_STATE_READ,
RESP_STATE_WRITE = 2'd2, RESP_STATE_WRITE,
RESP_STATE_CPL = 2'd3; 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 [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; 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) if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface requires byte (8-bit) granularity (instance %m)"); $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_3DW = 3'b000,
TLP_FMT_4DW = 3'b001, TLP_FMT_4DW = 3'b001,
TLP_FMT_3DW_DATA = 3'b010, TLP_FMT_3DW_DATA = 3'b010,
TLP_FMT_4DW_DATA = 3'b011, 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_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status 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] typedef enum logic [0:0] {
REQ_STATE_IDLE = 1'd0, REQ_STATE_IDLE,
REQ_STATE_WAIT_END = 1'd1; 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] typedef enum logic [1:0] {
RESP_STATE_IDLE = 2'd0, RESP_STATE_IDLE,
RESP_STATE_READ = 2'd1, RESP_STATE_READ,
RESP_STATE_WRITE = 2'd2, RESP_STATE_WRITE,
RESP_STATE_CPL = 2'd3; 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 [2:0] rx_req_tlp_hdr_fmt;
logic [4:0] rx_req_tlp_hdr_type; 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) if (AXIL_STRB_W * 8 != AXIL_DATA_W)
$fatal(0, "Error: AXI interface requires byte (8-bit) granularity (instance %m)"); $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_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001, REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010, REQ_IO_READ = 4'b0010,
@@ -96,23 +96,26 @@ localparam [3:0]
REQ_CFG_WRITE_1 = 4'b1011, REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100, REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101, 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_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status 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] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_HEADER = 3'd1, STATE_HEADER,
STATE_READ = 3'd2, STATE_READ,
STATE_WRITE_1 = 3'd3, STATE_WRITE_1,
STATE_WRITE_2 = 3'd4, STATE_WRITE_2,
STATE_WAIT_END = 3'd5, STATE_WAIT_END,
STATE_CPL_1 = 3'd6, STATE_CPL_1,
STATE_CPL_2 = 3'd7; STATE_CPL_2
} state_t;
wire [63:0] req_tlp_hdr_addr; wire [63:0] req_tlp_hdr_addr;
wire [10:0] req_tlp_hdr_length; wire [10:0] req_tlp_hdr_length;
@@ -161,7 +164,7 @@ logic [95:0] cpl_tlp_hdr;
logic [32:0] cpl_tuser_1; logic [32:0] cpl_tuser_1;
logic [80:0] cpl_tuser_2; 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 [10:0] dword_count_reg = '0, dword_count_next;
logic [3:0] type_reg = '0, type_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 PERIOD_CNT_W = $clog2(UPDATE_PERIOD+1);
localparam ACC_W = INC_W+CNT_W+1; localparam ACC_W = INC_W+CNT_W+1;
localparam [0:0] typedef enum logic [0:0] {
STATE_READ = 1'd0, STATE_READ,
STATE_WRITE = 1'd1; 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_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; 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
end end
localparam [3:0] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_HEADER_1 = 4'd1, STATE_HEADER_1,
STATE_HEADER_2 = 4'd2, STATE_HEADER_2,
STATE_HEADER_3 = 4'd3, STATE_HEADER_3,
STATE_READ_1 = 4'd4, STATE_READ_1,
STATE_READ_2 = 4'd5, STATE_READ_2,
STATE_WRITE_1 = 4'd6, STATE_WRITE_1,
STATE_WRITE_2 = 4'd7, STATE_WRITE_2,
STATE_WAIT_LAST = 4'd8, STATE_WAIT_LAST,
STATE_ID = 4'd9; 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 [COUNT_SIZE-1:0] ptr_reg = '0, ptr_next;
logic [7:0] count_reg = 8'd0, count_next; logic [7:0] count_reg = 8'd0, count_next;

View File

@@ -144,19 +144,20 @@ initial begin
end end
end end
localparam [3:0] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_HEADER_1 = 4'd1, STATE_HEADER_1,
STATE_HEADER_2 = 4'd2, STATE_HEADER_2,
STATE_HEADER_3 = 4'd3, STATE_HEADER_3,
STATE_READ_1 = 4'd4, STATE_READ_1,
STATE_READ_2 = 4'd5, STATE_READ_2,
STATE_WRITE_1 = 4'd6, STATE_WRITE_1,
STATE_WRITE_2 = 4'd7, STATE_WRITE_2,
STATE_WAIT_LAST = 4'd8, STATE_WAIT_LAST,
STATE_ID = 4'd9; 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 [COUNT_SIZE-1:0] ptr_reg = '0, ptr_next;
logic [7:0] count_reg = 8'd0, count_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_output = 1'b0;
store_xfcp_usp_us_int_to_temp = 1'b0; store_xfcp_usp_us_int_to_temp = 1'b0;
store_xfcp_usp_us_temp_to_output = 1'b0; store_xfcp_usp_us_temp_to_output = 1'b0;
if (xfcp_usp_us_tready_int_reg) begin if (xfcp_usp_us_tready_int_reg) begin
// input is ready // input is ready
if (xfcp_usp_us.tready || !xfcp_usp_us_tvalid_reg) begin 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_tvalid_reg <= 1'b0;
xfcp_usp_us_tready_int_reg <= 1'b0; xfcp_usp_us_tready_int_reg <= 1'b0;
temp_xfcp_usp_us_tvalid_reg <= 1'b0; temp_xfcp_usp_us_tvalid_reg <= 1'b0;
end end
end end
endmodule endmodule

View File

@@ -105,22 +105,23 @@ initial begin
end end
end end
localparam [3:0] typedef enum logic [3:0] {
STATE_IDLE = 4'd0, STATE_IDLE,
STATE_HEADER_1 = 4'd1, STATE_HEADER_1,
STATE_HEADER_2 = 4'd2, STATE_HEADER_2,
STATE_PROCESS = 4'd3, STATE_PROCESS,
STATE_STATUS = 4'd4, STATE_STATUS,
STATE_PRESCALE_L = 4'd5, STATE_PRESCALE_L,
STATE_PRESCALE_H = 4'd6, STATE_PRESCALE_H,
STATE_COUNT = 4'd7, STATE_COUNT,
STATE_NEXT_CMD= 4'd8, STATE_NEXT_CMD,
STATE_WRITE_DATA = 4'd9, STATE_WRITE_DATA,
STATE_READ_DATA = 4'd10, STATE_READ_DATA,
STATE_WAIT_LAST = 4'd11, STATE_WAIT_LAST,
STATE_ID = 4'd12; 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; 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_next = i2c_wr_data_reg;
i2c_wr_data_valid_next = i2c_wr_data_valid_reg && !i2c_wr_data.tready; 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_wr_data_last_next = i2c_wr_data_last_reg;
i2c_rd_data_ready_next = 1'b0; i2c_rd_data_ready_next = 1'b0;
prescale_next = prescale_reg; prescale_next = prescale_reg;
stop_on_idle_next = stop_on_idle_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_output = 1'b0;
store_up_xfcp_int_to_temp = 1'b0; store_up_xfcp_int_to_temp = 1'b0;
store_up_xfcp_temp_to_output = 1'b0; store_up_xfcp_temp_to_output = 1'b0;
if (xfcp_usp_us_tready_int_reg) begin if (xfcp_usp_us_tready_int_reg) begin
// input is ready // input is ready
if (xfcp_usp_us.tready || !xfcp_usp_us_tvalid_reg) begin if (xfcp_usp_us.tready || !xfcp_usp_us_tvalid_reg) begin

View File

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

View File

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