Code header
Files have load and execution addresses that specify where they are loaded to and executed. These specify I/O memory by being &FFxxxxxx and language memory by being <>&FFxxxxxx. The I/O processor is always a 65x2, but the language processor can be one of many CPUs. Files can have a header which specifies what processor the code is written for so if it is run on the wrong processor the client code can generate an error.
The header is the same as the ROM header as ROMs also need to specify what CPU the code is written for and where the code should be copied to in the language memory. The code header also allows files to be loaded from filesystems that don't have load/exec addresses, such as DOS/Windows.
Contents
Header
The general layout of the code header is the following:
Start+0: JMP Entry ; Code entry address or entry point Start+3: JMP Service ; Service entry point if a ROM Start+6: EQUB ROMtype ; Code type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Reloc+4: EQUD Offset ; Offsets if specified by the ROMtype etc: .... ; Possibly other data ... ALIGN ; If the code needs to be aligned Entry:
ROM type byte
The ROM type byte at Start+6 indicates what CPU the code is written for.
bit 7 - Service entry for ROMs, ignored when loaded bit 6 - Contains code, if clear will generate an error similar to 'This is not a language' bit 5 - Contains a relocation address, if clear the code loads to &8000 bit 4 - Electron key expansion bit 3-0 indicates the CPU type: 0 6502 BASIC 5 - 8 Z80 12 80286 1 Turbo6502 6 - 9 32016 13 ARM 2 6502 7 - 10 - 14 - 3 6800/6809/68000 8 PDP11 11 80186 15 -
Code in a ROM will normally have a ROM type byte of &E0+cpu, code loaded from a file that is not also a ROM image will normally have a ROM type byte of &60+cpu. If the ROM type byte is &40+cpu or &C0+cpu there is no relocation address and the code loads to &8000.
If the code is run on a CPU that does not match the CPU type an error similar to 'This is not Z80 code' is generated.
Entry point
The entry point at Start+0 must be an unconditional branch to the code's start point in the machine code for the CPU. If the ROM type byte bit 7 is set then Start+3 contains the ROM service entry point, so the entry point at Start+0 must fit into three bytes. If the ROM type byte bit 7 is clear the code at Start+0 can be up to six bytes long, and some CPUs require this.
If ROMtype bit 7 is set then the entry point at Start+3 must be a 6502 unconditional branch to the ROM's service code, or a 6502 RTS.
The code is entered at the entry point with the registers set to a defined state. This is normally:
Primary register: 0=raw code (no header), 1=code with a header Secondary register: points to command line tail Flags: CC=entered at reset, CS=entered otherwise, eg a *command
Example headers
65x2 - ROM type 0,1,2
Start+0: JMP Entry ; Code entry point Start+3: JMP Service ; Service entry point Start+6: EQUB ROMtype ; flags+&00, flags+&01, flags+&02 Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUW Start ; Load address if ROMtype bit 5 is set Reloc+2: EQUW RelocateTable ; Normally 0, only supported by MOS 3.50 Entry: ; Code start
6809 - ROM type 3
Start+0: BRA Entry:NOP ; If position-independent code or JMP >Entry ; If not position-independent code Start+3: EQUB &4C:EQUW Service ; 6502 jump to ROM service handler or EQUB &60:EQUW 0 ; 6502 RTS if no ROM service handler Start+6: EQUB flags+&03 ; ROM type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string Copyright: EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Entry: ; Code start
PDP11 - ROM type 7
Start+0: BR Entry:EQUB 0 ; Branch to code if ROMtype bit 5 is clear Start+3: EQUB &4C:EQUW Service ; 6502 jump to ROM service handler or EQUB &60:EQUW 0 ; 6502 RTS if no ROM service handler Start+6: EQUB flags+&07 ; ROM type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Reloc+4: EQUD Entry-Start ; Offset to entry if ROMtype bit 5 set ALIGN ; Alight to 16-bit words Entry: ; Code start
Z80 - ROM type 8
Start+0: JR Entry:NOP ; If position-independent code or JP Entry ; If not position-independent code Start+3: EQUB &4C:EQUW Service ; 6502 jump to ROM service handler or EQUB &60:EQUW 0 ; 6502 RTS if no ROM service handler Start+6: EQUB flags+&08 ; ROM type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Entry: ; Code start
32000 - ROM type 9
((NB: needs checking))
Start+0: EQUB 0:EQUW 0 ; Ignored Start+3: EQUB &4C:EQUW Service ; 6502 jump to ROM service handler or EQUB &60:EQUW 0 ; 6502 RTS if no ROM service handler Start+6: EQUB flags+&09 ; ROM type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Reloc+4: EQUD Entry-Start ; Offset to entry if ROMtype bit 5 set ALIGN ; Alight to 16-bit words Entry:
80186, 80286 - ROM type 11,12
((NB: needs checking))
Start+0: JR Entry:NOP ; If position-independant code or JP Entry ; If not position-independant code Start+3: EQUB &4C:EQUW Service ; 6502 jump to ROM service handler or EQUB &60:EQUW 0 ; 6502 RTS if no ROM service handler Start+6: EQUB flags+&0B or +&0C ; ROM type byte Start+7: EQUB Copyright-Start ; Offset to copyright string Start+8: EQUB 0:EQUS "Title" ; Binary version number and title string EQUB 0:EQUS "0.00 (01 Jan 2001)" ; Version string (optional) Copyright: EQUB 0:EQUS "(C)J.G.Harston":EQUB 0 ; Copyright string Reloc+0: EQUD Start ; Load address if ROMtype bit 5 is set Entry:
ARM - ROM type 13
The ARM ROM header is complicated by having been implemented differently on different platforms, the Acorn ARM Evaluation System, the Arthur/RISC OS RomFS, and the Sprow ARM CoProcessor.
((( I'm still writing this part, so will come back to it later )))
Extracting load/exec address
The load and execution addresses can be extracted from the code header with the follow pseudo-code:
load=unknown exec=unknown if start+7 does not point to &00,"(C)", then exit // Raw code load=&FFFF8000 exec=&FFFF8000 romtype=start[6] if rombyte bit 6 is clear, then exit // No code, service ROM load=&8000 exec=&8000 if romtype bit 5 is clear, then exit // No relocation address point to the relocation address after the zero byte at the end of the copyright string load=reload[0..3] exec=reload[0..3] switch (romtype AND 15) { when 7,9: exec=load+reload[4..7] // PDP11, 32000 when 13: exec=start+8+start[0..2]*4 // ARM (not complete) } exit