Buscar

ApostilaVHDL 2012 02 24

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 65 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 65 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 65 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

UNIVERSIDADE DE BRASÍLIA
Apostila de VHDLTradução livre do material "The Low-Carb VHDL Tutorial"
©Copyright: 2004 por Bryan Mealy (27 - 08 - 2004)
Tradutores: Francisco Frantz e Daniel Almeida
24/02/2012
Introdução
VHDL é uma abreviação para "Very high-speed integrated circuit Hardware Description 
Language". Como hoje em dia se utiliza basicamente circuitos integrados para design de hardware, 
suprimiu-se uma parte da sigla para simplificação.
Há dois principais motivos para descrever hardware usando VHDL. Primeiramente, o VHDL 
pode ser usado para modelar circuitos digitais. Isso permite fazer simulações e testes, e, talvez mais 
importante, criar um modelo na linguagem VHDL é uma ótima forma de aprendizado. Outro uso do 
VHDL (ou outras linguagens de descrição de hardware) é um dos primeiros passos na criação de 
complexos circuitos digitais, podendo testá-los sem a necessidade de construí-los fisicamente.
Há outros simuladores lógicos disponíveis que permitem modelar o comportamento de circuitos 
digitais, que possuem uma abordagem gráfica para descrever os circuitos. Pode ser um método melhor 
para o aprendizado, mas, quanto mais complexos forem os circuitos digitais, mais tedioso e confuso fica 
esse método, uma vez que se baseia na interconexão de linhas e portas lógicas. O VHDL propicia uma 
descrição exata como o circuito digital funciona, sem ter de se preocupar com os detalhes das muitas 
conexões internas ao mesmo. O conhecimento de VHDL será uma ferramenta para modelar circuitos 
digitais de uma maneira inteligente.
Finalmente, é possível criar circuitos funcionais usando o VHDL, o que permite implementar 
rapidamente circuitos relativamente complexos. A metodologia usada permite dedicar mais tempo ao 
projeto dos circuitos e menos a realmente construí-los em uma proto-board. Agora, deve-se descrever o 
circuito usando uma linguagem como o VHDL. Para fazer isso, é fundamental aprender a linguagem e 
dominar suas ferramentas envolvidas no processo.
Sintaxe do VHDL
Há diversos aspectos da linguagem VHDL que deve-se saber antes de prosseguir. Essa seção 
detalha a sintaxe básica de um código em VHDL, como o uso de parêntese e a atribuição de valores. São 
aspectos característicos da linguagem de programação, assim como existem em C, C++, Matlab e todas as 
outras. É interessante memorizar o que será abordado nessa seção, mas isso só é possível com a prática.
Sensibilidade a letras maiúsculas
O VHDL não diferencia caracteres maiúsculos e minúsculos. Isso quer dizer que ambas as 
sentenças na figura 1 tem o mesmo sentido para o compilador. O objetivo agora não é entender o que cada 
sentença executa: isso será visto na próxima seção.
Dout <= A and B; doUt <= a AND b;
Figura 1: exemplo da indiferença entre maiúsculas e minúsculas
Espaços em branco
O VHDL não é sensível a espaços em branco (espaço e "tab") no documento fonte. As linhas de 
código da figura 2 tem o mesmo significado.
nQ <= In_a or In_b; nQ <= in_a OR in_b;
Figure 2: Exemplo da indiferença para espaços em branco
Comentários
Isso é válido para todas as linguagens de programação: um uso adequado de comentários melhora 
a leitura e o entendimento de qualquer código. A regra geral é comentar toda linha ou seção de código que 
possa não ser óbvia para outro leitor. Isso pode parecer tolo, uma vez que o código executa com ou sem 
os comentários, mas é de fundamental importância, não apenas para outros leitores. Muitas vezes, faz-se 
um código em um dia e só se trabalha nele novamente depois de muito tempo. Na hora que o código é 
feito, se entende tudo ele contém. Mas depois, há a necessidade de parar e pensar o que cada linha está 
fazendo, o que poderia ser evitado com comentários bem colocados. Em empresas que trabalham com 
programação, há sempre uma política muito rígida em como devem ser comentados os códigos. É, 
portanto, uma boa prática já começar a treinar.
No VHDL, os comentários começam com dois hífens ("--"), e o compilador ignora tudo que os 
seguem na linha. Não existe caractere que implemente comentários de mais de uma linha. A figura 3 
mostra alguns tipos de comentários.
---------------------------Commentary 
example--------------------------------
-- This next section of code is used to blah-blah
-- blah-blah blah-blah. This type of comment is the best
-- fake for block-style commenting.
PS <= NS_reg; -- Assign next_state value to present_state
Figura 3 - três tipos típicos de comentário
Parênteses
O VHDL é relativamente frouxo no uso de parênteses. Como em outras linguagens, há ordens de 
procedência associadas com os vários operadores em VHDL. Mesmo sendo possível escrever um código 
que segue essa ordem, é uma boa prática colocar alguns parênteses para melhorar a leitura do código. As 
duas sentenças da figura 4 possuem o mesmo significado para o compilador.
if x = ‘0’ and y = ‘0’ or z = ‘1’ then
 blah;
 blah;
 blah;
end if;
if ( ((x = ‘0’) and (y = ‘0’)) or (z = ‘1’) ) then
 blah;
 blah;
 blah;
end if;
Figura 4 - uso de parênteses e espaços para melhor leitura
Sentenças
Como em outras linguagens, toda sentença de código em VHDL deve ser terminada com ponto e 
vírgula (";"). Isso ajuda a remover eventuais erros de compilação do código, uma vez que é recorrente o 
erro de esquecer o ponto e vírgula. Entretanto, deve-se entender o que constitui uma sentença em VHDL 
para usá-los corretamente: o VHDL não é tão flexível quanto o Matlab, por exemplo, com colocações a 
mais ou a menos de pontos e vírgulas.
Declarações if, case e loop
Uma fonte comum de frustração enquanto se desenvolve um código em VHDL é o clássico erro 
bobo envolvendo essas declarações. As regras abaixo devem ser memorizadas para evitar esse tipo de 
erro, evitando assim, perder tempo procurando os erros. É altamente recomendável marcar esta seção para 
releitura quando estas declarações forem melhor detalhadas.
• Todo if tem de ter um correspondente then (se .... então)
• Todo if deve ser terminada por "end if"
• Caso se queira usar um "else", a forma correta de fazê-lo é com "elsif"
• Todo case é terminado com "end case"
• Todo loop tem um "end loop" correspondente
Identificadores
Identificador se refere ao nome dado aos itens em VHDL para discerni-los uns dos outros. Em 
linguagens como C e Matlab, os nomes de variáveis e de funções são identificadores. Em VHDL, há os 
nomes de variáveis, de sinais e de portas lógicas (serão discutidos em breve). Há regras rígidas (precisam 
ser seguidas) e regras flexíveis (é bom serem seguidas) para usar identificadores, que podem tornar o 
código mais legível, compreensível e elegante se forem escolhidos apropriadamente. A lista e a tabela a 
seguir mostram regras gerais para escolha de identificadores.
BONS IDENTIFICADORES IDENTIFICADORES RUINS
data_bus_val Nome descritivo 3Bus_val
WE Clássica sigla para "write 
enable"
DDD
div_flag mid_$num
port_A last__value
in_bus Provavelmente "input bus" start_val_
clk Clássico nome para "system 
clock"
in
@#$%%$
this_sucks
Big_vAlUe
pa
sim-val
Tabela 1: Identificadores desejáveis e indesejáveis
• Identificadores devem realmente identificar o que representam, ou seja, ao olhar um identificador, 
deve-se ter uma ideia da sua informação e do seu propósito
• Identificadores podem ter quantos caracteres se desejar. Quanto mais curto, mais legível; quanto 
mais longo, mais informação ele possui. Deve-se levar isso em conta na hora de programar.
• Identificadores só podem conter combinações de letras (A-Z ou a-z), dígitos (0-9) e underlines 
('_')
• Identificadores só podem começar com caractere alfabético
• Identificadores não podem terminar em underline nem possuir dois deles consecutivos
Palavras reservadas
Há uma lista depalavras às quais foi atribuído algum significado pela linguagem VHDL. Essas 
palavras, chamadas palavras reservadas, não podem ser usadas como identificadores por programadores. 
Há uma pequena lista mostrada a seguir, e a lista completa se encontra no apêndice A.
access exit mod return while NOR
after file new signal with XNOR
alias for next shared constant NAND
all function null then loop
attribute generic of to rem
block group on type wait
body in open until AND
buffer is out use OR
bus label range variable XOR
 Tabela 2: Lista resumida de palavras reservadas em VHDL
Estilo de programação
Já falou-se disso neste material, mas deve-se reforçar esse ponto. O estilo de programação de 
refere à aparência do código escrito em VHDL. Com a liberdade dada pela indiferença entre maiúsculas e 
minúsculas e quanto a espaços em branco, há a tendência de se pensar no VHDL como uma linguagem 
próxima da anarquia. Entretanto, deve-se sempre pensar na legibilidade do código. Isso é 
primordialmente feito a parir dos identificadores, comentários, espaços em branco e parênteses 
desnecessários. Abaixo, lista-se boas práticas para chegar ao objetivo da legibilidade.
• Se o código for legível para o programador, provavelmente será legível para outras pessoas que 
precisem ver o documento. Essas pessoas podem ser um colega do grupo de laboratório, um 
professor que avaliará o trabalho ou a pessoa que paga seu salário ao final do mês. No primeiro 
caso, pode não ser tão motivante fazer um código legível; nos outros dois, é altamente 
recomendável.
• O código pode ser modelado a partir de algum outro código que se considere organizado e 
legível. Procurar um código na internet e seguir seu estilo é uma boa prática para programadores 
iniciantes.
• Boas práticas durante a elaboração do código propiciam uma melhor depuração de erros, caso 
existam. O compilador de VHDL é eficiente na detecção de erros, mas geralmente não diz onde 
esses erros se encontram. Um código organizado reduz o tempo de procura desses erros.
Unidades básicas do VHDL
O VHDL descreve circuitos utilizando a abordagem das "caixas pretas". O circuito (e partes dele) 
podem ser representados como caixas, que possuem entradas e saídas. Considere o seguinte exemplo:
Nesse caso, os pontos de interesse são as entradas (A,B e C) e a saída (F). Não interessa, ainda, o 
que acontece dentro da caixa preta para converter as entradas na saída. Essa parte da descrição do 
circuito, ou seja, a caixa preta que indica as entradas e saídas (interface), é chamada, em VHDL, de 
entidade (entity).
Para saber como acontece essa medição da corrente, há diversas possibilidades de descrever o 
problema. Por exemplo, supondo que F = A.B + B.C, as figuras a seguir descrevem formas de descrever o 
que ocorre dentro da caixa preta:
Nesse caso, detalhe-se como a saída é obtida a partir da entrada As interações que ocorrem dentro 
da caixa preta são definidos, em VHDL, como arquitetura (architecture). É na arquitetura que são 
definidos os parâmetros da caixa preta (resistência R) e os processos para a saída ser obtida. É 
interessante notar que, para uma mesma entidade, podem existir várias arquiteturas.
Em VHDL, a entidade e a arquitetura são as unidades fundamentais para o projeto. Defini-se a 
"caixa preta" e as "coisas que vão dentro da caixa preta". Será sempre assim quando se trabalha com 
VHDL. A criação da entidade, como se pode imaginar, é muito simples, enquanto a arquitetura é a parte 
mais trabalhosa do projeto. Hoje em dia, é na melhoria da arquitetura de circuitos que se concentra grande 
parte dos esforços de engenheiros, e o VHDL é uma plataforma interessante para simular diversos tipos 
de arquitetura.
A entidade
Como á foi dito, a entidade é a versão em VHDL da caixa preta. Ela propicia um método de 
abstrair a funcionalidade de um circuito. A entidade simplesmente lista as entradas e saídas de um circuito 
digital. Em termos de VHDL, a caixa preta é descrita por uma declaração de entidade. A figura a seguir 
mostra como essa declaração é feita.
entity entity_name is
 [port_clause]
end entity_name;
Figura 5: Forma genérica de uma declaração de entidade
O identificador entity_name serve para fazer referência a entidade. A parte em colchetes, 
[port_clause] realmente especifica a interface (entradas e saídas) da entidade. Sua sintaxe está 
detalhada na figura abaixo.
port (
 port_name : mode data_type;
 port_name : mode data_type;
 port_name : mode data_type
 );
Figura 6: Detalhamento de [port clause]
Uma "port" é essencialmente um sinal que interage com o "mundo" fora da caixa preta. Pode ser 
tanto um sinal de entrada na caixa preta quanto um sinal de saída dela. Colocando o código da figura 6 no 
lugar de [port_clause] na figura 5, a entidade está declarada por completo, ou seja, 
[port_clause] nada mais é do que uma lista de sinais do circuito que estão disponíveis ao "mundo". 
O port_name é um identificador usado para diferenciar os diversos sinais. Onde se encontra "mode" 
especifica-se a direção do sinal em relação à caixa preta: pode ser input (entrada) ou output (saída). Para 
os sinais de entrada, mode deve ser substituído por in; para os de saída, por out. O "data_type" se refere 
ao tipo de dados que a "port" possui. Em VHDL, há diversos tipos de dados, mas trabalharemos 
primeiramente com o tipo std_logic; os diversos tipos de dados serão discutidos mais tarde.
 A figura 7 mostra um exemplo de uma caixa preta e o código VHDL que a descreve. Abaixo se 
encontram algumas coisas importantes de se notar na figura; a maioria delas se refere a legibilidade e 
clareza do código. As palavras em negrito são apenas para lembrar as palavras-chave e não possuem 
função diferente no código por estarem assim escritas.
• Cada "port" possui nome único e tem "mode" e "type" associados
• O compilador do VHDL permite diversas ports em uma mesma linha, e elas são separadas por 
vírgulas. type e mode são definidos no final da linha
Engenheiro
Realce
• A listagem de entradas e saídas é feita de forma consecutiva
• Há uma tentativa de alinhar as colunas do nome da port, mode e type para melhor legibilidade: 
vale lembrar que espaços em branco são ignorados pelo compilador
• Um comentário que diz coisas quase inteligentes foi adicionado
Figura 7: Caixa preta exemplo e seu código
A figura 8 apresenta outra entidade em VHDL. Tudo que se foi dito sobre a figura 7 é válido 
também para esta figura.
Figura 8: Outro exemplo de declaração de entidade
Pode ser que não esteja claro o que cada circuito acima faz, mas o importante é entender como é 
feita a declaração da entidade.
A maior parte dos circuitos que serão projetados, analisados e testados usando VHDL terão 
diversas entradas tendo similaridades entre as mesmas. Para não ser necessário escrever cada entrada com 
um nome diferente, pode-se agrupá-las em "bus". Um bus será um agrupamento de entradas, que diferem 
entre si apenas por um caractere numérico que caracteriza a posição da respectiva entrada no bus. Cada 
sinal do bus é chamado de elemento. Pode-se fazer uma analogia: em um ônibus, há diversos passageiros 
sentados. O motorista não precisa saber o nome de cada passageiro para chamá-lo, basta saber o número 
do seu assento.
O uso de buses sintetiza muito o código VHDL. Eles são usados frequentemente, e são facilmente 
descritos no código. Alguns exemplos constam na figura 9, onde deve-se notar que o mode permanece o 
mesmo, enquanto o type mudou: o std_logic agora inclui a palavra vector para indicar que cada 
identificador de sinal possui, na realidade, mais de um sinal. A forma de referenciar cada elemento do bus 
será detalhadamais adiante.
magic_in_bus : in std_logic_vector(0 to 3);
big_magic_in_bus : in std_logic_vector(7 downto 0);
tragic_in_bus : in std_logic_vector(16 downto 1);
data_bus_in_32 : in std_logic_vector(0 to 31);
mux_out_bus_16 : out std_logic_vector(0 to 15);
addr_out_bus_16 : out std_logic_vector(15 downto 0);
Figura 9: Alguns exemplos de sinais bus
Note que há duas maneiras possíveis de se descrever sinais em um bus, que são mostrados nos 
termos entre parênteses (lista de argumentos) que seguem a declaração de type. Os sinais podem ser 
descritos em duas ordens: crescente (to) ou decrescente (downto). Não existe um método melhor que 
outro, a escolha entre eles é baseada na clareza do código. O importante é não esquecer como foi feita 
essa definição.
Vamos analisar a notação para descrever os bus em uma caixa preta. A figura 10 mostra uma 
caixa preta seguida da sua declaração de entidade. Note que é usado um sinal de uma barra com um 
número em cima, para indicar que a entrada ou saída é um bus e quantos elementos ele possui. É 
importante notar que os sinais de entrada sel1 e sel0 poderiam ser descritos em um bus de dois elementos, 
tendo em vista que ambos possuem mesmo type.
Engenheiro
Realce
Engenheiro
Realce
Figura 10: uma caixa preta contendo entradas e saídas bus, e sua respectiva declaração de entidade
A arquitetura
Enquanto a entidade descreve a interface ou a representação externa do circuito, a arquitetura 
descreve o que o circuito realmente faz. Em outras palavras, a arquitetura descreve a implementação 
interna da entidade associada. Como é de se imaginar, descrever a entidade é geralmente bem mais fácil 
que descrever como o circuito deve operar. Isso é cada vez mais verdade quanto mais complexos forem os 
circuitos que se pretende projetar.
A parte mais desafiadora do VHDL é aprender as inumeráveis maneiras de se descrever um 
circuito. A maior parte dessa apostila é exatamente discutir os diferentes métodos de descrever circuitos 
lógicos, então não será feita uma discussão prolongada de arquiteturas nesse ponto. Entretanto, algumas 
noções gerais são dadas à seguir:
• Podem existir diversas arquiteturas para descrever uma única entidade. O estilo de código na 
arquitetura tem efeitos significativos no circuito sintetizado, ou seja, se o circuito for fisicamente 
produzido, cada arquitetura terá um impacto diferente no resultado final. Uma pode proporcionar 
maior velocidade, enquanto outra melhora o consumo de energia, por exemplo.
• Os modelos básicos para descrição de arquitetura são fluxo de dados, estrutural e 
comportamental, bem como versões híbridas desses modelos, que serão descritos nas próximas 
seções desse material.
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
O paradigma de programação em VHDL
A última seção foi uma breve introdução das unidades básicas do VHDL: entidade e arquitetura. 
A entidade está praticamente definida por completo, dada a sua simplicidade quando comparada com a 
arquitetura. É essencial lembrar que a entidade descreve a interface do circuito com o mundo, enquanto a 
arquitetura descreve o funcionamento do circuito. Isso tem de estar claro nesse ponto.
Antes de entrar em detalhes das especificações da arquitetura, devemos dar um passo atrás e 
lembrar o que estamos fazendo com VHDL: estamos descrevendo um circuito digital. É importantíssimo 
pensar nisso. A tendência de alunos com alguma experiência em programação é ver o VHDL apenas como 
outra linguagem que devem aprender para passar em outra matéria. Isso pode até funcionar para esse 
propósito, mas isso é uma má abordagem. O VHDL é uma abordagem completamente difenrente à 
programação, mas como se assemelha em alguns aspectos a outras linguagens, há a tendência de vê-lo 
como tal. Deve-se ter em mente que, para toda abstração válida na programação em outras linguagens, no 
VHDL se está implementando algo fisicamente. Essa é a diferença fundamental entre linguagens de 
programação comuns e as que descrevem hardware.
Declarações simultâneas
As declarações são o coração da maioria das linguagens de programação. Elas representam 
quantidades finitas de "ações" a serem feitas. Em linguagens algorítmicas, como C ou Java, elas 
representam ações a serem feitas no processador, e, assim que terminada a ação, o processador começa a 
ação seguinte, especificada em algum lugar do código fonte associado. Isso faz sentido, e é de certa forma 
confortável para humanos que, como o processador, costumam fazer uma ação por vez.
Por sua vez, o VHDL não funciona dessa maneira: têm-se a capacidade de executar um número 
(virtualmente) infinito de ações ao mesmo tempo. Isso é possível quando pensamos que fazemos um 
projeto de hardware com o VHDL, onde várias coisas acontecem paralelamente, ou seja, 
simultaneamente.
A figura 11 a seguir mostra um exemplo simples de um circuito que executa múltiplas ações 
simultaneamente. A qualquer momento que uma entrada mudar, há a possibilidade da saída também 
mudar, o que é verdade para todos circuitos digitais em geral.
 
Figura 11: Circuito que executa ações simultaneamente
Aqui está a complicação: como somos humanos, somos capazes apenas de ler uma linha do 
código por vez de uma maneira sequencial, então como podemos descrever alguma coisa que é 
inerentemente paralela? Esse problema não aparece quando se discute algo inerentemente sequencial, 
como um algoritmo em linguagem de programação comum.
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
O paradigma da programação em VHDL se concentra no conceito de paralelismo de expressões e 
simultaneidade de descrições textuais de circuitos. A alma do VHDL são as declarações simultâneas, que 
se assemelham a declarações em linguagens algorítmicas comuns mas são significativamente diferentes 
porque executam mais de uma ação ao mesmo tempo.
Para ilustrar, a figura 12 mostra o código que implementa o circuito da figura 11, que mostra 
quatro declarações de atribuição de sinal simultâneas (concurrent signal assignement statements). O 
símbolo "<=" é o operador de atribuição de sinal. A verdade é que não podemos escrever todas essas 
operações de uma só vez, mas devemos interpretá-las como se estivessem ocorrendo simultaneamente. 
Novamente, esse é o principal ponto a ser entendido até aqui. Se o pensamento algorítmico (sequencial) 
começar se sobressair, tente contê-lo imediatamente. A próxima seção trará mais detalhes sobre atribuição 
simultânea de sinais.
G <= A AND B;
H <= C AND D;
I <= E AND F;
J <= G OR H OR I;
Figura 12: Código VHDL para o circuito da figura 11.
A figura 13 mostra um código "C" que é similar ao código da figura 12. Nesse caso, as funções 
lógicas foram substituídas operadores matemáticos, e os operadores de atribuição de sinal por operadores 
de atribuição. Nesse código, cada linha é executada por vez, ao contrário do VHDL da figura 12. É 
importante ressaltar que a figura 13 NÃO é um código VHDL válido.
G = A + B;
H = C + D;
I = E + F;
J = G + H + I;
Figura 13: código algorítmico SIMILAR ao da figura 12 (não é VHDL).
O operador de atribuição de sinal "<="
Todas linguagens algorítmicas tem um tipo de operador de atribuição, por exemplo, Em "C" e 
Matlab, é o "=", enquanto em Pascal é ":=". Esses operadores indicam uma transferência de informações 
do lado direito para o lado esquerdo. Em VHDL, usa-se "<=", e é conhecido oficialmente como operador 
de atribuição de sinal, para deixar evidente o seu verdadeiro propósito. Ele especifica uma relação entre 
os sinais, ou seja, o sinal à esquerda do operador depende dos sinais à direitado mesmo.
Sendo assim, você já deve entender o código da figura 12 e sua relação com a figura 11. A 
declaração "G = A AND B;" indica que o valor do sinal "G" representa a operação AND, com entradas 
A e B. Já no caso da programação algorítmica, "G = A + B;" indica que o valor representado pela 
variável A é adicionado ao valor representado pela variável B e o resultado da adição é atribuído à 
variável G. A distinção entre as declarações deve estar ficando mais clara agora.
Há quatro tipos de declarações simultâneas que são examinadas nesse material. Já foi examinado 
brevemente a declaração simultânea de atribuição de sinal, e em breve ela será analisada mais a fundo e 
colocado no contexto de um circuito verdadeiro. Os outro três tipos de declarações simultâneas são 
declarações de processo, atribuição condicional de sinais e atribuição seletiva de sinais.
Os 4 tipos de declarações são ferramentas que podem ser utilizadas para implementar circuitos 
digitais, e em breve, veremos a versatilidade desses tipos de declaração. Entretanto, deve-se ter em mente 
que, devido à essa versatilidade, há diversas maneiras de lidar com um mesmo problema. Assim, quando 
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
se analisar um exemplo deste material, é importante saber que este corresponde a uma solução de um 
conjunto muito grande delas, então é uma boa prática tentar resolvê-los de outra maneira, como exercício.
Atribuições de sinal simultâneas
A forma geral de uma atribuição simultânea é apresentada na figura 14, onde target é um sinal 
que recebe o valor de expression, que pode ser uma constante, um sinal ou um conjunto de operadores 
que operam em outros sinais e retornam algum valor.
target <= expression;
Figura 14: sitaxe da declaração de atribuição simultânea de sinal
EXAMPLO 1
Escreva um código em VHDL para implementar uma porta lógica NAND de três entradas. As entradas 
devem ser nomeadas como A,B e C, e a saída como F.
Solução: é boa prática sempre desenhar o diagrama do que se está projetando. Poderíamos ter mostrado 
diretamente o sinal da porta lógica NAND, mas usaremos uma caixa preta para não perder a generalidade. 
Assim, a entidade já está praticamente declarada.
-- cabeçalho e bibliotecas
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity my_nand3 is -- define o nome da entidade
 port ( A,B,C : in std_logic; 
 F : out std_logic);
end my_nand3;
architecture ex_nand3 of my_nand3 is
begin
 F <= NOT (A AND B AND C);
--
-- Uma outra forma de se fazer:
-- F <= A NAND B NAND C;
--
end ex_nand3;
Figura 15: resolução do exemplo 1
Esse exemplo contém alguns detalhes que devem ser comentados:
• Deve-se inserir arquivos de cabeçalho (header files) e bibliotecas (library files) para que o código 
compile de maneira correta. As linhas que descrevem essa inserção estão descritas no topo do 
código da figura 15. As linhas aqui utilizadas possuem mais itens do que é necessário para este 
exemplo, mas alguns exemplos subsequentes precisarão de todas elas.
• O exemplo destaca o uso de diversos operadores lógicos. Os operadores disponíveis em VHDL 
são AND, OR, NAND, NOR, XOR e XNOR. O operador NOT não é tecnicamente lógico mas 
também está disponível.
O exemplo 1 demonstra o uso da declaração de atribuição de sinal simultânea em um programa 
VHDL, mas como só há uma declaração desse tipo, o conceito de simultaneidade não está evidente. A 
ideia por trás dessa declaração é que a saída muda sempre que um dos sinais de entrada mudar. Em outras 
palavras, a saída F é reavaliada sempre que um sinal na entrada muda. O exemplo a seguir ilustra melhor 
a ideia de simultaneidade.
EXEMPLO 2
Escreva um código em VHDL que implemente a função descrita na tabela verdade a seguir:
L M N F
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 0
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1
Solução: O primeiro passo no processo é reduzir a função dada. Apesar de não ser obrigatório, pode 
ajudar a diminuir o tempo usado para escrever o código VHDL. Espera-se que o compilador em 
reduziria o código à forma mínima em algum ponto, mas isso pode ser um desejo frustrado. O 
diagrama da caixa preta e o código VHDL associado são mostrados na figura 16.
F3L,M,N= L.M.N+ L.M
------------------------------------------------------------------------------------
-
-- cabeçalho e bibliotecas devem ser aqui inseridos: não o foram para poupar espaço
------------------------------------------------------------------------------------
-
entity my_ckt_f3 is
 port ( L,M,N : in std_logic;
 F3 : out std_logic);
end my_ckt_f3;
architecture f3_1 of my_ckt_f3 is
 signal A1, A2 : std_logic; -- sinais intermediários (estão dentro da caixa preta)
begin
 A1 <= ((NOT L) AND (NOT M) AND N);
 A2 <= L AND M;
 F3 <= A1 OR A2;
end f3_1;
Figura 16: solução do exemplo 2
Esse exemplo contém novos conceitos e ideias. É importante notar que as informações de 
cabeçalho e bibliotecas foram suprimidas, e isso vai acontecer em todos os exemplos subsequentes desse 
material. Então, para implementar os códigos de exemplos, deve-se sempre inserir o cabeçalho e as 
bibliotecas, como no exemplo 1. O mais importante, entretanto, é notar que esse código demonstra a 
utilização de declarações de sinal (abaixo da declaração da arquitetura), que são usadas para declarar 
sinais intermediários. Essa abordagem é análoga a declarar variáveis extras em linguagens de 
programação algorítmica, onde pode-se utilizá-las para salvar resultados intermediários que, no geral, não 
são o ponto de interesse de um determinado programa. A declaração desses sinais é feita de maneira 
análoga à declaração de ports na entidade. A figura 17 ilustra outra arquitetura que implementa a tabela-
verdade, onde não é necessário fazer a declaração desses sinais.
architecture f3_2 of my_ckt_f3 is
begin
 F3 <= ((NOT L) AND (NOT M) AND N) OR (L AND M);
end f3_2;
Figura 17: arquitetura alternativa à f3_1
Apesar de as arquiteturas f3_1 e f3_2 das figuras 16 e 17 serem diferentes, elas funcionam da 
mesma maneira. Isso porque todas as declarações são de atribuições simultâneas de sinal, porque, mesmo 
f3_1 tendo três declarações desse tipo e f3_2 apenas uma, as declarações em f3_1 são executadas 
simultaneamente.
O exemplo 2 demonstra que pode-se facilmente converter uma função em formato de tabela-
verdade para código VHDL. A conversão da função simplificada para declarações de atribuição 
simultâneas de sinal foi de certa forma bem direta. A facilidade para se implementar ambas as arquiteturas 
é quase a mesma, mas deve-se notar que o exemplo 2 é bem simples, tinha o objetivo de ilustrar as 
atribuições simultâneas de sinal. Para circuitos muito complexos, entretanto, essa abordagem fica tediosa, 
e uma alternativa é mostrada na seção a seguir.
Atribuição condicional de sinal
As declarações de atribuição simultânea relacionam um alvo com uma expressão. O termo 
atribuição condicional de sinal é usado para descrever declarações que tenham apenas um alvo mas 
Engenheiro
Realce
Engenheiro
Realce
podem ter diversas expressões associadas, cada qual com uma determinada condição. Cada condição é 
avaliada sequencialmente até a primeira delas ser verdadeira (TRUE), onde a expressão associada a esta 
condição é avaliada e atribuída ao alvo. Apenas uma atribuição é usada.
A sintaxe de atribuição condicional de sinal é mostrada abaixo. O alvo nesse caso é o 
identificador de um sinal, e a condição é baseada no estado de outros sinais no circuito. É importante 
notar quehá apenas um operador de atribuição de sinal ("<=") com a declaração de atribuição 
condicional.
target <= expression when condition else
 expression when condition else
expression;
Figura 18: sintaxe da declaração de atribuição condicional de sinal
Essa é talvez a forma mais fácil de entender no contexto de um circuito. Por exemplo, pode-se 
refazer o exemplo 2 usando a atribuição condicional de sinal:
EXEMPLO 3
Escreva um código em VHDL que implemente a função descrita na tabela verdade a seguir:
L M N F
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 0
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1
Solução: A entidade não muda do exemplo 2, então a resposta será simplificada como apenas a 
arquitetura.
architecture f3_3 of my_ckt_f3 is
begin
 F3 <= ‘1’ when (L = ‘0’ AND M = ‘0’ AND N = ‘1’) else
 ‘1’ when (L = ‘1’ AND M = ‘1’) else
 ‘0’;
end f3_3;
Figura 19: Solução do exemplo 3
Alguns pontos interessantes:
• Essa arquitetura parece dar mais trabalho que as anteriores, por ter mais entradas.
• De fato, percebe-se que há apenas um alvo e diversas condições e expressões. A última expressão 
é a exceção às outras, ou seja, ela só é executada se nenhuma outra for TRUE.
Há razões mais fortes para se utilizar a atribuição condicional de sinal, e a mais clássica é a 
implementação de um multiplexador (MUX), descrita no exemplo a seguir.
EXEMPLO 4
Escreva um código VHDL que implemente um multiplexador 4:1 usando uma única declaração de atribuição 
condicional de sinal. As entradas devem ser os dados D3, D2, D1, D0 e um bus de controle de duas entradas SEL. 
A saída deve ser única, e MX_OUT.
Solução: Nesse exemplo deve-se recomeçar a descrição do problema. Isso incluí o diagrama de caixa 
preta e a entidade associada. A figura 20 mostra a solução completa.
-----------------------------------------------------------------
--entidade e arquitetura do multiplexador 4:1 implementado usando
--atribuição condicional de sinal
--(não esquecer cabeçalho e bibliotecas se for compilar)
-----------------------------------------------------------------
entity my_4t1_mux is
 port ( D3,D2,D1,D0 : in std_logic;
 SEL : in std_logic_vector(1 downto 0);
 MX_OUT : out std_logic);
end my_4t1_mux;
architecture mux4t1 of my_4t1_mux is
begin
 MX_OUT <= D3 when (SEL = “11”) else
 D2 when (SEL = “10”) else
 D1 when (SEL = “01”) else
 D0 when (SEL = “00”) else
 ‘0’;
end mux4t1;
Figura 20: solução do exemplo 4: 4:1 MUX usando atribuição condicional de sinal
Pontos interessantes:
• A solução parece eficiente se comparada à quantidade de lógica que seria necessária caso fossem 
utilizadas atribuições simultâneas de sinal. Além disso, o código está bem legível.
• O operador relacional "=" é usado em conjunto com um bus de sinais. Nesse caso, os valores do 
bus SEL são acessados usando aspas, e não apóstrofes.
• Apenas para ser mais completo, foram incluídas todas as possibilidades do sinal SEL além de um 
else. Poderíamos ter mudado a linha contendo '0' para D0 e removido a linha associada à 
condição SEL = "00", sendo assim, um descrição mas elegante da solução.
É importante ressaltar que, sempre que se fazemos uma atribuição condicional de sinal, 
fisicamente temos um multiplexador implementado. Para fins de projeto, é muito importante ter 
consciência disso.
Engenheiro
Realce
Lembre-se que a atribuição condicional é um tipo de declaração simultânea, onde a declaração é 
executada sempre que ocorrer uma mudança nos sinais da condição. Esse fato se assemelha à declaração 
de atribuição simultânea, onde a declaração é executada sempre que um dos sinais à direita do operador 
<= muda.
A atribuição condicional de sinal é um pouco menos intuitiva que a atribuição simultânea, mas 
pode-se pensar nela de outra forma: ela se assemelha, em função, às construções if-else das linguagens de 
programação comuns. Essa relação será melhor explorada quando falarmos de declarações sequenciais.
Atribuição seletiva de sinal
A atribuição seletiva de sinal é a terceira forma de declarações simultâneas que será explorada. 
Essas declarações podem ter apenas um sinal alvo, e uma expressão determina em que são baseadas as 
escolhas. Isso ficará mais claro a seguir. A sintaxe desse tipo de declaração é mostrada abaixo.
with chooser_expression select
 target <= {expression when choices, }
 expression when choices;
Figura 21: sintaxe da atribuição seletiva de sinal
EXEMPLO 5
Escreva um código em VHDL que implemente a função descrita na tabela verdade a seguir, usando apenas a 
atribuição seletiva de sinal.
L M N F
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 0
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1
Solução: Esse é outra versão do exemplo 2. O diagrama de caixa preta e a declaração de entidade desse 
exemplo continuam as mesmas da figura 16, e a solução está na figura 22.
architecture f3_4 of my_ckt_f3 is
begin
 with ( (L = ’0’ AND M = ’0’ and N = ’1’) or
 (L = ’1’ AND M = ’1’) ) select
 F3 <= ‘1’ when ‘1’,
 ‘0’ when ‘0’,
 ‘0’ when others;
end f3_4;
Figura 22: solução ao exemplo 5
EXEMPLO 6
Escreva um código VHDL que implemente um multiplexador 4:1 usando uma única declaração de atribuição 
seletiva de sinal. As entradas devem ser os dados D3, D2, D1, D0 e um bus de controle de duas entradas SEL. A 
saída deve ser única, e MX_OUT.
Solução: Essa é uma repetição do exemplo 4, exceto que a atribuição deve ser seletiva, não condicional. 
A declaração de entidade não muda, mas ela é repetida na figura 23. O diagrama de caixa preta é o mesmo 
da figura 20, e não é repetido.
-----------------------------------------------------------------
-- Entidade e arquitetura do MUX 4:1 do exemplo 6
-- Adicionar cabeçalho e bibliotecas caso queira compilar
-----------------------------------------------------------------
entity my_4t1_mux is
 port ( D3,D2,D1,D0 : in std_logic;
 SEL : in std_logic_vector(1 downto 0);
 MX_OUT : out std_logic);
end my_4t1_mux;
architecture mux4t1_2 of my_4t1_mux is
begin
 with SEL select
 MX_OUT <= D3 when “11”,
 D2 when “10”,
 D1 when “01”,
 D0 when “00”,
 ‘0’ when others;
end mux4t1_2;
Figura 23: Solução do exemplo 6
Novamente, há pontos a se destacar no exemplo 6, listados abaixo:
• O código possui diversas semelhanças com o da solução do exemplo 4. A aparência geral é a 
mesma. Ambas as soluções são bem mais eficientes que se fosse usada atribuição simultânea de 
sinal de maneira direta.
• Ao invés de usar else, como na atribuição condicional, usa-se when others, para tratar dos casos 
não abordados pelas condições listadas.
• O circuito do exemplo é um MUX 4:1, onde cada possível condição da chooser_expression 
(figura 21) - expressão de escolha - tem uma expressão correspondente nas atribuições de sinal. 
Isso não é necessário, mas é essencial que haja uma linha com when others no final da 
declaração de atribuição seletiva.
EXEMPLO 7
Escreva um código VHDL que implemente o seguinte circuito, que contém um bus de entrada contendo 4 sinais e 
um de saída contendo 3 sinais. O bus de entrada, D_IN, representa um número binário de 4 bits, e o bus de saída, 
SZ_OUT, é usado para indicar a magnitude do número de entrada. A relação entre entrada e saída é mostrada na 
tabela abaixo. Use uma declaração seletiva de sinal na solução.
Margem de entrada de D_IN Valor de saída de SZ_OUT
0000 até 0011 100
0100 até 1001 010
1010 até 1111 001
Condição desconhecida 000
Solução:
-----------------------------------------------------------------
-- Um circuito decodificador para o exemplo 7, usandoatribuição
-- seletiva de sinal.
-- 
-- Adicionar cabeçalho e bibliotecas caso queira compilar
-----------------------------------------------------------------
entity my_ckt is
 port ( D_IN : in std_logic_vector(3 downto 0);
 SX_OUT : out std_logic_vector(2 downto 0));
end my_ckt;
architecture spec_dec of my_ckt is
begin
 with D_IN select
 SX_OUT <= “100” when “0000” | “0001” | “0010” | “0011”,
 “010” when “0100” | “0101” | “0110” | “0111”
 | “1000” | “1001”,
 “001” when “1010” | “1011” | “1100” | “1101”
 | “1110” | “1111”,
 “000” when others;
end spec_dec;
Figura 24: Solução do exemplo 7
O único comentário dessa solução é que a barra vertical é usada como um caractere de seleção na 
seção choices (figura 21) da declaração de atribuição seletiva de sinal. Isso aprimora a legibilidade do 
código.
É importante ressaltar novamente que a atribuição seletiva de sinal é outra forma de atribuição 
simultânea, o que se justifica porque sempre que a chooser_expression mudar, a atribuição seletiva será 
reavaliada.
Um último comentário sobre a solução do exemplo 7: ela é comparável à declaração switch ou 
case de linguagens algorítmicas de programação como "C" e Java no caso da primeira, e Matlab no caso 
da segunda. Isso será melhor explorado na seção de declarações sequenciais.
A declaração de processo
A declaração de processo é o último tipo de atribuição simultânea que será abordada, mas 
primeiro, é necessário dar alguns passos para trás e explorar outras definições e princípios de VHDL que 
não foram detalhados até este ponto. Lembre-se que há mais de mil maneiras de aprender alguma coisa, 
especialmente uma linguagem de programação, onde há diversas soluções para um mesmo problema. 
Portanto, optou-se aqui por detalhar esse tipo de declaração depois, para ficar mais claro.
Engenheiro
Realce
Arquiteturas comuns em VHDL
Como você deve se lembrar, a arquitetura do VHDL descreve a função de alguma entidade. A 
arquitetura é composta de duas partes: a seção de declaração, onde se nomeia a arquitetura, seguida de 
uma coleção de declarações simultâneas. Estudamos três tipos de declarações simultâneas até este ponto: 
atribuição de sinal simultânea, atribuição condicional de sinal e a atribuição seletiva de sinal.
Há três diferentes estilos para se escrever arquiteturas no VHDL. Elas são fluxo de dados, 
estrutural e comportamental. Geralmente, se introduz cada estilo individualmente, usando como exercício 
elaborar circuitos para cada um deles, o que é uma abordagem boa por ser simples, mas é um pouco 
inapropriada quando se fala de circuitos mais complexos, onde se utiliza uma mistura dos estilos de 
programação. É importante ter isso em mente na discussão que segue, onde o foco estará nos estilos de 
fluxo de dados e comportamental. A modelagem pelo estilo estrutural é essencialmente um método de 
combinar um conjunto de modelos. Por esse motivo, não tanto um método de modelagem quanto uma 
forma de interligar modelos previamente elaborados.
A arquitetura por fluxo de dados
Até este ponto, todos os exemplos deste material foram feitos utilizando o estilo de fluxo de 
dados. Esse estilo de arquitetura especifica um circuito como uma representação simultânea do fluxo dos 
dados que atravessam o circuito. Os circuitos são descritos mostrando-se a relação entre entrada e saída, 
utilizando os componentes existentes na linguagem VHDL (AND,OR,XOR,NOT,etc). As três formas de 
declarações simultâneas que detalhamos até agora são todas encontradas no estilo de fluxo de dados. Se 
você examinar alguns exemplos que fizemos até agora, poderá de fato ver como os dados fluem pelo 
circuito, pelas declarações de atribuição de sinal, que realmente descrevem como os dados dos sinais do 
lado direito do operador <= fluem para o lado esquerdo do mesmo.
O estilo de arquitetura de fluxo de dados tem seus pontos fortes e fracos. Ele possibilita a 
visualização do fluxo de dados no circuito por simples inspeção do código, além de ser possível fazer 
uma boa predição de como o circuito lógico seria montado fisicamente. Para circuitos mais complexos, 
entretanto, é vantajoso utilizar a modelagem pelo estilo comportamental.
O estilo comportamental de arquitetura
Em comparação com o estilo por fluxo de dados, o estilo comportamental não nos provém de 
detalhes de como o modelo é implementado em hardware, ou seja, o código VHDL escrito no estilo 
comportamental não necessariamente reflete como o circuito é implementado quando sintetizado. Ao 
contrário, ele descreve como as saídas reagem (ou se comportam) às entradas. O estilo comportamental é 
essencialmente a utilização da abordagem da caixa-preta para modelar os circuitos, onde efetivamente 
não se sabe o que acontece dentro da caixa, apenas se sabe a saída para cada entrada. A ferramenta de 
síntese do VHDL é o que decide como o circuito será descrito fisicamente.
Todo esse estilo está centrado na declaração de processo, quarto tipo de declaração simultânea 
sobre a qual será falado. Ele é significativamente diferente dos outros três tipos estudados até aqui. A 
maior diferença reside na abordagem de simultaneidade desse tipo de declaração, que é a grande 
dificuldade no aprendizado da declaração de processo.
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
A declaração de processo
Para compreender a declaração de processo, vamos primeiramente examinar as suas semelhanças 
com a declaração de atribuição simultânea de sinal, para depois detalharmos as diferenças entre esses dois 
tipos de declaração.
A figura 25 ilustra a sintaxe da declaração de processo. O mais importante de se notar é que o 
corpo da declaração de processo consiste de declarações sequenciais, como as utilizadas nas linguagens 
de programação usuais (C, Java, Pascal, etc). Essa é a principal diferença entre as declarações simultâneas 
de atribuição de sinal e as de processo, mas vamos focar agora nas semelhanças.
label: process(sensitivity_list)
begin
 {sequential_statements}
end process label;
Figura 25: sintaxe da declaração de processo
A seguir, a figura 26 mostra a declaração de entidade para uma função XOR, enquanto a figura 27 
mostra dois estilos de arquiteturas possíveis, um usando fluxo de dados e outro comportamental. A maior 
diferença reside na presença da declaração de processo no estilo comportamental.
Lembre-se que a declaração de atribuição simultânea de sinal na descrição por fluxo de dados 
opera da seguinte forma: a qualquer momento que houver uma mudança nos sinais listados à direita do 
operador <=, o sinal à esquerda será reavaliado. No caso da descrição comportamental da arquitetura, 
sempre que um sinal presente na sensitivity_list de uma declaração de processo mudar, todas as 
declarações sequenciais do processo serão reavaliadas. Ou seja, a avaliação do processo é controlada 
pelos sinais presentes na "lista de sensibilidade" do processo, enquanto para as atribuições de sinal, para 
qualquer mudança, é necessária reavaliação. Essas abordagens são essencialmente as mesmas, apenas 
com uma mudança significativa na sintaxe.
Neste ponto, pode ficar um tanto estranho. Mesmo que ambas as arquiteturas da figura 27 tenham 
exatamente a mesma atribuição de sinal (F <= A XOR B;), a execução dessa atribuição no modelo 
comportamental é controlada pelos sinais que aparecem na lista de sensibilidade do processo, enquanto 
para o fluxo de dados, a atribuição é executada sempre que houver mudança nos sinais A ou B. Aqui nota-
se uma diferença na funcionalidade de cada estilo.
entity my_xor_fun is
 port ( A,B : in std_logic;
 F : out std_logic);
endmy_xor_fun;
Figura 26: declaração de entidade para um circuito que implementa a função XOR
architecture my_xor_dataflow of my_xor_fun is
begin
 F <= A XOR B;
end my_xor_dataflow;
architecture my_xor_behavioral of my_xor_fun is
begin
xor_proc: process(A,B)
 begin
 F <= A XOR B;
 end process xor_proc;
end my_xor_behavioral;
Figura 27: Descrição da entidade my_xor_fun usando as descrições por fluxo de dados e comportamental.
A outra grande diferença entre as arquiteturas por fluxo de dados e comportamental reside no 
corpo da declaração de processo, que contém apenas declarações sequenciais. A seguir, mostramos alguns 
tipos dessas declarações.
Declarações sequenciais
O termo "declaração sequencial" vem do fato de as declarações dentro do corpo de um processo 
são executadas sequencialmente, ou seja, uma de cada vez. A execução das declarações sequenciais 
começa quando ocorre uma mudança em algum sinal contido na lista de sensibilidade do processo, e 
termina quando todas as declarações de dentro do processo forem executadas.
Há três tipos de declarações simultâneas com as quais trabalharemos. Com a primeira (atribuição 
de sinal), já estamos bem familiarizados, então não a discutiremos com muitos detalhes. As outras duas 
são if e case, provavelmente já discutidas em outra(s) disciplina(s) de programação algorítmica. Em 
VHDL, a estrutura e função das declarações if e case são exatamente as mesmas.
A declaração de atribuição de sinal
Nesse ponto, ficará mais claro porque sempre temos o cuidado de falar atribuição simultânea de 
sinal quando se trabalha com a descrição por fluxo de dados.
Sintaticamente, a atribuição de sinal em um processo e a atribuição simultânea de sinal são 
equivalentes. Entretanto, em um processo, todas as declarações são sequenciais, por isso há essa diferença 
na nomenclatura da declaração de atribuição de sinal. Por exemplo, na arquitetura por fluxo de dados da 
figura 27, a atribuição de sinal é do tipo simultânea, enquanto na arquitetura comportamental, a mesma 
atribuição de sinal é sequencial. As diferenças funcionais entre declarações simultâneas e sequenciais já 
foram discutidas na seção de declarações de processos.
Declaração IF
A declaração if é usada para criar um ramo no fluxo de execução de declarações sequenciais. 
Dependendo das condições listadas no corpo da declaração if, podem ser realizadas as instruções de um 
ou de outro (ou até mesmo de nenhum) ramo do código. A forma geral de uma declaração if é mostrada na 
figura 28.
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
Engenheiro
Realce
if (condition) then
 { sequence of statements }
elsif (condition) then
 { sequence of statements }
else
 { sequence of statements }
end if;
Figura 28: Sintaxe da declaração if
A ideia da declaração if deve ser familiar para você em duas olhadas. Primeiramente, sua forma e 
função são parecidas com a maioria das linguagens de programação algorítmicas; a sintaxe, entretanto, é 
um pouco diferente. Além disso, o if em VHDL é a declaração sequencial equivalente da declaração de 
atribuição condicional de sinal. Essas duas declarações tem essencialmente a mesma função, mas a 
declaração if é a declaração sequencial encontrada dentro de um processo, enquanto a declaração de 
atribuição condicional de sinal é uma forma de atribuição simultânea.
Pontos importantes da declaração if:
• Os parênteses usados ao redor da expressão de condição condition são opcionais, mas é bom 
incluí-los para ter uma melhor legibilidade do código.
• Cada declaração if ou elseif possui um then associado (traduzindo: "se ... então; "caso contrário, 
se ... então"). O último else não possui then associado.
• Como na figura 28, o else é uma expressão que abrange todas as exceções. Caso nenhuma das 
condições prévias for avaliada como verdadeira, a sequência de declarações associada ao último 
else é executada. Dessa forma, ao menos uma sequência de instruções presentes no corpo do if 
será executada.
• O último else, entretanto, é opcional. A não inclusão do mesmo pode implicar na não execução de 
nenhuma sequência de declarações do if.
EXAMPLO 8
Escreva um código em VHDL que implemente a seguinte função lógica usando uma declaração IF
FoutA,B,C= A.B.C+ B.C
Solução: Embora não seja dito diretamente na descrição do problema, o código deve ser feito utilizando a 
arquitetura comportamental, uma vez que deve ser usada uma declaração if. O código de solução é 
mostrado na figura 29, onde não é mostrado o diagrama de caixa-preta devido à simplicidade do 
problema.
entity my_ex_7 is
 port ( A,B,C : in std_logic;
 F_OUT : out std_logic);
end my_ex_7;
architecture dumb_example of my_ex_7 is
begin
 proc1: process(A,B,C)
 begin
 if (A = ‘1’ and B = ‘0’ and C = ‘0’) then
 F_OUT <= ‘1’;
 elsif (B = ‘1’ and C = ‘1’) then
 F_OUT <= ‘1’;
 else
 F_OUT <= ‘0’;
 end if;
 end process proc1;
end dumb_example;
Figura 29: Solução do exemplo 8
Essa provavelmente não é a melhor maneira de implementar a função lógica, mas serviu para 
ilustrar a declaração if. Outra possível arquitetura que soluciona o problema é mostrada na figura 30, 
enquanto o exemplo 9 apresenta um problema em que o uso da declaração if é mais adequada.
architecture bad_example of my_ex_7 is
begin
proc1: process(A,B,C)
 begin
 if (A = ‘0’ and B = ‘0’ and C = ‘0’) or
 (B = ‘1’ and C = ‘1’) then
 F_OUT <= ‘1’;
 else
 F_OUT <= ‘0’;
 end if;
 end process proc1;
end bad_example;
Figura 30: solução alternativa ao problema do exemplo 8
EXAMPLO 9
Escreva um código VHDL que implemente o MUX 8:1 mostrado abaixo. Utilize uma declaração if.
Solução: A figura 31 mostra uma possível solução para o problema.
entity mux_8t1 is
 port ( Data_in : in std_logic_vector (7 downto 0);
 SEL : in std_logic_vector (2 downto 0);
 F_CTRL : out std_logic);
end mux_8t1;
architecture my_8t1_mux of mux_8t1 is
begin
my_proc: process (Data_in,SEL)
 begin
 if (SEL = “111”) then F_CTRL <= Data_in(7);
 elsif (SEL = “110”) then F_CTRL <= Data_in(6);
 elsif (SEL = “101”) then F_CTRL <= Data_in(5);
 elsif (SEL = “100”) then F_CTRL <= Data_in(4);
 elsif (SEL = “011”) then F_CTRL <= Data_in(3);
 elsif (SEL = “010”) then F_CTRL <= Data_in(2);
 elsif (SEL = “001”) then F_CTRL <= Data_in(1);
 elsif (SEL = “000”) then F_CTRL <= Data_in(0);
 else F_CTRL <= ‘0’;
 end if;
 end process my_proc;
end my_8t1_mux;
Figura 31: Solução ao problema do exemplo 9
EXAMPLO 10
Escreva um código VHDL que implemente o MUX 8:1 mostrado abaixo, utilizando quantas 
declarações if forem necessárias. No diagrama de caixa preta abaixo, a entrada CE é um "chip enable", 
ou seja, quando essa entrada for "1", a saída será como a do MUX do exemplo 9, e quando for "0", a 
saído do MUX é "0".
Solução: A solução para o exemplo 10 é similar à do exemplo 9. Note que nessa solução as declarações if 
podem ser aninhadas (colocadas umas dentro das outras) para melhorar o código. A figura 32 exibe a 
solução do exemplo 10.
Figura 32: Solução ao problema do exemplo 10
Declarações CASE
A declaração case é de certa forma similar à declaração if no sentido que uma sequência de 
declarações é executada quando sua expressão associada for verdadeira. A figura 33 abaixo ilustra a 
sintaxe da declaração case.
case (expression) is
 when choices =>
 {sequential statements}
 when choices =>
 {sequential statements}when others =>
 {sequential statements}
end case;
Figura 33: Sintaxe da declaração case
Como no caso da declaração if, a case deve estar familiar em poucas olhadas. Primeiramente, 
pode ser considerada uma forma diferente e talvez mais compacta do if, não sendo, entretanto, tão 
funcional quanto. Além disso, o case também é utilizado em outras linguagens de programação, com 
muitas similaridades em formato e função. Finalmente, o case em VHDL é a declaração sequencial 
equivalente à da atribuição seletiva de sinal, que é um tipo de atribuição simultânea. A linha " when 
others " não é necessária, mas é uma boa prática incluí-la para trabalhar com situações inesperadas.
A seguir, um exemplo de como se usar a declaração case.
EXEMPLO 11
Escreva um código em VHDL que implemente a seguinte função usando uma declaração case
Fout(A,B,C) = A.B.C + B.C
Solução: Novamente, este exemplo cai na categoria de não ser a melhor forma de implementar o circuito 
usando o VHDL. Entretanto, ele ilustra o uso da declaração case, outra ferramenta importante em VHDL. 
A primeira parte da solução requere que listemos a função como uma soma de mintermos. Se este assunto 
ainda não foi abordado em sala, não se preocupe: apenas tenha em mente que a seguinte simplificação 
ajuda a resolver este problema, e, em breve, este assunto será detalhado em sala. De forma simplificada, 
multiplica-se o produto que não possui termo com A por 1, no caso, A+A. Assim, teremos a função lógica 
como uma soma de produtos, sendo que cada produto possui todas as variáveis inclusas uma única vez: 
Fout(A,B,C) = A.B.C + A.B.C+A.B.C.
A segunda parte da solução é mostrada na figura 34, onde é interessante notar que o agrupamento 
dos três sinais de entrada nos possibilitou utilizar uma declaração case como solução. Essa abordagem 
demandou a definição de um sinal intermediário "ABC". Vale ressaltar que essa provavelmente não é a 
forma mais eficiente de solucionar este problema.
entity my_example is
 port ( A,B,C : in std_logic;
 F_OUT : out std_logic);
end my_example;
architecture my_soln_exam of my_example is
 signal ABC: std_logic_vector(2 downto 0);
begin
 ABC <= (A,B,C); -- Agrupa os sinais para usar o case
my_proc: process (ABC)
 begin
 case (ABC) is
 when “100” => F_OUT <= ‘1’;
 when “011” => F_OUT <= ‘1’;
 when “111” => F_OUT <= ‘1’;
 when others => F_OUT <= ‘0’;
 end case;
 end process my_proc;
end my_soln_exam;
Figura 34: Solução para o exemplo 11
A seguir, refazemos o exemplo 10, mas usando o case. Note a mudança quanto à legibilidade.
EXEMPLO 12
Escreva um código com VHDL que implemente o MUX 8:1 mostrado abaixo, utilizando uma 
declaração case. No diagrama de caixa preta abaixo, a entrada CE é um "chip enable", ou seja, quando 
ela for "1", o chip está ligado e a saída é a de um MUX normal; quando for "0", o chip está desativado 
e a saída é "0".
Solução: A solução é mostrada abaixo, na figura 35. A declaração de entidade foi repetida para sua 
conveniência. A solução insere o case dentro de uma declaração if. Caso ainda não esteja claro, o número 
de possíveis soluções para um problema aumenta com a complexidade do mesmo.
entity mux_8t1_ce is
 port ( Data_in : in std_logic_vector (7 downto 0);
 SEL : in std_logic_vector (2 downto 0);
 CE : in std_logic;
 F_CTRL : out std_logic);
end mux_8t1_ce;
architecture my_case_ex of mux_8t1_ce is
begin
 my_proc: process (SEL,Data_in,CE)
 begin
 if (CE = ‘1’) then
 case (SEL) is
 when “000” => F_CTRL <= Data_in(0);
 when “001” => F_CTRL <= Data_in(1);
 when “010” => F_CTRL <= Data_in(2);
 when “011” => F_CTRL <= Data_in(3);
 when “100” => F_CTRL <= Data_in(4);
 when “101” => F_CTRL <= Data_in(5);
 when “110” => F_CTRL <= Data_in(6);
 when “111” => F_CTRL <= Data_in(7);
 when others => F_CTRL <= ‘0’;
 end case;
 else
 F_OUT <= ‘0’;
 end if;
 end process my_proc;
end my_case_ex;
Loop FOR
Como em outras linguagens de programação, o loop for é usado quando o programador sabe o 
número de iterações que o loop irá realizar. Geralmente, declara-se o intervalo sobre o qual serão 
realizadas as iterações. Esse intervalo pode ser descrito de duas formas: a) o intervalo pode ser 
especificado na declaração do loop for ou b) o loop pode usar um intervalo definido anteriormente. 
Algumas observações devem ser feitas a respeito da variável de indexação para evitar futuros 
erros ao se compilar o código:
• A varável de indexação não precisa ser declarada.
• A variável de indexação não pode ser usada em atribuições. Porém, ela pode ser usada para cálculos dentro 
do loop.
• A variável de indexação só é incrementada no loop em passos de um.
• Como mostrado na figura anterior, o comando downto pode ser usado para declarar o intervalo da iteração.
Loops WHILE
Loops while não possuem uma variável de indexação e são, portanto, considerados mais simples 
de se trabalhar do que os loops for. A principal diferença entre os loops for e while é o fato de a estrutura 
do loop while não conter um critério de parada já embutido, como ocorre com o loop for. Ainda assim, o 
código associado ao loop while deve conter algum critério para que o loop termine. Na figura abaixo, há 
alguns exemplos:
Figura 35: Loops for equivalentes que em a) especifica o intervalo e em b) usa um intervalo especificado 
anteriormente.
Figura 36: Dois exemplos para o cálculo da sequência Fibonacci usando while.
Declarações NEXT e EXIT
A declaração next permite que o loop ignora as instruções restantes da linha de comando e inicie a 
próxima iteração. 
A declaração exit implica no término imediato da iteração:
Figura 37: Exemplos da declaração next em loops for e while.
Figura 38: Exemplos da declaração exit em loops for e while.
Operadores
Esta seção irá apresentar listagem dos principais operadores usados em VHDL. Serão apresentados alguns 
operadores lógicos, relacionais, de troca, de adição, de incremento, de multiplicação e outros que não se 
encaixam nos anteriores. Essa ordem na qual foram listados, é a ordem de prioridade a partir da qual os 
operadores serão analisados.
Essa prioridade só existe entre os tipos de operadores. Em uma mesma classe de operadores, não 
existe diferença de prioridade; essa, se existir, deve ser indicada pelo uso de parênteses. Abaixo segue 
uma tabela com os operadores mais comuns usados em VHDL:
Tipos de operadores
Lógicos and or nand nor xor xnor not
Relacionais = /= < <= > >=
Troca s11 sr1 s1a sra ro1 ror
Adição + -
Sinal + -
Multiplicação * / abs rem
Outros ** abs &
Operadores lógicos
São auto-explicativos: utilizados para realizar as operações lógicas entre os sinais.
Operadores relacionais
Os operadores relacionais irão relacionar variáveis de diversas formas. Alguns deles já foram 
utilizados em exemplos anteriores e uma lista com a função de cada um segue abaixo:
Operador Nome Explicação
= Equivalência O valor x é equivalente ao valor y?
/= Não – equivalência O valor x é não-equivalente ao valor y?
< Menor que O valor x é menor que o valor y?
<= Menor ou igual a O valor x é menor ou igual ao valor y?
> Maior O valor x é maior que o valor y?
>= Maior ou igual a O valor x é maior ou igual ao valor y?
Operadores de troca
Há três tipos de operadores de troca: troca simples, troca aritmética e rotação. A função desses 
operadores é basicamente acrescentar zeros à palavra binária em alguma ordem, seja da direita pra 
esquerda, ou da direita pra esquerda. As poucas diferenças entre eles podem ser vistas abaixo:
• Operadores de troca simples: acrescentam zeros à palavrabinária em uma determinada ordem, 
dependendo do comando utilizado. O operador ssl (shift left) acrescenta zeros da direita pra 
esquerda e o operador ssr (shift right), da esquerda para direita. Exemplo: tomando a palavra 
“110111” iremos realizar as duas operações em cima dela:
result <= “110111” ssl 2
“011100”
Nesse caso, acrescentam- se dois zeros no final da 
palavra binária, fazendo com que os outros bits se 
desloquem para a esquerda.
result <= “110111” ssr 3
“000110”
Nesse caso, acrescentam- se três zeros no 
início da palavra binária, fazendo com que os outros 
bits se desloquem para a direita.
• Operadores de troca aritmética: fazem a mesma operação dos operadores de troca simples com a 
diferença de que os bits mais significativos (bits de sinal) não são alterados. O comando sla (shift 
left arithmetic) é equivalente ao ssl e o comando slr (shift left arithmetic) é equivalente ao ssr. Ou 
seja, :
result <= “110011” sla 2
“101100”
Nesse caso, acrescentam- se dois zeros no final da 
palavra binária, fazendo com que os outros bits se 
desloquem para a esquerda, sem que o bit de sinal 
seja alterado.
result <= “110011” slr 3
“100010”
Nesse caso, acrescentam- se três zeros no início da 
palavra binária, fazendo com que os outros bits se 
desloquem para a direita, sem que o bit de sinal seja 
alterado.
• Operadores de rotação: transportam uma quantidade de bits definida pelo usuário de uma das 
extremidades de uma palavra para sua outra extremidade. O comando rol (rotate left) transporta 
os bits da extremidade esquerda para a extremidade direita e o comando ror (rotate right) faz o 
contrário, transporta os bits da extremidade direita para a extremidade esquerda. Exemplos:
result <= “101000” rol 2
“010010”
Os dígitos “10” em negrito foram levados da 
extremidade esquerda para a direita pelo comando 
rol. 
result <= “101001” ror 2
“011010”
Os dígitos “01” em negrito foram levados da 
extremidade direita para a esquerda pelo comando 
ror.
Operadores de troca
Os outros operadores são geralmente utilizados para manipulação numérica, sendo alguns de 
utilidade bem óbvia. A lista abaixo segue com alguns detalhes desses operadores sendo que os operadores 
mod, rem e & serão um pouco mais detalhados.
Operador Nome Comentário
Adição + Adição Calcula a operação entre dois números.
- Subtração Calcula a operação entre dois números.
Sinal + Identidade Especifica o sinal de um número.
- Negação Especifica o sinal de um número.
Multiplicação * Multiplicação Calcula a operação entre dois números.
/ Divisão Calcula a operação entre dois números.
mod Módulo
rem Resto
Outros ** Exponenciação Calcula a operação entre dois números.
abs Valor absoluto Calcula o valor absoluto de um número.
& Concatenação
• Operador de concatenação (&): muito usado em circuitos digitais pois é possível atribuir ao valor 
de uma variável, o valor de outras variáveis concatenadas. Por exemplo:
signal A_val, B_val : std_logic_vector(3 downto 
0);
signal C_val, E_val : std_logic_vector(6 downto 
0);
signal D_val, F_val : std_logic_vector(8 downto 
0);
C_val <= A_val & “000”;
E_val <= “111” & B_val;
D_val <= “00001” & A_val;
F_val <= A_val & B_val & “0”;
Pelo código acima, concluimos o seguinte:
✗ “C_val” é um vetor de 7 posições. As quatro primeiras posições serão preenchidas pelas 
componentes do vetor “A_val” e as outras três por zeros (“000”);
✗ “E_val” é um vetor de 7 posições. As três primeiras posições serão preenchidas por uns 
(“111”) e as outras quatro pelas componentes do vetor “B_val”;
✗ “D_val” é um vetor de 9 posições. As cinco primeiras posições serão preenchidas pelo 
conjunto de bits “0001” e as outras quatro pelas componentes do vetor “B_val”;
✗ “F_val” é um vetor de 9 posições. As quatro primeiras posições serão preenchidas pelas 
componentes do vetor “A_val”, as quatro seguintes pelas componentes do vetor “B_val”, 
e a última posição é preenchida por um zero.
• Operador de módulo (mod) e de resto (rem): esses dois operadores possuem definições muito 
específicas na linguagem. Suas definições e alguns exemplos são mostrados abaixo:
Operador Nome Definições Comentários
rem Resto (remainder) 1. (X rem Y) tem o mesmo sinal de X;
2. abs(X rem Y) < abs (X);
3. X = (X/Y)*X + (X rem Y).
mod Módulo 1. (X mod Y) tem o mesmo sinal de Y;
2. abs (X mod Y) < abs (Y);
3. X = Y*N + (X mod Y)
N é um valor inteiro
rem mod
8 rem 5 = 3
-8 rem 5 = 
-3
8 rem -5 = 3
-8 rem -5 = 
-3
8 mod 5 = 3
-8 mod 5 = 3
8 mod -5 = 
-3
-8 mod -5 = 
-3
Objetos de dados
Esta seção tem como objetivo explicar um pouco da teoria por trás da linguagem VHDL 
apresentando os objetos da linguagem. Objeto é um item da linguagem que possui um nome 
(identificador associado) e um tipo específico. Existem quatro tipos de objetos e diversos tipos de dados 
em VHDL. Alguns serão discutidos nesta seção.
Tipos de objetos de dados
- Declaração de objetos de dados
Como mencionado anteriormente, existem quatro tipos de objetos de dados: sinais (signals), 
variáveis (variables), constantes (constants) e arquivos (files). Serão apresentadas algumas informações 
sobre os três primeiros tipos de objetos, afim de melhorar o entendimento dos códigos implementados em 
laboratório. Os objetos do tipo files não serão detalhados.
Todos os três tipo de objetos que serão discutidos apresentam uma similaridade muito grande no 
modo como são declaradas. Abaixo apresentamos a forma como são declaradas sendo que as palavras 
reservadas do VHDL estão em negrito:
Objeto de dados Declaração
signal signal signal_name : signal_type := initial_value;
variable variable variable_name : variable_type := initial_value;
constant constant constant_name : constant_type := initial_value;
Em exemplos anteriores, essa forma de declaração já havia sido apresentada. É possível notar que 
todos os objetos acima listados podem começar com um valor inicial, e não somente a constante. Abaixo, 
alguns exemplos de declaração com alguns tipos que serão vistos mais adiante.
Objeto de dados Declaração
signal signal sig_var1 : std_logic := '0';
signal tmp_bus : std_logic_vector(3 downto 0) := “0011”;
variable variable my_var1,my_var2 : std_logic;
variable index_a : integer_range(0 to 255) := 0;
constant constant sel_var : std_logic_vector(2 downto 0) := “001”;
constant max_cnt : integer := 12;
- Variáveis e o operador de atribuição
Variáveis e sinais possuem características muito similares, mas variáveis não são tão funcionais 
uma vez que só podem ser declaradas dentro de funções, processos e procedimentos. Um dos erros mais 
comuns é usar uma variável fora de um processo.
O operador de atribuição de sinal “<=” é usado para transferir o valor de um sinal para outro 
quando se está trabalhando com objetos de dados do tipo signal. Quando se trata de variáveis, o operador 
de atribuição é “:=”.
- Sinais x Variáveis
Sinais e variáveis podem ser um pouco confusos porque são muito parecidos. Sinais, de forma 
geral, podem ser comparados com os “fios”ou algum outro tipo de conexão física no design de um 
circuito. Sinais também podem ser usados para ligar módulos dentro de uma interface VHDL, inclusive 
com os valores de entrada e saída. Uma diferença importante entre sinais e variáveis é que um valor pode 
ser previamente atribuído a um sinal; o que não ocorre com a variável.
Variáveis deveriam ser usadas principalmente como contadores em iterações ou como valores 
temporários em um algoritmo que realize certos cálculos. Em outras situações elas deveriam ser evitadas 
pois elas não possuem a mesma capacidade de ligar módulos em uma interface, já que não possuem uma 
memória.
Tipos de dados
- Tipos de dados mais comumente usados
Existem inúmerostipos de dados em VHDL. Na tabela abaixo encontram-se os mais comuns, 
sendo que alguns já foram mencionados anteriormente ou já foram usados em alguns exemplos neste 
tutorial. Os tipos integer e std_logic serão um pouco mais detalhados em seguida.
Tipo Exemplo
std_logic signal my_sig : std_logic;
std_logic_vector signal busA : std_logic_vector(3 downto 0);
Boolean Variable my_test : boolean := false;
integer signal iter_cnt : integer := 0;
- Tipos integer
O uso dos tipos integer é geralmente em códigos de descrição de circuitos digitais mais 
complexos. A faixa de valores que esse tipo pode ter vai de [-231 a +231]. Outros tipos similares ao tipo 
integer são os tipos natural e positive, sendo que estes apresentam uma faixa de valores diferente. Esses 
valores podem ser variados pelo usuário, fazendo-se uso dos comandos type, range and to (ou downto). 
Apesar de não serem muito úteis nesse curso, alguns exemplos são mostrados abaixo:
- Tipos std_logic
O tipo bit é um dos tipos mais comuns em VHDL, mas muito limitado. Ele pode conter apenas os 
valores de '0' e '1'. Por isso, o tipo std_logic é mais usado do que o tipo bit, devido à sua versatilidade e à 
maior possibilidade de valores. O tipo std_logic é definido como um tipo enumerado e dois dos possíveis 
valores são, obviamente, '0' ou '1'. A definição completa é mostrada abaixo. Essa definição, porém, lista 
Figura 39: Exemplos de variação de algumas variáveis do tipo integer
std_ulogic, ao invés de std_logic. Isso se deve pois o tipo std_logic é uma versão “resolvida” do tipo 
std_ulogic. A definição de “resolução” vai além do esse tutorial propõe.
Os valores mais comuns, dos listados acima, são '0', '1', 'Z' e '-'. O valor de alta impedância 'Z' é 
particularmente interessante. O 'Z' é geralmente utilizado quando se lida com estruturas “bus”. Isso 
permite que um sinal ou conjunto de sinais passe a ter a possibilidade de ser conduzido por múltiplas 
fontes, sem a necessidade de gerar funções de “resolução”. Quando um sinal é "dirigido" ao seu estado de 
alta impedância, o sinal não é dirigido a partir dessa fonte e é efetivamente removido do circuito. E, 
finalmente, uma vez que os caracteres utilizados no tipo std_ulogic fazem parte da definição, devem ser 
usados como listados. Uso de letras minúsculas irá gerar um erro. 
Figura 40: Definição do tipo std_logic.
Uso de VHDL para circuitos sequenciais
Esta seção irá mostrar como descrever alguns circuitos sequenciais usando a linguagem. Será 
dada uma atenção maior ao modelo comportamental da linguagem, aplicado a alguns flip-flops D. Será 
dada uma atenção maior aos conceitos básicos desses flip-flops, o que irá ajudar na modelagem das 
máquinas de estado.
Elementos simples de armazenamento usando VHDL
O flip-flop consiste de um dispositivo com uma lógica enable, um sinal com um certo clock. O 
primeiro flip-flop com o qual iremos trabalhar é o flip-flop tipo D mostrado abaixo:
O código que descreve o comportamento do flip-flop acima pode ser dado por:
Algumas observações a respeito do código acima:
• Como nós usamos um modelo comportamental, a arquitetura é composta principalmente de uma 
instrução process. As instruções dentro de process são executadas sequencialmente. Sempre que 
Figura 41: Flip-flop D.
Figura 42: Definição do flip-flop D.
uma mudança é detectada em qualquer um dos sinais na lista de sensitividade de process, essa 
instrução é executada. Neste caso, as instruções dentro de process são executadas cada vez que há 
mudança no nível lógico de D ou do Clock.
• A contrução rising_edge() é usada na instrução if para indicar que as mudanças na saída só 
ocorrem na subida do Clock. rising_edge é uma função já definida em uma das bibliotecas já 
incluídas na linguagem. 
• Para melhor entendimento, o processo foi nomeado: process dff.
A maior utilidade de um flip-flop é a sua função de “memória”. Pois, esse dispositivo mantém o 
bit anterior na saída caso não haja alteração na entrada. Isso está implícito no código quando não coloca-
se nenhuma condição ao if. Ou seja, a saída Q só será alterada caso a condição do if seja satisfeita.
O próximo exemplo é um outro flip-flop, mas agora com um enable., ou seja, uma entrada que 
liga/desliga o dispositivo:
O código que descreve o comportamento do flip-flop acima pode ser dado por:
Figura 43: Flip-flop com Set.
Algumas observações a respeito do código acima:
• Pelo código acima, podemos perceber que o dispositivo só funciona caso a entrada S seja '1'. 
Caso contrário, a saída será sempre '0'. 
O exemplo agora é um outro flip-flop tipo D, mas com um botão de Reset (R). O esquema do 
dispositivo pode ser visto abaixo:
O código que descreve o comportamento do flip-flop acima pode ser dado por:
Figura 44: Definição do flip-flop D com Set.
Figura 45: Flip-flop D com Reset.
Algumas observações a respeito do código acima:
• Pelo código acima, podemos perceber que o Reset, diferentemente do Set, não depende do Clock 
e tem prioridade sobre ele. O flip-flop só irá funcionar se o R for '1'.
Figura 46: Definição do flip-flop D com Reset.
Design de máquinas de estado com VHDL
Máquinas de estado (ME's) são geralmente usadas como controladores em circuitos digitais. Para 
projetar ME's em hardware, o primeiro passo (e facilitador do processo) é aprender a modela-las usando 
VHDL. Essa modelagem é uma continuidade das técnicas usadas na seção anterior, sobre circuitos 
sequenciais.
O diagrama de blocos da figura 47 traz um modelo padrão de uma máquina de estado de Moore. 
O bloco Next State Decoder é um bloco de lógica combinatória que usa as entradas externas atuais e o 
estado atual da ME para decidir o próximo estado da máquina. Em outras palavras, as entradas desse 
bloco são decodificadas e produzem uma saída correspondente ao próximo estado da ME. O próximo 
estado se torna o estado atual quando o clock na entrada do bloco State Registers torna-se ativo. O bloco 
State Registers contém elementos de armazenamento que armazenam o estado atual da máquina. As 
entradas do bloco Output Decoder são usadas para gerar as saídas externas desejadas. Esse bloco é 
constituido de circuitos combinatórios, que irão gerar as saídas desejadas. Como as saídas externas 
dependem apenas do estado atual da máquina, ela é classificada como máquina de Moore.
A versatilidade da linguagem irá nos permitir descrever máquinas de estado de forma mais 
simples do que quando o mesmo é feito em papel. Há muitas formas de descrever uma máquina de estado 
em VHDL. A abordagem utilizada nesta apostila é parcialmente descrita pelo diagrama de blocos da 
figura 48.
Figura 47: Diagrama de blocos de uma máquina de estado de Moore.
Figura 48: Modelo para implementação em VHDL das máquinas de estado.
A abordagem que usaremos divide a máquina de estado em dois processos em VHDL. O primeiro 
processo, o processo síncrono (synchronous process), engloba tudo que se refere a clock e outros 
controles associados a elementos de armazenamento. O outro processo, o processo combinatório 
(combinatorial process), engloba todos os elementos dos blocos Next State Decoder e Output Decoder, 
mostrados no diagrama da figura 40. Ou seja, esse último processo contém todos os circuitos 
combinatórios da máquina.
As entradas denominadas parallel inputs são entradas que agem em paralelo aos elementos 
armazenadores. Essas entradas incluem enables, resets, sets, clear, etc.. As entradas denominadas state 
transition inputs incluem entradas externas que controlam as transições de estado.
EXEMPLO 13: Escrever o código VHDL que descreve a máquina de estado abaixo.
Solução: Este problema representa uma implementação básica de uma máquina de estado.

Outros materiais

Materiais relacionados

Perguntas relacionadas

Materiais recentes

Perguntas Recentes