Desenhe o circuito esquemático do contador correspondente ao código em Verilog a seguir utilizando Flip-flops do tipo JK.
module counter (input wire clk, input wire rst);
    reg [2:0] cnt;
    always @ (posedge clk or posedge rst) begin
        if(rst) cnt[0] <= 1'b0;
        else cnt[0] <= ~cnt[0];
    end
    always @(negedge cnt[0] or posedge rst) begin
        if(rst) cnt[1] <= 1'b0;
        else cnt[1] <= ~cnt[1];
    end
    always @(negedge cnt[1] or posedge rst) begin
        if(rst) cnt[2] <= 1'b0;
        else cnt[2] <= ~cnt[2];
    end
endmodule

Passo 1

O enunciado pede: “Desenhe o circuito esquemático do contador correspondente ao código em Verilog a seguir utilizando Flip-flops do tipo JK.”
Informações relevantes extraídas do código (copiadas/interpretadas do enunciado):
  • Entradas: clk e rst.
  • Registradores: cnt[2:0] (ou seja, cnt[0], cnt[1], cnt[2]).
  • Blocos always:
    • Para cnt[0]: sensível a posedge\;clk e posedge\;rst. No reset cnt[0] recebe 1'b0; caso contrário, em cada posedge\;clk faz cnt[0] \leftarrow \lnot cnt[0].
    • Para cnt[1]: sensível a negedge\;cnt[0] e posedge\;rst. No reset cnt[1] recebe 1'b0; caso contrário, em cada negedge\;cnt[0] faz cnt[1] \leftarrow \lnot cnt[1].
    • Para cnt[2]: sensível a negedge\;cnt[1] e posedge\;rst. No reset cnt[2] recebe 1'b0; caso contrário, em cada negedge\;cnt[1] faz cnt[2] \leftarrow \lnot cnt[2].
  • O comportamento geral: é um contador ripple (divisor por 2 por estágio), onde cnt[0] alterna em cada borda de subida de clk; cnt[1] alterna em cada borda de descida de cnt[0]; cnt[2] alterna em cada borda de descida de cnt[1].
  • O reset rst é assíncrono (porque aparece em posedge rst nas sensibilidade): quando rst=1 todos os bits são forçados a 0 imediatamente.

Passo 2

O que precisamos implementar com JK flip-flops:
  • Cada bit cnt[i] vira a saída Q_i de um flip-flop JK.
  • Cada flip-flop tem comportamento “toggle” (inverte Q no evento de clock do seu bloco always).
  • O reset deve ser assíncrono e forçar Q_i=0 quando rst=1.
  • Os clocks dos estágios 1 e 2 devem responder às bordas de descida de cnt[0] e cnt[1], respectivamente.
Antes de desenhar, formalizo o que significa “toggle” com JK: colocar J=K=1 faz o flip-flop inverter sua saída no evento ativo do clock (bordas especificadas pelo tipo de FF).

Passo 3

Mini-aula sobre o flip-flop JK (o que vou usar):
  • O FF JK tem entradas J e K, saída atual Q e próxima saída Q^{+}. A equação booleana do próximo estado é:
Q^{+} = J\overline{Q} + \overline{K}Q.
  • Casos importantes:
    • J=K=0 => seguram estado ( Q^{+}=Q).
    • J=1, K=0 => set ( Q^{+}=1).
    • J=0, K=1 => reset ( Q^{+}=0).
    • J=K=1 => toggle ( Q^{+}=\overline{Q}).
  • Para obter o comportamento do código (inversão a cada evento de clock do bloco), escolhe-se J=K=1 no FF.
  • Reset assíncrono: muitos símbolos de FF têm entrada CLR (clear) assíncrona. Como no Verilog o reset é assíncrono e força a zero na borda de rst, ligar rst à entrada de clear assíncrona (ativa em nível alto) implementa exatamente aquele comportamento.

Passo 4

Mapeamento direto do Verilog para JK-FFs:
  • Para cnt[0]:
    • Usar um JK flip-flop (positivo-edge triggered) com J=K=1 para obter toggle em cada borda ativa.
    • Ligar o clock deste FF a clk para que o toggle ocorra em posedge\;clk.
    • Ligar rst à entrada de clear assíncrona do FF (ativa em nível alto) para forçar Q_0=0 quando rst=1.
    • A saída Q_0 será cnt[0].
  • Para cnt[1]:
    • Desejamos toggle em negedge\;cnt[0]. Se tivermos um FF JK de borda positiva (prático no desenho), podemos inverter cnt[0] e usar a saída invertida como clock: a posedge do \lnot cnt[0] corresponde à negedge de cnt[0].
    • Portanto: colocar um inversor com entrada cnt[0] e saída \lnot cnt[0]; ligar \lnot cnt[0] ao clock do segundo JK-FF (positivo-edge triggered). Novamente J=K=1.
    • Ligar rst à clear assíncrona do segundo FF.
    • A saída Q_1 será cnt[1].
  • Para cnt[2]:
    • Analogamente, precisamos de toggle em negedge\;cnt[1]. Inserir um inversor em cnt[1] e usar \lnot cnt[1] como clock do terceiro JK-FF (positivo-edge triggered).
    • Definir J=K=1 e ligar rst à clear assíncrona do terceiro FF.
    • A saída Q_2 será cnt[2].
Observação sobre alternativa: se forem usados JK-FFs com trigger em borda negativa nativa, pode-se conectar diretamente cnt[0] ao clock do FF1 e cnt[1] ao clock do FF2 sem inversores. Aqui descrevo a solução usando inversores porque é comum desenhar com FFs de borda positiva.

Passo 5

Detalhes elétricos e cuidados práticos (o que anotar no esquema):
  • Os sinais de clock que vêm de saídas de FF ( cnt[0] e cnt[1]) servindo como clock para outros FFs geram um contador do tipo ripple (assíncrono). Isso é exatamente o comportamento do Verilog original (blocos sensitive a negedge do bit anterior). No desenho, aceitar que há atraso de propagação entre os estágios — é esperado em ripple counters.
  • As ligações:
    • J_0 = K_0 = 1. CLK_0 \leftarrow clk. CLR_0 \leftarrow rst. Q_0 = cnt[0].
    • J_1 = K_1 = 1. CLK_1 \leftarrow \lnot cnt[0] (inversor entre cnt[0] e CLK_1). CLR_1 \leftarrow rst. Q_1 = cnt[1].
    • J_2 = K_2 = 1. CLK_2 \leftarrow \lnot cnt[1] (inversor entre cnt[1] e CLK_2). CLR_2 \leftarrow rst. Q_2 = cnt[2].
  • Se o símbolo do JK-FF no esquema possuir entradas \overline{CLR} (clear ativa baixa) ao invés de clear ativa alta, o arranjo de reset deve ser adaptado (por exemplo, usar inversor em rst etc.). No entanto, o código Verilog assume clear ativa em nível alto, então no esquema eu assumo entradas CLR ativas em nível alto.

Passo 6

Descrição esquemática final (passo a passo para desenhar o diagrama):
  1. Desenhar três blocos de flip-flop JK empilhados verticalmente: FF_0, FF_1, FF_2. Em cada bloco indicar entradas J, K, CLK, CLR e saída Q.
  2. Em cada FF_i conectar J e K ao nível lógico 1: escrever J_i = K_i = 1.
  3. Ligar rst à entrada CLR de todos os FFs (sinal comum). Escrever CLR_i \leftarrow rst para i=0,1,2.
  4. Para FF_0:
    • Ligar CLK_0 \leftarrow clk.
    • Sair Q_0 e rotular como cnt[0].
  5. Para FF_1:
    • Colocar um inversor cujo input é Q_0 (ou cnt[0]); a saída do inversor é \lnot cnt[0].
    • Ligar CLK_1 \leftarrow \lnot cnt[0] (saída do inversor).
    • Sair Q_1 e rotular como cnt[1].
  6. Para FF_2:
    • Colocar um inversor cujo input é Q_1 (ou cnt[1]); a saída é \lnot cnt[1].
    • Ligar CLK_2 \leftarrow \lnot cnt[1] (saída do segundo inversor).
    • Sair Q_2 e rotular como cnt[2].
  7. Opcional (observação prática no diagrama): indicar que cada inversor implementa a conversão de borda negativa desejada (ou substituir por FFs de borda negativa se disponível).

Passo 7

Representação textual condensada do esquema (próxima caixa que serve como “desenho” textual — usar isto para transpor para um diagrama esquemático gráfico):
  • Componentes:
    • FF_0: JK-FF (posedge), entradas: J_0=1,\;K_0=1; CLK_0 \leftarrow clk; CLR_0 \leftarrow rst; Q_0 \rightarrow cnt[0].
    • FF_1: JK-FF (posedge), entradas: J_1=1,\;K_1=1; CLK_1 \leftarrow saída do inversor em cnt[0] (ou seja, CLK_1=\lnot cnt[0]); CLR_1 \leftarrow rst; Q_1 \rightarrow cnt[1].
    • FF_2: JK-FF (posedge), entradas: J_2=1,\;K_2=1; CLK_2 \leftarrow saída do inversor em cnt[1] (ou seja, CLK_2=\lnot cnt[1]); CLR_2 \leftarrow rst; Q_2 \rightarrow cnt[2].
  • Interconexões:
    • cnt[0] = Q_0 feed → inversor → CLK_1.
    • cnt[1] = Q_1 feed → inversor → CLK_2.
    • Reset comum: rst CLR_0, CLR_1, CLR_2.

Resposta

FF0: JK-FF com J_0=K_0=1, CLK_0 \leftarrow clk, CLR_0 \leftarrow rst, Q_0 = cnt[0]
FF1: JK-FF com J_1=K_1=1, CLK_1 \leftarrow \lnot cnt[0] (inversor entre cnt[0] e CLK_1), CLR_1 \leftarrow rst, Q_1 = cnt[1]
FF2: JK-FF com J_2=K_2=1, CLK_2 \leftarrow \lnot cnt[1] (inversor entre cnt[1] e CLK_2), CLR_2 \leftarrow rst, Q_2 = cnt[2]

Exercícios relacionados