🔬Pixel, Bytes und Adressen
Bevor ein Sprite gezeichnet werden kann, muss man wissen, wie der CPC ein Bild im Speicher ablegt. Zwei Eigenheiten prägen jede Sprite-Routine: die verschachtelten Bits der Pixel und die verschachtelten Zeilen des Bildschirms.
🧮Ein Byte, mehrere Pixel
Das Gate Array liest jedes Byte und macht daraus 2, 4 oder 8 Pixel – je nach Modus. Die Bits eines Pixels stehen dabei nicht nebeneinander (SOFT 968, Abschnitt 6.4): in Modus 0 gehören zum linken Pixel die Bits 1, 5, 3, 7, zum rechten die Bits 0, 4, 2, 6 (jeweils höchstwertiges Bit der Tintennummer zuerst).
Klicken Sie ein Pixel an (Umschalt-Klick: mit Tinte 0 übermalen). Jedes Kästchen ist ein Modus-0-Pixel – so breit wie 4 Modus-2-Punkte.
Pixel x = 3, y = 4→ Byte 1 der Zeile, Pixel 1 darinWert &48 = %01001000
Bits klicken schaltet sie um – die Pixel ändern sich mit. Tx = Stelle x der Tintennummer (T3 = höchstwertig).
Pixel 1: Bits 0, 4, 2, 6 (MSB zuerst)Modus 0: die 4 Bits eines Pixels liegen verschachtelt – nicht als Halbbyte!encode([2,1]) = &48
Wo liegt dieses Byte im Bildschirmspeicher? (Sprite ab Byte 10, Zeile 50)
Zeile y = 50 + 4 = 54, Byte = 10 + 1 = 11 &C000 + (y MOD 8)·&800 + (y DIV 8)·80 + Byte &C000 + 6·&800 + 6·80 + 11 &C000 + &3000 + &01E0 + &000B = &F1EB
🗺️Wo liegt Zeile y?
Die Adresse von Byte x in Pixelzeile y ist
&C000 + (y MOD 8)·&800 + (y DIV 8)·80 + x. Zeile 0 beginnt bei &C000, Zeile 1 aber erst bei &C800 und Zeile 8 bei &C050.Zeile 4&E00AStart
Zeile 5&E80A+&800
Zeile 6&F00A+&800
Zeile 7&F80A+&800
Zeile 8&C05A+&800 läuft über → &C050-Korrektur
Zeile 9&C85A+&800
Zeile 10&D05A+&800
Zeile 11&D85A+&800
Zeile 12&E05A+&800
Zeile 13&E85A+&800
Zeile 14&F05A+&800
Zeile 15&F85A+&800
Zeile 16&C0AA+&800 läuft über → &C050-Korrektur
Zeile 17&C8AA+&800
Zeile 18&D0AA+&800
Zeile 19&D8AA+&800
Der Bildschirm (&C000–&FFFF) besteht aus 8 Blöcken à 2 KB. Block k enthält alle Pixelzeilen mit y MOD 8 = k – jeweils 25 Zeilen à 80 Bytes = 2000 Bytes, die restlichen 48 Bytes je Block sind unsichtbar. Die farbigen Striche sind die 16 Zeilen des Sprites.
Deshalb liegt „eine Zeile tiefer“ nicht 80 Bytes weiter, sondern &800 = 2048 Bytes weiter – und nach jeder 8. Zeile springt die Adresse zurück in Block 0, 80 Bytes weiter.
⬇️„Nächste Zeile“ Schritt für Schritt
Jede Sprite-Routine muss nach einer Zeile in die nächste springen. Statt die Formel jedes Mal auszurechnen, addiert man &800 und korrigiert nur, wenn man dabei aus dem 16-KB-Bereich herausläuft.
1LD A,H
2ADD A,8
3LD H,A
4AND &38
5RET NZbzw. JR NZ in einer Schleife
6LD A,L
7ADD A,&50
8LD L,A
9LD A,H
10ADC A,&C0
11LD H,A
Schritt 1 / 11 · Tasten ← →
Start HL
&F80C
HL jetzt
&F80C
A
&F8
Carry
0
▶ LD A,H – High-Byte der Adresse holen
; nächste Pixelzeile: HL → HL + &800, bei Überlauf −&4000 + &50
next_line:
ld a,h
add a,8 ; +&800 (8 im High-Byte)
ld h,a
and &38 ; Bits 3–5: Zeile MOD 8 – bei 0 sind wir übergelaufen
ret nz ; häufiger Fall: fertig
ld a,l
add a,&50 ; +80 = eine Zeichenzeile weiter
ld l,a
ld a,h
adc a,&c0 ; −&40 im High-Byte (+&C0 mod 256), Übertrag von L
ld h,a
retDie Firmware bietet dieselbe Aufgabe als SCR NEXT LINE (&BC26) an – als Aufruf über die Sprungleiste, also langsamer als diese eingebauten Befehle. Die Routine funktioniert für jeden 16-KB-Bildschirm (&4000 oder &C000) – ein Test in
tests/sprite.test.ts prüft alle 199 Übergänge.💡 Warum ist der CPC so aufgebaut?
Der CRTC 6845 zählt Zeichenzeilen (0–24) und Rasterzeilen innerhalb einer Zeichenzeile (0–7). Das Gate Array bildet die Adresse so, dass die Rasterzeile die Bits 11–13 der Adresse bestimmt – daher der Abstand &800 von Rasterzeile zu Rasterzeile. Für Text ist das bequem (ein Zeichen = 8 Bytes im Abstand &800), für Sprites bedeutet es die Rechnung oben.