Relocatable Sideways ROMs ========================= mdfs.net/ROMs/SROM/Modules J.G.Harston Introduction ------------ Many ROMs programs do not use the full 8K or 16K of the ROM, and have spare space in them. You can use this spare space to add extra ROM code. This is fairly easy to do as long as no more than one component of a multi-code ROM claims memory or provides a language. A service ROM that does not provide a language has no language entry, so the bytes at &8000-&8002 are unused. Usefully, this is the same size as a JSR instruction. Using this, you can find ROM images where two 8K ROMs have been joined together, with the second ROM starting at &A000 having the unused language entry replaced with a JSR to the first ROM's service code, and the first ROM's service entry jumping instead to the JSR at the start of the second ROM. The following shows an example of this: ; Lower ROM ; Lower ROM 8000 BRK:BRK:BRK --> 8000 BRK:BRK:BRK 8003 JMP &801E 8003 JMP &A000 801E Lower ROM service code 801E Lower ROM service code ; Upper ROM ; Upper ROM A000 BRK:BRK:BRK --> A000 JSR &801E A003 JMP &A03B A003 JMP &A03B A03B Upper ROM service code A03B Upper ROM service code You can see that in the joined ROM the service entry at &8003 jumps to the upper ROM, which then calls the lower ROM's service code before continuing into the upper ROM's service code. Obviously, the upper ROM code needs to be relocated or assembled at &A000 for it to work correctly. This is very close to how the combined DNFS ROM works, except that the upper ROM only has service code and none of the usual ROM header data. BBC Sideways ROMs (Relocatable Modules) --------------------------------------- 16-bit address must always be in adjacent bytes: don't use LDA #address AND 255:LDA #address DIV 256 must use LDA vector+0:lda vector+1 with .vector:EQUW address 16-bit addresses must always by 6502-style little-endian: don't use EQUB address DIV 256:EQUB address AND 255 must use EQUW address demo code SMLib Final byte must not be &00 or &FF to prevent merging into following empty space. The simplest method is to add purely service code to an existing ROM. I To do this, you need the image of the ROM you are adding to, and the source code (or a method of relocating the image) for the ROM code you want to add. This is done by changing the destination of the service call entry at &8003 to the start of the spare space at the end of the ROM. At the start of this spare space, the new code firstly calls the old service handler, and then continues with the new code's service handler:
8003 JMP SERV -> 8003 JMP MYCODE ... SERV \ Service handler ... MYCODE JSR SERV ... \ My service handlerThe additional code can even be a relocated ROM image with the language entry point in the first three bytes changed to the JSR SERV instruction. The following instruction will then be the relocated jump to the additional service handler.
Any number of ROM code fragments can be joined together like this. However, as each fragment is independent of each other, only one can claim workspace and use the workspace byte at &DF0+rom, and only one can be a language and be entered at &8000. To be entered as a language, the entry at &8000 should be changed to jump to the ROM code fragment's entry point:
8000 BRK:BRK:BRK -> 8000 JMP MYLANG 8003 JMP SERV -> 8003 JMP MYCODE ... SERV \ Service handler -> SERV ... MYCODE JSR SERV ... \ My service handler MYLANG \ My language startup BootFix ServROM SWOsw7F HADFS Support DisAssem MouseROM LibMax BLib.RelocROM newmodes Notes: ------ Service code *must* return X=ROM number as other service routines expect X=ROM number on entry. Consequently, LDX &F4 inserted into linked headers so X contains expected contents. Load as: 20 xx xx JSR xxxx xx xx LDX &F4 4C xx xx JMP xxxx CHAIN "SMJoin" -------------- SMJoin joins a collection of sideways ROM modules into a single file. It does the equivalent of *SMLoad but without loading them into sideways RAM. You can then load the resultant file into sideways RAM in one go, or program it into an EPROM to have present permanently. When SMJoin is run it prompts you for the files to join. You can also enter *commands at this prompt. The first file can be a normal non-relocatable ROM or a ROM with a language entry. All subsequent files must be relocatable modules. When you have entered all the files to join, press. You will then be prompted for the file to save the joined modules as. *SMList ------- Lists all relocatable modules in the following format: No. Position Name Version 1 FFFF8000 TERMINAL 1.00 (C)1984 Acorn 2 FFFC8000 BASIC 4.00 (C)1984 Acorn 3 FFFB8000 Edit 1.00 (C)1984 Acorn 4 FFFA8000 ViewSheet 1.00 (C) 1984 Acornsoft 5 FFF98000 DFS 2.24 (C)1985 Acorn 6 FFF78000 HADFS 5.62 (17 Feb 2012) (C)J.G.Harston 7 FFF7B7E0 NullKeyboard 0.12 (01 Aug 1998) (C)JGH 8 FFF7B80B SoftRTC 0.10 (23 Nov 1992) (C)JGH 9 FFF58000 VIEW 4.00 (C)JGH & Acornsoft 10 FFF5BB79 BootFix 0.00 (10 Oct 2012) (C)J.G.Harston 11 FFF5BBB9 Mouse 1.00 (12 Mar 2006) (C)J.G.Harston The high word of the position is the ROM bank the module is in, the low word is the address within the ROM bank of the start of the module. *SMLoad ------------------ Loads a relocatable module or sideways ROM to the highest available area of sideways RAM large enough. If the loaded file has a relocation table it is relocated and linked into the module chain. If it does not have a relocation table then it will only be enabled if it is loaded to the start of a bank of SRAM at &8000. Possible errors are: 133,Not enough SRAM 214,File not found 220,Syntax: SMLoad *SMFree ------- Displays the amount of free sideways RAM, showing how much is free in each bank. Relocatable Module code layout ------------------------------ Standard sideways ROM header assembled to start at &8000, with the language entry replaced with: 8000 EQUB &00 8001 EQUW RelocationTable The relocation table must be the last item in the sideways ROM. The relocation table is recognised by &8000 contining &00 and &8002 containing a byte with bit 7 set.