summaryrefslogtreecommitdiffstats
path: root/lab4/KBD_ENC.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'lab4/KBD_ENC.vhd')
-rw-r--r--lab4/KBD_ENC.vhd277
1 files changed, 277 insertions, 0 deletions
diff --git a/lab4/KBD_ENC.vhd b/lab4/KBD_ENC.vhd
new file mode 100644
index 0000000..6d4a0ab
--- /dev/null
+++ b/lab4/KBD_ENC.vhd
@@ -0,0 +1,277 @@
+--------------------------------------------------------------------------------
+-- KBD ENC
+-- Anders Nilsson
+-- 16-feb-2016
+-- Version 1.1
+
+
+-- library declaration
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL; -- basic IEEE library
+use IEEE.NUMERIC_STD.ALL; -- IEEE library for the unsigned type
+ -- and various arithmetic operations
+
+-- entity
+entity KBD_ENC is
+ port ( clk : in std_logic; -- system clock (100 MHz)
+ rst : in std_logic; -- reset signal
+ PS2KeyboardCLK : in std_logic; -- USB keyboard PS2 clock
+ PS2KeyboardData : in std_logic; -- USB keyboard PS2 data
+ data : out std_logic_vector(7 downto 0); -- tile data
+ addr : out unsigned(10 downto 0); -- tile address
+ we : out std_logic); -- write enable
+end KBD_ENC;
+
+-- architecture
+architecture behavioral of KBD_ENC is
+ signal PS2Clk : std_logic; -- Synchronized PS2 clock
+ signal PS2Data : std_logic; -- Synchronized PS2 data
+ signal PS2Clk_Q1, PS2Clk_Q2 : std_logic; -- PS2 clock one pulse flip flop
+ signal PS2Clk_op : std_logic; -- PS2 clock one pulse
+
+ signal PS2Data_sr : std_logic_vector(10 downto 0);-- PS2 data shift register
+
+ signal PS2BitCounter : unsigned(3 downto 0); -- PS2 bit counter
+ signal make_Q : std_logic; -- make one pulselse flip flop
+ signal make_op : std_logic; -- make one pulse
+
+ type state_type is (IDLE, MAKE, BREAK); -- declare state types for PS2
+ signal PS2state : state_type; -- PS2 state
+
+ signal ScanCode : std_logic_vector(7 downto 0); -- scan code
+ signal TileIndex : std_logic_vector(7 downto 0); -- tile index
+
+ type curmov_type is (FORWARD, BACKWARD, NEWLINE); -- declare cursor movement types
+ signal curMovement : curmov_type; -- cursor movement
+
+ signal curposX : unsigned(5 downto 0); -- cursor X position
+ signal curposY : unsigned(4 downto 0); -- cursor Y position
+
+ type wr_type is (STANDBY, WRINDEX, WRCUR); -- declare state types for write cycle
+ signal WRstate : wr_type; -- write cycle state
+
+begin
+
+ -- Synchronize PS2-KBD signals
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ PS2Clk <= PS2KeyboardCLK;
+ PS2Data <= PS2KeyboardData;
+ end if;
+ end process;
+
+
+ -- Generate one cycle pulse from PS2 clock, negative edge
+
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst='1' then
+ PS2Clk_Q1 <= '1';
+ PS2Clk_Q2 <= '0';
+ else
+ PS2Clk_Q1 <= PS2Clk;
+ PS2Clk_Q2 <= not PS2Clk_Q1;
+ end if;
+ end if;
+ end process;
+
+ PS2Clk_op <= (not PS2Clk_Q1) and (not PS2Clk_Q2);
+
+
+
+ -- PS2 data shift register
+
+ -- ***********************************
+ -- * *
+ -- * VHDL for : *
+ -- * PS2_data_shift_reg *
+ -- * *
+ -- ***********************************
+
+
+
+
+ ScanCode <= PS2Data_sr(8 downto 1);
+
+ -- PS2 bit counter
+ -- The purpose of the PS2 bit counter is to tell the PS2 state machine when to change state
+
+ -- ***********************************
+ -- * *
+ -- * VHDL for : *
+ -- * PS2_bit_Counter *
+ -- * *
+ -- ***********************************
+
+
+
+
+ -- PS2 state
+ -- Either MAKE or BREAK state is identified from the scancode
+ -- Only single character scan codes are identified
+ -- The behavior of multiple character scan codes is undefined
+
+ -- ***********************************
+ -- * *
+ -- * VHDL for : *
+ -- * PS2_State *
+ -- * *
+ -- ***********************************
+
+
+
+
+ -- Scan Code -> Tile Index mapping
+ with ScanCode select
+ TileIndex <= x"00" when x"29", -- space
+ x"01" when x"1C", -- A
+ x"02" when x"32", -- B
+ x"03" when x"21", -- C
+ x"04" when x"23", -- D
+ x"05" when x"24", -- E
+ x"06" when x"2B", -- F
+ x"07" when x"34", -- G
+ x"08" when x"33", -- H
+ x"09" when x"43", -- I
+ x"0A" when x"3B", -- J
+ x"0B" when x"42", -- K
+ x"0C" when x"4B", -- L
+ x"0D" when x"3A", -- M
+ x"0E" when x"31", -- N
+ x"0F" when x"44", -- O
+ x"10" when x"4D", -- P
+ x"11" when x"15", -- Q
+ x"12" when x"2D", -- R
+ x"13" when x"1B", -- S
+ x"14" when x"2C", -- T
+ x"15" when x"3C", -- U
+ x"16" when x"2A", -- V
+ x"17" when x"1D", -- W
+ x"18" when x"22", -- X
+ x"19" when x"35", -- Y
+ x"1A" when x"1A", -- Z
+ x"1B" when x"54", -- Å
+ x"1C" when x"52", -- Ä
+ x"1D" when x"4C", -- Ö
+ x"00" when others;
+
+
+ -- set cursor movement based on scan code
+ with ScanCode select
+ curMovement <= NEWLINE when x"5A", -- enter scancode (5A), so move cursor to next line
+ BACKWARD when x"66", -- backspace scancode (66), so move cursor backward
+ FORWARD when others; -- for all other scancodes, move cursor forward
+
+
+ -- curposX
+ -- update cursor X position based on current cursor position (curposX and curposY) and cursor
+ -- movement (curMovement)
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst='1' then
+ curposX <= (others => '0');
+ elsif (WRstate = WRINDEX) then
+ if (curMovement = FORWARD) then
+ if (curposX = 19) then
+ curposX <= (others => '0');
+ else
+ curposX <= curposX + 1;
+ end if;
+ elsif (curMovement = BACKWARD) then
+ if ((curposX = 0) and (curposY >= 0)) then
+ curposX <= to_unsigned(19, curposX'length);
+ else
+ curposX <= curposX - 1;
+ end if;
+ elsif (curMovement = NEWLINE) then
+ curposX <= (others => '0');
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+ -- curposY
+ -- update cursor Y position based on current cursor position (curposX and curposY) and cursor
+ -- movement (curMovement)
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst='1' then
+ curposY <= (others => '0');
+ elsif (WRstate = WRINDEX) then
+ if (curMovement = FORWARD) then
+ if (curposX = 19) then
+ if (curposY = 14) then
+ curposY <= (others => '0');
+ else
+ curposY <= curposY + 1;
+ end if;
+ end if;
+ elsif (curMovement = BACKWARD) then
+ if (curposX = 0) then
+ if (curposY = 0) then
+ curposY <= to_unsigned(14, curposY'length);
+ else
+ curposY <= curposY - 1;
+ end if;
+ end if;
+ elsif (curMovement = NEWLINE) then
+ if (curposY = 14) then
+ curposY <= (others => '0');
+ else
+ curposY <= curposY + 1;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+ -- write state
+ -- every write cycle begins with writing the character tile index at the current
+ -- cursor position, then moving to the next cursor position and there write the
+ -- cursor tile index
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst='1' then
+ WRstate <= STANDBY;
+ else
+ case WRstate is
+ when STANDBY =>
+ if (PS2state = MAKE) then
+ WRstate <= WRINDEX;
+ else
+ WRstate <= STANDBY;
+ end if;
+ when WRINDEX =>
+ WRstate <= WRCUR;
+ when WRCUR =>
+ WRstate <= STANDBY;
+ when others =>
+ WRstate <= STANDBY;
+ end case;
+ end if;
+ end if;
+ end process;
+
+
+ -- we will be enabled ('1') for two consecutive clock cycles during WRINDEX and WRCUR states
+ -- and disabled ('0') otherwise at STANDBY state
+ we <= '0' when (WRstate = STANDBY) else '1';
+
+
+ -- memory address is a composite of curposY and curposX
+ -- the "to_unsigned(20, 6)" is needed to generate a correct size of the resulting unsigned vector
+ addr <= to_unsigned(20, 6)*curposY + curposX;
+
+
+ -- data output is set to be x"1F" (cursor tile index) during WRCUR state, otherwise set as scan code tile index
+ data <= x"1F" when (WRstate = WRCUR) else TileIndex;
+
+
+end behavioral;