Entendendo Atribuições em Verilog: Tipos, Sintaxe e Boas Práticas
Atribuir valores a redes (nets) e variáveis é chamado de atribuição. Existem três formas básicas:
- Procedural
- Contínua
- Procedural contínua
Valores LHS Permitidos
Uma atribuição tem duas partes: lado direito (RHS) e lado esquerdo (LHS), com um símbolo de igual (=) ou menor-igual (<=) entre eles.
| Tipo de atribuição | Lado esquerdo (LHS) |
|---|---|
| Procedural |
|
| Contínua |
|
| Procedural Contínua |
|
O RHS pode conter qualquer expressão que avalie para um valor final, enquanto o LHS indica uma rede ou variável à qual o valor do RHS está sendo atribuído.
module tb;
reg clk;
wire a, b, c, d, e, f;
reg z, y;
// clk está no LHS e a negação de clk forma o RHS
always #10 clk = ~clk;
// y é o LHS e a constante 1 é o RHS
assign y = 1;
// f é o LHS, e a expressão de a,b,d,e forma o RHS
assign f = (a | b) ^ (d & e);
always @ (posedge clk) begin
// z é o LHS, e a expressão de a,b,c,d forma o RHS
z <= a + b + c + d;
end
initial begin
// Nomes de variáveis à esquerda formam LHS enquanto 0 é RHS
a <= 0;
b <= 0;
c <= 0;
d <= 0;
e <= 0;
clk <= 0;
end
endmodule
Atribuição Procedural
Atribuições procedurais ocorrem dentro de procedimentos como always, initial, task e function e são usadas para colocar valores em variáveis. A variável manterá o valor até a próxima atribuição à mesma variável.
O valor será colocado na variável quando a simulação executar esta instrução em algum momento durante o tempo de simulação. Isso pode ser controlado e modificado da forma desejada pelo uso de instruções de controle de fluxo como if-else-if, case e mecanismos de loop.
reg [7:0] data;
integer count;
real period;
initial begin
data = 8'h3e;
period = 4.23;
count = 0;
end
always @ (posedge clk)
count++;
Atribuição na Declaração de Variável
Um valor inicial pode ser colocado em uma variável no momento de sua declaração. A atribuição não tem duração e mantém o valor até a próxima atribuição à mesma variável. Note que atribuições na declaração para arrays não são permitidas.
module my_block;
reg [31:0] data = 32'hdead_cafe;
initial begin
#20 data = 32'h1234_5678;
// data terá dead_cafe do tempo 0 ao tempo 20
// No tempo 20, data receberá 12345678
end
endmodule
reg [3:0] a = 4'b4;
// é equivalente a
reg [3:0] a;
initial a = 4'b4;
Se a variável for inicializada na declaração e no tempo 0 em um bloco initial, a ordem de avaliação não é garantida, podendo resultar em 8'h05 ou 8'hee.
module my_block;
reg [7:0] addr = 8'h05;
initial addr = 8'hee;
endmodule
reg [3:0] array [3:0] = 0; // ilegal
integer i = 0, j; // declara dois integers i,j e i recebe 0
real r2 = 4.5, r3 = 8; // declara dois reals r2,r3 com 4.5, 8
time startTime = 40; // declara variável time com valor inicial 40
Blocos e atribuições procedurais serão abordados em mais detalhes em uma seção posterior.
Atribuição Contínua
Clique aqui para um exemplo de simulação passo a passo!
Usada para atribuir valores a redes escalares e vetoriais e ocorre sempre que há uma mudança no RHS. Fornece uma forma de modelar lógica combinacional sem especificar uma interconexão de portas e facilita o acionamento da rede com expressões lógicas.
// Modelo de exemplo de uma porta AND
wire a, b, c;
assign a = b & c;
Sempre que b ou c mudam de valor, toda a expressão no RHS será avaliada e a será atualizada com o novo valor.
Atribuição na Declaração de Rede
Permite colocar uma atribuição contínua na mesma instrução que declara a rede. Note que, como uma rede pode ser declarada apenas uma vez, apenas uma atribuição de declaração é possível para uma rede.
wire penable = 1;
Atribuição Procedural Contínua
São instruções procedurais que permitem expressões serem atribuídas continuamente a redes ou variáveis e são de dois tipos:
assign...deassignforce...release
assign deassign
Sobrescreve todas as atribuições procedurais a uma variável e é desativado usando o mesmo sinal com deassign. O valor da variável permanecerá o mesmo até que a variável receba um novo valor através de uma atribuição procedural ou procedural contínua. O LHS de um assign não pode ser seleção de bit, parte ou referência a array, mas pode ser uma variável ou concatenação de variáveis.
reg q;
initial begin
assign q = 0;
#10 deassign q;
end
force release
Semelhantes às instruções assign - deassign, mas também podem ser aplicadas a redes e variáveis. O LHS pode ser seleção de bit de rede, parte de rede, variável ou rede, mas não pode ser referência a array e seleção de bit/parte de variável. A instrução force sobrescreverá todas as outras atribuições feitas à variável até ser liberada com release.
reg o, a, b;
initial begin
force o = a & b;
...
release o;
end
Verilog
- Domine o Verilog: Tutorial Completo para Projeto de Circuitos Digitais
- Dominando Concatenação Verilog: Guia Prático
- Dominando Funções em Verilog para Design RTL Eficiente
- Entendendo Tasks em Verilog: Funções vs Tasks, Sintaxe e Uso
- Gerador de Clock Verilog: Guia de Design e Implementação
- Dominando Funções Matemáticas do Verilog para Design de Hardware Eficiente
- Dominando $timeformat do Verilog: Precisão e Controle de Exibição
- Entendendo e Imprimindo Timescales do Verilog em Qualquer Escopo
- Dominando I/O de Arquivos em Verilog: Abrir, Ler, Escrever e Fechar
- Guia para Iniciantes em Verilog: Exemplo Hello World