[Main] [Docs] [Installs] [Search] [Team] [Guestbook] [Links]

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 the 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 (so 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 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
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 for a NDOS demo/game 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
  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 the MFM decoding) with a hex-editor. Then cut the area (+/- $1000 bytes) found, disassemble it, and search for 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.
    One thing left to do is to create a nice Icon. Rip two pictures using the snoop feature of WHDLoad and SP or use a freezer or some kind of UAE to extract pictures and build the icon. The 16 color 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 disks the use of RawDIC is recommended. See the 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 to select 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 the 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

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 exists nor is accessible nor makes any sense to access! Therefore all accesses attempted by the installed program 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 information.

Common compatibility problems

Limited address space on 68000/68010/68ec020

On these processors the address space is limited to 16 MiB ($000000...$ffffff) because these CPUs do have only 24 address lines. As a result all accesses to higher addresses are performed to the lower 16 MiB by ignoring the most significant 8 bits. Some programs use these bits to store data, or simply forget to clear them. On a processor with full 4 GiB address space like the 68020/680ec30/68030/68040/68060 this does not work, because the full 32-bit addresses will be accessed.
To solve this you have to patch these accesses and redirect them to the correct addresses.
Sometimes the reason for accesses to strange addresses may be an uninitialized pointer. In these cases it may help to clear the memory $400 - ws_BaseMemSize which can also be accomplished by using the flag WHDL_ClearMem.

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 long, except for 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 compared to 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 unexpected results.
If a program does so, you'll have to fix this. Sometimes it may be enough to replace the RTE with a RTR.

MOVEM.x RL,-(An) on 68000/010 and 68020-68060

There is a difference if the register used in predecrement mode (RL) is also contained in the register list. For the 68020-68060 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).
Currently no software is known to have problems because of this.

General guidelines for writing installs

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).
[Main] [Docs] [Installs] [Search] [Team] [Guestbook] [Links]