How I persuaded Lander to run on the ARM Evaluation System
I have long been fascinated by the early history of ARM, and being a big fan of Elite, I'm especially fond of the story of how David Braben developed Lander on the ARM Evaluation System (you can read all about it in my deep dive on Lander's origins on the ARM1).
For this hack I wanted to create an homage to David Braben's original development environment by taking the version of Lander that came with the Archimedes and persuading it to run on the ARM Evaluation System (AES). Here are the results:
This clip shows Lander running in an AES that's attached to a BBC Master via the Tube interface. This is the same interface that the 6502 Second Processor uses, which was used to such great effect by Bell and Braben with their colour version of Elite (see my Elite project for more details on this version).
To get Lander working on the AES, I decided to reuse the same approach as Elite. In this setup, the code running on the ARM side of the Tube is the original Lander, it's just been patched to transmit graphics and keyboard across the Tube rather than talking to VIDC and IOC on an Archimedes. The code running on the 6502 side of the Tube is based on the I/O processor code from the 6502 Second Processor of Elite. So this is not only an ARM/6502 mash-up, it's also a Lander/Elite mash-up, and given that David Braben wrote Lander and co-wrote Elite, it's a very pleasing combination.
The slow speed is mainly down to the bottleneck of sending graphics data over the Tube. I'm guessing that it's somewhere between a half and one-third of the speed of the game running on an ARM2; the AES is clocked more slowly than an Archimedes too, so that's another factor. It's a lot more fluid if you play it in your emulator with the speed ramped up a bit.
As with all my hacks, I have released the source code, fully marked up with the before-and-after changes that I've made to Lander and Elite to get this working. It's in the arm-evaluation-system branch of my Lander repository, where you can find both the AES parasite and I/O processor sources. Search them for "Mod:" to see the code that I've changed.
The Tube API for Lander
-----------------------
For an explanation of how the Tube API works in Elite, see the deep dive on 6502 Second Processor Tube communication in my Elite project. Lander works in exactly the same way and reuses quite a bit of code from Elite, except the Lander API contains a set of commands that are modified to the requirements of Lander.
In the following tables, routines with all-capital names are taken from Elite and modified for use in Lander, while routines in camel case are brand new code for Lander. See the I/O processor source to see how these commands are implemented on the BBC Master side of the Tube.
Here are the OSBYTE commands:
| Offset | Variable | OSWRCH # | Action | I/O routine |
|---|---|---|---|---|
| 0 | - | 128 (&80) | Put back to USOSWRCH | USOSWRCH |
| 1 | - | 129 (&81) | Reserved for VDU code for mode 128+1 | USOSWRCH |
| 2 | #Tube_AddPixels | 130 (&82) | Receive a pixel to draw | ADDBYT |
| 3 | #Tube_BeginPixels | 131 (&83) | Start receiving pixels | BEGINLIN |
| 4 | #Tube_SetScreenBank | 132 (&84) | Set screen bank to main or shadow | SetScreenBank |
| 5 | #Tube_ClearScreen | 133 (&85) | Switch screen bank and clear screen | ClearScreen |
| 6 | #Tube_SetScreenMode | 134 (&86) | Set up the game's screen mode | SetScreenMode |
As with Elite, OSWRCH commands enjoy a degree of parallelism, so when sending batches of pixels to the AES with the BEGINLIN and ADDBYT commands, the last pixel will start the BBC Master drawing those pixels while the Lander code in the AES can continue processing in parallel.
Command 129 is reserved for changing the mode to mode 1 with shadow RAM enabled, which is done by writing ASCII 2 followed by the mode number 129. We reserve 129 for the mode number because otherwise the custom OSWRCH handler would interfere with the mode change.
Here are the OSWORD commands:
| Offset | Variable | OSWORD # | Action | I/O routine |
|---|---|---|---|---|
| 0 | #Tube_ReadKeyboard | 240 (&F0) | Scan the keyboard for game keys | KEYBOARD |
| 1 | #Tube_SendScreenRange | 241 (&F1) | Set max/min screen addresses | SetScreenRange |
| 2 | #Tube_ScanKeyboard | 242 (&F2) | Scan the keyboard for any key | ScanKeyboard |
Calling these commands will block the AES caller until the results are returned, just as with Elite. This works well for the keyboard commands, and it doesn't matter if we block for the Tube_SendScreenRange command as it is only called once for each frame, when switching screen bank (for the latter, using OSWORD is simply more convenient that OSBYTE for sending the four bytes of data in the maximum and minimum screen addresses).
So that's how Lander works on the ARM Evaluation System, by using Elite's co-processor API to process graphics and keyboard on the BBC Master while the ARM1 runs Lander.