Menu

Parameters em Verilog: Tornando modules configuráveis

Como usar parameter e localparam para definir constantes em tempo de compilação, parametrizar larguras e profundidades e sobrescrever valores ao instanciar um module.

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

Constantes com uma reviravolta

Um parameter é uma constante - o compilador escolhe seu valor e o assa no design antes da simulação começar. A reviravolta é que quem instancia o module pode mudar o valor. O mesmo arquivo fonte de module pode produzir circuitos de tamanhos diferentes dependendo de como chamadores o parametrizam.

É assim que você constrói IP reutilizável. Um module FIFO com parameters WIDTH e DEPTH pode servir cada equipe em uma empresa. Um contador com um parameter WIDTH é o mesmo fonte quer ele conte até 16 ou 4 bilhões.

Declaração básica de parameter

Três pedaços de sintaxe nova:

  1. Bloco de parameter: #( parameter WIDTH = 8 ) entre o nome do module e a lista de ports. O valor padrão 8 é o que o module usa quando ninguém sobrescreve.
  2. Local de uso: output reg [WIDTH-1:0] count. O parameter é só uma constante - nós o plugamos no range de bits. Mesmo fonte de module produz uma saída de 8 bits ou de 16 bits dependendo de WIDTH.
  3. Sintaxe de sobrescrita: counter #(.WIDTH(16)) dut16(...) no momento da instanciação. O bloco #(...) vai antes do nome da instância, depois do nome do module. Quaisquer parameters que você não mencionar mantêm seus padrões.

localparam: Constantes internas

Há constantes que você não quer que chamadores sobrescrevam. Codificações de estado são o caso clássico:

localparam torna IDLE, RUNNING, DONE disponíveis dentro do module mas não sobrescritíveis a partir da instanciação. Essa é a escolha certa - mudar o que o valor IDLE significa de fora do module seria aterrorizante.

Use parameter para coisas que chamadores devem configurar (larguras, profundidades, opções de comportamento) e localparam para todo o resto. Um padrão comum é derivar localparams de parameters:

parameter WIDTH = 32;
localparam WIDTH_M1 = WIDTH - 1;   // calculado uma vez; não sobrescritível

Larguras parametrizadas na prática

O uso mais comum de parameters é tornar larguras de barramento flexíveis. Aqui está um somador que funciona em qualquer largura:

Um arquivo fonte, duas instâncias, duas larguras diferentes, sem copy-paste. Essa é a recompensa inteira dos parameters.

Múltiplos parameters, sobrescrita nomeada

Para modules maiores você frequentemente terá vários parameters. Sobrescreva-os por nome em qualquer ordem:

module fifo #(
    parameter WIDTH = 8,
    parameter DEPTH = 16,
    parameter AFULL = DEPTH - 2
)(
    input  wire             clk,
    input  wire             reset,
    // ... ports ...
);
    // ...
endmodule

// No local de chamada:
fifo #(.WIDTH(32), .DEPTH(1024)) cmd_queue (.clk(clk), .reset(reset), ...);

Você não precisa sobrescrever cada parameter; os não mencionados mantêm seus padrões. O padrão AFULL no exemplo é calculado a partir de DEPTH, o que significa que se você sobrescrever DEPTH, AFULL segue automaticamente - exatamente o tipo de dependência que localparam também lidaria se você não quisesse que chamadores conseguissem sobrescrever AFULL independentemente.

Erros comuns

Esquecer o # na sobrescrita. counter (.WIDTH(16)) dut(...) parece uma sobrescrita mas Verilog lê (.WIDTH(16)) como uma conexão de port. Você precisa de counter #(.WIDTH(16)) dut(...).

Usar parameters onde eles não são constantes o suficiente. Parameters resolvem em tempo de elaboração, antes que qualquer sinal exista. Você não pode parametrizar com base em um sinal de runtime - se o valor depende do que uma entrada está fazendo no tempo de simulação, não é um parameter, é lógica.

Confundir parameter e localparam em listas de port. Apenas parameter vai no bloco #(...) no topo. localparam vive dentro do corpo. O compilador vai te avisar se você trocar.

O que vem a seguir

Você agora consegue fazer modules cujo tamanho é definido em tempo de compilação. Os próximos dois docs cobrem as regras para escrever constantes literais (8'h1F, 4'b1010, 32'd100) e os valores x e z que aparecem quando sinais não são conduzidos ou estão em contenção. Depois disso passamos a operadores - tudo que você consegue fazer com os vetores e parameters que agora viu.

Perguntas frequentes

O que é um parameter em Verilog?

Um parameter é uma constante em tempo de compilação declarada dentro de um module. Pode ser usado em qualquer lugar onde uma constante é permitida - larguras de barramento, profundidades de memória, codificações de estado, valores padrão. Crucialmente, cada instância do module pode sobrescrever o parameter, então o mesmo arquivo fonte pode produzir, digamos, um contador de 8 bits em um lugar e um contador de 32 bits em outro.

Qual a diferença entre parameter e localparam em Verilog?

Valores parameter podem ser sobrescritos de fora do module quando ele é instanciado. Valores localparam não podem - são constantes internas apenas. Use localparam para codificações de estado e constantes derivadas que o autor do module não quer que chamadores bagunçem.

Como sobrescrevo um parameter em Verilog?

Quando você instancia o module, adicione um bloco de override de parameter antes do nome da instância: counter #(.WIDTH(16)) my_inst (.clk(clk), .count(count));. A sintaxe .WIDTH(16) define esse parameter específico; quaisquer parameters que você não listar mantêm seus padrões. Múltiplas sobrescritas são separadas por vírgulas dentro do #(...).

O que é um module parametrizado?

Um module que expõe um ou mais parameters que chamadores podem sobrescrever. Um FIFO parametrizado pode ter parameters WIDTH e DEPTH para que o mesmo fonte produza um FIFO de 32 bits por 16 fundo em um lugar e um FIFO de 8 bits por 1024 fundo em outro. É assim que bibliotecas de blocos de IP reutilizáveis são escritas.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR