Programming WHDLoad

### Schematic execution flow

The following table shows the program flow when a WHDLoad installed program will be executed. I hope it helps to understand how WHDLoad works and how WHDLoad, the Slave and the installed program does cooperate.

The USER

- starts the demo or game by clicking a Icon or by starting WHDLoad via the command line

The Operating System

- loads the WHDLoad executable and starts it

WHDLoad

- checks the Software and Hardware environment
- loads and checks the Slave
- allocates required memory for the installed program
- if Preload/S is enabled it loads disk images and files into the RAM (as far as free memory is available)
- switches OS off (disables mutitasking and interrupts, degrades graphics hardware to OCS, inits all hardware with defined values)
- jumps into Slave

Slave

- loads the main executable of the installed program by calling a WHDLoad function (e.g. resload_DiskLoad or resload_LoadFile)
- patches the main executable (that the program will load his data via the Slave, to fix compatibility problems, to enable an exit from the program)
- calls the main executable

Installed program

- will do his stuff
- on loading data from disk it will call the Slave (because the Slave has patched it in this way previously), and the Slave will call WHDLoad, and WHDLoad will partially enable the OS to load the data (only if the data is not Preload'ed), then return, return and the installed program continues

The USER

- exits the program by pressing the QuitKey

Slave

- returns to WHDLoad by calling resload_Abort

WHDLoad

- re-enables the OS (restores hardware registers, display and memory)
- frees all allocated resources
- returns to the OS

### How to install a simple one disk trackloader

This is a very small and short step by step guide on how to create an install using WHDLoad. The guide reflects an ideal simple case. In the real world such a case will probably never occur. For special cases and problems, read the chapters that follow this.

1. Prework
   - Make a drawer which will hold all files.
   - Create a disk image using DIC in this drawer.
   - Create a #?.info file with "WHDLoad" as <Default Tool> and a Tooltype "SLAVE=#?" containing the name of the slave. (or simply copy the icon from an Example Install, and disable all tooltypes except "SLAVE=").
2. The Slave
   To write the slave we need following information:
   1. Where on disk is the main executable located?
   2. Where inside the main executable is the disk loader located?
   To get this information we first analyze the bootblock. Most times the main executable will be loaded from here via exec.DoIO(). Sometimes a special trackloader is in the bootblock. We now write a Slave which will simulate the bootblock and load the main executable from the disk image. Now we rip the main executable from the image or a memory dump. After that we have to find the loader in the main exe. A fast way is to search for the pattern `$AAAAAAAA` (used by MFM decoding) with a hex-editor. Then cut the area (+/- `$1000` bytes) found, disassemble it, and search the start of the routine. Understand the parameterlist. Now we create code for the Slave which will patch this loader routine in a way that all calls to the loader will be redirected to the Slave. The Slave will then adjust the parameters and call the WHDLoad function resload_DiskLoad.
3. In the ideal case the install is now complete.
   The only thing left to do is to create a nice Icon. Rip two pictures using the snoop feature of WHDLoad and SP or a freezer or U.A.E. and build the icon. The 16 colour RomIcon palette is recommended.

### Possible problems and special cases

#### Non standard trackloader

Some programs use their very own disk format. This means that DIC is unable to create the disk images. To create files or images from such disk the use of RawDIC is recommended. See documentation of RawDIC for more information.

#### Multiple disks

If the program uses more than one disk the slave must redirect the disk accesses to the appropriate image file. Sometimes this is not easy. Some programs support more than one drive, so you can use the drive number for selecting the disk. Most programs use an ID on every disk to distinguish them. In this case, use a variable which holds the disk number, and on every access to the disk ID (determine such an access by analyzing the parameters for the disk loader) increase the variable (if last disk is reached, decrease it). So hopefully the loader will read the ID again and again up until the correct disk is inserted. Perhaps there is a request from the program that the user should insert the right disk, disable it.

#### Highscore saving

Not much to say here. Use resload_SaveFile to write the appropriate memory area to the disk. If you like, encrypt it a bit so lamers can't patch it too easily. It is not recommended to write directly into disk images (using resload_SaveFileOffset), because if something goes wrong (e.g. crash) it's possible that the images will be damaged.

#### Savegames

Savegame handling is the same as with highscores.

#### Accesses to the operating system

At the time the slave and the installed program is executed, absolutely no OS exist nor is accessible nor makes any sense to access! Therefore all accesses tried by the installed program does must be disabled. If there aren't many of them, and they don't make sense in the WHDLoad environment (like exec.Disable() or exec.SuperState()) simply NOP (`$4e71`) them. If the accesses have an important function (like exec.DoIO()), redirect them to the Slave and emulate them. If there are loads of them, create a simple exec.library in an unused memory area (initialize the longword at address `$4`). You can check the source for the Oscar.slave, which emulates exec.AllocMem(). To detect accesses to the OS, the initial execbase is set to `$f0000001` with the intention that all routines which like to use the execbase will create an "Address Error" exception.
If there is heavy use of OS functions, use one of the kickemu packages which can be found in the whdload-dev package. There is one package for Kick 1.3 ('src/sources/whdload/kick13.s') and one for Kick 3.1 ('src/sources/whdload/kick31.s'). These packages require an original kickstart image and will create an complete OS enviroment inside the WHDLoad space. Consult also the approriate readme supplied for further informations.

### Common compatibility problems

#### Limited address space on 68000/68010/68ec020

On these processors the address space is limited to 16 MB (`$000000...$ffffff`) because these CPU's have only 24 address lines. As a result all accesses to higher addresses are performed to the lower 16 MB by ignoring the most significant 8 bits. Some programs use these bits to store data, or simply forgets to clear them. On a processor with full 4 GB address space like 68020/680ec30/68030/68040/68060 this will not work, because the full 32-bit address will be accessed.
To solve this you have to patch these accesses and redirect them to the appropriate address.
Sometimes the reason for accesses to strange addresses may be an uninitialized pointer. In this case it may help to clear `$400` - ws_BaseMemSize.

#### Different stackframes on each processor

The stackframes created by the processor on interrupts and exceptions are different for the members of the 68k family. On the 68000 a stackframe is 6 bytes, except on Bus and Address Errors. The stackframe contains the saved SR at (a7) and the saved PC at (2,a7). On all other processors (68010+) the minimal stackframe is 8 bytes and additionally contains the vector number as a word at (6,a7). This Four-Word stackframe format `$0` is created for "Trap #xx" and Interrupts on 68010-68060. The stackframes on other exceptions are different on each processor. The RTE instruction works differently on the 68000 against 68010+. On a 68000 it simply restores the SR and PC and continues program execution at the interrupted address. On the 68010+ it will additionally free the stackframe depending on the stackframe format.
Some programs push an address (PC) and an SR and then execute an RTE instruction. This works on a 68000 only, on 68010+ this will have undefinable results.
If a program does so, you'll have to fix this stuff. Sometimes it may be enough to replace the RTE with a RTR.

#### MOVEM.x RL,-(An) on 68000/010 and 68020/030/040

There is a difference if the register used in predecrement mode (RL) is also contained in the register list. For the 68020, 68030 and 68040 the value written to memory is the initial register value decemented by the size of the operation. The 68000 and 68010 write the initial register value (not decremented).
Because such a construction is not very useful, no current software is known to have problems due to this.

### General guidelines for writing installs

- Don't modify CPU registers present in higher processors like VBR or CACR. The VBR is always 0 from the Slave programmers view, even if it's moved because Auto Vectors (and Traps if the Flag WHDL_EmulTrap is set) are emulated. The bits in the CACR are different for each processor. There is only one valid way to modify the caches, use resload_SetCACR/SetCPU and the bitdef's from 'exec/execbase.i' and 'whdload.i'. Also all stuff present in the program to install banging these registers must be disabled or skipped, otherwise WHDLoad cannot correctly work!
- Never modify disk images. That has the advantage that if anybody wishes to start the program from a floppy he must only write the images back to a disk (provided that the program runs without several fixes, surely not the most frequent case).
- Never use original stuff from the program directly in the slave (copyright problem).
- Enable the Caches only if you are sure it runs on all processors.
- Use as little memory as possible for ws_BaseMemSize. Some people have resident tags on the end of the Chip memory, so it helps to use only `$1f0000` instead `$200000` and WHDLoad can use absolute allocated memory.

### Tips & tricks

#### What's better, using diskimages or files ?

Sometimes you will have the choice to use disk images or real files. Both has his advantages. The use of disk images is usually the easier and faster way to create the Slave. But real files are more easily cached (if there is very little memory or the memory is fragmented). The needed space on harddisk will also be smaller with real files than with disk images. You should only use disk images if there are a lot of files (more than 30).