1
VHDL
–
VHSIC HARDWARE DESCRIPTION LANGUAGE
Tutorial 05 - VHDL
2
TUTORIAL 05
–
Circuitos Sequenciais
Os circuitos sequenciais são aqueles em que o estado lógico atual das saídas dependem do estado anterior de algumas saídas, além do estado lógico atual das entradas. Assim, as saídas de um circuito sequencial apresentam uma sequência de valores ou estados lógicos, sendo cada estado função do estado anterior e de outros sinais de entrada. Um exemplo típico de circuito sequencial é um contador, que apresenta em sua saída, a cada pulso de clock, um novo valor, que depende do valor de saída anterior (0, 1, 2, 3,...).
Isto não ocorre para os circuitos combinacionais, onde o estado lógico atual das saídas dependem exclusivamente do estado lógico atual das entradas, não importando qual valor havia na saída anteriormente. Um exemplo é um decodificador, que apresenta em sua saída um valor que depende apenas do valor atual de entrada.
Em VHDL, os circuitos sequenciais são descritos dentro de unidades específicas para este fim (PROCESS, FUNCTION e PROCEDURE).
O código utilizado para descrição de circuitos sequenciais é chamado de “código
sequencial”. Porém, é importante lembrar que um PROCESS como um todo, também
opera de forma concorrente com outros circuitos sequenciais ou combinacionais.
Outra observação importante é que, enquanto um código concorrente é utilizado apenas para projeto de circuitos combinacionais, um código sequêncial pode ser usado indistintamente para circuitos sequenciais ou cobinacionais .
A linguagem VHDL tem as seguintes declarações puramente sequenciais e que só podem ser utilizadas dentro de um PROCESS, FUNCTION OU PROCEDURE:
IF
WAIT
LOOP
CASE
Signal e Variable
Um ponto importante ao se trablhar com circuito sequêncial é entender as diferenças entre SIGNAL e VARIBLE.
As principais propriedades do SIGNAL são:
3
Um signal, quando utilizado dentro de um código sequencial, não é atualizado imediatamente (quando um novo valor é atribuído a um signal, este valor só será assumido ao final do PROCESS).
A atribuição de um valor a um signal em função da transição de valor de outro signal provoca a inferência de registro (flip-flop), caso este signal afete a entidade.
Apenas uma atribuição é permitida a um signal. Se mais atribuições forem realizadas apenas a última terá efeito.
As principais propriedades da VARABLE são:
Uma variable só pode ser declarada e utilizada dentro de um PROCESS ou subprograma. Se se tratar de um variable compartilhada (shared variable) ela pode ser declarada em qualquer parte mas só pode ser utilizada dentro de uma unidade sequencial.
Uma variable é atualizada imediatamente. Assim, o novo valor já pode ser utilizado ou testado na próxima linha de código.
A atribuição de um valor a uma variable em função da transição de valor de outro signal provoca a inferência de registro (flip-flop), caso o valor da variable afete um signal, que por sua vez afete a entidade.
Multiplas atribuições são aceitas pela variable.
Latches e Flip-Flops
Como flip-flops são indispensáveis na construção de circuitos sequenciais é importante relembrarmos as diferenças entre estes e os latches, que eventualmente também são utilizados.
A principal diferença entre latches e flip-flops é que os primeiros são sensíveis ao nível logico e os últimos sensíveis à transição (borda de subida ou descida).
4
Abaixo, vemos dois sinais de entrada (clock e D), aplicados a um latche sensível a nível alto. Observe que o sinal de entrada (D) é transparente à saída (Q) enquanto o clock está em nível alto, mantendo o último valor enquanto está o clock está nível baixo.
5 PROCESS
PROCESS é uma seção sequencial do código VHDL, localizada na parte de declarações da ARQUITECTURE. Dentro do PROCESS são aceitas apenas declarações sequenciais (IF, WAIT, LOOP, CASE). A sintaxe simplificada do PROCESS é mostrada abaixo.
[rótulo:] PROCESS [(lista_de_sensibilidade)] [IS]
[parte_declarativa]
BEGIN
código sequencial
END PROCESS [Rótulo];
O rótulo é opcional e serve apenas para facilitar a leitura do código. A lista de sensibilidade é obrigatória (exceto quando WAIT é utilizado) e causa a execução do processo toda vez que um sinal da lista muda.
Na parte declarativa do PROCEES podem ser declaradas variáveis, constantes, subprogramas (FUCTION e PROCEDURE), alias, atributos, clausulas, modelos de agrupamento, agrupamentos. Não se pode declarar um signal nesta parte do código.
Exemplo:
A declaração IF
A declaração IF é a mais comumente utilizada em códigos sequenciais. Uma sintaxe simplificada para IF é mostrada a seguir.
[rótulo] IF condições THEN
declarações;
ELSIF condições THEN
6 ...
ELSE
Declarações;
END IF [rotulo];
Exemplo de utilização da declaração IF para produzir um contador de 0 a 9:
Declaração WAIT
A declaração sequencial WAIT apresenta três formas, da quais duas são para síntese uma para simulação. Quando WAIT é empregado, o PROCESS não pode ter lista de sensibilidade. A sintaxe simplificada da declaração WAIT é um das três mostradas abaixo.
[rótulo:] WAIT UNTIL conditions;
[rótulo:] WAIT ON lista_de_sensibilidade;
7 WAIT UNTIL
Esta declaração faz com que o PROCESS ou subprograma espere até que a condição seja atendida. No exemplo abaixo, o PROCESS espera que haja uma borda de subida de clock para transferir o valor da entrada d à saída q.
Exemplo:
WAIT ON
Esta declaração faz com que o PROCESS ou subprograma espere até que qualquer sinal listado, mude. No exemplo abaixo, o PROCESS espera que haja uma mudança no sinal de clock para executar o processo.
Exemplo:
WAIT FOR
8 Declaração CASE
CASE é outra declaração sequencial, sendo aproximadamente equivalente à declaração sequencial SELECT, utilizada em código concorrente. A sintaxe simplificada da declaração CASE é mostrada abaixo.
[rótulo:] CASE expressão IS
WHEN valor => expressão de atribuição;
WHEN valor => expressão de atribuição;
...
END CASE;
Exemplo:
Como pode ser observado CASE permite o uso de múltiplos valores (ao invés de condições), os quais podem ser agrupados com “|” (significa “ou”) ou TO (para faixas).
A declaração CASE requer que todos os valores de entrada sejam cobertos (Tabela Verdade completa), assim a palavra OTHERS é sempre útil.
Observe que CASE permite múltiplas atribuições por teste, o que não ocorre com SELECT.
Outro exemplo:
9
Na versão 2008 do VHDL, SELECT também pode ser utilizado para código sequencial, mas, no momento, iremos utiliza-lo apenas para código concorrente.
Tarefa: Desenvolva um código em VHDL para a criação de um contador de 0 a 5 utilizando IF para testar a borda de subida do clock e em seguida utilizando WAIT .
Modifique o contador para opção de contagem crescente, decrescente, parado ou reset, utilizando CASE.
Declaração LOOP
A declaração LOOP faz com que um pedaço de código seja instanciado várias vezes. Isto é semelhante à declaração GENERATE utilizada em código concorrente.
A declaração LOOP pode ser incondicional, com FOR, com WHILE, com EXIT, e com NEXT. A sintaxe simplificada para estes cinco casos é mostrada abaixo.
LOOP incondicional:
[rótulo:] LOOP
código-sequencial
END LOOP [rótulo];
LOOP com FOR:
[rótulo:] FOR identificador IN faixa LOOP
código-sequencial
END LOOP [rótulo];
LOOP com WHILE:
[rótulo:] WHILE condição LOOP
código-sequencial
END LOOP [rótulo];
10 [rótulo_loop:] FOR identificador IN faixa LOOP
código-sequencial
[rótulo_saída:] EXIT [rótulo_loop][WHEN condição]
END LOOP [rótulo_loop];
LOOP com NEXT:
[rótulo_loop:] FOR identificador IN faixa LOOP
código-sequencial
[rótulo_next:] NEXT [rótulo_loop][WHEN condição]
END LOOP [rótulo_loop];
Na figura abaixo vemos um exemplo da utilização de LOOP com FOR.
Este código é equivalente ao coódigo abaixo, que não utiliza LOOP.