Programming WHDLoad

### Схематическое описание работы программы

Следующая таблица показывает процесс выполнения программы, когда запускается программа, установленная с помощью WHDLoad. Я надеюсь, что это поможет понять, как работает WHDLoad и как WHDLoad, slave-модуль и установленная программа взаимодействуют между собой.

ПОЛЬЗОВАТЕЛЬ

- запускает демо или игру, щелкая на иконку или запуская WHDLoad через командную строку

Операционная Система

- загружает WHDLoad и призводит запуск

WHDLoad

- проверяет програмную среду и аппаратные средства
- загружает и проверяет slave-модуль
- резервирует необходимое количество памяти для установленной программы
- если активизирована опция Preload/S, то в оперативную память загружются образы диска и файлы (насколько позволяет свободная память)
- отключает OS (отключает многозадачность и перерывания, переключает графику на режим OCS, инициализирует все аппаратные средства, используя заданные значения)
- осущесвствляет переход на выполнение slave-модуля

Slave-модуль

- загружает главный исполняемый файл установленной программы, вызывая функцию WHDLoad (например, resload_DiskLoad или resload_LoadFile)
- исправляет исполняемый файл (чтобы программа загрузила свои данные через slave, устраняет проблемы несовместимости, активизирует функцию выхода из программы)
- запускает главный исполняемый файл

Установленная программа

- выполняется
- при подгрузке данных с диска, вызывает slave-модуль (потому что slave-модуль исправил исполняемый файл), slave-модуль вызывает WHDLoad, и WHDLoad частично активизирует OS чтобы загрузить данные (только если данные не были предварительно подгружены - см. Preload), затем возвращается в установленную программу и программа продолжает выполнение

ПОЛЬЗОВАТЕЛЬ

- выходит из программы, нажимая клавишу выхода QuitKey

Slave-модуль

- возвращается в WHDLoad, вызывая resload_Abort

WHDLoad

- перезапускает OS (восстанавливает состояние регистров, памяти, дисплея)
- освобождает все занятые ресурсы
- производит возврат в OS

### Как устанавить диск использующий трековый загрузчик (trackloader)

Это совсем краткое пошаговое описание того, как создать патч, использующий WHDLoad. Данный пункт поясняет самый простой вариант. В реальности такого варианта скорее всего не будет. В главах же следующих за этой, будут отдельно описаны особые случаи и проблемы, с которыми вы можете столкнуться.

1. Предварительная подготовка
   - Создайте папку, в которой будут находиться все файлы.
   - Создайте в этой же папке образ диска, используя DIC.
   - Создайте *? .info файл, в котором инструментом по умолчанию является "WHDLoad" и параметром (Tooltype) "SLAVE=#?", где "#?" - имя slave-модуля (или просто скопируйте иконку из инсталяционного примера и отключите все параметры (Tooltypes) кроме "SLAVE=").
2. Slave-модуль
   Для создания slave-модуля нам необходима следующая информация:
   1) Где на диске расположен главный исполняемый файл?
   2) Где внутри главного исполняемого файла располагается загрузчик диска?
   Чтобы получить эту информацию мы сначала анализируем загрузочный блок (bootblock). Как правило, главный исполняемый модуль загружается отсюда, используя функцию exec.DoIO(). Иногда в загрузочном блоке присутствует загрузчик дорожки (trackloader). Теперь мы напишем Slave-модуль, который будет эмулировать загрузочный блок и загружать главный исполняемый модуль и образа диска. Сейчас нам необходимо вытащить главный исполняемый модуль из образа диска или из дампа памяти. После этого нам нужно найти загрузчик в главном исполняемом файле. Самый быстрый путь состоит в том, чтобы попробовать найти с HEX-редакторе последовательность `$AAAAAAAA` (используется MFM-декодированием). Вырежте найденную область с захватом +/- $1000 байт, дизассемблируйте, и ищите начало процедуры. Когда загрузчик будет найден, разберитесь какие параметры загрузки он использует(адрес загрузки, длина). Теперь мы создаем код для slave-модуля, который исправит эту процедуру загрузчика, и который будет обрабатывать все запросы переадресовывая их slave-модулю. Slave-модуль будет корректировать параметры загрузки и вызывать функцию WHDLoad'а resload_DiskLoad.
3. В случае такого идеального варианта, slave-модуль уже готов.
   Теперь осталось единственное - создать хорошую иконку. Сграбьте две картинки, используя опцию Snoop программы WHDLoad и SP или системный монитор или UAE, и создайте иконку. Рекомендуются использовать 16 цветную RomIcon палитру.

### Возможные проблемы и особые случаи

#### Нестандартный загрузчик дорожки

Некоторые программы используют свой собственный формат диска. Это означает, что DIC не в состоянии создать образ такого диска. Чтобы прочитать файлы с такого диска или создать его образ, рекомендуется использовать RawDIC. За подробностями обращайтесь к документации программы RawDIC.

#### Программа использует несколько дисков

Если программа использует больше чем один диск, то slave-модуль должен переадресовать доступы к дискам к соответствующему файлу образа. Иногда это не легко. Некоторые программы поддерживают более одного дисковода, так что вы можете использовать номер дисковода для выбора нужного диска. Большинство программ использует идентификатор (например название) на каждом диске, чтобы различать их. В этом случае, используйте переменную, которая содержит номер диска, и при каждом обращении к идентификатору диска (определяйте такой доступ, анализируя параметры для загрузчика диска) и увеличивайте переменную (а если достигнут последний диск, то уменьшайте её), в надежде на то, что загрузчик будет перечитывать идентификаторы снова и снова пока не обнаружит нужный диск. Некоторые программы выдают запрос, чтобы пользователь вставил правильный диск - оключите этот запрос.

#### Сохранение таблицы рекордов (Highscore)

Ну, что тут сказать. Используйте функцию resload_SaveFile, чтобы записать соответствующую область памяти на диск. Если хотите, то можете еще и зашифровать ее так, чтобы "чайникам" было не легко её исправить. Не рекомендуется производить запись непосредственно в образ диска (используя функцию resload_SaveFileOffset) потому, что если что-то пойдет не так, как надо (например, какая-нибудь ошибка или зависание), то возможно, что образ диска будет поврежден.

#### Сохранение прогресса игры (Savegames)

Запись прогресса игры осуществляется теми же способами, что и в случае с таблице рекордов.

#### Доступы к операционной системе

Во время работы slave-модуль и установленная программа не должны иметь никаких обращений к OS! Поэтому все обращения из установленной программы должны быть отключены или перенаправлены. Если их не так много и они не нужны при работе через WHDLoad (типа exec.Disable() или exec.SuperState()), то просто замените их командой NOP (`$4e71`). Если вызовы несут важную функцию (типа exec.DoIO()), переадресуйте их slave-модулю, и эмулируйте их. Также можете создать простую exec.library в неиспользованной области памяти (проинициализируйте длинное слово по адресу `$4`). Посмотрите как это сделано в исходном тексте для модуля "Oscar.slave", который эмулирует exec.AllocMem(). Для обнаружения таких вызовов OS, выставьте начальный execbase в `$f0000001` с той целью, чтобы все программы, которые любят использовать execbase, выдали "Ошибку Адреса".
Если эмулировать функции OS слишком сложно, тогда просто используйте один из kickemu-пакетов, которые могут быть найдены в дистрибутиве whdload-dev. Там есть один пакет для Kick 1.3 ('src/sources/whdload/kick13.s'') и один для Kick 3.1 ('src/sources/whdload/kick31.s''). Эти пакеты требуют оригинального образа кикстарта и создают полноценную OS в WHDLoad. См. также файлы readme, которые поставляются в комплекте с этими пакетами.

### Проблемы совместимости

#### Ограниченное адресное пространство на 68000/68010/68ec020

На этих процессорах адресное пространство ограничено размером 16 Мб (`$000000... $ffffff`), потому что центральный процессор имеет только 24 адресных линии. В результате все доступы к более высоким адресам выполняются к адресам ниже 16 Мб, просто игнорируя старшие 8 бит адреса. Некоторые программы используют эти биты, для хранения данных, или просто забывают очищать их. На процессорах с полным 4Гб адресным пространством, типа 68020/680ec30/68030/68040/68060 это происходить не будет, потому что обращение будет идти к полному 32-х битному адресу.
Для решения этой проблемы, вы должны подкорректировать эти вызовы и перенаправить их на соответствующие адреса.
Иногда причиной доступа к странным адресам может быть непроинициализированный указатель. В этом случае может помочь очистка `$400` - ws_BaseMemSize.

#### Различный стековый фрейм на разных процессорах

Стековые фреймы, созданные процессором после перерываний и событий, различны для разных процессоров семейства 68К. На 68000 стековый фрейм составляет 6 байт, за исключением "Ошибки Адреса" и "Ошибки Шины". В стековом фрейме находится сохраненное значение SR в (a7) и PC в (2,a7). На всех других процессорах (68010 +) минимальный стековый фрейм составляет 8 байт и дополнительно содержит номер вектора как слово в (6,a7). Этот формат стекового фрейма $0, состоящий их четырёх слов, создан для "Trap #xx" и прерываний на 68010-68060. Стековые фреймы для других событий различны на каждом процессоре. Инструкция RTE на 68000 работает иначе чем на 68010+. На 68000 она просто восстанавливает SR и PC и продолжает выполнение программы с прерванного адреса. На 68010 + она дополнительно освобождает стековый фрейм в зависимости от его формата.
Некоторые программы проталкивают (записывают в стек?) адрес (PC) и SR, а затем выполняют инструкцию RTE. Это работает только на процессорах 68000, а на 68010+ результат непредсказуем.
Если программа работает таким образом, вы должны исправить это место. Иногда бывает достаточно заменить RTE на RTR.

#### MOVEM.x RL,-(An) на 68000/010 и 68020/030/040

Есть отличие, если регистр, используемый в случае адресации с предварительным уменьшением адреса до выполнения команды (RL) также содержится в списке регистров. На процессорах 68020, 68030, 68040 значение, записанное в память является исходным значением регистра, уменьшенным на размер операции. На процессорах же 68000 и 68010 записывается исходное значение (не уменьшенное).
Так как эта инструкция редко используется, то на данный момент не замечено ни одной программы, испытывающей поблемы из-за описанных различий.

### Общие принципы написания патчей

- Не изменяйте состояние регистров (таких как VBR или CACR), присутствующих на старших моделях процессоров. С точки зрения человека, программирующего Slave-модуль, VBR всегда равен 0, даже если он был перемещен, потому что эмулируются автовекторы (а также и Traps при условии, что установлен флаг WHDL_EmulTrap). Биты в CACR различны для каждого процессора. Есть только один надёжный способ изменять Cache - использовать resload_SetCACR/SetCPU и bitdef'ы из 'exec/execbase.i' и 'whdload.i'. Надо также убрать все обращения к этим регистрам из установленной программы, иначе WHDLoad не будет правильно работать!
- Никогда не изменяйте образы дисков. Это полезно в случае, если кто-то захочет запустить программу дискеты, то ему нужно будет просто записать образ обратно на диск (при условии, что программа работает без использования каких-либо патчей, хотя, нельзя сказать что такое бывает в большинстве случаев).
- Никогда не используйте оригинальный код из программы непосредственно в slave-модуле (с точки зрения защиты авторских прав).
- Включайте кэши только если вы уверены, что это заработает на всех процессорах.
- Насколько это возможно, используйте как можно меньше памяти для ws_BaseMemSize. У некоторых людей в конце Chip-памяти висят резидентные программы, так что это поможет использовать только `$1f0000`, вместо $`200000` и WHDLoad сможет использовать всю зарезервированную память.

### Советы и маленькие хитрости

#### Что лучше использовать: образы дисков или файлы?

Иногда перед вами будет стоять выбор, что использовать, образы дисков или файлы. Оба способа имеют свои преимущества. Использование образов диска, как правило, более легкий и более быстрый способ создать slave-модуль. Но реальные файлы значительно проще кэшировать (если очень мало памяти или память фрагментирована). Занимаемое место на жестком диске также будет меньше в случае с реальными файлами по сравнению с использованием образов дисков. Рекомендуется использовать образы дисков только, если файлов очень много (более 30-ти).