Fundamentos

Posted on sex 18 setembro 2020 in vhdl • 8 min read

Nest post falaremos das características fundamentais da linguagem VHDL. Quando aplicável, usaremos para indicar quais versões de VHDL suportam cada característica.

Elementos Léxicos

VHDL não diferencia maiúsculas de minúsculas. Os arquivos são todos arquivos de texto e a especificação da linguagem admite apenas caracteres ASCII. No entanto, sugiro usar codificação UTF-8, limitando-se aos caracteres que também existem no ASCII, pois isso maximiza a compatibilidade com editores e ferramentas de síntese. A extensão do arquivo não importa muito, mas as mais comuns são .vhd e .vhdl (não use .v pois esta extensão é interpretada como Verilog pelas ferramentas).

Tome cuidado com acentos pois o código dos caracteres, mesmo em UTF-8, deve ser compatível com ASCII. Evite caracteres acentuados fora dos comentários.

Comentários

Os comentários são parte importantíssima em engenharia de software e não é diferente em engenharia de hardware. São muito úteis para descrever as intenções do projetista, de forma que outro projetista entenda o que foi descrito quando, posteriormente, ler o arquivo.

O comentário básico em VHDL é --. Após estes dois caracteres, todo o restante da linha se torna um comentário. Há também o comentário delimitado, que começa com /* e termina com */, útil para comentários multi-linhas. Os comentários não podem ser aninhados (comentário dentro de comentário), mas um comentário com -- no início da linha desativa qualquer delimitador de comentário.

Por motivos óbvios, os comentários não são sintetizáveis.

Os comentários com delimitadores /* */ são suportados a partir do VHDL-2008.

Exemplo (VHDL<=2002)

1
2
3
4
5
6
7
8
9
-- Este é um comentário explicando o que a entidade abaixo faz. Não há
-- comentários multi-linhas em VHDL<=2002, então usamos vários comentários
-- de uma linha.
entity meu_circuito is
  port ( clk: in bit; -- e o pulso ainda pulsa
         reset: in bit -- zera todo mundo!
         -- TODO: adicionar as outras portas
       );
end entity meu_circuito;

Exemplo (VHDL>=2008)

1
2
3
4
5
6
7
8
9
/* Este é um comentário explicando o que a entidade abaixo faz. Em
   VHDL>=2008 podemos usar comentários multi-linhas.
 */
entity meu_circuito is
  port ( clk: in bit; -- e o pulso ainda pulsa
         reset: in bit -- zera todo mundo!
         /* TODO: adicionar as outras portas */
       );
end entity meu_circuito;

Identificadores

Os identificadores são cadeias de caracteres usadas para dar nomes a variáveis, sinais e qualquer outro elemento da descrição. Em VHDL, o identificador pode ser uma cadeia de qualquer tamanho, desde que siga as seguintes restrições:

  • Deve conter somente letras (A-Z e a-z), dígitos (0-9) ou o caractere _
  • Deve começar com uma letra
  • Não deve terminar com um _ e não pode conter dois _ seguidos

Essas limitações existem para que seu identificador não entre em conflito com identificadores usados internamente pelas ferramentas.

Lembre-se que VHDL não diferencia maiúsculas de minúsculas, então `meu_sinal` é o mesmo que `MEU_SINAL` ou `MeU_sInAl`.

Exemplo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- Identificadores válidos
meu_sinal
entidadeSomadora
-- Identificadores inválidos
5bola -- não começa com uma letra
_meusinal -- não começa com uma letra
meusinal_ -- termina com _
meu__sinal -- possui dois _ seguidos
balbertini@usp -- possui um caractere inválido (@)
xo:xo -- possui um caractere inválido (:)
😊-- possui um caractere inválido (U+1F60A em UTF-8)
-- alguns sintetizadores aceitam o acento abaixo
-- mas melhor evitar
saída -- possui um caractere inválido (í)

Identificadores estendidos

VHDL também suporta o que chamamos de identificador estendido. Os identificadores estendidos não tem as limitações dos identificadores e pode-se usar qualquer coisa dentro deles. Para usar, basta colocar seu identificador entre dois \.

Exemplo

-- Identificadores estendidos válidos
\5bola\
\_meusinal\
\meusinal_\
\MeuSinal_\
\meu__sinal\
\balbertini@usp\
\xo:xo\
\😊\
\saída\

Quando usamos identificadores estendidos, a linguagem interpreta o identificador exatamente como ele é, então neste caso a linguagem diferencia maiúsculas de minúsculas.

Os identificadores estendidos foram criados para serem usados pelas ferramentas de síntese, facilitando a troca de informações. Não recomendamos que utilize em suas descrições pois nem todas as ferramentas o suportam.
Os identificadores estendidos são suportados a partir do VHDL-1993.

Palavras reservadas

Os comandos em VHDL são chamados de palavras reservadas. Todas tem um significado especial e devem ser evitadas como identificadores. A tabela abaixo tem uma lista de todas as palavras reservadas da linguagem, em ordem alfabética.

abs else map range unaffected
access elsif mod record units
after end register until
alias entity nand reject use
all exit new release
and next rem variable
architecture fairness nor report vmode
array file not restrict vprop
assert for null restrict_guarantee vunit
assume force return
assume_guarantee function of rol ror wait
attribute on when
generate open select while
begin generic or sequence with
block group others severity xnor
body guarded out shared xor
buffer signal
bus if package sla
impure parameter sll
case in port sra
component inertial postponed srl
configuration inout procedure strong
constant is process subtype
context property
cover label protected then
library pure to
default linkage transport
disconnect literal type
downto loop

Algumas dessas palavras não são consideradas palavras reservadas em algumas versões de VHDL, mas para manter a compatibilidade entre as versões, considere esta lista como uma lista de palavras que você não deve usar como identificadores.

Símbolos Especiais

A linguagem VHDL usa a seguinte lista de símbolos, cada um com um significado específico na linguagem:

" # & ' ( ) * + - , . / : ; < = > ? @ [ ] \` |

Além desses, há símbolos com um único significado em VHDL, mas composto de dois caracteres:

1
=> ** := /= >= <= <> ?? ?= ?/= ?> ?< ?>= ?<= << >>

Para funcionarem, você precisa escrevê-los sem nenhum espaço entre eles (e.g. <= é um operador de atribuição, mas < = são duas comparações, de menor e igual respectivamente). Nos próximos posts falarei sobre o significado de cada um destes operadores.

Literais

Números

Há dois tipos de literais numéricos em VHDL: os inteiros e os reais. Ambos podem ser expressos usando notação científica.

1
2
3
4
5
6
7
8
9
1 -- exemplo de número inteiro
0 -- exemplo de número inteiro
123 -- exemplo de número inteiro
12E12 -- exemplo de número inteiro em notação científica
123e45 -- exemplo de número inteiro em notação científica
123E+7 -- exemplo de número inteiro em notação científica
3.1415 -- exemplo de número real
6.67430E-11 -- exemplo de número real em notação científica
6.02214076E+23  -- exemplo de número real em notação científica

Note que -123 não é um número inteiro mas sim uma negação de um inteiro. Os número reais precisam de ao menos um dígito antes e outro depois do . para serem considerados válidos.

Os literais numéricos também podem ser especificados em outras bases usando o operador # com a base expressa em decimal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-- Todos os números abaixo representam 253 em decimal
2#11111101# -- em binário (base 2)
16#FD# -- em hexadecimal (base 16)
16#0fd# -- em hexadecimal (base 16)
8#0375# -- em octal (base 8)
-- Todos os números abaixo representam 0.5 em decimal
2#0.100# -- em binário (base 2)
8#0.4# -- em octal (base 8)
12#0.6# -- em duodecimal (base 12)
-- Todos os números abaixo representam 1024 em decimal
2#1#E10 -- em binário (base 2)
16#4#E2 -- em hexadecimal (base 16)
10#1024#E+00 -- em decimal (base 10)
VHDL suporta as bases de 2 a 16 nativamente, mas sugerimos ater-se às bases 2, 8 e 16 pois nem todas as ferramentas suportam bases arbitrárias.

Não há ponto (ou vírgula) de separação de milhares, mas é possível usar o caractere _ para melhorar e legibilidade dos literais numéricos, respeitando-se as regras de composição de identificadores (não se pode aparecer no início ou final de um número, e também não pode aparecer duas vezes seguidas):

1
2
3
123_456
3.141_592_6
2#1111_1100_0000_0000#

O caractere _ em um literal é inerte e não tem significado algum, servindo apenas para melhorar a visualização.

Caracteres

Os caracteres em VHDL são expressos entre aspas simples ' e podem ser qualquer caractere ASCII imprimível.

1
2
3
4
5
'A'
'a'
'.'
'1'
' ' -- espaço

Strings

As strings são vetores de caracteres e são representadas em VHDL entre aspas duplas ":

1
2
3
4
5
6
"Bruno Albertini"
"caracteres ASCII quaisquer como @%*"
"10010011"
-- abaixo uma string contendo o caractere ", que é representado por dois "
-- seguidos mas conta como um caractere só na string
""""

Bit Strings

Como todo hardware no final das contas trabalha com zeros e uns, VHDL possui uma forma específica para representar cadeias de bits. As cadeias são tratadas de forma diferenciada pois sempre podem ser transformadas em bits sem ambiguidade. É possível especificar a base da cadeia usando os prefixos B para binário, O para octal, X para hexadecimal e D para decimal (este último só existe a partir de VHDL-2008).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
B"0100011" -- uma bitstring em binário
B"10" -- outra  bitstring em binário
b"111100100001" -- é possível usar minúsculas na especificação
B"1111_0010_0001" -- e também _ para melhorar a legibilidade
B"" -- uma bitstring vazia
O"372" -- equivalente a B"011_111_010"
o"00" -- equivalente a B"000_000"
X"FA" -- equivalente a B"1111_1010"
x"0_d" -- equivalente a B"0000_1101"
-- O prefixo D é válido somente em VHDL>=2008
D"23" -- equivalente a B"10111"
D"64" -- equivalente a B"1000000"
D"0003" -- equivalente a B"11"

O número de bits da cadeia equivalente é sempre o número de bits mínimo necessário para representar o literal. Quando usamos octal, a cadeia resultante será um múltiplo de 3 bits pois cada dígito octal corresponde a 3 bits binários. Similarmente, as cadeias em hexadecimal correspondem a múltiplos de 4 bits binários. Os dígitos especificados devem ser válidos na base desejada (e.g. em octal só existem os dígitos de 0-7, em hexadecimal, de 0-9 e A-F (ou a-f)). Algumas letras tem significado especial dependendo do tipo binário por trás da conversão, como o Z que significa alta impedância quando se usa lógica multi-variada.

A lógica multi-variada em VHDL é baseada no tipo std_logic, que aceita U, X, Z, W, L, H e - como dígitos, além dos tradicionais 0 e 1.

Há ainda uma forma de controlar quantos bits queremos que a cadeia possua, que funciona com VHDL>=2008, colocando o número de bits antes do prefixo:

1
2
3
4
-- Só em VHDL>=2008
7X"3C" -- equivalente a B"0111100"
8O"5" -- equivalente a B"00000101"
10B"X" -- equivalente a B"000000000X"

A cadeia será preenchida com 0 suficientes para completar o número de bits. Caso o número desejado seja menor, os zeros à esquerda serão cortados da cadeia, mas é um erro especificar um número de bits menor que o necessário para representar o número.

Também podemos especificar se o número representa um inteiro com sinal ou sem sinal, adicionando os prefixos S e U respectivamente. Esta especificação só é possível em VHDL>=2008 e não pode ser usada para números decimais (especificador D), que são sempre considerados inteiros sem sinal.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-- Só em VHDL>=2008
7UX"3C" -- equivalente a B"0111100"
8UO"5" -- equivalente a B"00000101"
10UB"1" -- equivalente a B"0000000001"
10SX"71" -- equivalente a B"0001110001"
10SX"88" -- equivalente a B"1110001000"
10SX"W0" -- equivalente a B"WWWWWW0000"
-- Se reduzirmos o tamanho usando o especificador S
-- os bits descartados devem ser iguais ao último que ficou
6SX"16" -- equivalente a B"010110"
6SX"E8" -- equivalente a B"101000"
6SX"13" -- equivalente a B"110011"
6SX"H3" -- equivalente a B"HH0011"
As versões de VHDL<2008 não suportam o especificador decimal D, nenhum especificador de tamanho (os números no prefixo), e nenhum especificador de sinal (U ou S). Aconselho a evitá-los se deseja manter a compatibilidade da sua descrição com todas as ferramentas.