Registrador de Deslocamento Bidirecional de N Bits em Verilog – Projeto e Implementação
Na eletrônica digital, um registrador de deslocamento é uma cascata de flip-flops onde o pino de saída q de um flop é conectado ao pino de entrada de dados (d) do próximo. Como todos os flops trabalham no mesmo clock, o array de bits armazenado no registrador de deslocamento será deslocado em uma posição. Por exemplo, se um registrador de deslocamento à direita de 5 bits tem um valor inicial de 10110 e a entrada do registrador de deslocamento está ligada a 0, então o próximo padrão será 01011 e o seguinte 00101.
Projeto
Este projeto de registrador de deslocamento tem cinco entradas e uma saída de n bits e o projeto é parametrizado usando parameter MSB para significar a largura do registrador de deslocamento. Se n é 4, então se torna um registrador de deslocamento de 4 bits. Se n é 8, então se torna um registrador de deslocamento de 8 bits.
Este registrador de deslocamento tem alguns recursos principais:
- Pode ser habilitado ou desabilitado conduzindo o pino en do projeto
- Pode deslocar para a esquerda e para a direita quando dir é conduzido
- Se rstn for puxado para baixo, resetará o registrador de deslocamento e a saída se tornará 0
- O valor de dado de entrada do registrador de deslocamento pode ser controlado pelo pino d
module shift_reg #(parameter MSB=8) (
input d, // Declara entrada para dados ao primeiro flop no registrador de deslocamento
input clk, // Declara entrada para clock para todos os flops no registrador de deslocamento
input en, // Declara entrada para enable para ligar/desligar o registrador de deslocamento
input dir, // Declara entrada para deslocar em direção esquerda ou direita
input rstn, // Declara entrada para resetar o registrador para um valor padrão
output reg [MSB-1:0] out // Declara saída para ler o valor atual de todos os flops neste registrador
);
// Este bloco always será "sempre" disparado na borda de subida do clock
// Uma vez que entra no bloco, primeiro verifica se reset é 0 e se sim então reseta registrador
// Se não, então verifica se o registrador de deslocamento está habilitado
// Se não => mantém saída anterior. Se sim, então desloca baseado na direção solicitada
always @ (posedge clk)
if (!rstn) out <= 0;
else begin
if (en)
case (dir)
0: out <= {out[MSB-2:0], d};
1: out <= {d, out[MSB-1:1]};
endcase
else out <= out;
end
endmodule
Esquemático de Hardware
Testbench
O testbench é usado para verificar a funcionalidade deste registrador de deslocamento. O projeto é instanciado no module superior e as entradas são conduzidas com diferentes valores. O comportamento do projeto para cada uma das entradas pode ser observado no pino de saída out.
module tb_sr;
parameter MSB = 16; // [Opcional] Declara um parâmetro para representar número de bits no registrador de deslocamento
reg data; // Declara uma variável para conduzir d-input do projeto
reg clk; // Declara uma variável para conduzir clock ao projeto
reg en; // Declara uma variável para conduzir enable ao projeto
reg dir; // Declara uma variável para conduzir direção do registrador de deslocamento
reg rstn; // Declara uma variável para conduzir reset ao projeto
wire [MSB-1:0] out; // Declara um wire para capturar saída do projeto
// Instancia projeto (registrador de deslocamento de 16 bits) passando MSB e conecta com sinais do TB
shift_reg #(MSB) sr0 (
.d(data),
.clk(clk),
.en(en),
.dir(dir),
.rstn(rstn),
.out(out)
);
// Gera clock período = 20ns, freq => 50MHz
always #10 clk = ~clk;
// Inicializa variáveis para valores padrão no tempo 0
initial begin
clk <= 0;
en <= 0;
dir <= 0;
rstn <= 0;
data <= 'h1;
end
// Conduz estímulo principal ao projeto para verificar se funciona
initial begin
// 1. Aplica reset e desassserta reset após algum tempo
rstn <= 0;
#20 rstn <= 1;
en <= 1;
// 2. Por 7 clocks, conduz valores alternados ao pino de dados
repeat (7) @ (posedge clk) data <= ~data;
// 4. Muda direção e conduz valor alternado ao pino de dados por mais 7 clocks
#10 dir <= 1;
repeat (7) @ (posedge clk) data <= ~data;
// 5. Não conduz nada por próximos 7 clocks, permite registrador simplesmente deslocar baseado em dir
repeat (7) @ (posedge clk);
// 6. Finaliza a simulação
$finish;
end
// Monitora valores destas variáveis e imprime no log para debug
initial $monitor("rstn=%0b data=%b, en=%0b, dir=%0b, out=%b", rstn, data, en, dir, out);
endmodule
O tempo quando o registrador de deslocamento está habilitado está destacado em verde no log abaixo. O tempo quando ele muda sua direção está destacado em amarelo. O tempo quando o pino de entrada de dados permanece constante está destacado em azul.
Log de Simulação
ncsim> run rstn=0 data=1, en=0, dir=0, out=xxxxxxxxxxxxxxxx rstn=0 data=1, en=0, dir=0, out=0000000000000000 rstn=1 data=1, en=1, dir=0, out=0000000000000000 rstn=1 data=0, en=1, dir=0, out=0000000000000001 rstn=1 data=1, en=1, dir=0, out=0000000000000010 rstn=1 data=0, en=1, dir=0, out=0000000000000101 rstn=1 data=1, en=1, dir=0, out=0000000000001010 rstn=1 data=0, en=1, dir=0, out=0000000000010101 rstn=1 data=1, en=1, dir=0, out=0000000000101010 rstn=1 data=0, en=1, dir=0, out=0000000001010101 rstn=1 data=0, en=1, dir=1, out=0000000001010101 rstn=1 data=1, en=1, dir=1, out=0000000000101010 rstn=1 data=0, en=1, dir=1, out=1000000000010101 rstn=1 data=1, en=1, dir=1, out=0100000000001010 rstn=1 data=0, en=1, dir=1, out=1010000000000101 rstn=1 data=1, en=1, dir=1, out=0101000000000010 rstn=1 data=0, en=1, dir=1, out=1010100000000001 rstn=1 data=1, en=1, dir=1, out=0101010000000000 rstn=1 data=1, en=1, dir=1, out=1010101000000000 rstn=1 data=1, en=1, dir=1, out=1101010100000000 rstn=1 data=1, en=1, dir=1, out=1110101010000000 rstn=1 data=1, en=1, dir=1, out=1111010101000000 rstn=1 data=1, en=1, dir=1, out=1111101010100000 rstn=1 data=1, en=1, dir=1, out=1111110101010000 Simulação completa via $finish(1) no tempo 430 NS + 0
Verilog
- Domine o Verilog: Tutorial Completo para Projeto de Circuitos Digitais
- Dominando Concatenação Verilog: Guia Prático
- Entendendo Atribuições em Verilog: Tipos, Sintaxe e Boas Práticas
- Verilog Blocking vs Non-Blocking: Diferenças Essenciais Explicadas
- Dominando Funções em Verilog para Design RTL Eficiente
- Entendendo Tasks em Verilog: Funções vs Tasks, Sintaxe e Uso
- Gerador de Clock Verilog: Guia de Design e Implementação
- Dominando Funções Matemáticas do Verilog para Design de Hardware Eficiente
- Dominando $timeformat do Verilog: Precisão e Controle de Exibição
- Entendendo e Imprimindo Timescales do Verilog em Qualquer Escopo