Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> VHDL

Hoe RAM vanuit een bestand te initialiseren met TEXTIO

Een handige manier om blok-RAM met beginwaarden te vullen, is door binaire of hexadecimale letterlijke waarden uit een ASCII-bestand te lezen. Dit is ook een goede manier om een ​​ROM (read-only memory) in VHDL te maken. RAM en ROM zijn immers hetzelfde in FPGA's, ROM is een RAM waarvan je alleen leest.

In de voorbeelden in dit artikel wordt ervan uitgegaan dat de volgende constanten en het RAM-type zijn gedeclareerd aan het begin van het declaratieve gebied van het VHDL-bestand.

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);

Deze blogpost maakt deel uit van een serie over het gebruik van de TEXTIO-bibliotheek in VHDL. Lees hier de andere artikelen:

Stimulusbestand gelezen in testbench met TEXTIO

BMP-bestand bitmapafbeelding gelezen met TEXTIO

READLINE, LINE, HREAD, OREAD en BROOD

De subprogramma's en typen die nodig zijn voor het lezen en schrijven van externe bestanden in VHDL bevinden zich in de TEXTIO pakket. Dit pakket maakt deel uit van de std bibliotheek. De standaardbibliotheek wordt altijd geladen; daarom hoeven we het niet expliciet te importeren met de library zoekwoord.

We kunnen gewoon doorgaan en de TEXTIO . gebruiken pakket in de header van ons VHDL-bestand als volgt:

use std.textio.all;

We slaan de RAM-gegevens op in een ASCII-bestand waarbij één regel tekst overeenkomt met een geheugenslot. Om een ​​regel tekst te lezen gebruiken we de READLINE procedure van de TEXTIO pakket. De procedure heeft twee argumenten, de bestandsnaam als constante invoer en de geparseerde tekstregel als een inout variabel. De prototypeverklaring van de READLINE procedure en de LINE type overgenomen uit de VHDL-standaardspecificatie wordt hieronder weergegeven.

procedure READLINE (file F: TEXT; L: inout LINE);

type LINE is access STRING; -- A LINE is a pointer
                            -- to a STRING value.

Hoewel de klasse van de LINE parameter is niet expliciet gespecificeerd in de prototypedeclaratie van READLINE , het is een variabele omdat dat de standaardklasse is voor inout parameters. De LINE type is gewoon een toegangstype tot een string, een pointer naar een dynamisch toegewezen stringobject.

VHDL-2008 definieert de OREAD , HREAD , en BREAD procedures voor het extraheren van octale, hexadecimale en binaire waarden uit een LINE object. De methoden voor het lezen van octale en hexadecimale waarden zijn vrij gelijkaardig, de octale waarden zijn slechts een subset van de hexadecimalen. Voor de eenvoud gaan we in dit artikel octale waarden overslaan en concentreren we ons op het lezen van hexadecimale en binaire waarden uit een tekstbestand.

De onderstaande code toont de definities van de procedures die voor ons relevant zijn, ze zijn alleen beschikbaar in VHDL-2008 en nieuwere revisies. De OREAD en HREAD procedures zijn er in twee overbelaste smaken voor elk van de ondersteunde uitvoertypen. De optionele GOOD output kan worden gebruikt voor het detecteren van leesfouten, hoewel de meeste tools een fout of waarschuwing zullen produceren, ongeacht of deze output wordt gebruikt of niet.

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];
Klik hier om de definities van de invoerprocedure uit de TEXTIO-bibliotheek te zien
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];
Klik hier om de definities van de invoerprocedure te zien uit de std_logic_1164 bibliotheek
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];

Lees hexadecimale waarden uit bestand

Hexadecimaal is een handig formaat voor het beschrijven van RAM-inhoud, omdat twee hexadecimale tekens direct worden vertaald in één byte, acht bits. Elk teken beschrijft een nibble (halve byte) en elke regel in het tekstbestand beschrijft de inhoud van één RAM-slot. De onderstaande lijst toont een fragment uit de ram_content_hex.txt het dossier. Het is gevuld met voorbeeldwaarden variërend van 1 tot 256 decimaal, geschreven als hex.

12–255256 00000001 00000002 ... 000000FF 00000100

Om de gegevens uit het tekstbestand te laden, gebruiken we een onzuivere functie die wordt gedeclareerd onder de ram_type , maar boven de RAM-signaaldeclaratie. De onderstaande code toont de init_ram_hex functie die de gegevens uit het tekstbestand leest en deze teruggeeft als een ram_type voorwerp.

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;

De readline procedure binnen de for-lus leest één regel tekst tegelijk en wijst deze toe aan de text_line variabel. Dit object is van het type line , wat een toegangstype is tot een tekenreeksobject, een aanwijzer naar een dynamisch toegewezen tekenreeks. Op de volgende regel, de hread procedure leest de string uit de line object en converteert het naar een std_ulogic_vector . Dit type kan direct worden toegewezen aan de std_logic_vector waaruit elke RAM-cel is opgebouwd.

Ten slotte declareren we het RAM-signaal terwijl we onze init_ram_hex . aanroepen functie om de beginwaarden ervoor te geven:

signal ram_hex : ram_type := init_ram_hex;

HREAD in VHDL-2002 en VHDL-93

Helaas is de HREAD procedure is alleen beschikbaar in VHDL-2008. In alle eerdere versies van VHDL de standaard READ in plaats daarvan moet de procedure worden gebruikt. De READ procedure is overbelast met veel verschillende uitvoertypes, maar er is geen optie voor het lezen van hexadecimale waarden.

Laten we een aangepast algoritme schrijven voor het converteren van hexadecimale ASCII-tekens naar een VHDL std_logic_vector . Eerst moeten we de tekens een voor een lezen uit de text_line object, dan decoderen we hun waarden en wijzen ze toe aan het juiste deel van de RAM-slotvector. De onderstaande code toont een equivalente implementatie van de init_ram_hex functie die ook werkt in oudere VHDL-versies.

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;

Het algoritme gaat gewoon door elke regel terwijl het naar elk teken kijkt en converteert het naar de juiste binaire waarde. Als een teken wordt aangetroffen dat niet in het bereik 0x0-0xF ligt, wordt een assertfout weergegeven in de when others tak. De offset variabele regelt de slice-positie binnen elke geheugencel waaraan de gedecodeerde waarde moet worden toegewezen.

Je vraagt ​​je misschien af ​​waarom we geen aangepaste hread . maken procedure in plaats van het te coderen in de init_ram_hex functie? Dan hoeven we de init_ram_hex . niet te veranderen functie helemaal niet gebruiken, zouden we gewoon onze aangepaste hread procedure in plaats van de ontbrekende standaardprocedure.

Dat zou werken in de meeste simulators en sommige synthesizers zoals Lattice iCEcube2, maar het zal niet synthetiseren in Xilinx Vivado. De onderstaande foutmelding geeft duidelijk aan wat het probleem is.

In Vivado:
[Synth 8-27] Procedure-argument van het type 'line' wordt niet ondersteund [init_ram_tb.vhd:15]

Klik hier om de alternatieve implementatie van de HREAD-procedure te zien
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;

Binaire waarden uit bestand lezen

U kunt de RAM-waarden opslaan als binaire letterlijke waarden in plaats van hexadecimale tekens als de RAM-breedte geen veelvoud van 8 is. De onderstaande lijst toont dezelfde inhoud als voorheen, maar weergegeven in binaire indeling met alleen de tekens 0 en 1 .

12–255256 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000

Het onderstaande algoritme is voor het lezen van binaire waarden uit een bestand. Het is vergelijkbaar met het lezen van hexadecimalen, maar in VHDL-2008 moet u de BREAD gebruiken procedureaanroep in plaats van HREAD . Het vertaalt één ASCII-teken naar een enkele std_ulogic waarde, die impliciet wordt geconverteerd naar 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;

Ten slotte initialiseren we het RAM-signaal door onze nieuwe onzuivere functie aan te roepen, zoals weergegeven in de onderstaande code.

signal ram_bin : ram_type := init_ram_bin;

BROOD in VHDL-2002 en VHDL-93

We kunnen onze code gemakkelijk overdraagbaar maken naar oudere VHDL-versies door READ . te bellen in plaats van BREAD . Het fragment uit de VHDL-standaard hieronder toont het prototype van READ die we willen gebruiken.

procedure READ (L: inout LINE; VALUE: out BIT);

De READ procedure die een std_ulogic . uitvoert bestond niet vóór VHDL-2008, daarom moeten we de bit . gebruiken versie van de TEXTIO bibliotheek. Gelukkig kan dit type eenvoudig worden omgezet naar std_logic door gebruik te maken van de standaard To_StdLogicVector functie.

De implementatie van init_ram_bin hieronder getoond werkt in VHDL-2002 en ook 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;

Backport van de IEEE std_logic_1164 bibliotheek

Een alternatief voor het wijzigen van de code voor oudere VHDL-versies is het gebruik van het std_logic_1164_additions pakket van derden. Door deze bibliotheek te downloaden en aan uw project toe te voegen, kunt u de nieuwe procedures ook in VHDL-2002 en VHDL-93 gebruiken. Dan importeer je natuurlijk veel meer en is je code altijd afhankelijk van dit pakket.


VHDL

  1. Hoe aluminium te beschermen tegen corrosie?
  2. Hoe metalen elementen verschillen van niet-metalen elementen
  3. Een CloudFormation-sjabloon maken met AWS
  4. Hoe verschilt cloud computing van traditioneel computergebruik?
  5. RC-servocontroller met PWM van een FPGA-pin
  6. Hoe opmerkingen te schrijven in C-programmering
  7. Java BufferedReader:hoe een bestand in Java te lezen met voorbeeld
  8. Python-gemiddelde:hoe het GEMIDDELDE van een lijst in Python te vinden?
  9. Wat is Micrometer? | Hoe lees je een micrometer af?
  10. Een functieblok aanroepen vanuit een OPC UA-client met behulp van een informatiemodel
  11. Hoe lees je CNC-blauwdrukken