URL
https://opencores.org/ocsvn/wishbone_spi_flash_interface/wishbone_spi_flash_interface/trunk
Subversion Repositories wishbone_spi_flash_interface
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 2 to Rev 1
- ↔ Reverse comparison
Rev 2 → Rev 1
/wishbone_spi_flash_interface/trunk/README.txt
File deleted
\ No newline at end of file
/wishbone_spi_flash_interface/trunk/spi_flash_interface_used_in_larger_FPGA_setting_for_register_initialization.zip
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
wishbone_spi_flash_interface/trunk/spi_flash_interface_used_in_larger_FPGA_setting_for_register_initialization.zip
Property changes :
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: wishbone_spi_flash_interface/trunk/spi_flash_sim.txt
===================================================================
--- wishbone_spi_flash_interface/trunk/spi_flash_sim.txt (revision 2)
+++ wishbone_spi_flash_interface/trunk/spi_flash_sim.txt (nonexistent)
@@ -1,256 +0,0 @@
-0D ; Carriage return for autobaud
-0A ;
-77 ; Write MAC address
-20 ;
-46 ;
-36 ;
-20 ;
-30 ;
-30 ;
-20 ;
-30 ;
-44 ;
-20 ;
-39 ;
-39 ;
-20 ;
-30 ;
-31 ;
-20 ;
-30 ;
-30 ;
-20 ;
-30 ;
-34 ;
-0D ;
-0A ;
-77 ; Wrote IP Address
-20 ;
-46 ;
-43 ;
-20 ;
-41 ;
-43 ;
-20 ;
-31 ;
-37 ;
-20 ;
-35 ;
-30 ;
-20 ;
-31 ;
-41 ;
-0D ;
-0A ;
-23 ; Comment
-20 ;
-53 ;
-65 ;
-6C ;
-66 ;
-20 ;
-4D ;
-41 ;
-43 ;
-20 ;
-26 ;
-20 ;
-49 ;
-50 ;
-20 ;
-41 ;
-64 ;
-64 ;
-72 ;
-65 ;
-73 ;
-73 ;
-65 ;
-73 ;
-20 ;
-69 ;
-6E ;
-69 ;
-74 ;
-69 ;
-61 ;
-6C ;
-69 ;
-7A ;
-65 ;
-64 ;
-2E ;
-0D ;
-0A ;
-00 ;
-00 ;
-00 ;
-00 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
-0E ;
-0F ;
-00 ;
-01 ;
-02 ;
-03 ;
-04 ;
-05 ;
-06 ;
-07 ;
-08 ;
-09 ;
-0A ;
-0B ;
-0C ;
-0D ;
Index: wishbone_spi_flash_interface/trunk/spi_pack.vhd
===================================================================
--- wishbone_spi_flash_interface/trunk/spi_pack.vhd (revision 2)
+++ wishbone_spi_flash_interface/trunk/spi_pack.vhd (nonexistent)
@@ -1,1620 +0,0 @@
---------------------------------------------------------------------------
--- Package of bit sync and DPLL components
---
---
---
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
-use IEEE.NUMERIC_STD.ALL;
-use IEEE.MATH_REAL.ALL;
-
-library work;
-use work.convert_pack.all;
-
-package spi_pack is
-
- component spi_flash_interface
- generic(
- NUM_CS : natural; -- Number of SPI device selects
- DEF_R_0 : unsigned(31 downto 0); -- SPI Chip Selects
- DEF_R_1 : unsigned(31 downto 0); -- SPI Command byte
- DEF_R_2 : unsigned(31 downto 0) -- SPI Address (24 bits)
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- Bus interface
- adr_i : in unsigned(3 downto 0);
- sel_i : in std_logic;
- we_i : in std_logic;
- dat_i : in unsigned(31 downto 0);
- dat_o : out unsigned(31 downto 0);
- ack_o : out std_logic;
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_cs_o : out unsigned(NUM_CS-1 downto 0);
- spi_sck_o : out std_logic;
- spi_so_o : out std_logic;
- spi_si_i : in std_logic
-
- );
- end component;
-
- component spi_flash_sys_init
- generic(
- SYS_CLK_RATE : real;
- FLASH_IDLE : natural; -- Number of ms idle before RAM-mapped FLASH operation closeout
- DECODE_BITS : natural; -- Number of init address upper-bits decoded to select individual SPI devices.
- DEF_R_0 : unsigned(31 downto 0) := str2u("00000001",32); -- low-level SPI Chip Select control
- DEF_R_1 : unsigned(31 downto 0) := str2u("00000003",32); -- low-level SPI Command byte
- DEF_R_2 : unsigned(31 downto 0) := str2u("007F0000",32); -- low-level SPI Address
- DEF_R_3 : unsigned(31 downto 0) := str2u("007F0000",32); -- Init Address
- DEF_R_4 : unsigned(31 downto 0) := str2u("00000100",32); -- Init Bytes
- DEF_R_5 : unsigned(31 downto 0) := str2u("00000001",32) -- Init Settings
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- Bus interface
- adr_i : in unsigned(3 downto 0);
- sel_i : in std_logic;
- we_i : in std_logic;
- dat_i : in unsigned(31 downto 0);
- dat_o : out unsigned(31 downto 0);
- ack_o : out std_logic;
-
- -- RAM mapped SPI FLASH access port
- -- (fl_ack_o may take ~5ms during page program)
- fl_adr_i : in unsigned(31 downto 0);
- fl_sel_i : in std_logic;
- fl_we_i : in std_logic;
- fl_dat_i : in unsigned(7 downto 0);
- fl_dat_o : out unsigned(7 downto 0);
- fl_ack_o : out std_logic;
-
- -- Init data output port
- init_adr_o : out unsigned(31 downto 0);
- init_dat_o : out unsigned(7 downto 0);
- init_cyc_o : out std_logic;
- init_ack_i : in std_logic;
- init_fin_o : out std_logic; -- Stays high when init is finished
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_adr_o : out unsigned(DECODE_BITS-1 downto 0);
- spi_cs_o : out std_logic;
- spi_sck_o : out std_logic;
- spi_so_o : out std_logic;
- spi_si_i : in std_logic
-
- );
- end component;
-
- component spi_flash_simulator
- generic(
- SYS_CLK_RATE : real;
- FLASH_ADR_BITS : natural; -- Flash memory size is based on this
- FLASH_INIT : string -- Default RX packet digestion settings
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_cs_i : in std_logic;
- spi_sck_i : in std_logic;
- spi_si_i : in std_logic;
- spi_so_o : out std_logic
-
- );
- end component;
-
-end spi_pack;
-
--------------------------------------------------------------------------------
--- SPI Flash Interface
--------------------------------------------------------------------------------
---
--- Author: John Clayton
--- Date : July 26, 2013 Created this module starting with code copied from
--- another module.
--- July 31, 2013 Modified this module in simulation, until it looked
--- correct. Tested in hardware. It works!
--- Aug. 10, 2013 Refined the design so that it enforces a minimum
--- spi_cs_o high time between assertions, thus allowing
--- the design to actually program SPI FLASH chips using
--- a 50 MHz clock, instead of just at 25 MHz.
---
--- Description
--------------------------------------------------------------------------------
--- This module is an interface to a SPI serial FLASH memory. The code was
--- written in order to keep it as generic as possible, but without many
--- extra frills. The module was written by reading the Adesto Technologies
--- AT25DF641 and ST Micro M25P64 datasheets.
---
--- There are three registers involved in its use. There is one for the
--- SPI command byte, one for the 24-bit SPI address, and one for data to
--- be read from, or written to, the SPI serial FLASH device.
---
--- The SPI serial FLASH interface is implemented using four signals:
--- spi_cs_o = SPI chip select outputs
--- spi_sck_o = Serial Clock output
--- spi_si_i = Serial Data input
--- spi_so_o = Serial Data output
---
--- For multiple SPI devices, the spi_cs_o output is implemented as a bus
--- of register driven outputs. The size of the bus is controlled by generics,
--- allowing any number of SPI devices to be selected. Because these outputs
--- are not decoded as a 1-active-of-N type signal, it is possible to select
--- multiple devices simultaneously, which may work well for writing and
--- erasing, but not for reading. You have been warned!
---
--- The spi_sck_o output is generated at half the sys_clk rate, and it is
--- not adjustable. To obtain operation at lower clock rates without
--- using a lower sys_clk frequency, consider slowing down the operation
--- of this module by the use of the sys_clk_en signal.
---
--- This module takes the approach that the serial communication with the
--- SPI device is not continuous. Instead, the command is completed in
--- segments or phases. To begin a command, a bus write to the SPI chip
--- select register asserts '0' on the desired chip select bits. Then, a write
--- to the command register causes the command to be sent out, generating a
--- burst of eight clock pulses. Another separate bus cycle is then required
--- in order to send out the address. After that, bus cycles can be used to
--- either read or write data bytes. At the conclusion of those activities,
--- the command can be terminated or executed by simply writing to the SPI
--- chip select register to raise the chip select bit back to a '1'.
---
--- This approach works because the spi_sck_o output is under control of
--- this module.
---
--- There are no provisions for use of the "hold" or "WP" (write protect)
--- signals. If desired, it might be possible to use sys_clk_en as a hold
--- signal, although this has not been tested or investigated in any detail.
---
--- The registers are summarized as follows:
---
--- Address Structure Function
--- ------- --------- -----------------------------------------------------
--- 0x0 (N:0) SPI chip Selects, where N=NUM_CS-1.
--- 0x1 (7:0) SPI Command Byte
--- 0x2 (23:0) SPI Address Bytes
--- 0x3+ (7:0) SPI Data
---
--- Notes on Registers:
---
--- (0x0) SPI Chip Selects
---
--- Writing to this register selects which associated spi_cs_o outputs are
--- active. The spi_cs_o outputs are driven directly from the register,
--- and can be changed at any time. SPI chip selects are low asserted,
--- so the bits in this register are loaded with all ones initially.
--- To initiate a command, the appropriate spi_cs_o bit must be cleared
--- to zero. To conclude and execute a command, the spi_cs_o bit must
--- be set back to one.
--- Reading this register returns the contents, but does not affect the
--- SPI interface.
--- Care should be exercised when using this register with multiple SPI
--- devices, as it is possible to activate more than one device. This
--- may work well for writing to the devices, but will result in data bit
--- collisions if multiple devices are read simultaneously.
---
--- (0x1) SPI Command Byte
---
--- Writing to this register causes the contents to be updated, and also
--- sends out the new contents in serial form, most significant bit first.
--- Reading this register returns the contents, but does not affect the
--- SPI interface.
---
--- (0x2) SPI Address Bytes
---
--- Writing to this register causes the contents to be updated, and also
--- sends out the new contents in serial form, most significant bit first.
--- Reading this register returns the contents, but does not affect the
--- SPI interface.
---
--- (0x3+) SPI Data Byte (Addresses in the range [0x3..0xF] access this.)
---
--- There is no local storage register inside the module for this address.
--- Writing to this address causes the data to be sent out in serial form,
--- most significant bit first.
--- Reading this address causes a burst of eight clock pulses to be issued
--- from the SPI interface, effectively reading in eight bits and returning
--- them in parallel over the bus interface.
--- Successive reads or writes therefore program or read successive locations
--- in the SPI device.
--- It should be noted that the SPI serial FLASH devices may allow continuous
--- reads which go on indefinitely, cycling through the entire contents of
--- the FLASH array. On the other hand, writes are buffered inside the
--- FLASH device, so that a "Byte/Page Program" instruction may allow from
--- 1 to 256 sequential bytes to be programmed. If more bytes are sent to
--- the FLASH device, it may simply cause the FIFO buffer inside the FLASH
--- device to hold the last 256 bytes for programming, discarding the bytes
--- which were written at first.
---
--- The sys_rst_n input is an asynchronous reset.
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
-use IEEE.NUMERIC_STD.ALL;
-use IEEE.MATH_REAL.ALL;
-
-library work;
-use work.convert_pack.all;
-
- entity spi_flash_interface is
- generic(
- NUM_CS : natural := 1; -- Number of SPI device selects
- DEF_R_0 : unsigned(31 downto 0) := str2u("00000001",32); -- SPI Chip Selects
- DEF_R_1 : unsigned(31 downto 0) := str2u("00000003",32); -- SPI Command byte
- DEF_R_2 : unsigned(31 downto 0) := str2u("007F0000",32) -- SPI Address (24 bits)
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- Bus interface
- adr_i : in unsigned(3 downto 0);
- sel_i : in std_logic;
- we_i : in std_logic;
- dat_i : in unsigned(31 downto 0);
- dat_o : out unsigned(31 downto 0);
- ack_o : out std_logic;
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_cs_o : out unsigned(NUM_CS-1 downto 0);
- spi_sck_o : out std_logic;
- spi_so_o : out std_logic;
- spi_si_i : in std_logic
-
- );
-end spi_flash_interface;
-
-architecture beh of spi_flash_interface is
-
--- Constants
-constant DAT_SIZE : natural := 32;
-
--- Internal signal declarations
-signal reg_cs : unsigned(NUM_CS-1 downto 0);
-signal reg_cmd : unsigned(7 downto 0);
-signal reg_adr : unsigned(23 downto 0);
-signal sr : unsigned(7 downto 0);
-signal clk_count : unsigned(4 downto 0);
-signal ack : std_logic;
- -- For the state machine
-type FSM_STATE_TYPE is (IDLE, SEND_CMD, SEND_ADR, SHIFT_A2, SHIFT_A1, SHIFT_A0, GET_BYTE, GIVE_ACK);
-signal fsm_state : FSM_STATE_TYPE;
-
-
------------------------------------------------------------------------------
-begin
-
- -- Register read mux
- with (adr_i) select
- dat_o <=
- u_resize(reg_cs,DAT_SIZE) when "0000",
- u_resize(reg_cmd,DAT_SIZE) when "0001",
- u_resize(reg_adr,DAT_SIZE) when "0010",
- u_resize(sr,DAT_SIZE) when others;
-
- -- Create acknowledge signal
- ack <= '1' when sel_i='1' and fsm_state=GIVE_ACK else '0';
-
- ack_o <= ack;
-
- -- Create SPI signals
- spi_cs_o <= reg_cs;
- spi_so_o <= sr(7);
- spi_sck_o <= clk_count(0);
-
- -- The main process
- main_proc: process(sys_clk, sys_rst_n)
- begin
- if (sys_rst_n='0') then
- reg_cs <= DEF_R_0(NUM_CS-1 downto 0);
- reg_cmd <= DEF_R_1(reg_cmd'length-1 downto 0);
- reg_adr <= DEF_R_2(reg_adr'length-1 downto 0);
- sr <= (others=>'0');
- clk_count <= to_unsigned(0,clk_count'length);
- fsm_state <= IDLE;
- elsif (sys_clk'event and sys_clk='1') then
- if (sys_clk_en='1') then
- -- Decrement the clock counter
- if (clk_count>0) then
- clk_count <= clk_count-1;
- -- Handle the shift register
- if (fsm_state=GET_BYTE and clk_count(0)='0') or (fsm_state/=GET_BYTE and clk_count(0)='1') then
- sr <= sr(6 downto 0) & spi_si_i;
- end if;
- end if;
- -- Handle state transitions
- case (fsm_state) is
-
- when IDLE =>
- null;
-
- when SEND_CMD =>
- sr <= reg_cmd;
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= SHIFT_A0;
-
- when SEND_ADR =>
- sr <= reg_adr(23 downto 16);
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= SHIFT_A2;
-
- when SHIFT_A2 =>
- if (clk_count=0) then
- sr <= reg_adr(15 downto 8);
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= SHIFT_A1;
- end if;
-
- when SHIFT_A1 =>
- if (clk_count=0) then
- sr <= reg_adr(7 downto 0);
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= SHIFT_A0;
- end if;
-
- when SHIFT_A0 =>
- if (clk_count=0) then
- fsm_state <= GIVE_ACK;
- end if;
-
- when GET_BYTE =>
- if (clk_count=0) then
- fsm_state <= GIVE_ACK;
- end if;
-
- when GIVE_ACK =>
- fsm_state <= IDLE;
-
- --when others =>
- -- fsm_state <= IDLE;
- end case;
-
- -- Handle bus writes to registers
- if (fsm_state=IDLE and sel_i='1' and we_i='1') then
- case (adr_i) is
- when "0000" =>
- reg_cs <= dat_i(NUM_CS-1 downto 0);
- fsm_state <= GIVE_ACK;
- when "0001" =>
- reg_cmd <= dat_i(reg_cmd'length-1 downto 0);
- fsm_state <= SEND_CMD;
- when "0010" =>
- reg_adr <= dat_i(reg_adr'length-1 downto 0);
- fsm_state <= SEND_ADR;
- when others => null;
- sr <= dat_i(sr'length-1 downto 0);
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= SHIFT_A0;
- end case;
- end if;
- -- Handle SPI read cycle
- if (fsm_state=IDLE and sel_i='1' and we_i='0') then
- case (adr_i) is
- when "0000" =>
- fsm_state <= GIVE_ACK;
- when "0001" =>
- fsm_state <= GIVE_ACK;
- when "0010" =>
- fsm_state <= GIVE_ACK;
- when others =>
- clk_count <= to_unsigned(16,clk_count'length);
- fsm_state <= GET_BYTE;
- end case;
- end if;
-
- end if; -- sys_clk_en
- end if; -- sys_clk
- end process;
-
-
-end beh;
-
--------------------------------------------------------------------------------
--- SPI Flash System Initializer
--------------------------------------------------------------------------------
---
--- Author: John Clayton
--- Date : July 31, 2013 Created this module starting with code copied from
--- another module. Began writing description.
--- Aug. 5, 2013 Simulated the design. Revamped the register
--- structure, added init_chain feature. Combined
--- states in fl_state FSM.
--- Aug. 7, 2013 Added explicit reset bit.
---
--- Description
--------------------------------------------------------------------------------
--- This module uses an interface to SPI serial FLASH memory devices to allow
--- reading/writing/erasing of the FLASH. It includes a state machine that
--- coordinates many of the required commands automatically, to make the
--- process of reading and writing SPI FLASH appear as though a simple RAM
--- is being used. Moreover, the state machine has an initialization mode
--- which can read bytes out of the selected SPI FLASH device and present
--- them on an 8-bit parallel output port.
---
--- The actual rate of outputting "initialization bytes" is determined by
--- the init_ack_i input, up to the maximum available rate Fmax of approx.
--- 2.7 MBytes/second. This maximum byte transfer rate is calculated
--- according to the following formula:
---
--- Fmax = (Fsys_clk / N)
---
--- Where N=18 sys_clks required per byte obtained, and Fsys_clk is
--- currently 50 MHz. Other sys_clk rates would also work.
---
--- The init_adr_o output allows the outgoing bytes to be treated in
--- different ways, or stored into different places, depending on the address
--- setting being used. Note that the init_adr_o output is taken directly
--- from the init address register, which refers to the addresses within
--- the SPI devices themselves. This signal therefore not required to be
--- used as-is during initialization. Feel free to substitute any addresses
--- you want, or re-map the initialization addresses as needed.
---
--- The idea is that the parallel output bytes can be used to send commands
--- on a system bus. One way to do this is to attach a UART, which would
--- inject ASCII characters into an ASCII command interpreter, such as
--- "async_syscon" or "udp_ip_syscon".
---
--- Another way would be to send the bytes into a binary command interpreter.
---
--- Another way would be to attach the init port as a requester on the arbiter
--- for the target bus.
---
--- In addition to creating initialization commands at power on, the output
--- bytes can also be treated as DSP samples of a waveform. Thus, the output
--- could be used to generate audio "sound bytes" [pun intended] at a set
--- sample rate and bits per sample.
---
--- In fact, it is conceivable that through the use of a command interpreter,
--- a final initialization command could reprogram the initialization address
--- and quantity, in order to begin a whole new initialization sequence! Oh,
--- the sheer joy of it! If there is no command interpreter being used, there
--- is an alternative method of achieving this serial-init-sequencing joy.
--- A chain enable bit is provided in the initialization settings register
--- which causes the initialization sequencer to "re-up" by using the last
--- eight bytes of the current initialization sequence as a new address and
--- quantity for the next one. Isn't that simply grand?
---
--- Think of what you could do... You could set up registers in the first
--- initialization sequence, and then invoke another sequence which would
--- play some kind of audio greeting. It could be music, or perhaps a voice.
--- Like the audio might say "System is now fully functional, and ready!"
--- Like that. You know, it isn't bad to have a healthy imagination.
--- At least, that's what I imagine.
---
--- As a corollary benefit of implementing the initialization function, an
--- additional SPI FLASH memory mapping "feature" is provided. This means
--- that the entire contents of the SPI FLASH device is memory mapped, with a
--- separate address for each byte within the device. Sequential reads and
--- writes are allowed within this address space, and the needed WREN and
--- other commands to perform the reads/writes are performed automatically.
--- This also means that the bus cycle acknowledge signal when using the
--- memory mapped region can take quite a long time to appear, on the order
--- of 5 ms. Also note that the key word when using the memory mapped
--- region is "sequential." This is so important that this module actually
--- enforces sequential accesses, by keeping a copy of the initial address
--- and incrementing that during the session. The "session" begins when
--- an access is requested within the memory mapped region, and ends when
--- an "access idle" timeout is reached. Therefore, temporally-sequential
--- accesses which attempt to decrement the address, or jump around in
--- other ways, will actually result in sequential bytes being read/written
--- during the session.
---
--- The system initializer is an extension of a much simpler register-based
--- "low-level" SPI Flash interface module. The "low-level" features are
--- preserved in this module.
---
--- The original interface was written in order to be as generic as possible,
--- without many extra frills. The module was written by and tested using
--- the Adesto Technologies AT25DF641 and ST Micro M25P64 datasheets. Also,
--- hardware testing was initially done on the M25P64 mounted on a Lattice
--- Semiconductor "Versa" FPGA development board. Nevertheless, this design
--- should work quite easily with other SPI FLASH devices and other FPGAs.
---
--- For the basic SPI interface, there are three registers involved.
--- There is one for the SPI command byte, one for the 24-bit SPI address,
--- and one for data to be read from, or written to, the SPI serial FLASH
--- device. The basic interface was preserved in order to allow for any
--- desired command to be explicitly executed via register accesses.
---
--- The SPI serial FLASH interface is implemented using four signals:
--- spi_cs_o = SPI chip select outputs
--- spi_sck_o = Serial Clock output
--- spi_si_i = Serial Data input
--- spi_so_o = Serial Data output
---
--- For multiple SPI devices, the spi_cs_o output is implemented as a bus
--- of register driven outputs. The size of the bus is controlled by generics,
--- allowing any number of SPI devices to be selected. Because these outputs
--- are not decoded as a 1-active-of-N type signal, it is possible to select
--- multiple devices simultaneously, which may work well for writing and
--- erasing, but not for reading. You have been warned!
---
--- The spi_sck_o output is generated at half the sys_clk rate, and it is
--- not adjustable. To obtain operation at lower clock rates without
--- using a lower sys_clk frequency, consider slowing down the operation
--- of this module by the use of the sys_clk_en signal.
---
--- This module takes the approach that the serial communication with the
--- SPI device is not continuous. Instead, the command is completed in
--- segments or phases. To begin a command, a bus write to the SPI chip
--- select register asserts '0' on the desired chip select bits. Then, a write
--- to the command register causes the command to be sent out, generating a
--- burst of eight clock pulses. Another separate bus cycle is then required
--- in order to send out the address. After that, bus cycles can be used to
--- either read or write data bytes. At the conclusion of those activities,
--- the command can be terminated or executed by simply writing to the SPI
--- chip select register to raise the chip select bit back to a '1'.
---
--- This approach works because the spi_sck_o output is under control of
--- this module.
---
--- There are no provisions for use of the "hold" or "WP" (write protect)
--- signals. If desired, it might be possible to use sys_clk_en as a hold
--- signal, although this has not been tested or investigated in any detail.
---
--- The registers are summarized as follows:
---
--- Address Structure Function
--- ------- -------------- -----------------------------------------------------
--- 0x0 (N+16:16,N:0) SPI chip Selects, where N=NUM_CS-1.
--- 0x1 (7:0) SPI Command Byte
--- 0x2 (23:0) SPI Address Bytes
--- 0x3 (31:0) Init Address
--- 0x4 (31:0) Init Quantity (bytes)
--- 0x5 (3:0) Init Settings
--- 0x6+ (7:0) SPI Data
---
--- Notes on Registers:
---
--- (0x0) low-level SPI Chip Select control
---
--- This register contains a single bit, which is directly mapped to the
--- spi_cs_o output during low-level SPI operations. During ram mapped
--- operations and initialization sequences, the spi_cs_o output is
--- controlled automatically by a state machine so that during those
--- operations, this bit has no effect.
---
--- (0x1) low-level SPI Command Byte
---
--- This is part of the low-level SPI interface, and is not involved in
--- initialization or RAM mapping of the SPI devices.
---
--- Writing to this register causes the contents to be updated, and also
--- sends out the new contents in serial form, most significant bit first.
--- Reading this register returns the contents, but does not affect the
--- SPI interface.
---
--- (0x2) low-level SPI Address
---
--- This is part of the low-level SPI interface, and is not involved in
--- initialization or RAM mapping of the SPI devices.
---
--- Writing to this register causes the contents to be updated, and also
--- sends out the new contents in serial form, most significant bits first.
--- Reading this register returns the contents, but does not affect the
--- SPI interface.
---
--- The number of bytes used for SPI addresses is set by the constant
--- SPI_ADR_BYTES.
---
--- (0x3) Init Address
---
--- Bits (31:0) contain the initialization address, which consists of
--- four bytes: [decode][sector][page][byte]
--- This grouping of fields is actually based on the size of the
--- SPI FLASH devices being tested. If larger devices are used,
--- for example, then the [decode] field may use fewer bits, and
--- the [sector] field may grow. Similarly, the [page] field might
--- change if the devices being used have pages larger than 256
--- bytes. So, it's a matter of interpretation. The main idea is
--- for form a flat address space which maps all the attached SPI
--- devices.
---
--- (0x4) Initialization Quantity (Bytes)
--- This register contains the number of bytes to read from the SPI
--- FLASH device during an initialization operation.
--- The number can be quite large, up to 0x800000 (8 Mbytes) for the
--- AT25DF641 and M25P64. In anticipation of larger future devices,
--- this field was made a full 32-bits, allowing up to 4 gigabytes.
--- Operation of the initialization cycle begins immediately once
--- this field is set to anything greater than zero. Also, the
--- quantity is "live" and it decrements during initialization.
---
--- (0x5) Init Settings
---
--- Bit (0) is the R/W Access Enable bit. Set this bit in order to
--- freely read and write to the SPI FLASH via the memory mapped
--- interface. When it is cleared, the memory mapped interface does
--- not respond with a bus cycle acknowledge, since it is not
--- operating.
--- Bit (1) is the Initialization chain enable bit. Setting this bit
--- causes the last eight bytes of the initialization to be withheld.
--- Instead of being sent out as bus cycles on the parallel init bus,
--- the bytes are used to reset the initializer for another run
--- using a new address and a new quantity. Since the init_ack_i
--- input is used to throttle initialization cycles when delays are
--- required, no delay is provided within the eight "re-up" bytes.
--- The re-up bytes are composed of four address bytes, followed by
--- four quantity bytes. The fields are stored least significant
--- byte first.
--- Bit (2) is the Erase bit. Set this bit to erase the sector
--- currently selected by the [sector] field in the address register.
--- Note that sector erase times can be on the order of seconds.
--- (Typically 1s, but up to 3s for M25P64. Typically 400ms, but
--- up to 950ms for AT25DF641.) Since the erase operation is
--- self-timed inside the device, this module polls the device status
--- register to see when the erase operation is completed. When it
--- is, the erase bit is then cleared. No other operations are
--- possible while this is occurring. Because the sector erase can
--- take so long, there is a way to break out by using the explicit
--- reset bit. Also, there is no automatic timeout from the sector
--- erase operation.
--- Bit (3) is an explicit reset bit. Setting it resets both state
--- machines. It is a write only bit, and returns a '0' when read.
--- It can be used to "break out" of an operation, such as a long
--- sector erase.
---
--- (0x6+) SPI Data Byte (System cycles in the range [0x6..0xF] access this.)
---
--- This is part of the low-level SPI interface, and is not involved in
--- initialization or RAM mapping of the SPI devices.
---
--- There is no local storage register inside the module for this address.
--- Writing to this address causes the data to be sent out in serial form,
--- most significant bit first.
--- Reading this address causes a burst of eight clock pulses to be issued
--- from the SPI interface, effectively reading in eight bits and returning
--- them in parallel over the bus interface.
--- Successive reads or writes therefore program or read successive locations
--- in the SPI device.
--- It should be noted that the SPI serial FLASH devices may allow continuous
--- reads which go on indefinitely, cycling through the entire contents of
--- the FLASH array. On the other hand, writes are buffered inside the
--- FLASH device, so that a "Byte/Page Program" instruction may allow from
--- 1 to 256 sequential bytes to be programmed. If more bytes are sent to
--- the FLASH device, it may simply cause the FIFO buffer inside the FLASH
--- device to hold the last 256 bytes for programming, discarding the bytes
--- which were written at first.
---
--- The sys_rst_n input is an asynchronous reset.
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
-use IEEE.NUMERIC_STD.ALL;
-use IEEE.MATH_REAL.ALL;
-
-library work;
-use work.dds_pack.all;
-use work.convert_pack.all;
-
- entity spi_flash_sys_init is
- generic(
- SYS_CLK_RATE : real := 50000000.0;
- FLASH_IDLE : natural := 2; -- Number of ms idle before RAM-mapped FLASH operation closeout
- DECODE_BITS : natural := 8; -- Number of init address upper-bits decoded to select individual SPI devices.
- DEF_R_0 : unsigned(31 downto 0) := str2u("00000001",32); -- low-level SPI Chip Select control
- DEF_R_1 : unsigned(31 downto 0) := str2u("00000003",32); -- low-level SPI Command byte
- DEF_R_2 : unsigned(31 downto 0) := str2u("007F0000",32); -- low-level SPI Address
- DEF_R_3 : unsigned(31 downto 0) := str2u("007F0000",32); -- Init Address
- DEF_R_4 : unsigned(31 downto 0) := str2u("00000100",32); -- Init Bytes
- DEF_R_5 : unsigned(31 downto 0) := str2u("00000001",32) -- Init Settings
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- Bus interface
- adr_i : in unsigned(3 downto 0);
- sel_i : in std_logic;
- we_i : in std_logic;
- dat_i : in unsigned(31 downto 0);
- dat_o : out unsigned(31 downto 0);
- ack_o : out std_logic;
-
- -- RAM mapped SPI FLASH access port
- -- (fl_ack_o may take ~5ms during page program)
- fl_adr_i : in unsigned(31 downto 0);
- fl_sel_i : in std_logic;
- fl_we_i : in std_logic;
- fl_dat_i : in unsigned(7 downto 0);
- fl_dat_o : out unsigned(7 downto 0);
- fl_ack_o : out std_logic;
-
- -- Init data output port
- init_adr_o : out unsigned(31 downto 0);
- init_dat_o : out unsigned(7 downto 0);
- init_cyc_o : out std_logic;
- init_ack_i : in std_logic;
- init_fin_o : out std_logic; -- Stays high when init is finished
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_adr_o : out unsigned(DECODE_BITS-1 downto 0);
- spi_cs_o : out std_logic;
- spi_sck_o : out std_logic;
- spi_so_o : out std_logic;
- spi_si_i : in std_logic
-
- );
-end spi_flash_sys_init;
-
-architecture beh of spi_flash_sys_init is
-
--- Constants
-constant DAT_SIZE : natural := 32;
-constant IDLE_TB_FREQ : real := 1000.0; -- Timebase is millisecond resolution
-constant IDLE_TB_ACC_BITS : natural := 24;
-constant IDLE_TIMER_WIDTH : natural := timer_width(FLASH_IDLE);
-
-constant SPI_ADR_BYTES : natural := 3; -- Increase for larger size devices
-constant SPI_ACNT_WIDTH : natural := timer_width(SPI_ADR_BYTES);
-
-constant SPI_CMD_PP : natural := 16#02#;
-constant SPI_CMD_READ : natural := 16#03#;
-constant SPI_CMD_RDSR : natural := 16#05#;
-constant SPI_CMD_WREN : natural := 16#06#;
-constant SPI_CMD_SE : natural := 16#D8#;
-
-constant CS_HIGH_CYCLES : natural := 8; -- minimum # of sysclks spi_cs_o will be driven high.
-constant CLK_COUNT_1BYTE : natural := 16;
-constant CLK_COUNT_DESEL : natural := CLK_COUNT_1BYTE+CS_HIGH_CYCLES;
-
--- Internal signal declarations
-signal reg_cs : std_logic;
-signal reg_cmd : unsigned(7 downto 0);
-signal reg_adr : unsigned(31 downto 0);
-signal reg_ispi_adr : unsigned(31 downto 0);
-signal adr_count : unsigned(SPI_ACNT_WIDTH-1 downto 0);
-signal adr_word : unsigned(31 downto 0);
-signal adr_byte : unsigned(7 downto 0);
-signal sr : unsigned(7 downto 0);
-signal clk_count : unsigned(4 downto 0);
-signal spi_ack : std_logic;
-signal reg_we : std_logic;
-signal reg_rw : std_logic;
-signal reg_chain : std_logic;
-signal reg_erasing : std_logic;
-signal reg_init_len : unsigned(31 downto 0);
-signal reg_new_len : unsigned(31 downto 0);
-signal idle_timer : unsigned(IDLE_TIMER_WIDTH-1 downto 0);
-signal idle_tb_pulse : std_logic;
-signal idle_tb_ftw : unsigned(IDLE_TB_ACC_BITS-1 downto 0);
-signal idle_tb_hold : std_logic;
-
- -- For the SPI state machine
-type SPI_STATE_TYPE is (IDLE, SEND_CMD, SEND_ADR, SHIFT_ADR, SHIFT_BYTE,
- GET_BYTE, GIVE_ACK);
-signal spi_state : SPI_STATE_TYPE;
-
- -- For the FLASH state machine
-type FLASH_STATE_TYPE is (IDLE, R_WREN, R_CMD, R_ADR, R_DAT, R_WAIT,
- R_STAT_1, R_STAT_2, INIT_CYCLE, INIT_CHAIN, INIT_RESTART);
-signal fl_state : FLASH_STATE_TYPE;
-signal fl_ack : std_logic;
-
-
------------------------------------------------------------------------------
-begin
-
- -- Register read mux
- with (adr_i) select
- dat_o <=
- to_unsigned(0,31) & reg_cs when "0000",
- u_resize(reg_cmd,DAT_SIZE) when "0001",
- reg_adr when "0010",
- reg_ispi_adr when "0011",
- u_resize(reg_init_len,DAT_SIZE) when "0100",
- to_unsigned(0,29) & reg_erasing & reg_chain & reg_rw when "0101",
- u_resize(sr,DAT_SIZE) when others;
-
- -- Create acknowledge signals
- spi_ack <= '1' when spi_state=GIVE_ACK else '0';
- ack_o <= '1' when spi_ack='1' and sel_i='1' else '0';
- fl_ack_o <= fl_ack;
-
- -- Provide FLASH data output
- fl_dat_o <= sr;
-
- -- Provide initialization outputs
- init_adr_o <= reg_ispi_adr;
- init_cyc_o <= '1' when fl_state=INIT_CYCLE else '0';
-
- -- Create SPI signals
- spi_adr_o <= adr_word(adr_word'length-1 downto adr_word'length-DECODE_BITS);
- spi_cs_o <= reg_cs when fl_state=IDLE else
- '0' when clk_count<=CLK_COUNT_1BYTE else
- '1';
- spi_so_o <= sr(7);
- spi_sck_o <= clk_count(0) when clk_count'0') when 0,
--- adr_word(8*to_integer(adr_count)-1 downto 8*(to_integer(adr_count)-1)) when others;
- with (to_integer(adr_count)) select
- adr_byte <=
- (others=>'0') when 0,
- adr_word(7 downto 0) when 1,
- adr_word(15 downto 8) when 2,
- adr_word(23 downto 16) when 3,
- adr_word(31 downto 24) when 4,
- (others=>'0') when others;
-
- -- Create timebase for idle timer
- idle_tb_ftw <= to_unsigned(integer(IDLE_TB_FREQ*(2**real(IDLE_TB_ACC_BITS))/SYS_CLK_RATE),idle_tb_ftw'length);
- idle_tb_hold <= '0' when (fl_state=IDLE or fl_state=R_WAIT or fl_state=INIT_CYCLE) else '1';
- timer_0 : dds_squarewave_phase_load
- generic map(
- ACC_BITS => IDLE_TB_ACC_BITS
- )
- port map(
-
- sys_rst_n => sys_rst_n,
- sys_clk => sys_clk,
- sys_clk_en => sys_clk_en,
-
- -- Frequency setting
- freq_i => idle_tb_ftw,
-
- -- Synchronous load
- phase_i => to_unsigned(2**(IDLE_TB_ACC_BITS-1),IDLE_TB_ACC_BITS),
- phase_ld_i => idle_tb_hold,
-
- -- Output
- pulse_o => idle_tb_pulse,
- squarewave_o => open
- );
-
- -- Handle state machines and writes to registers
- reg_proc: process(sys_clk, sys_rst_n)
- begin
- if (sys_rst_n='0') then
- reg_cs <= DEF_R_0(0);
- reg_cmd <= DEF_R_1(reg_cmd'length-1 downto 0);
- reg_adr <= DEF_R_2;
- reg_ispi_adr <= DEF_R_3;
- reg_rw <= DEF_R_5(0);
- reg_chain <= DEF_R_5(1);
- reg_init_len <= DEF_R_4(reg_init_len'length-1 downto 0);
- reg_new_len <= (others=>'0');
- sr <= (others=>'0');
- adr_count <= to_unsigned(1,adr_count'length);
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- spi_state <= IDLE;
- fl_state <= IDLE;
- fl_ack <= '0';
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- init_dat_o <= (others=>'0');
- reg_we <= '0';
- elsif (sys_clk'event and sys_clk='1') then
- if (sys_clk_en='1') then
- -- Decrement the SPI clock counter
- if (clk_count>0) then
- clk_count <= clk_count-1;
- -- Handle the SPI shift register
- if (spi_state=GET_BYTE and clk_count(0)='0' and clk_count0 and idle_tb_pulse='1') then
- idle_timer <= idle_timer-1;
- end if;
- ----------------------------------
- -- Handle SPI state transitions --
- ----------------------------------
- case (spi_state) is
-
- when IDLE =>
- null;
-
- when SEND_CMD =>
- sr <= reg_cmd;
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
-
- -- adr_count must have already been set when going into this state,
- -- to ensure that sr is loaded with the correct bytes
- when SEND_ADR =>
- sr <= adr_byte;
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_ADR;
-
- when SHIFT_ADR =>
- if (clk_count=0) then
- if (adr_count=1) then
- spi_state <= GIVE_ACK;
- else
- adr_count <= adr_count-1;
- spi_state <= SEND_ADR;
- end if;
- end if;
-
- when SHIFT_BYTE =>
- if (clk_count=0) then
- spi_state <= GIVE_ACK;
- end if;
-
- when GET_BYTE =>
- if (clk_count=0) then
- spi_state <= GIVE_ACK;
- end if;
-
- when GIVE_ACK =>
- spi_state <= IDLE;
-
- --when others =>
- -- spi_state <= IDLE;
- end case;
-
- ------------------------------------
- -- Handle FLASH state transitions --
- ------------------------------------
- -- Default Values
- fl_ack <= '0';
- case (fl_state) is
-
- when IDLE =>
- if (reg_rw='1' and spi_state=IDLE) then
- if (fl_sel_i='1') then
- -- Store local copy of requested address
- -- All subsequenct accesses within the SPI command session will be sequential
- -- The external address does not guarantee this, but the internal
- -- one does.
- reg_ispi_adr <= fl_adr_i;
- -- Store write/read indication
- reg_we <= fl_we_i;
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- if (fl_we_i='1') then
- reg_cmd <= to_unsigned(SPI_CMD_PP,reg_cmd'length);
- fl_state <= R_WREN;
- sr <= to_unsigned(SPI_CMD_WREN,sr'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- else
- reg_cmd <= to_unsigned(SPI_CMD_READ,reg_cmd'length);
- fl_state <= R_CMD;
- sr <= to_unsigned(SPI_CMD_READ,sr'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- end if;
- end if;
- end if;
- -- If there is initialization to do, get it done.
- -- This has priority over other operations.
- if (reg_init_len>0) then
- reg_cmd <= to_unsigned(SPI_CMD_READ,reg_cmd'length);
- fl_state <= R_CMD;
- sr <= to_unsigned(SPI_CMD_READ,sr'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- end if;
-
- when R_WREN =>
- if (spi_ack='1') then
- sr <= reg_cmd;
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_CMD;
- end if;
-
- when R_CMD =>
- if (spi_ack='1') then
- adr_count <= to_unsigned(SPI_ADR_BYTES,adr_count'length);
- spi_state <= SEND_ADR;
- fl_state <= R_ADR;
- end if;
-
- when R_ADR =>
- if (spi_ack='1') then
- if (reg_cmd=SPI_CMD_SE) then
- sr <= to_unsigned(SPI_CMD_RDSR,sr'length);
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_1;
- else
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_DAT;
- sr <= fl_dat_i; -- Needed for writes, and does not affect reads.
- end if;
- end if;
-
- when R_DAT =>
- if (reg_init_len>0) then
- -- Handle init case
- if (spi_ack='1') then
- if (reg_chain='1' and reg_init_len<=8) then
- fl_state <= INIT_CHAIN;
- else
- init_dat_o <= sr;
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- fl_state <= INIT_CYCLE;
- end if;
- end if;
- else
- -- Handle memory mapped I/O case
- -- Await timeout, in case current cycle is not de-asserted in time.
- if (idle_timer=0) then
- if (reg_cmd=SPI_CMD_READ) then
- fl_state <= IDLE;
- else
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- sr <= to_unsigned(SPI_CMD_RDSR,sr'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_1;
- end if;
- end if;
- -- Acknowledge the memory mapped cycle
- if (spi_ack='1') then
- fl_ack <= '1';
- end if;
- -- Handle de-assertion of current cycle
- if (fl_sel_i='0') then
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- fl_state <= R_WAIT;
- end if;
- end if;
-
- -- This is a "waiting state" to see if the current SPI session is
- -- going to continue. It continues if another write is requested.
- -- within the allowed timeout window.
- when R_WAIT =>
- -- On timeout, terminate the SPI PP command.
- if (idle_timer=0) then
- if (reg_cmd=SPI_CMD_READ) then
- fl_state <= IDLE;
- else
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- sr <= to_unsigned(SPI_CMD_RDSR,sr'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_1;
- end if;
- end if;
- -- If another similar cycle is requested, continue
- if (fl_sel_i='1' and fl_we_i=reg_we) then
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- sr <= fl_dat_i;
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_DAT;
- end if;
- -- If a different cycle is requested, terminate the SPI command
- if (fl_sel_i='1' and fl_we_i/=reg_we) then
- if (reg_cmd=SPI_CMD_READ) then
- fl_state <= IDLE;
- else
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- sr <= to_unsigned(SPI_CMD_RDSR,sr'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_1;
- end if;
- end if;
-
- -- Timeout is disabled for sector erase.
- -- The erase register bit can be cleared to reset the state machine.
- -- (It can take a veeeerrrryy long time to erase a sector...)
- -- (Like up to a second!)
- when R_STAT_1 =>
- if (spi_ack='1') then
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_2;
- end if;
-
- when R_STAT_2 =>
- if (idle_timer=0 and reg_cmd/=SPI_CMD_SE) then
- fl_state <= IDLE;
- elsif (spi_ack='1') then
- if (sr(0)='1') then -- If WIP is set, keep checking status.
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- else
- fl_state <= IDLE;
- end if;
- end if;
-
- -- This state creates an init cycle
- when INIT_CYCLE =>
- -- Await timeout, in case current cycle is not acknowledged in time.
- if (idle_timer=0) then
- fl_state <= IDLE;
- end if;
- -- Await acknowledge of current cycle
- if (init_ack_i='1') then
- reg_ispi_adr <= reg_ispi_adr+1;
- reg_init_len <= reg_init_len-1;
- if (reg_init_len=1) then
- fl_state <= IDLE;
- else
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_DAT;
- end if;
- end if;
-
- when INIT_CHAIN =>
- if (reg_init_len>4) then
- reg_ispi_adr(7 downto 0) <= sr;
- reg_ispi_adr(31 downto 8) <= reg_ispi_adr(23 downto 0);
- else
- reg_new_len(7 downto 0) <= sr;
- reg_new_len(31 downto 8) <= reg_new_len(23 downto 0);
- end if;
- reg_init_len <= reg_init_len-1;
- if (reg_init_len=1) then
- fl_state <= INIT_RESTART;
- else
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_DAT;
- end if;
-
- when INIT_RESTART =>
- if (reg_new_len>0) then
- reg_init_len <= reg_new_len;
- -- Deselect SPI device to execute SPI command
- clk_count <= to_unsigned(CLK_COUNT_DESEL,clk_count'length);
- idle_timer <= to_unsigned(FLASH_IDLE,idle_timer'length);
- sr <= to_unsigned(SPI_CMD_RDSR,sr'length);
- spi_state <= SHIFT_BYTE;
- fl_state <= R_STAT_1;
- else
- fl_state <= IDLE;
- end if;
-
- when others =>
- spi_state <= IDLE;
- end case;
-
- -- Handle bus writes to registers
- if (spi_state=IDLE and fl_state=IDLE and sel_i='1' and we_i='1') then
- case (adr_i) is
- when "0000" =>
- reg_cs <= dat_i(0);
- spi_state <= GIVE_ACK;
- when "0001" =>
- reg_cmd <= dat_i(reg_cmd'length-1 downto 0);
- spi_state <= SEND_CMD;
- when "0010" =>
- reg_adr <= dat_i;
- adr_count <= to_unsigned(SPI_ADR_BYTES,adr_count'length);
- spi_state <= SEND_ADR;
- when "0011" =>
- reg_ispi_adr <= dat_i(reg_ispi_adr'length-1 downto 0);
- spi_state <= GIVE_ACK; -- A quick acknowledgment
- when "0100" =>
- reg_init_len <= dat_i(reg_init_len'length-1 downto 0);
- spi_state <= GIVE_ACK; -- A quick acknowledgment
- when "0101" =>
- reg_rw <= dat_i(0);
- reg_chain <= dat_i(1);
- if (dat_i(2)='1') then
- if (reg_erasing='0') then
- reg_cmd <= to_unsigned(SPI_CMD_SE,reg_cmd'length);
- fl_state <= R_WREN;
- sr <= to_unsigned(SPI_CMD_WREN,sr'length);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- end if;
- else
- spi_state <= GIVE_ACK; -- A quick acknowledgment
- end if;
- if (dat_i(3)='1') then
- spi_state <= IDLE;
- fl_state <= IDLE;
- reg_init_len <= (others=>'0');
- end if;
- when others =>
- sr <= dat_i(sr'length-1 downto 0);
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= SHIFT_BYTE;
- end case;
- end if;
- -- Handle SPI read cycle
- if (spi_state=IDLE and fl_state=IDLE and sel_i='1' and we_i='0') then
- case (adr_i) is
- when "0000" =>
- spi_state <= GIVE_ACK;
- when "0001" =>
- spi_state <= GIVE_ACK;
- when "0010" =>
- spi_state <= GIVE_ACK;
- when "0011" =>
- spi_state <= GIVE_ACK;
- when "0100" =>
- spi_state <= GIVE_ACK;
- when "0101" =>
- spi_state <= GIVE_ACK;
- when others =>
- clk_count <= to_unsigned(CLK_COUNT_1BYTE,clk_count'length);
- spi_state <= GET_BYTE;
- end case;
- end if;
-
- end if; -- sys_clk_en
- end if; -- sys_clk
- end process;
-
- -- Create signal that is high during sector erase activity
- reg_erasing <= '1' when (fl_state/=IDLE and reg_cmd=SPI_CMD_SE) else '0';
-
- -- Create signal that is high whenever initialization is not active.
- init_fin_o <= '1' when reg_init_len=0 else '0';
-
-end beh;
-
--------------------------------------------------------------------------------
--- SPI Flash Simulator
--------------------------------------------------------------------------------
---
--- Author: John Clayton
--- Date : Aug. 7, 2013 Created this module starting with code copied from
--- another module.
--- Aug. 10, 2013 Added and simulated page programming and sector erase
--- with concurrent status register reads. Only the
--- WIP bit is implemented within the status register.
---
--- Description
--------------------------------------------------------------------------------
--- This module is a very simplistic SPI FLASH simulator. It was created with
--- the intent of running a simulation, so that real data can be returned from
--- this module to a device which is accessing a SPI FLASH device.
---
--- Because of its simple intent, this module does not implement all the
--- functions of a typical SPI FLASH, but it does do reading and writing.
--- It implements the "write enable latch" instruction, and it can be erased
--- too.
---
--- The kind of device being simulated has 24 address bits, although the size
--- of the simulated FLASH memory is much smaller. It will simply wrap around
--- to the beginning of the array if the end is passed.
---
--- Because the unit is for simulation only, a separate clock domain is created
--- for the spi_sclk_i input
---
--- The sys_rst_n input is an asynchronous reset.
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
-use IEEE.NUMERIC_STD.ALL;
-use IEEE.MATH_REAL.ALL;
-
-library work;
-use work.dds_pack.all;
-use work.convert_pack.all;
-use work.block_ram_pack.all;
-
- entity spi_flash_simulator is
- generic(
- SYS_CLK_RATE : real := 50000000.0;
- FLASH_ADR_BITS : natural := 8; -- Flash memory size is based on this
- FLASH_INIT : string := ".\flash_sim_init.txt" -- Default RX packet digestion settings
- );
- port (
- -- System Clock and Clock Enable
- sys_rst_n : in std_logic;
- sys_clk : in std_logic;
- sys_clk_en : in std_logic;
-
- -- SPI interface
- -- "hold" and "WP" are not implemented.
- spi_cs_i : in std_logic;
- spi_sck_i : in std_logic;
- spi_si_i : in std_logic;
- spi_so_o : out std_logic
-
- );
- end spi_flash_simulator;
-
-architecture beh of spi_flash_simulator is
-
--- Constants
-constant SPI_CMD_NOP : natural := 16#00#;
-constant SPI_CMD_PP : natural := 16#02#;
-constant SPI_CMD_READ : natural := 16#03#;
-constant SPI_CMD_RDSR : natural := 16#05#;
-constant SPI_CMD_WREN : natural := 16#06#;
-constant SPI_CMD_SE : natural := 16#D8#;
-
-constant WIP_PP_TIMEOUT : natural := 12; -- 1.2 milliseconds
---constant WIP_SE_TIMEOUT : natural := 12000; -- 1.2 seconds (realistic number)
-constant WIP_SE_TIMEOUT : natural := 24; -- 2.4 milliseconds (for faster simulation)
-constant WIP_TB_FREQ : real := 10000.0; -- Timebase is 100 microsecond resolution
-constant WIP_TB_ACC_BITS : natural := 24;
-constant WIP_TIMER_WIDTH : natural := timer_width(WIP_SE_TIMEOUT);
-constant SECTOR_BITS : natural := 16; -- Determines # of bytes to erase
-
--- Internal signal declarations
-signal reg_cmd : unsigned(7 downto 0);
-signal reg_adr : unsigned(23 downto 0);
-signal flash_adr : unsigned(FLASH_ADR_BITS-1 downto 0);
-signal array_adr : unsigned(FLASH_ADR_BITS-1 downto 0);
-signal flash_we : std_logic;
-signal flash_dat : unsigned(7 downto 0);
-signal sr : unsigned(7 downto 0);
-signal sr_full : std_logic;
-signal reg_wel : std_logic; -- Write Enable Latch bit
-signal reg_wip : std_logic; -- Write In Progress bit
-signal clk_count : unsigned(2 downto 0);
-signal clk_count_r1 : unsigned(2 downto 0);
-signal clk_count_r2 : unsigned(2 downto 0);
-signal wip_timer : unsigned(WIP_TIMER_WIDTH-1 downto 0);
-signal wip_tb_pulse : std_logic;
-signal wip_tb_ftw : unsigned(WIP_TB_ACC_BITS-1 downto 0);
-signal wip_tb_hold : std_logic;
-signal sector_adr : unsigned(SECTOR_BITS-1 downto 0);
-signal sector_erase : std_logic;
-signal erase_adr : unsigned(23 downto 0);
-signal array_dat_wr : unsigned(7 downto 0);
-
- -- For the state machine
-type FSM_STATE_TYPE is (AWAIT_CMD, AWAIT_ADR_2, AWAIT_ADR_1, AWAIT_ADR_0,
- AWAIT_CS_HI, STORE_BYTE);
-signal fsm_state : FSM_STATE_TYPE;
-
-
------------------------------------------------------------------------------
-begin
-
- -- Create SPI signals
- spi_so_o <= sr(7);
-
- -- The shift register process
- -- Nothing is ever synchronously cleared, loaded or reset here.
- -- The shift register and counter simply "roll over" in a cyclical
- -- way, forever after the asynchronous reset.
- sr_proc: process(spi_sck_i, sys_rst_n)
- begin
- if (sys_rst_n='0') then
- sr <= (others=>'0');
- clk_count <= (others=>'0');
- elsif (spi_sck_i'event and spi_sck_i='1') then
- if (spi_cs_i='0') then
- sr <= sr(6 downto 0) & spi_si_i;
- clk_count <= clk_count+1;
- -- Here assign the shift register
- -- Action depends on command type
- case (to_integer(reg_cmd)) is
- when SPI_CMD_READ =>
- if (fsm_state=AWAIT_CS_HI and clk_count=0) then
- sr <= flash_dat;
- end if;
- when SPI_CMD_PP =>
- null;
- when SPI_CMD_SE =>
- null;
- when SPI_CMD_RDSR =>
- if (fsm_state=AWAIT_CS_HI and clk_count=0) then
- sr <= "0000000" & reg_wip;
- end if;
- when others =>
- null;
- end case;
- else
- clk_count <= (others=>'0');
- end if;
- end if; -- spi_sck_i
- end process;
-
- -- Create timebase for WIP timer
- wip_tb_ftw <= to_unsigned(integer(WIP_TB_FREQ*(2**real(WIP_TB_ACC_BITS))/SYS_CLK_RATE),wip_tb_ftw'length);
- wip_tb_hold <= '0' when reg_wip='1' else '1';
- timer_0 : dds_squarewave_phase_load
- generic map(
- ACC_BITS => WIP_TB_ACC_BITS
- )
- port map(
-
- sys_rst_n => sys_rst_n,
- sys_clk => sys_clk,
- sys_clk_en => sys_clk_en,
-
- -- Frequency setting
- freq_i => wip_tb_ftw,
-
- -- Synchronous load
- phase_i => to_unsigned(2**(WIP_TB_ACC_BITS-1),WIP_TB_ACC_BITS),
- phase_ld_i => wip_tb_hold,
-
- -- Output
- pulse_o => wip_tb_pulse,
- squarewave_o => open
- );
- reg_wip <= '1' when (wip_timer>0) else '0';
-
- -- Create signal which indicates when the shift register is done shifting a byte
- sr_full <= '1' when (clk_count_r1=0 and clk_count_r2=7) else '0';
- -- Since the simulated FLASH memory array may be much smaller than the address,
- -- select the salient part for use in addressing the array.
- flash_adr <= u_resize(reg_adr,flash_adr'length);
-
- -- The main process
- main_proc: process(sys_clk, sys_rst_n)
- begin
- if (sys_rst_n='0') then
- reg_cmd <= to_unsigned(SPI_CMD_NOP,reg_cmd'length);
- reg_adr <= (others=>'0');
- reg_wel <= '0';
- fsm_state <= AWAIT_CMD;
- wip_timer <= to_unsigned(0,wip_timer'length);
- clk_count_r1 <= (others=>'0');
- clk_count_r2 <= (others=>'0');
- sector_adr <= (others=>'0');
- sector_erase <= '0';
- elsif (sys_clk'event and sys_clk='1') then
- if (sys_clk_en='1') then
- -- default values
-
- -- Synchronize and capture the clk_count value, in order to
- -- detect changes to it.
- clk_count_r1 <= clk_count;
- clk_count_r2 <= clk_count_r1;
-
- -- Handle WIP timer count down
- if (wip_tb_pulse='1' and wip_timer>0) then
- wip_timer <= wip_timer-1;
- end if;
-
- -- Handle actual sector erase array storage operations
- if (sector_erase='1') then
- sector_adr <= sector_adr+1;
- if (sector_adr=(2**sector_adr'length)-1) then
- sector_erase <= '0';
- end if;
- end if;
-
- -- Handle state transitions
- case (fsm_state) is
-
- when AWAIT_CMD =>
- if (sr_full='1' and spi_cs_i='0') then
- if (reg_wip='0') then
- reg_cmd <= sr;
- if (sr=SPI_CMD_WREN) then
- reg_wel <= '1';
- fsm_state <= AWAIT_CS_HI;
- else
- fsm_state <= AWAIT_ADR_2;
- end if;
- else
- fsm_state <= AWAIT_CS_HI;
- -- Only RDSR is allowed when there is a write in progress (WIP)
- if (sr=SPI_CMD_RDSR) then
- reg_cmd <= sr;
- else
- reg_cmd <= to_unsigned(SPI_CMD_NOP,reg_cmd'length);
- end if;
- end if;
- end if;
-
- when AWAIT_ADR_2 =>
- if (sr_full='1') then
- reg_adr(23 downto 16) <= sr;
- fsm_state <= AWAIT_ADR_1;
- end if;
-
- when AWAIT_ADR_1 =>
- if (sr_full='1') then
- reg_adr(15 downto 8) <= sr;
- fsm_state <= AWAIT_ADR_0;
- end if;
-
- when AWAIT_ADR_0 =>
- if (sr_full='1') then
- reg_adr(7 downto 0) <= sr;
- fsm_state <= AWAIT_CS_HI;
- end if;
-
- when AWAIT_CS_HI =>
- if (sr_full='1') then
- -- Action depends on command type
- case (to_integer(reg_cmd)) is
- when SPI_CMD_READ =>
- reg_adr <= reg_adr+1;
- when SPI_CMD_PP =>
- if (reg_wel='1') then
- fsm_state <= STORE_BYTE;
- end if;
- when SPI_CMD_SE =>
- null;
- when SPI_CMD_RDSR =>
- null;
- when others =>
- null;
- end case;
- end if;
- if (spi_cs_i='1') then
- fsm_state <= AWAIT_CMD;
- if (reg_cmd/=SPI_CMD_WREN) then
- reg_wel <= '0';
- end if;
- if (reg_cmd=SPI_CMD_PP) then
- wip_timer <= to_unsigned(WIP_PP_TIMEOUT,wip_timer'length);
- end if;
- if (reg_cmd=SPI_CMD_SE) then
- wip_timer <= to_unsigned(WIP_SE_TIMEOUT,wip_timer'length);
- sector_erase <= '1';
- end if;
- end if;
-
- -- Being in this state asserts the flash_we signal
- when STORE_BYTE =>
- reg_adr <= reg_adr+1;
- fsm_state <= AWAIT_CS_HI;
-
- --when others =>
- -- fsm_state <= IDLE;
- end case;
-
- end if; -- sys_clk_en
- end if; -- sys_clk
- end process;
-
- -- This BRAM contains the simulated FLASH contents
- flash_ram : block_ram_dp_writethrough_hexfile_init
- generic map(
- init_file => FLASH_INIT,
- fil_width => 8,
- adr_width => FLASH_ADR_BITS,
- dat_width => 8
- )
- port map (
- clk_a => sys_clk,
- clk_b => sys_clk,
-
- adr_a_i => array_adr,
- adr_b_i => to_unsigned(0,FLASH_ADR_BITS),
-
- we_a_i => flash_we,
- en_a_i => '1',
- dat_a_i => array_dat_wr,
- dat_a_o => flash_dat,
-
- we_b_i => '0',
- en_b_i => '0',
- dat_b_i => to_unsigned(0,8),
- dat_b_o => open
- );
- flash_we <= '1' when (fsm_state=STORE_BYTE or sector_erase='1') else '0';
- array_adr <= flash_adr when sector_erase='0' else u_resize(erase_adr,array_adr'length);
- erase_adr <= reg_adr(reg_adr'length-1 downto SECTOR_BITS) & sector_adr;
- array_dat_wr <= sr when sector_erase='0' else str2u("FF",8);
-
-end beh;
-