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