Menu

Operadores em Verilog: Aritméticos, comparação, lógicos e condicional

Os operadores principais em Verilog - aritméticos, comparação, lógicos e o condicional ?: - com as regras e pegadinhas em torno de larguras mistas e signedness.

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

O que "operador" significa em Verilog

Operadores pegam expressões que carregam sinais e produzem novas expressões que carregam sinais. a + b é hardware - o sintetizador transforma em um somador. a == b é hardware - constrói um comparador. Nada disso é "código que roda"; é tudo "circuitos que o operador descreve".

O menu completo de operadores é pequeno o suficiente para memorizar. Este doc cobre os operadores aritméticos, de comparação, lógicos e condicional. Bitwise and Reduction cobre os operadores em nível de bit que não têm análogos diretos em software.

Aritméticos: + - * / %

Três coisas para saber:

  1. Divisão é divisão inteira. 7/2 é 3, não 3.5. Verilog não tem um tipo float (bem, real, mas é só de simulação).
  2. Divisão e módulo são caros em hardware. Um /4 está ok (o sintetizador transforma em um shift à direita), mas um /n para n variável em runtime constrói um divisor multi-ciclo que você quase nunca quer.
  3. Overflow dá a volta. Somar dois valores unsigned de N bits que excedem N bits trunca para N bits. Se você quer capturar o carry, declare o resultado um bit mais largo:
wire [7:0] a, b;
wire [8:0] sum = a + b;   // soma de 9 bits captura carry out

Comparação: == != < > <= >=

Os seis operadores de comparação retornam um resultado de 1 bit: 1 se verdadeiro, 0 se falso, x se algum operando tem um bit x ou z. Para lidar com o caso x/z, recorra a === e !== (os operadores de case-equality) cobertos em X e Z Values.

<= aqui é o operador de comparação (menor-ou-igual). Os mesmos caracteres também significam non-blocking assignment em um bloco procedural (q <= d). O contexto os distingue: dentro de uma expressão é uma comparação; à esquerda de um valor sendo atribuído, é a atribuição. A sobreposição é confusa mas inambígua para o parser.

Lógicos: && || !

Operadores lógicos tratam seus operandos como booleanos (qualquer coisa não-zero é verdadeiro, zero é falso) e produzem um resultado de 1 bit:

A distinção crucial para internalizar: && lógico não é & bitwise.

4'b1100 && 4'b0011   // 1 (ambos sao nao-zero, AND logico e verdadeiro)
4'b1100 &  4'b0011   // 4'b0000 (nenhuma posicao de bit e 1 em ambos)

O mesmo para || vs |. Use lógico em condições if e predicados ?:; use bitwise quando quiser que cada posição de bit faça AND/OR independentemente.

&& e || são short-circuit no sentido do C: o lado direito não é avaliado se o resultado já estiver determinado pelo lado esquerdo. Isso importa para testbenches que verificam ponteiros ou chamadas de função; raramente importa para RTL sintetizável onde tudo acontece em paralelo de qualquer forma.

O operador condicional: ?:

O ternário é seu melhor amigo para construir muxes e expressões condicionais:

O padrão cond ? a : b é um multiplexador 2-para-1 com select de 1 bit em hardware. Encadear é fine para selects de 3 e 4 vias, mas além disso uma declaração case (coberta em Case Statement) é dramaticamente mais legível.

O operador ?: também é a forma padrão de dar a um register um valor padrão que você só sobrescreve às vezes:

next_value = update ? new_data : next_value;

Regras de largura: A pegadinha do iniciante

As regras de largura do Verilog para operadores aritméticos são notoriamente surpreendentes. A versão curta:

  • A largura do resultado é o máximo das larguras das entradas.
  • Se o resultado é atribuído a algo mais largo, é zero-extended (ou sign-extended se signed).
  • A largura de computações intermediárias também é a largura do resultado, o que significa que overflow acontece no intermediário.

A primeira multiplicação dá overflow porque as larguras dos operandos são ambas 8 bits, a largura do resultado é portanto 8 bits, e 40000 não cabe. A segunda funciona porque alargamos a explicitamente antes de multiplicar.

As técnicas de correção:

  • Use o operador de concatenação {8'b0, a} para zero-extend.
  • Use $unsigned(a) ou $signed(a) para influenciar interpretação.
  • Faça cast de expressões intermediárias para larguras maiores quando na dúvida.

Precedência de operadores

Você não vai memorizar a tabela, mas vai se apoiar em algumas regras:

  • *, /, % ligam mais fortemente que +, -.
  • Comparação liga mais fortemente que lógicos (&&, ||).
  • O operador condicional ?: tem precedência muito baixa - geralmente precisa de parênteses em torno de seus ramos em expressões maiores.
  • Na dúvida, parêntese. O simulador não cobra por caractere.
out = (mode == 2'd0) ? a + b : a - b;   // mais claro com parens

O que vem a seguir

Você cobriu cada operador que parece com seu primo de software. O próximo doc - Bitwise and Reduction - lida com os operadores que não têm análogos diretos em software: AND/OR/XOR bitwise por bit, mais as formas de reduction que colapsam um vetor inteiro em um único bit.

Perguntas frequentes

Quais operadores o Verilog suporta?

Verilog tem quatro famílias amplas de operadores: aritméticos (+, -, *, /, %), comparação (==, !=, <, >, <=, >=), lógicos (&&, ||, !) e bitwise/reduction (&, |, ^, ~, ~&, ~|, ~^). Mais operadores de shift (<<, >>, <<<, >>>), concatenação {}, replicação {N{...}} e o condicional ?:.

Qual a diferença entre && e & em Verilog?

&& é AND lógico - trata cada operando como um booleano (zero ou não-zero) e retorna um resultado de 1 bit. & é AND bitwise - pareia bits posição por posição. 4'b1100 && 4'b0011 é 1 (ambos são não-zero); 4'b1100 & 4'b0011 é 4'b0000. Use && em condições, & para operações em nível de bit.

Como funciona a divisão em Verilog?

Divisão inteira - a parte fracionária é descartada. 7 / 2 é 3, não 3.5. O operador % dá o resto: 7 % 2 é 1. Divisão por zero produz x (desconhecido) na simulação. Ambos operadores são tecnicamente sintetizáveis mas produzem hardware muito grande e lento em FPGAs e ASICs - evite-os em caminhos sintetizáveis a menos que o divisor seja uma potência de 2.

O que é o operador condicional em Verilog?

?: é o operador ternário ou condicional, copiado do C. cond ? a : b avalia para a se cond é verdadeiro (não-zero) e b caso contrário. É a construção mais usada para lógica tipo multiplexador: out = sel ? in1 : in0 constrói um mux 2-para-1. Cadeias de ?: constroem muxes mais largos, embora case geralmente seja mais claro além de duas entradas.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR