Akademia Górniczo Hutnicza im. Stanisława Staszica w Krakowie Wydział IET Katedra Elektroniki Projektowanie systemów za pomocą języków wysokiego poziomu ESL Ćwiczenie 4 Mixed Design: Impulse C + VHDL Zespół Rekonfigurowalnych Systemów Obliczeniowych Maciej Wielgosz, Grzegorz Gancarczyk http://home.agh.edu.pl/~wielgosz/ 09.10.2013
Wstęp Celem niniejszego ćwiczenia jest przystępne zapoznanie Studentów ze sposobami tworzenia tzw. projektów mieszanych (Mixed Designes) z użyciem języków wysokiego poziomu i HDL. W przykładzie przeznaczonym do zrealizowania w takcie zajęć laboratoryjnych, wykorzystane zostaną spreparowane wcześniej bloki logiczne, opisane w języku VHDL. Bloki te realizują bardzo proste operacje arytmetyczno-logiczne. Użycie takich elementów pozwoli zaznajomić studentów z procedurą dołączania zewnętrznych modułów, która okazuje się bardzo pomocna w wielu projektach. Moduły sprzętowe napisane w językach HDL są bardziej optymalne jeśli chodzi o zajętość zasobów logicznych, co zostanie pokazane podczas realizacji ćwiczenia. Należy jednak pokreślić, że dla zaawansowanych systemów cyfrowych ilość wymaganych zasobów logicznych jest problemem drugorzędnym. Najważniejszym aspektem jest czas potrzebny na przygotowanie gotowego do użycia systemu. Nadmiarowa logika wygenerowana w czasie kompilacji ImpulseC2HDL zazwyczaj stanowi jedynie pojedyncze procenty ogółu zasobów zajętych przez zaprojektowany system. Ponadto Studenci utrwalą, poszerzą i wykorzystają zdobytą w trakcie serii poprzednich zajęć wiedzę i umiejętności dotyczące języka Impulse C oraz metodyki projektowania układów cyfrowych z wykorzystaniem narzędzia CoDeveloper. Wymagania sprzętowe: komputer klasy PC, procesor o architekturze zgodnej z x86, procesor oferujący sprzętowy multithreading, dostęp do sieci Internet. Wymagania programowe: 32 bitowy system operacyjny Windows XP lub wyższy, narzędzie CoDeveloper, środowisko ISE Design Suite, przeglądarka internetowa. Wymagane doświadczenie: ukończone ćwiczenie nr 1. 2
1. Założenia projektowe Projekt realizowany w trakcie zajęć laboratoryjnych składać się będzie z dwóch części. 1. Głównej. Utworzonej i zrealizowanej z użyciem języka Impulse C, identycznie jak miało to miejsce na poprzednich zajęciach. Jej zadaniem będzie odczyt (pobranie) danych z pliku, przygotowanie ich do przetworzenia, a następnie zapis przetworzonych danych do pliku. Wyróżnić można w niej dwie części składowe: programową (_sw), sprzętową (_hw). 2. Opisu sprzętu. Składającej się z plików.vhd zawierających opis behawioralny modułów realizujących przetwarzanie danych. W plikach tych opisane zostały moduły realizujące funkcje: kombinacyjną, asynchroniczną, potokową. O konieczności inkorporacji do projektu realizowanego w języku Impulse C innych, zewnętrznych modułów opisanych w którymś z języków HDL informuje kompilator dyrektywa #pragma CO IMPLEMENTATION (proszę zapoznać się z jej opisem i przykładami użycia w pozycji CoDeveloper User s Guide). Jej użycie sprawia, że nie jest dokonywana translacji ciała funkcji, w której jej użyto, do kodu HDL. Zamiast tego dołączany jest wskazany plik. Celowość użycia gotowych modułów zrealizowanych przy pomocy któregoś z języków HDL wynika głównie z: potrzeby wykorzystania zaprojektowanych uprzednio modułów w języku HDL, dużych repozytoriów gotowego kodu HDL (np. zasoby witryny OpenCores.org) oraz narzędzi do automatycznej generacji kodu HDL o zadanej funkcjonalności (np. Xilinx s CoreGenerator), możliwości minimalizacji w ten sposób ilości nadmiarowej logiki generowanej w trakcie translacji ImpulseC2HDL, wysokiego stopnia optymalizacji bloków opisanych w języku HDL. 3
2. Projekt W razie jakichkolwiek problemów z pamięcią i/lub metodyką projektowania z wykorzystaniem języka Impulse C, należy w pierwszej kolejności posiłkować się instrukcją do ćwiczenia laboratoryjnego nr 1. Jeśli nie przyniesie to oczekiwanych rezultatów, proszę zwrócić się o pomoc do osoby prowadzącej zajęcia. 2.1. Utworzenie nowego projektu 1. Uruchomić przy pomocy znajdującego się na pulpicie skryptu CoDeveloper_start program CoDeveloper. 2. Stworzyć nowy projekt z użyciem szablonu jeden strumień wejściowy, jeden strumień wyjściowy. Dopilnować, aby ścieżka dostępu do projektu oraz jego nazwa nie zawierały znaku spacji. Nazwa projektu powinna być jednoznaczna i w miarę możliwości unikatowa. Zadbać o to, by szerokość strumieni wynosiła 16 bitów, zaś ich głębokość przyjąć równą 4 poziomom. 3. Stworzyć nowy projekt dla języka Impulse C. Dopilnować poprawnej ścieżki dostępu do katalogu roboczego nowoutworzonego projektu oraz jego jednoznacznej i unikalnej nazwy. 4. Skopiować z katalogu roboczego narzędzia CoDeveloper do katalogu roboczego wszystkie pliki kluczowe (do katalogu userip). 5. Skompilować wstępnie projekt. Uruchomić symulację. Jeśli symulacja uruchomiła się i wykonała poprawnie, przejść do kolejnego punktu. W przeciwnym wypadku wyeliminować błędy i powtórzyć krok. 2.2. Dostosowanie szablonu Wszystkie trzy moduły sprzętowe przyjmują jako argumenty wejściowe dane 8 bitowe. Argumentem wynikowym jest dana 16 bitowa. Mając to na uwadze, proszę dostosować do tych wytycznych projekt w Impulse C. Pomóc w tym mogą dodatkowo poniższe wskazówki. 1. Producer. Odczytywane z pliku wartości liczbowe należy przesłać do modułu sprzętowego jako liczby 8 bitowe przy użyciu strumienia o szerokości 8 bitów. 2. Dane wejściowe w module sprzętowym należy odczytać przy użyciu strumienia o szerokości 8 bitów. Dane te należy zapisać do zmiennej/zmiennych pomocniczych 8 bitowych. 3. Usunąć pragmę odpowiedzialną za potokowość procesu. 4. Zadbać o poprawną składnię funkcji konfiguracyjnej config_ modułu sprzętowego. Szczególną uwagę zwrócić na szerokość bitową strumieni. 5. Consumer. Dane odczytane z 16 bitowego strumienia wyjściowego modułu sprzętowego należy zapisywać do pliku. 6. Skompilować projekt i sprawdzić poprawność przepływu danych przez strumienie. 4
2.3. Opis funkcjonalności modułów w języku Impulse C Na zajęciach laboratoryjnych punkt ten należy wykonać w całości. W rzeczywistości opisane w nim wytyczne można pominąć, jeśli jest się całkowicie pewnym sposobu działania dołączanych, zewnętrznych modułów HDL, bądź też nie ma się zamiaru wykonywać programowej symulacji ich działania (działania całości projektu). Dołączenie do projektu zewnętrznych modułów HDL przy pomocy dyrektywy CO IMPLE- MENTATION gwarantuje ich użycie w niezmienionej formie, zamiast kompilacji całości projektu do kodu HDL. Niemożliwą jednak do wykonania w żaden sposób staje się wtedy programowa symulacji działania tych modułów (możliwa jest jedynie generacja testbencha i określenie poprawności działania całości systemu na podstawie wygenerowanych w nim przebiegów). Aby zapewnić możliwość symulacji zachowania dołączanych z zewnątrz modułów HDL, koniecznym jest stworzenie ich opisu funkcjonalnego, w ciałach korespondujących do nich funkcji. Innymi słowy konieczne jest opisanie w języku Impulse C funkcjonalności dołączanych z zewnątrz modułów HDL. Opis ten zostanie wykorzystany jedynie na etapie symulacji. Nie zostanie on natomiast użyty do generacji kodu HDL. 1. Moduł kombinacyjny. Realizuje operację konkatenacji (sklejenia) dwóch argumentów (wektorów) wejściowych o zadanej szerokości bitowej w jeden argument (wektor) wyjściowy o szerokości bitowej równej sumie szerokości bitowych argumentów wejściowych. Kolejność argumentów wejściowych ma znaczenie. Do jego opisu modułu proszę użyć funkcji software owej jak poniżej: co_uint16 CombProc(co_uint8 a, co_uint8 b){ #pragma CO IMPLEMENTATION CombProcEnt LOGIC co_uint16 r = a; r = (r << 8) b; return r; } Opis modułu w języku VHDL znajduje się w pliku CombProc.vhd (o czym później). 5
2. Moduł asynchroniczny. Realizuje operację dodania do pierwszego argumentu (wektora) wejściowego n-kolejnych liczb naturalnych (poczynając od 1). Wartość liczbowa drugiego argumentu wejściowego decyduje o tym, ile sumowań ma zostać wykonanych. Asynchroniczność modułu objawia się jako niemożliwość przewidzenia w chwili kompilacji ilości taktów zegara potrzebnych do otrzymania wyniku końcowego. Kolejność argumentów wejściowych ma znaczenie. Do opisu modułu w języku Impulse C proszę posłużyć się funkcją jak poniżej: co_uint16 AsyncProc(co_uint8 a, co_uint8 b){ #pragma CO IMPLEMENTATION AsyncProcEnt ASYNC co_uint16 r = a; int i; for(i = 1; i <= b; i++){ r = r + i; } } return r; Opis modułu w języku VHDL znajduje się w pliku AsyncProc.vhd (o czym później). Podłączenie modułów asynchronicznych jest znacznie bardziej skomplikowane niż w przypadku logiki kombinacyjnej. Ponieważ, jak już wspomniano, opóźnienie wnoszone przez moduł nie jest znane, toteż porozumiewanie się z nim musi odbywać się z zachowaniem ściśle przyjętego protokołu handshakingu. Dokładny opis protokołu komunikacyjnego omówiony został w CoDeveloper User s Guide (proszę się z nim zaznajomić). 3. Moduł potokowy. Realizuje operację obliczania kwadratu długości wektora na płaszczyźnie. W pierwszym stadium potoku pobrane zostają dane wejściowe i wykonane zostają stosowne operacje arytmetyczne. W drugim stadium potoku następuje wystawienie wyniku na wyjście modułu. Opóźnienie modułu wynosi 2 cykle. Kolejność argumentów wejściowych nie ma znaczenia. Do opisu modułu w języku Impulse C proszę posłużyć się funkcją jak poniżej: co_uint16 PipeProc(co_uint8 a, co_uint8 b){ #pragma CO IMPLEMENTATION PipeProcEnt PIPELINE LATENCY = 2 co_uint16 r1; co_uint16 r2; co_uint16 r3; r1 = a*a; r2 = b*b; r3 = r1 + r2; } return r3; Opis modułu w języku VHDL znajduje się w pliku PipeProc.vhd (o czym później). 6
Podłączenie modułu potokowego jest prostsze, niż modułu asynchronicznego, choć i tu również istnieje pewien protokół komunikacyjny. Jego dokładny opis został omówiony w CoDeveloper User s Guide (proszę się z nim zaznajomić). 1. Proszę umieścić deklarację wszystkich trzech modułów sprzętowych w pliku _hw, a następnie użyć ich kolejno w ciele funkcji sprzętowej (tzn. jedną funkcję na raz). 2. Skompilować projekt, a następnie uruchomić symulację. Prześledzić uzyskane wyniki i sprawdzić, czy zgadzają się one z wynikami oczekiwanymi. 3. Operacje 2. powtórzyć trzykrotnie, dla każdego z modułów osobno. Jeśli wszystkie symulacje przebiegły pomyślnie, można przejść do następnego punktu. W przeciwnym wypadku proszę wyeliminować błędy. W razie poważnych trudności, poprosić o pomoc osobę prowadzącą zajęcia. 3.4. Opis funkcjonalności modułów w języku VHDL Aby zaoszczędzić Studentom ich cennego czasu i nie fatygować ich koniecznością tworzenia modułów sprzętowych w języku VHDL (który zdążyli w toku swojej edukacji doskonale opanować), przygotowano archiwum z gotowymi plikami vhd. Znajduje się ono na stronie przedmiotu. 1. Proszę pobrać archiwum (Pliki) ze strony przedmiotu i zapisać go na dysku twardym komputera. 2. W katalogu roboczym projektu proszę założyć katalog o nazwie userip (nazwa obligatoryjna) i rozpakować do niego ściągnięte archiwum zip. 3. Wszystkie trzy rozpakowane pliki dodać do projektu. Skompilować projekt. 4. Jako cel kompilatora HDL proszę wybrać Xilinx Generic (VHDL). Pozostałe ustawienia identyczne, jak dla projektu sprzętowego generatora liczb pseudolosowych zrealizowanego na zajęciach nr 1. 5. Wygenerować kod VHDL i wyeksportować całość projektu (hardware + software). 6. Zaznajomić się ze schematem blokowym systemu przy użyciu narzędzia Stage Master Explorer. Projekt został właśnie ukończony. Proszę zapoznać się dokładnie z zawartością katalogu export. Szczególną uwagę zwrócić na zawartość katalogu na ścieżce dostępu /export/hw. Zaznajomić się ze składnią VHDL wszystkich trzech plików ściągniętych w archiwum. 3. Sprzętowa implementacja projektu 1. Dokonać syntezy i implementacji projektu w narzędziu ISE DS. Wszelkie ustawienia ISE DS należy przyjąć identyczne, jak dla projektu generatora liczb pseudolosowych zrealizowanego w trakcie zajęć nr 1. 2. Zaznajomić się z raportem końcowym (ilość zajętych zasobów logicznych, maksymalna częstotliwość pracy układu). 3. Kroki 1 i 2 powtórzyć kolejno dla wszystkich 3 zewnętrznych modułów sprzętowych. 7
4. Porównanie rozwiązań Zapewne wszyscy Studenci zastanawiają się teraz, jakie korzyści przyniosło dołączenie zewnętrznych modułów opisanych w języku VHDL? Aby się o tym przekonać na własne oczy, proszę zmodyfikować projekt w Impulse C. Zamiast dołączać zewnętrzne moduły sprzętowe, proszę wygenerować je przy użyciu języka Impulse C. W tym celu najprościej będzie: 1. Usunąć pragmę CO IMPLEMENTATION z ciała wszystkich funkcji zewnętrznych. 2. Dodać pragmę CO PRIMITIVE lub CO INLINE do ciała wszystkich funkcji zewnętrznych. 3. Skompilować projekt i wygenerować kod VHDL. 4. Utworzyć nowy projekt w ISE. Dodać do niego wszystkie wyeksportowane pliki. Wykonać syntezę i implementację. 5. Kroki 3 i 4 powtórzyć kolejno dla pozostałych dwóch funkcji zewnętrznych. 6. Porównać z sobą odpowiednie raporty. Wysnuć wnioski. Jakie różnice udało się zaobserwować? 8