Skip to content

A byte becomes pixels

Follow a byte from a labelled memory address through register A to the screen.

  • Sinclair ZX Spectrum
  • Assembly

A border colour uses one value. A picture needs a pattern. We will store eight bits in our program and copy them to the part of memory that controls the screen’s top-left eight pixels.

A bit is a binary digit: 0 or 1. Eight bits make a byte. We can write a byte as a decimal number, but binary makes its individual pixels easier to see.

Predict before you run

The editor below contains the whole program. Find pattern: and the defb line beneath it. defb means define byte: it tells the assembler to put the value in the built program. It does this during assembly, before the program runs. The % introduces binary notation.

That byte is copied to $4000, hexadecimal for 16384. This is the first byte of the Spectrum’s bitmap, the memory holding its pixel patterns. Its eight bits describe the top-left eight pixels inside the border, reading left to right.

A 1 selects ink and a 0 selects paper. Our starting program sets white ink on black paper. Use those rules to make your prediction before running. You are choosing a prediction, not editing the program, when you press the eight pixel buttons.

Which pixels will use ink?

Read the byte after defb. Select the pixels you expect to use ink, from left to right, then save your prediction and run the program.

Each experiment keeps your edits. Revert restores the lesson’s starting program.

Your prediction · 1 means ink, 0 means paper

Choose your pixels before looking at the result.

Source · view and edit
ZX Spectrum

Edit the source, then assemble.

Edits are saved in this browser. Keep a downloaded copy of work you want to keep.

The machine’s result

Run your program to inspect the screen and memory.

Explain this experiment

The leftmost written bit controls the leftmost pixel. In the starting program, 10101010 chooses ink, paper, ink, paper, ink, paper, ink, paper. The attribute makes ink white and paper black.

Work through the three experiments above in order. The same editor carries your changes between them. The magnified strip copies the real screen; the numbers beneath it read the running machine’s memory. Editing source alone changes neither: assemble and run to test each change.

Follow the byte

Now trace the instructions that made your pattern appear:

Source When What happens
pattern: defb %10101010 During assembly Emit the pattern byte in the built program. The label names its address.
ld a,(pattern) During execution Read the byte at that address into register A.
ld ($4000),a During execution Copy A’s value into the first bitmap byte.

For these ld instructions, parentheses mean the contents of a memory location. Compare ld a,71, which takes a value directly from the instruction, with ld a,(pattern), which reads a value from memory. The register is a temporary stop on the journey; the address identifies where a byte lives.

pattern: occupies no bytes of its own. Loading the built program places the pattern byte in memory along with the instruction bytes. There is no defb instruction for the Z80 to execute later: the byte is already there when we start.

The hold loop comes before the data, so normal execution never reaches it as an instruction. We read it through ld a,(pattern) instead. A byte in memory carries no tag saying “picture” or “instruction”. In lesson 1, defb $3E,$02 supplied instruction bytes. Here defb supplies a picture pattern. The same directive can serve either purpose.

The complete starting program
one-byte.asm
; A byte in our program becomes eight pixels at the top left.
; The remaining screen still belongs to the ROM loader.
 org 32768
start:
 ld a,0
 out ($FE),a
 ld a,71
 ld ($5800),a
 ld a,(pattern)
 ld ($4000),a
hold:
 jr hold
pattern:
 defb %10101010
 end start

Why the invisible pattern is still there

In the third experiment, the bitmap keeps its bits while the picture disappears. A 1 chooses ink, but ink does not have to differ from paper.

Colour comes from a separate byte: the attribute for the surrounding 8×8 pixel cell. The first cell’s attribute is at $5800, decimal 22528. ld a,71 and ld ($5800),a originally select bright white ink on black paper.

71 is %01000111: the top bit controls flash (0), the next controls bright (1), the next three select paper (000, black), and the last three select ink (111, white). That is 64 for bright plus 7 for white ink. Changing 71 to 64 keeps bright and selects black for both ink and paper. Changing it to 66 selects bright red ink on black paper.

The attribute colours all eight rows of the cell, even though our program writes only its first bitmap row. The remaining rows contain whatever the ROM left there.

Suppose you write %11110000 to $4000, then write %00001111 to the same address. Do all eight pixels use ink?

Show the explanation

No. The second write replaces the first byte: only the right four pixels use ink. Memory holds the latest value, not layers of earlier pictures. To test it, add ld a,%00001111 and ld ($4000),a immediately after the existing write to $4000, then run. The live bitmap reading should show 00001111.

Keep your experiment

Use Download your source to save your edited program as one-byte.asm. Revert restores the starting program, so save changes you want to keep before using it.

For a local build, use the tools from lesson 1 with the new filename:

Shell
asm198x --dialect pasmo --cpu z80 --tapbas one-byte.asm -o one-byte.tap

Or, with Pasmo:

Shell
pasmo --tapbas one-byte.asm one-byte.tap

Load one-byte.tap into a fresh 48K Spectrum using the same tape-loading procedure. If the border becomes black but the pixels are hard to find, inspect the top-left corner inside it. If the pattern is wrong, check the eight binary digits. If the colours are wrong, check the separate write to $5800.

We now have three distinct things: a byte stored at pattern, a copy in register A, and a copy in screen memory. Next we will choose eight patterns and put them on eight different rows.

Sources

Sinclair Research, ZX Spectrum BASIC Programming, chapter 24, display-file ordering and attribute layout. Zilog, Z80 CPU User Manual, UM008011-0816, instruction entries “LD A, (nn)” and “LD (nn), A”.

Julián Albo, Pasmo documentation, “Directives”, entries “DB” and “DEFB”, for emitting bytes during assembly.

Run it here

This unit's program, built for you.

Program
one-byte.tap
Machine
ZX Spectrum 48K (PAL)

Download one-byte.tap