🧩Z80-Architektur

Der Zilog Z80 (1976) ist das Herz des CPC: ein 8-Bit-Prozessor mit 16-Bit-Adressbus (64 KB), 4 MHz Takt im CPC, einem doppelten Registersatz und über 700 dokumentierten Befehlsformen.

🗃️Die Register

        Hauptregistersatz              Schattenregister (EX AF,AF' / EXX)
      ┌─────────┬─────────┐           ┌─────────┬─────────┐
 AF   │    A    │    F    │     AF'   │   A'    │   F'    │   A = Akkumulator, F = Flags
      ├─────────┼─────────┤           ├─────────┼─────────┤
 BC   │    B    │    C    │     BC'   │   B'    │   C'    │   B oft Zähler (DJNZ), BC Port/Länge
      ├─────────┼─────────┤           ├─────────┼─────────┤
 DE   │    D    │    E    │     DE'   │   D'    │   E'    │   DE Ziel (LDIR)
      ├─────────┼─────────┤           ├─────────┼─────────┤
 HL   │    H    │    L    │     HL'   │   H'    │   L'    │   HL Zeiger, 16-Bit-Akku
      └─────────┴─────────┘           └─────────┴─────────┘
      ┌───────────────────┐  ┌───────────────────┐
 IX   │  IXH  │  IXL      │  │  IY               │  Indexregister (IXH/IXL undokumentiert)
      ├───────────────────┤  ├───────────────────┤
 SP   │  Stapelzeiger     │  │  PC Befehlszähler │
      └───────────────────┘  └───────────────────┘
      ┌─────────┬─────────┐
      │ I Vektor│ R Refr. │   I: High-Byte der IM-2-Tabelle, R: zählt je Befehlsholung (7 Bit)
      └─────────┴─────────┘
💡 Schattenregister auf dem CPC
Die CPC-Firmware benutzt den zweiten Registersatz selbst: B' = &7F (Portadresse des Gate Arrays),C' = aktueller Wert für ROM-Zustand und Bildschirmmodus, Carry' = „im Interrupt“. Eigene Programme dürfen EXX/EX AF,AF' nur mit gesperrten Interrupts benutzen und müssen die Werte zurücktauschen (SOFT 968, Appendix XI „The Alternate Register Set“).
✅ Stapel
PUSH verringert SP um 2 und schreibt das High-Byte zuerst an die höhere Adresse. Beim CPC liegt der Firmware-Stapel unterhalb von &C000.

🚩Flags zum Ausprobieren

Wähle einen Befehl und die Werte – der Emulator rechnet und zeigt jedes Flag einzeln. Bit-Reihenfolge im Register F: S Z Y H X P/V N C (Bit 7 … 0).
Maschinencode: C6 01 · 7 T
A nachher = &80 = 128 = %10000000
S
1
Z
0
Y
0
H
1
X
0
P/V
1
N
0
C
0
  • S: Bit 7 des Ergebnisses – bei Zweierkomplement-Zahlen „negativ“.
  • Z: gesetzt, wenn das Ergebnis 0 ist (bei BIT: wenn das getestete Bit 0 ist).
  • H: Übertrag von Bit 3 nach Bit 4 (bzw. Borgen) – braucht DAA für BCD.
  • P/V: bei Arithmetik: Überlauf im Zweierkomplement (V); bei Logik/Rotation: gerade Anzahl Einsen (P).
  • N: 1 nach einer Subtraktion – damit DAA weiß, wie es korrigieren muss.
  • C: Übertrag aus Bit 7 (Addition), Borgen (Subtraktion) oder herausgeschobenes Bit.
  • X/Y: undokumentierte Bits 3 und 5 – meist Kopien der Ergebnisbits (Sean Young).

Berechnet vom Z80-Emulator dieser Seite (derselbe wie im Debugger).

🧭Adressierungsarten

Jede Zeile wurde mit dem Assembler dieser Seite übersetzt – so sieht der Maschinencode wirklich aus.
ArtBeispielBytesWirkungErklärung
UnmittelbarLD A,&413E 41A ← &41Der Wert steht im Befehl selbst.
Unmittelbar, 16 BitLD HL,&C00021 00 C0HL ← &C000Zwei Bytes Wert, niederwertiges zuerst (Little Endian).
RegisterLD B,A47B ← AQuelle und Ziel sind Register – 1 Byte, 1 µs auf dem CPC.
Register indirektLD A,(HL)7EA ← Speicher[HL]Das Registerpaar enthält die Speicheradresse.
Direkt (absolut)LD A,(&BE80)3A 80 BEA ← Speicher[&BE80]Die Adresse steht im Befehl.
IndiziertLD A,(IX+5)DD 7E 05A ← Speicher[IX+5]IX/IY plus vorzeichenbehafteter Versatz −128…+127.
RelativJR &401018 0EPC ← PC + eSprungweite relativ zum nächsten Befehl (−128…+127).
Seite 0 (Restart)RST &38FFCALL &0038Ein-Byte-Aufruf fester Adressen &00…&38.
ImplizitCPL2FA ← NOT ADer Operand (hier A) steckt im Befehl.
Bit-AdressierungSET 3,(HL)CB DEBit 3 von (HL) ← 1Einzelnes Bit eines Registers oder Speicherbytes.
Ein-/AusgabeOUT (C),CED 49Port[BC] ← CPort-Adresse in BC (CPC: B wählt den Baustein, z. B. &7F = Gate Array).

⚡Interrupt-Modi IM 0, IM 1, IM 2

IM 0

Das Gerät legt einen Befehl (meist ein RST) auf den Datenbus, die CPU führt ihn aus – kompatibel zum Intel 8080.

Auf dem CPC liefert der Bus &FF = RST &38, wirkt also wie IM 1.

IM 1

Jeder Interrupt ist ein RST &38: Rücksprungadresse auf den Stapel, Sprung nach &0038. 13 T.

Das benutzt die CPC-Firmware: INTERRUPT ENTRY bei &0038 (SOFT 968, Abschnitt 11.2).

IM 2

Die CPU bildet aus I (High-Byte) und dem Datenbus-Byte (Low-Byte) eine Tabellenadresse und springt an die dort stehende Adresse. 19 T.

Auf dem CPC für eigene Routinen üblich: 257-Byte-Tabelle mit gleichem Wert, weil das Bus-Byte nicht festgelegt ist.

CPC: Gate Array fordert alle 52 Rasterzeilen (3,328 ms) einen Interrupt an → 300 pro Sekunde, 6 pro Bild (50 Hz)

 Bild n                                                               Bild n+1
 │VSYNC                                                               │VSYNC
 ▼                                                                     ▼
 ├──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────
 INT        INT        INT        INT        INT        INT        INT
 │ Fast Ticker (300 Hz) bei jedem INT · Ton (100 Hz) bei jedem 3. · Frame Flyback, Ticker, Tastatur (50 Hz) bei jedem 6.
 └─ Firmware: RST &38 → INTERRUPT ENTRY → Ereignisse „anstoßen“ (KL EVENT) → EI, RET

⏱️Takte (T) und die 1-µs-Uhr des CPC

Das Datenblatt nennt T-Zustände bei 4 MHz. Im CPC teilen sich CPU und Bildausgabe den Speicher: Das Gate Array hält die CPU über /WAIT so an, dass jeder Speicherzugriff in ein 4-Takt-Raster fällt. Jeder Befehl dauert dadurch ein ganzes Vielfaches von 1 µs („NOP-Zeiten“) – effektiv rechnet der CPC wie ein Z80 mit etwa 3,3 MHz.
BefehlZ80 (T)T ÷ 4CPC gemessen (µs)
NOP41,001
LD A,B41,001
LD A,n71,752
LD A,(HL)71,752
LD A,(IX+d)194,755
PUSH HL112,754
POP HL102,503
CALL nn174,255
RET102,503
JR e123,003
JR NZ,e12/73,00 / 1,753/2
DJNZ e13/83,25 / 2,004/3
LDIR21/165,25 / 4,006/5
OUT (C),A123,004
EX (SP),HL194,756
ADD HL,DE112,753
💡 Warum PUSH 4 µs statt 2,75 µs?
PUSH HL besteht aus einer 5-Takt-Befehlsholung und zwei 3-Takt-Schreibzugriffen. Jeder Zugriff wird auf das 4-Takt-Raster ausgerichtet: 8 + 4 + 4 = 16 T = 4 µs. Deshalb reicht „T ÷ 4 aufrunden“ nicht immer (dort käme 3 heraus).
✅ Im Emulator
Der Debugger zählt beides: die Z80-Takte laut Datenblatt und die CPC-Zeit in µs nach der gemessenen Tabelle von Kevin Thacker (cpctech). Interrupts, Bildwechsel und KL TIME PLEASE laufen nach der CPC-Zeit.

Quellen: Zilog Z80 CPU User Manual (UM0080); Sean Young „The Undocumented Z80 Documented“ (Flags X/Y, SLL, IXH/IXL); SOFT 968 Abschnitt 11 und Appendix XI; CPC-Zeiten: K. Thacker „Instruction timings“ (cpctech.cpcwiki.de), Erklärung des Wartezyklus nach T. Harte „Amstrad CPC Timing“.