Skocz do zawartości

Pomocna odpowiedź

Napisano (edytowany)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MOUSE is
    Port ( Clk : in  STD_LOGIC;
		   Reset : in  STD_LOGIC;
           PS2_D : inout  STD_LOGIC;
           PS2_C : inout  STD_LOGIC;
           MoWE : out  STD_LOGIC;
           B0 : out  STD_LOGIC_VECTOR (7 downto 0);
           B1 : inout  STD_LOGIC_VECTOR (7 downto 0);
           B2 : inout  STD_LOGIC_VECTOR (7 downto 0);
           B3 : inout  STD_LOGIC_VECTOR (7 downto 0)
			  );
end MOUSE;

architecture Behavioral of MOUSE is

	signal SelB : std_logic_vector (3 downto 0) ;

	signal D : std_logic_vector (9 downto 0) ;
	signal Din : std_logic_vector (7 downto 0) ;
	signal Cnt : std_logic_vector (7 downto 0) ;
	signal Cnt1 : std_logic_vector (13 downto 0) ;
	signal Clk1 : std_logic;
	
	signal PS2_Cin : std_logic;
	signal PS2_Cout : std_logic;
	signal PS2_Dout : std_logic;
	
	signal ParityGen : std_logic_vector (6 downto 0);
	signal Parity : std_logic;
	signal Init : std_logic_vector (10 downto 0) ;
	
   type PS2State_type is (idle, datain, sel, rts, we, we1, rts1, rts2, dataout); 
   signal PS2State : PS2State_type;


begin
		
		process(Clk, PS2_C)								--oczekiwanie na stabilny sygnał zegarowy od myszy
		begin
			if PS2_C = '1' then
				Cnt <= (others => '0');
				PS2_Cin <= '1';
			else
				if Clk'event and Clk = '0' then
					if PS2_C = '0' then
						if Cnt = "11111111" then
							PS2_Cin <= '0';
						else
							Cnt <= Cnt + 1;
						end if;
					end if;
				end if;
			end if;
		end process;
		
		with PS2State select
			Clk1 <= Clk when rts,
					  Clk when rts1,
					  Clk when sel,
					  Clk when we,
					  Clk when we1,
					  PS2_Cin when others;
		
		with PS2State select
	  PS2_Dout <= '0' when rts1,
					  '0' when rts2,
					  D(0) when dataout,
					  '1' when others;
		
		with PS2State select
	  PS2_Cout <= '0' when rts,
					  '0' when rts1,
					  '1' when others;
		
		process(Clk1, Reset, PS2State, PS2_D)		--wysłanie, odbieranie danych myszy w maszynie stanów
		begin
			if Reset = '0' then
				D <= "1000000000";
				Din <= "00000000";
				B0 <= "00000000";
				MoWE <= '0';
				Init <= "10000000000";
				SelB <= "1000";
				Cnt1 <= (others => '0');
				PS2State <= idle;
			else
				if Clk1'event and Clk1 = '0' then
					case PS2State is
					
					when idle =>
								D <= "1000000000";
								PS2State <= datain;
					
					when datain =>
							if D(0) = '1' then
								D <= "1000000000";
								Din <= D(8 downto 1);
								PS2State <= sel;
							else
								D <= PS2_D & D(9 downto 1);
							end if;
					
					when sel =>
							if ((Init = "10000000000") and (Din = X"00")) then --F3 C8 F3 64 F3 50 E8 00 F4
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "01000000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"C8";
								PS2State <= rts;
						elsif ((Init = "00100000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "00010000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"64";
								PS2State <= rts;
						elsif ((Init = "00001000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "00000100000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"50";
								PS2State <= rts;
						elsif ((Init = "00000010000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"E8";
								PS2State <= rts;
						elsif ((Init = "00000001000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"00";
								PS2State <= rts;
						elsif ((Init = "00000000100") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F4";
								PS2State <= rts;
						elsif ((Init = "00000000010") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								SelB <= "1000";
								PS2State <= idle;
							else
								B3 <= Din;
								B2 <= B3;
								B1 <= B2;
								B0 <= B1;
								SelB <= SelB(0) & SelB(3 downto 1);
								PS2State <= we;
							end if;
					
					when we =>
							if SelB = "1000" then
								MoWE <= '1';
							end if;
								PS2State <= we1;
					
					when we1 =>
								MoWE <= '0';
								PS2State <= idle;
					
					when rts =>	 --reqest to send
							if Cnt1 = "11111100000000" then
								Cnt1 <= (others => '0');
								PS2State <= rts1;
							else
								Cnt1 <= Cnt1 + 1;
							end if;
					
					when rts1 =>	 --reqest to send
							if Cnt1 = "00000100000000" then
								Cnt1 <= (others => '0');
								PS2State <= rts2;
							else
								Cnt1 <= Cnt1 + 1;
							end if;
							
					when rts2 =>	 --reqest to send
								D <= '1' & Parity & Din;
								PS2State <= dataout;
							
					when dataout => --przesył danych do myszy
							if D = "0000000001" then
								PS2State <= idle;
							else
								D <= '0' & D(9 downto 1);
							end if;
							
					end case;
				end if;
			end if;
		end process;
		
		ParityGen(0) <= Din(0) xor Din(1);			--generator parztstości
		ParityGen(1) <= Din(2) xor Din(3);
		ParityGen(2) <= Din(4) xor Din(5);
		ParityGen(3) <= Din(6) xor Din(7);
		ParityGen(4) <= ParityGen(0) xor ParityGen(1);
		ParityGen(5) <= ParityGen(2) xor ParityGen(3);
		ParityGen(6) <= ParityGen(4) xor ParityGen(5);
		Parity <= not ParityGen(6);
		
		PS2_C <= 'Z' when PS2_Cout = '1' else '0';	--zmiana portów komunikacyjnych myszy z wejściowych na wyjściowe
		PS2_D <= 'Z' when PS2_Dout = '1' else '0';

end Behavioral;

Witam.

Załączam kod programu obsługującego mysz intellimouse ps2. Kod pisany dla układu z generatorem 100MHz.

Mysz jest inicjowana natychmiast po włączeniu zasilania.

Kontroler czeka na pierwsze dane od myszy po podaniu napięcia na złącze ps2 i w następnej kolejności ją inicjuje.

Po zakończonym procesie odbiera dane wystawione przez mysz w postaci 4 bajtowej paczki danych zapisanych do rejestrów B0, B1, B2, B3.

B0 rejestrem stanu przycisków, kierunku przesunięcia, i przepełnienia rejestrów B1, B2.

B1 i B2 są rejestrami odległości przesunięcia w osi X i Y . Liczniki podane są w dopełnieniu do 2.

B3 jest rejestrem kółka informuje o obrocie w dwóch kierunkach X"FF" lub w przeciwnym X"01" lub braku obrotu X"00"

Dane pełnej paczki (4 bajty) sygnalizowane są wysokim stanem trwającym 10ns wystawionym na linii MoWE.

Kod jest napisany dla myszy intellimouse i z innymi nie będzie współpracować ze względu na algorytm inicjowania i wielkość danych przychodzących.

W algorytmie użyłem kod E8 i 00 co zmienia liczenie odległości z (4x na 1 milimetr przesunięcia) na (1x na 1 milimetr przesunięcia). Dzięki temu wskaźnik myszy na wyświetlaczu monitora nie przemieszcza się zbyt szybko .

Może się komuś przyda...

Pozdrawiam

Edytowano przez kroszkanorber
Poprawiony kod żródłowy
  • Lubię! 1
(edytowany)

Witam.

Obliczenia pozycji wskaźnika myszy na monitorze.

Dane o pozycji są obliczane w kodzie dla rozdzielczości VGA 640 X 480. 

Rejestry wyników działań są odpowiednio oznaczone " Mouse_pos_X" i "Mouse_pos_Y" + rejestry wejściowe trzy 8 bitowe B0, B1, B2. Rejestry Mouse_pos_  o minimalnej długości 9 bit, mogą być większe. Dla rozdzielczości 800 x 600 powinny mieć 10 bit każdy.

W kodzie uwzględniłem przypadek przesunięcia wskaźnika poza obszar wyświetlany opisany prostym dekoderem. W przypadku gdy zakres w osi X lub Y zostanie przekroczony, wskaźnik myszy zostanie ustawiony w skrajnej pozycji na monitorze w zależności od kierunku przesunięcia. (warunek spełniany w tym przypadku to rejestr X > 640 i rejestr Y > 480). Kod jest uniwersalny i można zmienić wartość warunku np: ( rejestr X > 800 i rejestr Y > 600) dla rozdzielczości VESA800X600.

Wektor rejestru osi Y otrzymywany od myszy jest przeciwny do licznika Linii . Dzieje się tak ponieważ wielkość licznika Linii wyświetlanych na monitorze się zmniejsza gdy wskaźnik przesuwamy w górę, podczas gdy rejestr myszy tą wielkość zwiększa.

W przypadku gdy przesuwamy mysz w górę lub w prawo obliczenia są proste i wystarczy do odpowiednich rejestrów dodać lub odjąć wartości wysłane przez mysz. Gdy przesuwamy mysz w lewo lub dół musimy uwzględnić kod uzupełnienia U2. 


	process(Clk, Reset, B0, B1, B2, WE)
	begin
		if Reset = '0' then
			Mouse_pos_X <= (others => '0');
			Mouse_pos_Y <= (others => '0');
		else
			if Clk'event and Clk = '0' then
				if WE = '1' then
					if (B0(4) = '0') then
						Mouse_pos_X <= (Mouse_pos_X + (B0(6) & B1));
					else
						Mouse_pos_X <= (Mouse_pos_X - ((B0(6) & (not B1)) + 1));
					end if;
					if (B0(5) = '0') then
						Mouse_pos_Y <= (Mouse_pos_Y - (B0(7) & B2));
					else
						Mouse_pos_Y <= (Mouse_pos_Y + ((B0(7) & (not B2)) + 1));
					end if;
				else
					if (B0(4) = '0') then
						if Mouse_pos_X > 639 then
							Mouse_pos_X <= "1001111111";  --639
						end if;
					else
						if Mouse_pos_X > 639 then
							Mouse_pos_X <= (others => '0');
						end if;
					end if;
					if (B0(5) = '0') then
						if Mouse_pos_Y > 479 then
							Mouse_pos_Y <= (others => '0');
						end if;
					else
						if Mouse_pos_Y > 479 then
							Mouse_pos_Y <= "0111011111"; --479
						end if;
					end if;
				end if;
			end if;
		end if;
	end process;

Pozdrawiam.

Edytowano przez kroszkanorber
  • Lubię! 1
  • 1 miesiąc później...

Witam.

Poskładałem program służący do wyświetlenia wskaźnika myszy Intellimouse na monitorze VGA 640x480. Wskaźnik jest wyświetlany pod postacią strzałki w dwóch kolorach (czarny obrys i biały środek) i wielkości 8x8 pikseli. Cały kod składa się z licznika dla wyświetlanych linii i pikseli i dekoderów synchronizacji, oraz układu odczytującego dane myszy i dekodera pozycji wskaźnika.

Kod odczytujący dane myszy komputerowej potrafi ją inicjować. Pisząc ten kod starałem się uprościć algorytm. Konsekwencją tego jest wymaganie poprawnej kolejności podłączenia zasilania. Problem w tym, że mysz powinno się podłączyć po resecie układu. W algorytmie przycisk Reset powoduje ustawienie rejestru przesuwnego Init w pozycji początkowej i po tej procedurze można podłączyć mysz do portu. W następnej kolejności mysz wysyła dane logowania do systemu, a gdy algorytm rozpozna bajt X"00" rozpoczyna inicjalizację po której mysz intellimouse powinna wysyłać dane.

Stan przycisków i kółka wyświetlany jest na 8 diodach LED od LED1 do LED8. 

Pełny kod:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity WskaznikMyszy is
    Port ( Clk : in  STD_LOGIC;
           Reset : in  STD_LOGIC;
           PS2_D : inout  STD_LOGIC;
           PS2_C : inout  STD_LOGIC;
           LED1 : out  STD_LOGIC;
           LED2 : out  STD_LOGIC;
           LED3 : out  STD_LOGIC;
           LED4 : out  STD_LOGIC;
           LED5 : out  STD_LOGIC;
           LED6 : out  STD_LOGIC;
           LED7 : out  STD_LOGIC;
           LED8 : out  STD_LOGIC;
           HS : out  STD_LOGIC;
           VS : out  STD_LOGIC;
           RGB : out  STD_LOGIC_VECTOR(7 downto 0)
			  );
end WskaznikMyszy;

architecture Behavioral of WskaznikMyszy is

------------------------------------------------------------------------------
	signal SelB : std_logic_vector (3 downto 0) ;
	
	signal B0 : std_logic_vector (7 downto 0) ;
	signal B1 : std_logic_vector (7 downto 0) ;
	signal B2 : std_logic_vector (7 downto 0) ;
	signal B3 : std_logic_vector (7 downto 0) ;
	
	signal MoWE : std_logic;

	signal D : std_logic_vector (9 downto 0) ;
	signal Din : std_logic_vector (7 downto 0) ;
	signal Cnt : std_logic_vector (7 downto 0) ;
	signal Cnt1 : std_logic_vector (13 downto 0) ;
	signal Clk1 : std_logic;
	
	signal PS2_Cin : std_logic;
	signal PS2_Cout : std_logic;
	signal PS2_Dout : std_logic;
	
	signal ParityGen : std_logic_vector (6 downto 0);
	signal Parity : std_logic;
	signal Init : std_logic_vector (10 downto 0) ;
	
   type PS2State_type is (idle, datain, sel, rts, we, we1, rts1, rts2, dataout); 
   signal PS2State : PS2State_type;
------------------------------------------------------------------------------
	signal EnH : std_logic ;
	signal EnV : std_logic ;
	signal CntH1 : std_logic_vector (3 downto 0) ;
	signal CntV1 : std_logic_vector (3 downto 0) ;
	signal Mouse_pos_X : std_logic_vector (9 downto 0) ;
	signal Mouse_pos_Y : std_logic_vector (9 downto 0) ;
	signal Wskaznik : std_logic_vector (1 downto 0) ;
------------------------------------------------------------------------------
	signal CntH : std_logic_vector (9 downto 0) ;
	signal CntV : std_logic_vector (9 downto 0) ;
	signal Cnt25 : std_logic_vector (1 downto 0) ;
	signal BL : std_logic ;
------------------------------------------------------------------------------
	
begin

------------------------------------------------------------------------------
	process(MoWE, Clk, B0, B3, Reset)
	begin
		if Reset = '0' then
			LED1 <= '0';
			LED2 <= '0';
			LED3 <= '0';
			LED4 <= '0';
			LED5 <= '0';
			LED6 <= '0';
			LED7 <= '0';
			LED8 <= '0';
		else
			if Clk'event and Clk = '0' then
				if MoWE = '1' then
					LED1 <= B0(0);
					LED2 <= B0(1);
					LED3 <= B0(2);
					LED4 <= B0(3);
					LED5 <= B3(0);
					LED6 <= B3(1);
					LED7 <= B3(2);
					LED8 <= B3(3);
				end if;
			end if;
		end if;
	end process;
------------------------------------------------------------------------------
	process(Clk)
	begin
		if Clk'event and Clk = '0' then
			Cnt25 <= Cnt25 + 1;					--dzielnik częstotliwości
			if Cnt25 = "11" then
				if CntH = 799 then				--licznik pixeli
					CntH <= (others => '0');
				else
					CntH <= CntH + 1;
				end if;
				if CntH = 799 then
					if CntV = 524 then			--licznik linji
						CntV <= (others => '0');
					else
						CntV <= CntV + 1;
					end if;
				end if;
			end if;
		end if;
	end process;
	
	BL <= '1' when ((CntH < 640) and (CntV < 525)) else '0'; --dekoder obszaru obrazy wyświetlanego (aktywny = 1)
	HS <= '0' when ((CntH > 655) and (CntH < 753)) else '1'; --dekoder synchronizacji poziomej (aktywny = 0)
	VS <= '0' when ((CntV > 488) and (CntV < 491)) else '1'; --dekoder synchronizacji pionowej (aktywny = 0)
					
	process(Clk, Cnt25, BL, Wskaznik)
	begin
		if BL = '0' then
			RGB <= (others => '0');
		else
			if Clk'event and Clk = '0' then
				if Cnt25 = "01" then
					if Wskaznik = "10" then
						RGB <= (others => '0');
					elsif Wskaznik = "01" then
						RGB <= (others => '1');
					else
						RGB <= "01001000";
					end if;
				end if;
			end if;
		end if;
	end process;
------------------------------------------------------------------------------
		process(Clk, PS2_C)								--oczekiwanie na stabilny sygnał zegarowy od myszy
		begin
			if PS2_C = '1' then
				Cnt <= (others => '0');
				PS2_Cin <= '1';
			else
				if Clk'event and Clk = '0' then
					if PS2_C = '0' then
						if Cnt = "11111111" then
							PS2_Cin <= '0';
						else
							Cnt <= Cnt + 1;
						end if;
					end if;
				end if;
			end if;
		end process;
		
		with PS2State select
			Clk1 <= Clk when rts,
					  Clk when rts1,
					  Clk when sel,
					  Clk when we,
					  Clk when we1,
					  PS2_Cin when others;
		
		with PS2State select
	  PS2_Dout <= '0' when rts1,
					  '0' when rts2,
					  D(0) when dataout,
					  '1' when others;
		
		with PS2State select
	  PS2_Cout <= '0' when rts,
					  '0' when rts1,
					  '1' when others;
		
		process(Clk1, Reset, PS2State, PS2_D)		--wysłanie, odbieranie danych myszy w maszynie stanów
		begin
			if Reset = '0' then
				D <= "1000000000";
				Din <= "00000000";
				B0 <= "00000000";
				MoWE <= '0';
				Init <= "10000000000";
				SelB <= "1000";
				Cnt1 <= (others => '0');
				PS2State <= idle;
			else
				if Clk1'event and Clk1 = '0' then
					case PS2State is
					
					when idle =>
								D <= "1000000000";
								PS2State <= datain;
					
					when datain =>
							if D(0) = '1' then
								D <= "1000000000";
								Din <= D(8 downto 1);
								PS2State <= sel;
							else
								D <= PS2_D & D(9 downto 1);
							end if;
					
					when sel =>
							if ((Init = "10000000000") and (Din = X"00")) then --F3 C8 F3 64 F3 50 E8 00 F4
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "01000000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"C8";
								PS2State <= rts;
						elsif ((Init = "00100000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "00010000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"64";
								PS2State <= rts;
						elsif ((Init = "00001000000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F3";
								PS2State <= rts;
						elsif ((Init = "00000100000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"50";
								PS2State <= rts;
						elsif ((Init = "00000010000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"E8";
								PS2State <= rts;
						elsif ((Init = "00000001000") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"00";
								PS2State <= rts;
						elsif ((Init = "00000000100") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								Din <= X"F4";
								PS2State <= rts;
						elsif ((Init = "00000000010") and (Din = X"FA")) then
								Init <= Init(0) & Init(10 downto 1);
								SelB <= "1000";
								PS2State <= idle;
							else
								B3 <= Din;
								B2 <= B3;
								B1 <= B2;
								B0 <= B1;
								SelB <= SelB(0) & SelB(3 downto 1);
								PS2State <= we;
							end if;
					
					when we =>
							if SelB = "1000" then
								MoWE <= '1';
							end if;
								PS2State <= we1;
					
					when we1 =>
								MoWE <= '0';
								PS2State <= idle;
					
					when rts =>	 --reqest to send
							if Cnt1 = "11111100000000" then
								Cnt1 <= (others => '0');
								PS2State <= rts1;
							else
								Cnt1 <= Cnt1 + 1;
							end if;
					
					when rts1 =>	 --reqest to send
							if Cnt1 = "00000100000000" then
								Cnt1 <= (others => '0');
								PS2State <= rts2;
							else
								Cnt1 <= Cnt1 + 1;
							end if;
							
					when rts2 =>	 --reqest to send
								D <= '1' & Parity & Din;
								PS2State <= dataout;
							
					when dataout => --przesył danych do myszy
							if D = "0000000001" then
								PS2State <= idle;
							else
								D <= '0' & D(9 downto 1);
							end if;
							
					end case;
				end if;
			end if;
		end process;
		
		ParityGen(0) <= Din(0) xor Din(1);			--generator parztstości
		ParityGen(1) <= Din(2) xor Din(3);
		ParityGen(2) <= Din(4) xor Din(5);
		ParityGen(3) <= Din(6) xor Din(7);
		ParityGen(4) <= ParityGen(0) xor ParityGen(1);
		ParityGen(5) <= ParityGen(2) xor ParityGen(3);
		ParityGen(6) <= ParityGen(4) xor ParityGen(5);
		Parity <= not ParityGen(6);
		
		PS2_C <= 'Z' when PS2_Cout = '1' else '0';	--zmiana portów komunikacyjnych myszy z wejściowych na wyjściowe
		PS2_D <= 'Z' when PS2_Dout = '1' else '0';
------------------------------------------------------------------------------
	process(Clk, Reset, B0, B1, B2, MoWE)				--zmiana pozycji wskaźnika myszy
	begin
		if Reset = '0' then
			Mouse_pos_X <= "0101000000";
			Mouse_pos_Y <= "0011110000";
		else
			if Clk'event and Clk = '0' then
				if MoWE = '1' then
					if (B0(4) = '0') then
						Mouse_pos_X <= (Mouse_pos_X + (B0(6) & B1));
					else
						Mouse_pos_X <= (Mouse_pos_X - ((B0(6) & (not B1)) + 1));
					end if;
					if (B0(5) = '0') then
						Mouse_pos_Y <= (Mouse_pos_Y - (B0(7) & B2));
					else
						Mouse_pos_Y <= (Mouse_pos_Y + ((B0(7) & (not B2)) + 1));
					end if;
				else
					if (B0(4) = '0') then
						if Mouse_pos_X > 639 then
							Mouse_pos_X <= "1001111111";  --639
						end if;
					else
						if Mouse_pos_X > 639 then
							Mouse_pos_X <= (others => '0');
						end if;
					end if;
					if (B0(5) = '0') then
						if Mouse_pos_Y > 479 then
							Mouse_pos_Y <= (others => '0');
						end if;
					else
						if Mouse_pos_Y > 479 then
							Mouse_pos_Y <= "0111011111"; --479
						end if;
					end if;
				end if;
			end if;
		end if;
	end process;
------------------------------------------------------------------------------------------
	EnH <= '1' when ((CntH = Mouse_pos_X) and (Cnt25 = "01")) else '0';  --dekoder wskaźnika myszy
	EnV <= '1' when CntV = Mouse_pos_Y else '0';
	
	process(Clk, Cnt25, Reset, EnH)
	begin
		if Reset = '0' then
			CntH1 <= "1000";
		elsif EnH = '1' then
			CntH1 <= "0000";
		else
			if Clk'event and CLk = '0' then
				if Cnt25 = "11" then
					if CntH1 = "1001" then
						null;
					else
						CntH1 <= CntH1 + 1;
					end if;
				end if;
			end if;
		end if;
	end process;
	
	process(Clk, Reset, Cnt25, CntH1, EnV, EnH)
	begin
		if Reset = '0' then
			CntV1 <= "1000";
		elsif ((EnV = '1') and (EnH = '1')) then
			CntV1 <= "0000";
		else
			if Clk'event and CLk = '0' then
				if Cnt25 = "11" then
					if CntH1 = "1000" then
						if CntV1 = "1000" then
							null;
						else
							CntV1 <= CntV1 + 1;
						end if;
					end if;
				end if;
			end if;
		end if;
	end process;
-- C = Czarny kolor    B = Biały kolor
--   0 1 2 3 4 5 6 7
-- 0 C C C C C C C 0
-- 1 C B B B B C 0 0
-- 2 C B B B C 0 0 0
-- 3 C B B B B C 0 0
-- 4 C B C B B B C 0
-- 5 C C 0 C B B B C
-- 6 C 0 0 0 C B C 0
-- 7 0 0 0 0 0 C 0 0
	
	with (CntV1 & CntH1) select
	Wskaznik <= "10" when "00000000", --0
					"10" when "00000001",
					"10" when "00000010",
					"10" when "00000011",
					"10" when "00000100",
					"10" when "00000101",
					"10" when "00000110",
					
					"10" when "00010000", --1
					"01" when "00010001",
					"01" when "00010010",
					"01" when "00010011",
					"01" when "00010100",
					"10" when "00010101",
					
					"10" when "00100000", --2
					"01" when "00100001",
					"01" when "00100010",
					"01" when "00100011",
					"10" when "00100100",
					
					"10" when "00110000", --3
					"01" when "00110001",
					"01" when "00110010",
					"01" when "00110011",
					"01" when "00110100",
					"10" when "00110101",
					
					"10" when "01000000", --4
					"01" when "01000001",
					"10" when "01000010",
					"01" when "01000011",
					"01" when "01000100",
					"01" when "01000101",
					"10" when "01000110",
					
					"10" when "01010000", --5
					"10" when "01010001",
					"00" when "01010010",
					"10" when "01010011",
					"01" when "01010100",
					"01" when "01010101",
					"01" when "01010110",
					"10" when "01010111",
					
					"10" when "01100000", --6
					"10" when "01100100",
					"01" when "01100101",
					"10" when "01100110",
					
					"10" when "01110101", --7
					
					"00" when others;


end Behavioral;

Film z działającego programu:

https://youtube.com/shorts/-cqwtUyaPlM?feature=share

  • Lubię! 2
  • 2 lat(a) później...

Witam. Wracając do kodu z poprzedniego wpisu analizowałem zmianą pozycji myszy. Moja niewiedza o zastosowaniu praktycznym liczb u2 i przepełnieniu overflow jest w tym kodzie nie do niezauważenia.

Moja interpretacja danych przychodzących od myszy jest w wyżej załączonym kodzie błędna w założeniach:

1. W bajcie danych B0 bit 7 i 6 to flagi OV, a bit 5 i 4 informuje o znaku liczby.

2. Mamy zakres +-255 co składa się z 1 bit znaku i 8 bit danych, co daje wynik 9 bitów. Problemem jest jak te 9 bitów dodać do 10 bitowego licznika kolumn lub wierszy. Rozwiązanie jest proste, wystarczy rozszerzyć bit znaku do 10 bitów co oznacza jego powielenie o brakujące bity. X_OFFSET <= B0(4) & B0(4) & B1); Y_OFFSET <= B0(5) & B0(5) & B2);

3. Overvlow (przepełnienie) oznacza tyle co wyjście licznika poza zakres liczb które mogą być eksponowane w postaci liczby w punkcie 2. W kodzie powinno się użyć tej flagi by nie liczyć liczb które są błędną wartością lub precyzyjniej których nie można przedstawić fizycznie.

4. Właściwe wyliczenie przesunięć kursora myszy:
    Książkowo:
    X_OFFSET <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => B0(4));
    Y_OFFSET <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => B0(5));
    Moja walidacja i przypisanie 0 generuje mniej połączeń a wynik jest taki sam:
    X_OFFSET <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
    Y_OFFSET <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');

5. Negacja liczby w Y_OFFSET jest spowodowana odwrotnym naliczaniem kierunku w osi Y względem inkrementacji licznika wierszy w moim kodzie. oczywiście można odwrócić liczby w osi wierszy dla VGA i zmiana liczby wtedy nie musi zachodzić ale dla reszty użądzeń połaczonych do tego wyświetlacza jest taka zmiana niezasadna, więc zostawiam tą wersję.

6. Kod sterujący pozycją wskaźnika myszy:

	-- rozszerzenie liczby u2 i wykrywanie przepełnienia
	X_OFFSET <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
	Y_OFFSET <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');

	process(Clk, Rst)
	begin
		if Rst = '0' then
			MOUSE_X <= (others => '0');
			MOUSE_Y <= (others => '0');
		else
			if rising_edge(Clk) then
				if WE = '1' then
						MOUSE_X <= Mouse_pos_X + X_OFFSET;
						MOUSE_Y <= Mouse_pos_Y + Y_OFFSET;
				else
					if (B0(4) = '0') then
						if MOUSE_X > 639 then
							MOUSE_X <= "1001111111";  --639
						end if;
					else
						if MOUSE_X > 639 then
							MOUSE_X <= (others => '0');
						end if;
					end if;
					if (B0(5) = '0') then
						if MOUSE_Y > 479 then
							MOUSE_Y <= (others => '0');
						end if;
					else
						if MOUSE_Y > 479 then
							MOUSE_Y <= "0111011111"; --479
						end if;
					end if;
				end if;
			end if;
		end if;
	end process;

 

  • 2 miesiące później...

Witam.

Analizując kod z poprzedniego wpisu zauważyłem, że fragment odpowiedzialny za ograniczenia pozycji kursora można uprościć. W pierwotnej wersji porównanie do stałej wartości (639 lub 479) występowało wielokrotnie, co powodowało zagnieżdżenie warunków if i generowało dodatkowe połączenia w układzie FPGA.

Oryginalny fragment kodu:

if (B0(4) = '0') then
    if MOUSE_X > 639 then
        MOUSE_X <= "1001111111"; --639
    end if;
else
    if MOUSE_X > 639 then
        MOUSE_X <= (others => '0');
    end if;
end if;

if (B0(5) = '0') then
    if MOUSE_Y > 479 then
        MOUSE_Y <= (others => '0');
    end if;
else
    if MOUSE_Y > 479 then
        MOUSE_Y <= "0111011111"; --479
    end if;
end if;

W powyższym kodzie warunki MOUSE_X > 639 oraz MOUSE_Y > 479 są sprawdzane dwukrotnie, co zwiększa liczbę LUT‑ów i złożoność logiki.

Uproszczona wersja kodu:

-- rozszerzenie liczby u2 + obsługa overflow
X_OFFSET <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
Y_OFFSET <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');

process(Clk, Rst)
begin
    if Rst = '0' then
        MOUSE_X <= (others => '0');
        MOUSE_Y <= (others => '0');

    elsif rising_edge(Clk) then

        if WE = '1' then
            -- aktualizacja pozycji
            MOUSE_X <= MOUSE_X + X_OFFSET;
            MOUSE_Y <= MOUSE_Y + Y_OFFSET;

        else
            -- ograniczenia X
            if MOUSE_X > 639 then
                if B0(4) = '0' then
                    MOUSE_X <= "1001111111";  -- 639
                else
                    MOUSE_X <= (others => '0');
                end if;
            end if;

            -- ograniczenia Y
            if MOUSE_Y > 479 then
                if B0(5) = '0' then
                    MOUSE_Y <= (others => '0');
                else
                    MOUSE_Y <= "0111011111";  -- 479
                end if;
            end if;

        end if;
    end if;
end process;

W nowej wersji:

  1. warunek przekroczenia granicy jest sprawdzany tylko raz,
  2. zagnieżdżenia if/else zostały zredukowane,
  3. logika jest prostsza i bardziej czytelna,
  4. synteza generuje mniej połączeń i mniej LUT‑ów,
  5. funkcjonalnie kod działa identycznie jak wcześniej.

To jest mała optymalizacja, ale w FPGA takie rzeczy mają znaczenie. Każdy dodatkowy warunek if/else generuje kolejne poziomy logiki, co zwiększa liczbę LUT‑ów i wydłuża ścieżki routingu. A to właśnie routing — nie sama logika — najczęściej ogranicza maksymalną częstotliwość pracy układu. Uproszczenie warunków zmniejsza więc zarówno złożoność połączeń, jak i opóźnienia propagacji sygnałów.

(edytowany)

Witam

Wprowadziłem parę poprawek w kodzie wskaźnika myszy który podałem wcześniej.


Najważniejszą zmianą jest aktywacja myszy. Zmiana polega na tym , że aktywacja obejmuje wszystkie typy myszy (standard, intellimouse, explorer), które różnią się ilością przycisków i dodatkowym kółkiem. 

To jest pełna sekwencja aktywacji wszystkich myszy:

  1. E8 00 → Explorer
  2. F3 C8 → Explorer, IntelliMouse
  3. F3 64
  4. F3 50

Po tej sekwencji:

  1. zwykła mysz =  ID=00 (Wysyła po aktywacji 3 bajty) 
  2. IntelliMouse = ID=03  (Wysyła po aktywacji 4 bajty) 
  3. Explorer = ID=04         (Wysyła po aktywacji 4 bajty) 

Odczyt ID robimy za pomocą polecenia F2. Po F4 mysz zaczyna wysyłać pakiety ruchu i i dane o stanie przycisków wraz z kółkiem.

Druga zmiana dotyczy synchronizacji zegara systemowego z zegarem myszy. Zastosowałem rejestr przesuwający 8 bit z wejściem zegarowym myszy i taktowany zegarem systemowym. Mój zegar systemowy (Clk) = 100MHz , a  PS2_Cin rozpoznaje opadające zbocze linii PS2_C po czasie 80 ns. To gwarantuje, że po tym czasie, sygnał zegarowy myszy jest stabilny.

Trzecia zmiana w kodzie jest wymuszona różną ilością pakietów dla danego typu myszy i dotyczy 4 bajtowego rejestru FIFO (B3, B2, B1, B0). Modyfikacja polega na kopiowaniu danych by po skończonej transmisji pierwszy bajt trafiał do B0 zależnie od ilości bajtów wysyłanych w paczce danych. dodatkowa modyfikacja dotyczy sygnału zakończonej transmisji (MoWe).

W poprawionym kodzie  mysz inicjuje się po włączeniu zasilania, lub po sygnale Reset = 0. Czyli mysz można aktywować w dowolnym sposobem.

Kod obsługujący mysz PS2:

   -- synchronizacja zegara myszy z zegarem systemowym
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt <= PS2_C & Cnt(7 downto 1);
      end if;
   end process;
      
   PS2_Cin <= '1' when (Cnt = 1) else '0';
      
   --wysłanie, odbieranie danych myszy w maszynie stanów
   process(Clk, Reset)		
   begin
      if Reset = '0' then
            D <= "1000000000";
            Din <= "00000000";
            B0 <= "00000000";
            MoWE <= '0';
            Init <= "0000";
            SelB <= "1111";
            Cnt1 <= (others => '0');
            StandardMouse <= '0';
            IntelliMouse <= '0';
            ExplorerMouse <= '0';
            PS2State <= sel;
      elsif rising_edge(Clk) then
         case PS2State is
         -- oczekiwanie na bit start (takt 1)
         when idle =>
            if PS2_Cin = '1' then
               D <= "1000000000";
               PS2State <= datain;
            end if;
         -- zapis danych z portu PS2_D
         when datain =>
            if PS2_Cin = '1' then
               if D(0) = '1' then -- bitu stop powoduje przejście do następnego stanu (takt 11)
                  D <= "1000000000";
                  Din <= D(8 downto 1);
                  PS2State <= sel;
               else
                  D <= PS2_D & D(9 downto 1); -- (takt 2,3,4,5,6,7,8,9,10) 
               end if;
            end if;

         when sel =>
            if (Init = 0) then -- reset myszy
               Init <= Init + 1;
               Din <= X"FF";
               PS2State <= rts;
            elsif ((Init = 1) and (Din = X"00")) then -- (sekwencja pełnej aktywacji wszystkich myszy
               Init <= Init + 1;                      --  E8 00 F3 C8 F3 64 F3 50 F4)
               Din <= X"E8"; -- aktywacja trybu Explorer
               PS2State <= rts;
            elsif ((Init = 2) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"00";
               PS2State <= rts;
            elsif ((Init = 3) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3"; -- aktywacja trybu IntelliMouse
               PS2State <= rts;
            elsif ((Init = 4) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"C8";
               PS2State <= rts;
            elsif ((Init = 5) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 6) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"64";
               PS2State <= rts;
            elsif ((Init = 7) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 8) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"50";
               PS2State <= rts;
            elsif ((Init = 9) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F2"; -- odczyt ID myszy
               PS2State <= rts;
            elsif (Init = 10) then
               if (Din = X"00") then -- ID StandardMouse
                  Init <= Init + 1;
                  StandardMouse <= '1';
               elsif (Din = X"03") then -- ID Intellimouse
                  Init <= Init + 1;
                  IntelliMouse <= '1';
               elsif (Din = X"04") then -- ID ExplorerMouse
                  Init <= Init + 1;
                  ExplorerMouse <= '1';
               else
                  PS2State <= idle;
               end if;
            elsif (Init = 11) then
               Init <= Init + 1;
               Din <= X"F4"; -- włączenie raportowania
               PS2State <= rts;
            elsif ((Init = 12) and (Din = X"FA")) then
               Init <= Init + 1;
               SelB <= "1111";
               PS2State <= idle;
            else
               SelB <= '0' & SelB(3 downto 1);
               if (StandardMouse = '1') then -- 1=0111 / 2= 0011 / 3=0001
                  B2 <= Din;
               else                          -- 1=0111 / 2= 0011 / 3=0001 / 4=0000
                  B3 <= Din;
                  B2 <= B3;
               end if;
               B1 <= B2;
               B0 <= B1;
               PS2State <= we;
            end if;

         when we =>
            if (((SelB(1) = '0') and (StandardMouse = '1')) or (SelB(0) = '0')) then
               SelB <= "1111";
               MoWE <= '1';
            end if;
            PS2State <= we1;

         when we1 =>
            MoWE <= '0';
            PS2State <= idle;

         when rts =>	    -- reqest to send
            if Cnt1 = "11111100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts1;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts1 =>	 -- reqest to send
            if Cnt1 = "00000100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts2;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts2 =>	 -- reqest to send
            if PS2_Cin = '1' then
               D <= '1' & Parity & Din;
               PS2State <= dataout;
            end if;

         when dataout => --wysyłanie danych do myszy
            if PS2_Cin = '1' then
               if D = "0000000001" then
                  PS2State <= idle;
               else
                  D <= '0' & D(9 downto 1);
               end if;
            end if;

         end case;
      end if;
   end process;

   --generator parzystości		
   ParityGen(0) <= Din(0) xor Din(1);
   ParityGen(1) <= Din(2) xor Din(3);
   ParityGen(2) <= Din(4) xor Din(5);
   ParityGen(3) <= Din(6) xor Din(7);
   ParityGen(4) <= ParityGen(0) xor ParityGen(1);
   ParityGen(5) <= ParityGen(2) xor ParityGen(3);
   ParityGen(6) <= ParityGen(4) xor ParityGen(5);
   Parity <= not ParityGen(6);
		
   -- sterowanie portem danych myszy
   with PS2State select
  PS2_Dout <= '0' when rts1,
              '0' when rts2,
              D(0) when dataout,
              '1' when others;
		
   -- sterowanie portem zegara myszy
   with PS2State select
  PS2_Cout <= '0' when rts,
              '0' when rts1,
              '1' when others;
              
   -- obsługa portów komunikacyjnych               
   PS2_C <= 'Z' when PS2_Cout = '1' else '0';
   PS2_D <= 'Z' when PS2_Dout = '1' else '0';

Następna zmiana dotyczy dekodera wskaźnika myszy (strzałka). Usunąłem z kodu jeden licznik i uprościłem trigger. Zamiast jednego licznika zrobiłem dwa rejestry przesuwające Wb i Wc, które ładowane są równolegle w procesie (case) wyboru aktualnego wiersza. W ten sposób ładuje obraz wybranej linii i wysyłam go przesuwając rejestr w lewo aż będzie pusty, następnie czekam na kolejny wiersz i powtarzam sekwencję do końca obrazu wskaźnika. Dodatkowo użyłem dekoder końca linii (EndLine) który steruje przełączaniem licznika wierszy. Proces wyświetlania wskaźnika jest zsynchronizowany z wyświetlanym obrazem Zapis obrazu do wyjścia VGA (RGB) jest w czwartym takcie periody, a pobranie danych do rejestrów przesuwających w 3 takcie periody.

Kod obsługujący wskaźnik myszy:

   --dekoder wskaźnika myszy
   
   -- C = Czarny kolor    B = Biały kolor
   --   0 1 2 3 4 5 6 7
   -- 0 C C C C C C C 0
   -- 1 C B B B B C 0 0
   -- 2 C B B B C 0 0 0
   -- 3 C B B B B C 0 0
   -- 4 C B C B B B C 0
   -- 5 C C 0 C B B B C
   -- 6 C 0 0 0 C B C 0
   -- 7 0 0 0 0 0 C 0 0
  
   -- dekodery sygnałów triggera startu rysowania
	EnH <= '1' when CntH = Mouse_pos_X else '0';
	EnV <= '1' when CntV = Mouse_pos_Y else '0';
	
   -- licznikiem wierszy wskaźnika myszy
	process(Clk, Reset)
	begin
		if Reset = '0' then
         CntV1 <= "1000";
		elsif rising_edge(Clk) then
         if ((EnV = '1') and (EnH = '1')) then
            CntV1 <= "0000";
         elsif ((Cnt25 = "11") and (EndLine = '1')) then
            if CntV1 = "1000" then
               null;
            else
               CntV1 <= CntV1 + 1;
            end if;
         end if;
		end if;
	end process;

   -- zapis danych dla wybranego wiersza wiersza
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "10" then
            if ((EnH = '1') and (CntV1(3) = '0')) then
               case CntV1(2 downto 0) is        -- licznik wierszy wskaźnika
               when "000"  => Wc <= "11111110"; -- czarny obrys wskaźnika
                              Wb <= "0000000";  -- białe wypełnienie wskaźnika
               when "001"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "010"  => Wc <= "10001000";
                              Wb <= "0111000";
               when "011"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "100"  => Wc <= "10100010";
                              Wb <= "0101110";
               when "101"  => Wc <= "11010001";
                              Wb <= "0000111";
               when "110"  => Wc <= "10001010";
                              Wb <= "0000010";
               when others => Wc <= "00000100";
                              Wb <= "0000000";
               end case;
            elsif Wc /= 0 then
               Wc <= Wc(6 downto 0) & '0'; -- rejestr przesuwany w lewo
               Wb <= Wb(5 downto 0) & '0';
            end if;
         end if;
      end if;
   end process;
   
   WskaznikRGB <= "11111111" and (7 downto 0 => Wb(6)); 
   WskaznikEn <= Wc(7) or Wb(6); -- zezwolenie na wyświetlanie

Kolejną zmianą jest aktualizacja pozycji wskaźnika myszy, którą opisałem w poprzedniej wiadomości.

Kod aktualizacji pozycji wskaźnika myszy:

   --zmiana pozycji wskaźnika myszy
   
   -- rozszerzenie liczby u2 + obsługa overflow
   X_Offset <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
   Y_Offset <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');

   process(Clk, Reset)
   begin
      if Reset = '0' then
         Mouse_pos_X <= (others => '0');
         Mouse_pos_Y <= (others => '0');

      elsif rising_edge(Clk) then

         if MoWE = '1' then
            -- aktualizacja pozycji
            Mouse_pos_X <= Mouse_pos_X + X_Offset;
            Mouse_pos_Y <= Mouse_pos_Y + Y_Offset;

         else
         -- ograniczenia X
         if Mouse_pos_X > 639 then
            if B0(4) = '0' then
               Mouse_pos_X <= "1001111111";  -- 639
            else
               Mouse_pos_X <= (others => '0');
            end if;
         end if;

         -- ograniczenia Y
         if Mouse_pos_Y > 479 then
            if B0(5) = '0' then
               Mouse_pos_Y <= (others => '0');
            else
               Mouse_pos_Y <= "0111011111";  -- 479
            end if;
         end if;

        end if;
      end if;
   end process;

Kolejne zmiany dotyczą obsługi kontrolera VGA. Dekodery synchronizacji VS i HS opisałem jako oddzielne rejestry 1 bitowe. Rejestry te zatrzaskiwane są w 4 takcie periody tak jak liczniki CntH i CntV. Po tej zmianie obraz jest wyraźniejszy (poprzednia wersja kodu powodowała, że obraz był delikatnie rozmyty) w sensie poprawiła się ostrość. Zadbałem o to by wszystkie sygnały ważne dla wyświetlanego obrazu zostały zmieniane w 4 takcie. Cnt25 jest licznikem 2 bitowym i liczy do 4. Pixel Clock zgodny ze standardem VGA (640 x 480) => 100MHz / 4 = 25MHz.

Kod kontrolera VGA:

   -- kontroler VGA
   
   -- liczniki VGA
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt25 <= Cnt25 + 1 --dzielnik częstotliwości
         if Cnt25 = "11" then
            if CntH = 799 then --licznik kolumn
               CntH <= (others => '0');
            else
               CntH <= CntH + 1;
            end if;
            if CntH = 799 then
               if CntV = 524 then --licznik wierszy
                  CntV <= (others => '0');
               else
                  CntV <= CntV + 1;
               end if;
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji poziomej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 655 then
               HS <= '0';
            elsif CntH = 751 then
               HS <= '1';
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji pionowej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntV = 488 then
               VS <= '0';
            elsif CntV = 489 then
               VS <= '1';
            end if;
         end if;
      end if;
   end process;
   
   -- dekoder końca Linii
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 639 then
               Endline <= '1';
            else
               EndLine <= '0';
            end if;
         end if;
      end if;
   end process;
   
   -- dekoder obszaru obrazu wyświetlanego (aktywny = 1)
	BL <= '1' when ((CntH < 640) and (CntV < 480)) else '0'; 
	
   -- zapis wybranego koloru piksela do wyjścia RGB-VGA
   process(Clk, BL)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if BL = '0' then
               RGB <= (others => '0');
            elsif WskaznikEn = '1' then
               RGB <= WskaznikRGB;
            else
               RGB <= "10100000";
            end if;
         end if;
      end if;
   end process;

Ostania zmiana to dekoder dodatkowych przycisków myszy. Zdekodowane sygnały podłączyłem do 8 diod LED w celu weryfikacji działania kodu.

Kod dekodera przycisków myszy:

 -- przypisanie zdekodowanych przycisków myszy do wyjść LED
   process(Clk, Reset)
   begin
      if Reset = '0' then
         LED1 <= '0';
         LED2 <= '0';
         LED3 <= '0';
         LED4 <= '0';
         LED5 <= '0';
         LED6 <= '0';
         LED7 <= '0';
         LED8 <= '0';
      elsif rising_edge(Clk) then
         if MoWE = '1' then
            LED1 <= R_Button;
            LED2 <= M_Button;
            LED3 <= L_Button;
            LED4 <= B_Button;
            LED5 <= F_Button;
            LED6 <= U_Wheel;
            LED7 <= D_Wheel;
            LED8 <= B0(3);
         end if;
      end if;
   end process;
   
   L_Button <= B0(0);
   R_Button <= B0(1);
   M_Button <= B0(2);
   B_Button <= B3(4) and ExplorerMouse;
   F_Button <= B3(5) and ExplorerMouse;
   D_Wheel  <= '1' when ((B3(3 downto 0) = "0001") and ((ExplorerMouse = '1') or (IntelliMouse = '1'))) else '0';
   U_Wheel  <= '1' when ((B3(3 downto 0) = "1111") and ((ExplorerMouse = '1') or (IntelliMouse = '1'))) else '0';

Ostatni kod jest pełnym kodem obsługującym VGA, PS2 (mysz), dekoder wskaźnika i wyświetlanie wskaźnika na monitorze. Kod ten jest gotowy do implementacji w fpga.:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Mysz_PS2 is
    Port ( Clk : in  STD_LOGIC; -- 100MHz
           Reset : in  STD_LOGIC; -- aktywny = 0
           PS2_D : inout  STD_LOGIC; -- dane mysz
           PS2_C : inout  STD_LOGIC; -- zegar mysz
           LED1 : out  STD_LOGIC; -- diody led
           LED2 : out  STD_LOGIC;
           LED3 : out  STD_LOGIC;
           LED4 : out  STD_LOGIC;
           LED5 : out  STD_LOGIC;
           LED6 : out  STD_LOGIC;
           LED7 : out  STD_LOGIC;
           LED8 : out  STD_LOGIC;
           HS : out  STD_LOGIC; -- synchronizacja VGA
           VS : out  STD_LOGIC;
           RGB : out  STD_LOGIC_VECTOR(7 downto 0) -- 8 bitowe kodowanie barwy (BB GGG RRR)
         );
end Mysz_PS2;

architecture Behavioral of Mysz_PS2 is

------------------------------------------------------------------------------
	signal SelB      : std_logic_vector (3 downto 0);
	
	signal B0        : std_logic_vector (7 downto 0);
	signal B1        : std_logic_vector (7 downto 0);
	signal B2        : std_logic_vector (7 downto 0);
	signal B3        : std_logic_vector (7 downto 0);
	
	signal StandardMouse : std_logic;
	signal IntelliMouse  : std_logic;
	signal ExplorerMouse : std_logic;
	signal MoWE      : std_logic;
	signal L_Button  : std_logic;
	signal R_Button  : std_logic;
	signal M_Button  : std_logic;
	signal B_Button  : std_logic;
	signal F_Button  : std_logic;
	signal U_Wheel   : std_logic;
	signal D_Wheel   : std_logic;

	signal D         : std_logic_vector (9 downto 0);
	signal Din       : std_logic_vector (7 downto 0);
	signal Cnt       : std_logic_vector (7 downto 0) := "11111111";
	signal Cnt1      : std_logic_vector (13 downto 0);
	
	signal PS2_Cin   : std_logic;
	signal PS2_Cout  : std_logic;
	signal PS2_Dout  : std_logic;
	
	signal ParityGen : std_logic_vector (6 downto 0);
	signal Parity    : std_logic;
	signal Init      : std_logic_vector (3 downto 0) := "0000";
	
   type PS2State_type is (idle, datain, sel, rts, we, we1, rts1, rts2, dataout); 
   signal PS2State : PS2State_type;
------------------------------------------------------------------------------
	signal EnH         : std_logic;
	signal EnV         : std_logic;
	signal CntV1       : std_logic_vector (3 downto 0);
	signal X_Offset    : std_logic_vector (9 downto 0);
	signal Y_Offset    : std_logic_vector (9 downto 0);
	signal Mouse_pos_X : std_logic_vector (9 downto 0);
	signal Mouse_pos_Y : std_logic_vector (9 downto 0);
	signal WskaznikEn  : std_logic;
	signal WskaznikRGB : std_logic_vector (7 downto 0);
	signal Wc          : std_logic_vector (7 downto 0);
	signal Wb          : std_logic_vector (6 downto 0);
	signal EndLine     : std_logic;
------------------------------------------------------------------------------
	signal CntH  : std_logic_vector (9 downto 0);
	signal CntV  : std_logic_vector (9 downto 0);
	signal Cnt25 : std_logic_vector (1 downto 0);
	signal BL    : std_logic;
------------------------------------------------------------------------------
	
begin

------------------------------------------------------------------------------

   -- przypisanie zdekodowanych przycisków myszy do wyjść LED
   process(Clk, Reset)
   begin
      if Reset = '0' then
         LED1 <= '0';
         LED2 <= '0';
         LED3 <= '0';
         LED4 <= '0';
         LED5 <= '0';
         LED6 <= '0';
         LED7 <= '0';
         LED8 <= '0';
      elsif rising_edge(Clk) then
         if MoWE = '1' then
            LED1 <= R_Button;
            LED2 <= M_Button;
            LED3 <= L_Button;
            LED4 <= B_Button;
            LED5 <= F_Button;
            LED6 <= U_Wheel;
            LED7 <= D_Wheel;
            LED8 <= B0(3);
         end if;
      end if;
   end process;
   
   L_Button <= B0(0);
   R_Button <= B0(1);
   M_Button <= B0(2);
   B_Button <= B3(4) and ExplorerMouse;
   F_Button <= B3(5) and ExplorerMouse;
   D_Wheel  <= '1' when ((B3(3 downto 0) = "0001") and ((ExplorerMouse = '1') or (IntelliMouse = '1'))) else '0';
   U_Wheel  <= '1' when ((B3(3 downto 0) = "1111") and ((ExplorerMouse = '1') or (IntelliMouse = '1'))) else '0';
------------------------------------------------------------------------------
   -- kontroler VGA
   
   -- liczniki VGA
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt25 <= Cnt25 + 1 --dzielnik częstotliwości
         if Cnt25 = "11" then
            if CntH = 799 then --licznik kolumn
               CntH <= (others => '0');
            else
               CntH <= CntH + 1;
            end if;
            if CntH = 799 then
               if CntV = 524 then --licznik wierszy
                  CntV <= (others => '0');
               else
                  CntV <= CntV + 1;
               end if;
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji poziomej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 655 then
               HS <= '0';
            elsif CntH = 751 then
               HS <= '1';
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji pionowej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntV = 488 then
               VS <= '0';
            elsif CntV = 489 then
               VS <= '1';
            end if;
         end if;
      end if;
   end process;
   
   -- dekoder końca Linii
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 639 then
               Endline <= '1';
            else
               EndLine <= '0';
            end if;
         end if;
      end if;
   end process;
   
   -- dekoder obszaru obrazu wyświetlanego (aktywny = 1)
	BL <= '1' when ((CntH < 640) and (CntV < 480)) else '0'; 
	
   -- zapis wybranego koloru piksela do wyjścia RGB-VGA
   process(Clk, BL)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if BL = '0' then
               RGB <= (others => '0');
            elsif WskaznikEn = '1' then
               RGB <= WskaznikRGB;
            else
               RGB <= "10100000";
            end if;
         end if;
      end if;
   end process;
------------------------------------------------------------------------------
   -- synchronizacja zegara myszy z zegarem systemowym
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt <= PS2_C & Cnt(7 downto 1);
      end if;
   end process;
      
   PS2_Cin <= '1' when (Cnt = 1) else '0';
      
   --wysłanie, odbieranie danych myszy w maszynie stanów
   process(Clk, Reset)		
   begin
      if Reset = '0' then
            D <= "1000000000";
            Din <= "00000000";
            B0 <= "00000000";
            MoWE <= '0';
            Init <= "0000";
            SelB <= "1111";
            Cnt1 <= (others => '0');
            StandardMouse <= '0';
            IntelliMouse <= '0';
            ExplorerMouse <= '0';
            PS2State <= sel;
      elsif rising_edge(Clk) then
         case PS2State is
         -- oczekiwanie na bit start (takt 1)
         when idle =>
            if PS2_Cin = '1' then
               D <= "1000000000";
               PS2State <= datain;
            end if;
         -- zapis danych z portu PS2_D
         when datain =>
            if PS2_Cin = '1' then
               if D(0) = '1' then -- bitu stop powoduje przejście do następnego stanu (takt 11)
                  D <= "1000000000";
                  Din <= D(8 downto 1);
                  PS2State <= sel;
               else
                  D <= PS2_D & D(9 downto 1); -- (takt 2,3,4,5,6,7,8,9,10) 
               end if;
            end if;

         when sel =>
            if (Init = 0) then -- reset myszy
               Init <= Init + 1;
               Din <= X"FF";
               PS2State <= rts;
            elsif ((Init = 1) and (Din = X"00")) then -- (sekwencja pełnej aktywacji wszystkich myszy
               Init <= Init + 1;                      --  E8 00 F3 C8 F3 64 F3 50 F4)
               Din <= X"E8"; -- aktywacja trybu Explorer
               PS2State <= rts;
            elsif ((Init = 2) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"00";
               PS2State <= rts;
            elsif ((Init = 3) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3"; -- aktywacja trybu IntelliMouse
               PS2State <= rts;
            elsif ((Init = 4) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"C8";
               PS2State <= rts;
            elsif ((Init = 5) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 6) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"64";
               PS2State <= rts;
            elsif ((Init = 7) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 8) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"50";
               PS2State <= rts;
            elsif ((Init = 9) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F2"; -- odczyt ID myszy
               PS2State <= rts;
            elsif (Init = 10) then
               if (Din = X"00") then -- ID StandardMouse
                  Init <= Init + 1;
                  StandardMouse <= '1';
               elsif (Din = X"03") then -- ID Intellimouse
                  Init <= Init + 1;
                  IntelliMouse <= '1';
               elsif (Din = X"04") then -- ID ExplorerMouse
                  Init <= Init + 1;
                  ExplorerMouse <= '1';
               else
                  PS2State <= idle;
               end if;
            elsif (Init = 11) then
               Init <= Init + 1;
               Din <= X"F4"; -- włączenie raportowania
               PS2State <= rts;
            elsif ((Init = 12) and (Din = X"FA")) then
               Init <= Init + 1;
               SelB <= "1111";
               PS2State <= idle;
            else
               SelB <= '0' & SelB(3 downto 1);
               if (StandardMouse = '1') then -- 1=0111 / 2= 0011 / 3=0001
                  B2 <= Din;
               else                          -- 1=0111 / 2= 0011 / 3=0001 / 4=0000
                  B3 <= Din;
                  B2 <= B3;
               end if;
               B1 <= B2;
               B0 <= B1;
               PS2State <= we;
            end if;

         when we =>
            if (((SelB(1) = '0') and (StandardMouse = '1')) or (SelB(0) = '0')) then
               SelB <= "1111";
               MoWE <= '1';
            end if;
            PS2State <= we1;

         when we1 =>
            MoWE <= '0';
            PS2State <= idle;

         when rts =>	    -- reqest to send
            if Cnt1 = "11111100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts1;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts1 =>	 -- reqest to send
            if Cnt1 = "00000100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts2;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts2 =>	 -- reqest to send
            if PS2_Cin = '1' then
               D <= '1' & Parity & Din;
               PS2State <= dataout;
            end if;

         when dataout => --wysyłanie danych do myszy
            if PS2_Cin = '1' then
               if D = "0000000001" then
                  PS2State <= idle;
               else
                  D <= '0' & D(9 downto 1);
               end if;
            end if;

         end case;
      end if;
   end process;

   --generator parzystości		
   ParityGen(0) <= Din(0) xor Din(1);
   ParityGen(1) <= Din(2) xor Din(3);
   ParityGen(2) <= Din(4) xor Din(5);
   ParityGen(3) <= Din(6) xor Din(7);
   ParityGen(4) <= ParityGen(0) xor ParityGen(1);
   ParityGen(5) <= ParityGen(2) xor ParityGen(3);
   ParityGen(6) <= ParityGen(4) xor ParityGen(5);
   Parity <= not ParityGen(6);
		
   -- sterowanie portem danych myszy
   with PS2State select
  PS2_Dout <= '0' when rts1,
              '0' when rts2,
              D(0) when dataout,
              '1' when others;
		
   -- sterowanie portem zegara myszy
   with PS2State select
  PS2_Cout <= '0' when rts,
              '0' when rts1,
              '1' when others;
              
   -- obsługa portów komunikacyjnych               
   PS2_C <= 'Z' when PS2_Cout = '1' else '0';
   PS2_D <= 'Z' when PS2_Dout = '1' else '0';
------------------------------------------------------------------------------
   --zmiana pozycji wskaźnika myszy
   
   -- rozszerzenie liczby u2 + obsługa overflow
   X_Offset <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
   Y_Offset <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');

   process(Clk, Reset)
   begin
      if Reset = '0' then
         Mouse_pos_X <= (others => '0');
         Mouse_pos_Y <= (others => '0');

      elsif rising_edge(Clk) then

         if MoWE = '1' then
            -- aktualizacja pozycji
            Mouse_pos_X <= Mouse_pos_X + X_Offset;
            Mouse_pos_Y <= Mouse_pos_Y + Y_Offset;

         else
         -- ograniczenia X
         if Mouse_pos_X > 639 then
            if B0(4) = '0' then
               Mouse_pos_X <= "1001111111";  -- 639
            else
               Mouse_pos_X <= (others => '0');
            end if;
         end if;

         -- ograniczenia Y
         if Mouse_pos_Y > 479 then
            if B0(5) = '0' then
               Mouse_pos_Y <= (others => '0');
            else
               Mouse_pos_Y <= "0111011111";  -- 479
            end if;
         end if;

        end if;
      end if;
   end process;
   
------------------------------------------------------------------------------------------
   --dekoder wskaźnika myszy
   
   -- C = Czarny kolor    B = Biały kolor
   --   0 1 2 3 4 5 6 7
   -- 0 C C C C C C C 0
   -- 1 C B B B B C 0 0
   -- 2 C B B B C 0 0 0
   -- 3 C B B B B C 0 0
   -- 4 C B C B B B C 0
   -- 5 C C 0 C B B B C
   -- 6 C 0 0 0 C B C 0
   -- 7 0 0 0 0 0 C 0 0
  
   -- dekodery sygnałów triggera startu rysowania
	EnH <= '1' when CntH = Mouse_pos_X else '0';
	EnV <= '1' when CntV = Mouse_pos_Y else '0';
	
   -- licznikiem wierszy wskaźnika myszy
	process(Clk, Reset)
	begin
		if Reset = '0' then
         CntV1 <= "1000";
		elsif rising_edge(Clk) then
         if ((EnV = '1') and (EnH = '1')) then
            CntV1 <= "0000";
         elsif ((Cnt25 = "11") and (EndLine = '1')) then
            if CntV1 = "1000" then
               null;
            else
               CntV1 <= CntV1 + 1;
            end if;
         end if;
		end if;
	end process;

   -- zapis danych dla wybranego wiersza wiersza
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "10" then
            if ((EnH = '1') and (CntV1(3) = '0')) then
               case CntV1(2 downto 0) is        -- licznik wierszy wskaźnika
               when "000"  => Wc <= "11111110"; -- czarny obrys wskaźnika
                              Wb <= "0000000";  -- białe wypełnienie wskaźnika
               when "001"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "010"  => Wc <= "10001000";
                              Wb <= "0111000";
               when "011"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "100"  => Wc <= "10100010";
                              Wb <= "0101110";
               when "101"  => Wc <= "11010001";
                              Wb <= "0000111";
               when "110"  => Wc <= "10001010";
                              Wb <= "0000010";
               when others => Wc <= "00000100";
                              Wb <= "0000000";
               end case;
            elsif Wc /= 0 then
               Wc <= Wc(6 downto 0) & '0'; -- rejestr przesuwany w lewo
               Wb <= Wb(5 downto 0) & '0';
            end if;
         end if;
      end if;
   end process;
   
   WskaznikRGB <= "11111111" and (7 downto 0 => Wb(6)); 
   WskaznikEn <= Wc(7) or Wb(6); -- zezwolenie na wyświetlanie


end Behavioral;

Kod jest testowany i działa.

Edytowano przez kroszkanorber

Witam wszystkich.

Dopisałem do kodu obsługę sprite.

  1. działa na dwóch licznikach 5 bitowych,
  2. posiada funkcję przechwytywania przez kursor myszy co umożliwia jego przesuwanie w dwóch osiach,
  3. obraz sprite to 16x16 pikseli i 256 kolorów na piksel
  4. obraz sprite jest pobierany z wbudowanej pamięci BRAM w FPGA

kod sprite:

   --dekoder sprite
  
   SpriteEnH <= '1' when (Sprite_pos_X = CntH) else '0';
   SpriteEnV <= '1' when (Sprite_pos_Y = CntV) else '0';
  
   -- liczniki kolumn i wierszy sprite
   process(Clk, Reset)
   begin
      if (Reset = '0') then
         Sprite_cnt_X <= "10000";
         Sprite_cnt_Y <= "10000";
      elsif rising_edge(Clk) then
        
         if (Cnt25 = "01") then -- wykrycie sprite (kasowanie liczników)
            if (SpriteEnH = '1') then
               Sprite_cnt_X <= (others => '0');
               if (SpriteEnV = '1') then
                  Sprite_cnt_Y <= (others => '0');
               end if;
            end if;
         elsif (Cnt25 = "11") then -- inkrementacja liczników sprite
            if Sprite_cnt_X(4) = '0' then -- sprawdzanie granicznej wartości
               Sprite_cnt_X <= Sprite_cnt_X + 1; --inkrementacja licznika kolumn
            end if; 
            if ((EndLine = '1') and (Sprite_cnt_Y(4) = '0')) then -- wykrycie końca rysowanej linii
               Sprite_cnt_Y <= Sprite_cnt_Y + 1; -- inkrementacja licznika wierszy
            end if;
         end if;
      end if;
   end process;
   
   SpriteEn <= not (Sprite_cnt_X(4) or Sprite_cnt_Y(4));
   SpriteAddrRd <= "000" & Sprite_cnt_Y(3 downto 0) & Sprite_cnt_X(3 downto 0);
   
   -- przechwytywanie sprite przez mysz
   
   SpriteCapture <= EnH and EnV and not L_Button;
   
   process(Clk)
   begin
      if rising_edge(Clk) then
         if (SpriteCapture = '1') then
            if (SpriteEn = '1') then
               SpriteSet <= '1';
            else
               SpriteSet <= '0';
            end if;
         end if;
      end if;
   end process;
   
   -- przesuwanie sprite
   
   SpriteMove <= SpriteSet and L_Button;
   
   process(Clk, Reset)
   begin
      if (Reset = '0') then
         Sprite_pos_X <= "0000011111";
         Sprite_pos_Y <= "0000011111";
      elsif rising_edge(Clk) then
         
         -- aktualizacja pozycji
         if ((SpriteMove = '1') and (MoWe = '1')) then
            Sprite_pos_X <= Sprite_pos_X + X_Offset;
            Sprite_pos_Y <= Sprite_pos_Y + Y_Offset;
         end if;
         
      end if;
   end process;

BRAM 2048×8 mieści 8 sprite’ów 16×16 (256 bajtów każdy). Adres sprite’a to: BASE_ADDR + Y + X

Kod zainicjowanej pamięci BRAM:


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RAM_2048x8 is
    port (Clk  : in std_logic;
          EN   : in std_logic;
          WE   : in std_logic;
          ADDR_WE : in std_logic_vector(10 downto 0);
          ADDR_RD : in std_logic_vector(10 downto 0);
          DI   : in std_logic_vector(7 downto 0);
          DO   : out std_logic_vector(7 downto 0)
			 );
end RAM_2048x8;

architecture Behavioral of RAM_2048x8 is

    type ram_type is array (0 to 2047) of std_logic_vector (7 downto 0);
    signal RAM: ram_type := (
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 00
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 01
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 02
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 03
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 04
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 05
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 06
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 07
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 08
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 09
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 0A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 0B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 0C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 0D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 0E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 0F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 10
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 11
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 12
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 13
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 14
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 15
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 16
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 17
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 18
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 19
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 1A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 1B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 1C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 1D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 1E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 1F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 20
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 21
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 22
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 23
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 24
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 25
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 26
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 27
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 28
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 29
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 2A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 2B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 2C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 2D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 2E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 2F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 30
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 31
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 32
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 33
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 34
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 35
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 36
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 37
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 38
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 39
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 3A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 3B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 3C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 3D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 3E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 3F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 40
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 41
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 42
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 43
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 44
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 45
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 46
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 47
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 48
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 49
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 4A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 4B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 4C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 4D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 4E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 4F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 50
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 51
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 52
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 53
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 54
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 55
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 56
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 57
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 58
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 59
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 5A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 5B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 5C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 5D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 5E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 5F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 60
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 61
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 62
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 63
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 64
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 65
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 66
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 67
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 68
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 69
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 6A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 6B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 6C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 6D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 6E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 6F
    
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", -- 70
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 71
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 72
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 73
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 74
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 75
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 76
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 77
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 78
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 79
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 7A
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 7B
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 7C
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 7D
    X"A4", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"A4", -- 7E
    X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4", X"A4"  -- 7F
    
    );

begin

	
    process (CLK)
    begin
		if rising_edge(CLK) then
			if WE = '1' then
				RAM(conv_integer(ADDR_WE)) <= DI;
			end if;
			if EN = '1' then
				DO <= RAM(conv_integer(ADDR_RD));
			else
				DO <= (others => '0');
			end if;
		end if;
    end process;


end Behavioral;

Dodałem też obsługę wyświetlacza LCD 2x16 znaków. W kodzie używam maszyny stanów z algorytmem double dablle do przekształcenia liczby ze znakiem generowanej przesuwaniem myszy w osi x i y. LCD działa jako panel diagnostyczny — wyświetla aktualne przesunięcia myszy w formacie BCD oraz typ wykrytej myszy PS/2.

Double‑dabble w sprzęcie + wyświetlanie:

  1. znaku
  2. wartości X
  3. wartości Y
  4. typu myszy (Standard / Intelli / Explorer)

kod obsługujący LCD:


-- Typ użytego wyświetlacza
-- EA W162B-N3LW

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity LCD16x2 is
    Port ( 
           Clk    : in  STD_LOGIC;
           Reset  : in  STD_LOGIC;
           M_type : in  std_logic_vector(2 downto 0);
           Lcd_Wr : in  std_logic;
           X_sign : in  std_logic;
           Y_sign : in  std_logic;
           X_data : in  std_logic_vector(7 downto 0);
           Y_data : in  std_logic_vector(7 downto 0);
           LCD_E  : out STD_LOGIC;
           LCD_RW : out STD_LOGIC;
           LCD_RS : out STD_LOGIC;
           LCD_DB : out STD_LOGIC_VECTOR (7 downto 0)
         );
end LCD16x2;

architecture Behavioral of LCD16x2 is

   type LCD_type is (pon, idle, init, tas, pweh, tcyce); 
   signal LCDstate : LCD_type := pon;
   
   signal Cnt   : std_logic_vector (20 downto 0);
   signal Cnti  : std_logic_vector (2 downto 0);
   signal CntWr : std_logic_vector (4 downto 0);

   type BD_type is (idleBd, shleft, compare, wr); 
   signal BDstate : BD_type := idleBd;
   
   signal CntBd : std_logic_vector (2 downto 0);
   signal BinX  : std_logic_vector (7 downto 0);
   signal BinY  : std_logic_vector (7 downto 0);
   signal BcdX  : std_logic_vector (9 downto 0);
   signal BcdY  : std_logic_vector (9 downto 0);
   signal SigX  : std_logic_vector (1 downto 0);
   signal SigY  : std_logic_vector (1 downto 0);

begin
   
   process(Clk, Reset) -- double dabble algorithm
   begin
   
      if (Reset = '0') then
         BDstate <= idleBd;
   
      elsif rising_edge(Clk) then
      
         case BDstate is
            
            when idleBd => -- zapis danych do rejestrów roboczych
               if ((Lcd_Wr = '1') and (LCDstate = idle)) then
                  if X_sign = '1' then
                     SigX <= "10"; -- "-" 0010 1(10)1 dekoder znaku asci
                     BinX <= not X_data + 1;
                  else
                     SigX <= "01"; -- "+" 0010 1(01)1
                     BinX <= X_data;
                  end if;
                  if Y_sign = '1' then
                     SigY <= "10"; -- "-"
                     BinY <= not Y_data + 1;
                  else
                     SigY <= "01"; -- "+"
                     BinY <= Y_data;
                  end if;
                  BcdX  <= (others => '0');
                  BcdY  <= (others => '0');
                  CntBd <= (others => '1');
                  BDstate <= shleft;
               end if;
         
            when shleft =>             -- algorytm przesuwający
               BcdX  <= BcdX(8 downto 0) & BinX(7);
               BcdY  <= BcdY(8 downto 0) & BinY(7);
               BinX  <= BinX(6 downto 0) & '0';
               BinY  <= BinY(6 downto 0) & '0';
               CntBd <= CntBd + 1;
               BDstate <= compare;
               
            when compare =>  -- algorytm porównania do liczby 5
               
               if CntBd = 7 then -- licznik iteracji
                  BDstate <= wr;
               else
            
                  if (BcdX(3 downto 0) >= 5) then
                     BcdX(3 downto 0) <= BcdX(3 downto 0) + 3;
                  end if;
                  if (BcdX(7 downto 4) >= 5) then
                     BcdX(7 downto 4) <= BcdX(7 downto 4) + 3;
                  end if;
               
                  if (BcdY(3 downto 0) >= 5) then
                     BcdY(3 downto 0) <= BcdY(3 downto 0) + 3;
                  end if;
                  if (BcdY(7 downto 4) >= 5) then
                     BcdY(7 downto 4) <= BcdY(7 downto 4) + 3;
                  end if;
                  
                  BDstate <= shleft;
                  
               end if;
                  
            when wr =>
                  BDstate <= idleBd;
                  
         end case;
      end if;
   end process;
   
   LCD_RW <= '0';


   Process(Clk, Reset)
   begin
      if Reset = '0' then
         LCD_E    <= '0';
         LCD_RS   <= '0';
         LCD_DB   <= (others => '0');
         Cnti     <= (others => '0');
         Cnt      <= (others => '0');
         CntWr    <= "11000";
         LCDstate <= idle;
      elsif rising_edge(Clk) then
         case LCDstate is
            ---------------------------------------------
            -- uruchomienie po włączeniu zasilania
            when pon => -- power on czekamy minimum 15ms
               if Cnti = 7 then
                  Cnti <= (others => '0');
                  Cnt <= (others => '0');
                  LCDstate <= idle;
               elsif Cnt = 2000000 then
                  Cnti <= Cnti + 1;
               end if;
                  Cnt <= Cnt + 1;
            ---------------------------------------------
            -- wybór instrukcji
            when idle =>
               if Cnti = 4 then -- sprawdź czy inicjalizacja zakończona
                  if ((BDstate = wr) and (CntWr = 24))then
                     CntWr    <= (others => '0');
                  end if;
                  if (CntWr <= 23) then -- sprawdzamy czy wszystkie znaki zostały wysłane
                     if (CntWr = 0) then
                        LCD_RS <= '0';
                        LCD_DB <= "10000000"; -- set dd ram address (kursor na pierwsszy wiersz)
                     elsif (CntWr = 1) then
                        LCD_RS <= '1';
                        LCD_DB <= "00101" & SigX & '1';
                     elsif (CntWr = 2) then
                        LCD_DB <= "001100" & BcdX(9 downto 8);
                     elsif (CntWr = 3) then
                        LCD_DB <= "0011" & BcdX(7 downto 4);
                     elsif (CntWr = 4) then
                        LCD_DB <= "0011" & BcdX(3 downto 0);
                     elsif (CntWr = 5) then
                        LCD_DB <= X"20";
                     elsif (CntWr = 6) then
                        LCD_RS <= '1';
                        LCD_DB <= "00101" & SigY & '1';
                     elsif (CntWr = 7) then
                        LCD_DB <= "001100" & BcdY(9 downto 8);
                     elsif (CntWr = 8) then
                        LCD_DB <= "0011" & BcdY(7 downto 4);
                        LCD_RS <= '1';
                     elsif (CntWr = 9) then
                        LCD_DB <= "0011" & BcdY(3 downto 0);
                     elsif (CntWr = 10) then
                        LCD_RS <= '0';
                        LCD_DB <= "11000000"; -- set dd ram address (kursor na drugi wiersz)
                     elsif (CntWr = 11) then
                        LCD_RS <= '1';
                           if M_type(2) = '1' then
                              LCD_DB <= X"45"; -- (E)xplorer
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"20";
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"53"; -- (S)tandard
                        end if;
                     elsif (CntWr = 12) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"65"; -- E(x)plorer
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"49"; -- (I)ntelli
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"74"; -- S(t)andard
                        end if;
                     elsif (CntWr = 13) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"70"; -- Ex(p)lorer
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"6E"; -- I(n)telli
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"61"; -- St(a)ndard
                        end if;
                     elsif (CntWr = 14) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"6C"; -- Exp(l)orer
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"74"; -- In(t)elli
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"6E"; -- Sta(n)dard
                        end if;
                     elsif (CntWr = 15) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"6F"; -- Expl(o)rer
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"65"; -- Int(e)lli
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"64"; -- Stan(d)ard
                        end if;
                     elsif (CntWr = 16) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"72"; -- Explo(r)er
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"6C"; -- Inte(l)li
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"61"; -- Stand(a)rd
                        end if;
                     elsif (CntWr = 17) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"65"; -- Explor(e)r
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"6C"; -- Intel(l)i
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"72"; -- Standa(r)d
                        end if;
                     elsif (CntWr = 18) then
                           if M_type(2) = '1' then
                              LCD_DB <= X"72"; -- Explore(r)
                        elsif M_type(1) = '1' then
                              LCD_DB <= X"69"; -- Intell(i)
                        elsif M_type(0) = '1' then
                              LCD_DB <= X"64"; -- Standar(d)
                        end if;
                     elsif (CntWr = 19) then
                        LCD_DB <= X"6D"; -- (m)ouse
                     elsif (CntWr = 20) then
                        LCD_DB <= X"6F"; -- m(o)ouse
                     elsif (CntWr = 21) then
                        LCD_DB <= X"75"; -- mo(u)se
                     elsif (CntWr = 22) then
                        LCD_DB <= X"73"; -- mou(s)e
                     elsif (CntWr = 23) then
                        LCD_DB <= X"65"; -- mous(e)
                     end if;
                        CntWr <= CntWr + 1;
                        LCDState <= tas;
                  end if;
               else
                  LCDstate <= Init; 
               end if;
            ---------------------------------------------
            -- sekwencja syganłu LCD_E
            when tas => -- E = 0 czekamy minimum 140ns
               if Cnt = 50 then
                  Cnt <= (others => '0');
                  LCD_E <= '1';
                  LCDState <= pweh;
               else
                  Cnt <= Cnt + 1;
               end if;
               
            when pweh => -- E = 1 czekamy minimum 450ns
               if Cnt = 50 then
                  Cnt <= (others => '0');
                  LCD_E <= '0';
                  LCDState <= tcyce;
               else
                  Cnt <= Cnt + 1;
               end if;
            
            when tcyce => -- E = 0 czekamy minimum 350ns
               if Cnt = 40000 then -- 400 µs 
                  Cnt <= (others => '0');
                  LCDState <= idle;
               else
                  Cnt <= Cnt + 1;
               end if;
            
            ---------------------------------------------
            -- sekwencja inicjalizacji LCD
            when Init => -- seria poleceń inicjujących wyświetlacz
               if Cnti = 0 then
                  LCD_DB <= "00111000"; -- Function Set   (czekaj minimum 40µs)
               elsif Cnti = 1 then
                  LCD_DB <= "00001100"; -- Display ON/OFF (czekaj minimum 40µs)
               elsif Cnti = 2 then
                  LCD_DB <= "00000001"; -- Clear Display  (czekaj minimum 1,64ms)
               elsif Cnti = 3 then
                  LCD_DB <= "00000110"; -- Entry Mode Set (czekaj minimum 40µs)
               end if;
               if Cnt = 2000000 then    -- 2ms
                  Cnt <= (others => '0');
                  Cnti <= Cnti + 1;
                  if Cnti = 4 then
                     LCDState <= idle;
                  else
                     LCDState <= tas;
                  end if;
               else
                  Cnt <= Cnt + 1;
               end if;
               
         end case;
      end if;
   end process;


end Behavioral;

Kod myszy:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MOUSE is
    Port ( 
           Clk    : in    STD_LOGIC;
           Reset  : in    STD_LOGIC;
           PS2_D  : inout STD_LOGIC;
           PS2_C  : inout STD_LOGIC;
           LED1   : out   STD_LOGIC;
           LED2   : out   STD_LOGIC;
           LED3   : out   STD_LOGIC;
           LED4   : out   STD_LOGIC;
           LED5   : out   STD_LOGIC;
           LED6   : out   STD_LOGIC;
           LED7   : out   STD_LOGIC;
           LED8   : out   STD_LOGIC;
           HS     : out   STD_LOGIC;
           VS     : out   STD_LOGIC;
           RGB    : out   STD_LOGIC_VECTOR(7 downto 0);
           LCD_E  : out   STD_LOGIC;
           LCD_RW : out   STD_LOGIC;
           LCD_RS : out   STD_LOGIC;
           LCD_DB : out   STD_LOGIC_VECTOR (7 downto 0)
         );
end MOUSE;

architecture Behavioral of MOUSE is

------------------------------------------------------------------------------
	signal SelB      : std_logic_vector (3 downto 0);
	
	signal B0        : std_logic_vector (7 downto 0);
	signal B1        : std_logic_vector (7 downto 0);
	signal B2        : std_logic_vector (7 downto 0);
	signal B3        : std_logic_vector (7 downto 0);
	
	signal StandardMouse : std_logic;
	signal IntelliMouse  : std_logic;
	signal ExplorerMouse : std_logic;
	signal MoWE      : std_logic;
	signal L_Button  : std_logic;
	signal R_Button  : std_logic;
	signal M_Button  : std_logic;
	signal B_Button  : std_logic;
	signal F_Button  : std_logic;
	signal U_Wheel   : std_logic;
	signal D_Wheel   : std_logic;

	signal D         : std_logic_vector (9 downto 0);
	signal Din       : std_logic_vector (7 downto 0);
	signal Cnt       : std_logic_vector (7 downto 0) := "11111111";
	signal Cnt1      : std_logic_vector (13 downto 0);
   
	signal L_Button_cnt : std_logic_vector (7 downto 0);
	
	signal PS2_Cin   : std_logic;
	signal PS2_Cout  : std_logic;
	signal PS2_Dout  : std_logic;
	
	signal ParityGen : std_logic_vector (6 downto 0);
	signal Parity    : std_logic;
	signal Init      : std_logic_vector (3 downto 0) := "0000";
	
   type PS2State_type is (idle, datain, sel, rts, we, we1, rts1, rts2, dataout); 
   signal PS2State : PS2State_type;
------------------------------------------------------------------------------
	signal EnH         : std_logic;
	signal EnV         : std_logic;
	signal CntV1       : std_logic_vector (3 downto 0);
	signal X_Offset    : std_logic_vector (9 downto 0);
	signal Y_Offset    : std_logic_vector (9 downto 0);
	signal Mouse_pos_X : std_logic_vector (9 downto 0);
	signal Mouse_pos_Y : std_logic_vector (9 downto 0);
	signal WskaznikEn  : std_logic;
	signal WskaznikRGB : std_logic_vector (7 downto 0);
	signal Wc          : std_logic_vector (7 downto 0);
	signal Wb          : std_logic_vector (6 downto 0);
	signal EndLine     : std_logic;
------------------------------------------------------------------------------
	signal CntH  : std_logic_vector (9 downto 0);
	signal CntV  : std_logic_vector (9 downto 0);
	signal Cnt25 : std_logic_vector (1 downto 0);
	signal BL    : std_logic;
------------------------------------------------------------------------------
	COMPONENT LCD16x2
	PORT(
		Clk    : IN  std_logic;
		Reset  : IN  std_logic;
		M_type : IN  std_logic_vector(2 downto 0);
		Lcd_Wr : IN  std_logic;
		X_sign : IN  std_logic;
		Y_sign : IN  std_logic;
		X_data : IN  std_logic_vector(7 downto 0);
		Y_data : IN  std_logic_vector(7 downto 0);
		LCD_E  : OUT std_logic;
		LCD_RW : OUT std_logic;
		LCD_RS : OUT std_logic;          
		LCD_DB : OUT std_logic_vector(7 downto 0)
		);
	END COMPONENT;
   
   signal M_type : std_logic_vector(2 downto 0);
------------------------------------------------------------------------------
	COMPONENT RAM_2048x8
	PORT(
		Clk : IN std_logic;
		EN : IN std_logic;
		WE : IN std_logic;
		ADDR_WE : IN std_logic_vector(10 downto 0);
		ADDR_RD : IN std_logic_vector(10 downto 0);
		DI : IN std_logic_vector(7 downto 0);          
		DO : OUT std_logic_vector(7 downto 0)
		);
	END COMPONENT;
   
	signal SpriteEnH     : std_logic;
	signal SpriteEnV     : std_logic;
   signal SpriteEn      : std_logic;
   signal SpriteMove    : std_logic;
   signal SpriteSet     : std_logic;
   signal SpriteCapture : std_logic;
	signal Sprite_pos_X  : std_logic_vector (9 downto 0) := "0000011111";
	signal Sprite_pos_Y  : std_logic_vector (9 downto 0) := "0000011111";
	signal Sprite_cnt_X  : std_logic_vector (4 downto 0);
	signal Sprite_cnt_Y  : std_logic_vector (4 downto 0);
	signal SpriteRGB     : std_logic_vector (7 downto 0);
	signal SpriteAddrRd  : std_logic_vector (10 downto 0);
------------------------------------------------------------------------------
	
begin

	Inst_LCD16x2: LCD16x2 PORT MAP(
		Clk    => Clk,
		Reset  => Reset,
		M_type  => M_type,
      X_sign => B0(4),
      Y_sign => B0(5),
		X_data => B1,
		Y_data => B2,
      Lcd_Wr => MoWe,
		LCD_E  => LCD_E,
		LCD_RW => LCD_RW,
		LCD_RS => LCD_RS,
		LCD_DB => LCD_DB 
	);
   
   M_type(0) <= StandardMouse;
   M_type(1) <= IntelliMouse;
   M_type(2) <= ExplorerMouse;

------------------------------------------------------------------------------

	Inst_RAM_2048x8: RAM_2048x8 PORT MAP(
		Clk => Clk,
		EN => SpriteEn,
		WE => '0',
		ADDR_WE => "00000000000",
		ADDR_RD => SpriteAddrRd,
		DI => "00000000",
		DO => SpriteRGB
	);

------------------------------------------------------------------------------

   -- przypisanie zdekodowanych przycisków myszy do wyjść LED

   LED1 <= R_Button;
   LED2 <= M_Button;
   LED3 <= L_Button;
   LED4 <= B_Button;
   LED5 <= F_Button;
   LED6 <= U_Wheel;
   LED7 <= SpriteMove;
   LED8 <= SpriteSet;
   
   -- zapis stanu przycisków myszy
   process(Clk)
   begin
      if rising_edge(Clk) then
         if (MoWe = '1') then
            L_Button <= B0(0);
            R_Button <= B0(1);
            M_Button <= B0(2);
            B_Button <= B3(4) and ExplorerMouse;
            F_Button <= B3(5) and ExplorerMouse;
            if ((ExplorerMouse = '1') or (IntelliMouse = '1')) then
               if (B3(3 downto 0) = "0001") then
                  D_Wheel  <= '1';
               else
                  D_Wheel  <= '0';
               end if;
               if (B3(3 downto 0) = "1111") then
                  U_Wheel  <= '1';
               else
                  U_Wheel  <= '0';
               end if;
            end if;
         end if;
      end if;
   end process;
   
------------------------------------------------------------------------------
   -- VGA
   
   -- liczniki VGA
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt25 <= Cnt25 + 1;					--dzielnik częstotliwości
         if Cnt25 = "11" then
            if CntH = 799 then				--licznik kolumn
               CntH <= (others => '0');
            else
               CntH <= CntH + 1;
            end if;
            if CntH = 799 then
               if CntV = 524 then			--licznik wierszy
                  CntV <= (others => '0');
               else
                  CntV <= CntV + 1;
               end if;
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji poziomej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 655 then
               HS <= '0';
            elsif CntH = 752 then
               HS <= '1';
            end if;
         end if;
      end if;
   end process;
	
   --dekoder synchronizacji pionowej (aktywny = 0)
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntV = 489 then
               VS <= '0';
            elsif CntV = 492 then
               VS <= '1';
            end if;
         end if;
      end if;
   end process;
   
   -- dekoder końca wiersza
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if CntH = 639 then
               Endline <= '1';
            else
               EndLine <= '0';
            end if;
         end if;
      end if;
   end process;
   
   
   -- dekoder obszaru obrazu wyświetlanego (aktywny = 1)
	BL <= '1' when ((CntH < 640) and (CntV < 480)) else '0'; 
	
   -- zapis wybranego koloru piksela do wyjścia RGB-VGA
   process(Clk, BL)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "11" then
            if BL = '0' then
               RGB <= (others => '0');
            elsif WskaznikEn = '1' then
               RGB <= WskaznikRGB;
            elsif SpriteEn = '1' then
               RGB <= SpriteRGB;
            else
               RGB <= "10100000";
            end if;
         end if;
      end if;
   end process;
------------------------------------------------------------------------------
    -- synchronizacja zegara myszy z zegarem systemowym
   process(Clk)
   begin
      if rising_edge(Clk) then
         Cnt <= PS2_C & Cnt(7 downto 1);
      end if;
   end process;
      
   PS2_Cin <= '1' when (Cnt = 1) else '0';
      
   --wysłanie, odbieranie danych myszy w maszynie stanów
   process(Clk, Reset)		
   begin
      if Reset = '0' then
            D <= "1000000000";
            Din <= "00000000";
            B0 <= "00000000";
            MoWE <= '0';
            Init <= "0000";
            SelB <= "1111";
            Cnt1 <= (others => '0');
            StandardMouse <= '0';
            IntelliMouse <= '0';
            ExplorerMouse <= '0';
            PS2State <= sel;
      elsif rising_edge(Clk) then
         case PS2State is
         -- oczekiwanie na bit start (takt 1)
         when idle =>
            if PS2_Cin = '1' then
               D <= "1000000000";
               PS2State <= datain;
            end if;
         -- zapis danych z portu PS2_D
         when datain =>
            if PS2_Cin = '1' then
               if D(0) = '1' then -- bitu stop powoduje przejście do następnego stanu (takt 11)
                  D <= "1000000000";
                  Din <= D(8 downto 1);
                  PS2State <= sel;
               else
                  D <= PS2_D & D(9 downto 1); -- (takt 2,3,4,5,6,7,8,9,10) 
               end if;
            end if;

         when sel =>
            if (Init = 0) then -- reset myszy
               Init <= Init + 1;
               Din <= X"FF";
               PS2State <= rts;
            elsif ((Init = 1) and (Din = X"00")) then -- (sekwencja pełnej aktywacji wszystkich myszy
               Init <= Init + 1;                      --  E8 00 F3 C8 F3 64 F3 50 F4)
               Din <= X"E8"; -- aktywacja trybu Explorer
               PS2State <= rts;
            elsif ((Init = 2) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"00";
               PS2State <= rts;
            elsif ((Init = 3) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3"; -- aktywacja trybu IntelliMouse
               PS2State <= rts;
            elsif ((Init = 4) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"C8";
               PS2State <= rts;
            elsif ((Init = 5) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 6) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"64";
               PS2State <= rts;
            elsif ((Init = 7) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F3";
               PS2State <= rts;
            elsif ((Init = 8) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"50";
               PS2State <= rts;
            elsif ((Init = 9) and (Din = X"FA")) then
               Init <= Init + 1;
               Din <= X"F2"; -- odczyt ID myszy
               PS2State <= rts;
            elsif (Init = 10) then
               if (Din = X"00") then -- ID StandardMouse
                  Init <= Init + 1;
                  StandardMouse <= '1';
               elsif (Din = X"03") then -- ID Intellimouse
                  Init <= Init + 1;
                  IntelliMouse <= '1';
               elsif (Din = X"04") then -- ID ExplorerMouse
                  Init <= Init + 1;
                  ExplorerMouse <= '1';
               else
                  PS2State <= idle;
               end if;
            elsif (Init = 11) then
               Init <= Init + 1;
               Din <= X"F4"; -- włączenie raportowania
               PS2State <= rts;
            elsif ((Init = 12) and (Din = X"FA")) then
               Init <= Init + 1;
               SelB <= "1111";
               PS2State <= idle;
            else
               SelB <= '0' & SelB(3 downto 1);
               if (StandardMouse = '1') then -- 1=0111 / 2= 0011 / 3=0001
                  B2 <= Din;
               else                          -- 1=0111 / 2= 0011 / 3=0001 / 4=0000
                  B3 <= Din;
                  B2 <= B3;
               end if;
               B1 <= B2;
               B0 <= B1;
               PS2State <= we;
            end if;

         when we =>
            if (((SelB(1) = '0') and (StandardMouse = '1')) or (SelB(0) = '0')) then
               SelB <= "1111";
               MoWE <= '1';
            end if;
            PS2State <= we1;

         when we1 =>
            MoWE <= '0';
            PS2State <= idle;

         when rts =>	    -- reqest to send
            if Cnt1 = "11111100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts1;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts1 =>	 -- reqest to send
            if Cnt1 = "00000100000000" then
               Cnt1 <= (others => '0');
               PS2State <= rts2;
            else
               Cnt1 <= Cnt1 + 1;
            end if;

         when rts2 =>	 -- reqest to send
            if PS2_Cin = '1' then
               D <= '1' & Parity & Din;
               PS2State <= dataout;
            end if;

         when dataout => --wysyłanie danych do myszy
            if PS2_Cin = '1' then
               if D = "0000000001" then
                  PS2State <= idle;
               else
                  D <= '0' & D(9 downto 1);
               end if;
            end if;

         end case;
      end if;
   end process;

   --generator parzystości		
   ParityGen(0) <= Din(0) xor Din(1);
   ParityGen(1) <= Din(2) xor Din(3);
   ParityGen(2) <= Din(4) xor Din(5);
   ParityGen(3) <= Din(6) xor Din(7);
   ParityGen(4) <= ParityGen(0) xor ParityGen(1);
   ParityGen(5) <= ParityGen(2) xor ParityGen(3);
   ParityGen(6) <= ParityGen(4) xor ParityGen(5);
   Parity <= not ParityGen(6);
		
   -- sterowanie portem danych myszy
   with PS2State select
  PS2_Dout <= '0' when rts1,
              '0' when rts2,
              D(0) when dataout,
              '1' when others;
		
   -- sterowanie portem zegara myszy
   with PS2State select
  PS2_Cout <= '0' when rts,
              '0' when rts1,
              '1' when others;
              
   -- obsługa portów komunikacyjnych               
   PS2_C <= 'Z' when PS2_Cout = '1' else '0';
   PS2_D <= 'Z' when PS2_Dout = '1' else '0';
   
------------------------------------------------------------------------------
	--zmiana pozycji wskaźnika myszy
   
   -- rozszerzenie liczby u2 + obsługa overflow
--   X_Offset <= B0(4) & B0(4) & B1 when B0(6) = '0' else (others => '0');
--   Y_Offset <= (not (B0(5) & B0(5) & B2)) + 1 when B0(7) = '0' else (others => '0');
   
   process(StandardMouse, B0, B1, B2)
   begin
      X_Offset <= (others => '0');
      Y_Offset <= (others => '0');
      if B0(6) = '0' then
         if StandardMouse = '1' then
            X_Offset <= B1 & "00";
         else
            X_Offset <= B0(4) & B0(4) & B1;
         end if;
      end if;
      if B0(7) = '0' then
         if StandardMouse = '1' then
            Y_Offset <= (not (B2 & "00")) + 1;
         else
            Y_Offset <= (not (B0(5) & B0(5) & B2)) + 1;
         end if;
      end if;
   end process;

   process(Clk, Reset)
   begin
      if Reset = '0' then
         Mouse_pos_X <= (others => '0');
         Mouse_pos_Y <= (others => '0');

      elsif rising_edge(Clk) then

         if MoWE = '1' then
            -- aktualizacja pozycji
            Mouse_pos_X <= Mouse_pos_X + X_Offset;
            Mouse_pos_Y <= Mouse_pos_Y + Y_Offset;

         else
            -- ograniczenia X
            if Mouse_pos_X > 639 then
               if B0(4) = '0' then
                  Mouse_pos_X <= "1001111111";  -- 639
               else
                  Mouse_pos_X <= (others => '0');
               end if;
            end if;

            -- ograniczenia Y
            if Mouse_pos_Y > 479 then
               if B0(5) = '0' then
                  Mouse_pos_Y <= (others => '0');
               else
                  Mouse_pos_Y <= "0111011111";  -- 479
               end if;
            end if;

         end if;
      end if;
   end process;
   
------------------------------------------------------------------------------------------
   
   --dekoder sprite
  
   SpriteEnH <= '1' when (Sprite_pos_X = CntH) else '0';
   SpriteEnV <= '1' when (Sprite_pos_Y = CntV) else '0';
  
   -- liczniki kolumn i wierszy sprite
   process(Clk, Reset)
   begin
      if (Reset = '0') then
         Sprite_cnt_X <= "10000";
         Sprite_cnt_Y <= "10000";
      elsif rising_edge(Clk) then
        
         if (Cnt25 = "01") then -- wykrycie sprite (kasowanie liczników)
            if (SpriteEnH = '1') then
               Sprite_cnt_X <= (others => '0');
               if (SpriteEnV = '1') then
                  Sprite_cnt_Y <= (others => '0');
               end if;
            end if;
         elsif (Cnt25 = "11") then -- inkrementacja liczników sprite
            if Sprite_cnt_X(4) = '0' then -- sprawdzanie granicznej wartości
               Sprite_cnt_X <= Sprite_cnt_X + 1; --inkrementacja licznika kolumn
            end if; 
            if ((EndLine = '1') and (Sprite_cnt_Y(4) = '0')) then -- wykrycie końca rysowanej linii
               Sprite_cnt_Y <= Sprite_cnt_Y + 1; -- inkrementacja licznika wierszy
            end if;
         end if;
      end if;
   end process;
   
   SpriteEn <= not (Sprite_cnt_X(4) or Sprite_cnt_Y(4));
   SpriteAddrRd <= "000" & Sprite_cnt_Y(3 downto 0) & Sprite_cnt_X(3 downto 0);
   
   -- przechwytywanie sprite przez mysz
   
   SpriteCapture <= EnH and EnV and not L_Button;
   
   process(Clk)
   begin
      if rising_edge(Clk) then
         if (SpriteCapture = '1') then
            if (SpriteEn = '1') then
               SpriteSet <= '1';
            else
               SpriteSet <= '0';
            end if;
         end if;
      end if;
   end process;
   
   -- przesuwanie sprite
   
   SpriteMove <= SpriteSet and L_Button;
   
   process(Clk, Reset)
   begin
      if (Reset = '0') then
         Sprite_pos_X <= "0000011111";
         Sprite_pos_Y <= "0000011111";
      elsif rising_edge(Clk) then
         
         -- aktualizacja pozycji
         if ((SpriteMove = '1') and (MoWe = '1')) then
            Sprite_pos_X <= Sprite_pos_X + X_Offset;
            Sprite_pos_Y <= Sprite_pos_Y + Y_Offset;
         end if;
         
      end if;
   end process;
   
------------------------------------------------------------------------------------------
   --dekoder wskaźnika myszy
   
-- C = Czarny kolor    B = Biały kolor
--   0 1 2 3 4 5 6 7
-- 0 C C C C C C C 0
-- 1 C B B B B C 0 0
-- 2 C B B B C 0 0 0
-- 3 C B B B B C 0 0
-- 4 C B C B B B C 0
-- 5 C C 0 C B B B C
-- 6 C 0 0 0 C B C 0
-- 7 0 0 0 0 0 C 0 0
  
   -- dekodery sygnałów trigera startu rysowania wskaźnika myszy
	EnH <= '1' when CntH = Mouse_pos_X else '0';
	EnV <= '1' when CntV = Mouse_pos_Y else '0';
	
   -- licznikiem wierszy wskaźnika myszy
	process(Clk, Reset)
	begin
		if Reset = '0' then
         CntV1 <= "1000";
		elsif rising_edge(Clk) then
         if ((EnV = '1') and (EnH = '1')) then
            CntV1 <= "0000";
         elsif ((Cnt25 = "11") and (EndLine = '1')) then
            if CntV1 = "1000" then
               null;
            else
               CntV1 <= CntV1 + 1;
            end if;
         end if;
		end if;
	end process;

   -- zapis danych dla wybranego wiersza wiersza
   process(Clk)
   begin
      if rising_edge(Clk) then
         if Cnt25 = "10" then
            if ((EnH = '1') and (CntV1(3) = '0')) then
               case CntV1(2 downto 0) is        -- licznik wierszy wskaźnika
               when "000"  => Wc <= "11111110"; -- czarny obrys wskaźnika
                              Wb <= "0000000";  -- białe wypełnienie wskaźnika
               when "001"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "010"  => Wc <= "10001000";
                              Wb <= "0111000";
               when "011"  => Wc <= "10000100";
                              Wb <= "0111100";
               when "100"  => Wc <= "10100010";
                              Wb <= "0101110";
               when "101"  => Wc <= "11010001";
                              Wb <= "0000111";
               when "110"  => Wc <= "10001010";
                              Wb <= "0000010";
               when others => Wc <= "00000100";
                              Wb <= "0000000";
               end case;
            elsif Wc /= 0 then
               Wc <= Wc(6 downto 0) & '0'; -- rejestr przesuwany w lewo
               Wb <= Wb(5 downto 0) & '0';
            end if;
         end if;
      end if;
   end process;
   
   WskaznikRGB <= "11111111" and (7 downto 0 => Wb(6)); 
   WskaznikEn <= Wc(7) or Wb(6); -- zezwolenie na wyświetlanie


end Behavioral;

Zrzut ekranu z programem ise:
image.thumb.png.aa4e8c03dff3ea7440c01e7cc6d1beb1.png

Filmik z myszką w akcji:

 

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...