📄 mouse.vhd
字号:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
ENTITY MOUSE IS
PORT( clock_48Mhz, reset : IN std_logic;
SIGNAL mouse_data : INOUT std_logic;
SIGNAL mouse_clk : INOUT std_logic;
SIGNAL left_button, right_button: OUT std_logic;
SIGNAL mouse_cursor_row : OUT std_logic_vector(9 DOWNTO 0);
SIGNAL mouse_cursor_column : OUT std_logic_vector(9 DOWNTO 0));
END MOUSE;
ARCHITECTURE behavior OF MOUSE IS
TYPE STATE_TYPE IS (INHIBIT_TRANS, LOAD_COMMAND,LOAD_COMMAND2, WAIT_OUTPUT_READY,
WAIT_CMD_ACK, INPUT_PACKETS);
-- Signals for Mouse
SIGNAL mouse_state : state_type;
SIGNAL inhibit_wait_count : std_logic_vector(10 DOWNTO 0);
SIGNAL CHARIN, CHAROUT : std_logic_vector(7 DOWNTO 0);
SIGNAL new_cursor_row, new_cursor_column : std_logic_vector(9 DOWNTO 0);
SIGNAL cursor_row, cursor_column : std_logic_vector(9 DOWNTO 0);
SIGNAL INCNT, OUTCNT, mSB_OUT : std_logic_vector(3 DOWNTO 0);
SIGNAL PACKET_COUNT : std_logic_vector(1 DOWNTO 0);
SIGNAL SHIFTIN : std_logic_vector(8 DOWNTO 0);
SIGNAL SHIFTOUT : std_logic_vector(10 DOWNTO 0);
SIGNAL PACKET_CHAR1, PACKET_CHAR2,
PACKET_CHAR3 : std_logic_vector(7 DOWNTO 0);
SIGNAL MOUSE_CLK_BUF, DATA_READY, READ_CHAR : std_logic;
SIGNAL cursor, iready_set, break, toggle_next,
output_ready, send_char, send_data : std_logic;
SIGNAL MOUSE_DATA_DIR, MOUSE_DATA_OUT, MOUSE_DATA_BUF,
MOUSE_CLK_DIR : std_logic;
SIGNAL MOUSE_CLK_FILTER : std_logic;
SIGNAL filter : std_logic_vector(7 DOWNTO 0);
SIGNAL MOUSE_CLK_RISING_EDGE : std_logic;
SIGNAL MOUSE_CLK_FALLING_EDGE : std_logic;
SIGNAL Clock_24Mhz : std_logic;
BEGIN
mouse_cursor_row <= cursor_row;
mouse_cursor_column <= cursor_column;
-- tri_state control logic for mouse data and clock lines
MOUSE_DATA <= 'Z' WHEN MOUSE_DATA_DIR = '0' ELSE MOUSE_DATA_BUF;
MOUSE_CLK <= 'Z' WHEN MOUSE_CLK_DIR = '0' ELSE MOUSE_CLK_BUF;
-- Generate slower clock for mouse state machine
PROCESS
BEGIN
WAIT UNTIL clock_48Mhz'EVENT AND clock_48Mhz = '1';
clock_24Mhz <= NOT clock_24Mhz;
END PROCESS;
-- state machine to send init command and start recv process.
PROCESS (reset, clock_24Mhz)
BEGIN
IF reset = '0' THEN
mouse_state <= INHIBIT_TRANS;
inhibit_wait_count <= conv_std_logic_vector(0,11);
SEND_DATA <= '0';
ELSIF clock_24Mhz'EVENT AND clock_24Mhz = '1' THEN
CASE mouse_state IS
-- Mouse powers up and sends self test codes, AA and 00 out before board is downloaded
-- Pull clock line low to inhibit any transmissions from mouse
-- Need at least 60usec to stop a transmission in progress
-- Note: This is perhaps optional since mouse should not be tranmitting
WHEN INHIBIT_TRANS =>
inhibit_wait_count <= inhibit_wait_count + 1;
IF inhibit_wait_count(10 DOWNTO 9) = "11" THEN
mouse_state <= LOAD_COMMAND;
END IF;
-- Enable Streaming Mode Command, F4
charout <= "11110100";
-- Pull data low to signal data available to mouse
WHEN LOAD_COMMAND =>
SEND_DATA <= '1';
mouse_state <= LOAD_COMMAND2;
WHEN LOAD_COMMAND2 =>
SEND_DATA <= '1';
mouse_state <= WAIT_OUTPUT_READY;
-- Wait for Mouse to Clock out all bits in command.
-- Command sent is F4, Enable Streaming Mode
-- This tells the mouse to start sending 3-byte packets with movement data
WHEN WAIT_OUTPUT_READY =>
SEND_DATA <= '0';
-- Output Ready signals that all data is clocked out of shift register
IF OUTPUT_READY='1' THEN
mouse_state <= WAIT_CMD_ACK;
ELSE
mouse_state <= WAIT_OUTPUT_READY;
END IF;
-- Wait for Mouse to send back Command Acknowledge, FA
WHEN WAIT_CMD_ACK =>
SEND_DATA <= '0';
IF IREADY_SET='1' THEN
mouse_state <= INPUT_PACKETS;
END IF;
-- Release clock_24Mhz and data lines and go into mouse input mode
-- Stay in this state and recieve 3-byte mouse data packets forever
-- Default rate is 100 packets per second
WHEN INPUT_PACKETS =>
mouse_state <= INPUT_PACKETS;
END CASE;
END IF;
END PROCESS;
WITH mouse_state SELECT
-- Mouse Data Tri-state control line: '1' FLEX Chip drives, '0'=Mouse Drives
MOUSE_DATA_DIR <= '0' WHEN INHIBIT_TRANS,
'0' WHEN LOAD_COMMAND,
'0' WHEN LOAD_COMMAND2,
'1' WHEN WAIT_OUTPUT_READY,
'0' WHEN WAIT_CMD_ACK,
'0' WHEN INPUT_PACKETS;
-- Mouse Clock Tri-state control line: '1' FLEX Chip drives, '0'=Mouse Drives
WITH mouse_state SELECT
MOUSE_CLK_DIR <= '1' WHEN INHIBIT_TRANS,
'1' WHEN LOAD_COMMAND,
'1' WHEN LOAD_COMMAND2,
'0' WHEN WAIT_OUTPUT_READY,
'0' WHEN WAIT_CMD_ACK,
'0' WHEN INPUT_PACKETS;
WITH mouse_state SELECT
-- Input to FLEX chip tri-state buffer mouse clock_24Mhz line
MOUSE_CLK_BUF <= '0' WHEN INHIBIT_TRANS,
'1' WHEN LOAD_COMMAND,
'1' WHEN LOAD_COMMAND2,
'1' WHEN WAIT_OUTPUT_READY,
'1' WHEN WAIT_CMD_ACK,
'1' WHEN INPUT_PACKETS;
-- filter for mouse clock
PROCESS
BEGIN
WAIT UNTIL clock_24Mhz'event and clock_24Mhz = '1';
filter(7 DOWNTO 1) <= filter(6 DOWNTO 0);
filter(0) <= MOUSE_CLK;
IF filter = "11111111" THEN
------------------ START OF MODIFICATION -----------------
IF (MOUSE_CLK_FILTER='0') THEN
MOUSE_CLK_RISING_EDGE<='1';
ELSE
MOUSE_CLK_RISING_EDGE<='0';
END IF;
------------------ END OF MODIFICATION -------------------
MOUSE_CLK_FILTER <= '1';
ELSIF filter = "00000000" THEN
------------------ START OF MODIFICATION -----------------
IF (MOUSE_CLK_FILTER='1') THEN
MOUSE_CLK_FALLING_EDGE<='1';
ELSE
MOUSE_CLK_FALLING_EDGE<='0';
END IF;
------------------ END OF MODIFICATION -------------------
MOUSE_CLK_FILTER <= '0';
END IF;
END PROCESS;
--This process sends serial data going to the mouse
SEND_UART: PROCESS (send_data, clock_24Mhz, charout)
BEGIN
IF SEND_DATA = '1' THEN
OUTCNT <= "0000";
SEND_CHAR <= '1';
OUTPUT_READY <= '0';
-- Send out Start Bit(0) + Command(F4) + Parity Bit(0) + Stop Bit(1)
SHIFTOUT(8 DOWNTO 1) <= CHAROUT ;
-- START BIT
SHIFTOUT(0) <= '0';
-- COMPUTE ODD PARITY BIT
SHIFTOUT(9) <= not (charout(7) xor charout(6) xor charout(5) xor
charout(4) xor Charout(3) xor charout(2) xor charout(1) xor
charout(0));
-- STOP BIT
SHIFTOUT(10) <= '1';
-- Data Available Flag to Mouse
-- Tells mouse to clock out command data (is also start bit)
MOUSE_DATA_BUF <= '0';
ELSIF(clock_24Mhz'event and clock_24Mhz='1') THEN
IF MOUSE_CLK_FALLING_EDGE='1' THEN
IF MOUSE_DATA_DIR='1' THEN
-- SHIFT OUT NEXT SERIAL BIT
IF SEND_CHAR = '1' THEN
-- Loop through all bits in shift register
IF OUTCNT <= "1001" THEN
OUTCNT <= OUTCNT + 1;
-- Shift out next bit to mouse
SHIFTOUT(9 DOWNTO 0) <= SHIFTOUT(10 DOWNTO 1);
SHIFTOUT(10) <= '1';
MOUSE_DATA_BUF <= SHIFTOUT(1);
OUTPUT_READY <= '0';
-- END OF CHARACTER
ELSE
SEND_CHAR <= '0';
-- Signal the character has been output
OUTPUT_READY <= '1';
OUTCNT <= "0000";
END IF;
END IF;
END IF;
END IF;
END IF;
END PROCESS SEND_UART;
RECV_UART: PROCESS(reset, clock_24Mhz)
BEGIN
IF RESET='0' THEN
INCNT <= "0000";
READ_CHAR <= '0';
PACKET_COUNT <= "00";
LEFT_BUTTON <= '0';
RIGHT_BUTTON <= '0';
CHARIN <= "00000000";
ELSIF (clock_24Mhz'event and clock_24Mhz='1') THEN
IF MOUSE_CLK_RISING_EDGE='1' THEN
IF MOUSE_DATA_DIR='0' THEN
IF MOUSE_DATA='0' AND READ_CHAR='0' THEN
READ_CHAR<= '1';
IREADY_SET<= '0';
ELSE
-- SHIFT IN NEXT SERIAL BIT
IF READ_CHAR = '1' THEN
IF INCNT < "1001" THEN
INCNT <= INCNT + 1;
SHIFTIN(7 DOWNTO 0) <= SHIFTIN(8 DOWNTO 1);
SHIFTIN(8) <= MOUSE_DATA;
IREADY_SET <= '0';
-- END OF CHARACTER
ELSE
CHARIN <= SHIFTIN(7 DOWNTO 0);
READ_CHAR <= '0';
IREADY_SET <= '1';
PACKET_COUNT <= PACKET_COUNT + 1;
-- PACKET_COUNT = "00" IS ACK COMMAND
IF PACKET_COUNT = "00" THEN
-- Set Cursor to middle of screen
cursor_column <= CONV_STD_LOGIC_VECTOR(320,10);
cursor_row <= CONV_STD_LOGIC_VECTOR(240,10);
NEW_cursor_column <= CONV_STD_LOGIC_VECTOR(320,10);
NEW_cursor_row <= CONV_STD_LOGIC_VECTOR(240,10);
ELSIF PACKET_COUNT = "01" THEN
PACKET_CHAR1 <= SHIFTIN(7 DOWNTO 0);
-- Limit Cursor on Screen Edges
-- Check for left screen limit
-- All numbers are positive only, and need to check for zero wrap around.
-- Set limits higher since mouse can move up to 128 pixels in one packet
IF (cursor_row < 128) AND ((NEW_cursor_row > 256) OR
(NEW_cursor_row < 2)) THEN
cursor_row <= CONV_STD_LOGIC_VECTOR(0,10);
-- Check for right screen limit
ELSIF NEW_cursor_row > 480 THEN
cursor_row <= CONV_STD_LOGIC_VECTOR(480,10);
ELSE
cursor_row <= NEW_cursor_row;
END IF;
-- Check for top screen limit
IF (cursor_column < 128) AND ((NEW_cursor_column > 256) OR
(NEW_cursor_column < 2)) THEN
cursor_column <= CONV_STD_LOGIC_VECTOR(0,10);
-- Check for bottom screen limit
ELSIF NEW_cursor_column > 640 THEN
cursor_column <= CONV_STD_LOGIC_VECTOR(640,10);
ELSE
cursor_column <= NEW_cursor_column;
END IF;
ELSIF PACKET_COUNT = "10" THEN
PACKET_CHAR2 <= SHIFTIN(7 DOWNTO 0);
ELSIF PACKET_COUNT = "11" THEN
PACKET_CHAR3 <= SHIFTIN(7 DOWNTO 0);
END IF;
INCNT <= conv_std_logic_vector(0,4);
IF PACKET_COUNT = "11" THEN
PACKET_COUNT <= "01";
-- Packet Complete, so process data in packet
-- Sign extend X AND Y two's complement motion values and
-- add to Current Cursor Address
--
-- Y Motion is Negative since up is a lower row address
NEW_cursor_row <= cursor_row - (PACKET_CHAR3(7) &
PACKET_CHAR3(7) & PACKET_CHAR3);
NEW_cursor_column <= cursor_column + (PACKET_CHAR2(7) &
PACKET_CHAR2(7) & PACKET_CHAR2);
LEFT_BUTTON <= PACKET_CHAR1(0);
RIGHT_BUTTON <= PACKET_CHAR1(1);
END IF;
END IF;
END IF;
END IF;
END IF;
END IF;
END IF;
END PROCESS RECV_UART;
END behavior;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -