Programowanie WHDLoad

### Schemat działania programu

Poniższa tabela pokazuje kolejność wykonywanych operacji, które następują po uruchomieniu programy zainstalowanego przy pomocy pakietu WHDLoad. Mam nadzieję, że to pomoże zrozumieć jak działa WHDLoad i jak WHDLoad, plik .slave oraz zainstalowany program współpracują.

Użytkownik

- uruchamia demo lub grę poprzez kliknięcie na ikonę lub poprzez uruchomienie WHDLoad z linii poleceń (CLI)

System operacyjny

- uruchamia plik wykonywalny WHDLoad

WHDLoad

- sprawdza środowisko sprzętowe i programowe
- wczytuje i sprawdza plik .slave
- alokuje wymaganą dla zainstalowanego programu ilość pamięci
- jeśli Preload/S jest włączone, wczytuje obrazy dysków i plików do RAM-u (tylko wtedy, gdy dostępna jest wolna pamięć)
- wyłącza System Operacyjny (wyłącza multitasking i przerwania, degraduje kości graficzne do stanu OCS, initializuje cały sprzęt zgodnie ze zdefiniowanymi wartościami)
- wykonuje skok do pliku .slave

Slave

- wczytuje główny plik wykonywalny zainstalowanego programu poprzez wywołanie funkcji WHDLoad (np. resload_DiskLoad lub resload_LoadFile)
- "łata" główny plik wykonywalny (tak, aby program wczytał swoje dane poprzez plik .slave, naprawił problemy związane z kompatybilnością, uaktywnił opcję wyjścia z programu)
- uruchamia główny plik wykonywalny

Zainstalowany program

- robi swoje
- podczas odczytu danych z dysku, odwołuje się do pliku .slave (gdyż plik .slave wcześniej nałożył się na niego, "łatając" go), a następnie plik .slave odwołuje się do WHDLoad, który częściowo włącza OS, aby wczytał dane (tylko jeśli dane nie są załadowywane wcześniej (Preload)); na koniec wraca do dalszego wykonywania zainstalowanego programu.

Użytkownik

- wychodzi z programu poprzez naciśnięcie zdefiniowanego klawisza wyjścia (QuitKey)

Slave

- wywołuje WHDLoad poprzez funkcję resload_Abort

WHDLoad

- ponownie włącza OS (rejestry sprzętowe, ekran oraz pamięć wracają do poprzedniego stanu),
- uwalnia wszystkie zaalokowane obszary i zasoby,
- wraca do systemu.

### Jak zainstalować prosty, jednodyskowy program wczytywany po ścieżkach

To jest bardzo mały i krótki poradnik jak stworzyć wersję instalacyjną wykorzystującą WHDLoad. Poradnik opisuje zwykłą, idealną, prostą sytuację. W rzeczywistości taka sytuacja prawdopodobnie nigdy nie wystąpi. W ramach zapoznania się ze specjalnymi przypadkami i problemami, przeczytaj kolejny rozdział.

1. Początki
   - Stwórz katalog, w których przechowywane są wszystkie pliki.
   - Stwórz obraz dysku używając programu DIC .
   - Stwórz plik #?.info z "WHDLoad" jako <Default Tool> oraz Tooltype "SLAVE=#?" zawierającym nazwę pliku .slave. (lub prościej, skopiuj ikonę z Przykładowej Instalacji i wyłącz wszystkie parametry za wyjątkiem "SLAVE=").
2. Plik .slave
   Aby stworzyć plik .slave potrzebujemy następujących informacji:
   1. gdzie na dysku znajduje się główny plik wykonywalny (loader)?
   2. gdzie wewnątrz pliku wykonywalnego znajduje się disk loader?
   Aby zdobyć te informacje, najpierw należy przeanalizować botblok. W większości przypadków, główny plik wykonywalny będzie wczytywany właśnie stąd przy pomocy exec.DoIO(). Czasami bootblock zawiera specjalny trackloader. Kolejną czynnością jest utworzenie pliku .slave, który zastępuje botblok i wczytuje główny plik wykonywalny z obrazu dysku. Teraz należy wyciągnąć główny plik wykonywalny z obrazu dysku lub ze zrzutu pamięci. Następnie musimy odnaleźć w nim loader. Najszybszą metodą jest odszukanie ciągu `$AAAAAAAA` (używanego przez MFM decoding) przy pomocy hex-edytora. Następnie wycinamy obszar o długości (+/- `$1000` bajtów), deasemblujemy go i odszukujemy początek procedury. Rozszyfrowujemy listę parametrów i tworzymy kod pliku .slave, który zastąpi procedurę loadera, w taki sposób, że wszystkie odwołania do loadera będą przekierowane do pliku .slave. Następnie plik .slave dostosuje parametry i wywoła z WHDLoad funkcję resload_DiskLoad.
3. W idealnej sytuacji wersja instalacyjna jest gotowa.
   Jedyną rzeczą, która pozostała do zrobienia jest stworzenie ładnej Ikony. Wyciągnij z programu dwa obrazki wykorzystując do tego opcję snoop w WHDLoad i program SP lub jakiegoś programu zatrzymującego działanie innych programów albo U.A.E. Następnie stwórz ikonę. Zalecana jest 16-kolorowa paleta RomIcon.

### Możliwe problemy i sytuacje wyjątkowe

#### Niestandardowy trackloader

Niektóre programy używają swoich własnych formatów. Oznacza to, że DIC nie może stworzyć obrazów dysków. Aby je stworzyć należy do tego celu użyć programu RawDIC. Aby zasięgnąć więcej informacji, przeczytaj dokumentację programu RawDIC.

#### Zmiana dysków

Jeżeli program wykorzystuje więcej niż jeden dysk, plik .slave musi przekierować dostępy do dysków do odpowiedniego obrazu dysku. Czasami nie jest to proste. Niektóre programy obsługują więcej niż jedną stację dysków, tak więc można wykorzystać numer tego urządzenia w celu wyboru dysku. Większość programów używa specjalnego identyfikatora na każdym dysku w celu ich rozróżnienia. W takim przypadku należy wykorzystać zmienną, która przechowuje numer dysku i przy każdej próbie dostępu do identyfikatora dysku zwiększać jej wartość (jeżeli dojdziemy do ostatniego dysku, należy ją zmniejszać). Loader odczytuje identyfikator dysku w kółko, do czasu gdy prawidłowy dysk zostanie włożony. Czasami pojawiają się komunikaty z prośbą o włożenie dysku, które należy deaktywować.

#### Zapisywanie tablic z najlepszymi wynikami

Nie ma tutaj zbyt wiele do powiedzienia. Wykorzystaj resload_SaveFile, aby zapisać odpowiedni obszar pamięci na dysk. Jeżeli chcesz, możesz go trochę zaszyfrować, aby lamerzy za szybko nie doszli do tego, jak oszukiwać. Nie jest zalecane dokonywanie zapisów bezpośrednio do obrazów dysków (wykorzystując resload_SaveFileOffset), ponieważ, w sytuacji jakiegoś błędu (np. zawieszenie), istnieje duże prawdopodobieństwo, że obrazy dysków zostaną uszkodzone.

#### Zapisy stanów gry - Savegames

Sposób dokonywania zapisów stanu gry odbywa się w ten sam sposób co zapis tablic z najlepszymi wynikami.

#### Dostęp do systemu operacyjnego

W czasie, gdy plik .slave i zainstalowany program są wykonywane, nie jest możliwy dostęp do systemu operacyjnego! W związku z tym każda próba dostępu do systemu, jaka może się odbyć przez zainstalowany program, musi zostać wyłączona. Jeżeli nie jest ich dużo i dla środowiska WHDLoad są mało istotne (jak np. exec.Disable() lub exec.SuperState()) można je zdeaktywować instrukcją NOP (`$4e71`). Jeżeli dostępy do systemu są ważnymi elementami pracy zainstalowanego programu (jak np. exec.DoIO()), należy je przekierować do pliku .slave i zaemulować. Jeżeli jest ich dużo, w nieużywanym obszarze pamięci należy stworzyć prostą exec.library (inicjonowaną przez długie słowo w adresie `$4`). Za przykład niech posłuży dołączone źródło Oscar.slave, które emuluje exec.AllocMem(). Aby wykryć dostęp do systemu operacyjnego, należy posłużyć się początkową tablicą execbase, która jest wstawiana do adresu `$f0000001`, aby sprawić, że wszystkie procedury, które wykorzystują execbase wywołają wyjątek "Address Error".
Jeżeli wywołań funkcji systemowych jest bardzo dużo, należy wykorzystać jeden z pakietów kickemu, który znajduje się w pakiecie WHDLoad dla developerów. Znajduje się tam jeden pakiet dla Kickstartu 1.3 ('src/sources/whdload/kick13.s') i jeden dla Kickstartu 3.1 ('src/sources/whdload/kick31.s'). Pakiety wymagają oryginalnych obrazów kickstartów i utworzą one kompletne środowisko systemowe wewnątrz WHDLoad. Więcej informacji dostępnych jest w specjalnych dokumentacjach.

### Problemy z kompatybilnością

#### Ograniczony dostęp do adresów wolnej pamięci na procesorach 68000/68010/68ec020

Na tych procesorach przestrzeń adresowa jest ograniczona do 16 MB (`$000000...$ffffff`), ponieważ procesor posiada tylko 24 linie adresowe. W wyniku tego wszystkie próby dostępu do wyższych adresów wykonywane są na niższych 16 MB poprzez ignorację najmniej znaczących 8 bitów. Niektóre programy używają tych bitów do przechowywania danych lub po prostu zapominają ich wyczyścić. Na procesorach takich, jak 68020/680ec30/68030/68040/68060, które posiadają z pełną, 4-GB przestrzenią adresową, coś takiego po prostu nie zadziała z powodu dostępu do pełnych, 32-bitowych adresów.
Aby rozwiązać ten problem, trzeba "załatać" dostępy do tych adresów poprzez przekierowanie ich do właściwych adresów.
Czasami powodem dostępu do dziwnych adresów może być nieinicjowanie wskaźnika. W takim przypadku pomaga wyczyszczenie `$400` - ws_BaseMemSize.

#### Rożne ramki stosu dla różnych procesorów

Ramki stosu tworzone przez procesor na przerwaniach i wyjątkach są różne dla różnych członków rodziny 68k. Na 68000 ramka stosu wynosi 6 bajtów, za wyjątkiem błędów szyny i adresów (Bus Errors i Address Errors). Ramka stosu zawiera zapisane SR w rejestrze (a7) i zapisane PC w rejestrze (2,a7). Na wszystkich procesorach od 68010 wzwyż, minimalna ramka stosu wynosi 8 bajtów oraz dodatkowo zawiera liczbę wektorową jako słowo w rejestrze (6, a7). Ta žquot;złożona z czterech słów" ramka stosu formatowana jest na stan `$0` i tworzona jest dla potrzeb polecenia "Trap #xx" oraz przerwań (Interrupts) na procesorach 68010-68060. Ramki stosu dla innych wyjątków są różne dla różnych procesorów. Instrukcja RTE działa inaczej niż na 68000. Na 68000 po prostu przywraca poprzednie wartości rejestrów SR i PC i dalej kontynuuje pracę programu od przerwanego adresu. Na 68010 (i wyższych) dodatkowo zostanie zwolniona ramka stosu w zależności od jej sformatowania.
Niektóre adresy wyrzucają adres (PC) oraz SR i dopiero wtedy wykonują instrukcję RTE. Tak dzieje się tylko na 68000. Takie działanie na procesorach od 68010 wzwyż powoduje niedefiniowalne efekty.
Jeżeli program tak robi, należy to poprawić. Czasami wystarcza zamiana instrukcji RTE na RTR.

#### MOVEM.x RL,-(An) n a 68000/010 i 68020/030/040

Istnieje różnica, jeżeli rejestr używany w trybie wcześniejszego zmniejszania zawartości (RL) jest również zawarty w spisie rejestrów. Dla 68020, 68030 i 68040 wartość zapisywana do pamięci jest bazową wartością rejestru pomniejszoną o rozmiar operacji. Procesory 68000 i 68010 zapisują bazową wartość rejestru (nie pomniejszoną).
Ponieważ taka konstrukcja nie jest za bardzo użyteczna, nie jest znany żaden z obecnych programów, który wykazywałby w związku z tym jakieś problemy.

### Ogólne zasady pisania własnych programów instalacyjnych

- Nie zmieniaj rejestrów procesora obecnych w wyższych procesorach takich jak VBR czy CACR. VBR zawsze wynosi 0 z programistycznego punktu widzenia, nawet jeżeli został przesunięty z powodu emulacji Auto Vectorów (i poleceń "Trap", jeżeli flaga WHDL_EmulTrap jest ustawiona). Bity w CACR są różne dla każdego procesora. Istnieje tylko jedna metoda zmiany buforów, przy pomocy resload_SetCACR/SetCPU i bitdef z 'exec/execbase.i' i 'whdload.i'. Cała część kodu instalowanego programu, która narusza te rejestry musi być wyłączona lub ominięta. W przeciwnym razie WHDLoad nie będzie działać poprawnie!
- Nigdy nie modyfikuj obrazów dysków. Ma to ogromną zaletę, w chwili, gdy ktokolwiek chce uruchomić grę z dyskietek. Wystarczy tylko zapisać obrazy z powrotem na dyskietki (zakładając, że program działa bez stosowania poprawek).
- Nigdy nie stosuj oryginalnego kodu programu bezpośrednio w pliku .slave (problem praw autorskich).
- Włączaj Cache tylko wtedy, gdy jesteś pewien, że będzie to działać na wszystkich procesorach.
- Wykorzystuj najmniejszą możliwą ilość pamięci dla ws_BaseMemSize. Niektórzy lubią umieszczać tagi na końcu pamięci Chip, tak więc pomaga wykorzystywanie tylko adresów `$1f0000` zamiast `$200000`.

### Sztuczki i kruczki

#### Co lepiej wykorzystywać: obrazy dysków, czy pliki?

Czasami będzie istniała możliwość użycia obrazów dysków lub plików znajdujących się na dysku. Obie metody mają swoje zalety. Do utworzenia pliku .slave, wykorzystanie obrazów dysków jest z reguły prostsze i szybsze. Z kolei bezpośrednie pliki programu są prostsze do buforowania (w przypadku, gdy jest niewiele dostępnej pamięci lub pamięć jest pofragmentowana). Wymagana ilość wolnego miejsca na twardym dysku czasami również będzie w tym przypadku mniejsza. Obrazy dysków powinny być stosowane tylko wtedy, jeżeli liczba plików przekracza liczbę 30.