library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.spi_pkg.all;
entity spi_masterslave is
generic (
SIZES : natural_vector := (8, 16);
SIZES_2LOG : natural := 1;
DIVISORS : natural_vector := (2, 4, 8, 16, 32, 64, 128, 256);
DIVISORS_LOG2 : natural := 3;
CSN_PULSE_CYCLES : natural := 1
);
port (
-- IOs
sck_i : in std_logic;
miso_i : in std_logic;
mosi_i : in std_logic;
csn_i : in std_logic;
sck_o : out std_logic;
miso_o : out std_logic;
mosi_o : out std_logic;
csn_o : out std_logic;
sck_t : out std_logic;
miso_t : out std_logic;
mosi_t : out std_logic;
csn_t : out std_logic;
-- Control
clk_i : in std_logic;
rst_in : in std_logic;
en_i : in std_logic;
master_i : in std_logic;
clock_polarity_i : in std_logic;
clock_phase_i : in std_logic;
size_sel_i : in std_logic_vector(SIZES_2LOG - 1 downto 0);
div_sel_i : in std_logic_vector(DIVISORS_LOG2 - 1 downto 0);
pulse_csn_i : in std_logic;
rx_block_on_full_i : in std_logic;
lsbfirst_i : in std_logic;
-- Data
-- Rx
rx_en_i : in std_logic;
rx_data_o : out std_logic_vector(get_max_natural(SIZES) - 1 downto 0);
rx_valid_o : out std_logic;
rx_ready_i : in std_logic;
-- Tx
tx_en_i : in std_logic;
tx_data_i : in std_logic_vector(get_max_natural(SIZES) - 1 downto 0);
tx_valid_i : in std_logic;
tx_ready_o : out std_logic;
-- State
busy_o : out std_logic;
err_lost_rx_data_o : out std_logic;
clear_lost_rx_data_i : in std_logic);
end entity spi_masterslave;
architecture a1 of spi_masterslave is
constant MAX_SIZE : natural := get_max_natural(SIZES);
signal rst_n : std_logic;
signal ctrl_rst_n : std_logic;
signal master_ctrl_rst_n : std_logic;
signal slave_ctrl_rst_n : std_logic;
signal latch_sample_data : std_logic;
signal latch_change_data_out : std_logic;
signal latch_new_tx_data : std_logic;
signal tx_input_data : std_logic;
signal tx_input_index : natural range 0 to MAX_SIZE - 1;
signal tx_serial_data : std_logic_vector(0 downto 0);
signal rx_serial_data : std_logic;
signal selected_size : natural;
signal master_en : std_logic;
signal slave_en : std_logic;
signal slave_clock_rising : std_logic;
signal slave_rx_valid : std_logic;
signal slave_tx_ready : std_logic;
signal slave_busy : std_logic;
signal slave_err_lost_rx_data : std_logic;
signal slave_ctrl_rst : std_logic;
signal slave_csn_en : std_logic;
signal slave_mosi_en : std_logic;
signal slave_miso_en : std_logic;
signal slave_sck_mask : std_logic;
signal slave_sck_en : std_logic;
signal slave_start_clock : std_logic;
signal slave_latch_new_tx_data : std_logic;
signal slave_latch_sample_data : std_logic;
signal slave_latch_change_data : std_logic;
signal master_sck : std_logic;
signal master_counter_overflow : std_logic;
signal master_rx_valid : std_logic;
signal master_tx_ready : std_logic;
signal master_busy : std_logic;
signal master_err_lost_rx_data : std_logic;
signal master_csn : std_logic;
signal master_csn_en : std_logic;
signal master_mosi_en : std_logic;
signal master_miso_en : std_logic;
signal master_sck_mask : std_logic;
signal master_sck_en : std_logic;
signal master_start_clock : std_logic;
signal master_latch_new_tx_data : std_logic;
signal master_latch_sample_data : std_logic;
signal master_latch_change_data : std_logic;
signal csn, sck, mosi, miso : std_logic;
signal csn_en, sck_en, mosi_en, miso_en : std_logic;
begin -- architecture a1
master_en <= en_i and master_i;
slave_en <= en_i and not master_i;
rst_n <= rst_in and ctrl_rst_n;
selected_size <= SIZES(to_integer(unsigned(size_sel_i)));
master_ctrl : entity work.spi_master_ctrl
generic map (
DIVISORS => DIVISORS,
DIVISORS_LOG2 => DIVISORS_LOG2,
SIZES => SIZES,
SIZES_2LOG => SIZES_2LOG,
CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
port map (
clk_i => clk_i,
rst_in => rst_in,
en_i => master_en,
size_sel_i => size_sel_i,
div_sel_i => div_sel_i,
pulse_csn_i => pulse_csn_i,
clock_phase_i => clock_phase_i,
rx_block_on_full_i => rx_block_on_full_i,
rx_en_i => rx_en_i,
rx_ready_i => rx_ready_i,
tx_en_i => tx_en_i,
tx_valid_i => tx_valid_i,
clear_lost_rx_data_i => clear_lost_rx_data_i,
counter_overflow_i => master_counter_overflow,
rx_valid_o => master_rx_valid,
tx_ready_o => master_tx_ready,
busy_o => master_busy,
err_lost_rx_data_o => master_err_lost_rx_data,
rst_on => master_ctrl_rst_n,
csn_o => master_csn,
csn_en_o => master_csn_en,
mosi_en_o => master_mosi_en,
miso_en_o => master_miso_en,
sck_mask_o => master_sck_mask,
sck_en_o => master_sck_en,
gen_clk_en_o => master_start_clock,
latch_tx_data_o => master_latch_new_tx_data);
slave_ctrl : entity work.spi_slave_ctrl
generic map (
SIZES => SIZES,
SIZES_2LOG => SIZES_2LOG,
CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
port map (
clk_i => clk_i,
rst_in => rst_in,
en_i => master_en,
size_sel_i => size_sel_i,
pulse_csn_i => pulse_csn_i,
rx_block_on_full_i => rx_block_on_full_i,
rx_en_i => rx_en_i,
rx_ready_i => rx_ready_i,
tx_en_i => tx_en_i,
tx_valid_i => tx_valid_i,
clear_lost_rx_data_i => clear_lost_rx_data_i,
clock_rising_i => slave_clock_rising,
rx_valid_o => slave_rx_valid,
tx_ready_o => slave_tx_ready,
busy_o => slave_busy,
err_lost_rx_data_o => slave_err_lost_rx_data,
rst_on => slave_ctrl_rst,
csn_en_o => slave_csn_en,
mosi_en_o => slave_mosi_en,
miso_en_o => slave_miso_en,
sck_mask_o => slave_sck_mask,
sck_en_o => slave_sck_en,
gen_clk_en_o => slave_start_clock,
latch_tx_data_o => slave_latch_new_tx_data);
clkgen : entity work.spi_clkgen
generic map (
DIVISORS => DIVISORS,
DIVISORS_LOG2 => DIVISORS_LOG2)
port map (
clk_i => clk_i,
rst_in => master_ctrl_rst_n,
start_i => master_start_clock,
div_sel_i => div_sel_i,
clock_polarity_i => clock_polarity_i,
clock_phase_i => clock_phase_i,
sck_o => master_sck,
sck_mask_i => master_sck_mask,
counter_overflow_o => master_counter_overflow,
sample_data_o => master_latch_sample_data,
change_data_o => master_latch_change_data);
clkmon : entity work.spi_clkmon
port map (
clk_i => clk_i,
rst_in => slave_ctrl_rst_n,
clock_polarity_i => clock_polarity_i,
clock_phase_i => clock_phase_i,
sck_i => sck_i,
csn_i => csn_i,
clock_rising_o => slave_clock_rising,
sample_data_o => slave_latch_sample_data,
change_data_o => slave_latch_change_data);
shift_register : entity work.shift_register
generic map (
SIZE => MAX_SIZE)
port map (
clk_i => clk_i,
rst_in => rst_n,
-- Control
shift_i => latch_sample_data, -- sampling
latch_i => latch_new_tx_data, -- latching tx data
lsbfirst_i => lsbfirst_i,
-- Parallel
data_i => tx_data_i,
data_o => rx_data_o,
-- Serial
sd_i => rx_serial_data,
sd_o => open);
tx_input_index <= 0 when selected_size = 0 else
selected_size - 1 when lsbfirst_i = '0' else 0;
tx_input_data <= tx_data_i(tx_input_index) when latch_new_tx_data = '1' and latch_change_data_out = '1' else
rx_data_o(tx_input_index);
mosi_reg : entity work.reg
generic map (
SIZE => 1)
port map (
-- outputting different bit on mosi
clk_i => clk_i,
rst_in => rst_n,
d_i => (0 => tx_input_data),
q_o => tx_serial_data,
latch_i => latch_change_data_out);
mosi_t <= not slave_mosi_en when slave_en = '1' else
not master_mosi_en when master_en = '1' else
'0';
miso_t <= not slave_miso_en when slave_en = '1' else
not master_miso_en when master_en = '1' else
'0';
sck_t <= not slave_sck_en when slave_en = '1' else
not master_sck_en when master_en = '1' else
'0';
csn_t <= not slave_csn_en when slave_en = '1' else
not master_csn_en when master_en = '1' else
'0';
mosi_o <= tx_serial_data(0) when master_en = '1' else
'0' when slave_en = '1' else
'0';
miso_o <= '0' when master_en = '1' else
tx_serial_data(0) when slave_en = '1' else '0';
sck_o <= master_sck when master_en = '1' else
'0';
csn_o <= master_csn when master_en = '1' else '0';
rx_valid_o <= master_rx_valid when master_en = '1' else
slave_rx_valid when slave_en = '1' else
'0';
tx_ready_o <= master_tx_ready when master_en = '1' else
slave_tx_ready when slave_en = '1' else
'0';
busy_o <= master_busy when master_en = '1' else
slave_busy when slave_en = '1' else
'0';
err_lost_rx_data_o <= master_err_lost_rx_data when master_en = '1' else
slave_err_lost_rx_data when slave_en = '1' else
'0';
ctrl_rst_n <= master_ctrl_rst_n when master_en = '1' else
slave_ctrl_rst_n when slave_en = '1' else
'0';
latch_new_tx_data <= master_latch_new_tx_data when master_en = '1' else
slave_latch_new_tx_data when slave_en = '1' else
'0';
rx_serial_data <= miso_i when master_en = '1' else
mosi_i when slave_en = '1' else
'0';
latch_sample_data <= master_latch_sample_data when master_en = '1' else
slave_latch_sample_data when slave_en = '1' else
'0';
latch_change_data_out <= master_latch_change_data when master_en = '1' else
slave_latch_change_data when slave_en = '1' else
'0';
end architecture a1;