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

Verilog Blocking vs Non-Blocking: Diferenças Essenciais Explicadas

Atribuição Bloqueante (Blocking)

Atribuições blocking usam o operador = e são executadas sequencialmente dentro de um bloco procedural. No entanto, isso não impede a execução de instruções que rodam em blocos paralelos.

module tb;
  reg [7:0] a, b, c, d, e;
  
  initial begin
    a = 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    b = 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c = 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  
  initial begin
    d = 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    e = 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Note que existem dois blocos initial executados em paralelo no início da simulação. As instruções são executadas sequencialmente em cada bloco e ambos terminam no tempo 0ns. Para ser mais específico, a variável a recebe atribuição primeiro, seguida pela instrução $display e depois todas as outras. Isso é visível na saída onde b e c mostram 8'hxx no primeiro $display, pois suas atribuições ainda não foram executadas.

Log de Simulação

ncsim> run
[0] a=0xda b=0xx c=0xx
[0] a=0xda b=0xf1 c=0xx
[0] a=0xda b=0xf1 c=0x30
[0] d=0xaa e=0xx
[0] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.

No próximo exemplo, adicionamos atrasos ao mesmo conjunto de instruções para ver o comportamento.

module tb;
  reg [7:0] a, b, c, d, e;
  
  initial begin
    a = 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    #10 b = 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c = 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  
  initial begin
    #5 d = 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    #5 e = 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Log de Simulação

ncsim> run
[0] a=0xda b=0xx c=0xx
[5] d=0xaa e=0xx
[10] a=0xda b=0xf1 c=0xx
[10] a=0xda b=0xf1 c=0x30
[10] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.

Atribuição Não-Bloqueante (Non-blocking)

Atribuição non-blocking permite agendar atribuições sem bloquear a execução das instruções seguintes, especificada pelo símbolo <=. É interessante notar que o mesmo símbolo é usado como operador relacional em expressões e como operador de atribuição no contexto de atribuição não-bloqueante. Se pegarmos o primeiro exemplo e substituirmos todos os = por <=, veremos diferença na saída.

module tb;
  reg [7:0] a, b, c, d, e;
  
  initial begin
    a <= 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    b <= 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c <= 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  
  initial begin
    d <= 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    e <= 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Veja que todos os $display imprimiram 'h'x. A razão está na forma como atribuições não-bloqueantes são executadas: o RHS de cada instrução não-bloqueante de um determinado passo de tempo é capturado, e a execução passa para a próxima instrução. O valor RHS capturado é atribuído à variável LHS apenas no final do passo de tempo.

Log de Simulação

ncsim> run
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] d=0xx e=0xx
[0] d=0xx e=0xx
ncsim: *W,RNQUIE: Simulation is complete.

Analisando o fluxo de execução:

|__ Spawn Bloco1: initial
| |___ Tempo #0ns: a <= 8'DA, não-bloqueante, captura RHS (8'hDA) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa: mas a não recebeu novo valor, a=8'hx
| |___ Tempo #0ns: b <= 8'F1, não-bloqueante, captura RHS (8'hF1) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa. Mas b não recebeu novo valor, b=8'hx
| |___ Tempo #0ns: c <= 8'30, não-bloqueante, captura RHS (8'h30) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa. Mas c não recebeu novo valor, c=8'hx
| |___ Fim do passo de tempo e bloco initial, atribui valores capturados a a, b, c
|__ Spawn Bloco2: initial
| |___ Tempo #0ns: d <= 8'AA, não-bloqueante, captura RHS (8'hAA) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa: mas d não recebeu novo valor, d=8'hx
| |___ Tempo #0ns: e <= 8'55, não-bloqueante, captura RHS (8'h55) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa. Mas e não recebeu novo valor, e=8'hx
| |___ Fim do passo de tempo e bloco initial, atribui valores capturados a d e e
|__ Fim da simulação em #0ns

Agora, usamos o segundo exemplo substituindo todas as atribuições bloqueantes por não-bloqueantes.

module tb;
  reg [7:0] a, b, c, d, e;
  
  initial begin
    a <= 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    #10 b <= 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c <= 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  
  initial begin
    #5 d <= 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    #5 e <= 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Mais uma vez, a saída é diferente da anterior.

Log de Simulação

ncsim> run
[0] a=0xx b=0xx c=0xx
[5] d=0xx e=0xx
[10] a=0xda b=0xx c=0xx
[10] a=0xda b=0xx c=0xx
[10] d=0xaa e=0xx
ncsim: *W,RNQUIE: Simulation is complete.

Fluxo de execução detalhado:

|__ Spawn Bloco1 em #0ns: initial
| |___ Tempo #0ns: a <= 8'DA, não-bloqueante, captura RHS (8'hDA) e executa próximo passo
| |___ Tempo #0ns: $display() é bloqueante, executa: mas a não recebeu novo valor, a=8'hx
| |___ Fim do passo de tempo: Atribui valor capturado a a, a agora é 8'hDA
| |___ Espera até tempo avançar 10 unidades para #10ns
| | |___ Tempo #10ns: b <= 8'F1, não-bloqueante, captura RHS (8'hF1) e executa próximo passo
| |___ Tempo #10ns: $display() é bloqueante, executa. Mas b não recebeu novo valor, b=8'hx
| |___ Tempo #10ns: c <= 8'30, não-bloqueante, captura RHS (8'h30) e executa próximo passo
| |___ Tempo #10ns: $display() é bloqueante, executa. Mas c não recebeu novo valor, c=8'hx
| |___ Fim do passo de tempo e bloco initial, atribui valores capturados a b, c
|__ Spawn Bloco2 em #0ns: initial
| |___ Espera até tempo avançar 5 unidades para #5ns
| | |___ Tempo #5ns: d <= 8'AA, não-bloqueante, captura RHS (8'hAA) e executa próximo passo
| |___ Tempo #5ns: $display() é bloqueante, executa: mas d não recebeu novo valor, d=8'hx
| |___ Fim do passo de tempo: Atribui valor capturado a d, d agora é 8'hAA
| |___ Espera até tempo avançar 5 unidades para #5ns
| | |___ Tempo #10ns: e <= 8'55, não-bloqueante, captura RHS (8'h55) e executa próximo passo
| |___ Tempo #10ns: $display() é bloqueante, executa. Mas e não recebeu novo valor, e=8'hx
| |___ Fim do passo de tempo e bloco initial, atribui valores capturados a e, e agora é 8'h55
|__ Fim da simulação em #10ns

Verilog

  1. Domine o Verilog: Tutorial Completo para Projeto de Circuitos Digitais
  2. Dominando Concatenação Verilog: Guia Prático
  3. Dominando Funções em Verilog para Design RTL Eficiente
  4. Entendendo Tasks em Verilog: Funções vs Tasks, Sintaxe e Uso
  5. Gerador de Clock Verilog: Guia de Design e Implementação
  6. Dominando Funções Matemáticas do Verilog para Design de Hardware Eficiente
  7. Dominando $timeformat do Verilog: Precisão e Controle de Exibição
  8. Entendendo e Imprimindo Timescales do Verilog em Qualquer Escopo
  9. Dominando I/O de Arquivos em Verilog: Abrir, Ler, Escrever e Fechar
  10. Guia para Iniciantes em Verilog: Exemplo Hello World