VHDL
VHDL ou "VHSIC Hardware Description Language" (Linguagem de descrição de hardware VHSIC "Very High Speed Integrated Circuits") é uma linguagem usada para facilitar o design (projeto/concepção) de circuitos digitais em CPLDs, FPGAs e ASICs.
História
[editar | editar código-fonte]A linguagem VHDL foi originalmente desenvolvida sob o comando do Departamento de Defesa (DoD) dos Estados Unidos (DARPA), em meados da década de 1980, para documentar o comportamento de ASICs que compunham os equipamentos vendidos às Forças Armadas americanas. Isto quer dizer que a linguagem VHDL foi desenvolvida para substituir os complexos manuais que descreviam o funcionamento dos ASICs. Até aquele momento, a única metodologia largamente utilizada no projeto de circuitos era a criação através de diagramas esquemáticos. O problema com esta metodologia é o fato de que desenho tem menor portabilidade, são mais complexos para compreensão e são extremamente dependentes da ferramenta utilizada para produzi-los.
Uma vez que o projeto VHSIC era de alta prioridade militar e havia dezenas de fornecedores envolvidos, o DoD estava preocupado principalmente com as questões de portabilidade, documentação e compreensibilidade dos projetos. Cada um destes fornecedores atuava desenvolvendo partes dos projetos ou mesmo fornecendo componentes que viriam a se encaixar em outros sistemas maiores. Desta forma o DoD optou por buscar desenvolver uma linguagem que servisse como base para troca de informações sobre estes componentes e projetos. Uma linguagem que, independente do formato original do circuito, pudesse servir como uma descrição e documentação eficientes do circuito, possibilitando os mais diferentes fornecedores e participantes a entender o funcionamento das outras partes, padronizando a comunicação.
O desenvolvimento da VHDL serviu inicialmente aos propósitos de documentação do projeto VHSIC. Entretanto, nesta época buscava-se uma linguagem que facilitasse o projeto de um circuito; ou seja, a partir de uma descrição textual, um algoritmo, desenvolver o circuito, sem necessidade de especificar explicitamente as ligações entre componentes. A VHDL presta-se adequadamente a tais propósitos, podendo ser utilizada para as tarefas de documentação, descrição, síntese, simulação, teste, verificação formal e ainda compilação de software, em alguns casos.
Após o sucesso inicial do uso da VHDL, a sua definição foi posta em domínio público, o que levou a ser padronizada pelo IEEE (Institute of Electrical and Electronic Engineers) em 1987. O fato de ser padronizada e de domínio público ampliou ainda mais a sua utilização, novas alterações foram propostas, como é natural num processo de aprimoramento e a linguagem sofreu uma revisão e um novo padrão mais atualizado foi lançado em 1993. Pequenas alterações foram feitas em 2000 e 2002. Em setembro de 2008 foi aprovado pelo REVCOM a mais recente versão, IEEE 1076-2008.
Existe também ramificações desse padrão, a saber:
- IEEE 1076.1 VHDL analógica e de sinal misto
- IEEE 1076.1.1 VHDL-AMS pacotes padrão (stdpkgs)
- IEEE 1076.2 VHDL pacotes matemáticos (math)
- IEEE 1076.3 VHDL pacotes sintetizado (vhdlsynth)
- IEEE 1076.3 VHDL pacotes sintetizado - Ponto flutuante (fphdl)
- IEEE 1076.4 VHDL bibliotecas para ASIC: vital
- IEEE 1076.6 VHDL síntese de interoperabilidade
- IEEE 1164 VHDL pacote com multi valores lógicos (std_logic_1164)
Sintaxe
[editar | editar código-fonte]A linguagem VHDL não é case-sensitive e tem uma sintaxe similar às linguagens Pascal e da linguagem ADA.
Estrutura
[editar | editar código-fonte]Comentários
[editar | editar código-fonte]São iniciados com dois traços "--" e terminam no final da linha.
Entity
[editar | editar código-fonte]É a parte principal do projeto, é a interface do Sistema que descreve as entradas e saídas. Composta de duas partes: parameters e connections. Parameters refere-se aos parâmetros, exemplo largura de barramento, são declarados como generics. Connections por sua vez, refere-se como ocorre a transferência de informações, são declarados como ports.
O nome de uma entity deve identificar o sistema, podendo usar letras e números, porem deve iniciar por uma letra.
Exemplo de entity:
entity ORGATE is … end ORGATE;
Architecture
[editar | editar código-fonte]É o corpo do sistema, onde são feitas as atribuições, operações, comparações, etc…
Declarado como architecture nome of entidade is. Podem existir várias architecture para a mesma entity.
Exemplo de architecture:
architecture RTL of ANDGATE is begin … end RTL;
Process
[editar | editar código-fonte]Diretiva usada quando se quer fazer uma lista de operações a serem executadas. Implementada dentro de architecture. Possui forma estruturada.
Exemplo de process:
atrib : process begin A ⇐ X; B ⇐ Y; end process atrib;
Package
[editar | editar código-fonte]Usado quando precisa-se usar um comando que não existe nas bibliotecas padrão. Deve ser definido antes do inicio da entity. Para usar a package é necessário usar duas declarações: library use. O package mais conhecido é o STD_LOGIC_1164 da IEEE por conter a maioria dos comandos adicionais usados na linguagem.
Exemplo de package:
library IEEE; use IEEE.std_logic_1164.all;
Sinal
[editar | editar código-fonte]Transmite os dados internamente ou externamente ao sistema sendo que os sinais externos são definidos em entity e usam a diretiva ports, já os sinais internos são definidos em architecture e usam a diretiva signal.
Os sinais podem ser uma linha (bit) ou um barramento (bit_vector). No caso do bit_vector a ordem é de suma importância, sendo que o primeiro sinal é o mais significativo e o último o menos significativo. Estes dois tipos de sinais são nativos da linguagem VHDL, no entanto pode-se adicionar mais tipos, usando bibliotecas apropriadas. Com isso, teremos tipos como: 'U' (Não inicializado), 'X' (Força 0 ou 1), '0' (Força 0), '1' (Força 1), 'Z' (Alta Impedância), 'W' (0 ou 1 fraco), '-' (Não interessa).
Em ports tem que especificar a direção do sinal: entrada(in), saída (out) ou bidirecional (inout). Em signal não precisa especificar a direção devido ao fato do sinal ser interno.
Sendo assim, o exemplo a seguir define um port com dois vetores, sendo um vetor X (o bit10 é o sinal mais significativo e o bit0 o menos significativo) e um vetor Y(sendo o bit0 o sinal mais significativo e o bit5 o menos significativo).
port ( X : out bit_vector (10 downto 0); Y : inout bit_vector (0 to 5));
Já nesse exemplo definimos a e b como signal e ambos sendo bit.
signal a, b : bit;
Constantes
[editar | editar código-fonte]Servem para aumentar a legibilidade do código e facilitar a sua modificação.
CONSTANT <nome_da_constante> : <tipo> := <valor>;
Exemplo:
CONSTANT PI : REAL := 3.14; CONSTANT WIDTH : INTEGER := 8;
Variáveis
[editar | editar código-fonte]Usadas apenas em processos e subprogramas (funções e procedimentos), as variáveis usualmente não estão disponíveis para múltiplos componentes e processos. Todas as atribuições de variáveis tem efeito imediato.
VARIABLE <nome_variavel> : <tipo> [:= <valor>];
Exemplo:
VARIABLE opcode : BIT_VECTOR (3 DOWNTO 0) := "0000"; VARIABLE freq : INTEGER;
Operadores e Expressões
[editar | editar código-fonte]Operadores Lógicos
[editar | editar código-fonte]Os operadores and, or, nand, nor, xor e xnor exigem dois operandos, já o operador not exige apenas um operando.
Deslocamento
[editar | editar código-fonte]Restrito a vetores. Exige dois operandos, um sendo o array e o outro um integer, que é o número de posições a serem deslocadas.
As operações podem ser:
shift left logical (deslocamento lógico a esquerda);
shift right logical (deslocamento lógico a direita);
shift left arithmetic (deslocamento aritmético a esquerda);
shift right arithmetic (deslocamento aritmético a direita);
rotate left logical (rotacionamento lógico a esquerda);
rotate right logical (rotacionamento lógico a direita).
Operadores aritméticos
[editar | editar código-fonte]+ → soma ou identidade;
- → subtração ou negação;
* → multiplicação;
/ → divisão;
mod → módulo;
rem → resto da divisão;
abs → valor absoluto;
** → exponenciação.
Atribuição e comparações
[editar | editar código-fonte]<= → atribuição de valor para um sinal := → atribuição de valor para uma variável = → igual; /= → diferente; < → menor; <= → menor ou igual; > → maior; >= → maior ou igual;
After e Wait
[editar | editar código-fonte]After tem a finalidade de ativar o estado indicado depois de determinado tempo. Tem efeito apenas em simulação.
Exemplo de after:
x ⇐ '1' after 3s, '0' after 5s, '1' after 7s, '0' after 8s;
O resultado graficamente seria:
Já wait 'segura' o processo por determinado tempo.
Exemplo de wait:
x ⇐ '0'; wait for 2s; x ⇐ '1'; wait for 3s; x ⇐ '0'; wait for 1s;
O resultado graficamente seria:
Generic
[editar | editar código-fonte]Declarado na entity para definir os parâmetros da entidade. Composto pelo nome seguido de dois pontos, tipo de constante e valor precedido de :=. Seu escopo é sobre a entidade e suas arquiteturas.
Exemplo de generic:
generic SIZE : integer := 5;
Constant
[editar | editar código-fonte]Tem a mesma função de definir valores contantes. Se declarado em um pacote terá escopo sobre todo a entity que usa o pacote.
Exemplo de constant:
constant SIZE : integer := 5;
Controles condicionais
[editar | editar código-fonte]Existem cinco comandos condicionais: if then, if then else, case, for loop, next.
If Then
[editar | editar código-fonte]Será executado o que estiver dentro do bloco se a condição for verdadeira.
Exemplo de if then:
cmp : process begin if A /= B then C ⇐ B; end if; end process cmp;
If Then Else
[editar | editar código-fonte]Se a condição for verdadeira será executado o que estiver dentro de then, caso contrário será executado o que estiver dentro de else.
Exemplo de if then else:
cmp : process begin if A = B then C ⇐ 0; else C ⇐ 1; end if; end process cmp;
Case
[editar | editar código-fonte]Quando o teste de condição de uma variável poder assumir vários opções, é recomendado o uso do case.
Exemplo de case:
converte : process begin case Bin is when "0000" ⇒ Dec ⇐ 0; when "0001" ⇒ Dec ⇐ 1; when "0010" ⇒ Dec ⇐ 2; when "0011" ⇒ Dec ⇐ 3; when others ⇒ Dec ⇐ -1; end case; end process converte;
For Loop
[editar | editar código-fonte]Enquanto o contador estiver dentro da faixa especificada o loop é executado.
Exemplo de for loop:
conta : process begin for i in 5 downto 0 loop Num ⇐ Num + 1; end loop; end process conta;
Next
[editar | editar código-fonte]Quando se quer pular determinados comandos e ir diretamente para outro usa-se o comando next.
Exemplo de next:
soma : process begin aux : for i in 3 downto 0 loop Num ⇐ Num + X; if Num = 10 then Num ⇐ 0; next alfa; end if end loop aux; end process soma;
Test Bench
[editar | editar código-fonte]Testa o projeto (no Test Bench, o projeto é chamado de design ou Unit Under Test) através de sinais ou estímulos, monitorando suas respostas e com isso ter uma analise melhor do design. O Test Bench consiste em: um soquete para o UUT, um gerador de sinais e ferramentas para monitorar as suas respostas que por exemplo pode dizer se o circuito está ou não funcionando corretamente e sob quais aspectos estão ocorrendo os problemas. O design não geram circuitos, servindo apenas para a simulação.
Exemplo de Código VHDL
[editar | editar código-fonte]Código de uma porta lógica E.
-- importa std_logic da IEEE library library IEEE; use IEEE.std_logic_1164.all; -- Declara uma entidade entity ANDGATE is port ( IN1 : in std_logic; IN2 : in std_logic; OUT1: out std_logic); end ANDGATE; architecture RTL of ANDGATE is begin OUT1 ⇐ IN1 and IN2; end RTL;
O Uso da VHDL em Projetos de Circuitos
[editar | editar código-fonte]A VHDL, tal como outras linguagens seguem um fluxo de projeto bem definido, composto de sete etapas[carece de fontes], como apresenta a Figura 1: Especificação de Requisitos, Modelamento, Síntese de Alto Nível, Mapeamento Tecnológico, Implementação e ou Fabricação, Testes e Simulação. O tempo e o custo de cada etapa dentro de um projeto varia bastante, dependendo da tecnologia utilizada para implementar o sistema.
- Figura 1
- Ciclo de vida de um projeto
Durante a etapa de Especificação de Requisitos, o projetista e o usuário (em muitos casos podem ser a mesma pessoa), fazem um estudo e levantam todos os requisitos e características do sistema e definem o seu funcionamento. Características tais como atraso máximo permitido para as saídas, freqüência máxima de operação, consumo de potência, custo, temperatura de operação, tensão de alimentação são relacionadas a fim de buscar projetar um circuito que atenda a estes requisitos, que podem ser desejáveis ou necessários. Não é necessário especificar todas estas características, isso sempre dependerá de cada projeto. Esta fase é de extrema importância porque uma vez compreendido corretamente o funcionamento do sistema, evita-se a ocorrência de erros futuros. A cada unidade de tempo avançada no ciclo de projeto, maior o custo de correção de um erro e maior a dificuldade em encontrá-lo. Ou seja, além do prejuízo ser maior, maior também a probabilidade de que o erro passe despercebido e seja incluído na produção do sistema.
Na etapa de modelamento é que o projeto propriamente dito é iniciado. Baseado nas especificações da etapa inicial, o projetista irá escrever os modelos que representam o circuito. É de fundamental importância que o projetista tenha já um prévio conhecimento das ferramentas de software que utilizará no projeto e da tecnologia que irá utilizar, a fim de conduzir o modelamento a fim de obter os melhores resultados futuramente. Outras características importantes a serem incluídas nos modelos são: sempre que possível, de maneira a não afetar o desempenho e a portabilidade, escrever modelos que sigam o padrão estabelecido na linguagem, e não as extensões oferecidas pelos desenvolvedores das ferramentas de síntese; seguir um padrão de escrita de código uniforme para todos os modelos do projeto; documentar adequadamente os modelos, incluindo nome do autor, datas de manutenção, e comentários e explicações relevantes.
A Síntese de Alto Nível está para o hardware assim como a compilação está para o software. Na síntese, o modelo descrito será convertido para estruturas de dados representando as conexões, blocos, componentes e portas lógicas. Esta etapa é automática e dependente da ferramenta de software utilizada. Em geral, certos cuidados podem ser tomados durante o modelamento a fim de direcionar o algoritmo da síntese para que obtenha os melhores resultados para o circuito. Durante a síntese são pré-avaliados os requisitos do sistema a fim de indicar se o circuitos irá atendê-los adequadamente. Após a síntese ainda não está definido o circuito a ser implementado, a especificação intermediária que é resultante é ainda bastante genérica e pode ser direcionada para uma de muitas possibilidades de tecnologias de implementação.
Somente após o Mapeamento Tecnológico é que o circuito já está definido dentro da tecnologia em que será implementado. Fazendo uma analogia com o software, essa etapa corresponderia à geração de código executável que ocorre ao final da compilação de um código fonte. Só é possível entender essa etapa adequadamente conhecendo-se as diferentes tecnologias disponíveis no mercado, como full custom, gate array, FPGAs, entre outros. O projetista pouco consegue influir no mapeamento, especificando apenas os parâmetros de otimização desejados. A etapa de implementação/fabricação não há muito que ser explicada, nesse momento são criados os primeiros protótipos, avaliadas as condições finais, detalhes de produção entre outros detalhes de implementação final. Em seguida à fabricação, os circuitos são testados para que possam ser entregues ao usuário com garantia de isenção de falhas.
A Simulação é uma etapa auxiliar, mas de grande relevância no ciclo de vida do projeto. Simular consiste em avaliar o comportamento do circuito e validar o modelo produzido até aquele momento. Durante a simulação, são apresentados amostras de entradas possíveis ao modelo do circuito, e os valores das saídas, memórias e nós internos do circuito são analisados a fim de comparar com o esperado na especificação. A Simulação gera uma realimentação para os processos de modelamento, síntese e mapeamento, evitando a propagação de erros para etapas posteriores. Muitos dos problemas encontrados na simulação não estão necessariamente ligados a erros no projeto, mas ao não preenchimento dos requisitos necessários, principalmente no que se refere aos tempos do circuito (atraso, setup/hold, freqüência de operação).
Na simulação, um recurso muito interessante a ser utilizado são os test benches já comentados anteriormente.