Commit cc68c76a authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

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

parent ce0783b1
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;
......
-------------------------------------------------------------------------------
-- Title : SVEC Bootloader Core
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : sfpga_bootloader.vhd
-- Author : Tomasz Włostowski
-- Company : CERN BE-CO-HT
-- Created : 2013-01-24
-- Last update : 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Description: The main Application FPGA bootloader core:
-- - attepmpts to boot up the AFPGA from the Flash memory (immediately after
-- reset
-- - allows the host to boot up the AFPGA directly (via Wishbone/VME)
-- - provides raw access to the Flash SPI controller from the host (for
-- in-system reprogramming of the Flash)
-------------------------------------------------------------------------------
--
-- 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.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.sxldr_wbgen2_pkg.all;
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"
);
port (
-- system clock
clk_sys_i : in std_logic;
-- synchronous reset, active LOW
rst_n_i : in std_logic;
-- Wishbone bus
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_adr_i : in std_logic_vector(c_wishbone_address_width - 1 downto 0);
wb_sel_i : in std_logic_vector((c_wishbone_data_width + 7) / 8 - 1 downto 0);
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
-- Configuration clock (to pin CCLK)
xlx_cclk_o : out std_logic := '0';
-- Data output (to pin D0/DIN)
xlx_din_o : out std_logic;
-- Program enable pin (active low, to pin PROG_B)
xlx_program_b_o : out std_logic := '1';
-- Init ready pin (active low, to pin INIT_B)
xlx_init_b_i : in std_logic;
-- Configuration done pin (to pin DONE)
xlx_done_i : in std_logic;
-- FPGA suspend pin
xlx_suspend_o : out std_logic;
-- FPGA mode select pin. Connect to M1..M0 pins of the FPGA or leave open if
-- the pins are hardwired on the PCB
xlx_m_o : out std_logic_vector(1 downto 0);
-- Trigger sequence detector output:
-- 1-pulse: boot trigger sequence detected
boot_trig_p1_o : out std_logic := '0';
-- Exit bootloader mode, 1-pulse on write 1 to CSR.EXIT
boot_exit_p1_o : out std_logic := '0';
-- Bootloader enable. When disabled, all WB writes except for the trigger register are
-- 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
);
end sfpga_bootloader;
architecture behavioral of sfpga_bootloader is
-- Some helper structures to make multiplexing easier.
type t_xilinx_boot_in is record
swrst : std_logic;
start : std_logic;
data : std_logic_vector(31 downto 0);
dsize : std_logic_vector(1 downto 0);
dlast : std_logic;
msbf : std_logic;
empty : std_logic;
startup : std_logic;
clk_div : std_logic_vector(6 downto 0);
end record;
type t_xilinx_boot_out is record
rd : std_logic;
done : std_logic;
error : std_logic;
busy : std_logic;
end record;
component svec_xloader_wb
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_stall_o : out std_logic;
regs_i : in t_sxldr_in_registers;
regs_o : out t_sxldr_out_registers);
end component;
component flash_boot
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;
enable_i : in std_logic;
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_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;
component xilinx_loader
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
csr_swrst_i : in std_logic;
csr_start_i : in std_logic;
csr_clk_div_i : in std_logic_vector(6 downto 0);
csr_data_i : in std_logic_vector(31 downto 0);
csr_dsize_i : in std_logic_vector(1 downto 0);
csr_msbf_i : in std_logic;
csr_dlast_i : in std_logic;
csr_error_o : out std_logic;
csr_done_o : out std_logic;
csr_rd_o : out std_logic;
csr_empty_i : in std_logic;
csr_startup_i : in std_logic;
csr_busy_o : out std_logic;
xlx_cclk_o : out std_logic := '0';
xlx_din_o : out std_logic;
xlx_program_b_o : out std_logic := '1';
xlx_init_b_i : in std_logic;
xlx_done_i : in std_logic);
end component;
type t_bootseq_state is (TWORD0, TWORD1, TWORD2, TWORD3, TWORD4, TWORD5, TWORD6, TWORD7, BOOT_READY);
type t_boot_source is (FLASH, HOST);
signal wb_in : t_wishbone_master_out;
signal wb_out : t_wishbone_master_in;
signal regs_in : t_sxldr_out_registers;
signal regs_out, regs_out_local, regs_out_flash : t_sxldr_in_registers;
signal from_flash_ldr, from_host_ldr, to_xilinx_boot : t_xilinx_boot_in;
signal to_flash_ldr, to_host_ldr, from_xilinx_boot : t_xilinx_boot_out;
signal boot_state : t_bootseq_state;
signal boot_source : t_boot_source;
signal boot_trig_p1_int : std_logic;
signal flash_enable : std_logic;
-- 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
begin
if(regs.btrigr_wr_o = '1') then
if(regs.btrigr_o = match_val) then
st <= nstate;
else
st <= TWORD0;
end if;
end if;
end f_bootseq_step;
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.
p_select_boot_mode : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
boot_source <= FLASH;
elsif(boot_trig_p1_int = '1') then
boot_source <= HOST;
end if;
end if;
end process;
-- 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
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
regs_i => regs_in,
regs_o => regs_out_flash,
enable_i => flash_enable,
xldr_start_o => from_flash_ldr.start,
xldr_data_o => from_flash_ldr.data,
xldr_dsize_o => from_flash_ldr.dsize,
xldr_dlast_o => from_flash_ldr.dlast,
xldr_msbf_o => from_flash_ldr.msbf,
xldr_done_i => to_flash_ldr.done,
xldr_rd_i => to_flash_ldr.rd,
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);
-- 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
p_select_boot_source : process(from_host_ldr, from_flash_ldr, from_xilinx_boot)
begin
case boot_source is
when FLASH =>
to_xilinx_boot <= from_flash_ldr;
to_flash_ldr <= from_xilinx_boot;
to_host_ldr.rd <= '0';
to_host_ldr.done <= '0';
to_host_ldr.error <= '0';
to_host_ldr.busy <= '1';
when HOST =>
to_xilinx_boot <= from_host_ldr;
to_host_ldr <= from_xilinx_boot;
to_flash_ldr.rd <= '0';
to_flash_ldr.done <= '0';
to_flash_ldr.error <= '0';
to_flash_ldr.busy <= '1';
end case;
end process;
-- 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
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
csr_swrst_i => to_xilinx_boot.swrst,
csr_start_i => to_xilinx_boot.start,
csr_clk_div_i => to_xilinx_boot.clk_div,
csr_data_i => to_xilinx_boot.data,
csr_dsize_i => to_xilinx_boot.dsize,
csr_msbf_i => to_xilinx_boot.msbf,
csr_dlast_i => to_xilinx_boot.dlast,
csr_error_o => from_xilinx_boot.error,
csr_done_o => from_xilinx_boot.done,
csr_rd_o => from_xilinx_boot.rd,
csr_empty_i => to_xilinx_boot.empty,
csr_startup_i => to_xilinx_boot.startup,
csr_busy_o => from_xilinx_boot.busy,
xlx_cclk_o => xlx_cclk_o,
xlx_din_o => xlx_din_o,
xlx_program_b_o => xlx_program_b_o,
xlx_init_b_i => xlx_init_b_i,
xlx_done_i => xlx_done_i);
-- Bootloader trigger sequence detection.
-- Write of 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe to BTRIGR
-- produces a pulse on boot_trig_p1_o.
p_detect_boot_trigger : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
boot_trig_p1_int <= '0';
boot_state <= TWORD0;
else
case boot_state is
when TWORD0 =>
boot_trig_p1_int <= '0';
f_bootseq_step(boot_state, TWORD1, x"de", regs_in);
when TWORD1 => f_bootseq_step(boot_state, TWORD2, x"ad", regs_in);
when TWORD2 => f_bootseq_step(boot_state, TWORD3, x"be", regs_in);
when TWORD3 => f_bootseq_step(boot_state, TWORD4, x"ef", regs_in);
when TWORD4 => f_bootseq_step(boot_state, TWORD5, x"ca", regs_in);
when TWORD5 => f_bootseq_step(boot_state, TWORD6, x"fe", regs_in);
when TWORD6 => f_bootseq_step(boot_state, TWORD7, x"ba", regs_in);
when TWORD7 => f_bootseq_step(boot_state, BOOT_READY, x"be", regs_in);
when BOOT_READY =>
boot_trig_p1_int <= '1';
boot_state <= TWORD0;
end case;
end if;
end if;
end process;
boot_trig_p1_o <= boot_trig_p1_int;
boot_exit_p1_o <= regs_in.csr_exit_o;
xlx_m_o <= "11"; -- permamently select Passive serial
-- boot mode
xlx_suspend_o <= '0'; -- suspend feature is not used
-- Pipelined-classic adapter/converter
U_Adapter : wb_slave_adapter
generic map (
g_master_use_struct => true,
g_master_mode => CLASSIC,
g_master_granularity => WORD,
g_slave_use_struct => false,
g_slave_mode => g_interface_mode,
g_slave_granularity => g_address_granularity)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
sl_cyc_i => wb_cyc_i,
sl_stb_i => wb_stb_i,
sl_we_i => wb_we_i,
sl_adr_i => wb_adr_i,
sl_sel_i => wb_sel_i,
sl_dat_i => wb_dat_i,
sl_dat_o => wb_dat_o,
sl_ack_o => wb_ack_o,
sl_stall_o => wb_stall_o,
master_i => wb_out,
master_o => wb_in);
wb_out.err <= '0';
wb_out.rty <= '0';
wb_out.stall <= '0';
wb_out.int <= '0';
regs_out <= regs_out_local or regs_out_flash;
U_WB_SLAVE : svec_xloader_wb
port map (
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
wb_adr_i => wb_in.adr(2 downto 0),
wb_dat_i => wb_in.dat(31 downto 0),
wb_dat_o => wb_out.dat(31 downto 0),
wb_cyc_i => wb_in.cyc,
wb_sel_i => wb_in.sel(3 downto 0),
wb_stb_i => wb_in.stb,
wb_we_i => wb_in.we,
wb_ack_o => wb_out.ack,
regs_o => regs_in,
regs_i => regs_out);
end behavioral;
-----------------------------------------------------------------------------
-- 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;
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for SVEC FPGA loader
---------------------------------------------------------------------------------------
-- File : svec_xloader_wb.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;
use work.sxldr_wbgen2_pkg.all;
entity 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_stall_o : out std_logic;
regs_i : in t_sxldr_in_registers;
regs_o : out t_sxldr_out_registers
);
end svec_xloader_wb;
architecture syn of svec_xloader_wb is
signal sxldr_csr_start_dly0 : std_logic ;
signal sxldr_csr_start_int : std_logic ;
signal sxldr_csr_msbf_int : std_logic ;
signal sxldr_csr_swrst_dly0 : std_logic ;
signal sxldr_csr_swrst_int : std_logic ;
signal sxldr_csr_exit_dly0 : std_logic ;
signal sxldr_csr_exit_int : std_logic ;
signal sxldr_csr_clkdiv_int : std_logic_vector(5 downto 0);
signal sxldr_far_xfer_int : std_logic ;
signal sxldr_far_cs_int : std_logic ;
signal sxldr_fifo_rst_n : std_logic ;
signal sxldr_fifo_in_int : std_logic_vector(34 downto 0);
signal sxldr_fifo_out_int : std_logic_vector(34 downto 0);
signal sxldr_fifo_wrreq_int : std_logic ;
signal sxldr_fifo_full_int : std_logic ;
signal sxldr_fifo_empty_int : std_logic ;
signal sxldr_fifo_clear_bus_int : std_logic ;
signal sxldr_fifo_usedw_int : std_logic_vector(7 downto 0);
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(2 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments. For (foreseen) compatibility with other bus standards.
wrdata_reg <= wb_dat_i;
bwsel_reg <= wb_sel_i;
rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i));
wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i);
allones <= (others => '1');
allzeros <= (others => '0');
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
sxldr_csr_start_int <= '0';
sxldr_csr_msbf_int <= '0';
sxldr_csr_swrst_int <= '0';
sxldr_csr_exit_int <= '0';
sxldr_csr_clkdiv_int <= "000000";
regs_o.btrigr_wr_o <= '0';
regs_o.far_data_load_o <= '0';
sxldr_far_xfer_int <= '0';
sxldr_far_cs_int <= '0';
sxldr_fifo_clear_bus_int <= '0';
sxldr_fifo_wrreq_int <= '0';
elsif rising_edge(clk_sys_i) then
-- advance the ACK generator shift register
ack_sreg(8 downto 0) <= ack_sreg(9 downto 1);
ack_sreg(9) <= '0';
if (ack_in_progress = '1') then
if (ack_sreg(0) = '1') then
sxldr_csr_start_int <= '0';
sxldr_csr_swrst_int <= '0';
sxldr_csr_exit_int <= '0';
regs_o.btrigr_wr_o <= '0';
regs_o.far_data_load_o <= '0';
sxldr_fifo_wrreq_int <= '0';
sxldr_fifo_clear_bus_int <= '0';
ack_in_progress <= '0';
else
regs_o.btrigr_wr_o <= '0';
regs_o.far_data_load_o <= '0';
end if;
else
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(2 downto 0) is
when "000" =>
if (wb_we_i = '1') then
sxldr_csr_start_int <= wrdata_reg(0);
sxldr_csr_msbf_int <= wrdata_reg(4);
sxldr_csr_swrst_int <= wrdata_reg(5);
sxldr_csr_exit_int <= wrdata_reg(6);
sxldr_csr_clkdiv_int <= wrdata_reg(13 downto 8);
end if;
rddata_reg(0) <= 'X';
rddata_reg(1) <= regs_i.csr_done_i;
rddata_reg(2) <= regs_i.csr_error_i;
rddata_reg(3) <= regs_i.csr_busy_i;
rddata_reg(4) <= sxldr_csr_msbf_int;
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(13 downto 8) <= sxldr_csr_clkdiv_int;
rddata_reg(7) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when "001" =>
if (wb_we_i = '1') then
regs_o.btrigr_wr_o <= '1';
end if;
rddata_reg(0) <= 'X';
rddata_reg(1) <= 'X';
rddata_reg(2) <= 'X';
rddata_reg(3) <= 'X';
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010" =>
if (wb_we_i = '1') then
regs_o.far_data_load_o <= '1';
sxldr_far_xfer_int <= wrdata_reg(8);
sxldr_far_cs_int <= wrdata_reg(10);
end if;
rddata_reg(7 downto 0) <= regs_i.far_data_i;
rddata_reg(8) <= sxldr_far_xfer_int;
rddata_reg(9) <= regs_i.far_ready_i;
rddata_reg(10) <= sxldr_far_cs_int;
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.idr_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "100" =>
if (wb_we_i = '1') then
sxldr_fifo_in_int(1 downto 0) <= wrdata_reg(1 downto 0);
sxldr_fifo_in_int(2) <= wrdata_reg(2);
end if;
rddata_reg(0) <= 'X';
rddata_reg(1) <= 'X';
rddata_reg(2) <= 'X';
rddata_reg(3) <= 'X';
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "101" =>
if (wb_we_i = '1') then
sxldr_fifo_in_int(34 downto 3) <= wrdata_reg(31 downto 0);
sxldr_fifo_wrreq_int <= '1';
end if;
rddata_reg(0) <= 'X';
rddata_reg(1) <= 'X';
rddata_reg(2) <= 'X';
rddata_reg(3) <= 'X';
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "110" =>
if (wb_we_i = '1') then
if (rddata_reg(18) = '1') then
sxldr_fifo_clear_bus_int <= '1';
end if;
end if;
rddata_reg(16) <= sxldr_fifo_full_int;
rddata_reg(17) <= sxldr_fifo_empty_int;
rddata_reg(7 downto 0) <= sxldr_fifo_usedw_int;
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end process;
-- Drive the data output bus
wb_dat_o <= rddata_reg;
-- Start configuration
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
sxldr_csr_start_dly0 <= '0';
regs_o.csr_start_o <= '0';
elsif rising_edge(clk_sys_i) then
sxldr_csr_start_dly0 <= sxldr_csr_start_int;
regs_o.csr_start_o <= sxldr_csr_start_int and (not sxldr_csr_start_dly0);
end if;
end process;
-- Configuration done
-- Configuration error
-- Loader busy
-- Byte order select
regs_o.csr_msbf_o <= sxldr_csr_msbf_int;
-- Software resest
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
sxldr_csr_swrst_dly0 <= '0';
regs_o.csr_swrst_o <= '0';
elsif rising_edge(clk_sys_i) then
sxldr_csr_swrst_dly0 <= sxldr_csr_swrst_int;
regs_o.csr_swrst_o <= sxldr_csr_swrst_int and (not sxldr_csr_swrst_dly0);
end if;
end process;
-- Exit bootloader mode
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
sxldr_csr_exit_dly0 <= '0';
regs_o.csr_exit_o <= '0';
elsif rising_edge(clk_sys_i) then
sxldr_csr_exit_dly0 <= sxldr_csr_exit_int;
regs_o.csr_exit_o <= sxldr_csr_exit_int and (not sxldr_csr_exit_dly0);
end if;
end process;
-- Serial clock divider
regs_o.csr_clkdiv_o <= sxldr_csr_clkdiv_int;
-- Trigger Sequence Input
-- pass-through field: Trigger Sequence Input in register: Bootloader Trigger Register
regs_o.btrigr_o <= wrdata_reg(7 downto 0);
-- SPI Data
regs_o.far_data_o <= wrdata_reg(7 downto 0);
-- SPI Start Transfer
regs_o.far_xfer_o <= sxldr_far_xfer_int;
-- SPI Ready
-- SPI Chip Select
regs_o.far_cs_o <= sxldr_far_cs_int;
-- Identification code
-- extra code for reg/fifo/mem: Bitstream FIFO
regs_o.fifo_xsize_o <= sxldr_fifo_out_int(1 downto 0);
regs_o.fifo_xlast_o <= sxldr_fifo_out_int(2);
regs_o.fifo_xdata_o <= sxldr_fifo_out_int(34 downto 3);
sxldr_fifo_rst_n <= rst_n_i and (not sxldr_fifo_clear_bus_int);
sxldr_fifo_INST : wbgen2_fifo_sync
generic map (
g_size => 256,
g_width => 35,
g_usedw_size => 8
)
port map (
rd_req_i => regs_i.fifo_rd_req_i,
rd_full_o => regs_o.fifo_rd_full_o,
rd_empty_o => regs_o.fifo_rd_empty_o,
wr_full_o => sxldr_fifo_full_int,
wr_empty_o => sxldr_fifo_empty_int,
wr_usedw_o => sxldr_fifo_usedw_int,
wr_req_i => sxldr_fifo_wrreq_int,
rst_n_i => sxldr_fifo_rst_n,
clk_i => clk_sys_i,
wr_data_i => sxldr_fifo_in_int,
rd_data_o => sxldr_fifo_out_int
);
-- extra code for reg/fifo/mem: FIFO 'Bitstream FIFO' data input register 0
-- extra code for reg/fifo/mem: FIFO 'Bitstream FIFO' data input register 1
rwaddr_reg <= wb_adr_i;
wb_stall_o <= (not ack_sreg(0)) and (wb_stb_i and wb_cyc_i);
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
end syn;
-- -*- 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;
-------------------------------------------------------------------------------
-- Title : Xilinx FPGA Loader
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : xilinx_loader.vhd
-- Author : Tomasz Włostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-01-30
-- Last update : 2013-01-24
-- Platform : FPGA-generic
-- Standard : VHDL '93
-- Dependencies : none
-------------------------------------------------------------------------------
-- Description: A stripped-down version of the Wishbone Xilinx serial port
-- bitstream loader from general-cores library. Does not have Wishbone interface,
-- but it is driven direclty by the flash booting FSM.
-------------------------------------------------------------------------------
--
-- 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
--
-------------------------------------------------------------------------------
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
entity xilinx_loader is
port (
-- system clock
clk_sys_i : in std_logic;
-- synchronous reset, active LOW
rst_n_i : in std_logic;
csr_swrst_i : in std_logic;
csr_start_i : in std_logic;
csr_clk_div_i : in std_logic_vector(6 downto 0);
csr_data_i : in std_logic_vector(31 downto 0);
csr_dsize_i : in std_logic_vector(1 downto 0);
csr_msbf_i : in std_logic;
csr_dlast_i : in std_logic;
csr_error_o : out std_logic;
csr_done_o : out std_logic;
csr_rd_o : out std_logic;
csr_empty_i : in std_logic;
csr_startup_i : in std_logic;
csr_busy_o : out std_logic;
-- Configuration clock (to pin CCLK)
xlx_cclk_o : out std_logic := '0';
-- Data output (to pin D0/DIN)
xlx_din_o : out std_logic;
-- Program enable pin (active low, to pin PROG_B)
xlx_program_b_o : out std_logic := '1';
-- Init ready pin (active low, to pin INIT_B)
xlx_init_b_i : in std_logic;
-- Configuration done pin (to pin DONE)
xlx_done_i : in std_logic
);
end xilinx_loader;
architecture behavioral of xilinx_loader is
type t_xloader_state is (IDLE, WAIT_INIT, WAIT_INIT2, READ_FIFO, READ_FIFO2, OUTPUT_BIT, CLOCK_EDGE, WAIT_DONE, EXTEND_PROG, STARTUP_CCLK0, STARTUP_CCLK1, GOT_DONE);
signal state : t_xloader_state;
signal clk_div : unsigned(6 downto 0);
signal tick : std_logic;
signal init_b_synced : std_logic;
signal done_synced : std_logic;
signal timeout_counter : unsigned(20 downto 0);
-- PROG_B assertion duration
constant c_MIN_PROG_DELAY : unsigned(timeout_counter'left downto 0) := to_unsigned(1000, timeout_counter'length);
-- PROG_B active to INIT_B active timeout
constant c_INIT_TIMEOUT : unsigned(timeout_counter'left downto 0) := to_unsigned(200000, timeout_counter'length);
-- Last word written to DONE active timeout
constant c_DONE_TIMEOUT : unsigned(timeout_counter'left downto 0) := to_unsigned(200000, timeout_counter'length);
-- Number of CCLK cycles after assertion of DONE required to start up the FPGA.
constant c_STARTUP_CYCLES : integer := 1024;
signal d_data : std_logic_vector(31 downto 0);
signal d_size : std_logic_vector(1 downto 0);
signal d_last : std_logic;
signal bit_counter : unsigned(4 downto 0);
signal startup_count : unsigned(20 downto 0);
begin -- behavioral
-- Synchronization chains for async INIT_B and DONE inputs
U_Sync_INIT : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => xlx_init_b_i,
synced_o => init_b_synced);
U_Sync_DONE : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => xlx_done_i,
synced_o => done_synced);
-- Clock divider. Genrates a single-cycle pulse on "tick" signal every
-- CSR.CLKDIV system clock cycles.
p_divide_clock : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
clk_div <= (others => '0');
tick <= '0';
else
if(clk_div = unsigned(csr_clk_div_i)) then
tick <= '1';
clk_div <= (others => '0');
else
tick <= '0';
clk_div <= clk_div + 1;
end if;
end if;
end if;
end process;
p_main_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or csr_swrst_i = '1' then
state <= IDLE;
xlx_program_b_o <= '1';
xlx_cclk_o <= '0';
xlx_din_o <= '0';
timeout_counter <= (others => '0');
csr_done_o <= '0';
csr_error_o <= '0';
else
case state is
when IDLE =>
timeout_counter <= c_INIT_TIMEOUT;
if(csr_start_i = '1') then
xlx_program_b_o <= '0';
csr_done_o <= '0';
csr_error_o <= '0';
state <= EXTEND_PROG;
timeout_counter <= c_MIN_PROG_DELAY;
else
xlx_program_b_o <= '1';
xlx_cclk_o <= '0';
xlx_din_o <= '0';
end if;
when EXTEND_PROG =>
timeout_counter <= timeout_counter-1;
if(timeout_counter = 0) then
timeout_counter <= c_INIT_TIMEOUT;
state <= WAIT_INIT;
end if;
when WAIT_INIT =>
timeout_counter <= timeout_counter - 1;
if(timeout_counter = 0) then
csr_done_o <= '1';
csr_error_o <= '1';
state <= IDLE;
end if;
if (init_b_synced = '0') then
state <= WAIT_INIT2;
xlx_program_b_o <= '1';
end if;
when WAIT_INIT2 =>
if (init_b_synced /= '0') then
state <= READ_FIFO;
end if;
when READ_FIFO =>
xlx_cclk_o <= '0';
if(csr_empty_i = '0') then
state <= READ_FIFO2;
end if;
when READ_FIFO2 =>
if(csr_msbf_i = '0') then
d_data(31 downto 24) <= csr_data_i(7 downto 0);
d_data(23 downto 16) <= csr_data_i(15 downto 8);
d_data(15 downto 8) <= csr_data_i(23 downto 16);
d_data(7 downto 0) <= csr_data_i(31 downto 24); -- little-endian
else
d_data <= csr_data_i;
end if;
d_size <= csr_dsize_i;
d_last <= csr_dlast_i;
if(tick = '1') then
state <= OUTPUT_BIT;
bit_counter <= unsigned(csr_dsize_i) & "111";
end if;
when OUTPUT_BIT =>
if(tick = '1') then
xlx_din_o <= d_data(31);
xlx_cclk_o <= '0';
d_data(d_data'left downto 1) <= d_data(d_data'left-1 downto 0);
if(done_synced = '1') then
state <= GOT_DONE;
else
state <= CLOCK_EDGE;
end if;
end if;
when CLOCK_EDGE =>
if(tick = '1') then
xlx_cclk_o <= '1';
bit_counter <= bit_counter - 1;
if(bit_counter = 0) then
if(d_last = '1') then
state <= WAIT_DONE;
timeout_counter <= c_DONE_TIMEOUT;
else
state <= READ_FIFO;
end if;
else
state <= OUTPUT_BIT;
end if;
end if;
when WAIT_DONE =>
if(done_synced = '1') then
state <= IDLE;
csr_done_o <= '1';
csr_error_o <= '0';
end if;
timeout_counter <= timeout_counter - 1;
if(timeout_counter = 0) then
state <= IDLE;
csr_done_o <= '1';
csr_error_o <= '1';
end if;
-- DONE pin has just been asserted high. Stop loading the bitstream and wait
-- for EXIT command.
when GOT_DONE =>
csr_done_o <= '1';
csr_error_o <= '0';
if(csr_startup_i = '1') then
state <= STARTUP_CCLK0;
startup_count <= (others => '0');
end if;
-- After receiving EXIT command, pulse CCLK for several cycles to initiate the
-- FPGA startup. This is to ensure the freshly configured FPGA keeps all its
-- pins in hi-z mode until the host bootloader is done (for example in VME
-- carriers, where a small FPGA, implementing the bootloader shares the VME bus
-- with the main FPGA.
when STARTUP_CCLK0 =>
xlx_din_o <= '0';
if(tick = '1') then
xlx_cclk_o <= '0';
state <= STARTUP_CCLK1;
end if;
when STARTUP_CCLK1 =>
if(tick = '1') then
xlx_cclk_o <= '1';
if(startup_count = c_STARTUP_CYCLES) then
state <= IDLE;
else
state <= STARTUP_CCLK0;
end if;
startup_count <= startup_count + 1;
end if;
end case;
end if;
end if;
end process;
csr_rd_o <= '1' when ((csr_empty_i = '0') and (state = IDLE or state = READ_FIFO)) else '0';
csr_busy_o <= '0' when (state = IDLE) else '1';
end behavioral;
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / M25P128 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 128Mbit /
// _/_/_/_/_/_/ _/_/_/ / SERIAL FLASH /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.1 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2008 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
`timescale 1ns/1ps
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- TOP LEVEL MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module M25Pxxx (S, C, HOLD, D, Q, Vcc, Vpp_W); //P128
`include "include/DevParam.h"
input S;
input C;
input [`VoltageRange] Vcc;
`ifdef DUAL
inout DQ0;
inout DQ1;
`else
input D;
output Q;
`endif
`ifdef Vpp_pin //M25PX32
input [`VoltageRange] Vpp; `endif
`ifdef HOLD_pin //M25PX32, M25P128
input HOLD; `endif
`ifdef W_pin //M25PE16
input W; `endif
`ifdef RESET_pin //M25PE16
input RESET; `endif
`ifdef Vpp_W_pin //M25P128
input [`VoltageRange] Vpp_W; `endif
parameter [40*8:1] memory_file = "";
//----------------------
// HOLD signal
//----------------------
`ifdef HOLD_pin
reg intHOLD=1;
always @(HOLD) if (S==0 && C==0)
intHOLD = HOLD;
always @(negedge C) if(S==0 && intHOLD!=HOLD)
intHOLD = HOLD;
always @(posedge HOLD) if(S==1)
intHOLD = 1;
always @intHOLD
if(intHOLD==0)
$display("[%0t ns] ==INFO== Hold condition enabled: communication with the device has been paused.", $time);
else if(intHOLD==1)
$display("[%0t ns] ==INFO== Hold condition disabled: communication with the device has been activated.", $time);
`endif
//-------------------------
// Internal signals
//-------------------------
reg busy=0;
reg [2:0] ck_count = 0; //clock counter (modulo 8)
reg reset_by_powerOn = 1; //reset_by_powerOn is updated in "Power Up & Voltage check" section
`ifdef RESET_pin
assign int_reset = !RESET || reset_by_powerOn;
`else
assign int_reset = reset_by_powerOn;
`endif
`ifdef HOLD_pin
assign logicOn = !int_reset && !S && intHOLD;
`else
assign logicOn = !int_reset && !S;
`endif
reg deep_power_down = 0; //updated in "Deep power down" processes
reg ReadAccessOn = 0;
wire WriteAccessOn;
// indicate type of data that will be latched by the model:
// C=command , A=address , D=data, N=none, Y=dummy, F=dual_input(F=fast)
reg [8:1] latchingMode = "N";
reg [cmdDim-1:0] cmd='h0;
reg [addrDimLatch-1:0] addrLatch='h0;
reg [addrDim-1:0] addr='h0;
reg [dataDim-1:0] data='h0;
reg [dataDim-1:0] dataOut='h0;
//---------------------------------------
// Vpp_W signal : write protect feature
//---------------------------------------
`ifdef Vpp_W_pin
assign W_int = ( Vpp_W>=Vcc_min && Vpp_W!=='hX && Vpp_W!=='hZ ) ? 1 : 0;
`endif
//----------------------------
// CUI decoders istantiation
//----------------------------
`include "include/Decoders.h"
//---------------------------
// Modules istantiations
//---------------------------
Memory mem ();
UtilFunctions f ();
Program prog ();
StatusRegister stat ();
Read read ();
LockManager lock ();
`ifdef timingChecks
`ifdef M25PX32
TimingCheck timeCheck (S, C, `D, `Q, HOLD);
`elsif M25PE16
TimingCheck timeCheck (S, C, `D, `Q, W, RESET);
`elsif M25P128
TimingCheck timeCheck (S, C, `D, `Q, W_int, HOLD);
`endif
`endif
`ifdef DUAL
DualOps dual (S, C, ck_count, `D, `Q); `endif
`ifdef OTP
OTP_memory OTP (); `endif
//----------------------------------
// Signals for latching control
//----------------------------------
integer iCmd, iAddr, iData;
always @(negedge S) begin : CP_latchInit
latchingMode = "C";
ck_count = 0;
iCmd = cmdDim - 1;
iAddr = addrDimLatch - 1;
iData = dataDim - 1;
end
always @(posedge C) if(logicOn)
ck_count = ck_count + 1;
//-------------------------
// Latching commands
//-------------------------
event cmdLatched;
always @(posedge C) if(logicOn && latchingMode=="C") begin : CP_latchCmd
cmd[iCmd] = `D;
if (iCmd>0)
iCmd = iCmd - 1;
else if(iCmd==0) begin
latchingMode = "N";
-> cmdLatched;
end
end
//-------------------------
// Latching address
//-------------------------
event addrLatched;
always @(posedge C) if (logicOn && latchingMode=="A") begin : CP_latchAddr
addrLatch[iAddr] = `D;
if (iAddr>0)
iAddr = iAddr - 1;
else if(iAddr==0) begin
latchingMode = "N";
addr = addrLatch[addrDim-1:0];
-> addrLatched;
end
end
//-----------------
// Latching data
//-----------------
event dataLatched;
always @(posedge C) if (logicOn && latchingMode=="D") begin : CP_latchData
data[iData] = `D;
if (iData>0)
iData = iData-1;
else begin
-> dataLatched;
$display(" [%0t ns] Data latched: %h", $time, data);
iData=dataDim-1;
end
end
//-----------------
// Latching dummy
//-----------------
event dummyLatched;
always @(posedge C) if (logicOn && latchingMode=="Y") begin : CP_latchDummy
data[iData] = `D;
if (iData>0)
iData = iData-1;
else begin
-> dummyLatched;
$display(" [%0t ns] Dummy byte latched.", $time);
iData=dataDim-1;
end
end
//------------------------------
// Commands recognition control
//------------------------------
event codeRecognized, seqRecognized, startCUIdec;
reg [30*8:1] cmdRecName;
always @(cmdLatched) fork : CP_cmdRecControl
-> startCUIdec; // i CUI decoders si devono attivare solo dopo
// che e' partito il presente processo
begin : ok
@(codeRecognized or seqRecognized)
disable error;
end
begin : error
#0;
#0; //wait until CUI decoders execute recognition process (2 delta time maximum)
if (busy)
$display("[%0t ns] **WARNING** Device is busy. Command not accepted.", $time);
else if (deep_power_down)
$display("[%0t ns] **WARNING** Deep power down mode. Command not accepted.", $time);
else if (!ReadAccessOn || !WriteAccessOn)
$display("[%0t ns] **WARNING** Power up is ongoing. Command not accepted.", $time);
else if (!busy)
$display("[%0t ns] **ERROR** Command Not Recognized.", $time);
disable ok;
end
join
//--------------------------
// Power Up & Voltage check
//--------------------------
//--- Reset internal logic (latching disabled when Vcc<Vcc_wi)
assign Vcc_L1 = (Vcc>=Vcc_wi) ? 1 : 0 ;
always @Vcc_L1
if (reset_by_powerOn && Vcc_L1)
reset_by_powerOn = 0;
else if (!reset_by_powerOn && !Vcc_L1)
reset_by_powerOn = 1;
//--- Read access
assign Vcc_L2 = (Vcc>=Vcc_min) ? 1 : 0 ;
always @Vcc_L2 if(Vcc_L2 && ReadAccessOn==0) fork : CP_powUp_ReadAccess
begin : p1
#read_access_power_up_delay;
$display("[%0t ns] ==INFO== Power up: read access enabled.", $time);
ReadAccessOn=1;
deep_power_down=0;
disable p2;
end
begin : p2
@Vcc_L2 if(!Vcc_L2)
disable p1;
end
join
//--- Write access
reg WriteAccessCondition = 0;
always @Vcc_L1 if (WriteAccessCondition==0 && Vcc_L1) fork : CP_powUp_WriteAccess
begin : p1
#write_access_power_up_delay;
$display("[%0t ns] ==INFO== Power up: write access enabled (device fully accessible).", $time);
WriteAccessCondition=1;
disable p2;
end
begin : p2
@Vcc_L1 if(!Vcc_L1)
disable p1;
end
join
assign WriteAccessOn = ReadAccessOn && WriteAccessCondition;
//--- Voltage drop (power down)
always @Vcc_L1 if (!Vcc_L1 && (ReadAccessOn || WriteAccessCondition)) begin : CP_powerDown
$display("[%0t ns] ==INFO== Voltage below the threshold value: device not accessible.", $time);
ReadAccessOn=0;
WriteAccessCondition=0;
end
//--- Voltage fault (used during program and erase operations)
event voltageFault; //used in Program and erase dynamic check (see also "CP_voltageCheck" process)
assign VccOk = (Vcc>=Vcc_min && Vcc<=Vcc_max) ? 1 : 0 ;
always @VccOk if (!VccOk) ->voltageFault; //check is active when device is not reset
//(this is a dynamic check used during program and erase operations)
//---------------------------------
// Vpp (auxiliary voltage) checks
//---------------------------------
`ifdef Vpp_pin
// VppOk true if Vpp is in the range allowing enhanced program/erase
assign VppOk = ( (Vpp>=Vpp_min && Vpp<=Vpp_max) && Vpp!=='dX && Vpp!=='dZ ) ?
1 : 0;
always @(VppOk) if (VppOk)
$display("[%0t ns] ==INFO== Enhanced Program Supply Voltage is OK (%0d mV).", $time, Vpp);
assign VppError = ( !( Vpp===0 || (Vpp>=Vcc_min && Vpp<=Vcc_max) || (Vpp>=Vpp_min && Vpp<=Vpp_max) ) || Vpp==='dX || Vpp==='dZ ) ?
1 : 0;
always @(VppError or ReadAccessOn) if(ReadAccessOn && VppError)
$display("[%0t ns] **WARNING** Vpp should be in VPPH range, or connected to ground, or connected in Vcc range!", $time);
`endif
`ifdef Vpp_W_pin
// VppOk true if Vpp is in the range allowing enhanced program/erase
assign VppOk = ( (Vpp_W>=Vpp_min && Vpp_W<=Vpp_max) && Vpp_W!=='dX && Vpp_W!=='dZ ) ?
1 : 0;
always @(VppOk) if (VppOk)
$display("[%0t ns] ==INFO== Enhanced Program Supply Voltage is OK (%0d mV).", $time, Vpp_W);
assign VppError = ( !( Vpp_W===0 || (Vpp_W>=Vcc_min && Vpp_W<=Vcc_max) || (Vpp_W>=Vpp_min && Vpp_W<=Vpp_max) ) || Vpp_W==='dX || Vpp_W==='dZ ) ?
1 : 0;
always @(VppError or ReadAccessOn) if(ReadAccessOn && VppError)
$display("[%0t ns] **WARNING** Vpp should be in VPPH range, or connected to ground, or connected in Vcc range!", $time);
`endif
//-----------------
// Read execution
//-----------------
reg [addrDim-1:0] readAddr;
reg bitOut='hZ;
event sendToBus;
// values assumed by `D and `Q, when they are not forced
assign `D = 1'bZ;
assign `Q = 1'bZ;
// `Q : release of values assigned with "force statement"
always @(posedge S) #tSHQZ release `Q;
// effect on `Q by HOLD signal
`ifdef HOLD_pin
reg temp;
always @(intHOLD) if(intHOLD===0) begin : CP_HOLD_out_effect
begin : out_effect
temp = `Q;
#tHLQZ;
disable guardian;
release `Q;
@(posedge intHOLD) #tHHQX force `Q=temp;
end
begin : guardian
@(posedge intHOLD)
disable out_effect;
end
end
`endif
// read with `Q out bit
always @(negedge(C)) if(logicOn) begin : CP_read
if(read.enable==1 || read.enable_fast==1) begin
if(ck_count==0) begin
readAddr = mem.memAddr;
mem.readData(dataOut); //read data and increments address
f.out_info(readAddr, dataOut);
end
bitOut = dataOut[dataDim-1-ck_count];
-> sendToBus;
end else if (stat.enable_SR_read==1) begin
if(ck_count==0) begin
dataOut = stat.SR;
f.out_info(readAddr, dataOut);
end
bitOut = dataOut[dataDim-1-ck_count];
-> sendToBus;
`ifdef LockReg
end else if (lock.enable_lockReg_read==1) begin
if(ck_count==0) begin
readAddr = f.sec(addr);
f.out_info(readAddr, dataOut);
end
// dataOut is set in LockManager module
bitOut = dataOut[dataDim-1-ck_count];
-> sendToBus;
`endif
`ifdef OTP
end else if (read.enable_OTP==1) begin
if(ck_count==0) begin
readAddr = 'h0;
readAddr = OTP.addr;
OTP.readData(dataOut); //read data and increments address
f.out_info(readAddr, dataOut);
end
bitOut = dataOut[dataDim-1-ck_count];
-> sendToBus;
`endif
end else if (read.enable_ID==1) begin
if(ck_count==0) begin
readAddr = 'h0;
readAddr = read.ID_index;
if (read.ID_index==0) dataOut=Manufacturer_ID;
else if (read.ID_index==1) dataOut=MemoryType_ID;
else if (read.ID_index==2) dataOut=MemoryCapacity_ID;
if (read.ID_index<=1) read.ID_index=read.ID_index+1;
else read.ID_index=0;
f.out_info(readAddr, dataOut);
end
bitOut = dataOut[dataDim-1-ck_count];
-> sendToBus;
end
end
always @sendToBus fork : CP_sendToBus
#tCLQX force `Q = 1'bX;
#tCLQV
force `Q = bitOut;
join
//-----------------------
// Reset Signal
//-----------------------
event resetEvent; //Activated only in devices with RESET pin.
reg resetDuringDecoding=0; //These two boolean variables are used in TimingCheck
reg resetDuringBusy=0; //entity to check tRHSL timing constraint
`ifdef RESET_pin
always @RESET if (!RESET) begin : CP_reset
->resetEvent;
if(S===0 && !busy)
resetDuringDecoding=1;
else if (busy)
resetDuringBusy=1;
release `Q;
ck_count = 0;
latchingMode = "N";
cmd='h0;
addrLatch='h0;
addr='h0;
data='h0;
dataOut='h0;
iCmd = cmdDim - 1;
iAddr = addrDimLatch - 1;
iData = dataDim - 1;
// commands waiting to be executed are disabled internally
// read enabler are resetted internally, in the read processes
// CUIdecoders are internally disabled by reset signal
#0 $display("[%0t ns] ==INFO== Reset Signal has been driven low : internal logic will be reset.", $time);
end
`endif
//-----------------------
// Deep power down
//-----------------------
`ifdef PowDown
always @seqRecognized if (cmdRecName=="Deep Power Down") fork : CP_deepPowerDown
begin : exe
@(posedge S);
disable reset;
busy=1;
$display(" [%0t ns] Device is entering in deep power down mode...",$time);
#deep_power_down_delay;
$display(" [%0t ns] ...power down mode activated.",$time);
busy=0;
deep_power_down=1;
end
begin : reset
@resetEvent;
disable exe;
end
join
always @seqRecognized if (cmdRecName=="Release Deep Power Down") fork : CP_releaseDeepPowerDown
begin : exe
@(posedge S);
disable reset;
busy=1;
$display(" [%0t ns] Release from deep power down is ongoing...",$time);
#release_power_down_delay;
$display(" [%0t ns] ...release from power down mode completed.",$time);
busy=0;
deep_power_down=0;
end
begin : reset
@resetEvent;
disable exe;
end
join
`endif
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- CUI DECODER --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module CUIdecoder (cmdAllowed);
`include "include/DevParam.h"
input cmdAllowed;
parameter [30*8:1] cmdName = "Write Enable";
parameter [cmdDim-1:0] cmdCode = 'h06;
parameter withAddr = 1'b0; // 0 -> command with address / 1 -> without address
always @M25Pxxx.startCUIdec if (cmdAllowed && cmdCode==M25Pxxx.cmd) begin
if(!withAddr) begin
M25Pxxx.cmdRecName = cmdName;
$display("[%0t ns] COMMAND RECOGNIZED: %0s.", $time, cmdName);
-> M25Pxxx.seqRecognized;
end else if (withAddr) begin
M25Pxxx.latchingMode = "A";
$display("[%0t ns] COMMAND RECOGNIZED: %0s. Address expected ...", $time, cmdName);
-> M25Pxxx.codeRecognized;
fork : proc1
@(M25Pxxx.addrLatched) begin
if (cmdName!="Read OTP" && cmdName!="Program OTP")
$display(" [%0t ns] Address latched: %h (byte %0d of page %0d, sector %0d)", $time,
M25Pxxx.addr, f.col(M25Pxxx.addr), f.pag(M25Pxxx.addr), f.sec(M25Pxxx.addr));
else
$display(" [%0t ns] Address latched: column %0d", $time, M25Pxxx.addr);
M25Pxxx.cmdRecName = cmdName;
-> M25Pxxx.seqRecognized;
disable proc1;
end
@(posedge M25Pxxx.S) begin
$display(" - [%0t ns] S high: command aborted", $time);
disable proc1;
end
@(M25Pxxx.resetEvent or M25Pxxx.voltageFault) begin
disable proc1;
end
join
end
end
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- MEMORY MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module Memory;
`include "include/DevParam.h"
//-----------------------------
// data structures definition
//-----------------------------
reg [dataDim-1:0] memory [0:memDim-1];
reg [dataDim-1:0] page [0:pageDim];
//------------------------------
// Memory management variables
//------------------------------
reg [addrDim-1:0] memAddr;
reg [addrDim-1:0] pageStartAddr;
reg [colAddrDim-1:0] pageIndex = 'h0;
reg [colAddrDim-1:0] zeroIndex = 'h0;
integer i;
//-----------
// Init
//-----------
initial begin
for (i=0; i<=memDim-1; i=i+1)
memory[i] = data_NP;
if ( M25Pxxx.memory_file!="" && M25Pxxx.memory_file!=" ") begin
$readmemh(M25Pxxx.memory_file, memory);
$display("[%0t ns] ==INFO== Load memory content from file: \"%0s\".", $time, M25Pxxx.memory_file);
end
end
//-----------------------------------------
// Task used in program & read operations
//-----------------------------------------
// set start address & page index
// (for program and read operations)
task setAddr;
input [addrDim-1:0] addr;
begin
memAddr = addr;
pageStartAddr = {addr[addrDim-1:pageAddr_inf], zeroIndex};
pageIndex = addr[colAddrDim-1:0];
end
endtask
// reset page with FF data
task resetPage;
for (i=0; i<=pageDim-1; i=i+1)
page[i] = data_NP;
endtask
// in program operations data latched
// are written in page buffer
task writeDataToPage;
input [dataDim-1:0] data;
reg [addrDim-1:0] destAddr;
begin
page[pageIndex] = data;
pageIndex = pageIndex + 1;
end
endtask
// page buffer is written to the memory
task programPageToMemory; //logic and between old_data and new_data
for (i=0; i<=pageDim-1; i=i+1)
memory[pageStartAddr+i] = memory[pageStartAddr+i] & page[i];
// before page program the page should be reset
endtask
// in read operations data are readed directly from the memory
task readData;
output [dataDim-1:0] data;
begin
data = memory[memAddr];
if (memAddr < memDim-1)
memAddr = memAddr + 1;
else begin
memAddr=0;
$display(" [%0t ns] **WARNING** Highest address reached. Next read will be at the beginning of the memory!", $time);
end
end
endtask
//---------------------------------------
// Tasks used for Page Write operation
//---------------------------------------
// page is written into the memory (old_data are over_written)
task writePageToMemory;
for (i=0; i<=pageDim-1; i=i+1)
memory[pageStartAddr+i] = page[i];
// before page program the page should be reset
endtask
// pageMemory is loaded into the pageBuffer
task loadPageBuffer;
for (i=0; i<=pageDim-1; i=i+1)
page[i] = memory[pageStartAddr+i];
// before page program the page should be reset
endtask
//-----------------------------
// Tasks for erase operations
//-----------------------------
task eraseSector;
input [addrDim-1:0] A;
reg [sectorAddrDim-1:0] sect;
reg [sectorAddr_inf-1:0] zeros;
reg [addrDim-1:0] mAddr;
begin
sect = f.sec(A);
zeros = 'h0;
mAddr = {sect, zeros};
for(i=mAddr; i<=(mAddr+sectorSize-1); i=i+1)
memory[i] = data_NP;
end
endtask
`ifdef SubSect
task eraseSubsector;
input [addrDim-1:0] A;
reg [subsecAddrDim-1:0] subsect;
reg [subsecAddr_inf-1:0] zeros;
reg [addrDim-1:0] mAddr;
begin
subsect = f.sub(A);
zeros = 'h0;
mAddr = {subsect, zeros};
for(i=mAddr; i<=(mAddr+subsecSize-1); i=i+1)
memory[i] = data_NP;
end
endtask
`endif
task eraseBulk;
for (i=0; i<=memDim-1; i=i+1)
memory[i] = data_NP;
endtask
task erasePage;
input [addrDim-1:0] A;
reg [pageAddrDim-1:0] page;
reg [pageAddr_inf-1:0] zeros;
reg [addrDim-1:0] mAddr;
begin
page = f.pag(A);
zeros = 'h0;
mAddr = {page, zeros};
for(i=mAddr; i<=(mAddr+pageDim-1); i=i+1)
memory[i] = data_NP;
end
endtask
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- UTILITY FUNCTIONS --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module UtilFunctions;
`include "include/DevParam.h"
integer i;
//----------------------------------
// Utility functions for addresses
//----------------------------------
function [sectorAddrDim-1:0] sec;
input [addrDim-1:0] A;
sec = A[sectorAddr_sup:sectorAddr_inf];
endfunction
`ifdef SubSect
function [subsecAddrDim-1:0] sub;
input [addrDim-1:0] A;
sub = A[subsecAddr_sup:subsecAddr_inf];
endfunction
`endif
function [pageAddrDim-1:0] pag;
input [addrDim-1:0] A;
pag = A[pageAddr_sup:pageAddr_inf];
endfunction
function [pageAddrDim-1:0] col;
input [addrDim-1:0] A;
col = A[colAddr_sup:0];
endfunction
//----------------------------------
// Console messages
//----------------------------------
task clock_error;
$display(" [%0t ns] **WARNING** Number of clock pulse isn't multiple of eight: operation aborted!", $time);
endtask
task WEL_error;
$display(" [%0t ns] **WARNING** WEL bit not set: operation aborted!", $time);
endtask
task out_info;
input [addrDim-1:0] A;
input [dataDim-1:0] D;
if (read.enable || read.enable_fast)
$display(" [%0t ns] Data are going to be output: %h. [Read Memory. Address %h (byte %0d of page %0d, sector %0d)] ",
$time, D, A, col(A), pag(A), sec(A));
`ifdef DUAL
else if (read.enable_dual)
$display(" [%0t ns] Data are going to be output: %h. [Read Memory. Address %h (byte %0d of page %0d, sector %0d)] ",
$time, D, A, col(A), pag(A), sec(A));
`endif
else if (stat.enable_SR_read)
$display(" [%0t ns] Data are going to be output: %b. [Read Status Register]",
$time, D);
`ifdef LockReg
else if (lock.enable_lockReg_read)
$display(" [%0t ns] Data are going to be output: %h. [Read Lock Register of sector %0d]",
$time, D, A);
`endif
else if (read.enable_ID)
$display(" [%0t ns] Data are going to be output: %h. [Read ID, byte %0d]", $time, D, A);
`ifdef OTP
else if (read.enable_OTP) begin
if (A!=OTP_dim-1)
$display(" [%0t ns] Data are going to be output: %h. [Read OTP memory, column %0d]", $time, D, A);
else
$display(" [%0t ns] Data are going to be output: %b. [Read OTP memory, column %0d (control byte)]", $time, D, A);
end
`endif
endtask
//----------------------------------------------------
// Special tasks used for testing and debug the model
//----------------------------------------------------
//
// erase the whole memory, and resets pageBuffer and cacheBuffer
//
task fullErase;
begin
for (i=0; i<=memDim-1; i=i+1)
mem.memory[i] = data_NP;
$display("[%0t ns] ==INFO== The whole memory has been erased.", $time);
end
endtask
//
// unlock all sectors of the memory
//
task unlockAll;
begin
for (i=0; i<=nSector-1; i=i+1) begin
`ifdef LockReg
lock.LockReg_WL[i] = 0;
lock.LockReg_LD[i] = 0;
`endif
lock.lock_by_SR[i] = 0;
end
$display("[%0t ns] ==INFO== The whole memory has been unlocked.", $time);
end
endtask
//
// load memory file
//
task load_memory_file;
input [40*8:1] memory_file;
begin
for (i=0; i<=memDim-1; i=i+1)
mem.memory[i] = data_NP;
$readmemh(memory_file, mem.memory);
$display("[%0t ns] ==INFO== Load memory content from file: \"%0s\".", $time, M25Pxxx.memory_file);
end
endtask
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- PROGRAM MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module Program;
`include "include/DevParam.h"
event errorCheck, error, noError;
reg [30*8:1] operation; //get the value of the command currently decoded by CUI decoders
time delay;
//----------------------------
// Page Program & Page Write
//----------------------------
reg writePage_en=0;
reg [addrDim-1:0] destAddr;
always @M25Pxxx.seqRecognized
if(M25Pxxx.cmdRecName==="Page Program" || M25Pxxx.cmdRecName==="Dual Program" || M25Pxxx.cmdRecName==="Page Write")
fork : program_ops
begin
operation = M25Pxxx.cmdRecName;
if(operation!="Page Write")
mem.resetPage;
destAddr = M25Pxxx.addr;
mem.setAddr(destAddr);
if(operation=="Page Write")
mem.loadPageBuffer;
if(operation=="Page Program" || operation=="Page Write")
M25Pxxx.latchingMode="D";
else if(operation=="Dual Program") begin
M25Pxxx.latchingMode="F";
release M25Pxxx.`Q;
end
writePage_en = 1;
end
begin : exe
@(posedge M25Pxxx.S);
disable reset;
writePage_en=0;
M25Pxxx.latchingMode="N";
M25Pxxx.busy=1;
$display(" [%0t ns] Command execution begins: %0s.", $time, operation);
if (operation!="Page Write")
delay=program_delay;
`ifdef M25PE16
else if (operation=="Page Write")
delay=page_write_delay; `endif
-> errorCheck;
@(noError) begin
mem.writePageToMemory;
$display(" [%0t ns] Command execution completed: %0s.", $time, operation);
end
end
begin : reset
@M25Pxxx.resetEvent;
writePage_en=0;
operation = "None";
disable exe;
end
join
always @M25Pxxx.dataLatched if(writePage_en) begin
mem.writeDataToPage(M25Pxxx.data);
end
//------------------------
// Write Status register
//------------------------
reg [dataDim-1:0] SR_data;
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Write SR") begin : write_SR_ops
M25Pxxx.latchingMode="D";
@(posedge M25Pxxx.S) begin
operation=M25Pxxx.cmdRecName;
SR_data=M25Pxxx.data;
M25Pxxx.latchingMode="N";
M25Pxxx.busy=1;
$display(" [%0t ns] Command execution begins: Write SR.",$time);
delay=write_SR_delay;
-> errorCheck;
@(noError) begin
`ifdef M25PX32
`LOTP=SR_data[7];
`else //M25PE16, M25P128
`SRWD=SR_data[7]; `endif
`ifdef M25PX32
`TB=SR_data[5]; `endif //(TB is not used in M25PE16)
`BP2=SR_data[4];
`BP1=SR_data[3];
`BP0=SR_data[2];
`ifdef M25PX32
$display(" [%0t ns] Command execution completed: Write SR. SR=%h, (LOTP,TB,BP2,BP1,BP0)=%b",
$time, stat.SR, {`LOTP,`TB,`BP2,`BP1,`BP0} );
`else //M25PE16, M25P128
$display(" [%0t ns] Command execution completed: Write SR. SR=%h, (SRWD,BP2,BP1,BP0)=%b",
$time, stat.SR, {`SRWD,`BP2,`BP1,`BP0} );
`endif
end
end
end
//--------------
// Erase
//--------------
always @M25Pxxx.seqRecognized
if (M25Pxxx.cmdRecName==="Sector Erase" || M25Pxxx.cmdRecName==="Subsector Erase" ||
M25Pxxx.cmdRecName==="Bulk Erase" || M25Pxxx.cmdRecName==="Page Erase") fork : erase_ops
begin : exe
@(posedge M25Pxxx.S);
disable reset;
operation = M25Pxxx.cmdRecName;
destAddr = M25Pxxx.addr;
M25Pxxx.latchingMode="N";
M25Pxxx.busy = 1;
$display(" [%0t ns] Command execution begins: %0s.", $time, operation);
if (operation=="Sector Erase") delay=erase_delay;
else if (operation=="Bulk Erase") delay=erase_bulk_delay;
`ifdef M25PE16
else if (operation=="Page Erase") delay=erase_page_delay; `endif
`ifdef SubSect
else if (operation=="Subsector Erase") delay=erase_ss_delay; `endif
-> errorCheck;
@(noError) begin
if (operation=="Sector Erase") mem.eraseSector(destAddr);
else if (operation=="Bulk Erase") mem.eraseBulk;
else if (operation=="Page Erase") mem.erasePage(destAddr);
`ifdef SubSect
else if (operation=="Subsector Erase") mem.eraseSubsector(destAddr); `endif
$display(" [%0t ns] Command execution completed: %0s.", $time, operation);
end
end
begin : reset
@M25Pxxx.resetEvent;
operation = "None";
disable exe;
end
join
//---------------------------
// Program OTP (ifdef OTP)
//---------------------------
`ifdef OTP
reg write_OTP_buffer_en=0;
`define OTP_lockBit M25Pxxx.OTP.mem[OTP_dim-1][0]
always @M25Pxxx.seqRecognized if(M25Pxxx.cmdRecName=="Program OTP")
fork : OTP_prog_ops
begin
OTP.resetBuffer;
OTP.setAddr(M25Pxxx.addr);
M25Pxxx.latchingMode="D";
write_OTP_buffer_en = 1;
end
begin : exe
@(posedge M25Pxxx.S);
disable reset;
operation=M25Pxxx.cmdRecName;
write_OTP_buffer_en=0;
M25Pxxx.latchingMode="N";
M25Pxxx.busy=1;
$display(" [%0t ns] Command execution begins: OTP Program.",$time);
delay=program_delay;
-> errorCheck;
@(noError) begin
OTP.writeBufferToMemory;
$display(" [%0t ns] Command execution completed: OTP Program.",$time);
end
end
begin : reset
@M25Pxxx.resetEvent;
write_OTP_buffer_en=0;
operation = "None";
disable exe;
end
join
always @M25Pxxx.dataLatched if(write_OTP_buffer_en) begin
OTP.writeDataToBuffer(M25Pxxx.data);
end
`endif
//------------------------
// Error check
//------------------------
// This process also models
// the operation delays
always @(errorCheck) fork : errorCheck_ops
begin : static_check
if(M25Pxxx.ck_count!=0) begin
M25Pxxx.f.clock_error;
-> error;
end else if(`WEL==0) begin
M25Pxxx.f.WEL_error;
-> error;
end else if ( (operation=="Page Program" || operation=="Dual Program" || operation=="Page Write" ||
operation=="Sector Erase" || operation=="Subsector Erase" || operation=="Page Erase")
&&
(lock.isProtected_by_SR(destAddr)!==0 || lock.isProtected_by_lockReg(destAddr)!==0) ) begin
-> error;
if (lock.isProtected_by_SR(destAddr)!==0 && lock.isProtected_by_lockReg(destAddr)!==0)
$display(" [%0t ns] **WARNING** Sector locked by Status Register and by Lock Register: operation aborted.", $time);
else if (lock.isProtected_by_SR(destAddr)!==0)
$display(" [%0t ns] **WARNING** Sector locked by Status Register: operation aborted.", $time);
else if (lock.isProtected_by_lockReg(destAddr)!==0)
$display(" [%0t ns] **WARNING** Sector locked by Lock Register: operation aborted.", $time);
end else if (operation=="Bulk Erase" && lock.isAnySectorProtected(0)) begin
$display(" [%0t ns] **WARNING** Some sectors are locked: bulk erase aborted.", $time);
-> error;
end
`ifdef M25PX32
else if(operation=="Write SR" && `LOTP==1) begin
$display(" [%0t ns] **WARNING** Lock OTP bit set to 1: write SR isn't allowed!", $time);
-> error;
end
`elsif M25PE16
else if(operation=="Write SR" && `SRWD==1 && M25Pxxx.W===0) begin
$display(" [%0t ns] **WARNING** SRWD bit set to 1, and W=0: write SR isn't allowed!", $time);
-> error;
end
`elsif M25P128
else if(operation=="Write SR" && `SRWD==1 && M25Pxxx.W_int===0) begin
$display(" [%0t ns] **WARNING** SRWD bit set to 1, and W=0: write SR isn't allowed!", $time);
-> error;
end
`endif
`ifdef OTP
else if (operation=="Program OTP" && `OTP_lockBit==0) begin
$display(" [%0t ns] **WARNING** OTP is read only, because lock bit has been programmed to 0: operation aborted.", $time);
-> error;
end
`endif
end
fork : dynamicCheck
@(M25Pxxx.voltageFault) begin
$display(" [%0t ns] **WARNING** Operation Fault because of Vcc Out of Range!", $time);
-> error;
end
`ifdef RESET_pin
if (operation!="Write SR") @(M25Pxxx.resetEvent) begin
$display(" [%0t ns] **WARNING** Operation Fault because of Device Reset!", $time);
-> error;
end
`endif
#delay begin
M25Pxxx.busy=0;
-> stat.WEL_reset;
-> noError;
disable dynamicCheck;
disable errorCheck_ops;
end
join
join
always @(error) begin
M25Pxxx.busy = 0;
-> stat.WEL_reset;
disable errorCheck_ops;
if (operation=="Page Program" || operation=="Dual Program" || operation=="Page Write") disable program_ops;
else if (operation=="Sector Erase" || operation=="Subsector Erase" || operation=="Bulk Erase") disable erase_ops;
else if (operation=="Write SR") disable write_SR_ops;
`ifdef OTP
else if (operation=="Program OTP") disable OTP_prog_ops;
`endif
end
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- STATUS REGISTER MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module StatusRegister;
`include "include/DevParam.h"
// status register
reg [7:0] SR;
//--------------
// Init
//--------------
initial begin
//see alias in DevParam.h
SR[2] = 0; // BP0 - block protect bit 0
SR[3] = 0; // BP1 - block protect bit 1
SR[4] = 0; // BP2 - block protect bit 2
SR[5] = 0; // M25PX32: TB (block protect top/bottom) -- M25PE16, M25P128: not used
SR[6] = 0; // not used
SR[7] = 0; // M25PX32: LOTP - M25PE16, M25P128: SRWD
end
always @(M25Pxxx.ReadAccessOn) if(M25Pxxx.ReadAccessOn) begin
SR[0] = 0; // WIP - write in progress
SR[1] = 0; // WEL - write enable latch
end
//----------
// WIP bit
//----------
always @(M25Pxxx.busy)
`WIP = M25Pxxx.busy;
//----------
// WEL bit
//----------
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Write Enable") fork : WREN
begin : exe
@(posedge M25Pxxx.S);
disable reset;
`WEL = 1;
$display(" [%0t ns] Command execution: WEL bit set.", $time);
end
begin : reset
@M25Pxxx.resetEvent;
disable exe;
end
join
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Write Disable") fork : WRDI
begin : exe
@(posedge M25Pxxx.S);
disable reset;
`WEL = 0;
$display(" [%0t ns] Command execution: WEL bit reset.", $time);
end
begin : reset
@M25Pxxx.resetEvent;
disable exe;
end
join
event WEL_reset;
always @(WEL_reset)
`WEL = 0;
//------------------------
// write status register
//------------------------
// see "Program" module
//----------------------
// read status register
//----------------------
// NB : "Read SR" operation is also modelled in M25Pxxx.module
reg enable_SR_read;
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read SR") fork
enable_SR_read=1;
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_SR_read=0;
join
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- READ MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module Read;
`include "include/DevParam.h"
reg enable, enable_fast = 0;
//--------------
// Read
//--------------
// NB : "Read" operation is also modelled in M25Pxxx.module
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read") fork
begin
enable = 1;
mem.setAddr(M25Pxxx.addr);
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable=0;
join
//--------------
// Read Fast
//--------------
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read Fast") fork
begin
mem.setAddr(M25Pxxx.addr);
$display(" [%0t ns] Dummy byte expected ...",$time);
M25Pxxx.latchingMode="Y"; //Y=dummy
@M25Pxxx.dummyLatched;
enable_fast = 1;
M25Pxxx.latchingMode="N";
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_fast=0;
join
//-----------------
// Read ID
//-----------------
reg enable_ID;
reg [1:0] ID_index;
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read ID") fork
begin
enable_ID = 1;
ID_index=0;
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_ID=0;
join
//-------------------------
// Dual Read (ifdef DUAL)
//-------------------------
reg enable_dual=0;
`ifdef DUAL
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Dual Read") fork
begin
mem.setAddr(M25Pxxx.addr);
$display(" [%0t ns] Dummy byte expected ...",$time);
M25Pxxx.latchingMode="Y"; //Y=dummy
@M25Pxxx.dummyLatched;
enable_dual = 1;
M25Pxxx.latchingMode="N";
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_dual=0;
join
`endif
//-------------------------
// Read OTP (ifdef OTP)
//-------------------------
// NB : "Read OTP" operation is also modelled in M25Pxxx.module
reg enable_OTP=0;
`ifdef OTP
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read OTP") fork
begin
enable_OTP = 1;
OTP.setAddr(M25Pxxx.addr);
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_OTP=0;
join
`endif
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- LOCK MANAGER MODULE --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module LockManager;
`include "include/DevParam.h"
//---------------------------------------------------
// Data structures for protection status modelling
//---------------------------------------------------
// array of sectors lock status (status determinated by Block Protect Status Register bits)
reg [nSector-1:0] lock_by_SR; //(1=locked)
`ifdef LockReg
// Lock Registers (there is a pair of Lock Registers for each sector)
reg LockReg_WL [nSector-1:0]; // Lock Register Write Lock bit (1=lock enabled)
reg LockReg_LD [nSector-1:0]; // Lock Register Lock Down bit (1=lock down enabled)
`endif
integer i;
//----------------------------
// Initial protection status
//----------------------------
initial
for (i=0; i<=nSector-1; i=i+1)
lock_by_SR[i] = 0;
//LockReg_WL & LockReg_LD are initialized by powerUp
//------------------------
// Reset signal effects
//------------------------
`ifdef LockReg
always @M25Pxxx.resetEvent
for (i=0; i<=nSector-1; i=i+1) begin
`ifdef M25PX32
LockReg_WL[i]=1;
`elsif M25PE16
LockReg_WL[i]=0;
`endif
LockReg_LD[i] = 0;
end
`endif
//----------------------------------
// Power up : reset lock registers
//----------------------------------
`ifdef LockReg
always @(M25Pxxx.ReadAccessOn) if(M25Pxxx.ReadAccessOn)
for (i=0; i<=nSector-1; i=i+1) begin
`ifdef M25PX32
LockReg_WL[i]=1;
`elsif M25PE16
LockReg_WL[i]=0;
`endif
LockReg_LD[i] = 0;
end
`endif
//------------------------------------------------
// Protection managed by BP status register bits
//------------------------------------------------
integer nLockedSector;
integer temp;
`ifdef M25PX32
always @(`TB or `BP2 or `BP1 or `BP0) begin
for (i=0; i<=nSector-1; i=i+1) //reset lock status of all sectors
lock_by_SR[i] = 0;
temp = {`BP2, `BP1, `BP0};
nLockedSector = 2**(temp-1);
if (nLockedSector>0 && `TB==0) // upper sectors protected
for ( i=nSector-1 ; i>=nSector-nLockedSector ; i=i-1 ) begin
lock_by_SR[i] = 1;
$display(" [%0t ns] ==INFO== Sector %0d locked", $time, i);
end
else if (nLockedSector>0 && `TB==1) // lower sectors protected
for ( i = 0 ; i <= nLockedSector-1 ; i = i+1 ) begin
lock_by_SR[i] = 1;
$display(" [%0t ns] ==INFO== Sector %0d locked", $time, i);
end
end
`else // M25PE16, M25P128
always @(`BP2 or `BP1 or `BP0) begin
for (i=0; i<=nSector-1; i=i+1) //reset lock status of all sectors
lock_by_SR[i] = 0;
temp = {`BP2, `BP1, `BP0};
nLockedSector = 2**(temp-1);
if (nLockedSector>0) // upper sectors protected
for ( i=nSector-1 ; i>=nSector-nLockedSector && i>=0 ; i=i-1 ) begin
lock_by_SR[i] = 1;
$display(" [%0t ns] ==INFO== Sector %0d locked", $time, i);
end
end
`endif
//--------------------------------------
// Protection managed by Lock Register
//--------------------------------------
reg enable_lockReg_read=0;
`ifdef LockReg
reg [sectorAddrDim-1:0] sect;
reg [dataDim-1:0] sectLockReg;
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Write Lock Reg") fork : WRLR
begin : exe1
sect = f.sec(M25Pxxx.addr);
M25Pxxx.latchingMode = "D";
@(M25Pxxx.dataLatched) sectLockReg = M25Pxxx.data;
end
begin : exe2
@(posedge M25Pxxx.S);
disable exe1;
disable reset;
-> stat.WEL_reset;
if(`WEL==0)
M25Pxxx.f.WEL_error;
else if (LockReg_LD[sect]==1)
$display(" [%0t ns] **WARNING** Lock Down bit is set. Write lock register is not allowed!", $time);
else begin
LockReg_LD[sect]=sectLockReg[1];
LockReg_WL[sect]=sectLockReg[0];
$display(" [%0t ns] Command execution: lock register of sector %0d set to (%b,%b)",
$time, sect, LockReg_LD[sect], LockReg_WL[sect] );
end
end
begin : reset
@M25Pxxx.resetEvent;
disable exe1;
disable exe2;
end
join
// Read lock register
always @(M25Pxxx.seqRecognized) if (M25Pxxx.cmdRecName=="Read Lock Reg") fork
begin
sect = f.sec(M25Pxxx.addr);
M25Pxxx.dataOut = {4'b0, LockReg_LD[sect], LockReg_WL[sect]};
enable_lockReg_read=1;
end
@(posedge(M25Pxxx.S) or M25Pxxx.resetEvent or M25Pxxx.voltageFault)
enable_lockReg_read=0;
join
`endif
//-------------------------------------------
// Function to test sector protection status
//-------------------------------------------
function isProtected_by_SR;
input [addrDim-1:0] byteAddr;
reg [sectorAddrDim-1:0] sectAddr;
begin
sectAddr = f.sec(byteAddr);
isProtected_by_SR = lock_by_SR[sectAddr];
end
endfunction
function isProtected_by_lockReg;
input [addrDim-1:0] byteAddr;
reg [sectorAddrDim-1:0] sectAddr;
begin
`ifdef LockReg
sectAddr = f.sec(byteAddr);
isProtected_by_lockReg = LockReg_WL[sectAddr];
`else
isProtected_by_lockReg = 0; //if LockReg is not defined the function return always zero
`endif
end
endfunction
function isAnySectorProtected;
input required;
begin
i=0;
isAnySectorProtected=0;
while(isAnySectorProtected==0 && i<=nSector-1) begin
`ifdef LockReg
isAnySectorProtected=lock_by_SR[i] || LockReg_WL[i];
`else
isAnySectorProtected=lock_by_SR[i]; `endif
i=i+1;
end
end
endfunction
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------
-----------------------------------------------------------
-- --
-- TIMING CHECK --
-- --
-----------------------------------------------------------
-----------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
module TimingCheck (S, C, D, Q, W, H); //P128
`include "include/DevParam.h"
input S, C, D, Q;
`ifdef HOLD_pin
input H; `endif
`ifdef W_pin
input W; `endif
`ifdef Vpp_W_pin
input W; `endif
`ifdef RESET_pin
input R; `endif
`ifdef W_pin
`define W_feature
`elsif Vpp_W_pin
`define W_feature
`endif
time delta; //used for interval measuring
//--------------------------
// Task for timing check
//--------------------------
task check;
input [8*8:1] name; //constraint check
input time interval;
input time constr;
begin
if (interval<constr)
$display("[%0t ns] --TIMING ERROR-- %0s constraint violation. Measured time: %0t ns - Constraint: %0t ns",
$time, name, interval, constr);
end
endtask
//----------------------------
// Istants to be measured
//----------------------------
parameter initialTime = -1000;
time C_high=initialTime, C_low=initialTime;
time S_low=initialTime, S_high=initialTime;
time D_valid=initialTime;
`ifdef HOLD_pin
time H_low=initialTime, H_high=initialTime; `endif
`ifdef RESET_pin
time R_low=initialTime, R_high=initialTime; `endif
`ifdef W_feature
time W_low=initialTime, W_high=initialTime; `endif
//------------------------
// C signal checks
//------------------------
always
@C if(C===0) //posedge(C)
@C if(C===1)
begin
delta = $time - C_low;
check("tCL", delta, tCL);
delta = $time - S_low;
check("tSLCH", delta, tSLCH);
delta = $time - D_valid;
check("tDVCH", delta, tDVCH);
delta = $time - S_high;
check("tSHCH", delta, tSHCH);
// clock frequency checks
delta = $time - C_high;
if (read.enable && delta<TR)
$display("[%0t ns] --TIMING ERROR-- Violation of Max clock frequency (%0d MHz) during READ operation. T_ck_measured=%0d ns, T_clock_min=%0d ns.",
$time, fR, delta, TR);
else if ( (read.enable_fast || read.enable_ID || read.enable_dual || read.enable_OTP ||
stat.enable_SR_read || lock.enable_lockReg_read )
&&
delta<TC )
//else if ( !read.enable && delta<TC ) da verificare
$display("[%0t ns] --TIMING ERROR-- Violation of Max clock frequency (%0d MHz). T_ck_measured=%0d ns, T_clock_min=%0d ns.",
$time, fC, delta, TC);
`ifdef HOLD_pin
delta = $time - H_low;
check("tHLCH", delta, tHLCH);
delta = $time - H_high;
check("tHHCH", delta, tHHCH);
`endif
C_high = $time;
end
always
@C if(C===1) //negedge(C)
@C if(C===0)
begin
delta = $time - C_high;
check("tCH", delta, tCH);
C_low = $time;
end
//------------------------
// S signal checks
//------------------------
always
@S if(S===1) //negedge(S)
@S if(S===0)
begin
delta = $time - C_high;
check("tCHSL", delta, tCHSL);
delta = $time - S_high;
check("tSHSL", delta, tSHSL);
`ifdef W_feature
delta = $time - W_high;
check("tWHSL", delta, tWHSL);
`endif
`ifdef RESET_pin
//check during decoding
if (M25Pxxx.resetDuringDecoding) begin
delta = $time - R_high;
check("tRHSL", delta, tRHSL_1);
M25Pxxx.resetDuringDecoding = 0;
end
//check during program-erase operation
else if ( M25Pxxx.resetDuringBusy && (prog.operation=="Page Program" || prog.operation=="Page Write" ||
prog.operation=="Sector Erase" || prog.operation=="Bulk Erase" || prog.operation=="Page Erase") )
begin
delta = $time - R_high;
check("tRHSL", delta, tRHSL_2);
M25Pxxx.resetDuringBusy = 0;
end
//check during subsector erase
else if ( M25Pxxx.resetDuringBusy && prog.operation=="Subsector Erase" ) begin
delta = $time - R_high;
check("tRHSL", delta, tRHSL_3);
M25Pxxx.resetDuringBusy = 0;
end
//check during WRSR
else if ( M25Pxxx.resetDuringBusy && prog.operation=="Write SR" ) begin
delta = $time - R_high;
check("tRHSL", delta, tRHSL_4);
M25Pxxx.resetDuringBusy = 0;
end
`endif
S_low = $time;
end
always
@S if(S===0) //posedge(S)
@S if(S===1)
begin
delta = $time - C_high;
check("tCHSH", delta, tCHSH);
S_high = $time;
end
//----------------------------
// D signal (data in) checks
//----------------------------
always @D
begin
delta = $time - C_high;
check("tCHDX", delta, tCHDX);
if (isValid(D)) D_valid = $time;
end
//------------------------
// Hold signal checks
//------------------------
`ifdef HOLD_pin
always
@H if(H===1) //negedge(H)
@H if(H===0)
begin
delta = $time - C_high;
check("tCHHL", delta, tCHHL);
H_low = $time;
end
always
@H if(H===0) //posedge(H)
@H if(H===1)
begin
delta = $time - C_high;
check("tCHHH", delta, tCHHH);
H_high = $time;
end
`endif
//------------------------
// W signal checks
//------------------------
`ifdef W_feature
always
@W if(W===1) //negedge(W)
@W if(W===0)
begin
delta = $time - S_high;
check("tSHWL", delta, tSHWL);
W_low = $time;
end
always
@W if(W===0) //posedge(W)
@W if(W===1)
W_high = $time;
`endif
//------------------------
// RESET signal checks
//------------------------
`ifdef RESET_pin
always
@R if(R===1) //negedge(R)
@R if(R===0)
R_low = $time;
always
@R if(R===0) //posedge(R)
@R if(R===1)
begin
delta = $time - S_high;
check("tSHRH", delta, tSHRH);
delta = $time - R_low;
check("tRLRH", delta, tRLRH);
R_high = $time;
end
`endif
//----------------
// Others tasks
//----------------
function isValid;
input bit;
if (bit!==0 && bit!==1) isValid=0;
else isValid=1;
endfunction
endmodule
`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;
......
-------------------------------------------------------------------------------
-- Title : SVEC System FPGA top level
-- Project : Simple VME64x FMC Carrier (SVEC)
-------------------------------------------------------------------------------
-- File : svec_sfpga_top.vhd
-- Author : Tomasz Włostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-03-20
-- Last update : 2013-01-25
-- Platform : FPGA-generic
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Description: Top level of the System FPGA. Contains a stripped-down VME64x
-- core and the Appliaction FPGA bootloader core. Used solely for booting up
-- the AFPGA. Possible boot configurations are: HOST -> AFPGA, FLASH -> AFPGA
-- and HOST -> FLASH.
-------------------------------------------------------------------------------
--
-- 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;
......@@ -5,6 +42,7 @@ use IEEE.NUMERIC_STD.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.svec_bootloader_pkg.all;
library UNISIM;
use UNISIM.vcomponents.all;
......@@ -14,10 +52,10 @@ entity svec_sfpga_top is
(
-------------------------------------------------------------------------
-- Standard SVEC ports (Gennum bridge, LEDS, Etc. Do not modify
-- Standard SVEC ports (Clocks & Reset)
-------------------------------------------------------------------------
lclk_n_i : in std_logic; -- 20MHz VCXO clock
lclk_n_i : in std_logic; -- 20 MHz VCXO clock
rst_n_i : in std_logic;
-------------------------------------------------------------------------
......@@ -41,10 +79,10 @@ entity svec_sfpga_top is
-- unused pins, tied hi-impedance
VME_ADDR_DIR_o : inout std_logic := 'Z';
VME_ADDR_OE_N_o : inout std_logic := 'Z';
VME_ADDR_DIR_o : inout std_logic := 'Z';
VME_ADDR_OE_N_o : inout std_logic := 'Z';
VME_BBSY_n_i : in std_logic;
-------------------------------------------------------------------------
-- AFPGA boot signals
-------------------------------------------------------------------------
......@@ -55,10 +93,20 @@ entity svec_sfpga_top is
boot_dout_o : out std_logic;
boot_status_i : in std_logic;
-------------------------------------------------------------------------
-- SPI Flash Interface
-------------------------------------------------------------------------
spi_cs_n_o : out std_logic;
spi_mosi_o : out std_logic;
spi_miso_i : in std_logic;
spi_sclk_o : out std_logic;
debugled_o : out std_logic_vector(2 downto 1);
pll_ce_o: out std_logic
-- Onboard PLL enable signal. Must be one for the clock system to work.
pll_ce_o : out std_logic
);
end svec_sfpga_top;
......@@ -71,7 +119,6 @@ architecture rtl of svec_sfpga_top is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
passive_i : in std_logic;
VME_RST_n_i : in std_logic;
VME_AS_n_i : in std_logic;
VME_LWORD_n_i : in std_logic;
......@@ -90,7 +137,7 @@ architecture rtl of svec_sfpga_top is
master_i : in t_wishbone_master_in);
end component;
component xwb_xilinx_fpga_loader
component sfpga_bootloader
generic (
g_interface_mode : t_wishbone_interface_mode;
g_address_granularity : t_wishbone_address_granularity;
......@@ -98,9 +145,15 @@ architecture rtl of svec_sfpga_top is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
desc_o : out t_wishbone_device_descriptor;
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_adr_i : in std_logic_vector(c_wishbone_address_width - 1 downto 0);
wb_sel_i : in std_logic_vector((c_wishbone_data_width + 7) / 8 - 1 downto 0);
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
xlx_cclk_o : out std_logic := '0';
xlx_din_o : out std_logic;
xlx_program_b_o : out std_logic := '1';
......@@ -108,28 +161,15 @@ architecture rtl of svec_sfpga_top is
xlx_done_i : in std_logic;
xlx_suspend_o : out std_logic;
xlx_m_o : out std_logic_vector(1 downto 0);
boot_trig_p1_o : out std_logic;
boot_exit_p1_o : out std_logic;
boot_trig_p1_o : out std_logic := '0';
boot_exit_p1_o : out std_logic := '0';
boot_en_i : in std_logic;
gpio_o : out std_logic_vector(7 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 VME_DATA_o_int : std_logic_vector(31 downto 0);
signal vme_dtack_oe_int, VME_DTACK_n_int : std_logic;
signal vme_data_dir_int : std_logic;
signal VME_DATA_OE_N_int : std_logic;
signal wb_vme_in : t_wishbone_master_out;
signal wb_vme_out : t_wishbone_master_in;
signal passive : std_logic := '1';
signal gpio : std_logic_vector(7 downto 0);
-- bootloader is active right after bootup
signal boot_en : std_logic := '1';
signal boot_trig_p1, boot_exit_p1 : std_logic;
component chipscope_ila
port (
CONTROL : inout std_logic_vector(35 downto 0);
......@@ -145,22 +185,36 @@ architecture rtl of svec_sfpga_top is
CONTROL0 : inout std_logic_vector (35 downto 0));
end component;
signal VME_DATA_o_int : std_logic_vector(31 downto 0);
signal vme_dtack_oe_int, VME_DTACK_n_int : std_logic;
signal vme_data_dir_int : std_logic;
signal VME_DATA_OE_N_int : std_logic;
signal wb_vme_in : t_wishbone_master_out;
signal wb_vme_out : t_wishbone_master_in;
signal passive : std_logic := '0';
-- VME bootloader is inactive by default
signal CONTROL : std_logic_vector(35 downto 0);
signal CLK : std_logic;
signal TRIG0 : std_logic_vector(31 downto 0);
signal TRIG1 : std_logic_vector(31 downto 0);
signal TRIG2 : std_logic_vector(31 downto 0);
signal TRIG3 : std_logic_vector(31 downto 0);
signal boot_en : std_logic := '0';
signal boot_trig_p1, boot_exit_p1 : std_logic;
signal CONTROL : std_logic_vector(35 downto 0);
signal CLK : std_logic;
signal TRIG0 : std_logic_vector(31 downto 0);
signal TRIG1 : std_logic_vector(31 downto 0);
signal TRIG2 : std_logic_vector(31 downto 0);
signal TRIG3 : std_logic_vector(31 downto 0);
signal boot_config_int : std_logic;
signal erase_afpga_n, erase_afpga_n_d0 : std_logic;
signal pllout_clk_fb_sys, pllout_clk_sys, clk_sys : std_logic;
signal rst_n_sys: std_logic;
begin
cmp_dmtd_clk_pll : PLL_BASE
-- PLL for producing 62.5 MHz system clock (clk_sys) from a 20 MHz reference.
U_Sys_clk_pll : PLL_BASE
generic map (
BANDWIDTH => "OPTIMIZED",
CLK_FEEDBACK => "CLKFBOUT",
......@@ -192,12 +246,23 @@ begin
CLKFBIN => pllout_clk_fb_sys,
CLKIN => lclk_n_i);
cmp_clk_sys_buf : BUFG
U_clk_sys_buf : BUFG
port map (
O => clk_sys,
I => pllout_clk_sys);
U_Sync_Reset : gc_sync_ffs
port map (
clk_i => clk_sys,
rst_n_i => '1',
data_i => rst_n_i,
synced_o => rst_n_sys);
-------------------------------------------------------------------------------
-- Chipscope instantiation (for VME bus monitoring, I sincerely hate VMetro)
-------------------------------------------------------------------------------
chipscope_ila_1 : chipscope_ila
port map (
CONTROL => CONTROL,
......@@ -230,15 +295,13 @@ begin
trig2(25) <= VME_RST_n_i;
trig2(26) <= passive;
U_MiniVME : xmini_vme
generic map (
g_user_csr_start => resize(x"70000", 21),
g_user_csr_end => resize(x"70020", 21))
port map (
clk_sys_i => clk_sys,
rst_n_i => rst_n_i,
passive_i => '0',
rst_n_i => rst_n_sys,
VME_RST_n_i => VME_RST_n_i,
VME_AS_n_i => VME_AS_n_i,
VME_LWORD_n_i => VME_LWORD_n_b,
......@@ -256,45 +319,61 @@ begin
master_o => wb_vme_in,
master_i => wb_vme_out);
U_Xilinx_Loader : xwb_xilinx_fpga_loader
U_Bootloader_Core : sfpga_bootloader
generic map (
g_interface_mode => PIPELINED,
g_interface_mode => CLASSIC,
g_address_granularity => BYTE,
g_idr_value => x"53564543")
g_idr_value => c_CSR_SIGNATURE)
port map (
clk_sys_i => clk_sys,
rst_n_i => rst_n_i,
slave_i => wb_vme_in,
slave_o => wb_vme_out,
rst_n_i => rst_n_sys,
wb_cyc_i => wb_vme_in.cyc,
wb_stb_i => wb_vme_in.stb,
wb_we_i => wb_vme_in.we,
wb_adr_i => wb_vme_in.adr,
wb_sel_i => wb_vme_in.sel,
wb_dat_i => wb_vme_in.dat,
wb_dat_o => wb_vme_out.dat,
wb_ack_o => wb_vme_out.ack,
wb_stall_o => wb_vme_out.stall,
xlx_cclk_o => boot_clk_o,
xlx_din_o => boot_dout_o,
xlx_program_b_o => boot_config_int,
xlx_init_b_i => boot_status_i,
xlx_done_i => boot_done_i,
xlx_suspend_o => open,
xlx_m_o => open,
boot_trig_p1_o => boot_trig_p1,
boot_exit_p1_o => boot_exit_p1,
boot_en_i => boot_en,
gpio_o => gpio);
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);
-- produces a longer pulse on PROGRAM_B pin of the Application FPGA when
-- the VME bootloader mode is activated
U_Extend_Erase_Pulse : gc_extend_pulse
generic map (
g_width => 100)
port map (
clk_i => clk_sys,
rst_n_i => rst_n_i,
rst_n_i => rst_n_sys,
pulse_i => boot_trig_p1,
extended_o => erase_afpga_n);
-- Erase the application FPGA as soon as we have received a bootloader
-- trigger command - this is to prevent two VME cores from working simultaneously
-- on a single bus.
boot_config_o <= boot_config_int and (not erase_afpga_n);
p_enable_disable_bootloader : process(clk_sys)
p_enable_disable_bootloader : process(clk_sys, VME_RST_n_i, rst_n_i)
begin
if rising_edge(clk_sys) then
if(rst_n_i = '0' or VME_RST_n_i = '0') then
boot_en <= '0'; -- VME bootloader is inactive after reset
elsif rising_edge(clk_sys) then
erase_afpga_n_d0 <= erase_afpga_n;
-- VME activation occurs after erasing the AFPGA
if(erase_afpga_n = '0' and erase_afpga_n_d0 = '1') then
boot_en <= '1';
elsif(boot_exit_p1 = '1') then
......@@ -303,9 +382,9 @@ begin
end if;
end process;
-- When the VME bootloader is not active, do NOT drive any outputs and sit quiet.
passive <= not boot_en;
VME_ADDR_b <= (others => 'Z');
VME_DTACK_n_o <= VME_DTACK_n_int when passive = '0' else 'Z';
......@@ -317,9 +396,10 @@ begin
VME_ADDR_DIR_o <= '0' when passive = '0' else 'Z';
VME_LWORD_n_b <= 'Z';
debugled_o(1) <= gpio(0);
debugled_o(1) <= '0';
debugled_o(2) <= boot_en;
-- Permanently enable onboard PLL
pll_ce_o <= '1';
end rtl;
......
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