Sunday 30 November 2014

Rocket Raid Under the Hood 6: Hall of Fame

This is the sixth part in a series of posts on digging into the code of the Acornsoft side-scrolling arcade game, Rocket Raid.

Note: in the previous post we replaced some of the labels that had been automatically assigned by BeebDis with custom labels to make the code more readable (such as replacing the label "L3402" with "copyBytes"). To help make the code more readable going forward, I’ll show the disassembly snippets with labels that I have replaced.

Hall of Fame Set-up

Next we'll look at code that sets the starting scores and names for the "Top Eight" Hall of Fame that is displayed at the end of each game, and the code that inserts a player's qualifying score into the table after a game.

The default scores and names are set during program initialization.

Default Hall of Fame Score Data


After setting a flag to mark that sound effects are "on", the program fills out a table, scoreLadder, to hold the default high score entries for the game.

Relevant BeebDis custom labels:
scoreLadder     $06D0
scoreLadder+1 $06D1
scoreLadder+2 $06D2
soundFlag        $0075
initHighScores $341C
Disassembly:
        DEY                      ; Y at this point is zero, so subtract 1 to get &FF
        STY     soundFlag        ; Set the sound flag to "on"
        LDY     #$1E             ; Set starting table offset to 30 
.initHighScores
        LDA     #$00             ;
        STA     scoreLadder,Y    ;
        STA     scoreLadder+2,Y  ;
        LDA     #$10             ;
        STA     scoreLadder+1,Y  ; Set 3-byte score to 1000 points (BCD)
        DEY
        DEY
        DEY                      ; Move down 3 bytes for next entry
        BPL     initHighScores   ; Loop while Y>=0
Scores in Rocket Raid are represented internally using 3 bytes of data, in binary-coded decimal (BCD) format. Hence each entry in the scoreLadder table has 3 bytes which are set to &00, &10 and &00, representing a score of 1000 points for each entry.

There is actually a small bug in the logic above, although this is not obvious without looking at the rest of the code: namely that one entry too many is created (counting down from an offset of 30 to 0 writes 11 entries instead of 10), placing one entry in data space that will be overwritten by other data. Fortunately, this doesn't cause a problem when the game runs because later high score logic does not refer to this extra entry. The fix is to set the Y offset to 27, not 30, at the start of the loop.

Also, only nine of the entries are used in practice; of which eight represent the Top Eight scores for display in the Hall of Fame, while the ninth serves as a work area when re-sorting the high score table. The tenth entry is not used.

Default Hall of Fame Name Data


Next the names associated with the default high scores are set - in this case, being the all-familiar "Acornsoft". The data buffer for the names, which I have labelled "nameLadder", has space for 10 entries of 20 bytes each.

Relevant BeebDis custom labels:
nameLadder-1 $070B
nameLadder $070C
initNames $3430
copyChar $3432

Disassembly:
        LDY     #$C8                    ; Set total byte counter to 200
.initNames
        LDX     #$09                    ; Length of "Acornsoft"
.copyChar
        LDA     acornsoftString,X
        STA     nameLadder-1,Y
        DEY
        DEX
        BPL     copyChar                ; Copy 10 bytes total (string chars + CR) to nameLadder
        TYA
        BNE     initNames               ; Repeat a total of 20 times

The code uses a trick to simplify the logic, which explains why it repeats 20 times instead of 10 times: instead of copying the "Acornsoft" string once and skipping 10 bytes to the next entry, the loop writes it twice consecutively, relying on the fact that the length of the string plus carriage return is exactly 10 bytes. (The second occurrence of the string within an entry will be ignored by the string output routine). So by writing it twice, the counter neatly lines up with the start of the next entry.


Look-up Table for Hall of Fame Names



The third part of the set-up creates a look-up table of pointers, called nameLookup, which point to the Hall of Fame strings in the nameLadder table we looked at above.

The nameLookup table contains space for 10 address pointers. Having a look-up table for the strings makes it easier to manipulate, for example when inserting a new entry in the high score table, by swapping around pointers rather than their underlying data strings.

Each pointer is allocated 3 bytes which gives it a structure consistent with the scoreLadder table, although only two of these bytes are needed to store the address (ordered LSB, MSB). The third byte of each entry is not set or used.

Relevant BeebDis custom labels:
nameLookup $06EE
nameLookup+1 $06EF
initNameLookup $3443
acornsoftString $3493


Disassembly:
        LDX     #$0C              ; &0C is the least-significant byte of nameLadder table at &070C
        LDY     #$1B              ; Fill from the 10th pointer position (27 byte offset)
.initNameLookup
        TXA
        STA     nameLookup,Y      ; Store LSB of address pointer in the look-up table
        CLC
        ADC     #$14              ; Point to next string in nameLadder (20 bytes higher)
        TAX
        LDA     #$07              ; &07 is the most-significant byte of nameLadder table at &070C
        STA     nameLookup+1,Y    ; Store MSB of address pointer in the look-up table
        DEY
        DEY
        DEY
        BPL     initNameLookup    ; Decrease offset & loop back to create 10 entries
The string data is defined a little further down, at the end of the program:
.acornsoftString
        EQUS "Acornsoft"
        EQUB $0D                  ; carriage return
After the above loop is carried out, the nameLadder table is filled with pointers as follows:

nameLookup        -> (nameLadder + 180) [Rank 9 name]
(nameLookup + 3)  -> (nameLadder + 160) [Rank 8 name]
(nameLookup + 6)  -> (nameLadder + 140) [Rank 7 name]
(nameLookup + 9)  -> (nameLadder + 120) [Rank 6 name]
(nameLookup + 12) -> (nameLadder + 100) [Rank 5 name]
(nameLookup + 15) -> (nameLadder + 80)  [Rank 4 name]
(nameLookup + 18) -> (nameLadder + 60)  [Rank 3 name]
(nameLookup + 21) -> (nameLadder + 40)  [Rank 2 name]
(nameLookup + 24) -> (nameLadder + 20)  [Rank 1 name]
(nameLookup + 27) -> nameLadder         [unused]

In the next post we'll look at how the nameLookup and scoreLadder tables are updated at the end of a game to display the Hall of Fame .

Friday 28 November 2014

Rocket Raid Under The Hood 5: Program Initialization

This is the fifth part in a series of posts on digging into the code of the Acornsoft side-scrolling arcade game, Rocket Raid.

Initialization on Entry


Let's look at the first action the program takes upon entry at location &3400.


Data Relocation


Here is the disassembly that was generated by BeebDis in the last post (with comments added):

.L3400
        LDY #$00      ; Set counter to zero
.L3402
        LDA L3000,Y   ;
        STA L0400,Y   ; Copy data from location &3000+Y to &0400+Y
        LDA L3100,Y   ;
        STA L0500,Y   ; Copy data from location &3100+Y to &0500+Y
        LDA L3200,Y   ;
        STA L0600,Y   ; Copy data from location &3200+Y to &0600+
        DEY ;
BNE L3402             ; Loop back a total of &FF times
Hence this loop copies data in the range [&3000, &32FF] down to [&400, &6FF]. The Advanced User Guide indicates that the area of memory between &400 and &7FF is a workspace for the currently active language ROM (such as BASIC). Since the main game code does not use BASIC, this area is available for its use.

This answers the puzzle in the previous post of what happens to the data at &3000 which will otherwise be overwritten by screen graphics upon switching MODE. 

There is no need for the program to similarly guard the code that sits in the area [&3300, &349D] after it has been used during program initialization, as it is used only once.



BeebDis Custom Labels

It would be nice if some of the automatically-generated labels were replaced with more explanatory names. For example, we might like to replace "L3400" with "entry".

This can be achieved with BeebDis by creating a custom list of labels. First, we create a new text file (called "mylabels.txt" for example) and in it define any labels we wish:
entry         $3400
copyBytes $3402
Adding an extra line in the control file will direct BeebDis to use the file:
symbols mylabels.txt
Running BeebDis again, we can see that the labels have been replaced in the disassembly:
.entry
        LDY #$00    ; Set counter to zero
.copyBytes
        LDA L3000,Y

        ...[snipped]... 
BNE copyBytes



Disassembly of the Relocated Code

I took an extra step to deal with the code [&3000, &32FF] that gets relocated down to location &400. Although there is no major problem with disassembling this section of code in place (i.e. before relocation), there are a few places in the main Rocket Raid code where jumps are made directly into the relocated area, so I decided to disassemble the code using its relocated addresses, for consistency.

I manually "relocated" the section of code by splitting it out as a separately-saved file using a hex editor. This allows it to be loaded by BeebDis with a second control file specifying the relocated starting address:

load $0400 $.RAIDOBJ_relocated
save disassembly_relocated.txt
symbols labels.txt
symbols mylabels.txt



Thursday 27 November 2014

Rocket Raid Under The Hood 4: Generating a Disassembly

This is the fourth part in a series of posts on digging into the code of the Acornsoft side-scrolling arcade game, Rocket Raid.

In the last post, we left off at the point where the loading program makes a CALL to the address of entry to the main code at &3400. At last, it is time to disassemble the core game code and have a look at what happens from here.

Disassembling with BeebDis


To generate a disassembly of the game code, we will make use of the BeebDis command-line tool. An interesting possibility with BeebDis is that the disassembly output is in a form that can then be run through BeebAsm to build a new object code file, allowing us to make changes to the code and building a new version.

As a first step we need to extract the file containing the machine code of the game, which we saw in the last post was the file $.RAIDOBJ, from the emulated disc image to our local PC desktop so that it can be processed by BeebDis.

Note: the BeebEm emulator also contains a built-in Debugger which is handy for disassembling short chunks of code while probing a program that has been loaded into memory.

Extracting the Object File

Files can be extracted from a disc image using the BBC Explorer utility. Simply open the disc image for Rocket Raid, select the appropriate file, then click on Extract to save the file.

BBC Explorer: Extracting the RAIDOBJ file

BeebDis Set-up

BeebDis needs a "command file" to be created in order to use it. This is a simple text file with instructions relating to the disassembly. Our command file looks like this:

load $e00 RAIDOBJ$
save disassembly.txt
symbols labels.txt
entry $3400

The first line specifies the name of the object code file extracted from the disc above, and the address at which to load it (note that BeebDis uses $ to denote hexadecimal numbers). Next is the filename for saving the disassembled output. The "symbols" line points to a list of memory locations which BeebDis will automatically replace with labels when found in the code. The file "labels.txt" file comes with BeebDis and contains definitions for common OS routines and vectors, which will make the disassembled code easier to read.

This command file can be easily adjusted and the disassembly regenerated at any time.

Setting the Disassembly Start Location

The final command in the command file tells BeebDis to start disassembly from location &3400. This can be set to any start-point of interest; in this case it represents the address of the entry point to the game that is CALLed by the loader.

Setting the start to &E00 straight away results in broken disassembly output, since the disassembler can easily get confused by areas of data interspersed in the code. As we identify which areas respresent data, we will be able to mark these by adding instructions in the BeebDis command file.

Generating the Disassembly

Now we are ready to run BeebDis from a command-line prompt, giving the name of the control file as the parameter, to generate the disassembly file:
BeebDis control.txt
Various messages will scroll up the screen as BeebDis works, but the end result is the generation of a file named disassembly.txt that contains the disassembly.

Examining the Output

Let's take a look at the result by opening up the file in a text editor. The first thing that we see, in the top section of the file, is a list of label definitions.


Labels of the form the form "L" followed by 4 hexidecimal digits are ones that been created automatically by BeebDis to replace references in the code to fixed memory locations. Labels for various operating system routines that have been identified can also be seen; these are taken from the "labels.txt" file specified in the BeebDis command file.

After the label definitions is an "org" directive indicating the start of the disassembly proper, a label that BeebDis has inserted to mark the start address, and then a long list of EQUB instructions which represent byte data.
        org     $0E00
.BeebDisStartAddr
        EQUB    $BA,$86,$0E,$20,$62,$11,$20,$8B
These raw bytes have not been disassembled since we told BeebDis to start disassembly at location &3400. If we scroll down to near the end of the file, the start of the disassembly can be seen:
.L3400
        LDY     #$00
.L3402
        LDA     L3000,Y
        STA     L0400,Y 
At last, we are able to start analyzing the code to see how the game has been put together!

Wednesday 26 November 2014

Rocket Raid Under The Hood 3: Loading process

This is the third part in a series of posts on digging into the code of the Acornsoft side-scrolling arcade game, Rocket Raid.

Now that we have gathered together all the materials needed, we're almost ready to start looking at the code itself. But first let's take a brief look at the memory map for the BBC B.

The BBC B Memory Map


The Beeb's memory is laid out as per the following diagram (from the book "Assembly Programming Made Easy for the BBC Micro", by lan Murray). A standard machine has 32K of RAM, being the lower half of the diagram.

BBC Micro Memory Map
Location &E00 is the standard start of the area for BASIC programs to be stored, assuming the system uses only tape for external storage; this jumps up to &1900 with a disc system installed. 

&8000 represents the upper boundary for graphics RAM. The amount of RAM used for screen memory depends on the graphics mode that is used. For example, in the BBC's MODE 2 which supports display of all 8 colours at once, screen graphics take up a relatively huge 20K of memory (from &3000 to &7FFF), whereas in the efficient Teletext-based MODE 7, only locations from &7C00 to &7FFF are needed.

There is also a special area of 256 bytes at the start of RAM (from &0000 to &00FF) known as "zero page". Although small in size, it is special due to the design of the 6502 processor which can store and retrieve values more quickly than when using other locations in memory, giving programs a speed advantage. Zero page is available for use by machine-language programs when BASIC is not in use.

One technique used to counter the lack memory caused by the use of the disc filing system (DFS), for example, is to load into memory using a memory-friendly MODE such as MODE 7, and then once loaded relocate the code lower down to make use of the memory used by the DFS, knowing that disc access will no longer be necessary. This is something we will see that the Rocket Raid code does in order to squeeze itself into memory.

Examining the Loader

Let's have a look at the loading process after setting the Rocket Raid disc image in BeebEm, The loader for Rocket Raid consists of two small BASIC programs: RAID and RAID2.

RAID simply displays a loading screen, which consists of MODE 7 Teletext graphics, and then calls the second part of the loader:
100 PAGE=&5000:CHAIN"RAID2"
Rocket Raid loading screen
The significance of setting PAGE is that it allows the second loader program to be brought into memory somewhere that leaves enough room for the main game code that it will be loading in. It sits below the start of the screen graphics area for MODE 7, which has a very small screen graphics footprint starting at &7C00. 

RAID2 has a more substantial job. First it loads the compiled game code, stored as the file RAIDOBJ, into memory at location &2000:
400 *L.RAIDOBJ 2000
Address &2000 is high enough to avoid memory areas used by the disc operating system and the BASIC loading program itself. So how large is the game code? This can be found by running the DFS command *INFO at the BASIC prompt, which gives the following result:
> *INFO RAIDOBJ
$.RAIDOBJ    002000 003400 00269D 00C
The first number is the default load address, &2000. The second is the execution address of the code, &3400, and the third is the size of the file which is &269D bytes - i.e. the main game code is just 9K! (The last number represents the start sector on disk, which is not of interest).

However since the game will be running in MODE 2 the code will have to be moved to somewhere else in memory to avoid being overwritten by the screen graphics when the mode is switched. At its current position, the end address of the code (&2000+&269D=&469D) sits well inside the start of screen graphics memory for MODE 2 at &3000.

To achieve this, the next line of the loader copies the game code down to location to a lower place in memory, in 4-byte chunks.
410 FOR A%=&2000 TO &46A0 STEP 4:!(A%-&1200)=!A%:NEXT
The effective new start location is &2000-&1200=&E00, which is recognizable as the standard start of user memory for programs on a tape-based system.

But even once the code has been moved down, a quick calculation shows that the end of the code still runs over the screen memory boundary at &3000. This can be confirmed by adding the length of the code to its starting location, giving &E00+&269D=&349D. Any code that remains in this area runs the risk of being wiped out on a change to MODE 2.

This puzzle will be solved once we look at the start of the main game code to see how this is handled before making the switch into MODE 2.
Instructions page,
courtesy of the RAID2 loader

Finally, the RAID2 loader displays a simple Teletext page of instructions to the player on how to play the game, and then calls the entry point of the newly-relocated machine code:
1900 CALL&3400
(Since the instruction page is displayed by the loader program, once the screen is cleared it won't be available again for display later in the game. Instead, the game reverts to a high score table page when prompting the user to play again).

Next time we'll make a start on trying to disassemble the main game code itself.

Tuesday 25 November 2014

Rocket Raid Under The Hood 2: Disassembly Tools and References

This is the second part in a series of posts on digging into the code of the Acornsoft side-scrolling arcade game, Rocket Raid.

There are a number of tools that we will need in order to dig into the code of Rocket Raid, and some books that will come in handy.

Software Tools


First is a BBC Emulator for running the game and for its debugger/monitor feature which allows memory locations to be updated on the fly. I will be using the excellent BeebEm.

The disassembler BeebDis, by Phil Harvey-Smith, allows game code to be turned back into assembly language instructions for closer examination. Not only that, but the assembly instructions can be modified for reassembly which will be very useful for investigations.

BeebAsm, by Rich Talbot-Watkins, is an assembler which will allow assembly code to be assembled into machine code for running on the emulator. The BeebDis assembler produces code in a format that is compatible for feeding into BeebAsm.

BBC Explorer by Laurie Whiffen. This easy-to-use GUI-based utility allows the contents of a BBC disc to be extracted into individual files, and is compatible with various emulated disc formats.

Reference Material


The Advanced User Guide
One useful reference manual is the BBC Advanced User Guide, which can be downloaded from here. This guide was the companion to the standard User Guide for the BBC, and contains a wealth of information including operating system calls, memory locations and assembly language instructions.










Creative Assembler
 by Jonathan Griffiths
As mentioned in the previous post, Jonathan Griffiths wrote a book called "Creative Assembler - How To Write Arcade Games" which is available online here. Inside are a number of assembly-language routines with comments by the author which will hopefully help shed light on some of the code found in the Rocket Raid game.








And Last But Not Least...

And of course we will need to obtain a disc image of the game itself, which can be found on various websites such as Stairway To Hell.

Monday 24 November 2014

Rocket Raid Under the Hood 1: Introduction

Acornsoft

In the early days of the BBC Micro, the quality of software for the new machine was quite mixed. However one software company in particular, Acornsoft, seemed to be able to consistently produce games of high quality that earned favourable reviews, including a range of games that were clones of, or closely based on, popular arcade games of the time such as Snapper (a clone of Pacman), Planetoids (a clone of Defender) and Rocket Raid (a clone of Scramble).

Rocket Raid

Rocket Raid was written in 1982 by Acornsoft programmer Jonathan Griffiths, who also created the classic Snapper for the BBC & Electron (and, later on, JCB Digger for the BBC).
Rocket Raid - disc version cover

The game will no doubt be familiar to most people who have owned a BBC micro. In the game, you must guide your rocket ship through a hazard-filled landscape (which includes vertically-rising rockets, alien-filled tunnels and an asteroid belt) through to the last level where success if found by bombing the robot waiting at the end.

As soon as you fired up the game the first thing that hit you was the smooth and fast horizontal scrolling which gave it a sense of frantic action. The difficulty level of the game is fairly high and it was likely that a newcomer to the game would find it all over in a matter of seconds. But the gameplay was very addictive and I remember devoting many hours to working out how to weave through the cave in the second level without running into the aliens, and later on trying to navigate the near-impossible vertical rises and drops of the yellow tunnel level. The sprite collision detection did seem to be a little dodgy at times though, with rockets miraculously surviving your barrage of bullets for you to run unceremoniously into them and disappear in a ball of flames.

The game ending was also a slight let-down. After battling through to the very end of the game and managing to successfully drop a well-positioned bomb on the final robot enemy, you would receive a short congratulatory message and find that the game simply started again.

But players in those days were used to brief game endings (or none at all), especially given the limited memory space into which the games had to be squeezed.

Rocket Raid - first level

Coming Up

In this series of blog posts we'll try to disassemble the Rocket Raid code to see how it the game was put together.

Some of the areas of interest include:

  • sprite plotting and movement
  • collision detection
  • hardware scrolling
  • sound
  • text display
  • text input

The game was written in 6502 assembly language and runs in Mode 2, giving use of the full set of 8 colours (plus 8 flashing) at the expense of losing 20K of memory for screen display, leaving only a few kilobytes of memory on an unexpanded Beeb for the game code itself.

One book that will be a very useful reference is one that was written by the author of the game soon after the publication of Rocket Raid, called "Creative Assembler - How To Write Arcade Games" which should give some insight into similar assembler routines used in Rocket Raid. (Despite its name, I found the book itself to be rather dry and fairly hard to digest, at least in terms of a games-writing guide, but for our purposes it is likely that some of the routines mentioned will be similar to those found in Rocket Raid).

In the next post I'll make a quick summary of the tools and books before we roll up our sleeves and start to take the code apart.