mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-09 05:18:44 -07:00
Compare commits
19 Commits
442eb06868
...
32b073ade9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32b073ade9 | ||
|
|
e27b5c0b94 | ||
|
|
0ff8e5fb9e | ||
|
|
901606a64d | ||
|
|
ee204d1665 | ||
|
|
f8d2c26663 | ||
|
|
aee0483835 | ||
|
|
1530f8cecf | ||
|
|
450960c564 | ||
|
|
d055cb7857 | ||
|
|
b7aa9623c4 | ||
|
|
08f6586c2e | ||
|
|
bc0f8c0df2 | ||
|
|
6cf03d6435 | ||
|
|
1740e09a8a | ||
|
|
5df2aa3cfd | ||
|
|
8d7cdaa689 | ||
|
|
a39c62f85a | ||
|
|
896dff2fd1 |
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
47
src/cndm/modules/cndm/cndm_cmd.c
Normal file
47
src/cndm/modules/cndm/cndm_cmd.c
Normal 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);
|
||||||
|
}
|
||||||
103
src/cndm/modules/cndm/cndm_hw.h
Normal file
103
src/cndm/modules/cndm/cndm_hw.h
Normal 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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
265
src/cndm/rtl/cndm_micro_cmd_mbox.sv
Normal file
265
src/cndm/rtl/cndm_micro_cmd_mbox.sv
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
546
src/cndm/rtl/cndm_micro_dp_mgr.sv
Normal file
546
src/cndm/rtl/cndm_micro_dp_mgr.sv
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
469
src/pcie/rtl/taxi_pcie_msix_apb.sv
Normal file
469
src/pcie/rtl/taxi_pcie_msix_apb.sv
Normal 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
|
||||||
517
src/pcie/rtl/taxi_pcie_msix_axil.sv
Normal file
517
src/pcie/rtl/taxi_pcie_msix_axil.sv
Normal 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
|
||||||
@@ -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;
|
||||||
|
|||||||
56
src/pcie/tb/taxi_pcie_msix_apb/Makefile
Normal file
56
src/pcie/tb/taxi_pcie_msix_apb/Makefile
Normal 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
|
||||||
1
src/pcie/tb/taxi_pcie_msix_apb/pcie_if.py
Symbolic link
1
src/pcie/tb/taxi_pcie_msix_apb/pcie_if.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../pcie_if.py
|
||||||
349
src/pcie/tb/taxi_pcie_msix_apb/test_taxi_pcie_msix_apb.py
Normal file
349
src/pcie/tb/taxi_pcie_msix_apb/test_taxi_pcie_msix_apb.py
Normal 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,
|
||||||
|
)
|
||||||
93
src/pcie/tb/taxi_pcie_msix_apb/test_taxi_pcie_msix_apb.sv
Normal file
93
src/pcie/tb/taxi_pcie_msix_apb/test_taxi_pcie_msix_apb.sv
Normal 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
|
||||||
56
src/pcie/tb/taxi_pcie_msix_axil/Makefile
Normal file
56
src/pcie/tb/taxi_pcie_msix_axil/Makefile
Normal 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
|
||||||
1
src/pcie/tb/taxi_pcie_msix_axil/pcie_if.py
Symbolic link
1
src/pcie/tb/taxi_pcie_msix_axil/pcie_if.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../pcie_if.py
|
||||||
353
src/pcie/tb/taxi_pcie_msix_axil/test_taxi_pcie_msix_axil.py
Normal file
353
src/pcie/tb/taxi_pcie_msix_axil/test_taxi_pcie_msix_axil.py
Normal 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,
|
||||||
|
)
|
||||||
95
src/pcie/tb/taxi_pcie_msix_axil/test_taxi_pcie_msix_axil.sv
Normal file
95
src/pcie/tb/taxi_pcie_msix_axil/test_taxi_pcie_msix_axil.sv
Normal 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
|
||||||
72
src/prim/rtl/taxi_ram_1r1w_1c.sv
Normal file
72
src/prim/rtl/taxi_ram_1r1w_1c.sv
Normal 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
|
||||||
74
src/prim/rtl/taxi_ram_1r1w_2c.sv
Normal file
74
src/prim/rtl/taxi_ram_1r1w_2c.sv
Normal 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
|
||||||
70
src/prim/rtl/taxi_ram_1rw.sv
Normal file
70
src/prim/rtl/taxi_ram_1rw.sv
Normal 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
|
||||||
97
src/prim/rtl/taxi_ram_2rw_1c.sv
Normal file
97
src/prim/rtl/taxi_ram_2rw_1c.sv
Normal 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
|
||||||
99
src/prim/rtl/taxi_ram_2rw_2c.sv
Normal file
99
src/prim/rtl/taxi_ram_2rw_2c.sv
Normal 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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user