Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> Verilog

Dominando Primitivas Definidas pelo Usuário (UDP) em Verilog: Modelagem Avançada de Lógica

Primitivas padrão Verilog como nand e not nem sempre são fáceis ou suficientes para representar lógica complexa. Novos elementos primitivos chamados UDP (User-Defined Primitives) ou primitivas definidas pelo usuário podem ser definidas para modelar lógica combinacional ou sequencial.

Todas UDPs têm exatamente uma saída que pode ser 0, 1 ou X (nunca Z, não suportado). Qualquer entrada com valor Z será tratada como X.

Símbolos Verilog UDP

UDPs podem ser escritas no mesmo nível que definições de module, mas nunca entre module e endmodule. Podem ter muitas portas de entrada mas sempre uma porta de saída, portas bidirecionais não válidas. Todos sinais de porta devem ser escalares (1-bit).

Comportamento de hardware descrito como tabela de estados primitiva listando combinações possíveis de entradas e saídas correspondentes dentro de table e endtable. Valores de sinais de entrada/saída indicados pelos símbolos:

Símbolo Comentários
0 Lógica 0
1 Lógica 1
x Desconhecido, pode ser 0 ou 1. Usado como entrada/saída ou estado atual de UDPs sequenciais
? Lógica 0, 1 ou x. Não pode ser saída de UDP
- Sem mudança, só permitido em saída de UDP
ab Mudança de valor de a para b (a ou b = 0, 1, ou x)
* Mesmo que ??, indica qualquer mudança no valor de entrada
r Mesmo que 01 -> borda de subida na entrada
f Mesmo que 10 -> borda de descida na entrada
p Borda de subida potencial: 0->1, 0->x, ou x->1
n Borda de descida potencial: 1->0, x->0, 1->x

Exemplo UDP Combinacional

// Saída sempre primeiro sinal na lista de portas
primitive mux (out, sel, a, b);
  output out;
  input sel, a, b;
  
  table
    // sel a b out
    0 1 ? : 1;
    0 0 ? : 0;
    1 ? 0 : 0;
    1 ? 1 : 1;
    x 0 0 : 0;
    x 1 1 : 1;
  endtable
endprimitive

O ? indica que o sinal pode ser 0, 1 ou x e não importa para decidir a saída final.

Testbench instanciando o UDP:

module tb;
  reg sel, a, b;
  reg [2:0] dly;
  wire out;
  integer i;
  
  // Instancia UDP - UDPs não podem ser instanciados com conexão por nome de porta
  mux u_mux (out, sel, a, b);
  
  initial begin
    a <= 0; b <= 0;
    $monitor("[T=%0t] a=%0b b=%0b sel=%0b out=%0b", $time, a, b, sel, out);
    
    // Aciona a, b, sel após atrasos aleatórios diferentes
    for (i = 0; i < 10; i = i + 1) begin
      dly = $random; #(dly) a <= $random;
      dly = $random; #(dly) b <= $random;
      dly = $random; #(dly) sel <= $random;
    end
  end
endmodule

Log de Simulação

xcelium> run
[T=0] a=0 b=0 sel=x out=0
[T=4] a=1 b=0 sel=x out=x
[T=5] a=1 b=1 sel=x out=1
[T=10] a=1 b=1 sel=1 out=1
[T=15] a=0 b=1 sel=1 out=1
[T=28] a=0 b=0 sel=1 out=0
[T=33] a=0 b=0 sel=0 out=0
[T=38] a=1 b=0 sel=0 out=1
[T=40] a=1 b=1 sel=0 out=1
[T=51] a=1 b=1 sel=1 out=1
[T=54] a=0 b=0 sel=1 out=0
[T=62] a=1 b=0 sel=1 out=0
[T=67] a=1 b=1 sel=1 out=1
[T=72] a=0 b=1 sel=1 out=1
[T=80] a=0 b=1 sel=0 out=0
[T=84] a=0 b=0 sel=0 out=0
[T=85] a=1 b=0 sel=0 out=1
xmsim: *W,RNQUIE: Simulation is complete.

Exemplo UDP Sequencial

Lógica sequencial pode ser sensível a nível ou borda, havendo dois tipos de UDPs sequenciais. Porta de saída deve ser declarada como reg na definição do UDP e pode ser inicializada opcionalmente em initial.

UDPs sequenciais têm campo adicional entre entrada e saída delimitado por : representando o estado atual.

UDPs Sensíveis a Nível (Level-Sensitive UDPs)

primitive d_latch (q, clk, d);
  output q;
  input clk, d;
  reg q;
  
  table
    // clk d q q+
    1 1 : ? : 1;
    1 0 : ? : 0;
    0 ? : ? : -;
  endtable
endprimitive

Na tabela acima, hífen - na última linha indica sem mudança no valor de q+.

module tb;
  reg clk, d;
  reg [1:0] dly;
  wire q;
  integer i;
  
  d_latch u_latch (q, clk, d);
  
  always #10 clk = ~clk;
  
  initial begin
    clk = 0;
    $monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
    #10; // Para ver efeito de X
    for (i = 0; i < 50; i = i+1) begin
      dly = $random; #(dly) d <= $random;
    end
    #20 $finish;
  end
endmodule

Log de Simulação

xcelium> run
[T=0] clk=0 d=x q=x
[T=10] clk=1 d=1 q=1
[T=13] clk=1 d=0 q=0
[T=14] clk=1 d=1 q=1
[T=17] clk=1 d=0 q=0
[T=20] clk=0 d=1 q=0
[T=28] clk=0 d=0 q=0
[T=30] clk=1 d=1 q=1
[T=38] clk=1 d=0 q=0
[T=39] clk=1 d=1 q=1
[T=40] clk=0 d=1 q=1
[T=42] clk=0 d=0 q=1
[T=47] clk=0 d=1 q=1
[T=50] clk=1 d=0 q=0
[T=55] clk=1 d=1 q=1
[T=59] clk=1 d=0 q=0
[T=60] clk=0 d=0 q=0
[T=61] clk=0 d=1 q=0
[T=64] clk=0 d=0 q=0
[T=67] clk=0 d=1 q=0
[T=70] clk=1 d=0 q=0
[T=73] clk=1 d=1 q=1
[T=74] clk=1 d=0 q=0
[T=77] clk=1 d=1 q=1
[T=79] clk=1 d=0 q=0
[T=80] clk=0 d=0 q=0
[T=84] clk=0 d=1 q=0
[T=86] clk=0 d=0 q=0
[T=87] clk=0 d=1 q=0
[T=90] clk=1 d=1 q=1
[T=91] clk=1 d=0 q=0
[T=100] clk=0 d=0 q=0
[T=110] clk=1 d=0 q=0
Simulation complete via $finish(1) at time 111 NS + 0

UDPs Sensíveis a Borda (Edge-Sensitive UDPs)

Um D flip-flop modelado como UDP Verilog. Borda de subida do clock especificada por 01 ou 0?.

primitive d_flop (q, clk, d);
  output q;
  input clk, d;
  reg q;
  
  table
    // clk d q q+
    // obtém saída na borda de subida do clk (01)
    0 : ? : 0;
    (01) 1 : ? : 1;
    (0?) 1 : 1 : 1;
    (0?) 0 : 0 : 0;
    // ignora borda de descida do clk
    (?0) ? : ? : -;
    // ignora mudanças de dados em clk estável
    ? (??) : ? : -;
  endtable
endprimitive

No testbench, UDP instanciado e acionado com valores aleatórios de d após número aleatório de clocks.

module tb;
  reg clk, d;
  reg [1:0] dly;
  wire q;
  integer i;
  
  d_flop u_flop (q, clk, d);
  
  always #10 clk = ~clk;
  
  initial begin
    clk = 0;
    $monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
    #10; // Para ver efeito de X
    for (i = 0; i < 20; i = i+1) begin
      dly = $random; repeat(dly) @(posedge clk); d <= $random;
    end
    #20 $finish;
  end
endmodule

Pode-se ver na imagem que saída q segue entrada d após 1 clock de atraso, comportamento desejado para D flip-flop.

Log de Simulação

xcelium> run
[T=0] clk=0 d=x q=x
[T=10] clk=1 d=1 q=x
[T=20] clk=0 d=1 q=x
[T=30] clk=1 d=1 q=1
[T=40] clk=0 d=1 q=1
[T=50] clk=1 d=1 q=1
[T=60] clk=0 d=1 q=1
[T=70] clk=1 d=0 q=1
[T=80] clk=0 d=0 q=1
[T=90] clk=1 d=1 q=0
[T=100] clk=0 d=1 q=0
[T=110] clk=1 d=1 q=1
[T=120] clk=0 d=1 q=1
[T=130] clk=1 d=1 q=1
[T=140] clk=0 d=1 q=1
[T=150] clk=1 d=0 q=1
[T=160] clk=0 d=0 q=1
[T=170] clk=1 d=0 q=0
[T=180] clk=0 d=0 q=0
[T=190] clk=1 d=0 q=0
[T=200] clk=0 d=0 q=0
[T=210] clk=1 d=1 q=0
[T=220] clk=0 d=1 q=0
[T=230] clk=1 d=1 q=1
[T=240] clk=0 d=1 q=1
[T=250] clk=1 d=1 q=1
[T=260] clk=0 d=1 q=1
[T=270] clk=1 d=1 q=1
[T=280] clk=0 d=1 q=1
[T=290] clk=1 d=1 q=1
[T=300] clk=0 d=1 q=1
[T=310] clk=1 d=1 q=1
[T=320] clk=0 d=1 q=1
[T=330] clk=1 d=1 q=1
[T=340] clk=0 d=1 q=1
[T=350] clk=1 d=1 q=1
[T=360] clk=0 d=1 q=1
[T=370] clk=1 d=0 q=1
[T=380] clk=0 d=0 q=1
[T=390] clk=1 d=0 q=0
[T=400] clk=0 d=0 q=0
[T=410] clk=1 d=1 q=0
[T=420] clk=0 d=1 q=0
[T=430] clk=1 d=1 q=1
[T=440] clk=0 d=1 q=1
[T=450] clk=1 d=1 q=1
[T=460] clk=0 d=1 q=1
[T=470] clk=1 d=1 q=1
[T=480] clk=0 d=1 q=1
Simulation complete via $finish(1) at time 490 NS + 0

Verilog

  1. Domine o Verilog: Tutorial Completo para Projeto de Circuitos Digitais
  2. Dominando Concatenação Verilog: Guia Prático
  3. Entendendo Atribuições em Verilog: Tipos, Sintaxe e Boas Práticas
  4. Verilog Blocking vs Non-Blocking: Diferenças Essenciais Explicadas
  5. Dominando Funções em Verilog para Design RTL Eficiente
  6. Entendendo Tasks em Verilog: Funções vs Tasks, Sintaxe e Uso
  7. Gerador de Clock Verilog: Guia de Design e Implementação
  8. Dominando Funções Matemáticas do Verilog para Design de Hardware Eficiente
  9. Dominando $timeformat do Verilog: Precisão e Controle de Exibição
  10. Entendendo e Imprimindo Timescales do Verilog em Qualquer Escopo