48K Spectrum

The memory map on a 48K Spectrum is fairly straightforward.

The Z80 processor can address 64KB of RAM; the 48K Spectrum uses all of this address space without paging.

The first 16K is ROM; the rest of the memory map is RAM.

Reserving memory

There are two ways to run machine code on the Spectrum. You can reserve memory for your code and preserve all the system memory areas. That way you can drop back into BASIC after the machine code has completed. Or, you can use all the memory from &5B00 to &FFFF but the only way back to BASIC is with a reset or switching the Spectrum off and on. Games programmers tended to go for the latter option as it gave them the most available RAM.

If you do wish to reserve memory, then issue the command CLEAR n, where n is the last byte you wish to be available to BASIC. So, if you want your machine code to sit at address &8000 in the memory map, then issue the command

CLEAR 32767

We want the last byte of memory available to basic to be just before our code, so (&8000 – 1) is 32767 in decimal. Assemble and load your code into address 32768 and run.

NB:

  • The machine code will survive a NEW command, but won’t survive power off
  • It will proportionally reduce the amount of memory available to your BASIC code
  • Yet it is protected from BASIC programs overwriting the machine code

Saving and Loading memory blocks

Back in the day, before emulators, you would have to ensure that your code could load into memory, preserving system variables, so that the BASIC game preloader could execute the RANDOMIZE USR command to execute the machine code.

A simple preloader would be a couple of lines of BASIC like this

10 CLEAR 32767
20 LOAD "gamecode" CODE 32768
30 RANDOMIZE USR 32768

Where the LOAD CODE parameter is the address to load the code in memory.

This would be saved, to autorun from line 10, by the command

SAVE "gamename" LINE 10

And the machine code would be saved with a command like this

SAVE "gamecode" CODE 32768,9182

Where the first parameter is the address of the code in memory, and the second the number of bytes to save.

This small BASIC preloader would then autorun, load the file gamecode (which would have been saved on the cassette straight after the preloader) and then execute the machine code with the RANDOMIZE USR command; assuming that the entry point in the machine code was 32768.

NB:

  • As a general rule of thumb, machine code is not relocatable (there are the odd exceptions). So if the code is saved from a certain address, say 32768, then it must be loaded back in and executed from the same address.

A whole chapter of history was written about the subject of piracy. There were various attempts to obfuscate the loader code to prevent this. Nearly all anti piracy measures failed the twin tape deck test and those that did succeed just annoyed the users.

Spectrum 128K Toastrack / +2

The 128K Spectrums employ paging to map the extra memory into the 64K Z80 address space.

The memory is paged by writing to port &7FFD.

  • RAM – The RAM bank to page into &C000 to &FFFF
  • SCR – Set to 0 to display normal screen, 1 to display screen in bank 7
  • ROM – Set to 0 to page in the 128K editor, or 1 to page in the 48K BASIC ROM
  • DIS – Set to 1 to disable memory paging until next reset

NB:

  • The port is write-only – reading it will just return a floating bus value. This may crash the machine due to a bug in earlier GALs.
  • Setting the screen page determines the area of memory the ULA is looking at to render the screen – it does not page Bank 7 into &4000 to &7FFF.
  • Selecting 48K Spectrum from the startup menu, or using the BASIC command ‘SPECTRUM’ from 128K mode, sets the DIS bit to prevent the extra memory from being accessed. You can however boot into 48K BASIC by typing in ‘RANDOMIZE USR 0’ from 128K BASIC without setting this bit.

Spectrum +2A/+3

The Spectrum motherboard underwent a revision under Amstrad for the +3 to add extra ROM storage for the disk operating system and enhanced RAM paging modes for CP/M. This revised motherboard was rolled back into the cassette version, the black Spectrum +2A.

There is an extra port to control this functionality at &1FFD

  • PRTS – Printer Strobe controls the printer port
  • DSKM – Disk Motor controls the disk drive motor

Bit 0 controls the paging mode. If it is 0 then it is in 128K/+2 compatibility mode, with one difference – bit 4 of port &7FFD is combined with bit 2 of port &1FFD to select between the four ROM images:

If bit 0 of &1FFD is 1, then enhanced paging mode is enabled, with bits 1 and 2 (MEMMODE) selecting between one of four memory map layouts.

These modes are primarly used for CP/M compatibility, that specifies RAM in the first page (256 bytes) of memory which is normally occupied by ROM.

Reserved Banks

On the Spectrum +2A/+3 the following memory blocks are reserved by BASIC / +3DOS:

  • Banks 1, 3, 4, 6: RAM disk and cache
  • Bank 7: Workspace for +3DOS and the editor

Contended Screen Ram

On all Spectrums, the block of RAM between &4000 and &7FFF is contented, that is access to the RAM is shared between the processor and the ULA. The ULA has priority access when the screen is being drawn.

In addition, on 128K variants, some of the banked memory is contended:

  • On 128K/+2 Spectrums, odd-numbered banks (1, 3, 5 and 7)
  • On +2A/+3 Spectrums, banks 4 to 7

This is another GAL bug, the behaviour on later Spectrum 128Ks should have been the same as earlier models.

Code that runs in or accesses contended memory will run slightly slower. For that reason it is recommended that speed critical routines (sprites, scrolling, etc) are not executed in this area of RAM.

Thank you to Brendan Alford for providing additional information on contented memory.