Skip to navigation

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 4         |
  |                                   |
  +-----------------------------------+   &08D0 = objectSegmentLo
  |                                   |
  | MOS sound envelope 1 buffer       |
  |                                   |
  +-----------------------------------+   &08C0
  |                                   |
  | Main variable workspace 3         |
  |                                   |
  +-----------------------------------+   &0880 = objSectionSegmt
  |                                   |
  | MOS sound workspace and buffer    |
  |                                   |
  +-----------------------------------+   &0800
  |                                   |
  | Main variable workspace 2         |
  |                                   |
  +-----------------------------------+   &0400 = leftSegment
  |                                   |
  | MOS keyboard buffer               |
  |                                   |
  +-----------------------------------+   &03E0
  |                                   |
  | 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. The figures show the number of available bytes in each section and how many of those are unused:

Memory contents (ROMs)Address rangeBytesUnused
Paged ROMs&8000 to &BFFF16,384-
Machine operating system (MOS) ROM&C000 to &FFFF16,384-
Total ROM memory 32,768-
Memory contents (MOS workspace)Address rangeBytesUnused
MOS zero page filing system workspace&00B0 to &00CF3232
MOS zero page VDU workspace&00D0 to &00E118-
MOS zero page tape filing system workspace&00E2 to &00E322
MOS zero page general workspace&00E4 to &00FF28-
MOS general workspace&0200 to &02FF256-
MOS VDU workspace&0300 to &037F128-
MOS keyboard buffer&03E0 to &03FF32-
MOS sound workspace and buffer&0800 to &087F128-
MOS sound envelope 1 buffer&08C0 to &08CF16-
Total MOS workspace memory 64034
Memory contents (shared memory)Address rangeBytesUnused
6502 stack&01B8 to &01FF72-
Memory for the custom screen mode&5A80 to &7AFF8,320-
Total shared memory 8,392-
Memory contents (game code)Address rangeBytesUnused
Zero page workspace&0000 to &00AF17632
Stack variables&0100 to &01B7184-
Main variable workspace 1&0380 to &03DF96-
Main variable workspace 2&0400 to &07FF1,02428
Main variable workspace 3&0880 to &08BF64-
Main variable workspace 4&08D0 to &0AFF56014
Main game code & screen buffer&0B00 to &5A7F20,352279
Game code above screen memory&7B00 to &7FFF1,2801
Total game code memory 23,736354
Summary BytesUnused
Total ROM memory 32,768-
Total MOS workspace memory 64034
Total shared memory 8,392-
Total game code memory 23,736354
Totals 65,536388

As you can see, Revs does not use every single last byte of the BBC Micro's usable memory - there are 388 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 388 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 144 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 configAssist5Main variable workspace 2
After volumeLevel1Main variable workspace 2
After lapTenths2Main variable workspace 2
After lapSeconds2Main variable workspace 2
After lapMinutes2Main variable workspace 2
After segmentFlags8Main variable workspace 2
After lineBufferAddrHi8Main variable workspace 2
After zSegmentCoordOLo4Main variable workspace 4
After zHelmetCoordLo3Main variable workspace 4
After zSegmentCoordOHi4Main variable workspace 4
After zHelmetCoordHi3Main variable workspace 4
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 190 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.

Revs code as an image
---------------------

To see just how small the game code for Revs is, we can convert the main game binary into an image, with one byte per pixel, and a greyscale showing each byte's value, with 0 being shown as black, 255 being shown as white, and interim values as greyscale pixels. The result is a 185-pixel square, like this (shown here at double size, so you can see the pixels more clearly):

The game binary for BBC Micro Revs as an image

This image contains the entire game, including the track data for Silverstone and the four extra tracks from the Revs 4 Tracks expansion pack. That's some nice, bloat-free code!