Project

General

Profile

718 markw
---------------------------------------------------------------------------
-- (c) 2018 mark watson
-- I am happy for anyone to use this for non-commercial use.
-- If my vhdl files are used commercially or otherwise sold,
-- please contact me for explicit permission at scrameta (gmail).
-- This applies for source and binary form and derived works.
---------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;

938 markw
-- TALK to PCAL6408A io expander over i2c
718 markw
-- goals:
-- keyboard:
-- set keyboard 6 lines to output
-- drive keyboard 6 lines constantly
-- receive keyboard 2 lines constantly
-- review if we need pull ups on 2 keyboard inputs
-- work out which pins in invert on keyboard


ENTITY iox_glue IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;

ENA : OUT STD_LOGIC;
ADDR : OUT STD_LOGIC_VECTOR(7 downto 1);
RW : OUT STD_LOGIC;
WRITE_DATA : OUT STD_LOGIC_VECTOR(7 downto 0);

BUSY : IN STD_LOGIC;
READ_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
ERROR : IN STD_LOGIC;

726 markw
INT : IN STD_LOGIC;

718 markw
KEYBOARD_SCAN : IN STD_LOGIC_VECTOR(5 downto 0);
726 markw
KEYBOARD_RESPONSE : OUT STD_LOGIC_VECTOR(1 downto 0);
1239 markw
KEYBOARD_SCAN_UPDATE : IN STD_LOGIC;
KEYBOARD_SCAN_ENABLE : OUT STD_LOGIC
718 markw
);
END iox_glue;

ARCHITECTURE vhdl OF iox_glue IS
-- requests to send to i2c
1283 markw
signal state_reg : std_logic_vector(3 downto 0);
signal state_next : std_logic_vector(3 downto 0);
constant state_setup1 : std_logic_vector(3 downto 0) := "0000";
constant state_setup3 : std_logic_vector(3 downto 0) := "0010";
constant state_setup4 : std_logic_vector(3 downto 0) := "0011";
constant state_setup5 : std_logic_vector(3 downto 0) := "0100";
constant state_setup6 : std_logic_vector(3 downto 0) := "0101";
938 markw
--addr,$4f (driven),00000000 (port 1 is driven)
--addr,$03 (cfg port1), 10000001 (p1_0,p1_7 are inputs)
--addr,$43 (pull up/down),10000001 (use pull ups/downs)
--addr,$44 (pull up/down),10000001 (use pull up 100ks)
1283 markw
constant state_kbscan : std_logic_vector(3 downto 0) := "0110";
constant state_kbread : std_logic_vector(3 downto 0) := "0111";
constant state_setup7 : std_logic_vector(3 downto 0) := "1001";
constant state_kbscan_delay : std_logic_vector(3 downto 0) := "1010";
718 markw
-- address, write input port0(02),val
-- address, read input port1(01),0xff(in)
-- address, write input port1(03),val

signal w2 : std_logic;
signal write1 : std_logic_vector(7 downto 0);
signal write2 : std_logic_vector(7 downto 0);

1283 markw
signal i2c_state_reg : std_logic_vector(1 downto 0);
signal i2c_state_next : std_logic_vector(1 downto 0);
constant i2c_state_idle : std_logic_vector(1 downto 0) := "00";
constant i2c_state_part1 : std_logic_vector(1 downto 0) := "01";
constant i2c_state_part2 : std_logic_vector(1 downto 0) := "10";
constant i2c_state_part3 : std_logic_vector(1 downto 0) := "11";
718 markw
signal op_complete : std_logic;
signal busy_reg : std_logic;
1197 markw
signal keyboard_response_reg : std_logic_vector(1 downto 0);
signal keyboard_response_next : std_logic_vector(1 downto 0);
1224 markw
1239 markw
signal keyboard_scan_update_pending_reg : std_logic;
signal keyboard_scan_update_pending_next : std_logic;

1224 markw
signal request : std_logic;
718 markw
begin
process(clk,reset_n)
begin
if (reset_n='0') then
state_reg <= state_setup1;
1224 markw
i2c_state_reg <= i2c_state_idle;
718 markw
busy_reg <= '0';
1197 markw
keyboard_response_reg <= "11";
1239 markw
keyboard_scan_update_pending_reg <= '0';
718 markw
elsif (clk'event and clk='1') then
state_reg <= state_next;
i2c_state_reg <= i2c_state_next;
busy_reg <= busy;
1197 markw
keyboard_response_reg <= keyboard_response_next;
1239 markw
keyboard_scan_update_pending_reg <= keyboard_scan_update_pending_next;
718 markw
end if;
end process;


1224 markw
process(i2c_state_reg,w2,write1,write2,busy_reg,busy,request)
718 markw
variable busy_latched : std_logic;
begin
i2c_state_next <= i2c_state_reg;

ena <= '0';
addr <= "0100000"; -- $40
719 markw
rw <= '1';
718 markw
write_data <= (others=>'0');
op_complete <= '0';

busy_latched := '0';
if(busy_reg = '0' AND busy = '1') then
busy_latched := '1';
end if;

case (i2c_state_reg) is
1224 markw
when i2c_state_idle =>
if (request = '1') then
i2c_state_next <= i2c_state_part1;
end if;
718 markw
when i2c_state_part1 =>
ena <= '1';
719 markw
rw <= '0';
718 markw
write_data <= write1;

if (busy_latched='1') then
i2c_state_next <= i2c_state_part2;
end if;
when i2c_state_part2 =>
ena <= '1';
719 markw
rw <= not(w2);
718 markw
write_data <= write2;

if (busy_latched='1') then
i2c_state_next <= i2c_state_part3;
end if;
when i2c_state_part3 =>
ena <= '0';
if (busy='0') then
1224 markw
i2c_state_next <= i2c_state_idle;
718 markw
op_complete <= '1';
end if;
when others =>
1224 markw
i2c_state_next <= i2c_state_idle;
718 markw
end case;

end process;


1239 markw
process(state_reg,keyboard_scan,keyboard_scan_update,keyboard_scan_update_pending_reg,busy,busy_reg,read_data,op_complete,int,keyboard_response_reg)
718 markw
begin
state_next <= state_reg;

1239 markw
keyboard_scan_enable <= '0';
1197 markw
keyboard_response_next <= keyboard_response_reg;
1239 markw
keyboard_scan_update_pending_next <= keyboard_scan_update_pending_reg or keyboard_scan_update;
726 markw
1224 markw
request <= '0';
718 markw
w2 <= '0';
write1 <= x"ff";
write2 <= x"ff";

case (state_reg) is
when state_setup1 =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
728 markw
write1 <= x"4f";
718 markw
write2 <= "00000000";
if (op_complete='1') then
state_next <= state_setup3;
end if;
when state_setup3 =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
938 markw
write1 <= x"03";
write2 <= "10000001";
718 markw
if (op_complete='1') then
state_next <= state_setup4;
end if;
when state_setup4 =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
938 markw
write1 <= x"43";
write2 <= "10000001";
718 markw
if (op_complete='1') then
state_next <= state_setup5;
end if;
when state_setup5 =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
938 markw
write1 <= x"44";
write2 <= "10000001";
718 markw
if (op_complete='1') then
726 markw
state_next <= state_setup6;
718 markw
end if;
726 markw
when state_setup6 =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
938 markw
write1 <= x"45";
write2 <= "01111110";
726 markw
if (op_complete='1') then
728 markw
state_next <= state_setup7;
end if;
when state_setup7 =>
1224 markw
request <= '1';
728 markw
w2 <= '1';
write1 <= x"4f";
938 markw
write2 <= "00000000";
728 markw
if (op_complete='1') then
726 markw
state_next <= state_kbscan;
end if;
when state_kbread =>
1224 markw
request <= '1';
718 markw
w2 <= '0';
938 markw
write1 <= x"00";
718 markw
write2 <= x"ff";
if (op_complete='1') then
1197 markw
keyboard_response_next <= read_data(0)&read_data(7);
state_next <= state_kbscan_delay;
718 markw
end if;
1197 markw
when state_kbscan_delay =>
1232 markw
if (int='0') then
state_next <= state_kbread;
end if;
1239 markw
if (keyboard_scan_update_pending_reg='1') then
keyboard_scan_update_pending_next <= '0';
keyboard_scan_enable <= '1';
1224 markw
state_next <= state_kbscan;
end if;
1197 markw

-- keyboard_scan_enable <= '1';
-- state_next <= state_kbscan;
726 markw
when state_kbscan =>
1224 markw
request <= '1';
718 markw
w2 <= '1';
938 markw
write1 <= x"01";
718 markw
-- Some pokey bits are inverted (k2,k1,k0,k5), handle FPGA side
727 markw
--write2 <= not(keyboard_scan(5))&keyboard_scan(4)&keyboard_scan(3)&not(keyboard_scan(0)&keyboard_scan(1)&keyboard_scan(2))&"00";
938 markw
write2 <= "0"&keyboard_scan(0)&keyboard_scan(1)&keyboard_scan(2)&keyboard_scan(3)&keyboard_scan(4)&keyboard_scan(5)&"0";
--v1
--p1_0 - KR2 (act low)
--p1_1 - KR1 (act low)
--p1_2 - K2 (act low)
--p1_3 - k1 (act low)
--p1_4 - k0 (act low)
--p1_5 - k3
--p1_6 - k4
--p1_7 - k5 (act low)

--v2
--P0_0,KR2,
--P0_1,K5,
--P0_2,K4
--P0_3,K3
--P0_4,K2
--P0_5,K1
--P0_6,K0
--P0_7,KR1
718 markw
if (op_complete='1') then
1232 markw
state_next <= state_kbscan_delay;
718 markw
end if;
when others =>
state_next <= state_setup1;
end case;

end process;

1197 markw
keyboard_response <= keyboard_response_reg;

718 markw
end vhdl;