From 2e8f9f8731b9a7bfb5021ba2915c9a3ba4403368 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 6 Mar 2026 21:07:25 -0800 Subject: [PATCH] cndm: Copy cndm-micro core logic as cndm-lite Signed-off-by: Alex Forencich --- src/cndm/rtl/cndm_lite_core.f | 22 + src/cndm/rtl/cndm_lite_core.sv | 563 +++++++++++++++++ src/cndm/rtl/cndm_lite_pcie_us.f | 6 + src/cndm/rtl/cndm_lite_pcie_us.sv | 580 ++++++++++++++++++ src/cndm/tb/cndm_lite_pcie_us/Makefile | 71 +++ src/cndm/tb/cndm_lite_pcie_us/cndm.py | 1 + .../test_cndm_lite_pcie_us.py | 516 ++++++++++++++++ .../test_cndm_lite_pcie_us.sv | 309 ++++++++++ 8 files changed, 2068 insertions(+) create mode 100644 src/cndm/rtl/cndm_lite_core.f create mode 100644 src/cndm/rtl/cndm_lite_core.sv create mode 100644 src/cndm/rtl/cndm_lite_pcie_us.f create mode 100644 src/cndm/rtl/cndm_lite_pcie_us.sv create mode 100644 src/cndm/tb/cndm_lite_pcie_us/Makefile create mode 120000 src/cndm/tb/cndm_lite_pcie_us/cndm.py create mode 100644 src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py create mode 100644 src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv diff --git a/src/cndm/rtl/cndm_lite_core.f b/src/cndm/rtl/cndm_lite_core.f new file mode 100644 index 0000000..c41d976 --- /dev/null +++ b/src/cndm/rtl/cndm_lite_core.f @@ -0,0 +1,22 @@ +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 diff --git a/src/cndm/rtl/cndm_lite_core.sv b/src/cndm/rtl/cndm_lite_core.sv new file mode 100644 index 0000000..71e8345 --- /dev/null +++ b/src/cndm/rtl/cndm_lite_core.sv @@ -0,0 +1,563 @@ +// 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, + + // 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 +) +( + 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, + + output wire logic [PORTS-1:0] 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; + +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'h0100: s_axil_rdata_reg <= PORTS; // port count + 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 #( + .PORTS(PORTS), + + .WQN_W(WQN_W), + .CQN_W(CQN_W), + + .PTP_EN(PTP_TS_EN), + .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_DENOM) + ) + 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) +); + +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]), + + .irq(irq[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 diff --git a/src/cndm/rtl/cndm_lite_pcie_us.f b/src/cndm/rtl/cndm_lite_pcie_us.f new file mode 100644 index 0000000..0075f39 --- /dev/null +++ b/src/cndm/rtl/cndm_lite_pcie_us.f @@ -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 diff --git a/src/cndm/rtl/cndm_lite_pcie_us.sv b/src/cndm/rtl/cndm_lite_pcie_us.sv new file mode 100644 index 0000000..a15ccf8 --- /dev/null +++ b/src/cndm/rtl/cndm_lite_pcie_us.sv @@ -0,0 +1,580 @@ +// 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, + + // Queue configuration + parameter CQN_W = 5, + + // 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, + + // 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) +); + +wire [PORTS-1:0] irq; +wire [31:0] msi_irq = 32'(irq); + +taxi_pcie_us_msi #( + .MSI_CNT(32) +) +msi_inst ( + .clk(pcie_clk), + .rst(pcie_rst), + + /* + * Interrupt request inputs + */ + .msi_irq(msi_irq), + + /* + * 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), + + // 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_DENOM(PTP_CLK_PER_NS_DENOM) +) +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), + + .irq(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 diff --git a/src/cndm/tb/cndm_lite_pcie_us/Makefile b/src/cndm/tb/cndm_lite_pcie_us/Makefile new file mode 100644 index 0000000..cc1fa73 --- /dev/null +++ b/src/cndm/tb/cndm_lite_pcie_us/Makefile @@ -0,0 +1,71 @@ +# 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 + +# 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 + +# 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 diff --git a/src/cndm/tb/cndm_lite_pcie_us/cndm.py b/src/cndm/tb/cndm_lite_pcie_us/cndm.py new file mode 120000 index 0000000..cfb5ba9 --- /dev/null +++ b/src/cndm/tb/cndm_lite_pcie_us/cndm.py @@ -0,0 +1 @@ +../cndm.py \ No newline at end of file diff --git a/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py b/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py new file mode 100644 index 0000000..ca64418 --- /dev/null +++ b/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py @@ -0,0 +1,516 @@ +#!/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 + + # 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 + + # 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, + ) diff --git a/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv b/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv new file mode 100644 index 0000000..1f77b50 --- /dev/null +++ b/src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv @@ -0,0 +1,309 @@ +// 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, + + // 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, + + // 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), + + // 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), + + // 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