KursyPoradnikiInspirujące DIYForum

Kurs FPGA – #7 – symulacja działania układu

Kurs FPGA – #7 – symulacja działania układu

Za nami kilka ćwiczeń praktycznych, wiemy już, że FPGA działa poprawnie i możemy tworzyć na jego podstawie przeróżne układy cyfrowe.

Podczas analizy bardziej złożonych projektów przydaje się możliwość symulowania tworzonego układu. Dzięki wykorzystaniu nowej funkcji ISE, otrzymamy wykresy (przebiegi czasowe), które pozwolą ocenić czy układ działa poprawnie.

Na tym etapie nauki VHDLa korzystanie z symulacji nie jest konieczne. Warto jednak wykonać ćwiczenia z tej części kursu FPGA, aby poznać możliwości naszego środowiska.

Symulacja działania układu FPGA z ISim

Symulacja "to potężne narzędzie", które pozwala na tworzenie jeszcze lepszych układów. Jest to ważny etap podczas przygotowywania większych projektów. Symulacja pozwala odpowiedzieć na pytanie "Czy układ działa poprawnie?" przed wgraniem konfiguracji do rzeczywistego układu.

Zacznijmy od programu, na którym będziemy trenować. Najlepiej wrócić do prostego przykładu z poprzednich lekcji. Poniżej widoczny jest kod VHDL bramki AND z piątej części kursu FPGA.

-- dodajemy biblioteki
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- tu okreslamy jakie wejscia i wyjscia bedzie mial nasz uklad cyfrowy
entity podstawowe_bramki is
Port( Switch : in STD_LOGIC_VECTOR(1 downto 0); -- dwa przyciski jako wejscia bramki logicznej

      LED : out STD_LOGIC_VECTOR(0 downto 0));  -- dioda led jako wyjscie naszej bramki logicznej
                                                -- zwroc UWAGE! na dodatkowy nawias zamykajacy blok Port
                                                -- przed srednikiem!
end podstawowe_bramki;

-- slowo "Behavioral" odnosi sie do stopnia abstrakcji opisu naszej architektury
-- nie musisz sie nim na tym etapie zbytnio przejmowac
-- zagadnienie to obejmuje bardziej zaawansowane elementy tworzenia aplikacji w VHDL
architecture Behavioral of podstawowe_bramki is

begin

-- opis dzialania naszej aplikacji zawiera sie w ponizszej instrukcji;
LED(0) <= (not Switch(0)) and (not Switch(1));
   
end Behavioral;

Oraz zawartość niezbędnego pliku UCF:

NET "LED[0]"             LOC = P46   | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "Switch[0]"          LOC = P80   | PULLUP  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "Switch[1]"          LOC = P79   | PULLUP  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;

Warto wgrać program dla testu i sprawdzić, czy wszystko działa poprawnie!

Poprawne działanie bramki AND w praktyce.

Poprawne działanie bramki AND w praktyce.

Gotowe zestawy do kursów Forbota

 Komplet elementów  Gwarancja pomocy  Wysyłka w 24h

Zestaw uruchomieniowy Elbert v2 - Spartan 3A z wszystkimi niezbędnymi peryferiami do wykonania ćwiczeń z kursu FPGA!

Zamów w Botland.com.pl »

Przygotowanie do symulacji

Wiemy, że program działa, przejdźmy więc do symulacji. Na czym ma ona polegać? Chcemy, aby program przetestował działanie całego układu. W przypadku bramki AND najlepiej będzie jeśli sprawdzimy jak zachowuje się "wyjście układu" w zależności o wszystkich możliwych stanów na wejściach (00, 01, 10, 11).

Inaczej mówiąc chcemy przetestować wszystkie warianty występujące w tabeli prawdy dla AND:

Krok 1. W projekcie dotyczącym bramek logicznych klikamy prawym przyciskiem myszy (PPM) w drzewie projektu na pliku/module VHDL i wybieramy New Source:

Dodajemy nowy plik...

Dodajemy nowy plik...

Krok 2. Z listy typów plików wybieramy VHDL Test Bench. Jako nazwę podajemy "test_bramek". Warto się upewnić, że opcja Add to project jest zaznaczona. Na koniec klikamy Next.

Kurs_FPGA_4_2

Tworzenie pliku TestBench.

Krok 3. Pojawi się pole wyboru modułu VHDL, dla którego ma być stworzony testbench. Mamy do wyboru jeden moduł więc nie musimy się nad tym więcej zastanawiać. Klikamy Next.

Krok 4. Pojawi się okno podsumowania, w którym klikamy tylko Finish.

Ostatni etap przed wprowadzeniem zmian.

Ostatni etap przed wprowadzeniem zmian.

Krok 5. Teraz przełączamy widok środowiska na Simulation. Odpowiednie pole do zaznaczenia znajduje się po lewej stronie ISE (nad drzewkiem projektu).

Do wyboru jest tam Implementation oraz Simulation:

Kurs_FPGA_4_3

Zmiana widoku na "Simulation".

Po przełączeniu widzimy nowy widok hierarchii projektu. Plik test_bramek to opis symulacji. Po rozwinięciu widoku pojawi się plik uut - podstawowe_bramki. Jest to moduł VHDL z naszym kodem, który będzie poddany symulacji.

Rozwinięty widok symulacji.

Rozwinięty widok symulacji.

Wróćmy do pliku z opisem symulacji, czyli test_bramek. Poniżej widoczny jest wygenerowany przez ISE kod. Usunięte zostały jedynie zbędne fragmenty, jak np. długie wstępne komentarze:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 

ENTITY test_bench IS
END test_bench;
 
ARCHITECTURE behavior OF test_bench IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT podstawowe_bramki
    PORT(
         Switch : IN  std_logic_vector(1 downto 0);
         LED : OUT  std_logic_vector(0 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal Switch : std_logic_vector(1 downto 0) := (others => '0');

 	--Outputs
   signal LED : std_logic_vector(0 downto 0);
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 
 
   constant period : time := 10 ns;
 
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: podstawowe_bramki PORT MAP (
          Switch => Switch,
          LED => LED
        );

   -- Stimulus process
   stim_proc: process
   begin		
      -- insert stimulus here 
  
   end process;

END;

Na pierwszy rzut oka kod symulacji jest podobny do kodu aplikacji w VHDL, są jednak pewne różnice. Kod rozpoczyna się standardowo od dołączenia bibliotek:

biblioteki wykorzystywane w symulacji
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

Następnie umieszczony jest pusty blok entity.

blok entity w pliku symulacji
ENTITY test_bench IS
END test_bench;

Niżej zaczyna się blok architecture. Na początku następuje zdefiniowanie komponentów. Tutaj są wszystkie sygnały, które w module VHDL były deklarowane wewnątrz "Port" w sekcji "entity". Blok ten został wypełniony automatycznie:

blok component w pliku symulacji
COMPONENT podstawowe_bramki
    PORT(
         Switch : IN  std_logic_vector(1 downto 0);
         LED : OUT  std_logic_vector(0 downto 0)
        );
    END COMPONENT;

Niżej znajduje się deklaracja sygnałów lokalnych pliku z symulacją:

deklaracja sygnałów lokalnych w pliku symulacji
--Inputs
   signal Switch : std_logic_vector(1 downto 0) := (others => '0');

 	--Outputs
   signal LED : std_logic_vector(0 downto 0);

W pliku symulacji istnieje również możliwość zadeklarowania stałych, które będą używane w opisie procesu symulacji:

deklaracja stałych w pliku symulacji
constant period : time := 10 ns;

Tworzenie instancji (podczepienie sygnałów testujących do modułu VHDL):

podczepienie sygnałów testujących do modułu VHDL w pliku symulacji
-- Instantiate the Unit Under Test (UUT)
   uut: podstawowe_bramki PORT MAP (
          Switch => Switch,
          LED => LED
        );

Niżej znajduje się najciekawsza część, czyli miejsce na kod naszej symulacji:

-- Stimulus process
   stim_proc: process
   begin		
      -- insert stimulus here 
  
   end process;

W przypadku naszej bramki (zgodnie z wcześniejszym opisem) chcemy zasymulować działanie układu we wszystkich możliwych konfiguracjach wejść. Gotowy kod będzie więc wyglądał tak:

kod symulacji dla bramek logicznych
-- Stimulus process
   stim_proc: process
   begin		
      -- insert stimulus here 
      wait for 50 ns;
      Switch(0) <= '0';
      Switch(1) <= '0';
       
      wait for period;
      Switch(0) <= '1';
      Switch(1) <= '0';
       
      wait for period;
      Switch(0) <= '0';
      Switch(1) <= '1';
       
      wait for period;
      Switch(0) <= '1';
      Switch(1) <= '1';
      wait;
   end process;

Mamy tutaj blok "process", który poznaliśmy przy tworzeniu rejestru przesuwnego. To co jest nowe, to instrukcje zawarte wewnątrz tego bloku. Znajdują się tam komendy wait for, a zaraz po nich wpisany jest okres oczekiwania. Jako okres należy podać stałą zadeklarowaną wcześniej (jak to zrobiliśmy ze zmienną period) lub podać liczbę wraz z odpowiednim przyrostkiem:

Powyższy program pozwoli na sprawdzenie działania układu dla kolejnych kombinacji wejść AND. Zaczynając od 00, przez 10, 01, do 11. Po każdej zmianie wejść będziemy czekać przez czas ustalony w stałej period.

Cały program testujący dostępny jest poniżej:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 

ENTITY test_bench IS
END test_bench;
 
ARCHITECTURE behavior OF test_bench IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT podstawowe_bramki
    PORT(
         Switch : IN  std_logic_vector(1 downto 0);
         LED : OUT  std_logic_vector(0 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal Switch : std_logic_vector(1 downto 0) := (others => '0');

 	--Outputs
   signal LED : std_logic_vector(0 downto 0);
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 
 
   constant period : time := 10 ns;
 
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: podstawowe_bramki PORT MAP (
          Switch => Switch,
          LED => LED
        );

   -- Stimulus process
   stim_proc: process
   begin		
      -- insert stimulus here 
      wait for 50 ns;
      Switch(0) <= '0';
      Switch(1) <= '0';
       
      wait for period;
      Switch(0) <= '1';
      Switch(1) <= '0';
       
      wait for period;
      Switch(0) <= '0';
      Switch(1) <= '1';
       
      wait for period;
      Switch(0) <= '1';
      Switch(1) <= '1';
      wait;
   end process;

END;

Uruchomienie procesu symulacji

Krok 1. Tym razem skorzystamy z symulatora ISim, więc należy się upewnić, że jest on wybrany w ustawieniach projektu. Klikamy PPM w hierarchii projektu na b_bramki_logiczne i wybieramy opcję "Design Properties". Następnie w pozycji Simulator wybieramy wyżej wspomniany ISim:

Wybór odpowiedniego symulatora.

Wybór odpowiedniego symulatora.

Po zatwierdzeniu wyboru symulatora upewniamy się, że plik z symulacją jest zapisany. Następnie zaznaczamy go w hierarchii projektu. W poniższym menu klikamy PPM na Behavioral Check Syntax i dalej na Run.

Przeprowadzanie poprawności symulacji

Przeprowadzanie poprawności symulacji.

Gdy sprawdzanie symulacji zakończy się poprawnie pokaże się zielona ikona, tak jak miało to miejsce w procesie syntezy pliku VHDL.

Krok 2. Przed uruchomieniem symulacji należy zdefiniować jak długa ma trwać symulacja. W tym celu klikamy PPM na Simulate Behavioural Model i wybieramy Process Properties.

Czas trwania symulacji.

Ustawienie czasu trwania symulacji.

W polu Simulation Run Time określamy czas trwania symulacji. W przypadku testowania bramki AND wystarczy 100 ns.

Ustawienie czasu trwania symulacji cd.

Ustawienie czasu trwania symulacji cd.

Krok 3. Teraz możemy uruchomić test! Zaznaczamy plik z symulacją w hierarchii projektu. Dalej klikamy PPM na Simulate Behavioural Model i wybieramy Run.

Krok 4. Po chwili powinno się pojawić nowe okno* programu-symulatora ISim. Dla łatwiejszej analizy przebiegów warto kliknąć wtedy ikonkę Zoom to Full View.

*Jeśli program się nie uruchomił, to wystarczy usunąć poniższy plik i zrestartować środowisko.

C:\Xilinx\14.7\ISE_DS\ISE\gnu\MinGW\5.0.0\nt\libexec\gcc\mingw32\3.4.2\collect2.exe

Podczas pierwszego startu symulatora może również pojawić się problem z antywirusem. Avast bierze ten plik np. w "kwarantannę" i otwiera go w sposób bezpieczny. Po chwili pokazuje się komunikat, że plik nie jest groźny. Należy wtedy kliknąć opcję Kontynuuj wykonywanie:

Komunikat z programu antywirusowego.

Komunikat z programu antywirusowego.

Jeśli po chwili nie pojawi się program symulatora lub będzie się ciągle ładował, to wystarczy zrobić restart środowiska. Od tej pory wszystko powinno działać poprawnie, bez konieczności usuwania plików itd.

Krok 5. Analiza wyników. Gdy mamy włączone okno symulatora, to warto "poklikać" i sprawdzić jakie funkcje ułatwiające analizowanie wyników tam wbudowano. Szczególnie ważne jest dobre ustawienie przybliżenia (zoom).

Wynik naszej symulacji widoczny jest na poniższym zrzucie ekranu:

Otrzymana symulacja.

Otrzymana symulacja.

Na powyższym zrzucie ekranu widać trzy wykresy, które reprezentują:

  • stan wejścia nr 1,
  • stan wejścia nr 2,
  • stan wyjścia układu.

Teraz można sprawdzić czy otrzymane przebiegi zgadzają się z przewidywanym działaniem układu. Jak widać, jeśli na wejściu mamy 00, to na wyjściu jest 1. Przy innych kombinacjach na wyjściu mamy 0. Nasz program został wcześniej zmodyfikowany w taki sposób, aby działał poprawnie przy "odwrotnej logice" przycisków. Stąd odwrotny wynik naszej symulacji. Należy pamiętać o tej zamianie podczas analizy wyników lub zanegować przyciski podczas symulacji!

Wynik symulacji przy zanegowanych przyciskach w testbenchu wygląda następująco:

Wynik symulacji przy zanegowanych wejściach układu.

Wynik symulacji przy zanegowanych wejściach układu.

Reasumując, cały proces tworzenia symulacji przebiega następująco:

  • Najpierw deklarujemy wejścia i wyjścia dla obiektu, który ma być testowany (wewnątrz bloku "Component"). Są takie same, jak w bloku "port" w "entity" testowanego modułu.
  • Następnie deklarujemy sygnały analogiczne do tych z bloku "Component", jednak tutaj są one sygnałami lokalnymi dla "architecture" danego testu.
  • Za "BEGIN" następuje przypisanie/tworzenie instancji sygnałów lokalnych danego testu z tym co ma być testowane wewnątrz bloku "component".
  • Otrzymane wyniki mówią o reakcji wyjść - tutaj już sami musimy ocenić, czy układ działa zgodnie z oczekiwaniami.

Podsumowanie

Oczywiście w tym przypadku zdecydowanie łatwiej było sprawdzić działanie programu w praktyce (wgrywając konfigurację do FPGA). Przy bardziej rozbudowanych projektach warto jednak mieć na uwadze możliwość przeprowadzenia szczegółowej symulacji. Podejrzenie tego, co dzieje się "wewnątrz naszego FPGA" okazuje się bardzo pomocne np. podczas wyszukiwania błędów.

Nawigacja kursu

Autor kursu: Adam Bemski
Redakcja: Damian Szymański
Ilustracje, testy: Piotr Adamczyk

O autorze: Adam Bemski

Adam Bemski
Autorem kursu jest Adam Bemski, specjalista od systemow wbudowanych. Pracuje w obszarze automatycznego testowania urządzeń z funkcjonalnością IoT. Adam dodatkowo prowadzi zajęcia z techniki mikroprocesorowej na wyższej uczelni DHBW Stuttgart. Więcej szczegółów o Adamie na blogu adambemski.com.

kurs, kursFPGA, symulacja, vhdl

Trwa ładowanie komentarzy...