So initialisieren Sie RAM aus einer Datei mit TEXTIO
Eine bequeme Möglichkeit, den Block-RAM mit Anfangswerten zu füllen, besteht darin, binäre oder hexadezimale Literale aus einer ASCII-Datei zu lesen. Dies ist auch eine gute Möglichkeit, ein ROM (Read-Only Memory) in VHDL zu erstellen. Schließlich sind RAM und ROM in FPGAs dasselbe, ROM ist ein RAM, aus dem Sie nur lesen.
Die Beispiele in diesem Artikel gehen davon aus, dass die folgenden Konstanten und RAM-Typen am Anfang des deklarativen Bereichs der VHDL-Datei deklariert wurden.
constant ram_depth : natural := 256; constant ram_width : natural := 32; type ram_type is array (0 to ram_depth - 1) of std_logic_vector(ram_width - 1 downto 0);
Dieser Blogbeitrag ist Teil einer Reihe über die Verwendung der TEXTIO-Bibliothek in VHDL. Lesen Sie die anderen Artikel hier:
Stimulus-Datei in Testbench mit TEXTIO eingelesen
BMP-Datei-Bitmap-Bild, gelesen mit TEXTIO
READLINE, LINE, HREAD, OREAD und BREAD
Die Unterprogramme und Typen, die zum Lesen und Schreiben externer Dateien in VHDL benötigt werden, befinden sich im TEXTIO
Paket. Dieses Paket ist Teil von std
Bibliothek. Die Standardbibliothek wird immer geladen; Daher müssen wir es nicht explizit mit library
importieren Schlüsselwort.
Wir können einfach weitermachen und den TEXTIO
verwenden package im Header unserer VHDL-Datei wie folgt:
use std.textio.all;
Wir speichern die RAM-Daten in einer ASCII-Datei, wobei eine Textzeile einem Speicherplatz entspricht. Um eine Textzeile zu lesen, verwenden wir den READLINE
Prozedur aus dem TEXTIO
Paket. Die Prozedur nimmt zwei Argumente, den Dateinamen als konstanten Input und die geparste Textzeile als inout
Variable. Die Prototypdeklaration von READLINE
Prozedur und die LINE
Der aus der VHDL-Standardspezifikation übernommene Typ ist unten dargestellt.
procedure READLINE (file F: TEXT; L: inout LINE); type LINE is access STRING; -- A LINE is a pointer -- to a STRING value.
Obwohl die Klasse des LINE
-Parameter ist in der Prototyp-Deklaration von READLINE
nicht explizit angegeben , es ist eine Variable, da dies die Standardklasse für inout
ist Parameter. Die LINE
type ist einfach ein Zugriffstyp auf einen String, ein Zeiger auf ein dynamisch zugewiesenes String-Objekt.
VHDL-2008 definiert den OREAD
, HREAD
, und BREAD
Prozeduren zum Extrahieren von Oktal-, Hexadezimal- und Binärwerten aus einem LINE
Objekt. Die Methoden zum Lesen von Oktal- und Hexadezimalwerten sind ziemlich ähnlich, die Oktalwerte sind lediglich eine Teilmenge der Hexadezimalwerte. Der Einfachheit halber werden wir in diesem Artikel oktale Lesevorgänge überspringen und uns darauf konzentrieren, wie hexadezimale und binäre Werte aus einer Textdatei gelesen werden.
Der folgende Code zeigt die Definitionen der für uns relevanten Prozeduren, sie sind nur in VHDL-2008 und neueren Revisionen verfügbar. Die OREAD
und HREAD
Prozeduren gibt es in zwei überladenen Varianten für jeden der unterstützten Ausgabetypen. Der optionale GOOD
Die Ausgabe kann zum Erkennen von Lesefehlern verwendet werden, obwohl die meisten Tools einen Fehler oder eine Warnung erzeugen, unabhängig davon, ob diese Ausgabe verwendet wird oder nicht.
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN); procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR); procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN); procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR); alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN]; alias BREAD is READ [LINE, STD_ULOGIC_VECTOR];Klicken Sie hier, um die Definitionen der Eingabeprozeduren aus der TEXTIO-Bibliothek
procedure READLINE (file F: TEXT; L: inout LINE); procedure READ (L: inout LINE; VALUE: out BIT; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out BIT); procedure READ (L: inout LINE; VALUE: out BIT_VECTOR; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out BIT_VECTOR); procedure READ (L: inout LINE; VALUE: out BOOLEAN; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out CHARACTER; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out CHARACTER); procedure READ (L: inout LINE; VALUE: out INTEGER; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out INTEGER); procedure READ (L: inout LINE; VALUE: out REAL; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out REAL); procedure READ (L: inout LINE; VALUE: out STRING; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out STRING); procedure READ (L: inout LINE; VALUE: out TIME; GOOD: out BOOLEAN); procedure READ (L: inout LINE; VALUE: out TIME); procedure SREAD (L: inout LINE; VALUE: out STRING; STRLEN: out NATURAL); alias STRING_READ is SREAD [LINE, STRING, NATURAL]; alias BREAD is READ [LINE, BIT_VECTOR, BOOLEAN]; alias BREAD is READ [LINE, BIT_VECTOR]; alias BINARY_READ is READ [LINE, BIT_VECTOR, BOOLEAN]; alias BINARY_READ is READ [LINE, BIT_VECTOR]; procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR; GOOD: out BOOLEAN); procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR); alias OCTAL_READ is OREAD [LINE, BIT_VECTOR, BOOLEAN]; alias OCTAL_READ is OREAD [LINE, BIT_VECTOR]; procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR; GOOD: out BOOLEAN); procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR); alias HEX_READ is HREAD [LINE, BIT_VECTOR, BOOLEAN]; alias HEX_READ is HREAD [LINE, BIT_VECTOR];anzuzeigen Klicken Sie hier, um die Definitionen der Eingabeprozeduren aus der std_logic_1164-Bibliothek
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC; GOOD : out BOOLEAN); procedure READ (L : inout LINE; VALUE : out STD_ULOGIC); procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN); procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR); alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN]; alias BREAD is READ [LINE, STD_ULOGIC_VECTOR]; alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN]; alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR]; procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN); procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR); alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN]; alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR]; procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN); procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR); alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN]; alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR];anzuzeigen
Hex-Werte aus Datei lesen
Hexadezimal ist ein praktisches Format zum Beschreiben von RAM-Inhalten, da zwei Hexadezimalzeichen direkt in ein Byte mit acht Bits übersetzt werden. Jedes Zeichen beschreibt ein Nibble (halbes Byte) und jede Zeile in der Textdatei beschreibt den Inhalt eines RAM-Slots. Die folgende Auflistung zeigt einen Auszug aus der ram_content_hex.txt Datei. Es wurde mit Beispielwerten gefüllt, die von 1 bis 256 dezimal reichen und als Hex geschrieben werden.
12–255256 | 00000001 00000002 ... 000000FF 00000100 |
Um die Daten aus der Textdatei zu laden, verwenden wir eine unreine Funktion, die unter ram_type
deklariert ist , aber über der RAM-Signaldeklaration. Der folgende Code zeigt den init_ram_hex
Funktion, die die Daten aus der Textdatei liest und als ram_type
zurückgibt Objekt.
impure function init_ram_hex return ram_type is file text_file : text open read_mode is "ram_content_hex.txt"; variable text_line : line; variable ram_content : ram_type; begin for i in 0 to ram_depth - 1 loop readline(text_file, text_line); hread(text_line, ram_content(i)); end loop; return ram_content; end function;
Der readline
Prozedur innerhalb der for-Schleife liest jeweils eine Textzeile und weist sie dem text_line
zu Variable. Dieses Objekt ist vom Typ line
, das ist ein Zugriffstyp auf ein Zeichenfolgenobjekt, ein Zeiger auf eine dynamisch zugewiesene Zeichenfolge. In der nächsten Zeile der hread
Die Prozedur liest den String aus line
-Objekt und wandelt es in einen std_ulogic_vector
um . Dieser Typ kann direkt dem std_logic_vector
zugeordnet werden aus denen jede RAM-Zelle aufgebaut ist.
Schließlich deklarieren wir das RAM-Signal, während wir unseren init_ram_hex
aufrufen Funktion, um die Anfangswerte dafür bereitzustellen:
signal ram_hex : ram_type := init_ram_hex;
HREAD in VHDL-2002 und VHDL-93
Leider ist die HREAD
Prozedur ist nur in VHDL-2008 verfügbar. In allen früheren Versionen von VHDL war der Standard READ
Verfahren muss stattdessen verwendet werden. Der READ
Die Prozedur ist mit vielen verschiedenen Ausgabetypen überladen, aber es gibt keine Option zum Lesen von Hexadezimalwerten.
Lassen Sie uns einen benutzerdefinierten Algorithmus zum Konvertieren eines hexadezimalen ASCII-Zeichens in ein VHDL std_logic_vector
schreiben . Zuerst müssen wir die Zeichen einzeln aus dem text_line
lesen Objekt, dann decodieren wir ihre Werte und weisen sie dem richtigen Abschnitt des RAM-Slot-Vektors zu. Der folgende Code zeigt eine äquivalente Implementierung von init_ram_hex
Funktion, die auch in älteren VHDL-Versionen funktioniert.
impure function init_ram_hex return ram_type is file text_file : text open read_mode is "ram_content_hex.txt"; variable text_line : line; variable ram_content : ram_type; variable c : character; variable offset : integer; variable hex_val : std_logic_vector(3 downto 0); begin for i in 0 to ram_depth - 1 loop readline(text_file, text_line); offset := 0; while offset < ram_content(i)'high loop read(text_line, c); case c is when '0' => hex_val := "0000"; when '1' => hex_val := "0001"; when '2' => hex_val := "0010"; when '3' => hex_val := "0011"; when '4' => hex_val := "0100"; when '5' => hex_val := "0101"; when '6' => hex_val := "0110"; when '7' => hex_val := "0111"; when '8' => hex_val := "1000"; when '9' => hex_val := "1001"; when 'A' | 'a' => hex_val := "1010"; when 'B' | 'b' => hex_val := "1011"; when 'C' | 'c' => hex_val := "1100"; when 'D' | 'd' => hex_val := "1101"; when 'E' | 'e' => hex_val := "1110"; when 'F' | 'f' => hex_val := "1111"; when others => hex_val := "XXXX"; assert false report "Found non-hex character '" & c & "'"; end case; ram_content(i)(ram_content(i)'high - offset downto ram_content(i)'high - offset - 3) := hex_val; offset := offset + 4; end loop; end loop; return ram_content; end function;
Der Algorithmus geht einfach jede Zeile durch, während er sich jedes Zeichen ansieht, und wandelt es in den richtigen Binärwert um. Wenn ein Zeichen gefunden wird, das nicht im Bereich 0x0-0xF liegt, wird ein Bestätigungsfehler in when others
ausgelöst Zweig. Der offset
Die Variable steuert die Slice-Position innerhalb jeder Speicherzelle, der der decodierte Wert zugewiesen werden soll.
Sie fragen sich vielleicht, warum wir nicht einen benutzerdefinierten hread
erstellen Prozedur, anstatt sie innerhalb von init_ram_hex
zu codieren Funktion? Dann müssten wir den init_ram_hex
nicht ändern überhaupt funktionieren, würden wir einfach unseren benutzerdefinierten hread
verwenden Verfahren anstelle des fehlenden Standardverfahrens.
Das würde in den meisten Simulatoren und einigen Synthesizern wie Lattice iCEcube2 funktionieren, aber es wird nicht in Xilinx Vivado synthetisiert. Die folgende Fehlermeldung gibt deutlich an, wo das Problem liegt.
In Vivado:
[Synth 8-27] Prozedurargument vom Typ ‚line‘ wird nicht unterstützt [init_ram_tb.vhd:15]
procedure hread(l: inout line; value: out std_logic_vector) is variable c : character; variable ok : boolean; variable i : integer := 0; variable hex_val : std_logic_vector(3 downto 0); begin while i < value'high loop read(l, c); case c is when '0' => hex_val := "0000"; when '1' => hex_val := "0001"; when '2' => hex_val := "0010"; when '3' => hex_val := "0011"; when '4' => hex_val := "0100"; when '5' => hex_val := "0101"; when '6' => hex_val := "0110"; when '7' => hex_val := "0111"; when '8' => hex_val := "1000"; when '9' => hex_val := "1001"; when 'A' | 'a' => hex_val := "1010"; when 'B' | 'b' => hex_val := "1011"; when 'C' | 'c' => hex_val := "1100"; when 'D' | 'd' => hex_val := "1101"; when 'E' | 'e' => hex_val := "1110"; when 'F' | 'f' => hex_val := "1111"; when others => hex_val := "XXXX"; assert false report "Found non-hex character '" & c & "'"; end case; value(value'high - i downto value'high - i - 3) := hex_val; i := i + 4; end loop; end procedure;
Binärwerte aus Datei lesen
Möglicherweise möchten Sie die RAM-Werte als binäre Literale anstelle von Hex-Zeichen speichern, wenn die RAM-Breite kein Vielfaches von 8 ist. Die folgende Auflistung zeigt den gleichen Inhalt wie zuvor, aber im Binärformat dargestellt, indem nur die Zeichen 0
und 1
.
12–255256 | 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000 |
Der unten gezeigte Algorithmus dient zum Lesen von Binärwerten aus einer Datei. Es ähnelt dem Lesen von Hexadezimalzahlen, aber in VHDL-2008 sollten Sie den BREAD
verwenden Prozeduraufruf statt HREAD
. Es übersetzt ein ASCII-Zeichen in einen einzelnen std_ulogic
-Wert, der implizit in std_logic
umgewandelt wird .
impure function init_ram_bin return ram_type is file text_file : text open read_mode is "ram_content_bin.txt"; variable text_line : line; variable ram_content : ram_type; begin for i in 0 to ram_depth - 1 loop readline(text_file, text_line); bread(text_line, ram_content(i)); end loop; return ram_content; end function;
Schließlich initialisieren wir das RAM-Signal, indem wir unsere neue unreine Funktion aufrufen, wie im folgenden Code gezeigt.
signal ram_bin : ram_type := init_ram_bin;
BROT in VHDL-2002 und VHDL-93
Wir können unseren Code einfach auf ältere VHDL-Versionen portieren, indem wir READ
aufrufen statt BREAD
. Der folgende Auszug aus dem VHDL-Standard zeigt den Prototyp von READ
an deren Verwendung wir interessiert sind.
procedure READ (L: inout LINE; VALUE: out BIT);
Die READ
Prozedur, die einen std_ulogic
ausgibt gab es vor VHDL-2008 nicht, daher müssen wir den bit
verwenden Version aus dem TEXTIO
Bibliothek. Glücklicherweise kann dieser Typ leicht in std_logic
konvertiert werden indem Sie den Standard To_StdLogicVector
verwenden Funktion.
Die Implementierung von init_ram_bin
unten gezeigt funktioniert sowohl in VHDL-2002 als auch in VHDL-93.
impure function init_ram_bin return ram_type is file text_file : text open read_mode is "ram_content_bin.txt"; variable text_line : line; variable ram_content : ram_type; variable bv : bit_vector(ram_content(0)'range); begin for i in 0 to ram_depth - 1 loop readline(text_file, text_line); read(text_line, bv); ram_content(i) := To_StdLogicVector(bv); end loop; return ram_content; end function;
Rückportierung der IEEE std_logic_1164-Bibliothek
Eine Alternative zum Ändern des Codes für ältere VHDL-Versionen ist die Verwendung des Drittanbieterpakets std_logic_1164_additions. Durch Herunterladen und Hinzufügen dieser Bibliothek zu Ihrem Projekt können Sie die neuen Prozeduren auch in VHDL-2002 und VHDL-93 verwenden. Natürlich werden Sie dann viel mehr importieren und Ihr Code wird immer von diesem Paket abhängen.
VHDL
- So schützen Sie Aluminium vor Korrosion
- Wie sich Metallelemente von Nichtmetallelementen unterscheiden
- So erstellen Sie eine CloudFormation-Vorlage mit AWS
- Inwiefern unterscheidet sich Cloud Computing von herkömmlichem Computing?
- Wie man Kommentare in der C-Programmierung schreibt
- Java BufferedReader:Lesen von Dateien in Java mit Beispiel
- Python-Durchschnitt:So finden Sie den DURCHSCHNITT einer Liste in Python
- Was ist Mikrometer? | Wie liest man ein Mikrometer ab
- So rufen Sie einen Funktionsblock von einem OPC UA-Client mithilfe eines Informationsmodells auf
- Wie man CNC-Baupläne liest