Inicialización de RAM de bloques FPGA desde archivos de texto usando la biblioteca TEXTIO de VHDL
Poblar RAM de bloques con valores predefinidos se hace de forma más eficiente leyendo literales binarios o hexadecimales desde un archivo ASCII. Esta técnica también sirve para crear ROMs, ya que la ROM de FPGA es simplemente una RAM que solo se lee.
Para los ejemplos siguientes, se declaran las siguientes constantes y tipo de RAM en 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);
Este artículo es parte de una serie sobre la biblioteca TEXTIO en VHDL. Lectura de archivo de estímulo en testbench usando TEXTIO | Lectura de imagen bitmap BMP usando TEXTIO
Lectura de líneas y datos con TEXTIO
El paquete TEXTIO, ubicado en la biblioteca estándar std, proporciona los subprogramas requeridos para E/S de archivos. Está disponible automáticamente, así que solo necesita importarlo:
use std.textio.all;
Nuestros datos de RAM se almacenarán en un archivo ASCII donde cada línea representa una palabra de memoria. El procedimiento READLINE lee una sola línea en un objeto LINE. Su prototipo es:
procedure READLINE (file F: TEXT; L: inout LINE); type LINE is access STRING; -- puntero a string asignada dinámicamente
VHDL‑2008 introduce OREAD, HREAD y BREAD para extraer valores octales, hexadecimales y binarios de un objeto LINE. Por brevedad nos centraremos en lecturas hexadecimales y binarias. Las declaraciones relevantes son:
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];
Para versiones VHDL legacy (pre‑2008), debe usarse el procedimiento estándar READ, que no soporta hexadecimal directamente. En ese caso se requiere una rutina de conversión personalizada.
Carga de datos hexadecimales
La notación hexadecimal es conveniente porque cada par de dígitos hex mapea directamente a un byte. El archivo de ejemplo ram_content_hex.txt contiene 256 líneas, cada una con una cadena hex de 8 caracteres desde 00000001 hasta 00000100:
| 1 2 … 255 256 | 0000000100000002…000000FF00000100 |
La siguiente función impura lee el archivo y devuelve un array ram_type completamente inicializado. Funciona con VHDL‑2008 y posteriores:
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;
Tras definir la función, la señal RAM se instancia con el contenido inicial:
signal ram_hex : ram_type := init_ram_hex;
VHDL Legacy: Implementación manual de HREAD
Cuando HREAD no está disponible (p.ej., VHDL‑93 o VHDL‑2002), se puede incrustar una rutina de conversión manual en la función de inicialización. El siguiente ejemplo demuestra este enfoque:
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;
Aunque se podría definir un procedimiento dedicado HREAD, la mayoría de herramientas de síntesis (p.ej., Xilinx Vivado) no soportan procedimientos que acepten un argumento LINE. El siguiente error ilustra esta limitación:
En Vivado:
[Synth 8-27] Procedure argument of type ‘line’ is not supported [init_ram_tb.vhd:15]
Lectura de datos binarios
Si la anchura de la RAM no es múltiplo de 8, los literales binarios pueden ser preferibles. El archivo de ejemplo ram_content_bin.txt contiene 256 líneas, cada una con una cadena binaria de 32 bits:
| 1 2 … 255 256 | 0000000000000000000000000000000100000000000000000000000000000010…0000000000000000000000001111111100000000000000000000000100000000 |
En VHDL‑2008, el procedimiento BREAD puede usarse para leer valores binarios directamente:
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;
Instancie la RAM con:
signal ram_bin : ram_type := init_ram_bin;
VHDL Legacy: Lecturas binarias con READ
Para VHDL‑2002 o VHDL‑93, debe usarse el procedimiento READ. Como devuelve un vector bit, el resultado se convierte a std_logic_vector vía To_StdLogicVector:
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;
Retrocompatibilidad de características modernas de TEXTIO
Si prefiere no modificar el código legacy, puede importar el paquete tercero std_logic_1164_additions. Esta biblioteca retrocompatibiliza los procedimientos HREAD y BREAD a versiones antiguas de VHDL, a costa de una dependencia adicional.
Para ejemplos más detallados y lectura adicional, consulte los artículos acompañantes de esta serie.
VHDL
- Micrómetro Explicado: Cómo Leer y Usar Esta Herramienta de Medición de Precisión
- Invocar bloques de función PLC vía clientes OPC UA: Guía práctica
- Protección del aluminio contra la corrosión: Estrategias expertas para una durabilidad duradera
- Elementos metálicos vs. no metálicos: Diferencias clave explicadas
- Dominando la Lectura de Planos CNC: Habilidades Esenciales para Maquinistas Modernos
- Construya su primera plantilla AWS CloudFormation – Guía práctica
- Computación en la nube vs. Computación tradicional: Comparación práctica
- Dominando los comentarios en C: Escribir notas claras y efectivas
- Diseño de un controlador RC Servo basado en FPGA con PWM preciso
- Calculando Promedios en Python: Guía Práctica con Múltiples Métodos
- Lectura de archivos en Java con BufferedReader – Guía práctica con ejemplos