André Castelan
"Em teoria não há diferença entre a pratica e a teoria, já na pratica..."

sábado, 20 de julho de 2013

Implementação de um shift register em VHDL

Boa noite,

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.

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;  
 end architecture RTL;  

Nosso registrador de 4 bits está representado pelo dado_registrado e somente o ultimo 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.

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 pulso de clocks 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;  


Nenhum comentário:

Postar um comentário