mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-09 05:18:44 -07:00
Compare commits
23 Commits
ce8da1bc59
...
50ba1d4c89
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50ba1d4c89 | ||
|
|
8773672f26 | ||
|
|
9af793edc6 | ||
|
|
2bb2710bbd | ||
|
|
86b9947794 | ||
|
|
9ec5bd0190 | ||
|
|
3ac7484e16 | ||
|
|
bb278958b2 | ||
|
|
4b7ca2a569 | ||
|
|
9d701c9186 | ||
|
|
f9a5d08365 | ||
|
|
a59a4dfd84 | ||
|
|
438c082f73 | ||
|
|
283ef97cec | ||
|
|
e2823a65ef | ||
|
|
dde401e095 | ||
|
|
09f1b278e8 | ||
|
|
2e8f9f8731 | ||
|
|
4a2b9dd10c | ||
|
|
798756ac89 | ||
|
|
41b87dc65c | ||
|
|
f464a21e1d | ||
|
|
96630b8f61 |
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
23
src/cndm/rtl/cndm_lite_core.f
Normal file
23
src/cndm/rtl/cndm_lite_core.f
Normal 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
|
||||
638
src/cndm/rtl/cndm_lite_core.sv
Normal file
638
src/cndm/rtl/cndm_lite_core.sv
Normal 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
|
||||
6
src/cndm/rtl/cndm_lite_pcie_us.f
Normal file
6
src/cndm/rtl/cndm_lite_pcie_us.f
Normal 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
|
||||
605
src/cndm/rtl/cndm_lite_pcie_us.sv
Normal file
605
src/cndm/rtl/cndm_lite_pcie_us.sv
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
77
src/cndm/tb/cndm_lite_pcie_us/Makefile
Normal file
77
src/cndm/tb/cndm_lite_pcie_us/Makefile
Normal 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
|
||||
1
src/cndm/tb/cndm_lite_pcie_us/cndm.py
Symbolic link
1
src/cndm/tb/cndm_lite_pcie_us/cndm.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../cndm.py
|
||||
522
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py
Normal file
522
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py
Normal 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,
|
||||
)
|
||||
321
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv
Normal file
321
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 +278,17 @@ class TB:
|
||||
# Ethernet
|
||||
self.port_mac = []
|
||||
|
||||
eth_clock_period = 3.2
|
||||
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)):
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
253
src/pcie/rtl/taxi_irq_rate_limit.sv
Normal file
253
src/pcie/rtl/taxi_irq_rate_limit.sv
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
51
src/pcie/tb/taxi_irq_rate_limit/Makefile
Normal file
51
src/pcie/tb/taxi_irq_rate_limit/Makefile
Normal 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
|
||||
193
src/pcie/tb/taxi_irq_rate_limit/test_taxi_irq_rate_limit.py
Normal file
193
src/pcie/tb/taxi_irq_rate_limit/test_taxi_irq_rate_limit.py
Normal 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,
|
||||
)
|
||||
62
src/pcie/tb/taxi_irq_rate_limit/test_taxi_irq_rate_limit.sv
Normal file
62
src/pcie/tb/taxi_irq_rate_limit/test_taxi_irq_rate_limit.sv
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user