Projeto VLSI - Introdução ao Verilog
Verilog é uma LINGUAGEM DE DESCRIÇÃO DE HARDWARE (HDL). É uma linguagem usada para descrever um sistema digital como um switch de rede ou um microprocessador ou uma memória ou um flip-flop. Isso significa que, usando um HDL, podemos descrever qualquer hardware digital em qualquer nível. Os projetos, que são descritos em HDL, são independentes da tecnologia, muito fáceis de projetar e depurar e normalmente são mais úteis do que os esquemas, especialmente para grandes circuitos.
Verilog oferece suporte a projetos em vários níveis de abstração. Os três principais são -
- Nível comportamental
- Nível de transferência de registro
- Nível do portão
Nível comportamental
Este nível descreve um sistema por algoritmos concorrentes (comportamentais). Todo algoritmo é sequencial, o que significa que consiste em um conjunto de instruções que são executadas uma a uma. Funções, tarefas e blocos são os elementos principais. Não há consideração pela realização estrutural do projeto.
Nível de Registro-Transferência
Projetos usando o nível de transferência de registro especificam as características de um circuito usando operações e a transferência de dados entre os registros. A definição moderna de um código RTL é "Qualquer código sintetizável é chamado de código RTL".
Nível do portão
No nível lógico, as características de um sistema são descritas por links lógicos e suas propriedades de temporização. Todos os sinais são sinais discretos. Eles só podem ter valores lógicos definidos (`0 ',` 1', `X ',` Z`). As operações utilizáveis são primitivas lógicas predefinidas (portas básicas). A modelagem de nível de porta pode não ser uma ideia certa para o projeto lógico. O código de nível de portão é gerado usando ferramentas como ferramentas de síntese e sua netlist é usada para simulação de nível de portão e backend.
Tokens lexicais
Os arquivos de texto de origem do idioma Verilog são um fluxo de tokens lexicais. Um token consiste em um ou mais caracteres e cada caractere está em exatamente um token.
Os tokens lexicais básicos usados pelo Verilog HDL são semelhantes aos da linguagem de programação C. Verilog diferencia maiúsculas de minúsculas. Todas as palavras-chave estão em minúsculas.
Espaço em Branco
Os espaços em branco podem conter caracteres para espaços, tabulações, novas linhas e avanços de formulário. Esses caracteres são ignorados, exceto quando servem para separar tokens.
Os caracteres de espaço em branco são Espaço em branco, Tabulações, Retornos de carro, Nova linha e Avanços de formulário.
Comentários
Existem duas formas de representar os comentários
- 1) Comentários de linha única começam com o token // e terminam com retorno de carro.
Ex .: // esta é uma sintaxe de linha única
- 2) Os comentários de várias linhas começam com o token / * e terminam com o token * /
Ex .: / * esta é uma sintaxe multilinha * /
Números
Você pode especificar um número em formato binário, octal, decimal ou hexadecimal. Os números negativos são representados em números de complemento de 2. Verilog permite números inteiros, números reais e números com e sem sinal.
A sintaxe é fornecida por - <size> <radix> <value>
O tamanho ou número não dimensionado pode ser definido em <Size> e <radix> define se é binário, octal, hexadecimal ou decimal.
Identificadores
Identificador é o nome usado para definir o objeto, como uma função, módulo ou registro. Os identificadores devem começar com caracteres alfabéticos ou sublinhados. Ex. A_Z, a_z, _
Os identificadores são uma combinação de caracteres alfabéticos, numéricos, sublinhados e $. Eles podem ter até 1.024 caracteres.
Operadores
Operadores são caracteres especiais usados para colocar condições ou operar as variáveis. Existem um, dois e às vezes três caracteres usados para realizar operações em variáveis.
Ex. >, +, ~, &! =
Palavras-chave Verilog
Palavras que têm significado especial em Verilog são chamadas de palavras-chave Verilog. Por exemplo, atribua, caso, enquanto, fio, reg, e, ou, nand e módulo. Eles não devem ser usados como identificadores. Palavras-chave Verilog também incluem diretivas de compilador e tarefas e funções do sistema.
Modelagem de nível de portão
Verilog tem primitivas embutidas como portas lógicas, portas de transmissão e interruptores. Estes raramente são usados para trabalho de design, mas são usados no mundo da pós-síntese para modelagem de células ASIC / FPGA.
A modelagem de nível de portão exibe duas propriedades -
Drive strength- A força das portas de saída é definida pela força do drive. A saída é mais forte se houver uma conexão direta com a fonte. A força diminui se a conexão for por meio de um transistor condutor e, pelo menos, quando conectado por meio de um resistivo pull-up / down. A força da unidade geralmente não é especificada, caso em que a força é padronizada como forte1 e forte0.
Delays- Se os atrasos não forem especificados, as portas não terão atrasos de propagação; se dois atrasos forem especificados, o primeiro representa o atraso de subida e o segundo, o atraso de queda; se apenas um atraso for especificado, então ambos, aumento e queda são iguais. Atrasos podem ser ignorados na síntese.
Gate Primitivos
As portas lógicas básicas usando uma saída e muitas entradas são usadas em Verilog. GATE usa uma das palavras-chave - and, nand, or, nor, xor, xnor para uso em Verilog para N número de entradas e 1 saída.
Example:
Module gate()
Wire ot0;
Wire ot1;
Wire ot2;
Reg in0,in1,in2,in3;
Not U1(ot0,in0);
Xor U2(ot1,in1,in2,in3);
And U3(ot2, in2,in3,in0)
Transmission Gate Primitivos
As primitivas de porta de transmissão incluem buffers e inversores. Eles têm uma única entrada e uma ou mais saídas. Na sintaxe de instanciação de porta mostrada abaixo, GATE significa a palavra-chave buf ou NOT gate.
Exemplo: Not, buf, bufif0, bufif1, notif0, notif1
Inversor de saída não - n
Buf - buffer de saída n
Bufifo - buffer tristate, ativo baixo habilitar
Bufif1 - buffer tristate, ativo alto habilitar
Notifo - inversor tristate, habilitação baixa ativa
Notif1 - inversor tristate, habilitar alto ativo
Example:
Module gate()
Wire out0;
Wire out1;
Reg in0,in1;
Not U1(out0,in0);
Buf U2(out0,in0);
Tipos de dados
Conjunto de valores
Verilog consiste, principalmente, em quatro valores básicos. Todos os tipos de dados Verilog, que são usados em Verilog, armazenam esses valores -
0 (zero lógico ou condição falsa)
1 (lógica um ou condição verdadeira)
x (valor lógico desconhecido)
z (estado de alta impedância)
o uso de x e z é muito limitado para síntese.
Fio
Um fio é usado para representar um fio físico em um circuito e é usado para conexão de portas ou módulos. O valor de um fio só pode ser lido e não atribuído em uma função ou bloco. Um fio não pode armazenar valor, mas é sempre conduzido por uma instrução de atribuição contínua ou conectando o fio à saída de um portão / módulo. Outros tipos específicos de fios são -
Wand (wired-AND) - aqui o valor de Wand depende do AND lógico de todos os drivers de dispositivo conectados a ele.
Wor (wired-OR) - aqui o valor de um Wor depende do OR lógico de todos os drivers de dispositivo conectados a ele.
Tri (three-state) - aqui todos os drivers conectados a um tri devem ser z, exceto apenas um (que determina o valor de tri).
Example:
Wire [msb:lsb] wire_variable_list;
Wirec // simple wire
Wand d;
Assign d = a; // value of d is the logical AND of
Assign d = b; // a and b
Wire [9:0] A; // a cable (vector) of 10 wires.
Wand [msb:lsb] wand_variable_list;
Wor [msb:lsb] wor_variable_list;
Tri [msb:lsb] tri_variable_list;
Registro
Um reg (registrador) é um objeto de dados, que mantém o valor de uma atribuição procedural para a próxima e é usado apenas em diferentes funções e blocos procedurais. Um reg é um Verilog simples, registrador de tipo variável e não pode implicar em um registro físico. Em registradores de vários bits, os dados são armazenados na forma de números sem sinal e a extensão do sinal não é usada.
Exemplo -
reg c; // única variável de registro de 1 bit
gema reg [5: 0]; // um vetor de 6 bits;
reg [6: 0] d, e; // duas variáveis de 7 bits
Entrada, saída, entrada
Essas palavras-chave são usadas para declarar portas de entrada, saída e bidirecionais de uma tarefa ou módulo. Aqui, as portas de entrada e saída, que são do tipo fio, e a porta de saída são configuradas para serem do tipo fio, reg, varinha, wor ou tri. Sempre, o padrão é o tipo de fio.
Example
Module sample(a, c, b, d);
Input c; // An input where wire is used.
Output a, b; // Two outputs where wire is used.
Output [2:0] d; /* A three-bit output. One must declare type in a separate statement. */
reg [1:0] a; // The above ‘a’ port is for declaration in reg.
Inteiro
Os inteiros são usados em variáveis de propósito geral. Eles são usados principalmente em loops-indicies, constantes e parâmetros. Eles são do tipo de dados 'reg'. Eles armazenam dados como números assinados, enquanto os tipos reg declarados explicitamente os armazenam como dados não assinados. Se o número inteiro não for definido no momento da compilação, o tamanho padrão será 32 bits.
Se um inteiro contém uma constante, o sintetizador os ajusta para a largura mínima necessária no momento da compilação.
Example
Integer c; // single 32-bit integer
Assign a = 63; // 63 defaults to a 7-bit variable.
Fornecimento0, Fornecimento1
Supply0 define os fios ligados à lógica 0 (terra) e a fonte1 define os fios ligados à lógica 1 (energia).
Example
supply0 logic_0_wires;
supply0 gnd1; // equivalent to a wire assigned as 0
supply1 logic_1_wires;
supply1 c, s;
Tempo
O tempo é uma quantidade de 64 bits que pode ser usada em conjunto com a tarefa do sistema $ time para manter o tempo de simulação. O tempo não é suportado para síntese e, portanto, é usado apenas para fins de simulação.
Example
time time_variable_list;
time c;
c = $time; //c = current simulation time
Parâmetro
Um parâmetro é definir uma constante que pode ser definida quando você usa um módulo, o que permite a personalização do módulo durante o processo de instanciação.
Example
Parameter add = 3’b010, sub = 2’b11;
Parameter n = 3;
Parameter [2:0] param2 = 3’b110;
reg [n-1:0] jam; /* A 3-bit register with length of n or above. */
always @(z)
y = {{(add - sub){z}};
if (z)
begin
state = param2[1];
else
state = param2[2];
end
Operadores
Operadores aritméticos
Esses operadores realizam operações aritméticas. Os + e −são usados como operadores unários (x) ou binários (z − y).
Os operadores incluídos na operação aritmética são -
+ (adição), - (subtração), * (multiplicação), / (divisão),% (módulo)
Example -
parameter v = 5;
reg[3:0] b, d, h, i, count;
h = b + d;
i = d - v;
cnt = (cnt +1)%16; //Can count 0 thru 15.
Operadores Relacionais
Esses operadores comparam dois operandos e retornam o resultado em um único bit, 1 ou 0.
As variáveis de fio e reg são positivas. Assim (−3'd001) = = 3'd111 e (−3b001)> 3b110.
Os operadores que estão incluídos na operação relacional são -
- == (igual a)
- ! = (diferente de)
- > (maior que)
- > = (maior ou igual a)
- <(menos que)
- <= (menor ou igual a)
Example
if (z = = y) c = 1;
else c = 0; // Compare in 2’s compliment; d>b
reg [3:0] d,b;
if (d[3]= = b[3]) d[2:0] > b[2:0];
else b[3];
Equivalent Statement
e = (z == y);
Operadores bit a bit
Operadores bit a bit que estão fazendo uma comparação bit a bit entre dois operandos.
Os operadores que estão incluídos na operação bit a bit são -
- & (bit a bit AND)
- | (OR bit a bit)
- ~ (NÃO bit a bit)
- ^ (XOR bit a bit)
- ~ ^ ou ^ ~ (XNOR bit a bit)
Example
module and2 (d, b, c);
input [1:0] d, b;
output [1:0] c;
assign c = d & b;
end module
Operadores lógicos
Os operadores lógicos são operadores bit a bit e são usados apenas para operandos de bit único. Eles retornam um único valor de bit, 0 ou 1. Eles podem trabalhar com inteiros ou grupos de bits, expressões e tratar todos os valores diferentes de zero como 1. Operadores lógicos geralmente são usados em declarações condicionais, pois trabalham com expressões.
Os operadores que estão incluídos na operação lógica são -
- ! (NÃO lógico)
- && (AND lógico)
- || (OU lógico)
Example
wire[7:0] a, b, c; // a, b and c are multibit variables.
reg x;
if ((a == b) && (c)) x = 1; //x = 1 if a equals b, and c is nonzero.
else x = !a; // x =0 if a is anything but zero.
Operadores de redução
Operadores de redução são a forma unária dos operadores bit a bit e operam em todos os bits de um vetor operando. Eles também retornam um valor de bit único.
Os operadores incluídos na operação de redução são -
- & (redução AND)
- | (redução OU)
- ~ & (redução NAND)
- ~ | (redução NOR)
- ^ (redução XOR)
- ~ ^ ou ^ ~ (redução XNOR)
Example
Module chk_zero (x, z);
Input [2:0] x;
Output z;
Assign z = & x; // Reduction AND
End module
Operadores de turno
Operadores de deslocamento, que estão deslocando o primeiro operando pelo número de bits especificado pelo segundo operando na sintaxe. As posições vagas são preenchidas com zeros para ambas as direções, deslocamentos para a esquerda e para a direita (não há extensão de sinal de uso).
Os operadores que estão incluídos na operação de turno são -
- << (deslocar para a esquerda)
- >> (deslocar para a direita)
Example
Assign z = c << 3; /* z = c shifted left 3 bits;
Os cargos vagos são preenchidos com 0's * /
Operador de concatenação
O operador de concatenação combina dois ou mais operandos para formar um vetor maior.
O operador incluído na operação de concatenação é - {} (concatenação)
Example
wire [1:0] a, h; wire [2:0] x; wire [3;0] y, Z;
assign x = {1’b0, a}; // x[2] = 0, x[1] = a[1], x[0] = a[0]
assign b = {a, h}; /* b[3] = a[1], b[2] = a[0], b[1] = h[1],
b[0] = h[0] */
assign {cout, b} = x + Z; // Concatenation of a result
Operador de replicação
O operador de replicação está fazendo várias cópias de um item.
O operador usado na operação de replicação é - {n {item}} (replicação n vezes de um item)
Example
Wire [1:0] a, f; wire [4:0] x;
Assign x = {2{1’f0}, a}; // Equivalent to x = {0,0,a }
Assign y = {2{a}, 3{f}}; //Equivalent to y = {a,a,f,f}
For synthesis, Synopsis did not like a zero replication.
For example:-
Parameter l = 5, k = 5;
Assign x = {(l-k){a}}
Operador Condicional
O operador condicional é sintetizado em um multiplexador. É o mesmo tipo usado em C / C ++ e avalia uma das duas expressões com base na condição.
O operador usado na operação condicional é -
(Doença) ? (Resultado se a condição for verdadeira) -
(resultado se a condição for falsa)
Example
Assign x = (g) ? a : b;
Assign x = (inc = = 2) ? x+1 : x-1;
/* if (inc), x = x+1, else x = x-1 */
Operandos
Literais
Literais são operandos de valor constante usados em expressões Verilog. Os dois literais Verilog comumente usados são -
String - Um operando literal de string é uma matriz unidimensional de caracteres, que são colocados entre aspas duplas ("").
Numeric - Um operando de número constante é especificado em número binário, octal, decimal ou hexadecimal.
Example
n - inteiro representando o número de bits
F - um dos quatro formatos de base possíveis -
b para binário, o para octal, d para decimal, h para hexadecimal.
“time is” // string literal
267 // 32-bit decimal number
2’b01 // 2-bit binary
20’hB36F // 20-bit hexadecimal number
‘062 // 32-bit octal number
Fios, Regs e Parâmetros
Wires, regs e parâmetros são os tipos de dados usados como operandos em expressões Verilog.
Seleção de bits “x [2]” e Seleção de parte “x [4: 2]”
Bit-selects e part-selects são usados para selecionar um bit e vários bits, respectivamente, de um vetor de fio, reg ou parâmetro com o uso de colchetes “[]”. As seleções de bits e as seleções parciais também são usadas como operandos em expressões da mesma forma que seus objetos de dados principais são usados.
Example
reg [7:0] x, y;
reg [3:0] z;
reg a;
a = x[7] & y[7]; // bit-selects
z = x[7:4] + y[3:0]; // part-selects
Chamadas de função
Nas chamadas de Função, o valor de retorno de uma função é usado diretamente em uma expressão sem a necessidade de primeiro atribuí-lo a um registrador ou fio. Basta colocar a chamada de função como um dos tipos de operandos. É necessário ter certeza de que você está sabendo a largura de bits do valor de retorno da chamada de função.
Example
Assign x = y & z & chk_yz(z, y); // chk_yz is a function
. . ./* Definition of the function */
Function chk_yz; // function definition
Input z,y;
chk_yz = y^z;
End function
Módulos
Declaração de Módulo
Em Verilog, um módulo é a principal entidade de design. Isso indica o nome e a lista de portas (argumentos). As próximas linhas especificam o tipo de entrada / saída (entrada, saída ou entrada) e a largura de cada porta. A largura padrão da porta é de apenas 1 bit. As variáveis da porta devem ser declaradas por fio, varinha ,. . ., reg. A variável de porta padrão é fio. Normalmente, as entradas são conectadas porque seus dados estão travados fora do módulo. As saídas são do tipo reg se seus sinais forem armazenados internamente.
Example
module sub_add(add, in1, in2, out);
input add; // defaults to wire
input [7:0] in1, in2; wire in1, in2;
output [7:0] out; reg out;
... statements ...
End module
Atribuição Contínua
A atribuição contínua em um módulo é usada para atribuir um valor a um fio, que é a atribuição normal usada fora de sempre ou dos blocos iniciais. Essa atribuição é feita com uma instrução de atribuição explícita ou para atribuir um valor a uma ligação durante sua declaração. A atribuição contínua é executada continuamente no momento da simulação. A ordem das instruções de atribuição não o afeta. Se você fizer qualquer alteração em qualquer um dos sinais de entrada do lado direito, ele mudará um sinal de saída do lado esquerdo.
Example
Wire [1:0] x = 2’y01; // assigned on declaration
Assign y = c | d; // using assign statement
Assign d = a & b;
/* the order of the assign statements does not matter. */
Instanciações do Módulo
As declarações de módulo são modelos para a criação de objetos reais. Os módulos são instanciados dentro de outros módulos e cada instanciação está criando um único objeto a partir desse modelo. A exceção é o módulo de nível superior, que é sua própria instanciação. As portas do módulo devem corresponder àquelas definidas no modelo. É especificado -
By name, usando um ponto “.template nome da porta (nome do fio conectado à porta)”. Ou
By position, colocando as portas no mesmo lugar nas listas de portas do modelo e da instância.
Example
MODULE DEFINITION
Module and4 (x, y, z);
Input [3:0] x, y;
Output [3:0] z;
Assign z = x | y;
End module