library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library utils; entity startstop_condition_generator is generic ( DELAY : integer range 0 to 31); port ( clk_i : in std_logic; rst_in : in std_logic; sda_i : in std_logic; scl_rising_i : in std_logic; scl_falling_i : in std_logic; scl_falling_delayed_i : in std_logic; sda_enable_o : out std_logic; start_condition_i : in std_logic; stop_condition_i : in std_logic; gen_start_i : in std_logic; gen_stop_i : in std_logic; req_scl_fall_o : out std_logic; req_scl_rise_o : out std_logic; early_condition_o : out std_logic; done_o : out std_logic); end entity startstop_condition_generator; architecture a1 of startstop_condition_generator is -- 1. prepare sda to NOT condition level, -- 2. request to rise the scl line, -- 3. generate the condition - set sda to condition level, -- 4. request to fall the scl line (this is to allow for disengaging sda_enable -- and take it from another entity instead, without communicating the current -- level.), -- 5. done! type state_t is (IDLE, PREREQ_SCL_FALL, PREPARE_SDA, REQ_SCL_RISE, GEN_COND, REQ_SCL_FALL, EARLY_COND, DONE); signal curr_state : state_t := IDLE; signal next_state : state_t; signal curr_count : integer range 0 to DELAY; signal next_count : integer range 0 to DELAY; signal curr_scl : std_logic; signal next_scl : std_logic; signal curr_count_en : std_logic; signal next_count_en : std_logic; signal request_sda : std_logic; signal any_request : std_logic; begin -- architecture a1 any_request <= gen_start_i or gen_stop_i; request_sda <= '0' when gen_start_i = '1' else '1' when gen_stop_i = '1' else 'X'; done_o <= '1' when curr_state = DONE else '0'; early_condition_o <= '1' when curr_state = EARLY_COND else '0'; req_scl_rise_o <= '1' when curr_state = REQ_SCL_RISE else '0'; req_scl_fall_o <= '1' when curr_state = REQ_SCL_FALL or curr_state = PREREQ_SCL_FALL else '0'; sda_enable_o <= request_sda when curr_state = PREPARE_SDA or curr_state = REQ_SCL_RISE else not request_sda when curr_state = GEN_COND or curr_state = REQ_SCL_FALL else '0'; next_scl <= '1' when scl_rising_i = '1' else '0' when scl_falling_delayed_i = '1' else curr_scl; next_count <= 0 when curr_state /= next_state else curr_count + 1 when curr_count < DELAY and curr_count_en = '1' else curr_count; set_next_state: process (all) is begin -- process set_next_state next_state <= curr_state; next_count_en <= curr_count_en; if curr_state = IDLE then next_count_en <= '0'; if any_request = '1' then if curr_scl = '1' and sda_i /= not request_sda then next_state <= PREREQ_SCL_FALL; elsif curr_scl = '1' then next_state <= GEN_COND; elsif sda_i = not request_sda then next_state <= REQ_SCL_RISE; else next_state <= PREPARE_SDA; end if; end if; elsif curr_state = PREREQ_SCL_FALL then if scl_falling_i = '1' then next_count_en <= '1'; elsif curr_count = DELAY then next_state <= PREPARE_SDA; next_count_en <= '0'; elsif curr_scl = '1' then next_count_en <= '0'; end if; elsif curr_state = PREPARE_SDA then next_count_en <= '1'; if curr_scl = '1' then -- cannot do anything :( elsif curr_count = DELAY then next_state <= REQ_SCL_RISE; next_count_en <= '0'; elsif curr_scl = '1' then next_state <= GEN_COND; next_count_en <= '0'; end if; elsif curr_state = REQ_SCL_RISE then if scl_rising_i = '1' then next_count_en <= '1'; elsif curr_count = DELAY then next_state <= GEN_COND; next_count_en <= '0'; elsif curr_scl = '1' then next_count_en <= '1'; end if; elsif curr_state = GEN_COND then -- assume correct condition here. If it's the wrong one, -- state entity should take care of that. (abort) if start_condition_i = '1' or stop_condition_i = '1' then next_count_en <= '1'; elsif curr_count = DELAY then if gen_start_i = '1' then next_state <= REQ_SCL_FALL; else next_state <= DONE; end if; next_count_en <= '0'; end if; elsif curr_state = REQ_SCL_FALL then if scl_falling_i = '1' then next_count_en <= '1'; elsif curr_count = DELAY then next_state <= DONE; next_count_en <= '0'; elsif curr_scl = '0' then next_count_en <= '1'; end if; elsif curr_state = DONE then next_count_en <= '0'; if any_request = '0' then next_state <= IDLE; end if; elsif curr_state = EARLY_COND then next_count_en <= '0'; if any_request = '0' then next_state <= IDLE; end if; end if; if start_condition_i = '1' or stop_condition_i = '1' then if curr_state = PREREQ_SCL_FALL or curr_state = PREPARE_SDA or curr_state = REQ_SCL_RISE then next_state <= EARLY_COND; end if; end if; end process set_next_state; set_regs: process (clk_i) is begin -- process set_regs if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) curr_state <= IDLE; curr_count <= 0; curr_count_en <= '0'; curr_scl <= '1'; else curr_scl <= next_scl; curr_state <= next_state; curr_count <= next_count; curr_count_en <= next_count_en; end if; end if; end process set_regs; end architecture a1;