library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.spi_pkg.all;
entity spi_master is
generic (
SIZES : natural_vector := (8, 16);
SIZES_2LOG : natural := 1;
DIVISORS : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256);
DIVISORS_LOG2 : natural := 3;
CSN_PULSE_CYCLES : natural := 1
);
port (
-- IOs
sck_o : out std_logic;
miso_i : in std_logic;
mosi_o : out std_logic;
csn_o : out std_logic;
-- Control
clk_i : in std_logic;
rst_in : in std_logic;
en_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;
-- 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 : out 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 : out 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_master;
architecture a1 of spi_master is
constant MAX_SIZE : natural := get_max_natural(SIZES);
signal rst_n : std_logic;
signal ctrl_rst : std_logic;
signal latch_sample_data : std_logic;
signal counter_overflow : std_logic;
signal latch_change_data_out : std_logic;
signal latch_new_tx_data : std_logic;
signal tx_serial_data : std_logic;
signal sck : std_logic;
signal csn : std_logic;
signal mosi : std_logic_vector(0 downto 0);
signal start_clock : std_logic;
signal sck_mask : std_logic;
signal sck_en : std_logic;
signal csn_en : std_logic;
signal mosi_en : std_logic;
signal miso_en : std_logic;
signal selected_size : natural;
begin -- architecture a1
rst_n <= rst_in and ctrl_rst;
selected_size <= SIZES(to_integer(unsigned(size_sel_i)));
ctrl : entity work.spi_master_ctrl
generic map (
SIZES => SIZES,
SIZES_2LOG => SIZES_2LOG,
DIVISORS => DIVISORS,
DIVISORS_LOG2 => DIVISORS_LOG2,
CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
port map (
clk_i => clk_i,
rst_in => rst_in,
en_i => en_i,
size_sel_i => size_sel_i,
div_sel_i => div_sel_i,
clock_phase_i => clock_phase_i,
pulse_csn_i => pulse_csn_i,
counter_overflow_i => counter_overflow,
rx_block_on_full_i => rx_block_on_full_i,
rx_en_i => rx_en_i,
rx_ready_i => rx_ready_i,
rx_valid_o => rx_valid_o,
tx_en_i => tx_en_i,
tx_valid_i => tx_valid_i,
tx_ready_o => tx_ready_o,
busy_o => busy_o,
err_lost_rx_data_o => err_lost_rx_data_o,
clear_lost_rx_data_i => clear_lost_rx_data_i,
rst_on => ctrl_rst,
csn_o => csn,
csn_en_o => csn_en,
mosi_en_o => mosi_en,
miso_en_o => miso_en,
sck_mask_o => sck_mask,
sck_en_o => sck_en,
gen_clk_en_o => start_clock,
latch_tx_data_o => 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 => rst_n,
start_i => start_clock,
div_sel_i => div_sel_i,
clock_polarity_i => clock_polarity_i,
clock_phase_i => clock_phase_i,
sck_o => sck,
sck_mask_i => sck_mask,
counter_overflow_o => counter_overflow,
sample_data_o => latch_sample_data,
change_data_o => latch_change_data_out);
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 => '0',
-- Parallel
data_i => tx_data_i,
data_o => rx_data_o,
-- Serial
sd_i => miso_i,
sd_o => open);
tx_serial_data <= rx_data_o(selected_size - 1);
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_serial_data),
q_o => mosi,
latch_i => latch_change_data_out);
sck_o <= sck when sck_en = '1' else 'Z';
mosi_o <= mosi(0) when mosi_en = '1' else 'Z';
csn_o <= csn when csn_en = '1' else 'Z';
end architecture a1;