Line 125... |
Line 125... |
-- data. The fix consists in engaging continuous transfer regardless of the user strobing write enable, and
|
-- data. The fix consists in engaging continuous transfer regardless of the user strobing write enable, and
|
-- sequencing from state 1 to N as long as the master clock is present. If the user does not write new
|
-- sequencing from state 1 to N as long as the master clock is present. If the user does not write new
|
-- data, the last data word is repeated.
|
-- data, the last data word is repeated.
|
-- 2011/08/08 v2.02.0123 [JD] ISSUE: continuous transfer mode bug, for ignored 'di_req' cycles. Instead of repeating the last data word,
|
-- 2011/08/08 v2.02.0123 [JD] ISSUE: continuous transfer mode bug, for ignored 'di_req' cycles. Instead of repeating the last data word,
|
-- the slave will send (others => '0') instead.
|
-- the slave will send (others => '0') instead.
|
--
|
-- 2011/08/28 v2.02.0126 [JD] ISSUE: the miso_o MUX that preloads tx_bit when slave is desselected will glitch for CPHA='1'.
|
|
-- FIX: added a registered drive for the MUX select that will transfer the tx_reg only after the first tx_reg update.
|
--
|
--
|
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
-- TODO
|
-- TODO
|
-- ====
|
-- ====
|
--
|
--
|
Line 172... |
Line 173... |
-- There are several output ports that are used to simulate and verify the core operation.
|
-- There are several output ports that are used to simulate and verify the core operation.
|
-- Do not map any signals to the unused ports, and the synthesis tool will remove the related interfacing
|
-- Do not map any signals to the unused ports, and the synthesis tool will remove the related interfacing
|
-- circuitry.
|
-- circuitry.
|
-- The same is valid for the transmit and receive ports. If the receive ports are not mapped, the
|
-- The same is valid for the transmit and receive ports. If the receive ports are not mapped, the
|
-- synthesis tool will remove the receive logic from the generated circuitry.
|
-- synthesis tool will remove the receive logic from the generated circuitry.
|
|
-- Alternatively, you can remove these ports and related circuitry once the core is verified and
|
|
-- integrated to your circuit.
|
--================================================================================================================
|
--================================================================================================================
|
|
|
architecture rtl of spi_slave is
|
architecture rtl of spi_slave is
|
-- constants to control FlipFlop synthesis
|
-- constants to control FlipFlop synthesis
|
constant SHIFT_EDGE : std_logic := (CPOL xnor CPHA); -- MOSI data is captured and shifted at this SCK edge
|
constant SHIFT_EDGE : std_logic := (CPOL xnor CPHA); -- MOSI data is captured and shifted at this SCK edge
|
Line 186... |
Line 189... |
-- 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
|
-- especially for the Spartan-6 and newer CLB architectures, where a local reset can
|
-- especially for the Spartan-6 and newer CLB architectures, where a local reset can
|
-- reduce the usability of the slice registers, due to the need to share the control
|
-- reduce the usability of the slice registers, due to the need to share the control
|
-- set (RESET/PRESET, CLOCK ENABLE and CLOCK) by all 8 registers in a slice.
|
-- set (RESET/PRESET, CLOCK ENABLE and CLOCK) by all 8 registers in a slice.
|
-- By using GSR for the initialization, and reducing RESET local init to the bare
|
-- By using GSR for the initialization, and reducing RESET local init to the really
|
-- essential, the model achieves better LUT/FF packing and CLB usability.
|
-- essential, the model achieves better LUT/FF packing and CLB usability.
|
------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------
|
-- internal state signals for register and combinatorial stages
|
-- internal state signals for register and combinatorial stages
|
signal state_next : natural range N downto 0 := 0; -- state 0 is idle state
|
signal state_next : natural range N downto 0 := 0; -- state 0 is idle state
|
signal state_reg : natural range N downto 0 := 0; -- state 0 is idle state
|
signal state_reg : natural range N downto 0 := 0; -- state 0 is idle state
|
-- shifter signals for register and combinatorial stages
|
-- shifter signals for register and combinatorial stages
|
signal sh_next : std_logic_vector (N-1 downto 0);
|
signal sh_next : std_logic_vector (N-1 downto 0);
|
signal sh_reg : std_logic_vector (N-1 downto 0);
|
signal sh_reg : std_logic_vector (N-1 downto 0);
|
-- mosi and miso connections
|
-- mosi and miso connections
|
signal rx_bit_next : std_logic;
|
signal rx_bit_next : std_logic; -- sample of MOSI input
|
signal tx_bit_next : std_logic;
|
signal tx_bit_next : std_logic;
|
signal tx_bit_reg : std_logic;
|
signal tx_bit_reg : std_logic; -- drives MISO during sequential logic
|
|
signal preload_miso : std_logic; -- controls the MISO MUX
|
-- 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);
|
signal di_reg : std_logic_vector (N-1 downto 0);
|
-- internal wren_i stretcher for fsm combinatorial stage
|
-- internal wren_i stretcher for fsm combinatorial stage
|
signal wren : std_logic;
|
signal wren : std_logic;
|
signal wr_ack_next : std_logic := '0';
|
signal wr_ack_next : std_logic := '0';
|
Line 306... |
Line 310... |
--=============================================================================================
|
--=============================================================================================
|
-- fsm state and data registers change on spi SHIFT_EDGE
|
-- fsm state and data registers change on spi SHIFT_EDGE
|
core_reg_proc : process (spi_sck_i, spi_ssel_i) is
|
core_reg_proc : process (spi_sck_i, spi_ssel_i) is
|
begin
|
begin
|
-- FFD registers clocked on SHIFT edge and cleared on idle (spi_ssel_i = 1)
|
-- FFD registers clocked on SHIFT edge and cleared on idle (spi_ssel_i = 1)
|
|
-- state fsm register (fdr)
|
if spi_ssel_i = '1' then -- async clr
|
if spi_ssel_i = '1' then -- async clr
|
state_reg <= 0; -- state falls back to idle when slave not selected
|
state_reg <= 0; -- state falls back to idle when slave not selected
|
elsif spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on SHIFT edge, update all core registers
|
elsif spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on SHIFT edge, update state register
|
state_reg <= state_next; -- core fsm changes state with spi SHIFT clock
|
state_reg <= state_next; -- core fsm changes state with spi SHIFT clock
|
end if;
|
end if;
|
-- FFD registers clocked on SHIFT edge
|
-- FFD registers clocked on SHIFT edge
|
|
-- rtl core registers (fd)
|
if spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on fsm state change, update all core registers
|
if spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on fsm state change, update all core registers
|
sh_reg <= sh_next; -- core shift register
|
sh_reg <= sh_next; -- core shift register
|
do_buffer_reg <= do_buffer_next; -- registered data output
|
do_buffer_reg <= do_buffer_next; -- registered data output
|
do_transfer_reg <= do_transfer_next; -- cross-clock transfer flag
|
do_transfer_reg <= do_transfer_next; -- cross-clock transfer flag
|
di_req_reg <= di_req_next; -- input data request
|
di_req_reg <= di_req_next; -- input data request
|
wr_ack_reg <= wr_ack_next; -- wren ack for data load synchronization
|
wr_ack_reg <= wr_ack_next; -- wren ack for data load synchronization
|
end if;
|
end if;
|
|
-- FFD registers clocked on CHANGE edge and cleared on idle (spi_ssel_i = 1)
|
|
-- miso MUX preload control register (fdp)
|
|
if spi_ssel_i = '1' then -- async preset
|
|
preload_miso <= '1'; -- miso MUX sees top bit of parallel input when slave not selected
|
|
elsif spi_sck_i'event and spi_sck_i = CHANGE_EDGE then -- on CHANGE edge, change to tx_reg output
|
|
preload_miso <= spi_ssel_i; -- miso MUX sees tx_bit_reg when it is driven by SCK
|
|
end if;
|
-- FFD registers clocked on CHANGE edge
|
-- FFD registers clocked on CHANGE edge
|
|
-- tx_bit register (fd)
|
if spi_sck_i'event and spi_sck_i = CHANGE_EDGE then
|
if spi_sck_i'event and spi_sck_i = CHANGE_EDGE then
|
tx_bit_reg <= tx_bit_next; -- update MISO driver from the MSb
|
tx_bit_reg <= tx_bit_next; -- update MISO driver from the MSb
|
end if;
|
end if;
|
end process core_reg_proc;
|
end process core_reg_proc;
|
|
|
Line 416... |
Line 430... |
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; -- copy registered do_valid_o to output
|
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; -- copy registered di_req_o to output
|
wr_ack_o_proc: wr_ack_o <= wr_ack_reg; -- copy registered wr_ack_o to output
|
wr_ack_o_proc: wr_ack_o <= wr_ack_reg; -- copy registered wr_ack_o to output
|
|
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- MISO driver process: copy next tx bit at reset
|
-- MISO driver process: preload top bit of parallel data to MOSI at reset
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- this is a MUX that selects the combinatorial next tx bit at reset, and the registered tx bit
|
-- this is a MUX that selects the combinatorial next tx bit at reset, and the registered tx bit
|
-- at sequential operation. The mux gives us a preload of the first bit, simplifying the shifter logic.
|
-- at sequential operation. The mux gives us a preload of the first bit, simplifying the shifter logic.
|
spi_miso_o_proc: process (spi_ssel_i, tx_bit_reg, tx_bit_next) is
|
spi_miso_o_proc: process (preload_miso, tx_bit_reg, di_reg) is
|
begin
|
begin
|
if spi_ssel_i = '1' then
|
if preload_miso = '1' then
|
spi_miso_o <= tx_bit_next; -- copy next => reg at reset
|
spi_miso_o <= di_reg(N-1); -- copy top bit of parallel data at reset
|
else
|
else
|
spi_miso_o <= tx_bit_reg;
|
spi_miso_o <= tx_bit_reg; -- copy top bit of shifter at sequential operation
|
end if;
|
end if;
|
end process spi_miso_o_proc;
|
end process spi_miso_o_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- DEBUG LOGIC PROCESSES
|
-- DEBUG LOGIC PROCESSES
|