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

Usando Integrated Logic Analyzer (ILA) e Virtual Input/Output (VIO)


Este tutorial aborda o uso do Analisador de lógica integrado (ILA) e Entrada/Saída Virtual (VIO) núcleos para depurar e monitorar seu design VHDL no Xilinx Vivado IDE.

Em muitos casos, os designers precisam realizar a verificação no chip. Ou seja, obter acesso ao comportamento de um sinal interno em seu projeto de FPGA para fins de verificação.

Uma opção é trazer esses sinais para os pinos do FPGA e conectá-los aos LEDs para ver seu comportamento visualmente. Essa opção é fácil, rápida e funciona bem para casos simples, mas não é flexível, escalável ou realista.

Outra opção é ter um analisador lógico externo com recursos avançados que podem exibir e retratar o comportamento desses sinais, mas requer equipamentos externos e relativamente caros.

O Integrated Logic Analyzer (ILA) é uma alternativa que combina as vantagens das duas opções anteriores. É fácil, rápido, flexível e possui muitos recursos avançados que ajudam os projetistas a visualizar e verificar rapidamente o comportamento dos sinais escolhidos.

Visão geral


Este artigo contém várias capturas de tela da GUI do Vivado. Clique nas imagens para aumentá-las!

Use a barra lateral para navegar pelo contorno para este tutorial ou role para baixo e clique no botão de navegação pop-up no canto superior direito se estiver usando um dispositivo móvel.

ILA e VIO


O ILA e o VIO são IPs personalizáveis ​​gratuitos da Xilinx. O IP do ILA ajuda você a sondar facilmente os sinais internos dentro do seu FPGA e trazê-los para um ambiente de simulação para monitorá-los e verificar seu comportamento.

Ao contrário do ILA, o VIO IP permite que você gerencie virtualmente sinais internos dentro de seu FPGA para estimular ou controlar seu projeto, como dirigir o sinal RESET.

Requisitos

  1. Uma placa Xilinx FPGA
  2. Suíte Design Vivado
  3. Conhecimentos básicos de VHDL

Estou usando o kit de avaliação Kintex-7 FPGA KC705, mas os métodos mostrados neste tutorial devem funcionar em qualquer placa Xilinx FPGA moderna.

Faça o download do projeto de exemplo


Você pode baixar o projeto de exemplo e o código VHDL usando o formulário abaixo. Deve funcionar no Vivado versão 2020.2 ou mais recente.

Extraia o Zip e abra o ila_tutorial.xpr arquivo no Vivado para visualizar o design de exemplo ou leia o restante deste artigo para aprender a criá-lo do zero.

Crie um projeto com o Vivado


Comece abrindo o Vivado. Na tela de boas-vindas do Vivado, clique em Criar projeto botão.



Clique em Próximo continuar.



Altere o nome do projeto para ila_tutorial e clique em Próximo.

Observação: Não use espaços no nome do projeto. Em vez disso, use um sublinhado ou traço.



Escolha projeto RTL e desmarque Não especificar fontes neste momento e clique em Próximo continuar.



Adicione os arquivos de origem; counter.vhdl e counter_top.vhdl da pasta de desenho. Escolha VHDL para a língua-alvo. Marque Copiar fontes no projeto e clique em Próximo continuar.



Adicione o arquivo de restrição top.xdc da pasta de desenho. Verifique Copiar arquivos de restrições no projeto e clique em Próximo continuar.

Observação: este arquivo de restrição é específico para a placa KC705. Você precisa alterar o pin do clk e o pino led de acordo com sua placa. E também, o -período do seu relógio de bordo.



Procure sua placa e selecione-a na lista. Clique em Próximo continuar.



Esta é a tela final do assistente de Novo Projeto. Clique em Concluir para abrir seu projeto.


A explicação do exemplo de design


Usaremos um exemplo simples de cadeia de dois contadores para este tutorial.



O counter.vhdl O arquivo contém o código RTL para um contador trivial de 4 bits que conta de 0 a 15 quando ativado. Ele afirma a saída de 1 bit quando a contagem está entre 12 e 15. Para todos os outros valores, a saída permanece baixo '0' .

Aqui está a interface da entidade para o módulo do contador.
----------------------------------------------------------------------------
-- ENTITY DECLARATION.
----------------------------------------------------------------------------
  ENTITY counter IS
    PORT(clk     : IN  STD_LOGIC;  -- Main clock 
         reset   : IN  STD_LOGIC;  -- reset, active_high
         enable  : IN  STD_LOGIC;  -- enable the next counter
         trigger : OUT STD_LOGIC   -- trigger the next counter
        );
  END ENTITY;

O design do contador tem dois sinais internos:contagem e trigger_o .

contagem é usado para implementar a funcionalidade de contagem.

– e trigger_o é um sinal intermediário para conectar a porta de saída trigger .

Não se preocupe com ATTRIBUTE , será explicado mais adiante.
----------------------------------------------------------------------------
-- ARCHITECTURE DECLARATION.  
----------------------------------------------------------------------------
  ARCHITECTURE rtl OF counter IS

    -- INTERNAL SIGNALS DECLARATION --
    SIGNAL count     : UNSIGNED(3 DOWNTO 0) := (OTHERS => '0');
    SIGNAL trigger_o : STD_LOGIC := '0';
  
    -- ATTRIBUTE DECLARATION --  
    ATTRIBUTE MARK_DEBUG : STRING;
    ATTRIBUTE MARK_DEBUG OF count : SIGNAL IS "true";

Na listagem abaixo, vemos a implementação para o contador. O seq_proc processo é acionado na borda ascendente da porta de entrada clk e está no modo de reinicialização quando a porta de entrada reinicializar é alto '1'.

A contagem o sinal é incrementado quando a porta de entrada ativa é alto '1' e o trigger_o sinal é declarado alto quando o valor do sinal contagem está entre 12 e 15.
seq_proc: PROCESS (reset, clk)
BEGIN -- for seq_proc
  IF (reset = '1') THEN
    count     <= (OTHERS => '0');
    trigger_o <= '0';
  ELSIF rising_edge(clk) THEN
    IF (enable = '1') THEN
      count <= count + 1;
      IF (count > x"B" AND count <= x"F") THEN
        trigger_o <= '1';
      ELSE
        trigger_o <= '0';
      END IF;
    END IF;
  END IF;
END PROCESS;

O arquivo counter_top.vhdl contém dois instantes do contador conectados sequencialmente.

– O counter_1_inst está sempre ativado e cronometra o counter_2_inst . Ou seja, a porta de saída dispara de counter_1_inst está conectado à porta de entrada clk de counter_2_inst .

– O comportamento resultante é que counter_1_inst ativa counter_2_inst apenas 4 dos 16 ciclos de clock. Assim, counter_2_inst incrementará seu contador quatro vezes a cada 16 contagens.


Criando o núcleo VIO para RESET


Agora que você entendeu o exemplo de design, criaremos um VIO para controlar a porta de entrada redefinir . Isso nos dará a capacidade de manipular (alternar) a redefinição do Vivado IDE para que possamos controlar manualmente quando iniciar/parar os contadores.

Clique em Catálogo de IP , em seguida, pesquise VIO e clique duas vezes em VIO (Virtual Input/Output) .



Primeiro, alteramos o nome para vio_reset .

Em segundo lugar, precisamos apenas de uma porta de saída para a redefinição, então colocamos 0 na caixa de contagem de sonda de entrada, e colocamos 1 na caixa de contagem de sonda de saída .



Clique no PROBE_OUT guia porta. Como o reset é um sinal de 1 bit, colocamos 1 na caixa probe_width, e também colocamos 0x1 na caixa de valor inicial então começa com '1' alto. Em seguida, clique em OK e Gerar . A Vivado agora começará a sintetizar o VIO.



Depois que o Vivado termina de sintetizar o VIO, precisamos adicioná-lo ao nosso design declarando um componente para ele e instanciando-o no counter_top.vhdl arquivo como abaixo.

Primeiro, adicione uma declaração de componente para o vio_reset na seção de declaração do componente no counter_top.vhdl Arquivo.
  -- Declare vio_reset
  COMPONENT vio_reset
    PORT(
      clk        : IN STD_LOGIC;
      probe_out0 : OUT STD_LOGIC_VECTOR(0 DOWNTO 0)
    );
  END COMPONENT;

Agora, o VIO está completo e estamos prontos para sintetizar o design. Mas antes disso, precisamos alterar a configuração de síntese flatten_hierarchy para Nenhum .



Clique em Executar síntese e depois em OK .



Quando o Vivado terminar a síntese, clique em Abrir Design Sintetizado .



Altere o layout para depurar clicando em Layout e então Depurar .

Inserindo fluxo de sonda de depuração


Nosso design sintetizado agora contém o vio_reset instância, e é hora de especificar os sinais que queremos sondar. Existem três maneiras de fazer isso:
  1. Inserção de arquivo VHDL
  2. Inserção da Netlist
  3. Inserção do arquivo xdc/tcl

Usaremos os dois primeiros métodos e deixaremos o terceiro para um tutorial posterior.

Inserção de arquivo VHDL


Esse método é a maneira mais fácil e rápida de inserir uma sonda, especialmente quando é do tipo composto (array ou registro). Mas requer a adição de código aos arquivos de design, código VHDL que é redundante no produto real.

Podemos inserir uma sonda no arquivo de design VHDL por:
  1. Declarando um atributo especial chamado MARK_DEBUG
  2. Anexar o sinal que queremos sondar com este atributo
  3. E ative-o dando-lhe o valor “true” conforme abaixo:
    -- ATTRIBUTE DECLARATION --  
    ATTRIBUTE MARK_DEBUG : STRING;
    ATTRIBUTE MARK_DEBUG OF count : SIGNAL IS "true";

Observação: só precisamos declarar o atributo uma vez em cada arquivo de design VHDL, permitindo anexá-lo a vários sinais.

Podemos ver pelo design sintetizado que o sinal conta em ambos counter_1_inst e counter_2_inst estão listados em Redes de depuração não atribuídas e marcado com um ícone de bug na Netlist e o esquema .


Inserção da Netlist


Esse método de inserção também é fácil, mas exige que você primeiro sintetize o design e, em seguida, clique manualmente em cada sinal para marcá-lo para depuração. Pode ser exaustivo se o design for grande e você quiser monitorar muitos sinais.

Vamos investigar a porta de saída trigger em ambos os contadores usando a Netlist . Podemos fazer isso na janela Netlist ou o esquema localizando a rede de sinal e, em seguida, clique com o botão direito nele e escolha Marcar Depuração .

Na janela Netlist, encontre trigger em counter_1_inst → Redes → acionador . Em seguida, clique com o botão direito nele e escolha Marcar Depuração .



Na janela Schematic, encontre trigger saída de counter_2_inst . Em seguida, clique com o botão direito nele e escolha Marcar Depuração .



Podemos ver que eles agora estão listados em Redes de depuração não atribuídas .


Criando o núcleo de depuração do ILA


Agora é hora de criar o núcleo de depuração do ILA. Precisamos criar uma sonda para cada sinal que queremos analisar. A maneira mais fácil é aproveitar o assistente do Vivado Configurar Depuração .

Clique em Configurar depuração e clique em Próximo .



O Vivado listará todos os sinais de depuração e capturará o domínio do relógio para você automaticamente. Aqui vemos que nossos quatro sinais estão listados. Você pode remover os sinais nos quais não está interessado ou adicionar sinais extras, mas usaremos todos eles.

Observação: não precisamos usar todos os sinais que marcamos como Debug.

Clique em Próximo .



Agora configuramos o ILA escolhendo a profundidade FIFO e verificando o Controle de captura . Podemos deixar o FIFO em 1024, pois é profundidade suficiente para o nosso exemplo.

Clique em Próximo .



Agora vemos que o Vivado encontrou um relógio e criará um núcleo de depuração.

Clique em Concluir .



Agora podemos ver um núcleo de depuração de ILA com quatro probes adicionados à guia de depuração e a janela Netlist .



IMPORTANTE: É muito importante salvar a restrição neste estágio para que ela possa ser adicionada ao projeto. Caso contrário, corremos o risco de perder nosso núcleo de ILA.

Clique no botão Salvar ícone ou pressione Ctrl+S.



Nomeie o arquivo ila_core e clique em OK .



O ila_core.xdc será adicionado à restrição e inclui o código e as configurações do ILA.

Vamos dar uma olhada no conteúdo do arquivo. Você pode abrir o arquivo indo para a janela de origem → expanda a pasta de restrição → expanda constr_1 .

Primeiro, vemos que o arquivo adiciona um atributo debug aos sinais que marcamos debug usando a inserção Netlist.



A seguir, vemos a criação e configuração de um núcleo ILA.



Em seguida, vemos a criação, configuração e conexão para cada probe.



Em seguida, vemos a criação de um hub de depuração (dbg_hub ).



O hub de depuração é responsável pela comunicação entre o Vivado IDE e os núcleos de depuração (ILA e VIO). Vemos que ele define uma frequência de clock (o padrão é 300 MHz). Você precisa alterar esse relógio para corresponder à frequência do seu relógio e salvar o arquivo.

Observação: o relógio conectado ao ILA e ao Debug_hub deve ser um relógio de execução livre.

Agora, o ILA está concluído e salvo. Precisamos executar novamente a síntese para que o ILA possa ser adicionado ao projeto sintetizado.

Clique em Executar síntese e depois em OK .

Quando o Vivado terminar de executar a síntese, clique em Abrir Design Sintetizado e depois em Esquema .

Podemos ver agora que o Vivado adicionou o ILA e o Debug_Hub ao nosso design e conectou os sinais de depuração às sondas do ILA.



Agora estamos prontos para implementar nosso design e gerar o fluxo de bits para que possamos testar nosso design.

Clique em Executar implementação e depois em OK .



Depois que o Vivado terminar de executar a implementação, clique em Gerar Bitstream e depois em OK .



Depois que o Vivado terminar de gerar o bitstream, clique em Abrir Gerenciador de Hardware e depois em Abrir destino, e finalmente em Conexão automática .



Em seguida, precisamos programar o FPGA com o arquivo de bits (*.bit) e o arquivo de teste de depuração (*.ltx). O Vivado os encontra automaticamente para você.

Clique em Dispositivo de programa e depois em Programa .


Configurando os acionadores de ILA


Depois de programar o dispositivo, podemos ver que o layout da GUI do Vivado mudou e um novo hw_ila_1 painel foi aberto, contendo várias janelas.

Vamos minimizar algumas janelas que não precisamos para que possamos trabalhar confortavelmente.



Nas opções do painel, verifique hw_vio_1 e desmarque Configurar captura .

Além disso, feche o hw_vios guia porque quando verificamos hw_vio_1 , ele foi adicionado à configuração do acionador janela.



Agora, precisamos adicionar o redefinir botão para o VIO para que possamos controlar o reiniciar .

Clique em hw_vio_1 e, em seguida, adicione redefinir como mostrado na imagem abaixo.



Podemos ver que hw_vio_1 agora contém a redefinição sonda.

Altere o valor da redefinição em vio_reset para 1 se não for 1.

Agora, adicionaremos os gatilhos que usaremos. Uma mudança de valor em um sinal de disparo fará com que o ILA comece a gravar os sinais sondados.

Digamos que queremos disparar (começar a gravar) na borda de subida da porta de saída trigger de counter_1_inst . Para fazer isso, siga estas etapas:
  1. Vá para a Configuração do gatilho – hw_ila_1 janela
  2. Clique no + ícone para adicionar um novo acionador e escolha counter_1_inst/trigger e clique em OK.


  1. Podemos ver que o gatilho foi adicionado e agora precisamos configurar a condição. Clique na caixa de valor e escolha R(transição de 0 para 1) . Clique na caixa do operador e escolha ==(igual)

Também mudaremos a posição do trigger para 32, o que significa que ele gravará 32 samples antes do evento de trigger além do que vem depois.

Agora, o gatilho está configurado e pronto para ser armado.



Agora, vamos para a janela de forma de onda para adicionar os sinais que queremos ver. Primeiro, vamos maximizar a janela interna para obter uma visão melhor.

Em segundo lugar, precisamos adicionar alguns sinais ausentes à sonda. O Vivado geralmente adiciona todos os sinais atribuídos automaticamente, mas neste caso não.



Agora, alteramos a base da contagem sinal para Unsigned, pois é mais fácil de seguir.

Clique com o botão direito do mouse na contagem nome do sinal e, em seguida, escolha raiz e, em seguida, Não assinado .


Executando o ILA e o VIO


Agora, terminamos de configurar e personalizar o ILA e estamos prontos para executá-lo.

O ILA tem dois modos de execução:Imediato e acionar .

Modo imediato


O modo imediato aciona o ILA imediatamente e começa a gravar as amostras diretamente até que o FIFO esteja cheio.

Clique no botão Executar acionador imediatamente botão.

Agora podemos ver as amostras gravadas na janela de forma de onda. Vemos que ambos contam os sinais são 0, e ambos acionam os sinais são baixo '0' porque a reinicialização está ativo.


Modo de disparo


O modo Trigger requer que configuremos uma condição para pelo menos um trigger e o armemos. O ILA continuará esperando que a condição do trigger armado se torne verdadeira, e então começará a gravar as amostras diretamente até que o FIFO esteja cheio.

Já adicionamos o gatilho e o configuramos para R(0 to 1 transition) .

Executando ILA com um gatilho


Alterar redefinir voltar para 1 de vio_reset .



Clique na janela Status hw_ila_1 . Vemos que o status principal é Inativo pois não há gatilhos armados. Clique no acionador Executar botão, e isso irá armar o gatilho.

Vemos agora que o status principal mudou para aguardando acionamento . Como a redefinição é alto, não há atividade em nosso sinal de gatilho (porta trigger de counter_1_inst ), e o ILA está esperando.



Agora, vamos alterar o redefinir para 0 para que os contadores comecem a funcionar.



Vemos agora que o ILA foi acionado e gravou as amostras, e o status do núcleo voltou a ser Inativo .

Vemos a linha vertical vermelha (marcador) na borda ascendente do nosso sinal de disparo (porta trigger de counter_1_inst ), e está na posição 32 . Também podemos verificar se o sinal conta está se comportando corretamente e o sinal counter_1_inst/trigger é alto para quatro ciclos de clock entre 12 e 15 (a saída é atrasada em um ciclo de clock).



Se diminuirmos um pouco o zoom, também podemos verificar o comportamento de count e acionar sinais para counter_2_inst .


Executando ILA com vários acionadores


Podemos usar uma combinação de gatilhos para condições complexas ou avançadas. Para capturar vários quadros de tempo desconexos na mesma forma de onda, podemos usar vários gatilhos que disparam repetidamente.

Por exemplo, digamos que queremos acionar quando a contagem sinal de counter_1_inst é igual a 9 (contagem ==9) e quando a contagem sinal de counter_2_inst é maior que 2 (contagem> 2). Para fazer isso e dividir o FIFO em quatro janelas de tempo, siga estas etapas:
  1. Alterar redefinir voltar para 1 de vio_reset
  2. Remover a sonda de gatilho anterior:


  1. Adicione ambos contagem sinais como gatilhos:


  1. Configurar o sinal contagem para counter_1_inst para (contagem ==9):


  1. Configurar o sinal contagem para counter_2_inst para (contar> 2):




  1. Configure o número de janelas para 4 e profundidade FIFO para 256, e posição para 32 .


  1. Clique no acionador Executar botão, e isso irá armar o gatilho. Observe que na janela Status hw_ila_1 , o status de captura agora é janela 1 de 4 porque temos quatro janelas.

Alterar redefinir voltar para 0 de vio_reset .



Maximize a janela da forma de onda. Vemos agora que temos quatro janelas e um gatilho associado a cada janela. Observe que essas janelas são independentes e não contínuas.

O ILA aguarda a ocorrência do evento de disparo e, quando isso ocorre, o ILA usa a primeira janela para registrar 256 amostras. Em seguida, ele aguarda imediatamente pelo próximo acionador até que todas as janelas estejam cheias.


Executando ILA com modo de reativação automática


O ILA tem um bom recurso chamado Reacionamento automático que irá armar automaticamente o gatilho depois que ele for acionado. It is useful when monitoring events that occur seldom and you want to run a test overnight. Or you can use it when the trigger happens so often and fast that you cannot arm the trigger manually to capture the samples repeatedly.

Let us assume that the output port trigger of counter_2_inst gets asserted every 3 hours, and you want to record the data each time it happens. To use the Auto trigger, follow these steps:
  1. Change reset back to 1 from vio_reset
  2. Remove the previous trigger probe
  3. Add trigger_2_OBUF signal as trigger:


  1. Configure the trigger to the condition to equal (==) and falling edge F(1-to-0 transition)
  2. Configure the number of windows to 1 and FIFO depth to 1024, and position to 32:


  1. Click on Auto re-trigger button:


  1. Finally, change reset back to 0 from vio_reset:



We can see now that the waveform window is getting refreshed and updated as the trigger happen. It is fast, but the behavior is noticeable.

Click on Stop trigger and toggle Auto re-trigger .

Running ILA with Capture mode


Another feature of ILA is the Capture mode . In some cases, you are not interested in recording all the data but rather capture a specific sample. Capture mode helps you filter out data and record only the samples you are interested in.

Let’s say we are only interested in sampling when the output port trigger of counter_1_inst is ‘1’ AND the output port trigger of counter_2_inst is ‘0’.

To use Capture mode to achieve this, follow these steps:
  1. Change reset back to 1 from vio_reset
  2. Remove the previous trigger probe
  3. From the dashboard, Uncheck Trigger Setup and check Capture Setup . Notice that a Capture Setup window will appear. From the Settings – hw_ila_1 window, Change Capture mode to BASIC , the window to 1, the FIFO depth to 1024, and position to 1:


  1. Add trigger_2_OBUF , and counter_1_inst/trigger from the Capture Setup window:


  1. Configure counter_1_inst/trigger to the condition equal (==) and 1 (logical one) :


  1. Configure trigger_2_OBUF to the condition equal (==) and 0 (logical zero) :


  1. Change the Capture Condition to Global AND :


  1. Click on the Run trigger button and then change reset to 0 from vio_reset :



As we can see from the image below, the waveform has only recorded data when counter_1_inst’s count signal is 13, 14, 15, or 0. Any other counts are filtered out because counter_1_inst/trigger is high on these counts only.


Conclusion


In this tutorial, we learned about ILA and VIO and different use-cases for them. ILA and VIO are excellent options for on-chip debugging. They are free, easy to use, flexible, scalable, and simple yet offer advanced features. The use of multiple triggers and Capture mode helps you achieve a complex debugging scheme.

VHDL

  1. Tutorial - Escrevendo Código Combinacional e Sequencial
  2. Para a nuvem infinita e além
  3. Entrada e saída básica em C#
  4. Entrada/saída básica de C++
  5. C Entrada Saída (E/S)
  6. Entrada, Saída e Importação do Python
  7. Entrada e Saída Java Basic
  8. D Trava
  9. C - Entrada e Saída
  10. RightHand Robotics e Element Logic lançam solução robótica integrada de seleção de peças