-------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 18:05:41 10/22/05 -- Design Name: -- Module Name: ps2_core - Behavioral -- Project Name: -- Target Device: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- -------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; ---- Uncomment the following library declaration if instantiating ---- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity ps2_core is Generic (f_sys_clk : real := 100.0); Port ( rst : in std_logic; clk : in std_logic; ce : in std_logic; d_in : in std_logic_vector(7 downto 0); d_out : out std_logic_vector(7 downto 0); input_rdy : out std_logic; output_rdy : out std_logic; write_en : in std_logic; read_en : in std_logic; ps2_clk_in : in std_logic; ps2_data_in : in std_logic; ps2_clk_out : out std_logic; ps2_data_out : out std_logic); end ps2_core; architecture Behavioral of ps2_core is COMPONENT prescaler GENERIC (divide : integer); PORT( rst : IN std_logic; clk : IN std_logic; ce : IN std_logic; rdy : OUT std_logic ); END COMPONENT; COMPONENT timeout_counter GENERIC (N : integer); PORT( rst : IN std_logic; clk : IN std_logic; ce : IN std_logic; load : IN integer range 0 to N-1; load_en : IN std_logic; rdy : OUT std_logic ); END COMPONENT; COMPONENT sipo GENERIC (N : integer); PORT( rst : IN std_logic; clk : IN std_logic; ce : IN std_logic; d_in : IN std_logic; d_out : OUT std_logic_vector(7 downto 0) ); END COMPONENT; COMPONENT piso GENERIC (N : integer); PORT( rst : IN std_logic; clk : IN std_logic; ce : IN std_logic; load_en : IN std_logic; d_in : IN std_logic_vector(7 downto 0); d_out : OUT std_logic ); END COMPONENT; COMPONENT parity_bitser PORT( rst : IN std_logic; clk : IN std_logic; srst : IN std_logic; ce : IN std_logic; d_in : IN std_logic; parity : OUT std_logic ); END COMPONENT; COMPONENT oneshot GENERIC (mode : integer); PORT( rst : IN std_logic; clk : IN std_logic; input : IN std_logic; output : OUT std_logic ); END COMPONENT; -- Types type line_state_rx_t is (start_wait_st, start_trans_st, start_sample_st, data_wait_st, data_trans_st, data_sample_st, parity_wait_st, parity_trans_st, parity_sample_st, stop_wait_st, stop_trans_st, stop_sample_st, valid_st); type line_state_tx_t is (tx_idle_st, tx_clock_assert_st, tx_start_latency_st, tx_start_assert_st, tx_clock_release_st, tx_dev_trans_st, tx_data_wait_st, tx_data_trans_st, tx_data_sample_st, tx_parity_update_st, tx_dev_wait_st, tx_parity_wait_st, tx_parity_trans_st, tx_parity_sample_st, tx_stop_wait_st, tx_stop_trans_st, tx_stop_sample_st, tx_ack_trans_st, tx_ack_sample_st, tx_valid_st); -- Constant constant prescaler_us : integer := f_sys_clk/1E6; constant timeout_us : integer := 15000; constant time_clock_assert : integer := 120; -- Signals signal en_us : std_logic; signal timeout_load_en : std_logic; signal timeout_en : std_logic; signal timeout_flag : std_logic; signal timeout_tx_load_en : std_logic; signal timeout_tx_en : std_logic; signal timeout_tx_flag : std_logic; signal timeval_tx : integer := time_clock_assert-1; signal read_cs : line_state_rx_t; signal read_ns : line_state_rx_t; signal write_cs : line_state_tx_t; signal write_ns : line_state_tx_t; signal data_cnt_en : std_logic; signal data_cnt_rst : std_logic; signal data_cnt : integer range 0 to 7; signal data_cnt_tx_en : std_logic; signal data_cnt_tx_rst : std_logic; signal data_cnt_tx : integer range 0 to 7; signal sipo_en : std_logic; signal piso_en : std_logic; signal piso_out : std_logic; signal piso_load_en : std_logic; signal rx_en : std_logic; signal tx_en : std_logic; signal rx_busy : std_logic; signal tx_busy : std_logic; signal rx_rdy : std_logic; signal tx_rdy : std_logic; signal tx_req : std_logic; signal rx_reg : std_logic_vector(7 downto 0); signal tx_reg : std_logic_vector(7 downto 0); signal parity_rst : std_logic; signal parity_en : std_logic; signal parity : std_logic; signal parity_tx_rst : std_logic; signal parity_tx_en : std_logic; signal parity_tx : std_logic; begin Inst_prescaler: prescaler GENERIC MAP ( divide => prescaler_us) PORT MAP( rst => rst, clk => clk, ce => ce, rdy => en_us ); Inst_timeout_counter_rx: timeout_counter GENERIC MAP ( N => timeout_us) PORT MAP( rst => rst, clk => clk, ce => timeout_en, load => timeout_us - 1, load_en => timeout_load_en, rdy => timeout_flag ); Inst_timeout_counter_tx: timeout_counter GENERIC MAP ( N => timeout_us) PORT MAP( rst => rst, clk => clk, ce => timeout_tx_en, load => timeval_tx, load_en => timeout_tx_load_en, rdy => timeout_tx_flag ); Inst_sipo: sipo GENERIC MAP ( N => 8) PORT MAP( rst => rst, clk => clk, ce => sipo_en, d_in => ps2_data_in, d_out => rx_reg ); Inst_piso: piso GENERIC MAP ( N => 8) PORT MAP( rst => rst, clk => clk, ce => piso_en, load_en => piso_load_en, d_in => tx_reg, d_out => piso_out ); Inst_parity_bitser_rx: parity_bitser PORT MAP( rst => rst, clk => clk, srst => parity_rst, ce => parity_en, d_in => ps2_data_in, parity => parity ); Inst_parity_bitser_tx: parity_bitser PORT MAP( rst => rst, clk => clk, srst => parity_tx_rst, ce => parity_tx_en, d_in => piso_out, parity => parity_tx ); ------------------------------------------- tx_en <= tx_req and (not rx_busy); rx_en <= not tx_busy; ------------------------------------------- out_reg: process(rst, clk, rx_rdy, read_en) begin if rst = '1' then d_out <= (others => '0'); output_rdy <= '0'; elsif rising_edge(clk) then if rx_rdy = '1' then d_out <= rx_reg; output_rdy <= '1'; elsif read_en = '1' then output_rdy <= '0'; end if; end if; end process; in_reg: process(rst, clk, piso_load_en, write_en) begin if rst = '1' then input_rdy <= '1'; tx_req <= '0'; elsif rising_edge(clk) then if piso_load_en = '1' then tx_reg <= d_in; input_rdy <= '1'; tx_req <= '0'; elsif write_en = '1' then input_rdy <= '0'; tx_req <= '1'; end if; end if; end process; ------------------------------------------- read_state_clk: process(rst, clk) begin if rst = '1' then read_cs <= start_wait_st; else if rising_edge(clk) then read_cs <= read_ns; if (data_cnt_rst = '1') then data_cnt <= 7; elsif (data_cnt_en = '1') then if (data_cnt /= 0) then data_cnt <= data_cnt - 1; end if; end if; end if; end if; end process; ------------------------------------------- write_state_clk: process(rst, clk) begin if rst = '1' then write_cs <= tx_idle_st; else if rising_edge(clk) then write_cs <= write_ns; if (data_cnt_tx_rst = '1') then data_cnt_tx <= 7; elsif (data_cnt_tx_en = '1') then if (data_cnt_tx /= 0) then data_cnt_tx <= data_cnt_tx - 1; end if; end if; end if; end if; end process; ------------------------------------------- read_state_output: process(read_cs, en_us) begin timeout_load_en <= '0'; timeout_en <= en_us; data_cnt_en <= '0'; data_cnt_rst <= '0'; sipo_en <= '0'; rx_rdy <= '0'; parity_en <= '0'; parity_rst <= '0'; rx_busy <= '1'; case (read_cs) is when start_wait_st => timeout_load_en <= '1'; timeout_en <= '0'; rx_busy <= '0'; when start_sample_st => data_cnt_rst <= '1'; parity_rst <= '1'; timeout_load_en <= '1'; when data_sample_st => data_cnt_en <= '1'; parity_en <= '1'; sipo_en <= '1'; timeout_load_en <= '1'; when parity_sample_st => timeout_load_en <= '1'; parity_en <= '1'; when valid_st => rx_busy <= '0'; rx_rdy <= '1'; when others => null; end case; end process; read_state_decode: process (read_cs, timeout_flag, rx_en, data_cnt, ps2_data_in, ps2_clk_in) begin --declare default state for next_state to avoid latches read_ns <= read_cs; --default is to stay in current state --insert statements to decode next_state --below is a simple example case (read_cs) is when start_wait_st => if ps2_data_in = '0' and ps2_clk_in = '1' and rx_en = '1' then read_ns <= start_trans_st; end if; when start_trans_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_data_in = '0' and ps2_clk_in = '0' then read_ns <= start_sample_st; end if; when start_sample_st => read_ns <= data_wait_st; -- Wait data change when data_wait_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '1' then read_ns <= data_trans_st; end if; -- Wait data trans when data_trans_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '0' then read_ns <= data_sample_st; end if; -- Data sample when data_sample_st => read_ns <= data_wait_st; if data_cnt = 0 then read_ns <= parity_wait_st; end if; when parity_wait_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '1' then read_ns <= parity_trans_st; end if; when parity_trans_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '0' then read_ns <= parity_sample_st; end if; when parity_sample_st => read_ns <= stop_wait_st; when stop_wait_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '1' then read_ns <= stop_trans_st; end if; when stop_trans_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '0' and ps2_data_in = '1' then read_ns <= stop_sample_st; end if; when stop_sample_st => if timeout_flag = '1' then read_ns <= start_wait_st; elsif ps2_clk_in = '1' then read_ns <= valid_st; end if; when valid_st => read_ns <= start_wait_st; when others => read_ns <= start_wait_st; end case; end process; ------------------------------------------- write_state_output: process(write_cs, en_us, piso_out, parity_tx) begin timeout_tx_load_en <= '0'; timeout_tx_en <= en_us; tx_rdy <= '0'; tx_busy <= '1'; piso_load_en <= '0'; ps2_clk_out <= '1'; ps2_data_out <= '1'; piso_en <= '0'; timeval_tx <= time_clock_assert - 1; data_cnt_tx_en <= '0'; data_cnt_tx_rst <= '0'; parity_tx_rst <= '0'; parity_tx_en <= '0'; case (write_cs) is when tx_idle_st => tx_busy <= '0'; timeout_tx_load_en <= '1'; timeout_tx_en <= '0'; when tx_clock_assert_st => parity_tx_rst <= '1'; piso_load_en <= '1'; data_cnt_tx_rst <= '1'; ps2_clk_out <= '0'; when tx_start_assert_st => ps2_clk_out <= '0'; ps2_data_out <= '0'; when tx_clock_release_st => ps2_data_out <= '0'; timeout_tx_load_en <= '1'; timeval_tx <= timeout_us - 1; when tx_dev_wait_st => ps2_data_out <= '0'; when tx_dev_trans_st => ps2_data_out <= '0'; timeout_tx_load_en <= '1'; timeval_tx <= timeout_us - 1; when tx_data_wait_st => ps2_data_out <= piso_out; when tx_data_trans_st => data_cnt_tx_en <= '1'; ps2_data_out <= piso_out; piso_en <= '1'; timeout_tx_load_en <= '1'; timeval_tx <= timeout_us - 1; parity_tx_en <= '1'; when tx_data_sample_st => ps2_data_out <= piso_out; when tx_parity_update_st => parity_tx_en <= '1'; ps2_data_out <= piso_out; when tx_parity_sample_st => ps2_data_out <= parity_tx; when tx_parity_wait_st => ps2_data_out <= parity_tx; when tx_parity_trans_st => ps2_data_out <= piso_out; timeout_tx_load_en <= '1'; timeval_tx <= timeout_us - 1; when tx_valid_st => tx_rdy <= '1'; when others => null; end case; end process; write_state_decode: process (write_cs, tx_en, data_cnt_tx, timeout_tx_flag, ps2_data_in, ps2_clk_in) begin --declare default state for next_state to avoid latches write_ns <= write_cs; --default is to stay in current state --insert statements to decode next_state --below is a simple example case (write_cs) is when tx_idle_st => if tx_en = '1' then write_ns <= tx_clock_assert_st; end if; when tx_clock_assert_st => if timeout_tx_flag = '1' then write_ns <= tx_start_assert_st; end if; when tx_start_assert_st => write_ns <= tx_clock_release_st; when tx_clock_release_st => write_ns <= tx_dev_wait_st; when tx_dev_wait_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '1' then write_ns <= tx_dev_trans_st; end if; when tx_dev_trans_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '0' then write_ns <= tx_data_wait_st; end if; when tx_data_wait_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '1' then write_ns <= tx_data_sample_st; end if; when tx_data_sample_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '0' then write_ns <= tx_data_trans_st; if (data_cnt_tx = 0) then write_ns <= tx_parity_update_st; end if; end if; when tx_data_trans_st => write_ns <= tx_data_wait_st; when tx_parity_update_st => write_ns <= tx_parity_trans_st; when tx_parity_trans_st => write_ns <= tx_parity_wait_st; when tx_parity_wait_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '1' then write_ns <= tx_parity_sample_st; end if; when tx_parity_sample_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '0' then write_ns <= tx_stop_trans_st; end if; when tx_stop_trans_st => write_ns <= tx_stop_wait_st; when tx_stop_wait_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '1' then write_ns <= tx_ack_trans_st; end if; when tx_ack_trans_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '0' and ps2_data_in = '0' then write_ns <= tx_ack_sample_st; end if; when tx_ack_sample_st => if timeout_tx_flag = '1' then write_ns <= tx_idle_st; elsif ps2_clk_in = '1' and ps2_data_in = '1' then write_ns <= tx_valid_st; end if; when others => write_ns <= tx_idle_st; end case; end process; ------------------------------------------- end Behavioral;