Files
vhdl/projects/ps2if/src/ps2_core.vhd
T
jens 5309734167 - added
git-svn-id: http://moon:8086/svn/vhdl/trunk@1422 cc03376c-175c-47c8-b038-4cd826a8556b
2021-03-21 11:25:09 +00:00

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;