Our ship needs to move less than one character at a time. First, move two pixels one place to the right without losing either of them.
This is a fresh project for a 48K PAL ZX Spectrum. We will use registers, memory addresses, calls and branches from Meet Assembly. You do not need BASIC. Each editor contains a complete program; Assemble and run starts a fresh machine without a tape wait. Save your edits before using Revert.
A row that crosses a boundary
The byte %10000001, hexadecimal $81, lights its leftmost and rightmost pixels. Put an empty byte after it and we have sixteen possible pixel positions:
Before: 10000001 00000000
After: 01000000 10000000The rightmost 1 of the first byte must become the leftmost bit of the second. Throw it away and one of our pixels vanishes every time it crosses a byte boundary.
Run the program. Most of the screen will stay black: these two rows are tiny. The magnified view reads the actual screen bytes. Its first row is the original pair; its second is the shifted pair.
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.
Run the program to inspect it. Editing source does not change the running machine.
Run to read the bytes.
Follow the carry
The program sets A to $81 and B to zero. srl a shifts A right, puts zero into its leftmost bit, and puts the bit that fell off the right into the carry flag. Carry is one bit in the flags register; here it remembers the displaced pixel.
rr b rotates B right through carry. The previous carry enters B’s leftmost bit. B’s former rightmost bit becomes the new carry. After these two instructions A is $40 and B is $80.
ld a,%10000001
ld ($480C),a
; Shift right once, carrying the lost bit into the next byte.
; RR starts with the carry from SRL: $81,0 becomes $40,$80.
ld a,%10000001
ld b,0
srl a
rr b
ld ($490C),a
ld a,b
ld ($490D),aThe writes to $480C, $490C and $490D choose two neighbouring bytes on neighbouring pixel rows. We will derive those addresses shortly. ld (address),a copies the value; it does not move the value out of A.
Change one thing
Replace both occurrences of %10000001 with %11111111. Predict both rows, then assemble again.
After changing both patterns to %11111111, what should the original and shifted rows contain?
Show the explanation
The original pair is $FF,$00. The shifted pair is $7F,$80: seven set bits remain in the first byte and the eighth enters the second.
What would happen if we replaced rr b with srl b?
Show the explanation
B would stay zero. SRL inserts zero at the left instead of accepting the carry from A. The pixel that left A would not appear anywhere. Try that single instruction change, then Revert to recover both the original pattern and instruction.
clear prepares black bitmap memory and white ink. It uses LDIR: copy the byte at HL to DE, advance both pointers, decrement BC and repeat until BC is zero. The source and destination are one byte apart, so the first value propagates through the range. Bitmap and attribute memory are cleared separately. The hold loop keeps execution away from the following helper code.
Use Download source for meteor-storm.asm. For local work, Asm198x is the primary tool; upstream Pasmo accepts the same source:
asm198x --dialect pasmo --cpu z80 --tapbas meteor-storm.asm -o meteor-storm.tap
# Or:
pasmo --tapbas meteor-storm.asm meteor-storm.tapTo run the tape on the desktop, use Emu198x, the recommended emulator; getting started covers downloading it and the 48K ROM it needs. From its folder:
./emu198x-spectrum --rom "path/to/48.rom" --tape meteor-storm.tap --autoload-tapeReassembling reloads the whole experiment. Use the magnified bitmap reading to inspect the two rows.
Sources
Sinclair Research, ZX Spectrum BASIC Programming, chapter 24, display-file and attribute layout. Zilog, Z80 CPU User Manual, UM008011-0816, instruction descriptions for shifts, logical operations and loads.
Run it here
This unit's program, built for you.
- Program
- meteor-storm.tap
- Machine
- ZX Spectrum 48K (PAL)