diff --git a/lib/ps2_port/sim/tb_ps2_core.fdo b/lib/ps2_port/sim/tb_ps2_core.fdo new file mode 100644 index 0000000..5beb4d4 --- /dev/null +++ b/lib/ps2_port/sim/tb_ps2_core.fdo @@ -0,0 +1,13 @@ +## NOTE: Do not edit this file. +## + +vlib work +vcom -explicit -93 "../src/ps2_core.vhd" +vcom -explicit -93 "../src/tb_ps2_core.vhd" + +vsim -t 1ps -lib work tb_ps2_core +do {tb_ps2_core.wdo} +view wave +view structure +view signals +run 5 ms diff --git a/lib/ps2_port/sim/tb_ps2_core.wdo b/lib/ps2_port/sim/tb_ps2_core.wdo new file mode 100644 index 0000000..2b99b72 --- /dev/null +++ b/lib/ps2_port/sim/tb_ps2_core.wdo @@ -0,0 +1,33 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb_ps2_core/rst +add wave -noupdate -format Logic /tb_ps2_core/clk +add wave -noupdate -format Literal /tb_ps2_core/din +add wave -noupdate -format Logic /tb_ps2_core/tx_empty +add wave -noupdate -format Logic /tb_ps2_core/din_vld +add wave -noupdate -format Literal /tb_ps2_core/dout +add wave -noupdate -format Logic /tb_ps2_core/rx_present +add wave -noupdate -format Logic /tb_ps2_core/read_en +add wave -noupdate -format Literal /tb_ps2_core/dout_reg +add wave -noupdate -format Logic /tb_ps2_core/ps2_data_rx +add wave -noupdate -format Logic /tb_ps2_core/ps2_clk_rx +add wave -noupdate -format Logic /tb_ps2_core/ps2_clk_tx +add wave -noupdate -format Logic /tb_ps2_core/ps2_data_tx +add wave -noupdate -format Logic /tb_ps2_core/ps2_clk_i +add wave -noupdate -format Logic /tb_ps2_core/tx_trig +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {4999629518 ps} 0} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 100 +configure wave -griddelta 40 +configure wave -timeline 1 +update +WaveRestoreZoom {0 ps} {5250 us} diff --git a/lib/ps2_port/src/debounce.vhd b/lib/ps2_port/src/debounce.vhd new file mode 100644 index 0000000..3c5cd39 --- /dev/null +++ b/lib/ps2_port/src/debounce.vhd @@ -0,0 +1,89 @@ +-------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 19:34:24 10/23/05 +-- Design Name: +-- Module Name: debounce - 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 debounce is + Generic ( ncyc_latency : integer := 100); + Port ( rst : in std_logic; + clk : in std_logic; + input : in std_logic; + output : out std_logic); +end debounce; + +architecture Behavioral of debounce is + +type debounce_state_t is (init_st, wait_st, rel_st); +signal debounce_cs : debounce_state_t; +signal debounce_ns : debounce_state_t; +signal count : integer range 0 to ncyc_latency-1; +signal input_last : std_logic; + +begin + + debounce_clk: process(rst, clk, debounce_ns, debounce_cs, input) + begin + if (rst = '1') then + count <= 0; + output <= input; + input_last <= input; + else + if rising_edge(clk) then + debounce_cs <= debounce_ns; + if (debounce_cs = wait_st) then + if (count /= 0) then + count <= count - 1; + end if; + else + count <= ncyc_latency-1; + if (debounce_cs = rel_st) then + output <= input; + input_last <= input; + end if; + end if; + end if; + end if; + end process; + + debounce_in: process(rst, clk, input, input_last, debounce_cs, count) + begin + debounce_ns <= debounce_cs; + case debounce_cs is + when init_st => + if (input /= input_last) then + debounce_ns <= wait_st; + end if; + when wait_st => + if (count = 0) then + debounce_ns <= rel_st; + end if; + when others => + debounce_ns <= init_st; + end case; + end process; + +end Behavioral; diff --git a/lib/ps2_port/src/ps2_core.vhd b/lib/ps2_port/src/ps2_core.vhd new file mode 100644 index 0000000..5beb50e --- /dev/null +++ b/lib/ps2_port/src/ps2_core.vhd @@ -0,0 +1,592 @@ +-------------------------------------------------------------------------------- +-- 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.NUMERIC_STD.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_hz : integer := 100E6 + ); + Port + ( + rst : in std_logic; + clk : in std_logic; + din : in unsigned(7 downto 0); + dout : out unsigned(7 downto 0); + tx_empty : out std_logic; + rx_present : out std_logic; + din_vld : in std_logic; + read_en : in std_logic; + ps2_clk_rx : in std_logic; + ps2_data_rx : in std_logic; + ps2_clk_tx : out std_logic; + ps2_data_tx : out std_logic + ); + +end ps2_core; + +architecture Behavioral of ps2_core is + +-- 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_hz/1E6; +constant timeout_us : integer := 15000; +constant time_clock_assert : integer := 120; + +-- Signals +signal en_us : std_logic; +signal timeout_rx_load_en : std_logic; +signal timeout_rx_en : std_logic; +signal timeout_rx_flag : std_logic; + +signal timeout_tx_load_en : std_logic; +signal timeout_tx_en : std_logic; +signal timeout_tx_flag : std_logic; + +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 : unsigned(7 downto 0); +signal tx_reg : unsigned(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; + +signal timeout_count_rx : integer range 0 to timeout_us-1; +signal timeout_count_tx : integer range 0 to timeout_us-1; +signal timeval_tx : integer range 0 to timeout_us-1; + +signal sipo_reg : unsigned(7 downto 0); +signal piso_reg : unsigned(7 downto 0); + +begin + +proc_prescaler: +process(clk) + variable cnt_prescaler : integer range 0 to prescaler_us-1; + begin + if rising_edge(clk) then + if rst = '1' then + cnt_prescaler := prescaler_us - 1; + en_us <= '0'; + elsif cnt_prescaler = 0 then + cnt_prescaler := prescaler_us - 1; + en_us <= '1'; + else + cnt_prescaler := cnt_prescaler - 1; + en_us <= '0'; + end if; + end if; +end process proc_prescaler; + +proc_timeout_counter_rx: +process (clk) +begin + if rising_edge(clk) then + if timeout_rx_load_en ='1' then + timeout_count_rx <= timeout_us - 1; + timeout_rx_flag <= '0'; + else + if (timeout_count_rx /= 0) then + if timeout_rx_en ='1' then + timeout_count_rx <= timeout_count_rx - 1; + end if; + else + timeout_rx_flag <= '1'; + end if; + end if; + end if; +end process; + +proc_timeout_counter_tx: +process (clk) +begin + if rising_edge(clk) then + if timeout_tx_load_en ='1' then + timeout_count_tx <= timeval_tx; + timeout_tx_flag <= '0'; + else + if (timeout_count_tx /= 0) then + if timeout_tx_en ='1' then + timeout_count_tx <= timeout_count_tx - 1; + end if; + else + timeout_tx_flag <= '1'; + end if; + end if; + end if; +end process; + +proc_rx_sipo: +process (clk) +begin + if rising_edge(clk) then + if (rst = '1') then + sipo_reg <= (others => '0'); + elsif sipo_en = '1' then + sipo_reg <= ps2_data_rx & sipo_reg(sipo_reg'left downto 1); + end if; + end if; + rx_reg <= sipo_reg; +end process; + +proc_tx_piso: +process (clk) +begin + if rising_edge(clk) then + if rst ='1' then + piso_reg <= (others => '0'); + elsif piso_load_en = '1' then + piso_reg <= tx_reg; + elsif piso_en = '1' then + piso_reg <= '0' & piso_reg(piso_reg'left downto 1); + end if; + end if; + piso_out <= piso_reg(0); +end process; + +proc_parity_bitser_rx: +process (clk) +begin + if rising_edge(clk) then + if parity_rst='1' then + parity <= '1'; + elsif parity_en = '1' and ps2_data_rx = '1' then + parity <= not parity; + end if; + end if; +end process; + +proc_parity_bitser_tx: +process (clk) +begin + if rising_edge(clk) then + if parity_tx_rst='1' then + parity_tx <= '1'; + elsif parity_tx_en = '1' and piso_out = '1' then + parity_tx <= not parity_tx; + end if; + end if; +end process; + + + ------------------------------------------- + tx_en <= tx_req and (not rx_busy); + rx_en <= not tx_busy; + + ------------------------------------------- +proc_out_reg: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + dout <= (others => '0'); + rx_present <= '0'; + elsif rx_rdy = '1' then + dout <= rx_reg; + rx_present <= '1'; + elsif read_en = '1' then + rx_present <= '0'; + end if; + end if; +end process; + +proc_in_reg: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + tx_empty <= '1'; + tx_req <= '0'; + elsif piso_load_en = '1' then + tx_reg <= din; + tx_empty <= '1'; + tx_req <= '0'; + elsif din_vld = '1' then + tx_empty <= '0'; + tx_req <= '1'; + end if; + end if; +end process; + + ------------------------------------------- +proc_read_state_clk: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + read_cs <= start_wait_st; + else + 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; + + ------------------------------------------- +proc_write_state_clk: +process(rst, clk) +begin + if rising_edge(clk) then + if rst = '1' then + write_cs <= tx_idle_st; + else + 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_rx_load_en <= '0'; + timeout_rx_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_rx_load_en <= '1'; + timeout_rx_en <= '0'; + rx_busy <= '0'; + when start_sample_st => + data_cnt_rst <= '1'; + parity_rst <= '1'; + timeout_rx_load_en <= '1'; + when data_sample_st => + data_cnt_en <= '1'; + parity_en <= '1'; + sipo_en <= '1'; + timeout_rx_load_en <= '1'; + when parity_sample_st => + timeout_rx_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_rx_flag, rx_en, data_cnt, ps2_data_rx, ps2_clk_rx) +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_rx = '0' and ps2_clk_rx = '1' and rx_en = '1' then + read_ns <= start_trans_st; + end if; + when start_trans_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_data_rx = '0' and ps2_clk_rx = '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_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '1' then + read_ns <= data_trans_st; + end if; + -- Wait data trans + when data_trans_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '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_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '1' then + read_ns <= parity_trans_st; + end if; + when parity_trans_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '0' then + read_ns <= parity_sample_st; + end if; + when parity_sample_st => + read_ns <= stop_wait_st; + when stop_wait_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '1' then + read_ns <= stop_trans_st; + end if; + when stop_trans_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '0' and ps2_data_rx = '1' then + read_ns <= stop_sample_st; + end if; + when stop_sample_st => + if timeout_rx_flag = '1' then + read_ns <= start_wait_st; + elsif ps2_clk_rx = '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_tx <= '1'; + ps2_data_tx <= '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_tx <= '0'; + when tx_start_assert_st => + ps2_clk_tx <= '0'; + ps2_data_tx <= '0'; + when tx_clock_release_st => + ps2_data_tx <= '0'; + timeout_tx_load_en <= '1'; + timeval_tx <= timeout_us - 1; + when tx_dev_wait_st => + ps2_data_tx <= '0'; + when tx_dev_trans_st => + ps2_data_tx <= '0'; + timeout_tx_load_en <= '1'; + timeval_tx <= timeout_us - 1; + when tx_data_wait_st => + ps2_data_tx <= piso_out; + when tx_data_trans_st => + data_cnt_tx_en <= '1'; + ps2_data_tx <= 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_tx <= piso_out; + when tx_parity_update_st => + parity_tx_en <= '1'; + ps2_data_tx <= piso_out; + when tx_parity_sample_st => + ps2_data_tx <= parity_tx; + when tx_parity_wait_st => + ps2_data_tx <= parity_tx; + when tx_parity_trans_st => + ps2_data_tx <= 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_rx, ps2_clk_rx) + 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_rx = '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_rx = '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_rx = '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_rx = '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_rx = '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_rx = '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_rx = '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_rx = '0' and ps2_data_rx = '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_rx = '1' and ps2_data_rx = '1' then + write_ns <= tx_valid_st; + end if; + when others => + write_ns <= tx_idle_st; + end case; + end process; + + ------------------------------------------- +end Behavioral; diff --git a/lib/ps2_port/src/ps2_phy_virtex.vhd b/lib/ps2_port/src/ps2_phy_virtex.vhd new file mode 100644 index 0000000..3b8d685 --- /dev/null +++ b/lib/ps2_port/src/ps2_phy_virtex.vhd @@ -0,0 +1,122 @@ +-------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 20:52:44 10/26/05 +-- Design Name: +-- Module Name: ps2_phy - 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_phy is + Port + ( + rst : in std_logic; + clk : in std_logic; + ps2_clk : inout std_logic; + ps2_data : inout std_logic; + rx_clk : out std_logic; + rx_data : out std_logic; + tx_clk : in std_logic; + tx_data : in std_logic + ); +end ps2_phy; + +architecture Behavioral of ps2_phy is + + COMPONENT debounce + GENERIC (ncyc_latency : integer); + PORT + ( + rst : IN std_logic; + clk : IN std_logic; + input : IN std_logic; + output : OUT std_logic + ); + END COMPONENT; + +signal clk_in : std_logic; +signal data_in : std_logic; + +begin + + Inst_debounce_clk: debounce + GENERIC MAP + ( + ncyc_latency => 8 + ) + PORT MAP + ( + rst => rst, + clk => clk, + input => clk_in, + output => rx_clk + ); + + Inst_debounce_data: debounce + GENERIC MAP + ( + ncyc_latency => 8 + ) + PORT MAP + ( + rst => rst, + clk => clk, + input => data_in, + output => rx_data + ); + +IOBUF_inst_ps2_clk : IOBUF + generic map + ( + DRIVE => 2, + IBUF_DELAY_VALUE => "0", -- Specify the amount of added input delay for buffer, "0"-"16" (Spartan-3E only) + IFD_DELAY_VALUE => "AUTO", -- Specify the amount of added delay for input register, "AUTO", "0"-"8" (Spartan-3E only) + IOSTANDARD => "DEFAULT", + SLEW => "SLOW" + ) + port map + ( + O => clk_in, -- Buffer output + IO => ps2_clk, -- Buffer inout port (connect directly to top-level port) + I => tx_clk, -- Buffer input + T => tx_clk -- 3-state enable input + ); + + IOBUF_inst_ps2_data : IOBUF + generic map + ( + DRIVE => 2, + IBUF_DELAY_VALUE => "0", -- Specify the amount of added input delay for buffer, "0"-"16" (Spartan-3E only) + IFD_DELAY_VALUE => "AUTO", -- Specify the amount of added delay for input register, "AUTO", "0"-"8" (Spartan-3E only) + IOSTANDARD => "DEFAULT", + SLEW => "SLOW" + ) + port map + ( + O => data_in, -- Buffer output + IO => ps2_data, -- Buffer inout port (connect directly to top-level port) + I => tx_data, -- Buffer input + T => tx_data -- 3-state enable input + ); + +end Behavioral; diff --git a/lib/ps2_port/src/ps2_wb.vhd b/lib/ps2_port/src/ps2_wb.vhd new file mode 100644 index 0000000..3d5d2bb --- /dev/null +++ b/lib/ps2_port/src/ps2_wb.vhd @@ -0,0 +1,136 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY ps2_wb IS + Generic + ( + f_sys_clk_hz : integer := 100E6 + ); + Port + ( + CLK_I : in STD_LOGIC; + RST_I : in STD_LOGIC; + CYC_I : in STD_LOGIC; + STB_I : in STD_LOGIC; + SEL_I : in unsigned(3 downto 0); + WE_I : in STD_LOGIC; + ACK_O : out STD_LOGIC; + SRDY_O : out STD_LOGIC; + MRDY_I : in STD_LOGIC; + ADDR_I : in unsigned(31 downto 0); + DAT_I : in unsigned(31 downto 0); + DAT_O : out unsigned(31 downto 0); + INT_O : out STD_LOGIC; + clk_rx : in std_logic; + data_rx : in std_logic; + clk_tx : out std_logic; + data_tx : out std_logic + ); +END ps2_wb; + +ARCHITECTURE behavior OF ps2_wb IS + + + -- Signals for ps2 connections + signal reg_we_ps2_tx : std_logic; + signal reg_re_ps2_rx : std_logic; + signal reg_ps2_tx : unsigned(7 downto 0); + signal reg_ps2_rx : unsigned(7 downto 0); + signal rx_data_present : std_logic; + signal ps2_status_port : unsigned(15 downto 0); + signal rx_int_en : std_logic; + signal tx_int_en : std_logic; + signal irq_rx : std_logic; + signal irq_tx : std_logic; + signal tx_empty : std_logic; + +begin + + SRDY_O <= CYC_I; + +------------------------------------------------------------------ +registers_write: + process(CLK_I) + begin + if rising_edge(CLK_I) then + reg_we_ps2_tx <= '0'; + if RST_I = '1' then + rx_int_en <= '0'; + tx_int_en <= '0'; + elsif (STB_I and CYC_I and WE_I) = '1' then + case ADDR_I(5 downto 2) is + + when "0000" => + reg_we_ps2_tx <= '1'; + reg_ps2_tx <= DAT_I(7 downto 0); + + when "0001" => + rx_int_en <= DAT_I(6); + tx_int_en <= DAT_I(5); + + when others => null; + end case; + end if; + end if; + end process; + +registers_read: + process(CLK_I) + begin + if rising_edge(CLK_I) then + reg_re_ps2_rx <= '0'; + ACK_O <= '0'; + if (STB_I and CYC_I) = '1' then + ACK_O <= not WE_I; + DAT_O <= (others => '0'); + case ADDR_I(5 downto 2) is + + when "0000" => + reg_re_ps2_rx <= not WE_I; + DAT_O(7 downto 0) <= unsigned(reg_ps2_rx); + + when "0001" => + DAT_O(15 downto 0) <= ps2_status_port; + + when others => null; + end case; + end if; + end if; + end process; + +irq_register: + process(CLK_I) + begin + if rising_edge(CLK_I) then + INT_O <= irq_rx or irq_tx; + irq_tx <= tx_empty and tx_int_en; + irq_rx <= rx_data_present and rx_int_en; + end if; + end process; + +inst_ps2_core: entity work.ps2_core + GENERIC MAP + ( + f_sys_clk_hz => f_sys_clk_hz + ) + PORT MAP + ( + rst => RST_I, + clk => CLK_I, + din => reg_ps2_tx, + dout => reg_ps2_rx, + tx_empty => tx_empty, + rx_present => rx_data_present, + din_vld => reg_we_ps2_tx, + read_en => reg_re_ps2_rx, + ps2_clk_rx => clk_rx, + ps2_data_rx => data_rx, + ps2_clk_tx => clk_tx, + ps2_data_tx => data_tx + ); + + ps2_status_port <= "000000" & irq_rx & irq_tx & '0' & rx_int_en & tx_int_en & '0' & '0' & rx_data_present & '0' & tx_empty; +-- INT_O <= irq_rx or irq_tx; + +end behavior; diff --git a/lib/ps2_port/src/tb_ps2_core.vhd b/lib/ps2_port/src/tb_ps2_core.vhd new file mode 100644 index 0000000..e013fba --- /dev/null +++ b/lib/ps2_port/src/tb_ps2_core.vhd @@ -0,0 +1,290 @@ + +-------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 20:35:49 10/22/2005 +-- Design Name: ps2_core +-- Module Name: tb_ps2_core.vhd +-- Project Name: ps2if +-- Target Device: +-- Tool versions: +-- Description: +-- +-- VHDL Test Bench Created by ISE for module: ps2_core +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +-- Notes: +-- This testbench has been automatically generated using types std_logic and +-- std_logic_vector for the ports of the unit under test. Xilinx recommends +-- that these types always be used for the top-level I/O of a design in order +-- to guarantee that the testbench will bind correctly to the post-implementation +-- simulation model. +-------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY tb_ps2_core IS +END tb_ps2_core; + +ARCHITECTURE behavior OF tb_ps2_core IS + + -- Component Declaration for the Unit Under Test (UUT) + COMPONENT ps2_core + PORT( + rst : IN std_logic; + clk : IN std_logic; + din : IN unsigned(7 downto 0); + din_vld : IN std_logic; + read_en : IN std_logic; + ps2_clk_rx : IN std_logic; + ps2_data_rx : IN std_logic; + ps2_clk_tx : out std_logic; + ps2_data_tx : out std_logic; + dout : OUT unsigned(7 downto 0); + tx_empty : OUT std_logic; + rx_present : OUT std_logic + ); + END COMPONENT; + + --Constants + constant SYSPERIOD : time := 10 ns; + constant PS2PERIOD : time := 100 us; + + --Inputs + SIGNAL rst : std_logic := '1'; + SIGNAL clk : std_logic := '0'; + SIGNAL din_vld : std_logic := '0'; + SIGNAL read_en : std_logic := '0'; + SIGNAL ps2_clk_rx : std_logic := '1'; + SIGNAL ps2_data_rx : std_logic := '1'; + SIGNAL din : unsigned(7 downto 0) := (others=>'0'); + + --Outputs + SIGNAL dout : unsigned(7 downto 0); + SIGNAL dout_reg : unsigned(7 downto 0); + SIGNAL tx_empty : std_logic; + SIGNAL rx_present : std_logic; + SIGNAL ps2_clk_i : std_logic := '1'; + SIGNAL ps2_clk_j : std_logic := '1'; + SIGNAL ps2_clk_tx : std_logic; + SIGNAL ps2_data_tx : std_logic; + SIGNAl tx_trig : std_logic := '0'; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) +uut: ps2_core + PORT MAP + ( + rst => rst, + clk => clk, + din => din, + dout => dout, + tx_empty => tx_empty, + rx_present => rx_present, + din_vld => din_vld, + read_en => read_en, + ps2_clk_rx => ps2_clk_rx, + ps2_data_rx => ps2_data_rx, + ps2_clk_tx => ps2_clk_tx, + ps2_data_tx => ps2_data_tx + ); + + ps2_clk_j <= ps2_clk_i after PS2PERIOD/4; + tb_pswclk : PROCESS + BEGIN + wait until ps2_clk_j'event; + ps2_clk_rx <= ps2_clk_j; + +-- wait for SYSPERIOD; +-- ps2_clk_rx <= not ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= not ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= not ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= not ps2_clk_j; +-- wait for SYSPERIOD; +-- ps2_clk_rx <= ps2_clk_j; + END PROCESS; + + tb_sysclk : PROCESS + BEGIN + clk <= not clk; + wait for SYSPERIOD/2; + END PROCESS; + + read_en <= rx_present; + tb_read : PROCESS(clk) + BEGIN + if rising_edge(clk) then + if rx_present = '1' then + dout_reg <= dout; + end if; + end if; + + END PROCESS; + + tb_write : PROCESS + BEGIN + wait until ps2_clk_tx = '0'; + wait for PS2PERIOD; + wait until ps2_data_tx = '0'; + wait until ps2_clk_tx = '1'; + wait for PS2PERIOD/2; + tx_trig <= '1'; + + END PROCESS; + + tb : PROCESS + BEGIN + + wait for 20*SYSPERIOD; + rst <= '0'; + + for iter in 1 to 2 loop +-- wait for 2*PS2PERIOD; + + --Start bit + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '0'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 0 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 1 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 2 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '0'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 3 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 4 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 5 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '0'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 6 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Data bit 7 + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Parity + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + --Stop + wait for PS2PERIOD/2; + ps2_clk_i <= '0'; + ps2_data_rx <= '1'; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + + end loop; + + ps2_data_rx <= '1'; + ps2_clk_i <= '1'; + + wait for PS2PERIOD; + wait until rising_edge(clk); + din <= x"A5"; + din_vld <= '1'; + wait until rising_edge(clk); + din_vld <= '0'; + + wait until tx_trig = '1'; + wait for 2*PS2PERIOD; + -- Start + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + + for iter in 1 to 8 loop + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + end loop; + + -- Stop + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + + -- Parity + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + + ps2_data_rx <= '0'; + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + + ps2_clk_i <= not ps2_clk_i; + wait for PS2PERIOD/2; + ps2_data_rx <= '1'; + ps2_clk_i <= '1'; + -- Place stimulus here + + wait; -- will wait forever + END PROCESS; + +END;