Line 58... |
Line 58... |
--
|
--
|
--
|
--
|
-- PARALLEL READ INTERFACE
|
-- PARALLEL READ INTERFACE
|
-- =======================
|
-- =======================
|
-- An internal buffer is used to copy the internal shift register data to drive the 'do_o' port. When a complete word is received,
|
-- An internal buffer is used to copy the internal shift register data to drive the 'do_o' port. When a complete word is received,
|
-- the core shift register is transferred to the buffer, at the rising edge of the spi clock, 'spi_2x_clk_i'.
|
-- the core shift register is transferred to the buffer, at the rising edge of the spi clock, 'spi_clk'.
|
-- The signal 'do_valid_o' is set one 'spi_2x_clk_i' clock after, to directly drive a synchronous memory or fifo write enable.
|
-- The signal 'do_valid_o' is set one 'spi_clk' clock after, to directly drive a synchronous memory or fifo write enable.
|
-- 'do_valid_o' is synchronous to the parallel interface clock, and changes only on rising edges of 'pclk_i'.
|
-- 'do_valid_o' is synchronous to the parallel interface clock, and changes only on rising edges of 'pclk_i'.
|
-- When the interface is idle, data at the 'do_o' port holds the last word received.
|
-- When the interface is idle, data at the 'do_o' port holds the last word received.
|
--
|
--
|
-- PARALLEL READ SEQUENCE
|
-- PARALLEL READ SEQUENCE
|
-- ======================
|
-- ======================
|
-- ______ ______ ______ ______
|
-- ______ ______ ______ ______
|
-- spi_2x_clk_i bit1 \______/ bitN \______/bitN-1\______/bitN-2\__... -- spi 2x base clock
|
-- spi_clk bit1 \______/ bitN \______/bitN-1\______/bitN-2\__... -- spi 2x base clock
|
-- _ __ __ __ __ __ __ __ __
|
-- _ __ __ __ __ __ __ __ __
|
-- pclk_i \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_... -- parallel interface clock (may be async to sclk_i)
|
-- pclk_i \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_... -- parallel interface clock (may be async to sclk_i)
|
-- _____________ _____________________________________... -- 1) rx data is transferred to 'do_buffer_reg'
|
-- _____________ _____________________________________... -- 1) rx data is transferred to 'do_buffer_reg'
|
-- do_o ___old_data__X__________new_data___________________... -- after last rx bit, at rising 'spi_2x_clk_i'.
|
-- do_o ___old_data__X__________new_data___________________... -- after last rx bit, at rising 'spi_clk'.
|
-- ____________
|
-- ____________
|
-- do_valid_o ____________________________/ \_________... -- 2) 'do_valid_o' strobed for 2 'pclk_i' cycles
|
-- do_valid_o ____________________________/ \_________... -- 2) 'do_valid_o' strobed for 2 'pclk_i' cycles
|
-- -- on the 3rd 'pclk_i' rising edge.
|
-- -- on the 3rd 'pclk_i' rising edge.
|
--
|
--
|
--
|
--
|
Line 167... |
Line 167... |
spi_ssel_o : out std_logic; -- spi bus slave select line
|
spi_ssel_o : out std_logic; -- spi bus slave select line
|
spi_sck_o : out std_logic; -- spi bus sck
|
spi_sck_o : out std_logic; -- spi bus sck
|
spi_mosi_o : out std_logic; -- spi bus mosi output
|
spi_mosi_o : out std_logic; -- spi bus mosi output
|
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
|
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_2x_clk_i 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
|
do_valid_o : out std_logic; -- do_o data valid signal, valid during one spi_2x_clk_i 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_2x_clk_i 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 for the application circuit ---
|
--- debug ports: can be removed for the application circuit ---
|
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
|
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
|
Line 187... |
Line 187... |
);
|
);
|
end spi_master;
|
end spi_master;
|
|
|
--================================================================================================================
|
--================================================================================================================
|
-- this architecture is a pipelined register-transfer description.
|
-- this architecture is a pipelined register-transfer description.
|
-- all signals are clocked at the rising edge of the system clock 'spi_2x_clk_i'.
|
-- all signals are clocked at the rising edge of the system clock 'sclk_i'.
|
--================================================================================================================
|
--================================================================================================================
|
architecture rtl of spi_master is
|
architecture rtl of spi_master is
|
-- core clocks, generated from 'spi_2x_clk_i': initialized to differential values
|
-- core clocks, generated from 'sclk_i': initialized to differential values
|
signal core_clk : std_logic := '0'; -- continuous core clock, positive logic
|
signal core_clk : std_logic := '0'; -- continuous core clock, positive logic
|
signal core_n_clk : std_logic := '1'; -- continuous core clock, negative logic
|
signal core_n_clk : std_logic := '1'; -- continuous core clock, negative logic
|
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
|
Line 293... |
Line 293... |
-- The clock enable phase is selected for serial input sampling, fsm clocking, and spi SCK output,
|
-- The clock enable phase is selected for serial input sampling, fsm clocking, and spi SCK output,
|
-- based on the configuration of CPOL and CPHA.
|
-- based on the configuration of CPOL and CPHA.
|
-- Each phase is selected so that all the registers can be clocked with a rising edge on all SPI
|
-- Each phase is selected so that all the registers can be clocked with a rising edge on all SPI
|
-- modes, by a single high-speed global clock, preserving clock resources.
|
-- modes, by a single high-speed global clock, preserving clock resources.
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- generate the core clock enables from the serial high-speed input clock
|
-- generate the 2x spi base clock enable from the serial high-speed input clock
|
spi_2x_ce_gen_proc: process (sclk_i) is
|
spi_2x_ce_gen_proc: process (sclk_i) is
|
variable clk_cnt : integer range SPI_2X_CLK_DIV-1 downto 0 := 0;
|
variable clk_cnt : integer range SPI_2X_CLK_DIV-1 downto 0 := 0;
|
begin
|
begin
|
if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
if clk_cnt = SPI_2X_CLK_DIV-1 then
|
if clk_cnt = SPI_2X_CLK_DIV-1 then
|
Line 308... |
Line 308... |
clk_cnt := clk_cnt + 1;
|
clk_cnt := clk_cnt + 1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process spi_2x_ce_gen_proc;
|
end process spi_2x_ce_gen_proc;
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- generate the core antiphase clocks and clock enables.
|
-- generate the core antiphase clocks and clock enables from the 2x base CE.
|
core_clock_gen_proc : process (sclk_i) is
|
core_clock_gen_proc : process (sclk_i) is
|
begin
|
begin
|
if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
if spi_2x_ce = '1' then
|
if spi_2x_ce = '1' then
|
-- generate the 2 antiphase core clocks
|
-- generate the 2 antiphase core clocks
|
Line 351... |
Line 351... |
if CPHA = '1' generate
|
if CPHA = '1' generate
|
begin
|
begin
|
samp_ce <= core_n_ce;
|
samp_ce <= core_n_ce;
|
end generate;
|
end generate;
|
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- FSM clock 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;
|