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.
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