|★ APPLICATIONS ★ PROGRAMMATION ★ Investigating CPC roms ★|
|Investigating CPC Roms|Amstrad Computer User)||Applications Programmation|
Richard Sargent looks at the workings of add-on roms for the CPC, and how to make them work for you.
ROMS, like small children, should be seen and not heard. (Hey that's a bit ageist - Ed). OK, they should be recognised (at least by the computer), they should work (with all CPC models) and they should not clash with one another.
Most of the time they behave themselves, and this is particularly so of the internal roms. ROM 0 (Basic) on the 464 and roms 0 (Basic) and 7 (CP/M) on the 6128. If they didn't work the computer would be dead anyway. So you take them for granted and perhaps occasionally use routines inside them by calling a jumpblock address taken from the Firmware Spec.
No fixed address
The sideways roms, those which hang out of the back of the computer and which you have to buy, are much more interesting because they have to be fitted in a ROM slot of your choice. And you get a manual with the ROM which explains all the glorious | commands available.
You are not told the addresses of the l routines because they may change from one month to the next as newer versions of the same ROM are produced. Writing and debugging software takes time - ROM wasn't built in a day.
Exactly why you may need to obtain and use, quite legally, the starting address of one of more routines in sideways ROM will become clear in a moment.
Collecting roms is habit-forming. You need a ROM box to house just one off-the-shelf rom, and this peripheral is likely to have six or eight blank ROM sockets in it. No hardened hacker can stare at an empty socket for long - to the computer techie it's like a newly hatched chick, mouth open ready to be filled. The purchase of roms tends to accelerate to fill the space available.
Before long you will find you have a ROM with a l HELP command which lists all your roms, and a |HELP,n command which will list all the I commands of ROM number n. |HELP,n is provided as a memory aid to relieve you of the need to consult the manual. (It is not - there to allow you to pirate the software without the instructions - Ed).
Assuming you have a |HELP command, typing lHELP,7 lists the 14 commands of the CP/M rom, which are lCPM, lDISC, |TAPE and so on. Listing II prints the command names and the addresses of commands from ROM n, and so takes us a little further forward.
A spare time job
Since machine code can be incorporated efficiently into the Amstrad's interrupt structure, it only requires a small amount of code to enable a ROM routine of your choice to be executed as an interrupt. Then the program can be interrupted, a sideways ROM routine run, and the original program restarted.
There is one sideways ROM routine which is ideal for the interrupt application: The graphics screen dump. Before seeing how to get at such a dump (for example, there's one in the Superpower's Toolbox ROM and another in Arnor's Utopia rom), we must first see how to take a look into these sideways roms.
Basic's PEEK doesn't work, since PEEK only ever looks at RAM between 0000 and &FFFF. The solution is to move the contents of the ROM into main memory. The starting address of all upper roms (the sideways roms, Basic and CP/M) is &C000 and they are all 16k or &4000 bytes in size.
Moving the entire 16k to location &4000 takes but a moment in machine code - this job is performed by Listing I. As soon as the ROM has been relocated at &4000 it can be examined.
Listing II contains the code of Listing 1 and will first move the ROM of your choice to &4000, then go on to find and print the ROM version number, the commands and command addresses. Don't try it with ROM 0 though - there are no | commands listed for the Basic ROM.
If you have no lHELP on your computer, you will need to physically examine your ROM box or the relevant manual to ascertain which ROM occupies which position. On the 464 the legal positions are 1-6 and on the 6128 they are 1-6 and 8-15.
The Basic program will prompt you to tell it which ROM you wish to investigate and it will ask you whether you want screen or hard-copy output of the command list.
Back to the dump
Returning now to those specific screen dump commands, Listing II reports that Utopia has the IGDUMP command at &F67E and Toolbox has l DUMP at &C888. Note that any other addresses reported will be valid -the difference simply means that the ROM has been rearranged since I bought my versions.
Now (and carefully coached by the firmware spec) we can carry out the equivalent of Basic's I GDUMP in machine code. Assuming you have the relevant ROM in position number 2 the code is:
Go to the bottom of the class if you thought it should have been CALL &F67E. Once again, the operating system needs to be told the ROM and the address of the routine you're interested in, hence load C and load HL.
Getting to the code
However, the three instructions act just like CALL GDUMP. CALL &F67E on the other hand rushes off to screen RAM and promptly crashes the Amstrad. Load register C with a different number for a different ROM and load register HL with a different address for a different routine.
Note that on returning from the call, all registers and flags are as set by the target routine and register IY points to the rom's data area. You must save all registers which you wish to preserve before calling the ROM routine.
The machine code needed to put the GDUMP routine (or any other sideways ROM routine) into an interrupt handler comes in four short modules, as in Listing III. They are placed at address &9200 and sit there seemingly doing nothing much at all. The code is consulted 50 times a second and is keeping an eye on key f0 to see if it is pressed.
Rom turn on
Module one ISR_ON contains the code which tells the Amstrad to add a new routine to its list of events which it is currently servicing at the 2 millisecond interrupt rate. The new routine is called ISR and is officially logged into the system by calling ISR_ON, (CALL &9220).
Module ISR_OFF removes ISR from the system, so CALL ISR_OFF, (CALL &922E) restores normality. (As soon as we are sure what is normal anyway -Ed).
The ISR module is the Interrupt Service Routine. It scans the keyboard and considers whether function key ft) has been pressed. All the Z80 registers are saved - this is essential as the computer would crash if it were not done.
After all the PUSHs, a CALL to the firmware routine &BB1E establishes whether the key f0 (code 15) has been pressed.
If it hasn't an immediate exit from the interrupt routine is made via label KFIN and the ISR routine has done its job in no time at all. If, on the other hand, the correct function key is pressed, a jump is made to TEST_ROUTINE. This is a routine in Amstrad's lower ROM which doesn't do anything too drastic (it clears the screen) and it is useful for test purposes. TEST_ROUTINE is a simple JUMP but because the Z80 stack has been fiddled (see the assembler instruction ld hl/kfin: push hl ) the jump acts as a CALL which returns to the KFIN label.
Any jump can be placed at label TEST.ROUTINE, including jumps to your own machine code subroutines. However, as it stands, Listing IV loads the screen-clearing routine, so every time you press fO, regardless of what the computer happens to be doing at the time, the screen should immediately clear.
Choosing your code
If this works, you have entered the code correctly and can start experimenting. Turn the ISR off with CALL &922E (or GOTO 250 if Listing IV is still in memory) and set about altering line 160, and possibly lines 200 and 220. The data on line 160 becomes 3E. This substitutes the Rom_ROUTINE for the TEST_ROUTINE.
If the ROM number you are going to use isn't 2, alter the data on line 200. Next alter the data on line 220 to the address of the ROM routine. Note the address is printed with the low byte first, so leave it as 7E,F6 for Utopia's GDUMP but change it to 88,C8 for Toolbox's DUMP command.
Run Listing IV and the altered code will be entered into memory: The ISR will be logged on, and henceforth whenever you press key A3 you should get a screen dump on your printer regardless of what the computer is doing. If the screen happens to be constantly changing, you get a snapshot of the screen as it appeared the instant f0 was pressed.
There are some limitations to this. Most commercial software will be upset by your interrupt routine, so don't expect to be able to dump a screen from a top 20 game. And some ROM routines cannot be called from inside an interrupt, notably disc commands which use an interrupt themselves. Have fun.