Compare commits

..

23 Commits

Author SHA1 Message Date
Alex Forencich
50ba1d4c89 cndm: Make IRQ assignments configurable, add IRQ rate limiter
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 21:21:09 -07:00
Alex Forencich
8773672f26 cndm: Board-level parameter cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 21:20:41 -07:00
Alex Forencich
9af793edc6 cndm: Parameter cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 17:39:28 -07:00
Alex Forencich
2bb2710bbd pcie: Add IRQ rate limit module and testbench
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 17:38:04 -07:00
Alex Forencich
86b9947794 stats: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:43:31 -07:00
Alex Forencich
9ec5bd0190 ptp: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:43:14 -07:00
Alex Forencich
3ac7484e16 pcie: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:42:31 -07:00
Alex Forencich
bb278958b2 eth: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:42:08 -07:00
Alex Forencich
4b7ca2a569 dma: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:41:24 -07:00
Alex Forencich
9d701c9186 axi: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:40:38 -07:00
Alex Forencich
f9a5d08365 apb: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:40:11 -07:00
Alex Forencich
a59a4dfd84 cndm: Remove port count registers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:22:52 -08:00
Alex Forencich
438c082f73 cndm: Read config in driver
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:22:36 -08:00
Alex Forencich
283ef97cec cndm: Initialize ID ROM differently to make Vivado happy
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:01:44 -08:00
Alex Forencich
e2823a65ef cndm: Read config in driver model
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 00:08:05 -08:00
Alex Forencich
dde401e095 cndm: Add config command to read config data from HW
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-07 23:12:40 -08:00
Alex Forencich
09f1b278e8 cndm: Make scratch registers more generic in datapath manager
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-07 23:12:02 -08:00
Alex Forencich
2e8f9f8731 cndm: Copy cndm-micro core logic as cndm-lite
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 21:07:25 -08:00
Alex Forencich
4a2b9dd10c dma: Fix incorrect width cast
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 20:39:10 -08:00
Alex Forencich
798756ac89 dma: Fix incorrect width cast
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:38:59 -08:00
Alex Forencich
41b87dc65c cndm: Set MAC clock frequency and rate in core testbench, remove commented out code
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:20:03 -08:00
Alex Forencich
f464a21e1d cndm: Parametrize core tests over PCIe interface width
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:19:53 -08:00
Alex Forencich
96630b8f61 cndm: Remove extraneous files from testbench file lists
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 18:04:14 -08:00
71 changed files with 3691 additions and 579 deletions

View File

@@ -77,7 +77,7 @@ logic [DATA_W-1:0] s_apb_b_prdata_pipe_reg = '0;
// verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W];
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN
wire [VALID_ADDR_W-1:0] s_apb_a_paddr_valid = VALID_ADDR_W'(s_apb_a.paddr >> (ADDR_W - VALID_ADDR_W));
@@ -95,16 +95,6 @@ assign s_apb_b.pslverr = 1'b0;
assign s_apb_b.pruser = '0;
assign s_apb_b.pbuser = '0;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin
mem_wr_en_a = 1'b0;
mem_rd_en_a = 1'b0;

View File

@@ -59,7 +59,7 @@ logic [DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic [DATA_W-1:0] s_apb_prdata_pipe_reg = '0;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W];
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
wire [VALID_ADDR_W-1:0] s_apb_paddr_valid = VALID_ADDR_W'(s_apb.paddr >> (ADDR_W - VALID_ADDR_W));
@@ -69,16 +69,6 @@ assign s_apb.pslverr = 1'b0;
assign s_apb.pruser = '0;
assign s_apb.pbuser = '0;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin
mem_wr_en = 1'b0;
mem_rd_en = 1'b0;

View File

@@ -251,10 +251,10 @@ logic [TR_CNT_W-1:0] trans_count_reg = 0;
wire trans_limit = trans_count_reg >= TR_CNT_W'(S_ACCEPT) && !trans_complete;
// transfer ID thread tracking
logic [ID_W-1:0] thread_id_reg[S_INT_THREADS-1:0];
logic [SEL_W-1:0] thread_m_reg[S_INT_THREADS-1:0];
logic [3:0] thread_region_reg[S_INT_THREADS-1:0];
logic [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0];
logic [ID_W-1:0] thread_id_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [SEL_W-1:0] thread_m_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [3:0] thread_region_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0] = '{default: '0};
// TODO fix loop
/* verilator lint_off UNOPTFLAT */
@@ -266,10 +266,6 @@ wire [S_INT_THREADS-1:0] thread_trans_start;
wire [S_INT_THREADS-1:0] thread_trans_complete;
for (genvar n = 0; n < S_INT_THREADS; n = n + 1) begin
initial begin
thread_count_reg[n] = '0;
end
assign thread_active[n] = thread_count_reg[n] != 0;
assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid;
assign thread_match_dest[n] = thread_match[n] && thread_m_reg[n] == m_select_next && (M_REGIONS < 2 || thread_region_reg[n] == m_axi_aregion_next);

View File

@@ -100,7 +100,7 @@ logic s_axi_rlast_pipe_reg = 1'b0;
logic s_axi_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W];
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
wire [VALID_ADDR_W-1:0] read_addr_valid = VALID_ADDR_W'(read_addr_reg >> (ADDR_W - VALID_ADDR_W));
wire [VALID_ADDR_W-1:0] write_addr_valid = VALID_ADDR_W'(write_addr_reg >> (ADDR_W - VALID_ADDR_W));
@@ -120,16 +120,6 @@ assign s_axi_rd.rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg
assign s_axi_rd.ruser = '0;
assign s_axi_rd.rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin
write_state_next = WRITE_STATE_IDLE;

View File

@@ -155,9 +155,9 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = 0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW];
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic fifo_decerr[2**FIFO_AW];
logic fifo_decerr[2**FIFO_AW] = '{default: '0};
wire [CL_M_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_decerr;
@@ -171,15 +171,6 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = 0;
fifo_decerr[i] = 0;
end
end
always_ff @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;
@@ -321,7 +312,7 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW];
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
wire [CL_S_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_en;
wire fifo_rd_en;
@@ -329,12 +320,6 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
end
end
always_ff @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;

View File

@@ -172,9 +172,9 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW];
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic fifo_decerr[2**FIFO_AW];
logic fifo_decerr[2**FIFO_AW] = '{default: '0};
wire [CL_M_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_decerr;
@@ -188,13 +188,6 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
fifo_decerr[i] = '0;
end
end
always_ff @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;
@@ -382,7 +375,7 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW];
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
wire [CL_S_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_en;
wire fifo_rd_en;
@@ -390,12 +383,6 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
end
end
always_ff @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;

View File

@@ -96,7 +96,7 @@ logic s_axil_b_rvalid_pipe_reg = 1'b0;
// verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W];
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN
wire [VALID_ADDR_W-1:0] s_axil_a_awaddr_valid = VALID_ADDR_W'(s_axil_wr_a.awaddr >> (ADDR_W - VALID_ADDR_W));
@@ -129,16 +129,6 @@ assign s_axil_rd_b.rresp = 2'b00;
assign s_axil_rd_b.ruser = '0;
assign s_axil_rd_b.rvalid = PIPELINE_OUTPUT ? s_axil_b_rvalid_pipe_reg : s_axil_b_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = 0;
end
end
end
always_comb begin
mem_wr_en_a = 1'b0;
mem_rd_en_a = 1'b0;

View File

@@ -67,7 +67,7 @@ logic [DATA_W-1:0] s_axil_rdata_pipe_reg = '0;
logic s_axil_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W];
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
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));
@@ -84,16 +84,6 @@ assign s_axil_rd.rresp = 2'b00;
assign s_axil_rd.ruser = '0;
assign s_axil_rd.rvalid = PIPELINE_OUTPUT ? s_axil_rvalid_pipe_reg : s_axil_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin
mem_wr_en = 1'b0;

View File

@@ -579,7 +579,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -572,7 +572,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -803,7 +803,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -766,7 +766,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -748,7 +748,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -737,7 +737,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -754,7 +754,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -47,7 +47,7 @@ module fpga_core #
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter PTP_CLK_PER_NS_NUM = 32,
parameter PTP_CLK_PER_NS_DENOM = 5,
parameter PTP_CLK_PER_NS_DEN = 5,
// PCIe interface configuration
parameter RQ_SEQ_NUM_W = 6,
@@ -753,7 +753,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -745,7 +745,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -59,7 +59,7 @@ export PARAM_GTY_CLK_CNT := $(PARAM_GTY_QUAD_CNT)
# PTP configuration
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_CLK_PER_NS_NUM := 32
export PARAM_PTP_CLK_PER_NS_DENOM := 5
export PARAM_PTP_CLK_PER_NS_DEN := 5
# AXI lite interface configuration (control)
export PARAM_AXIL_CTRL_DATA_W := 32

View File

@@ -519,7 +519,7 @@ def test_fpga_core(request, mac_data_w):
# PTP configuration
parameters['PTP_TS_EN'] = 1
parameters['PTP_CLK_PER_NS_NUM'] = 32
parameters['PTP_CLK_PER_NS_DENOM'] = 5
parameters['PTP_CLK_PER_NS_DEN'] = 5
# AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32

View File

@@ -45,7 +45,7 @@ module test_fpga_core #
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter PTP_CLK_PER_NS_NUM = 32,
parameter PTP_CLK_PER_NS_DENOM = 5,
parameter PTP_CLK_PER_NS_DEN = 5,
// PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 512,
@@ -215,7 +215,7 @@ fpga_core #(
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -665,7 +665,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -816,7 +816,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -1003,7 +1003,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -615,7 +615,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -622,7 +622,7 @@ cndm_micro_pcie_us #(
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165),
.PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -58,6 +58,45 @@ struct cndm_dev {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
u64 ptp_nom_period;
// config
u16 cfg_page_max;
u32 cmd_ver;
// FW ID
u32 fpga_id;
u32 fw_id;
u32 fw_ver;
u32 board_id;
u32 board_ver;
u32 build_date;
u32 git_hash;
u32 release_info;
char build_date_str[32];
// HW config
u16 sys_clk_per_ns_num;
u16 sys_clk_per_ns_den;
u16 ptp_clk_per_ns_num;
u16 ptp_clk_per_ns_den;
// Resources
u8 log_max_eq;
u8 log_max_eq_sz;
u8 eq_pool;
u8 eqe_ver;
u8 log_max_cq;
u8 log_max_cq_sz;
u8 cq_pool;
u8 cqe_ver;
u8 log_max_sq;
u8 log_max_sq_sz;
u8 sq_pool;
u8 sqe_ver;
u8 log_max_rq;
u8 log_max_rq_sz;
u8 rq_pool;
u8 rqe_ver;
};
struct cndm_tx_info {

View File

@@ -15,6 +15,8 @@ Authors:
#define CNDM_CMD_OP_NOP 0x0000
#define CNDM_CMD_OP_CFG 0x0100
#define CNDM_CMD_OP_ACCESS_REG 0x0180
#define CNDM_CMD_OP_PTP 0x0190
@@ -43,28 +45,68 @@ Authors:
#define CNDM_CMD_OP_QUERY_QP 0x0242
#define CNDM_CMD_OP_DESTROY_QP 0x0243
struct cndm_cmd_queue {
struct cndm_cmd_cfg {
__le16 rsvd;
union {
__le16 opcode;
__le16 status;
};
__le32 flags;
__le32 port;
__le32 qn;
struct {
__le16 cfg_page;
__le16 cfg_page_max;
};
__le32 cmd_ver;
__le32 qn2;
__le32 pd;
__le32 size;
__le32 dboffs;
__le32 fw_ver;
__u8 port_count;
__u8 rsvd2[3];
__le32 rsvd3[2];
__le64 ptr1;
__le64 ptr2;
__le32 dw12;
__le32 dw13;
__le32 dw14;
__le32 dw15;
union {
struct {
// Page 0: FW ID
__le32 fpga_id;
__le32 fw_id;
__le32 fw_ver;
__le32 board_id;
__le32 board_ver;
__le32 build_date;
__le32 git_hash;
__le32 release_info;
} p0;
struct {
// Page 1: HW config
__le16 port_count;
__le16 rsvd1;
__le32 rsvd2[3];
__le16 sys_clk_per_ns_den;
__le16 sys_clk_per_ns_num;
__le16 ptp_clk_per_ns_den;
__le16 ptp_clk_per_ns_num;
__le32 rsvd3[2];
} p1;
struct {
// Page 2: Resources
__u8 log_max_eq;
__u8 log_max_eq_sz;
__u8 eq_pool;
__u8 eqe_ver;
__u8 log_max_cq;
__u8 log_max_cq_sz;
__u8 cq_pool;
__u8 cqe_ver;
__u8 log_max_sq;
__u8 log_max_sq_sz;
__u8 sq_pool;
__u8 sqe_ver;
__u8 log_max_rq;
__u8 log_max_rq_sz;
__u8 rq_pool;
__u8 rqe_ver;
__le32 rsvd[4];
} p2;
};
};
#define CNDM_CMD_REG_FLG_WRITE 0x00000001
@@ -77,21 +119,11 @@ struct cndm_cmd_reg {
__le16 status;
};
__le32 flags;
__le32 dw2;
__le32 dw3;
__le32 dw4;
__le32 dw5;
__le32 dw6;
__le32 rsvd1[5];
__le32 reg_addr;
__le64 write_val;
__le64 read_val;
__le32 dw12;
__le32 dw13;
__le32 dw14;
__le32 dw15;
__le32 rsvd2[4];
};
#define CNDM_CMD_PTP_FLG_SET_TOD 0x00000001
@@ -118,6 +150,29 @@ struct cndm_cmd_ptp {
__le64 nom_period;
__le64 period;
__le32 rsvd2[2];
};
struct cndm_cmd_queue {
__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 prod;
__le32 cons;
__le32 dw14;
__le32 dw15;
};

View File

@@ -9,9 +9,9 @@ Authors:
*/
#include "cndm.h"
#include "cndm_hw.h"
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/version.h>
MODULE_DESCRIPTION("Corundum device driver");
@@ -44,9 +44,13 @@ static int cndm_common_probe(struct cndm_dev *cdev)
{
struct devlink *devlink = priv_to_devlink(cdev);
struct device *dev = cdev->dev;
struct rtc_time tm;
int ret = 0;
int k;
struct cndm_cmd_cfg cmd;
struct cndm_cmd_cfg rsp;
mutex_init(&cdev->mbox_lock);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
@@ -55,9 +59,125 @@ static int cndm_common_probe(struct cndm_dev *cdev)
devlink_register(devlink, dev);
#endif
cdev->port_count = ioread32(cdev->hw_addr + 0x0100);
// Read config page 0
cmd.opcode = CNDM_CMD_OP_CFG;
cmd.flags = 0x00000000;
cmd.cfg_page = 0;
cndm_exec_cmd(cdev, &cmd, &rsp);
cdev->cfg_page_max = rsp.cfg_page_max;
cdev->cmd_ver = rsp.cmd_ver;
dev_info(dev, "Config pages: %d", cdev->cfg_page_max+1);
dev_info(dev, "Command version: %d.%d.%d", cdev->cmd_ver >> 20,
(cdev->cmd_ver >> 12) & 0xff,
cdev->cmd_ver & 0xfff);
// FW ID
cdev->fpga_id = rsp.p0.fpga_id;
cdev->fw_id = rsp.p0.fw_id;
cdev->fw_ver = rsp.p0.fw_ver;
cdev->board_id = rsp.p0.board_id;
cdev->board_ver = rsp.p0.board_ver;
cdev->build_date = rsp.p0.build_date;
cdev->git_hash = rsp.p0.git_hash;
cdev->release_info = rsp.p0.release_info;
rtc_time64_to_tm(cdev->build_date, &tm);
dev_info(dev, "FPGA ID: 0x%08x", cdev->fpga_id);
dev_info(dev, "FW ID: 0x%08x", cdev->fw_id);
dev_info(dev, "FW version: %d.%d.%d", cdev->fw_ver >> 20,
(cdev->fw_ver >> 12) & 0xff,
cdev->fw_ver & 0xfff);
dev_info(dev, "Board ID: 0x%08x", cdev->board_id);
dev_info(dev, "Board version: %d.%d.%d", cdev->board_ver >> 20,
(cdev->board_ver >> 12) & 0xff,
cdev->board_ver & 0xfff);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
snprintf(cdev->build_date_str, sizeof(cdev->build_date_str), "%ptRd %ptRt", &tm, &tm);
#else
snprintf(cdev->build_date_str, sizeof(cdev->build_date_str), "%04d-%02d-%02d %02d:%02d:%02d",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
#endif
dev_info(dev, "Build date: %s UTC (raw: 0x%08x)", cdev->build_date_str, cdev->build_date);
dev_info(dev, "Git hash: %08x", cdev->git_hash);
dev_info(dev, "Release info: %08x", cdev->release_info);
// Read config page 1
cmd.opcode = CNDM_CMD_OP_CFG;
cmd.flags = 0x00000000;
cmd.cfg_page = 1;
cndm_exec_cmd(cdev, &cmd, &rsp);
// HW config
cdev->port_count = rsp.p1.port_count;
cdev->sys_clk_per_ns_num = rsp.p1.sys_clk_per_ns_num;
cdev->sys_clk_per_ns_den = rsp.p1.sys_clk_per_ns_den;
cdev->ptp_clk_per_ns_num = rsp.p1.ptp_clk_per_ns_num;
cdev->ptp_clk_per_ns_den = rsp.p1.ptp_clk_per_ns_den;
dev_info(dev, "Port count: %d", cdev->port_count);
if (cdev->sys_clk_per_ns_num != 0) {
u64 a, b, c;
a = (u64)cdev->sys_clk_per_ns_den * 1000;
b = a / cdev->sys_clk_per_ns_num;
c = a - (b * cdev->sys_clk_per_ns_num);
c = (c * 1000000000) / cdev->sys_clk_per_ns_num;
dev_info(dev, "Sys clock freq: %lld.%09lld MHz (raw %d/%d ns)", b, c, cdev->sys_clk_per_ns_num, cdev->sys_clk_per_ns_den);
}
if (cdev->ptp_clk_per_ns_num != 0) {
u64 a, b, c;
a = (u64)cdev->ptp_clk_per_ns_den * 1000;
b = a / cdev->ptp_clk_per_ns_num;
c = a - (b * cdev->ptp_clk_per_ns_num);
c = (c * 1000000000) / cdev->ptp_clk_per_ns_num;
dev_info(dev, "PTP clock freq: %lld.%09lld MHz (raw %d/%d ns)", b, c, cdev->ptp_clk_per_ns_num, cdev->ptp_clk_per_ns_den);
}
// Read config page 2
cmd.opcode = CNDM_CMD_OP_CFG;
cmd.flags = 0x00000000;
cmd.cfg_page = 2;
cndm_exec_cmd(cdev, &cmd, &rsp);
// Resources
cdev->log_max_eq = rsp.p2.log_max_eq;
cdev->log_max_eq_sz = rsp.p2.log_max_eq_sz;
cdev->eq_pool = rsp.p2.eq_pool;
cdev->eqe_ver = rsp.p2.eqe_ver;
cdev->log_max_cq = rsp.p2.log_max_cq;
cdev->log_max_cq_sz = rsp.p2.log_max_cq_sz;
cdev->cq_pool = rsp.p2.cq_pool;
cdev->cqe_ver = rsp.p2.cqe_ver;
cdev->log_max_sq = rsp.p2.log_max_sq;
cdev->log_max_sq_sz = rsp.p2.log_max_sq_sz;
cdev->sq_pool = rsp.p2.sq_pool;
cdev->sqe_ver = rsp.p2.sqe_ver;
cdev->log_max_rq = rsp.p2.log_max_rq;
cdev->log_max_rq_sz = rsp.p2.log_max_rq_sz;
cdev->rq_pool = rsp.p2.rq_pool;
cdev->rqe_ver = rsp.p2.rqe_ver;
dev_info(dev, "Max EQ count: %d (log %d)", 1 << cdev->log_max_eq, cdev->log_max_eq);
dev_info(dev, "Max EQ size: %d (log %d)", 1 << cdev->log_max_eq_sz, cdev->log_max_eq_sz);
dev_info(dev, "EQ pool: %d", cdev->eq_pool);
dev_info(dev, "EQE version: %d", cdev->eqe_ver);
dev_info(dev, "Max CQ count: %d (log %d)", 1 << cdev->log_max_cq, cdev->log_max_cq);
dev_info(dev, "Max CQ size: %d (log %d)", 1 << cdev->log_max_cq_sz, cdev->log_max_cq_sz);
dev_info(dev, "CQ pool: %d", cdev->cq_pool);
dev_info(dev, "CQE version: %d", cdev->cqe_ver);
dev_info(dev, "Max SQ count: %d (log %d)", 1 << cdev->log_max_sq, cdev->log_max_sq);
dev_info(dev, "Max SQ size: %d (log %d)", 1 << cdev->log_max_sq_sz, cdev->log_max_sq_sz);
dev_info(dev, "SQ pool: %d", cdev->sq_pool);
dev_info(dev, "SQE version: %d", cdev->sqe_ver);
dev_info(dev, "Max RQ count: %d (log %d)", 1 << cdev->log_max_rq, cdev->log_max_rq);
dev_info(dev, "Max RQ size: %d (log %d)", 1 << cdev->log_max_rq_sz, cdev->log_max_rq_sz);
dev_info(dev, "RQ pool: %d", cdev->rq_pool);
dev_info(dev, "RQE version: %d", cdev->rqe_ver);
if (cdev->port_count > ARRAY_SIZE(cdev->ndev))
cdev->port_count = ARRAY_SIZE(cdev->ndev);

View File

@@ -0,0 +1,23 @@
cndm_lite_core.sv
cndm_micro_cmd_mbox.sv
cndm_micro_dp_mgr.sv
cndm_micro_port.sv
cndm_micro_rx.sv
cndm_micro_tx.sv
cndm_micro_queue_state.sv
cndm_micro_desc_rd.sv
cndm_micro_cpl_wr.sv
../lib/taxi/src/prim/rtl/taxi_ram_2rw_1c.sv
../lib/taxi/src/dma/rtl/taxi_dma_client_axis_source.sv
../lib/taxi/src/dma/rtl/taxi_dma_client_axis_sink.sv
../lib/taxi/src/dma/rtl/taxi_dma_if_mux.f
../lib/taxi/src/dma/rtl/taxi_dma_psdpram.sv
../lib/taxi/src/apb/rtl/taxi_apb_if.sv
../lib/taxi/src/apb/rtl/taxi_apb_interconnect.sv
../lib/taxi/src/axi/rtl/taxi_axil_interconnect_1s.f
../lib/taxi/src/axis/rtl/taxi_axis_async_fifo_adapter.f
../lib/taxi/src/axis/rtl/taxi_axis_arb_mux.f
../lib/taxi/src/axis/rtl/taxi_axis_demux.sv
../lib/taxi/src/ptp/rtl/taxi_ptp_td_phc_apb.f
../lib/taxi/src/ptp/rtl/taxi_ptp_td_rel2tod.sv
../lib/taxi/src/pcie/rtl/taxi_irq_rate_limit.sv

View File

@@ -0,0 +1,638 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2025-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Corundum-lite core logic
*/
module cndm_lite_core #(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'hDEADBEEF,
parameter FW_ID = 32'h0000C002,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1234_0000,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DEN = 165
)
(
input wire logic clk,
input wire logic rst,
/*
* Control register interface
*/
taxi_axil_if.wr_slv s_axil_ctrl_wr,
taxi_axil_if.rd_slv s_axil_ctrl_rd,
/*
* DMA
*/
taxi_dma_desc_if.req_src dma_rd_desc_req,
taxi_dma_desc_if.sts_snk dma_rd_desc_sts,
taxi_dma_desc_if.req_src dma_wr_desc_req,
taxi_dma_desc_if.sts_snk dma_wr_desc_sts,
taxi_dma_ram_if.wr_slv dma_ram_wr,
taxi_dma_ram_if.rd_slv dma_ram_rd,
/*
* Interrupts
*/
taxi_axis_if.src m_axis_irq,
/*
* PTP
*/
input wire logic ptp_clk = 1'b0,
input wire logic ptp_rst = 1'b0,
input wire logic ptp_sample_clk = 1'b0,
input wire logic ptp_td_sdi = 1'b0,
output wire logic ptp_td_sdo,
output wire logic ptp_pps,
output wire logic ptp_pps_str,
output wire logic ptp_sync_locked,
output wire logic [63:0] ptp_sync_ts_rel,
output wire logic ptp_sync_ts_rel_step,
output wire logic [95:0] ptp_sync_ts_tod,
output wire logic ptp_sync_ts_tod_step,
output wire logic ptp_sync_pps,
output wire logic ptp_sync_pps_str,
/*
* Ethernet
*/
input wire logic mac_tx_clk[PORTS],
input wire logic mac_tx_rst[PORTS],
taxi_axis_if.src mac_axis_tx[PORTS],
taxi_axis_if.snk mac_axis_tx_cpl[PORTS],
input wire logic mac_rx_clk[PORTS],
input wire logic mac_rx_rst[PORTS],
taxi_axis_if.snk mac_axis_rx[PORTS]
);
localparam CL_PORTS = $clog2(PORTS);
localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
localparam RAM_SEGS = dma_ram_wr.SEGS;
localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W;
localparam RAM_SEG_DATA_W = dma_ram_wr.SEG_DATA_W;
localparam RAM_SEG_BE_W = dma_ram_wr.SEG_BE_W;
localparam RAM_SEL_W = dma_ram_wr.SEL_W;
localparam PORT_OFFSET_DP = PTP_TS_EN ? 1 : 0;
localparam PORT_OFFSET_HOST = 2;
localparam PORT_BASE_ADDR_DP = PTP_TS_EN ? 32'h00010000 : 32'h00000000;
localparam PORT_BASE_ADDR_HOST = 32'h00020000;
localparam SYS_CLK_CYC_PER_US = (1000*SYS_CLK_PER_NS_DEN+SYS_CLK_PER_NS_NUM-1)/SYS_CLK_PER_NS_NUM;
taxi_axil_if #(
.DATA_W(s_axil_ctrl_wr.DATA_W),
.ADDR_W(16),
.STRB_W(s_axil_ctrl_wr.STRB_W),
.AWUSER_EN(s_axil_ctrl_wr.AWUSER_EN),
.AWUSER_W(s_axil_ctrl_wr.AWUSER_W),
.WUSER_EN(s_axil_ctrl_wr.WUSER_EN),
.WUSER_W(s_axil_ctrl_wr.WUSER_W),
.BUSER_EN(s_axil_ctrl_wr.BUSER_EN),
.BUSER_W(s_axil_ctrl_wr.BUSER_W),
.ARUSER_EN(s_axil_ctrl_wr.ARUSER_EN),
.ARUSER_W(s_axil_ctrl_wr.ARUSER_W),
.RUSER_EN(s_axil_ctrl_wr.RUSER_EN),
.RUSER_W(s_axil_ctrl_wr.RUSER_W)
)
axil_ctrl[PORTS+PORT_OFFSET_HOST]();
taxi_axil_interconnect_1s #(
.M_COUNT($size(axil_ctrl)),
.ADDR_W(s_axil_ctrl_wr.ADDR_W),
.M_REGIONS(1),
.M_BASE_ADDR('0),
.M_ADDR_W({$size(axil_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(axil_ctrl){1'b0}})
)
port_intercon_inst (
.clk(clk),
.rst(rst),
/*
* AXI4-lite slave interface
*/
.s_axil_wr(s_axil_ctrl_wr),
.s_axil_rd(s_axil_ctrl_rd),
/*
* AXI4-lite master interfaces
*/
.m_axil_wr(axil_ctrl),
.m_axil_rd(axil_ctrl)
);
logic s_axil_awready_reg = 1'b0;
logic s_axil_wready_reg = 1'b0;
logic s_axil_bvalid_reg = 1'b0;
logic s_axil_arready_reg = 1'b0;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0;
logic s_axil_rvalid_reg = 1'b0;
assign axil_ctrl[0].awready = s_axil_awready_reg;
assign axil_ctrl[0].wready = s_axil_wready_reg;
assign axil_ctrl[0].bresp = '0;
assign axil_ctrl[0].buser = '0;
assign axil_ctrl[0].bvalid = s_axil_bvalid_reg;
assign axil_ctrl[0].arready = s_axil_arready_reg;
assign axil_ctrl[0].rdata = s_axil_rdata_reg;
assign axil_ctrl[0].rresp = '0;
assign axil_ctrl[0].ruser = '0;
assign axil_ctrl[0].rvalid = s_axil_rvalid_reg;
logic cmd_mbox_start_reg = 1'b0;
wire cmd_mbox_busy;
logic [95:0] get_ptp_ts_tod_reg = '0;
logic [63:0] get_ptp_ts_rel_reg = '0;
always_ff @(posedge clk) begin
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= s_axil_bvalid_reg && !axil_ctrl[0].bready;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= s_axil_rvalid_reg && !axil_ctrl[0].rready;
cmd_mbox_start_reg <= 1'b0;
if (axil_ctrl[0].awvalid && axil_ctrl[0].wvalid && !s_axil_bvalid_reg) begin
s_axil_awready_reg <= 1'b1;
s_axil_wready_reg <= 1'b1;
s_axil_bvalid_reg <= 1'b1;
case ({axil_ctrl[0].awaddr[15:2], 2'b00})
// 16'h0100: begin
// txq_en_reg <= axil_ctrl[0].wdata[0];
// txq_size_reg <= axil_ctrl[0].wdata[19:16];
// end
// 16'h0104: txq_prod_reg <= axil_ctrl[0].wdata[15:0];
// 16'h0108: txq_base_addr_reg[31:0] <= axil_ctrl[0].wdata;
// 16'h010c: txq_base_addr_reg[63:32] <= axil_ctrl[0].wdata;
16'h0200: begin
cmd_mbox_start_reg <= axil_ctrl[0].wdata[0];
end
default: begin end
endcase
end
if (axil_ctrl[0].arvalid && !s_axil_rvalid_reg) begin
s_axil_rdata_reg <= '0;
s_axil_arready_reg <= 1'b1;
s_axil_rvalid_reg <= 1'b1;
case ({axil_ctrl[0].araddr[15:2], 2'b00})
16'h0200: begin
s_axil_rdata_reg[0] <= cmd_mbox_busy;
end
16'h0300: s_axil_rdata_reg <= {ptp_sync_ts_tod[15:0], 16'd0}; // PTP cur fns
16'h0304: s_axil_rdata_reg <= ptp_sync_ts_tod[47:16]; // PTP cur ToD ns
16'h0308: s_axil_rdata_reg <= ptp_sync_ts_tod[79:48]; // PTP cur ToD sec l
16'h030C: s_axil_rdata_reg <= 32'(ptp_sync_ts_tod[95:80]); // PTP cur ToD sec h
16'h0310: s_axil_rdata_reg <= ptp_sync_ts_rel[47:16]; // PTP cur rel ns l
16'h0314: s_axil_rdata_reg <= 32'(ptp_sync_ts_rel[63:48]); // PTP cur rel ns h
16'h0318: s_axil_rdata_reg <= '0; // PTP cur PTM l
16'h031C: s_axil_rdata_reg <= '0; // PTP cur PTM h
16'h0320: begin
// PTP snapshot fns
get_ptp_ts_tod_reg <= ptp_sync_ts_tod;
get_ptp_ts_rel_reg <= ptp_sync_ts_rel;
s_axil_rdata_reg <= {ptp_sync_ts_tod[15:0], 16'd0};
end
16'h0324: s_axil_rdata_reg <= 32'(get_ptp_ts_tod_reg[45:16]); // PTP snapshot ToD ns
16'h0328: s_axil_rdata_reg <= get_ptp_ts_tod_reg[79:48]; // PTP snapshot ToD sec l
16'h032C: s_axil_rdata_reg <= 32'(get_ptp_ts_tod_reg[95:80]); // PTP snapshot ToD sec h
16'h0330: s_axil_rdata_reg <= get_ptp_ts_rel_reg[47:16]; // PTP snapshot rel ns l
16'h0334: s_axil_rdata_reg <= 32'(get_ptp_ts_rel_reg[63:48]); // PTP snapshot rel ns h
16'h0338: s_axil_rdata_reg <= '0; // PTP snapshot PTM l
16'h033C: s_axil_rdata_reg <= '0; // PTP snapshot PTM h
default: begin end
endcase
end
if (rst) begin
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= 1'b0;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= 1'b0;
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
localparam APB_DP_ADDR_W = 16+$clog2(PORTS+PORT_OFFSET_DP);
taxi_apb_if #(
.DATA_W(32),
.ADDR_W(APB_DP_ADDR_W)
)
apb_dp_ctrl();
cndm_micro_dp_mgr #(
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// Addressing
.PTP_BASE_ADDR_DP(0),
.PORT_BASE_ADDR_DP(PORT_BASE_ADDR_DP),
.PORT_BASE_ADDR_HOST(PORT_BASE_ADDR_HOST)
)
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[PORT_OFFSET_DP+PORTS]();
taxi_apb_interconnect #(
.M_CNT($size(apb_port_dp_ctrl)),
.ADDR_W(APB_DP_ADDR_W),
.M_REGIONS(1),
.M_BASE_ADDR('0),
.M_ADDR_W({$size(apb_port_dp_ctrl){{1{32'd16}}}}),
.M_SECURE({$size(apb_port_dp_ctrl){1'b0}})
)
port_dp_intercon_inst (
.clk(clk),
.rst(rst),
/*
* APB slave interface
*/
.s_apb(apb_dp_ctrl),
/*
* APB master interfaces
*/
.m_apb(apb_port_dp_ctrl)
);
if (PTP_TS_EN) begin : ptp
taxi_ptp_td_phc_apb #(
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DEN)
)
ptp_inst (
.clk(clk),
.rst(rst),
/*
* Control register interface
*/
.s_apb(apb_port_dp_ctrl[0]),
/*
* PTP
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdo(ptp_td_sdo),
.ptp_pps(ptp_pps),
.ptp_pps_str(ptp_pps_str),
.ptp_sync_locked(ptp_sync_locked),
.ptp_sync_ts_rel(ptp_sync_ts_rel),
.ptp_sync_ts_rel_step(ptp_sync_ts_rel_step),
.ptp_sync_ts_tod(ptp_sync_ts_tod),
.ptp_sync_ts_tod_step(ptp_sync_ts_tod_step),
.ptp_sync_pps(ptp_sync_pps),
.ptp_sync_pps_str(ptp_sync_pps_str)
);
end else begin : ptp
assign ptp_td_sdo = 1'b0;
assign ptp_pps = 1'b0;
assign ptp_pps_str = 1'b0;
assign ptp_sync_locked = 1'b0;
assign ptp_sync_ts_rel = '0;
assign ptp_sync_ts_rel_step = 1'b0;
assign ptp_sync_ts_tod = '0;
assign ptp_sync_ts_tod_step = 1'b0;
assign ptp_sync_pps = 1'b0;
assign ptp_sync_pps_str = 1'b0;
end
taxi_dma_desc_if #(
.SRC_ADDR_W(dma_rd_desc_req.SRC_ADDR_W),
.SRC_SEL_EN(dma_rd_desc_req.SRC_SEL_EN),
.SRC_SEL_W(dma_rd_desc_req.SRC_SEL_W),
.SRC_ASID_EN(dma_rd_desc_req.SRC_ASID_EN),
.DST_ADDR_W(dma_rd_desc_req.DST_ADDR_W),
.DST_SEL_EN(dma_rd_desc_req.DST_SEL_EN),
.DST_SEL_W(dma_rd_desc_req.DST_SEL_W-CL_PORTS),
.DST_ASID_EN(dma_rd_desc_req.DST_ASID_EN),
.IMM_EN(dma_rd_desc_req.IMM_EN),
.LEN_W(dma_rd_desc_req.LEN_W),
.TAG_W(dma_rd_desc_req.TAG_W-CL_PORTS),
.ID_EN(dma_rd_desc_req.ID_EN),
.DEST_EN(dma_rd_desc_req.DEST_EN),
.USER_EN(dma_rd_desc_req.USER_EN)
) dma_rd_desc_int[PORTS]();
taxi_dma_desc_if #(
.SRC_ADDR_W(dma_wr_desc_req.SRC_ADDR_W),
.SRC_SEL_EN(dma_wr_desc_req.SRC_SEL_EN),
.SRC_SEL_W(dma_wr_desc_req.SRC_SEL_W-CL_PORTS),
.SRC_ASID_EN(dma_wr_desc_req.SRC_ASID_EN),
.DST_ADDR_W(dma_wr_desc_req.DST_ADDR_W),
.DST_SEL_EN(dma_wr_desc_req.DST_SEL_EN),
.DST_SEL_W(dma_wr_desc_req.DST_SEL_W),
.DST_ASID_EN(dma_wr_desc_req.DST_ASID_EN),
.IMM_EN(dma_wr_desc_req.IMM_EN),
.IMM_W(dma_wr_desc_req.IMM_W),
.LEN_W(dma_wr_desc_req.LEN_W),
.TAG_W(dma_wr_desc_req.TAG_W-CL_PORTS),
.ID_EN(dma_wr_desc_req.ID_EN),
.DEST_EN(dma_wr_desc_req.DEST_EN),
.USER_EN(dma_wr_desc_req.USER_EN)
) dma_wr_desc_int[PORTS]();
taxi_dma_ram_if #(
.SEGS(RAM_SEGS),
.SEG_ADDR_W(RAM_SEG_ADDR_W),
.SEG_DATA_W(RAM_SEG_DATA_W),
.SEG_BE_W(RAM_SEG_BE_W),
.SEL_W(RAM_SEL_W-CL_PORTS)
) dma_ram_int[PORTS]();
taxi_dma_if_mux #(
.PORTS(PORTS),
.ARB_ROUND_ROBIN(1),
.ARB_LSB_HIGH_PRIO(1)
)
dma_mux_inst (
.clk(clk),
.rst(rst),
/*
* DMA descriptors from clients
*/
.client_rd_req(dma_rd_desc_int),
.client_rd_sts(dma_rd_desc_int),
.client_wr_req(dma_wr_desc_int),
.client_wr_sts(dma_wr_desc_int),
/*
* DMA descriptors to DMA engines
*/
.dma_rd_req(dma_rd_desc_req),
.dma_rd_sts(dma_rd_desc_sts),
.dma_wr_req(dma_wr_desc_req),
.dma_wr_sts(dma_wr_desc_sts),
/*
* RAM interface (from DMA interface)
*/
.dma_ram_wr(dma_ram_wr),
.dma_ram_rd(dma_ram_rd),
/*
* RAM interface (towards RAM)
*/
.client_ram_wr(dma_ram_int),
.client_ram_rd(dma_ram_int)
);
taxi_axis_if #(
.DATA_W(m_axis_irq.DATA_W),
.KEEP_EN(0),
.KEEP_W(1)
) axis_irq_int(), axis_irq_port[PORTS]();
taxi_axis_arb_mux #(
.S_COUNT($size(axis_irq_port)),
.ARB_ROUND_ROBIN(1),
.ARB_LSB_HIGH_PRIO(1)
)
irq_mux_inst (
.clk(clk),
.rst(rst),
/*
* AXI4-Stream input (sink)
*/
.s_axis(axis_irq_port),
/*
* AXI4-Stream output (source)
*/
.m_axis(axis_irq_int)
);
taxi_irq_rate_limit
irq_rate_limit_inst (
.clk(clk),
.rst(rst),
/*
* Interrupt request input
*/
.s_axis_irq(axis_irq_int),
/*
* Interrupt request output
*/
.m_axis_irq(m_axis_irq),
/*
* Configuration
*/
.prescale(16'(SYS_CLK_CYC_PER_US)),
.min_interval(10) // TODO make configurable
);
for (genvar p = 0; p < PORTS; p = p + 1) begin : port
cndm_micro_port #(
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD)
)
port_inst (
.clk(clk),
.rst(rst),
/*
* Control register interface
*/
.s_axil_ctrl_wr(axil_ctrl[PORT_OFFSET_HOST+p]),
.s_axil_ctrl_rd(axil_ctrl[PORT_OFFSET_HOST+p]),
/*
* Datapath control register interface
*/
.s_apb_dp_ctrl(apb_port_dp_ctrl[PORT_OFFSET_DP+p]),
/*
* DMA
*/
.dma_rd_desc_req(dma_rd_desc_int[p]),
.dma_rd_desc_sts(dma_rd_desc_int[p]),
.dma_wr_desc_req(dma_wr_desc_int[p]),
.dma_wr_desc_sts(dma_wr_desc_int[p]),
.dma_ram_wr(dma_ram_int[p]),
.dma_ram_rd(dma_ram_int[p]),
/*
* Interrupts
*/
.m_axis_irq(axis_irq_port[p]),
/*
* PTP
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_td_sdi(ptp_td_sdo),
/*
* Ethernet
*/
.mac_tx_clk(mac_tx_clk[p]),
.mac_tx_rst(mac_tx_rst[p]),
.mac_axis_tx(mac_axis_tx[p]),
.mac_axis_tx_cpl(mac_axis_tx_cpl[p]),
.mac_rx_clk(mac_rx_clk[p]),
.mac_rx_rst(mac_rx_rst[p]),
.mac_axis_rx(mac_axis_rx[p])
);
end
endmodule
`resetall

View File

@@ -0,0 +1,6 @@
cndm_lite_pcie_us.sv
cndm_lite_core.f
../lib/taxi/src/pcie/rtl/taxi_pcie_us_axil_master.sv
../lib/taxi/src/pcie/rtl/taxi_pcie_us_msi.sv
../lib/taxi/src/pcie/rtl/taxi_pcie_us_cfg.sv
../lib/taxi/src/dma/rtl/taxi_dma_if_pcie_us.f

View File

@@ -0,0 +1,605 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2025-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Corundum-lite core logic for UltraScale PCIe
*/
module cndm_lite_pcie_us #(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'hDEADBEEF,
parameter FW_ID = 32'h0000C002,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1234_0000,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DEN = 165,
// PCIe interface configuration
parameter RQ_SEQ_NUM_W = 6,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24
)
(
/*
* PCIe
*/
input wire logic pcie_clk,
input wire logic pcie_rst,
taxi_axis_if.snk s_axis_pcie_cq,
taxi_axis_if.src m_axis_pcie_cc,
taxi_axis_if.src m_axis_pcie_rq,
taxi_axis_if.snk s_axis_pcie_rc,
input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0,
input wire logic pcie_rq_seq_num_vld0,
input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1,
input wire logic pcie_rq_seq_num_vld1,
input wire logic [2:0] cfg_max_payload,
input wire logic [2:0] cfg_max_read_req,
input wire logic [3:0] cfg_rcb_status,
output wire logic [9:0] cfg_mgmt_addr,
output wire logic [7:0] cfg_mgmt_function_number,
output wire logic cfg_mgmt_write,
output wire logic [31:0] cfg_mgmt_write_data,
output wire logic [3:0] cfg_mgmt_byte_enable,
output wire logic cfg_mgmt_read,
input wire logic [31:0] cfg_mgmt_read_data,
input wire logic cfg_mgmt_read_write_done,
input wire logic [7:0] cfg_fc_ph,
input wire logic [11:0] cfg_fc_pd,
input wire logic [7:0] cfg_fc_nph,
input wire logic [11:0] cfg_fc_npd,
input wire logic [7:0] cfg_fc_cplh,
input wire logic [11:0] cfg_fc_cpld,
output wire logic [2:0] cfg_fc_sel,
input wire logic [3:0] cfg_interrupt_msi_enable,
input wire logic [11:0] cfg_interrupt_msi_mmenable,
input wire logic cfg_interrupt_msi_mask_update,
input wire logic [31:0] cfg_interrupt_msi_data,
output wire logic [1:0] cfg_interrupt_msi_select,
output wire logic [31:0] cfg_interrupt_msi_int,
output wire logic [31:0] cfg_interrupt_msi_pending_status,
output wire logic cfg_interrupt_msi_pending_status_data_enable,
output wire logic [1:0] cfg_interrupt_msi_pending_status_function_num,
input wire logic cfg_interrupt_msi_sent,
input wire logic cfg_interrupt_msi_fail,
output wire logic [2:0] cfg_interrupt_msi_attr,
output wire logic cfg_interrupt_msi_tph_present,
output wire logic [1:0] cfg_interrupt_msi_tph_type,
output wire logic [7:0] cfg_interrupt_msi_tph_st_tag,
output wire logic [7:0] cfg_interrupt_msi_function_number,
/*
* PTP
*/
input wire logic ptp_clk = 1'b0,
input wire logic ptp_rst = 1'b0,
input wire logic ptp_sample_clk = 1'b0,
input wire logic ptp_td_sdi = 1'b0,
output wire logic ptp_td_sdo,
output wire logic ptp_pps,
output wire logic ptp_pps_str,
output wire logic ptp_sync_locked,
output wire logic [63:0] ptp_sync_ts_rel,
output wire logic ptp_sync_ts_rel_step,
output wire logic [95:0] ptp_sync_ts_tod,
output wire logic ptp_sync_ts_tod_step,
output wire logic ptp_sync_pps,
output wire logic ptp_sync_pps_str,
/*
* Ethernet
*/
input wire logic mac_tx_clk[PORTS],
input wire logic mac_tx_rst[PORTS],
taxi_axis_if.src mac_axis_tx[PORTS],
taxi_axis_if.snk mac_axis_tx_cpl[PORTS],
input wire logic mac_rx_clk[PORTS],
input wire logic mac_rx_rst[PORTS],
taxi_axis_if.snk mac_axis_rx[PORTS]
);
localparam CL_PORTS = $clog2(PORTS);
taxi_axil_if #(
.DATA_W(AXIL_CTRL_DATA_W),
.ADDR_W(AXIL_CTRL_ADDR_W),
.AWUSER_EN(1'b0),
.WUSER_EN(1'b0),
.BUSER_EN(1'b0),
.ARUSER_EN(1'b0),
.RUSER_EN(1'b0)
) axil_ctrl_bar();
taxi_pcie_us_axil_master
pcie_axil_master_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* UltraScale PCIe interface
*/
.s_axis_cq(s_axis_pcie_cq),
.m_axis_cc(m_axis_pcie_cc),
/*
* AXI Lite Master output
*/
.m_axil_wr(axil_ctrl_bar),
.m_axil_rd(axil_ctrl_bar),
/*
* Configuration
*/
.completer_id('0),
.completer_id_en(1'b0),
/*
* Status
*/
.stat_err_cor(),
.stat_err_uncor()
);
localparam AXIS_PCIE_DATA_W = m_axis_pcie_rq.DATA_W;
localparam PCIE_ADDR_W = 64;
// TODO
localparam logic RQ_SEQ_NUM_EN = 1'b1;
localparam RAM_SEL_W = 2+CL_PORTS;
localparam RAM_ADDR_W = 16;
localparam RAM_SEGS = 2;//AXIS_PCIE_DATA_W > 256 ? AXIS_PCIE_DATA_W / 128 : 2;
localparam PCIE_TAG_CNT = 64;//AXIS_PCIE_RQ_USER_W == 60 ? 64 : 256,
localparam logic IMM_EN = 1'b0;
localparam IMM_W = 32;
localparam LEN_W = 20;
localparam TAG_W = 8;
localparam RD_OP_TBL_SIZE = PCIE_TAG_CNT;
localparam RD_TX_LIMIT = 2**(RQ_SEQ_NUM_W-1);
localparam logic RD_TX_FC_EN = 1'b1;
localparam RD_CPLH_FC_LIMIT = 512;
localparam RD_CPLD_FC_LIMIT = RD_CPLH_FC_LIMIT*4;
localparam WR_OP_TBL_SIZE = 2**(RQ_SEQ_NUM_W-1);
localparam WR_TX_LIMIT = 2**(RQ_SEQ_NUM_W-1);
localparam logic WR_TX_FC_EN = 1'b1;
localparam RAM_DATA_W = AXIS_PCIE_DATA_W*2;
localparam RAM_SEG_DATA_W = RAM_DATA_W / RAM_SEGS;
localparam RAM_SEG_BE_W = RAM_SEG_DATA_W / 8;
localparam RAM_SEG_ADDR_W = RAM_ADDR_W - $clog2(RAM_SEGS*RAM_SEG_BE_W);
logic [RQ_SEQ_NUM_W-1:0] s_axis_rq_seq_num_0;
logic s_axis_rq_seq_num_valid_0;
logic [RQ_SEQ_NUM_W-1:0] s_axis_rq_seq_num_1;
logic s_axis_rq_seq_num_valid_1;
logic [7:0] pcie_tx_fc_nph_av;
logic [7:0] pcie_tx_fc_ph_av;
logic [11:0] pcie_tx_fc_pd_av;
logic ext_tag_en;
assign cfg_fc_sel = 3'b100;
taxi_dma_desc_if #(
.SRC_ADDR_W(PCIE_ADDR_W),
.SRC_SEL_EN(1'b0),
.SRC_ASID_EN(1'b0),
.DST_ADDR_W(RAM_ADDR_W),
.DST_SEL_EN(1'b1),
.DST_SEL_W(RAM_SEL_W),
.DST_ASID_EN(1'b0),
.IMM_EN(1'b0),
.LEN_W(LEN_W),
.TAG_W(TAG_W),
.ID_EN(1'b0),
.DEST_EN(1'b0),
.USER_EN(1'b0)
) dma_rd_desc();
taxi_dma_desc_if #(
.SRC_ADDR_W(RAM_ADDR_W),
.SRC_SEL_EN(1'b1),
.SRC_SEL_W(RAM_SEL_W),
.SRC_ASID_EN(1'b0),
.DST_ADDR_W(PCIE_ADDR_W),
.DST_SEL_EN(1'b0),
.DST_ASID_EN(1'b0),
.IMM_EN(IMM_EN),
.IMM_W(IMM_W),
.LEN_W(LEN_W),
.TAG_W(TAG_W),
.ID_EN(1'b0),
.DEST_EN(1'b0),
.USER_EN(1'b0)
) dma_wr_desc();
taxi_dma_ram_if #(
.SEGS(RAM_SEGS),
.SEG_ADDR_W(RAM_SEG_ADDR_W),
.SEG_DATA_W(RAM_SEG_DATA_W),
.SEG_BE_W(RAM_SEG_BE_W),
.SEL_W(RAM_SEL_W)
) dma_ram();
logic stat_rd_busy;
logic stat_wr_busy;
logic stat_err_cor;
logic stat_err_uncor;
logic [$clog2(RD_OP_TBL_SIZE)-1:0] stat_rd_op_start_tag;
logic stat_rd_op_start_valid;
logic [$clog2(RD_OP_TBL_SIZE)-1:0] stat_rd_op_finish_tag;
logic [3:0] stat_rd_op_finish_status;
logic stat_rd_op_finish_valid;
logic [$clog2(PCIE_TAG_CNT)-1:0] stat_rd_req_start_tag;
logic [12:0] stat_rd_req_start_len;
logic stat_rd_req_start_valid;
logic [$clog2(PCIE_TAG_CNT)-1:0] stat_rd_req_finish_tag;
logic [3:0] stat_rd_req_finish_status;
logic stat_rd_req_finish_valid;
logic stat_rd_req_timeout;
logic stat_rd_op_tbl_full;
logic stat_rd_no_tags;
logic stat_rd_tx_limit;
logic stat_rd_tx_stall;
logic [$clog2(WR_OP_TBL_SIZE)-1:0] stat_wr_op_start_tag;
logic stat_wr_op_start_valid;
logic [$clog2(WR_OP_TBL_SIZE)-1:0] stat_wr_op_finish_tag;
logic [3:0] stat_wr_op_finish_status;
logic stat_wr_op_finish_valid;
logic [$clog2(WR_OP_TBL_SIZE)-1:0] stat_wr_req_start_tag;
logic [12:0] stat_wr_req_start_len;
logic stat_wr_req_start_valid;
logic [$clog2(WR_OP_TBL_SIZE)-1:0] stat_wr_req_finish_tag;
logic [3:0] stat_wr_req_finish_status;
logic stat_wr_req_finish_valid;
logic stat_wr_op_tbl_full;
logic stat_wr_tx_limit;
logic stat_wr_tx_stall;
// register to break timing path from PCIe HIP 500 MHz clock domain
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0_reg = '0;
logic pcie_rq_seq_num_vld0_reg = 1'b0;
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1_reg = '0;
logic pcie_rq_seq_num_vld1_reg = 1'b0;
always_ff @(posedge pcie_clk) begin
pcie_rq_seq_num0_reg <= pcie_rq_seq_num0;
pcie_rq_seq_num_vld0_reg <= pcie_rq_seq_num_vld0;
pcie_rq_seq_num1_reg <= pcie_rq_seq_num1;
pcie_rq_seq_num_vld1_reg <= pcie_rq_seq_num_vld1;
if (pcie_rst) begin
pcie_rq_seq_num_vld0_reg <= 1'b0;
pcie_rq_seq_num_vld1_reg <= 1'b0;
end
end
taxi_dma_if_pcie_us #(
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
.RQ_SEQ_NUM_EN(RQ_SEQ_NUM_EN),
.PCIE_TAG_CNT(PCIE_TAG_CNT),
.RD_OP_TBL_SIZE(RD_OP_TBL_SIZE),
.RD_TX_LIMIT(RD_TX_LIMIT),
.RD_TX_FC_EN(RD_TX_FC_EN),
.RD_CPLH_FC_LIMIT(RD_CPLH_FC_LIMIT),
.RD_CPLD_FC_LIMIT(RD_CPLD_FC_LIMIT),
.WR_OP_TBL_SIZE(WR_OP_TBL_SIZE),
.WR_TX_LIMIT(WR_TX_LIMIT),
.WR_TX_FC_EN(WR_TX_FC_EN)
)
dma_if_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* UltraScale PCIe interface
*/
.m_axis_rq(m_axis_pcie_rq),
.s_axis_rc(s_axis_pcie_rc),
/*
* Transmit sequence number input
*/
.s_axis_rq_seq_num_0(pcie_rq_seq_num0_reg),
.s_axis_rq_seq_num_valid_0(pcie_rq_seq_num_vld0_reg),
.s_axis_rq_seq_num_1(pcie_rq_seq_num1_reg),
.s_axis_rq_seq_num_valid_1(pcie_rq_seq_num_vld1_reg),
/*
* Transmit flow control
*/
.pcie_tx_fc_nph_av(cfg_fc_nph),
.pcie_tx_fc_ph_av(cfg_fc_ph),
.pcie_tx_fc_pd_av(cfg_fc_pd),
/*
* Read descriptor
*/
.rd_desc_req(dma_rd_desc),
.rd_desc_sts(dma_rd_desc),
/*
* Write descriptor
*/
.wr_desc_req(dma_wr_desc),
.wr_desc_sts(dma_wr_desc),
/*
* RAM interface
*/
.dma_ram_wr(dma_ram),
.dma_ram_rd(dma_ram),
/*
* Configuration
*/
.read_enable(1'b1),
.write_enable(1'b1),
.ext_tag_en(ext_tag_en),
.rcb_128b(cfg_rcb_status[0]),
.requester_id('0),
.requester_id_en(1'b0),
.max_rd_req_size(cfg_max_read_req),
.max_payload_size(cfg_max_payload),
/*
* Status
*/
.stat_rd_busy(stat_rd_busy),
.stat_wr_busy(stat_wr_busy),
.stat_err_cor(stat_err_cor),
.stat_err_uncor(stat_err_uncor),
/*
* Statistics
*/
.stat_rd_op_start_tag(stat_rd_op_start_tag),
.stat_rd_op_start_valid(stat_rd_op_start_valid),
.stat_rd_op_finish_tag(stat_rd_op_finish_tag),
.stat_rd_op_finish_status(stat_rd_op_finish_status),
.stat_rd_op_finish_valid(stat_rd_op_finish_valid),
.stat_rd_req_start_tag(stat_rd_req_start_tag),
.stat_rd_req_start_len(stat_rd_req_start_len),
.stat_rd_req_start_valid(stat_rd_req_start_valid),
.stat_rd_req_finish_tag(stat_rd_req_finish_tag),
.stat_rd_req_finish_status(stat_rd_req_finish_status),
.stat_rd_req_finish_valid(stat_rd_req_finish_valid),
.stat_rd_req_timeout(stat_rd_req_timeout),
.stat_rd_op_tbl_full(stat_rd_op_tbl_full),
.stat_rd_no_tags(stat_rd_no_tags),
.stat_rd_tx_limit(stat_rd_tx_limit),
.stat_rd_tx_stall(stat_rd_tx_stall),
.stat_wr_op_start_tag(stat_wr_op_start_tag),
.stat_wr_op_start_valid(stat_wr_op_start_valid),
.stat_wr_op_finish_tag(stat_wr_op_finish_tag),
.stat_wr_op_finish_status(stat_wr_op_finish_status),
.stat_wr_op_finish_valid(stat_wr_op_finish_valid),
.stat_wr_req_start_tag(stat_wr_req_start_tag),
.stat_wr_req_start_len(stat_wr_req_start_len),
.stat_wr_req_start_valid(stat_wr_req_start_valid),
.stat_wr_req_finish_tag(stat_wr_req_finish_tag),
.stat_wr_req_finish_status(stat_wr_req_finish_status),
.stat_wr_req_finish_valid(stat_wr_req_finish_valid),
.stat_wr_op_tbl_full(stat_wr_op_tbl_full),
.stat_wr_tx_limit(stat_wr_tx_limit),
.stat_wr_tx_stall(stat_wr_tx_stall)
);
taxi_pcie_us_cfg #(
.PF_COUNT(1),
.VF_COUNT(0),
.VF_OFFSET(m_axis_pcie_rq.USER_W == 60 ? 64 : 4),
.PCIE_CAP_OFFSET(m_axis_pcie_rq.USER_W == 60 ? 12'h0C0 : 12'h070)
)
cfg_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* Configuration outputs
*/
.ext_tag_en(ext_tag_en),
.max_read_req_size(),
.max_payload_size(),
/*
* Interface to Ultrascale PCIe IP core
*/
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done)
);
localparam IRQN_W = $clog2(32);
taxi_axis_if #(
.DATA_W(IRQN_W),
.KEEP_EN(0),
.KEEP_W(1)
) axis_irq();
logic [31:0] msi_irq_reg = '0;
assign axis_irq.tready = 1'b1;
always @(posedge pcie_clk) begin
msi_irq_reg <= '0;
if (axis_irq.tvalid) begin
msi_irq_reg[axis_irq.tdata] <= 1'b1;
end
end
taxi_pcie_us_msi #(
.MSI_CNT(32)
)
msi_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* Interrupt request inputs
*/
.msi_irq(msi_irq_reg),
/*
* Interface to UltraScale PCIe IP core
*/
/* verilator lint_off WIDTHEXPAND */
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_vf_enable(),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number)
/* verilator lint_on WIDTHEXPAND */
);
cndm_lite_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.CQN_W(CQN_W),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN)
)
core_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* Control register interface
*/
.s_axil_ctrl_wr(axil_ctrl_bar),
.s_axil_ctrl_rd(axil_ctrl_bar),
/*
* DMA
*/
.dma_rd_desc_req(dma_rd_desc),
.dma_rd_desc_sts(dma_rd_desc),
.dma_wr_desc_req(dma_wr_desc),
.dma_wr_desc_sts(dma_wr_desc),
.dma_ram_wr(dma_ram),
.dma_ram_rd(dma_ram),
/*
* Interrupts
*/
.m_axis_irq(axis_irq),
/*
* PTP
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.ptp_td_sdo(ptp_td_sdo),
.ptp_pps(ptp_pps),
.ptp_pps_str(ptp_pps_str),
.ptp_sync_locked(ptp_sync_locked),
.ptp_sync_ts_rel(ptp_sync_ts_rel),
.ptp_sync_ts_rel_step(ptp_sync_ts_rel_step),
.ptp_sync_ts_tod(ptp_sync_ts_tod),
.ptp_sync_ts_tod_step(ptp_sync_ts_tod_step),
.ptp_sync_pps(ptp_sync_pps),
.ptp_sync_pps_str(ptp_sync_pps_str),
/*
* Ethernet
*/
.mac_tx_clk(mac_tx_clk),
.mac_tx_rst(mac_tx_rst),
.mac_axis_tx(mac_axis_tx),
.mac_axis_tx_cpl(mac_axis_tx_cpl),
.mac_rx_clk(mac_rx_clk),
.mac_rx_rst(mac_rx_rst),
.mac_axis_rx(mac_axis_rx)
);
endmodule
`resetall

View File

@@ -20,3 +20,4 @@ cndm_micro_cpl_wr.sv
../lib/taxi/src/axis/rtl/taxi_axis_demux.sv
../lib/taxi/src/ptp/rtl/taxi_ptp_td_phc_apb.f
../lib/taxi/src/ptp/rtl/taxi_ptp_td_rel2tod.sv
../lib/taxi/src/pcie/rtl/taxi_irq_rate_limit.sv

View File

@@ -35,6 +35,8 @@ module cndm_micro_core #(
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
@@ -44,7 +46,7 @@ module cndm_micro_core #(
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DENOM = 165
parameter PTP_CLK_PER_NS_DEN = 165
)
(
input wire logic clk,
@@ -66,7 +68,10 @@ module cndm_micro_core #(
taxi_dma_ram_if.wr_slv dma_ram_wr,
taxi_dma_ram_if.rd_slv dma_ram_rd,
output wire logic [PORTS-1:0] irq,
/*
* Interrupts
*/
taxi_axis_if.src m_axis_irq,
/*
* PTP
@@ -115,6 +120,8 @@ localparam PORT_OFFSET_HOST = 2;
localparam PORT_BASE_ADDR_DP = PTP_TS_EN ? 32'h00010000 : 32'h00000000;
localparam PORT_BASE_ADDR_HOST = 32'h00020000;
localparam SYS_CLK_CYC_PER_US = (1000*SYS_CLK_PER_NS_DEN+SYS_CLK_PER_NS_NUM-1)/SYS_CLK_PER_NS_NUM;
taxi_axil_if #(
.DATA_W(s_axil_ctrl_wr.DATA_W),
.ADDR_W(16),
@@ -220,7 +227,6 @@ always_ff @(posedge clk) begin
s_axil_rvalid_reg <= 1'b1;
case ({axil_ctrl[0].araddr[15:2], 2'b00})
16'h0100: s_axil_rdata_reg <= PORTS; // port count
16'h0200: begin
s_axil_rdata_reg[0] <= cmd_mbox_busy;
end
@@ -313,14 +319,32 @@ taxi_apb_if #(
apb_dp_ctrl();
cndm_micro_dp_mgr #(
.PORTS(PORTS),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_EN(PTP_TS_EN),
.PTP_BASE_ADDR_DP(0),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// Addressing
.PTP_BASE_ADDR_DP(0),
.PORT_BASE_ADDR_DP(PORT_BASE_ADDR_DP),
.PORT_BASE_ADDR_HOST(PORT_BASE_ADDR_HOST)
)
@@ -373,7 +397,7 @@ if (PTP_TS_EN) begin : ptp
taxi_ptp_td_phc_apb #(
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM)
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DEN)
)
ptp_inst (
.clk(clk),
@@ -498,6 +522,54 @@ dma_mux_inst (
.client_ram_rd(dma_ram_int)
);
taxi_axis_if #(
.DATA_W(m_axis_irq.DATA_W),
.KEEP_EN(0),
.KEEP_W(1)
) axis_irq_int(), axis_irq_port[PORTS]();
taxi_axis_arb_mux #(
.S_COUNT($size(axis_irq_port)),
.ARB_ROUND_ROBIN(1),
.ARB_LSB_HIGH_PRIO(1)
)
irq_mux_inst (
.clk(clk),
.rst(rst),
/*
* AXI4-Stream input (sink)
*/
.s_axis(axis_irq_port),
/*
* AXI4-Stream output (source)
*/
.m_axis(axis_irq_int)
);
taxi_irq_rate_limit
irq_rate_limit_inst (
.clk(clk),
.rst(rst),
/*
* Interrupt request input
*/
.s_axis_irq(axis_irq_int),
/*
* Interrupt request output
*/
.m_axis_irq(m_axis_irq),
/*
* Configuration
*/
.prescale(16'(SYS_CLK_CYC_PER_US)),
.min_interval(10) // TODO make configurable
);
for (genvar p = 0; p < PORTS; p = p + 1) begin : port
cndm_micro_port #(
@@ -534,7 +606,10 @@ for (genvar p = 0; p < PORTS; p = p + 1) begin : port
.dma_ram_wr(dma_ram_int[p]),
.dma_ram_rd(dma_ram_int[p]),
.irq(irq[p]),
/*
* Interrupts
*/
.m_axis_irq(axis_irq_port[p]),
/*
* PTP

View File

@@ -40,15 +40,22 @@ module cndm_micro_cpl_wr #(
taxi_dma_desc_if.sts_snk dma_wr_desc_sts,
taxi_dma_ram_if.rd_slv dma_ram_rd,
taxi_axis_if.snk s_axis_cpl,
output wire logic irq
/*
* Interrupts
*/
taxi_axis_if.src m_axis_irq,
taxi_axis_if.snk s_axis_cpl
);
localparam DMA_ADDR_W = dma_wr_desc_req.DST_ADDR_W;
localparam IRQN_W = m_axis_irq.DATA_W;
logic [CQN_W-1:0] cq_req_cqn_reg = '0;
logic cq_req_valid_reg = 1'b0;
logic cq_req_ready;
logic [IRQN_W-1:0] cq_rsp_irqn;
logic [DMA_ADDR_W-1:0] cq_rsp_addr;
logic cq_rsp_phase_tag;
logic cq_rsp_error;
@@ -57,7 +64,7 @@ logic cq_rsp_ready_reg = 1'b0;
cndm_micro_queue_state #(
.QN_W(CQN_W),
.DQN_W(CQN_W), // TODO
.DQN_W(IRQN_W),
.IS_CQ(1),
.QTYPE_EN(0),
.QE_SIZE(16),
@@ -86,7 +93,7 @@ cq_mgr_inst (
.req_valid(cq_req_valid_reg),
.req_ready(cq_req_ready),
.rsp_qn(),
.rsp_dqn(),
.rsp_dqn(cq_rsp_irqn),
.rsp_addr(cq_rsp_addr),
.rsp_phase_tag(cq_rsp_phase_tag),
.rsp_error(cq_rsp_error),
@@ -104,9 +111,17 @@ state_t state_reg = STATE_IDLE;
logic phase_tag_reg = 1'b0;
logic irq_reg = 1'b0;
logic [IRQN_W-1:0] m_axis_irq_irqn_reg = '0;
logic m_axis_irq_tvalid_reg = 1'b0;
assign irq = irq_reg;
assign m_axis_irq.tdata = m_axis_irq_irqn_reg;
assign m_axis_irq.tkeep = '1;
assign m_axis_irq.tstrb = m_axis_irq.tkeep;
assign m_axis_irq.tvalid = m_axis_irq_tvalid_reg;
assign m_axis_irq.tlast = 1'b1;
assign m_axis_irq.tid = '0;
assign m_axis_irq.tdest = '0;
assign m_axis_irq.tuser = '0;
always_ff @(posedge clk) begin
s_axis_cpl.tready <= 1'b0;
@@ -127,7 +142,7 @@ always_ff @(posedge clk) begin
cq_req_valid_reg <= cq_req_valid_reg && !cq_req_ready;
cq_rsp_ready_reg <= 1'b0;
irq_reg <= 1'b0;
m_axis_irq_tvalid_reg <= m_axis_irq_tvalid_reg && !m_axis_irq.tready;
case (state_reg)
STATE_IDLE: begin
@@ -149,6 +164,7 @@ always_ff @(posedge clk) begin
if (cq_rsp_valid && cq_rsp_ready_reg) begin
cq_rsp_ready_reg <= 1'b0;
m_axis_irq_irqn_reg <= cq_rsp_irqn;
dma_wr_desc_req.req_dst_addr <= cq_rsp_addr;
phase_tag_reg <= cq_rsp_phase_tag;
@@ -165,7 +181,7 @@ always_ff @(posedge clk) begin
STATE_WRITE_DATA: begin
if (dma_wr_desc_sts.sts_valid) begin
s_axis_cpl.tready <= 1'b1;
irq_reg <= 1'b1;
m_axis_irq_tvalid_reg <= 1'b1;
state_reg <= STATE_IDLE;
end
end
@@ -178,7 +194,7 @@ always_ff @(posedge clk) begin
state_reg <= STATE_IDLE;
cq_req_valid_reg <= 1'b0;
cq_rsp_ready_reg <= 1'b0;
irq_reg <= 1'b0;
m_axis_irq_tvalid_reg <= 1'b0;
end
end

View File

@@ -17,14 +17,32 @@ Authors:
*/
module cndm_micro_dp_mgr #
(
parameter PORTS = 2,
// FW ID
parameter FPGA_ID = 32'hDEADBEEF,
parameter FW_ID = 32'h0000C002,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1234_0000,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_EN = 1'b1,
parameter PTP_BASE_ADDR_DP = 0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DEN = 165,
// Addressing
parameter PTP_BASE_ADDR_DP = 0,
parameter PORT_BASE_ADDR_DP = 0,
parameter PORT_BASE_ADDR_HOST = 0,
parameter PORT_STRIDE = 'h10000,
@@ -57,6 +75,8 @@ localparam DP_APB_STRB_W = m_apb_dp_ctrl.STRB_W;
typedef enum logic [15:0] {
CMD_OP_NOP = 16'h0000,
CMD_OP_CFG = 16'h0100,
CMD_OP_ACCESS_REG = 16'h0180,
CMD_OP_PTP = 16'h0190,
@@ -96,6 +116,7 @@ typedef enum logic [2:0] {
typedef enum logic [4:0] {
STATE_IDLE,
STATE_START,
STATE_CFG_READ,
STATE_REG_1,
STATE_REG_2,
STATE_REG_3,
@@ -135,13 +156,94 @@ 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[2**CMD_AW] = '{default: '0};
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];
// ID ROM
localparam ID_PAGES = 3;
localparam ID_AW = $clog2((ID_PAGES+1)*8);
logic [31:0] id_rom[(ID_PAGES+1)*8] = '{
// Common
0, // 0: status
0, // 1: flags
{ // 2
16'(ID_PAGES-1), // [31:16] cfg_page_max
16'd0 // [15:0] cfg_page (replaced)
},
32'h000_01_000, // 3: CMD_VER
FW_VER, // 4
{ // 5
8'd0, // [31:24]
8'd0, // [23:16]
8'd0, // [15:8]
8'(PORTS) // [7:0]
},
0, // 6
0, // 7
// Page 0: FW ID
FPGA_ID, // 8
FW_ID, // 9
FW_VER, // 10
BOARD_ID, // 11
BOARD_VER, // 12
BUILD_DATE, // 13
GIT_HASH, // 14
RELEASE_INFO, // 15
// Page 1: HW config
{ // 16
16'd0, // [31:16]
16'(PORTS) // [15:0]
},
0, // 17
0, // 18
0, // 19
{ // 20
16'(SYS_CLK_PER_NS_NUM), // [31:16]
16'(SYS_CLK_PER_NS_DEN) // [15:0]
},
{ // 21
16'(PTP_CLK_PER_NS_NUM), // [31:16]
16'(PTP_CLK_PER_NS_DEN) // [15:0]
},
0, // 22
0, // 23
// Page 2: Resources
{ // 24
8'd0, // [31:24] EQE_VER
8'd0, // [23:16] EQ_POOL
8'd0, // [15:8] LOG_MAX_EQ_SZ
8'd0 // [7:0] LOG_MAX_EQ
},
{ // 25
8'd1, // [31:24] CQE_VER
8'd0, // [23:16] CQ_POOL
8'd15, // [15:8] LOG_MAX_CQ_SZ
8'(CQN_W) // [7:0] LOG_MAX_CQ
},
{ // 26
8'd1, // [31:24] SQE_VER
8'd1, // [23:16] SQ_POOL
8'd15, // [15:8] LOG_MAX_SQ_SZ
8'(WQN_W) // [7:0] LOG_MAX_SQ
},
{ // 27
8'd1, // [31:24] RQE_VER
8'd1, // [23:16] RQ_POOL
8'd15, // [15:8] LOG_MAX_RQ_SZ
8'(WQN_W) // [7:0] LOG_MAX_RQ
},
0, // 28
0, // 29
0, // 30
0 // 31
};
logic [ID_AW-1:0] id_rom_rd_addr;
wire [31:0] id_rom_rd_data = id_rom[id_rom_rd_addr];
assign s_axis_cmd.tready = s_axis_cmd_tready_reg;
assign m_axis_rsp.tdata = m_axis_rsp_tdata_reg;
@@ -172,9 +274,9 @@ 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 [23:0] qn2_reg = '0, qn2_next;
logic [31:0] dw2_reg = '0, dw2_next;
logic [31:0] dw3_reg = '0, dw3_next;
logic [31:0] dw4_reg = '0, dw4_next;
logic [2:0] qtype_reg = '0, qtype_next;
logic [3:0] cmd_ptr_reg = '0, cmd_ptr_next;
@@ -203,6 +305,8 @@ always_comb begin
cmd_ram_wr_en = 1'b0;
cmd_ram_rd_addr = '0;
id_rom_rd_addr = ID_AW'(cnt_reg);
cmd_frame_next = cmd_frame_reg;
cmd_wr_ptr_next = cmd_wr_ptr_reg;
rsp_frame_next = rsp_frame_reg;
@@ -212,9 +316,9 @@ always_comb begin
opcode_next = opcode_reg;
flags_next = flags_reg;
port_next = port_reg;
qn_next = qn_reg;
qn2_next = qn2_reg;
dw2_next = dw2_reg;
dw3_next = dw3_reg;
dw4_next = dw4_reg;
qtype_next = qtype_reg;
cmd_ptr_next = cmd_ptr_reg;
@@ -244,9 +348,9 @@ always_comb begin
case (cmd_wr_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];
4'd4: qn2_next = s_axis_cmd.tdata[23:0];
4'd2: dw2_next = s_axis_cmd.tdata;
4'd3: dw3_next = s_axis_cmd.tdata;
4'd4: dw4_next = s_axis_cmd.tdata;
default: begin end
endcase
@@ -272,64 +376,64 @@ always_comb begin
// // EQ
// CMD_OP_CREATE_EQ:
// begin
// qn_next = 0;
// dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
// host_ptr_next = 32'({port_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
// dw3_next = 0;
// dp_ptr_next = DP_APB_ADDR_W'({dw2_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
// host_ptr_next = 32'({dw2_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
// end
// CMD_OP_MODIFY_EQ,
// CMD_OP_QUERY_EQ,
// CMD_OP_DESTROY_EQ:
// begin
// dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
// host_ptr_next = 32'({port_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
// dp_ptr_next = DP_APB_ADDR_W'({dw2_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
// host_ptr_next = 32'({dw2_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
// end
// CQ
CMD_OP_CREATE_CQ:
begin
cnt_next = 2**CQN_W-1;
qtype_next = QTYPE_CQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + CQM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + CQM_OFFSET + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + CQM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + CQM_OFFSET + PORT_BASE_ADDR_HOST;
end
CMD_OP_MODIFY_CQ,
CMD_OP_QUERY_CQ,
CMD_OP_DESTROY_CQ:
begin
qtype_next = QTYPE_CQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + CQM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + CQM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + CQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + CQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
end
// SQ
CMD_OP_CREATE_SQ:
begin
cnt_next = 2**WQN_W-1;
qtype_next = QTYPE_SQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
end
CMD_OP_MODIFY_SQ,
CMD_OP_QUERY_SQ,
CMD_OP_DESTROY_SQ:
begin
qtype_next = QTYPE_SQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + QM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + QM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
end
// RQ
CMD_OP_CREATE_RQ:
begin
cnt_next = 2**WQN_W-1;
qtype_next = QTYPE_RQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + QM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + QM_OFFSET + (qn_reg * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
end
CMD_OP_MODIFY_RQ,
CMD_OP_QUERY_RQ,
CMD_OP_DESTROY_RQ:
begin
qtype_next = QTYPE_RQ;
dp_ptr_next = DP_APB_ADDR_W'((port_reg * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
host_ptr_next = (port_reg * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
end
default: begin end
endcase
@@ -343,6 +447,12 @@ always_comb begin
state_next = STATE_SEND_RSP;
end
CMD_OP_CFG: begin
// dump config page
cmd_ptr_next = 2;
cnt_next = 2;
state_next = STATE_CFG_READ;
end
CMD_OP_ACCESS_REG: begin
// access register
state_next = STATE_REG_1;
@@ -378,7 +488,7 @@ always_comb begin
CMD_OP_CREATE_RQ:
begin
// create queue operation
qn_next = '0;
dw3_next = '0;
state_next = STATE_CREATE_Q_FIND_1;
end
CMD_OP_MODIFY_EQ,
@@ -427,6 +537,36 @@ always_comb begin
end
endcase
end
STATE_CFG_READ: begin
// read config page data
id_rom_rd_addr = ID_AW'(cnt_reg);
cmd_ram_wr_data = id_rom_rd_data;
cmd_ram_wr_addr = cmd_ptr_reg;
cmd_ram_wr_en = 1'b1;
if (cmd_ptr_reg == 2) begin
cmd_ram_wr_data[15:0] = dw2_reg[15:0];
end
cnt_next = cnt_reg + 1;
cmd_ptr_next = cmd_ptr_reg + 1;
if (cmd_ptr_reg == 15) begin
// done
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 if (cmd_ptr_reg == 7) begin
// jump to selected page
cnt_next = 16'((dw2_reg + 1) * 8);
state_next = STATE_CFG_READ;
end else begin
// more to read
state_next = STATE_CFG_READ;
end
end
STATE_REG_1: begin
// register access 1
cmd_ram_rd_addr = 7;
@@ -493,7 +633,7 @@ always_comb begin
state_next = STATE_CREATE_Q_RESET_1;
end else begin
// queue is active
qn_next = qn_reg + 1;
dw3_next = dw3_reg + 1;
dp_ptr_next = dp_ptr_reg + WQ_REG_STRIDE;
host_ptr_next = host_ptr_reg + WQ_REG_STRIDE;
if (cnt_reg == 0) begin
@@ -516,7 +656,7 @@ always_comb begin
// reset queue 1
// store queue number
cmd_ram_wr_data = 32'(qn_reg);
cmd_ram_wr_data = dw3_reg;
cmd_ram_wr_addr = 3;
cmd_ram_wr_en = 1'b1;
@@ -634,13 +774,13 @@ always_comb begin
// set up port
if (!m_apb_dp_ctrl_psel_reg) begin
if (qtype_reg == QTYPE_SQ) begin
m_apb_dp_ctrl_paddr_next = DP_APB_ADDR_W'(PORT_BASE_ADDR_DP + (port_reg * PORT_STRIDE) + PORT_CTRL_OFFSET + 'h0010);
m_apb_dp_ctrl_paddr_next = DP_APB_ADDR_W'(PORT_BASE_ADDR_DP + (dw2_reg[15:0] * PORT_STRIDE) + PORT_CTRL_OFFSET + 'h0010);
end else begin
m_apb_dp_ctrl_paddr_next = DP_APB_ADDR_W'(PORT_BASE_ADDR_DP + (port_reg * PORT_STRIDE) + PORT_CTRL_OFFSET + 'h0020);
m_apb_dp_ctrl_paddr_next = DP_APB_ADDR_W'(PORT_BASE_ADDR_DP + (dw2_reg[15:0] * PORT_STRIDE) + PORT_CTRL_OFFSET + 'h0020);
end
m_apb_dp_ctrl_psel_next = 1'b1;
m_apb_dp_ctrl_pwrite_next = qtype_reg == QTYPE_SQ || qtype_reg == QTYPE_RQ;
m_apb_dp_ctrl_pwdata_next = 32'(qn_reg);
m_apb_dp_ctrl_pwdata_next = dw3_reg;
m_apb_dp_ctrl_pstrb_next = '1;
m_axis_rsp_tdata_next = '0; // TODO
@@ -892,9 +1032,9 @@ always_ff @(posedge clk) begin
opcode_reg <= opcode_next;
flags_reg <= flags_next;
port_reg <= port_next;
qn_reg <= qn_next;
qn2_reg <= qn2_next;
dw2_reg <= dw2_next;
dw3_reg <= dw3_next;
dw4_reg <= dw4_next;
qtype_reg <= qtype_next;
cmd_ptr_reg <= cmd_ptr_next;

View File

@@ -35,15 +35,18 @@ module cndm_micro_pcie_us #(
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter CQN_W = 5,
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DENOM = 165,
parameter PTP_CLK_PER_NS_DEN = 165,
// PCIe interface configuration
parameter RQ_SEQ_NUM_W = 6,
@@ -456,8 +459,25 @@ cfg_inst (
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done)
);
wire [PORTS-1:0] irq;
wire [31:0] msi_irq = 32'(irq);
localparam IRQN_W = $clog2(32);
taxi_axis_if #(
.DATA_W(IRQN_W),
.KEEP_EN(0),
.KEEP_W(1)
) axis_irq();
logic [31:0] msi_irq_reg = '0;
assign axis_irq.tready = 1'b1;
always @(posedge pcie_clk) begin
msi_irq_reg <= '0;
if (axis_irq.tvalid) begin
msi_irq_reg[axis_irq.tdata] <= 1'b1;
end
end
taxi_pcie_us_msi #(
.MSI_CNT(32)
@@ -469,7 +489,7 @@ msi_inst (
/*
* Interrupt request inputs
*/
.msi_irq(msi_irq),
.msi_irq(msi_irq_reg),
/*
* Interface to UltraScale PCIe IP core
@@ -512,15 +532,18 @@ cndm_micro_core #(
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM)
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN)
)
core_inst (
.clk(pcie_clk),
@@ -542,7 +565,10 @@ core_inst (
.dma_ram_wr(dma_ram),
.dma_ram_rd(dma_ram),
.irq(irq),
/*
* Interrupts
*/
.m_axis_irq(axis_irq),
/*
* PTP

View File

@@ -49,7 +49,10 @@ module cndm_micro_port #(
taxi_dma_ram_if.wr_slv dma_ram_wr,
taxi_dma_ram_if.rd_slv dma_ram_rd,
output wire logic irq,
/*
* Interrupts
*/
taxi_axis_if.src m_axis_irq,
/*
* PTP
@@ -505,8 +508,12 @@ cpl_wr_inst (
.dma_wr_desc_sts(dma_wr_desc_int[0]),
.dma_ram_rd(dma_ram_rd_int[0]),
.s_axis_cpl(axis_cpl),
.irq(irq)
/*
* Interrupts
*/
.m_axis_irq(m_axis_irq),
.s_axis_cpl(axis_cpl)
);
// TX path

View File

@@ -9,6 +9,7 @@ Authors:
"""
import array
import datetime
import logging
import struct
from collections import deque
@@ -19,6 +20,8 @@ from cocotb.queue import Queue
# Command opcodes
CNDM_CMD_OP_NOP = 0x0000
CNDM_CMD_OP_CFG = 0x0100
CNDM_CMD_OP_ACCESS_REG = 0x0180
CNDM_CMD_OP_PTP = 0x0190
@@ -605,6 +608,44 @@ class Driver:
self.free_packets = deque()
self.allocated_packets = []
# config
self.cfg_page_max = None
self.cmd_ver = None
# FW ID
self.fpga_id = None
self.fw_id = None
self.fw_ver = None
self.board_id = None
self.board_ver = None
self.build_date = None
self.git_hash = None
self.release_info = None
# HW config
self.sys_clk_per_ns_num = None
self.sys_clk_per_ns_den = None
self.ptp_clk_per_ns_num = None
self.ptp_clk_per_ns_den = None
# Resources
self.log_max_eq = None
self.log_max_eq_sz = None
self.eq_pool = None
self.eqe_ver = None
self.log_max_cq = None
self.log_max_cq_sz = None
self.cq_pool = None
self.cqe_ver = None
self.log_max_sq = None
self.log_max_sq_sz = None
self.sq_pool = None
self.sqe_ver = None
self.log_max_rq = None
self.log_max_rq_sz = None
self.rq_pool = None
self.rqe_ver = None
async def init_pcie_dev(self, dev):
self.dev = dev
self.pool = dev.rc.mem_pool
@@ -618,10 +659,156 @@ class Driver:
await self.init_common()
async def init_common(self):
self.port_count = await self.hw_regs.read_dword(0x0100)
# Get config information
rsp = await self.exec_cmd(struct.pack("<HHLHHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CFG, # opcode
0x00000000, # flags
0, # cfg_page
0, # num_cfg_pages
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
))
rsp_unpacked = struct.unpack("<HHLHHLLLLLLLLLLLLL", rsp)
print(rsp_unpacked)
self.cfg_page_max = rsp_unpacked[4]
self.cmd_ver = rsp_unpacked[5]
self.log.info("Config pages: %d", self.cfg_page_max+1)
self.log.info("Command version: %d.%d.%d", self.cmd_ver >> 20, (self.cmd_ver >> 12) & 0xff, self.cmd_ver & 0xfff)
self.fpga_id = rsp_unpacked[10]
self.fw_id = rsp_unpacked[11]
self.fw_ver = rsp_unpacked[12]
self.board_id = rsp_unpacked[13]
self.board_ver = rsp_unpacked[14]
self.build_date = rsp_unpacked[15]
self.git_hash = rsp_unpacked[16]
self.release_info = rsp_unpacked[17]
self.log.info("FPGA JTAG ID: 0x%08x", self.fpga_id)
self.log.info("FW ID: 0x%08x", self.fw_id)
self.log.info("FW version: %d.%d.%d", self.fw_ver >> 20, (self.fw_ver >> 12) & 0xff, self.fw_ver & 0xfff)
self.log.info("Board ID: 0x%08x", self.board_id)
self.log.info("Board version: %d.%d.%d", self.board_ver >> 20, (self.board_ver >> 12) & 0xff, self.board_ver & 0xfff)
self.log.info("Build date: %s UTC (raw: 0x%08x)", datetime.datetime.fromtimestamp(self.build_date, datetime.timezone.utc).isoformat(' '), self.build_date)
self.log.info("Git hash: %08x", self.git_hash)
self.log.info("Release info: %08x", self.release_info)
# Get config information
rsp = await self.exec_cmd(struct.pack("<HHLHHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CFG, # opcode
0x00000000, # flags
1, # cfg_page
0, # num_cfg_pages
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
))
rsp_unpacked = struct.unpack("<HHLHHLLLLLLLLLLLLL", rsp)
print(rsp_unpacked)
self.port_count = rsp_unpacked[10] & 0xff
self.sys_clk_per_ns_den = rsp_unpacked[14] & 0xffff
self.sys_clk_per_ns_num = rsp_unpacked[14] >> 16
self.ptp_clk_per_ns_den = rsp_unpacked[15] & 0xffff
self.ptp_clk_per_ns_num = rsp_unpacked[15] >> 16
self.log.info("Port count: %d", self.port_count)
self.log.info("Sys clock period: %f MHz (raw %d/%d ns)",
1000/(self.sys_clk_per_ns_num/self.sys_clk_per_ns_den),
self.sys_clk_per_ns_num, self.sys_clk_per_ns_den)
self.log.info("PTP clock period: %f MHz (raw %d/%d ns)",
1000/(self.ptp_clk_per_ns_num/self.ptp_clk_per_ns_den),
self.ptp_clk_per_ns_num, self.ptp_clk_per_ns_den)
# Get config information
rsp = await self.exec_cmd(struct.pack("<HHLHHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CFG, # opcode
0x00000000, # flags
2, # cfg_page
0, # num_cfg_pages
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
))
rsp_unpacked = struct.unpack("<HHLHHLLLLLLLLLLLLL", rsp)
print(rsp_unpacked)
# Resources
self.log_max_eq = rsp_unpacked[10] & 0xff
self.log_max_eq_sz = (rsp_unpacked[10] >> 8) & 0xff
self.eq_pool = (rsp_unpacked[10] >> 16) & 0xff
self.eqe_ver = (rsp_unpacked[10] >> 24) & 0xff
self.log_max_cq = rsp_unpacked[11] & 0xff
self.log_max_cq_sz = (rsp_unpacked[11] >> 8) & 0xff
self.cq_pool = (rsp_unpacked[11] >> 16) & 0xff
self.cqe_ver = (rsp_unpacked[11] >> 24) & 0xff
self.log_max_sq = rsp_unpacked[12] & 0xff
self.log_max_sq_sz = (rsp_unpacked[12] >> 8) & 0xff
self.sq_pool = (rsp_unpacked[12] >> 16) & 0xff
self.sqe_ver = (rsp_unpacked[12] >> 24) & 0xff
self.log_max_rq = rsp_unpacked[13] & 0xff
self.log_max_rq_sz = (rsp_unpacked[13] >> 8) & 0xff
self.rq_pool = (rsp_unpacked[13] >> 16) & 0xff
self.rqe_ver = (rsp_unpacked[13] >> 24) & 0xff
self.log.info("Max EQ count: %d (log %d)", 2**self.log_max_eq, self.log_max_eq)
self.log.info("Max EQ size: %d (log %d)", 2**self.log_max_eq_sz, self.log_max_eq_sz)
self.log.info("EQ pool: %d", self.eq_pool)
self.log.info("EQE version: %d", self.eqe_ver)
self.log.info("Max CQ count: %d (log %d)", 2**self.log_max_cq, self.log_max_cq)
self.log.info("Max CQ size: %d (log %d)", 2**self.log_max_cq_sz, self.log_max_cq_sz)
self.log.info("CQ pool: %d", self.cq_pool)
self.log.info("CQE version: %d", self.cqe_ver)
self.log.info("Max SQ count: %d (log %d)", 2**self.log_max_sq, self.log_max_sq)
self.log.info("Max SQ size: %d (log %d)", 2**self.log_max_sq_sz, self.log_max_sq_sz)
self.log.info("SQ pool: %d", self.sq_pool)
self.log.info("SQE version: %d", self.sqe_ver)
self.log.info("Max RQ count: %d (log %d)", 2**self.log_max_rq, self.log_max_rq)
self.log.info("Max RQ size: %d (log %d)", 2**self.log_max_rq_sz, self.log_max_rq_sz)
self.log.info("RQ pool: %d", self.rq_pool)
self.log.info("RQE version: %d", self.rqe_ver)
# Get PTP information
rsp = await self.exec_cmd(struct.pack("<HHLLLQQQQQLL",
0, # rsvd
@@ -644,6 +831,7 @@ class Driver:
nom_period = rsp_unpacked[8]
self.log.info("PHC nominal period: %.09f ns (raw 0x%x)", nom_period / 2**32, nom_period)
# Test setting PTP time
rsp = await self.exec_cmd(struct.pack("<HHLLLQQQQQLL",
0, # rsvd
CNDM_CMD_OP_PTP, # opcode
@@ -651,7 +839,7 @@ class Driver:
0, # fns
0x12345678, # tod_ns
0x123456654321, # tod_sec
0x11223344, # rel_ns
0x112233445566, # rel_ns
0, # ptm
0, # nom_period
nom_period, # period

View File

@@ -0,0 +1,77 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0
#
# Copyright (c) 2020-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 = cndm_lite_pcie_us
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).f
# 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_SIM := "1'b1"
export PARAM_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"virtexuplus\""
# Structural configuration
export PARAM_PORTS := 2
export PARAM_SYS_CLK_PER_NS_NUM := 4
export PARAM_SYS_CLK_PER_NS_DEN := 1
# Queue configuration
export PARAM_WQN_W := 5
export PARAM_CQN_W := $(PARAM_WQN_W)
# PTP configuration
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TS_FMT_TOD := 0
export PARAM_PTP_CLK_PER_NS_NUM := 512
export PARAM_PTP_CLK_PER_NS_DEN := 165
# PCIe interface configuration
export PARAM_AXIS_PCIE_DATA_W := 512
# AXI lite interface configuration (control)
export PARAM_AXIL_CTRL_DATA_W := 32
export PARAM_AXIL_CTRL_ADDR_W := 24
# MAC configuration
export PARAM_MAC_DATA_W := 512
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

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

View File

@@ -0,0 +1,522 @@
#!/usr/bin/env python
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2020-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import logging
import os
import sys
import pytest
import cocotb_test.simulator
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotbext.axi import AxiStreamBus
from cocotbext.eth import EthMac
from cocotbext.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
try:
import cndm
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
import cndm
finally:
del sys.path[0]
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
# PCIe
self.rc = RootComplex()
self.rc.max_payload_size = 0x1 # 256 bytes
self.rc.max_read_request_size = 0x2 # 512 bytes
self.dev = UltraScalePlusPcieDevice(
# configuration options
pcie_generation=3,
#pcie_link_width=16,
user_clk_frequency=250e6,
alignment="dword",
cq_straddle=False,
cc_straddle=False,
rq_straddle=False,
rc_straddle=False,
rc_4tlp_straddle=False,
pf_count=1,
max_payload_size=1024,
enable_client_tag=True,
enable_extended_tag=True,
enable_parity=False,
enable_rx_msg_interface=False,
enable_sriov=False,
enable_extended_configuration=False,
pf0_msi_enable=True,
pf0_msi_count=32,
pf1_msi_enable=False,
pf1_msi_count=1,
pf2_msi_enable=False,
pf2_msi_count=1,
pf3_msi_enable=False,
pf3_msi_count=1,
pf0_msix_enable=False,
pf0_msix_table_size=31,
pf0_msix_table_bir=4,
pf0_msix_table_offset=0x00000000,
pf0_msix_pba_bir=4,
pf0_msix_pba_offset=0x00008000,
pf1_msix_enable=False,
pf1_msix_table_size=0,
pf1_msix_table_bir=0,
pf1_msix_table_offset=0x00000000,
pf1_msix_pba_bir=0,
pf1_msix_pba_offset=0x00000000,
pf2_msix_enable=False,
pf2_msix_table_size=0,
pf2_msix_table_bir=0,
pf2_msix_table_offset=0x00000000,
pf2_msix_pba_bir=0,
pf2_msix_pba_offset=0x00000000,
pf3_msix_enable=False,
pf3_msix_table_size=0,
pf3_msix_table_bir=0,
pf3_msix_table_offset=0x00000000,
pf3_msix_pba_bir=0,
pf3_msix_pba_offset=0x00000000,
# signals
# Clock and Reset Interface
user_clk=dut.pcie_clk,
user_reset=dut.pcie_rst,
# user_lnk_up
# sys_clk
# sys_clk_gt
# sys_reset
# phy_rdy_out
# Requester reQuest Interface
rq_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_rq),
pcie_rq_seq_num0=dut.pcie_rq_seq_num0,
pcie_rq_seq_num_vld0=dut.pcie_rq_seq_num_vld0,
pcie_rq_seq_num1=dut.pcie_rq_seq_num1,
pcie_rq_seq_num_vld1=dut.pcie_rq_seq_num_vld1,
# pcie_rq_tag0
# pcie_rq_tag1
# pcie_rq_tag_av
# pcie_rq_tag_vld0
# pcie_rq_tag_vld1
# Requester Completion Interface
rc_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_rc),
# Completer reQuest Interface
cq_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_cq),
# pcie_cq_np_req
# pcie_cq_np_req_count
# Completer Completion Interface
cc_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_cc),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=dut.pcie_tfc_nph_av,
# pcie_tfc_npd_av=dut.pcie_tfc_npd_av,
# Configuration Management Interface
cfg_mgmt_addr=dut.cfg_mgmt_addr,
cfg_mgmt_function_number=dut.cfg_mgmt_function_number,
cfg_mgmt_write=dut.cfg_mgmt_write,
cfg_mgmt_write_data=dut.cfg_mgmt_write_data,
cfg_mgmt_byte_enable=dut.cfg_mgmt_byte_enable,
cfg_mgmt_read=dut.cfg_mgmt_read,
cfg_mgmt_read_data=dut.cfg_mgmt_read_data,
cfg_mgmt_read_write_done=dut.cfg_mgmt_read_write_done,
# cfg_mgmt_debug_access
# Configuration Status Interface
# cfg_phy_link_down
# cfg_phy_link_status
# cfg_negotiated_width
# cfg_current_speed
# cfg_max_payload=dut.cfg_max_payload,
# cfg_max_read_req=dut.cfg_max_read_req,
# cfg_function_status
# cfg_vf_status
# cfg_function_power_state
# cfg_vf_power_state
# cfg_link_power_state
# cfg_err_cor_out
# cfg_err_nonfatal_out
# cfg_err_fatal_out
# cfg_local_error_out
# cfg_local_error_valid
# cfg_rx_pm_state
# cfg_tx_pm_state
# cfg_ltssm_state
# cfg_rcb_status=dut.cfg_rcb_status,
# cfg_obff_enable
# cfg_pl_status_change
# cfg_tph_requester_enable
# cfg_tph_st_mode
# cfg_vf_tph_requester_enable
# cfg_vf_tph_st_mode
# Configuration Received Message Interface
# cfg_msg_received
# cfg_msg_received_data
# cfg_msg_received_type
# Configuration Transmit Message Interface
# cfg_msg_transmit
# cfg_msg_transmit_type
# cfg_msg_transmit_data
# cfg_msg_transmit_done
# Configuration Flow Control Interface
cfg_fc_ph=dut.cfg_fc_ph,
cfg_fc_pd=dut.cfg_fc_pd,
cfg_fc_nph=dut.cfg_fc_nph,
cfg_fc_npd=dut.cfg_fc_npd,
cfg_fc_cplh=dut.cfg_fc_cplh,
cfg_fc_cpld=dut.cfg_fc_cpld,
cfg_fc_sel=dut.cfg_fc_sel,
# Configuration Control Interface
# cfg_hot_reset_in
# cfg_hot_reset_out
# cfg_config_space_enable
# cfg_dsn
# cfg_bus_number
# cfg_ds_port_number
# cfg_ds_bus_number
# cfg_ds_device_number
# cfg_ds_function_number
# cfg_power_state_change_ack
# cfg_power_state_change_interrupt
# cfg_err_cor_in=dut.status_error_cor,
# cfg_err_uncor_in=dut.status_error_uncor,
# cfg_flr_in_process
# cfg_flr_done
# cfg_vf_flr_in_process
# cfg_vf_flr_func_num
# cfg_vf_flr_done
# cfg_pm_aspm_l1_entry_reject
# cfg_pm_aspm_tx_l0s_entry_disable
# cfg_req_pm_transition_l23_ready
# cfg_link_training_enable
# Configuration Interrupt Controller Interface
# cfg_interrupt_int
# cfg_interrupt_sent
# cfg_interrupt_pending
cfg_interrupt_msi_enable=dut.cfg_interrupt_msi_enable,
cfg_interrupt_msi_mmenable=dut.cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=dut.cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=dut.cfg_interrupt_msi_data,
cfg_interrupt_msi_select=dut.cfg_interrupt_msi_select,
cfg_interrupt_msi_int=dut.cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=dut.cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=dut.cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=dut.cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=dut.cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=dut.cfg_interrupt_msi_fail,
# cfg_interrupt_msix_enable=dut.cfg_interrupt_msix_enable,
# cfg_interrupt_msix_mask=dut.cfg_interrupt_msix_mask,
# cfg_interrupt_msix_vf_enable=dut.cfg_interrupt_msix_vf_enable,
# cfg_interrupt_msix_vf_mask=dut.cfg_interrupt_msix_vf_mask,
# cfg_interrupt_msix_address=dut.cfg_interrupt_msix_address,
# cfg_interrupt_msix_data=dut.cfg_interrupt_msix_data,
# cfg_interrupt_msix_int=dut.cfg_interrupt_msix_int,
# cfg_interrupt_msix_vec_pending=dut.cfg_interrupt_msix_vec_pending,
# cfg_interrupt_msix_vec_pending_status=dut.cfg_interrupt_msix_vec_pending_status,
# cfg_interrupt_msix_sent=dut.cfg_interrupt_msix_sent,
# cfg_interrupt_msix_fail=dut.cfg_interrupt_msix_fail,
cfg_interrupt_msi_attr=dut.cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=dut.cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=dut.cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=dut.cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=dut.cfg_interrupt_msi_function_number,
# Configuration Extend Interface
# cfg_ext_read_received
# cfg_ext_write_received
# cfg_ext_register_number
# cfg_ext_function_number
# cfg_ext_write_data
# cfg_ext_write_byte_enable
# cfg_ext_read_data
# cfg_ext_read_data_valid
)
# self.dev.log.setLevel(logging.DEBUG)
self.rc.make_port().connect(self.dev)
self.dev.functions[0].configure_bar(0, 2**int(dut.uut.axil_ctrl_bar.ADDR_W))
# PTP
cocotb.start_soon(Clock(dut.ptp_clk, 3.102, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
# Ethernet
self.port_mac = []
if len(dut.mac_axis_tx[0].tdata) == 512:
# assuming US+ 100G CMAC, 512 bits at 322.265625 MHz
eth_clock_period = 3.102
eth_speed = 100e9
elif len(dut.mac_axis_tx[0].tdata) == 64:
# assuming 25G MAC in low-latency mode, 64 bits at 402.83203125 MHz
eth_clock_period = 2.482
eth_speed = 25e9
else:
# assuming 25G MAC in low-latency mode, 512 bits at 322.265625 MHz
eth_clock_period = 3.102
eth_speed = 10e9
for k in range(len(dut.mac_axis_tx)):
cocotb.start_soon(Clock(dut.mac_tx_clk[k], eth_clock_period, units="ns").start())
cocotb.start_soon(Clock(dut.mac_rx_clk[k], eth_clock_period, units="ns").start())
dut.mac_tx_rst[k].setimmediatevalue(0)
dut.mac_rx_rst[k].setimmediatevalue(0)
mac = EthMac(
tx_clk=dut.mac_tx_clk[k],
tx_rst=dut.mac_tx_rst[k],
tx_bus=AxiStreamBus.from_entity(dut.mac_axis_tx[k]),
rx_clk=dut.mac_rx_clk[k],
rx_rst=dut.mac_rx_rst[k],
rx_bus=AxiStreamBus.from_entity(dut.mac_axis_rx[k]),
tx_ptp_time=dut.mac_axis_tx[k].tid, # TODO
tx_ptp_ts=dut.mac_axis_tx_cpl[k].tdata, # TODO
tx_ptp_ts_valid=dut.mac_axis_tx_cpl[k].tvalid, # TODO
ifg=12, speed=eth_speed
)
self.port_mac.append(mac)
self.loopback_enable = False
cocotb.start_soon(self._run_loopback())
async def init(self):
self.dut.ptp_rst.setimmediatevalue(0)
for mac in self.port_mac:
mac.rx.reset.setimmediatevalue(0)
mac.tx.reset.setimmediatevalue(0)
await FallingEdge(self.dut.pcie_rst)
await Timer(100, 'ns')
for k in range(10):
await RisingEdge(self.dut.pcie_clk)
self.dut.ptp_rst.value = 1
for mac in self.port_mac:
mac.rx.reset.value = 1
mac.tx.reset.value = 1
for k in range(10):
await RisingEdge(self.dut.pcie_clk)
self.dut.ptp_rst.value = 0
for mac in self.port_mac:
mac.rx.reset.value = 0
mac.tx.reset.value = 0
for k in range(10):
await RisingEdge(self.dut.pcie_clk)
await self.rc.enumerate()
async def _run_loopback(self):
while True:
await RisingEdge(self.dut.pcie_clk)
if self.loopback_enable:
for mac in self.port_mac:
while not mac.tx.empty():
await mac.rx.send(await mac.tx.recv())
@cocotb.test()
async def run_test(dut):
tb = TB(dut)
await tb.init()
tb.log.info("Init driver model")
driver = cndm.Driver()
await driver.init_pcie_dev(tb.rc.find_device(tb.dev.functions[0].pcie_id))
tb.log.info("Init complete")
tb.log.info("Send and receive single packet on each port")
for k in range(len(driver.ports)):
data = f"Corundum rocks on port {k}!".encode('ascii')
await driver.ports[k].start_xmit(data)
pkt = await tb.port_mac[k].tx.recv()
tb.log.info("Got TX packet: %s", pkt)
assert bytes(pkt) == data
await tb.port_mac[k].rx.send(pkt)
pkt = await driver.ports[k].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == data
tb.log.info("Multiple small packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k]
tb.loopback_enable = False
tb.log.info("Multiple large packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k]
tb.loopback_enable = False
await RisingEdge(dut.pcie_clk)
await RisingEdge(dut.pcie_clk)
# 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(("pcie_data_w", "mac_data_w"), [
(128, 32),
(128, 64),
(256, 32),
(256, 64),
(512, 32),
(512, 64),
(512, 512),
])
def test_cndm_lite_pcie_us(request, pcie_data_w, mac_data_w):
dut = "cndm_lite_pcie_us"
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}.f"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['SIM'] = "1'b1"
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"virtexuplus\""
# Structural configuration
parameters['PORTS'] = 2
parameters['SYS_CLK_PER_NS_NUM'] = 4
parameters['SYS_CLK_PER_NS_DEN'] = 1
# Queue configuration
parameters['WQN_W'] = 5
parameters['CQN_W'] = parameters['WQN_W']
# PTP configuration
parameters['PTP_TS_EN'] = 1
parameters['PTP_TS_FMT_TOD'] = 0
parameters['PTP_CLK_PER_NS_NUM'] = 512
parameters['PTP_CLK_PER_NS_DEN'] = 165
# PCIe interface configuration
parameters['AXIS_PCIE_DATA_W'] = pcie_data_w
# AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32
parameters['AXIL_CTRL_ADDR_W'] = 24
# MAC configuration
parameters['MAC_DATA_W'] = mac_data_w
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,321 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2025-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic testbench
*/
module test_cndm_lite_pcie_us #
(
/* verilator lint_off WIDTHTRUNC */
parameter logic SIM = 1'b0,
parameter string VENDOR = "XILINX",
parameter string FAMILY = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'hDEADBEEF,
parameter FW_ID = 32'h0000C002,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1234_0000,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DEN = 165,
// PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 512,
parameter AXIS_PCIE_RC_USER_W = AXIS_PCIE_DATA_W < 512 ? 75 : 161,
parameter AXIS_PCIE_RQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 62 : 137,
parameter AXIS_PCIE_CQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 85 : 183,
parameter AXIS_PCIE_CC_USER_W = AXIS_PCIE_DATA_W < 512 ? 33 : 81,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24,
// MAC configuration
parameter MAC_DATA_W = 512
/* verilator lint_on WIDTHTRUNC */
)
();
localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48;
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
localparam RQ_SEQ_NUM_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
logic sfp_mgt_refclk_p;
logic sfp_mgt_refclk_n;
logic sfp_mgt_refclk_out;
logic [1:0] sfp_npres;
logic [1:0] sfp_tx_fault;
logic [1:0] sfp_los;
logic pcie_clk;
logic pcie_rst;
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CQ_USER_W)
) s_axis_pcie_cq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CC_USER_W)
) m_axis_pcie_cc();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RQ_USER_W)
) m_axis_pcie_rq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RC_USER_W)
) s_axis_pcie_rc();
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0;
logic pcie_rq_seq_num_vld0;
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1;
logic pcie_rq_seq_num_vld1;
logic [2:0] cfg_max_payload;
logic [2:0] cfg_max_read_req;
logic [3:0] cfg_rcb_status;
logic [9:0] cfg_mgmt_addr;
logic [7:0] cfg_mgmt_function_number;
logic cfg_mgmt_write;
logic [31:0] cfg_mgmt_write_data;
logic [3:0] cfg_mgmt_byte_enable;
logic cfg_mgmt_read;
logic [31:0] cfg_mgmt_read_data;
logic cfg_mgmt_read_write_done;
logic [7:0] cfg_fc_ph;
logic [11:0] cfg_fc_pd;
logic [7:0] cfg_fc_nph;
logic [11:0] cfg_fc_npd;
logic [7:0] cfg_fc_cplh;
logic [11:0] cfg_fc_cpld;
logic [2:0] cfg_fc_sel;
logic [3:0] cfg_interrupt_msi_enable;
logic [11:0] cfg_interrupt_msi_mmenable;
logic cfg_interrupt_msi_mask_update;
logic [31:0] cfg_interrupt_msi_data;
logic [1:0] cfg_interrupt_msi_select;
logic [31:0] cfg_interrupt_msi_int;
logic [31:0] cfg_interrupt_msi_pending_status;
logic cfg_interrupt_msi_pending_status_data_enable;
logic [1:0] cfg_interrupt_msi_pending_status_function_num;
logic cfg_interrupt_msi_sent;
logic cfg_interrupt_msi_fail;
logic [2:0] cfg_interrupt_msi_attr;
logic cfg_interrupt_msi_tph_present;
logic [1:0] cfg_interrupt_msi_tph_type;
logic [7:0] cfg_interrupt_msi_tph_st_tag;
logic [7:0] cfg_interrupt_msi_function_number;
logic ptp_rst;
logic ptp_clk;
logic ptp_sample_clk;
logic ptp_td_sdo;
logic ptp_pps;
logic ptp_pps_str;
logic ptp_sync_locked;
logic [63:0] ptp_sync_ts_rel;
logic ptp_sync_ts_rel_step;
logic [95:0] ptp_sync_ts_tod;
logic ptp_sync_ts_tod_step;
logic ptp_sync_pps;
logic ptp_sync_pps_str;
logic mac_tx_clk[PORTS];
logic mac_tx_rst[PORTS];
taxi_axis_if #(
.DATA_W(MAC_DATA_W),
.ID_W(8),
.USER_EN(1),
.USER_W(1)
) mac_axis_tx[PORTS]();
logic mac_rx_clk[PORTS];
logic mac_rx_rst[PORTS];
taxi_axis_if #(
.DATA_W(PTP_TS_W),
.KEEP_W(1),
.ID_W(8)
) mac_axis_tx_cpl[PORTS]();
taxi_axis_if #(
.DATA_W(MAC_DATA_W),
.ID_W(8),
.USER_EN(1),
.USER_W(PTP_TS_W+1)
) mac_axis_rx[PORTS]();
cndm_lite_pcie_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W)
)
uut (
/*
* PCIe
*/
.pcie_clk(pcie_clk),
.pcie_rst(pcie_rst),
.s_axis_pcie_cq(s_axis_pcie_cq),
.m_axis_pcie_cc(m_axis_pcie_cc),
.m_axis_pcie_rq(m_axis_pcie_rq),
.s_axis_pcie_rc(s_axis_pcie_rc),
.pcie_rq_seq_num0(pcie_rq_seq_num0),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
.pcie_rq_seq_num1(pcie_rq_seq_num1),
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_rcb_status(cfg_rcb_status),
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* PTP
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdo(ptp_td_sdo),
.ptp_pps(ptp_pps),
.ptp_pps_str(ptp_pps_str),
.ptp_sync_locked(ptp_sync_locked),
.ptp_sync_ts_rel(ptp_sync_ts_rel),
.ptp_sync_ts_rel_step(ptp_sync_ts_rel_step),
.ptp_sync_ts_tod(ptp_sync_ts_tod),
.ptp_sync_ts_tod_step(ptp_sync_ts_tod_step),
.ptp_sync_pps(ptp_sync_pps),
.ptp_sync_pps_str(ptp_sync_pps_str),
/*
* Ethernet: SFP+
*/
.mac_tx_clk(mac_tx_clk),
.mac_tx_rst(mac_tx_rst),
.mac_axis_tx(mac_axis_tx),
.mac_axis_tx_cpl(mac_axis_tx_cpl),
.mac_rx_clk(mac_rx_clk),
.mac_rx_rst(mac_rx_rst),
.mac_axis_rx(mac_axis_rx)
);
endmodule
`resetall

View File

@@ -24,9 +24,6 @@ MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
@@ -41,12 +38,18 @@ export PARAM_FAMILY := "\"virtexuplus\""
# Structural configuration
export PARAM_PORTS := 2
export PARAM_SYS_CLK_PER_NS_NUM := 4
export PARAM_SYS_CLK_PER_NS_DEN := 1
# Queue configuration
export PARAM_WQN_W := 5
export PARAM_CQN_W := $(PARAM_WQN_W)
# PTP configuration
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TS_FMT_TOD := 0
export PARAM_PTP_CLK_PER_NS_NUM := 512
export PARAM_PTP_CLK_PER_NS_DENOM := 165
export PARAM_PTP_CLK_PER_NS_DEN := 165
# PCIe interface configuration
export PARAM_AXIS_PCIE_DATA_W := 256

View File

@@ -52,7 +52,7 @@ class TB:
self.dev = UltraScalePlusPcieDevice(
# configuration options
pcie_generation=3,
pcie_link_width=8,
#pcie_link_width=8,
user_clk_frequency=250e6,
alignment="dword",
cq_straddle=False,
@@ -278,8 +278,18 @@ class TB:
# Ethernet
self.port_mac = []
eth_clock_period = 3.2
eth_speed = 10e9
if len(dut.mac_axis_tx[0].tdata) == 512:
# assuming US+ 100G CMAC, 512 bits at 322.265625 MHz
eth_clock_period = 3.102
eth_speed = 100e9
elif len(dut.mac_axis_tx[0].tdata) == 64:
# assuming 25G MAC in low-latency mode, 64 bits at 402.83203125 MHz
eth_clock_period = 2.482
eth_speed = 25e9
else:
# assuming 25G MAC in low-latency mode, 512 bits at 322.265625 MHz
eth_clock_period = 3.102
eth_speed = 10e9
for k in range(len(dut.mac_axis_tx)):
cocotb.start_soon(Clock(dut.mac_tx_clk[k], eth_clock_period, units="ns").start())
@@ -302,53 +312,6 @@ class TB:
)
self.port_mac.append(mac)
# cocotb.start_soon(Clock(dut.sfp_mgt_refclk_p, 6.4, units="ns").start())
# self.sfp_sources = []
# self.sfp_sinks = []
# for ch in dut.uut.sfp_mac_inst.ch:
# gt_inst = ch.ch_inst.gt.gt_inst
# if ch.ch_inst.DATA_W.value == 64:
# if ch.ch_inst.CFG_LOW_LATENCY.value:
# clk = 2.482
# gbx_cfg = (66, [64, 65])
# else:
# clk = 2.56
# gbx_cfg = None
# else:
# if ch.ch_inst.CFG_LOW_LATENCY.value:
# clk = 3.102
# gbx_cfg = (66, [64, 65])
# else:
# clk = 3.2
# gbx_cfg = None
# cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
# cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
# self.sfp_sources.append(BaseRSerdesSource(
# data=gt_inst.serdes_rx_data,
# data_valid=gt_inst.serdes_rx_data_valid,
# hdr=gt_inst.serdes_rx_hdr,
# hdr_valid=gt_inst.serdes_rx_hdr_valid,
# clock=gt_inst.rx_clk,
# slip=gt_inst.serdes_rx_bitslip,
# reverse=True,
# gbx_cfg=gbx_cfg
# ))
# self.sfp_sinks.append(BaseRSerdesSink(
# data=gt_inst.serdes_tx_data,
# data_valid=gt_inst.serdes_tx_data_valid,
# hdr=gt_inst.serdes_tx_hdr,
# hdr_valid=gt_inst.serdes_tx_hdr_valid,
# gbx_sync=gt_inst.serdes_tx_gbx_sync,
# clock=gt_inst.tx_clk,
# reverse=True,
# gbx_cfg=gbx_cfg
# ))
#
self.loopback_enable = False
cocotb.start_soon(self._run_loopback())
@@ -490,8 +453,15 @@ def process_f_files(files):
return list(lst.values())
@pytest.mark.parametrize("mac_data_w", [32, 64])
def test_cndm_micro_pcie_us(request, mac_data_w):
@pytest.mark.parametrize(("pcie_data_w", "mac_data_w"), [
(128, 32),
(128, 64),
(256, 32),
(256, 64),
(512, 32),
(512, 64),
])
def test_cndm_micro_pcie_us(request, pcie_data_w, mac_data_w):
dut = "cndm_micro_pcie_us"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
@@ -499,9 +469,6 @@ def test_cndm_micro_pcie_us(request, mac_data_w):
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.f"),
os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_async_fifo.f"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.sv"),
]
verilog_sources = process_f_files(verilog_sources)
@@ -514,15 +481,21 @@ def test_cndm_micro_pcie_us(request, mac_data_w):
# Structural configuration
parameters['PORTS'] = 2
parameters['SYS_CLK_PER_NS_NUM'] = 4
parameters['SYS_CLK_PER_NS_DEN'] = 1
# Queue configuration
parameters['WQN_W'] = 5
parameters['CQN_W'] = parameters['WQN_W']
# PTP configuration
parameters['PTP_TS_EN'] = 1
parameters['PTP_TS_FMT_TOD'] = 0
parameters['PTP_CLK_PER_NS_NUM'] = 512
parameters['PTP_CLK_PER_NS_DENOM'] = 165
parameters['PTP_CLK_PER_NS_DEN'] = 165
# PCIe interface configuration
parameters['AXIS_PCIE_DATA_W'] = 256
parameters['AXIS_PCIE_DATA_W'] = pcie_data_w
# AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32

View File

@@ -34,12 +34,18 @@ module test_cndm_micro_pcie_us #
// Structural configuration
parameter PORTS = 2,
parameter SYS_CLK_PER_NS_NUM = 4,
parameter SYS_CLK_PER_NS_DEN = 1,
// Queue configuration
parameter WQN_W = 5,
parameter CQN_W = WQN_W,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
parameter logic PTP_TS_FMT_TOD = 1'b0,
parameter PTP_CLK_PER_NS_NUM = 512,
parameter PTP_CLK_PER_NS_DENOM = 165,
parameter PTP_CLK_PER_NS_DEN = 165,
// PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 256,
@@ -206,12 +212,18 @@ cndm_micro_pcie_us #(
// Structural configuration
.PORTS(PORTS),
.SYS_CLK_PER_NS_NUM(SYS_CLK_PER_NS_NUM),
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
// Queue configuration
.WQN_W(WQN_W),
.CQN_W(CQN_W),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM),
.PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -265,7 +265,7 @@ always_comb begin
length_next = 0;
cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1)) >> $clog2(AXIS_KEEP_W_INT);
cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1) >> $clog2(AXIS_KEEP_W_INT));
last_cycle_next = cycle_count_next == 0;
if (cycle_count_next == 0 && last_cycle_offset_next != 0) begin
keep_mask_next = {AXIS_KEEP_W_INT{1'b1}} >> (AXIS_KEEP_W_INT - last_cycle_offset_next);

View File

@@ -227,8 +227,8 @@ always_comb begin
axis_cmd_axis_dest_next = desc_req.req_dest;
axis_cmd_axis_user_next = desc_req.req_user;
axis_cmd_cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1)) >> $clog2(AXIS_KEEP_W_INT);
read_cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1)) >> $clog2(AXIS_KEEP_W_INT);
axis_cmd_cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1) >> $clog2(AXIS_KEEP_W_INT));
read_cycle_count_next = CYCLE_COUNT_W'(desc_req.req_len - LEN_W'(1) >> $clog2(AXIS_KEEP_W_INT));
axis_cmd_valid_next = 1'b1;

View File

@@ -328,46 +328,29 @@ logic op_tbl_finish_en;
logic [2**OP_TAG_W-1:0] op_tbl_active = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [AXI_ADDR_W-1:0] op_tbl_axi_addr[2**OP_TAG_W];
logic [AXI_ADDR_W-1:0] op_tbl_axi_addr[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_SEL_W-1:0] op_tbl_ram_sel[2**OP_TAG_W];
logic [RAM_SEL_W-1:0] op_tbl_ram_sel[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_ADDR_W-1:0] op_tbl_ram_addr[2**OP_TAG_W];
logic [RAM_ADDR_W-1:0] op_tbl_ram_addr[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [12:0] op_tbl_len[2**OP_TAG_W];
logic [12:0] op_tbl_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_zero_len[2**OP_TAG_W];
logic op_tbl_zero_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W];
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W];
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_last[2**OP_TAG_W];
logic op_tbl_last[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_write_complete[2**OP_TAG_W];
logic op_tbl_write_complete[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_error_a[2**OP_TAG_W];
logic op_tbl_error_a[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_error_b[2**OP_TAG_W];
logic op_tbl_error_b[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [3:0] op_tbl_error_code[2**OP_TAG_W];
initial begin
for (integer i = 0; i < 2**OP_TAG_W; i = i + 1) begin
op_tbl_axi_addr[i] = '0;
op_tbl_ram_sel[i] = '0;
op_tbl_ram_addr[i] = '0;
op_tbl_len[i] = '0;
op_tbl_zero_len[i] = 1'b0;
op_tbl_cycle_count[i] = '0;
op_tbl_tag[i] = '0;
op_tbl_last[i] = '0;
op_tbl_write_complete[i] = '0;
op_tbl_error_a[i] = '0;
op_tbl_error_b[i] = '0;
op_tbl_error_code[i] = '0;
end
end
logic [3:0] op_tbl_error_code[2**OP_TAG_W] = '{default: '0};
always_comb begin
req_state_next = REQ_STATE_IDLE;

View File

@@ -357,40 +357,25 @@ logic op_tbl_finish_en;
logic [2**OP_TAG_W-1:0] op_tbl_active = '0;
logic [2**OP_TAG_W-1:0] op_tbl_write_complete = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [AXI_ADDR_W-1:0] op_tbl_axi_addr[2**OP_TAG_W];
logic [AXI_ADDR_W-1:0] op_tbl_axi_addr[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [IMM_W-1:0] op_tbl_imm[2**OP_TAG_W];
logic [IMM_W-1:0] op_tbl_imm[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_imm_en[2**OP_TAG_W];
logic op_tbl_imm_en[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [12:0] op_tbl_len[2**OP_TAG_W];
logic [12:0] op_tbl_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_zero_len[2**OP_TAG_W];
logic op_tbl_zero_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W];
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_OFFSET_W-1:0] op_tbl_offset[2**OP_TAG_W];
logic [RAM_OFFSET_W-1:0] op_tbl_offset[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W];
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_last[2**OP_TAG_W];
logic op_tbl_last[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [3:0] op_tbl_error_code[2**OP_TAG_W];
initial begin
for (integer i = 0; i < 2**OP_TAG_W; i = i + 1) begin
op_tbl_axi_addr[i] = '0;
op_tbl_imm[i] = '0;
op_tbl_imm_en[i] = '0;
op_tbl_len[i] = '0;
op_tbl_zero_len[i] = 1'b0;
op_tbl_cycle_count[i] = '0;
op_tbl_offset[i] = '0;
op_tbl_tag[i] = '0;
op_tbl_last[i] = '0;
op_tbl_error_code[i] = '0;
end
end
logic [3:0] op_tbl_error_code[2**OP_TAG_W] = '{default: '0};
always_comb begin
req_state_next = REQ_STATE_IDLE;

View File

@@ -484,17 +484,17 @@ logic [PCIE_TAG_W-1:0] pcie_tag_table_finish_ptr;
logic pcie_tag_table_finish_en;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_SEL_W-1:0] pcie_tag_table_ram_sel[2**PCIE_TAG_W];
logic [RAM_SEL_W-1:0] pcie_tag_table_ram_sel[2**PCIE_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_ADDR_W-1:0] pcie_tag_table_ram_addr[2**PCIE_TAG_W];
logic [RAM_ADDR_W-1:0] pcie_tag_table_ram_addr[2**PCIE_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [OP_TAG_W-1:0] pcie_tag_table_op_tag[2**PCIE_TAG_W];
logic [OP_TAG_W-1:0] pcie_tag_table_op_tag[2**PCIE_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic pcie_tag_table_zero_len[2**PCIE_TAG_W];
logic pcie_tag_table_zero_len[2**PCIE_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic pcie_tag_table_active_a[2**PCIE_TAG_W];
logic pcie_tag_table_active_a[2**PCIE_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic pcie_tag_table_active_b[2**PCIE_TAG_W];
logic pcie_tag_table_active_b[2**PCIE_TAG_W] = '{default: '0};
logic [PCIE_TAG_W-1:0] pcie_tag_fifo_wr_tag;
@@ -524,23 +524,23 @@ logic [OP_TAG_W-1:0] op_tbl_rd_finish_ptr;
logic op_tbl_rd_finish_en;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [TAG_W-1:0] op_tbl_tag [2**OP_TAG_W];
logic [TAG_W-1:0] op_tbl_tag [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_rd_init_a [2**OP_TAG_W];
logic op_tbl_rd_init_a [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_rd_init_b [2**OP_TAG_W];
logic op_tbl_rd_init_b [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_rd_commit [2**OP_TAG_W];
logic op_tbl_rd_commit [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [OP_TBL_RD_COUNT_W-1:0] op_tbl_rd_count_start [2**OP_TAG_W];
logic [OP_TBL_RD_COUNT_W-1:0] op_tbl_rd_count_start [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [OP_TBL_RD_COUNT_W-1:0] op_tbl_rd_count_finish [2**OP_TAG_W];
logic [OP_TBL_RD_COUNT_W-1:0] op_tbl_rd_count_finish [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_error_a [2**OP_TAG_W];
logic op_tbl_error_a [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_error_b [2**OP_TAG_W];
logic op_tbl_error_b [2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [3:0] op_tbl_error_code [2**OP_TAG_W];
logic [3:0] op_tbl_error_code [2**OP_TAG_W] = '{default: '0};
logic [OP_TAG_W+1-1:0] op_tag_fifo_wr_ptr_reg = '0;
logic [OP_TAG_W+1-1:0] op_tag_fifo_rd_ptr_reg = '0, op_tag_fifo_rd_ptr_next;
@@ -549,29 +549,6 @@ logic [OP_TAG_W-1:0] op_tag_fifo_mem [2**OP_TAG_W];
logic [OP_TAG_W-1:0] op_tag_fifo_wr_tag;
logic op_tag_fifo_we;
initial begin
for (integer i = 0; i < 2**OP_TAG_W; i = i + 1) begin
op_tbl_tag[i] = '0;
op_tbl_rd_init_a[i] = '0;
op_tbl_rd_init_b[i] = '0;
op_tbl_rd_commit[i] = '0;
op_tbl_rd_count_start[i] = '0;
op_tbl_rd_count_finish[i] = '0;
op_tbl_error_a[i] = '0;
op_tbl_error_b[i] = '0;
op_tbl_error_code[i] = '0;
end
for (integer i = 0; i < 2**PCIE_TAG_W; i = i + 1) begin
pcie_tag_table_ram_sel[i] = '0;
pcie_tag_table_ram_addr[i] = '0;
pcie_tag_table_op_tag[i] = '0;
pcie_tag_table_zero_len[i] = '0;
pcie_tag_table_active_a[i] = '0;
pcie_tag_table_active_b[i] = '0;
end
end
always_comb begin
req_state_next = REQ_STATE_IDLE;

View File

@@ -405,34 +405,21 @@ logic op_tbl_finish_en;
logic [2**OP_TAG_W-1:0] op_tbl_active = '0;
logic [2**OP_TAG_W-1:0] op_tbl_tx_done = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [PCIE_ADDR_W-1:0] op_tbl_pcie_addr[2**OP_TAG_W];
logic [PCIE_ADDR_W-1:0] op_tbl_pcie_addr[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [11:0] op_tbl_len[2**OP_TAG_W];
logic [11:0] op_tbl_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_zero_len[2**OP_TAG_W];
logic op_tbl_zero_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [10:0] op_tbl_dword_len[2**OP_TAG_W];
logic [10:0] op_tbl_dword_len[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W];
logic [CYCLE_COUNT_W-1:0] op_tbl_cycle_count[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [RAM_OFFSET_W-1:0] op_tbl_offset[2**OP_TAG_W];
logic [RAM_OFFSET_W-1:0] op_tbl_offset[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W];
logic [TAG_W-1:0] op_tbl_tag[2**OP_TAG_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic op_tbl_last[2**OP_TAG_W];
initial begin
for (integer i = 0; i < 2**OP_TAG_W; i = i + 1) begin
op_tbl_pcie_addr[i] = '0;
op_tbl_len[i] = '0;
op_tbl_zero_len[i] = '0;
op_tbl_dword_len[i] = '0;
op_tbl_cycle_count[i] = '0;
op_tbl_offset[i] = '0;
op_tbl_tag[i] = '0;
op_tbl_last[i] = '0;
end
end
logic op_tbl_last[2**OP_TAG_W] = '{default: '0};
always_comb begin
req_state_next = REQ_STATE_IDLE;

View File

@@ -58,26 +58,12 @@ if (SEGS != dma_ram_rd.SEGS || SEG_DATA_W != dma_ram_rd.SEG_DATA_W)
for (genvar n = 0; n < SEGS; n = n + 1) begin
(* ramstyle = "no_rw_check" *)
logic [SEG_DATA_W-1:0] mem_reg[2**INT_ADDR_W];
logic [SEG_DATA_W-1:0] mem_reg[2**INT_ADDR_W] = '{default: '0};
logic wr_done_reg = 1'b0;
logic [PIPELINE-1:0] rd_resp_valid_pipe_reg = '0;
logic [SEG_DATA_W-1:0] rd_resp_data_pipe_reg[PIPELINE];
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**INT_ADDR_W; i = i + 2**(INT_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(INT_ADDR_W/2); j = j + 1) begin
mem_reg[j] = '0;
end
end
for (integer i = 0; i < PIPELINE; i = i + 1) begin
rd_resp_data_pipe_reg[i] = '0;
end
end
logic [SEG_DATA_W-1:0] rd_resp_data_pipe_reg[PIPELINE] = '{default: '0};
always_ff @(posedge clk) begin
wr_done_reg <= 1'b0;

View File

@@ -59,26 +59,12 @@ if (SEGS != dma_ram_rd.SEGS || SEG_DATA_W != dma_ram_rd.SEG_DATA_W)
for (genvar n = 0; n < SEGS; n = n + 1) begin
(* ramstyle = "no_rw_check" *)
logic [SEG_DATA_W-1:0] mem_reg[2**INT_ADDR_W];
logic [SEG_DATA_W-1:0] mem_reg[2**INT_ADDR_W] = '{default: '0};
logic wr_done_reg = 1'b0;
logic [PIPELINE-1:0] rd_resp_valid_pipe_reg = '0;
logic [SEG_DATA_W-1:0] rd_resp_data_pipe_reg[PIPELINE];
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**INT_ADDR_W; i = i + 2**(INT_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(INT_ADDR_W/2); j = j + 1) begin
mem_reg[j] = '0;
end
end
for (integer i = 0; i < PIPELINE; i = i + 1) begin
rd_resp_data_pipe_reg[i] = '0;
end
end
logic [SEG_DATA_W-1:0] rd_resp_data_pipe_reg[PIPELINE] = '{default: '0};
always_ff @(posedge clk_wr) begin
wr_done_reg <= 1'b0;

View File

@@ -76,17 +76,11 @@ for (genvar n = 0; n < SEGS; n = n + 1) begin
logic [FIFO_AW+1-1:0] fifo_wr_ptr_reg = '0;
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_PORTS-1:0] fifo_sel[2**FIFO_AW];
logic [CL_PORTS-1:0] fifo_sel[2**FIFO_AW] = '{default: '0};
wire fifo_empty = fifo_wr_ptr_reg == fifo_rd_ptr_reg;
wire fifo_full = fifo_wr_ptr_reg == (fifo_rd_ptr_reg ^ (1 << FIFO_AW));
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_sel[i] = '0;
end
end
// RAM read command demux
wire [DMA_SEL_W-1:0] seg_ctrl_rd_cmd_sel = dma_ram_rd.rd_cmd_sel[n];

View File

@@ -76,17 +76,11 @@ for (genvar n = 0; n < SEGS; n = n + 1) begin
logic [FIFO_AW+1-1:0] fifo_wr_ptr_reg = '0;
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_PORTS-1:0] fifo_sel[2**FIFO_AW];
logic [CL_PORTS-1:0] fifo_sel[2**FIFO_AW] = '{default: '0};
wire fifo_empty = fifo_wr_ptr_reg == fifo_rd_ptr_reg;
wire fifo_full = fifo_wr_ptr_reg == (fifo_rd_ptr_reg ^ (1 << FIFO_AW));
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_sel[i] = '0;
end
end
// RAM write command demux
wire [DMA_SEL_W-1:0] seg_ctrl_wr_cmd_sel = dma_ram_wr.wr_cmd_sel[n];

View File

@@ -95,22 +95,15 @@ end
if (SERDES_PIPELINE > 0) begin
(* srl_style = "register" *)
logic [DATA_W-1:0] serdes_rx_data_pipe_reg[SERDES_PIPELINE-1:0];
logic [DATA_W-1:0] serdes_rx_data_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic serdes_rx_data_valid_pipe_reg[SERDES_PIPELINE-1:0];
logic serdes_rx_data_valid_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic [HDR_W-1:0] serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0];
logic [HDR_W-1:0] serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic serdes_rx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0];
logic serdes_rx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
for (genvar n = 0; n < SERDES_PIPELINE; n = n + 1) begin
initial begin
serdes_rx_data_pipe_reg[n] = '0;
serdes_rx_data_valid_pipe_reg[n] = '0;
serdes_rx_hdr_pipe_reg[n] = '0;
serdes_rx_hdr_valid_pipe_reg[n] = '0;
end
always_ff @(posedge clk) begin
serdes_rx_data_pipe_reg[n] <= n == 0 ? serdes_rx_data_rev : serdes_rx_data_pipe_reg[n-1];
serdes_rx_data_valid_pipe_reg[n] <= n == 0 ? serdes_rx_data_valid : serdes_rx_data_valid_pipe_reg[n-1];

View File

@@ -100,25 +100,17 @@ end
if (SERDES_PIPELINE > 0) begin
(* srl_style = "register" *)
logic [DATA_W-1:0] serdes_tx_data_pipe_reg[SERDES_PIPELINE-1:0];
logic [DATA_W-1:0] serdes_tx_data_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic serdes_tx_data_valid_pipe_reg[SERDES_PIPELINE-1:0];
logic serdes_tx_data_valid_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic [HDR_W-1:0] serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1:0];
logic [HDR_W-1:0] serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic serdes_tx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0];
logic serdes_tx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
(* srl_style = "register" *)
logic serdes_tx_gbx_sync_pipe_reg[SERDES_PIPELINE-1:0];
logic serdes_tx_gbx_sync_pipe_reg[SERDES_PIPELINE-1:0] = '{default: '0};
for (genvar n = 0; n < SERDES_PIPELINE; n = n + 1) begin
initial begin
serdes_tx_data_pipe_reg[n] = '0;
serdes_tx_data_valid_pipe_reg[n] = '0;
serdes_tx_hdr_pipe_reg[n] = '0;
serdes_tx_hdr_valid_pipe_reg[n] = '0;
serdes_tx_gbx_sync_pipe_reg[n] = '0;
end
always_ff @(posedge clk) begin
serdes_tx_data_pipe_reg[n] <= n == 0 ? serdes_tx_data_int : serdes_tx_data_pipe_reg[n-1];
serdes_tx_data_valid_pipe_reg[n] <= n == 0 ? serdes_tx_data_valid_reg : serdes_tx_data_valid_pipe_reg[n-1];

View File

@@ -85,7 +85,7 @@ logic [QFB-1:0] quanta_cnt_reg = '0, quanta_cnt_next;
logic [1:0] quanta_inc_reg = '0, quanta_inc_next;
logic [QW-1:0] lfc_quanta_reg = '0, lfc_quanta_next;
logic [QW-1:0] pfc_quanta_reg[8], pfc_quanta_next[8];
logic [QW-1:0] pfc_quanta_reg[8] = '{default: '0}, pfc_quanta_next[8];
logic stat_rx_lfc_pkt_reg = 1'b0, stat_rx_lfc_pkt_next;
logic stat_rx_lfc_xon_reg = 1'b0, stat_rx_lfc_xon_next;
@@ -106,12 +106,6 @@ assign stat_rx_pfc_xon = stat_rx_pfc_xon_reg;
assign stat_rx_pfc_xoff = stat_rx_pfc_xoff_reg;
assign stat_rx_pfc_paused = pfc_req_reg;
initial begin
for (integer k = 0; k < 8; k = k + 1) begin
pfc_quanta_reg[k] = '0;
end
end
always_comb begin
stat_rx_lfc_pkt_next = 1'b0;
stat_rx_lfc_xon_next = 1'b0;

View File

@@ -99,7 +99,7 @@ logic [QFB-1:0] quanta_cnt_reg = '0, quanta_cnt_next;
logic [1:0] quanta_inc_reg = '0, quanta_inc_next;
logic [QW-1:0] lfc_refresh_reg = '0, lfc_refresh_next;
logic [QW-1:0] pfc_refresh_reg[8], pfc_refresh_next[8];
logic [QW-1:0] pfc_refresh_reg[8] = '{default: '0}, pfc_refresh_next[8];
logic stat_tx_lfc_pkt_reg = 1'b0, stat_tx_lfc_pkt_next;
logic stat_tx_lfc_xon_reg = 1'b0, stat_tx_lfc_xon_next;
@@ -146,12 +146,6 @@ assign stat_tx_pfc_xon = stat_tx_pfc_xon_reg;
assign stat_tx_pfc_xoff = stat_tx_pfc_xoff_reg;
assign stat_tx_pfc_paused = pfc_req_reg;
initial begin
for (integer k = 0; k < 8; k = k + 1) begin
pfc_refresh_reg[k] = 0;
end
end
always_comb begin
lfc_req_next = lfc_req_reg;
lfc_act_next = lfc_act_reg;

View File

@@ -0,0 +1,253 @@
// 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
/*
* IRQ rate limit module
*/
module taxi_irq_rate_limit
(
input wire logic clk,
input wire logic rst,
/*
* Interrupt request input
*/
taxi_axis_if.snk s_axis_irq,
/*
* Interrupt request output
*/
taxi_axis_if.src m_axis_irq,
/*
* Configuration
*/
input wire logic [15:0] prescale,
input wire logic [15:0] min_interval
);
localparam IRQN_W = s_axis_irq.DATA_W;
localparam TSTAMP_W = 17;
// check configuration
if (m_axis_irq.DATA_W != IRQN_W)
$fatal(0, "Error: AXI stream width mismatch (instance %m)");
typedef enum logic [1:0] {
STATE_INIT,
STATE_IDLE,
STATE_IRQ_IN,
STATE_IRQ_OUT
} state_t;
state_t state_reg = STATE_INIT, state_next;
logic [IRQN_W-1:0] cur_index_reg = '0, cur_index_next;
logic [IRQN_W-1:0] irqn_reg = '0, irqn_next;
localparam MEM_W = TSTAMP_W+1+1;
logic mem_rd_en;
logic mem_wr_en;
logic [IRQN_W-1:0] mem_addr;
logic [MEM_W-1:0] mem_wr_data;
logic [MEM_W-1:0] mem_rd_data_reg;
logic mem_rd_data_valid_reg = 1'b0, mem_rd_data_valid_next;
(* ramstyle = "no_rw_check, mlab" *)
logic [MEM_W-1:0] mem_reg[2**IRQN_W] = '{default: '0};
logic s_axis_irq_tready_reg = 0, s_axis_irq_tready_next;
logic [IRQN_W-1:0] m_axis_irq_irqn_reg = '0, m_axis_irq_irqn_next;
logic m_axis_irq_tvalid_reg = 1'b0, m_axis_irq_tvalid_next;
assign s_axis_irq.tready = s_axis_irq_tready_reg;
assign m_axis_irq.tdata = m_axis_irq_irqn_reg;
assign m_axis_irq.tkeep = '1;
assign m_axis_irq.tstrb = m_axis_irq.tkeep;
assign m_axis_irq.tvalid = m_axis_irq_tvalid_reg;
assign m_axis_irq.tlast = 1'b1;
assign m_axis_irq.tid = '0;
assign m_axis_irq.tdest = '0;
assign m_axis_irq.tuser = '0;
logic [15:0] prescale_count_reg = '0;
logic [TSTAMP_W-1:0] time_count_reg = '0;
always_ff @(posedge clk) begin
if (prescale_count_reg != 0) begin
prescale_count_reg <= prescale_count_reg - 1;
end else begin
prescale_count_reg <= prescale;
time_count_reg <= time_count_reg + 1;
end
if (rst) begin
prescale_count_reg <= '0;
time_count_reg <= '0;
end
end
always_comb begin
state_next = STATE_INIT;
cur_index_next = cur_index_reg;
irqn_next = irqn_reg;
s_axis_irq_tready_next = 1'b0;
m_axis_irq_irqn_next = m_axis_irq_irqn_reg;
m_axis_irq_tvalid_next = m_axis_irq_tvalid_reg && !m_axis_irq.tready;
mem_rd_en = 1'b0;
mem_wr_en = 1'b0;
mem_addr = cur_index_reg;
mem_wr_data = mem_rd_data_reg;
mem_rd_data_valid_next = mem_rd_data_valid_reg;
case (state_reg)
STATE_INIT: begin
// init - clear all timers
mem_addr = cur_index_reg;
mem_wr_data[0] = 1'b0;
mem_wr_data[1] = 1'b0;
mem_wr_data[2 +: TSTAMP_W] = '0;
mem_wr_en = 1'b1;
cur_index_next = cur_index_reg + 1;
if (&cur_index_reg) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_INIT;
end
end
STATE_IDLE: begin
// idle - wait for requests and check timers
if (s_axis_irq.tvalid) begin
// new interrupt request
irqn_next = s_axis_irq.tdata;
mem_addr = s_axis_irq.tdata;
mem_rd_en = 1'b1;
mem_rd_data_valid_next = 1'b1;
s_axis_irq_tready_next = 1'b1;
state_next = STATE_IRQ_IN;
end else if (mem_rd_data_valid_reg && mem_rd_data_reg[1] && (mem_rd_data_reg[2 +: TSTAMP_W] - time_count_reg) >> (TSTAMP_W-1) != 0) begin
// timer expired
state_next = STATE_IRQ_OUT;
end else begin
// read next timer
irqn_next = cur_index_reg;
mem_addr = cur_index_reg;
mem_rd_en = 1'b1;
mem_rd_data_valid_next = 1'b1;
cur_index_next = cur_index_reg + 1;
state_next = STATE_IDLE;
end
end
STATE_IRQ_IN: begin
// pass through IRQ
if (mem_rd_data_reg[1]) begin
// timer running, set pending bit
mem_addr = irqn_reg;
mem_wr_data[0] = 1'b1;
mem_wr_data[1] = 1'b1;
mem_wr_data[2 +: TSTAMP_W] = mem_rd_data_reg[2 +: TSTAMP_W];
mem_wr_en = 1'b1;
mem_rd_data_valid_next = 1'b0;
state_next = STATE_IDLE;
end else if (!m_axis_irq_tvalid_reg || m_axis_irq.tready) begin
// timer not running, start timer and generate IRQ
mem_addr = irqn_reg;
mem_wr_data[0] = 1'b0;
mem_wr_data[1] = min_interval != 0;
mem_wr_data[2 +: TSTAMP_W] = time_count_reg + min_interval;
mem_wr_en = 1'b1;
mem_rd_data_valid_next = 1'b0;
m_axis_irq_tvalid_next = 1'b1;
m_axis_irq_irqn_next = irqn_reg;
state_next = STATE_IDLE;
end else begin
state_next = STATE_IRQ_IN;
end
end
STATE_IRQ_OUT: begin
// handle timer expiration
if (mem_rd_data_reg[0]) begin
// pending bit set, generate IRQ and restart timer
if (!m_axis_irq_tvalid_reg || m_axis_irq.tready) begin
mem_addr = irqn_reg;
mem_wr_data[0] = 1'b0;
mem_wr_data[1] = min_interval != 0;
mem_wr_data[2 +: TSTAMP_W] = time_count_reg + min_interval;
mem_wr_en = 1'b1;
mem_rd_data_valid_next = 1'b0;
m_axis_irq_tvalid_next = 1'b1;
m_axis_irq_irqn_next = irqn_reg;
state_next = STATE_IDLE;
end else begin
state_next = STATE_IRQ_OUT;
end
end else begin
// pending bit not set, reset timer
mem_addr = irqn_reg;
mem_wr_data[0] = 1'b0;
mem_wr_data[1] = 1'b0;
mem_wr_data[2 +: TSTAMP_W] = '0;
mem_wr_en = 1'b1;
mem_rd_data_valid_next = 1'b0;
state_next = STATE_IDLE;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
cur_index_reg <= cur_index_next;
irqn_reg <= irqn_next;
s_axis_irq_tready_reg <= s_axis_irq_tready_next;
m_axis_irq_irqn_reg <= m_axis_irq_irqn_next;
m_axis_irq_tvalid_reg <= m_axis_irq_tvalid_next;
if (mem_wr_en) begin
mem_reg[mem_addr] <= mem_wr_data;
end else if (mem_rd_en) begin
mem_rd_data_reg <= mem_reg[mem_addr];
end
mem_rd_data_valid_reg <= mem_rd_data_valid_next;
if (rst) begin
state_reg <= STATE_INIT;
cur_index_reg <= '0;
s_axis_irq_tready_reg <= 1'b0;
m_axis_irq_tvalid_reg <= 1'b0;
mem_rd_data_valid_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -139,11 +139,11 @@ logic msix_mask_reg = 1'b0;
// MSI-X table
(* ramstyle = "no_rw_check, mlab" *)
logic [63:0] tbl_mem[2**TBL_ADDR_W];
logic [63:0] tbl_mem[2**TBL_ADDR_W] = '{default: '0};
// MSI-X PBA
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [63:0] pba_mem[2**PBA_ADDR_W];
logic [63:0] pba_mem[2**PBA_ADDR_W] = '{default: '0};
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;
@@ -176,15 +176,6 @@ 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;

View File

@@ -149,11 +149,11 @@ logic msix_mask_reg = 1'b0;
// MSI-X table
(* ramstyle = "no_rw_check, mlab" *)
logic [63:0] tbl_mem[2**TBL_ADDR_W];
logic [63:0] tbl_mem[2**TBL_ADDR_W] = '{default: '0};
// MSI-X PBA
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [63:0] pba_mem[2**PBA_ADDR_W];
logic [63:0] pba_mem[2**PBA_ADDR_W] = '{default: '0};
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;
@@ -194,15 +194,6 @@ 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;

View File

@@ -0,0 +1,51 @@
# 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_irq_rate_limit
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 += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_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_IRQN_W := 11
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1,193 @@
#!/usr/bin/env python
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2021-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import cocotb_test.simulator
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Timer
from cocotb.regression import TestFactory
from cocotbext.axi import AxiStreamSource, AxiStreamSink, AxiStreamBus
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.irq_source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_irq), dut.clk, dut.rst)
self.irq_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_irq), dut.clk, dut.rst)
dut.prescale.setimmediatevalue(0)
dut.min_interval.setimmediatevalue(0)
def set_idle_generator(self, generator=None):
if generator:
self.irq_source.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
self.irq_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_irq(dut, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
dut.prescale.setimmediatevalue(249)
dut.min_interval.setimmediatevalue(100)
tb.log.info("Test interrupts (single shot)")
for k in range(8):
await tb.irq_source.send([k])
for k in range(8):
irq = await tb.irq_sink.recv()
tb.log.info(irq)
assert irq.tdata[0] == k
assert tb.irq_sink.empty()
await Timer(110, 'us')
assert tb.irq_sink.empty()
tb.log.info("Test interrupts (multiple)")
for n in range(5):
for k in range(8):
await tb.irq_source.send([k])
for k in range(8):
irq = await tb.irq_sink.recv()
tb.log.info(irq)
assert irq.tdata[0] == k
assert tb.irq_sink.empty()
await Timer(99, 'us')
assert tb.irq_sink.empty()
await Timer(11, 'us')
assert not tb.irq_sink.empty()
for k in range(8):
irq = await tb.irq_sink.recv()
tb.log.info(irq)
assert irq.tdata[0] == k
assert tb.irq_sink.empty()
await Timer(110, 'us')
assert tb.irq_sink.empty()
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_irq
]:
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())
def test_taxi_irq_rate_limit(request):
dut = "taxi_irq_rate_limit"
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(taxi_src_dir, "axis", "rtl", "taxi_axis_if.sv"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['IRQN_W'] = 11
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* IRQ rate limit module testbench
*/
module test_taxi_irq_rate_limit #
(
/* verilator lint_off WIDTHTRUNC */
parameter IRQN_W = 11
/* verilator lint_on WIDTHTRUNC */
)
();
logic clk;
logic rst;
taxi_axis_if #(
.DATA_W(IRQN_W),
.KEEP_EN(0),
.KEEP_W(1)
) s_axis_irq(), m_axis_irq();
logic [15:0] prescale;
logic [15:0] min_interval;
taxi_irq_rate_limit
uut (
.clk(clk),
.rst(rst),
/*
* Interrupt request input
*/
.s_axis_irq(s_axis_irq),
/*
* Interrupt request output
*/
.m_axis_irq(m_axis_irq),
/*
* Configuration
*/
.prescale(prescale),
.min_interval(min_interval)
);
endmodule
`resetall

View File

@@ -128,17 +128,17 @@ if (PIPELINE_OUTPUT > 0) begin
// pipeline
(* shreg_extract = "no" *)
logic [95:0] output_ts_tod_reg[0:PIPELINE_OUTPUT-1];
logic [95:0] output_ts_tod_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_ts_tod_step_reg[0:PIPELINE_OUTPUT-1];
logic output_ts_tod_step_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic [63:0] output_ts_rel_reg[0:PIPELINE_OUTPUT-1];
logic [63:0] output_ts_rel_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_ts_rel_step_reg[0:PIPELINE_OUTPUT-1];
logic output_ts_rel_step_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_pps_reg[0:PIPELINE_OUTPUT-1];
logic output_pps_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_pps_str_reg[0:PIPELINE_OUTPUT-1];
logic output_pps_str_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
assign output_ts_tod = output_ts_tod_reg[PIPELINE_OUTPUT-1];
assign output_ts_tod_step = output_ts_tod_step_reg[PIPELINE_OUTPUT-1];
@@ -149,19 +149,6 @@ if (PIPELINE_OUTPUT > 0) begin
assign output_pps = output_pps_reg[PIPELINE_OUTPUT-1];
assign output_pps_str = output_pps_str_reg[PIPELINE_OUTPUT-1];
initial begin
for (integer i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
output_ts_tod_reg[i] = '0;
output_ts_tod_step_reg[i] = 1'b0;
output_ts_rel_reg[i] = '0;
output_ts_rel_step_reg[i] = 1'b0;
output_pps_reg[i] = 1'b0;
output_pps_str_reg[i] = 1'b0;
end
end
always_ff @(posedge clk) begin
output_ts_tod_reg[0][95:48] <= ts_tod_s_reg;
output_ts_tod_reg[0][47:46] <= 2'b00;

View File

@@ -106,10 +106,10 @@ logic ts_step_reg = 1'b0, ts_step_next;
logic pps_reg = 1'b0;
logic pps_str_reg = 1'b0;
logic [47:0] ts_s_pipe_reg[0:PIPELINE_OUTPUT-1];
logic [TS_NS_W+CMP_FNS_W-1:0] ts_ns_pipe_reg[0:PIPELINE_OUTPUT-1];
logic ts_step_pipe_reg[0:PIPELINE_OUTPUT-1];
logic pps_pipe_reg[0:PIPELINE_OUTPUT-1];
logic [47:0] ts_s_pipe_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
logic [TS_NS_W+CMP_FNS_W-1:0] ts_ns_pipe_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
logic ts_step_pipe_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
logic pps_pipe_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
logic [PHASE_CNT_W-1:0] src_phase_reg = '0;
logic [PHASE_ACC_W-1:0] dest_phase_reg = '0, dest_phase_next;
@@ -151,28 +151,19 @@ if (PIPELINE_OUTPUT > 0) begin
// pipeline
(* shreg_extract = "no" *)
logic [TS_W-1:0] output_ts_reg[0:PIPELINE_OUTPUT-1];
logic [TS_W-1:0] output_ts_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_ts_step_reg[0:PIPELINE_OUTPUT-1];
logic output_ts_step_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_pps_reg[0:PIPELINE_OUTPUT-1];
logic output_pps_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
(* shreg_extract = "no" *)
logic output_pps_str_reg[0:PIPELINE_OUTPUT-1];
logic output_pps_str_reg[0:PIPELINE_OUTPUT-1] = '{default: '0};
assign output_ts = output_ts_reg[PIPELINE_OUTPUT-1];
assign output_ts_step = output_ts_step_reg[PIPELINE_OUTPUT-1];
assign output_pps = output_pps_reg[PIPELINE_OUTPUT-1];
assign output_pps_str = output_pps_str_reg[PIPELINE_OUTPUT-1];
initial begin
for (integer i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
output_ts_reg[i] = 0;
output_ts_step_reg[i] = 1'b0;
output_pps_reg[i] = 1'b0;
output_pps_str_reg[i] = 1'b0;
end
end
always_ff @(posedge output_clk) begin
if (TS_W == 96) begin
output_ts_reg[0][95:48] <= ts_s_reg;
@@ -220,15 +211,6 @@ end else begin
end
initial begin
for (integer i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
ts_s_pipe_reg[i] = 0;
ts_ns_pipe_reg[i] = 0;
ts_step_pipe_reg[i] = 1'b0;
pps_pipe_reg[i] = 1'b0;
end
end
// source PTP clock capture and sync logic
logic input_ts_step_reg = 1'b0;

View File

@@ -122,7 +122,7 @@ wire [ACC_W-1:0] acc_int[CNT];
logic [CNT-1:0] acc_clear;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [STAT_INC_W-1:0] mem_reg[CNT];
logic [STAT_INC_W-1:0] mem_reg[CNT] = '{default: '0};
logic [STAT_INC_W-1:0] mem_rd_data_reg = '0;

View File

@@ -64,9 +64,9 @@ logic stage_active;
logic [PIPELINE-1:0] op_axil_read_pipe_reg = 0, op_axil_read_pipe_next;
logic [PIPELINE-1:0] op_acc_pipe_reg = 0, op_acc_pipe_next;
logic [STAT_ID_W-1:0] mem_addr_pipeline_reg[PIPELINE], mem_addr_pipeline_next[PIPELINE];
logic [WORD_SELECT_W-1:0] axil_shift_pipeline_reg[PIPELINE], axil_shift_pipeline_next[PIPELINE];
logic [STAT_INC_W-1:0] stat_inc_pipeline_reg[PIPELINE], stat_inc_pipeline_next[PIPELINE];
logic [STAT_ID_W-1:0] mem_addr_pipeline_reg[PIPELINE] = '{default: '0}, mem_addr_pipeline_next[PIPELINE];
logic [WORD_SELECT_W-1:0] axil_shift_pipeline_reg[PIPELINE] = '{default: '0}, axil_shift_pipeline_next[PIPELINE];
logic [STAT_INC_W-1:0] stat_inc_pipeline_reg[PIPELINE] = '{default: '0}, stat_inc_pipeline_next[PIPELINE];
logic s_axis_stat_tready_reg = 1'b0, s_axis_stat_tready_next;
@@ -78,14 +78,14 @@ logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = 0, s_axil_rdata_next;
logic s_axil_rvalid_reg = 0, s_axil_rvalid_next;
(* ramstyle = "no_rw_check" *)
logic [STAT_COUNT_W-1:0] mem[2**STAT_ID_W];
logic [STAT_COUNT_W-1:0] mem[2**STAT_ID_W] = '{default: '0};
logic [STAT_ID_W-1:0] mem_rd_addr;
logic [STAT_ID_W-1:0] mem_wr_addr;
logic [STAT_COUNT_W-1:0] mem_wr_data;
logic mem_wr_en;
logic [STAT_COUNT_W-1:0] mem_read_data_reg = 0;
logic [STAT_COUNT_W-1:0] mem_read_data_pipeline_reg[PIPELINE-1:1];
logic [STAT_COUNT_W-1:0] mem_read_data_pipeline_reg[PIPELINE-1:1] = '{default: '0};
assign s_axis_stat.tready = s_axis_stat_tready_reg;
@@ -102,21 +102,6 @@ assign s_axil_rd.rvalid = s_axil_rvalid_reg;
wire [STAT_ID_W-1:0] s_axil_araddr_id = STAT_ID_W'(s_axil_rd.araddr >> ID_SHIFT);
wire [WORD_SELECT_W-1:0] s_axil_araddr_shift = WORD_SELECT_W'(s_axil_rd.araddr >> WORD_SELECT_SHIFT);
initial begin
// break up loop to work around iteration termination
for (integer i = 0; i < 2**STAT_ID_W; i = i + 2**(STAT_ID_W/2)) begin
for (integer j = i; j < i + 2**(STAT_ID_W/2); j = j + 1) begin
mem[j] = 0;
end
end
for (integer i = 0; i < PIPELINE; i = i + 1) begin
mem_addr_pipeline_reg[i] = 0;
axil_shift_pipeline_reg[i] = 0;
stat_inc_pipeline_reg[i] = 0;
end
end
always_comb begin
init_next = init_reg;
init_ptr_next = init_ptr_reg;

View File

@@ -61,8 +61,8 @@ logic stage_active;
logic [PIPELINE-1:0] op_axil_read_pipe_reg = 0, op_axil_read_pipe_next;
logic [STAT_ID_W-1:0] mem_addr_pipeline_reg[PIPELINE], mem_addr_pipeline_next[PIPELINE];
logic [WORD_SELECT_W-1:0] axil_shift_pipeline_reg[PIPELINE], axil_shift_pipeline_next[PIPELINE];
logic [STAT_ID_W-1:0] mem_addr_pipeline_reg[PIPELINE] = '{default: '0}, mem_addr_pipeline_next[PIPELINE];
logic [WORD_SELECT_W-1:0] axil_shift_pipeline_reg[PIPELINE] = '{default: '0}, axil_shift_pipeline_next[PIPELINE];
logic s_axil_awready_reg = 0, s_axil_awready_next;
logic s_axil_wready_reg = 0, s_axil_wready_next;
@@ -72,7 +72,7 @@ logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = 0, s_axil_rdata_next;
logic s_axil_rvalid_reg = 0, s_axil_rvalid_next;
(* ramstyle = "no_rw_check" *)
logic [127:0] mem[2**STAT_ID_W];
logic [127:0] mem[2**STAT_ID_W] = '{default: '0};
logic [STAT_ID_W-1:0] mem_rd_addr;
logic [STAT_ID_W-1:0] mem_wr_addr;
@@ -95,20 +95,6 @@ assign s_axil_rd.rvalid = s_axil_rvalid_reg;
wire [STAT_ID_W-1:0] s_axil_araddr_id = STAT_ID_W'(s_axil_rd.araddr >> ID_SHIFT);
wire [WORD_SELECT_W-1:0] s_axil_araddr_shift = WORD_SELECT_W'(s_axil_rd.araddr >> WORD_SELECT_SHIFT);
initial begin
// break up loop to work around iteration termination
for (integer i = 0; i < 2**STAT_ID_W; i = i + 2**(STAT_ID_W/2)) begin
for (integer j = i; j < i + 2**(STAT_ID_W/2); j = j + 1) begin
mem[j] = 0;
end
end
for (integer i = 0; i < PIPELINE; i = i + 1) begin
mem_addr_pipeline_reg[i] = 0;
axil_shift_pipeline_reg[i] = 0;
end
end
always_comb begin
init_next = init_reg;
init_ptr_next = init_ptr_reg;