Comment initialiser la RAM à partir d'un fichier à l'aide de TEXTIO
Un moyen pratique de remplir la RAM de bloc avec des valeurs initiales consiste à lire des littéraux binaires ou hexadécimaux à partir d'un fichier ASCII. C'est aussi un bon moyen de créer une ROM (mémoire en lecture seule) en VHDL. Après tout, la RAM et la ROM sont la même chose dans les FPGA, la ROM est une RAM à partir de laquelle vous ne lisez que.
Les exemples de cet article supposeront que les constantes et le type de RAM suivants ont été déclarés au début de la région déclarative du fichier VHDL.
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);
Ce billet de blog fait partie d'une série sur l'utilisation de la bibliothèque TEXTIO en VHDL. Lisez les autres articles ici :
Fichier Stimulus lu dans testbench avec TEXTIO
Image bitmap de fichier BMP lue à l'aide de TEXTIO
READLINE, LINE, HREAD, OREAD et BREAD
Les sous-programmes et types nécessaires à la lecture et à l'écriture de fichiers externes en VHDL se trouvent dans le TEXTIO
forfait. Ce package fait partie du std
bibliothèque. La bibliothèque standard est toujours chargée; par conséquent, nous n'avons pas à l'importer explicitement avec le library
mot-clé.
Nous pouvons simplement continuer et utiliser le TEXTIO
package dans l'en-tête de notre fichier VHDL comme ceci :
use std.textio.all;
Nous stockerons les données RAM dans un fichier ASCII où une ligne de texte correspond à un emplacement mémoire. Pour lire une ligne de texte on utilise le READLINE
procédure du TEXTIO
forfait. La procédure prend deux arguments, le nom du fichier comme entrée constante et la ligne de texte analysée comme un inout
variable. La déclaration prototype du READLINE
procédure et le LINE
type tiré de la spécification standard VHDL est illustré ci-dessous.
procedure READLINE (file F: TEXT; L: inout LINE); type LINE is access STRING; -- A LINE is a pointer -- to a STRING value.
Bien que la classe du LINE
le paramètre n'est pas explicitement spécifié dans la déclaration de prototype de READLINE
, c'est une variable car c'est la classe par défaut pour inout
paramètres. Le LINE
type est simplement un type d'accès à une chaîne, un pointeur vers un objet chaîne alloué dynamiquement.
VHDL-2008 définit le OREAD
, HREAD
, et BREAD
procédures d'extraction des valeurs octales, hexadécimales et binaires d'un LINE
objet. Les méthodes de lecture des valeurs octales et hexadécimales sont assez similaires, les valeurs octales ne sont qu'un sous-ensemble des hexadécimaux. Pour plus de simplicité, nous allons ignorer les lectures octales dans cet article et nous concentrer sur la lecture des valeurs hexadécimales et binaires à partir d'un fichier texte.
Le code ci-dessous montre les définitions des procédures qui sont pertinentes pour nous, elles ne sont disponibles que dans VHDL-2008 et les révisions plus récentes. Le OREAD
et HREAD
les procédures sont disponibles en deux versions surchargées pour chacun des types de sortie pris en charge. Le GOOD
facultatif la sortie peut être utilisée pour détecter les erreurs de lecture, bien que la plupart des outils produisent une erreur ou un avertissement, que cette sortie soit utilisée ou non.
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];Cliquez ici pour voir les définitions des procédures de saisie de la bibliothèque TEXTIO
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];Cliquez ici pour voir les définitions des procédures d'entrée de la bibliothèque std_logic_1164
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];
Lire les valeurs hexadécimales du fichier
L'hexadécimal est un format pratique pour décrire le contenu de la RAM car deux caractères hexadécimaux se traduisent directement en un octet, huit bits. Chaque caractère décrit un quartet (demi-octet) et chaque ligne du fichier texte décrit le contenu d'un emplacement RAM. La liste ci-dessous montre un extrait du ram_content_hex.txt dossier. Il a été rempli d'exemples de valeurs allant de 1 à 256 décimales, écrites en hexadécimal.
12–255256 | 00000001 00000002 ... 000000FF 00000100 |
Pour charger les données du fichier texte, nous utilisons une fonction impure déclarée sous le ram_type
, mais au-dessus de la déclaration du signal RAM. Le code ci-dessous montre le init_ram_hex
fonction qui lit les données du fichier texte et les renvoie sous la forme d'un ram_type
objet.
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;
Le readline
procédure à l'intérieur de la boucle for lit une ligne de texte à la fois et l'assigne au text_line
variable. Cet objet est de type line
, qui est un type d'accès à un objet chaîne, un pointeur vers une chaîne allouée dynamiquement. Sur la ligne suivante, le hread
la procédure lit la chaîne à partir du line
objet et le convertit en un std_ulogic_vector
. Ce type peut être affecté directement au std_logic_vector
dont chaque cellule RAM est constituée.
Enfin, nous déclarons le signal RAM en appelant notre init_ram_hex
fonction pour lui fournir les valeurs initiales :
signal ram_hex : ram_type := init_ram_hex;
HREAD en VHDL-2002 et VHDL-93
Malheureusement, le HREAD
La procédure n'est disponible qu'en VHDL-2008. Dans toutes les versions précédentes de VHDL, le standard READ
procédure doit être utilisée à la place. Le READ
La procédure est surchargée avec de nombreux types de sortie différents, mais il n'y a pas d'option pour lire les valeurs hexadécimales.
Écrivons un algorithme personnalisé pour convertir un caractère ASCII hexadécimal en un VHDL std_logic_vector
. Tout d'abord, nous devons lire les caractères un par un à partir du text_line
objet, puis nous décodons leurs valeurs et les attribuons à la bonne tranche du vecteur d'emplacement de RAM. Le code ci-dessous montre une implémentation équivalente du init_ram_hex
fonction qui fonctionne également dans les anciennes versions VHDL.
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;
L'algorithme parcourt simplement chaque ligne tout en examinant chaque caractère, en le convertissant en la valeur binaire correcte. Si un caractère qui n'est pas dans la plage 0x0-0xF est rencontré, un échec d'assertion est déclenché dans le when others
bifurquer. Le offset
contrôle la position de la tranche dans chaque cellule de mémoire à laquelle attribuer la valeur décodée.
Vous vous demandez peut-être pourquoi ne pas créer un hread
personnalisé procédure au lieu de la coder à l'intérieur du init_ram_hex
fonction? Alors nous n'aurions pas à changer le init_ram_hex
fonction du tout, nous utiliserions simplement notre hread
personnalisé procédure à la place de la procédure standard manquante.
Cela fonctionnerait dans la plupart des simulateurs et certains synthétiseurs comme Lattice iCEcube2, mais il ne synthétisera pas dans Xilinx Vivado. Le message d'erreur ci-dessous indique clairement quel est le problème.
Dans Vivado :
[Synth 8-27] L'argument de procédure de type 'line' n'est pas supporté [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;
Lire les valeurs binaires du fichier
Vous pouvez stocker les valeurs RAM sous forme de littéraux binaires au lieu de caractères hexadécimaux si la largeur de la RAM n'est pas un multiple de 8. La liste ci-dessous montre le même contenu qu'avant, mais représenté au format binaire en utilisant uniquement les caractères 0
et 1
.
12–255256 | 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000 |
L'algorithme présenté ci-dessous sert à lire les valeurs binaires du fichier. C'est similaire à la lecture d'hexadécimaux, mais en VHDL-2008, vous devez utiliser le BREAD
appel de procédure au lieu de HREAD
. Il traduira un caractère ASCII en un seul std_ulogic
valeur, qui est implicitement convertie en std_logic
.
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;
Enfin, nous initialisons le signal RAM en appelant notre nouvelle fonction impure comme indiqué dans le code ci-dessous.
signal ram_bin : ram_type := init_ram_bin;
BREAD en VHDL-2002 et VHDL-93
Nous pouvons facilement rendre notre code portable aux anciennes versions VHDL en appelant READ
au lieu de BREAD
. L'extrait de la norme VHDL ci-dessous montre le prototype de READ
que nous souhaitons utiliser.
procedure READ (L: inout LINE; VALUE: out BIT);
Le READ
procédure qui produit un std_ulogic
n'existait pas avant VHDL-2008, nous devons donc utiliser le bit
version du TEXTIO
bibliothèque. Heureusement, ce type peut facilement être converti en std_logic
en utilisant la norme To_StdLogicVector
fonction.
L'implémentation de init_ram_bin
illustré ci-dessous fonctionne en VHDL-2002 ainsi qu'en 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;
Backport de la bibliothèque IEEE std_logic_1164
Une alternative à la modification du code des versions VHDL héritées consiste à utiliser le package tiers std_logic_1164_additions. En téléchargeant et en ajoutant cette bibliothèque à votre projet, vous pourrez également utiliser les nouvelles procédures en VHDL-2002 et VHDL-93. Bien sûr, vous importerez alors beaucoup plus et votre code dépendra toujours de ce package.
VHDL
- Comment protéger l'aluminium de la corrosion
- Comment les éléments métalliques diffèrent des éléments non métalliques
- Comment créer un modèle CloudFormation à l'aide d'AWS
- En quoi le cloud computing est-il différent de l'informatique traditionnelle ?
- Comment écrire des commentaires en programmation C
- Java BufferedReader :comment lire un fichier en Java avec un exemple
- Python Average :Comment trouver la MOYENNE d'une liste en Python
- Qu'est-ce qu'un micromètre ? | Comment lire un micromètre
- Comment appeler un bloc fonction depuis un client OPC UA à l'aide d'un modèle d'information