This piece of source code is only for advanced 6502 programmers or users wishing to create their own Paged ROMs. The explanation following is quite technical so if you require further information then contact EUG and any queries will be passed on.
This source code demonstrates a simple way of making a robust Paged ROM that can either be loaded into Sideways RAM or blown onto an EPROM. The code has been designed not for compactness or optimisation, but to allow easy implantation of extra commands and readability. (When I first started writing ROMs, I used to write custom headers, which always made updates difficult to implement and error-prone.) Some coders will look at this code and frown at the use of what seems like unnecessary JMP instructions. However, it is specifically written in such a way that each code section is totally independent of each other and thus code and data can be implanted anywhere without any relatives moving out of range. (Goodbyte BYTE errors!)
Advanced ROM coders should not that this header example does not support Autoboot, Private Workspace Claims or Claims of the NMI Workspace or zero-page locations. If you require these service calls, you should implant/intercept them in the Service Entry part of the source code. (Not forgetting to add release claims also!!!)
The first part of the code consists of a standard ROM header, as used by all Paged ROMs. (Please note that I have removed the bug in the header that the Acorn Electron Advanced User Guide contains!!) The ROM title in this header is the text that is used to compare against and printer when a *HELP command is received. However, altering this so that another text string is used, is very easy and only requires changing one EQUW statement. A portion of this text is also printed by the operating system when a *ROMS command is issued.
The Command Data is, as its name suggests, the commands that are accepted by the Service ROM. All of this text between the labels .cdt and .cde is printed by the RON when a *HELP command is received with an argument of the ROM title. *HELP with no arguments just yields the ROM titles and version number. Each ROM command in this data block should have its own label and be terminated with carriage return (&0D) for readability's sake when echoed to the screen. Please be aware that lowercase to uppercase character conversion is used in the comparing of issued commands (unrecognised commands that are offered to the Paged ROMs) so please do not used weird characters or numbers in your command names. Should you desperately require numbers in command names, you will need to reqrite the Command Interpreter (and possibly the Help Interpreter also).
The Service Entry is the piece of code called when the ROM is entered and there is nothing complex about this code. It simply stores the ROM entry registers and restores them on exit. The code only supports unrecognised commands issued to the Paged ROMs and *HELP commands. As I said earlier, if you ROM requires workspace or an NMI handler, you'll need to add code here.
I am actually open to debate on whether I should use zero-page locations (&70-&8F) as given to the user by BASIC. In actuality, your ROM should probably reserve workspace, but I actually think that reserving an entire page for just a few locations is very wasteful! I did think of grabbing the NMI and using its allocation of zero-page, but another ROM could request the NMI workspace whilst this ROM was active. The ROM would then be forced into relinquishing the NMI workspace and you would again need some zero-page workspace!!
The most important part of the source code is the Command Structure. It is this data that defines what text is printed and checked for when *HELP is issued and also how many and what commands the ROM actually has. The first entry in this table is the .hcs entry, which consists of a byte that specifies how long the *HELP ROM title is, minus one. Following this is a 16 bit (word) pointer to the ROM title itself. It is this text that will be used for comparison when a *HELP command is received with an argument of the ROM name.
The .cms entry is where the command pointers are located. The first byte is the number of ROM commands minus one. Each command entry consists of five bytes. Therefore, if your ROM has four commands, your total .cms length would be (5 x 4) + 1. A command entry has a very simple structure: A byte specifying the command length minus one, a word pointer to the command name itself and a final word which is the JMP address in the Jump Table. Please be aware that a register is used to step through this Command Structure and therefore the number of possible commands is limited to a maximum of 85. With careful reprogramming using indirect addressing, it would be possible to increase this, but I would have though that 85 was sufficient!!
The Jump Array comes next. This might be considered by some programmers to be superfluous when the command structure could achieve the same results. Well, I thought about this and since everything in this header is very modular, a jump table was a much neater way of achieving order.
The Help Interpreter is the code called when a *HELP command is issued. It first scans the CLI looking for arguments and if none are found simply reports the ROM name and version number. However, if the supplied argument matches the text pointed to by the .hcs pointer, then the ROM command list is echoed to the screen. Character conversion is performed on the input stream so that character case is equal. Please be aware of this if you are planning on using any strange characters.
The Command Interpreter is roughly the same as the Help Interpreter. Character case conversion is done on the input stream so special characters may cause commands to not be recognised. It scans the Command Structure for as many commands as indicated and, when one is recognised, it clears location (&70) which is the Accumulator of the ROM exit value. If you are writing a large ROM with many commands, please take care that the Command Structure does not exceed a Page in length! As warned earlier, the Command Structure is stepped through using a register and is therefore limited to 256 bytes.
There are some points to note about this code. Firsty, no dodgy self-modifying code is used at all. Secondly, it should work on any machine, from all BBCs to the Acorn Electron with whatever expansions they may have. Thirdly, when writing your ROM code, do not use locations &70, &71 or &72 for storage. The other BASIC user locations (&73-&8F) may be used as you see fit.
Chris Warburton
welder@majesty.net