Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

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]

Cliquez ici pour voir l'implémentation alternative de la procédure HREAD
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

  1. Comment protéger l'aluminium de la corrosion
  2. Comment les éléments métalliques diffèrent des éléments non métalliques
  3. Comment créer un modèle CloudFormation à l'aide d'AWS
  4. En quoi le cloud computing est-il différent de l'informatique traditionnelle ?
  5. Comment écrire des commentaires en programmation C
  6. Java BufferedReader :comment lire un fichier en Java avec un exemple
  7. Python Average :Comment trouver la MOYENNE d'une liste en Python
  8. Qu'est-ce qu'un micromètre ? | Comment lire un micromètre
  9. Comment appeler un bloc fonction depuis un client OPC UA à l'aide d'un modèle d'information