OOStuBS - Technische Informatik II (TI-II)
2.4
|
Der PIC 8259A ist ein Chip - meist nur Teil eines Chips- der wie der Prozessor selbst auf dem Motherboard eines jeden PCs zu finden ist. Seine Aufgabe besteht in der Koordination der Unterbrechungsanforderungen der verschiedenen Geräte.
Dazu besitzt der PIC acht Eingänge IR0
bis IR7
, an die jeweils der Interruptausgang eines Gerätes angeschlossen werden kann. Beispiele für diese Geräte sind der Timer, die Tastatur, die seriellen Schnittstellen (Maus) und der Festplattencontroller. Die Nummer des IR Pins gibt gleichzeitig die Priorität der Unterbrechung an. Das Gerät, das an IR0 angeschlossen ist, wird mit höchster Priorität behandelt, das an IR7
mit der niedrigsten.
Der PIC hat mehrere Ausgänge, durch die er mit der CPU verbunden ist. Unter anderem ist der Pin INT des PICs direkt an den Pin INTR
der CPU angeschlossen, ebenso sind die bei PIC und CPU gleichermaßen mit INTA
bezeichneten Pins gekoppelt. Die Pins D0
bis D7
des PICs sind mit den acht niederwertigsten Leiterbahnen des Datenbusses verbunden.
Wenn der PIC feststellt, dass auf mindestens einem seiner Eingänge IR0
bis IR7
eine Interruptanforderung anliegt und dem PIC nicht mitgeteilt wurde, dass er die entsprechende Anforderung ignorieren soll, so gibt er die Interruptanforderung über seinen Ausgang INTR
an die CPU weiter. Diese wird die Anforderung mit Hilfe der INTA
Leitung quittieren und durch ein zweites Signal auf INTA
nach der Nummer des Interrupts fragen. Der PIC antwortet daraufhin, indem er die Nummer des Interrupts (gleich der Nummer der Eingangsleitung + einem Offset) auf den Datenbus legt. Die CPU ist nun in der Lage, die Anfangsadresse der Unterbrechungsbehandlungsroutine zu finden und die Unterbrechungsbehandlung zu starten.
Damit der PIC sich merken kann, von welchen Geräten er Interruptanforderungen erhalten hat, welche er ignorieren soll und welche gerade von der CPU behandelt werden, besitzt er drei interne Register, die jeweils acht Bit breit sind.
Hier speichert der PIC, auf welchen der IR Leitungen eine Interruptanforderung signalisiert wurden. Dadurch braucht das betreffende Gerät nur eine kurze Änderung des Pegels auf der Leitung auszulösen.
Liegen die Interruptanforderungen mehrerer Geräte gleichzeitig an, so wird der PIC zunächst nur die wichtigste weiterleiten. Dazu wird die Unterbrechungsanforderung der CPU über die Leitung INT
angezeigt. Sobald diese daraufhin mit zwei INTA Signalen reagiert hat, wird nicht nur die Nummer des Interrupts auf den Datenleitungen D0
bis D7
ausgegeben, sondern auch das entsprechende Bit im ISR
gesetzt. Gleichzeitig wird das Bit im IRR
gelöscht. Da das Bit im ISR
gesetzt bleibt, bis es von der Unterbrechungsbehandlungsroutine mit Hilfe eines speziellen Befehls explizit gelöscht wird, kann der PIC beim Eintreffen einer weiteren Unterbrechung leicht erkennen, ob diese noch wichtiger als die gerade bearbeitete ist. In diesem Fall wird er dies der CPU durch ein erneutes Signal auf der INT
Leitung mitteilen.
Mit Hilfe dieses Registers ist es möglich, Interrupts selektiv zu unterdrücken. Ein gesetztes Bit im IMR sorgt dafür, dass der PIC Interrupts des entsprechenden Gerätes ignoriert.
Um mehr als acht Interruptquellen unterscheiden zu können, enthalten moderne PCs - das heißt alle ab dem XT von 1983 - zwei PICs, die hintereinander geschaltet sind. Der INT
Ausgang des Slave-PICs hat also keine direkte Verbindung zu dem INTR
Eingang der CPU, sondern wird an einen der IR Einänge (IR2) des Master PICs angeschlossen. Außerdem stehen Master und Slave über drei weitere Leitungen in Verbindungen, über die der Master dem Slave mitteilen kann, wann dieser die Nummer des von ihm signalisierten Interrupts auf den Datenbus legen soll.
OOStuBS implementiert das Master-Slave in der Klasse PIC.
Mittlerweile wird der APIC
- Advanced Programmable Interrupt Controller - verwendet. Mit diesem ist ein Mehrkern- und Mehrprozessorbetrieb möglich. OOStuBS verwendet diesen allerdings nicht. Das Grundprinzip kann nach wie vor mit dem einfacher zu bedienenden PIC verdeutlicht werden.
CPU-seitig kann dafür gesorgt werden, dass das laufende Programm nicht durch Interrupts unterbrochen wird. Dazu wird mit der Assembleranweisung cli
das Interrupt-Bit im EFLAGS
-Register gelöscht. Der Prozessor wird auf Signale seiner INTR
Leitung nun nicht mehr reagieren. Da der PIC einen Interrupt frühestens dann weitergibt, wenn die CPU auf den vorhergehenden Interrupt reagiert hat, wird der PIC keine Interrupts weiterleiten, solange die CPU Interrupts ignoriert.
Dieser Vorgang kann mit dem Befehl sti
wieder rückgängig gemacht werden.
Interrupts können auch selektiv unterdrückt werden. Dazu muss der PIC programmiert werden. Das geht wie üblich mit in
und out
Befehlen.
Wenn ein Interrupt ankommt, der sowohl seitens des PICs als auch seitens der CPU zugelassen wurde, verzweigt der Prozessor automatisch zur Interruptbehandlungsroutine.
Deren Adresse wird einer Interruptdeskriptortabelle (IDT
) entnommen, wobei die von dem PIC auf den Datenbus gelegte Nummer des Interrupts als Index dient. Beim 8086 Prozessor war die Lage der Interruptdeskriptortabelle noch fest von der Hardware vorgegeben, ab dem 80386 wird ihr Anfang und ihre Größe durch das IDT-Register beschrieben.
Die Interruptdeskriptortabelle kann maximal 256 Interruptgate-Deskriptoren enthalten, von denen es drei verschiedene Typen gibt
Bevor der Prozessor infolge eines Interrupts oder Traps die angegebene Behandlungsroutine aufruft, legt er den aktuellen Inhalt des EFLAGS
-Registers auf den Stack ab. Dies ermöglicht es ihm, nun das Interrupt-Enable-Flag im EFLAGS
-Register zu löschen und auf diese Weise die geschachtelte Behandlung weiterer Interrupts zu verhindern. Wie bei einem normalen Funktionsaufruf wird dann noch die Rücksprungadresse - Inhalt von Code-Segment und Instruction Pointer - auf dem Stack gesichert, bevor die Behandlungsroutine begonnen wird.
Bei manchen Exceptions legt der Prozessor zusätzlich einen Fehlercode auf dem Stack ab.
Wurde die Unterbrechung durch einen Interrupt ausgelöst, besteht eine Aufgabe der Interruptbehandlungsroutine darin, dem PIC mitzuteilen, dass der Interrupt behandelt wurde. Anderenfalls wird der PIC nämlich keine weiteren Interrupts desselben Gerätes weiterleiten. Das Senden dieses Interrupt-Acknowledge-Signals erfolgt wieder mit einem bzw. bei einer Kaskadierung der PICs mit zwei out Befehlen an den Port des PICs.
Mit dem iret
Befehl wird die Unterbrechungsbehandlung abgeschlossen. Der Prozessor holt die Rücksprungadresse vom Stack, stellt den Inhalt des EFLAGS
-Registers wieder her und kehrt zu der unterbrochenen Methode zurück. Dadurch, dass auch die EFLAGS
wieder hergestellt werden, werden spätestens jetzt die Interrupts CPU-seitig wieder zugelassen.
Jedem der beiden PICs in einem PC sind zwei Ports im I/O-Adressraum zugeordnet, die wie folgt belegt sind:
Port(IRQ0-7/IRQ8-15) | Lesedaten | Schreibdaten |
---|---|---|
0x20 / 0xa0 | IRR, ISR, Int.Vektor | ICW1, OCW2, OCW3 |
0x21 / 0xa1 | IMR | ICW2, ICW3, ICW4, OCW1 |
Die Bezeichnungen ICW
und OCW
stehend dabei für Initialization Control Word und Operation Control Word. Für die Lösung der Aufgabe sind nur die Operationsbefehlsworte OCW1
und OCW2
relevant:
OCW1
ist schlicht ein Platzhalter für die Maske der gesperrten Interrupts. Diese Maske wird direkt in das Interrupt Mask Register (IMR
, 0x21/0xa1
) übertragen; ein gesetztes Bit X sorgt dafür, dass der entsprechende Interrupt X gesperrt wird. OCW2
wird verwendet um dem PIC einen EOI
-Befehl zu senden, damit dieser erfährt, dass der Interrupt bearbeitet wird und das gesetzte Bit im ISR
löscht. Bei OOStuBS verwenden wir den "unspezifischen \c EOI -Befehl": OCW2
== 0x20
wird nach der Bearbeitung eines Interrupts in die Kontrollregister 0x20/0xa0
geschrieben.Die Initialisierungsbefehlsworte ICW1
bis ICW4
dienen der Initialisierung des Chips. Dies erfolgt bei OOStuBS innerhalb des Konstruktors des PIC, so dass ihr euch darum ausnahmsweise mal nicht selber kümmern müsst.