Thanks for the tip in EUG #26, Rob.
For everyone's benefit, my objective is to save a memory dump of THRUST, in order to extract routines for my own games, etc, especially the hardware scrolling routine Thrust uses - the screen scrolls by a fixed amount when your ship reaches a set distance from the edge of the screen.
I had the usual problems, in that as with most games the author uses EORing routines to make life difficult for hackers. In the case of Thrust, there is more than one EORing routine, as well as the code and data relocation routines. Previous attempts to decypher the code after running one EORing routine have yielded mostly gibberish, so I was looking for another method of getting the decoded game onto a disk.
Following Rob's tip in EUG #26 of causing an IRQ by pulling the NIRQ pin of the 1MHz bus low (by shorting pin 7 to pin 8 with a screwdriver) and trapping the interrupt in a Sideways RAM image with servie call &05, I have managed to save most of the game to disk in decoded form. (The parts which remain are &D00 to &DFF - the NMI workspace - as I decided that saving to tape was too laborious, being used to disk systems with instant file access; and &700 to &780 - the CLI buffer - which is corrupted by *SAVEing the contents of memory to disk). Attempts to *SAVE to memory from the Sideways RAM image failed. I shall save the missing bits later, using a memory relocation routine in the Sideways RAM image.
The machine configuration was as follows for the successful save:
Master 128 with Double DS DD 5.25" drive
Important *CONFIGURE parameters: | Mode 128 - important so as not to wipe main memory when BREAK is pressed File 9 - ADFS No Directory No Boot - autoboot would be a nuisance |
The program THHACK was used to create a ROM image in sideways RAM which would intercept the unrecognised interrupt and disable the wipe-on-break function of *FX200,3. This program is on the disk.
The following is a record of what happened:
*FX151,78,127 | disable all IRQs |
CTRL-BREAK | reset machine. Since the IRQs are disabled, the machine is reset to its power-on state. This technique will clear even the mysterious ROM-not-found-even-when-it-wasn't-*UNPLUGged errors (See later). |
*DIR $.THRUST | Move to ADFS directory containing THHACK and Thrust. |
CHAIN"THHACK" | Run hacking program. |
PRINT O% e.g.944 |
Get location of end of source code (O% is used on the Master series to enable code to be set to run elsewhere in memory - in this case at &8000) |
*SAVE THHACK? 900 945 8000 | Save the RAM image. |
*SRLOAD THHACK? 8000 4 Q | Load RAM image into SWRAM bank 4. |
CTRL-BREAK | Reset to ADFS, Mode 128 and install RAM image. |
*DIR $.THRUST | Go to THRUST directory. |
*THRUST | Run THRUST game. |
Lift computer, ready to interrupt the game.
Short pins 7-8 of 1MHz bus with a screwdriver.
The machine locks up, as the error stack has filled up, due to "switch bounce" on the 1MHz bus pins, and has begun to overwrite the stack.
N.B. - I noticed that Thrust intercepts the IRQ1V vector - if it had masked all the IRQs it didn't use (by returning with RTI instead of exiting via the old contents of the vector), then it might not have permitted the MOS to pass the 1MHz bus interrupt round the paged ROMs for the THHACK ROM to intercept it. |
|
CTRL-BREAK | This is safe, as the ROM code has disabled the wipe-on-break with *FX200,0
The machine is reset to mode 128 and BASIC, but ADFS is nowhere to be found! |
CTRL-D-BREAK | Try DFS instead. |
Grab a DFS disk.
*SAVE MEM 0 8000 | Save memory to disk (no point saving memory above &8000 as it will contain the DFS ROM, workspace and the MOS) |
*SAVE MEM2 E00 8000 | Save a block of memory which can be reloaded (attempting to reload a file over MOS variables or NMI workspace will cause a crash) |
*DUMP MEM (CTRL-N) | Look through memory dump for messages such as "Game over" or "Press space to start", and note their locations in memory (in some games the messages appear backwards - note the location of the last letter or trailing null byte in this case). |
And so the process continues...
Find routines that point to the messages, and also ones which change vectors or poke the CRTC registers (Not sure about Elk equivalent here).
You will need a table of opcodes, such as is provided in part 2 of the MASTER REFERENCE MANUAL, in order to work in hex.
I have found the following program useful for finding routines which use key locations:
10FORI%=&xxxx TO &yyyy
20IF ?I%=&ll AND ?(I%+1)=&hh THEN PRINT (I%-1),!(I%-1)
30NEXTI%
The program searches from &xxxx to &yyyy for all occurrences of instructions which use location &hhll.
The output is as follows:
2416 603456AD = LDA&5634 : RTS, beginning at &2416N.B. Beware of bogus output from data areas - check the surrounding code in each case.
To trace a routine which points to a message, set &hhll to be the location of the message which you noted down from using *DUMP.
An example to find pokes or peeks to the CRTC registers:
20IF ?I%<=1 AND ?(I%+1)=&FE THEN PRINT (I%-1),!(I%-1)
Using the above line as line 20 will yield all the uses of locations &FE00 and &FE01 - I shall use this to find the hardware scrolling routines by looking at what is loaded into X and Y registers before the pokes - if X = &0C or &0D and the program gives:
mmmm xxFE008E = STX&FE00this will indicate that the game is poking the CRTC registers which control hardware scrolling from location mmmm.
As well as looking for this, and routines which perform a loop containing:
LDX #0 initialise index register .loop LDA (&zz),X get character of message JSR oswrch print character CMP #0 test for null character BEQ exit exit the loop if the last character has been printed INX increment the index register BNE loop loop back for another character (the message is unlikely to be as long as 256 bytes, so the Z flag will be non-zero so BNE will act as a branch-always) .exit ...I shall look for call to system routines: xxFFF420 = JSR osbyte etc...
To find sprites (this is the reason why I saved a reloadable portion of memory earlier), *LOAD MEM2 3000, and you can pick out the sprites on the screen. You can then find the sprite plotting routine by looking for code such as:
LDA#Sprite_Utilitieste_location MOD 256 set two bytes in zero-page to point to STA&zz the sprite location. LDA#Sprite_Utilitieste_location DIV 256 STA&zz+1 LDY#0 .loop LDA(&zz),Y load byte of sprite STA&ssss,Y save to screen location INY CPY#8 8 = example height of sprite BCC loop loop if Y < 8 ... .sprite_location <data>I hope that you can decode games as well as this letter - if so, you should each be able to write excellent games for us all to play!
Happy hacking!
Mark Bellis, EUG #28