.. _z2-harddoom2: ======================= Urządzenie HardDoom ][™ ======================= .. contents:: Grafika w grze Doom 2 ===================== Rzutowanie dowolnej geometrii trójwymiarowej na dwuwymiarową płaszczyznę jest dość skomplikowane obliczeniowo. Jednym z ważniejszych elementów jest obliczenie współczynnika perspektywy dla każdego rysowanego piksela -- wymaga to obliczenia odwrotności pierwiastka kwadratowego. Jest to bardzo kosztowna operacja i wykonanie jej dla każdego piksela ekranu jest niemożliwe przy zachowaniu rozsądnej ilości ramek na sekundę, nawet dla najnowocześniejszych i napotężniejszych procesorów i486, nie mówiąc już o procesorach i386 używanych obecnie przez większość graczy. Gra Doom 2 zalicza się do tzw. gier 2.5D -- choć grafika wygląda na trójwymiarową (i jest bardzo realistyczna), użyta geometria oraz punkt widzenia są bardzo ograniczone. Użytkownik może patrzeć tylko przed siebie (a nie w górę czy w dół), a w świecie gry spotkamy tylko 3 typy obiektów: - pionowe ściany -- po zrzutowaniu na ekran, każda pokryta kolumna pikseli składa się z pikseli o równym współczynniku perspektywy, pozwalając na wyliczenie go tylko raz na każdą kolumnę. - poziome płaszczyzny (podłogi i sufity) -- po zrzutowaniu na ekran, każda pokryta linia pikseli składa się z pikseli o równym współczynniku perspektywy. - obiekty ruchome, rysowane przez skopiowanie prosto na ekran przeskalowanych tzw. sprite'ów, czyli przygotowanych przez autorów zdjęć, zrobionych z 8 różnych kątów. Główna praca rysowania świata gry spada na dwie gorące funkcje: - ``R_DrawColumn`` -- rysuje kolumnę pikseli z podanej kolumny tekstury i z podanym współczynnikiem skalowania. Używane do rysowania ścian, obiektów oraz grafiki interfejsu. - ``R_DrawSpan`` -- rysuje poziomy pasek pikseli, teksturując podaną teksturą płaszczyzny (wycinając z tej tekstury linię pod dowolnym kątem i nakładając ją na rysowany pasek). Urządzenie HardDoom ][™ dostarcza sprzętową implementację powyższych funkcji, przejmując większość obciążenia z głównego procesora i pozwalając na grę w wysokich rozdzielczościach (płynna rozgrywka na 640×480!) nawet na starszych procesorach. Oprócz tych funkcji, urządzenie dostarcza również kilka pomniejszych funkcji pomocniczych, pozwalając na rysowanie całej grafiki gry na urządzeniu. Urządzenie ========== Urządzenie jest podłączane do komputera przez szynę PCI -- identyfikator producenta to ``0x0666``, a identyfikator urządzenia to ``0x1994``. Urządzenie nie posiada własnej pamięci i operuje na buforach w głównej pamięci komputera przez bezpośredni dostęp do pamięci (DMA). Ponieważ główna pamięć komputera podlega fragmentacji, a bufory mogą być całkiem duże (urządzenie obsługuje 2048×2048 pikseli), urządzenie wykonuje dostęp do większości buforów przez tablicę stron w swoim własnym formacie. Urządzeniem steruje się przez rejestry wejścia/wyjścia zmapowane do pamięci (MMIO). Ten obszar MMIO jest pierwszym i jedynym obszarem BAR używanym przez urządzenie (BAR0). Urządzenie wykorzystuje również jedną linię przerwania PCI. Obszar MMIO ma wielkość 8kiB, ale tylko niektóre bajty z tego zakresu są używane na rejestry. Wszystkie udokumentowane rejestry są 32-bitowe w formacie little-endian i powinny być używane tylko przez wyrównane 32-bitowe odczyty i zapisy. Bufory i blok stronicowania =========================== Urządzenie używa następujących buforów (opisanych bardziej szczegółowo niżej): - bufor poleceń -- zmiennego rozmiaru. - bufory ramki ("surface") -- zmiennego rozmiaru. - atlas tekstur kolumnowych ("texture") -- zmiennego rozmiaru. - atlas tekstur płaskich ("flat") -- zmiennego rozmiaru, wielokrotność 2**12 bajtów. - atlas map kolorów ("colormap") -- zmiennego rozmiaru, wielokrotność 2**8 bajtów. - mapa przezroczystości ("tranmap") -- zawsze rozmiaru 2**16 bajtów. Urządzenie pisze tylko do bufora ramki -- pozostałe bufory są używane tylko do odczytu. Bufory wybiera się przez podanie adresu ich tabeli stron. W każdej chwili wybrane jest 8 buforów: - ``CMD``: bufor poleceń, z którego urządzenie wczytuje polecenia. - ``SURF_DST``: bufor ramki, do którego urządzenie będzie rysować. - ``SURF_SRC``: bufor ramki, z którego urządzenie będzie kopiować dane (dla polecenia ``COPY_RECT``). - ``TEXTURE``: atlas tekstur kolumnowych, z których urządzenie będzie rysować (dla polecenia ``DRAW_COLUMN``). - ``FLAT``: atlas tekstur płaskich, z których urządzenie będzie rysować (dla poleceń ``DRAW_BACKGROUND``, ``DRAW_SPAN``). - ``COLORMAP``: atlas map kolorów do oświetlenia i efektów specjalnych. - ``TRANSLATION``: atlas map kolorów do zmiany palety kolorów. - ``TRANMAP``: mapa przezroczystości. Urządzenie używa 40-bitowych adresów fizycznych (zarówno dla buforów jak i dla tabel stron). Wybrany bufor poleceń ustawia się przez zapis rejestru ``CMD_PT``. Pozostałe bufory ustawia się przez wysłanie polecenia ``SETUP``. W każdym wypadku, wybrany bufor podaje się jako 32-bitową wartość, która jest przesuniętym wskaźnikiem adresu tabeli stron bufora (bity 8-39 adresu fizycznego tabeli stron to podana wartość, pozostałe bity adresu są zerami). Urządzenie używa stron o wielkości 4kiB. Tabele stron mogą zawierać maksymalnie 1024 wpisy (czyli opisywać 4MiB pamięci -- maksymalny rozmiar bufora) i muszą być wyrównane do 256 bajtów. Wpisy tabeli stron mają 4 bajty i odpowiadają bezpośrednio kolejnym stronom bufora. Wpisy tabeli stron są 32-bitowymi słowami o następującym formacie: - bit 0: ``VALID`` -- jeśli ustawiony, wpis jest poprawny i może być użyty. Jeśli nie jest ustawiony, próba użycia wpisu spowoduje błąd ``PAGE_FAULT`` i wyłączenie odpowiedniego bloku w ``ENABLE`` (``XY`` dla ``SURF_*``, ``TEX`` dla ``TEXTURE``). [XXX: ``FE``] - bit 1: ``WRITABLE`` -- jeśli ustawiony, ta strona jest dostępna do odczytu i zapisu. Jeśli nie jest ustawiony, ta strona jest dostępna tylko do odczytu, a próba zapisu spowoduje błąd ``PAGE_FAULT`` i wyłączenie odpowiedniego bloku w ``ENABLE``. - bity 2-3: nieużywane, powinny być równe 0. - bity 4-31: ``ADDR`` -- bity 12-39 adresu fizycznego strony. Rozmiar tabeli stron nie jest nigdzie podawany -- urządzenie w żaden sposób nie sprawdza, czy użyty offset w buforze zmieści się w tabeli stron. Sterownik powinien zapewnić, że tabela będzie odpowiednio duża i pilnować wysyłanych poleceń, czyli: - weryfikować, że wysyłane współrzędne y mieszczą się w wysokości buforów ramek, - limitować odczyt tekseli z tekstur kolumnowych przez użycie ``TEXTURE_LIMIT``, - weryfikować, że ``FLAT_IDX``, ``COLORMAP_IDX``, ``TRANSLATION_IDX`` mieszczą się w rozmiarze odpowiednich atlasów. Aby nie czytać ciągle tabeli stron, urządzenie może zapamiętywać dane z tabeli stron w buforach TLB. Zmiana aktywnego bufora (przez polecenie ``SETUP`` bądź zapis ``CMD_PT``) czyści bufory TLB odpowiadające danemu buforowi, a użycie bitu ``TLB`` w rejestrze ``RESET`` czyści wszystkie bufory TLB. W razie wystąpienia błędu ``PAGE_FAULT``, urządzenie można zrestartować przez wpisanie odpowiedniej wartości w tabelę stron, skasowanie TLB, oraz włączenie z powrotem odpowiedniego bloku w ``ENABLE`` -- kontynuuje wtedy pracę od momentu w którym trafiło na błąd strony. Bufory ramek ------------ Bufor ramki to obszar w pamięci służący do rysowania. Jest to po prostu dwuwymiarowa tablicą pikseli. Ponieważ urządzenie było projektowane zanim wynaleziono kolor 24-bitowy (albo nawet 16-bitowy), każdy piksel jest po prostu bajtem -- odpowiadającym jakiemuś kolorowi z palety (obsługą palety zajmuje się urządzenie wyświetlające i nie musimy się nią przejmować). Urządzenie obsługuje bufory ramki o dowolnej dodatniej szerokości podzielnej przez 64 i nie większej niż 2048 piksele. Wysokość natomiast może być dowolna z zakresu 1 .. 2048. Bufor ramki jest prostą tablicą bajtów -- adres piksela (x, y) wewnątrz bufora to po prostu ``x + y * width``. Szerokość aktywnych buforów ramki jest ustawiana poleceniem ``SETUP``. Urządzenie sprawdza współrzędną x pikseli, których używa -- przekroczenie szerokości bufora spowoduje błąd ``SURF_DST_OVERFLOW`` lub ``SURF_SRC_OVERFLOW`` i wyłączenie bloku ``XY`` w ``ENABLE``. Tekstury kolumnowe ------------------ Tekstury kolumnowe zawierają dane obrazu, który polecenie ``DRAW_COLUMN`` będzie rysowało do bufora ramki (po przeskalowaniu i przetworzeniu). Mają dość skomplikowany format i składają z tekseli pogrupowanych w kolumny (które nie muszą pokrywać całej powierzchni tekstury -- tekstury kolumnowe mogą mieć dziury). Urządzenie nie przejmuje się dokładnym formatem tych tekstur -- znalezienie w nim początku odpowiedniej kolumny jest zadaniem silnika gry. Tekstury kolumnowe mogą mieć dość dowolny rozmiar (w praktyce od kilkudziesięciu bajtów do kilkudziesięciu kilobajtów, zazwyczaj ok. 2 kiB) i mogą być grupowane w atlasy (bufory zawierające wiele tekstur). Urządzenie obsługuje atlasy o wielkościach do 4MiB. Aktywny atlas tekstur kolumnowych ustawia się poleceniem ``SETUP``. Aktywną teksturę (a właściwie kolumnę z tekstury) wybiera się przy wysyłaniu polecenia ``DRAW_COLUMN`` przez podanie parametrów ``TEXTURE_OFFSET``, ``TEXTURE_HEIGHT`` i ``TEXTURE_LIMIT``. Wysokość jest używana do powtarzania tekstury w pionie -- współrzędne w kolumnie tekstury będą brane modulo wysokość. Próba czytania adresu z poza zakresu 0 .. ``TEXTURE_LIMIT << 6 | 0x3f`` zostanie zablokowana przez urządzenie i spowoduje użycie do teksturowania tekseli zerowych. Urządzenie może zapamiętywać dane z używanego atlasu tekstur w swojej pamięci podręcznej -- aby wyczyścić tą pamięć, wystarczy zmienić aktywny atlas przez wysłanie polecenia ``SETUP`` z flagą ``TEXTURE`` (to zresetuje pamięć podręczną nawet, jeśli nie zmieni się przez to adres aktywnej tabeli stron). .. note:: Aby nie mylić pojęć z odpowiadającymi pojęciami w buforach ramki, w grafice komputerowej przyjęło się nazywać współrzędne w teksturze U oraz V (zamiast X i Y), a pojedynczy element -- tekselem (zamiast piksela). Tekstury płaskie ---------------- Tekstury płaskie są używane przez polecenie ``DRAW_SPAN`` do rysowania podłóg i sufitów. Mają zawsze wymiary 64×64 tekseli, zajmują 2**12 bajtów, a ich adres początkowy musi być wyrównany do 2**12 bajtów. Podobnie do tekstur kolumnowych, mogą być grupowane w atlasy tekstur płaskich. Aktywny atlas tekstur płaskich ustawia się poleceniem ``SETUP`` z flagą ``FLAT``. Aktywną teksturę wybiera sie przy wysyłaniu polecenia ``DRAW_SPAN`` bądź ``DRAW_BACKGROUND`` przez parametr ``FLAT_IDX`` (wybrana tekstura płaska jest pod adresem ``FLAT_IDX * 2 ** 12`` wewnątrz bufora). Analogicznie do tekstury kolumnowej, urządzenie może zapamiętywać dane z tekstury płaskiej w pamięci podręcznej. Wysłanie polecenia ``SETUP`` z flagą ``FLAT`` czyści tą pamięć. Mapy kolorów ------------ Mapy kolorów są po prostu tablicami mapującymi kolory z palety na inne kolory -- mają przez to zawsze dokładnie 256 bajtów. Ich adres musi być również wyrównany do 256 bajtów. Są używane do wielu efektów: - zamiana palety kolorów, aby umożliwić użycie tej samej tekstury do kilku wersji kolorystycznych (tzw. palette swap) -- w końcu pamięć jest droga - ściemnianie kolorów (do symulacji słabego oświetlenia) - zmiana skali kolorów (np. przefarbowanie wszystkiego na niebiesko pod wodą) Urządzenie ma dwa aktywne atlasy map kolorów, wybierane poleceniem ``SETUP`` z flagami ``COLORMAP`` i ``TRANSLATION``. Aktywną mapę kolorów można wybrać dla każdego polecenia przez podanie indeksu w odpowiednim atlasie (wybrana mapa kolorów znajduje się pod adresem ``indeks * 256`` w odpowienim buforze). Podobnie do tekstur, urządzenie może kopiować dane map do pamięci podręcznej. Wysłanie polecenia ``SETUP`` z flagą ``COLORMAP`` bądż ``TRANSLATION`` czyści zawartość odpowiadającej pamięci. Ustawione mapy kolorów są używane przez polecenia ``DRAW_COLUMN`` i ``DRAW_SPAN`` tylko wtedy, gdy ustawione są odpowiednie flagi -- ``COLORMAP`` dla mapy ``COLORMAP_*``, ``TRANSLATION`` dla mapy ``TRANSLATION_*``. Polecenie ``DRAW_FUZZ`` zawsze używa mapy ``COLORMAP_*`` do efektu cienia. Mapy przezroczystości --------------------- Aby uzyskać efekt przezroczystości w grafice komputerowej, potrzebna jest jakaś funkcja scalająca dwa kolory -- kolor tła oraz kolor rysowanego obiektu. W przypadku grafiki używającej schematu True Color, wystarczyłoby zsumować składowe kolorów z odpowiednimi wagami. Jednak w przypadku grafiki używającej palety kolorów, trzeba to zrobić używając obliczonej wcześniej tabeli -- mapy przezroczystości. Mapa przezroczystości jest dwuwymiarową tablicą bajtów o rozmiarze 256×256. Jest to po prostu tablica mapująca pary kolorów na scalony kolor. Urządzenie ma jedną aktywną mapę przezroczystości, wybieraną poleceniem ``SETUP`` z flagą ``TRANMAP``. Znajduje się ona pod adresem 0 w wybranym buforze. Podobnie do tekstur i map kolorów, dane z mapy kolorów mogą być przechowywane przez urządzenie w pamięci podręcznej. Wysyłanie poleceń ================= Urządzenie sterowane jest w większości przez wysyłanie mu poleceń. Każde polecenie jest pakietem złożonym z ośmiu 32-bitowych słów. Polecenia mogą być wysyłane bezpośrednio przez rejestry MMIO (jest to mniej wydajna opcja), bądź przez wskazanie bufora w pamięci, z którego urządzenie powinno wczytywać polecenia (bardziej wydajna opcja). W przypadku wysłania niepoprawnego polecenia, wyzwalane jest przerwanie ``FE_ERROR``, a blok ``FE`` zostanie wyłączony w rejestrze ``ENABLE``. Urządzenie obsługuje 8 różnych poleceń: - ``0``: ``COPY_RECT`` -- kopiuje prostokątny obszar między dwoma buforami ramki. - ``1``: ``FILL_RECT`` -- wypełnia prostokątny obszar jednym kolorem. - ``2``: ``DRAW_LINE`` -- rysuje prostą jednokolorową linię między dwoma punktami. - ``3``: ``DRAW_BACKGROUND`` -- rysuje tło -- wypełnia prostokątny obszar powtarzaną w nieskończoność teksturą płaską. - ``4``: ``DRAW_COLUMN`` -- rysuje kolumnę pikseli używając tekstury kolumnowej. - ``5``: ``DRAW_FUZZ`` -- aplikuje efekt rozmytego cienia na kolumnie pikseli. - ``6``: ``DRAW_SPAN`` -- rysuje pasek pikseli używając tekstury płaskiej. - ``7``: ``SETUP`` -- zmiena bufory używane przez urządzenie. Urządzenie przyjmuje polecenia w jednym z dwóch formatów. Format pierwszy jest używany dla wszystkich poleceń poza ``SETUP`` i wygląda następująco: - słowo 0: - bity 0-3: ``CMD_TYPE`` -- typ polecenia (z powyższej listy). - bit 4: ``INTERLOCK`` -- zapewnia zakończenie wszystkich wcześniejeszych poleceń przed rozpoczęciem wczytywania danych dla tego polecenia (i wszystkich późniejszych). - bit 5: ``PING_ASYNC`` -- wyzwala przerwanie po wczytaniu tego polecenia. - bit 6: ``PING_SYNC`` -- wyzwala przerwanie po zakończeniu przetwarzania tego polecenia. - bit 7: ``FENCE`` -- zwiększa licznik ``FENCE_COUNTER`` po zakończeniu przetwarzania tego polecenia (i wszystkich wcześniejszych). - bit 8: ``TRANSLATION`` -- włącza zamianę palety kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów z ``TRANSLATION_IDX``. - bit 9: ``COLORMAP`` -- włącza mapowanie rysowanych kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów z ``COLORMAP_IDX`` (po ``TRANSLATION_IDX``, jeśli obydwie mapy są włączone). - bit 10: ``TRANMAP`` -- włącza przezroczystość. Jeśli włączony, rysowane kolory są scalane z obecnymi kolorami w buforze ramki przez mapę przezroczystości (``TRANMAP_PT``). - słowo 1: - bity 0-13: ``TRANSLATION_IDX`` -- indeks użytej mapy kolorów dla zmiany palety w ``DRAW_COLUMN`` i ``DRAW_SPAN``. Użyta mapa kolorów pochodzi z adresu ``TRANSLATION_IDX * 2**8`` wewnątrz bufora wyznaczonego przez ``TRANSLATION_PT`` - bity 16-29: ``COLORMAP_IDX`` -- indeks użytej mapy kolorów dla oświetlenia i efektów dla ``DRAW_COLUMN``, ``DRAW_SPAN``, oraz ``DRAW_FUZZ``. Użyta mapa kolorów pochodzi z adresu ``COLORMAP_IDX * 2**8`` wewnątrz bufora wyznaczonego przez ``COLORMAP_PT`` - słowo 2: - bity 0-10: ``X_A`` -- współrzędna x pierwszego punktu będącego parametrem operacji (interepretacja zależy od konkretnego polecenia, nie wszystkie polecenia tego używają). - bity 11-21: ``Y_A`` -- współrzędna y pierwszego punktu będącego parametrem operacji. - bity 22-31: ``FLAT_IDX`` -- indeks użytej tekstury płaskiej w aktywnym atlasie tekstur płaskich (dla ``DRAW_BACKGROUND``, ``DRAW_SPAN``). - słowo 3: - bity 0-10: ``X_B`` -- współrzędna x drugiego punktu będącego parametrem operacji. - bity 11-21: ``Y_B`` -- współrzędna y drugiego punktu będącego parametrem operacji. - słowo 4: ``USTART`` -- współrzędna u w teksturze używana dla skrajnie lewego piksela paska (dla ``DRAW_SPAN``) bądź górnego piksela kolumny (dla ``DRAW_COLUMN``). Jest to liczba stałoprzecinkowa -- 16 wysokich bitów to część całkowita, a 16 niskich to część ułamkowa. - słowo 5: ``USTEP`` -- pochodna współrzędnej u w teksturze względem współrzędnej x lub y w buforze ramki. Liczba stałoprzecinkowa ze znakiem. - słowo 6: - dla poleceń ``COPY_RECT``, ``FILL_RECT``, ``DRAW_LINE``, ``DRAW_BACKGROUND``: - bity 0-11: ``WIDTH`` -- szerokość prostokąta (dla ``COPY_RECT``, ``FILL_RECT``, ``DRAW_BACKGROUND``). - bity 12-23: ``HEIGHT`` -- wysokość prostokąta. - bity 24-31: ``FILL_COLOR`` -- kolor wypełnienia dla ``FILL_RECT``, kolor linii dla ``DRAW_LINE``. - dla polecenia ``DRAW_COLUMN``: - bity 0-21: ``TEXTURE_OFFSET`` -- offset początku danych kolumny w aktywnym atlasie tekstur kolumnowych w bajtach. - dla polecenia ``DRAW_SPAN``: ``VSTART`` -- współrzędna v w teksturze używana dla skrajnie lewego piksela paska (dla ``DRAW_SPAN``). Również liczba stałoprzecinkowa. - dla polecenia ``DRAW_FUZZ``: - bity 0-10: ``FUZZ_START`` -- współrzędna y początku pola widzenia. - bity 12-22: ``FUZZ_END`` -- współrzędna y końca pola widzenia. - bity 24-29: ``FUZZ_POS`` -- źródło losowości dla efektu cienia. - słowo 7: - dla polecenia ``DRAW_COLUMN``: - bity 0-15: ``TEXTURE_LIMIT`` -- określa ostatni poprawny adres w teksturze kolumnowej, liczony w 64-bajtowych blokach (adres ostatniego poprawnego bajtu to ``TEXTURE_LIMIT << 6 | 0x3f``). - bity 16-31: ``TEXTURE_HEIGHT`` -- wysokość tekstury w tekselach, jeśli tekstura ma być powtarzana w pionie (współrzędne w kolumnie tekstury będą brane modulo wysokość) bądź 0, jeśli tekstura nie ma być powtarzana. - dla polecenia ``DRAW_SPAN``: ``VSTEP`` -- pochodna współrzędnej u w teksturze względem współrzędnej x lub y w buforze ramki. Liczba stałoprzecinkowa ze znakiem. - dla pozostałych poleceń: nieużywane. Format drugi jest używany dla polecenia ``SETUP`` i jest opisany razem z nim. Wszystkie nieużywane pola (czy to kompletnie niezdefiniowane, czy nie stosujące się dla danego typu polecenia) muszą być ustawione na 0 -- w przeciwnym wypadku, zachowanie urządzenia nie jest zdefiniowane. Bezpośredni dostęp ------------------ Polecenia można wysyłać do urządzenia bezpośrednio przez MMIO, używając następujących rejestrów: ``BAR0 + 0x0070: CMD_FREE`` Rejestr tylko do odczytu. Odczytana wartość jest liczbą wolnych miejsc w kolejce poleceń (tyle poleceń można natychmiast zapisać do ``CMD_SEND`` bez obaw o ``CMD_OVERFLOW``). Kolejka ta ma maksymalną pojemność 512 poleceń. ``BAR0 + 0x0040 + i * 4, i < 8: CMD_SEND`` Rejestry tylko do zapisu. Można wysłać polecenie do urządzenia, zapisując jego kolejne słowa do kolejnych rejestrów z tej tablicy (i-te słowo do i-tego rejestru, w kolejności). Zapis ostatniego słowa powoduje dopisanie zapisanego polecenia na koniec kolejki poleceń. Jeśli kolejka jest już pełna (``CMD_FREE == 0``), zamiast tego wyzwalane jest przerwanie ``CMD_OVERFLOW``, a blok ``CMD_SEND`` jest wyłączany w ``ENABLE``. Blok wczytywania poleceń ------------------------ Blok wczytywania poleceń pozwala na efektywne sterowanie urządzeniem (bez konieczności ręcznego wysyłania każdego polecenia przez MMIO) przez samodzielne wczytywanie poleceń z pamięci. Rejestry bloku wczytywania poleceń sa następujące: ``BAR0 + 0x0060: CMD_PT`` Wskaźnik na tabelę stron opisującą bufor poleceń, przesunięty w prawo o 8 bitów (rejestr przechowuje bity 8-39 adresu fizycznego). Zapis tego rejestru powoduje spłukanie bufora TLB dotyczącego bufora poleceń. ``BAR0 + 0x0064: CMD_SIZE`` Rozmiar bufora poleceń, liczony w poleceniach (czyli w 32-bajtowych pakietach). Gdy urządzenie zwiększa ``CMD_READ_IDX``, a obecną wartością jest ``CMD_SIZE-1``, zachodzi zawinięcie bufora i nową wartością będzie ``0``. ``BAR0 + 0x0068: CMD_READ_IDX`` Indeks następnego polecenie do wczytania (liczony w 32-bajtowych pakietach). ``BAR0 + 0x006c: CMD_WRITE_IDX`` Indeks miejsca, gdzie procesor ma zapisać następne polecenie. Jeśli ``CMD_WRITE_IDX == CMD_READ_IDX``, blok wczytywania poleceń zostanie zatrzymany, aż procesor załaduje więcej poleceń i przesunie ``CMD_WRITE_IDX``. Blok wczytywania poleceń będzie wczytywał polecenia zawsze, gdy zachodzą wszystkie z następujących warunków: - blok wczytywania poleceń jest włączony w ``ENABLE`` - są jakieś nieprzetworzone polecenia, tzn. ``CMD_READ_IDX != CMD_WRITE_IDX`` - jest miejsce w kolejce poleceń, tzn. ``CMD_FREE != 0`` Polecenie wczytywane jest z indeksu ``CMD_READ_IDX``, jest on zwiększany o 1 (ewentualnie jest zawijany do 0, jesli wynosi obecnie ``CMD_SIZE-1``), po czym polecenie jest dopisywane do kolejki (tak, jakby zostało wpisane do ``CMD_SEND``). .. warning:: Po resecie urządzenia, ``CMD_READ_IDX`` nie musi być równe ``CMD_WRITE_IDX`` -- blok wczytywania poleceń może więc próbować wczytać jakieś polecenia po włączeniu go w ``ENABLE``. Aby tego uniknąć, należy zainicjować te rejestry. Opis poleceń ============ Polecenie ``SETUP`` ------------------- Polecenie ``SETUP`` służy do zmiany aktywnych buforów. Ma specjalny format, inny od pozostałych poleceń: - słowo 0: - bity 0-3: ``CMD_TYPE`` -- typ polecenia (z powyższej listy). - bit 4: ``INTERLOCK`` -- zapewnia zakończenie wszystkich wcześniejeszych poleceń przed rozpoczęciem wczytywania danych dla tego polecenia (i wszystkich późniejszych). - bit 5: ``PING_ASYNC`` -- wyzwala przerwanie po wczytaniu tego polecenia. - bit 6: ``PING_SYNC`` -- wyzwala przerwanie po zakończeniu przetwarzania tego polecenia. - bit 7: ``FENCE`` -- zwiększa licznik ``FENCE_COUNTER`` po zakończeniu przetwarzania tego polecenia (i wszystkich wcześniejszych). - bit 9: ``SURF_DST`` -- zmienia aktywny docelowy bufor ramki. - bit 10: ``SURF_SRC`` -- zmienia aktywny źródłowy bufor ramki. - bit 11: ``TEXTURE`` -- zmienia aktywną teksturę kolumnową. - bit 12: ``FLAT`` -- zmienia aktywną teksturę płaską. - bit 13: ``TRANSLATION`` -- zmienia aktywny atlas map kolorów do zmiany palety. - bit 14: ``COLORMAP`` -- zmienia aktywny atlas map kolorów do efektów i oświetlenia. - bit 15: ``TRANMAP`` -- zmienia aktywną mapę przezroczystości. - bity 16-21: ``SURF_DST_WIDTH`` -- bity 6-11 szerokości ramki docelowej (bity 0-5 szerokości są równe 0). Ignorowane, jeśli nie jest ustawiony bit ``SURF_DST``. - bity 24-29: ``SURF_SRC_WIDTH`` -- bity 6-11 szerokości ramki źródłowej (bity 0-5 szerokości są równe 0). Ignorowane, jeśli nie jest ustawiony bit ``SURF_SRC``. - słowo 1: ``SURF_DST_PT``: bity 8-39 adresu tabeli stron opisującej docelowy bufor ramki. Ignorowane, jeśli nie jest ustawiony bit ``SURF_DST``. - słowo 2: ``SURF_SRC_PT``: jak wyżej, źródłowy bufor ramki. - słowo 3: ``TEXTURE_PT``: jak wyżej, bufor tekstury kolumnowej. - słowo 4: ``FLAT_PT``: jak wyżej, bufor tekstury płaskiej. - słowo 5: ``TRANSLATION_PT``: jak wyżej, atlas map kolorów do zmiany palety. - słowo 6: ``COLORMAP_PT``: jak wyżej, atlas map kolorów do efektów i oświetlenia. - słowo 7: ``TRANMAP_PT``: jak wyżej, mapa przezroczystości. Jednym poleceniem ``SETUP`` można zmienić dowolny podzbiór ustawień (wybrany przez bity w słowie 0). Będą one obowiązywały aż do zmiany ich przez kolejne polecenie ``SETUP``. Wykonanie tego polecenia resetuje jednocześnie bufory TLB dla wszystkich buforów wybranych w słowie 0 (nawet, jeśli wybrany adres tabeli stron jest identyczny z wcześniej obowiązującym). Analogicznie, dla wybranych buforów czyszczona jest pamięć podręczna. Polecenie ``COPY_RECT`` ----------------------- Polega na skopiowaniu zadanego prostokąta z jednego bufora ramki (``SURF_SRC_PT``) do drugiego (``SURF_DST_PT``). Obydwa bufory ramki muszą być tych samych rozmiarów. Jego parametry to: - pozycja lewego górnego rogu prostokąta docelowego (``X_A``, ``Y_A``), - pozycja lewego górnego rogu prostokąta źródłówego (``X_B``, ``Y_B``), - wymiary prostokąta (``WIDTH``, ``HEIGHT``). Polecenie ``COPY_RECT`` nie powinno być wykonywane, gdy kopiujemy wewnątrz jednego bufora, a prostokąt źródłowy ma część wspólną z prostokątem docelowym -- wynik jest wtedy niedeterministyczny. .. warning:: Urządzenie może wczytywać dane źródłowe dla ``COPY_RECT`` asynchronicznie do procesu rysowania. Aby zapewnić, że urządzenie zakończyło wcześniejesze operacje rysowania do źródłowego prostokąta zanim zacznie z niego czytać, należy ustawić flagę ``INTERLOCK`` (opisane niżej). Polecenie jest używane w grze do skopiowania przygotowanego wcześniej panelu dolnego oraz do efektu przejścia ("melt"). Polecenie ``FILL_RECT`` ----------------------- Polega na wypełnieniu zadanego prostokąta w buforze ramki (``SURF_DST_PT``) jednym kolorem. Jego parametry to: - pozycja lewego górnego rogu prostokąta (``X_A``, ``Y_A``), - wymiary prostokąta (``WIDTH``, ``HEIGHT``), - kolor (``FILL_COLOR``). Jest używane w grze do rysowania tła mapy (dostępnej pod klawiszem *Tab*). Polecenie ``DRAW_LINE`` ----------------------- Rysuje jednokolorową linię prostą o szerokości 1 piksela między podanymi dwoma punktami w zadanym buforze ramki (``SURF_DST_PT``). Jego parametry to: - pozycja punktu początkowego (``X_A``, ``Y_A``), - pozycja punktu końcowego (``X_B``, ``Y_B``), - kolor (``FILL_COLOR``). Jest używane w grze do rysowania mapy (dostępnej pod klawiszem *Tab*). Polecenie ``DRAW_BACKGROUND`` ----------------------------- Wypełnia zadany prostokąt w buforze ramki (``SURF_DST_PT``) powtarzającymi się kopiami tekstury płaskiej (``FLAT_PT``). Jego parametry to: - pozycja lewego górnego rogu prostokąta (``X_A``, ``Y_A``), - wymiary prostokąta (``WIDTH``, ``HEIGHT``), Jest używane w grze do rysowania tła do ekranu opcji, tła do tekstu "fabuły" wyświetlanego po ukończeniu niektórych poziomów, oraz jako obramowanie ekranu w przypadku wybrania pola widzenia mniejszego niż ekran (klawisz *-*). Polecenie ``DRAW_COLUMN`` ------------------------- Rysuje teksturowaną kolumnę do bufora ramki (``SURF_DST_PT``). Jego parametry to: - współrzędne górnego punktu kolumny (``X_A``, ``Y_A``), - współrzędne dolnego punktu kolumny (``X_B``, ``Y_B``), - flagi ``TRANSLATION``, ``COLORMAP``, ``TRANMAP``, - wartość początkowa współrzędnej u w teksturze (``USTART``), - pochodna współrzędnej u po współrzędnej y (``USTEP``), - offset początku danych kolumny w teksturze kolumnowej (``TEXTURE_OFFSET``), - mapa kolorów do efektów i oświetlenia (``COLORMAP_IDX``) -- jeśli ustawiona jest flaga ``COLORMAP``, - mapa kolorów do zmiany palety (``TRANSLATION_IDX`` -- jeśli ustawiona jest flaga ``TRANSLATION``. Polecenie rysuje kolumnę pikseli do bufora ramki na współrzędnych ``X_A, Y_A`` do ``X_B, Y_B``. ``X_A`` powinno być równe ``X_B``, a ``Y_A`` powinno być mniejsze od lub równe ``Y_B`` (inaczej zachowanie urządzenia jest niezdefiniowane). Rysowana kolumna jest teksturowana za pomocą następującego algorytmu:: # Obliczenie koloru dla piksela (x, y). coord = (USTART + USTEP * (y - Y_A)) >> 16 if TEXTURE_DIMS.HEIGHT != 0: coord %= TEXTURE_HEIGHT tex_offset = TEXTURE_OFFSET + coord if tex_offset < 0 or (tex_offset >> 6) > TEXTURE_LIMIT: color = 0; else: color = read_paged(TEXTURE_PT, tex_offset) if TRANSLATION: color = read_paged(TRANSLATION_PT, TRANSLATION_IDX << 8 | color) if COLORMAP: color = read_paged(COLOR_PT, COLOR_IDX << 8 | color) if TRANMAP: bg_color = surf_read(SURF_DST_PT, x, y); color = read_paged(TRANMAP_PT, bg_color << 8 | color) Polecenie ``DRAW_FUZZ`` ----------------------- Aplikuje efekt rozmytego cienia na kolumnie w buforze ramki (``SURF_DST_PT``). Jego parametry to: - współrzędne górnego punktu kolumny (``X_A``, ``Y_A``), - współrzędne dolnego punktu kolumny (``X_B``, ``Y_B``), - mapa kolorów do efektu cienia (``COLORMAP_IDX``), - początkowa współrzędna y pola widzenia (``FUZZ_START``) -- potrzebna, by efekt rozmycia nie użył pikseli z poza rysowanego obszaru ramki, - końcowa współrzędna y pola widzenia (``FUZZ_END``), - źródło losowości dla efektu cienia (``FUZZ_POS``) -- liczba z zakresu 0-55, Polecenie modyfikuje kolumnę pikseli w buforze ramki na współrzędnych ``X_A, Y_A`` do ``X_B, Y_B``. ``X_A`` powinno być równe ``X_B``, a współrzędnie y powinny spełniać nierówność ``FUZZ_START ≤ Y_A ≤ Y_B ≤ FUZZ_END`` (inaczej zachowanie urządzenia jest niezdefiniowane). Urządzenie może przeczytać piksele z wybranej kolumny o współrzędnych y z zakresu ``[FUZZ_START, FUZZ_END]``. Polecenie ``DRAW_SPAN`` ----------------------- Rysuje teksturowany pasek do bufora ramki (``SURF_DST_PT``). Jego parametry to: - współrzędne lewego punktu paska (``X_A``, ``Y_A``), - współrzędne prawego punktu paska (``X_B``, ``Y_B``), - flagi ``TRANSLATE``, ``COLORMAP``, ``TRANMAP`` - wartość początkowa współrzędnych u i v w teksturze (``USTART``, ``VSTART``), - pochodna współrzędnych u i v po współrzędnej x (``USTEP``, ``VSTEP``), - mapa kolorów do efektów i oświetlenia (``COLORMAP_IDX``) -- jeśli ustawiona jest flaga ``COLORMAP``, - mapa kolorów do zmiany palety (``TRANSLATION_IDX`` -- jeśli ustawiona jest flaga ``TRANSLATE``. Polecenie rysuje pasek pikseli do bufora ramki na współrzędnych ``X_A, Y_A`` do ``X_B, Y_B``. ``Y_A`` powinno być równe ``Y_B``, a ``X_A`` powinno być mniejsze od lub równe ``X_B`` (inaczej zachowanie urządzenia jest niezdefiniowane). Rysowany pasek jest teksturowany za pomocą następującego algorytmu:: # Obliczenie koloru dla piksela (x, y). u = (USTART + USTEP * (x - X_A)) >> 16 & 0x3f v = (VSTART + VSTEP * (x - X_A)) >> 16 & 0x3f color = read_paged(FLAT_PT, u | v << 6) if TRANSLATE: color = read_paged(TRANSLATION_PT, TRANSLATION_IDX << 8 | color) if COLORMAP: color = read_paged(COLOR_PT, COLOR_IDX << 8 | color) if TRANMAP: bg_color = surf_read(SURF_DST_PT, x, y); color = read_paged(TRANMAP_PT, bg_color << 8 | color) Synchronizacja ============== Blok rysujący działa wysoce asynchronicznie i równolegle. W szczególności, urządzenie może: - wczytywać nowe polecenia przed zakończeniem wykonania poprzednich. - wczytywać dane źródłowe dla polecenia przed zakończeniem wykonywania poprzednich poleceń (należy na to uważać przy operacji ``COPY_RECT``!). - rozpocząć rysowanie pikseli dla nowej operacji przed zakończeniem poprzedniej operacji (ale tylko, jeśli operacje te operują na rozłącznych pikselach w buforze ramki). - opóźnić rozpoczęcie wykonywania operacji do momentu wysłania kolejnych poleceń (aby spróbować połączyć je w większą paczkę wewnętrznych operacji). Mamy jednak następujące gwarancje: - każde polecenie będzie używało stanu parametrów (adresów i rozmiarów buforów) z momentu jego rozpoczęcia. - jeśli wyślemy polecenie resetujące pamięć podręczną bądź bufor TLB, każde polecenie wysłane później będzie widziało dane wczytane już po wykonaniu tego resetu. - dla konkretnego piksela w docelowym buforze ramki, polecenia będą wykonywane zgodnie z kolejnością wysyłania (czyli wygra ostatni zapis). - polecenie ``COPY_RECT`` wczyta wszystkie swoje dane źródłowe przed rozpoczęciem rysowania późniejszych poleceń. - urządzenie nie może mieć więcej niż 2048 poleceń w locie (wczytanych do FIFO, ale jeszcze nie wykonanych) -- dopóki nasz bufor poleceń jest mniejszy niż ``2**32 - 2048``, nie musimy się przejmować, że skończą nam się wolne identyfikatory do ``FENCE_COUNTER``. - wysłanie polecenia z flagą ``FENCE`` bądź ``PING_SYNC`` spowoduje wykonanie go w skończonym czasie (bez tych flag, mikrokod może oczekiwać na kolejne polecenia, by spróbować połączyć je w większe paczki). Flaga ``INTERLOCK`` ------------------- W praktyce, wykonanie przez urządzenie daje efekty identyczne do wykonania sekwencyjnego, z jednym ważnym wyjątkiem -- polecenie ``COPY_RECT`` może wczytać piksele danego bufora ramki zanim poprzednie polecenia zdążą je zapisać. Aby uniknąć tego problemu, należy wykryć taką możliwość w sterowniku i użyć flagi ``INTERLOCK`` w poleceniu. Flaga ``INTERLOCK`` blokuje rozpoczęcie wczytywania danych przez obecne i późniejsze polecenia ``COPY_RECT`` do momentu pełnego zakończenia wcześniejszych operacji rysujących. Aby wszystko działało poprawnie, wystarczy zapewnić, że między operacją rysowania do danego bufora a operacją ``COPY_RECT`` czytającą z niego znajdzie się co najmniej jedno polecenie z ustawioną flagą ``INTERLOCK``. Flagi ``PING_SYNC`` i ``PING_ASYNC`` ------------------------------------ W każdym poleceniu możemy ustawić flagi ``PING_SYNC`` oraz ``PING_ASYNC``. Jeśli ustawiona jest flaga ``PING_SYNC``, urządzenie wyzwoli przerwanie ``PONG_SYNC`` po pełnym zakończeniu wykonywania danego polecenia. Jeśli ustawiona jest flaga ``PING_ASYNC``, urządzenie wyzwoli przerwanie ``PONG_ASYNC`` gdy tylko polecenie zostanie wczytane z kolejki i zacznie się wykonywać. Licznik poleceń --------------- Do elastycznego oczekiwania na wykonanie operacji przez urządzenie służy licznik poleceń, dostępny w następujących rejestrach MMIO: ``BAR0 + 0x0010: FENCE_COUNTER`` Rejestr do odczytu i zapisu, 32-bitowy. Zlicza zakończone polecenia z ustawioną flagą ``FENCE`` -- licznik jest zwiększany o 1 (modulo ``2**32``), gdy dane polecenie (i wszystkie poprzednie polecenia) zostanie w pełni zakończone. (Jeśli licznik na początku wynosi 0 i zaczniemy wysyłać polecenia, po czym odczytamy wartość ``x``, oznacza to, że polecenia ``0..x-1`` zostały w pełni zakońćzone.) ``BAR0 + 0x0014: FENCE_WAIT`` Rejestr do odczytu i zapisu, 32-bitowy (tak jak ``FENCE_COUNTER``). Gdy ``FENCE_COUNTER`` zostanie zwiększony przez urządzenie i osiągnie przez to wartość równą wartości tego rejestru, zostanie wyzwolone przerwanie ``FENCE``. ``FENCE_WAIT`` pozwala na zaawansowaną implementację oczekiwania na wysłane wcześniej polecenia. Przykładowy mechanizm użycia wygląda następująco: - przed włączeniem urządzenia, inicjujemy ``FENCE_COUNTER`` na 0. - na końcu każdej paczki poleceń, na zakończenie której chcemy czekać, wysyłamy polecenie z ustawioną flagą ``FENCE``. - dla każdego wysłanego polecenia z flagą ``FENCE`` pamiętamy jego odpowiadającą wartość ``FENCE_COUNTER`` (dla kolejnych poleceń, kolejno ``1, 2, 3, ...``, zawijając się modulo ``2**32``). - nie dopuszczamy, by kiedykolwiek było więcej niż 2**32 poleceń z flagą ``FENCE`` "w locie" (w razie potrzeby czekając na zakończenie poprzednich poleceń przed wysłaniem kolejnego). - jeśli w pewnym momencie uznamy, że chcemy oczekiwać na wykonanie wysłanego wcześniej polecenia: - czyścimy przerwanie ``FENCE``. - ustawiamy ``FENCE_WAIT`` na numer polecenia, na które chcemy oczekiwać. - czytamy ``FENCE_COUNTER`` i sprawdzamy, czy polecenie już się wykonało. - jeśli się nie wykonało, czekamy na wyzwolenie przerwania ``FENCE``. Przed rozpoczęciem pracy, sterownik może zainicjować ``FENCE_COUNTER`` na pożądaną wartość początkową (prawdopodobnie 0). Pisanie do tego rejestru, gdy urządzenie jest już aktywne, jest prawdopodobnie złym pomysłem. Rejestry sterujące ================== Blok sterujący zajmuje się nadzorowaniem pracy całego urządzenia. Jego rejestry to: ``BAR0 + 0x0000: ENABLE`` Rejestr kontrolujący pracę pozostałych bloków, dostępny do odczytu i zapisu. Ma wiele bitów, z których każdy kontroluje pracę jednego bloku urządzenia (1 -- blok jest aktywny i może wykonywać pracę, 0 -- blok jest nieaktywny). Wyłączenie bloku w tym rejestrze nie spowoduje jego resetu -- po ponownym włączeniu, blok kontynuuje pracę od momentu, w którym skończył. Bity: - bit 0: ``CMD_FETCH`` -- blok wczytywania poleceń. - bit 1: ``CMD_SEND`` -- dostęp do kolejki poleceń przez ``CMD_SEND``. - bit 2: ``FE`` -- blok rysujący, przetwarzanie poleceń. - bit 3: ``XY`` -- blok rysujący, przeliczanie współrzędnych na adresy. - bit 4: ``TEX`` -- blok rysujący, obsługa tekstur kolumnowych. - bit 5: ``FLAT`` -- blok rysujący, obsługa tekstur płaskich. - bit 6: ``FUZZ`` -- blok rysujący, efekt ``FUZZ``. - bit 7: ``SR`` -- blok rysujący, wczytywanie pikseli z bufora ramki. - bit 8: ``OG`` -- blok rysujący, zbieranie danych i mapy kolorów - bit 9: ``SW`` -- blok rysujący, mapy przezroczystości i zapis do bufora ramki. Rejestr jest ustawiany na 0 przez reset maszyny, blokując urządzenie do momentu załadowania sterownika. W przypadku zgłoszenia błędu przez blok rysujący, urządzenie wyzeruje odpowiedni bit w tym rejestrze, zatrzymując blok do momentu naprawienia problemu przez sterownik. .. warning:: Przed włączeniem urządzenia, należy pamiętać o: - załadowaniu mikrokodu przez ``FE_CODE_ADDR`` i ``FE_CODE_WINDOW`` - zresetowaniu wszystkich bloków w ``RESET``, - zainicjowaniu rejestrów ``CMD_*_IDX`` (jeśli używamy bloku wczytywania poleceń) - wyzerowaniu przerwań (w ``INTR``) ``BAR0 + 0x0004: RESET`` Rejestr resetowania stanu urządzenia, dostępny tylko do zapisu. Ma wiele bitów, odpowiadających blokom urządzenia. Przy zapisie, wszystkie bloki, których bity są równe 1 w zapisanej wartości, są resetowane: wszystkie polecenia w trakcie wykonywania są przerywane i kasowane, kolejki poleceń i pamięci podręczne są czyszczone. Bity: - bit 2: ``FE`` -- blok rysujący, przetwarzanie poleceń. - bit 3: ``XY`` -- blok rysujący, przeliczanie współrzędnych na adresy. - bit 4: ``TEX`` -- blok rysujący, obsługa tekstur kolumnowych. - bit 5: ``FLAT`` -- blok rysujący, obsługa tekstur płaskich. - bit 6: ``FUZZ`` -- blok rysujący, efekt ``FUZZ``. - bit 7: ``SR`` -- blok rysujący, wczytywanie pikseli z bufora ramki. - bit 8: ``OG`` -- blok rysujący, zbieranie danych i mapy kolorów - bit 9: ``SW`` -- blok rysujący, mapy przezroczystości i zapis do bufora ramki. - bit 10: ``STATS`` -- blok statystyk. Wszystkie liczniki są ustawiane na 0. - bit 11: ``TLB`` -- bufory TLB. Wszystkie wpisy tabeli stron zapisane w TLB są kasowane i, w razie potrzeby, zostaną wczytane na nowo. - bit 12: ``TEX_CACHE`` -- pamięć podręczna tekstury kolumnowej. - bit 13: ``FLAT_CACHE`` -- pamięć podręczna tekstury płaskiej. - bit 14: ``SW_CACHE`` -- pamięć podręczna mapy przezroczystości. - bit 16: ``FIFO_FECMD`` -- główna kolejka poleceń bloku rysującego. - bit 17: ``FIFO_XYCMD`` -- wewnętrzna kolejka urządzenia. - bit 18: ``FIFO_TEXCMD`` -- wewnętrzna kolejka urządzenia. - bit 19: ``FIFO_FLATCMD`` -- wewnętrzna kolejka urządzenia. - bit 20: ``FIFO_FUZZCMD`` -- wewnętrzna kolejka urządzenia. - bit 21: ``FIFO_OGCMD`` -- wewnętrzna kolejka urządzenia. - bit 22: ``FIFO_SWCMD`` -- wewnętrzna kolejka urządzenia. - bit 24: ``FIFO_XYOUTR`` -- wewnętrzna kolejka urządzenia. - bit 25: ``FIFO_XYOUTW`` -- wewnętrzna kolejka urządzenia. - bit 26: ``FIFO_SROUT`` -- wewnętrzna kolejka urządzenia. - bit 27: ``FIFO_TEXOUT`` -- wewnętrzna kolejka urządzenia. - bit 28: ``FIFO_FLATOUT`` -- wewnętrzna kolejka urządzenia. - bit 29: ``FIFO_FUZZOUT`` -- wewnętrzna kolejka urządzenia. - bit 30: ``FIFO_OGOUT`` -- wewnętrzna kolejka urządzenia. - bit 31: ``FIFO_XYSYNC`` -- wewnętrzna kolejka urządzenia. Użycie bitów ``TLB``, ``STATS`` i ``*_CACHE`` w dowolnym momencie nie wpłynie negatywnie na pracę urządzenia. Wszystkie pozostałe bity powinny być używane w zasadzie tylko wtedy, gdy resetujemy całe urządzenie (gdyż w przeciwnym przypadku stan poszczególnych bloków się rozsynchronizuje). .. warning:: Przed użyciem urządzenia (włączeniem bloku rysującego w ``ENABLE``) należy zresetować cały blok rysujący (zapisując ``0xff7f7ffc`` do tego rejestru) -- w przeciwnym wypadku, wewnętrzne rejestry stanu urządzenia mogą zawierać śmieci, powodując wykonanie nieokreślonych poleceń przez urządzenie (w tym zapisu do dowolnej pamięci) bądź zawieszenie urządzenia. Blok wczytywania poleceń nie ma swojego bitu resetującego -- jeśli sterownik chce go użyć, powinien zamiast tego zainicjować rejestry ``CMD_*_IDX``. Przerwania ---------- Urządzenie wewnętrznie używa 10 przerwań (które są agregowane w jedno przerwanie PCI): - ``FENCE`` -- przerwanie używane do powiadomienia sterownika o wykonaniu polecenia. Wyzwalane, gdy licznik poleceń osiągnie wartość ``FENCE_WAIT``. - ``PONG_SYNC`` -- wyzwalane przez polecenie z flagą ``PING_SYNC``. - ``PONG_ASYNC`` -- wyzwalane przez polecenie z flagą ``PING_ASYNC``. - ``FE_ERROR`` -- wyzwalane, gdy blok rysujący zauważy błędne polecenie. - ``CMD_OVERFLOW`` -- wyzwalane, gdy sterownik spróbuje pisać do ``CMD_SEND``, gdy nie ma już wolnego miejsca w kolejce, lub blok ``CMD_SEND`` jest wyłączony. - ``SURF_DST_OVERFLOW`` -- wyzwalane, gdy blok rysujący spróbuje pisać lub czytać piksel o współrzędnych poza szerokością docelowego bufora ramki (ustaloną przez ``SURF_DST_WIDTH``). - ``SURF_SRC_OVERFLOW`` -- wyzwalane, gdy blok rysujący spróbuje lub czytać piksel o współrzędnych poza szerokością źródłowego bufora ramki (ustaloną przez ``SURF_SRC_WIDTH``). - ``PAGE_FAULT_CMD`` -- wyzwalane, gdy blok wczytywania poleceń użyć strony oznaczonej w tabeli stron jako nieobecna. - ``PAGE_FAULT_SURF_DST`` -- wyzwalane, gdy blok rysujący spróbuje użyć strony oznaczonej w tabeli stron jako nieobecna bądź tylko do odczytu przy pisaniu lub czytaniu docelowego bufora ramki. - ``PAGE_FAULT_SURF_SRC`` -- jak wyżej, ale do źródłowego bufora ramki. - ``PAGE_FAULT_TEXTURE`` -- jak wyżej, ale do czytania tekstury kolumnowej. - ``PAGE_FAULT_FLAT`` -- jak wyżej, ale do czytania tekstury płaskiej. - ``PAGE_FAULT_TRANSLATION`` -- jak wyżej, ale do czytania map kolorów do zmiany palety. - ``PAGE_FAULT_COLORMAP`` -- jak wyżej, ale do czytania map kolorów do efektów i oświetlenia. - ``PAGE_FAULT_TRANMAP`` -- jak wyżej, ale do czytania mapy przezroczystości. .. warning:: Wyzwolenie przerwania ``SURF_*_OVERFLOW`` jest zasadniczo błędem krytycznym -- nie ma sensownej możliwości obsługi tego błędu innej niż pełny reset urządzenia. To przerwanie (tak jak i ``FE_ERROR`` czy ``CMD_OVERFLOW``) nie powinno się nigdy zdarzyć z poprawnym sterownikiem. Przerwania ``PAGE_FAULT_*`` teoretycznie mogą zostać użyte do ładowania stron na żądanie, ale w praktyce nie jest to zbyt przydatne i w zasadzie służą również do wykrywania błędów sterownika. Każde z powyższych przerwań może być w danej chwili aktywne bądź nie. Przerwanie staje się aktywne, gdy zajdzie odpowiednie zdarzenie. Przerwanie staje się nieaktywne, gdy sterownik zapisze 1 do odpowiedniego bitu w rejestrze ``INTR``. Aby sprawdzić, które przerwania są aktywne, należy przeczytać rejestr ``INTR``. Niezależnie, każde z powyższych przerwań może być w danej chwili włączone bądź nie. Sterownik może ustawić włączony podzbiór przerwań przez zapis odpowiedniej maski do rejestru ``INTR_ENABLE``. Urządzenie zgłasza przerwanie na swojej linii przerwań PCI wtedy i tylko wtedy, gdy istnieje włączone i aktywne przerwanie. ``BAR0 + 0x0008: INTR`` Rejestr statusu przerwań. Ma 15 bitów, każdy odpowiadający jednemu rodzajowi przerwań: - bit 0: ``FENCE``, - bit 1: ``PONG_SYNC``, - bit 2: ``PONG_ASYNC``, - bit 4: ``FE_ERROR``, - bit 5: ``CMD_OVERFLOW`` - bit 6: ``SURF_DST_OVERFLOW`` - bit 7: ``SURF_SRC_OVERFLOW`` - bit 8: ``PAGE_FAULT_CMD`` - bit 9: ``PAGE_FAULT_SURF_DST`` - bit 10: ``PAGE_FAULT_SURF_SRC`` - bit 11: ``PAGE_FAULT_TEXTURE`` - bit 12: ``PAGE_FAULT_FLAT`` - bit 13: ``PAGE_FAULT_TRANSLATION`` - bit 14: ``PAGE_FAULT_COLORMAP`` - bit 15: ``PAGE_FAULT_TRANMAP`` Odczyt tego rejestru zwróci 1 dla aktywnych przerwań, 0 dla nieaktywnych. Zapis spowoduje wyzerowanie (ustawienie na nieaktywne) wszystkich przerwań, dla których został zapisany bit 1. Przykładowo, zapisanie 0x12 spowoduje wyzerowanie przerwań ``FE_ERROR`` oraz ``PONG_SYNC``. ``BAR0 + 0x000c: INTR_ENABLE`` Rejestr włączania przerwań, dostępny do odczytu i zapisu. Ma takie same bity jak ``INTR``. 1 oznacza przerwanie włączone, a 0 -- przerwanie wyłączone. Przy resecie maszyny, rejestr zostaje ustawiony na 0, blokując możliwość zgłaszania przerwania PCI przez urządzenie do momentu załadowania sterownika. Mikrokod -------- Blok rysujący opiera się na zaawansowanym procesorze odpowiadającym za przetwarzanie poleceń. Przed włączeniem bloku rysującego w ``ENABLE``, sterownik musi załadować odpowiedni mikrokod na urządzenie -- w przeciwnym wypadku, zachowanie urządzenia jest kompletnie niezdefiniowane. Mikrokod jest tablicą 32-bitowych słów, maksymalnie 4096-elementową. Jest dostarczany w pliku https://github.com/koriakin/harddoom2/blob/master/doomcode2.bin w formacie little-endian, a jego format i działanie jest tajemnicą handlową firmy DoomDevices® (i nie należy zadawać niewygodnych pytań na jego temat). Można go również pobrać jako plik nagłówkowy gotowy do załączenia do kodu w C: https://github.com/koriakin/harddoom2/blob/master/doomcode2.h . Do ładowania mikrokodu służą następujące rejestry: ``BAR0 + 0x0100: FE_CODE_ADDR`` Indeks w tablicy, który będziemy widoczny przez ``FE_CODE_WINDOW`` (dostępny do odczytu i zapisu). ``BAR0 + 0x0104: FE_CODE_WINDOW`` Okno do tablicy mikrokodu -- odczytuje bądź zapisuje komórkę wybrana przez ``FE_CODE_ADDR``, po czym zwiększa ``FE_CODE_ADDR`` o 1 (pozwalając na szybki sekwencyjny odczyt bądź zapis wielu komórek tablicy). Uruchomienie urządzenia ----------------------- Poprawna procedura uruchamiania urządzenia jest następująca (użycie dowolnej innej procedury spowoduje utratę gwarancji i brak możliwości zwrotu urządzenia): - zapisać 0 do ``FE_CODE_ADDR``, - wczytać zawartość pliku ``doomcode2.bin`` jako tablicę 32-bitowych słów little-endian, - kolejno zapisać wszystkie wczytane słowa do ``FE_CODE_WINDOW``, - zresetować wszystkie bloki urządzenia przez zapis ``0xff7f7ffc`` do ``RESET``, - zainicjować ``CMD_PT``, ``CMD_SIZE`` i ``CMD_*_IDX``, jeśli chcemy użyć bloku wczytywania pleceń, - wyzerować ``INTR`` przez zapis ``0xfff7``, - włączyć używane przez nas przerwania w ``INTR_ENABLE``, - zainicjować ``FENCE_COUNTER``, jeśli czujemy taką potrzebę, - włączyć wszystkie bloki urządzenia w ``ENABLE`` (być może z wyjątkiem ``CMD_FETCH``). Po wykonaniu tej procedury można rozpocząć wysyłanie poleceń do urządzenia (przez ``CMD_SEND`` lub ``CMD_WRITE_IDX``). Żeby wyłączyć urządzenie, wystarczy zapisać 0 do ``ENABLE`` oraz ``INTR_ENABLE``, po czym przeczytać dowolny rejestr urządzenia. Inne rejestry ============= Dokumentacja sprzętowa nigdy nie mówi całej prawdy (i rzadko mówi tylko prawdę). Urządzenie może mieć inne rejestry i polecenia ponad wyżej wymienione, lecz używanie ich w ostatecznym sterowniku jest złym pomysłem -- są to po prostu szczegóły implementacyjne. Mogą jednak być przydatne przy debugowaniu... Poniższe rejestry nie są potrzebne do napisania sterownika, ale mają sporą szansę się przydać (oprócz nich, urządzenie zawiera wiele nieudokumentowanych rejestrów). Rejestry błędów --------------- W przypadku popełnienia błędu przez sterownik, przydatne może być przeczytanie następujących rejestrów: ``BAR0 + 0x004: STATUS`` Rejestr statusu, tylko do odczytu. Ma wiele bitów, odpowiadających blokom urządzenia. Gdy bit jest równy 1, dany blok ma pracę do wykonania (i, jeśli odpowiedni bit w ``ENABLE`` jest równy 1, będzie próbował ją wykonać). Gdy bit jest równy 0, dany blok nie ma nic do zrobienia (ale może się to w każdej chwili zmienić, jeżeli inny blok zleci mu jakieś zadania). Bity: - bit 0: ``CMD_FETCH`` -- blok wczytywania poleceń (ten bit jest efektywnie równy ``CMD_READ_IDX != CMD_WRITE_IDX``). - bit 2: ``FE`` -- blok rysujący, przetwarzanie poleceń. - bit 3: ``XY`` -- blok rysujący, przeliczanie współrzędnych na adresy. - bit 4: ``TEX`` -- blok rysujący, obsługa tekstur kolumnowych. - bit 5: ``FLAT`` -- blok rysujący, obsługa tekstur płaskich. - bit 6: ``FUZZ`` -- blok rysujący, efekt ``FUZZ``. - bit 7: ``SR`` -- blok rysujący, wczytywanie pikseli z bufora ramki. - bit 8: ``OG`` -- blok rysujący, zbieranie danych i mapy kolorów - bit 9: ``SW`` -- blok rysujący, mapy przezroczystości i zapis do bufora ramki. - bit 16: ``FIFO_FECMD`` -- główna kolejka poleceń bloku rysującego. - bit 17: ``FIFO_XYCMD`` -- wewnętrzna kolejka urządzenia. - bit 18: ``FIFO_TEXCMD`` -- wewnętrzna kolejka urządzenia. - bit 19: ``FIFO_FLATCMD`` -- wewnętrzna kolejka urządzenia. - bit 20: ``FIFO_FUZZCMD`` -- wewnętrzna kolejka urządzenia. - bit 21: ``FIFO_OGCMD`` -- wewnętrzna kolejka urządzenia. - bit 22: ``FIFO_SWCMD`` -- wewnętrzna kolejka urządzenia. - bit 24: ``FIFO_XYOUTR`` -- wewnętrzna kolejka urządzenia. - bit 25: ``FIFO_XYOUTW`` -- wewnętrzna kolejka urządzenia. - bit 26: ``FIFO_SROUT`` -- wewnętrzna kolejka urządzenia. - bit 27: ``FIFO_TEXOUT`` -- wewnętrzna kolejka urządzenia. - bit 28: ``FIFO_FLATOUT`` -- wewnętrzna kolejka urządzenia. - bit 29: ``FIFO_FUZZOUT`` -- wewnętrzna kolejka urządzenia. - bit 30: ``FIFO_OGOUT`` -- wewnętrzna kolejka urządzenia. - bit 31: ``FIFO_XYSYNC`` -- wewnętrzna kolejka urządzenia. ``BAR0 + 0x0110: FE_ERROR_CODE`` Kod ostatnio zgłoszonego błędu ``FE_ERROR``. Zdefiniowane są następujące kody: - ``0x00``: ``RESERVED_TYPE`` -- nieznany typ polecenia. - ``0x01``: ``RESERVED_BIT`` -- nieużywany bit nie jest ustawiony na 0. - ``0x02``: ``SURF_WIDTH_ZERO`` -- zerowa szerokość bufora ramki. - ``0x03``: ``SURF_WIDTH_OVF`` -- bufor ramki szerszy niż 2048 pikseli. - ``0x04``: ``DRAW_COLUMN_REV`` -- pierwszy piksel kolumny ma większą współrzędną Y niż drugi. - ``0x05``: ``DRAW_FUZZ_REV`` -- pierwszy piksel kolumny ma większą współrzędną Y niż drugi. - ``0x06``: ``DRAW_SPAN_REV`` -- pierwszy piksel paska ma większą współrzędną X niż drugi. ``BAR0 + 0x0180 + i * 4, i < 8: FE_REG`` Polecenie, którego dotyczy ostatnio zgłoszony błąd ``FE_ERROR``. ``BAR0 + 0x0600: XY_STATE`` Szerokości buforów ramki obowiązujące w momencie zgłoszenia błędu ``SURF_OVERFLOW``. Bity: - bity 0-5: ``SURF_DST_WIDTH``. - bity 8-13: ``SURF_SRC_WIDTH``. ``BAR0 + 0x0608: XY_DST_DATA`` W przypadku błędów ``PAGE_FAULT_SURF_DST`` oraz ``SURF_DST_OVERFLOW`` można tu przeczytać współrzędne, które wywołały błąd: - bity 0-4: bity 6-10 współrzędnej x (bity 0-5 nie są zapisywane) - bity 5-15: współrzędna y ``BAR0 + 0x060c: XY_SRC_DATA`` Jak wyżej, ale do ``PAGE_FAULT_SURF_SRC`` i ``SURF_SRC_OVERFLOW``. ``BAR0 + 0x0080: TLB_PT_CMD`` ``BAR0 + 0x0084: TLB_PT_SURF_DST`` ``BAR0 + 0x0088: TLB_PT_SURF_SRC`` ``BAR0 + 0x008c: TLB_PT_TEXTURE`` ``BAR0 + 0x0090: TLB_PT_FLAT`` ``BAR0 + 0x0094: TLB_PT_TRANSLATION`` ``BAR0 + 0x0098: TLB_PT_COLORMAP`` ``BAR0 + 0x009c: TLB_PT_TRANMAP`` Adres początku tabeli stron używanej w momencie wyzwolenia błędu ``PAGE_FAULT_*`` (przesunięty w prawo o 8 bitów, jak w poleceniu ``SETUP``). ``BAR0 + 0x00c0: TLB_VADDR_CMD`` ``BAR0 + 0x00c4: TLB_VADDR_SURF_DST`` ``BAR0 + 0x00c8: TLB_VADDR_SURF_SRC`` ``BAR0 + 0x00cc: TLB_VADDR_TEXTURE`` ``BAR0 + 0x00d0: TLB_VADDR_FLAT`` ``BAR0 + 0x00d4: TLB_VADDR_TRANSLATION`` ``BAR0 + 0x00d8: TLB_VADDR_COLORMAP`` ``BAR0 + 0x00dc: TLB_VADDR_TRANMAP`` Adres wirtualny, który spowodował błąd ``PAGE_FAULT_*``. Niskie 6 bitów nie jest zapisywane (jest zawsze równe 0). Blok statystyk -------------- Blok rysujący zbiera różnorodne statystyki dotyczące pracy urządzenia. Są one bezpośrednio widoczne jako rejestry MMIO. Każdy taki rejestr jest 32-bitowym licznikiem (który może się przekręcić -- urządzenie nie robi wtedy nic specjalnego). Te liczniki zliczają następujące zdarzenia: - ``BAR0 + 0x0400: STATS_FE_COPY_RECT_HORIZONTAL`` -- polecenie ``COPY_RECT`` realizowane poziomo - ``BAR0 + 0x0404: STATS_FE_COPY_RECT_LINE`` -- jedna linia poziomego polecenia ``COPY_RECT`` - ``BAR0 + 0x0408: STATS_FE_COPY_RECT_VERTICAL`` -- polecenie ``COPY_RECT`` realizowane pionowo - ``BAR0 + 0x040c: STATS_FE_FILL_RECT_HORIZONTAL`` -- polecenie ``FILL_RECT`` realizowane poziomo - ``BAR0 + 0x0410: STATS_FE_FILL_RECT_LINE`` -- jedna linia poziomego polecenia ``FILL_RECT`` - ``BAR0 + 0x0414: STATS_FE_FILL_RECT_VERTICAL`` -- polecenie ``FILL_RECT`` realizowane pionowo - ``BAR0 + 0x0418: STATS_FE_DRAW_BACKGROUND`` -- polecenie ``DRAW_BACKGROUND`` - ``BAR0 + 0x041c: STATS_FE_DRAW_BACKGROUND_LINE`` -- jedna linia polecenia ``DRAW_BACKGROUND`` - ``BAR0 + 0x0420: STATS_FE_DRAW_LINE_HORIZONTAL`` -- polecenie ``DRAW_LINE`` realizowane poziomo - ``BAR0 + 0x0424: STATS_FE_DRAW_LINE_VERTICAL`` -- polecenie ``DRAW_LINE`` realizowane pionowo - ``BAR0 + 0x0428: STATS_FE_DRAW_LINE_H_CHUNK`` -- rysowanie prostokąta N×1 linii poziomej - ``BAR0 + 0x042c: STATS_FE_DRAW_LINE_V_CHUNK`` -- rysowanie prostokąta 1×N linii pionowej - ``BAR0 + 0x0430: STATS_FE_DRAW_LINE_H_PIXEL`` -- rysowanie piksela linii poziomej - ``BAR0 + 0x0434: STATS_FE_DRAW_LINE_V_PIXEL`` -- rysowanie piksela linii pionowej - ``BAR0 + 0x0438: STATS_FE_DRAW_COLUMN_BATCH`` -- grupa poleceń ``DRAW_COLUMN`` przetwarzana równolegle - ``BAR0 + 0x043c: STATS_FE_DRAW_FUZZ_BATCH`` -- grupa poleceń ``DRAW_FUZZ`` przetwarzana równolegle - ``BAR0 + 0x0440: STATS_FE_DRAW_COLUMN`` -- polecenie ``DRAW_COLUMN`` - ``BAR0 + 0x0444: STATS_FE_DRAW_FUZZ`` -- polecenie ``DRAW_FUZZ`` - ``BAR0 + 0x0448: STATS_FE_DRAW_COLUMN_CHUNK`` -- jeden pionowy segment grupy poleceń ``DRAW_COLUMN`` - ``BAR0 + 0x044c: STATS_FE_DRAW_FUZZ_CHUNK`` -- jeden pionowy segment grupy poleceń ``DRAW_FUZZ`` - ``BAR0 + 0x0450: STATS_FE_PING_ASYNC`` -- polecenie z flagą ``PING_ASYNC`` - ``BAR0 + 0x0454: STATS_FE_LOAD_FLAT`` -- załadowanie nowej tekstury płaskiej - ``BAR0 + 0x0458: STATS_FE_LOAD_TRANSLATION`` -- załadowanie nowej mapy kolorów do zmiany palety - ``BAR0 + 0x045c: STATS_FE_LOAD_COLORMAP`` -- załadowanie nowej mapy kolorów do efektów - ``BAR0 + 0x0460: STATS_FE_BATCH_END_MISMATCH_COLORMAP`` -- przerwanie paczki poleceń przez zmianę aktywnej mapy kolorów - ``BAR0 + 0x0464: STATS_FE_BATCH_END_MISMATCH_TEX_DIMS`` -- przerwanie paczki poleceń przez zmianę aktywnej wysokości bądź limitu tekstury - ``BAR0 + 0x0468: STATS_FE_BATCH_END_MISMATCH_CMD`` -- przerwanie paczki poleceń przez wysłanie nowego typu polecenia - ``BAR0 + 0x046c: STATS_FE_BATCH_END_MISMATCH_FUZZ`` -- przerwanie paczki poleceń przez zmianę granic efektu ``DRAW_FUZZ`` - ``BAR0 + 0x0470: STATS_FE_BATCH_END_SIZE`` -- przerwanie paczki poleceń przez osiągnięcie maksymalnego rozmiaru paczki - ``BAR0 + 0x0474: STATS_FE_BATCH_END_XY`` -- przerwanie paczki poleceń przez niepasujące współrzędne kolejnej kolumny - ``BAR0 + 0x0478: STATS_FE_BATCH_END_SYNC`` -- przerwanie paczki poleceń przez wysłanie flagi synchronizacyjnej (``FENCE`` lub ``PING_SYNC``) - ``BAR0 + 0x047c: STATS_FE_DRAW_SPAN`` -- polecenie ``DRAW_SPAN`` - ``BAR0 + 0x0480: STATS_TLB_CMD_HIT`` -- trafienie w buforze TLB dla bufora poleceń. - ``BAR0 + 0x0484: STATS_TLB_SURF_DST_HIT`` -- j/w, docelowy bufor ramki. - ``BAR0 + 0x0488: STATS_TLB_SURF_SRC_HIT`` -- j/w, źródłowy bufor ramki. - ``BAR0 + 0x048c: STATS_TLB_TEXTURE_HIT`` -- j/w, tekstura kolumnowa. - ``BAR0 + 0x0490: STATS_TLB_FLAT_HIT`` -- j/w, tekstura płaska. - ``BAR0 + 0x0494: STATS_TLB_TRANSLATION_HIT`` -- j/w, mapa kolorów do zmiany palety. - ``BAR0 + 0x0498: STATS_TLB_COLORMAP_HIT`` -- j/w, mapa kolorów do efektów. - ``BAR0 + 0x049c: STATS_TLB_TRANMAP_HIT`` -- j/w, mapa przezroczystości. - ``BAR0 + 0x04a0: STATS_TLB_CMD_MISS`` -- chybienie w buforze TLB dla bufora poleceń. - ``BAR0 + 0x04a4: STATS_TLB_SURF_DST_MISS`` -- j/w, docelowy bufor ramki. - ``BAR0 + 0x04a8: STATS_TLB_SURF_SRC_MISS`` -- j/w, źródłowy bufor ramki. - ``BAR0 + 0x04ac: STATS_TLB_TEXTURE_MISS`` -- j/w, tekstura kolumnowa. - ``BAR0 + 0x04b0: STATS_TLB_FLAT_MISS`` -- j/w, tekstura płaska. - ``BAR0 + 0x04b4: STATS_TLB_TRANSLATION_MISS`` -- j/w, mapa kolorów do zmiany palety. - ``BAR0 + 0x04b8: STATS_TLB_COLORMAP_MISS`` -- j/w, mapa kolorów do efektów. - ``BAR0 + 0x04bc: STATS_TLB_TRANMAP_MISS`` -- j/w, mapa przezroczystości. - ``BAR0 + 0x04c0: STATS_TLB_CMD_CHANGE`` -- zmiana aktywnej tabeli stron dla bufora ramki. - ``BAR0 + 0x04c4: STATS_TLB_SURF_DST_CHANGE`` -- j/w, docelowy bufor ramki. - ``BAR0 + 0x04c8: STATS_TLB_SURF_SRC_CHANGE`` -- j/w, źródłowy bufor ramki. - ``BAR0 + 0x04cc: STATS_TLB_TEXTURE_CHANGE`` -- j/w, tekstura kolumnowa. - ``BAR0 + 0x04d0: STATS_TLB_FLAT_CHANGE`` -- j/w, tekstura płaska. - ``BAR0 + 0x04d4: STATS_TLB_TRANSLATION_CHANGE`` -- j/w, mapa kolorów do zmiany palety. - ``BAR0 + 0x04d8: STATS_TLB_COLORMAP_CHANGE`` -- j/w, mapa kolorów do efektów. - ``BAR0 + 0x04dc: STATS_TLB_TRANMAP_CHANGE`` -- j/w, mapa przezroczystości. - ``BAR0 + 0x04e0: STATS_TEX_CACHE_HIT`` -- trafienie teksela w pamięci podręcznej tekstury kolumnowej - ``BAR0 + 0x04e4: STATS_TEX_CACHE_SPEC_HIT`` -- trafienie spekulatywnego teksela w pamięci podręcznej tekstury kolumnowej - ``BAR0 + 0x04e8: STATS_TEX_CACHE_MISS`` -- chybienie teksela (czyli wczytanie 64 bajtów z tekstury) - ``BAR0 + 0x04ec: STATS_TEX_CACHE_SPEC_MISS`` -- chybienie spekulatywnego teksela (czyli porzucenie spekulatywnego teksturowania danej kolumny) - ``BAR0 + 0x04f0: STATS_FLAT_SPAN_BLOCK`` -- oteksturowanie bloku pikseli teksturą płaską - ``BAR0 + 0x04f4: STATS_FLAT_SPAN_PIXEL`` -- oteksturowanie piksela teksturą płaską - ``BAR0 + 0x04f8: STATS_FLAT_CACHE_HIT`` -- trafienie teksela w pamięci podręcznej tekstury płaskiej - ``BAR0 + 0x04fc: STATS_FLAT_CACHE_MISS`` -- chybienie teksela (czyli wczytanie 64 bajtów z tekstury) - ``BAR0 + 0x0500: STATS_OG_DRAW_BUF_BLOCK`` -- rysowanie bloku pikseli przez ``FILL_RECT``, ``DRAW_LINE`` lub ``DRAW_BACKGROUND`` - ``BAR0 + 0x0504: STATS_OG_DRAW_BUF_PIXEL`` -- rysowanie piksela przez ``FILL_RECT``, ``DRAW_LINE`` lub ``DRAW_BACKGROUND`` - ``BAR0 + 0x0508: STATS_OG_COPY_BLOCK`` -- rysowanie bloku pikseli przez ``COPY_RECT`` - ``BAR0 + 0x050c: STATS_OG_COPY_PIXEL`` -- rysowanie piksela przez ``COPY_RECT`` - ``BAR0 + 0x0510: STATS_OG_TRANSLATION_BLOCK`` -- przetwarzanie bloku pikseli przez flagę ``TRANSLATION`` - ``BAR0 + 0x0514: STATS_OG_COLORMAP_BLOCK`` -- przetwarzanie bloku pikseli przez flagę ``COLORMAP`` - ``BAR0 + 0x0518: STATS_OG_TRANSLATION_PIXEL`` -- przetwarzanie piksela przez flagę ``TRANSLATION`` - ``BAR0 + 0x051c: STATS_OG_COLORMAP_PIXEL`` -- przetwarzanie piksela przez flagę ``COLORMAP`` - ``BAR0 + 0x0520: STATS_OG_FUZZ_PIXEL`` -- rysowanie piksela przez ``DRAW_COLUMN`` z ``FUZZ`` - ``BAR0 + 0x0524: STATS_SW_XFER`` -- rysowanie ciągłej grupy pikseli - ``BAR0 + 0x0528: STATS_SW_FENCE`` -- przetworzenie polecenia z flagą ``FENCE`` - ``BAR0 + 0x052c: STATS_SW_PING_SYNC`` -- przetworzenie polecenia z flagą ``PING_SYNC`` - ``BAR0 + 0x0530: STATS_SW_TRANMAP_BLOCK`` -- przetwarzanie bloku pikseli przez flagę ``TRANMAP`` - ``BAR0 + 0x0534: STATS_SW_TRANMAP_PIXEL`` -- przetwarzanie piksela przez flagę ``TRANMAP`` - ``BAR0 + 0x0538: STATS_SW_TRANMAP_HIT`` -- trafienie piksela w pamięci podręcznej mapy przezroczystościj - ``BAR0 + 0x053c: STATS_SW_TRANMAP_MISS`` -- chybienie piksela w tej mapie (czyli wczytanie 64 bajtów z mapy) - ``BAR0 + 0x0540: STATS_FIFO_FECMD`` -- przetworzenie polecenia od użytkownika przez urządzenie - ``BAR0 + 0x0544: STATS_FIFO_XYCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``XY`` - ``BAR0 + 0x0548: STATS_FIFO_TEXCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``TEX`` - ``BAR0 + 0x054c: STATS_FIFO_FLATCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``FLAT`` - ``BAR0 + 0x0550: STATS_FIFO_FUZZCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``FUZZ`` - ``BAR0 + 0x0554: STATS_FIFO_OGCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``OG`` - ``BAR0 + 0x0558: STATS_FIFO_SWCMD`` -- przetworzenie polecenia wewnętrznego przez jednostkę ``SW`` - ``BAR0 + 0x055c: STATS_FIFO_XYSYNC`` -- przetworzenie polecenia z flagą ``INTERLOCK`` - ``BAR0 + 0x0560: STATS_FIFO_SROUT`` -- wczytanie bloku pikseli z bufora ramki - ``BAR0 + 0x0564: STATS_FIFO_TEXOUT`` -- oteksturowanie bloku pikseli teksturą kolumnową - ``BAR0 + 0x0568: STATS_FIFO_FLATOUT`` -- oteksturowanie bloku pikseli teksturą płaską bądź wczytanie bloku pikseli przez ``DRAW_BACKGROUND`` - ``BAR0 + 0x056c: STATS_FIFO_FUZZOUT`` -- nałożenie efektu ``FUZZ`` na blok pikseli - ``BAR0 + 0x0570: STATS_FIFO_OGOUT`` -- zapisanie bloku pikseli do bufora ramki - ``BAR0 + 0x0574: STATS_FIFO_TEXOUT_PIXEL`` -- narysowanie piksela przez ``DRAW_COLUMN`` - ``BAR0 + 0x0578: STATS_FIFO_OGOUT_PIXEL`` -- rysowanie piksela jakiegokolwiek typu - ``BAR0 + 0x057c: STATS_FENCE_INTR`` -- przetworzenie polecenia ``FENCE`` powodującego przerwanie Blok pikseli to maksymalnie 64 piksele różniące się tylko niskimi 6 bitami współrzędnej X (urządzenie grupuje wszystkie rysowane oraz wczytywane piksele w takie bloki). Dzieląc statystyki ``*_PIXEL`` przez ``*_BLOCK`` można zmierzyć efektywność grupowania pikseli przez urządzenie. Dzieląc ``STAT_TEX_COLUMN`` przez ``STAT_FE_DRAW_COLUMN_TEX_BATCH`` można zmierzyć efektywność grupowania kolumn. Dzieląc statystyki ``*_HIT`` przez ``*_HIT + *_MISS`` można zmierzyć efektywność działania pamięci podręcznych i buforów TLB. Zresetowanie bloku statystyk (w rejestrze ``RESET``) jest równoznaczne z zapisem 0 do każdego z wyżej wymienionych liczników.