There is an unfortunate convention that "header type 5" EXOS applications and IS-DOS applications both use ".COM" files. So I wanted my program to work when loaded both ways.
EXOS loads the type 5 .com program into memory at 100h and jumps to it. IS-DOS loads the header itself at 100h followed by the program and then jumps to 100h
So I needed to make the header executable!
The first header byte is 0, which is a NOP
The next header byte is 5, the type byte. 05 is DEC B, so harmless.
The next byte is the low byte of the program size. So I padded the end of the program with 0s until it was xx3eh bytes long. 3e is LD A,n
The next byte is the high byte of the program size which will be loaded into A by the LD A,n instruction
Normally we then 12 0s (NOP), but I used 11 0s and a final opcode byte
Instead of 0 the last byte is 21h = LD HL,n
The program code then follows the header.
The first instruction in the code is a two-byte JR instruction, so this will be skipped when the above header is executed as it will be loaded into HL but not when loaded as a type 5 program as this is EXOS's entry point. This allows the program to detect if it was loaded by IS-DOS. It needs to do this because in this case it needs to do an EXOS reset instruction, mess about with paging a bit to get it compatible with an EXOS type 5 load, and also to copy the main program down in memory by 16 bytes, overwriting the header.
The final "trick" is to do the copy by putting an LDIR instruction at 0feh and jumping to it. When it has finished the next instruction will be the JR at the start.
Source code enclosed
B.