git-svn-id: http://moon:8086/svn/vhdl/trunk@1422 cc03376c-175c-47c8-b038-4cd826a8556b
611 lines
17 KiB
VHDL
611 lines
17 KiB
VHDL
--------------------------------------------------------------------------------
|
|
-- 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;
|