13

What format is the (Timex) Sinclair ZX Spectrum SCREEN$/.SCR file and how is the fore/background and attribute data encoded within this format?

3 Answers 3

25

For a standard screen, compatible with ZX Spectrum, a SCREEN$ file is 6912 bytes. It's just a dump of the screen memory.

The first 6144 bytes store the screen bitmap: 256x192 pixels, 1 bit per pixel (on or off). The layout is not linear.

  • The screen bitmap is divided horizontally into three thirds: each one is 2048 bytes and store 8 text rows of 32 column each one (each character cell has 8 scans of 8 pixels each one).
  • For each third, the first scan of each character cell is stored, left to right, top to bottom. Then, the second scan, then the third, until the last one, the eighth. After this, a new third is stored in the same fashion.
  • Each byte stored has 8 pixels: the MSb belongs to the leftmost pixel as shown on the screen.

Following the bitmap region, the remaining 768 bytes store the attributes. There is 1 byte of attribute for each character cell. Stored left to right, top to bottom. Bits 2-0 store the foreground colour, or "ink" colour (colour assigned to "on" pixels). Bits 5-3 store the background colour or "paper" colour (colour assigned to "off" pixels). Bit 6 is bright. If set, both paper and ink colours are lighter. Bit 7 is flash. If set, the paper and ink colour swap every 640 ms to give a kind of flashing character.

To have a clue of how bitmap and attribute are stored, you can type this little BASIC program that will shows you the arrangement of pixels on the screen, by dumping part of the ROM to the screen (which will show up as random pixels and colours):

10 FOR n=0 TO 6911: POKE 16384+n,PEEK n: NEXT n

A similar program gives this result:

enter image description here

For each paper or ink colour, the arrangement of the three bits encode a RGB value in this order: G R B. So, colour 6 (binary 110) is green + red = yellow. The complete table is this: 0: black, 1: blue, 2: red, 3:magenta, 4: green, 5:cyan, 6:yellow, 7: white

With bright set, all these colours except black are intensified. This gives a total of 15 different colours.

The Timex 2048/2068 computers add two more screen modes, called HiColour and HiRes.

HiColour mode is entered by setting bit 1 of port $FF. It differs a little from the standard mode, explained above. HiColour mode uses an attribute region which is not 768 bytes, but 6144 bytes in size, the same as the bitmap region. The attribute region does not start following the bitmap region, but there is a gap of 1280 bytes between the end of the bitmap and the start of the attribute region. The total screen size is 12288 bytes, not including this gap.

The layout of this attribute region is the same as the bitmap region (3 thirds, the first scan is stored, then the second, etc). There is now 1 byte of attribute for each scan of 8 pixels. The format of the attribute byte is the same as in the standard mode.

On tape, some programs use two different blocks to load the bitmap region, then the attribute region (as they are not contiguous). Some others use a single block containing both regions along with 1280 byte gap between them.

The following program will show you the arrangement in this mode. It won't work on a regular Sinclair Spectrum, but in a Timex TC2048/2068.

10 OUT 255,2: FOR n=0 TO 6143: POKE 16384+n,PEEK n:POKE 24576+n,PEEK n: NEXT n

HiRes is entered by setting bit 3 of port $FF. This mode shows a screen of 512x192 pixels, using two different bitmap regions. One region is the same as in the standard and HiColour mode, and the second one is located in the same place as the attribute region of the HiColour mode.

For each scan of 16 pixels, the left most 8 pixels are stored in the first bitmap region, and the rightmost 8 pixels are stored in the second bitmap region.

Each bitmap region is arranged the same way as the other screen modes.

The foreground, background and border colour is set separately on bits 5-3 of port $FF. These three bits store the ink colour which will be applied to all "on" pixels. The 1-complement of this value will be used for both paper and border colours. In HiRes mode, the bright bit is always set and there is no flash.

The following program will show you how the HiRes mode is arranged:

10 OUT 255,4: FOR n=0 TO 6143: POKE 16384+n,PEEK n:POKE 24576+n,PEEK n: NEXT n

On tape, HiRes SCREEN$ are stored the same way as HiColour SCREEN$. I haven't seen that the global ink colour is stored too, so a separate BASIC program must provide it, along with the mode change command.

6
  • It's the animated GIF that sealed the deal. (Serve's me right for trying to explain it textually.) :-) Apr 22, 2016 at 11:46
  • 1
    Thanks! They are a good tool for things like this, aren't they? :D Apr 22, 2016 at 12:34
  • (I wrote some comments here, but decided there was too much info for comments so have moved them to an answer)
    – Jules
    Jun 7, 2016 at 8:25
  • I think the wrong impression is given by saying "screen bitmap is divided horizontally into three thirds". Might be better to say "... divided from top to bottom..."
    – intrepidis
    Feb 28, 2022 at 10:13
  • Both of these BASIC examples crash the machine on the Mame emulator, which seems to work great for Speccy stuff and I think well enough otherwise too. I don't have a second emulator that can do TS2068 for me to compare. Sep 16, 2022 at 20:21
11

A couple of things seem a little odd about the way the Spectrum display memory was arranged until you understand why it was done the way it was. The first thing is the odd division into three blocks -- this was done so that if you have a pointer to a scan line of a character block stored in a register pair (e.g. HL) you can just increment the high order byte (e.g. with an inc h instruction) to get a pointer to the next scan line of the same character block. In order for this to work, there must be exactly 256 character blocks between successive scan lines so the bitmap must be divided into groups of 256/32 = 8 rows. This simplifies (and accelerates) the code for printing a character substantially.

The other odd thing is something that I've seen commented on less frequently, and this is the unusual order of the colour components in the attributes. AFAICT the reason for this is that the designers wanted a system that would produce reasonable grayscale output if hooked up to a black & white TV. They therefore designed it so that each colour component was also associated with a brightness level, which were picked according to the human eye's sensitive for the colours, i.e. green brightest, then red, then blue. Then, by putting the brightest in the most significant bit and the darkest in the least, they could have the colours appear in numeric order of brightness when viewed on a black and white output.

8

The SCR file format is effectively a raw data dump of the video memory area on the standard ZX Spectrum 48/128k.

As such, the data is divided into three 2,048 byte sections, each of which describes the pixel data for a third of the screen, from top to bottom. This is then followed by 768 bytes of attribute data information - resulting in a total of 6,912 bytes.

Background

For those unfamiliar with the Spectrum's video architecture, on the standard Spectrums, the 256x192 display is treated as 768 8x8 pixel blocks, with each block being capable of displaying two colours. (i.e.: Each block is effectively a bitmap and associated ink and background colour combination.) By using this approach, it's possible to display the fill 256x192 resolution of screen using only 6,912 bytes.

Additionally, the Spectrum palette consists of both normal and "bright" colours, with each block capable of being set as bright. (i.e.: You can't mix normal and bright colours within a single 8x8 pixel block.) The blocks can also be set to flash, but perhaps the less said about that the better.

In more detail:

Screen thirds

Each of the screen thirds describes a slice of the screen - the first third being horizontal lines 0 thru 63, the second being 64 thru 127 and finally 128 thru 192, hence describing the 192 horizontal lines of the Spectrum's 256x192 display.

However, rather than simply describe each row in a linear fashion (i.e.: 0 thru 63, then 64 thru 127, etc.), due to the nature of the Spectrum, the data within each third instead describes a full horizontal line across each of the 8x8 blocks in turn (i.e: horizontal line 0, 8, 16, etc.) before moving onto the next line in the row of blocks (i.e.: line 1, 9, etc.)

This will make way more sense if you've ever seen a ZX Spectrum loading screen data.

In more detail, each of the 64 lines within each third is structured into a series of 32 byte blocks as follows, each block being a line of screen data.

  0 ..  31 - 256 bits of data for horizontal line 0
 32 ..  63 - 256 bits of data for horizontal line 8
 64 ..  95 - 256 bits of data for horizontal line 16
 96 .. 127 - 256 bits of data for horizontal line 24
128 .. 159 - 256 bits of data for horizontal line 32
160 .. 191 - 256 bits of data for horizontal line 40
192 .. 223 - 256 bits of data for horizontal line 48
224 .. 255 - 256 bits of data for horizontal line 56

This is then followed by...

  0 ..  31 - 256 bits of data for horizontal line 1
 32 ..  63 - 256 bits of data for horizontal line 9
 64 ..  95 - 256 bits of data for horizontal line 17
 96 .. 127 - 256 bits of data for horizontal line 25
128 .. 159 - 256 bits of data for horizontal line 33
160 .. 191 - 256 bits of data for horizontal line 41
192 .. 223 - 256 bits of data for horizontal line 49
224 .. 255 - 256 bits of data for horizontal line 57

...

Attribute data

Once each of the thirds has been completed, this is followed by the attribute data, which is simply another array of bytes detailing the ink and paper colours as well as whether or not bright or flash is set.

Each of these bytes is constructed as follows:

0,1,2 - Ink colour
3,4,5 - Paper colour 
6 - Whether or not the colours are bright or standard
7 - Whether or not the block should flash

For more information see Claus Jahn's ZX Spectrum page

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .