Commit 550f71d3 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

rtl/bootloader: support for physically separate SYS and APP FPGA flashes

parent 98ba5e3b
......@@ -50,7 +50,8 @@ entity sfpga_bootloader is
generic(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD;
g_idr_value : std_logic_vector(31 downto 0) := x"626f6f74"
g_idr_value : std_logic_vector(31 downto 0) := x"626f6f74";
g_target_board : string
);
port (
-- system clock
......@@ -97,11 +98,16 @@ entity sfpga_bootloader is
-- ignored.
boot_en_i : in std_logic;
-- Bitstream flash interface (SPI)
spi_cs_n_o : out std_logic;
spi_sclk_o : out std_logic;
spi_mosi_o : out std_logic;
spi_miso_i : in std_logic
-- Bitstream flash interface (SPI, App/Sys FPGA on SVEC, Sys on SVEC7)
spi_sys_cs_n_o : out std_logic;
spi_sys_sclk_o : out std_logic;
spi_sys_mosi_o : out std_logic;
spi_sys_miso_i : in std_logic;
-- Bitstream flash interface (SPI, App on SVEC7 only)
spi_app_cs_n_o : out std_logic;
spi_app_sclk_o : out std_logic;
spi_app_mosi_o : out std_logic;
spi_app_miso_i : in std_logic
);
end sfpga_bootloader;
......@@ -214,6 +220,9 @@ architecture behavioral of sfpga_bootloader is
signal flash_enable : std_logic;
signal flash_no_bitstream_p1 : std_logic;
signal spi0_start_host, spi1_start_host : std_logic;
signal spi0_wdata_host, spi1_wdata_host : std_logic_vector(7 downto 0);
-- Trivial helper for boot sequence detection. Advances the state machine if
-- a matching byte has been detected or goes back to the starting point.
procedure f_bootseq_step(signal st : out t_bootseq_state; nstate : t_bootseq_state; match_val : std_logic_vector; regs : t_sxldr_out_registers) is
......@@ -232,6 +241,9 @@ begin -- behavioral
-- Selects the boot source: upon reset, we try to boot up from flash.
-- Host bootloader is activated by writing a magic trigger sequence.
gen_svec_only: if g_target_board = "SVEC" generate
p_select_boot_mode : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
......@@ -243,10 +255,44 @@ begin -- behavioral
end if;
end process;
boot_trig_p1_o <= boot_trig_p1_int or flash_no_bitstream_p1;
end generate gen_svec_only;
gen_svec7_only: if g_target_board = "SVEC7" generate
boot_source <= HOST;
to_xilinx_boot <= from_host_ldr;
to_host_ldr <= from_xilinx_boot;
boot_trig_p1_o <= boot_trig_p1_int;
end generate gen_svec7_only;
-- Route host registers to the boot source multiplexer (p_select_boot_source).
from_host_ldr.start <= regs_in.csr_start_o and boot_en_i;
from_host_ldr.data <= regs_in.fifo_xdata_o;
from_host_ldr.dsize <= regs_in.fifo_xsize_o;
from_host_ldr.dlast <= regs_in.fifo_xlast_o;
from_host_ldr.msbf <= regs_in.csr_msbf_o;
from_host_ldr.startup <= regs_in.csr_exit_o;
from_host_ldr.clk_div <= '0' & regs_in.csr_clkdiv_o;
from_host_ldr.swrst <= regs_in.csr_swrst_o;
from_host_ldr.empty <= regs_in.fifo_rd_empty_o;
regs_out_local.csr_done_i <= to_host_ldr.done;
regs_out_local.csr_error_i <= to_host_ldr.error;
regs_out_local.csr_busy_i <= to_host_ldr.busy;
regs_out_local.fifo_rd_req_i <= to_host_ldr.rd;
regs_out_local.idr_i <= g_idr_value;
gen_svec_only2: if g_target_board = "SVEC" generate
-- Flash bootloader engine: finds an SDB file containing the AFPGA bitstream in
-- the flash, and if present, loads it to the SFPGA via U_Xilinx_Loader
flash_enable <= '1' when boot_source = FLASH else '0';
U_Flash_Boot_Engine : flash_boot
......@@ -266,27 +312,12 @@ begin -- behavioral
xldr_empty_o => from_flash_ldr.empty,
xldr_startup_o => from_flash_ldr.startup,
xldr_clk_div_o => from_flash_ldr.clk_div,
spi_cs_n_o => spi_cs_n_o,
spi_sclk_o => spi_sclk_o,
spi_mosi_o => spi_mosi_o,
spi_miso_i => spi_miso_i,
spi_cs_n_o => spi_sys_cs_n_o,
spi_sclk_o => spi_sys_sclk_o,
spi_mosi_o => spi_sys_mosi_o,
spi_miso_i => spi_sys_miso_i,
no_bitstream_p1_o => flash_no_bitstream_p1);
-- Route host registers to the boot source multiplexer (p_select_boot_source).
from_host_ldr.start <= regs_in.csr_start_o and boot_en_i;
from_host_ldr.data <= regs_in.fifo_xdata_o;
from_host_ldr.dsize <= regs_in.fifo_xsize_o;
from_host_ldr.dlast <= regs_in.fifo_xlast_o;
from_host_ldr.msbf <= regs_in.csr_msbf_o;
from_host_ldr.startup <= regs_in.csr_exit_o;
from_host_ldr.clk_div <= '0' & regs_in.csr_clkdiv_o;
from_host_ldr.swrst <= regs_in.csr_swrst_o;
from_host_ldr.empty <= regs_in.fifo_rd_empty_o;
regs_out_local.csr_done_i <= to_host_ldr.done;
regs_out_local.csr_error_i <= to_host_ldr.error;
regs_out_local.csr_busy_i <= to_host_ldr.busy;
regs_out_local.fifo_rd_req_i <= to_host_ldr.rd;
regs_out_local.idr_i <= g_idr_value;
-- Multiplexes the access to the Xilinx Serial Bootloader module between
-- the host (accessed via Wishbine registers) and the internal Flash loader
......@@ -310,6 +341,81 @@ begin -- behavioral
end case;
end process;
end generate gen_svec_only2;
gen_svec7_only2: if g_target_board = "SVEC7" generate
U_SPI_Master_SFPGA_Flash : entity work.spi_master
generic map (
g_div_ratio_log2 => 0,
g_num_data_bits => 8)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
cs_i => regs_in.far_cs_o,
start_i => spi0_start_host,
cpol_i => '0',
data_i => spi0_wdata_host,
ready_o => regs_out_local.far_ready_i,
data_o => regs_out_local.far_data_i,
spi_cs_n_o => spi_sys_cs_n_o,
spi_sclk_o => spi_sys_sclk_o,
spi_mosi_o => spi_sys_mosi_o,
spi_miso_i => spi_sys_miso_i);
U_SPI_Master_APP_Flash : entity work.spi_master
generic map (
g_div_ratio_log2 => 0,
g_num_data_bits => 8)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
cs_i => regs_in.far2_cs_o,
start_i => spi1_start_host,
cpol_i => '0',
data_i => spi1_wdata_host,
ready_o => regs_out_local.far2_ready_i,
data_o => regs_out_local.far2_data_i,
spi_cs_n_o => spi_app_cs_n_o,
spi_sclk_o => spi_app_sclk_o,
spi_mosi_o => spi_app_mosi_o,
spi_miso_i => spi_app_miso_i);
-- Host flash data register (bidirectional), updated by writing to FAR.DATA
p_host_spi_registers : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
spi0_start_host <= '0';
spi0_wdata_host <= (others => '0');
spi1_start_host <= '0';
spi1_wdata_host <= (others => '0');
else
if regs_in.far_data_load_o = '1' then
spi0_wdata_host <= regs_in.far_data_o;
spi0_start_host <= regs_in.far_xfer_o;
else
spi0_start_host <= '0';
end if;
if regs_in.far2_data_load_o = '1' then
spi1_wdata_host <= regs_in.far2_data_o;
spi1_start_host <= regs_in.far2_xfer_o;
else
spi1_start_host <= '0';
end if;
end if;
end if;
end process;
end generate gen_svec7_only2;
-- The Xilinx bootloader. Takes a bitstream and loads it into a Xilinx FPGA
-- configured in Passive Serial mode (signals: CCLK, DIN, PROG_B, INIT_B, DONE).
U_Xilinx_Loader : xilinx_loader
......@@ -364,7 +470,9 @@ begin -- behavioral
end if;
end process;
boot_trig_p1_o <= boot_trig_p1_int or flash_no_bitstream_p1;
boot_exit_p1_o <= regs_in.csr_exit_o;
xlx_m_o <= "11"; -- permamently select Passive serial
......
......@@ -6,7 +6,7 @@
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-01-24
-- Last update: 2014-01-13
-- Last update: 2021-09-02
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -60,5 +60,6 @@ package svec_bootloader_pkg is
-- Signature of the bootloader in the card's CSR space. Used by the software
-- for probing the bootloader core.
constant c_CSR_SIGNATURE : std_logic_vector(31 downto 0) := x"53564543";
constant c_CSR_SIGNATURE_SVEC7 : std_logic_vector(31 downto 0) := x"53564537";
end svec_bootloader_pkg;
This diff is collapsed.
......@@ -144,7 +144,7 @@ peripheral {
reg {
name = "Flash Access Register";
description = "Provides direct access to the SPI flash memory containing the bitstream.";
description = "Provides direct access to the SPI flash memory containing the bitstream. On SVEC there's a single flash (and so single FAR), on SVEC7, the app flash is handled by the FAR2 register";
prefix = "FAR";
field {
......@@ -235,5 +235,52 @@ write 0: Disable target SPI controller";
};
};
reg {
name = "Flash Access Register (2nd flash)";
description = "Provides direct access to the SPI flash memory containing the bitstream. On SVEC there's a single flash (and so single FAR), on SVEC7, the app flash is handled by the FAR2 register";
prefix = "FAR2";
field {
prefix = "DATA";
name = "SPI Data";
description = "Data to be written / read to/from the flash SPI controller.";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
prefix = "XFER";
name = "SPI Start Transfer";
description = "write 1: initiate an SPI transfer with an 8-bit data word taken from the <code>DATA</code>field\
write 0: no effect";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
prefix = "READY";
name = "SPI Ready";
description = "read 1: Core is ready to initiate another transfer. DATA field contains the data read during previous transaction.\
read 0: core is busy";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
prefix = "CS";
name = "SPI Chip Select";
description = "write 1: Enable target SPI controller\
write 0: Disable target SPI controller";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
};
\ No newline at end of file
};
......@@ -3,7 +3,7 @@
---------------------------------------------------------------------------------------
-- File : sxldr_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from svec_xloader_wb.wb
-- Created : Mon Aug 11 10:59:42 2014
-- Created : Thu Sep 2 14:18:56 2021
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE svec_xloader_wb.wb
......@@ -28,7 +28,9 @@ package sxldr_wbgen2_pkg is
far_ready_i : std_logic;
idr_i : std_logic_vector(31 downto 0);
fifo_rd_req_i : std_logic;
end record;
far2_data_i : std_logic_vector(7 downto 0);
far2_ready_i : std_logic;
end record;
constant c_sxldr_in_registers_init_value: t_sxldr_in_registers := (
csr_done_i => '0',
......@@ -37,84 +39,121 @@ package sxldr_wbgen2_pkg is
far_data_i => (others => '0'),
far_ready_i => '0',
idr_i => (others => '0'),
fifo_rd_req_i => '0'
);
-- Output registers (WB slave -> user design)
type t_sxldr_out_registers is record
csr_start_o : std_logic;
csr_msbf_o : std_logic;
csr_swrst_o : std_logic;
csr_exit_o : std_logic;
csr_clkdiv_o : std_logic_vector(5 downto 0);
btrigr_o : std_logic_vector(7 downto 0);
btrigr_wr_o : std_logic;
far_data_o : std_logic_vector(7 downto 0);
far_data_load_o : std_logic;
far_xfer_o : std_logic;
far_cs_o : std_logic;
fifo_rd_full_o : std_logic;
fifo_rd_empty_o : std_logic;
fifo_xsize_o : std_logic_vector(1 downto 0);
fifo_xlast_o : std_logic;
fifo_xdata_o : std_logic_vector(31 downto 0);
end record;
constant c_sxldr_out_registers_init_value: t_sxldr_out_registers := (
csr_start_o => '0',
csr_msbf_o => '0',
csr_swrst_o => '0',
csr_exit_o => '0',
csr_clkdiv_o => (others => '0'),
btrigr_o => (others => '0'),
btrigr_wr_o => '0',
far_data_o => (others => '0'),
far_data_load_o => '0',
far_xfer_o => '0',
far_cs_o => '0',
fifo_rd_full_o => '0',
fifo_rd_empty_o => '0',
fifo_xsize_o => (others => '0'),
fifo_xlast_o => '0',
fifo_xdata_o => (others => '0')
);
function "or" (left, right: t_sxldr_in_registers) return t_sxldr_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
fifo_rd_req_i => '0',
far2_data_i => (others => '0'),
far2_ready_i => '0'
);
-- Output registers (WB slave -> user design)
type t_sxldr_out_registers is record
csr_start_o : std_logic;
csr_msbf_o : std_logic;
csr_swrst_o : std_logic;
csr_exit_o : std_logic;
csr_clkdiv_o : std_logic_vector(5 downto 0);
btrigr_o : std_logic_vector(7 downto 0);
btrigr_wr_o : std_logic;
far_data_o : std_logic_vector(7 downto 0);
far_data_load_o : std_logic;
far_xfer_o : std_logic;
far_cs_o : std_logic;
fifo_rd_full_o : std_logic;
fifo_rd_empty_o : std_logic;
fifo_xsize_o : std_logic_vector(1 downto 0);
fifo_xlast_o : std_logic;
fifo_xdata_o : std_logic_vector(31 downto 0);
far2_data_o : std_logic_vector(7 downto 0);
far2_data_load_o : std_logic;
far2_xfer_o : std_logic;
far2_cs_o : std_logic;
end record;
constant c_sxldr_out_registers_init_value: t_sxldr_out_registers := (
csr_start_o => '0',
csr_msbf_o => '0',
csr_swrst_o => '0',
csr_exit_o => '0',
csr_clkdiv_o => (others => '0'),
btrigr_o => (others => '0'),
btrigr_wr_o => '0',
far_data_o => (others => '0'),
far_data_load_o => '0',
far_xfer_o => '0',
far_cs_o => '0',
fifo_rd_full_o => '0',
fifo_rd_empty_o => '0',
fifo_xsize_o => (others => '0'),
fifo_xlast_o => '0',
fifo_xdata_o => (others => '0'),
far2_data_o => (others => '0'),
far2_data_load_o => '0',
far2_xfer_o => '0',
far2_cs_o => '0'
);
function "or" (left, right: t_sxldr_in_registers) return t_sxldr_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
component svec_xloader_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
regs_i : in t_sxldr_in_registers;
regs_o : out t_sxldr_out_registers
);
end component;
end package;
package body sxldr_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_sxldr_in_registers) return t_sxldr_in_registers is
variable tmp: t_sxldr_in_registers;
variable tmp: t_sxldr_in_registers;
begin
tmp.csr_done_i := f_x_to_zero(left.csr_done_i) or f_x_to_zero(right.csr_done_i);
tmp.csr_error_i := f_x_to_zero(left.csr_error_i) or f_x_to_zero(right.csr_error_i);
tmp.csr_busy_i := f_x_to_zero(left.csr_busy_i) or f_x_to_zero(right.csr_busy_i);
tmp.far_data_i := f_x_to_zero(left.far_data_i) or f_x_to_zero(right.far_data_i);
tmp.far_ready_i := f_x_to_zero(left.far_ready_i) or f_x_to_zero(right.far_ready_i);
tmp.idr_i := f_x_to_zero(left.idr_i) or f_x_to_zero(right.idr_i);
tmp.fifo_rd_req_i := f_x_to_zero(left.fifo_rd_req_i) or f_x_to_zero(right.fifo_rd_req_i);
return tmp;
tmp.csr_done_i := f_x_to_zero(left.csr_done_i) or f_x_to_zero(right.csr_done_i);
tmp.csr_error_i := f_x_to_zero(left.csr_error_i) or f_x_to_zero(right.csr_error_i);
tmp.csr_busy_i := f_x_to_zero(left.csr_busy_i) or f_x_to_zero(right.csr_busy_i);
tmp.far_data_i := f_x_to_zero(left.far_data_i) or f_x_to_zero(right.far_data_i);
tmp.far_ready_i := f_x_to_zero(left.far_ready_i) or f_x_to_zero(right.far_ready_i);
tmp.idr_i := f_x_to_zero(left.idr_i) or f_x_to_zero(right.idr_i);
tmp.fifo_rd_req_i := f_x_to_zero(left.fifo_rd_req_i) or f_x_to_zero(right.fifo_rd_req_i);
tmp.far2_data_i := f_x_to_zero(left.far2_data_i) or f_x_to_zero(right.far2_data_i);
tmp.far2_ready_i := f_x_to_zero(left.far2_ready_i) or f_x_to_zero(right.far2_ready_i);
return tmp;
end function;
end package body;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment