Projektujemy rejestr szeregowo-równoległy 1


Rejestr szeregowo równoległy jest układem którego wejście jest szeregowe 1-bitowe natomiast wyjście jest równoległe n-bitowe

Taki układ przesuwa dane w takt zegara. W takim razie nie ma żadnej trudności z napisaniem takiego układu. Można również zaprojektować go w dowolny sposób tzn. (dla przypomnienia) behavioralny (zachowanie układu), RTL (Register Transfer Level), albo na poziomie bramek. My jednak dla uproszczenia zaprojektujmy go behavioralnie.

Założenia projektu

Załóżmy, że chcemy aby szerokość magistrali mogła być zmieniana za pomocą stałych w części generic. Takie rozwiązanie pozwoli nam na późniejsze wykorzystanie tego układu w innych projektach. Na początek załóżmy 8-bitowe wyjście.
Chcemy również aby była możliwość asynchronicznego wyczyszczenia rejestru zapisując go wyłącznie zerami..
Wejście -> 1-bitowe
Przesuwane w takt zegara – CLK

Opis wyprowadzeń

entity SHIFT_REGISTER is
    generic(
        BUS_WIDTH : INTEGER := 8 );
    port(
        CLK     : IN STD_LOGIC;
        RST_N   : IN STD_LOGIC;
        DATA_IN : IN STD_LOGIC;
        DATA_OUT: BUFFER STD_LOGIC_VECTOR(BUS_WIDTH-1 downto 0) := (OTHERS => '0') );
end SHIFT_REGISTER;

Tutaj widzimy, że wystarczy zmienić wartość BUS_WIDTH, żeby od razu zmieniła się szerokość magistrali. Wygląda to dosyć niepotrzebne bo przecież możnaby wprowadzić po prostu liczbę żeby opisała nam magistralę. Tutaj to może tak wyglądać – jednakże przy większych projektach jest to wręcz konieczne zachowanie.
Ważnym również uwagi jest opisanie wyjścia jako BUFFER – jest to konieczne zachowanie ze względu na potrzebę odczytu poprzedniej wartości wyjścia w opisie behavioralnym w celu utworzenia nowej wartości.

Opis architektury

architecture Behavioral of SHIFT_REGISTER is
begin
    process(CLK,RST_N,DATA_IN)
        variable TEMP : STD_LOGIC_VECTOR(BUS_WIDTH-1 downto 0);
    begin
        if RST_N = '0' then
            TEMP := (OTHERS => '0');
        elsif rising_edge(CLK) then
            TEMP := DATA_OUT;
            TEMP := TEMP(BUS_WIDTH-2 downto 0) & DATA_IN;
        end if;
 
        DATA_OUT <= TEMP;
    end process;
end Behavioral;

W procesie reagującym wyłącznie na narastające zbocze sygnału zegarowego (na liście czułości jest DATA_IN, ale jego zmiana nie wpłynie na zmianę wyjścia ze względu na funkcję rising_egde w warunku „if”) dodałem zmienną pomocniczą, która najpierw przyjmuje wartość naszego wejścia, a kolejnie jest uaktualniona przez n-1 poprzednich bitów starej wartości sklejonych z wartością wejścia DATA_IN.
Na sam koniec zapisujemy do wyjścia nasze przekształcenie.

Cały plik

library IEEE;
use IEEE.STD_LOGIC_1164.all;
 
entity SHIFT_REGISTER is
    generic(
        BUS_WIDTH : INTEGER := 8 );
    port(
        CLK     : IN STD_LOGIC;
        RST_N   : IN STD_LOGIC;
        DATA_IN : IN STD_LOGIC;
        DATA_OUT: BUFFER STD_LOGIC_VECTOR(BUS_WIDTH-1 downto 0) := (OTHERS => '0') );
end SHIFT_REGISTER;
 
architecture Behavioral of SHIFT_REGISTER is
begin
    process(CLK,RST_N,DATA_IN)
        variable TEMP : STD_LOGIC_VECTOR(BUS_WIDTH-1 downto 0);
    begin
        if RST_N = '0' then
            TEMP := (OTHERS => '0');
        elsif rising_edge(CLK) then
            TEMP := DATA_OUT;
            TEMP := TEMP(BUS_WIDTH-2 downto 0) & DATA_IN;
        end if;
 
        DATA_OUT <= TEMP;
    end process;
end Behavioral;

Na załączonej symulacji widać, że układ działa bardzo dobrze.

Ten układ może być przydatny np. do implementacji protokołu SPI w naszym urządzeniu.

One thought on “Projektujemy rejestr szeregowo-równoległy”

  1. Misiek

    W tekście pod opisem architektury masz drobny błąd, zamiast „…przyjmuje wartość naszego WEJŚCIA” powinno być WYJŚCIA – podkreślałeś nawet początkowo, że jest to dozwolone poprzez tryb portu BUFFER.
    W każdym razie fajnie wszystko rozpisałeś ;]

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Rating*