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.
Source · view and edit
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.
Top-left eight pixels, magnified · copied from the Spectrum screen
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
; 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 startWhy 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:
asm198x --dialect pasmo --cpu z80 --tapbas one-byte.asm -o one-byte.tapOr, with Pasmo:
pasmo --tapbas one-byte.asm one-byte.tapLoad 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)