Menu

Verilog Wire vs Reg: Quando usar cada um (com exemplos)

Os dois principais tipos de dados em Verilog - wire para conexões contínuas e reg para armazenamento procedural - e a regra para escolher entre eles toda vez.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Dois nomes, um trabalho

Cada sinal em Verilog tem um tipo. Os dois tipos que você encontra primeiro são wire e reg. Ambos podem manter um valor. Ambos podem ser de bit único ou multi-bit. A diferença não é sobre o que o sinal é - é sobre quem o aciona.

  • Sinais wire são conduzidos fora de blocos procedurais - por declarações assign, pelas saídas de submódulos ou por ports de entrada do module.
  • Sinais reg são conduzidos dentro de blocos procedurais - initial ou always.

Essa é a regra inteira. Os nomes das palavras-chave são esquisitos porque antecedem a forma moderna de escrever Verilog. reg nem sempre se torna um register em hardware. Continue lendo para entender por quê.

Wire: A conexão contínua

Um wire é um wire elétrico. Ele carrega o que seu driver estiver produzindo, continuamente. Duas formas de um wire ser conduzido:

Três coisas para notar:

  • y e z são declarados wire no module e wire novamente no testbench.
  • São conduzidos por assign - essa é a forma de continuous-assignment. O lado direito do = é recalculado sempre que algum sinal nele muda.
  • Não podemos escrever y = a & b dentro de um bloco always mantendo y como wire. O compilador rejeitaria.

Se você esquecer a palavra-chave wire, Verilog vai implicitamente declarar o sinal como um wire de bit único para você - o que às vezes é conveniente e às vezes é um bug silencioso. A maioria das equipes habilita uma opção da ferramenta que dá erro em wires implícitos. Seja explícito e evite a armadilha.

Reg: Armazenamento dentro de um bloco procedural

Um reg é um sinal ao qual você atribui dentro de initial ou always. O nome é uma relíquia dos primeiros dias da linguagem quando "reg" soava como "register"; no uso moderno um reg é apenas o tipo de qualquer sinal que código procedural escreve.

count é reg dentro do module (porque o bloco always escreve nele) e wire no testbench (porque a porta de saída do DUT o aciona). Mesmo sinal, papéis diferentes, tipos diferentes em cada escopo.

Por que "Reg" nem sempre significa "Register"

Aqui está a armadilha mais comum de iniciante. Este module declara y como reg - mas o hardware sintetizado não contém um flip-flop:

O bloco always @(*) é sensível a qualquer mudança de entrada. É combinacional. Uma ferramenta de síntese vê esse padrão e produz uma porta AND - sem flip-flop, sem clock, só lógica. A palavra-chave reg é puramente uma exigência sintática porque y é atribuído dentro de um always.

Para conseguir um flip-flop de verdade, o bloco always precisa ser sensível a uma borda de clock:

always @(posedge clk) begin
    q <= d;
end

Esse é o padrão "sintetizador-por-favor-faça-um-flip-flop": lista de sensibilidade clocked, non-blocking assignment. Mesma palavra-chave reg, hardware completamente diferente. Cobrimos a distinção em Always Block e Blocking vs Non-blocking.

A decisão na prática

Toda vez que você declara um sinal, pergunte: como vou acioná-lo?

  • Acionar com assign? → wire.
  • Conectar à porta de saída de um submódulo? → wire.
  • Port de entrada do module? → wire. (Entradas são sempre wire.)
  • Acionar a partir de initial ou always? → reg.
  • Port de saída do module conduzido por código procedural? → output reg.
  • Port de saída do module conduzido por assign? → output wire. (Ou apenas output - só direção padroniza para wire.)

Essa árvore de decisão cobre cada situação que você vai encontrar em Verilog puro.

Conflitos de driver

Sinais wire podem ter múltiplos drivers em teoria - é assim que barramentos tri-state funcionam, onde vários modules podem conduzir o mesmo wire e os inativos ficam em alta impedância (z). Para lógica comum, duas declarações assign escrevendo no mesmo wire produzem comportamento indefinido:

assign y = a;
assign y = b;   // RUIM - y tem dois drivers

O simulador pode escolher um, pode marcar o sinal como X, depende da ferramenta. De qualquer forma é um bug. Um driver por wire a menos que você esteja explicitamente construindo um barramento.

Sinais reg só podem ser conduzidos por um único bloco procedural. Dois blocos always ambos atribuindo o mesmo reg é um erro de síntese e bizarro em simulação. Mesma regra: um driver.

A atualização do SystemVerilog: logic

SystemVerilog (o superconjunto em que o Verilog evoluiu) adiciona uma única palavra-chave que substitui ambos: logic. Um sinal logic pode ser conduzido por assign ou por um bloco procedural - mas não ambos - e o compilador te impede de acidentalmente configurar um bug de múltiplos drivers.

module modern(input logic a, input logic b, output logic y);
    assign y = a ^ b;
endmodule

Se você está começando um projeto do zero e sua ferramenta suporta SystemVerilog (que o editor desta página suporta, com -g2012), usar logic em todo lugar simplifica as regras. Arquivos .v puros ainda precisam do split wire/reg, e você verá os dois estilos no mundo real para sempre.

O que vem a seguir

O próximo doc - Vectors and Arrays - pega os mesmos dois tipos e mostra como torná-los multi-bit. Larguras de barramento, ranges, dimensões packed, a diferença entre um vetor de bits e um array de vetores. Tudo que você precisa antes de conseguir construir qualquer coisa maior que um somador de um bit.

Perguntas frequentes

Qual a diferença entre wire e reg em Verilog?

wire e reg ambos mantêm um valor de sinal em cada momento da simulação, mas você escolhe entre eles com base em quem aciona o sinal. Um wire é conduzido de fora de um bloco procedural - por um assign ou pela saída de um submódulo. Um reg é conduzido de dentro de um bloco initial ou always. Os nomes são históricos e enganosos; reg nem sempre significa 'register'.

reg em Verilog significa um flip-flop?

Não necessariamente. Um reg só sintetiza para um flip-flop quando seu bloco always é sensível a uma borda de clock e usa non-blocking assignment. Um reg atribuído dentro de um bloco combinacional always @(*) sintetiza para lógica combinacional pura. A palavra-chave escolhe o tipo de dado Verilog, não o hardware.

Quando devo usar wire vs reg?

Regra de ouro: se você vai conduzir o sinal com assign ou conectá-lo à porta de saída de um submódulo, use wire. Se você vai atribuir a ele dentro de um bloco always ou initial, use reg. Entradas de um module são sempre wire. Saídas são wire se conduzidas por assign e reg se conduzidas por um bloco procedural.

Posso atribuir a um wire dentro de um bloco always?

Não - isso é um erro de sintaxe. Sinais wire só podem ser conduzidos por continuous assignments (assign) ou sendo conectados como saída de uma instância de submódulo. Qualquer coisa dentro de initial ou always precisa mirar um reg (ou em SystemVerilog, um logic). O compilador vai pegar isso e reclamar de uma 'left-hand side type mismatch'.

O que é logic em SystemVerilog?

logic é a unificação que o SystemVerilog faz de wire e reg. Pode ser conduzido por uma continuous assignment ou por um bloco procedural (mas não ambos ao mesmo tempo). Código moderno cada vez mais usa logic em todos os lugares e esquece a distinção wire/reg. Arquivos Verilog puro ainda precisam escolher.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR