Z80 Interrupt-Logik

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

Die Z80 Interrupt-Logik dient der Interrupt-Steuerung des Zilog-Z80-Prozessors.

Mikroprozessoren kommunizieren mit externen Geräten über Peripheriebausteine, um beispielsweise Daten von einem Modem zu empfangen. Damit der Prozessor schnell auf externe Ereignisse – zum Beispiel den Empfang eines Zeichens – reagieren kann, sendet das Peripheriegerät eine Unterbrechungsanforderung (Interrupt) an den Hauptprozessor (central processing unit, CPU), der sein normales Programm unterbricht, in eine Interrupt-Service-Routine (ISR) verzweigt und nach Verarbeitung des Zeichens im normalen Programmfluss fortfährt. Um einen Interrupt an den Prozessor zu übergeben, werden meist spezielle Bausteine benötigt, die Interrupt-Controller. An diese Controller können mehrere Peripheriebausteine angeschlossen werden, im Ur-IBM Personal Computer von 1983 beispielsweise acht Stück. Sollten mehr als acht externe Geräte angeschlossen werden, wurde ein weiterer Controller benötigt, was zu aufwendigen Design-Änderungen führte.

Das Interrupt-Konzept des Z80

[Bearbeiten | Quelltext bearbeiten]
Verweis der Interrupt-Register auf die Vektortabelle

Zilog baute bereits 1976 die Interrupt-Steuerung des Z80-Prozessors daher völlig anders auf. Der Z80 benötigt keinen Interrupt-Controller, kann im Interruptmodus IM2 aber trotzdem bis zu 128 externe Interrupt-Quellen bedienen – bei einer zugleich sehr einfachen Software-Struktur. Damit der Z80 die zugehörige ISR aufrufen kann, besitzt jeder Peripheriebaustein ein 8 bit breites Register, das zusammen mit einem internen Prozessor-Register auf eine Interruptvektor-Tabelle im Speicher zeigt, die wiederum die Einsprungadressen der Interrupt-Service-Routine enthält. Da das unterste Bit des Interrupt-Registers immer Null sein muss, ergeben sich somit maximal 128 Einträge in der Interruptvektor-Tabelle.

Ablauf einer Unterbrechungsanforderung

[Bearbeiten | Quelltext bearbeiten]
  • Das Peripheriegerät aktiviert an der CPU eine Unterbrechungsanforderung (interrupt request signal, IRQ)
  • Die CPU bestätigt die Unterbrechungsanforderung.
  • Das Peripheriegerät legt daraufhin den Inhalt des Interrupt-Registers auf den Datenbus.
  • Die CPU unterbricht das laufende Programm, liest die Adresse, holt sich aus der Interruptvektor-Tabelle die Adresse des zugehörigen Programmcodes ISR und führt diesen aus. Nach Abarbeitung der Interrupt-Service-Routine führt die CPU das unterbrochene Programm fort.

Konfliktmanagement

[Bearbeiten | Quelltext bearbeiten]

Da mehrere externe Ereignisse gleichzeitig eintreffen und außerdem auch wichtige Ereignisse die ISR von unwichtigeren Ereignissen unterbrechen können, braucht man eine Konflikt- oder Prioritätssteuerung. Wie bei den Vektoren sind auch hier die Peripheriebausteine dafür verantwortlich. Jeder Baustein besitzt je einen Eingang (interrupt enable input, IEI) und einen Ausgang (interrupt enable output, IEO). Alle beteiligten Bausteine sind in Kette geschaltet, der IEO ist mit dem IEI des jeweils nächsten verbunden. Der IEI des ersten Gliedes liegt fest auf logisch 1. Es gilt:

  • Ein Interrupt wird nur ausgelöst, wenn IEI logisch 1 ist.
  • Ist ein Interrupt aktiv, so wird IEO logisch 0, was zur Folge hat, dass alle folgenden Glieder der Kette gesperrt sind.
  • Daraus ergibt sich, dass das erste Glied der Kette immer die höchste Priorität hat.

Das Bild erläutert diese Kette näher:

Interrupt-Kette der Peripheriebausteine
Interrupt-Kette der Peripheriebausteine
  • A: Ruhezustand, alle Bausteine können einen Interrupt auslösen.
  • B: Kanal 2 hat Interrupt ausgelöst, sperrt Kanal 3
  • C: Kanal 1 löst Interrupt aus, unterbricht die ISR von Kanal 2
  • D: Interrupt von Kanal 1 ist beendet, ISR von Kanal 2 geht weiter.
  • E: Interrupt von Kanal 2 ist beendet, es geht im normalen Programmfluss weiter.

Damit die Peripheriebausteine wissen, wann sie ihr IEO wieder freigeben dürfen, lauschen sie mit, welchen Programmcode die CPU gerade ausführt. Jede ISR endet mit dem Befehl RETI (ED 4D), was der externe Baustein erkennt und daraufhin sein IEO freigibt.

Oft ist es wünschenswert, die Interrupt-Prioritäten vom Programm aus zu ändern, was aber wegen der starren Hardware-Verdrahtung nicht möglich ist. Mit einigen Kniffen geht es trotzdem, dass beispielsweise Kanal 3 die ISR von Kanal 1 unterbricht.

Standard-ISR:

 Kanal2:
       PUSH AF               ;Sichern der Register
       PUSH BC
       PUSH DE
       PUSH HL
       EI                    ;neue Interrupts gleich wieder erlauben
       
       LD   HL,irgendwas     ;der Programmcode
       
       POP  HL
       POP  DE
       POP  BC
       POP  AF               ;Zurückholen der Register
       RETI                  ;Ende der ISR

Kanal 1 könnte die ISR von Kanal 2 unterbrechen, nicht aber Kanal 3, da dieser per Hardware gesperrt ist. Um die Hardware zu überlisten, wird folgendes Programmfragment benutzt:

Tricky ISR:

 Main:
       LD   DE,wasauchimmer
       ADD  HL,DE
       
       LD   A,1    ;<--- Hier wird der Interrupt wirksam,
                      ;die Adresse Main_R
                      ;wird als Rücksprungadresse auf den Stack gelegt.
 Main_R:
       LD    B,2
       

 ;Interrupt-Service-Routine fuer Kanal2
 Kanal2:
       CALL TRICKY_SAVE  ;Unterprogramm
 Kanal2_R:
       
       LD   HL,irgendwas
       
       RET


 TRICKY_SAVE:
       EX   (SP),HL     ;Rücksprung-Adresse nach HL holen
       PUSH AF          ;Register sichern
       PUSH BC
       PUSH DE          ;Stack: MAIN, HL, AF, BC, DE
                           ;HL:    Kanal2_R
       LD   DE,CONTINUE ;Adresse von Programmcode CONTINUE
       PUSH DE          ;als Rücksprungadresse auf Stack legen
       EI
       RETI             ;Programm wird durch den RETI-Befehl
                           ;an der manipulierten Rücksprungadresse CONTINUE fortgesetzt.
                           ;Das Peripheriegerät erkennt die RETI-Instruktion,
                           ;betrachtet damit "seine" ISR als beendet
                           ;und gibt den Interrupt wieder frei.

 CONTINUE:
       CALL  HL_JP      ;Programmcode wird an der im HL-Register gespeicherten Adresse
                           ;(=Kanal2_R) fortgesetzt
       POP   DE         ;Register zurückholen
       POP   BC
       POP   AF
       POP   HL
       RET              ;normales "return" reicht hier aus, da RETI bereits ausgeführt wurde.

 HL_JP:
       JP    (HL)

Jedes Peripheriegerät kann damit jederzeit einen Interrupt auslösen, die Prioritätssteuerung kann per Software erfolgen.