Popularny post kroszkanorber Napisano Luty 18, 2023 Popularny post Udostępnij Napisano Luty 18, 2023 Wyświetlacz obrazu VGA 640 x 480 + kod VHDL Układ jest taktowany generatorem 100 MHz . Układ łączy się z monitorem za pomocą przewodu VGA . Układ zasilany jest przez port mikro USB np. ładowarka do telefonu. Uwaga! Układ sterowany jest napięciem 3,3V! Przekroczenie tej wartości uszkodzi wyświetlacz. Do wyjścia RGB podłączony jest przetwornik cyfrowo – analogowy. Można użyć rezystorów o odpowiednich wartościach jak na schemacie. System oparty jest na układzie programowalnym Xlilnx XC2C64-7VQ100. Można użyć układ o większych zasobach. Kompatybilne układy które można zastosować bez zmian na płytce drukowanej : XC2C128-7VQ100, XC2C256-7VQ100 Ilość portów I/O w układzie programowalnym >= 62 . Obsługiwana pamięć statyczna RAM 512kB/do10ns 3,3V np. ISSI IS61LV5128AL-10TLI. Na wejściach portów są podłączone rezystory szeregowo małej wartości w celu wyeliminowania odbić sygnałów. Gwarantują one poprawny zapis danych. Zapis danych do pamięci RAM wykonywany jest gdy pamięć nie jest odczytywana. Częstotliwość zegara jest dzielona przez licznik 2 bitowy (Cnt25) czyli 100MHz/4 = 25 MHz. Użyta pamięć jest jedno portowa i zapis do niej występuje w 3 i 4 takcie zegara podczas gdy odczyt do wyjścia portu RGB występuje w 1 i 2 takcie. Czas zapisu i odczytu ustalany jest na podstawie wartości licznika (Cnt25). Sprawia to, że pamięć zachowuje się jak dwu portowa . Dzięki temu obraz może być zapisywany w trakcie wyświetlania bez artefaktów na wyświetlaczu monitora. Maksymalna częstotliwość zapisu danych do pamięci RAM = 25 MHz . Maksymalna częstotliwość zapisu danych do rejestru (Din) = 150 MHz . W trybie braku zapisu danych do rejestru (Din) na linię (WI) powinno być podane logiczne 1 !!! W trybie braku zapisu danych do pamięci RAM na linię (WR) powinno być podane logiczne 1 !!! -Dane barwy obrazu podawane są przez port DI(7,6,5,4,3,2,1,0) = 256 kolorów w rozdzielczości 8 bit. Podajemy je przed sygnałem (WI) i zatrzaskiwane są przy opadającym zboczu sygnału (WI) [„1 => 0”] w rejestrze (Din). Dane barwy obrazu do zapisu pamięci RAM pobierane są z wewnętrznego rejestru (Din). -Adres zapisu wyświetlanego punktu na monitorze podawany jest przez port DI(9,8,7,6,5,4,3,2,1,0) =0 – 640. -Adres zapisu wyświetlanej linii na monitorze podawany jest przez port DI(18,17,16,15,14,13,12,11,10) = 0 – 480. Podczas zapisu pamięci RAM podany adres do portu (DI) nie może być zmieniony aż do końca procedury ! Jest to spowodowane brakiem rejestru adresu w układzie. 0 Zapis danych do pamięci RAM: 1 Podać adres punktu który ma być wyświetlany na monitorze . 2 Do portu (WR) podać logiczne 0 . 3 Czekać na logiczne 1 na wyjściu (EN). 4 Do portu (WR) podać logiczne 1 . 5 Czekać na logiczne 0 na wyjściu (EN) . 6 Koniec procedury zapisu . Układ wyświetlacza obrazu został złożony i przetestowany. Oprogramowanie można modyfikować dla własnych potrzeb. Zmiany wartości sygnałów synchronizacji dla monitora skutkują brakiem obrazu. Płytka drukowana została narysowana w programie EasyEDA library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity VGA is Port ( RGB : out STD_LOGIC_VECTOR (7 downto 0); HS : out STD_LOGIC; VS : out STD_LOGIC; Clk : in STD_LOGIC; A: out STD_LOGIC_vector (18 downto 0); D: inout STD_LOGIC_vector (7 downto 0); WE : out STD_LOGIC; OE : out STD_LOGIC; EN : inout STD_LOGIC; WR : in STD_LOGIC; WI : in STD_LOGIC; DI: in STD_LOGIC_vector (18 downto 0) ); end VGA; architecture Behavioral of VGA is signal Cnt25 : std_logic_vector (1 downto 0); signal CntH : std_logic_vector (9 downto 0); signal CntV : std_logic_vector (9 downto 0); signal ClkH : std_logic; signal ClkV : std_logic; signal BL : std_logic; signal Din : std_logic_vector (7 downto 0); ---------------------------------------------------- begin --dzielnik częstotliwości Clk = 100MHz process (Clk) begin if Clk'event and Clk = '0' then Cnt25 <= Cnt25 + 1; end if; end process; ClkH <= Cnt25(Cnt25'left); --ClkH = 100MHz/4 = 25MHz --licznik punktów w poziomie process (ClkH, CntH) begin if ClkH'event and ClkH = '0' then if CntH = 799 then CntH <= (others => '0'); else CntH <= CntH + 1; end if; end if; end process; ClkV <= CntH(CntH'left); --ClkV = 25MHz/800 = 31,25kHz --licznik punktów w pionie process (ClkV, CntV) begin if ClkV'event and ClkV = '0' then if CntV = 524 then CntV <= (others => '0'); else CntV <= CntV + 1; end if; end if; end process; HS <= '0' when ((CntH > 655) and (CntH < 752)) else '1'; --dekoder sygnału synchronizacji poziomej BL <= '0' when ((CntH > 639) or (CntV > 479)) else '1'; --dekoder sygnału synchronizacji pionowej VS <= '0' when ((CntV > 489) and (CntV < 492)) else '1'; --dekoder wygaszania obrazu poza obszarem wyświetlanym ---------------------------------------------------- --zapis danych koloru pojedynczego punktu na ekranie za pomocą linji WI process(WI, DI) begin if WI'event and WI = '0' then Din <= DI(7 downto 0); end if; end process; ---------------------------------------------------- --sterowanie zewnętrznym sygnałem zezwolenia na zapis process(Cnt25, WR, Clk) begin if Clk'event and Clk = '0' then if Cnt25 = "01" then if WR = '0' then EN <= '1'; else EN <= '0'; end if; end if; end if; end process; ---------------------------------------------------- --wyświetlenie obrazu zapisanego w pamięci RAM process(Clk, Cnt25, BL, D) begin if Clk'event and Clk = '1' then --zapis sygnału do protu RGB przy wzrastającym zboczu zegarowym if Cnt25 = "01" then --opóżnienie odczytu z pamięci RAM po podaniu sygnału na wejścia adresowe if BL = '0' then --sygnał blanc = brak obrazu (obraz poza obszarem wyświetlanym) RGB <= (others => '0'); else RGB <= D; --wyświetlenie koloru zapisanego w pamięci RAM end if; end if; end if; end process; ---------------------------------------------------- --zapis danych do pamięci RAM A <= DI when ((Cnt25(1) = '1') and (EN = '1')) else (CntV(8 downto 0) & CntH); D <= Din when ((Cnt25(1) = '1') and (EN = '1')) else (others => 'Z'); WE <= '0' when ((Cnt25(1) = '1') and (EN = '1')) else '1'; OE <= '0'; ---------------------------------------------------- end Behavioral; 4
FlyingDutch Luty 19, 2023 Udostępnij Luty 19, 2023 Plus za prosty układ i prosty oraz czytelny kod Pozdrawiam 2
kroszkanorber Luty 22, 2023 Autor tematu Udostępnij Luty 22, 2023 WItam. Dziękuję za słowa uznania. Karta którą opisałem w projekcie jest tylko wyświetlaczem graficznym o wyjściu VGA. Błąd opisu kodu dotyczy sygnałów BL= (wygaszanie) i VS= (synchronizacja pionowa) Wprowadziłem małe zmiany w kodzie. Sygnał zapisu do pamięci RAM i przypisanie linii adresowych działa poza obszarem wyświetlanym ( zezwolenie sygnałem BL ). Działa stabilniej przy wyższych częstotliwościach zapisywania danych. Sygnał WE przekierowałem przez sygnał zezwolenia na pin WR i zostawiłem procedurę zapisu dla kontrolera. Cały wyświetlacz zapisuje się w ten sposób z szybkością niezauważalną dla ludzkiego wzroku. ( Dla mnie wystarczy ) W przyszłości chcę użyć sdram i fpga. Bedzie można zrobić małą grafikę animowaną. Potrzebuję pomocy przy wysterowaniu możliwie prostym kodem SDRAM. Nie do końca rozumiem procedury zapisu i odczytu pozdrawiam 1
FlyingDutch Luty 26, 2023 Udostępnij Luty 26, 2023 Dnia 22.02.2023 o 21:35, kroszkanorber napisał: W przyszłości chcę użyć sdram i fpga. Bedzie można zrobić małą grafikę animowaną. Potrzebuję pomocy przy wysterowaniu możliwie prostym kodem SDRAM. Nie do końca rozumiem procedury zapisu i odczytu pozdrawiam Cześć, zobacz ten post - po winien być przydatny: Pozdrawiam 1 1
kroszkanorber Marzec 2, 2023 Autor tematu Udostępnij Marzec 2, 2023 Część. Dziękuję za linki. Czytałem o tym na fpga for fun. Dla mnie najbardziej zrozumiałe. Dzięki informacjom zawartym na stronie fpga for fun zaczynam rozumieć noty katalogowe układów. SDRAM nie są takie szybkie ze względu na sekwencję zapisu i odczytu z adresów nie występujących po sobie. Odświeżanie też jest małym wyzwaniem. Poza tym będę musiał napisać dodatkowy kod do jego obsługi. SRAM są wygodniejsze w obsłudze, za to cena do pojemności... Kody staram się pisać sam bo wiem co robię, a kody napisane przez innych są dla mnie inspiracją i nauką. Dziękuję za pomoc i brnę w to dalej. Inni sobie poradzili... 1
kroszkanorber 28 lutego Autor tematu Udostępnij 28 lutego (edytowany) ---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 22:19:45 02/22/2026 -- Design Name: -- Module Name: VGA_640x480 - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- -- 640x480 @ 60Hz (Industry standard) -- hsync: 31.5kHz -- 640x480 visible area -- 25.2 MHz pixel clock -- cnth -- 640 -- 656 752 -hsync -- 800 -- cntv -- 480 -- 490 492 -vsync -- 525 -- -- SRAM 512kx8 10ns -- -- Clk = 100MHz ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity VGA_640x480 is Port ( Clk : in STD_LOGIC; -- zegar 100 MHz WR : in STD_LOGIC; -- L->H zapis informacji (zatrzask) BUSY : out STD_LOGIC; -- '1' = dane w trakcie zapisu, '0' = gotowy na nowe dane SEL_IN : in STD_LOGIC_VECTOR (4 downto 0); -- wybór 1 z 32 poleceń DATA_IN : in STD_LOGIC_VECTOR (15 downto 0); -- wejście danych 16 bit HS : out STD_LOGIC; -- wyjście dla monitora vga (synchronizacja pozioma) VS : out STD_LOGIC; -- wyjście dla monitora vga (synchronizacja pionowa) RGB : out STD_LOGIC_VECTOR (7 downto 0); -- wyjście dla monitora vga (B 2 bity/ G 3 bity / R 3 bity) RAM_OE : out STD_LOGIC; -- wyjście do sram '0' = zezwolenie na odczyt RAM_WE : out STD_LOGIC; -- wyjście do sram '0' = zezwolenie na zapis RAM_ADDR : out STD_LOGIC_VECTOR (18 downto 0); -- wyjście do sram 19 bit adres RAM_DATA : inout STD_LOGIC_VECTOR (7 downto 0) -- we/wy danych sram ); end VGA_640x480; architecture Behavioral of VGA_640x480 is signal Cnt25 : std_logic_vector (1 downto 0) := "00"; -- dzielnik częstotliwości signal CntH : std_logic_vector (9 downto 0) := "0000000000"; -- licznik kolumn signal CntV : std_logic_vector (9 downto 0) := "0000000000"; -- licznik wierszy signal EnH : std_logic; -- zezwolenie na inkrementację licznika kolumn signal EnV : std_logic; -- zezwolenie na inkrementację licznika wierszy signal Bl : std_logic; -- wygaszanie sygnału rgb signal H : std_logic; -- sygnał synchronizaji pozomej signal V : std_logic; -- sygnał synchronizaji pionowej signal Color : std_logic_vector (7 downto 0); -- kolor zapis sram signal IMcolor : std_logic_vector (15 downto 0) := "0000000000000000"; -- rejestr koloru obrazu(8 bitów) i tła(8 bitów) signal FGcolor : std_logic_vector (7 downto 0); -- kolor obrazu signal BGcolor : std_logic_vector (7 downto 0); -- kolor tła signal CHcolor : std_logic_vector (7 downto 0); -- kolor znaku signal ScrollH : std_logic_vector (9 downto 0) := "0000000000"; -- rejestr przewijania kolumn signal ScrollV : std_logic_vector (8 downto 0) := "000000000"; -- rejestr przewijania wierszy signal Cnthscr : std_logic_vector (9 downto 0); -- suma licznika kolumn i rejestru przewijania kolumn signal Cntvscr : std_logic_vector (8 downto 0); -- suma licznika wierszy i rejestru przewijania wierszy signal Addrmux : std_logic_vector (18 downto 0) := "0000000000000000000"; -- adres sram signal Addrreg : std_logic_vector (18 downto 0) := "0000000000000000000"; -- rejestr adresu sram dla zpisu signal Cnt : std_logic_vector (18 downto 0) := "0000000000000000000"; -- licznik iteracji zapisu signal Charsel : std_logic_vector (7 downto 0); -- adres znaku w tablicy rom signal Charaddr : std_logic_vector (18 downto 0); -- adres jednego pixela zapisywanego znaku signal Clsaddr : std_logic_vector (18 downto 0); -- adres jednego pixela nadpisywanego obrazu signal Wraddr : std_logic_vector (18 downto 0); -- adres jednego pixela zapisywanego obrazu signal We : std_logic := '0'; -- zapis sram signal Cls : std_logic := '0'; -- czyszczenie sram signal Char : std_logic := '0'; -- zapis znaku signal Lthrst : std_logic; -- reset sygnałów signal Wr_en : std_logic; -- sygnał okna czasowego zapisu ram signal Rd_en : std_logic; -- sygnał okna czasowego odczytu ram signal Sync : std_logic; -- synchronizacja sygnałów z zewnątrz signal En : std_logic; -- sygnał zajętości type Ram_type is array (0 to 4095) of std_logic_vector (7 downto 0); signal Spriteram : Ram_type; signal Spr_di : std_logic_vector (7 downto 0) := "00000000"; signal Spr_do : std_logic_vector (7 downto 0); signal Spr_we_a : std_logic_vector (11 downto 0) := "000000000000"; signal Spr_rd_a : std_logic_vector (11 downto 0); signal Spr_cnt : std_logic_vector (9 downto 0); signal Spr_rgb1 : std_logic_vector (3 downto 0); signal Spr_rgb2 : std_logic_vector (3 downto 0); signal Spr_rgb16 : std_logic_vector (3 downto 0); signal Spr_rgb : std_logic_vector (7 downto 0); signal Spr_we : std_logic; signal Spr1_h : std_logic_vector (9 downto 0); signal Spr1_v : std_logic_vector (8 downto 0); signal Spr1_hen : std_logic; signal Spr1_ven : std_logic; signal Spr1_en : std_logic; ---------------------------------------------------------------------------- signal Romaddr : std_logic_vector (10 downto 0) := "00000000000"; -- adres taplicy znaków signal Romdo : std_logic_vector (7 downto 0) := "00000000"; -- wyjście danych tablicy znaków type rom_type is array (0 to 2047) of std_logic_vector (7 downto 0); -- tablica znaków constant Charrom : rom_type:= (X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --01 X"04", X"08", X"1C", X"20", X"20", X"22", X"1C", X"00", --ć --02 X"04", X"08", X"3E", X"04", X"08", X"10", X"3E", X"00", --ź --03 X"18", X"08", X"0E", X"38", X"08", X"08", X"1E", X"00", --ł --04 X"00", X"00", X"1C", X"22", X"3E", X"20", X"1C", X"04", --ę --05 X"04", X"08", X"1C", X"22", X"22", X"22", X"1C", X"00", --ó --06 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --07 X"04", X"08", X"2C", X"32", X"22", X"22", X"22", X"00", --ń --08 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --09 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0A X"08", X"00", X"3E", X"04", X"08", X"10", X"3E", X"00", --ż --0B X"04", X"08", X"1E", X"20", X"1C", X"02", X"3C", X"00", --ś --0C X"00", X"00", X"1C", X"02", X"1E", X"22", X"1E", X"04", --ą --0D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0E X"10", X"08", X"04", X"00", X"00", X"00", X"00", X"00", -- ` --0F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --10 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --11 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --12 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --13 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --14 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --15 X"00", X"00", X"1A", X"26", X"22", X"1E", X"02", X"02", --q --16 X"08", X"18", X"08", X"08", X"08", X"08", X"1C", X"00", --1 --17 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --18 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --19 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1A X"00", X"00", X"3E", X"04", X"08", X"10", X"3E", X"00", --z --1B X"00", X"00", X"1E", X"20", X"1C", X"02", X"3C", X"00", --s --1C X"00", X"00", X"1C", X"02", X"1E", X"22", X"1E", X"00", --a --1D X"00", X"00", X"22", X"22", X"2A", X"2A", X"14", X"00", --w --1E X"1C", X"22", X"02", X"04", X"08", X"10", X"3E", X"00", --2 --1F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --20 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --21 X"00", X"00", X"1C", X"20", X"20", X"22", X"1C", X"00", --c --22 X"00", X"00", X"22", X"14", X"08", X"14", X"22", X"00", --x --23 X"02", X"02", X"1A", X"26", X"22", X"22", X"1E", X"00", --d --24 X"00", X"00", X"1C", X"22", X"3E", X"20", X"1C", X"00", --e --25 X"04", X"0C", X"14", X"24", X"3E", X"04", X"04", X"00", --4 --26 X"3E", X"04", X"08", X"04", X"02", X"22", X"1C", X"00", --3 --27 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --28 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --29 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --2A X"00", X"00", X"22", X"22", X"22", X"14", X"08", X"00", --v --2B X"0C", X"10", X"10", X"38", X"10", X"10", X"10", X"00", --f --2C X"10", X"10", X"38", X"10", X"10", X"12", X"0C", X"00", --t --2D X"00", X"00", X"2C", X"32", X"20", X"20", X"20", X"00", --r --2E X"3E", X"20", X"3C", X"02", X"02", X"22", X"1C", X"00", --5 --2F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --30 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --31 X"00", X"00", X"2C", X"32", X"22", X"22", X"22", X"00", --n --32 X"20", X"20", X"2C", X"32", X"22", X"22", X"3C", X"00", --b --33 X"20", X"20", X"2C", X"32", X"22", X"22", X"22", X"00", --h --34 X"00", X"00", X"1E", X"22", X"22", X"1E", X"02", X"1C", --g --35 X"00", X"00", X"22", X"22", X"22", X"1E", X"02", X"1C", --y --36 X"0C", X"10", X"20", X"3C", X"22", X"22", X"1C", X"00", --6 --37 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --38 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --39 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --3A X"00", X"00", X"34", X"2A", X"2A", X"2A", X"2A", X"00", --m --3B X"04", X"00", X"0C", X"04", X"04", X"04", X"24", X"18", --j --3C X"00", X"00", X"22", X"22", X"22", X"26", X"1A", X"00", --u --3D X"3E", X"22", X"04", X"08", X"10", X"10", X"10", X"00", --7 --3E X"1C", X"22", X"22", X"1C", X"22", X"22", X"1C", X"00", --8 --3F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --40 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --41 X"00", X"00", X"00", X"00", X"18", X"18", X"08", X"10", -- , --42 X"20", X"20", X"24", X"28", X"30", X"28", X"24", X"00", --k --43 X"08", X"00", X"18", X"08", X"08", X"08", X"1C", X"00", --i --44 X"00", X"00", X"1C", X"22", X"22", X"22", X"1C", X"00", --o --45 X"1C", X"22", X"26", X"2A", X"32", X"22", X"1C", X"00", --0 --46 X"1C", X"22", X"22", X"1E", X"02", X"22", X"1C", X"00", --9 --47 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --48 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --49 X"00", X"00", X"00", X"00", X"00", X"18", X"18", X"00", -- . --4A X"00", X"02", X"04", X"08", X"10", X"20", X"00", X"00", -- / --4B X"18", X"08", X"08", X"08", X"08", X"08", X"1C", X"00", --l --4C X"00", X"00", X"18", X"18", X"00", X"18", X"08", X"10", -- ; --4D X"00", X"00", X"3C", X"22", X"22", X"3C", X"20", X"20", --p --4E X"00", X"00", X"00", X"3E", X"00", X"00", X"00", X"00", -- - --4F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --50 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --51 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --52 X"18", X"08", X"08", X"00", X"00", X"00", X"00", X"00", -- ' --53 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --54 X"1C", X"10", X"10", X"10", X"10", X"10", X"1C", X"00", -- [ --55 X"00", X"00", X"3E", X"00", X"3E", X"00", X"00", X"00", -- = --56 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --57 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --58 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --59 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --5A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --5B X"1C", X"04", X"04", X"04", X"04", X"04", X"1C", X"00", -- ] --5C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --5D X"00", X"20", X"10", X"08", X"04", X"02", X"00", X"00", -- \ --5E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --5F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --60 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --61 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --62 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --63 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --64 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --65 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --66 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --67 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --68 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --69 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --6F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --70 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --71 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --72 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --73 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --74 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --75 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --76 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --77 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --78 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --79 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --7F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --80 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --81 X"04", X"1C", X"22", X"20", X"20", X"22", X"1C", X"00", --Ć --82 X"04", X"3E", X"04", X"08", X"10", X"20", X"3E", X"00", --Ź --83 X"20", X"20", X"2C", X"30", X"20", X"20", X"3E", X"00", --Ł --84 X"3E", X"20", X"20", X"3C", X"20", X"20", X"3E", X"02", --Ę --85 X"04", X"1C", X"22", X"22", X"22", X"22", X"1C", X"00", --Ó --86 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --87 X"04", X"2A", X"32", X"32", X"2A", X"26", X"22", X"00", --Ń --88 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --89 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8A X"08", X"3E", X"04", X"08", X"10", X"20", X"3E", X"00", --Ż --8B X"04", X"1E", X"20", X"1C", X"02", X"02", X"3C", X"00", --Ś --8C X"1C", X"22", X"22", X"22", X"3E", X"22", X"24", X"02", --Ą --8D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8E X"00", X"00", X"10", X"2A", X"04", X"00", X"00", X"00", -- ~~ --8F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --90 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --91 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --92 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --93 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --94 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --95 X"1C", X"22", X"22", X"22", X"2A", X"24", X"1A", X"00", --Q --96 X"08", X"08", X"08", X"08", X"08", X"00", X"08", X"00", --! --97 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --98 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --99 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9A X"3E", X"02", X"04", X"08", X"10", X"20", X"3E", X"00", --Z --9B X"1E", X"20", X"20", X"1C", X"02", X"02", X"3C", X"00", --S --9C X"1C", X"22", X"22", X"22", X"3E", X"22", X"22", X"00", --A --9D X"22", X"22", X"22", X"2A", X"2A", X"2A", X"14", X"00", --W --9E X"1C", X"22", X"02", X"1A", X"2A", X"2A", X"1C", X"00", --@ --9F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A1 X"1C", X"22", X"20", X"20", X"20", X"22", X"1C", X"00", --C --A2 X"22", X"22", X"14", X"08", X"14", X"22", X"22", X"00", --X --A3 X"38", X"24", X"22", X"22", X"22", X"24", X"38", X"00", --D --A4 X"3E", X"20", X"20", X"3C", X"20", X"20", X"3E", X"00", --E --A5 X"08", X"1E", X"28", X"1C", X"0A", X"3C", X"08", X"00", --$ --A6 X"14", X"14", X"3E", X"14", X"3E", X"14", X"14", X"00", --# --A7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AA X"22", X"22", X"22", X"22", X"22", X"14", X"08", X"00", --V --AB X"3E", X"20", X"20", X"3C", X"20", X"20", X"20", X"00", --F --AC X"3E", X"08", X"08", X"08", X"08", X"08", X"08", X"00", --T --AD X"3C", X"22", X"22", X"3E", X"28", X"24", X"22", X"00", --R --AE X"30", X"32", X"04", X"08", X"10", X"26", X"05", X"00", --% --AF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B1 X"22", X"22", X"32", X"2A", X"26", X"22", X"22", X"00", --N --B2 X"3C", X"22", X"22", X"3C", X"22", X"22", X"3C", X"00", --B --B3 X"22", X"22", X"22", X"3E", X"22", X"22", X"22", X"00", --H --B4 X"1C", X"22", X"20", X"2E", X"22", X"22", X"1E", X"00", --G --B5 X"22", X"22", X"22", X"14", X"08", X"08", X"08", X"00", --Y --B6 X"08", X"14", X"22", X"00", X"00", X"00", X"00", X"00", --^ --B7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BA X"22", X"36", X"2A", X"22", X"22", X"22", X"22", X"00", --M --BB X"1C", X"04", X"04", X"04", X"04", X"24", X"18", X"00", --J --BC X"22", X"22", X"22", X"22", X"22", X"22", X"1C", X"00", --U --BD X"18", X"24", X"28", X"10", X"2A", X"24", X"1A", X"00", --& --BE X"00", X"2A", X"1C", X"3E", X"1C", X"2A", X"00", X"00", --* --BF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C1 X"04", X"08", X"10", X"20", X"10", X"08", X"04", X"00", -- < --C2 X"22", X"24", X"28", X"30", X"28", X"24", X"22", X"00", --K --C3 X"1C", X"08", X"08", X"08", X"08", X"08", X"1C", X"00", --I --C4 X"1C", X"22", X"22", X"22", X"22", X"22", X"1C", X"00", --O --C5 X"10", X"08", X"04", X"04", X"04", X"08", X"10", X"00", --) --C6 X"04", X"08", X"10", X"10", X"10", X"08", X"04", X"00", --( --C7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C9 X"10", X"08", X"04", X"02", X"04", X"08", X"10", X"00", -- > --CA X"1C", X"22", X"02", X"04", X"08", X"00", X"08", X"00", -- ? --CB X"20", X"20", X"20", X"20", X"20", X"20", X"3E", X"00", --L --CC X"00", X"00", X"18", X"18", X"00", X"18", X"18", X"00", -- : --CD X"3C", X"22", X"22", X"3C", X"20", X"20", X"20", X"00", --P --CE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"3E", -- _ --CF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D2 X"14", X"14", X"14", X"00", X"00", X"00", X"00", X"00", -- " --D3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D4 X"04", X"08", X"08", X"10", X"08", X"08", X"04", X"00", -- { --D5 X"00", X"08", X"08", X"3E", X"08", X"08", X"00", X"00", -- + --D6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DB X"10", X"08", X"08", X"04", X"08", X"08", X"10", X"00", -- } --DC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DD X"08", X"08", X"08", X"08", X"08", X"08", X"08", X"00", -- | --DE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --ED X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00" ); ---------------------------------------------------------------------------- begin --dzielnik częstotliwości Clk = 100MHz process(Clk) begin if Clk'event and Clk = '0' then Cnt25 <= Cnt25 + 1; end if; end process; EnH <= '1' when (cnt25 = 2) else '0'; --EnH = 100MHz/4 = 25MHz --licznik kolumn process(Clk) begin if rising_edge(Clk) then if EnH = '1' then if CntH = 799 then CntH <= (others => '0'); else CntH <= CntH + 1; end if; end if; end if; end process; EnV <= '1' when (CntH = 799 and cnt25 = 2) else '0'; --EnV = 25MHz/800 = 31,25kHz --licznik wierszy process(Clk) begin if rising_edge(Clk) then if EnV = '1' then if CntV = 524 then CntV <= (others => '0'); else CntV <= CntV + 1; end if; end if; end if; end process; H <= '0' when ((CntH > 655) and (CntH < 753)) else '1'; --dekoder sygnału synchronizacji poziomej V <= '0' when ((CntV > 489) and (CntV < 493)) else '1'; --dekoder sygnału synchronizacji pionowej Bl <= '0' when ((CntH > 639) or (CntV > 479)) else '1'; --dekoder wygaszania obrazu poza obszarem wyświetlanym -- wyświetlanie obrazu process(Clk) begin if rising_edge(Clk) then if Cnt25 = 0 then if Bl = '0' then RGB <= (others => '0'); else if Spr1_en = '1' then RGB <= Spr_rgb; else RGB <= RAM_DATA; end if; end if; HS <= H; VS <= V; end if; end if; end process; -- zatrzask sygnału zapisu do pamięci ram process(WR, Lthrst) begin if Lthrst = '1' then We <= '0'; -- zapis koloru pixela sram Char <= '0'; -- zapis znaku Cls <= '0'; -- czyszczenie obrazu sram Spr_we <= '0'; -- zapisywanie koloru pixela sprite elsif rising_edge(WR) then if En = '0' then case SEL_IN is when "00000" => IMcolor <= DATA_IN; when "00001" => Charsel <= DATA_IN(7 downto 0); when "00010" => Addrreg(9 downto 0) <= DATA_IN(9 downto 0); when "00011" => Addrreg(18 downto 10) <= DATA_IN(8 downto 0); when "00100" => Addrreg(9 downto 0) <= Addrreg(9 downto 0) + 1; when "00101" => Addrreg(9 downto 0) <= Addrreg(9 downto 0) - 1; when "00110" => Addrreg(18 downto 10) <= Addrreg(18 downto 10) + 1; when "00111" => Addrreg(18 downto 10) <= Addrreg(18 downto 10) - 1; when "01000" => ScrollH <= ScrollH + 1; when "01001" => ScrollH <= ScrollH - 1; when "01010" => ScrollV <= ScrollV + 1; when "01011" => ScrollV <= ScrollV - 1; when "01100" => We <= '1'; when "01101" => Cls <= '1'; when "01110" => Char <= '1'; when "10000" => Spr_di <= DATA_IN(7 downto 0); when "10001" => Spr_we_a <= DATA_IN(11 downto 0); when "10010" => Spr_we <= '1'; when "10011" => Spr1_h <= DATA_IN(9 downto 0); when "10100" => Spr1_v <= DATA_IN(8 downto 0); when others => Addrreg <= (others => '0'); ScrollH <= (others => '0'); ScrollV <= (others => '0'); end case; end if; end if; end process; -- BGcolor <= IMcolor(7 downto 0); FGcolor <= IMcolor(15 downto 8); -- synchronizacja sygnałów sterujących process(Clk) begin if rising_edge(Clk) then Sync <= We or Cls or Char or Spr_we; end if; end process; -- sterowanie długością zapisu i odczytu process(Clk) begin if rising_edge(Clk) then if Cnt25 = 2 and Sync = '1' then if We = '1' or Spr_we = '1' then -- zapis jednej komórki ram if Cnt = 2 then Cnt <= (others => '0'); Lthrst <= '1'; else Cnt <= Cnt + 1; end if; elsif Char = '1' then -- zapis znaku 8x8 if Cnt = 63 then Cnt <= (others => '0'); Lthrst <= '1'; else Cnt <= Cnt + 1; end if; elsif Cls = '1' then -- czyszczenie pamięci ram if Cnt = 524287 then Cnt <= (others => '0'); Lthrst <= '1'; else Cnt <= Cnt + 1; end if; end if; end if; if Cnt = 0 then Lthrst <= '0'; end if; end if; end process; -- sygnał zajętości En <= '0' when Cnt = 0 else '1'; BUSY <= En; -- sterowanie sygnałami adresów Charaddr <= (Addrreg(18 downto 13) & Cnt(5 downto 3) & Addrreg(9 downto 3) & Cnt(2 downto 0)) and (18 downto 0 => Char); Clsaddr <= Cnt and (18 downto 0 => Cls); Wraddr <= Addrreg and (18 downto 0 => We); Addrmux <= Charaddr or Clsaddr or Wraddr; Cnthscr <= CntH + ScrollH; Cntvscr <= CntV(8 downto 0) + ScrollV; -- odczyt znaków z tablicy rom Romaddr <= Charsel & Cnt(5 downto 3); process(Clk) begin if rising_edge(Clk) then Romdo <= Charrom (conv_integer(Romaddr)); end if; end process; -- wybór koloru pixela znaku i tła znaku process(Romdo, Cnt, FGcolor, BGcolor) begin case Cnt(2 downto 0) is when "000" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(7))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "001" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(6))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "010" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(5))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "011" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(4))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "100" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(3))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "101" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(2))) or (BGcolor and (7 downto 0 => not Romdo(7))); when "110" => CHcolor <= (FGcolor and (7 downto 0 => Romdo(1))) or (BGcolor and (7 downto 0 => not Romdo(7))); when others => CHcolor <= (FGcolor and (7 downto 0 => Romdo(0))) or (BGcolor and (7 downto 0 => not Romdo(7))); end case; end process; -- sterowanie sygnałem danych Color <= (CHcolor and (7 downto 0 => Char)) or (FGcolor and (7 downto 0 => We)) or (BGcolor and (7 downto 0 => Cls)); -- zapis Cnt25 = 1,2 / odczyt Cnt = 0,3 Rd_en <= Cnt25(1) xnor Cnt25(0); Wr_en <= (Cnt25(1) xor Cnt25(0)) and (We or Cls or Char); -- sterowanie portami sram RAM_ADDR <= ((Cntvscr & Cnthscr) and (18 downto 0 => Rd_en)) or (Addrmux and (18 downto 0 => Wr_en)); RAM_DATA <= Color when (Wr_en = '1') else (others => 'Z'); RAM_WE <= not (Wr_en and Cnt25(1)); RAM_OE <= Wr_en; -- sprite process(Clk) begin if rising_edge(Clk) then if Spr_we = '1' then Spriteram(conv_integer(Spr_we_a)) <= Spr_di; end if; Spr_do <= Spriteram(conv_integer(Spr_rd_a)); end if; end process; -- maskowanie sygnałów rgb sprite Spr_rgb1 <= Spr_do(7 downto 4) and (3 downto 0 => not Spr_cnt(0)); Spr_rgb2 <= Spr_do(3 downto 0) and (3 downto 0 => Spr_cnt(0)); Spr_rgb16 <= Spr_rgb1 or Spr_rgb2; with Spr_rgb16 & Spr1_en select Spr_rgb <= "00000010" when "00011", "00001100" when "00101", "00001001" when "00111", "00010100" when "01001", "00010010" when "01011", "00110110" when "01101", "00111111" when "01111", "10000000" when "10001", "01000010" when "10011", "01010000" when "10101", "10000111" when "10111", "01010000" when "11001", "01010010" when "11011", "11111000" when "11101", "11111111" when "11111", "00000000" when others; -- komparator adresu sprite Spr1_hen <= '1' when (Cnth >= Spr1_h and CntH <= Spr1_h + 31) else '0'; Spr1_ven <= '1' when (CntV >= Spr1_v and CntV <= Spr1_v + 31) else '0'; Spr1_en <= Spr1_hen and Spr1_ven; -- licznik kolumn i wierszy sprite process(Clk, Spr1_ven, Spr1_hen) begin if Spr1_ven = '0' then Spr_cnt <= (others => '0'); elsif Spr1_hen = '0' then Spr_cnt(4 downto 0) <= (others => '0'); elsif rising_edge(Clk) then if Cnt25 = 2 then Spr_cnt(4 downto 0) <= Spr_cnt(4 downto 0) + 1; end if; if EnV = '1' then Spr_cnt(9 downto 0) <= Spr_cnt(9 downto 0) + 1; end if; end if; end process; -- przypisanie adresu sprite Spr_rd_a <= "0000" & Spr_cnt(9 downto 6) & Spr_cnt(4 downto 1); end Behavioral; Witam. Projekt rozwijam na układzie spartan xc3s50a. W kodzie inspirowałem się układem vic-II z commodore c64. Moje informacje na temat tego układu są nie szczegółowe i dotyczą jego funkcjonalności (nie widzę potrzeby by zagłębiać się w głębiej w działanie vic). sugerowałem się wpisywaniem znaków i ich wyświetlaniem, duszkami. projekt jest w fazie rozwoju i nie jest kompletny. Względem poprzedniego kodu poprawiłem synchronizację zapisu do sram i odczytu danych z sram. sram to bufor (tablica) obrazu 1024x512 pixeli 256 kolorów każdy. Dodałem przewijanie poziome i pionowe tablicy obrazu zapisanego w sram. dodałem tez możliwość wpisania znaku z klawiatury po wcześniejszym podaniu współrzędnych znaku. 64byte ( bitmapa znaku), 256 kolorów dla tła i znaku, są automatycznie wpisywane z tablicy znaków rom do sram. Dopisałem obsługę sprite z dekoderem pozycji. sprite wyświetlany jest w rozdzielczości 32x32 pixele o 16 kolorach każdy. Pozostała pamięć bram 4096x8 pozwala na wyświetanie 16 sprite. jak wcześniej napisałem projekt w fazie rozwoju i w niedalekim czasie dopisze nowe funkcje takie jak kolizje sprite i priorytet wyświetlania. piszę projekt w ise 14.6 i mój vhdl nie może być tak nowoczesny jak w vivado zdjęcie niezainicjowanego obrazu (pamięć sram po włączeniu zasilania ma zapisane losowe wartości) Zdjęcie zainicjowanej pamięci sram (użyłem funkcji Cls) w lewym górnym rogu ( widoczny kwadrat...) modyfikowałem tymczasowo kod dla wyświetlenia sprite 32x32 pixele na ostatnim zdjęciu moja nowa platforma testowa spartan 3 z układem xc3s400, 5 kości sram 512kx8 i inne peryferia użyte do testów. pozdrawiam Edytowano 1 marca przez kroszkanorber 1
kroszkanorber 28 lutego Autor tematu Udostępnij 28 lutego (edytowany) Architektura modułu VGA 640×480 (Spartan‑3, SRAM 512 kB) Poniższy moduł to kompletny silnik graficzny pracujący w standardzie VGA 640×480 @ 60 Hz, z pełnym framebufferem w zewnętrznej pamięci SRAM 512 kB, obsługą sprite’a, przewijaniem obrazu i własną tablicą znaków. Całość działa na zegarze 100 MHz i nie korzysta z żadnych IP‑core’ów – wszystko jest napisane w czystym VHDL. 1. Generacja sygnałów VGA. Moduł generuje sygnały zgodne z klasycznym standardem VGA: 25 MHz pixel clock (dzielnik z 100 MHz), CntH 0–799 – licznik kolumn, CntV 0–524 – licznik wierszy, HSYNC aktywny w zakresie 656–752, VSYNC aktywny w zakresie 490–492, obszar widoczny 640×480, reszta wygaszona. Sygnały synchronizacji i blankingu są generowane sprzętowo na podstawie liczników. 2. Framebuffer w SRAM 512 kB. Obraz jest przechowywany w zewnętrznej pamięci 512 kB × 8 bit. Moduł generuje: RAM_ADDR – 19‑bitowy adres, RAM_DATA – magistralę danych, RAM_OE / RAM_WE – sterowanie odczytem i zapisem. Odczyt odbywa się w czasie rzeczywistym podczas generowania obrazu. Zapis jest wykonywany w oknach czasowych, aby nie zakłócać odczytu. 3. Interfejs sterujący (pod przyszłe MCU 16‑bit). Moduł ma prosty interfejs: WR – impuls L→H wyzwalający zapis, SEL_IN[4:0] – wybór jednej z 32 komend, DATA_IN[15:0] – dane 16‑bitowe, BUSY – sygnał zajętości. Pozwala to na łatwe sterowanie grafiką z zewnętrznego procesora (w przyszłości własny MCU 16‑bit). 4. Scroll poziomy i pionowy. Moduł posiada rejestry: ScrollH (10 bit) – przesunięcie poziome, ScrollV (9 bit) – przesunięcie pionowe. Przesunięcie jest dodawane do liczników CntH i CntV, co daje płynne przewijanie całego obrazu bez zmiany zawartości pamięci. 5. Sprite engine (1 sprite 16×16, 16 kolorów). Wbudowana pamięć BRAM (4 kB) przechowuje dane sprite’a. Moduł obsługuje: pozycję sprite’a (h/v), maskowanie, kolor 16‑poziomowy (4 bity), priorytet nad tłem. Sprite jest nakładany na obraz w czasie rzeczywistym. 6. Generator znaków (ROM 2 kB). W module znajduje się tablica znaków: 256 znaków × 8 wierszy, pełne polskie znaki (ą, ę, ś, ć, ł, ż, ź, ó, ń), zapisane jako stała ROM w VHDL. Pozwala to na sprzętowe wyświetlanie tekstu bez udziału procesora. 7. Obsługa czyszczenia ekranu i zapisu pikseli. Moduł posiada trzy tryby zapisu: CLS – czyszczenie całej pamięci SRAM, CHAR – zapis znaku z ROM do framebuffer’a, WE – zapis pojedynczego piksela. Każdy tryb ma własny generator adresów i licznik iteracji. 8. Pipeline wyjściowy RGB. Wyjście RGB (8 bitów: R3 G3 B2) jest wybierane według priorytetu: sprite (jeśli aktywny), dane z SRAM, czarne tło poza obszarem widocznym. Sygnały HS/VS i RGB są aktualizowane w fazie Cnt25 = 0, co zapewnia stabilny timing. 9. Co jest już gotowe. pełne timingi VGA 640×480, odczyt z SRAM w czasie rzeczywistym, zapis pikseli, znaków i czyszczenie ekranu, scroll H/V, sprite 16×16, tablica znaków z polskimi literami, interfejs sterujący pod MCU. 10. Co planuję dodać. priorytety wielu sprite’ów, wykrywanie kolizji, paletę kolorów (LUT), tilemapę 8×8 lub 16×16, tryb tekstowy 80×30,DMA z MCU. Jeśli ktoś chce się pobawić grafiką na FPGA bez użycia gotowych IP‑core’ów, to ten moduł jest dobrym punktem startowym. Konstrukcja jest w pełni otwarta i można ją rozwijać w dowolnym kierunku ┌────────────┐ │ VGA_640x480 │ └────────────┘ │ ▼ ┌───────────┐ │ CLK 100 MHz │ └───────────┘ │ ▼ ┌───────────┐ │ Dzielnik 25 MHz│ └───────────┘ │ ▼ ┌──────────────────────┐ │ Liczniki CntH / CntV │ │ - generacja pozycji piksela │ │ - okna HSYNC / VSYNC / BLANK │ └──────────────────────┘ │ ▼ ┌────────────────────────────┐ │ Generator adresu RAM │ │ - ScrollH / ScrollV │ │ - Addrmux (adres odczytu) │ │ - Addrreg (adres zapisu) │ └────────────────────────────┘ │ ▼ ┌─────────────────────┐ │ SRAM 512 kB │ │ - RAM_ADDR (19 bit) │ │ - RAM_DATA (8 bit) │ │ - RAM_OE / RAM_WE │ └─────────────────────┘ │ ▼ ┌──────────────────────────┐ │ MUX koloru wyjściowego │ │ - Sprite (jeśli aktywny) │ │ - Dane z RAM │ │ - Czarne tło poza obszarem │ └──────────────────────────┘ │ ▼ ┌────────────────────┐ │ Wyjście VGA: RGB / HS / VS │ └────────────────────┘ ┌─────────────────────────┐ │ Sprite Engine │ │ - BRAM 4 kB (16×16, 16 kolorów) │ │ - Spr1_h / Spr1_v (pozycja) │ │ - Spr_cnt (licznik pikseli) │ │ - Spr_rgb (kolor sprite’a) | └─────────────────────────┘ ┌────────────────────────┐ │ Generator znaków │ │ - ROM 2 kB (256 znaków × 8 linii) │ │ - Charaddr (adres piksela znaku) │ │ - CHcolor (kolor znaku) │ └────────────────────────┘ ┌─────────────────────────┐ │ Interfejs sterujący MCU │ │ - WR (zatrzask komendy) │ │ - SEL_IN (5 bit – wybór polecenia) │ │ - DATA_IN (16 bit – dane) │ │ - BUSY (moduł zajęty) │ └─────────────────────────┘ Opis protokołu WR / SEL / DATA Moduł VGA ma prosty interfejs sterujący, który pozwala na wysyłanie komend z zewnętrznego procesora (lub innego układu FPGA). Interfejs jest jednokierunkowy i poziomowy, bez zegara – działa na zasadzie „zatrzasku”. Sygnały sterujące: WR – impuls L→H wyzwalający wykonanie komendy, SEL_IN[4:0] – numer komendy (0–31), DATA_IN[15:0] – dane 16‑bitowe, BUSY – informacja, czy moduł jest zajęty Jak działa zapis. MCU ustawia: SEL_IN – numer komendy, DATA_IN – dane. MCU podaje impuls: WR = 0 → 1. Moduł VGA: zatrzaskuje dane, ustawia BUSY = 1, wykonuje operację (np. zapis piksela, zapis znaku, scroll, CLS), po zakończeniu ustawia BUSY = 0. MCU może wysłać kolejną komendę. Przykładowe komendy (przykładowe znaczenie) SEL_IN Funkcja Dane (DATA_IN) 0x00 Ustaw kolor tła[15:8] FG, [7:0] BG 0x01 Ustaw pozycję sprite’a H w [15:8], V w [7:0] 0x02 Zapis piksela adres w DATA_IN, kolor w rejestrze 0x03Zapis znak kod znaku + pozycja 0x04 Scroll poziomy DATA_IN[9:0] 0x05 Scroll pionowy DATA_IN[8:0] 0x06 CLS – czyszczenie ekran ignoruje DATA_IN Przykład użycia (pseudokod MCU) Kod DATA_IN = 0x001F; -- kolor SEL_IN = 0x00; -- ustaw kolor WR = 1; WR = 0; -- impuls czekaj aż BUSY = 0; Dlaczego ten protokół jest dobry. działa bez zegara – łatwy do podłączenia do dowolnego MCU, nie wymaga synchronizacji domen zegarowych, jest odporny na jitter, pozwala na rozbudowę (32 komendy), jest prosty do debugowania. Tabela komend sterujących modułem VGA (WR / SEL / DATA) Moduł VGA obsługuje 32 komendy, wybierane przez SEL_IN[4:0]. Każda komenda jest wykonywana po impulsie WR = 0 → 1. W trakcie wykonywania operacji moduł ustawia BUSY = 1. Poniżej znajduje się pełna tabela komend, zgodna z aktualną architekturą modułu. Lista komend (SEL_IN → funkcja) SELNazwa komendyOpis działaniaFormat DATA_IN 0x00Ustaw kolor FG/BGUstawia kolor obrazu i tła[15:8] FG, [7:0] BG 0x01 Ustaw pozycję sprite’a Ustawia pozycję sprite’a 16×16[15:8] X, [7:0] Y 0x02 Zapis piksela Zapisuje 1 piksel do SRAM[15:0] adres lub współrzędne 0x03 Zapis znaku Rysuje znak z ROM w framebufferze[15:8] kod, [7:0] pozycja 0x04 Scroll poziomy Ustawia przesunięcie poziome[9:0] ScrollH 0x05 Scroll pionowy Ustawia przesunięcie pionowe[8:0] ScrollV 0x06 CLS (Clear Screen)Czyści cały framebuffer SRAM ignorowane 0x07 Zapis do sprite RAM Zapisuje bajt do BRAM sprite’a[15:12] adres, [7:0] dane 0x08 Ustaw kolor sprite’a Ustawia paletę sprite’a[7:0] kolor 0x09 Ustaw adres zapisu Ustawia rejestr adresu RAM[18:0] adres (w 2 cyklach) 0x0A Zapis kolejnego bajtu Zapisuje bajt pod aktualny adres[7:0] dane 0x0B Inkrementuj adres Przesuwa adres o +1ignorowane 0x0C Ustaw CHcolor Kolor znaków (tekst)[7:0] kolor 0x0D Ustaw FGcolor Kolor obrazu[7:0] kolor 0x0E Ustaw BGcolor Kolor tła[7:0] kolor 0x0F Rezerwacja wolne— SEL 0x10–0x1F – wolne, do przyszłych funkcji: tilemapa, kolizje, priorytety sprite’ów, DMA, paleta kolorów. Opis działania komend 0x00 – Ustaw kolor FG/BG Ustawia dwa kolory jednocześnie: FG – kolor obrazu (pikseli), BG – kolor tła. 0x01 – Pozycja sprite’a Ustawia współrzędne sprite’a 16×16: X w DATA_IN[15:8], Y w DATA_IN[7:0]. 0x02 – Zapis piksela Zapisuje pojedynczy piksel do SRAM. Adres może być: bezpośredni (19 bitów), lub wyliczany przez MCU. 0x03 – Zapis znaku Rysuje znak z ROM (8×8) w framebufferze. 0x04 / 0x05 – Scroll H/V Przesuwa cały obraz bez zmiany zawartości RAM. 0x06 – CLS Czyści cały framebuffer (512 kB). Moduł ustawia BUSY = 1 na czas operacji. 0x07 – Zapis do sprite RAM Zapisuje bajt do BRAM sprite’a (4 kB). 0x08 – Kolor sprite’a Ustawia kolor sprite’a (8 bitów). 0x09 / 0x0A / 0x0B – Tryb ręcznego zapisu RAM Pozwala MCU zapisywać RAM jak zwykłą pamięć: 0x09 – ustaw adres 0x0A – zapisz bajt 0x0B – inkrementuj adres Idealne do szybkiego ładowania grafik. pozdrawiam Edytowano 1 marca przez kroszkanorber 1
kroszkanorber 6 marca Autor tematu Udostępnij 6 marca Witam Projekt finalny musiałem okroić do 8 sprite ze względu na ograniczone zasoby xc3s50a i zrezygnowałem z generatora kolizji. Zacznę od generatora kolizji: W moim założeniu kolizja miała występować gdy aktywny piksel sprite x pokrywa się z aktywnym pikselem sprite y. Jest to możliwe do realizacji i odczycie, ale forma dekodera musi przebiegać sekwencyjnie i nie mieści się w mojej architekturze opartej na 4 taktach zegara 100MHz/ 1 cykl = 25MHz. Projekt opiera się na wbudowanych pamięciach bram i lut więc nigdy nie będzie odzwierciedlać oryginalnej integracji układu vic II (pomijając fakt sygnałów propagacji w układach z lat 80 i dzisiejszych, dla mnie dwa różne światy). Podsumowując , generator sprite nie jest w stanie odczytać pozycji aktualnie zainicjowanego piksela dla każdego sprite i wybór jest priorytetowy, ze względu na ograniczenia układu, który nie jest vic II. Wracając do tematu... Zapis kolejnego znaku asci się nie zmienił i po podaniu współrzędnych x , y dla lewego górnego rogu i następnie podaniu komendy Char, następuje automatyczny zapis jako format bitmap w rozdzielczości 8 * 8 pikseli. Taką komendą zapisujemy tylko 1 zank. w przyszłości podam uniwersalny wzór na renderowanie tekstu z poziomu kontrolera (w komputerach za kontrolę tekstu odpowiedzialny jest software i ma to uzasadnienie w postaci np. zmiany wymiarów okna... idt...) Niemniej jest to do ogarnięcia w prosty sposób, a słowem kluczowym jest endline i inne podobne znaki asci na początku, czyli od X"00" do X"33" (listę kodów asci przerabiam z PS2ScanCodeSet2 i będzie tez niedługo dostępna). Kod dla licznika kolumn i wierszy dla generatora sprite: Sygnał Size oznacza "zwielokrotnienie" piksela dla licznika wierszy i kolumn. gdy = 0 Liczniki liczą co jeden Piksel. gdy = 2 liczą co drugi piksel co powoduje dwukrotne powiększenie. Size jest 2 bitowy i możemy w ten sposób powielać piksel do 4 razy co daje 4 krotne powiększenie. Sygnał Sprite_en oznacza, że oba liczniki są aktywne = 1. Divv i Divh są dzielnikami liczników kolumn i wierszy i są porównywane z wartością size w celu uzyskania powiększenia. EnV i EnH są sygnałami zezwolenia na inkrementację i są zsynchronizowane z licznikiem vga. Spr_hen i Spr_ven są wejściami komparatorów dla górnej i lewej krawędzi sprite i odblokowują liczniki kolumn i wierszy wyświetlanego sprite. Clk jest zegarem systemowym i w moim przypadku wynosi 100 MHz. (układ xc3s50a posiada mnożniki i można taki zegar uzyskać z generatora 25 MHz za pomocą wbudowanego DCM przez mnożenie * 4) Spr_Cntv i Spr_Cnth to liczniki adresów piksela dla jednego sprite. Liczniki 4 bitowe liczą do 16. czyli mamy 16 * 16 pixeli na 1 sprite. ---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 20:47:02 03/02/2026 -- Design Name: -- Module Name: Sprite_cnt - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity Sprite_cnt is Port ( Spr_hen : in STD_LOGIC; Spr_ven : in STD_LOGIC; Clk : in STD_LOGIC; EnH : in STD_LOGIC; EnV : in STD_LOGIC; Size : in STD_LOGIC_VECTOR (1 downto 0); Spr_en : out STD_LOGIC; Spr_cnth : out STD_LOGIC_VECTOR (3 downto 0); Spr_cntv : out STD_LOGIC_VECTOR (3 downto 0) ); end Sprite_cnt; architecture Behavioral of Sprite_cnt is signal Divh : std_logic_vector (1 downto 0) := "00"; signal Divv : std_logic_vector (1 downto 0) := "00"; signal Cnth : std_logic_vector (4 downto 0) := "10000"; signal Cntv : std_logic_vector (4 downto 0) := "10000"; begin Sprite_h : process(Clk, Spr_hen) begin if Spr_hen = '0' then Cnth(4) <= '0'; Divh <= "00"; elsif rising_edge(Clk) then if EnH = '1' then if Cnth(4) = '0' and Divh = Size then Cnth <= Cnth + 1; end if; if Divh = size then Divh <= "00"; else Divh <= Divh + 1; end if; end if; end if; end process; Sprite_v : process(Clk, Spr_ven) begin if Spr_ven = '0' then Cntv(4) <= '0'; Divv <= "00"; elsif rising_edge(Clk) then if EnV = '1' then if Cntv(4) = '0' and Divv = Size then Cntv <= Cntv + 1; end if; if Divv = size then Divv <= "00"; else Divv <= Divv + 1; end if; end if; end if; end process; Spr_cnth <= Cnth(3 downto 0); Spr_cntv <= CntV(3 downto 0); Spr_en <= Cnth(4) nand CntV(4); end Behavioral; Pozdrawiam
kroszkanorber 13 marca Autor tematu Udostępnij 13 marca witam. Zmieniłem inicjację CharRom, by była zgodna z ascicode. poniżej gotowy plik. -- tablica znaków CharRom -- -- Implementacja BRAM FPGA SPARTAN 3 -- Adres 11 bit = 2048x8 -- -- przykład kodowania znaku 'A': -- -- X"1C', X"22", X"22, X"22", X"3E", X"22", X"22", X"00" -- -- 0 1 2 3 4 5 6 7 -- _________________ -- X"1C" 0 | 0 0 0 1 1 1 0 0 -- X"22" 1 | 0 0 1 0 0 0 1 0 -- X"22" 2 | 0 0 1 0 0 0 1 0 -- X"22" 3 | 0 0 1 0 0 0 1 0 -- X"3E" 4 | 0 0 1 1 1 1 1 0 -- X"22" 5 | 0 0 1 0 0 0 1 0 -- X"22" 6 | 0 0 1 0 0 0 1 0 -- X"00" 7 | 0 0 0 0 0 0 0 0 -- adres(8 bitów) | bajty danych znaku (wybierane przez dolne 3 bity adresu) razem 11 bitów adresu --00 = (górne 8 bitów) X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- (dolne 3 bity) --01 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --02 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --03 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --04 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --05 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --06 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --07 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --08 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --09 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --0F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --10 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --11 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --12 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --13 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --14 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --15 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --16 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --17 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --18 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --19 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --1F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --20 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --21 X"08", X"08", X"08", X"08", X"08", X"00", X"08", X"00", -- ! --22 X"14", X"14", X"14", X"00", X"00", X"00", X"00", X"00", -- " --23 X"14", X"14", X"3E", X"14", X"3E", X"14", X"14", X"00", -- # --24 X"08", X"1E", X"28", X"1C", X"0A", X"3C", X"08", X"00", -- $ --25 X"30", X"32", X"04", X"08", X"10", X"26", X"05", X"00", -- % --26 X"18", X"24", X"28", X"10", X"2A", X"24", X"1A", X"00", -- & --27 X"18", X"08", X"08", X"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", --28 X"04", X"08", X"10", X"10", X"10", X"08", X"04", X"00", -- ( X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --29 X"10", X"08", X"04", X"04", X"04", X"08", X"10", X"00", -- ) X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --2A X"00", X"2A", X"1C", X"3E", X"1C", X"2A", X"00", X"00", -- * --2B X"00", X"08", X"08", X"3E", X"08", X"08", X"00", X"00", -- + --2C X"00", X"00", X"00", X"00", X"18", X"18", X"08", X"10", -- , --2D X"00", X"00", X"00", X"3E", X"00", X"00", X"00", X"00", -- - --2E X"00", X"00", X"00", X"00", X"00", X"18", X"18", X"00", -- . --2F X"00", X"02", X"04", X"08", X"10", X"20", X"00", X"00", -- / --30 X"1C", X"22", X"26", X"2A", X"32", X"22", X"1C", X"00", --0 --31 X"08", X"18", X"08", X"08", X"08", X"08", X"1C", X"00", --1 --32 X"1C", X"22", X"02", X"04", X"08", X"10", X"3E", X"00", --2 --33 X"3E", X"04", X"08", X"04", X"02", X"22", X"1C", X"00", --3 --34 X"04", X"0C", X"14", X"24", X"3E", X"04", X"04", X"00", --4 --35 X"3E", X"20", X"3C", X"02", X"02", X"22", X"1C", X"00", --5 --36 X"0C", X"10", X"20", X"3C", X"22", X"22", X"1C", X"00", --6 --37 X"3E", X"22", X"04", X"08", X"10", X"10", X"10", X"00", --7 --38 X"1C", X"22", X"22", X"1C", X"22", X"22", X"1C", X"00", --8 --39 X"1C", X"22", X"22", X"1E", X"02", X"22", X"1C", X"00", --9 --3A X"00", X"00", X"18", X"18", X"00", X"18", X"18", X"00", -- : --3B X"00", X"00", X"18", X"18", X"00", X"18", X"08", X"10", -- ; --3C X"04", X"08", X"10", X"20", X"10", X"08", X"04", X"00", -- < --3D X"00", X"00", X"3E", X"00", X"3E", X"00", X"00", X"00", -- = --3E X"10", X"08", X"04", X"02", X"04", X"08", X"10", X"00", -- > --3F X"1C", X"22", X"02", X"04", X"08", X"00", X"08", X"00", -- ? --40 X"1C", X"22", X"02", X"1A", X"2A", X"2A", X"1C", X"00", -- @ --41 X"1C", X"22", X"22", X"22", X"3E", X"22", X"22", X"00", --A --42 X"3C", X"22", X"22", X"3C", X"22", X"22", X"3C", X"00", --B --43 X"1C", X"22", X"20", X"20", X"20", X"22", X"1C", X"00", --C --44 X"38", X"24", X"22", X"22", X"22", X"24", X"38", X"00", --D --45 X"3E", X"20", X"20", X"3C", X"20", X"20", X"3E", X"00", --E --46 X"3E", X"20", X"20", X"3C", X"20", X"20", X"20", X"00", --F --47 X"1C", X"22", X"20", X"2E", X"22", X"22", X"1E", X"00", --G --48 X"22", X"22", X"22", X"3E", X"22", X"22", X"22", X"00", --H --49 X"1C", X"08", X"08", X"08", X"08", X"08", X"1C", X"00", --I --4A X"1C", X"04", X"04", X"04", X"04", X"24", X"18", X"00", --J --4B X"22", X"24", X"28", X"30", X"28", X"24", X"22", X"00", --K --4C X"20", X"20", X"20", X"20", X"20", X"20", X"3E", X"00", --L --4D X"22", X"36", X"2A", X"22", X"22", X"22", X"22", X"00", --M --4E X"22", X"22", X"32", X"2A", X"26", X"22", X"22", X"00", --N --4F X"1C", X"22", X"22", X"22", X"22", X"22", X"1C", X"00", --O --50 X"3C", X"22", X"22", X"3C", X"20", X"20", X"20", X"00", --P --51 X"1C", X"22", X"22", X"22", X"2A", X"24", X"1A", X"00", --Q --52 X"3C", X"22", X"22", X"3E", X"28", X"24", X"22", X"00", --R --53 X"1E", X"20", X"20", X"1C", X"02", X"02", X"3C", X"00", --S --54 X"3E", X"08", X"08", X"08", X"08", X"08", X"08", X"00", --T --55 X"22", X"22", X"22", X"22", X"22", X"22", X"1C", X"00", --U --56 X"22", X"22", X"22", X"22", X"22", X"14", X"08", X"00", --V --57 X"22", X"22", X"22", X"2A", X"2A", X"2A", X"14", X"00", --W --58 X"22", X"22", X"14", X"08", X"14", X"22", X"22", X"00", --X --59 X"22", X"22", X"22", X"14", X"08", X"08", X"08", X"00", --Y --5A X"3E", X"02", X"04", X"08", X"10", X"20", X"3E", X"00", --Z --5B X"1C", X"10", X"10", X"10", X"10", X"10", X"1C", X"00", -- [ --5C X"00", X"20", X"10", X"08", X"04", X"02", X"00", X"00", -- \ --5D X"1C", X"04", X"04", X"04", X"04", X"04", X"1C", X"00", -- ] --5E X"08", X"14", X"22", X"00", X"00", X"00", X"00", X"00", -- ^ --5F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"3E", -- _ --60 X"10", X"08", X"04", X"00", X"00", X"00", X"00", X"00", -- ` --61 X"00", X"00", X"1C", X"02", X"1E", X"22", X"1E", X"00", --a --62 X"20", X"20", X"2C", X"32", X"22", X"22", X"3C", X"00", --b --63 X"00", X"00", X"1C", X"20", X"20", X"22", X"1C", X"00", --c --64 X"02", X"02", X"1A", X"26", X"22", X"22", X"1E", X"00", --d --65 X"00", X"00", X"1C", X"22", X"3E", X"20", X"1C", X"00", --e --66 X"0C", X"10", X"10", X"38", X"10", X"10", X"10", X"00", --f --67 X"00", X"00", X"1E", X"22", X"22", X"1E", X"02", X"1C", --g --68 X"20", X"20", X"2C", X"32", X"22", X"22", X"22", X"00", --h --69 X"08", X"00", X"18", X"08", X"08", X"08", X"1C", X"00", --i --6A X"04", X"00", X"0C", X"04", X"04", X"04", X"24", X"18", --j --6B X"20", X"20", X"24", X"28", X"30", X"28", X"24", X"00", --k --6C X"18", X"08", X"08", X"08", X"08", X"08", X"1C", X"00", --l --6D X"00", X"00", X"34", X"2A", X"2A", X"2A", X"2A", X"00", --m --6E X"00", X"00", X"2C", X"32", X"22", X"22", X"22", X"00", --n --6F X"00", X"00", X"1C", X"22", X"22", X"22", X"1C", X"00", --o --70 X"00", X"00", X"3C", X"22", X"22", X"3C", X"20", X"20", --p --71 X"00", X"00", X"1A", X"26", X"22", X"1E", X"02", X"02", --q --72 X"00", X"00", X"2C", X"32", X"20", X"20", X"20", X"00", --r --73 X"00", X"00", X"1E", X"20", X"1C", X"02", X"3C", X"00", --s --74 X"10", X"10", X"38", X"10", X"10", X"12", X"0C", X"00", --t --75 X"00", X"00", X"22", X"22", X"22", X"26", X"1A", X"00", --u --76 X"00", X"00", X"22", X"22", X"22", X"14", X"08", X"00", --v --77 X"00", X"00", X"22", X"22", X"2A", X"2A", X"14", X"00", --w --78 X"00", X"00", X"22", X"14", X"08", X"14", X"22", X"00", --x --79 X"00", X"00", X"22", X"22", X"22", X"1E", X"02", X"1C", --y --7A X"00", X"00", X"3E", X"04", X"08", X"10", X"3E", X"00", --z --7B X"04", X"08", X"08", X"10", X"08", X"08", X"04", X"00", -- { --7C X"08", X"08", X"08", X"08", X"08", X"08", X"08", X"00", -- | --7D X"10", X"08", X"08", X"04", X"08", X"08", X"10", X"00", -- } --7E X"00", X"00", X"10", X"2A", X"04", X"00", X"00", X"00", -- ~ --7F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --80 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --81 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --82 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --83 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --84 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --85 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --86 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --87 X"04", X"2A", X"32", X"32", X"2A", X"26", X"22", X"00", --Ń --88 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --89 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --8F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --90 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --91 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --92 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --93 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --94 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --95 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --96 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --97 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --98 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --99 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9A X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9B X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9C X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9D X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9E X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --9F X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --A9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --AF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --B9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --BF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --C9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --CF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --D9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --DF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --E9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --ED X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --EF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F0 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F1 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F2 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F3 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F4 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F5 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F6 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F7 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F8 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --F9 X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FA X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FB X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FC X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FD X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FE X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", --FF X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00" ); pozdrawiam.
kroszkanorber 29 czerwca Autor tematu Udostępnij 29 czerwca Cześć, chciałbym przedstawić mój kontroler VGA 640×480 napisany w VHDL, który korzysta z zewnętrznej pamięci SRAM 512k×8 jako VRAM. Projekt działa na zegarze 100 MHz i generuje sygnał VGA zgodny ze standardem VESA 640×480 @ 60 Hz. 1. Kontroler obsługuje: odczyt danych pikseli z SRAM, zapis danych do SRAM przez zewnętrzny port, pipeline dwóch pikseli na cykl, spłaszczanie adresu VRAM, pełną synchronizację HSYNC/VSYNC, 12‑bitowy kolor (4bity R, 4bity G, 4bity B). 7 2. Format danych RGB Każdy piksel ma 12 bitów: R – 4 bity G – 4 bity B – 4 bity Dwa piksele zapisane są w trzech bajtach: Bajt 1 = R1 (4b), G1 (4b) Bajt 2 = B1 (4b), B2 (4b) Bajt 2 = R2 (4b), G2 (4b) 2. Format danych RGB Każdy piksel ma 12 bitów: R – 4 bity G – 4 bity B – 4 bity Dwa piksele zapisane są w trzech bajtach: Bajt Zawartość 1 R1 (4b), G1 (4b) 2 B1 (4b), B2 (4b) 3 R2 (4b), G2 (4b) 3. Pipeline Cnt25 (8 faz) Kontroler działa w ośmiu fazach zegara 100 MHz: Faza Opis 000 start cyklu, BUSY=1 001 odczyt bajtu 1 (R1,G1) 002 odczyt bajtu 2 (B1,B2) 003 odczyt bajtu 3 (R2,G2), wyświetlenie piksela 1 100 faza przejściowa 101 zapis do SRAM (okno 1) 110 zapis do SRAM (okno 2) 111 wyświetlenie piksela 2, BUSY=0 6. Spłaszczanie adresu VRAM Adres VRAM jest liczony jako: Adres = 960 * CntV + CntF gdzie: 960 bajtów = dane jednego wiersza (640 pikseli × 1.5 bajta/piksel) CntV = numer wiersza CntF = licznik bajtów w wierszu 7. Interfejs VRAM (VGA_PORT) Sygnały: Sygnał Opis WR zapis danych do kontrolera RD odczyt danych z kontrolera SEL[1:0] wybór rejestru DIO[7:0] magistrala danych BUSY sygnał zajętości Zapis adresu: Wystaw dane na DIO Ustaw SEL Wygeneruj impuls WR ≥ 10 ns Zapis danych: Wystaw dane na DIO Ustaw SEL Wygeneruj impuls WR ≥ 10 ns Czekaj na BUSY=0 Odczyt danych: Ustaw adres jak przy zapisie Ustaw RD=1 Czekaj na BUSY=0 Odczytaj DIO 8. Kod źródłowy (VHDL) ---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 19:16:03 06/27/2026 -- Design Name: -- Module Name: VGA_640x480 - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- ________ ______________ _______ -- | | VWE <- | | VGA_HS -> | | -- | SRAM | VOE <- | | VGA_VS -> | VGA | -- | 512kx8 | VA <- | | | RGB | -> ( DAC -> monitor VGA ) -- |________| VD <-> | VGA | VGA_RGB -> |_______| -- ________ | kontroler | -- | | WR -> | | -- | VGA | RD -> | | -- | PORT | BUSY <- | | -- |________| DIO <-> |______________| -- -- Format danych RGB: -- Dane BGR kodowane są w trzech kolorach składowych o łącznej rozdzielczości 12 bit: -- B = 4 bity (16 odcieni) - niebieski -- G = 4 bity (16 odcieni) - zielony -- R = 4 bity (16 odcieni) - czerwony -- -- Kodowanie kolorów w pamięci SRAM: -- Informacje o kolorach dwóch pikseli zapisane są w trzech bajtach: -- Bajt 1 Bajt 2 Bajt 3 -- 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 -- R1 R1 R1 R1 G1 G1 G1 G1 | B1 B1 B1 B1 B2 B2 B2 B2 | R2 R2 R2 R2 G2 G2 G2 G2 -- -- Dekodowanie pikseli: -- Pixel 1 = R1, G1, B1 (łącznie 12 bit) -- Pixel 2 = R2, G2, B2 (łącznie 12 bit) -- -- Opis sygnałów: -- BUSY - 1 oznacza, że kontroler przetwarza dane -- DIO - magistrala danych portu zewnętrznego (dwukierunkowa) -- WR - sygnał zapisu do kontrolera VGA (z portu zewnętrznego) -- RD - sygnał odczytu z kontrolera VGA (z portu zewnętrznego) -- SEL - wybór rejestru adresowego lub danych -- -- VWE - sygnał zapisu do pamięci SRAM (aktywny niski) -- VOE - sygnał odczytu z pamięci SRAM (aktywny niski) -- VD - magistrala danych pamięci SRAM (dwukierunkowa) -- VA - magistrala adresu pamięci SRAM -- -- Zapis pojedynczego bajtu: -- 1. Ustawiamy dane na porcie DIO -- 2. Ustawiamy polecenie na linii SEL: -- SEL = "00" - zapis danych koloru piksela -- SEL = "01" - zapis dolnego bajtu adresu SRAM (bity 0-7) -- SEL = "10" - zapis górnego bajtu adresu SRAM (bity 8-15) -- SEL = "11" - zapis rozszerzenia adresu SRAM (bity 16-18) -- 3. Generujemy impuls WR (WE) o długości minimum 10 ns -- -- Odczyt pojedynczego bajtu: -- 1. Zapisujemy adres piksela jak wyżej -- 2. Ustawiamy RD = 1 -- 3. Czekamy na BUSY = 0 -- 4. Odczytujemy dane z magistrali DIO -- -- Sekwencja przepływu danych w kontrolerze (Cnt25): -- 1. Cnt25 = "000" -- Liczniki VGA wskazują aktualną pozycję -- WR lub RD = 1 -> BUSY = '1' -- 2. Cnt25 = "001" -- Odczyt bajtu 1 (R1,G1) -- 3. Cnt25 = "010" -- Odczyt bajtu 2 (B1,B2) -- 4. Cnt25 = "011" -- Odczyt bajtu 3 (R2,G2) -- Wyświetlenie piksela 1 (B1,R1,G1) -- 5. Cnt25 = "100" -- Faza przejściowa -- 6. Cnt25 = "101" -- WeLatch = 1 -> zapis do SRAM (okno 1) -- 7. Cnt25 = "110" -- WeLatch = 1 -> zapis do SRAM (okno 2) -- 8. Cnt25 = "111" -- Wyświetlenie piksela 2 (B2,R2,G2) -- BUSY = '0' -- -- Odczyt składowych koloru z pamięci SRAM: -- Cnt25 = 1 -> R1,G1 -- Cnt25 = 2 -> B1,B2 -- Cnt25 = 3 -> R2,G2 -- -- Sterowanie licznikiem adresu odczytu: -- Cnt25 = 1 -> CntF + 1 -- Cnt25 = 2 -> CntF + 1 -- Cnt25 = 3 -> CntF + 1 -- -- Spłaszczanie adresu pamięci SRAM: -- Adres = (960 * CntV) + CntF -- gdzie 960 bajtów = dane dla całego wiersza (640 pikseli * 1.5 bajta/piksel) library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity VGA_640x480 is port ( -- zegar i reset systemowy Clk : in STD_LOGIC; -- sygnały vga VGA_HS : out STD_LOGIC; VGA_VS : out STD_LOGIC; VGA_B : out STD_LOGIC_VECTOR(3 downto 0); VGA_R : out STD_LOGIC_VECTOR(3 downto 0); VGA_G : out STD_LOGIC_VECTOR(3 downto 0); -- sygnały sram VOE : out STD_LOGIC; VWE : out STD_LOGIC; VD : inout STD_LOGIC_VECTOR(7 downto 0); VA : out STD_LOGIC_VECTOR(18 downto 0); -- sygnały zapisu / odczytu sram dla urządzeń zewnętrznych BUSY : out STD_LOGIC; WE : in STD_LOGIC; RD : in STD_LOGIC; SEL : in STD_LOGIC_VECTOR(1 downto 0); DIO : inout STD_LOGIC_VECTOR(7 downto 0) ); end VGA_640x480; architecture Behavioral of VGA_640x480 is signal H, V, BL, EnH, EnV, WrEn, WePrev, WeEdge, WeLatch : std_logic; signal Cnt25 : std_logic_vector(2 downto 0); signal CntH, CntV, CntF : std_logic_vector(9 downto 0); signal B1, B2, R1, R2, G1, G2 : std_logic_vector(3 downto 0); signal MemFlat, Addr : std_logic_vector(18 downto 0); signal DoReg, DiReg : std_logic_vector(7 downto 0); signal CntB : std_logic_vector(1 downto 0); begin --dzielnik częstotliwości Clk = 100MHz process(CLK) begin if rising_edge(CLK) then Cnt25 <= Cnt25 + 1; end if; end process; EnH <= '1' when (Cnt25(1 downto 0) = 3) else '0'; --EnH = 100MHz/4 = 25MHz --licznik kolumn process(CLK) begin if rising_edge(CLK) then if EnH = '1' then if CntH = 799 then CntH <= (others => '0'); else CntH <= CntH + 1; end if; end if; end if; end process; EnV <= '1' when (CntH = 799 and Cnt25(1 downto 0) = 3) else '0'; --EnV = 25MHz/800 = 31,25kHz --licznik wierszy process(CLK) begin if rising_edge(CLK) then if EnV = '1' then if CntV = 524 then CntV <= (others => '0'); else CntV <= CntV + 1; end if; end if; end if; end process; --dekoder synchronizacji poziomej H <= '0' when ((CntH > 655) and (CntH < 753)) else '1'; --dekoder synchronizacji pionowej V <= '0' when ((CntV > 489) and (CntV < 493)) else '1'; --dekoder wygaszania obrazu poza obszarem wyświetlanym Bl <= '0' when ((CntH > 639) or (CntV > 479)) else '1'; -- wyświetlanie obrazu process(CLK) begin if rising_edge(CLK) then if Cnt25(1 downto 0) = 3 then if Bl = '0' then VGA_B <= (others => '0'); VGA_R <= (others => '0'); VGA_G <= (others => '0'); else if Cnt25(2) = '0' then VGA_B <= B1; VGA_R <= R1; VGA_G <= G1; else VGA_B <= B2; VGA_R <= R2; VGA_G <= G2; end if; end if; VGA_HS <= H; VGA_VS <= V; end if; end if; end process; -- odczyt 12 bitowego słowa o kolorze pixela z pamięci sram process(CLK) begin if rising_edge(CLK) then if EnV = '1' then CntF <= (others => '0'); end if; if Cnt25 = 1 then R1 <= VD(7 downto 4); G1 <= VD(3 downto 0); CntF <= CntF + 1; end if; if Cnt25 = 2 then B1 <= VD(7 downto 4); B2 <= VD(3 downto 0); CntF <= CntF + 1; end if; if Cnt25 = 3 then R2 <= VD(7 downto 4); G2 <= VD(3 downto 0); CntF <= CntF + 1; end if; end if; end process; -- spłaszczanie pamięci sram MemFlat <= ("1111000000" * CntV(8 downto 0)) + CntF; -- 640 + 320 = 960 -- dekoder sygnału sterującego liniami sygnałowymi do sram -- sygnał zapisu występuje tylko gdy: -- 1. Cnt25(2) = 1 jest w fazie drugiego pixela -- 2. WeLatch = 1 sygnał zapisu jest aktywny -- 3. CntB(0) xor CntB(1) = 1 okno zapisu 2 takty = 20 ns -- 4. SEL(0) or SEL(1) = "00" wybór instrukcji wskazuje na zapis do sram -- 5. RD = 0 sygnał odczytu nie jest aktywny WrEn <= Cnt25(2) and WeLatch and (CntB(0) xor CntB(1)) and not (SEL(0) or SEL(1) or RD); -- wybór adresu dla sram VA <= Addr when (Cnt25(2) = '1') else MemFlat; -- sterowanie portem danych sram VOE <= WrEn; -- sterowanie zapisem do sram VWE <= not WrEn; -- dekoder sygnału zajętości podczas przetwarzania danych BUSY <= CntB(0) xor CntB(1); -- sterowanie kierunkiem przepływu danych do pamięci sram VD <= DiReg when (WrEn = '1') else (others => 'Z'); -- kierowanie kierunkiem przepływu danych w porcie komunikacyjnym DIO <= DoReg when ((RD = '1') and (WE= '0')) else (others => 'Z'); -- licznik dla sygnału zajętości i długości zapisu / odczytu w drugiej fazie process(CLK) begin if rising_edge(CLK) then if ((WE = '0') or (RD = '0')) then CntB <= (others => '0'); elsif (CntB = 0) then CntB <= CntB + 1; elsif ((Cnt25 = 3) and (CntB = 1)) then CntB <= CntB + 1; elsif ((Cnt25 = 7) and (CntB = 2)) then CntB <= CntB + 1; end if; end if; end process; -- odczyt danych z pamięci sram process(CLK) begin if rising_edge(CLK) then if (Cnt25 = 7) then DoReg <= VD; end if; end if; end process; -- zatrzask sygnału WE process(CLK) begin if rising_edge(CLK) then if WE = '1' then WeLatch <= '1'; elsif CntB = 3 then WeLatch <= '0'; end if; end if; end process; -- zapis danych do rejestrów process(CLK) begin if rising_edge(CLK) then WeEdge <= WE and not WePrev; -- wykrycie zbocza narastającego WE WePrev <= WE; if (WeEdge = '1') then -- zapis adresu przy narastającym zboczu sygnału case SEL is when "01" => Addr(7 downto 0) <= DIO; when "10" => Addr(15 downto 8) <= DIO; when "11" => Addr(18 downto 16) <= DIO(2 downto 0); when others => DiReg <= DIO; end case; end if; end if; end process; end Behavioral; Synteza przeszła poprawnie bez ostrzeżeń i błędów: Uwagi praktyczne: Port DIO jest dwukierunkowy — kierunek magistrali zależy od sygnału RD. Gdy RD=1, kontroler wystawia dane na DIO. Gdy RD=0, kontroler ustawia DIO w stan wysokiej impedancji (Z). Kontroler sam zarządza pamięcią SRAM — urządzenia zewnętrzne nie mają bezpośredniego dostępu do SRAM. Dzięki temu nie ma ryzyka kolizji na magistrali VD. Zatrzask sygnału WE działa po ok. 10 ns — oznacza to, że kontroler można sterować praktycznie dowolnym mikrokontrolerem (Arduino, AVR, PIC, STM32, ESP32, AGNES). Minimalny czas impulsu WE jest bardzo krótki. Jeśli impuls WE jest zbyt długi, kontroler sam rozpozna koniec okna zapisu i zakończy operację poprawnie. Nie ma ryzyka „zawieszenia” zapisu. Sygnał RD musi być utrzymywany w stanie wysokim aż do momentu pojawienia się danych na porcie DIO. Moment gotowości danych jest sygnalizowany przez BUSY = 0. Kontroler sam rozpoznaje koniec okna odczytu. 1
Pomocna odpowiedź
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ę »