vga/ps/2: ip-core hinzugefuegt
[hwmod.git] / src / ps2 / ps2_transceiver_beh.vhd
diff --git a/src/ps2/ps2_transceiver_beh.vhd b/src/ps2/ps2_transceiver_beh.vhd
new file mode 100644 (file)
index 0000000..8706c52
--- /dev/null
@@ -0,0 +1,396 @@
+-------------------------------------------------------------------------\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