mirror of
https://github.com/fpganinja/taxi.git
synced 2026-02-28 05:55:09 -08:00
pcie: Add VSEC AXIL register access extended capability implementation for UltraScale
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
186
src/pcie/rtl/taxi_pcie_us_vsec_axil.sv
Normal file
186
src/pcie/rtl/taxi_pcie_us_vsec_axil.sv
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user