Skip to content

Instantly share code, notes, and snippets.

@kratsg
Created June 30, 2015 18:30
Show Gist options
  • Save kratsg/783da60a9274601e855a to your computer and use it in GitHub Desktop.
Save kratsg/783da60a9274601e855a to your computer and use it in GitHub Desktop.
--*********************************************************************************
-- Indiana University
-- Center for Exploration of Energy and Matter (CEEM)
--
-- Project: ATLAS
--
-- Author: Brandon Kunkler
--
-- Date: 03/04/2015
--
--*********************************************************************************
-- Description:
-- Writes data to algorithm FPGA SPI flash. Assumes program and read-back data
-- written and read on Ethernet or algorithm FPGA clock. The configuration data is
-- written into the FIFO and will be written to flash when an entire page is present.
-- There is a state machine for each low-level function. The low-level state machines
-- are controlled by a high-level mode state machine.
--
-- The rate at which operations will be completed is based upon RATE_DIV. The logic
-- operates at clock frequency/RATE_DIV because all states are transitioned by a
-- clock enable that is created base upon RATE_DIV.
--
-- The timing of MISO can be changed with SODLY.
--
-- A MULT-CYCLE PATH CONSTRAINT SHOULD BE CREATED FOR FLIP-FLOPS WITH CE PIN CONNECTED
-- TO BIT_CE AND BYT_CE.
--
-- The entire array must be un-protected (unless the hardware is changed). To keep
-- the contents protected the entire device mus be un-protected, the half that will
-- not be programmed protected, the erase + programming operation executed, and the
-- half that was programmed protected.
--
-- DO NOT USE PROTECTION UNTIL ALL OF FUNCTIONS HAVE BEEN TESTED. THE FLASH CAN BE
-- PLACED INTO A NON-WORKING CONFIGURATION.
--
-- A sector is 256 kBytes. An entire sector can be erased or protected.
--
-- A page size is 512 bytes. A full page can be read or written.
--
-- PROTECTION:
-- The Persistent Protection Bits (PPB) are located in a separate non-volatile flash
-- array. One of the PPB bits is related to each sector. When a PPB is 0, its related
-- sector is protected from program and erase operations. The PPB are programmed
-- individually but must be erased as a group, similar to the way individual words may
-- be programmed in the main array but an entire sector must be erased at the same time.
-- The PPB have the same program and erase endurance as the main flash memory array.
-- Pre-programming and verification prior to erasure are handled by the device.
--
-- Deficiencies:
--*********************************************************************************
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
library unisim;
use unisim.vcomponents.all;
entity flash_prog is
generic(
RATE_DIV : integer := 0;
SODLY : integer := 4;
SIM_SPEEDUP : std_logic := '0');
port(
-- control signals ---------------
clk : in std_logic;
reset : in std_logic;
rd_wr_n : in std_logic;--1=read-back, 0=write (program)
wrptct : in std_logic;--write protect flash contents
gld_upgd_n : in std_logic;--1=write golden, 0=write upgrade
start : in std_logic;--1=start operation
done : out std_logic;--1=operation complete
-- Program FIFO interface ------------
fifo_afull : out std_logic;--1=entire page in FIFO
fifo_full : out std_logic;--1=FIFO completely full
fifo_wren : in std_logic;--1=write configuration data
fifo_di : in std_logic_vector(7 downto 0);--configuration data input
-- Read-back interface ---------------
dvalid : out std_logic;
dout : out std_logic_vector(7 downto 0);
-- SPI flash interface ---------------
mux_s : out std_logic := '1';-- 0 = write flash, 1 = configure FPGA
sclk : out std_logic := '1';
csn : out std_logic := '1';
mosi : out std_logic := '1';
miso : in std_logic;
-- Status Data ------------------------
status : out std_logic_vector(7 downto 0));
end flash_prog;
---------------------------------------------------------------------------------------------------------
-- Architecture declaration
---------------------------------------------------------------------------------------------------------
architecture behave of flash_prog is
constant GLDN_BASE : std_logic_vector(31 downto 0) := X"00000000";
constant UPGD_BASE : std_logic_vector(31 downto 0) := X"02000000";
constant NSECTORS : std_logic_vector(7 downto 0) := X"7F";--1/2 256 sector device
constant NPAGES : std_logic_vector(15 downto 0) := X"FFFF";--1/2 65536*2=131072 sector device
constant CMD_WREN : std_logic_vector(7 downto 0) := X"06";
constant CMD_ERSE : std_logic_vector(7 downto 0) := X"DC";
constant CMD_STS1 : std_logic_vector(7 downto 0) := X"05";
constant CMD_PGPM : std_logic_vector(7 downto 0) := X"12";
constant CMD_READ : std_logic_vector(7 downto 0) := X"13";
constant CMD_UPTT : std_logic_vector(7 downto 0) := X"E4";
constant CMD_PTCT : std_logic_vector(7 downto 0) := X"E3";
constant SCR_INITV : std_logic_vector(7 downto 0) := NSECTORS;
constant SCR_SIMV : std_logic_vector(7 downto 0) := X"02";
constant ERS_SIMV : std_logic_vector(31 downto 0) := X"00000004";
constant PGE_INITV : std_logic_vector(15 downto 0) := NPAGES;
constant PGE_SIMV : std_logic_vector(15 downto 0) := X"0004";
constant SECTOR_SZ : std_logic_vector(19 downto 0) := X"40000";
constant SECTOR_SIM : std_logic_vector(19 downto 0) := X"40000";
constant PAGE_SZ : std_logic_vector(11 downto 0) := X"200";
constant PAGE_SIM : std_logic_vector(11 downto 0) := X"200";
constant FAEPTY : bit_vector(15 downto 0) := X"0002";
constant FAFULL : bit_vector(15 downto 0) := X"0008";--make sure we have an entire page
type mode_fsm_type is (IDLES,UNPTCTS,PTCT1S,ERASES,WRITES,PTCT2S,READS,DONES);--mode state machine
type wren_fsm_type is (IDLES,LDCMDS,WRCMDS,RDSTSS,DONES);
type sts_fsm_type is (IDLES,LDCMDS,WRCMDS,RDSTSS,DONES);
type erase_fsm_type is (IDLES,WRENS,LDCMDS,WRCMDS,RDSTSS,NXTBKS,DONES);
type write_fsm_type is (IDLES,WRENS,LDCMDS,WRCMDS,WRPGES,RDSTSS,NXTPGS,DONES);
type read_fsm_type is (IDLES,WRENS,LDCMDS,WRCMDS,RDARYS,DONES);
type uptct_fsm_type is (IDLES,WRENS,LDCMDS,WRCMDS,RDSTSS,DONES);
type ptct_fsm_type is (IDLES,WRENS,LDCMDS,WRCMDS,RDSTSS,NXTBKS,DONES);
signal ptt_sel : std_logic_vector(1 downto 0);
signal base_addr : std_logic_vector(31 downto 0);
signal ce_ctr : std_logic_vector(4 downto 0) := (others => '1');
signal ce_bitsel : std_logic := '0';
signal ce_bytsel : std_logic := '0';
signal ce_bit : std_logic := '0';
signal ce_byt : std_logic := '0';
signal ce_bitstb : std_logic := '0';
signal bit_ce : std_logic := '0';
signal byt_ce : std_logic := '0';
signal lreset : std_logic;
signal freset : std_logic;
signal rst_shift : std_logic_vector(7 downto 0) :=X"F8";
signal dvalidf : std_logic_vector(1 downto 0);
--signal read_regv : std_logic_vector(3 downto 0);--valid --%works in hardware no I/O FFs
--signal read_regv : std_logic_vector(2 downto 0);--valid --%works in simulation no I/O FFs
--signal read_regv : std_logic_vector(3 downto 0);--valid --%works in simulation with I/O FFs
--signal read_regv : std_logic_vector(4 downto 0);--valid --%works in hardware with I/O FFs
signal read_regv : std_logic_vector(SODLY downto 0);--valid --%works in hardware with I/O FFs
signal read_reg : std_logic_vector(7 downto 0) := (others => '0');
signal write_reg_ld : std_logic_vector(7 downto 0) := (others => '0');
signal write_reg : std_logic_vector(47 downto 0);
-- mode state machine signals
signal mode_fsm_cs : mode_fsm_type;
signal uptct_en : std_logic;
signal erase_en : std_logic;
signal write_en : std_logic;
signal ptct_en : std_logic;
signal read_en : std_logic;
signal ptct_1_2_n : std_logic;
-- write enable state machine
signal wren_fsm_cs : wren_fsm_type;
signal wren_en : std_logic;
signal wren_cs : std_logic :='0';
signal wren_ldc : std_logic;
signal wren_ack : std_logic;
signal wren_sen : std_logic;
signal wren_sse : std_logic;
-- status state machine
signal sts_fsm_cs : sts_fsm_type;
signal sts_en : std_logic;
signal sts_cs : std_logic :='0';
signal sts_ldc : std_logic;
signal sts_ack : std_logic;
signal sts_sen : std_logic;
signal sts_wel : std_logic := '0';-- Status register 1 WEL bit
signal sts_wip : std_logic := '0';-- Status register 1 WIP bit
signal sts_perr : std_logic := '0';-- Status register 1 P_ERR bit
signal sts_errr : std_logic := '0';-- Status register 1 E_ERR bit
-- erase state machine
signal erase_fsm_cs : erase_fsm_type;
signal erase_wren : std_logic;
signal erase_ldc : std_logic;
signal erase_lds : std_logic;-- load sector count
signal erase_cs : std_logic :='0';-- chip select
signal erase_sen : std_logic;-- shift enable
signal erase_sce : std_logic;-- sector count enable
signal erase_sse : std_logic;-- status enable
signal erase_ack : std_logic;
-- write state machine
signal write_fsm_cs : write_fsm_type;
signal write_wren : std_logic;
signal write_ldc : std_logic;
signal write_ldd : std_logic;--load data
signal write_ldp : std_logic;
signal write_cs : std_logic :='0';
signal write_sen : std_logic;
signal write_pce : std_logic;
signal write_sse : std_logic;-- status enable
signal write_ack : std_logic;
signal write_rden : std_logic;
-- read state machine
signal read_fsm_cs : read_fsm_type;
signal read_wren : std_logic;
signal read_ldc : std_logic;
signal read_ldp : std_logic;
signal read_cs : std_logic :='0';
signal read_sen : std_logic;
signal read_pce : std_logic;
signal read_rbe : std_logic; --read-back enable
signal read_ack : std_logic;
-- un-protect state machine
signal uptct_fsm_cs : uptct_fsm_type;
signal uptct_wren : std_logic;
signal uptct_ldc : std_logic;
signal uptct_cs : std_logic :='0';
signal uptct_sen : std_logic;
signal uptct_sse : std_logic;
signal uptct_ack : std_logic;
-- protect state machine
signal ptct_fsm_cs : ptct_fsm_type;
signal ptct_wren : std_logic;
signal ptct_ldc : std_logic;
signal ptct_lds : std_logic;-- load sector count
signal ptct_cs : std_logic :='0';-- chip select
signal ptct_sen : std_logic;-- shift enable
signal ptct_sce : std_logic;-- sector count enable
signal ptct_sse : std_logic;-- status enable
signal ptct_ack : std_logic;
signal fifo_rden : std_logic := '0';
signal fifo_do : std_logic_vector(fifo_di'length-1 downto 0);
signal fifo_aepty : std_logic;
signal fifo_epty : std_logic;
signal fifo_rderr : std_logic;
signal fifo_wrerr : std_logic;
signal fifo_do0 : std_logic_vector(63 downto 0);
signal fifo_di0 : std_logic_vector(63 downto 0);
signal byte_plen : std_logic_vector(11 downto 0) := (others => '1');
signal byte_slen : std_logic_vector(19 downto 0) := (others => '1');
signal byte_ctr_ld : std_logic;
signal byte_ctr : std_logic_vector(19 downto 0) := (others => '1');
signal byte_ctr_tc0 : std_logic := '0';
signal byte_ctr_tc1 : std_logic := '0';
signal byte_ctr_tc2 : std_logic := '0';
signal pge_init : std_logic_vector(15 downto 0);
signal pge_ctr_ld : std_logic;
signal pge_ctr_en : std_logic;
signal pge_ctr : std_logic_vector(15 downto 0) := (others => '1');
signal pge_ctr_tc : std_logic := '0';
signal scr_init : std_logic_vector(7 downto 0);
signal scr_ctr_ld : std_logic;
signal scr_ctr_en : std_logic;
signal scr_ctr : std_logic_vector(7 downto 0) := (others => '1');
signal scr_ctr_tc : std_logic := '0';
signal ers_addr_ld : std_logic;
signal ers_addr_en : std_logic;
signal ers_addr : std_logic_vector(31 downto 0) := (others => '1');
signal ptt_init : std_logic_vector(31 downto 0) := (others => '1');
signal ptt_addr_ld : std_logic;
signal ptt_addr_en : std_logic;
signal ptt_addr : std_logic_vector(31 downto 0) := (others => '1');
signal wr_addr_ld : std_logic;
signal wr_addr_en : std_logic;
signal wr_addr : std_logic_vector(31 downto 0) := (others => '1');
begin
FIFO36E1_inst : FIFO36E1
generic map(
ALMOST_EMPTY_OFFSET => FAEPTY, -- Sets the almost empty threshold
ALMOST_FULL_OFFSET => FAFULL, -- Sets almost full threshold
DATA_WIDTH => 9, -- Sets data width to 4-72
DO_REG => 0, -- Enable output register (1-0) Must be 1 if EN_SYN = FALSE
EN_ECC_READ => FALSE, -- Enable ECC decoder, FALSE, TRUE
EN_ECC_WRITE => FALSE, -- Enable ECC encoder, FALSE, TRUE
EN_SYN => TRUE, -- Specifies FIFO as Asynchronous (FALSE) or Synchronous (TRUE)
FIFO_MODE => "FIFO36", -- Sets mode to "FIFO36" or "FIFO36_72"
FIRST_WORD_FALL_THROUGH => FALSE, -- Sets the FIFO FWFT to FALSE, TRUE
INIT => X"000000000000000000", -- Initial values on output port
SIM_DEVICE => "7SERIES", -- Must be set to "7SERIES" for simulation behavior
SRVAL => X"000000000000000000") -- Set/Reset value for output port
port map(
-- ECC Signals: 1-bit (each) output: Error Correction Circuitry ports
DBITERR => open, -- 1-bit output: Double bit error status
ECCPARITY => open, -- 8-bit output: Generated error correction parity
SBITERR => open, -- 1-bit output: Single bit error status
-- Read Data: 64-bit (each) output: Read output data
DO => fifo_do0, -- 64-bit output: Data output
DOP => open, -- 8-bit output: Parity data output
-- Status: 1-bit (each) output: Flags and other FIFO status outputs
ALMOSTEMPTY => fifo_aepty, -- 1-bit output: Almost empty flag
ALMOSTFULL => fifo_afull, -- 1-bit output: Almost full flag
EMPTY => fifo_epty, -- 1-bit output: Empty flag
FULL => fifo_full, -- 1-bit output: Full flag
RDCOUNT => open, -- 13-bit output: Read count
RDERR => fifo_rderr, -- 1-bit output: Read error
WRCOUNT => open, -- 13-bit output: Write count
WRERR => fifo_wrerr, -- 1-bit output: Write error
-- ECC Signals: 1-bit (each) input: Error Correction Circuitry ports
INJECTDBITERR => '0', -- 1-bit input: Inject a double bit error input
INJECTSBITERR => '0',
-- Read Control Signals: 1-bit (each) input: Read clock, enable and reset input signals
RDCLK => clk, -- 1-bit input: Read clock
RDEN => fifo_rden, -- 1-bit input: Read enable
REGCE => '1', -- 1-bit input: Clock enable
RST => freset, -- 1-bit input: Reset
RSTREG => '0', -- 1-bit input: Output register set/reset
-- Write Control Signals: 1-bit (each) input: Write clock and enable input signals
WRCLK => clk, -- 1-bit input: Rising edge write clock.
WREN => fifo_wren, -- 1-bit input: Write enable
-- Write Data: 64-bit (each) input: Write input data
DI => fifo_di0, -- 64-bit input: Data input
DIP => X"00" -- 8-bit input: Parity input
);
-- assertions for simulation
assert (fifo_rderr='0' or fifo_rderr='U') report "flash_prog FIFO read error" severity ERROR;
assert (fifo_wrerr='0' or fifo_wrerr='U') report "flash_prog FIFO write error" severity ERROR;
------------------------------------------------------------------------------------------------
-- Component instantiations
------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
-- Concurrent statements
------------------------------------------------------------------------------------------------
--------------------------------------------------------
-- Map signals to ports
--------------------------------------------------------
fifo_di0 <= STD_LOGIC_VECTOR(RESIZE(UNSIGNED(fifo_di),fifo_di0'length));
fifo_do <= fifo_do0(fifo_di'length-1 downto 0);
--------------------------------------------------------
-- Combinational logic
--------------------------------------------------------
base_addr <= GLDN_BASE when gld_upgd_n = '1' else UPGD_BASE;
byte_plen <= (PAGE_SIM-2) when SIM_SPEEDUP = '1' else (PAGE_SZ-2);
byte_slen <= SECTOR_SIM when SIM_SPEEDUP = '1' else SECTOR_SZ;
scr_init <= SCR_SIMV when SIM_SPEEDUP = '1' else SCR_INITV;
pge_init <= PGE_SIMV when SIM_SPEEDUP = '1' else PGE_INITV;
-- add or remove control signals here to add or remove low-level functions ----------
wren_en <= ptct_wren or uptct_wren or read_wren or write_wren or erase_wren;
sts_en <= ptct_sse or uptct_sse or write_sse or erase_sse or wren_sse;
byte_ctr_ld <= not (ptct_sen or uptct_sen or read_sen or write_sen or erase_sen);
--byte_ctr_ld <= erase_lds;
scr_ctr_ld <= ptct_lds or erase_lds;
scr_ctr_en <= ptct_sce or erase_sce;
pge_ctr_ld <= read_ldp or write_ldp;
pge_ctr_en <= read_pce or write_pce;
write_reg_ld <= ptct_ldc & uptct_ldc & read_ldc & write_ldd & write_ldc & erase_ldc & sts_ldc & wren_ldc;
-------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
-- Asynchronous and Synchronous processes
------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- Asynchronous processes
-------------------------------------------------------------------------------------------
--------------------------------------------------------------------------
-- Select the address which to protect. When the golden is to be programmed
-- must protect the upgrade before erase then the golden after program.
-- When the upgrade is to be programmed must protect the golden before
-- erase then the upgrade after program.
--------------------------------------------------------------------------
ptt_sel <= ptct_1_2_n & gld_upgd_n;
ptt_init_pcs : process(ptt_sel)
begin
case ptt_sel is
when "00" =>
ptt_init <= UPGD_BASE;
when "01" =>
ptt_init <= GLDN_BASE;
when "10" =>
ptt_init <= GLDN_BASE;
when "11" =>
ptt_init <= UPGD_BASE;
when others =>
ptt_init <= (others => 'X');
end case;
end process;
-------------------------------------------------------------------------------------------
-- Synchronous processes
-------------------------------------------------------------------------------------------
--------------------------------------------------------------------------
-- Generate clock enables - one for bit period and one for byte period.
-- Use them to lower the rate and synchronize read/write operations. Byte
-- clock enable will keep the state machines synchronized.
--------------------------------------------------------------------------
ce_pcs : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
ce_ctr <= (others => '1');
ce_bitsel <= '0';
ce_bytsel <= '0';
ce_bit <= '0';
ce_byt <= '0';
ce_bitstb <= '0';
bit_ce <= '0';
byt_ce <= '0';
else
ce_ctr <= ce_ctr - '1';
if RATE_DIV = 2 then
ce_bitsel <= ce_ctr(0);
ce_bytsel <= ce_ctr(3);
else
ce_bitsel <= ce_ctr(1);
ce_bytsel <= ce_ctr(4);
end if;
ce_bit <= ce_bitsel;
ce_byt <= ce_bytsel;
ce_bitstb <= ce_bit;
bit_ce <= (not ce_bit) and ce_bitsel;
byt_ce <= (not ce_byt) and ce_bytsel;
end if;
end if;
end process;
--------------------------------------------------------------------------
-- Generate resets that satisfy FIFO constraints.
--------------------------------------------------------------------------
reset_pcs : process(clk)
begin
if (clk'event and clk='1') then
if reset = '1' then
rst_shift <= X"F8";
freset <= '0';
lreset <= '0';
else
rst_shift <= '0' & rst_shift(rst_shift'length-1 downto 1);
freset <= rst_shift(0);
lreset <= OR_REDUCE(rst_shift(5 downto 0));
end if;
end if;
end process;
--------------------------------------------------------------------------
-- Register the inputs
--------------------------------------------------------------------------
in_regs_pcs : process(clk)
begin
if (clk'event and clk = '1') then
if bit_ce = '1' then
end if;
end if;
end process;
-------------------------------------------------------------
-- Input serial to parallel shift register (read register).
-------------------------------------------------------------
rd_reg_pcs : process(clk)
begin
if (clk'event and clk='1') then
if bit_ce = '1' then
read_reg <= read_reg(read_reg'length-2 downto 0) & miso;
end if;
-- latch the status bits when valid
if bit_ce = '1' then
read_regv <= byt_ce & read_regv(read_regv'length-1 downto 1);
end if;
if bit_ce = '0' then
if read_regv(1) = '1' then
sts_wel <= read_reg(1);
sts_wip <= read_reg(0);
if sts_cs = '1' then
sts_perr <= read_reg(6);
sts_errr <= read_reg(5);
end if;
end if;
end if;
-- mask first read valid pulses so wait for valid first read data
if read_rbe = '0' then
dvalidf <= (others => '0');
else
if byt_ce = '1' then
dvalidf <= '1' & dvalidf(dvalidf'length-1 downto 1);
end if;
end if;
end if;
end process;
--------------------------------------------------------------------------
-- Output registers.
--------------------------------------------------------------------------
out_regs_pcs : process(clk)
begin
if (clk'event and clk = '1') then
if lreset = '1' then
mux_s <= '1';
dvalid <= '0';
dout <= (others => '0');
sclk <= '1';
csn <= '1';
mosi <= '1';
else
-- SPI Interface registers
mux_s <= not (uptct_en or erase_en or write_en or ptct_en or read_en);--assert if any mode active
dvalid <= bit_ce and dvalidf(0) and read_regv(1) and read_rbe;
dout <= read_reg;
sclk <= not ce_bitstb;
csn <= not (ptct_cs or uptct_cs or wren_cs or sts_cs or erase_cs or write_cs or read_cs);
mosi <= write_reg(write_reg'length-1);
end if;
-- concatenate the current mode and status register 1 error bits into a status word
status <= "0" & sts_perr & sts_errr & uptct_en & erase_en & write_en & ptct_en & read_en;
end if;
end process;
-------------------------------------------------------------
-- Output parallel to serial shift register with multiplexed
-- input. Make it long enough to shift command, address, and
-- first data byte to avoid delays.
-------------------------------------------------------------
write_reg_pcs : process(clk)
begin
if (clk'event and clk='1') then
if bit_ce = '1' then
case write_reg_ld is
when X"00" =>--shift
write_reg <= write_reg(write_reg'length-2 downto 0) & '0';
when X"01" =>--set WEL bit command
write_reg <= CMD_WREN & X"0000000000";
when X"02" =>--read status command
write_reg <= CMD_STS1 & X"0000000000";
when X"04" =>--erase array command
write_reg <= CMD_ERSE & ers_addr & X"00";
when X"08" =>--program array command
write_reg <= CMD_PGPM & wr_addr & fifo_do;
when X"10" =>--program array values with FIFO data
write_reg <= fifo_do & X"0000000000";
when X"20" =>--read array data command
write_reg <= CMD_READ & base_addr & X"00";
when X"40" =>--un-protect command
write_reg <= CMD_UPTT & X"0000000000";
when X"80" =>--protect command
write_reg <= CMD_PTCT & ptt_addr & X"00";
when others =>--shift
write_reg <= write_reg(write_reg'length-2 downto 0) & '0';
end case;
end if;
end if;
end process;
-------------------------------------------------------------
-- Mode state machine. High-level control of the functionality.
-------------------------------------------------------------
mode_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
ptct_1_2_n <= '1';
uptct_en <= '0';
erase_en <= '0';
write_en <= '0';
ptct_en <= '0';
read_en <= '0';
done <= '0';
mode_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
ptct_1_2_n <= '1';
uptct_en <= '0';
erase_en <= '0';
write_en <= '0';
ptct_en <= '0';
read_en <= '0';
done <= '0';
-------------------------------------------
case mode_fsm_cs is
when IDLES =>
-- wait for start to go high
if start = '1' then
if rd_wr_n = '1' then
-- read
mode_fsm_cs <= READS;
else
-- write
if wrptct = '1' then
-- un-protect
mode_fsm_cs <= UNPTCTS;
else
-- just write (after erase)
mode_fsm_cs <= ERASES;
end if;
end if;
else
mode_fsm_cs <= IDLES;
end if;
when UNPTCTS =>-- un-protect the entire flash
uptct_en <= '1';
if uptct_ack = '1' then
mode_fsm_cs <= PTCT1S;
else
mode_fsm_cs <= UNPTCTS;
end if;
when PTCT1S =>-- protect half of flash that will not program
ptct_1_2_n <= '1';
ptct_en <= '1';
if ptct_ack = '1' then
mode_fsm_cs <= ERASES;
else
mode_fsm_cs <= PTCT1S;
end if;
when ERASES =>-- sector erase half of flash (must erase before write)
erase_en <= '1';
if erase_ack = '1' then
mode_fsm_cs <= WRITES;
else
mode_fsm_cs <= ERASES;
end if;
when WRITES =>-- page program half of the flash
write_en <= '1';
if write_ack = '1' then
if wrptct = '1' then
-- protect flash array
mode_fsm_cs <= PTCT2S;
else
-- we are done
mode_fsm_cs <= DONES;
end if;
else
mode_fsm_cs <= WRITES;
end if;
when PTCT2S =>-- protect half of flash that we programmed
ptct_1_2_n <= '0';
ptct_en <= '1';
if ptct_ack = '1' then
mode_fsm_cs <= DONES;
else
mode_fsm_cs <= PTCT2S;
end if;
when READS =>-- read back array
-- read entire flash
read_en <= '1';
if read_ack = '1' then
mode_fsm_cs <= DONES;
else
mode_fsm_cs <= READS;
end if;
when DONES =>-- pulse done to signal end of operation
done <= '1';
mode_fsm_cs <= IDLES;
when others =>
mode_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- WREN state machine. Must execute this command before doing
-- anything else. Allows write to command registers.
-------------------------------------------------------------
wren_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
wren_ldc <= '0';
wren_cs <= '0';
wren_sen <= '0';--shift enable
wren_ack <= '0';
wren_sse <= '0';
wren_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
wren_cs <= '0';
wren_ldc <= '0';
wren_sen <= '0';
wren_ack <= '0';
wren_sse <= '0';
-------------------------------------------
case wren_fsm_cs is
when IDLES =>-- wait for start to go high
if wren_en = '1' then
wren_fsm_cs <= LDCMDS;
else
wren_fsm_cs <= IDLES;
end if;
when LDCMDS =>-- load the command
wren_ldc <= '1';
if byt_ce = '1' then
wren_fsm_cs <= WRCMDS;
else
wren_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>--write command
wren_cs <= '1';
wren_sen <= '1';
if byt_ce = '1' then
wren_fsm_cs <= RDSTSS;
else
wren_fsm_cs <= WRCMDS;
end if;
when RDSTSS =>-- read status register
wren_sse <= '1';
-- wait until status good
if (sts_wel and (not sts_wip)) = '1' then
wren_fsm_cs <= DONES;
else
wren_fsm_cs <= RDSTSS;
end if;
when DONES =>-- signal end of operation
wren_ack <= sts_ack;
if (wren_en or sts_ack) = '0' then
wren_fsm_cs <= IDLES;
else
wren_fsm_cs <= DONES;
end if;
when others =>
wren_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Status state machine. Read status register 1. Assume this
-- will be executed until operation successful.
-- MAKE SURE THIS FSM IS DONE BEFORE TRANSITIONING STATES IN
-- CONTROLLING STATE MACHINE.
-------------------------------------------------------------
sts_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
sts_ldc <= '0';
sts_cs <= '0';
sts_sen <= '0';--shift enable
sts_ack <= '0';
sts_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
sts_cs <= '0';
sts_ldc <= '0';
sts_sen <= '0';
sts_ack <= '0';
-------------------------------------------
case sts_fsm_cs is
when IDLES =>-- wait for start to go high
sts_cs <= '0';
sts_ldc <= '0';
sts_sen <= '0';
sts_ack <= '0';
if sts_en = '1' then
sts_fsm_cs <= LDCMDS;
else
sts_fsm_cs <= IDLES;
end if;
when LDCMDS =>-- load the command
sts_ldc <= '1';
if byt_ce = '1' then
sts_fsm_cs <= WRCMDS;
else
sts_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>--write command
sts_cs <= '1';
sts_sen <= '1';
if byt_ce = '1' then
sts_fsm_cs <= RDSTSS;
else
sts_fsm_cs <= WRCMDS;
end if;
when RDSTSS =>-- read status register
sts_cs <= '1';
sts_sen <= '1';
if ((not sts_en) and byt_ce) = '1' then
sts_fsm_cs <= DONES;
else
sts_fsm_cs <= RDSTSS;
end if;
when DONES =>-- signal end of operation
sts_ack <= '1';
if sts_en = '0' then
sts_fsm_cs <= IDLES;
else
sts_fsm_cs <= DONES;
end if;
when others =>
sts_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Erase state machine. Must execute this command before
-- writing configuration data to flash.
-------------------------------------------------------------
erase_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
erase_wren <= '0';
erase_ldc <= '0';
erase_lds <= '0';
ers_addr_ld <= '0';
erase_cs <= '0';
erase_sen <= '0';
erase_sce <= '0';
ers_addr_en <= '0';
erase_sse <= '0';
erase_ack <= '0';
erase_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
erase_wren <= '0';
erase_ldc <= '0';
erase_lds <= '0';
ers_addr_ld <= '0';
erase_cs <= '0';
erase_sen <= '0';
erase_sce <= '0';
ers_addr_en <= '0';
erase_sse <= '0';
erase_ack <= '0';
-------------------------------------------
case erase_fsm_cs is
when IDLES =>-- until erase required
if erase_en = '1' then
erase_lds <= '1';
ers_addr_ld <= '1';
erase_fsm_cs <= WRENS;
else
erase_lds <= '0';
ers_addr_ld <= '0';
erase_fsm_cs <= IDLES;
end if;
when WRENS =>-- set WEL bit
erase_wren <= '1';
if wren_ack = '1' then
erase_fsm_cs <= LDCMDS;
else
erase_fsm_cs <= WRENS;
end if;
when LDCMDS =>-- load the sector erase command and address
erase_ldc <= '1';
if byt_ce = '1' then
erase_fsm_cs <= WRCMDS;
else
erase_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>-- erase half of the flash
erase_sen <= '1';
if byte_ctr_tc0 = '1' then
erase_cs <= '0';
ers_addr_en <= '1';
erase_fsm_cs <= RDSTSS;
else
erase_cs <= '1';
ers_addr_en <= '0';
erase_fsm_cs <= WRCMDS;
end if;
when RDSTSS =>-- read the status bit
-- read entire flash
erase_sse <= '1';
if (read_regv(0) and (not sts_wip)) = '1' then
erase_fsm_cs <= NXTBKS;--!check the WIP (SR1[0]) and E_ERR (SR1[5]) bits
else
erase_fsm_cs <= RDSTSS;
end if;
when NXTBKS =>-- read next block or done
-- read entire flash
if sts_ack = '1' then
erase_sce <= '1';
if scr_ctr_tc = '1' then
erase_fsm_cs <= DONES;
else
erase_fsm_cs <= WRENS;
end if;
else
erase_sce <= '0';
erase_fsm_cs <= NXTBKS;
end if;
when DONES =>-- signal end of operation
erase_ack <= '1';
if erase_en = '0' then
erase_fsm_cs <= IDLES;
else
erase_fsm_cs <= DONES;
end if;
when others =>
erase_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Write state machine. Write pages of data to the flash array.
-- Must have an entire page in FIFO before write starts
-- (WRPGES state).
-------------------------------------------------------------
write_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
write_wren <= '0';
write_ldc <= '0';
write_ldd <= '0';
write_ldp <= '0';
wr_addr_ld <= '0';
write_cs <= '0';
write_sen <= '0';
write_pce <= '0';
wr_addr_en <= '0';
write_sse <= '0';
write_ack <= '0';
write_rden <= '0';
write_fsm_cs <= IDLES;
fifo_rden <= '0';
else
-- generate one clock FIFO read enable
fifo_rden <= write_rden and byt_ce;
if bit_ce = '1' then
-- default values -------------------------
write_wren <= '0';
write_ldc <= '0';
write_ldd <= '0';
write_ldp <= '0';
wr_addr_ld <= '0';
write_cs <= '0';
write_sen <= '0';
write_pce <= '0';
wr_addr_en <= '0';
write_sse <= '0';
write_ack <= '0';
write_rden <= '0';
-------------------------------------------
case write_fsm_cs is
when IDLES =>-- wait for start
if (write_en and (not fifo_aepty)) = '1' then
write_ldp <= '1';
wr_addr_ld <= '1';
write_fsm_cs <= WRENS;
else
write_ldp <= '0';
wr_addr_ld <= '0';
write_fsm_cs <= IDLES;
end if;
when WRENS =>-- set the WEL bit so we can write command
write_wren <= '1';
if (wren_ack and (not fifo_aepty)) = '1' then
write_fsm_cs <= LDCMDS;
else
write_fsm_cs <= WRENS;
end if;
when LDCMDS =>-- load the sector erase command and address and first data byte
write_ldc <= '1';
write_rden <= '1';
if byt_ce = '1' then
write_fsm_cs <= WRCMDS;
else
write_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>-- erase half of the flash
write_cs <= '1';
if byte_ctr_tc0 = '1' then
write_sen <= '0';
wr_addr_en <= '1';
write_fsm_cs <= WRPGES;
else
write_sen <= '1';
wr_addr_en <= '0';
write_fsm_cs <= WRCMDS;
end if;
when WRPGES =>-- write a page
write_ldd <= byt_ce;-- wait until FIFO data valid
write_sen <= '1';
write_rden <= '1';
if byte_ctr_tc1 = '1' then
write_cs <= '0';
write_fsm_cs <= RDSTSS;
else
write_cs <= '1';
write_fsm_cs <= WRPGES;
end if;
when RDSTSS =>-- check the WIP (SR1[0]) and P_ERR (SR1[6]) bits
write_sse <= '1';
if (read_regv(0) and (not sts_wip)) = '1' then
write_fsm_cs <= NXTPGS;
else
write_fsm_cs <= RDSTSS;
end if;
when NXTPGS =>-- get the next page or finish
write_sen <= '1';
if sts_ack = '1' then
write_pce <='1';
if pge_ctr_tc = '1' then
write_fsm_cs <= DONES;
else
write_fsm_cs <= WRENS;
end if;
else
write_pce <='0';
write_fsm_cs <= NXTPGS;
end if;
when DONES =>-- signal end of operation
write_ack <= '1';
if write_en = '0' then
write_fsm_cs <= IDLES;
else
write_fsm_cs <= DONES;
end if;
when others =>
write_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Read state machine. Read half of the memory array.
-------------------------------------------------------------
read_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
read_wren <= '0';
read_ldc <= '0';
read_ldp <= '1';
read_cs <= '0';
read_sen <= '0';
read_pce <= '0';
read_rbe <= '0';
read_ack <= '0';
read_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
read_wren <= '0';
read_ldc <= '0';
read_ldp <= '0';
read_cs <= '0';
read_sen <= '0';
read_pce <= '0';
read_rbe <= '0';
read_ack <= '0';
-------------------------------------------
case read_fsm_cs is
when IDLES =>-- wait for start
if read_en = '1' then
read_fsm_cs <= WRENS;
else
read_fsm_cs <= IDLES;
end if;
when WRENS =>-- set the WEL so we can write
read_wren <= '1';
if wren_ack = '1' then
read_fsm_cs <= LDCMDS;
else
read_fsm_cs <= WRENS;
end if;
when LDCMDS =>-- load the sector erase command and address
read_ldc <= '1';
read_ldp <= '1';
read_sen <= '1';
if byt_ce = '1' then
read_fsm_cs <= WRCMDS;
else
read_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>-- write command to device
read_ldp <= '1';
read_cs <= '1';
if byte_ctr_tc0 = '1' then
read_sen <= '0';
read_fsm_cs <= RDARYS;
else
read_sen <= '1';
read_fsm_cs <= WRCMDS;
end if;
when RDARYS =>-- read half of the flash (+ one more byte?)
read_cs <= '1';
read_sen <= not (byte_ctr_tc1 and byt_ce);
read_pce <= byte_ctr_tc1 and byt_ce;
read_rbe <= '1';
if (pge_ctr_tc and byt_ce) = '1' then
read_fsm_cs <= DONES;
else
read_fsm_cs <= RDARYS;
end if;
when DONES =>-- signal end of operation
read_ldp <= '1';
read_ack <= '1';
read_rbe <= '1';--capture the last byte
if read_en = '0' then
read_fsm_cs <= IDLES;
else
read_fsm_cs <= DONES;
end if;
when others =>
read_ldp <= '1';
read_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Un-protect state machine. Protect half of the flash.
-------------------------------------------------------------
uptct_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
uptct_wren <= '0';
uptct_ldc <= '0';
uptct_cs <= '0';
uptct_sen <= '0';
uptct_sse <= '0';
uptct_ack <= '0';
uptct_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
uptct_wren <= '0';
uptct_ldc <= '0';
uptct_cs <= '0';
uptct_sen <= '0';
uptct_sse <= '0';
uptct_ack <= '0';
-------------------------------------------
case uptct_fsm_cs is
when IDLES =>-- wait until un-protect required
if uptct_en = '1' then
uptct_fsm_cs <= WRENS;
else
uptct_fsm_cs <= IDLES;
end if;
when WRENS =>-- set the WEL so we can write
uptct_wren <= '1';
if wren_ack = '1' then
uptct_fsm_cs <= LDCMDS;
else
uptct_fsm_cs <= WRENS;
end if;
when LDCMDS =>-- load the sector unptct command and address
uptct_ldc <= '1';
if byt_ce = '1' then
uptct_fsm_cs <= WRCMDS;
else
uptct_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>-- unptct half of the flash
uptct_sen <= '1';
uptct_cs <= '1';
if byt_ce = '1' then
uptct_fsm_cs <= RDSTSS;
else
uptct_fsm_cs <= WRCMDS;
end if;
when RDSTSS =>-- read the status register
uptct_sse <= '1';
if (read_regv(0) and (not sts_wip)) = '1' then
uptct_fsm_cs <= DONES;--check the WIP (SR1[0]) bit
else
uptct_fsm_cs <= RDSTSS;
end if;
when DONES =>-- signal end of operation
uptct_ack <= '1';
if uptct_en = '0' then
uptct_fsm_cs <= IDLES;
else
uptct_fsm_cs <= DONES;
end if;
when others =>
uptct_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Protect state machine. Protect the half of the flash that
-- is not to be written or that was just written.
-------------------------------------------------------------
ptct_fsm : process(clk)
begin
if (clk'event and clk='1') then
if lreset = '1' then
ptct_wren <= '0';
ptct_ldc <= '0';
ptct_lds <= '0';
ptt_addr_ld <= '0';
ptct_cs <= '0';
ptct_sen <= '0';
ptct_sce <= '0';
ptt_addr_en <= '0';
ptct_sse <= '0';
ptct_ack <= '0';
ptct_fsm_cs <= IDLES;
else
if bit_ce = '1' then
-- default values -------------------------
ptct_wren <= '0';
ptct_ldc <= '0';
ptct_lds <= '0';
ptt_addr_ld <= '0';
ptct_cs <= '0';
ptct_sen <= '0';
ptct_sce <= '0';
ptt_addr_en <= '0';
ptct_sse <= '0';
ptct_ack <= '0';
-------------------------------------------
case ptct_fsm_cs is
when IDLES =>-- until protect required
if ptct_en = '1' then
ptct_lds <= '1';
ptt_addr_ld <= '1';
ptct_fsm_cs <= WRENS;
else
ptct_lds <= '0';
ptt_addr_ld <= '0';
ptct_fsm_cs <= IDLES;
end if;
when WRENS =>-- set the WEL so we can write
ptct_wren <= '1';
if wren_ack = '1' then
ptct_fsm_cs <= LDCMDS;
else
ptct_fsm_cs <= WRENS;
end if;
when LDCMDS =>-- load the sector erase command and address
ptct_ldc <= '1';
if byt_ce = '1' then
ptct_fsm_cs <= WRCMDS;
else
ptct_fsm_cs <= LDCMDS;
end if;
when WRCMDS =>-- erase half of the flash
ptct_sen <= '1';
if byte_ctr_tc0 = '1' then
ptct_cs <= '0';
ptt_addr_en <= '1';
ptct_fsm_cs <= RDSTSS;
else
ptct_cs <= '1';
ptt_addr_en <= '0';
ptct_fsm_cs <= WRCMDS;
end if;
when RDSTSS =>-- read the status bit
ptct_sse <= '1';
if (read_regv(0) and (not sts_wip)) = '1' then
ptct_fsm_cs <= NXTBKS;--check the WIP (SR1[0]) and P_ERR (SR1[6]) bits
else
ptct_fsm_cs <= RDSTSS;
end if;
when NXTBKS =>-- protect next block or done
if sts_ack = '1' then
ptct_sce <= '1';
if scr_ctr_tc = '1' then
ptct_fsm_cs <= DONES;
else
ptct_fsm_cs <= WRENS;
end if;
else
ptct_sce <= '0';
ptct_fsm_cs <= NXTBKS;
end if;
when DONES =>-- signal end of operation
ptct_ack <= '1';
if ptct_en = '0' then
ptct_fsm_cs <= IDLES;
else
ptct_fsm_cs <= DONES;
end if;
when others =>
ptct_fsm_cs <= IDLES;
end case;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Count the number of bytes so we know when to increment the
-- page counter.
-------------------------------------------------------------
byte_count_pcs : process(clk)
begin
if (clk'event and clk='1') then
if byte_ctr_ld = '1' then
byte_ctr <= (others => '0');
else
if byt_ce = '1' then
if byt_ce = '1' then
byte_ctr <= byte_ctr + 1;
end if;
end if;
end if;
-- terminal counts ---------------
if byt_ce = '1' then
-- control word + address
if (byte_ctr = X"000004") then
byte_ctr_tc0 <= '1';
else
byte_ctr_tc0 <= '0';
end if;
-- full page
if (byte_ctr = byte_plen) then
byte_ctr_tc1 <= '1';
else
byte_ctr_tc1 <= '0';
end if;
-- full sector
if (byte_ctr = byte_slen) then
byte_ctr_tc2 <= '1';
else
byte_ctr_tc2 <= '0';
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Count the number of pages we have written or read.
-------------------------------------------------------------
page_count_pcs : process(clk)
begin
if (clk'event and clk='1') then
if pge_ctr_ld = '1' then
pge_ctr <= pge_init;
else
if bit_ce = '1' then
if pge_ctr_en = '1' then
pge_ctr <= pge_ctr - 1;
end if;
end if;
end if;
-- terminal count ---------------
if (pge_ctr = 0) then
pge_ctr_tc <= '1';
else
pge_ctr_tc <= '0';
end if;
end if;
end process;
-------------------------------------------------------------
-- Count the number of sectors we have erased or protected.
-------------------------------------------------------------
sector_count_pcs : process(clk)
begin
if (clk'event and clk='1') then
if scr_ctr_ld = '1' then
scr_ctr <= scr_init;
else
if bit_ce = '1' then
if scr_ctr_en = '1' then
scr_ctr <= scr_ctr - 1;
end if;
end if;
end if;
-- terminal count ---------------
if (scr_ctr = 0) then
scr_ctr_tc <= '1';
else
scr_ctr_tc <= '0';
end if;
end if;
end process;
-------------------------------------------------------------
-- Generate address for sector erase.
-------------------------------------------------------------
ers_addr_pcs : process(clk)
begin
if (clk'event and clk='1') then
if ers_addr_ld = '1' then
ers_addr <= base_addr;
else
if bit_ce = '1' then
if ers_addr_en = '1' then
ers_addr <= ers_addr + SECTOR_SZ;
end if;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Generate address for sector protect.
-------------------------------------------------------------
ptt_addr_pcs : process(clk)
begin
if (clk'event and clk='1') then
if ptt_addr_ld = '1' then
ptt_addr <= ptt_init;
else
if bit_ce = '1' then
if ptt_addr_en = '1' then
ptt_addr <= ptt_addr + SECTOR_SZ;
end if;
end if;
end if;
end if;
end process;
-------------------------------------------------------------
-- Generate address for array write.
-------------------------------------------------------------
wr_addr_pcs : process(clk)
begin
if (clk'event and clk='1') then
if wr_addr_ld = '1' then
wr_addr <= base_addr;
else
if bit_ce = '1' then
if wr_addr_en = '1' then
wr_addr <= wr_addr + PAGE_SZ;
end if;
end if;
end if;
end if;
end process;
end behave;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment