Skocz do zawartości

FPGA(własne badania #2) Sprzętowy układ mnożący - Spartan3A


FlyingDutch

Pomocna odpowiedź

Cześć,

zamieszczam drugą część moich prób dotyczących optymalizacji układów budowanych przy pomocy układu Spartan 3A (XC3S50A) z zestawu "Elbert V2". Tematy tych prób dotyczą bardziej efektywnej syntezy układu cyfrowego poprzez wykorzystanie wewnętrznych specjalizowanych zasobów układu FPGA.

Drugim tematem, który wziąłem pod uwagę jest efektywne wykonywanie operacji matematycznych (dla liczb stało i zmienno-pozycyjnych). jedną z takich operacji jest mnożenie liczb. Rozpocznijmy od liczb stało-pozycyjnych: można zbudować układ mnożący dwie liczby o ustalonej długości (bez znaku lub ze znakiem) syntetyzując go z uniwersalnych zasobów FPGA (4-wejściowe LUT), jednakże takie rozwiązanie pochłonie bardzo dużą liczbę zasobów LUT z naszego układu FPGA. Poza tym rozwiązanie takie będzie mniej wydajne jeśli chodzi o szybkość działania. Zamieszę później porównanie dla układu mnożącego dwie liczby 18-to bitowe ze znakiem.

Część układów z serii Spartan 3 (niestety nie kostka z zestawu Elbert) zawiera pewną ilości specjalizowanych bloków DSP przyśpieszających wykonywanie różnych operacji matematycznych. Zacząłem szukać w dokumentacji i okazało się, że chociaż wersja Spartan 3A użyta w Elbercie nie ma bloków DSP, to posiada wbudowane trzy specjalizowane układy mnożące (mnożenie dwóch liczb stało-pozycyjnych o długości do 18-tu bitów ze znakiem lub bez). Patrz nota "Using Embedded Multipliers

in Spartan-3 FPGAs" - strona 17 w tym dokumencie:

https://www.xilinx.com/support/documentation/application_notes/xapp467.pdf

Testy te mają pewien cel praktyczny: mianowicie chciałbym rozszerzyć zestaw operacji arytmetycznych prostego CPU, którego projekt zamieścił Elvis w tym dziale o mnożenie (aktualnie odejmowanie i dodawanie dwóch liczba 8-mio bitowych), oraz zwiększyć jego pamięć programu do 1024 słów 8-mio bitowych (emulacja ROM w block RAM Spartana 3A - pierwszy post z tej serii).

Ponownie okazuje się, że najprostszym sposobem osiągnięcia tego celu jest użycie "IP Core" generatora ze środowiska "ISE Webpack" Xilinxa. Oto czynności jakie należy wykonać:

Zakładamy nowy projekt w "ISE" (ja nazwałem go "Multiplier1"). Klikamy prawym klawiszem na pliku projektu (w ISE) i wybieramy "New Source.." i wybieramy "VHDL Module" nadajemy mu nazwę "Multiplier" klikamy dalej (nie deklarujemy portów). Otwieramy nowe źródło i modyfikujemy treść następująco:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Multiplier is
   Port ( clki : in  STD_LOGIC;
          ai : in  STD_LOGIC_VECTOR (7 downto 0);
          bi : in  STD_LOGIC_VECTOR (7 downto 0);
          po : out  STD_LOGIC_VECTOR (15 downto 0));
end Multiplier;

architecture Behavioral of Multiplier is

begin

end Behavioral;

Następnie znowu wybieramy opcję "New Source .." i z menu kontekstowego wybieramy opcję "IP (CORE Generator & Architecture Wizard)" w polu "File name:" wpisujemy multiply1

Patrz obrazek:

klikamy "Next" następnie w oknie "Select IP" rozwijamy grupę "Math Functions" -> "Multipliers" (ważne jerst aby checkbox "Only IP compatible with choosen part" był zaznaczony.Patrz zrzut ekranu:

Umieszczamy kursor na pozycji "Multipler 11.2" i klikamy "Next" a potem "finish".Po pewnym czasie pokaże się okno parametrów IP core (układu mnożącego) - patrz obrazek:

Jak widzimy nasz IP Core domyślnie jest skonfigurowany tak aby mnożyć dwie liczby stało-pozycyjne o długości 18 bitów ze znakiem, oraz zakłada iż układ mnożący będzie zbudowany z LUTs układu FPGA. Taki układ zająłby 364 4-ro wejściowe LUT z układu FPGA (górny lewy fragment okna poniżej "Resource Estimates") co przy pojemności 1400 LUT dla całego układu jest bardzo dużą wartością. Zmieniamy parametry w tym oknie jak następuje:

Przy takich parametrach nasz układ mnożący będzie mnożył dwie liczby 8-mio bitowe bez znaku. Klikamy "next", a gdy pojwie się nastep0ne okno z parametrami zmieniamy "Multiplier Construction" na "Use Mults" i radio button "Optimization options" na "Area Optimized". Patrz zrzut ekranu:

i klikamy "Next", na następnym oknie parametrów IP core zmieniamy opcję "Pipeline Stages (z listy) na 4, i klikamy klawisz "Generate":

Czekamy dłuższy czas, aż IP Core układu mnożącego zostanie wygenerowany (w tym czasie w konsoli ISE przewijają się komunikaty dotyczące syntezy układu).

Gdy zakończy się generacja IP core w oknie "Design"-> Hierarchy pojawi się pozycja "multiply1 (multiply1.xco)" - jest to właśnie nasz układ mnożący jako "IP Core".

Zaznaczamy tą pozycję myszą i w okienku poniżej procesów) rozwijamy pozycję "CORE Generator" zaznaczamy pozycję "View HDL Instantation Template" i prawym klawiszem myszy wybieramy z menu "Run". Otworzy się template z kodem VHDL, który należy przekleić do głównego pliku projektu z entity " Multiplier" (VHDL). Docelowy kod zawarrty w pliku projektu "Multiplier.vhd" powinien wyglądać nastepująco:


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Multiplier is
   Port ( clki : in  STD_LOGIC;
          ai : in  STD_LOGIC_VECTOR (7 downto 0);
          bi : in  STD_LOGIC_VECTOR (7 downto 0);
          po : out  STD_LOGIC_VECTOR (15 downto 0));
end Multiplier;

architecture Behavioral of Multiplier is

COMPONENT multiply1
 PORT (
   clk : IN STD_LOGIC;
   a : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
   b : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
   p : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
 );
END COMPONENT;

begin

uk_mnozacy : multiply1
 PORT MAP (
   clk => clki,
   a => ai,
   b => bi,
   p => po
 );

end Behavioral;

Następnie zanaczamy w oknie "Design" ISE "Multiplier" i zielonym Klawiszem Run uruchamiamy syntezę projektu (tak jak synteza każdego dotychczas opisywanego układu) patrz kurs FPGA Forbot. Poz syntezie jak widać z podsumowania nasz układ mnożący zajmuje 16 LUT układu, oraz wykorzystany jest jeden z trzech sprzętowych układów mnożących Spartana 3A - patrz zrzut ekranu:

UWAGA! - celowo nie zamieszczałem pliku ucf ponieważ występują tu dwie magistrale 8-mio bitowe (mnożone liczby bez znaku) i jedna 16-to bitowa (wynik mnożenia) i trzeba by w projekcie robić multipleksery na dane wprowadzane i wynik. Napisałem "test-bench" dla naszego projektu układu mnożącego, tak aby można było wykonać symulację czasową układu. Kod testu jest w pliku: "Mul_TSTB.vhd":

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

ENTITY Mul_TSTB IS
END Mul_TSTB;

ARCHITECTURE behavior OF Mul_TSTB IS 

   -- Component Declaration for the Unit Under Test (UUT)

   COMPONENT Multiplier
   PORT(
        clki : IN  std_logic;
        ai : IN  std_logic_vector(7 downto 0);
        bi : IN  std_logic_vector(7 downto 0);
        po : OUT  std_logic_vector(15 downto 0)
       );
   END COMPONENT;


  --Inputs
  signal clki : std_logic := '0';
  signal ai : std_logic_vector(7 downto 0) := (others => '0');
  signal bi : std_logic_vector(7 downto 0) := (others => '0');

	--Outputs
  signal po : std_logic_vector(15 downto 0);

  -- Clock period definitions
  constant clki_period : time := 10 ns;

BEGIN

-- Instantiate the Unit Under Test (UUT)
  uut: Multiplier PORT MAP (
         clki => clki,
         ai => ai,
         bi => bi,
         po => po
       );

  -- Clock process definitions
  clki_process :process
  begin
	clki <= '0';
	wait for clki_period/2;
	clki <= '1';
	wait for clki_period/2;
  end process;


  -- Stimulus process
  stim_proc: process
  begin		
     -- hold reset state for 100 ns.
     wait for 100 ns;	

     wait for clki_period*10;

     -- insert stimulus here 
	ai <= "11111111";
	bi <= "00000000";

	wait for clki_period*10;

	ai <= "11111111";
	bi <= "00000001";

	wait for clki_period*10;

	ai <= "11111111";
	bi <= "11111111";

	wait for clki_period*10;

	ai <= "00001000";
	bi <= "00001000";

	wait for clki_period*10;

	ai <= "00001010";
	bi <= "00001010";

     wait;
  end process;

END;

Jak widać co 10 okresów zegara są zmieniane dane wejściowe dla układu (mnożone liczby 8-mio bitowe bez znaku), wynik jest liczbą 16-to bitową bez znaku. Celowo skróciłem okres zegara do 10 ns, aby skrócić cały czas symulacji układu. Sami możecie sprawdzić, czy nasz układ działa prawidłowo dodać nowe wektory pobudzeń dla układu w pliku "Mul_TSTB.vhd".

Aby uruchomić symulację w onie ISE "Design" przełączamy radio-button na "Simulation", zaznaczamy w herarchi projektu "Mul_TSTB - bahavior (Mul_TSTB.vhd)" a woknie poniżej "Procesy" rozwijamy "ISim Simulator" zaznaczmy "Simulate Behavioral Model" i prawym klawiszem myszy z menu kontekstowego wybieramy "Run":

A oto wyniki symulacji:

Zachęcam wszystkich do korzystania z wewnętrznych zasobów układu FPGA Spartan 3A (znajdującego się w zestawie Elbert V2) przyspieszających pracę projektowanych układów - szczególnie wewnętrznej pamięci RAM oraz układów przyśpieszających operacje arytmetyczne (nie wypróbowałem jeszcze pętli PLL do generowania szybszego zegara dla naszej płytki). Zachęcam także do używania darmowych "IP Core" dostarczanych przez Xilinx'a razem ze środowiskiem "ISE Webpack", oraz darmowych IP cores z sieci WWW np ze strony "Opencores.org":

https://opencores.org/

W pliku załącznika "Multiplier1.zip" cały (z bench-testem i wygenerowanym IP corem) plik projektu "ISE Webpack" dla opisywanego układu mnożącego.

Pozdrawiam i życzę udanej reszty Świat 😃

Multiplier1.zip

  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.