Skip to navigation

Revs on the BBC Micro

The Revs memory map

Memory usage is really tight in BBC Micro Revs

Revs is an extremely sophisticated piece of programming, so it's no surprise that it leaves very little spare memory when loaded into a standard BBC Micro. The complex loading system unfolds the game code into every nook and cranny, leaving hardly any room for anything else; the game manages to squeeze working game code into screen memory, hiding it right in the middle of the blue sky; and even the game text is tokenised to save precious memory.

Indeed, when author Geoff Crammond added a new feature, computer assisted steering (CAS), to the 1986 Superior Software release of Revs, he could only fit in the additional code by repurposing the memory used by the SetupGame routine, which is only run once and isn't needed again once the game has started. The Superior version reuses this memory to store the drivers' accumulated points, overwriting the setup code once it has served its purpose.

To say that Revs is a tight squeeze is a bit of an understatement. Let's take a deeper look at just how tight things are.

The Revs memory map

When the cassette version of Revs is loaded, this is what the memory map of the BBC Micro Model B looks like. On the left is the memory map of the game running in the custom screen mode, during the driving part of the game, while the right side shows the game running in mode 7, when displaying the various game menus and leaderboards. The game starts in the mode 7 configuration, and switches to the left configuration when heading to the track.

  +-----------------------------------+   &FFFF
  |                                   |
  | Machine Operating System (MOS)    |
  |                                   |
  +-----------------------------------+   &C000
  |                                   |
  | Paged ROMs                        |
  |                                   |                             Mode 7
  +-----------------------------------+-- &8000 --------------------------+
  |                                   |                                   |
  |                                   |                     Screen memory |
  |                                   |                                   |
  | Game code (dash data 0-25)        +-- &7C00 --------------------------+
  |                                   |                                   |
  |                                   |                                   |
  |                                   |                                   |
  +---------- &7B00 = UpdateMirrors --+                &7768-&7BFF unused |
  |                                   |                                   |
  | Screen memory (dash data 25-40)   |                                   |
  |                                   |                                   |
  +-----------------------------------+-- &7768 --------------------------+
  |                                   |                                   |
  | Screen memory (dash data 41-42)   |                   Dash data 41-42 |
  |                                   |                                   |
  +-----------------------------------+-- &6C00 --------------------------+
  |                                   |                                   |
  | Screen memory (track & horizon)   |                &6700-&6BFF unused |
  |                                   |                                   |
  +-----------------------------------+-- &6700 --------------------------+
  |                                   |                                   |
  | Screen memory (game code in sky)  |                         Game code |
  |                                   |                                   |
  +-----------------------------------+-- &5E40 = xVergeRightLo ----------+
  |                                   |                                   |
  | Screen memory (race info text)    |                &5A80-&5E3F unused |
  |                                   |                                   |
  +-----------------------------------+-- &5A80 --------------------------+
  |                                   |                                   |
  | Main game code & screen buffer    |   Main game code & dash data 0-40 |
  |                                   |                                   |
  +-----------------------------------+-- &0B00 --------------------------+
  |                                   |
  | Main variable workspace 2         |
  |                                   |
  +-----------------------------------+   &0880
  |                                   |
  | MOS sound workspace               |
  |                                   |
  +-----------------------------------+   &0800
  |                                   |
  | Main variable workspace 1         |
  |                                   |
  +-----------------------------------+   &0380 = objYawAngleLo
  |                                   |
  | MOS VDU workspace                 |
  |                                   |
  +-----------------------------------+   &0300
  |                                   |
  | MOS general workspace             |
  |                                   |
  +-----------------------------------+   &0200
  |                                   |
  | 6502 stack descends from &01FF    |
  |                                   |
  |                                   |
  .                                   .
  .                                   .
  .                                   .
  .                                   .
  .                                   .
  |                                   |
  +-----------------------------------+   &01B8
  |                                   |
  | Stack variables workspace         |
  |                                   |
  +-----------------------------------+   &0100 = positionNumber
  |                                   |
  | Zero page workspace               |
  |                                   |
  +-----------------------------------+   &0000 = carMoving

The left configuration shows dash data blocks #0 to #40 after they are moved out of the main game code by the CopyDashData routine, leaving space in the main game code for the screen buffer. The right configuration shows the dash data after it's been put back into the main game code, with only blocks #41 and #42 left in memory, where they remain untouched, ready for the next switch to the custom mode. For a detailed look at the dash data and the complex moving process, see the deep dive on the jigsaw puzzle binary.

Another item of note is the game code between &5E40 and &6700, which is used in both modes, but which is hidden in the custom screen's blue sky during races. For more information on the custom screen mode, see the deep dive on hidden secrets of the custom screen mode.

Note that the memory map shows the full 64K of addressable memory that's supported by the BBC's 6502 processor, but only the bottom 32K is writable RAM, and hence usable by Revs. The top 16K is mapped to the MOS (Machine Operating System) ROM, and the next 16K is mapped to the currently selected paged ROM, which might be anything from BBC BASIC to the VIEW word processor.

This 32K of RAM includes both screen memory and the various operating system workspaces, which can leave a pretty small amount for programs (especially in high resolution screen modes). Let's take a look at exactly how much unused memory there is in Revs.

Memory usage

Here's a full breakdown of memory usage in bytes, once the Acornsoft version of Revs is loaded and we have started driving:

                                                               Used     Unused

  Machine operating system (MOS) ROM                         16,384          -
  Paged ROMs                                                 16,384          -
  MOS general workspace in page 2                               256          -
  MOS VDU workspace in page 3                                   128          -
  MOS sound workspace in page 8                                 128          -
  MOS zero page locations, &D0-&E1 and &E4-&FF inclusive         46          -
                                                             ------     ------
                              Total MOS and ROM memory       33,326          -

  Memory for the custom screen mode                           8,320          -
  6502 stack, stack variables (at opposite ends of page 1)      256          -
                                                             ------     ------
                              Total shared memory             8,576          -

  Main game code & screen buffer (in the dash data blocks)   20,352        279
  Game code above screen memory (from UpdateMirrors and up)   1,280          1
  Main variable workspace 1 (various tables, config)          1,152         52
  Main variable workspace 2 (various tables, coordinates)       640         30
  Zero page workspace (commonly used variables)                 210         66
                                                             ------     ------
                              Total game code memory         23,634        428

                              Total memory                   65,536

As you can see, Revs does not use every single last byte of the BBC Micro's usable memory - there are 428 unused bytes. Let's look at these in more detail.

Counting the free space

Even when Revs is using its custom screen mode, the game contains a few unused blocks of memory, though most of these are in small blocks of one or two bytes, often spacing out variables so they start on page-aligned or easily calculated addresses. For example, a number of the dash data blocks have unused bytes sandwiched between the preceding game code and the start of the dash data; some of these unused blocks are large enough that they could be used for game code or variables, though extending Revs in any meaningful way using these blocks would still be tricky.

I've managed to track down 428 unused bytes in the original Acornsoft version, once the game is fully loaded and we're driving around the track (there is a lot more unused memory when we're in the mode 7 game menus, but that doesn't count). For comparison, Elite only has 66 spare bytes, which sounds like a big difference, but Elite needs to use the filing system when running and Revs doesn't, so Elite's memory constraints are slightly higher (though conversely, that's why Revs could use zero page locations &90-&CF, which it doesn't). Whatever the difference, both games are impressively compact.

Here's a summary of all the unused bytes I know about.

Location(s)Unused bytesSection
Zero page: &90-&CF and &E2-&E366Zero page workspace
After objectSize32Main variable workspace 1
After configAssist5Main variable workspace 1
After volumeLevel1Main variable workspace 1
After lapTenths2Main variable workspace 1
After lapSeconds2Main variable workspace 1
After lapMinutes2Main variable workspace 1
After segmentFlags8Main variable workspace 1
After totalRaceSeconds16Main variable workspace 2
After zSegmentCoordOLo4Main variable workspace 2
After zHelmetCoordLo3Main variable workspace 2
After zSegmentCoordOHi4Main variable workspace 2
After zHelmetCoordHi3Main variable workspace 2
Before soundData16Main game code
After GetObjectDistance15Main game code
After DrawSegmentEdge (part 7)10Main game code
After vergeScale2Main game code
After handPixels6Main game code
After staDrawByte26Main game code
After DrawFence (part 2)1Main game code
After token181Main game code
After CheckRestartKeys2Main game code
After pixelsToLeft7Main game code
After token115Main game code
After token254Main game code
After token514Main game code
After token34Main game code
After token04Main game code
After token1713Main game code
After token355Main game code
After token452Main game code
After Print2DigitBCD1Main game code
After token391Main game code
After token493Main game code
After dashDataOffset3Main game code
After token302Main game code
After token532Main game code
After token383Main game code
After mirrorSegment2Main game code
After token244Main game code
After token159Main game code
After token3412Main game code
After token214Main game code
After timeFromOption1Main game code
After pointsForPlace2Main game code
After token94Main game code
After token124Main game code
After token374Main game code
After fillDataOffset7Main game code
After token75Main game code
After dashData3116Main game code
After yLookupLo7Main game code
After driverNames13Main game code
After ResetBestLapTime1Main game code
After endMirror3Main game code
After driverNames24Main game code
After PrintHeader5Main game code
After token118Main game code
After token406Main game code
After token522Main game code
After FlushSoundBuffers1Main game code
After sectionSteering6Main game code
After vergePixelMask2Main game code
After zRoadSignCoordHi3Main game code
After yCursor2Main game code
After DrawCarInMirror1Game code above screen memory

Most of these blocks are tiny, but it would be feasible to add code or data into the larger blocks and connect the code with jumps and branches. Adding up the unused blocks with double-figure sizes gives 118 bytes, which has potential, if nothing else.

But it's certainly fair to say that Revs does an impressive job of squeezing itself into the standard BBC Micro, using pretty much everything the 32K micro has to offer. Looking at the finished game, you wouldn't expect anything less.