CPU w FPGA
| TechnikaOd chwili pojawienia się na rynku układów programowalnych projektantom zaczęła towarzyszyć pokusa zsyntezowania własnego procesora. Początkowo bardzo ograniczona liczba zasobów pozwalała budować jedynie proste automaty i uproszczone rdzenie CPU, jednakże z czasem sytuacja uległa zmianie. Wzrost złożoności układów FPGA i niebotyczne niekiedy zasoby logiczne pozwalają w dzisiejszych czasach umieścić w układzie programowalnym procesor o bardzo złożonej architekturze.
System połączeń
Bez względu na przeznaczenie czy rodzaj procesora konieczne jest rozwiązanie problemu magistral i dostępu do pamięci. Istnieje wiele sposobów zapewnienia wymiany danych między poszczególnymi blokami systemu mikroprocesorowego, począwszy od autorskich rozwiązań jak Avalon w układach Nios, a skończywszy na coraz bardziej powszechnym rozwiązaniu spotykanym w rosnącej grupie produktów AXI (Advanced eXtensible Interconnect) opracowanym przez ARM (wykorzystuje go m.in. MicroBlaze - rys. 2).
W obecnych czasach "goły" rdzeń to za mało, aby usatysfakcjonować projektantów, którzy oczekują pełnego i funkcjonalnego środowiska do szybkiego budowania działającego ekosystemu procesorowego. Narzędzie takie powinno oferować możliwość łatwego wskazywania, jakie elementy (pamięci, układy peryferyjne, kontrolery pamięci) mają wejść w skład systemu i zostać automatycznie podłączone.
Główne okno pakietu EDK udostępnionego przez firmę Xilinx i przeznaczonego do procesora MicroBlaze pokazuje rysunek 3. Kreatory pozwalają stworzyć docelowy system za pomocą graficznego interfejsu w którym można określić szczegółowo, co ma wejść w skład projektu. Możliwe jest wybranie z listy i dołączenie układów peryferyjnych (kontroler pamięci DDR, port szeregowy, pamięć cache, liczniki, system przerwań, etc.) oraz konfiguracja samego MicroBlaze (sprzętowa jednostka zmiennoprzecinkowa, układ MMU na potrzeby Linuxa, etc.). Połączenia pomiędzy poszczególnymi blokami wygeneruje EDK, ale możliwa jest ich zmiana lub dodawanie nowych. Pakiet SDK (Soft ware Development Kit) zawiera kompilator języka C/C++ oraz debugger z możliwością pracy krokowej i podglądu zmiennych.
Microsemi również udostępnia pakiet narzędzi z graficznym interfejsem użytkownika zapewniający projektantom możliwość wybierania bloków funkcjonalnych, pamięci, układów peryferyjnych i łączenie ich z CPU poprzez magistralą AHB (Advanced Highperformance Bus).
Lattice zdecydowało się postawić na magistralę Wishbone dostępną z otwartym kodem źródłowym, podobnie jak i sam rdzeń. Jest ona zbliżona do magistrali Avalon, jednakże różnice są na tyle znaczące, że wykluczają wzajemną kompatybilność. Lattice oferuje graficzne narzędzia do generowania plików RTL na podstawie schematu blokowego.
Ograniczenia narzucane przez pamięć
Rozmiar pamięci RAM dla syntezowanych procesorów nie jest problemem, gdyż współczesne układy FPGA są wyposażone w pamięć blokową. Pojemność takiej pamięci może sięgać kilkudziesięciu megabitów w najbardziej rozbudowanych układach. Sytuacja komplikuje się jednak, gdy należy zapewnić sprawną wymianę danych między rdzeniem a pamięcią. Bezpośredni dostęp do RAM wprowadza opóźnienia w wykonywaniu instrukcji przez procesor.
Współcześnie procesory wyposażone są w pamięć podręczną, której zadanie polega na zmniejszeniu liczby odwołań do głównej pamięci i tym samym przyspieszeniu wykonania instrukcji. Warto zauważyć, że jej rozmiar, w procesorach przewidzianych do uruchamiania systemu operacyjnego, jest duży. Inaczej sytuacja wygląda, gdy CPU ma wykonywać relatywnie statyczne operacje - w takim przypadku często wystarczająca okazuje się prostsza pamięć podręczna z mapowaniem bezpośrednim bądź pamięć TCM (patrz ramka).
Microsemi w układach rodziny Smart-Fusion zapewnia dwa, wydzielone bloki pamięci SRAM o rozmiarze 32 kB na potrzeby rdzenia Cortex-M3, który zawiera własne, wbudowane mechanizmy zarządzające i obsługujące pamięć (w tym cache). Inaczej sytuacja wygląda, gdy wykorzystywany jest procesor oparty na Corteksie-M1, w którym pamięć podręczna nie jest obsługiwana. Projektantom pozostawiono możliwość włączenie do projektu pamięci TCM za pomocą udostępnionych narzędzi.
W produktach Xilinx implementacja pamięci cache odbywa się przy wykorzystaniu pamięci blokowej RAM lub pamięci syntezowanej z rejestrów. Cache jest najczęściej mapowany bezpośrednio, jednakże przewidziano możliwość zastosowania pamięci asocjacyjnej (znajdzie to jednak odzwierciedlenie w obniżeniu maksymalnej częstotliwości taktowania CPU wskutek wzrostu złożoności projektu).
Altera kwestię pamięci podręcznej w procesorach rodziny Nios pozostawiła do decyzji projektantów. Kontroler pamięci cache jest syntezowalny i wykorzystuje zasoby pamięci RAM układu FPGA. Może on być typu asocjacyjnego i według zapewnień producenta ma to niewielki wpływ na maksymalną częstotliwość pracy układu, niemniej odczuwalny wzrost wydajności przetwarzania jest uzależniony w dużej mierze od sposobu napisania samego kodu.
Specjalizowane bloki funkcjonalne
Korzyścią wynikająca z budowy systemów opartych na logice programowalnej i osadzonego w niej procesora jest możliwość wykorzystania sprzętowych akceleratorów. Są to bloki funkcjonalne opracowane w celu realizacji wyspecjalizowanych zadań bez angażowania mocy obliczeniowej CPU, często w jednym cyklu zegara. Należy podkreślić, że są to zwykle jednostki wysoce zoptymalizowane pod kątem użycia w konkretnym projekcie. Znaczna przewaga wydajności wynika również z możliwości zrównoleglenia pracy - w FPGA może być więcej niż jeden sprzętowy akcelerator.
Integracja własnego bloku sprzętowego z rdzeniem procesora przebiega w każdej rodzinie układów programowalnych nieco inaczej, niemniej producenci starają się zapewnić szybki i wygodny sposób realizacji tego zadania. W układach Nios istnieje możliwość definiowania własnych instrukcji i dodawania ich do standardowej listy rozkazów procesora.
Udostępnione narzędzia odpowiadają za wprowadzenie niezbędnych zmian w opisie sprzętowym, które uwzględnią cykl dekodowania i wykonania nowych rozkazów, tak aby były one akceptowane przez potok przetwarzający (pipeline). Rozbudowa zestawu instrukcji jest przydatna w sytuacji, gdy celowe jest przeciwdziałanie obniżeniu wydajność pracy CPU na skutek wykonywania określonych zadań.
Xilinx oferuje dwa sposoby dołączenia sprzętowych akceleratorów. Pierwszy jest oparty na magistrali AXI, do której można dołączyć własne bloki peryferyjne. Staną się one wtedy dostępne w przestrzeni adresowej procesora i możliwa będzie wymiana danych między CPU a układem peryferyjnym. Mechanizm ten jest powszechnie wykorzystywany w systemach opartych na standardowych procesorach i z punktu widzenia programisty jest on wygodny na etapie pisania kodu.
W przypadku mniej skomplikowanych bloków funkcjonalnych (np. filtrów cyfrowy) możliwe jest ich bezpośrednie zintegrowanie z rdzeniem procesora.
Weryfikacja projektu
Weryfikacja projektów zawierających osadzony rdzeń procesora nastręcza szereg trudności. Na pierwszym etapie weryfikowana jest poprawność samego rdzenia - zarówno pod kątem współpracy z otoczeniem, jak i braku błędów w programie. Wykorzystanie CPU pochodzących od producentów FPGA, w wersji sprzętowej bądź syntezowanej, może okazać się najłatwiejszym i najszybszym rozwiązaniem.
Producenci zapewniają o gruntownym przetestowaniu i zweryfikowaniu poprawności dostarczonych implementacji razem z dołączonymi blokami IP. Ponadto dokładają oni wszelkich starań, aby projekt zbudowany na bazie takich komponentów był poprawny również w ujęciu całościowym, tzn. jako pełny system złożony z procesora i jego otoczenia.
Sprawa komplikuje się, gdy wykorzystywany jest rdzeń od zewnętrznych dostawców albo po wprowadzeniu przez projektantów własnych modyfikacji. Konieczna staje się ścisła kontrola projektu, gdyż nawet firmowe pakiety narzędzi producenta FPGA nie zawsze są w stanie wykryć wszystkie potencjalne problemy i właściwie przełożyć na język opisu sprzętu wprowadzone zmiany.
Podstawę stanowi bieżące monitorowanie zużycia zasobów logicznych oraz weryfikacja wyników syntezy na podstawie analizy schematu RTL i symulacji. Wszelkie nieoptymalne konstrukcje zawarte w opisie sprzętu najczęściej zwiększą zużycie zasobów logicznych i wydłużą ścieżkę krytyczną, w efekcie czego zmniejszy się dopuszczalna częstotliwość taktowania układu.
Wyzwanie stanowi również konieczność analizy projektu na poziomie dużo bardziej złożonym niż proste uruchomienie projektu na platformie sprzętowej i sprawdzenie, czy działa zgodnie z oczekiwaniami. Złożoność tego typu projektów wymusza użycie modeli czasowych oraz modeli symulacyjnych poszczególnych bloków funkcjonalnych. Nieodzowne często okazują się specjalizowane bloki IP przeprowadzające testy na wybranych elementach systemu - rysunek 4.
Problemy napotykane na etapie weryfikacji całego sytemu sprawiają, że projektanci często wolą rozpocząć pracę w oparciu o sprawdzony projekt referencyjny. Po uruchomieniu i zapoznaniu się z jego specyfiką następuje etap wprowadzania zmian i przystosowywania całości do wymagań projektowanej aplikacji.
Ograniczona zostaje tym samym złożoność procesu weryfikacji i większa jest szansa na poprawną pracę od razu po uruchomieniu, choćby w ograniczonym zakresie funkcjonalności. Metoda ta jest chętnie wybierana zwłaszcza przez osoby, które nie chcą zagłębiać się w analizę na poziomie schematu RTL i każdorazowo po wprowadzeniu drobnych modyfikacji testują działanie projektu na platformie sprzętowej.
Osobną kwestię stanowią błędy w oprogramowaniu procesora. Sytuacja jest o tyle korzystna, że jednostki osadzone w strukturze FPGA mogą być wspierane przez debuggery. Przykładowo układy SoC z rodziny Zynq-7000 (Xilinx) wyposażone w rdzeń Cortex-A9 mają moduł CoreSight opracowany przez ARM.
Pozwala on śledzić wykonanie programu, wstrzymywać go i tym samym ułatwia wyszukiwanie błędów i weryfikowanie poprawności oprogramowania. MicroBlaze ma port JTAG umożliwiający zastawianie pułapek (breakpoints) oraz krokowe wykonywanie programu. Podobnie rdzenie Nios oraz LatticeMico udostępniają mechanizmy umożliwiające pracę z debuggerem i ułatwiają tym samym wyszukiwanie błędów.
Szczegółowa analiza pracy całego urządzenia najczęściej wymaga włączenia do projektu bloku testującego. Blok taki, umieszczony w FPGA, może odpowiadać za wymuszanie bądź symulowanie konkretnych działań ze strony części sprzętowej. Wadę stanowi duża ilość czasu tracona na syntezę projektu, co jest szczególnie zauważalne dla dużych układach programowalnych z zajętą sporą częścią zasobów.
Alternatywę stanowią narzędzia diagnostyczne udostępniane przez producentów. Przykład stanowi ChipScope dostarczany przez Xilinxa dla produkowanych przez niego układów FPGA. Umożliwia on monitorowanie sygnałów wewnątrz układu programowalnego - możliwe staje się obserwowanie zmian rejestrów, magistral procesora, stanów automatów, itd.
Pamięci cachePamięć cache jest przeznaczona do przechowywania danych najczęściej pobieranych z głównej pamięci. Są one szybsze w stosunku do pamięci podstawowej, przez co osiąga się zauważalny wzrost wydajności rdzenia i szybsze wykonywanie instrukcji. Procesor, odczytując dane, w pierwszej kolejności sięga do pamięci cache i w razie możliwości odczytuje stamtąd potrzebne informacje. Działanie to może także być odwrócone - procesor zapisuje dane do pamięci podręcznej, z której następnie są one kopiowane do głównej pamięci. Uzyskuje się w ten sposób optymalizację zapisu informacji do głównej pamięci. Ograniczony rozmiar pamięci podręcznej sprawia, że nieużywane dane są zastępowane nowymi. Przebieg tego procesu jest uzależniony od rodzaju pamięci cache. Pamięci w pełni asocjacyjne umieszczają nowe dane pod dowolnym adresem, a oczywistą wadą takiego podejścia jest konieczność wyszukiwania optymalnej lokalizacji w całym obszarze (dla danych pobranych z głównej pamięci). Pociąga to za sobą większe zużycie energii, bardziej złożoną architekturę i potencjalnie większą stratę czasu. Uzyskuje się w ten sposób największe prawdopodobieństwo uniknięcia odwołania do głównej pamięci. Przeciwieństwem pamięci w pełni asocjacyjnych są pamięci cache z mapowaniem bezpośrednim. W takim podejściu nie ma dowolności wyboru miejsca umieszczenia nowej danej - każda komórka podstawowej pamięci ma przypisane miejsce, do jakiego może zostać skopiowana. Unika się tym samym konieczności stosowania złożonych algorytmów przeszukujących. Oszczędność zużycia energii i czasu jest okupiona znacznie częstszymi odniesieniami do pamięci podstawowej. Kompromis stanowią asocjacyjne pamięci n-drożne, w których dane mogą być umieszczonej w jednej z n komórek pamięci podręcznej (rys. 5). W przybliżeniu przyjmuje się, że podwojenie drożności (np. z mapowania bezpośredniego na 2-drożne, z 2-drożnego na 4-drożne) zapewnia taki sam rezultat jak dwukrotne zwiększenie pojemności pamięci podręcznej mapowanej bezpośrednio. |
Podsumowanie
Obecnie projektanci decydujący się wykorzystać procesor umieszczony w strukturze FPGA dysponują szerokim wyborem architektury oraz struktury całego systemu. Istnieje wybór pomiędzy jednostkami syntezowanymi z zasobów logicznych i sprzętowymi rdzeniami umieszczonymi razem z układem programowalnym w jednej obudowie.
Szeroka oferta pochodząca od producentów FPGA i niezależnych dostawców sprawia, że procesor może zostać dobrany adekwatnie do potrzeb - począwszy od prostych obliczeń i zarządzania pracą urządzenia, poprzez obsługę złożonych protokołów komunikacyjnych, a skończywszy na uruchamianiu kompletnego systemu operacyjnego takiego jak Linux.
Najczęstszym problemem staje się w takiej sytuacji wzrost złożoności projektu i utrudniona, wieloaspektowa weryfikacja obejmująca sprzęt, implementację w układzie programowalnym oraz debugowania oprogramowania. Niezbędny staje się opracowanie właściwego planu testowania, który obejmie wszystkie aspekty wymagane do poprawnego funkcjonowania całego systemu.
Jakub Borzdyński