Forum: FPGA, VHDL & Co. VHDL: 4Bit Hex -> ASCII


von Randy (Gast)


Lesenswert?

Hallo,

wie sieht eine elegante Lösung aus einem 4Bit-Hex Wert das zugehörige 
8-Bit ASCII Zeichen zuzuordnen? Das kriege ich zwar auch als 
VHDL-Anfänger hin, aber im Netz hab eich jetzt tatsächlich keinen 
Codeschnippsel dazu gefunden. Wollte mal sehen ob es da eine "elegante" 
Lösung gibt. Ich hab da eine if-Konstruktion die vermutlich weder 
besonders gut noch resourenschondend ist...

Vielen Dank
Randy

von Falk B. (falk)


Lesenswert?

@Randy (Gast)

>wie sieht eine elegante Lösung aus einem 4Bit-Hex Wert das zugehörige
>8-Bit ASCII Zeichen zuzuordnen?

Du meinst die Zahlen 0-9 und A-F?

>Codeschnippsel dazu gefunden. Wollte mal sehen ob es da eine "elegante"
>Lösung gibt.

Gibt es, das ist ja eine einfache Tabelle.

> Ich hab da eine if-Konstruktion die vermutlich weder
>besonders gut noch resourenschondend ist...

Naja, der Optimierer macht das schon. Aber es ist tonnenweise sinnlose 
Tipperei, und besonders übersichtlich ist es auch nicht.

Gute Beispiele gibt es im Artikel TTL74185

MFG
Falk

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Randy schrieb:
> wie sieht eine elegante Lösung aus einem 4Bit-Hex Wert das zugehörige
> 8-Bit ASCII Zeichen zuzuordnen?
Beschreib ein RAM:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity BCD_ASCII is
6
    Port ( data      : in   STD_LOGIC_VECTOR (3 downto 0);
7
           asciichar : out  STD_LOGIC_VECTOR (7 downto 0));
8
end BCD_ASCII;
9
10
architecture Behavioral of BCD_ASCII is
11
   type Rom16x8 is array (0 to 15) of std_logic_vector (7 downto 0);
12
   constant BCDRom : Rom16x8 := ( 
13
       std_logic_vector(to_unsigned(character'pos('0'),8)),
14
       std_logic_vector(to_unsigned(character'pos('1'),8)),
15
       std_logic_vector(to_unsigned(character'pos('2'),8)),
16
       std_logic_vector(to_unsigned(character'pos('3'),8)),
17
       std_logic_vector(to_unsigned(character'pos('4'),8)),
18
       std_logic_vector(to_unsigned(character'pos('5'),8)),
19
       std_logic_vector(to_unsigned(character'pos('6'),8)),
20
       std_logic_vector(to_unsigned(character'pos('7'),8)),
21
       std_logic_vector(to_unsigned(character'pos('8'),8)),
22
       std_logic_vector(to_unsigned(character'pos('9'),8)),
23
       std_logic_vector(to_unsigned(character'pos('A'),8)),
24
       std_logic_vector(to_unsigned(character'pos('B'),8)),
25
       std_logic_vector(to_unsigned(character'pos('C'),8)),
26
       std_logic_vector(to_unsigned(character'pos('D'),8)),
27
       std_logic_vector(to_unsigned(character'pos('E'),8)),
28
       std_logic_vector(to_unsigned(character'pos('F'),8)));
29
begin
30
   asciichar <= BCDRom(to_integer(unsigned(data)));
31
end Behavioral;

Falls jetzt Fragen zum 'pos auftauchen:
Siehe Beitrag "Re: String in std_logic_vector umwandeln"

von Randy (Gast)


Lesenswert?

OK, vielen Dank. Eine Tabelle ist also das Mittel der Wahl. Ich hatte 
eine if-Abfrage (48+Wert oder 55+Wert je nach Bereich, aber auch an 
jeder Stelle an der ich das gebraucht habe), ich bau das jetzt so um wie 
Lothar beschrieben hat. Eine Frage zur Struktur: Die Entity von Lothar 
kommt in eine eigene Datei? Oder füge ich die Entity anders ein?
Zur allgemeinen Vorgehensweise: Würde man andere mehr oder weniger 
kleine Funktionsblöcke auch in eigene Dateien schreiben? Gäbe am Ende 
sehr viel Dateien mit je nur 20-50 Zeilen Code. Wird das so gemacht? Vom 
uC in C programmieren kenne ich es so dass man wegen einer popeligen 
Funktion kein extra Modul (oder extra c-Datei) gemacht hat. So dass ich 
am Ende eher nur 2 bis 6 Dateien mit je 100-1000 Zeilen Code hatte. Wie 
hält man das bei VHDL?

Randy

von Falk B. (falk)


Lesenswert?

@  Randy (Gast)

>Funktion kein extra Modul (oder extra c-Datei) gemacht hat. So dass ich
>am Ende eher nur 2 bis 6 Dateien mit je 100-1000 Zeilen Code hatte. Wie
>hält man das bei VHDL?

Meist genauso.

MFG
Falk

von Harald F. (hfl)


Lesenswert?

Hallo Randy,

sorry, wenn ich mich mal wieder ungefragt einmische, aber wenn ich 
solche VHDL-Konstrukte sehe, dann tun mir immer die Augen weh. Ich 
empfehle eine lockere und leichte Beschreibungssprache, nämlich Verilog, 
und dann sähe die Entity (das Modul) so aus:

module ascii
    (
    input   [3:0]   hex_in,
    output  [7:0]   ascii_out
    );
assign ascii_out = (hex_in > 9) ? hex_in - 'ha + 'h61 : hex_in + 'h30;
endmodule

Ein 7-Zeiler also, mehr nicht.

Aber zu deiner anderen Frage (wie viele Dateien?). Früher gab es mal 
eine aus der ASIC-Welt stammende Regel namens OMPF (one module per 
file). Die Regel war vor allem ein Zugeständnis an die Synthesetools, 
und in der FPGA-Welt muss man sich nicht unbedingt daran halten. Ich 
mach's trotzdem.

von Falk B. (falk)


Lesenswert?

@  Harald Flügel (hfl)

>sorry, wenn ich mich mal wieder ungefragt einmische, aber wenn ich
>solche VHDL-Konstrukte sehe, dann tun mir immer die Augen weh.

Mir auch, obwohl ich VHDLer bin ;-)

Ich empfehle diese Version.

http://www.mikrocontroller.net/articles/TTL74185#Konstanten_Array

>Ein 7-Zeiler also, mehr nicht.

Dito in VHDL.

MFG
Falk

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Randy schrieb:
> Vom uC in C programmieren kenne ich es so dass man wegen einer popeligen
> Funktion kein extra Modul (oder extra c-Datei) gemacht hat.
Ich treibe es gern sogar noch weiter und packe sehr viel in 1 Prozess 
hinein. So wird dann aus eine seriellen Schnittstelle, die bei anderen 4 
Dateien braucht (siehe 
Beitrag "Re: VHDL zu Verilog" --> DeepLink), bei 
mir 1 Datei mit 2 Prozessen:
http://www.lothar-miller.de/s9y/categories/42-RS232
Oder ähnliches bei einer PS/2 Schnittstelle:
http://www.lothar-miller.de/s9y/categories/55-PS2

Und nein: ein VHDL-Code wird nicht durchschaubarer, wenn man 7 
Editorfenster geöffnet haben muß, um ihn zu überblicken. Er sieht nur 
wichtiger aus... ;-)

Ohne Glaubenskriege heraufzubeschwören:
> assign ascii_out = (hex_in > 9) ? hex_in - 'ha + 'h61 : hex_in + 'h30;
Zeig das mal bei unbedarften Elektronikern rum und frag, was da 
passiert.
Und vor allem: was der Synthesizer evtl. draus macht.
Und dann machst du das mit dem VHDL-Code...

Aber bitte, es geht auch kürzer:
1
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL;
2
entity BCD_ASCII is  Port ( data      : in   unsigned (3 downto 0);
3
                            asciichar : out  unsigned (7 downto 0));
4
end BCD_ASCII;
5
architecture Behavioral of BCD_ASCII is begin
6
   asciichar <= resize(data,8)+x"61"  when  data>9  else resize(data,8)+x"30";
7
end Behavioral;
Auch 7 Zeilen... ;-)


BTW: das Fehlen des ? Operators bei VHDL ist eigentlich nicht 
schlecht... ;-)

EDIT
>> sorry, wenn ich mich mal wieder ungefragt einmische, aber wenn ich
>> solche VHDL-Konstrukte sehe, dann tun mir immer die Augen weh.
> Mir auch, obwohl ich VHDLer bin ;-)
@ Falk: Meint er meine oder deine Konstrukte?
@ Harald: Komm sags uns... ;-)
Ich kann die Tabelle auch kompakter schreiben, aber irgendwie finde ich 
das oben trotz des Herumgecasts übersichtlicher, als nur Hex-Kolonnen 
dastehen zu haben...

von Harald F. (hfl)


Lesenswert?

Hallo Lothar, Hallo Falk,

die Augenschmerzen bekam ich bei der Anreihung der

std_logic_vector(to_unsigned(character'pos('*'),8)),

-Statements. Der 7-Zeiler von Lothar mit der Zeile

asciichar <= resize(data,8)+x"61"  when  data>9  else 
resize(data,8)+x"30";

ist schon wesentlich besser und fast baugleich zu dem Verilog-Code

assign ascii_out = (hex_in > 9) ? hex_in - 'ha + 'h61 : hex_in + 'h30;

Wenn ich diese Verilog-Zeile unbedarften Elektronikern zeige und dazu 
sage, dass 'h das Prefix für die hexidezimale Notation ist, dann 
verstehen die das, denn die können alle C. Das ist IMHO der größe 
Vorteil von Veriog überhaupt: Die syntaktische Nähe zu C.

Aber nochmal zurück zur eigentlichen Aufgabenstellung. Die erste Lösung 
von Lothar legt den Schluss nahe, dass der Entwickler ein ROM (RAM) 
haben will, während Lothars zweite Lösung aussieht, als sollten das 
Logikelemente geben. Ich mache bei Altera Quartus die Erfahrung, dass 
der Synthesizer selbst entscheidet, was die bessere Lösung ist. Deckt 
sich das mit euren Beobachtungen?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Harald Flügel schrieb:
> Wenn ich diese Verilog-Zeile unbedarften Elektronikern zeige und dazu
> sage, dass 'h das Prefix für die hexidezimale Notation ist
Neineinein, ich meinte, ohne was zu sagen... ;-)
Zeig den Fragezeichen-Operator mal einem eingefleischten 
Basic-Programmierer... ;-)
Und auch "übliche" C-Programmierer haben ihre liebe Not damit.

> Die syntaktische Nähe zu C.
Könnte dann aber auch zur C-Software-Denkweise verführen (mit Schleifen 
und delay() und all den Dingen)...

> Ich mache bei Altera Quartus die Erfahrung, dass der Synthesizer
> selbst entscheidet, was die bessere Lösung ist.
> Deckt sich das mit euren Beobachtungen?
Die Xilinx-Synthese XST macht daraus durchaus einmal ein BROM und einmal 
einen Addierer, allerdings sind beide Lösungen beim Ressourcenverbrauch 
und bei der Geschwindigkeit aufs Zehntel gleich...
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity BCD2ASCII is
6
    Port ( di : in  STD_LOGIC_VECTOR (3 downto 0);
7
           do : out STD_LOGIC_VECTOR (7 downto 0));
8
end BCD2ASCII;
9
10
-- 1. Variante mit BROM
11
-- Maximum combinational path delay: 7.276ns
12
-- Number of Slices         3
13
-- Number of 4 input LUTs   6
14
architecture Behavioral of BCD2ASCII is
15
   type Rom16x8 is array (0 to 15) of std_logic_vector (7 downto 0);
16
   constant BCDRom : Rom16x8 := ( 
17
       std_logic_vector(to_unsigned(character'pos('0'),8)),
18
       std_logic_vector(to_unsigned(character'pos('1'),8)),
19
       :
20
       :
21
       std_logic_vector(to_unsigned(character'pos('F'),8)));
22
begin
23
   do <= BCDRom(to_integer(unsigned(di)));
24
end Behavioral;
25
26
-- 2. Variante mit Addierer
27
-- Maximum combinational path delay: 7.276ns
28
-- Number of Slices         3
29
-- Number of 4 input LUTs   6
30
architecture Behavioral of BCD2ASCII is
31
begin
32
     do <= std_logic_vector(resize(unsigned(di),8)+to_unsigned(character'pos('A')-10,8))  when unsigned(di)>9  else  
33
           std_logic_vector(resize(unsigned(di),8)+to_unsigned(character'pos('0'),8));
34
end Behavioral;
35
36
-- 3. wie 2. aber -10 ungünstig platziert
37
-- --> trotz Konstanten werden Addierer und Subtrahierer synthetisiert !!!
38
-- Maximum combinational path delay: 10.471ns
39
-- Number of Slices         6
40
-- Number of 4 input LUTs   10
41
architecture Behavioral of BCD2ASCII is
42
begin
43
     do <= std_logic_vector(resize(unsigned(di),8)+to_unsigned(character'pos('A'),8)-10)  when unsigned(di)>9  else  
44
           std_logic_vector(resize(unsigned(di),8)+to_unsigned(character'pos('0'),8));
45
end Behavioral;


BTW:
Es ist klar, dass VHDL durch die strengen Typkonvertierungen die 
"geschwätzigere" Sprache ist. Allerdings wird der Entwickler dadurch 
auch eher zum Nachdenken gezwungen...

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Lothar Miller schrieb:

> BTW:
> Es ist klar, dass VHDL durch die strengen Typkonvertierungen die
> "geschwätzigere" Sprache ist. Allerdings wird der Entwickler dadurch
> auch eher zum Nachdenken gezwungen...

Super Beitrag Lothar,

Didaktisch fast eine genialer Schachstreich. Erst eine ROM Tabelle und 
dann der sieben Zeiler. Ich hätte es als Funktion geschieben.

Vom Gedankenschmalz ein super Beitrag.

Wenn ich einen Wunsch für den Weihnachtsmann hätte, dann eine Buch von 
Lothar Miller. Ein VHDL-Praxisbuch zum Mitdenken.

von Harald F. (hfl)


Lesenswert?

Hallo Lothar,

ich hätte da noch eine Frage. Du weißt ja, Xilinx-Software ist nicht 
gerade mein Spezialgebiet. Ernst gemeint: Was bringt Dich zu der 
Annahme, dass...

Lothar Miller schrieb:
> Die Xilinx-Synthese XST macht daraus durchaus einmal ein BROM und einmal
> einen Addierer...
> -- 1. Variante mit BROM
> -- Maximum combinational path delay: 7.276ns
> -- Number of Slices         3
> -- Number of 4 input LUTs   6
> -- 2. Variante mit Addierer
> -- Maximum combinational path delay: 7.276ns
> -- Number of Slices         3
> -- Number of 4 input LUTs   6

Meiner Meinung nach macht XST in beiden Fällen eine kombinatorische 
Schaltung mit 6 LUTs, unabhängig davon, ob man das gewünschte Ergebnis 
als Tabelle oder als Ausdruck beschreibt. Was hab ich da übersehen?

Und dann hätt' ich doch noch 'was zum Streiten. Basic? Geht's noch?

Grüße,
Harald

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Harald Flügel schrieb:
> Meiner Meinung nach macht XST in beiden Fällen eine kombinatorische
> Schaltung mit 6 LUTs, unabhängig davon, ob man das gewünschte Ergebnis
> als Tabelle oder als Ausdruck beschreibt. Was hab ich da übersehen?
Du hast recht.
Es wird kein BROM instatiiert, sondern nur ein "normales" Distributed 
ROM. Es kann auch gar kein BROM verwendet werden, weil weit&breit kein 
Takt zusehen ist...

> Basic? Geht's noch?
Oder Pascal? Modula? LOGO?  ;-)

BTW: Ich nehme in C auch mal gern den ? Operator, und sei es nur, um 
damit herumzuprotzen...
1
  dir = enable?endschalter?0:right^left?right?1:2:0:0;

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.