Shift registers são elementos comuns em sistemas digitais utilizados para os mais diversos fins, como por exemplo: conversão de dados serial-paralelo e vice-versa; geração de atrasos; contadores e etc.
Um shift register nada mais é do que um array de flip-flops conectados em um mesmo clock de forma que a cada pulso de clock a entrada de um flip-flop recebe o valor da saída de seu anterior. Desta forma a cada pulso de clock o flip-flop n+1 recebe o valor de n. A Figura 1 retirada da wikipedia retrata o circuito.

Vamos representar este comportamento em VHDL, para isto vamos descrever o comportamento do circuito da Figura 1 em VHDL, como entrada temos o data_in representado pelo sinal dado_entrada e como saída o Q4(dado_registrado(3)) é o nosso dado_saida.
library ieee;
use ieee.std_logic_1164.all;
ENTITY shift_register IS
port
(
sys_clk : in std_logic;
sys_rst : in std_logic;
dado_entrada : in std_logic;
dado_saida : out std_logic
);
end shift_register;
architecture RTL of shift_register is
signal dado_registrado : std_logic_vector (3 downto 0);
begin
dado_saida <= dado_registrado(3);
process(sys_clk,sys_rst)
begin
if (sys_rst = '1') then
dado_registrado <= "0000";
elsif rising_edge(sys_clk) then
dado_registrado(0) <= dado_entrada;
dado_registrado(1) <= dado_registrado(0);
dado_registrado(2) <= dado_registrado(1);
dado_registrado(3) <= dado_registrado(2);
end if;
end process;
Nosso registrador de 4 bits está representado pelo dado_registrado e somente o último bit deste registrador é enviado para a saída. Como podemos ver a cada pulso de clock o valor do flip-flop recebe o valor de seu antecessor, sendo assim são necessários 4 pulsos de clock para que o valor de entrada passe por todos os flip-flops e vá para a saída como mostra a simulação na Figura 2.

Outra forma de se implementar o mesmo shift register utilizando menos linhas o que é muito útil quando se tem um maior número de bits (imagine só escrever 512 linhas para um shift register de 512 bits) é alterar o process da seguinte forma:
process(sys_clk,sys_rst)
begin
if (sys_rst = '1') then
dado_registrado <= "0000";
elsif rising_edge(sys_clk) then
dado_registrado(0) <= dado_entrada;
dado_registrado(3 downto 1) <= dado_registrado(2 downto 0);
end if;
end process;
end architecture RTL;
O funcionamento é idêntico, todos os flip-flops recebem os valores dos seus anteriores a cada pulso de clock. Neste caso os bits 3 2 1 vão receber os bits 2 1 0 e o 0 será atualizado. (mesmo comportamento)
Este código também pode ser utilizado como um conversor serial-paralelo, a cada 4 pulsos de clock você tem uma palavra paralela de 4 bits em um registrador. Incrivelmente simples, não?
No caso de um contador em anel basta ligar a saída do ultimo flip-flop a entrada do primeiro e fazer com que no reset um dos flip-flops assuma o valor de ‘1’. Teremos a sequência infinita de {0001}, {0010}, {0100}, {1000}, {0001} …
O testbench utilizado neste post caso queiram se divertir:
library ieee;
use ieee.std_logic_1164.all;
-------------------------------------------------------------------------------
entity tb_shift_register is
end entity tb_shift_register;
-------------------------------------------------------------------------------
architecture tb of tb_shift_register is
signal sysclk : std_logic;
signal reset_n : std_logic := '0';
signal entrada_simulacao : std_logic := '0';
signal saida_simulacao : std_logic;
-- clock
signal Clk : std_logic := '1';
begin
-- component instantiation
DUT : entity work.shift_register
port map (
sys_clk => sysclk,
sys_rst => reset_n,
dado_entrada => entrada_simulacao,
dado_saida => saida_simulacao);
-- clock generation
Clk <= not Clk after 5 ns;
sysclk <= Clk;
process
begin
reset_n <= '1';
wait for 10 ns;
reset_n <= '0';
wait for 10 ns;
entrada_simulacao <= '1';
wait for 10 ns;
entrada_simulacao <= '0';
wait;
end process;
end architecture tb;










Bom dia, nesse exemplo o deslocamento está ocorrendo para direita, como eu faria para um deslocamento para esquerda?
Acho que seria interessante um curso por partes sobre VHDL ou Verilog com exemplos, estou precisando de um desses… Aliás, aproveitando a deixa, vocês que são mais experientes nessa questão, qual livro/site indicariam para iniciar o estudo?
Olá Sandro fiz alguns posts sobre o básico de VHDL : https://embarcados.com.br/vhdl-basico-parte-1-entidade/ https://embarcados.com.br/vhdl-basico-parte-2-arquitetura/ e estou com turmas abertas para o treinamento em FPGA aos sábados junto com a Macnica DHW: https://embarcados.com.br/treinamentofpga/ , como livro gosto de indicar os do Pong. Chu. Para VHDL Este : RTL Hardware Design Using VHDL por Pong. P Chu
Fiz um post sobre alguns livros que li recentemente no meu antigo blog – https://www.andrecastelan.com.br/2013/08/livros-em-fpga.html
Opa, obrigado André! Vai ser muito útil no meu aprendizado.
Ola André, apenas um aporte para a coletividade
O processo
process(sys_clk,sys_rst)
begin
if (sys_rst = ‘1’) then
dado_registrado <= "0000";
elsif rising_edge(sys_clk) then
dado_registrado(0) <= dado_entrada;
dado_registrado(3 downto 1) <= dado_registrado(2 downto 0);
end if;
end process;
Pode ser simplificado usando o operador de concatenação.
ShiftReg : PROCESS(sys_clk,sys_rst)
BEGIN
IF (sys_rst = '1') THEN
dado_registrado <= "0000";
ELSE rising_edge(sys_clk) THEN
dado_registrado(3 downto 1) <= dado_registrado(2 downto 0) & dado_entrada;
END IF;
END PROCESS ShiftReg;
Além disto acho seria bom você comentar o uso do RESET neste casso.
Quem esta iniciando em VHDL poderia não conhecer os efeitos colaterais.
Atenciosamente
Walter
Verdade Walter, obrigado! Quis deixar como coloquei para ficar mais didático mas a sua solução é mais elegante. e no caso seria (3 downto 0) recebendo o 2 downto 0 & dado entrada
Fiz um post sobre esquemas de reset aqui: https://embarcados.com.br/arquiteturaresetfpga/ que discute o exemplo do reset assíncrono utilizado neste post.
abs
Opps, meu erro !! Esqueci de apagar os índices no exemplo, porem bom para ver quem esta atento ao código… Quanto ao RESET eu falava dos efeitos colaterais nos recursos usados na FPGA, Depende da arquitetura da FPGA e da ferramenta SIGNAL dado_registrado : STD_LOGIC_VECTOR(3 DOWNTO 0) := “0000”; — Depende da ferramenta pode ser ignorado na implementação. ShiftReg : PROCESS(sys_clk) BEGIN IF rising_edge(sys_clk) THEN dado_registrado <= dado_registrado(2 downto 0) & dado_entrada; END IF; END PROCESS ShiftReg; Se a arquitetura da FPGA aceita esse ShiftReg seria implementado em LUT sem usar FF passando de consumir 4 FF para 0 FF.… Leia mais »
Ah sim, inicialização de sinais desta forma serve tão somente para simulação e não para síntese.
E também é verdade que dependendo da arquitetura de FPGA ele usaria uma estrutura do próprio FPGA e não gastaria lógica/memória. Se não me engano, na Xilinx, essa codificação sem reset faria isto.
Ótimas observações Walter! Obrigado
abs
Correto, um VHDL genérico, mais a implementação depende da ferramenta e da arquitetura no casso da Xilinx não usaria FF.
Apenas para complementar
SIGNAL dado_registrado : STD_LOGIC_VECTOR(3 DOWNTO 0) := “0000”;
No casso do XST ( Sínteses Xilinx ) seria aceito para simulação e sínteses.
Abraços,
Walter
Obrigado pelos comentários!
Abs