From 5d3aff95cc3fcee00d484fbc80c05d812b4db8f1 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 24 Feb 2026 12:20:02 -0800 Subject: [PATCH] pcie: Add VSEC AXIL register access extended capability implementation for UltraScale Signed-off-by: Alex Forencich --- src/pcie/rtl/taxi_pcie_us_vsec_axil.sv | 186 +++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/pcie/rtl/taxi_pcie_us_vsec_axil.sv diff --git a/src/pcie/rtl/taxi_pcie_us_vsec_axil.sv b/src/pcie/rtl/taxi_pcie_us_vsec_axil.sv new file mode 100644 index 0000000..6b852ee --- /dev/null +++ b/src/pcie/rtl/taxi_pcie_us_vsec_axil.sv @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * UltraScale PCIe vendor-specific capability for register access via AXI lite + */ +module taxi_pcie_us_vsec_apb # +( + parameter logic [15:0] EXT_CAP_ID = 16'h000B, + parameter logic [3:0] EXT_CAP_VERSION = 4'h1, + parameter logic [11:0] EXT_CAP_OFFSET = 12'h480, + parameter logic [11:0] EXT_CAP_NEXT = 12'h000, + parameter logic [15:0] EXT_CAP_VSEC_ID = 16'h00FF, + parameter logic [3:0] EXT_CAP_VSEC_REV = 4'h1, + parameter logic [11:0] EXT_CAP_VSEC_LEN = 12'h0010 +) +( + input wire logic clk, + input wire logic rst, + + /* + * AXI lite interface for register space + */ + taxi_axil_if.wr_mst m_axil_wr, + taxi_axil_if.rd_mst m_axil_rd, + + /* + * Interface to Ultrascale PCIe IP core + */ + input wire logic cfg_ext_read_received, + input wire logic cfg_ext_write_received, + input wire logic [9:0] cfg_ext_register_number, + input wire logic [7:0] cfg_ext_function_number, + input wire logic [31:0] cfg_ext_write_data, + input wire logic [3:0] cfg_ext_write_byte_enable, + output wire logic [31:0] cfg_ext_read_data, + output wire logic cfg_ext_read_data_valid +); + +localparam ADDR_W = m_axil_wr.ADDR_W; +localparam DATA_W = m_axil_wr.DATA_W; +localparam STRB_W = m_axil_wr.STRB_W; + +// check configuration +if (DATA_W > 32) + $fatal(0, "Error: Data width must be 32 or less (instance %m)"); + +if (STRB_W * 8 != DATA_W) + $fatal(0, "Error: Interface requires byte (8-bit) granularity (instance %m)"); + +if (m_axil_rd.ADDR_W != ADDR_W || m_axil_rd.DATA_W != DATA_W) + $fatal(0, "Error: Interface configuration mismatch (instance %m)"); + +logic [31:0] cfg_ext_read_data_reg = '0, cfg_ext_read_data_next; +logic cfg_ext_read_data_valid_reg = 1'b0, cfg_ext_read_data_valid_next; + +logic flag_reg = 1'b0, flag_next; +logic [ADDR_W-1:0] addr_reg = '0, addr_next; +logic [DATA_W-1:0] data_reg = '0, data_next; +logic [STRB_W-1:0] strb_reg = '0, strb_next; + +logic m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next; +logic m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next; +logic m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next; + +assign m_axil_wr.awaddr = addr_reg; +assign m_axil_wr.awprot = 3'b010; +assign m_axil_wr.awuser = '0; +assign m_axil_wr.awvalid = m_axil_awvalid_reg; +assign m_axil_wr.wdata = data_reg; +assign m_axil_wr.wstrb = strb_reg; +assign m_axil_wr.wuser = '0; +assign m_axil_wr.wvalid = m_axil_wvalid_reg; +assign m_axil_wr.bready = 1'b1; +assign m_axil_rd.araddr = addr_reg; +assign m_axil_rd.arprot = 3'b010; +assign m_axil_wr.aruser = '0; +assign m_axil_rd.arvalid = m_axil_arvalid_reg; +assign m_axil_rd.rready = 1'b1; + +assign cfg_ext_read_data = cfg_ext_read_data_reg; +assign cfg_ext_read_data_valid = cfg_ext_read_data_valid_reg; + +always_comb begin + cfg_ext_read_data_next = '0; + cfg_ext_read_data_valid_next = 1'b0; + + flag_next = flag_reg; + addr_next = addr_reg; + data_next = data_reg; + strb_next = strb_reg; + + m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_wr.awready; + m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wr.wready; + m_axil_arvalid_next = m_axil_arvalid_reg&& !m_axil_rd.arready; + + if (m_axil_rd.rvalid) begin + // read complete + flag_next = 1'b1; + data_next = m_axil_rd.rdata; + end + + if (m_axil_wr.bvalid) begin + // write complete + flag_next = 1'b0; + end + + if (cfg_ext_read_received) begin + if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+0) begin + cfg_ext_read_data_next[15:0] = EXT_CAP_ID; + cfg_ext_read_data_next[19:16] = EXT_CAP_VERSION; + cfg_ext_read_data_next[31:20] = EXT_CAP_NEXT; + cfg_ext_read_data_valid_next = 1'b1; + end else if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+1) begin + cfg_ext_read_data_next[15:0] = EXT_CAP_VSEC_ID; + cfg_ext_read_data_next[19:16] = EXT_CAP_VSEC_REV; + cfg_ext_read_data_next[31:20] = EXT_CAP_VSEC_LEN; + cfg_ext_read_data_valid_next = 1'b1; + end else if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+2) begin + cfg_ext_read_data_next[30:0] = 31'(addr_reg); + cfg_ext_read_data_next[31] = flag_reg; + cfg_ext_read_data_valid_next = 1'b1; + end else if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+3) begin + cfg_ext_read_data_next = 32'(data_reg); + cfg_ext_read_data_valid_next = 1'b1; + end + end + + if (cfg_ext_write_received && !(m_axil_awvalid_reg || m_axil_wvalid_reg || m_axil_arvalid_reg)) begin + if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+2) begin + addr_next = ADDR_W'(cfg_ext_write_data[30:0]); + flag_next = cfg_ext_write_data[31]; + + if (cfg_ext_write_data[31]) begin + // write + m_axil_awvalid_next = 1'b1; + m_axil_wvalid_next = 1'b1; + end else begin + // read + m_axil_arvalid_next = 1'b1; + end + end else if (cfg_ext_register_number == 10'(EXT_CAP_OFFSET >> 2)+3) begin + data_next = DATA_W'(cfg_ext_write_data); + strb_next = STRB_W'(cfg_ext_write_byte_enable); + end + end +end + +always_ff @(posedge clk) begin + cfg_ext_read_data_reg <= cfg_ext_read_data_next; + cfg_ext_read_data_valid_reg <= cfg_ext_read_data_valid_next; + + flag_reg <= flag_next; + addr_reg <= addr_next; + data_reg <= data_next; + strb_reg <= strb_next; + + m_axil_awvalid_reg <= m_axil_awvalid_next; + m_axil_wvalid_reg <= m_axil_wvalid_next; + m_axil_arvalid_reg <= m_axil_arvalid_next; + + if (rst) begin + cfg_ext_read_data_valid_reg <= 1'b0; + flag_reg <= 1'b0; + addr_reg <= '0; + data_reg <= '0; + m_axil_awvalid_reg <= 1'b0; + m_axil_wvalid_reg <= 1'b0; + m_axil_arvalid_reg <= 1'b0; + end +end + +endmodule + +`resetall