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

Arquivo de estímulo lido no testbench usando TEXTIO


A leitura de valores de sinal do arquivo é uma forma alternativa de gerar estímulos para o dispositivo em teste (DUT). A sequência e o tempo do testbench são codificados em um arquivo de estímulo que é lido pelo testbench VHDL, linha por linha. Isso permite que você altere facilmente o padrão da forma de onda que deseja alimentar para o objeto de teste.

Às vezes, você tem um padrão de teste muito específico ou uma sequência de eventos que deseja realizar com seu DUT. Você pode conseguir isso especificando em um arquivo ASCII os valores de sinal que cada sinal deve ter, bem como o tempo de simulação relativo em que eles devem mudar. O papel do testbench VHDL em tal estratégia é ler os dados do arquivo de estímulo e aplicar os valores às entradas do DUT no momento correto.

Este artigo é o segundo de uma série sobre acesso a arquivos em VHDL. Analisamos como ler valores hexadecimais, octais e binários do arquivo na postagem anterior do blog, volte e leia-o se quiser saber mais sobre a leitura do arquivo usando o TEXTIO biblioteca em VHDL.

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

Como inicializar a RAM do arquivo usando TEXTIO

Imagem de bitmap de arquivo BMP lida usando TEXTIO

O caso de teste


O exemplo de DUT será um multiplexador de 4 entradas (MUX) retirado de um dos meus posts anteriores. É um MUX assíncrono padrão de 4 para 1 com largura de dados de um byte. Como funciona não é importante para este artigo porque não vamos fazer nenhuma verificação das saídas, é apenas para fins de demonstração.

A entidade do MUX é mostrada abaixo.
entity mux_4 is
  port(
    -- Data in
    din_0 : in unsigned(7 downto 0);
    din_1 : in unsigned(7 downto 0);
    din_2 : in unsigned(7 downto 0);
    din_3 : in unsigned(7 downto 0);

    -- Selector
    sel  : in unsigned(1 downto 0);

    -- Data out
    dout : out unsigned(7 downto 0));
end entity;

Após importar os pacotes necessários no topo do arquivo VHDL, passamos a declarar os sinais de entrada que vamos conectar ao DUT. Como você pode ver na listagem abaixo, eles são esquemas da declaração da entidade MUX.
signal din_0 : unsigned(7 downto 0);
signal din_1 : unsigned(7 downto 0);
signal din_2 : unsigned(7 downto 0);
signal din_3 : unsigned(7 downto 0);
signal sel  : unsigned(1 downto 0);
signal dout : unsigned(7 downto 0);

Usamos o método de instanciação de entidade para criar uma instância do MUX com o rótulo “DUT” no topo da região de arquitetura do nosso testbench. Os sinais de entidade são conectados aos sinais do testbench local com os mesmos nomes, conforme mostrado no código abaixo.
DUT: entity work.mux_4(rtl)
port map (
    din_0 => din_0,
    din_1 => din_1,
    din_2 => din_2,
    din_3 => din_3,
    sel  => sel,
    dout => dout
);

O arquivo de estímulo


Um arquivo de estímulo pode ter muitos formatos diferentes, o apresentado aqui é apenas um exemplo que eu criei do topo da minha cabeça enquanto escrevia este artigo. No entanto, quando você entender como eu o criei, você poderá modificá-lo para atender às suas necessidades.

A lista abaixo mostra o arquivo de estímulo completo usado neste exemplo.
# Column description:
# wait_time | sel | din_0 | din_1 | din_2 | din3 # Optional console printout

0 ns 0 AA BB CC DD # Setting initial values
10 ns 1 AA BB CC DD # Testing by changing the selector signal
10 ns 2 AA BB CC DD
10 ns 3 AA BB CC DD
10 ns 3 A1 B1 C1 D1 # Testing by changing all data inputs
10 ns 3 A2 B2 C2 D2
10 ns 3 A3 B3 C3 D3
10 ns 3 00 00 00 D2 # Changing all unselected inputs
10 ns 3 01 02 03 D2
10 ns 3 11 22 33 D2
1 ns 0 CC DD EE FF # Changing all inputs fast
1 ns 1 DD EE FF CC
1 ns 2 EE FF CC DD
1 ns 3 FF CC DD EE
10 ns 0 00 00 00 00 # Simulation stop

Vamos ignorar os comentários por enquanto, esses são os marcados em verde, sempre começando com o caractere ‘#’. Cada linha representa um passo de tempo na simulação. Existem seis colunas de comandos em cada linha, na verdade sete colunas de texto, mas as duas primeiras colunas pertencem ao mesmo item de dados.

As colunas de texto um e dois descrevem um valor de tempo, por quanto tempo o simulador deve pausar nessa linha antes de aplicar os valores listados nas outras colunas. Assim, o tempo absoluto de simulação quando o comando é executado é relativo ao evento descrito pela linha anterior. Estamos usando apenas 0, 1 ou 10 nanossegundos, mas pode ser qualquer coisa, 1.000 nanossegundos ou 1.000 horas (1000 hr ) para esse assunto.

As cinco colunas de texto restantes descrevem os valores de sinal a serem aplicados às entradas do DUT. Eles são dados como literais hexadecimais e a ordenação do sinal é sel , din_0 , din_1 , din_2 , e finalmente din_3 .

Agora, vamos aos comentários. Existem dois tipos de comentários; comentários de linha única e comentários finais. Eles devem ser tratados de forma diferente pelo nosso testbench. Comentários de linha única, como os que estão na parte superior do arquivo, serão ignorados. Os comentários finais, por outro lado, devem ser impressos no console do simulador. Podemos usá-los para nos dar pistas sobre o que está acontecendo enquanto a simulação está em execução.

Ler o arquivo de estímulo em VHDL


VHDL não é a melhor linguagem para processamento de texto, mas faz o trabalho. O suporte para strings dinâmicas é limitado e faltam rotinas de conveniência, por exemplo, para remover ou pular espaços em branco. Para facilitar para nós mesmos, vamos supor que o arquivo de estímulo está bem escrito. Vamos tomar muito cuidado para garantir que haja sempre um espaço entre os elementos do texto e um único espaço entre o caractere '#' e o texto do comentário. Além disso, nenhum espaço extra à esquerda ou à direita em qualquer lugar no arquivo de estímulo.




PROC_SEQUENCER : process
  file text_file : text open read_mode is "stimulus.txt";
  variable text_line : line;
  variable ok : boolean;
  variable char : character;
  variable wait_time : time;
  variable selector : sel'subtype;
  variable data : dout'subtype;
begin

A região declarativa do PROC_SEQUENCER procedimento é mostrado acima. Primeiro, declaramos o file especial objeto, um tipo de manipulador de arquivo VHDL. Em seguida, declaramos uma variável do tipo line . Este é simplesmente um tipo de acesso a uma string, um ponteiro para um objeto string alocado dinamicamente. O ok variável do tipo booleano é para verificar se as operações de leitura foram bem-sucedidas. Finalmente, declaramos as quatro variáveis ​​char , wait_time , selector e data . Essas variáveis ​​são para extrair os dados de cada coluna de cada linha de texto.
  while not endfile(text_file) loop

    readline(text_file, text_line);

    -- Skip empty lines and single-line comments
    if text_line.all'length = 0 or text_line.all(1) = '#' then
      next;
    end if;

No corpo do processo, vamos direto para um loop while que irá percorrer cada linha de texto no arquivo de estímulo. O readline procedimento atribui uma nova linha de texto ao text_line variável em cada iteração deste loop. Depois de ler a linha, verificamos se a linha está vazia ou se o primeiro caractere é '#', nesse caso vamos para a próxima linha imediatamente usando o next palavra-chave para pular uma iteração do loop. Observe que estamos usando text_line.all para obter acesso à string dentro do line objeto.
    read(text_line, wait_time, ok);
    assert ok
      report "Read 'wait_time' failed for line: " & text_line.all
      severity failure;

    hread(text_line, selector, ok);
    assert ok
      report "Read 'sel' failed for line: " & text_line.all
      severity failure;
    sel <= selector;

    hread(text_line, data, ok);
    assert ok
      report "Read 'din_0' failed for line: " & text_line.all
      severity failure;
    din_0 <= data;

    hread(text_line, data, ok);
    assert ok
      report "Read 'din_1' failed for line: " & text_line.all
      severity failure;
    din_1 <= data;

    hread(text_line, data, ok);
    assert ok
      report "Read 'din_2' failed for line: " & text_line.all
      severity failure;
    din_2 <= data;

    hread(text_line, data, ok);
    assert ok
      report "Read 'din_3' failed for line: " & text_line.all
      severity failure;
    din_3 <= data;

Em seguida, segue um número de leituras do text_line objeto. O read e hread chamadas de procedimento pulam os espaços iniciais para que não tenhamos que fazer nenhuma leitura fictícia para mover a posição inicial de leitura interna dentro do text_line objeto. Poderíamos ter omitido as declarações assert, mas quero que a simulação pare se uma leitura falhar. Pelo menos no ModelSim, a simulação não para automaticamente quando isso acontece. Atribuímos cada variável lida com sucesso ao sinal DUT relevante, exceto para o wait_time variável que não tem uma entrada DUT correspondente.
    wait for wait_time;

Depois de atribuir os valores do sinal, aguardamos o tempo especificado. Acertar a instrução de espera faz com que os valores de sinal programados se tornem efetivos com o mesmo ciclo delta.
    -- Print trailing comment to console, if any
    read(text_line, char, ok); -- Skip expected newline
    read(text_line, char, ok);
    if char = '#' then
      read(text_line, char, ok); -- Skip expected newline
      report text_line.all;
    end if;

  end loop;

  finish;

end process;

Por fim, quando o programa desperta da instrução de espera, procuramos um comentário final adicional no text_line objeto. Qualquer comentário é impresso no console usando a instrução report após removermos o caractere '#' e o seguinte espaço em branco usando leituras fictícias.

Depois que a última linha de texto do arquivo de estímulo for processada, o loop while termina. Há um VHDL-2008 finish palavra-chave no final do processo que é responsável por parar o testbench.

A saída


O testbench de exemplo imprime o texto mostrado abaixo no console do simulador quando executado no ModelSim. Podemos ver que os comentários são os do arquivo de estímulo. Os valores de tempo impressos são os tempos de simulação acumulados com base nos atrasos de nanossegundos que foram especificados no arquivo de estímulo.

# ** Note: Setting initial values
#    Time: 0 ns  Iteration: 1  Instance: /file_stim_tb
# ** Note: Testing by changing the selector signal
#    Time: 10 ns  Iteration: 0  Instance: /file_stim_tb
# ** Note: Testing by changing all data inputs
#    Time: 40 ns  Iteration: 0  Instance: /file_stim_tb
# ** Note: Changing all unselected inputs
#    Time: 70 ns  Iteration: 0  Instance: /file_stim_tb
# ** Note: Changing all inputs fast
#    Time: 91 ns  Iteration: 0  Instance: /file_stim_tbf
# ** Note: Simulation stop
#    Time: 104 ns  Iteration: 0  Instance: /file_stim_tb
# Break in Process PROC_SEQUENCER at file_stim_tb.vhd line 98

A forma de onda para a simulação é mostrada abaixo. Ele mostra uma representação visual de como os valores do nosso arquivo de estímulo são aplicados aos sinais nos tempos de simulação especificados.


Considerações finais


Ler os estímulos do banco de teste do arquivo pode ser vantajoso se você tiver um padrão de teste muito específico que precisa aplicar. Todo o testbench não precisa ser controlado pelo arquivo de texto, este exemplo serve apenas para mostrar as possibilidades de acesso a arquivos em VHDL.

No entanto, uma coisa que não discutimos é a verificação das saídas do DUT. Nosso testbench de exemplo não verifica as saídas. Você pode verificar o comportamento do DUT exatamente como faria em um testbench VHDL completo, por exemplo, usando um modelo comportamental para comparar. Ou você pode modificar o código e o arquivo de estímulo para incluir os valores de saída esperados. Seja qual for a estratégia escolhida, certifique-se de criar um banco de teste de autoverificação e não confie na verificação manual da forma de onda.





VHDL

  1. C# usando
  2. C Manipulação de Arquivos
  3. Classe de arquivo Java
  4. Como inicializar a RAM do arquivo usando TEXTIO
  5. Como criar um testbench de autoverificação
  6. Java BufferedReader:Como Ler Arquivo em Java com Exemplo
  7. Python JSON:codificar (despejar), decodificar (carregar) e ler arquivo JSON
  8. Operações de E/S de arquivo Verilog
  9. C - Arquivos de cabeçalho
  10. O que é um arquivo triangular?