Commit 09abd1ca authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

hdl: flash-to-AFPGA and host-to-flash boot modes

parent 2082833e
files = ["mini_vme.vhd"];
files = [ "flash_boot.vhd",
"m25p_flash.vhd",
"mini_vme.vhd",
"spi_master.vhd",
"xilinx_loader.vhd",
"sxldr_wbgen2_pkg.vhd",
"svec_xloader_wb.vhd",
"sfpga_bootloader.vhd",
"svec_bootloader_pkg.vhd"
]
-----------------------------------------------------------------------------
-- Title : Flash-to-Xilinx FPGA bitstream loader
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : flash_boot.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-01-24
-- Last update: 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Searches for an Application FPGA bitstream in the flash memory
-- and uploads it to the FPGA through external xilinx_loader module. The bitstream
-- resides at a fixed location (defined in svec_bootloader_pkg) and the flash
-- is assumed to be formatted with SDB filesystem.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sxldr_wbgen2_pkg.all;
use work.svec_bootloader_pkg.all;
entity flash_boot is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Wbgen2 registers (for host access to the flash SPI controller via the
-- FAR register)
regs_i : in t_sxldr_out_registers;
regs_o : out t_sxldr_in_registers;
-- 1: boot process is enabled (transition from 0 to 1 starts bootup sequence).
-- It can be performed only once, re-booting AFPGA from the flash memory
-- requires a reset of the System FPGA
enable_i : in std_logic;
-- Xilinx loader module interface (see xilinx_loader.vhd) for descriptions.
xldr_start_o : out std_logic;
xldr_mode_o : out std_logic;
xldr_data_o : out std_logic_vector(31 downto 0);
xldr_dsize_o : out std_logic_vector(1 downto 0);
xldr_dlast_o : out std_logic;
xldr_msbf_o : out std_logic;
xldr_done_i : in std_logic;
xldr_rd_i : in std_logic;
xldr_empty_o : out std_logic;
xldr_startup_o : out std_logic;
xldr_clk_div_o : out std_logic_vector(6 downto 0);
-- SPI bus to the flash memory
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
);
end flash_boot;
architecture behavioral of flash_boot is
component m25p_flash
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
regs_i : in t_sxldr_out_registers;
regs_o : out t_sxldr_in_registers;
set_addr_i : in std_logic;
addr_i : in std_logic_vector(23 downto 0);
read_i : in std_logic;
data_o : out std_logic_vector(7 downto 0);
ready_o : out std_logic;
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);
end component;
type t_boot_state is (STARTUP, SELECT_SDB, WAIT_SELECT_SDB, CHECK_SIG0, CHECK_SIG1, CHECK_SIG2, CHECK_SIG3, SELECT_BITSTREAM, WAIT_SELECT_BITSTREAM, FETCH_BS_BYTE, LOAD_BS_BYTE, NO_BITSTREAM, BOOT_DONE);
-- helper procedure to eliminate redundant code in the main FSM. Compares
-- subsequent bytes of the SDB filesystem magic ID and advances the FSM if it
-- matches.
procedure f_check_signature (
signal ready : in std_logic;
signal data : in std_logic_vector(7 downto 0);
byte_id : integer;
signal state : out t_boot_state;
next_state : t_boot_state;
signal read : out std_logic;
read_next : std_logic) is
begin
if ready = '1' then
if data = c_SDB_SIGNATURE(byte_id) then
state <= next_state;
else
state <= NO_BITSTREAM;
end if;
read <= read_next;
else
read <= '0';
end if;
end f_check_signature;
signal flash_set_addr : std_logic;
signal flash_addr : std_logic_vector(23 downto 0);
signal flash_read : std_logic;
signal flash_data : std_logic_vector(7 downto 0);
signal flash_ready : std_logic;
signal byte_count : unsigned(23 downto 0);
signal state : t_boot_state;
begin -- rtl
U_Flash_Controller : m25p_flash
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
regs_i => regs_i,
regs_o => regs_o,
set_addr_i => flash_set_addr,
addr_i => flash_addr,
read_i => flash_read,
data_o => flash_data,
ready_o => flash_ready,
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);
-- We know our endian
xldr_msbf_o <= '0';
-- We startup the FPGA immediately after loading the bitstream if
-- booting from the flash (no need to mess around with VME buffer switching,
-- since while we boot up from flash, the VME is in passive mode)
xldr_startup_o <= '1';
-- 32 MHz should be just fine.
xldr_clk_div_o <= "0000001";
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or enable_i = '0' then
state <= STARTUP;
flash_set_addr <= '0';
flash_read <= '0';
xldr_start_o <= '0';
xldr_empty_o <= '1';
else
case state is
-- Wait until we are allowed to start flash boot sequence
when STARTUP =>
if enable_i = '1' then
state <= SELECT_SDB;
byte_count <= (others => '0');
end if;
-- Go to the SDB record location
when SELECT_SDB =>
flash_set_addr <= '1';
flash_addr <= c_SDB_ROOT_OFFSET;
state <= WAIT_SELECT_SDB;
-- Wait until the address is set
when WAIT_SELECT_SDB =>
if flash_ready = '1' then
flash_read <= '1';
state <= CHECK_SIG0;
else
flash_set_addr <= '0';
end if;
-- Read and check 4 subsequent bytes of the signature 'SDB-'. If OK, proceed
-- with loading the bitstream
when CHECK_SIG0 =>
f_check_signature(flash_ready, flash_data, 0, state, CHECK_SIG1, flash_read, '1');
when CHECK_SIG1 =>
f_check_signature(flash_ready, flash_data, 1, state, CHECK_SIG2, flash_read, '1');
when CHECK_SIG2 =>
f_check_signature(flash_ready, flash_data, 2, state, CHECK_SIG3, flash_read, '1');
when CHECK_SIG3 =>
f_check_signature(flash_ready, flash_data, 3, state, SELECT_BITSTREAM, flash_read, '0');
-- Go to the beginning of the 'afpga.bin' file in the filesystem (fixed location)
when SELECT_BITSTREAM =>
xldr_start_o <= '1';
flash_set_addr <= '1';
flash_addr <= c_SDB_BITSTREAM_OFFSET;
state <= WAIT_SELECT_BITSTREAM;
-- ... and wait until the flash address is set
when WAIT_SELECT_BITSTREAM =>
xldr_start_o <= '0';
flash_set_addr <= '0';
if(flash_ready = '1') then
state <= FETCH_BS_BYTE;
flash_read <= '1';
else
flash_read <= '0';
end if;
-- Fetch another byte of the bitstream
when FETCH_BS_BYTE =>
if(flash_ready = '1') then
xldr_empty_o <= '0';
xldr_data_o(7 downto 0) <= flash_data;
xldr_dsize_o <= "00";
xldr_dlast_o <= '0';
state <= LOAD_BS_BYTE;
else
flash_read <= '0';
end if;
-- And push it to the Xilinx Loader module
when LOAD_BS_BYTE =>
if(xldr_rd_i = '1') then
flash_read <= '1';
xldr_empty_o <= '1';
-- AFPGA indicated finish of bitstream download?
if(xldr_done_i = '1') then
state <= BOOT_DONE;
-- ... or we exceeded maximum bitstream size (something is seriously wrong on board
-- or the BS is invalid)
elsif byte_count = unsigned(c_BITSTREAM_SIZE) then
state <= NO_BITSTREAM;
-- otherwise, just proceed with another byte of the BS
else
state <= FETCH_BS_BYTE;
end if;
byte_count <= byte_count + 1;
else
flash_read <= '0';
end if;
-- We have no (or invalid) bitstream. Wait until reset
when NO_BITSTREAM =>
flash_read <= '0';
if enable_i = '0' then
state <= STARTUP;
end if;
-- Bitstream was correctly loaded. Wait forever (or until reset).
when BOOT_DONE =>
flash_read <= '0';
end case;
end if;
end if;
end process;
end behavioral;
-----------------------------------------------------------------------------
-- Title : M25Pxxx Flash Controller
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : m25p_flash.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2013-01-24
-- Last update: 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Simple controller for M25Pxxx series of SPI flash memories.
-- Provides two interfaces: host interface (accessible via FAR register), which
-- can execute any kind of operations, and a simple memory bus which can only read
-- blocks of bytes starting at a given address.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sxldr_wbgen2_pkg.all;
entity m25p_flash is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Wishbone registers (FAR register access)
regs_i : in t_sxldr_out_registers;
regs_o : out t_sxldr_in_registers;
-- Data readout interface.
-- 1: sets flash read address to addr_i
set_addr_i : in std_logic;
-- start address for read operations
addr_i : in std_logic_vector(23 downto 0);
-- data request: when 1, the controller reads subsequent bytes from
-- the flash, starting from addr_i address.
read_i : in std_logic;
-- read data output
data_o : out std_logic_vector(7 downto 0);
-- when 1, data_o contains a valid byte and the controller is ready to accept
-- another command
ready_o : out std_logic;
-- SPI bus, connect to the flash memory.
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
);
end m25p_flash;
architecture behavioral of m25p_flash is
component spi_master
generic (
g_div_ratio_log2 : integer;
g_num_data_bits : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
cs_i : in std_logic;
start_i : in std_logic;
cpol_i : in std_logic;
data_i : in std_logic_vector(g_num_data_bits - 1 downto 0);
ready_o : out std_logic;
data_o : out std_logic_vector(g_num_data_bits - 1 downto 0);
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);
end component;
signal spi_cs, spi_cs_muxed : std_logic;
signal spi_start, spi_start_host, spi_start_muxed : std_logic;
signal spi_wdata, spi_wdata_host, spi_wdata_muxed : std_logic_vector(7 downto 0);
signal spi_rdata : std_logic_vector(7 downto 0);
signal spi_ready : std_logic;
type t_read_state is (IDLE, CSEL, COMMAND, ADDR0, ADDR1, ADDR2, DUMMY_XFER, DATA);
signal state : t_read_state;
signal ready_int : std_logic;
begin -- rtl
-- 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
spi_start_host <= '0';
spi_wdata_host <= (others => '0');
elsif regs_i.far_data_load_o = '1' then
spi_wdata_host <= regs_i.far_data_o;
spi_start_host <= regs_i.far_xfer_o;
else
spi_start_host <= '0';
end if;
end if;
end process;
-- Multplexes the access between to the flash SPI controller between
-- the bootloader host (through FAR register) and the flash readout
-- FSM.
p_mux_spi_access : process(spi_cs, spi_start, spi_wdata, spi_start_host, spi_wdata, spi_ready, regs_i, state)
begin
spi_cs_muxed <= regs_i.far_cs_o or spi_cs;
spi_wdata_muxed <= spi_wdata_host or spi_wdata;
spi_start_muxed <= spi_start_host or spi_start;
end process;
regs_o.far_ready_i <= spi_ready;
regs_o.far_data_i <= spi_rdata;
-- SPI Master: executes SPI read/write transactions.
U_SPI_Master : 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 => spi_cs_muxed,
start_i => spi_start_muxed,
cpol_i => '0',
data_i => spi_wdata_muxed,
ready_o => spi_ready,
data_o => spi_rdata,
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);
-- Main State machine
p_main_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
spi_start <= '0';
spi_cs <= '0';
spi_wdata <= (others => '0');
ready_int <= '1';
-- any access to FAR register stops internal bus request
elsif(regs_i.far_data_load_o = '1') then
spi_start <= '0';
spi_cs <= '0';
spi_wdata <= (others => '0');
state <= IDLE;
else
case state is
-- Idle: wait for "Set Address" or "Read" commands
when IDLE =>
if set_addr_i = '1' then
spi_cs <= '0';
spi_start <= '1';
ready_int <= '0';
state <= CSEL;
elsif read_i = '1' then
spi_start <= '1';
ready_int <= '0';
state <= DATA;
else
spi_start <= '0';
ready_int <= '1';
end if;
-- executes a dummy SPI cycle with the SPI chip disabled (CS = 0), to
-- make sure it will correctly interpret the next transfer as a READ
-- command
when CSEL =>
if(spi_ready = '1') then
state <= COMMAND;
spi_wdata <= x"0b";
spi_cs <= '1';
spi_start <= '1';
else
spi_start <= '0';
end if;
-- Send command 0x3 (FAST READ DATA)
when COMMAND =>
if(spi_ready = '1') then
state <= ADDR0;
spi_wdata <= addr_i(23 downto 16);
spi_start <= '1';
else
spi_start <= '0';
end if;
-- Send 1st byte of read address
when ADDR0 =>
if(spi_ready = '1') then
state <= ADDR1;
spi_wdata <= addr_i(15 downto 8);
spi_start <= '1';
else
spi_start <= '0';
end if;
-- Send 2nd byte of read address
when ADDR1 =>
if(spi_ready = '1') then
state <= ADDR2;
spi_wdata <= addr_i(7 downto 0);
spi_start <= '1';
else
spi_start <= '0';
end if;
-- Send 3nd byte of read address
when ADDR2 =>
if(spi_ready = '1') then
state <= DUMMY_XFER;
spi_wdata <= "XXXXXXXX";
spi_start <= '1';
else
spi_start <= '0';
end if;
-- dummy transfer (necessary for fast read mode)
when DUMMY_XFER =>
spi_start <= '0';
if(spi_ready = '1') then
state <= IDLE;
end if;
-- Data readout: waits for completion of read transaction initiated
-- upon assertion of read_i and returns the byte read data_o.
when DATA =>
spi_start <= '0';
if(spi_ready = '1')then
data_o <= spi_rdata;
ready_int <= '1';
state <= IDLE;
else
ready_int <= '0';
end if;
end case;
end if;
end if;
end process;
-- De-assert ready flag early
ready_o <= ready_int and not (set_addr_i or read_i);
end behavioral;
-- minimalistic VME core providing only CR/CSR accesses. For SVEC AFPGA bootup
-- purposes.
-------------------------------------------------------------------------------
-- Title : Minimalistic VME64x Core
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : mini_vme.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2012-01-20
-- Last update: 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: A stripped-down version of VME64x core. Supports only CR/CSR/D32
-- accesses to a range of addresses specified in g_user_csr_start/end. Matching
-- transactions are executed through a Wishbone master.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 - 2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.STD_LOGIC_1164.all;
......@@ -10,33 +45,35 @@ use work.wishbone_pkg.all;
entity xmini_vme is
generic (
-- Start/end of our CSR space
g_user_csr_start : unsigned(20 downto 0);
g_user_csr_end : unsigned(20 downto 0));
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- "Passive" mode enable: when '1', the core never touches the bus
passive_i : in std_logic;
-- stripped-down VME I/O
-- Stripped-down VME bus.
VME_RST_n_i : in std_logic;
VME_AS_n_i : in std_logic;
VME_LWORD_n_i : in std_logic;
VME_WRITE_n_i : in std_logic;
VME_DS_n_i : in std_logic_vector(1 downto 0);
VME_GA_i : in std_logic_vector(5 downto 0); -- Geographical Address and GA parity
VME_DTACK_n_o : out std_logic;
VME_DTACK_OE_o : out std_logic;
-- Geographical Address. Bit 5 is GA parity.
VME_GA_i : in std_logic_vector(5 downto 0);
VME_AM_i : in std_logic_vector(5 downto 0);
VME_ADDR_i : in std_logic_vector(31 downto 1);
-- Bidirectional/tristate driver signals: please put the tristates in the
-- top level entity of your design.
VME_DTACK_n_o : out std_logic;
VME_DTACK_OE_o : out std_logic;
VME_DATA_b_i : in std_logic_vector(31 downto 0);
VME_DATA_b_o : out std_logic_vector(31 downto 0);
VME_DATA_DIR_o : out std_logic;
VME_DATA_OE_N_o : out std_logic;
-- Wishbone master
master_o : out t_wishbone_master_out;
master_i : in t_wishbone_master_in
);
......@@ -45,7 +82,10 @@ end xmini_vme;
architecture rtl of xmini_vme is
-- We are only interested in CR/CSR transfers (AM = 0x2f)
constant c_AM_CS_CSR : std_logic_vector(5 downto 0) := "101111";
-- How long (in clock cycles) is our DTACK. Useful for slower VME controllers.
constant c_DTACK_LENGTH : integer := 20;
signal as_synced, ds_synced : std_logic;
......@@ -143,8 +183,8 @@ begin -- rtl
else
am_match <= '0';
end if;
-- ... D32 data type
-- ... D32 data type
if(ds_latched = "00" and lword_latched = '0' and addr_latched(1) = '0') then
dtype_match <= '1';
else
......@@ -222,15 +262,9 @@ begin -- rtl
when DTACK =>
VME_DATA_b_o <= readback_data;
if(passive_i = '1') then
VME_DATA_DIR_o <= '0';
VME_DATA_DIR_o <= '0';
VME_DTACK_OE_o <= '0';
else
VME_DTACK_n_o <= '0';
VME_DTACK_OE_o <= '1';
VME_DATA_DIR_o <= not is_write;
end if;
VME_DTACK_n_o <= '0';
VME_DTACK_OE_o <= '1';
VME_DATA_DIR_o <= not is_write;
dtack_counter <= dtack_counter + 1;
......
This diff is collapsed.
-----------------------------------------------------------------------------
-- Title : SPI Bus Master
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : spi_master.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-08-24
-- Last update: 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Just a simple SPI master (bus-less).
-------------------------------------------------------------------------------
--
-- Copyright (c) 2011-2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity spi_master is
generic(
-- clock division ratio (SCLK = clk_sys_i / (2 ** g_div_ratio_log2).
g_div_ratio_log2 : integer := 2;
-- number of data bits per transfer
g_num_data_bits : integer := 2);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- state of the Chip select line (1 = CS active). External control
-- allows for multi-transfer commands (SPI master itself does not
-- control the state of spi_cs_n_o)
cs_i : in std_logic;
-- 1: start next transfer (using CPOL, DATA and SEL from the inputs below)
start_i : in std_logic;
-- Clock polarity: 1: slave clocks in the data on rising SCLK edge, 0: ...
-- on falling SCLK edge
cpol_i : in std_logic;
-- TX Data input
data_i : in std_logic_vector(g_num_data_bits - 1 downto 0);
-- 1: data_o contains the result of last read operation. Core is ready to initiate
-- another transfer.
ready_o : out std_logic;
-- data read from selected slave, valid when ready_o == 1.
data_o : out std_logic_vector(g_num_data_bits - 1 downto 0);
-- these are obvious
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
);
end spi_master;
architecture behavioral of spi_master is
signal divider : unsigned(11 downto 0);
signal tick : std_logic;
signal sreg : std_logic_vector(g_num_data_bits-1 downto 0);
signal rx_sreg : std_logic_vector(g_num_data_bits-1 downto 0);
type t_state is (IDLE, TX_CS, TX_DAT1, TX_DAT2, TX_SCK1, TX_SCK2, TX_CS2, TX_GAP);
signal state : t_state;
signal sclk : std_logic;
signal counter : unsigned(4 downto 0);
begin -- rtl
-- Simple clock divder. Produces a 'tick' signal which defines the timing for
-- the main state machine transitions.
p_divide_spi_clock: process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
divider <= (others => '0');
else
if(start_i = '1' or tick = '1') then
divider <= (others => '0');
else
divider <= divider + 1;
end if;
end if;
end if;
end process;
tick <= divider(g_div_ratio_log2);
-- Main state machine. Executes SPI transfers
p_main_fsm: process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
sclk <= '0';
sreg <= (others => '0');
rx_sreg <= (others => '0');
spi_mosi_o <= '0';
counter <= (others => '0');
else
case state is
-- Waits for start of transfer command
when IDLE =>
sclk <= '0';
counter <= (others => '0');
if(start_i = '1') then
sreg <= data_i;
state <= TX_CS;
spi_mosi_o <= data_i(sreg'high);
end if;
-- Generates a gap between the externally asserted Chip Select and
-- the beginning of data transfer
when TX_CS =>
if tick = '1' then
state <= TX_DAT1;
end if;
-- Outputs subsequent bits to MOSI line.
when TX_DAT1 =>
if(tick = '1') then
spi_mosi_o <= sreg(sreg'high);
sreg <= sreg(sreg'high-1 downto 0) & '0';
state <= TX_SCK1;
end if;
-- Flips the SCLK (active edge)
when TX_SCK1 =>
if(tick = '1') then
sclk <= not sclk;
counter <= counter + 1;
state <= TX_DAT2;
end if;
-- Shifts in bits read from the slave
when TX_DAT2 =>
if(tick = '1') then
rx_sreg <= rx_sreg(rx_sreg'high-1 downto 0) & spi_miso_i;
state <= TX_SCK2;
end if;
-- Flips the SCLK (inactive edge). Checks if all bits have been
-- transferred.
when TX_SCK2 =>
if(tick = '1') then
sclk <= not sclk;
if(counter = g_num_data_bits) then
state <= TX_CS2;
else
state <= TX_DAT1;
end if;
end if;
-- Generates a gap for de-assertoin of CS line
when TX_CS2 =>
if(tick = '1') then
state <= TX_GAP;
data_o <= rx_sreg;
end if;
when TX_GAP =>
if (tick = '1') then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
ready_o <= '1' when (state = IDLE and start_i = '0') else '0';
-- SCLK polarity control
spi_sclk_o <= sclk xor cpol_i;
spi_cs_n_o <= not cs_i;
end behavioral;
-------------------------------------------------------------------------------
-- Title : SVEC FPGA Bootloader main package
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : svec_bootloader_pkg.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-01-24
-- Last update: 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Contains definitions of the bootloader's parameters (base
-- addresses and timing).
-------------------------------------------------------------------------------
--
-- Copyright (c) 2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package svec_bootloader_pkg is
type t_byte_array is array(integer range <>) of std_logic_vector(7 downto 0);
-- SDB descriptor magic ID. Used to check for presence of valid filesystem
-- in the flash memory
constant c_SDB_SIGNATURE : t_byte_array(0 to 3) := (x"53", x"44", x"42", x"2D");
-- Filesystem root offset (i.e. the location of the SDB record table)
constant c_SDB_ROOT_OFFSET : std_logic_vector(23 downto 0) := x"500000";
-- Offset of the file containing our bitstream (afpga.bin)
constant c_SDB_BITSTREAM_OFFSET : std_logic_vector(23 downto 0) := x"100000";
-- Size of our bitstream (maximum possible value). Used to limit download time
-- when the bitstream is invalid or the FPGA is not responding.
constant c_BITSTREAM_SIZE : std_logic_vector(23 downto 0) := x"400000";
-- 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";
end svec_bootloader_pkg;
This diff is collapsed.
-- -*- Mode: LUA; tab-width: 2 -*-
-------------------------------------------------------------------------------
-- Title : Xilinx FPGA Loader
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : svec_xloader_wb.wb
-- Author : Tomasz Włostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-01-30
-- Last update : 2013-01-24
-- Standard : Lua 5.1
-- Dependencies : wbgen2 ver 0.6+
-------------------------------------------------------------------------------
-- Description: Wishbone register block definition for Xilinx FPGA loader core.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 - 2013 CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
peripheral {
name = "SVEC FPGA loader";
description = "A very simple serial firmware loader for Xilinx FPGAs. Programs the FPGA using serial slave mode method";
prefix = "sxldr";
hdl_entity = "svec_xloader_wb";
reg {
name = "Control/status register";
prefix = "CSR";
field {
name = "Start configuration";
description = "write 1: starts the configuration process.\
write 0: no effect";
prefix = "START";
type = MONOSTABLE;
};
field {
name = "Configuration done";
description = "read 1: the bitstream has been loaded\
read 0: configuration still in progress";
prefix = "DONE";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Configuration error";
description = "read 1: an error occured during the configuration (DONE/INIT_B timeout)\
read 0: configuration was successful";
prefix = "ERROR";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Loader busy";
prefix = "BUSY";
description = "read 1: the loader is busy (can't start configuration yet)\
read 0: the loader is ready to re-configure the FPGA";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Byte order select";
description = "write 1: MSB first (big endian host)\
write 0: LSB first (little endian host)";
prefix = "MSBF";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Software resest";
description = "write 1: resets the loader core\
write 0: no effect";
prefix = "SWRST";
type = MONOSTABLE;
};
field {
name = "Exit bootloader mode";
description = "write 1: terminate bootloader mode and go passive (VME only)";
prefix = "EXIT";
type = MONOSTABLE;
};
field {
name = "Serial clock divider";
description = "CCLK division ratio. CCLK frequency = F_sysclk / 2 / (CLKDIV + 1)";
prefix = "CLKDIV";
type = SLV;
align = 8;
size = 6;
access_bus = READ_WRITE;
access_dev =READ_ONLY;
};
};
reg {
name = "Bootloader Trigger Register";
prefix = "BTRIGR";
field {
name = "Trigger Sequence Input";
description = "Write a sequence of 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe to enter bootloader mode (VME only)";
size = 8;
type = PASS_THROUGH;
};
};
reg {
name = "Flash Access Register";
description = "Provides direct access to the SPI flash memory containing the bitstream.";
prefix = "FAR";
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;
};
};
reg {
name = "ID Register";
prefix = "IDR";
field {
name = "Identification code";
description = "User-defined identification code (g_idr_value generic)";
size = 32;
type = SLV;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
fifo_reg {
size = 256;
direction = BUS_TO_CORE;
prefix = "FIFO";
name = "Bitstream FIFO";
flags_bus = {FIFO_CLEAR, FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
description = "Number of bytes to send (0 = 1 byte .. 3 = full 32-bit word)";
name = "Entry size";
prefix = "XSIZE";
size = 2;
type = SLV;
};
field {
description = "write 1: indicates the last word to be written to the FPGA";
name = "Last xfer";
prefix = "XLAST";
type = BIT;
};
field {
description = "Subsequent words of the bitstream";
name = "Data";
prefix = "XDATA";
size = 32;
type = SLV;
};
};
};
\ No newline at end of file
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for SVEC FPGA loader
---------------------------------------------------------------------------------------
-- File : sxldr_registers_pkg.vhd
-- Author : auto-generated by wbgen2 from svec_xloader_wb.wb
-- Created : Thu Jan 24 13:07:26 2013
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE svec_xloader_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wbgen2_pkg.all;
package sxldr_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_sxldr_in_registers is record
csr_done_i : std_logic;
csr_error_i : std_logic;
csr_busy_i : std_logic;
idr_i : std_logic_vector(31 downto 0);
fifo_rd_req_i : std_logic;
far_data_i : std_logic_vector(7 downto 0);
far_ready_i : std_logic;
end record;
constant c_sxldr_in_registers_init_value: t_sxldr_in_registers := (
csr_done_i => '0',
csr_error_i => '0',
csr_busy_i => '0',
idr_i => (others => '0'),
fifo_rd_req_i => '0',
far_data_i => (others => '0'),
far_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;
gpior_o : std_logic_vector(7 downto 0);
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);
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;
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',
gpior_o => (others => '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'),
far_data_o => (others => '0'),
far_data_load_o => '0',
far_xfer_o => '0',
far_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;
end package;
package body sxldr_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if(x = 'X' or x = 'U') then
return '0';
else
return x;
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);
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;
end function;
function "or" (left, right: t_sxldr_in_registers) return t_sxldr_in_registers is
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.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.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);
return tmp;
end function;
end package body;
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for SVEC FPGA loader
---------------------------------------------------------------------------------------
-- File : sxldr_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from svec_xloader_wb.wb
-- Created : Fri Jan 25 14:55:57 2013
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE svec_xloader_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wbgen2_pkg.all;
package sxldr_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_sxldr_in_registers is record
csr_done_i : std_logic;
csr_error_i : std_logic;
csr_busy_i : std_logic;
far_data_i : std_logic_vector(7 downto 0);
far_ready_i : std_logic;
idr_i : std_logic_vector(31 downto 0);
fifo_rd_req_i : std_logic;
end record;
constant c_sxldr_in_registers_init_value: t_sxldr_in_registers := (
csr_done_i => '0',
csr_error_i => '0',
csr_busy_i => '0',
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;
end package;
package body sxldr_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if(x = 'X' or x = 'U') then
return '0';
else
return x;
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);
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;
end function;
function "or" (left, right: t_sxldr_in_registers) return t_sxldr_in_registers is
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;
end function;
end package body;
This diff is collapsed.
This diff is collapsed.
`define ADDR_SXLDR_CSR 5'h0
`define SXLDR_CSR_START_OFFSET 0
`define SXLDR_CSR_START 32'h00000001
`define SXLDR_CSR_DONE_OFFSET 1
`define SXLDR_CSR_DONE 32'h00000002
`define SXLDR_CSR_ERROR_OFFSET 2
`define SXLDR_CSR_ERROR 32'h00000004
`define SXLDR_CSR_BUSY_OFFSET 3
`define SXLDR_CSR_BUSY 32'h00000008
`define SXLDR_CSR_MSBF_OFFSET 4
`define SXLDR_CSR_MSBF 32'h00000010
`define SXLDR_CSR_SWRST_OFFSET 5
`define SXLDR_CSR_SWRST 32'h00000020
`define SXLDR_CSR_EXIT_OFFSET 6
`define SXLDR_CSR_EXIT 32'h00000040
`define SXLDR_CSR_CLKDIV_OFFSET 8
`define SXLDR_CSR_CLKDIV 32'h00003f00
`define ADDR_SXLDR_BTRIGR 5'h4
`define ADDR_SXLDR_FAR 5'h8
`define SXLDR_FAR_DATA_OFFSET 0
`define SXLDR_FAR_DATA 32'h000000ff
`define SXLDR_FAR_XFER_OFFSET 8
`define SXLDR_FAR_XFER 32'h00000100
`define SXLDR_FAR_READY_OFFSET 9
`define SXLDR_FAR_READY 32'h00000200
`define SXLDR_FAR_CS_OFFSET 10
`define SXLDR_FAR_CS 32'h00000400
`define ADDR_SXLDR_IDR 5'hc
`define ADDR_SXLDR_FIFO_R0 5'h10
`define SXLDR_FIFO_R0_XSIZE_OFFSET 0
`define SXLDR_FIFO_R0_XSIZE 32'h00000003
`define SXLDR_FIFO_R0_XLAST_OFFSET 2
`define SXLDR_FIFO_R0_XLAST 32'h00000004
`define ADDR_SXLDR_FIFO_R1 5'h14
`define SXLDR_FIFO_R1_XDATA_OFFSET 0
`define SXLDR_FIFO_R1_XDATA 32'hffffffff
`define ADDR_SXLDR_FIFO_CSR 5'h18
`define SXLDR_FIFO_CSR_FULL_OFFSET 16
`define SXLDR_FIFO_CSR_FULL 32'h00010000
`define SXLDR_FIFO_CSR_EMPTY_OFFSET 17
`define SXLDR_FIFO_CSR_EMPTY 32'h00020000
`define SXLDR_FIFO_CSR_CLEAR_BUS_OFFSET 18
`define SXLDR_FIFO_CSR_CLEAR_BUS 32'h00040000
`define SXLDR_FIFO_CSR_USEDW_OFFSET 0
`define SXLDR_FIFO_CSR_USEDW 32'h000000ff
`define ADDR_XLDR_CSR 5'h0
`define XLDR_CSR_START_OFFSET 0
`define XLDR_CSR_START 32'h00000001
`define XLDR_CSR_DONE_OFFSET 1
`define XLDR_CSR_DONE 32'h00000002
`define XLDR_CSR_ERROR_OFFSET 2
`define XLDR_CSR_ERROR 32'h00000004
`define XLDR_CSR_BUSY_OFFSET 3
`define XLDR_CSR_BUSY 32'h00000008
`define XLDR_CSR_MSBF_OFFSET 4
`define XLDR_CSR_MSBF 32'h00000010
`define XLDR_CSR_SWRST_OFFSET 5
`define XLDR_CSR_SWRST 32'h00000020
`define XLDR_CSR_EXIT_OFFSET 6
`define XLDR_CSR_EXIT 32'h00000040
`define XLDR_CSR_CLKDIV_OFFSET 8
`define XLDR_CSR_CLKDIV 32'h00003f00
`define ADDR_XLDR_BTRIGR 5'h4
`define ADDR_XLDR_GPIOR 5'h8
`define ADDR_XLDR_FIFO_R0 5'hc
`define XLDR_FIFO_R0_XSIZE_OFFSET 0
`define XLDR_FIFO_R0_XSIZE 32'h00000003
`define XLDR_FIFO_R0_XLAST_OFFSET 2
`define XLDR_FIFO_R0_XLAST 32'h00000004
`define ADDR_XLDR_FIFO_R1 5'h10
`define XLDR_FIFO_R1_XDATA_OFFSET 0
`define XLDR_FIFO_R1_XDATA 32'hffffffff
`define ADDR_XLDR_FIFO_CSR 5'h14
`define XLDR_FIFO_CSR_FULL_OFFSET 16
`define XLDR_FIFO_CSR_FULL 32'h00010000
`define XLDR_FIFO_CSR_EMPTY_OFFSET 17
`define XLDR_FIFO_CSR_EMPTY 32'h00020000
`define XLDR_FIFO_CSR_USEDW_OFFSET 0
`define XLDR_FIFO_CSR_USEDW 32'h000000ff
This source diff could not be displayed because it is too large. You can view the blob instead.
action = "simulation"
target = "xilinx"
fetchto = "../../ip_cores"
vlog_opt="+incdir+../../sim/vme64x_bfm +incdir+../../sim/wb +incdir+../../sim/regs +incdir+../../sim"
vlog_opt="+incdir+../../sim/vme64x_bfm +incdir+../../sim/flash/include +incdir+../../sim/wb +incdir+../../sim/regs +incdir+../../sim"
files = [ "main.sv", "glbl.v", "SIM_CONFIG_S6_SERIAL.v" ]
files = [ "main.sv", "glbl.v", "SIM_CONFIG_S6_SERIAL.v", "../../sim/flash/M25P128.v" ]
modules = { "local" : [ "../../top/sfpga_bootloader" ] }
`include "vme64x_bfm.svh"
`include "svec_vme_buffers.svh"
`include "regs/xloader_regs.vh"
`include "regs/sxldr_regs.vh"
`define WIRE_VME_PINS2(slot_id) \
.VME_AS_n_i(VME_AS_n),\
......@@ -33,7 +33,7 @@ module main;
always #25ns clk_20m <= ~clk_20m;
initial begin
repeat(20) @(posedge clk_20m);
repeat(10000) @(posedge clk_20m);
rst_n = 1;
end
......@@ -55,7 +55,13 @@ module main;
.boot_config_o(program_b),
.boot_status_i(init_b),
.boot_done_i(done),
.boot_dout_o(din)
.boot_dout_o(din),
.spi_cs_n_o(spi_cs),
.spi_sclk_o(spi_sclk),
.spi_mosi_o(spi_mosi),
.spi_miso_i(spi_miso)
);
SIM_CONFIG_S6_SERIAL2
......@@ -72,24 +78,66 @@ module main;
);
M25Pxxx Flash(.S(spi_cs), .C(spi_sclk), .HOLD(1'b1), .D(spi_mosi), .Q(spi_miso), .Vpp_W(32'h0), .Vcc(32'd3000));
parameter [12*8:1] mem = "../../../software/sdb-flash/image.vmf";
defparam Flash.memory_file = mem;
class CSimDrv_Xloader;
protected CBusAccessor_VME64x acc;
protected uint64_t base;
protected byte _dummy;
function new(CBusAccessor_VME64x _acc, uint64_t _base);
acc = _acc;
base = _base;
endfunction
protected task flash_xfer(bit cs, byte data_in, ref byte data_out = _dummy);
uint64_t rv;
while(1) begin
acc.read(base + `ADDR_SXLDR_FAR, rv);
if(rv & `SXLDR_FAR_READY)
break;
end
acc.write(base + `ADDR_SXLDR_FAR, data_in | (cs ? `SXLDR_FAR_CS:0) | `SXLDR_FAR_XFER);
while(1) begin
acc.read(base + `ADDR_SXLDR_FAR, rv);
if(rv & `SXLDR_FAR_READY)
break;
end
data_out = rv & 'hff;
endtask // flash_xfer
task flash_command(int cmd, byte data_in[], output byte data_out[], input int size);
int i;
flash_xfer(0, 0);
flash_xfer(1, cmd);
for(i=0;i<size;i++)
begin
byte t;
flash_xfer(1, data_in[i], t);
data_out[i] = t;
end
flash_xfer(0, 0);
endtask // flash_command
task enter_boot_mode();
int i;
const int boot_seq[8] = '{'hde, 'had, 'hbe, 'hef, 'hca, 'hfe, 'hba, 'hbe};
for(i=0;i<8;i++)
acc.write(base + `ADDR_XLDR_BTRIGR, boot_seq[i]);
acc.write(base + `ADDR_SXLDR_BTRIGR, boot_seq[i]);
endtask // enter_boot_mode
......@@ -97,16 +145,16 @@ class CSimDrv_Xloader;
int f,i, pos=0;
uint64_t csr;
acc.write(base + `ADDR_XLDR_CSR, `XLDR_CSR_SWRST );
acc.write(base + `ADDR_XLDR_CSR, `XLDR_CSR_START | `XLDR_CSR_MSBF);
acc.write(base + `ADDR_SXLDR_CSR, `SXLDR_CSR_SWRST );
acc.write(base + `ADDR_SXLDR_CSR, `SXLDR_CSR_START | `SXLDR_CSR_MSBF);
f = $fopen(filename, "r");
while(!$feof(f))
begin
uint64_t r,r2;
acc.read(base + `ADDR_XLDR_FIFO_CSR, r);
acc.read(base + `ADDR_SXLDR_FIFO_CSR, r);
if(!(r&`XLDR_FIFO_CSR_FULL)) begin
if(!(r&`SXLDR_FIFO_CSR_FULL)) begin
int n;
int x;
......@@ -118,19 +166,19 @@ class CSimDrv_Xloader;
r=x;
r2=(n - 1) | ($feof(f) ? `XLDR_FIFO_R0_XLAST : 0);
acc.write(base +`ADDR_XLDR_FIFO_R0, r2);
acc.write(base +`ADDR_XLDR_FIFO_R1, r);
r2=(n - 1) | ($feof(f) ? `SXLDR_FIFO_R0_XLAST : 0);
acc.write(base +`ADDR_SXLDR_FIFO_R0, r2);
acc.write(base +`ADDR_SXLDR_FIFO_R1, r);
end
end
$fclose(f);
while(1) begin
acc.read (base + `ADDR_XLDR_CSR, csr);
if(csr & `XLDR_CSR_DONE) begin
$display("Bitstream loaded, status: %s", (csr & `XLDR_CSR_ERROR ? "ERROR" : "OK"));
acc.write(base + `ADDR_XLDR_CSR, `XLDR_CSR_EXIT);
acc.read (base + `ADDR_SXLDR_CSR, csr);
if(csr & `SXLDR_CSR_DONE) begin
$display("Bitstream loaded, status: %s", (csr & `SXLDR_CSR_ERROR ? "ERROR" : "OK"));
acc.write(base + `ADDR_SXLDR_CSR, `SXLDR_CSR_EXIT);
return;
end
end
......@@ -143,18 +191,23 @@ endclass
initial begin
uint64_t d;
byte payload[];
int i, result;
CBusAccessor_VME64x acc = new(VME.master);
CSimDrv_Xloader drv;
payload[0] = 0;
payload[1] = 0;
payload[2] = 0;
#10us;
#600us;
acc.set_default_modifiers(A32 | CR_CSR | D32);
// acc.write('h70000 + `ADDR_XLDR_GPIOR, 'haa);
drv = new(acc, 'h70000);
......@@ -163,8 +216,13 @@ endclass
drv.enter_boot_mode();
#100us;
// read ID from the flash
drv.flash_command('h9f, payload, payload, 3);
$display("Flash ID: %02x %02x %02x\n", payload[0], payload[1], payload[2]);
drv.load_bitstream("sample_bitstream/crc_gen.bin");
// drv.load_bitstream("sample_bitstream/crc_gen.bin");
end
......
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/DUT/lclk_n_i
add wave -noupdate /main/DUT/rst_n_i
add wave -noupdate /main/DUT/VME_AS_n_i
add wave -noupdate /main/DUT/VME_RST_n_i
add wave -noupdate /main/DUT/VME_WRITE_n_i
add wave -noupdate /main/DUT/VME_AM_i
add wave -noupdate /main/DUT/VME_DS_n_i
add wave -noupdate /main/DUT/VME_GA_i
add wave -noupdate /main/DUT/VME_DTACK_n_o
add wave -noupdate /main/DUT/VME_LWORD_n_b
add wave -noupdate /main/DUT/VME_ADDR_b
add wave -noupdate /main/DUT/VME_DATA_b
add wave -noupdate /main/DUT/VME_DTACK_OE_o
add wave -noupdate /main/DUT/VME_DATA_DIR_o
add wave -noupdate /main/DUT/VME_DATA_OE_N_o
add wave -noupdate /main/DUT/VME_ADDR_DIR_o
add wave -noupdate /main/DUT/VME_ADDR_OE_N_o
add wave -noupdate /main/DUT/VME_BBSY_n_i
add wave -noupdate /main/DUT/boot_clk_o
add wave -noupdate /main/DUT/boot_config_o
add wave -noupdate /main/DUT/boot_done_i
add wave -noupdate /main/DUT/boot_dout_o
add wave -noupdate /main/DUT/boot_status_i
add wave -noupdate /main/DUT/debugled_o
add wave -noupdate /main/DUT/pll_ce_o
add wave -noupdate /main/DUT/VME_DATA_o_int
add wave -noupdate /main/DUT/vme_dtack_oe_int
add wave -noupdate /main/DUT/VME_DTACK_n_int
add wave -noupdate /main/DUT/vme_data_dir_int
add wave -noupdate /main/DUT/VME_DATA_OE_N_int
add wave -noupdate /main/DUT/wb_vme_in
add wave -noupdate /main/DUT/wb_vme_out
add wave -noupdate /main/DUT/passive
add wave -noupdate /main/DUT/gpio
add wave -noupdate /main/DUT/boot_en
add wave -noupdate /main/DUT/boot_trig_p1
add wave -noupdate /main/DUT/boot_exit_p1
add wave -noupdate /main/DUT/CONTROL
add wave -noupdate /main/DUT/TRIG0
add wave -noupdate /main/DUT/TRIG1
add wave -noupdate /main/DUT/TRIG2
add wave -noupdate /main/DUT/TRIG3
add wave -noupdate /main/DUT/boot_config_int
add wave -noupdate /main/DUT/erase_afpga_n
add wave -noupdate /main/DUT/erase_afpga_n_d0
add wave -noupdate /main/DUT/pllout_clk_fb_sys
add wave -noupdate /main/DUT/pllout_clk_sys
add wave -noupdate /main/DUT/clk_sys
add wave -noupdate /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/enable_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/clk_sys_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/rst_n_i
add wave -noupdate -radix hexadecimal -expand -subitemconfig {/main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.csr_start_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.csr_msbf_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.csr_swrst_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.csr_exit_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.csr_clkdiv_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.btrigr_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.btrigr_wr_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.gpior_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.fifo_rd_full_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.fifo_rd_empty_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.fifo_xsize_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.fifo_xlast_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.fifo_xdata_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.far_data_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.far_data_load_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.far_xfer_o {-height 17 -radix hexadecimal} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i.far_cs_o {-height 17 -radix hexadecimal}} /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/regs_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/set_addr_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/addr_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/read_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/data_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/ready_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_cs_n_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_sclk_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_mosi_o
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_miso_i
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_cs
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_cs_muxed
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_start
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_start_host
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_start_muxed
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_wdata
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_wdata_host
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_wdata_muxed
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_rdata
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/spi_ready
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/state
add wave -noupdate -radix hexadecimal /main/DUT/U_Bootloader_Core/U_Flash_Boot_Engine/U_Flash_Controller/ready_int
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {1539887 ps} 0}
WaveRestoreCursors {{Cursor 1} {729769000 ps} 0}
configure wave -namecolwidth 177
configure wave -valuecolwidth 100
configure wave -justifyvalue left
......@@ -64,4 +42,4 @@ configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {282492928 ps}
WaveRestoreZoom {446436072 ps} {1011421928 ps}
......@@ -3,6 +3,6 @@ files = [ "svec_sfpga_top.vhd", "svec_sfpga_top.ucf" ]
fetchto = "../../ip_cores"
modules = {
"local" : ["../../rtl" ],
"local" : ["../../rtl/bootloader" ],
"git" : [ "git://ohwr.org/hdl-core-lib/general-cores.git" ]
}
......@@ -233,6 +233,16 @@ NET "boot_status_i" IOSTANDARD="LVCMOS33";
NET "debugled_o[2]" IOSTANDARD="LVCMOS33";
NET "debugled_o[1]" IOSTANDARD="LVCMOS33";
NET "spi_sclk_o" IOSTANDARD="LVCMOS33";
NET "spi_cs_n_o" IOSTANDARD="LVCMOS33";
NET "spi_mosi_o" IOSTANDARD="LVCMOS33";
NET "spi_miso_i" IOSTANDARD="LVCMOS33";
NET "spi_sclk_o" LOC = R11;
NET "spi_cs_n_o" LOC = T3;
NET "spi_mosi_o" LOC = T10;
NET "spi_miso_i" LOC = P10;
# Clocks/resets
NET "rst_n_i" LOC = E15;
......
This diff is collapsed.
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