Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Cómo inicializar RAM desde un archivo usando TEXTIO

Una forma conveniente de llenar la memoria RAM de bloques con valores iniciales es leer literales binarios o hexadecimales de un archivo ASCII. Esta también es una buena manera de crear una ROM (memoria de solo lectura) en VHDL. Después de todo, la RAM y la ROM son lo mismo en las FPGA, la ROM es una RAM de la que solo se lee.

Los ejemplos a lo largo de este artículo supondrán que las siguientes constantes y tipos de RAM se declararon al comienzo de la región declarativa del archivo 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);

Esta publicación de blog es parte de una serie sobre el uso de la biblioteca TEXTIO en VHDL. Lea los otros artículos aquí:

Archivo de estímulo leído en el banco de pruebas usando TEXTIO

Imagen de mapa de bits de archivo BMP leída con TEXTIO

READLINE, LINE, HREAD, OREAD y BREAD

Los subprogramas y tipos necesarios para leer y escribir archivos externos en VHDL se encuentran en el TEXTIO paquete. Este paquete es parte del std biblioteca. La biblioteca estándar siempre está cargada; por lo tanto, no tenemos que importarlo explícitamente con el library palabra clave.

Simplemente podemos seguir adelante y usar el TEXTIO paquete en el encabezado de nuestro archivo VHDL como este:

use std.textio.all;

Almacenaremos los datos de RAM en un archivo ASCII donde una línea de texto corresponde a una ranura de memoria. Para leer una línea de texto usamos el READLINE procedimiento del TEXTIO paquete. El procedimiento toma dos argumentos, el nombre del archivo como una entrada constante y la línea de texto analizada como un inout variable. La declaración prototipo del READLINE procedimiento y el LINE El tipo tomado de la especificación estándar VHDL se muestra a continuación.

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

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

Aunque la clase del LINE el parámetro no se especifica explícitamente en la declaración del prototipo de READLINE , es una variable porque esa es la clase predeterminada para inout parámetros El LINE type es simplemente un tipo de acceso a una cadena, un puntero a un objeto de cadena asignado dinámicamente.

VHDL-2008 define el OREAD , HREAD y BREAD procedimientos para extraer valores octales, hexadecimales y binarios de un LINE objeto. Los métodos para leer valores octales y hexadecimales son bastante similares, los valores octales son simplemente un subconjunto de los hexadecimales. Para simplificar, omitiremos las lecturas octales en este artículo y nos centraremos en cómo leer valores hexadecimales y binarios de un archivo de texto.

El siguiente código muestra las definiciones de los procedimientos que son relevantes para nosotros, solo están disponibles en VHDL-2008 y revisiones más recientes. El OREAD y HREAD Los procedimientos vienen en dos sabores sobrecargados para cada uno de los tipos de salida admitidos. El GOOD opcional La salida se puede usar para detectar errores de lectura, aunque la mayoría de las herramientas generarán un error o una advertencia, independientemente de si se usa o no esta salida.

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];
Haga clic aquí para ver las definiciones de procedimientos de entrada de la biblioteca 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];
Haga clic aquí para ver las definiciones de procedimientos de entrada de la biblioteca 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];

Leer valores hexadecimales del archivo

Hexadecimal es un formato útil para describir el contenido de RAM porque dos caracteres hexadecimales se traducen directamente en un byte, ocho bits. Cada carácter describe un nibble (medio byte) y cada línea en el archivo de texto describe el contenido de una ranura de RAM. La siguiente lista muestra un extracto del ram_content_hex.txt expediente. Se ha llenado con valores de ejemplo que van desde 1 a 256 decimales, escritos como hexadecimal.

12–255256 00000001 00000002 ... 000000FF 00000100

Para cargar los datos del archivo de texto usamos una función impura declarada debajo del ram_type , pero por encima de la declaración de la señal RAM. El siguiente código muestra el init_ram_hex función que lee los datos del archivo de texto y los devuelve como ram_type objeto.

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;

El readline El procedimiento dentro del ciclo for lee una línea de texto a la vez y la asigna al text_line variable. Este objeto es de tipo line , que es un tipo de acceso a un objeto de cadena, un puntero a una cadena asignada dinámicamente. En la siguiente línea, el hread procedimiento lee la cadena del line objeto y lo convierte en un std_ulogic_vector . Este tipo se puede asignar directamente al std_logic_vector con el que está construida cada celda RAM.

Finalmente, declaramos la señal de RAM mientras llamamos a nuestro init_ram_hex función para proporcionar los valores iniciales para ello:

signal ram_hex : ram_type := init_ram_hex;

HREAD en VHDL-2002 y VHDL-93

Desafortunadamente, el HREAD El procedimiento solo está disponible en VHDL-2008. En todas las versiones anteriores de VHDL, el estándar READ en su lugar debe utilizarse el procedimiento. El READ El procedimiento está sobrecargado con muchos tipos de salida diferentes, pero no hay una opción para leer valores hexadecimales.

Escribamos un algoritmo personalizado para convertir caracteres ASCII hexadecimales a VHDL std_logic_vector . Primero, necesitamos leer los caracteres uno por uno del text_line objeto, luego decodificamos sus valores y los asignamos a la porción correcta del vector de ranura de RAM. El siguiente código muestra una implementación equivalente del init_ram_hex función que también funciona en versiones heredadas de 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;

El algoritmo simplemente pasa por cada línea mientras mira cada carácter, convirtiéndolo al valor binario correcto. Si se encuentra un carácter que no está en el rango 0x0-0xF, se genera un error de afirmación en el when others rama. El offset La variable controla la posición del segmento dentro de cada celda de memoria para asignarle el valor decodificado.

Puede que se pregunte por qué no creamos un hread personalizado procedimiento en lugar de codificarlo dentro del init_ram_hex ¿función? Entonces no tendríamos que cambiar el init_ram_hex en absoluto, simplemente usaríamos nuestro hread personalizado procedimiento en lugar del estándar que falta.

Eso funcionaría en la mayoría de los simuladores y algunos sintetizadores como Lattice iCEcube2, pero no se sintetizará en Xilinx Vivado. El siguiente mensaje de error indica claramente cuál es el problema.

En Vivado:
[Synth 8-27] El argumento de procedimiento de tipo 'línea' no es compatible [init_ram_tb.vhd:15]

Haga clic aquí para ver la implementación alternativa del procedimiento 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;

Leer valores binarios del archivo

Es posible que desee almacenar los valores de RAM como literales binarios en lugar de caracteres hexadecimales si el ancho de RAM no es un múltiplo de 8. La siguiente lista muestra el mismo contenido que antes, pero representado en formato binario usando solo los caracteres 0 y 1 .

12–255256 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000

El algoritmo que se muestra a continuación es para leer valores binarios del archivo. Es similar a leer hexadecimales, pero en VHDL-2008 debe usar el BREAD llamada de procedimiento en lugar de HREAD . Traducirá un carácter ASCII a un solo std_ulogic valor, que se convierte implícitamente a 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;

Finalmente, inicializamos la señal de RAM llamando a nuestra nueva función impura como se muestra en el código a continuación.

signal ram_bin : ram_type := init_ram_bin;

PAN en VHDL-2002 y VHDL-93

Podemos hacer que nuestro código sea fácilmente portátil a las versiones heredadas de VHDL llamando a READ en lugar de BREAD . El extracto del estándar VHDL a continuación muestra el prototipo de READ que estamos interesados ​​en usar.

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

El READ procedimiento que genera un std_ulogic no existía antes de VHDL-2008, por lo que tenemos que usar el bit versión del TEXTIO biblioteca. Afortunadamente, este tipo se puede convertir fácilmente a std_logic usando el estándar To_StdLogicVector función.

La implementación de init_ram_bin que se muestra a continuación funciona en VHDL-2002 y también 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 biblioteca IEEE std_logic_1164

Una alternativa a cambiar el código para las versiones heredadas de VHDL es usar el paquete de terceros std_logic_1164_additions. Al descargar y agregar esta biblioteca a su proyecto, podrá usar los nuevos procedimientos también en VHDL-2002 y VHDL-93. Por supuesto, importará mucho más y su código siempre dependerá de este paquete.


VHDL

  1. Cómo proteger el aluminio de la corrosión
  2. En qué se diferencian los elementos metálicos de los no metálicos
  3. Cómo crear una plantilla de CloudFormation con AWS
  4. ¿En qué se diferencia la computación en la nube de la computación tradicional?
  5. Servocontrolador RC usando PWM desde un pin FPGA
  6. Cómo escribir comentarios en programación C
  7. Java BufferedReader:cómo leer un archivo en Java con un ejemplo
  8. Promedio de Python:cómo encontrar el PROMEDIO de una lista en Python
  9. ¿Qué es Micrómetro? | ¿Cómo se lee un micrómetro?
  10. Cómo llamar a un bloque de funciones desde un cliente OPC UA utilizando un modelo de información
  11. Cómo leer planos CNC