library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.spi_pkg.all; entity spi_clkgen is generic ( DIVISORS : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256); DIVISORS_LOG2 : natural := 3 ); port ( clk_i : in std_logic; rst_in : in std_logic; start_i : in std_logic; -- next_data_i : in std_logic; div_sel_i : in std_logic_vector(DIVISORS_LOG2 - 1 downto 0); clock_polarity_i : in std_logic; clock_phase_i : in std_logic; sck_o : out std_logic; sck_mask_i : in std_logic; counter_overflow_o : out std_logic; sample_data_o : out std_logic; change_data_o : out std_logic); end entity spi_clkgen; architecture a1 of spi_clkgen is constant MAX : natural := get_max_natural(DIVISORS); type state_t is (IDLE, CLK_GEN, SCK_GEN); signal running : std_logic; signal selected_divisor : natural range 0 to MAX := 1; signal changing : std_logic; signal curr_state : state_t; signal next_state : state_t; signal curr_counter : integer range 0 to MAX - 1; signal next_counter : integer range 0 to MAX - 1; signal curr_sck : std_logic; signal next_sck : std_logic; begin -- architecture a1 set_data: process (clk_i) is begin -- process set_data if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) curr_sck <= '0'; curr_counter <= 0; curr_state <= IDLE; else curr_sck <= next_sck; curr_counter <= next_counter; curr_state <= next_state; end if; end if; end process set_data; state: process (all) is begin -- process state next_state <= curr_state; running <= '0'; sample_data_o <= '0'; change_data_o <= '0'; case curr_state is when IDLE => if start_i = '1' then if sck_mask_i = '1' then next_state <= SCK_GEN; change_data_o <= not clock_phase_i; else next_state <= CLK_GEN; end if; end if; when CLK_GEN => running <= '1'; if start_i = '0' then next_state <= IDLE; elsif sck_mask_i = '1' then next_state <= SCK_GEN; end if; when SCK_GEN => running <= '1'; if changing = '1' then if curr_sck = clock_phase_i then sample_data_o <= '1'; else change_data_o <= '1'; end if; end if; if start_i = '0' and ((changing = '1' and curr_sck /= '0') or (curr_sck = '0')) then next_state <= IDLE; sample_data_o <= '0'; change_data_o <= '0'; elsif sck_mask_i = '0' and ((changing = '1' and curr_sck /= '0') or (curr_sck = '0')) then next_state <= CLK_GEN; sample_data_o <= '0'; change_data_o <= '0'; end if; when others => null; end case; end process state; selected_divisor <= DIVISORS(to_integer(unsigned(div_sel_i))); changing <= '1' when curr_counter = 0 and running = '1' and curr_state = SCK_GEN else '0'; next_counter <= selected_divisor - 2 when changing = '1' else 0 when curr_counter = 0 else curr_counter - 1 when running = '1' else selected_divisor - 1; -- sample_data_o <= '1' when curr_sck = clock_phase_i and changing = '1' else '0'; -- change_data_o <= '1' when curr_sck /= clock_phase_i and changing = '1' else -- '1' when clock_phase_i = '0' and start_i = '1' and running = '0' else -- -- '1' when next_data_i = '1' else -- '0'; next_sck <= '0' when curr_state /= SCK_GEN else not curr_sck when changing = '1' else curr_sck when running = '1' else '0'; sck_o <= clock_polarity_i when curr_state /= SCK_GEN else curr_sck when clock_polarity_i = '0' else not curr_sck; counter_overflow_o <= '1' when running = '1' and curr_counter = 0 else '0'; end architecture a1;