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

Como inicializar a RAM do arquivo usando TEXTIO


Uma maneira conveniente de preencher a RAM do bloco com valores iniciais é ler literais binários ou hexadecimais de um arquivo ASCII. Essa também é uma boa maneira de criar uma ROM (memória somente leitura) em VHDL. Afinal, RAM e ROM são a mesma coisa em FPGAs, ROM é uma RAM que você só lê.

Os exemplos ao longo deste artigo assumirão que as seguintes constantes e o tipo de RAM foram declarados no início da 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);

Esta postagem de blog é parte de uma série sobre o uso da biblioteca TEXTIO em VHDL. Leia os outros artigos aqui:

Arquivo de estímulo lido no testbench usando TEXTIO

Imagem de bitmap de arquivo BMP lida usando TEXTIO

READLINE, LINE, HREAD, OREAD e PÃO


Os subprogramas e tipos necessários para ler e escrever arquivos externos em VHDL estão localizados no arquivo TEXTIO pacote. Este pacote faz parte do std biblioteca. A biblioteca padrão é sempre carregada; portanto, não precisamos importá-lo explicitamente com o library palavra-chave.

Podemos simplesmente seguir em frente e usar o TEXTIO pacote no cabeçalho do nosso arquivo VHDL assim:
use std.textio.all;

Armazenaremos os dados da RAM em um arquivo ASCII onde uma linha de texto corresponde a um slot de memória. Para ler uma linha de texto usamos o READLINE procedimento do TEXTIO pacote. O procedimento recebe dois argumentos, o nome do arquivo como uma entrada constante e a linha de texto analisada como um inout variável. A declaração de protótipo do READLINE procedimento e o LINE tipo retirado da especificação padrão VHDL é mostrado abaixo.
procedure READLINE (file F: TEXT; L: inout LINE);

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

Embora a classe do LINE parâmetro não é especificado explicitamente na declaração de protótipo de READLINE , é uma variável porque é a classe padrão para inout parâmetros. O LINE type é simplesmente um tipo de acesso a uma string, um ponteiro para um objeto string alocado dinamicamente.

VHDL-2008 define o OREAD , HREAD e BREAD procedimentos para extrair valores octais, hexadecimais e binários de um LINE objeto. Os métodos para leitura de valores octais e hexadecimais são bastante semelhantes, os valores octais são apenas um subconjunto dos hexadecimais. Para simplificar, vamos pular leituras octais neste artigo e focar em como ler valores hexadecimais e binários de um arquivo de texto.

O código abaixo mostra as definições dos procedimentos que são relevantes para nós, estão disponíveis apenas em VHDL-2008 e revisões mais recentes. O OREAD e HREAD procedimentos vêm em dois tipos sobrecarregados para cada um dos tipos de saída suportados. O opcional GOOD A saída pode ser usada para detectar erros de leitura, embora a maioria das ferramentas produza um erro ou aviso, independentemente de essa saída ser usada ou não.
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];
Clique aqui para ver as definições do procedimento de entrada da 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];
Clique aqui para ver as definições do procedimento de entrada da 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];

Ler valores hexadecimais do arquivo


Hexadecimal é um formato útil para descrever o conteúdo da RAM porque dois caracteres hexadecimais se traduzem diretamente em um byte, oito bits. Cada caractere descreve um nibble (meio byte) e cada linha no arquivo de texto descreve o conteúdo de um slot de RAM. A lista abaixo mostra um trecho do ram_content_hex.txt Arquivo. Ele foi preenchido com valores de exemplo que variam de 1 a 256 decimal, escritos como hexadecimal.
12–255256 00000001 00000002 ... 000000FF 00000100

Para carregar os dados do arquivo de texto, usamos uma função impura declarada abaixo do ram_type , mas acima da declaração do sinal RAM. O código abaixo mostra o init_ram_hex função que lê os dados do arquivo de texto e os retorna como um 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;

O readline O procedimento dentro do loop for lê uma linha de texto por vez e a atribui ao text_line variável. Este objeto é do tipo line , que é um tipo de acesso a um objeto string, um ponteiro para uma string alocada dinamicamente. Na próxima linha, o hread procedimento lê a string do line objeto e o converte em um std_ulogic_vector . Este tipo pode ser atribuído diretamente ao std_logic_vector que cada célula de RAM é construída.

Por fim, declaramos o sinal de RAM enquanto chamamos nosso init_ram_hex função para fornecer os valores iniciais para ela:
signal ram_hex : ram_type := init_ram_hex;




HREAD em VHDL-2002 e VHDL-93


Infelizmente, o HREAD procedimento está disponível apenas em VHDL-2008. Em todas as versões anteriores do VHDL, o padrão READ procedimento deve ser usado em seu lugar. O READ O procedimento está sobrecarregado com muitos tipos de saída diferentes, mas não há uma opção para ler valores hexadecimais.

Vamos escrever um algoritmo personalizado para converter caracteres hexadecimais ASCII em VHDL std_logic_vector . Primeiro, precisamos ler os caracteres um por um do text_line objeto, então decodificamos seus valores e os atribuímos à fatia correta do vetor de slot RAM. O código abaixo mostra uma implementação equivalente do init_ram_hex função que também funciona em versões legadas 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;

O algoritmo simplesmente passa por todas as linhas enquanto observa todos os caracteres, convertendo-os no valor binário correto. Se um caractere que não está no intervalo 0x0-0xF for encontrado, uma falha de declaração será gerada no when others ramo. O offset A variável controla a posição da fatia dentro de cada célula de memória à qual atribuir o valor decodificado.

Você pode estar se perguntando por que não criamos um hread personalizado procedimento em vez de codificá-lo dentro do init_ram_hex função? Então não precisaríamos alterar o init_ram_hex funcionar, simplesmente usaríamos nosso hread personalizado procedimento no lugar do padrão ausente.

Isso funcionaria na maioria dos simuladores e alguns sintetizadores como o Lattice iCEcube2, mas não será sintetizado no Xilinx Vivado. A mensagem de erro abaixo indica claramente qual é o problema.

Em Vivado:
[Synth 8-27] O argumento de procedimento do tipo 'linha' não é suportado [init_ram_tb.vhd:15]
Clique aqui para ver a implementação alternativa do procedimento 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;

Ler valores binários do arquivo


Você pode querer armazenar os valores de RAM como literais binários em vez de caracteres hexadecimais se a largura da RAM não for um múltiplo de 8. A lista abaixo mostra o mesmo conteúdo de antes, mas representado em formato binário usando apenas os caracteres 0 e 1 .
12–255256 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000

O algoritmo mostrado abaixo é para ler valores binários do arquivo. É semelhante à leitura de hexadecimais, mas no VHDL-2008 você deve usar o BREAD chamada de procedimento em vez de HREAD . Ele traduzirá um caractere ASCII para um único std_ulogic value, que é convertido implicitamente em 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 o sinal de RAM chamando nossa nova função impura conforme mostrado no código abaixo.
signal ram_bin : ram_type := init_ram_bin;




PÃO em VHDL-2002 e VHDL-93


Podemos facilmente tornar nosso código portátil para versões legadas de VHDL chamando READ em vez de BREAD . O trecho do padrão VHDL abaixo mostra o protótipo de READ que estamos interessados ​​em usar.
procedure READ (L: inout LINE; VALUE: out BIT);

O READ procedimento que gera um std_ulogic não existia antes do VHDL-2008, portanto, temos que usar o bit versão do TEXTIO biblioteca. Felizmente, esse tipo pode ser facilmente convertido para std_logic usando o padrão To_StdLogicVector função.

A implementação de init_ram_bin mostrado abaixo funciona em VHDL-2002 e também em 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 da biblioteca IEEE std_logic_1164


Uma alternativa para alterar o código das versões herdadas do VHDL é usar o pacote de terceiros std_logic_1164_additions. Ao baixar e adicionar esta biblioteca ao seu projeto, você poderá usar os novos procedimentos também em VHDL-2002 e VHDL-93. Claro, então você estará importando muito mais e seu código sempre dependerá desse pacote.

VHDL

  1. Como proteger o alumínio da corrosão
  2. Como os elementos metálicos diferem dos elementos não metálicos
  3. Como criar um modelo CloudFormation usando AWS
  4. Como a computação em nuvem difere da computação tradicional?
  5. Como escrever comentários em programação C
  6. Java BufferedReader:Como Ler Arquivo em Java com Exemplo
  7. Python Average:Como encontrar a AVERAGE de uma lista em Python
  8. O que é Micrômetro? | Como você lê um micrômetro
  9. Como chamar um Bloco Funcional de um Cliente OPC UA usando um Modelo de Informação
  10. Como ler plantas CNC