Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> VHDL

Inicializando Block RAM de FPGA a partir de Arquivos de Texto Usando a Biblioteca TEXTIO do VHDL

Popular block RAM com valores predefinidos é feito mais eficientemente lendo literais binários ou hexadecimais de um arquivo ASCII. Esta técnica também serve para criar ROMs, pois ROM de FPGA é simplesmente uma RAM que só é lida.

Para os exemplos abaixo, as seguintes constantes e tipo de RAM são declarados na região declarativa do arquivo 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 artigo é parte de uma série sobre a biblioteca TEXTIO em VHDL. Leitura de arquivo de estímulo em testbench usando TEXTIO | Leitura de imagem bitmap BMP usando TEXTIO

Lendo Linhas e Dados com TEXTIO

O pacote TEXTIO, localizado na biblioteca padrão std, fornece os subprogramas necessários para I/O de arquivo. Ele está disponível automaticamente, então você só precisa importá-lo:

use std.textio.all;

Nossos dados de RAM serão armazenados em um arquivo ASCII onde cada linha representa uma palavra de memória. O procedimento READLINE lê uma única linha em um objeto LINE. Seu protótipo é:

procedure READLINE (file F: TEXT; L: inout LINE); type LINE is access STRING; -- pointer to a dynamically allocated string

VHDL-2008 introduz OREAD, HREAD e BREAD para extrair valores octais, hexadecimais e binários de um objeto LINE. Para brevidade, focaremos em leituras hexadecimais e binárias. As declarações relevantes são:

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 versões VHDL legadas (pré-2008), o procedimento padrão READ deve ser usado, que não suporta hexadecimal diretamente. Nesse caso, uma rotina de conversão customizada é necessária.

Carregando Dados Hexadecimais

Notação hexadecimal é conveniente porque cada par de dígitos hex mapeia diretamente para um byte. O arquivo de exemplo ram_content_hex.txt contém 256 linhas, cada uma com uma string hex de 8 caracteres de 00000001 a 00000100:

1
2
…
255
256
00000001
00000002
…
000000FF
00000100

A seguinte função impura lê o arquivo e retorna um array ram_type totalmente inicializado. Funciona com VHDL-2008 e mais recente:

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;

Após definir a função, o sinal RAM é instanciado com o conteúdo inicial:

signal ram_hex : ram_type := init_ram_hex;

VHDL Legado: Implementando HREAD Manualmente

Quando HREAD não está disponível (ex: VHDL-93 ou VHDL-2002), uma rotina de conversão manual pode ser embutida na função de inicialização. O exemplo a seguir demonstra esta abordagem:

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;

Embora um procedimento HREAD dedicado pudesse ser definido, a maioria das ferramentas de síntese (ex: Xilinx Vivado) não suporta procedimentos que aceitam argumento LINE. O erro a seguir ilustra esta limitação:

No Vivado:
[Synth 8-27] Procedure argument of type 'line' is not supported [init_ram_tb.vhd:15]

Lendo Dados Binários

Se a largura da RAM não é múltiplo de 8, literais binários podem ser preferíveis. O arquivo de exemplo ram_content_bin.txt contém 256 linhas, cada uma com uma string binária de 32 bits:

1
2
…
255
256
00000000000000000000000000000001
00000000000000000000000000000010
…
00000000000000000000000011111111
00000000000000000000000100000000

Em VHDL-2008, o procedimento BREAD pode ser usado para ler valores binários diretamente:

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 a RAM com:

signal ram_bin : ram_type := init_ram_bin;

VHDL Legado: Leituras Binárias com READ

Para VHDL-2002 ou VHDL-93, o procedimento READ deve ser usado. Como ele retorna um vetor bit, o resultado é convertido para std_logic_vector via 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;

Retroportando Recursos Modernos do TEXTIO

Se você preferir não modificar o código legado, pode importar o pacote terceirizado std_logic_1164_additions. Esta biblioteca retroporta os procedimentos HREAD e BREAD para versões VHDL mais antigas, ao custo de uma dependência adicional.

Para exemplos mais detalhados e leitura adicional, veja os artigos acompanhantes desta série.

VHDL

  1. Protegendo o Alumínio Contra a Corrosão: Estratégias de Especialistas para Durabilidade Duradoura
  2. Elementos Metálicos vs. Não Metálicos: Principais Diferenças Explicadas
  3. Crie Seu Primeiro Template AWS CloudFormation — Um Guia Prático
  4. Computação em Nuvem vs. Computação Tradicional: Uma Comparação Prática
  5. Dominando Comentários em C: Escrevendo Notas Claras e Eficazes
  6. Lendo Arquivos em Java com BufferedReader – Guia Prático com Exemplos
  7. Calculando Médias em Python: Guia Prático
  8. Micrômetro Explicado: Como Ler e Usar Esta Ferramenta de Medição de Precisão
  9. Invocando Function Blocks PLC via Clientes OPC UA: Guia Prático
  10. Dominando a Leitura de Desenhos Técnicos CNC: Habilidades Essenciais para Usinadores Modernos