Więcej o firmie ELESOFTROM

Firma ELESOFTROM specjalizuje się w wykonywaniu i naprawianiu oprogramowania dla sterowników mikroprocesorowych.

Posiadamy ponad 10-letnie doświadczenie w tej dziedzinie.

W realizowanych projektach stawiamy na niezawodność i wydajność programów.

Naprawa oprogramowania

Oprogramowanie na zamówienie


Strona główna

Pełna oferta

Doświadczenie

O firmie

Kontakt


DioneOS - RTOS dla urządzeń embedded

Firma ELESOFTROM opracowała system RTOS dla procesorów ARM Cortex-M3 oraz msp430.

System jest zoptymalizowany pod względem wydajności, dzięki czemu uzyskano krótki czas przełączania pomiędzy wątkami.
System dostarcza elementy (np. semafory, mutexy, timery, kolejki itp.) niezbędne do tworzenia wielowątkowego firmware'u.

Wersja dla Cortexa została całkowicie przetestowana przy pomocy środowiska do automatycznego testowania.

Przeczytaj więcej:

Strona o systemie DioneOS

Niezawodność

Wydajność

Dokumentacja DioneOSa

Prezentacje n.t. DioneOS


^ Blog index    << Broadcom VideoCoreIV 3D, podstawy programowania    >> Programowanie QPU

Broadcom VideoCoreIV 3D, IDE i narzędzia

2018-01-02   Piotr Romaniuk, Ph.D.

Spis treści

Mountowanie zdalnego katalogu
Edytory: Eclipse i Notepad++
Asembler i disassembler dla VC4
Tworzenie i debugowanie programów na QPU
Wzorzec wyników obliczeń
Przykladowy projekt programu używającego QPU
Linki

Montowanie zdalnego katalogu

Podczas tworzenia oprogramowania dla systemu embedded wiele rzeczy może pójść nie tak, płytka może się zawiesić albo system plików może się uszkodzić. W takich okolicznościach zawsze istnieje ryzyko utraty kodu źródłowego, jeśli znajduje się on jedynie na docelowej platformie. Aby uniknąć takiego problemu, zalecane jest przechowywnie plików źródłowych na jakimś zewnetrznym komputerze (np. laptopie). Nie jest specjalnie istotne jaki system operacyjny będzie miał ten komputer, ma umożliwiać łatwą edycję plików źródłowych, kontrolę wersji oraz udostępnić usługę montowania katalogu plików dla Raspberry-Pi.
Jeśli ten komputer będzie pracował pod Linuxem, NFS może być użyty do montowania. Jeśli będzie pod Windows, to można użyć systemu plików CIFS. Skupmy się na Windows, ponieważ jest to przykład współpracy dwóch różnych systemów.
Uzyskanie podłączenia katalogu pod Windows wymaga nastepujących kroków:

  1. utworzenie użytkownika przeznaczonego do dostępu zdalnego (np. pi_user),
  2. utworzenie katalogu, który będzie udostepniany (shared),
  3. ustawienie odwpowiednich praw dostępu do tego folderu dla nowego użytkownika (pełne prawa do tego folderu),
  4. właczenie i konfiguracja współdzielenia folderu (nazwa folderu, np. shared-rpi),
  5. sprawdzenie adresu IP komputera hosta.

i na Raspberry-pi:

  1. utworzenie folderu gdzie będzie podmontowywany zdalny katalog (np. ~/vc4/shared-rpi),
  2. utworzenie skryptu montującego jeśli chce się go montować ręcznie (jeśli ma byc montowany automatycznie, to nalezy dodać stosowna linięif w fstab)
    np. mount-win.sh,
  3. dodanie praw wykonywania do skryptu
  4. dodanie użytkownika pi do sudoers

Poniżej przedstawiony jest przykład skryptu montującego, który montuje zdalny folder windows z komputera o adresie IP 192.168.0.6. Katalog jest montowany w folderze domowym użytkownika pi z odpowiednimi prawami dla tego użytkownika.

#!/bin/bash

mount -t cifs -o rw,user=pi_user,uid=pi,gid=pi //192.168.0.6/shared-rpi /home/pi/vc4/shared-rpi

Rys. 1. Skrypt do montowania zdalnego folderu ze źródłami.

W celu zamontowania folderu należy uruchomić skrypt i wpisać hasło użytkownika z systemu windows. Następnie, można przejść do zamontowanego katalogu i sprawdzić czy widoczne są w nim pliki oraz czy można tam zapisać plik.

pi@raspberrypi:~ $ sudo ./mount-win.sh
Password for smb_access@//192.168.0.6/shared-rpi:  *********
pi@raspberrypi:~ $ cd vc4/shared-rpi
pi@raspberrypi:~/vc4/shared-rpi $ ls

   { tu powinny być wylistowane pliki które są w katalogu pod Windows }

pi@raspberrypi:~/vc4/shared-rpi $ echo "123" > test.txt

   { a teraz, można sprawdzić czy plik test.txt pojawił się pod Windows i zawiera 123 }


Rys. 2. Przykład ustanawiania podłączenia katalogu.

Edytory: Eclipse i Notepad++
W celu ułatwienia sobie pracy polecane są dwa edytory: Eclipse i Notepad++. Eclipse został wybrany ze względu na jego dobre zarządzanie projektem i źródłami. Będzie on użyty do tworzenia aplikacji w C++, która będzie uruchamiana na Raspberry-Pi. Eclipse bedzie też używane do pełnego tworzenia kodu źródłowego, tzn. edycji plików, przeglądania definicji, drzewa wywołań funkcji i wielu innych przydatnych funkcji. Projekt powinien mieć makefile, gdzie będzie zdefiniowany proces budowania. Cała kompilacja będzie wykonywana na Raspberry-Pi na konsoli SSH (putty.exe może być użyty pod Windows do zalogowania).
Drugi edytor - Notepad++ jest wygodny do pisania kodu dla rdzeni QPU w asemblerze. W Notepad++ można łatwo zdefiniować sobie podświetlanie składni.
Podświetlanie składni dla asemblera QPU. - kliknij ten link prawym klawiszem myszy i zaznacz zapisz jako, a następnie zaimportuj definicję jezyka w Notepadzie++ wybierając z menu Language|Define your language...|Import



Rys. 3. Podświetlanie składni w Notepad++ dla asemblera QPU.

Asembler i disassembler dla VC4
Marcel Muller stworzył
macroassembler dla VideoCoreIV-3D - wspaniałe narzędzie do programowania VideoCore. Jest tam również disassembler, więc można przegladać istniejący lub wygenerowany kod, właczając w to wypisywanie pól instrukcji. Warto zapoznać się ze wszystkimi stronami, które tam umieścił: te o instrukcjach, wyrażeniach a szczególnie z dodatkiem do dokumentacji Broadcoma - gdzie autor omawia specyficzne aspekty QPU.
Budowanie tych narzędzi (tzn. vc4asm i vc4dis) jest trywialne, z jednym wyjątkiem. Oryginalne budowanie działa właściwie, ale problem powstaje gdy montuje się katalog Windows7-x64, czyli taki jak tu jest omawiany.

        pi@raspberrypi:~/vc4/qpu/shared-rpi/test1 $ make
        vc4asm -V -C hex/gpu_test1.cshader qasm/gpu_test1.qasm
        "qasm/gpu_test1.qasm" not found or no regular file.
        makefile:60: recipe for target 'hex/gpu_test1.cshader' failed
        make: *** [hex/gpu_test1.cshader] Error 1   
Rys. 4. Błąd asemblowania z powodu pliku źródłowego dla QPU w folderze windows-x64,
oryginalne budowanie vc4asm.

Problemem jest funkcja stat(), która sprawdza czy włączany plik (include) jest dostępny i czy jest normalnym plikiem. Stat() zwraca -1 a errno=75, co oznacza przepełnienie - zobacz man funkcji stat(). Kompilacja musi być dostosowana do wiekszych offsetów plików. Rozwiązanie okazuje się bardzo proste, wystarczy dodać definicję _FILE_OFFSET_BITS=64 przy kompilacji źródeł narzędzi:

1  FLAGS    = -Wall -std=c++11 -g#-O3
2  CPPFLAGS = -c -fPIC
3  #Added file-offset-bits=64 because otherwise stat() will not work with windows7-x64 mounted folders (cifs)
4  CPPFLAGS += -D_FILE_OFFSET_BITS=64 
5  LDFLAGS  =
...
Rys. 5. Poprawka w makefile'u do budowania vc4asm
aby współpracował z współdzielonym katalogiem windows7-x64.

Gdy narzędzia zostaną zbudowane, należy dodoać ich katalog bin do ścieżki PATH aby były dostępne do użycia.

Tworzenie i debugowanie programów dla QPU
Tworzenie i debugowanie programów dla rdzeni QPU wydaje się być bardzo kłopotliwe, a to ze względu na wielo-rdzeniowość, to że programy pracują poza głównym CPU, a także na niebezpośredni dostęp do wewnętrznej pamięci VideoCore'a oraz rejestrów. Brakuje też ogólnie znanego debugowania. Coś tam musi być, niestety dokumentacja nie jest dostępna (w dokumentacji układu pojawia się przerwanie BRPT, co może wskazywać, że da się wstrzymać program rdzenia QPU).
Niemniej jednak, możliwe poradzenie sobie z debugowaniem przed odpowiednie postępowanie:

Zrzut rejestrów może być zaimplementowany jako minimalne makro, stąd łatwo jest wstawić go w dowolne miejsce w programie QPU. Jeśli będzie potrzebne sprawdzenie zawartości rejestrów po jakiejś instrukcji, to makro można wpisać w odpowiedniej linii w kodzie źródłowym.



Rys. 6. Przykład breakpointu wstawionego w kod źródłowy.

Kiedy spojrzy się na implementację makra wywołania, to wygląda ono jak poniżej.



Rys. 7. Implementacja makra wywołania Breakpointu.

Główny kod używa dwóch makr wspomagających do zrzutu zestawu rejestrów (dump_regs) oraz and zapisu z pamięci VPM do SDRAM (store_dump). Wykonują one również niezbędne oczekiwanie na zakończenie transferu danych. Pełny kod źródłowy jest dostępny do pobrania jako część przykładowego projektu dla QPU (zobacz poniżej) - plik qasm/breakpoint.qinc.



Rys. 8. Główny kod makra breakpoint'u.

Kod makra (_breakpoint) zapisuje zrzucane rejestry (zestaw rejestrów oraz akumulatory) do pamięci VPM (Vertex Pipe Memory) a potem przepisuje to do pamięci współdzielonej z CPU. Adresy buforów są przekazywane przez tabelę uniforms i zapamiętywane w dwóch rejestrach z zestawu, ukrywanymi pod nazwami symbolicznymi: dbg_rfile_dump and dbg_accus_dump. Po wykonaniu niezbędnych zapisów makro zakończy program QPU, więc oczekujący program CPU zostanie zwolniony i może wypisać zawartość buforów w czytelnej formie. Przykład takiego loga jest przedstawiony poniżej:



Rys. 9. Przykład zrzutu rejstrów procesora QPU - prosta technika debugowania.

UWAGA
Powyższy zrzut jest wykonany dla jednego rdzenia QPU. Sklada się on z 2 części: treści akumulatorów oraz zestawu rejestrów (zestaw rejestrów rb jest widoczny tylko w części na tym rysunku). Każdy rejestr jest wypisany poziomo, z kolejnymi 16-ma elementami wektora SIMD od lewej do prawej. Akumulatory są wypisane dwukrotnie, raz jako zmiennoprzecinkowe, a drugi raz jako 32-bitowe liczby całkowite szestnastkowe. Akumulatory specjalne r4 i r5 są pominięte. Dla każdego rejestru z zestawu jego format i nazwa symboliczna jest definiowana w aplikacji.


W tym przypadku, podejście przyrostowe do programowania oznacza, że zaczyna się od programu dla jednego QPU, który przetwarza małą cześć danych, a następnie skaluje ten program na wiele rdzeni oraz duzy zestaw danych.
W pierwszej fazie można skupic się na tworzeniu programu w asemblerze i sprawdzaniu specyficznego zachowania procesora QPU. Jeśli jest to pierwszy program, który się tworzy dla QPU, z pewnością okaże się, że niektóre instrukcje działają inaczej niż się tego spodziewało. 'Odkryje' się też, że pewne kombinacje argumentów są niedopuszczalne, więc instrukcje nie są aż tak elastyczne jakby się mogło wydawać. W programowaniu QPU, są też pewne zależności pomiędzy kolejnymi instrukcjami, których trzeba przestrzegać, bo w przeciwnym przypadku wynik będzie niewłaściwy (np. zapis do rejestru zestawu nie jest jeszcze dostępny w następnej instrukcji).
To jest oczywiście faza debugowania, kiedy koryguje się program. Nie będzie to zbytnio klopotliwe, jeśli korzysta się ze zrzutu rejestrów. Kod może być w tym momencie również poddany optymalizacji, szczególnie poprzez użycie dwubieżności ALU.
W kolejnej fazie można dodać pętlę, która przetwarza następne paczki danych. Makro do zrzutu rejestrów kończy program, więc nie jest zbyt dobre do badania zachowania pętli. Niemniej jednak możliwe jest obejście tej niedogodności. Można wykonać skopiowac treść pętli, więc będzie wtedy pierwsza i druga iteracja w osobnych miejscach kodu. W ten sposób możliwe stanie się sprawdzenie zachowania pętli (tzn. sprawdzenie czy zmienne pętli sa własciwie modyfikowane z jednej iteracji na drugą).
Kolejny etap jest rtudniejszy, trzeba przejść jednego QPU na wiele. Można zacząć od programu na dwa QPU a kiedy będzie działać rozszerzyć na więcej QPU. Trzeba pamięteć, że powinno się mieć jeden program dla wielu QPU, moga być jego wersje ale kod powinien być jeden - rozmiar pamięci cache dla instrukcji QPU jest dość ograniczony!
Należy przydzielić każdemu QPU inną porcję danych. Nowym elementem programu dla wielu rdzeni będzie synchronizacja pomiędzy rdzeniami. Można nauczyć się jak to zrobić obserwując gotowe przykłady.
W tej fazie wyniki będą zapisywane do pamięci VPM a potem gdy wszystkie QPU zakończą obliczenia do pamięci współdzielonej z CPU. W ten sposób będą juz dostępne do zweryfikowania.

Wzorzec wyników obliczeń
Nawet przy debugowaniu programu dla jednego QPU jest to trudniejsze niż dla zwykłego procesora (jak np. jednordzeniowego ARM). Problemem jest duży zestaw danych i jego wektorowa natura. Aby poradzić sobie z tym zaleca się przygotowanie wzorcowego wyniku obliczeń. Taki wzorzec może być wyliczony przez program napisany w C lub C++ a powinien on dostarczyć wzorca do weryfikacji: jakiś danych wejściowych oraz poprawnych danych wyjściowych dla kluczowych etapów obliczeń. Wygodnie jest używać formy tekstowej, bo wyniki moga być łatwo porównane z tymi uzyskanymi na QPU i wypisanymi w logu. Porównanie można wykonać w jakimś arkuszu kalkulacyjnym (OpenOffice Calc, itp.), a wtedy dane będa widoczne jako wektorowe. Dane można przenosić z konsoli loga do arkusza za pomocą schowka. Alternatywnie można wbudować weryfikację w aplikację.



Rys. 10. Przykład weryfikacji SIMD16 w OpenOffice Calc.

Przykładowy projekt programu używającego QPU
Można pobrać przyklad programu używającego i potraktować go jako podstawę do eksperymentów z rdzeniami QPU. Ten przykład oblicza Dyskretna Transformatę Falkową (Discrete Wavelet Transform) wykorzytując cztery rdzenie QPU oraz równoległe obliczanie w oparciu o SIMD16. Ten kod zawiera metody opisane na tej stronie, szczególnie użyteczne dla innych programistów może być makro do breakpointu. Zobacz README.txt w tym pakiecie aby zapoznać się ze szczegółami.
To oprogramowanie zostało opracowane na podstawie przykładu hello_fft, przez wprowadzenie pewnych zmian i dostosowania. Kod QPU został napisany od początku ale używa on pewnych metod pochodzących z przykładu obliczania FFT.
Proszę pamiętać, że to oprogramowanie jest tylko demonstracją technik programowania i jest udostępniane na zasadach "TAKIE JAKIE JEST" bez żadnej gwarancji. Licencje wykorzystania można znaleźć w plikach źródłowych.
Pobierz projekt Eclipse zawierający obliczanie Discrete Wavelet Transform na rdzeniach QPU (zawiera kod źródłowy dla QPU).


Linki

[1] Broadcom VideoCore IV 3D, Architecture Reference Guide - dokumentacja producenta układu VideoCore
[2] Addendum to the Broadcom VideoCore IV documentation, Marcel Muller
[3] Obliczanie FFT, hello_fft https://github.com/raspberrypi/firmware/tree/master/opt/vc/src/hello_pi/hello_fft
    To jest również w obrazach Raspbiana w /opt/vc/src/hello_pi/hello_fft.