Implementação de um shift register em VHDL

shift register

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.

 

 

shift register
Figura 1. Shift register de 4 bits

 

 

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.

 

shift register
Figura 2. Funcionamento do Shift Register

 

 

 

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;  

 

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

9
Deixe um comentário

avatar
 
2 Comment threads
7 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
Sandro DutraAndré CastelanWalter Gallegos Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Sandro Dutra
Visitante
Sandro Dutra

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?

André Castelan
Visitante

Olá Sandro fiz alguns posts sobre o básico de VHDL : http://embarcados.com.br/vhdl-basico-parte-1-entidade/ http://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: http://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 - http://www.andrecastelan.com.br/2013/08/livros-em-fpga.html

Sandro Dutra
Visitante
Sandro Dutra

Opa, obrigado André! Vai ser muito útil no meu aprendizado.

Walter Gallegos
Visitante

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

André Castelan
Visitante

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: http://embarcados.com.br/arquiteturaresetfpga/ que discute o exemplo do reset assíncrono utilizado neste post.

abs

Walter Gallegos
Visitante

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 »

André Castelan
Visitante

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

Walter Gallegos
Visitante

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

André Castelan
Visitante

Obrigado pelos comentários!
Abs