Line 1... |
Line 1... |
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
-- Author: Jonny Doin, jdoin@opencores.org
|
-- Author: Jonny Doin, jdoin@opencores.org, jonnydoin@gmail.com
|
--
|
--
|
-- Create Date: 12:18:12 04/25/2011
|
-- Create Date: 12:18:12 04/25/2011
|
-- Module Name: SPI_MASTER - RTL
|
-- Module Name: SPI_MASTER - RTL
|
-- Project Name: SPI MASTER / SLAVE INTERFACE
|
-- Project Name: SPI MASTER / SLAVE INTERFACE
|
-- Target Devices: Spartan-6
|
-- Target Devices: Spartan-6
|
Line 122... |
Line 122... |
-- 2011/06/05 v0.96.0053 [JD] changed async clear to sync resets.
|
-- 2011/06/05 v0.96.0053 [JD] changed async clear to sync resets.
|
-- 2011/06/07 v0.97.0065 [JD] added cross-clock buffers, fixed fsm async glitches.
|
-- 2011/06/07 v0.97.0065 [JD] added cross-clock buffers, fixed fsm async glitches.
|
-- 2011/06/09 v0.97.0068 [JD] reduced control sets (resets, CE, presets) to the absolute minimum to operate, to reduce
|
-- 2011/06/09 v0.97.0068 [JD] reduced control sets (resets, CE, presets) to the absolute minimum to operate, to reduce
|
-- synthesis LUT overhead in Spartan-6 architecture.
|
-- synthesis LUT overhead in Spartan-6 architecture.
|
-- 2011/06/11 v0.97.0075 [JD] redesigned all parallel data interfacing ports, and implemented cross-clock strobe logic.
|
-- 2011/06/11 v0.97.0075 [JD] redesigned all parallel data interfacing ports, and implemented cross-clock strobe logic.
|
-- 2011/06/12 v0.97.0079 [JD] streamlined wren_ack for all cases and eliminated unnecessary register resets.
|
-- 2011/06/12 v0.97.0079 [JD] streamlined wr_ack for all cases and eliminated unnecessary register resets.
|
-- 2011/06/14 v0.97.0083 [JD] (bug CPHA effect) : redesigned SCK output circuit.
|
-- 2011/06/14 v0.97.0083 [JD] (bug CPHA effect) : redesigned SCK output circuit.
|
-- (minor bug) : removed fsm registers from (not rst_i) chip enable.
|
-- (minor bug) : removed fsm registers from (not rst_i) chip enable.
|
-- 2011/06/15 v0.97.0086 [JD] removed master MISO input register, to relax MISO data setup time (to get higher speed).
|
-- 2011/06/15 v0.97.0086 [JD] removed master MISO input register, to relax MISO data setup time (to get higher speed).
|
-- 2011/07/09 v1.00.0095 [JD] changed all clocking scheme to use a single high-speed clock with clock enables to control lower
|
-- 2011/07/09 v1.00.0095 [JD] changed all clocking scheme to use a single high-speed clock with clock enables to control lower
|
-- frequency sequential circuits, to preserve clocking resources and avoid path delay glitches.
|
-- frequency sequential circuits, to preserve clocking resources and avoid path delay glitches.
|
Line 136... |
Line 136... |
-- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock.
|
-- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock.
|
-- 2011/07/17 v1.11.0080 [JD] BUG: CPOL='1', CPHA='1' @50MHz causes MOSI to be shifted one bit earlier.
|
-- 2011/07/17 v1.11.0080 [JD] BUG: CPOL='1', CPHA='1' @50MHz causes MOSI to be shifted one bit earlier.
|
-- BUG: CPOL='0', CPHA='1' causes SCK to have one extra pulse with one sclk_i width at the end.
|
-- BUG: CPOL='0', CPHA='1' causes SCK to have one extra pulse with one sclk_i width at the end.
|
-- 2011/07/18 v1.12.0105 [JD] CHG: spi sck output register changed to remove glitch at last clock when CPHA='1'.
|
-- 2011/07/18 v1.12.0105 [JD] CHG: spi sck output register changed to remove glitch at last clock when CPHA='1'.
|
-- for CPHA='1', max spi clock is 25MHz. for CPHA= '0', max spi clock is >50MHz.
|
-- for CPHA='1', max spi clock is 25MHz. for CPHA= '0', max spi clock is >50MHz.
|
|
-- 2011/07/24 v1.13.0125 [JD] FIX: 'sck_ena_ce' is on half-cycle advanced to 'fsm_ce', elliminating CPHA='1' glitches.
|
|
-- Core verified for all CPOL, CPHA at up to 50MHz, simulates to over 100MHz.
|
|
-- 2011/07/29 v1.14.0130 [JD] Removed global signal setting at the FSM, implementing exhaustive explicit signal attributions
|
|
-- for each state, to avoid reported inference problems in some synthesis engines.
|
|
-- Streamlined port names and indentation blocks.
|
--
|
--
|
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
-- TODO
|
-- TODO
|
-- ====
|
-- ====
|
--
|
--
|
Line 177... |
Line 182... |
spi_miso_i : in std_logic := 'X'; -- spi bus spi_miso_i input
|
spi_miso_i : in std_logic := 'X'; -- spi bus spi_miso_i input
|
---- parallel interface ----
|
---- parallel interface ----
|
di_req_o : out std_logic; -- preload lookahead data request line
|
di_req_o : out std_logic; -- preload lookahead data request line
|
di_i : in std_logic_vector (N-1 downto 0) := (others => 'X'); -- parallel data in (clocked on rising spi_clk after last bit)
|
di_i : in std_logic_vector (N-1 downto 0) := (others => 'X'); -- parallel data in (clocked on rising spi_clk after last bit)
|
wren_i : in std_logic := 'X'; -- user data write enable, starts transmission when interface is idle
|
wren_i : in std_logic := 'X'; -- user data write enable, starts transmission when interface is idle
|
|
wr_ack_o : out std_logic; -- write acknowledge
|
do_valid_o : out std_logic; -- do_o data valid signal, valid during one spi_clk rising edge.
|
do_valid_o : out std_logic; -- do_o data valid signal, valid during one spi_clk rising edge.
|
do_o : out std_logic_vector (N-1 downto 0); -- parallel output (clocked on rising spi_clk after last bit)
|
do_o : out std_logic_vector (N-1 downto 0); -- parallel output (clocked on rising spi_clk after last bit)
|
--- debug ports: can be removed or left unconnected for the application circuit ---
|
--- debug ports: can be removed or left unconnected for the application circuit ---
|
|
sck_ena_o : out std_logic; -- debug: internal sck enable signal
|
|
sck_ena_ce_o : out std_logic; -- debug: internal sck clock enable signal
|
do_transfer_o : out std_logic; -- debug: internal transfer driver
|
do_transfer_o : out std_logic; -- debug: internal transfer driver
|
wren_o : out std_logic; -- debug: internal state of the wren_i pulse stretcher
|
wren_o : out std_logic; -- debug: internal state of the wren_i pulse stretcher
|
wren_ack_o : out std_logic; -- debug: wren ack from state machine
|
|
rx_bit_reg_o : out std_logic; -- debug: internal rx bit
|
rx_bit_reg_o : out std_logic; -- debug: internal rx bit
|
state_dbg_o : out std_logic_vector (5 downto 0); -- debug: internal state register
|
state_dbg_o : out std_logic_vector (5 downto 0); -- debug: internal state register
|
core_clk_o : out std_logic;
|
core_clk_o : out std_logic;
|
core_n_clk_o : out std_logic;
|
core_n_clk_o : out std_logic;
|
core_ce_o : out std_logic;
|
core_ce_o : out std_logic;
|
Line 206... |
Line 213... |
signal core_ce : std_logic := '0'; -- core clock enable, positive logic
|
signal core_ce : std_logic := '0'; -- core clock enable, positive logic
|
signal core_n_ce : std_logic := '1'; -- core clock enable, negative logic
|
signal core_n_ce : std_logic := '1'; -- core clock enable, negative logic
|
-- spi bus clock, generated from the CPOL selected core clock polarity
|
-- spi bus clock, generated from the CPOL selected core clock polarity
|
signal spi_2x_ce : std_logic := '1'; -- spi_2x clock enable
|
signal spi_2x_ce : std_logic := '1'; -- spi_2x clock enable
|
signal spi_clk : std_logic := '0'; -- spi bus output clock
|
signal spi_clk : std_logic := '0'; -- spi bus output clock
|
signal spi_clk_reg : std_logic := '0'; -- output pipeline delay for spi sck
|
signal spi_clk_reg : std_logic; -- output pipeline delay for spi sck (do NOT global initialize)
|
-- core fsm clock enables
|
-- core fsm clock enables
|
signal fsm_ce : std_logic := '1'; -- fsm clock enable
|
signal fsm_ce : std_logic := '1'; -- fsm clock enable
|
signal ena_sck_ce : std_logic := '1'; -- SCK clock enable
|
signal sck_ena_ce : std_logic := '1'; -- SCK clock enable
|
signal samp_ce : std_logic := '1'; -- data sampling clock enable
|
signal samp_ce : std_logic := '1'; -- data sampling clock enable
|
--
|
--
|
-- GLOBAL RESET:
|
-- GLOBAL RESET:
|
-- all signals are initialized to zero at GSR (global set/reset) by giving explicit
|
-- all signals are initialized to zero at GSR (global set/reset) by giving explicit
|
-- initialization values at declaration. This is needed for all Xilinx FPGAs, and
|
-- initialization values at declaration. This is needed for all Xilinx FPGAs, and
|
Line 233... |
Line 240... |
signal rx_bit_reg : std_logic := '0';
|
signal rx_bit_reg : std_logic := '0';
|
-- buffered di_i data signals for register and combinatorial stages
|
-- buffered di_i data signals for register and combinatorial stages
|
signal di_reg : std_logic_vector (N-1 downto 0) := (others => '0');
|
signal di_reg : std_logic_vector (N-1 downto 0) := (others => '0');
|
-- internal wren_i stretcher for fsm combinatorial stage
|
-- internal wren_i stretcher for fsm combinatorial stage
|
signal wren : std_logic := '0';
|
signal wren : std_logic := '0';
|
signal wren_ack_next : std_logic := '0';
|
signal wr_ack_next : std_logic := '0';
|
signal wren_ack_reg : std_logic := '0';
|
signal wr_ack_reg : std_logic := '0';
|
-- internal SSEL enable control signals
|
-- internal SSEL enable control signals
|
signal ena_ssel_next : std_logic := '0';
|
signal ssel_ena_next : std_logic := '0';
|
signal ena_ssel_reg : std_logic := '0';
|
signal ssel_ena_reg : std_logic := '0';
|
-- internal SCK enable control signals
|
-- internal SCK enable control signals
|
signal ena_sck_next : std_logic := '0';
|
signal sck_ena_next : std_logic;
|
signal ena_sck_reg : std_logic := '0';
|
signal sck_ena_reg : std_logic;
|
-- buffered do_o data signals for register and combinatorial stages
|
-- buffered do_o data signals for register and combinatorial stages
|
signal do_buffer_next : std_logic_vector (N-1 downto 0) := (others => '0');
|
signal do_buffer_next : std_logic_vector (N-1 downto 0) := (others => '0');
|
signal do_buffer_reg : std_logic_vector (N-1 downto 0) := (others => '0');
|
signal do_buffer_reg : std_logic_vector (N-1 downto 0) := (others => '0');
|
-- internal signal to flag transfer to do_buffer_reg
|
-- internal signal to flag transfer to do_buffer_reg
|
signal do_transfer_next : std_logic := '0';
|
signal do_transfer_next : std_logic := '0';
|
Line 334... |
Line 341... |
core_ce <= '0';
|
core_ce <= '0';
|
core_n_ce <= '0';
|
core_n_ce <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process core_clock_gen_proc;
|
end process core_clock_gen_proc;
|
-----------------------------------------------------------------------------------------------
|
|
|
--=============================================================================================
|
|
-- GENERATE BLOCKS
|
|
--=============================================================================================
|
-- spi clk generator: generate spi_clk from core_clk depending on CPOL
|
-- spi clk generator: generate spi_clk from core_clk depending on CPOL
|
spi_sck_cpol_0_proc :
|
spi_sck_cpol_0_proc: if CPOL = '0' generate
|
if CPOL = '0' generate
|
|
begin
|
begin
|
spi_clk <= core_clk; -- for CPOL=0, spi clk has idle LOW
|
spi_clk <= core_clk; -- for CPOL=0, spi clk has idle LOW
|
end generate;
|
end generate;
|
spi_sck_cpol_1_proc :
|
|
if CPOL = '1' generate
|
spi_sck_cpol_1_proc: if CPOL = '1' generate
|
begin
|
begin
|
spi_clk <= core_n_clk; -- for CPOL=1, spi clk has idle HIGH
|
spi_clk <= core_n_clk; -- for CPOL=1, spi clk has idle HIGH
|
end generate;
|
end generate;
|
|
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- Sampling clock enable generation: generate 'samp_ce' from 'core_ce' or 'core_n_ce' depending on CPHA
|
-- Sampling clock enable generation: generate 'samp_ce' from 'core_ce' or 'core_n_ce' depending on CPHA
|
-- always sample data at the half-cycle of the fsm update cell
|
-- always sample data at the half-cycle of the fsm update cell
|
samp_ce_cpha_0_proc :
|
samp_ce_cpha_0_proc: if CPHA = '0' generate
|
if CPHA = '0' generate
|
|
begin
|
begin
|
samp_ce <= core_ce;
|
samp_ce <= core_ce;
|
end generate;
|
end generate;
|
samp_ce_cpha_1_proc :
|
|
if CPHA = '1' generate
|
samp_ce_cpha_1_proc: if CPHA = '1' generate
|
begin
|
begin
|
samp_ce <= core_n_ce;
|
samp_ce <= core_n_ce;
|
end generate;
|
end generate;
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- FSM clock enable generation: generate 'fsm_ce' from core_ce or core_n_ce depending on CPHA
|
-- FSM clock enable generation: generate 'fsm_ce' from core_ce or core_n_ce depending on CPHA
|
fsm_ce_cpha_0_proc :
|
fsm_ce_cpha_0_proc: if CPHA = '0' generate
|
if CPHA = '0' generate
|
|
begin
|
begin
|
fsm_ce <= core_n_ce; -- for CPHA=0, latch registers at rising edge of negative core clock enable
|
fsm_ce <= core_n_ce; -- for CPHA=0, latch registers at rising edge of negative core clock enable
|
end generate;
|
end generate;
|
fsm_ce_cpha_1_proc :
|
|
if CPHA = '1' generate
|
fsm_ce_cpha_1_proc: if CPHA = '1' generate
|
begin
|
begin
|
fsm_ce <= core_ce; -- for CPHA=1, latch registers at rising edge of positive core clock enable
|
fsm_ce <= core_ce; -- for CPHA=1, latch registers at rising edge of positive core clock enable
|
end generate;
|
end generate;
|
|
|
ena_sck_ce <= core_n_ce; -- for CPHA=1, SCK is advanced one-half cycle
|
sck_ena_ce <= core_n_ce; -- for CPHA=1, SCK is advanced one-half cycle
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- REGISTERED INPUTS
|
-- REGISTERED INPUTS
|
--=============================================================================================
|
--=============================================================================================
|
-- rx bit flop: capture rx bit after SAMPLE edge of sck
|
-- rx bit flop: capture rx bit after SAMPLE edge of sck
|
Line 421... |
Line 429... |
-- generate a 2-clocks pulse at the 3rd clock cycle
|
-- generate a 2-clocks pulse at the 3rd clock cycle
|
do_valid_next <= do_valid_A and do_valid_B and not do_valid_D;
|
do_valid_next <= do_valid_A and do_valid_B and not do_valid_D;
|
di_req_o_next <= di_req_o_A and di_req_o_B and not di_req_o_D;
|
di_req_o_next <= di_req_o_A and di_req_o_B and not di_req_o_D;
|
end process out_transfer_proc;
|
end process out_transfer_proc;
|
-- parallel load input registers: data register and write enable
|
-- parallel load input registers: data register and write enable
|
in_transfer_proc: process ( pclk_i, wren_i, wren_ack_reg ) is
|
in_transfer_proc: process ( pclk_i, wren_i, wr_ack_reg ) is
|
begin
|
begin
|
-- registered data input, input register with clock enable
|
-- registered data input, input register with clock enable
|
if pclk_i'event and pclk_i = '1' then
|
if pclk_i'event and pclk_i = '1' then
|
if wren_i = '1' then
|
if wren_i = '1' then
|
di_reg <= di_i; -- parallel data input buffer register
|
di_reg <= di_i; -- parallel data input buffer register
|
Line 433... |
Line 441... |
end if;
|
end if;
|
-- stretch wren pulse to be detected by spi fsm (ffd with sync preset and sync reset)
|
-- stretch wren pulse to be detected by spi fsm (ffd with sync preset and sync reset)
|
if pclk_i'event and pclk_i = '1' then
|
if pclk_i'event and pclk_i = '1' then
|
if wren_i = '1' then -- wren_i is the sync preset for wren
|
if wren_i = '1' then -- wren_i is the sync preset for wren
|
wren <= '1';
|
wren <= '1';
|
elsif wren_ack_reg = '1' then -- wren_ack is the sync reset for wren
|
elsif wr_ack_reg = '1' then -- wr_ack is the sync reset for wren
|
wren <= '0';
|
wren <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process in_transfer_proc;
|
end process in_transfer_proc;
|
|
|
Line 457... |
Line 465... |
end if;
|
end if;
|
-- FF registers clocked synchronous to the fsm state
|
-- FF registers clocked synchronous to the fsm state
|
if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
if fsm_ce = '1' then
|
if fsm_ce = '1' then
|
sh_reg <= sh_next; -- shift register
|
sh_reg <= sh_next; -- shift register
|
ena_ssel_reg <= ena_ssel_next; -- spi select enable
|
ssel_ena_reg <= ssel_ena_next; -- spi select enable
|
ena_sck_reg <= ena_sck_next; -- spi clock enable
|
|
do_buffer_reg <= do_buffer_next; -- registered output data buffer
|
do_buffer_reg <= do_buffer_next; -- registered output data buffer
|
do_transfer_reg <= do_transfer_next; -- output data transferred to buffer
|
do_transfer_reg <= do_transfer_next; -- output data transferred to buffer
|
di_req_reg <= di_req_next; -- input data request
|
di_req_reg <= di_req_next; -- input data request
|
wren_ack_reg <= wren_ack_next; -- wren ack for data load synchronization
|
wr_ack_reg <= wr_ack_next; -- write acknowledge for data load synchronization
|
end if;
|
end if;
|
end if;
|
end if;
|
-- FF registers clocked one-half cycle earlier than the fsm state
|
-- FF registers clocked one-half cycle earlier than the fsm state
|
-- if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
-- if ena_sck_ce = '1' then
|
if sck_ena_ce = '1' then
|
-- ena_sck_reg <= ena_sck_next; -- spi clock enable
|
sck_ena_reg <= sck_ena_next; -- spi clock enable: look ahead logic
|
-- end if;
|
end if;
|
-- end if;
|
end if;
|
end process core_reg_proc;
|
end process core_reg_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- RTL combinatorial LOGIC PROCESSES
|
-- RTL combinatorial LOGIC PROCESSES
|
--=============================================================================================
|
--=============================================================================================
|
-- state and datapath combinatorial logic
|
-- state and datapath combinatorial logic
|
core_combi_proc : process ( sh_reg, state_reg, rx_bit_reg, ena_ssel_reg, ena_sck_reg, do_buffer_reg,
|
core_combi_proc : process ( sh_reg, state_reg, rx_bit_reg, ssel_ena_reg, sck_ena_reg, do_buffer_reg,
|
do_transfer_reg, di_reg, wren ) is
|
do_transfer_reg, wr_ack_reg, di_req_reg, di_reg, wren ) is
|
begin
|
begin
|
sh_next <= sh_reg; -- all output signals are assigned to (avoid latches)
|
sh_next <= sh_reg; -- all output signals are assigned to (avoid latches)
|
ena_ssel_next <= ena_ssel_reg; -- controls the slave select line
|
ssel_ena_next <= ssel_ena_reg; -- controls the slave select line
|
ena_sck_next <= ena_sck_reg; -- controls the clock enable of spi sck line
|
sck_ena_next <= sck_ena_reg; -- controls the clock enable of spi sck line
|
do_buffer_next <= do_buffer_reg; -- output data buffer
|
do_buffer_next <= do_buffer_reg; -- output data buffer
|
do_transfer_next <= do_transfer_reg; -- output data flag
|
do_transfer_next <= do_transfer_reg; -- output data flag
|
wren_ack_next <= '0'; -- remove data load ack for all but the load stages
|
wr_ack_next <= wr_ack_reg; -- write acknowledge
|
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
|
di_req_next <= di_req_reg; -- prefetch data request
|
|
state_next <= state_reg; -- next state
|
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
|
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
|
case state_reg is
|
case state_reg is
|
when (N+1) => -- this state is to enable SSEL before SCK
|
when (N+1) => -- this state is to enable SSEL before SCK
|
ena_ssel_next <= '1'; -- tx in progress: will assert SSEL
|
ssel_ena_next <= '1'; -- tx in progress: will assert SSEL
|
ena_sck_next <= '1'; -- enable SCK on next cycle (stays off on first SSEL clock cycle)
|
sck_ena_next <= '1'; -- enable SCK on next cycle (stays off on first SSEL clock cycle)
|
|
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
when (N) => -- deassert 'di_rdy'
|
when (N) => -- deassert 'di_rdy'
|
|
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
when (N-1) downto (PREFETCH+3) => -- if rx data is valid, raise 'do_valid'. remove 'do_transfer'
|
when (N-1) downto (PREFETCH+3) => -- if rx data is valid, raise 'do_valid'. remove 'do_transfer'
|
|
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
|
do_transfer_next <= '0'; -- reset transfer signal
|
do_transfer_next <= '0'; -- reset transfer signal
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
when (PREFETCH+2) downto 2 => -- raise prefetch 'di_req_o_next' signal and remove 'do_valid'
|
when (PREFETCH+2) downto 2 => -- raise prefetch 'di_req_o_next' signal and remove 'do_valid'
|
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
|
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
when 1 => -- transfer rx data to do_buffer and restart if wren
|
when 1 => -- transfer rx data to do_buffer and restart if wren
|
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
|
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
|
do_buffer_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift rx data directly into rx buffer
|
do_buffer_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift rx data directly into rx buffer
|
do_buffer_next(0) <= rx_bit_reg; -- shift last rx bit into rx buffer
|
do_buffer_next(0) <= rx_bit_reg; -- shift last rx bit into rx buffer
|
do_transfer_next <= '1'; -- signal transfer to do_buffer
|
do_transfer_next <= '1'; -- signal transfer to do_buffer
|
if wren = '1' then -- load tx register if valid data present at di_i
|
if wren = '1' then -- load tx register if valid data present at di_i
|
state_next <= N; -- next state is top bit of new data
|
state_next <= N; -- next state is top bit of new data
|
sh_next <= di_reg; -- load parallel data from di_reg into shifter
|
sh_next <= di_reg; -- load parallel data from di_reg into shifter
|
ena_sck_next <= '1'; -- SCK enabled
|
sck_ena_next <= '1'; -- SCK enabled
|
wren_ack_next <= '1'; -- acknowledge data in transfer
|
wr_ack_next <= '1'; -- acknowledge data in transfer
|
else
|
else
|
ena_sck_next <= '0'; -- SCK disabled: tx empty, no data to send
|
sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
|
state_next <= state_reg - 1; -- update next state at each sck pulse
|
end if;
|
end if;
|
when 0 =>
|
when 0 =>
|
di_req_next <= '1'; -- will request data if shifter empty
|
di_req_next <= '1'; -- will request data if shifter empty
|
ena_sck_next <= '0'; -- SCK disabled: tx empty, no data to send
|
sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send
|
if wren = '1' then -- load tx register if valid data present at di_i
|
if wren = '1' then -- load tx register if valid data present at di_i
|
ena_ssel_next <= '1'; -- enable interface SSEL
|
ssel_ena_next <= '1'; -- enable interface SSEL
|
state_next <= N+1; -- start from idle: let one cycle for SSEL settling
|
state_next <= N+1; -- start from idle: let one cycle for SSEL settling
|
spi_mosi_o <= di_reg(N-1); -- special case: shift out first tx bit from the MSb (look ahead)
|
spi_mosi_o <= di_reg(N-1); -- special case: shift out first tx bit from the MSb (look ahead)
|
sh_next <= di_reg; -- load bits from di_reg into shifter
|
sh_next <= di_reg; -- load bits from di_reg into shifter
|
wren_ack_next <= '1'; -- acknowledge data in transfer
|
wr_ack_next <= '1'; -- acknowledge data in transfer
|
else
|
else
|
ena_ssel_next <= '0'; -- deassert SSEL: interface is idle
|
ssel_ena_next <= '0'; -- deassert SSEL: interface is idle
|
|
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
|
state_next <= 0; -- when idle, keep this state
|
state_next <= 0; -- when idle, keep this state
|
end if;
|
end if;
|
when others =>
|
when others =>
|
state_next <= 0; -- state 0 is safe state
|
state_next <= 0; -- state 0 is safe state
|
end case;
|
end case;
|
Line 539... |
Line 560... |
|
|
--=============================================================================================
|
--=============================================================================================
|
-- OUTPUT LOGIC PROCESSES
|
-- OUTPUT LOGIC PROCESSES
|
--=============================================================================================
|
--=============================================================================================
|
-- data output processes
|
-- data output processes
|
spi_ssel_o_proc: spi_ssel_o <= not ena_ssel_reg; -- drive active-low slave select line
|
spi_ssel_o_proc: spi_ssel_o <= not ssel_ena_reg; -- active-low slave select line
|
do_o_proc : do_o <= do_buffer_reg; -- do_o always available
|
do_o_proc: do_o <= do_buffer_reg; -- parallel data out
|
do_valid_o_proc: do_valid_o <= do_valid_o_reg; -- copy registered do_valid_o to output
|
do_valid_o_proc: do_valid_o <= do_valid_o_reg; -- data out valid
|
di_req_o_proc: di_req_o <= di_req_o_reg; -- copy registered di_req_o to output
|
di_req_o_proc: di_req_o <= di_req_o_reg; -- input data request for next cycle
|
|
wr_ack_o_proc: wr_ack_o <= wr_ack_reg; -- write acknowledge
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- SCK out logic: pipeline phase compensation for the SCK line
|
-- SCK out logic: pipeline phase compensation for the SCK line
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- This is a MUX with an output register. The register gives us a pipeline delay for the SCK line,
|
-- This is a MUX with an output register.
|
-- enabling higher SCK frequency. The MOSI and SCK phase are compensated by the pipeline delay.
|
-- The register gives us a pipeline delay for the SCK line, pairing with the state machine moore
|
spi_sck_o_gen_proc : process (sclk_i, ena_sck_reg, spi_clk, spi_clk_reg) is
|
-- output pipeline delay for the MOSI line, and thus enabling higher SCK frequency.
|
begin
|
spi_sck_o_gen_proc : process (sclk_i, sck_ena_reg, spi_clk, spi_clk_reg) is
|
-- if sclk_i'event and sclk_i = '1' then
|
begin
|
-- if ena_sck_reg = '1' then
|
|
-- spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
|
-- else
|
|
-- spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
|
-- end if;
|
|
-- end if;
|
|
if ena_sck_reg = '1' then
|
|
if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
|
if sck_ena_reg = '1' then
|
spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
end if;
|
|
else
|
else
|
spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
end if;
|
end if;
|
|
end if;
|
spi_sck_o <= spi_clk_reg; -- connect register to output
|
spi_sck_o <= spi_clk_reg; -- connect register to output
|
end process spi_sck_o_gen_proc;
|
end process spi_sck_o_gen_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- DEBUG LOGIC PROCESSES
|
-- DEBUG LOGIC PROCESSES
|
--=============================================================================================
|
--=============================================================================================
|
-- these signals are useful for verification, and can be deleted or commented-out after debug.
|
-- these signals are useful for verification, and can be deleted or commented-out after debug.
|
do_transfer_proc: do_transfer_o <= do_transfer_reg;
|
do_transfer_proc: do_transfer_o <= do_transfer_reg;
|
state_dbg_proc: state_dbg_o <= std_logic_vector(to_unsigned(state_reg, 6)); -- export internal state to debug
|
state_dbg_proc: state_dbg_o <= std_logic_vector(to_unsigned(state_reg, 6));
|
rx_bit_reg_proc: rx_bit_reg_o <= rx_bit_reg;
|
rx_bit_reg_proc: rx_bit_reg_o <= rx_bit_reg;
|
wren_o_proc: wren_o <= wren;
|
wren_o_proc: wren_o <= wren;
|
wren_ack_o_proc: wren_ack_o <= wren_ack_reg;
|
sh_reg_dbg_proc: sh_reg_dbg_o <= sh_reg;
|
sh_reg_dbg_proc: sh_reg_dbg_o <= sh_reg; -- export sh_reg to debug
|
|
core_clk_o_proc: core_clk_o <= core_clk;
|
core_clk_o_proc: core_clk_o <= core_clk;
|
core_n_clk_o_proc: core_n_clk_o <= core_n_clk;
|
core_n_clk_o_proc: core_n_clk_o <= core_n_clk;
|
core_ce_o_proc: core_ce_o <= core_ce;
|
core_ce_o_proc: core_ce_o <= core_ce;
|
core_n_ce_o_proc: core_n_ce_o <= core_n_ce;
|
core_n_ce_o_proc: core_n_ce_o <= core_n_ce;
|
|
sck_ena_o_proc: sck_ena_o <= sck_ena_reg;
|
|
sck_ena_ce_o_proc: sck_ena_ce_o <= sck_ena_ce;
|
|
|
end architecture RTL;
|
end architecture RTL;
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|