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

Implementando Lógica Sequencial Usando Blocos 'always' do Verilog

Um artigo anterior mostrou diferentes exemplos de uso de um bloco always para implementar lógica combinacional. Um bloco always também é principalmente usado para implementar lógica sequencial, que possui elementos de memória como flip-flops que podem reter valores.

Flip-Flop JK

Um flip-flop JK é um dos muitos tipos de flops usados para armazenar valores e possui duas entradas de dados j e k, junto com uma para reset rstn e outra para clock clk. A tabela-verdade para um flip-flop JK é mostrada abaixo e é tipicamente implementada usando portas NAND.

rstn j k q Comentários
0 0 0 0 Quando reset é afirmado, saída é sempre zero
1 0 0 Mantém valor Quando tanto j quanto k são 0, saída permanece a mesma de antes
1 0 1 1 Quando k=1, saída torna-se 1
1 1 0 0 Quando k=0, saída torna-se 0
1 1 1 Alterna valor Quando j=1,k=1 saída alterna valor atual

O código Verilog comportamental para um flip-flop JK pode ser escrito como mostrado abaixo:


module jk_ff (
    input j,        // Entrada J
    input k,        // Entrada K
    input rstn,     // Reset assíncrono ativo-baixo
    input clk,      // Clock de entrada
    output reg q    // Saída Q
);
    always @ (posedge clk or negedge rstn) begin
        if (!rstn) begin
            q <= 0;
        end else begin
            q <= (j & ~q) | (~k & q);
        end
    end
endmodule

Testbench

Primeiro declare todas as variáveis usadas no testbench e inicie um clock usando um bloco always simples que pode ser conduzido ao design. Então instancie o design e conecte suas portas com as variáveis correspondentes do testbench. Note que q é do tipo wire porque está conectado a uma saída do design que estará ativamente conduzindo-o. Todas as outras entradas para o design são do tipo reg para que possam ser conduzidas dentro de um bloco procedural como initial.

O estímulo primeiro inicializa todas as entradas do design para zero e então desafirma reset após algum tempo. Um loop for é usado para conduzir diferentes valores para j e k que são conduzidos em tempos aleatórios. Uma vez que o loop termina, espere mais algum tempo e termine a simulação.


module tb;
    // Declarar variáveis do testbench
    reg j, k, rstn, clk;
    wire q;
    integer i;
    reg [2:0] dly;

    // Iniciar o clock
    always #10 clk = ~clk;

    // Instanciar o design
    jk_ff u0 (
        .j(j),
        .k(k),
        .clk(clk),
        .rstn(rstn),
        .q(q)
    );

    // Escrever o estímulo
    initial begin
        {j, k, rstn, clk} <= 0;
        #10 rstn <= 1;
        for (i = 0; i < 10; i = i+1) begin
            dly = $random;
            #(dly) j <= $random;
            #(dly) k <= $random;
        end
        #20 $finish;
    end
endmodule

Note na onda de simulação que na borda de subida do clock, a saída q muda valor baseado no estado das entradas j e k como dado na tabela-verdade.

Contador Módulo-10

Contadores de Módulo (MOD) simplesmente contam até um certo número antes de voltar a zero. Um contador MOD-N contará de 0 a N-1 e então voltará a zero e começará a contar novamente. Tais contadores tipicamente requerem log2N número de flops para reter o valor da contagem. Mostrado abaixo está o código Verilog para um contador MOD-10 que continua contando a cada clock clk enquanto reset rstn estiver desafirmado.

Parâmetros Verilog podem ser usados para tornar um contador MOD-N mais escalável.


module mod10_counter (
    input clk,
    input rstn,
    output reg [3:0] out
);
    always @ (posedge clk) begin
        if (!rstn) begin
            out <= 0;
        end else begin
            if (out == 10)
                out <= 0;
            else
                out <= out + 1;
        end
    end
endmodule

Testbench

O testbench primeiro declara algumas variáveis que podem ser atribuídas alguns valores e conduzidas às entradas do design. O módulo contador é então instanciado e conectado com os sinais do testbench que são posteriormente conduzidos com alguns valores no estímulo. Como o contador também requer um clock, o clock do testbench é modelado com um bloco always. O estímulo simplesmente define valores padrão no tempo 0ns, então desafirma reset após 10ns e o design é permitido rodar por algum tempo.


module tb;
    reg clk, rstn;
    reg [3:0] out;

    mod10_counter u0 (
        .clk(clk),
        .rstn(rstn),
        .out(out)
    );

    always #10 clk = ~clk;

    initial begin
        {clk, rstn} <= 0;
        #10 rstn <= 1;
        #450 $finish;
    end
endmodule

Veja que o módulo contador conta de zero a 9, volta para zero e começa a contar novamente.

Registrador de Deslocamento à Esquerda de 4 bits

Mostrado abaixo está um registrador de deslocamento à esquerda de 4 bits que aceita uma entrada d no LSB e todos os outros bits serão deslocados à esquerda por 1. Por exemplo, se d for igual a zero e o valor inicial do registrador for 0011, ele se tornará 0110 na próxima borda do clock clk.


module lshift_4b_reg (
    input d,
    input clk,
    input rstn,
    output reg [3:0] out
);
    always @ (posedge clk) begin
        if (!rstn) begin
            out <= 0;
        end else begin
            out <= {out[2:0], d};
        end
    end
endmodule

Testbench

O testbench segue um modelo similar ao mostrado antes onde algumas variáveis são declaradas, módulo de design é instanciado e conectado com os sinais do testbench. Então um clock é iniciado e o estímulo é conduzido ao design usando um bloco initial. Neste exemplo de testbench, diferentes valores de d têm que ser exercidos e portanto um loop for é usado para iterar 20 vezes e aplicar valores aleatórios ao design.


module tb;
    reg clk, rstn, d;
    wire [3:0] out;
    integer i;

    lshift_4b_reg u0 (
        .d(d),
        .clk(clk),
        .rstn(rstn),
        .out(out)
    );

    always #10 clk = ~clk;

    initial begin
        {clk, rstn, d} <= 0;
        #10 rstn <= 1;
        for (i = 0; i < 20; i=i+1) begin
            @(posedge clk) d <= $random;
        end
        #10 $finish;
    end
endmodule

Note que cada bit é deslocado à esquerda por 1 e o novo valor de d é aplicado ao LSB.

Verilog

  1. Dominando VHDL & Verilog: Escrevendo Lógica Combinacional e Sequencial Limpa
  2. Circuito com Chave: Guia Prático para Circuitos Elétricos Básicos
  3. Circuitos Integrados: Fundamentos de Portas Lógicas Digitais
  4. Controladores Lógicos Programáveis (CLPs): Controle Digital Moderno para Sistemas Industriais
  5. Entendendo Álgebra Booleana: Dos Fundamentos Lógicos a Circuitos Digitais
  6. Dominando Simplificação Lógica com Mapas de Karnaugh
  7. Lógica Digital com Realimentação: De Portas Determinísticas a Multivibradores
  8. Projeto de Contador Mod-N em Verilog: Módulo Parametrizado e Testbench
  9. Módulo Contador Gray em Verilog – Gerador de Código Gray de 4 Bits
  10. Obtenha Acabamentos Perfeitos com as Retificadoras de Precisão Okamoto