Text renderen op een FPGA offset probleem

Hallo,

Ik ben bezig om mijn FPGA kennis weer wat te verbeteren. Nu leek het me leuk om een scherm aan te sturen via VGA. Mijn idee was om text weer te geven op het scherm als eerste stap. Later misschien nog wat sprites of primitives.

Het idee is als volgt:
RAM, bevat een stukje text. Voor de test is dit "A B C D"
ROM, bevat de font. https://github.com/dhepper/font8x8

Als eerste bereken ik het adres van de RAM adhv de x en y locatie.
char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));

Met de output van deze ram zoek ik het character op in de ROM.
rom_addr(2 downto 0) <= std_logic_vector(to_unsigned(py, 4))(2 downto 0);
rom_addr(9 downto 3) <= char_val(6 downto 0);

De manier waarop de font is ingedeeld moet ik nog bitshiften om te bepalen of de pixel aan of uit moet:
pixel <= rom_q(px+4 mod 8);

Het vervelende is dat de characters niet goed worden weer gegeven. Het linkse en rechtse deel van de characters is omgedraaid.

Het probleem moet zitten in de char_addr selectie aangezien het volgende wel werkt:
char_addr <= "10 0000 1000";
Dit leidt tot een scherm vol met de letter A.

Mijn vermoeden is dat het ergens een afrondings of signed dingetje is in
char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));



LIBRARY ieee;
USE ieee.numeric_std.all;
use ieee.std_logic_1164.all;





entity hw_image_generator is
	generic(
		res_x :  INTEGER := 800;
		res_y :  INTEGER := 600
	);
	port(
		clk		:  IN   STD_LOGIC;
		disp_ena :  IN   STD_LOGIC;  --display enable ('1' = display time, '0' = blanking time)
		px      	:  IN   INTEGER;    --row pixel coordinate
		py   		:  IN   INTEGER;    --column pixel coordinate
		red      :  OUT  STD_LOGIC;  --red magnitude output to DAC
		green    :  OUT  STD_LOGIC;  --green magnitude output to DAC
		blue     :  OUT  STD_LOGIC  --blue magnitude output to DAC
	);
end entity;



ARCHITECTURE behavior OF hw_image_generator IS
	signal div			: STD_LOGIC_VECTOR(2 downto 0);
	signal char_addr	: STD_LOGIC_VECTOR (9 DOWNTO 0);
	signal char_val	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	signal rom_addr	: STD_LOGIC_VECTOR (9 DOWNTO 0);
	signal rom_q		: STD_LOGIC_VECTOR (7 DOWNTO 0);
	signal pixel 		: STD_LOGIC;
	signal chval		: INTEGER;
BEGIN

	txtram : entity work.txtram
	port map(
		address_a	=> "0000000000",
		clock_a		=> '0',
		data_a		=> "00000000",
		wren_a		=> '0',
		--q_a				
		
		address_b 	=> char_addr,
		clock_b	 	=> clk,
		data_b		=> "00000000",
		wren_b    	=> '0',			
		q_b		 	=> char_val
	);
	
	
	
	fontrom : entity work.fontrom 
	port map(	
		address_a	=> "0000000000",
		clock_a		=> '0',
		data_a		=> "00000000",
		wren_a		=> '0',
		--q_a				
		
		address_b 	=> rom_addr,
		clock_b	 	=> clk,
		data_b		=> "00000000",
		wren_b    	=> '0',			
		q_b		 	=> rom_q
	);
	

	PROCESS(disp_ena, clk)
	BEGIN
		char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));
				
		rom_addr(2 downto 0) <= std_logic_vector(to_unsigned(py, 4))(2 downto 0);
		rom_addr(9 downto 3) <= char_val(6 downto 0);
		pixel <= rom_q(px mod 8);
		

		IF(disp_ena = '1') THEN

			red 	<= std_logic_vector(to_unsigned(px / 8, 1))(0);
			green <= pixel;
			blue 	<= '1';
			
		else
			red 	<= '0';
			green <= '0';
			blue 	<= '0';
		end if;
		

	END PROCESS;
END behavior;
PE2BAS

Gewoon even zonder inhoudelijk te kijken, maar ehm... je doet serieus zomaar een paar deel-operaties uit de losse pols? Heb je ook nagedacht wat voor logica dat op gaat leveren? Denk hardware.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Kan het begrijpen als je zo diep in programmeertaal zit, maar bedoel je in plaats van "text" niet gewoon het Nederlandse 'tekst'?

Op 30 juli 2022 22:26:58 schreef flipflop:
Gewoon even zonder inhoudelijk te kijken, maar ehm... je doet serieus zomaar een paar deel-operaties uit de losse pols? Heb je ook nagedacht wat voor logica dat op gaat leveren? Denk hardware.

Delen door 8 kost vrijwel niks in hardware. Dat is een simpele shift die ook nog eens hardwired gemaakt is. Dus alleen maar "draadjes" geroteerd aansluiten als het meezit.

Als je het experiment met de enkele A eens met een niet 'vertikaal symmetrische' letter doet de B bijvoorbeeld? Is die ook goed?

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Op 30 juli 2022 23:02:49 schreef Leeuw van Recht:
Kan het begrijpen als je zo diep in programmeertaal zit, maar bedoel je in plaats van "text" niet gewoon het Nederlandse 'tekst'?

@LvR,
Voor mij is "text" en "tekst" hetzelfde, maar als jij de startpost niet snapt omdat hardbass "text" gebruikt, dan zal je vast ook geen antwoord op hardbass zijn probleem hebben.
Ik heb veel meer moeite om deze instructie te begrijpen: char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));

char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));

Ik ken VHDL ook niet echt, maar ergens moet er een "px modulo 8" in zitten om het juiste karakter in de rom te kunnen selecteren. Als ik aanneem dat px de horizontale pixel clock counter is.
Ik zou dat in het bovenstaande stukje verwachten.
Oops, die 'px modulo 8' heb je nodig om in de ROM je juiste kolom van het font te slecteren.

-edit- Eigenlijk heb je een Horizontale char counter die je RAM data opzoekt wat er moet staan (Die "A B C D"). Dan nog een vertikale counter voor de juiste regel. Die combinatie is dan je RAM address, de data die uit je RAM komt is weer input voor je character ROM.

Het lastige is dat je X en Y character resolutie bijna nooit een 2-macht is. Anders zou je de counter bits mooi tegen elkaar aan kunnen plakken. Dus moet je nu wat aanklungelen met counters om je RAM goed (=lees efficient kwa ruimte) te addresseren.

Ik zie dat jij dat doet door de px te pakken en te delen door 8. Eigenlijk kan dat niet want dan heb je geen ruimte tussen de characters als je font 8x8 is. Je moet dan 9 pixels hebben. Tjsa, en dan wordt die deling wel erg beroerd.

Wat is je effectieve scherm resolutie kwa characters (80x32)?

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Op 30 juli 2022 23:10:32 schreef henri62:
Delen door 8 kost vrijwel niks in hardware....ook nog eens hardwired gemaakt is.

Klopt helemaal, kost niks. Maar als je een deling opschrijft, zou de synthese maar zo een echte deler neer kunnen leggen. Maar goed, die discussie leidt af van het probleem. Case closed :-)

Meer inhoudelijk antwoord (maar het heeft wel met m'n bovenstaande opmerking te maken!): je bent erg scheutig met hardware. De verdachte regel
char_addr <= std_logic_vector(to_unsigned(px / 8 + (py / 8) * (res_x/8), char_addr'length));
doet een deling op een integer. Dat px en py zijn 32 bits getallen die ook nog eens signed zijn. Als je eea correct omzet naar vectors zal dat in de praktijk best goed moeten gaan, maar je code wordt er wel veel onoverzichteijker van waardoor je nu niet ziet waar het mis gaat. Mijn advies:

  • Gebruik zoveel mogelijk vectoren. Maak die niet langer dan nodig (px loopt echt niet van -2147483648 tot +2147483647).
  • Deling vervangen door de lage 3 bits eraf te laten.
  • Ik vind het vaak makkelijk om een paar signalen te gebruiken om tussenresultaten in te zetten zodat je niet zo'n enorme spreuk krijgt als het genoemde assignment.
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Hallo,

Bedankt voor de input zover. Wat betreft text en tekst, tja, we begrijpen elkaar toch? :)

Wat info
Resolutie scherm = 800*600
Characters = 8 * 8 maar... daar zit ook de whitespace al in, tussen de characters.
Zoals ook op de github aangegeven zitten de characters als volgt opgeslagen in de rom:

The character 'A' (0x41 / 65) is encoded as { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}
0x0C => 0000 1100 => ..XX....
0X1E => 0001 1110 => .XXXX...
0x33 => 0011 0011 => XX..XX..
0x33 => 0011 0011 => XX..XX..
0x3F => 0011 1111 => xxxxxx..
0x33 => 0011 0011 => XX..XX..
0x33 => 0011 0011 => XX..XX..
0x00 => 0000 0000 => ........

Efficiëntie van de hdl
Waar ik ook mee zit is dat ik beginner ben qua fpga's. Daarmee is het voor mij lastig om dit soort dingen in te zien. Ik vergelijk het maar een beetje als een beginnend Arduino programmeur. De code is niet mooi en het kan zeker beter. Maar voor een hobbyist maakt het niet zo uit. Zolang het maar werkt. Ik zou graag meer ervaring opdoen zodat ik hier beter in wordt. Dat zal nog wel wat tijd kosten. Wat ik wel al had bedacht, deze deling door 8 kan ik ook doen door gewoon de onderste 3 bits niet te gebruiken. Ik zie dat flipflop dit nu ook voorstelt, dus dit ga ik zeker doen!

Ik schrijf al wel erg lang software, dus het is nog wel eens lastig om anders te denken als ik hiermee bezig ben.

Toelichting adres selectie
address = px / 8 + (py / 8) * (res_x/8)
px/8 = de kolom.
py/8 = de rij
res_x/8 = characters per rij
address = kolom + rij * characters per rij

Eigenlijk geeft henri62 het al goed aan. De eerste text-ram bevat de tekst. Deze uitput wordt gebruik om in de font-ram op te zoeken hoe het character getekend moet worden.

En dan nu
Ik ga flipflop zijn advies opvolgen en een aantal dingen aanpassen. Het optellen zou met een adder kunnen die is vrij eenvoudig te maken. Vermenigvuldigen kan ook digitaal natuurlijk. Ook het gebruik van tussen signalen ga ik zeker toepassen.

PE2BAS

Op 30 juli 2022 23:02:49 schreef Leeuw van Recht:
Kan het begrijpen als je zo diep in programmeertaal zit, maar bedoel je in plaats van "text" niet gewoon het Nederlandse 'tekst'?

Begrijp ik het goed als ik hier moet concluderen dat hij het volgens de formele "nederlands" regels fout geschreven heeft, maar dat jij feilloos wist wat ie bedoelde?

Beste "Leeuw van Recht", er zijn onderzoeken die zeggen dat zo'n 10% van de bevolking "dyslexie" heeft. Het blijkt ook dat mensen die dat hebben niet als hobby "een extra taal" kiezen ("ik ga altijd naar Italie op vakantie om m'n italiaans op peil te houden!"), maar vaker voor iets als "elektronica" kiezen. De concentratie dyslectici hier op CO is hoger dan in de algemene bevolking. Significant ook. Niet 11% waar de bevolking 10% is, maar iets van 50%.

Dat zeiken over taal begint mij en anderen met mij de keel uit te hangen. Je zult moeten accepteren dat op dit forum er onevenredig veel spel- en schrijf-fouten gemaakt worden.

Daarnaast heb je mensen die zeggen: "Dat nederlands-taal-genootschap op z'n hoge stoelen, die kunnen me wat. Ik vind de oude spelling mooier." Zo heb ik hierboven een "spelfout" laten staan omdat ik het zo consistenter, netter en makkelijker leesbaar vind. Maar volgens de officiele spelling is het een spelfout.

Ik had dit best "prive" willen uitleggen, maar je schermt jezelf af voor prive-berichten. Dan moet het maar openbaar.

Over debuggen van dit soort "ketens" in een FPGA: Je kan redelijk makkelijk "testdata" in je keten injecteren in een FPGA. Dus

if (line is odd) 0x0f; else character_rom[....];

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 31 juli 2022 11:31:35 schreef hardbass:
..De code is niet mooi en het kan zeker beter. Maar voor een hobbyist maakt het niet zo uit. Zolang het maar werkt.

Ja, dat zou zo zijn als het simpelweg "niet zo mooi" is. Maar dat is niet waarom ik m'n opmerkingen hierboven schreef. Wat ik bedoel is, als je het warrig en onoverzichtelijk opschrijft, het ook lastiger in te zien is hoe het werkt, en dus ook waar het mis gaat. Bv, ik kan zo niet inschatten wat er gebeurt in die omzetting van integer naar std_logic_vector. Best kans dat daardoor die swap in het karakter komt(?). En dan heb ik dagelijks VHDL op m'n scherm staan.

Over typefouten: we mogen met z'n allen best moeite doen om een beetje correct NL te typen, maar om er speciaal een post voor te typen om een ander te corrigeren gaat best ver.

[edit] Nabrander: ik kan je ook sterk aanbevelen om ELK ontwerp eerste te simuleren voordat je het op target laadt. Dit soort fouten waar je nu tegenaan loopt vindt je binnen 5 minuten in simulatie. En een testbench is ook zo gemaakt.

[Bericht gewijzigd door flipflop op zondag 31 juli 2022 12:47:09 (12%)

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein