+-------------------------------------------------------------------------\r
+--\r
+-- Filename: ps2_transceiver_beh.vhd\r
+-- =========\r
+--\r
+-- Short Description:\r
+-- ==================\r
+-- Behavioral implementation of the PS/2 transceiver\r
+--\r
+-------------------------------------------------------------------------\r
+\r
+library ieee;\r
+use ieee.std_logic_1164.all;\r
+\r
+architecture beh of ps2_transceiver is\r
+ constant PREPARE_TIMEOUT1_MAX : integer := CLK_FREQ / 5000; -- 200 us\r
+ constant PREPARE_TIMEOUT2_MAX : integer := CLK_FREQ / 100000; -- 10 us\r
+ type PS2_TRANSCEIVER_STATE_TYPE is\r
+ (\r
+ IDLE,\r
+\r
+ PREPARE_SEND_ASSIGN_CLK, PREPARE_SEND_WAIT1, PREPARE_SEND_DATA, PREPARE_SEND_WAIT2,\r
+ PREPARE_SEND_RELEASE_CLK, SEND_WAIT_DATA0, SEND_DATA0, SEND_WAIT_DATA1, SEND_DATA1,\r
+ SEND_WAIT_DATA2, SEND_DATA2, SEND_WAIT_DATA3, SEND_DATA3, SEND_WAIT_DATA4, SEND_DATA4,\r
+ SEND_WAIT_DATA5, SEND_DATA5, SEND_WAIT_DATA6, SEND_DATA6, SEND_WAIT_DATA7, SEND_DATA7,\r
+ SEND_WAIT_PARITY, SEND_PARITY, SEND_WAIT_STOP, SEND_STOP, SEND_WAIT_ACK1, SEND_WAIT_ACK2,\r
+ SEND_READ_ACK, SEND_FINISH,\r
+ \r
+ RECEIVE_START, RECEIVE_WAIT_DATA0, RECEIVE_DATA0, RECEIVE_WAIT_DATA1, RECEIVE_DATA1,\r
+ RECEIVE_WAIT_DATA2, RECEIVE_DATA2, RECEIVE_WAIT_DATA3, RECEIVE_DATA3, RECEIVE_WAIT_DATA4,\r
+ RECEIVE_DATA4, RECEIVE_WAIT_DATA5, RECEIVE_DATA5, RECEIVE_WAIT_DATA6, RECEIVE_DATA6,\r
+ RECEIVE_WAIT_DATA7, RECEIVE_DATA7, RECEIVE_WAIT_PARITY, RECEIVE_PARITY, RECEIVE_WAIT_STOP,\r
+ RECEIVE_STOP\r
+ );\r
+ signal ps2_transceiver_state, ps2_transceiver_state_next : PS2_TRANSCEIVER_STATE_TYPE;\r
+ signal ps2_clk_last, ps2_clk_internal, ps2_clk_next, ps2_clk_hz, ps2_clk_hz_next : std_logic;\r
+ signal ps2_data_internal, ps2_data_next, ps2_data_hz, ps2_data_hz_next : std_logic;\r
+ signal ps2_clk_sync, ps2_data_sync : std_logic_vector(1 to SYNC_STAGES);\r
+ signal output_data_next, output_data_internal : std_logic_vector(7 downto 0);\r
+ signal parity, parity_next : std_logic;\r
+ signal new_data_next : std_logic;\r
+ signal prepare_timeout1, prepare_timeout1_next : integer range 0 to PREPARE_TIMEOUT1_MAX;\r
+ signal prepare_timeout2, prepare_timeout2_next : integer range 0 to PREPARE_TIMEOUT2_MAX;\r
+begin\r
+\r
+ process(ps2_transceiver_state, ps2_clk_sync(SYNC_STAGES), ps2_clk_last, ps2_data_sync(SYNC_STAGES), send_request, prepare_timeout1, prepare_timeout2, output_data_internal)\r
+ begin\r
+ ps2_transceiver_state_next <= ps2_transceiver_state;\r
+ \r
+ case ps2_transceiver_state is\r
+ when IDLE => \r
+ if ps2_clk_sync(SYNC_STAGES) = '1' and ps2_clk_last = '0' then\r
+ if ps2_data_sync(SYNC_STAGES) = '0' then\r
+ ps2_transceiver_state_next <= RECEIVE_START;\r
+ end if;\r
+ elsif send_request = '1' then\r
+ ps2_transceiver_state_next <= PREPARE_SEND_ASSIGN_CLK;\r
+ end if;\r
+\r
+\r
+ when PREPARE_SEND_ASSIGN_CLK =>\r
+ ps2_transceiver_state_next <= PREPARE_SEND_WAIT1;\r
+ when PREPARE_SEND_WAIT1 =>\r
+ if prepare_timeout1 = PREPARE_TIMEOUT1_MAX - 1 then\r
+ ps2_transceiver_state_next <= PREPARE_SEND_DATA;\r
+ end if;\r
+ when PREPARE_SEND_DATA =>\r
+ ps2_transceiver_state_next <= PREPARE_SEND_WAIT2;\r
+ when PREPARE_SEND_WAIT2 =>\r
+ if prepare_timeout2 = PREPARE_TIMEOUT2_MAX - 1 then\r
+ ps2_transceiver_state_next <= PREPARE_SEND_RELEASE_CLK;\r
+ end if;\r
+ when PREPARE_SEND_RELEASE_CLK =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA0;\r
+ when SEND_WAIT_DATA0 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA0;\r
+ end if;\r
+ when SEND_DATA0 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA1;\r
+ when SEND_WAIT_DATA1 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA1;\r
+ end if;\r
+ when SEND_DATA1 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA2;\r
+ when SEND_WAIT_DATA2 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA2;\r
+ end if;\r
+ when SEND_DATA2 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA3;\r
+ when SEND_WAIT_DATA3 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA3;\r
+ end if;\r
+ when SEND_DATA3 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA4;\r
+ when SEND_WAIT_DATA4 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA4;\r
+ end if;\r
+ when SEND_DATA4 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA5;\r
+ when SEND_WAIT_DATA5 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA5;\r
+ end if;\r
+ when SEND_DATA5 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA6;\r
+ when SEND_WAIT_DATA6 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA6;\r
+ end if;\r
+ when SEND_DATA6 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_DATA7;\r
+ when SEND_WAIT_DATA7 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_DATA7;\r
+ end if;\r
+ when SEND_DATA7 =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_PARITY;\r
+ when SEND_WAIT_PARITY =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_PARITY;\r
+ end if;\r
+ when SEND_PARITY =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_STOP;\r
+ when SEND_WAIT_STOP =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= SEND_STOP;\r
+ end if;\r
+ when SEND_STOP =>\r
+ ps2_transceiver_state_next <= SEND_WAIT_ACK1; \r
+ when SEND_WAIT_ACK1 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then -- ACK is written by device\r
+ ps2_transceiver_state_next <= SEND_WAIT_ACK2;\r
+ end if;\r
+ when SEND_WAIT_ACK2 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '1' and ps2_clk_last = '0' then -- ACK is valid\r
+ ps2_transceiver_state_next <= SEND_READ_ACK;\r
+ end if;\r
+ when SEND_READ_ACK =>\r
+ ps2_transceiver_state_next <= SEND_FINISH;\r
+ when SEND_FINISH =>\r
+ ps2_transceiver_state_next <= IDLE;\r
+\r
+ \r
+ \r
+ when RECEIVE_START =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA0;\r
+ when RECEIVE_WAIT_DATA0 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA0;\r
+ end if;\r
+ when RECEIVE_DATA0 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA1;\r
+ when RECEIVE_WAIT_DATA1 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA1;\r
+ end if;\r
+ when RECEIVE_DATA1 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA2;\r
+ when RECEIVE_WAIT_DATA2 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA2;\r
+ end if;\r
+ when RECEIVE_DATA2 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA3;\r
+ when RECEIVE_WAIT_DATA3 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA3;\r
+ end if;\r
+ when RECEIVE_DATA3 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA4;\r
+ when RECEIVE_WAIT_DATA4 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA4;\r
+ end if;\r
+ when RECEIVE_DATA4 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA5;\r
+ when RECEIVE_WAIT_DATA5 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA5;\r
+ end if;\r
+ when RECEIVE_DATA5 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA6;\r
+ when RECEIVE_WAIT_DATA6 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA6;\r
+ end if;\r
+ when RECEIVE_DATA6 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_DATA7;\r
+ when RECEIVE_WAIT_DATA7 =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_DATA7;\r
+ end if;\r
+ when RECEIVE_DATA7 =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_PARITY;\r
+ when RECEIVE_WAIT_PARITY =>\r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_PARITY;\r
+ end if;\r
+ when RECEIVE_PARITY =>\r
+ ps2_transceiver_state_next <= RECEIVE_WAIT_STOP;\r
+ when RECEIVE_WAIT_STOP => \r
+ if ps2_clk_sync(SYNC_STAGES) = '0' and ps2_clk_last = '1' then\r
+ ps2_transceiver_state_next <= RECEIVE_STOP;\r
+ end if;\r
+ when RECEIVE_STOP =>\r
+ ps2_transceiver_state_next <= IDLE;\r
+ end case;\r
+ end process;\r
+ \r
+ process(ps2_transceiver_state, ps2_data_internal, ps2_clk_internal, parity, input_data, ps2_data_sync(SYNC_STAGES), output_data_internal, prepare_timeout1, prepare_timeout2, ps2_clk_hz, ps2_data_hz)\r
+ begin\r
+ input_data_send_ok <= '0';\r
+ input_data_send_finished <= '0';\r
+ ps2_data_next <= ps2_data_internal;\r
+ ps2_data_hz_next <= ps2_data_hz;\r
+ ps2_clk_next <= ps2_clk_internal;\r
+ ps2_clk_hz_next <= ps2_clk_hz;\r
+ parity_next <= parity;\r
+ output_data_next <= output_data_internal;\r
+ new_data_next <= '0';\r
+ prepare_timeout1_next <= prepare_timeout1;\r
+ prepare_timeout2_next <= prepare_timeout2;\r
+ \r
+ case ps2_transceiver_state is\r
+ when IDLE => \r
+ ps2_clk_next <= '1';\r
+ ps2_clk_hz_next <= '1';\r
+ ps2_data_next <= '1';\r
+ ps2_data_hz_next <= '1';\r
+\r
+ when PREPARE_SEND_ASSIGN_CLK =>\r
+ ps2_clk_next <= '0';\r
+ ps2_clk_hz_next <= '0';\r
+ parity_next <= '1';\r
+ prepare_timeout1_next <= 0;\r
+ when PREPARE_SEND_WAIT1 =>\r
+ prepare_timeout1_next <= prepare_timeout1 + 1;\r
+ when PREPARE_SEND_DATA =>\r
+ ps2_data_next <='0';\r
+ ps2_data_hz_next <= '0';\r
+ prepare_timeout2_next <= 0;\r
+ when PREPARE_SEND_WAIT2 =>\r
+ prepare_timeout2_next <= prepare_timeout2 + 1;\r
+ when PREPARE_SEND_RELEASE_CLK =>\r
+ ps2_clk_next <= '1';\r
+ ps2_clk_hz_next <= '1';\r
+ when SEND_WAIT_DATA0 =>\r
+ null;\r
+ when SEND_DATA0 =>\r
+ ps2_data_next <= input_data(0);\r
+ parity_next <= parity xor input_data(0);\r
+ when SEND_WAIT_DATA1 =>\r
+ null;\r
+ when SEND_DATA1 =>\r
+ ps2_data_next <=input_data(1);\r
+ parity_next <= parity xor input_data(1);\r
+ when SEND_WAIT_DATA2 =>\r
+ null;\r
+ when SEND_DATA2 =>\r
+ ps2_data_next <=input_data(2);\r
+ parity_next <= parity xor input_data(2);\r
+ when SEND_WAIT_DATA3 =>\r
+ null;\r
+ when SEND_DATA3 =>\r
+ ps2_data_next <=input_data(3);\r
+ parity_next <= parity xor input_data(3);\r
+ when SEND_WAIT_DATA4 =>\r
+ null;\r
+ when SEND_DATA4 =>\r
+ ps2_data_next <=input_data(4);\r
+ parity_next <= parity xor input_data(4);\r
+ when SEND_WAIT_DATA5 =>\r
+ null;\r
+ when SEND_DATA5 =>\r
+ ps2_data_next <=input_data(5);\r
+ parity_next <= parity xor input_data(5);\r
+ when SEND_WAIT_DATA6 =>\r
+ null;\r
+ when SEND_DATA6 =>\r
+ ps2_data_next <=input_data(6);\r
+ parity_next <= parity xor input_data(6);\r
+ when SEND_WAIT_DATA7 =>\r
+ null;\r
+ when SEND_DATA7 =>\r
+ ps2_data_next <=input_data(7);\r
+ parity_next <= parity xor input_data(7);\r
+ when SEND_WAIT_PARITY =>\r
+ null;\r
+ when SEND_PARITY =>\r
+ ps2_data_next <= parity;\r
+ when SEND_WAIT_STOP =>\r
+ null;\r
+ when SEND_STOP =>\r
+ ps2_data_next <='1';\r
+ ps2_data_hz_next <='1';\r
+ when SEND_WAIT_ACK1 =>\r
+ null;\r
+ when SEND_WAIT_ACK2 =>\r
+ null;\r
+ when SEND_READ_ACK =>\r
+ input_data_send_ok <= not ps2_data_sync(SYNC_STAGES);\r
+ input_data_send_finished <= '1';\r
+ when SEND_FINISH =>\r
+ \r
+ when RECEIVE_START =>\r
+ null;\r
+ when RECEIVE_WAIT_DATA0 =>\r
+ null;\r
+ when RECEIVE_DATA0 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA1 =>\r
+ null;\r
+ when RECEIVE_DATA1 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA2 =>\r
+ null;\r
+ when RECEIVE_DATA2 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA3 =>\r
+ null;\r
+ when RECEIVE_DATA3 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA4 =>\r
+ null;\r
+ when RECEIVE_DATA4 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA5 =>\r
+ null;\r
+ when RECEIVE_DATA5 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA6 =>\r
+ null;\r
+ when RECEIVE_DATA6 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_DATA7 =>\r
+ null;\r
+ when RECEIVE_DATA7 =>\r
+ output_data_next <= ps2_data_sync(SYNC_STAGES) & output_data_internal(7 downto 1);\r
+ when RECEIVE_WAIT_PARITY =>\r
+ null;\r
+ when RECEIVE_PARITY =>\r
+ null; -- Currently igonring parity\r
+ when RECEIVE_WAIT_STOP =>\r
+ null;\r
+ when RECEIVE_STOP =>\r
+ new_data_next <= '1';\r
+ end case;\r
+ end process;\r
+ \r
+ process(sys_clk, sys_res_n)\r
+ begin\r
+ if sys_res_n = '0' then\r
+ ps2_transceiver_state <= IDLE;\r
+ ps2_clk_last <= '1';\r
+ ps2_clk_internal <= '1';\r
+ ps2_clk_hz <= '1';\r
+ ps2_data_internal <= '1';\r
+ ps2_data_hz <= '1';\r
+ output_data_internal <= (others => '0');\r
+ parity <= '0';\r
+ new_data <= '0';\r
+ prepare_timeout1 <= 0;\r
+ prepare_timeout2 <= 0;\r
+ ps2_clk_sync <= (others => '1');\r
+ ps2_data_sync <= (others => '1');\r
+ elsif rising_edge(sys_clk) then\r
+ ps2_transceiver_state <= ps2_transceiver_state_next;\r
+ ps2_clk_last <= ps2_clk_sync(SYNC_STAGES);\r
+ ps2_clk_internal <= ps2_clk_next;\r
+ ps2_clk_hz <= ps2_clk_hz_next;\r
+ ps2_data_internal <= ps2_data_next;\r
+ ps2_data_hz <= ps2_data_hz_next;\r
+ output_data_internal <= output_data_next;\r
+ parity <= parity_next;\r
+ new_data <= new_data_next;\r
+ prepare_timeout1 <= prepare_timeout1_next;\r
+ prepare_timeout2 <= prepare_timeout2_next;\r
+ ps2_clk_sync(1) <= ps2_clk;\r
+ ps2_data_sync(1) <= ps2_data;\r
+ for i in 2 to SYNC_STAGES loop\r
+ ps2_clk_sync(i) <= ps2_clk_sync(i - 1);\r
+ ps2_data_sync(i) <= ps2_data_sync(i - 1);\r
+ end loop;\r
+ end if;\r
+ end process;\r
+ ps2_clk <= ps2_clk_internal when ps2_clk_hz = '0'\r
+ else 'Z';\r
+ ps2_data <= ps2_data_internal when ps2_data_hz = '0'\r
+ else 'Z';\r
+ output_data <= output_data_internal;\r
+end architecture beh;\r