Files
taxi/src/pyrite/rtl/pyrite_pcie_us_vpd_bpi.sv
Alex Forencich c37b4cbbfa pyrite: Cast widths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 22:14:20 -08:00

287 lines
9.3 KiB
Systemverilog

// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Pyrite flashing support for UltraScale+ PCIe VPD and BPI flash
*/
module pyrite_pcie_us_vpd_bpi #
(
parameter logic [7:0] VPD_CAP_ID = 8'h03,
parameter logic [7:0] VPD_CAP_OFFSET = 8'hB0,
parameter logic [7:0] VPD_CAP_NEXT = 8'h00,
// FW ID
parameter FPGA_ID = 32'hDEADBEEF,
parameter FW_ID = 32'h00000000,
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,
// Flash
parameter logic [3:0] FLASH_SEG_COUNT = 2,
parameter logic [3:0] FLASH_SEG_DEFAULT = 1,
parameter logic [3:0] FLASH_SEG_FALLBACK = 0,
parameter logic [31:0] FLASH_SEG0_SIZE = 32'h00000000,
parameter FLASH_ADDR_W = 16,
parameter FLASH_DATA_W = 23,
parameter FLASH_RGN_W = 1
)
(
input wire logic clk,
input wire logic rst,
/*
* PCIe
*/
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,
/*
* BPI flash
*/
output wire logic fpga_boot,
input wire logic [FLASH_DATA_W-1:0] flash_dq_i,
output wire logic [FLASH_DATA_W-1:0] flash_dq_o,
output wire logic flash_dq_oe,
output wire logic [FLASH_ADDR_W-1:0] flash_addr,
output wire logic [FLASH_RGN_W-1:0] flash_region,
output wire logic flash_region_oe,
output wire logic flash_ce_n,
output wire logic flash_oe_n,
output wire logic flash_we_n,
output wire logic flash_adv_n
);
taxi_apb_if #(
.DATA_W(32),
.ADDR_W(15)
) vpd_apb();
taxi_pcie_us_vpd #(
.CAP_ID(VPD_CAP_ID),
.CAP_OFFSET(VPD_CAP_OFFSET),
.CAP_NEXT(VPD_CAP_NEXT)
)
vpd_cap_inst (
.clk(clk),
.rst(rst),
/*
* APB interface for VPD address space
*/
.m_apb(vpd_apb),
/*
* Interface to Ultrascale PCIe IP core
*/
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid)
);
taxi_apb_if #(
.DATA_W(32),
.ADDR_W(14)
) vpd_apb_int[2]();
taxi_apb_interconnect #(
.M_CNT(2),
.ADDR_W(15),
.M_REGIONS(1),
.M_BASE_ADDR('0),
.M_ADDR_W({2{{1{{32'd14}}}}}),
.M_SECURE({2{1'b0}})
)
vpd_apb_intercon (
.clk(clk),
.rst(rst),
/*
* APB slave interface
*/
.s_apb(vpd_apb),
/*
* APB master interface
*/
.m_apb(vpd_apb_int)
);
taxi_apb_ram #(
.ADDR_W(11),
.PIPELINE_OUTPUT(1)
)
vpd_ram_inst (
.clk(clk),
.rst(rst),
/*
* AXI4-Lite slave interface
*/
.s_apb(vpd_apb_int[0])
);
logic vpd_apb_pready_reg = 1'b0;
logic [31:0] vpd_apb_prdata_reg = '0;
logic fpga_boot_reg = 1'b0;
logic [FLASH_DATA_W-1:0] flash_dq_o_reg = '0;
logic flash_dq_oe_reg = 1'b0;
logic [FLASH_ADDR_W-1:0] flash_addr_reg = '0;
logic [FLASH_RGN_W-1:0] flash_region_reg = '0;
logic flash_region_oe_reg = 1'b0;
logic flash_ce_n_reg = 1'b1;
logic flash_oe_n_reg = 1'b1;
logic flash_we_n_reg = 1'b1;
logic flash_adv_n_reg = 1'b1;
assign vpd_apb_int[1].pready = vpd_apb_pready_reg;
assign vpd_apb_int[1].prdata = vpd_apb_prdata_reg;
assign vpd_apb_int[1].pslverr = 1'b0;
assign vpd_apb_int[1].pruser = '0;
assign vpd_apb_int[1].pbuser = '0;
assign fpga_boot = fpga_boot_reg;
assign flash_dq_o = flash_dq_o_reg;
assign flash_dq_oe = flash_dq_oe_reg;
assign flash_addr = flash_addr_reg;
assign flash_region = flash_region_reg;
assign flash_region_oe = flash_region_oe_reg;
assign flash_ce_n = flash_ce_n_reg;
assign flash_oe_n = flash_oe_n_reg;
assign flash_we_n = flash_we_n_reg;
assign flash_adv_n = flash_adv_n_reg;
always_ff @(posedge clk) begin
vpd_apb_pready_reg <= 1'b0;
if (vpd_apb_int[1].penable && vpd_apb_int[1].psel && !vpd_apb_pready_reg) begin
vpd_apb_pready_reg <= 1'b1;
vpd_apb_prdata_reg <= '0;
if (vpd_apb_int[1].pwrite) begin
case (8'({vpd_apb_int[1].paddr >> 2, 2'b00}))
// FW ID
8'h0C: begin
// FW ID: FPGA JTAG ID
fpga_boot_reg <= vpd_apb_int[1].pwdata == 32'hFEE1DEAD;
end
// BPI flash
8'h4C: begin
// BPI flash ctrl: format
fpga_boot_reg <= vpd_apb_int[1].pwdata == 32'hFEE1DEAD;
end
8'h50: begin
// BPI flash ctrl: control
if (vpd_apb_int[1].pstrb[0]) begin
flash_ce_n_reg <= vpd_apb_int[1].pwdata[0];
flash_oe_n_reg <= vpd_apb_int[1].pwdata[1];
flash_we_n_reg <= vpd_apb_int[1].pwdata[2];
flash_adv_n_reg <= vpd_apb_int[1].pwdata[3];
end
if (vpd_apb_int[1].pstrb[1]) begin
flash_dq_oe_reg <= vpd_apb_int[1].pwdata[8];
end
if (vpd_apb_int[1].pstrb[2]) begin
flash_region_oe_reg <= vpd_apb_int[1].pwdata[16];
end
end
8'h54: begin
// BPI flash ctrl: address
{flash_region_reg, flash_addr_reg} <= vpd_apb_int[1].pwdata;
end
8'h58: flash_dq_o_reg <= vpd_apb_int[1].pwdata; // BPI flash ctrl: data
default: begin end
endcase
end
case (8'({vpd_apb_int[1].paddr >> 2, 2'b00}))
// FW ID
8'h00: vpd_apb_prdata_reg <= 32'hffffffff; // FW ID: Type
8'h04: vpd_apb_prdata_reg <= 32'h000_01_000; // FW ID: Version
8'h08: vpd_apb_prdata_reg <= 32'h40; // FW ID: Next header
8'h0C: vpd_apb_prdata_reg <= FPGA_ID; // FW ID: FPGA JTAG ID
8'h10: vpd_apb_prdata_reg <= FW_ID; // FW ID: Firmware ID
8'h14: vpd_apb_prdata_reg <= FW_VER; // FW ID: Firmware version
8'h18: vpd_apb_prdata_reg <= BOARD_ID; // FW ID: Board ID
8'h1C: vpd_apb_prdata_reg <= BOARD_VER; // FW ID: Board version
8'h20: vpd_apb_prdata_reg <= BUILD_DATE; // FW ID: Build date
8'h24: vpd_apb_prdata_reg <= GIT_HASH; // FW ID: Git commit hash
8'h28: vpd_apb_prdata_reg <= RELEASE_INFO; // FW ID: Release info
// BPI flash
8'h40: vpd_apb_prdata_reg <= 32'h0000C121; // BPI flash ctrl: Type
8'h44: vpd_apb_prdata_reg <= 32'h000_01_000; // BPI flash ctrl: Version
8'h48: vpd_apb_prdata_reg <= 0; // BPI flash ctrl: Next header
8'h4C: begin
// BPI flash ctrl: format
vpd_apb_prdata_reg[3:0] <= FLASH_SEG_COUNT; // configuration
vpd_apb_prdata_reg[7:4] <= FLASH_SEG_DEFAULT; // default segment
vpd_apb_prdata_reg[11:8] <= FLASH_SEG_FALLBACK; // fallback segment
vpd_apb_prdata_reg[31:12] <= 20'(FLASH_SEG0_SIZE >> 12); // first segment size
end
8'h50: begin
// BPI flash ctrl: control
vpd_apb_prdata_reg[0] <= flash_ce_n_reg; // chip enable (inverted)
vpd_apb_prdata_reg[1] <= flash_oe_n_reg; // output enable (inverted)
vpd_apb_prdata_reg[2] <= flash_we_n_reg; // write enable (inverted)
vpd_apb_prdata_reg[3] <= flash_adv_n_reg; // address valid (inverted)
vpd_apb_prdata_reg[8] <= flash_dq_oe_reg; // data output enable
vpd_apb_prdata_reg[16] <= flash_region_oe_reg; // region output enable (addr bit 25)
end
8'h54: begin
// BPI flash ctrl: address
vpd_apb_prdata_reg <= {flash_region_reg, flash_addr_reg};
end
8'h58: vpd_apb_prdata_reg <= flash_dq_i; // BPI flash ctrl: data
default: begin end
endcase
end
if (rst) begin
vpd_apb_pready_reg <= 1'b0;
fpga_boot_reg <= 1'b0;
flash_dq_o_reg <= '0;
flash_dq_oe_reg <= 1'b0;
flash_addr_reg <= '0;
flash_region_reg <= '0;
flash_region_oe_reg <= 1'b0;
flash_ce_n_reg <= 1'b1;
flash_oe_n_reg <= 1'b1;
flash_we_n_reg <= 1'b1;
flash_adv_n_reg <= 1'b1;
end
end
endmodule
`resetall