Urządzenie CasinoDev¶
Urządzenie¶
Urządzenie jest podłączane do komputera przez szynę PCI –
identyfikator producenta to 0x0666
, a identyfikator urządzenia to
0x777
.
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 urządzenie może używać całkiem dużo pamięci, urządzenie wykonuje dostęp do pamięci przez tablicę stron w swoim własnym formacie.
Urządzenie jest zaprojektowane tak, by można było je obsługiwać z minimalną ingerencją jądra w przesyłane polecenia — wszystkie polecenia są walidowane przez urządzenie i operują tylko tylko na adresach wirtualnych, tłumaczonych przez tabele stron — użytkownik przygotowujący bufor poleceń nie ma możliwości zawieszenia urządzenia ani dostępu do nie swojej pamięci. Co najwyżej, może spowodować zgłoszenie błędu przez urządzenie, który może być obsłużony przez jądro systemu.
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ść 64kiB, 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¶
Wszystkie dane i polecenia używane przez urządzenie są zawarte w stronicowanych
buforach. Urządzenie może jednocześnie używać do 16 buforów — blok stronicowania
ma 16 “slotów” (identyfikowane przez liczby 0..15), w które można wpiąć bufor
za pomocą polecenia BIND_SLOT
.
Każdy slot ma następujące atrybuty, wybierane przy wpięciu bufora:
ENABLED
: jeśli ustawiony, do slota wpięty jest bufor, ma tabelę stron, i może być użyty przez urządzenie; jeśli nie jest ustawiony, każda próba użycia tego slotu spowoduje błądTYPE
: Określa typ talii wpiętej w bufor (52 lub 24 karty)PT_ADDR
: adres fizyczny tabeli stronSEED
: używany do losowego generowania kart
Urządzenie używa 40-bitowych adresów fizycznych (zarówno dla buforów jak i dla tabel stron), 22-bitowych adresów wirtualnych w ramach bufora, i stron o rozmiarze 4kiB. Tabele stron używane przez urządzenie są jednopoziomowe:
jądro podaje urządzeniu adres fizyczny katalogu stron przy podpinaniu bufora
bity 12-21 adresu wirtualnego wybierają wpis w tabeli stron (page table), który zawiera adres fizyczny strony
bity 0-11 adresu wirtualnego to offset wewnątrz strony
Tabele stron mają rozmiar 4kiB (taki jak strona) i składają się z 1024 wpisów, gdzie każdy wpis jest 32-bitowym słowem w formacie little-endian. Wpis w tabeli stron ma następujący format:
bit 0:
PRESENT
— jeśli ustawiony, dany wpis jest obecny i może być użyty. Jeśli wyzerowany, wpis jest nieobecny i użycie go spowoduje błąd braku strony (MEM_ERROR
).bity 4-31:
PA
— bity 12-39 adresu fizycznego strony (bity 0-11 adresu są zawsze równe 0 — strony muszą być wyrównane).
Katalog stron wybiera się, podając bity 12-39 jego adresu fizycznego (czyli adres przesunięty w prawo o 12 bitów).
Jeśli urządzenie napotka niepoprawny adres wirtualny (bez flagi PRESENT
), zgłaszane jest przerwanie MEM_ERROR
.
Wysyłanie poleceń¶
Urządzenia używa się przez wysyłanie mu poleceń. Polecenia składają się ze zmiennej liczby 32-bitowych słów w formacie little-endian. Istnieje 6 różnych typów poleceń, rozróżnianych po niskich 4 bitach pierwszego słowa.
Wszystkie nieużywane pola muszą być ustawione na 0 — w przeciwnym wypadku, zachowanie urządzenia nie jest zdefiniowane.
Urządzenia mogą być wysyłane do urządzenia ręcznie przez zapis kolejnych słów polecenia do rejestru MMIO urządzenia.
Ręczne wysyłanie poleceń¶
Polecenia można wysyłać do urządzenia bezpośrednio przez MMIO, używając następujących rejestrów:
BAR0 + 0x008c: CMD_MANUAL_FREE
Rejestr tylko do odczytu. Odczytana wartość jest liczbą wolnych miejsc w kolejce poleceń (tyle słów można natychmiast zapisać do
CMD_MANUAL_FEED
bez obaw oFEED_OVERFLOW
). Kolejka ta ma maksymalną pojemność 255 słów. Można założyć, że ten rejestr będzie równy 255 bezpośrednio po resecie urządzenia bądź gdy zostaną przetworzone wszystkie wcześniej wysłane polecenia.BAR0 + 0x008c: CMD_MANUAL_FEED
Rejestr tylko do zapisu. Każdy zapis do tego rejestru wysyła jedno słowo do kolejki poleceń. Jeśli kolejka jest już pełna (
CMD_MANUAL_FREE == 0
), zamiast tego wyzwalane jest przerwanieFEED_ERROR
.
Polecenie NOP
¶
Nic nie robi. Składa się z 1 słowa. Może być użyte do zapchania nieużywanych słów w buforze poleceń, jeśli czujemy taką potrzebę.
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x0
)
Polecenie BIND_SLOT
¶
Służy do wpięcia bufora do slotu. Składa się z 2 słów:
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x1
)bity 4-7:
SLOT
— numer slotu, który przepinamybity 12-27:
SEED
— inicjalny SEED buforabity 28-31:
TYPE
— typ talii
słowo 1: - bity 0-31:
PA
: pierwsze 32 bity pełnego fizycznego adresu tabeli stronsłowo 2: - bity 0-31:
PA
: ostatnie 32 bity pełnego fizycznego adresu tabeli stron
Polecenie GET_CARDS
¶
Służy do pobrania zadanej liczby kart. Składa się z 1 słowa:
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x2
)bity 4-19:
NUM
— liczba kart które chcemy pobraćbity 20-23:
OUTPUT_TYPE
— Typ pobrania kart:FAIR
(karty są uczciwie losowane) lubGOOD
/BAD
aby celowo zwracać lepsze i gorsze karty.bity 24-27:
SLOT
— Numer slotu z buforem w którym zwracamy karty, ustawiane przez sterownik.
Polecenie FENCE
¶
Służy do powiadamiania sterownika o zakończeniu wykonywania wszystkich poprzednich poleceń. Składa się z 1 słowa.
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x3
)bity 4-31:
VAL
— parametr; nie ma zdefinowanej semantyki przez urządzenie, zalecamy użycie go jako numeru kolejnej serii poleceń (modulo2**28
).
To polecenie ma następujące efekty:
Oczekuje na pełne zakończenie wykonania wszystkich wcześniejszych poleceń.
Ustawia wartość rejestru
CMD_FENCE_LAST
na parametrVAL
Jeśli parametr
VAL
jest równy rejestrowiCMD_FENCE_WAIT
, wyzwala przerwanieFENCE_WAIT
.
BAR0 + 0x0090: CMD_FENCE_LAST
28-bitowy rejestr do odczytu i zapisu, ustawiany na parametr
VAL
przy wykonaniu poleceniaFENCE
. Może być użyty do ustalenia, które polecenia już zostały wykonane. Zalecamy zapisanie go ze sterownika dokładnie raz, przed uruchomieniem urządzenia, aby nadać mu wartość początkową.BAR0 + 0x0094: CMD_FENCE_WAIT
Rejestr do odczytu i zapisu, służy do wyzwolenia przerwania gdy podane polecenie
FENCE
zostanie wykonane.bity 0-27:
VAL
, wartość na którą sterownik czeka. Gdy zostanie wykonane polecenieFENCE
z równą wartością, zostaje wyzwolone przerwanieFENCE_WAIT
.
Polecenie NEW_DECK
¶
Służy do wygenerowania i przetasowania nowej talii. Składa się z 1 słowa:
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x4
)bity 4-7:
SLOT
— Numer slotu z buforem w którym zwracamy karty, ustawiane przez sterownik.
Polecenie UNBIND_SLOT
¶
Służy do odpięcia nieużywanego slotu. Składa się z 1 słowa:
słowo 0: nagłówek
bity 0-3: typ polecenia (
0x5
)bity 4-7:
SLOT
— Numer slotu który zwalniamy po stronie urządzenia.
Rejestry sterujące¶
Poza wcześniej opisanymi rejestrami urządzenie używa również:
BAR0 + 0x0008: ENABLE
Rejestr kontrolujący pracę pozostałych bloków, dostępny do odczytu i zapisu. Jeśli jego wartość to 0 to komendy nie są przetwarzane.
BAR0 + 0x000c: INCREMENT_SEED
Rejestr odpowiadający za funkcjonalność inkrementacji seedów buforów przy nowym losowaniu, dostępny do odczytu i zapisu. Domyślnie jest ustawiony na 0 (m.in. dla łatwiejszego testowania), ale praktyczne zastosowanie urządzenia zakłada jego przestawienia na 1.
BAR0 + 0x0010: PROC_STATE
Rejestr odpowiadający za stan obsługi wczytanych poleceń, dostępny do odczytu i zapisu.
Przerwania¶
Urządzenie wewnętrznie używa 5 przerwań (które są agregowane w jedno przerwanie PCI):
FENCE_WAIT
— przerwanie używane do powiadomienia sterownika o wykonaniu wybranego poleceniaFENCE
przez blokCMD
.FEED_ERROR
— użycie rejestruCMD_MANUAL_FEED
, gdy nie ma miejsca w kolejceCMD_ERROR
— wyzwalane, gdy urządzenie otrzyma niepoprawne polecenieMEM_ERROR
— wyzwalane, gdy urządzenie otrzyma nieprawidłowy dostęp do pamięciSLOT_ERROR
— wyzwalane, gdy urządzenie otrzyma zapytanie używające nieaktywnego slotu
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 + 0x0000: INTR
Rejestr statusu przerwań. Ma 5 bitów, każdy odpowiadający jednemu rodzajowi przerwań:
bit 0:
FENCE_WAIT
,bit 1:
FEED_ERROR
,bit 2:
CMD_ERROR
,bit 3:
MEM_ERROR
,bit 4:
SLOT_ERROR
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.
BAR0 + 0x0004: 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.
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):
wyzerować
INTR
włączyć używane przez nas przerwania w
INTR_ENABLE
,włączyć wszystkie bloki urządzenia w
ENABLE
.zainicjować
CMD_FENCE_LAST
iCMD_FENCE_WAIT
, jeśli czujemy taką potrzebę.
Żeby wyłączyć urządzenie, wystarczy zapisać 0 do ENABLE
oraz INTR_ENABLE
.
W przypadku zgłoszenia błędu przez urządzenie, należy je zresetować w sposób analogiczny do uruchamiania urządzenia.