DI2022802 2024 2 AULA12: mudanças entre as edições

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Douglas (discussão | contribs)
Douglas (discussão | contribs)
 
(8 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 18: Linha 18:
;INTRODUÇÃO: VHDL ou (''Very High Speed Integrated Circuits'') é uma linguagem utilizada para descrever hardware. Ela foi concebida pelo departamento de defesa dos Estados Unidos (DARPA) na década de 80 para a documentação dos circuitos integrados vendidos às forças áreas americanas. Em 1987 ela foi padronizada pela IEEE como uma linguagem de descrição de hardware, o fato de ser padronizada e de domínio público ampliou e muito a sua utilização. A sua sintaxe é altamente tipada e lembra ADA e Pascal mas as semelhanças param por ai. A descrição de um circuito difere completamente de um software e muitas pessoas quando saem de uma linguagem de software e vem para linguagens de descrição de hardware encontram muitas dificuldades. Sempre mantenha em mente que você está descrevendo hardware e não escrevendo um algoritmo que um processador vai executar sequencialmente. VHDL é utilizando tanto para concepção de circuitos ASIC (por exemplo um i7 da Intel), quanto para desenvolvimento em FPGA. O resultado de uma “compilação” de um VHDL não é um executável mas sim uma ''netlist'' com todos os fios, conexões, componentes combinacionais e sequências de um hardware. [1]
;INTRODUÇÃO: VHDL ou (''Very High Speed Integrated Circuits'') é uma linguagem utilizada para descrever hardware. Ela foi concebida pelo departamento de defesa dos Estados Unidos (DARPA) na década de 80 para a documentação dos circuitos integrados vendidos às forças áreas americanas. Em 1987 ela foi padronizada pela IEEE como uma linguagem de descrição de hardware, o fato de ser padronizada e de domínio público ampliou e muito a sua utilização. A sua sintaxe é altamente tipada e lembra ADA e Pascal mas as semelhanças param por ai. A descrição de um circuito difere completamente de um software e muitas pessoas quando saem de uma linguagem de software e vem para linguagens de descrição de hardware encontram muitas dificuldades. Sempre mantenha em mente que você está descrevendo hardware e não escrevendo um algoritmo que um processador vai executar sequencialmente. VHDL é utilizando tanto para concepção de circuitos ASIC (por exemplo um i7 da Intel), quanto para desenvolvimento em FPGA. O resultado de uma “compilação” de um VHDL não é um executável mas sim uma ''netlist'' com todos os fios, conexões, componentes combinacionais e sequências de um hardware. [1]


<blockquote style="background:#E6E6FA; border: 2px solid #8A2BE2; margin-left: 100px; margin-right: 100px; padding: 2em;">
<blockquote style="background:#F0FFFF; border: 2px solid #2E8B57; margin-left: 150px; margin-right: 150px; padding: 2em;">
;NOTA: Este texto foi adaptado da Apostila Básica de VHDL do Prof. Dr. Renato Giacomini e da Apostila de Dispositivos Lógicos Programáveis dos professores: Caio Augusto de Oliveira, Jéssica Azevedo de Aguiar e Mateus Galvão Said Fontanini  (UNESP).
;NOTA: Este texto foi adaptado da Apostila Básica de VHDL do Prof. Dr. Renato Giacomini e da Apostila de Dispositivos Lógicos Programáveis dos professores: Caio Augusto de Oliveira, Jéssica Azevedo de Aguiar e Mateus Galvão Said Fontanini  (UNESP).
</blockquote>
</blockquote>
Linha 197: Linha 197:
-- comparador de 4 bits
-- comparador de 4 bits
entity comp4 is
entity comp4 is
     port ( a, b: in bit_vector (3 downto Æ);
     port ( a, b: in bit_vector (3 downto 0);
           equals: out bit);
           equals: out bit);
end comp4;
end comp4;
Linha 216: Linha 216:


Uma arquitetura pode ter mais de um processo e eles serão executados concorrentemente entre si.
Uma arquitetura pode ter mais de um processo e eles serão executados concorrentemente entre si.


===Descrição por fluxo de dados===
===Descrição por fluxo de dados===
Linha 587: Linha 586:


De fato, a maioria dos projetos não necessita do <code style="color: red">std_logic</code> e acabam por utilizá-lo apenas com os valores <code style="color: red">0</code> ou <code style="color: red">1</code>, como substituição ao tipo <code style="color: red">bit</code>. Como regra geral, utilize o tipo de dado certo para o trabalho que está fazendo e, enquanto você estiver aprendendo, utilize somente o tipo bit para evitar problemas. Quando estiver confortável, transicione para o tipo <code style="color: red">std_ulogic</code> quando precisar de sinais multivariados e só quando realmente precisar de um sinal de multivariado com múltiplas atribuições (e.g. barramento) use o <code style="color: red">std_logic</code>.[5]
De fato, a maioria dos projetos não necessita do <code style="color: red">std_logic</code> e acabam por utilizá-lo apenas com os valores <code style="color: red">0</code> ou <code style="color: red">1</code>, como substituição ao tipo <code style="color: red">bit</code>. Como regra geral, utilize o tipo de dado certo para o trabalho que está fazendo e, enquanto você estiver aprendendo, utilize somente o tipo bit para evitar problemas. Quando estiver confortável, transicione para o tipo <code style="color: red">std_ulogic</code> quando precisar de sinais multivariados e só quando realmente precisar de um sinal de multivariado com múltiplas atribuições (e.g. barramento) use o <code style="color: red">std_logic</code>.[5]
=Tutorial ModelSim&#174;=
;OBJETIVOS
:O aluno será capaz de:
:*Utilizar a ferramenta de simulação ModelSim&#174;.
;METODOLOGIA
:A aula será expositiva e neste tutorial vamos apresentar o que é necessário para realizar a simulação da aplicação e seu de comportamento utilizando a ferramenta de simulação ModelSim&#174;.
;INTRODUÇÃO: Ferramentas de simulação são grandes aliadas no desenvolvimento de aplicações embarcadas, pois facilitam a vida do desenvolvedor, em FPGA é extremamente recomendado que todo o código seja testado em um simulador antes de ser sintetizado em um FPGA. Nesta aula será apresentado um rápido tutorial de ModelSim&#174;. O processo de gravar o FPGA e testar é muito mais demorado do que simplesmente rodar o simulador. Além disso não existem muitas interfaces da FPGA com o mundo externo, é praticamente impossível saber sobre tudo que está acontecendo no seu sistema em tempo real. Alguns ''bugs'' são difíceis de serem encontrados em tempo de execução pois podem ocorrer só em situações especificas que demoram muito a acontecer ou por necessitar de vários equipamentos externos para simular a situação em que ocorreriam.
:O ModelSim&#174; é um simulador de HDL (''Hardware Description Language'') desenvolvido pela Mentor Graphics. Ele suporta a simulação das linguagens VHDL e Verilog e pode simular o código a nível de RTL (''Register Transfer Level'') e ''Gate Level''. Em nível de RTL é analisado o circuito a nível de comportamento dos registradores e em Gate Level é analisado a nível de netlist com inclusão de atrasos das portas lógicas e etc.
==Download do ModelSim&#174;==
A primeira coisa que deve ser feita, é instalar o ModelSim&#174; no seu computador. Uma edição de graça do ModelSim&#174; para estudantes pode ser obtido no site da [http://www.altera.com/products/software/quartus-ii/modelsim/qts-modelsim-index.html Altera]. Recomendo o download junto com o Quartus 14.
É importante notar que a versão gratuita possui algumas limitações, tais como: limitação de performance, limite para o número de linhas de código executáveis e não trabalhar com duas linguagens em um mesmo projeto (misturar VHDL e Verilog).
==Criar um TestBench==
Uma das utilidades de VHDL é a simulação que é usada para estudar a operação de um circuito ou para verificar se um design está correto. Fazer uma simulação em VHDL é simular um experimento com um circuito físico, em que as entradas do circuito são conectadas a algum sinal de estímulo (por exemplo, um gerador de sinais) , e com isso, as saídas deste circuito podem ser observadas.
Simular uma lógica programada em VHDL é similar a fazer um experimento virtual, em que o circuito físico é substituído pela sua descrição em VHDL, bem como os estímulos de entrada e as saídas. Este conjunto de ferramentas e práticas são implantadas em um Testbench (arquivo de teste).
O código VHDL abaixo apresenta o arquivo '''testbench_pisca_led.vhd''' para o nosso exemplo.
<syntaxhighlight lang=vhdl>
library ieee;
use ieee.std_logic_1164.all;
entity testbench_pisca_led is
end entity testbench_pisca_led;
architecture rtl of testbench_pisca_led is
signal clk: std_logic := '0';
signal rs: std_logic;
signal led_status: std_logic;
component pisca_led
port
(
sys_clk_50mhz : in std_logic;
sys_rst : in std_logic;
led : out std_logic
);
end component;
begin
clk <= NOT clk after 10 ns; -- clock de 50 MHz
pisca_led1: pisca_led PORT MAP(clk, rs, led_status);
end architecture rtl;
</syntaxhighlight>
Pode-se observar as entradas de estímulo criadas do clock de 50MHz e o sinal de reset. A saída é o led_status. (10ns para alto, 10ns para baixo = período de 20ns = frequência de 50 MHz).
Para melhor visualizar a simulação o código '''pisca_led.vhd''' teve a frequência de pisca alterada para um período de 10ms. Isso foi feito alterando o valor da comparação do sinal led_delay para 500000;
<syntaxhighlight lang=vhdl>
library ieee;
use ieee.std_logic_1164.all;
entity pisca_led is
port
(
sys_clk_50mhz : in std_logic;
sys_rst : in std_logic;
led : out std_logic
);
end entity pisca_led;
architecture rtl of pisca_led is
signal led_delay : NATURAL range 0 to 50000000;
signal led_reg : std_logic;
begin
led <= led_reg; -- Atribui a porta de saída chamada led o valor do registrador
process(sys_clk_50mhz, sys_rst) -- Executado a cada pulso de clock ou reset
begin
if sys_rst = '0' then -- Reset assíncrono, independe do clock
led_delay <= 0;
led_reg <= '0';
elsif rising_edge(sys_clk_50mhz) then
led_delay <= led_delay + 1;
if led_delay = 500000 then
led_delay <= 0;
led_reg <= not led_reg; -- Inverte o valor do registrador do led
end if;
end if;
end process;
end architecture rtl;
</syntaxhighlight>
A seguir será mostrado como criar um projeto no ModelSim&#174; para que os códigos apresentados sejam testados.
==Criar um Projeto, Adicionar os Arquivos, e Compilar==
Podemos então abrir o ModelSim&#174;. Isto deve ser o que você vai encontrar ao executar o Modelsim e clicar em '''Jumpstart''' pela primeira vez.
[[Imagem:fig68_DIG222802.png|center]]
<center>
Figura 1 - Informações sobre o projeto inicial.
</center>
Preencha as informações adequadamente e clique em Ok. Uma nova janela irá se abrir.
[[Imagem:fig69_DIG222802.png|center]]
<center>
Figura 2 - Adicionando arquivos ao projeto.
</center>
Se você já tem os arquivos .vhd do Testbench e do módulo disponível pisca_led , clique em ‘Add Existing File’ e adicione os arquivos ao projeto. Se não os tiver, o ModelSim&#174; possui um editor que pode ser utilizado para esse fim. Então clique em Create New File e copie o conteúdo para o novo arquivo. A tela do seu projeto deve ficar como mostra a Figura 3 abaixo.
[[Imagem:fig70_DIG222802.png|center|650px]]
<center>
Figura 3 - Visão da tela do projeto.
</center>
Não esqueça que você deverá ter os códigos dos dois arquvios: '''pisca_led.vhd e testebench_pisca_led.vhd'''.
Agora vamos compilar os arquivos para isto é só clicar em '''Compile > Compile All'''. Se não houver erros nos arquivos a seguinte mensagem irá aparecer na tela Transcript:
[[Imagem:fig71_DIG222802.png|center]]
<center>
Figura 4 - Visão da área da tela com as informações do Transcript.
</center>
==Rodar a Simulação==
Agora vamos rodar a simulação. Para isso clique em '''Simulate > Start Simulation...''' A seguinte tela vai aparecer:
[[Imagem:fig72_DIG222802.png|center]]
<center>
Figura 5 - Janela com as informações da Simulação.
</center>
Clicando em '''OK''', deverá aparecer a tela de Wave -default. Caso não apareça, vá em '''View > Wave'''.
[[Imagem:fig73_DIG222802.png|center|800px]]
<center>
Figura 6 - Janela da Simulação.
</center>
É possível observar os seguintes itens, descritos na imagem:
*Tempo de simulação: Especifica o tempo de cada passo da simulação;
*Instancias: Instâncias disponíveis;
*Objects: Sinais disponíveis dentro da instância selecionada;
*Wave: Analisador de ondas, onde é possível verificar os sinais em determinados instante de tempo.
Antes de começar a simulação, escolha os sinais de interesse que serão analisados. Para tal, selecione primeiramente a instância do testbench_pisca_led no Instance Viewer. Observe que os sinais clk, rs e led_status ficarão disponíveis em Objects. Arraste estes 3 sinais para a janela Wave. Em seguida, selecione a instância pisca_led1 e arraste o sinal led_delay para a janela Wave.
Na janela Wave, o sinal de reset não está sendo setado, e com isso ele está no estado unknown. Antes de simularmos temos que fazer com que o sinal rs fique em 0 para que ocorra o reset e os sinais sejam iniciados corretamente. Para fazer isso clique com o botão direito sobre o sinal rs. No menu que irá se abrir, clique em Forc... . Coloque value = 0 e clique em OK.
[[Imagem:fig74_DIG222802.png|center]]
<center>
Figura 7 - Atribuindo um valor a um sinal.
</center>
Em seguida, altere o tempo do passo da simulação para 10ms e clique em play. Essa operação irá levar algum tempo devido às limitações da versão free do ModelSim&#174;.
Altere o sinal de rs para 1 e rode novamente 10ms. Rode mais uma vez 10 ms.
Ao fim estará simulado 30 ms em que os primeiros 20 ms foram utilizados para dar reset no módulo de pisca_led e os próximos 10 ms foram utilizados para o led alterar seu status para 1.
Ao final da simulação, podemos observar o resultado na janela wave. O zoom (icone lupa) pode ser utilizado para melhor visualizar a simulação. Para observar o evento da alteração do status do led, selecione o sinal led_status e clique no botão para procurar o nível de borda. Conforme podemos observar na Figura 8 abaixo.
[[Imagem:fig75_DIG222802.png|center|800px]]
<center>
Figura 8 - Resultado da simulação.
</center>
Observamos que a simulação aconteceu conforme o esperado. A cada pulso de clock, o contador led_delay foi incrementado e quando atingiu o valor 500000 (10 ms) o valor de led_status foi alterado.
;EXEMPLO
Um contador de Johnson é um circuito digital que consiste de uma série de flip-flops do tipo D ligados entre si num circuito de com realimentação da saída '''Q\''' do último FF na entrada D do primeiro FF. Quando o circuito é acionado todas as saídas '''Q''' dos FF ficam em nível lógico zero, enquanto todas às saídas '''Q\''' ficam em 1.
O diagrama de circuito para um contador Johnson de 4 bits é mostrado abaixo :
[[Imagem:fig43_DIG222802.png|center]]
<center>
Figura 9 - Contador Johnson.
</center>
O código VHDL para um contador Johnson de 4 bits é mostrado abaixo:
<syntaxhighlight lang=vhdl>
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity johnson_counter is
port (
        DAT_O : out unsigned(3 downto 0);
        RST_I : in std_logic;
        CLK_I : in std_logic
        );
end johnson_counter;
architecture Behavioral of johnson_counter is
signal temp : unsigned(3 downto 0):=(others => '0');
begin
DAT_O <= temp;
process(CLK_I)
begin
    if( rising_edge(CLK_I) ) then
        if (RST_I = '1') then
            temp <= (others => '0');
        else
            temp(1) <= temp(0);
            temp(2) <= temp(1);
            temp(3) <= temp(2);
            temp(0) <= not temp(3);
        end if;
    end if;
end process;
   
end Behavioral;
</syntaxhighlight>
O código '''testbench''' utilizado para testar o código é dada abaixo:
<syntaxhighlight lang=vhdl>
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY tb2 IS
END tb2;
ARCHITECTURE behavior OF tb2 IS
  --Inputs
  signal RST_I : std_logic := '0';
  signal CLK_I : std_logic := '0';
    --Outputs
  signal DAT_O : unsigned(3 downto 0);
  -- Clock period definitions
  constant CLK_I_period : time := 1 ns;
BEGIN
    -- Instantiate the Unit Under Test (UUT)
  uut: entity work.johnson_counter PORT MAP (
          DAT_O => DAT_O,
          RST_I => RST_I,
          CLK_I => CLK_I
        );
  -- Clock process definitions
  CLK_I_process :process
  begin
        CLK_I <= '0';
        wait for CLK_I_period/2;
        CLK_I <= '1';
        wait for CLK_I_period/2;
  end process;
  -- Stimulus process
  stim_proc: process
  begin       
        RST_I <= '1';
      wait for 2 ns;   
        RST_I <= '0';
        wait for 2 ns; 
        RST_I <= '1';
        wait for 1 ns; 
        RST_I <= '0';
      wait;
  end process;
END;
</syntaxhighlight>
<blockquote style="background:#F0F8FF; border: 2px solid #0000CD; margin-left: 100px; margin-right: 100px; padding: 2em;">
;NOTA: Você deve definir um período de simulação de 1ns, também definir o sinal CLK_I como ''clock'' (botão direito do mouse > Clock...) e simular (botão '''run''') para RST_I (botão direto do mouse > Force...) igual a 1, depois igual a zero (0).
</blockquote>
A Figura 10 abaixo mostra o resultado esperado para as formas da onda da simulação.
[[Imagem:fig76_DIG222802.png|center|800px]]
<center>
Figura 10 - Formas de ondas simuladas para o Contador Johnson.
</center>
==Conclusões==
Simulações são de suma importância para o desenvolvedor VHDL, pois o tempo de compilação de tais ferramentas é excessivamente grande conforme o projeto vai aumentando de complexidade. Fica muito trabalhoso testar um design diretamente em um placa ou kit de desenvolvimento. Além disso, ela permite verificar se o comportamento está de acordo com o projetado antes de ir para o kit, permitindo encontrar possíveis “furos”.
Por fim, sugiro que você faça algumas modificações no código, principalmente para que a simulação não demore tanto. Isso pode ser feito alterando-se o valor de comparação do registrador led_delay.
Existem diversas formas de criar um testbench e testar um circuito, neste tutorial fiz de forma básica pois a intenção era mostrar o Modelsim! Mais para frente faço um post exclusivo sobre testbenchs.
''*Adaptamos esse Texto Original, publicado por Andre Prado em seu blog e escrito em conjunto com Raphael Silva.''


=Exercícios=
=Exercícios=
Linha 912: Linha 591:
;Parte 1
;Parte 1


1.#O que significa CPLD, FPGA e VHDL?
#O que significa CPLD, FPGA e VHDL?
#Quais as principais vantagens no uso do VHDL?
#Quais as principais vantagens no uso do VHDL?
#Quais as etapas de um ciclo de projeto de sistemas em VHDL?
#Quais as etapas de um ciclo de projeto de sistemas em VHDL?
Linha 1 184: Linha 863:


{{collapse bottom}}
{{collapse bottom}}
;Parte 3
# O que é o ModelSIM?
# Para que serve o ModelSIM?
# O que é o ''Jumpstart'' que aparece na primeira vez que se executa o ModelSIM?
# O que é um ''testbench''?
# O que eu devo fazer para rodar um simulação? Onde devo clicar?
# O que é ''Wave''? Esse termo é utiliza pra quê?
# O que é "passo da simulação"?
# O que é "tempo de simulação"?
;Parte 4
#Tente simular código VHDL abaixo. É importante estabelecer um passo de simulação na ordem 100 ps. Perceba também que, quando ele atinge a contagem de 15 ele para de contar. Tente resolver esse problema alterando o range e/ou mudando a forma com que as informações são enviadas para o saída.
<syntaxhighlight lang=vhdl>
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity CONTADOR is
port(
CLK: in  std_logic;
    RESET: in  std_logic;
ENABLE: in  std_logic;
Q: out std_logic_vector (3 downto 0)
);
end CONTADOR;
architecture CONTADOR_arq of CONTADOR is
begin
process(CLK,RESET)
variable X: integer range 0 to 15;
begin
if (RESET = '1') then
X := 0;
elsif (CLK'event and CLK='1') then
if (ENABLE = '1') then
X := X + 1;
end if;
end if;
Q <= conv_std_logic_vector(X, 4);
end process;
end CONTADOR_arq;
</syntaxhighlight>
[2] Tente simular o seguinte código:
<syntaxhighlight lang=vhdl>
library ieee;
use ieee.std_logic_1164.all;
ENTITY mux4x1 is
    port(i0, i1, i2, i3: in bit;
        a0, a1: in bit;
        y: out bit);
END mux4x1;
ARCHITECTURE teste of mux4x1 is
BEGIN
    y <= i0 when a1='0' and a0='0' else
        i1 when a1='0' and a0='1' else
        i2 when a1='1' and a0='0' else
        i3;
END teste;           
</syntaxhighlight>


=Referências=
=Referências=
Linha 1 266: Linha 873:
[3] https://www.altera.com/products/design-software/model---simulation/modelsim-altera-software.html
[3] https://www.altera.com/products/design-software/model---simulation/modelsim-altera-software.html


[4] [https://drive.google.com/file/d/1zVjHMsvCz-HFm3S2Vp0vWk1MSqTRHmqK/view?usp=sharing Videoaula VHDL]
[4] https://balbertini.github.io/vhdl_datatypes-pt_BR.html
 
[5] https://balbertini.github.io/vhdl_datatypes-pt_BR.html


[6] [[C%C3%B3digos_VHDL_para_uso_nas_Aulas]]




Linha 1 276: Linha 880:
[[Imagem:icone_voltar.png|link=DI2022802_2024_2_AULA11]]
[[Imagem:icone_voltar.png|link=DI2022802_2024_2_AULA11]]
[[Imagem:icone_menu.png|link=DI2022802_2024_2#Aulas]]
[[Imagem:icone_menu.png|link=DI2022802_2024_2#Aulas]]
[[Imagem:icone_prox.png|link=DI2022802_2024_1_AULA13]]
[[Imagem:icone_prox.png|link=DI2022802_2024_2_AULA13]]

Edição atual tal como às 16h32min de 3 de fevereiro de 2025

1 VHDL - Linguagem de Descrição de Hardware

OBJETIVOS
O aluno será capaz de:
  • Saber sobre as definições da linguagem VHDL;
  • Conhecer o ciclo de projeto;
  • Diferenciar Entidades e Arquiteturas; e
  • Conhecer Identificadores e Tipos de Dados.


METODOLOGIA
A aula será expositiva (gravada), utilizando apresentação de texto base na Internet, onde será apresentado uma introdução ao VHDL que uma linguagem utilizada para descrição de hardware amplamente utilizada.


INTRODUÇÃO
VHDL ou (Very High Speed Integrated Circuits) é uma linguagem utilizada para descrever hardware. Ela foi concebida pelo departamento de defesa dos Estados Unidos (DARPA) na década de 80 para a documentação dos circuitos integrados vendidos às forças áreas americanas. Em 1987 ela foi padronizada pela IEEE como uma linguagem de descrição de hardware, o fato de ser padronizada e de domínio público ampliou e muito a sua utilização. A sua sintaxe é altamente tipada e lembra ADA e Pascal mas as semelhanças param por ai. A descrição de um circuito difere completamente de um software e muitas pessoas quando saem de uma linguagem de software e vem para linguagens de descrição de hardware encontram muitas dificuldades. Sempre mantenha em mente que você está descrevendo hardware e não escrevendo um algoritmo que um processador vai executar sequencialmente. VHDL é utilizando tanto para concepção de circuitos ASIC (por exemplo um i7 da Intel), quanto para desenvolvimento em FPGA. O resultado de uma “compilação” de um VHDL não é um executável mas sim uma netlist com todos os fios, conexões, componentes combinacionais e sequências de um hardware. [1]
NOTA
Este texto foi adaptado da Apostila Básica de VHDL do Prof. Dr. Renato Giacomini e da Apostila de Dispositivos Lógicos Programáveis dos professores: Caio Augusto de Oliveira, Jéssica Azevedo de Aguiar e Mateus Galvão Said Fontanini (UNESP).


1.1 Definições e Abreviaturas

ASIC (Application Specific Integrated Circuits) Circuito integrado de aplicação específica.
CPLD (Complex Programmable Logic Devices) Dispositivo lógico programável complexo.
FPGA (Field Programmable Gate Array) Arranjo de portas programável em campo.
VHDL (VHSIC Hardware Description Language). A sigla é derivada de outra abreviatura - VHSIC (Very High Speed Integrated Circuits), já que seu objetivo inicial era voltado ao projeto de circuitos integrados de altíssima velocidade.
VHSIC (Very High Speed Integrated Circuits) Circuito integrado de altíssima velocidade.


1.2 Histórico

Nas décadas de 70 e 80 foi posto em prática um programa do Departamento de Defesa (DoD) americano, para desenvolvimento de circuitos integrados de alta velocidade, denominado VHSIC e originado da preocupação de domínio das tecnologias envolvidas. Desde o princípio, anteviu-se o problema de representação dos projetos segundo uma linguagem que fosse comum às várias empresas envolvidas e que permitisse uma documentação fechada e clara para projetos de complexidade crescente. Nesta mesma época, já havia no mercado de computação a chamada crise do software, caracterizada pela dificuldade de gestão, documentação e sistematização do ciclo de vida do software (que envolve, em termos gerais, todas as atividades de relativas à sua criação e uso)[1]. O problema surgiu inicialmente no software porque era no software que se desenvolviam as aplicações, que tornavam o produto particular para um uso específico. Isso fazia com que um grande volume de projetos fossem conduzidos, quase sempre com muita complexidade e pouco método. No hardware a questão era mais bem controlada, pois os projetos eram, em geral, mais genéricos, especialmente para o hardware digital. Os projetos de microprocessadores, que eram os mais complexos, visavam na maior parte dos casos o uso geral. Um mesmo microprocessador seria utilizado em várias aplicações, seria reproduzido e testado aos milhões. Isso significava que o investimento em um único projeto poderia ser muito maior, inclusive em termos de especificação e testes. A evolução da metodologia de projeto de software foi então natural, em função dos argumentos sustentados pela crise. Hoje ainda é grande o desenvolvimento de novos métodos e a busca por uma linguagem descritiva universal, como o UML, para especificação e projeto de software orientado a objetos.

A questão preocupante quanto ao hardware, para o programa VHSIC americano, era que alguns fatos indicavam para uma evolução do mercado que faria surgirem problemas semelhantes aos apresentados pela crise de software. Entre estes fatos:

  • A fabricação de circuitos integrados deixava de ser exclusiva de alguns poucos fabricantes. Surgiam empresas especializadas na fabricação de projetos de terceiros, o que permitiria, em conjunto com o desenvolvimento de tecnologias de fabricação menos custosas, a criação de CIs de uso específico para certas aplicações.
  • As novas tecnologias de fabricação (abaixo de 2mm, na época) permitiam um aumento de densidade dos CIs, com conseqüente aumento de complexidade.
  • Surgiam componentes de lógica programável (PLDs e PALs), inicialmente de pequena densidade, mas que poderiam evoluir para densidades muito maiores rapidamente. Tais componentes poderiam criar, como de fato ocorreu posteriormente, um grande mercado de projetos de pequena escala e aplicações específicas, muito parecido com o mercado de projetos de software.

A criação de uma linguagem de descrição de hardware patrocinada pelo programa e, em paralelo algumas outras linguagens criadas pela indústria, foi então uma decorrência natural. Em 1987, o VHDL foi normalizado pelo IEEE, tornando-se um padrão mundial, ao lado do Verilog, uma alternativa também expressiva no mercado de projetos de hardware. Hoje, praticamente todas as ferramentas de desenvolvimento de hardware computadorizadas aceitam essas linguagens como entrada, de forma que um projeto baseado em VHDL ou Verilog pode ser implementado com qualquer tecnologia.


1.3 Vantagens do Uso

A alternativa para uso de uma linguagem formal de descrição de hardware como o VHDL é a descrição por diagramas esquemáticos. O VHDL apresenta as seguintes vantagens:

  • Em sistemas sequenciais, o detalhamento da lógica de controle é realizado pelas ferramentas de automação do projeto, o que evita a trabalhosa e limitada aplicação das técnicas manuais tradicionais;
  • O objetivo do projeto fica mais claro que na representação por esquemáticos, nos quais a implementação se sobrepõe à intenção do projeto;
  • O volume de documentação diminui, já que um código bem comentado em VHDL substitui com vantagens o esquemático e a descrição funcional do sistema;
  • O projeto ganha portabilidade, já que pode ser compilado em qualquer ferramenta e para qualquer tecnologia. É comum, na indústria, o uso de FPGAs e CPLDs para produções iniciais ou de menores escalas em projetos que posteriormente possam ser implementados em ASICs. Todas as implementações podem usar o mesmo código VHDL.


1.4 Ciclo de Projeto

O projeto de um sistema digital auxiliado por ferramentas computadorizadas segue normalmente as etapas descritas a seguir.


1. Especificação

Esta etapa visa determinar os requisitos e funcionalidade de projeto, incluindo timing dos sinais e definido completamente as interfaces. É uma etapa comum e necessária a qualquer projeto, independentemente do uso do VHDL.

2. Codificação

Nesta etapa, o objetivo é descrever, de forma estruturada e bem documentada, em VHDL, todo o projeto, segundo seus padrões de sintaxe. Assim, formaliza-se a especificação da etapa anterior, numa implementação de alto nível, em que são descritos apenas os aspectos relevantes à solução do problema.

3. Simulação de Código Fonte

Nesta etapa, procura-se simular o código em uma ferramenta confiável, a fim de verificar, preliminarmente, o cumprimento da especificação. Esta simulação não considera ainda detalhes tecnológicos de implementação.

4. Síntese Otimização e Fitting

Síntese - É o processo de “tradução” ou compilação de um código VHDL para uma descrição abstrata, em linguagem mais próxima da implementação. Naturalmente, a síntese é ainda um processo independente da tecnologia. Basicamente, o resultado obtido é o que se chama de RTL (register- transfer level), em que se definem registros, suas entradas e saídas e a lógica combinacional entre elas. Otimização - É o processo de seleção da melhor solução de implementação para uma dada tecnologia. Logicamente, as ferramentas EDA (Engineering Design Automation) são preparadas para aceitar diretivas de otimização, dependendo do resultado que se quer (minimização de área, consumo, tempo de resposta, etc). Fitting - É o processo em que a lógica sintezada e otimizada é mapeada nos recursos oferecidos pela tecnologia.

5. Simulação do modelo pós-layout

A simulação realizada com o resultado do fitting permite resultados mais apurados de comportamento e timing, porque considera as características da implementação definitiva na tecnologia, como, por exemplo, os tempos de propagação dos sinais.

6. Geração

É a fase de configuração das lógicas programáveis ou de fabricação de ASICs.

2 Entidades e Arquiteturas

O código abaixo representa um comparador binário para palavras de quatro bits:


-- comparador de 4 bits
entity comp4 is
    port ( a, b: in bit-vector (3 downto 0);
           equals: out bit);
end comp4;

architecture arq1 of comp4 is
begin
    equals <= 1 when (a=b) else O;
end arq1;


Uma entidade (entity) é uma abstração que descreve um sistema, uma placa, um chip, uma função ou, até mesmo, uma porta lógica. Na declaração de uma entidade, descreve-se o conjunto de entradas e saídas. No exemplo dado, a entidade comp4 possui duas entradas, a e b, e uma saída, equals, que definem o port da entidade.

Os ports correspondem a pinos e são tratados como objetos de dados. Pode-se atribuir valores ou obtê-los de ports. Cada entrada ou saída possui um modo (mode) de operação. Os modos possíveis são:

in – entrada;

out – saída: os pinos definidos como saída não podem ser utilizados como entradas, nem seus valores utilizados na lógica interna;

buffer - saída com possibilidade de realimentação;

inout - substitui qualquer um dos outros, mas seu uso deve ser limitado aos casos em que o pino deva ser utilizado como entrada e saída, para clareza na descrição.


2.1 Corpo de Arquitetura

A arquitetura de uma entidade pode ser descrita de três formas distintas, mas que, em geral, conduzem a uma mesma implementação.


2.1.1 Descrição comportamental

A arquitetura (architecture) descreve as funções realizadas pela entidade. No caso do exemplo é atribuído o valor ‘1 ‘ à saída equals, sempre que as entradas forem iguais e ‘0’, caso contrário.

Esta é a forma mais flexível e poderosa de descrição. São definidos processos concorrentes (process). A cada processo é associada uma lista de sensibilidade, que indica quais são as variáveis cuja alteração deve levar à reavaliação da saída. No simulador funcional, quando uma variável da lista é modificada, o processo é simulado novamente. O código abaixo ilustra a aplicação deste tipo de descrição ao comparador do exemplo.


-- comparador de 4 bits
entity comp4 is
    port ( a, b: in bit_vector (3 downto 0);
           equals: out bit);
end comp4;

architecture comport of comp4 is
begin
    comp: process (a,b) -- lista de sensibilidade
    begin
       if a = b then
          equals < = 1 ;
       else
          equals < = O ;
       end if;
    end process comp;
end comport;


Uma arquitetura pode ter mais de um processo e eles serão executados concorrentemente entre si.

2.1.2 Descrição por fluxo de dados

Neste tipo de descrição, os valores de saída são atribuídos diretamente, através de expressões lógicas. Todas as expressões são concorrentes no tempo.

-- comparador de 4 bits
entity comp4 is
    port ( a, b: in bit_vector (3 downto 0);
           equals: out bit);
end comp4;
architecture fluxo of comp4 is
begin
    equals < = 1 when (a=b) else O;
end fluxo;

2.1.3 Descrição estrutural

A descrição estrutural apresenta netlists e instanciação de componentes básicos, ou seja, é como se fosse uma lista de ligações entre componentes básicos pré-definidos.

-- comparador de 4 bits
entity comp4 is
    port ( a, b: in bit_vector (3 downto 0);
           equals: out bit);
end comp4;

use work.gateskg.all;
architecture estrut of comp4 is
    signal x bit_vector (0 to 3);
begin
    U0: xnor2 port map (a(0), b(0), x(0));
    U1: xnor2 port map (a(1), b(1), x(1));
    U2: xnor2 port map (a(2), b(2), x(2));
    U3: xnor2 port map (a(3), b(3), x(3));
    U4: and4 port map (x(0), x(1), x(2), x(3), equals);
end estrut;

2.2 Identificadores

Os identificadores são usados como referência a todos os objetos declarados no código. As regras para formação de nomes são:

  • O primeiro carácter deve ser uma letra.
  • O último não pode ser underscore.
  • Não são permitidos dois underscores em sequência.
  • Maiúscula / Minúscula são equivalentes.

2.3 Objetos de dados

Existem 3 tipos de objetos: sinais, constantes e variáveis. Observadas as seguintes regras:

  1. Não pode ser uma palavra-chave de VHDL.
  2. Tem que iniciar com uma letra.
  3. Não pode terminar com underscore "_".
  4. Não pode ter dois caracteres underscore juntos.
CONSTANTES
- Assumem apenas um valor em todo o código.

Exemplo:

constant largura: integer: = 8 ;

Podem ser declaradas no níveis de

package
entity
architecture
process

e valem apenas no contexto em que são declaradas.


SINAIS
- Representam ligações (fios) que interligam componentes. Ports são exemplos de sinais.

Exemplo:

signal valor-de-contagem: bit-vector (3 downto 0):

Podem ser declarados na entidade ou na arquitetura.


VARIÁVEIS
- São utilizadas em processos e subprogramas e devem ser declaradas neles. São atualizadas imediatamente e não correspondem à implementação física, como no caso dos sinais.

Exemplo:

variable resultado: std-logic := ‘0’

2.4 Tipos de Dados Básicos em VHDL

Um tipo de dado é uma classificação do conjunto possível de valores que determinado item pode assumir. VHDL é uma linguagem fortemente tipada, o que significa que a escolha do tipo de dado para um sinal, variável ou constante é de suma importância pois, para converter de um tipo ao outro, devemos utilizar funções de conversão. Uma vantagem de se utilizar uma linguagem fortemente tipada é que o sintetizador pode perceber a maioria dos erros cometidos pelos projetistas. Por exemplo, atribuir um grupo de sinais de 4 bits para um grupo de 8 bits ou atribuir um grupo de bits sem representação numérica para um grupo de bits representando um inteiro.

É importante salientar que, apesar de usar um estilo de programação, a linguagem VHDL é uma linguagem de descrição de hardware, portanto no final da síntese todos os tipos assumem valores altos ou baixos. Os conceitos de tipos das linguagens de programação não existem em nenhuma HDL e esse é um dos erros mais comuns dos projetistas de hardware.

Lembre-se
Você não está descrevendo um programa e sim um hardware.

O tipo de dado implicitamente influencia na síntese do seu circuito.

2.4.1 Tipos pré-definidos

Os tipos de VHDL são definidos pelos padrões IEEE 1076 e IEEE 1164. São divididos em escalares, vetores, enumerados e compostos. Todos os tipos pré-definidos estão na biblioteca std.standard, que é incluída implicitamente em todos os projetos de VHDL (não é necessário incluí-la).


Tipo Categoria Sintetizável? Valores
bit enumerado Sim 0 ou 1
boolean enumerado Sim FALSE ou TRUE
real escalar Não -1.0E38 a +1.0E38
character enumerado Não ASCII


O tipo bit é o mais utilizado. O boolean é útil para tomadas de decisão, como por exemplo em condições para um if-else. É importante notar que há um mapeamento direto entre FALSE e 0, e entre TRUE e 1, portanto FALSE<TRUE. O real normalmente é tratado como um número de ponto flutuante de precisão dupla. O character representa um grupo de 8 bits correspondentes aos 256 caracteres da tabela ASCII. Note que estes dois últimos não são sintetizáveis, portanto não devem ser utilizados como entradas ou saídas dos módulos. Apesar de não serem sintetizáveis, estes tipos são úteis durante as simulações.

O tipo integer também é bastante utilizado e possui dois subtipos padrões:


Tipo Categoria Sintetizável? Valores
integer escalar Sim -2147483647 a 2147483647
natural escalar Sim 0 a 2147483647
positive escalar Sim 1 a 2147483647

A especificação da linguagem demanda que no mínimo os números da tabela sejam aceitos, mas não limita o número de bits do inteiro. Grande parte das ferramentas implementam o inteiro como um mapeamento direto para o inteiro de 32 bits, presente na maioria das plataformas. A forma de interpretação também não é definida, mas a maioria das ferramentas interpreta como uma representação em complemento de dois. Os tipos natural e positive são apenas limitações nos valores que um objeto deste tipo poderá assumir. É possível declarar inteiros com uma limitação personalizada:

signal meusinal : integer range -8 to 7;

O trecho acima declara o meusinal como um inteiro de 4 bits. Contudo, valores maiores que a implementação da ferramenta de síntese não são possíveis, portanto se você precisar de um inteiro maior que 32 bits, verifique se sua ferramenta suporta inteiros grandes ou utilize vetores. A utilização da limitação do inteiro (com range ou usando os subtipos natural e positive) ajuda na detecção de erros pois, se em algum momento da simulação for feita a tentativa de atribuir um valor fora da faixa permitida, o simulador irá emitir uma mensagem de erro. Além disso, usar a limitação explícita diminui o número de bits utilizados para a representação, o que economizará portas lógicas no seu circuito. Pense assim: por que você precisa de um somador de 32 bits se seus inteiros só vão assumir valores de -16 a 15?

Os tipos bit e character também possuem suas versões em vetores:

Tipo Categoria Sintetizável? Valores
bit_vector vetor Sim bits
string vetor Não caracteres

O bit_vector é muito utilizado para representar um grupo de bits. Já o tipo string é usado somente para mensagens durante a simulação (note que ele não é sintetizável).

Há ainda dois tipos que não são sintetizáveis mas são importantes em VHDL:

Tipo Categoria Sintetizável? Valores
severity_level enumerado Não note, warning, error ou failure
time enumerado Não depende

O tipo severity_level é usado em testbenchs para informar a gravidade do problema encontrado. O tipo time é usado para descrever a temporização do circuito, tanto em descrições temporizadas quanto em testbenchs. Os valores de tempo são acompanhados dos multiplicadores que indicam a escala de tempo: fs (fentosegundos), ps (picosegungos), ns (nanosegundos), us (microsegundos), ms (milisegundos), sec (segundos), min (minutos) e hr (horas).

No exemplo abaixo, a mensagem "Teste" será impressa na tela sem parar a simulação e o sinal assumirá o valor entrada, mas somente após 10ns.

report "Teste" severity note;
sinal <= entrada after 10 ns;

Neste outro exemplo a definição dos valores de tempo:

type time in range - 2147483647 to 2147483647
units
    fs;
    ps = 1000 fs;
    ns = 1000 ps;
    us = 1000 ns;
    ms = 1000 us;
    sec = 1000 ms;
    min = 60 sec;
    hr = 60 min;
end units;

2.4.2 Pacote IEEE 1164

Um dos pacotes mais utilizados em VHDL é o std_logic_1164 da biblioteca ieee, que define um MVL (lógica multivariada, ou o nome completo Multivalue Logic System for VHDL Model Interoperability). Pra usar este pacote, é necessário incluir a declaração de uso no preambulo do seu projeto:


library ieee;
use ieee.std_logic_1164.all;


O tipo de dado primário definido nesta biblioteca é o std_ulogic (standard unresolved logic), que pode assumir outros valores usados em projeto digital além dos valores ideais 0 e 1. Esta modelagem de valores é mais próxima do mundo real, mas deve ser utilizada com cuidado.

Valor Significado
U Não inicializado (uninitialized)
X Desconhecido (forte)
0 Zero (forte)
1 Um (forte)
Z Alta impedância (tri-state)
W Desconhecido (fraco)
L Zero (fraco)
H Um (fraco)
- Qualquer um (don't care)

Exemplo de código std_ulogic definidos pela norma:

type boolean is (FALSE, TRUE);
type bit is (O, 1);
type std_ulogic is ( U, -- não inicializada
                     X, -- desconhecida forte
                     0, -- 0 forte
                     1, -- 1 forte
                     Z, -- alta impedância
                     W, -- desconhecida fraca
                     L, -- O fraco
                     H, -- 1 fraco
                     -, -- tanto faz
);
subtype std_logic is resolved std_ulogic


O valor U não foi pensado para ser utilizado pelo projetista mas sim pelas ferramentas de simulação. Quando seu circuito é simulado, um sinal em U significa que até aquele momento não houve nenhuma atribuição para aquele sinal. Isso é útil para depuração pois permite diferenciar um sinal que nunca foi atribuído de um que foi atribuído com zero, por exemplo. É especialmente útil para detectar o esquecimento do acionamento do reset de um circuito, pois é comum os projetistas negligenciarem o reset antes de começar a simular.

Já o X e o W indicam valores que estão fora do escopo naquele ponto do projeto. Atribuir o valor X para um sinal não é uma boa prática, mas ele também é útil em uma simulação. Quando aparecer um sinal com valor X ou W na sua simulação, muito provavelmente houve mais de uma atribuição para o mesmo sinal e elas são divergentes (e.g. uma atribuição 0 e uma 1 em pontos diferentes da sua descrição). Se sua simulação tem um destes valores, corrija o seu circuito antes de sintetizá-lo pois este valor não existe no mundo real: o circuito vai efetivamente assumir 1 ou 0, fechando um curto-circuito caso haja uma atribuição divergente.

Note também que o X não representa o don't care mas sim um valor desconhecido. Como a letra X é utilizada para o don't care nos métodos manuais (e.g. mapa de Karnaugh), é comum a confusão entre os dois valores.

A diferença entre um valor forte e fraco é apenas que os fracos indicam a utilização de resistores de pull-up ou pull-down, portanto se uma saída H for ligada a uma saída 0, o sinal será 0 e não há problemas além do consumo de energia extra ocasionado pelo resistor. Contudo, se uma saída forte 1 for ligada a uma saída 0, o resultado é um curto-circuito e possível dano ao circuito. Você pode livremente atribuir H, 1, L ou 0 para um sinal, e ambos serão sintetizados similarmente, mas as versões H e L instruem o sintetizador a usar portas com tecnologia de dreno aberto (open-drain) ou similar, permitindo a utilização de resistores de pull-up ou pull-down.

Se a plataforma alvo não suportar buffers tri-state o valor Z não será sintetizado, mas as ferramentas normalmente conseguem inferir um decisor baseado em multiplexador para substituir a escolha de qual saída será colocada no sinal. Note que a plataforma alvo pode não ter tri-state, então tome cuidado ao interligá-la com circuitos externos que esperam que ela tenha.

Outro tipo desta biblioteca é o std_logic. Ele é idêntico ao std_ulogic e pode assumir qualquer valor dos citados acima, mas tem uma diferença aos olhos do sintetizador: ele pode ser resolvido. O std_ulogic não especifica o que acontece quando você faz duas atribuições para o mesmo sinal (não importa se diferente ou iguais). Se o sinal for std_logic, o sintetizador entende que você sabe o que está fazendo e não te indicará nada ou no máximo mostrará uma mensagem de alerta, enquanto se o sinal for do tipo std_ulogic, o sintetizador irá se recusar a continuar a síntese, alertando-o que há mais de uma atribuição para aquele sinal.

Ambos os tipos desta biblioteca suportam a versão em vetor:


Tipo Categoria Sintetizável? Valores
std_ulogic enumerado Sim multivariado
std_logic enumerado Sim multivariado
std_ulogic_vector vetor Sim std_ulogic s
std_logic_vector vetor Sim std_logic s

Os valores multivariados são qualquer um da tabela no início desta seção. A síntese é possível para estes tipos, mas esteja atento para as observações nesta seção quando eles forem diferentes de 0 ou 1.

2.4.3 Qual tipo utilizar?

Não existe uma regra de que tipo utilizar, mas há várias dicas de como utilizar melhor a infraestrutura de tipos em VHDL.

A primeira dica é usar o bom senso. Se você está projetando uma unidade aritmética (e.g. multiplicador), faz pleno sentido que as entradas e saídas sejam unsigned ou signed de acordo com a maneira como a unidade aritmética as interpreta (e.g. o multiplicador é de inteiros sem ou com sinal). Contudo, se você está projetando um multiplexador, não faz sentido usar um tipo de dados com interpretação embutida pois o multiplexador não opera sobre os dados. Nesse caso, utilize o tipo bit ou std_logic.


std_logic oubit


Este é um tema de debate entre os projetistas há anos. A maioria dos projetistas opta por utilizar o std_logic e evitar aborrecimentos, mas esta não é uma boa prática. Para escolher corretamente, você precisa pensar no circuito que está desenvolvendo e na arquitetura alvo.

O FPGA, por exemplo, não suporta internamente nenhum dos tipos dostd_logic, portanto não faz sentido utilizá-lo pois internamente só haverá bits. Se sua arquitetura alvo é um FPGA, como por exemplo nas disciplinas de laboratório, use sempre o tipo bit. As exceções onde a utilização do std_logic é correta são: (i) quando você estiver projetando um barramento, (ii) quando estiver lidando com a saída, e (iii) em simulações.

No caso (i) a utilização do tri-state pode ser útil pois você poderá interligar saídas sem problemas, desde que somente uma delas esteja ativa e as demais estejam em tri-state. Contudo, se o seu barramento for interno ao FPGA, ele será sintetizado usando multiplexadores e não tri-state real pois o FPGA não tem esta funcionalidade internamente. Lembre-se que o tri-state do std_logic é representado por Z.

Já no caso (ii) você pode utilizar o std_logic livremente pois a maioria dos FPGAs implementa open-drain e tri-state nos buffers de saída. Você pode facilmente usar tri-state e valores de weak (que implementam pull-up e pull-down), mas lembre-se que nem todos os valores do std_logic são sintetizáveis.

No último caso (iii), o valor U (uninitialized) pode ser útil para saber se um determinado valor foi ou não escrito alguma vez durante a simulação pois é o valor padrão do std_logic. Na simulação todos os valores do std_logic são expressos corretamente, mas lembre-se que na síntese os valores sempre vão assumir 0 ou 1 mesmo que nunca tenham tido um valor atribuído.

Uma das falácias do tipo std_logic é o don't care. Ele é representado pelo - e não pelo X (unknown) normalmente usado nos métodos manuais (e.g mapa de Karnaugh). Se usado corretamente, a maioria das ferramentas interpreta o - como o don't care esperado, inclusive na atribuição condicional. Algumas ferramentas tratam ambos os X e o - como don't care para evitar a confusão, mas ela ainda acontece especialmente entre projetistas iniciantes, portanto evite-o.

De fato, a maioria dos projetos não necessita do std_logic e acabam por utilizá-lo apenas com os valores 0 ou 1, como substituição ao tipo bit. Como regra geral, utilize o tipo de dado certo para o trabalho que está fazendo e, enquanto você estiver aprendendo, utilize somente o tipo bit para evitar problemas. Quando estiver confortável, transicione para o tipo std_ulogic quando precisar de sinais multivariados e só quando realmente precisar de um sinal de multivariado com múltiplas atribuições (e.g. barramento) use o std_logic.[5]

3 Exercícios

Parte 1
  1. O que significa CPLD, FPGA e VHDL?
  2. Quais as principais vantagens no uso do VHDL?
  3. Quais as etapas de um ciclo de projeto de sistemas em VHDL?
  4. Qual a diferença entre uma Entidade (entity) e uma Arquitetura (architecture)?
  5. O que são os Ports?
  6. Que tipo de pinos (ports) existem e onde são aplicados?
  7. O que é uma Descrição comportamental?
  8. O que é uma Descrição por fluxo de dados?
  9. O que é uma Descrição estrutural?
  10. Quais são as regras para a formação dos Identificadores?
  11. O que é uma constante?
  12. Qual a diferença de Sinais e de Variáveis?
  13. Quais os tipos de dados disponíveis em VHDL?
Parte 2
  1. Projetar:
    1. Biestável tipo JK com clock e borda de subida, com descrição comportamental.
    2. Idem, com Preset e Clear assíncronos
  2. Realizar o projeto de um contador síncrono, com uma sequência pré-definida em VHDL e simular.
  3. Comentar os códigos abaixo:
Código 1
 
library ieee;
use ieee.std_logic_1164.all;

entity FF_D is
	port
	(
		D	: in  std_logic;
		clk	: in  std_logic;
		Q	: out std_logic
	);
end FF_D;

architecture Ex1 of FF_D is
begin
-- Update the register output on the clock's rising edge
process (clk)
begin
	if (rising_edge(clk)) then
		Q <= D;
	end if;
end process;
end Ex1;
Código 2
 
library ieee;
use ieee.std_logic_1164.all;
 
ENTITY ff_jk is
    port(j,k,clk: in bit;
         q: out bit);
END ff_jk;
 
ARCHITECTURE teste of ff_jk is
BEGIN

process(clk)
variable temp : bit :='0';
begin
	if( falling_edge(clk) ) then
		if (j='1' and k='0') then
			temp:='1';
		elsif (j='0' and k='1') then
			temp:='0';
		elsif (j='1' and k='1') then
			temp:= not temp;
		else
			temp:=temp;
		end if;
		q<=temp;
	end if;
end process;
END teste;
Código 3
 
library ieee;
use ieee.std_logic_1164.all; 
use ieee.std_logic_arith.all;

entity CONTADOR is
port(
	CLK:	in  std_logic;
    	RESET:	in  std_logic;
	ENABLE:	in  std_logic;
	Q:	out std_logic_vector (3 downto 0)
);
end CONTADOR;

architecture CONTADOR_arq of CONTADOR is 
begin
	process(CLK,RESET)
		variable X: integer range 0 to 15;
	begin
		if (RESET = '1') then
			X := 0;

		elsif (CLK'event and CLK='1') then
			if (ENABLE = '1') then
				X := X + 1;
			end if;
		end if;

		Q <= conv_std_logic_vector(X, 4);

	end process;
end CONTADOR_arq;
Outros Exemplos
  • Código 4: VIGIA
--1 - VIGIA
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY Vigia IS
PORT( clk : IN STD_LOGIC;
      SensorA, SensorB : IN STD_LOGIC;
      Multa_Vel, Multa_Comp : OUT STD_LOGIC);
END Vigia;

ARCHITECTURE Intuitiva OF Vigia IS
    TYPE STATE_TYPE IS (Espera,
        Verificando_Velocidade,
        Verificando_Tamanho,
        Multa_Velocidade,
        Multa_Tamanho, 
    Erro);
    SIGNAL Estado: STATE_TYPE;
    SIGNAL Cronometro: INTEGER RANGE 0 to 31;

BEGIN
    PROCESS (clk)
    BEGIN
        IF clk'EVENT AND clk = '1' THEN
            Multa_Vel <= '0';
            Multa_Comp <= '0';
            CASE Estado IS
                WHEN Espera =>
                    IF SensorA = '1' THEN
                        IF SensorB = '0' THEN
                            Estado <= Verificando_Velocidade;
                        ELSE
                            Estado <= Erro;
                        END IF;
                    END IF;
                WHEN Verificando_Velocidade =>
                    IF SensorA = '1' THEN
                        IF SensorB = '0' THEN
                            Cronometro <= Cronometro + 1;
                        ELSE
                            IF Cronometro < 8 OR Cronometro > 24 THEN
                                Estado <= Multa_Velocidade;
                            ELSE
                                Estado <= Verificando_Tamanho;
                            END IF;
                        END IF;
                    ELSE
                        IF SensorB = '0' THEN
                            Estado <= Espera;
                            Cronometro <= 0;
                        ELSE
                            Estado <= Erro;
                        END IF;
                    END IF;
                WHEN Verificando_Tamanho =>
                    IF SensorA = '1' THEN
                        IF SensorB = '1' THEN
                            Cronometro <= Cronometro -1;
                            IF Cronometro = 0 THEN
                                Estado <= Multa_Tamanho;
                            END IF;
                        ELSE
                            Estado <= Erro;
                        END IF;
                    ELSE
                        Estado <= Espera;
                        Cronometro <= 0;
                    END IF;
                WHEN Multa_Velocidade =>
                    Multa_Vel <= '1';
                WHEN Multa_Tamanho =>
                    Multa_Comp <= '1';
                WHEN Erro =>
                    Multa_Vel <= '1';
                Multa_Comp <= '1';
            END CASE;
        END IF;
END PROCESS;
END Intuitiva;
Exemplo 5: RECEPTOR
--2 – RECEPTOR
-- Receptor serial
entity Receptor is
    port( data_in, clock, limpa: in bit;
          pronto, ocupado: out bit;
          data_out: buffer bit_vector(7 downto 0));
end Receptor

architecture Receptor of Receptor is
    TYPE STATE_TYPE IS ( Espera,
                         Start_bit,
                         Recebendo,
                         Pronto);
    SIGNAL Estado: STATE_TYPE;
    SIGNAL Cronometro: INTEGER RANGE 0 to 7;
    SIGNAL Conta_bits: INTEGER RANGE 0 to 7;
process
begin
    if clock'event and clock = '1' then
    CASE Estado IS
        WHEN Espera =>
            IF Data_in = '0'then
                Cronometro <= 0;
                Ocupado <= '1';
                Estado <= Start_bit;
            ELSE
                Ocupado <= '0';
            END IF;
        WHEN Start_bit =>
            IF Cronometro < 4 then
                Cronometro = Cronometro+1;
            ELSE
                Cronômetro = 0;
                Conta_bits =0;
                Estado <= Recebendo;
            END IF;
        WHEN Recebendo =>
            IF Conta_bits < 6 then
                IF Cronometro < 3 then
                    Cronometro = Cronometro+1;
                ELSE
                    Cronômetro = 0;
                    Conta_bits = Conta_bits+1;
                    Data_out(0)<= Data_out(1);
                    Data_out(1)<= Data_out(2);
                    Data_out(2)<= Data_out(3);
                    Data_out(3)<= Data_out(4);
                    Data_out(4)<= Data_out(5);
                    Data_out(5)<= Data_out(6);
                    Data_out(6)<= Data_out(7);
                    Data_out(7)<= Data_in;
                END IF;
            ELSE
                Estado <= Pronto;
                Pronto <= '1';
            END IF;
        WHEN Pronto =>
            IF Limpa = 0 Then
                Ocupado <= '0';
                Pronto <= '0';
                Estado <= Espera;
            END IF;
    END CASE;
    END IF;
end process;
end Receptor;

4 Referências

[1] https://www.embarcados.com.br/vhdl-basico-parte-1-entidade/

[2] http://www.embarcados.com.br/tutorial-de-modelsim-vhdl-fpga/

[3] https://www.altera.com/products/design-software/model---simulation/modelsim-altera-software.html

[4] https://balbertini.github.io/vhdl_datatypes-pt_BR.html