| Inhaltsverzeichnis | |||||
| Übersicht Kapitel 2 | |||||
| |||||
|
|
Während der normalen Bearbeitung eines Programmes kann es in einem Mikroprozessor-System immer wieder zu Ausnahmesituationen (Exceptions) kommen, die vom Prozessor eine vorübergehende Unterbrechung oder aber einen endgültigen Abbruch des Programms, also in jedem Fall eine Änderung des normalen Programmablaufes verlangen. Diese Ausnahmesituationen können einerseits durch das aktuell ausgeführte Programm selber herbeigeführt werden, mit diesem also in einem logischen Zusammenhang stehen, andererseits aber auch ohne jegliche Beziehung zum Programm sein. Ursachen sind im ersten Fall das Vorliegen von Fehlern im System oder im Prozessor selbst, im zweiten Fall der Wunsch externer Systemkomponenten, vom Prozessor "bedient" zu werden. Durch einen Abbruch reagiert das System stets auf schwere Fehler, die eine Fortsetzung der Programmausführung verhindern, also z.B. auf Hardware-Fehler oder falsche Werte in einer Systemtabelle.
Im folgenden werden nun die erwähnten Möglichkeiten im einzelnen dargestellt. Zu jeder wird beschrieben, welche Maßnahmen ergriffen werden, um die Ausnahmesituation zu beenden. Man spricht allgemein von Ausnahmebehandlung (Exception Handling) oder Ausnahmebearbeitung (Exception Processing). Die Ausnahmebehandlung wird von einer Komponente des Steuerwerks ausgeführt, die wir mit dem Begriff Unterbrechungslogik (Interrupt System) bezeichnen (vgl. Bild 2.1-7).
Einige Ausnahmesituationen werden nur durch die Hardware des Prozessors behoben. Dazu zählen beispielsweise das unten beschriebene Rücksetzen des Prozessors oder das Wiederholen einer Systembus-Operation im Fehlerfall. Die meisten Ausnahmesituationen, insbesondere die, bei denen das Programm lediglich kurzzeitig unterbrochen, nicht aber abgebrochen werden soll, werden durch die Ausführung spezieller Routinen bereinigt. Wir nennen sie im weiteren kurz Ausnahmeroutinen. Diese Ausnahmeroutinen müssen in der Regel, wie alle anderen Programme auch, vom Betriebssystem oder dem Anwender selbst zur Verfügung gestellt werden. Die Auswahl und Aktivierung einer bestimmten Routine muß durch die bereits erwähnte Hardwarekomponente im Steuerwerk des Prozessors, die Unterbrechungslogik, wirksam unterstützt werden. Insbesondere müssen alle Aktivitäten aus Zeitgründen möglichst parallel zu den Operationen der übrigen Prozessorkomponenten ablaufen.
2.3.1 Vergleich zwischen Unterprogramm und Ausnahmeroutine |
Der Aufbau einer Ausnahmeroutine ähnelt stark dem Aufbau eines Unterprogramms.
In einem Unterprogramm bringt man gewöhnlich Programmteile unter, die häufiger
benutzt werden, aber nur einmal im Speicher abgelegt werden sollen. Ein Unterprogramm
kann nur an zur Programmierzeit festgelegten Stellen im Hauptprogramm (oder
einem anderen Unterprogramm) durch spezielle Befehle (Call Subroutine,
Jump to Subroutine) aufgerufen werden (vgl. Abschnitt
3.2). In diesen Befehlen muß die Startadresse des Unterprogramms angegeben
werden. Durch das Steuerwerk wird zunächst der aktuelle Inhalt des Programmzählers
und bei einigen Prozessortypen auch der des Statusregisters auf dem Stack abgelegt.
Danach wird die im Befehl angegebene Startadresse in den Programmzähler
geladen und der Programmablauf an der dadurch bezeichneten Speicherstelle fortgesetzt.
Die Beendigung des Unterprogramms geschieht durch einen besonderen Befehl (Return
from Subroutine), durch den der Programmzähler und gegebenenfalls auch
das Statusregister mit ihren alten Werten aus dem Stack restauriert und das
Programm an der Unterbrechungsstelle fortgesetzt werden.
Demgegenüber tritt der Aufruf einer Ausnahmeroutine in einem Programm nicht explizit in Erscheinung. Statt dessen wird er durch ein externes Signal oder das Auftreten einer Fehlerbedingung im Prozessor veranlaßt. Dies kann prinzipiell an beliebigen Stellen des Programms, z.B. nach jeder Befehlsausführung geschehen. Dabei wird die Startadresse der Ausnahmeroutine durch das Steuerwerk festen Speicherzellen entnommen. Wie bei einem Unterprogrammaufruf wird zunächst der aktuelle Inhalt des Programmzählers auf den Stack gerettet und dann an der durch die Startadresse bezeichneten Stelle im Speicher fortgefahren. Um möglichst rasch auf Unterbrechungsanforderungen reagieren zu können, wird manchmal auf die Sicherung des Statusregister-Inhaltes verzichtet. Die Beendigung der Ausnahmeroutine geschieht durch einen speziellen Befehl (Return from Interrupt/Exception), durch den der Programmzähler mit seinem alten, auf dem Stack geretteten Inhalt restauriert und die Programmausführung an der Unterbrechungsstelle fortgesetzt wird.
Genauer betrachtet, kann man bei der Behandlung von vorübergehenden Programmunterbrechungen die folgenden Schritte unterscheiden:
Feststellen, ob eine interne oder externe Unterbrechungsanforderung vorliegt; bei externen Anforderungen weiterhin feststellen, ob durch das Interrupt Enable Bit (IE, s. Abschnitt 2.3.2) im Steuerregister eine Unterbrechung zugelassen ist. (Diese Abfrage entfällt bei den unten beschriebenen "nicht maskierbaren" Unterbrechungen!)
Zuendeführen der augenblicklich bearbeiteten Operation, sofern dies sinnvoll ist, (wobei es sich je nach Situation um einen vollständigen Maschinenbefehl oder aber nur um einen Systembus-Zugriff handeln kann,)
Übertragen des Prozessor-Zustandes, also des Inhalts von Programmzähler, Statusregister und eventuell weiterer Register in den Stack,
Feststellen der Quelle der Unterbrechungsanforderung,
Informieren der Systemkomponenten über spezielle Leitungen (Interrupt Acknowledge INTA) oder die Prozessor-Statussignale, daß die Unterbrechungsanforderung akzeptiert wurde,
Deaktivieren bestimmter anderer Unterbrechungsanforderungen,
Ermitteln der Startadresse der Ausnahmeroutine für die festgestellte Quelle der Unterbrechungsanforderung und Laden dieser Adresse in den Programmzähler,
Ausführen der Ausnahmeroutine,
Beenden der Ausnahmeroutine durch einen speziellen Befehl (Return from Interrupt RTI, auch: IRET),
Restaurieren der anfänglich gesicherten Registerinhalte, Reaktivierung der zeitweise gesperrten Unterbrechungsanforderungen und Fortsetzung des Programms an der Unterbrechungsstelle, also mit dem unmittelbar auf die Unterbrechungsstelle folgenden Maschinenbefehl.
Bis auf die Ausführung der Ausnahmeroutine werden alle diese Schritte durch die Hardware der Interrupt-Logik - und das so weit wie möglich parallel - ausgeführt. Wie die Startadresse der Ausnahmeroutine genau ermittelt wird, wird erst im Anschluß an die folgende Beschreibung der verschiedenen Ausnahmesituationen gezeigt. Außerdem wird zunächst vorausgesetzt, daß zu jedem Zeitpunkt höchstens eine Unterbrechungsanforderung vorliegt. Zum Schluß dieses Abschnitts wird dann gezeigt, wie mehrere gleichzeitig vorliegende Anforderungen bearbeitet werden.
Für die Ausnahmesituationen können sowohl prozessorinterne als auch prozessorexterne Ursachen vorliegen. Prozessorexterne Ursachen treten in der Regel asynchron zum Programmablauf auf und werden durch die Hardware des Systems erzeugt. Hingegen werden fast alle Ausnahmesituationen mit prozessorinternen Ursachen durch das Programm selbst an fest vorgegebenen Stellen ausgelöst. Sie treten also synchron zum Programmablauf auf.
2.3.2 Prozessorexterne Ursachen für Ausnahmesituationen |
Die einfachste und "wirksamste" Ausnahmesituation liegt vor, wenn der Prozessor in einen definierten Anfangszustand zurückgesetzt wird ("Initialisierung"). Dies geschieht durch ein Signal am RESET-Eingang des Steuerwerks, wie es im Abschnitt 2.2 beschrieben wurde. Dort wurden bereits die Möglichkeiten erwähnt, das Zurücksetzen automatisch beim Einschalten der Betriebsspannung (POR) oder durch eine Taste durchzuführen. In beiden Fällen liegt gewöhnlich kein Bezug zu einem laufenden Programm vor.
Andererseits werden in Mikroprozessor-Systemen mit hohen Verfügbarkeitsanforderungen häufig Überwachungsschaltungen (Watch Dogs) eingesetzt, die immer dann den Prozessor über den RESET-Eingang neu initialisieren, wenn dieser nicht innerhalb einer maximalen Zeitschranke durch eine genau definierte Aktion gezeigt hat, daß er noch korrekt arbeitet. Durch diese Schaltungen wird also insbesondere erkannt, wenn der Prozessor in einer Endlosschleife festhängt oder durch eine Störung verursacht den normalen Programmbereich verlassen hat. In diesem Fall besteht also ein Zusammenhang zwischen dem auszuführenden Programm und dem Rücksetzen des Prozessors. (Eine einfache Realisierung eines Watch Dogs ist ein Monoflop, dessen Ausgang am RESET-Eingang anliegt und das in regelmäßigen Abständen durch ein Ausgangssignal des Prozessors 'nachgetriggert' werden muß.)
Sobald der RESET-Eingang aktiviert wird, bricht der Prozessor, wie bereits in
Abschnitt 2.2 beschrieben, alle augenblicklich ausgeführten Operationen und Busaktivitäten ab. Danach setzt er (z.B. durch ein Mikroprogramm) alle bzw. einige Register auf vordefinierte Werte (häufig den Wert 0). Anschließend holt er aus einer vorbestimmten Stelle im (Festwert-)Speicher die Startadresse für das nach dem Rücksetzen zuerst auszuführende Programm. Diese wird in den Programmzähler geladen. Bei diesem Programm handelt es sich meist um eine Betriebssystemroutine, die nun alle Hardware- und Software-Systemkomponenten in die erforderlichen Anfangszustände versetzt. Abschließend wird der Teil des Steuerwerks aktiviert, der für die sequentielle Ausführung der Maschinenbefehle sorgt.
Im Abschnitt 2.2 wurde gezeigt, daß einige Mikroprozessoren spezielle Eingänge (HALT, HOLD) besitzen, über die sie in einen Haltezustand versetzt werden können. Das bedeutet, daß der Prozessor nach Abschluß des laufenden Zugriffs auf den Systembus seine Programmbearbeitung unterbricht. Während dieser Zeit werden die Systembus-Ausgänge des Prozessors in den hochohmigen Zustand (Tristate, Three State) versetzt. Die beiden Signale HALT bzw. HOLD unterscheiden sich darin, wie lange der Haltezustand des Prozessors andauert: Im ersten Fall dauert der Zustand meist solange, bis er durch ein Rücksetzen des µPs oder eine Unterbrechungsanforderung beendet wird. Im zweiten Fall kann der Prozessor intern vorliegende Befehle und Daten weiter bearbeiten und wird nur dann und solange angehalten, wie das HOLD-Signal aktiviert ist und der Prozessor auf den Bus zugreifen will. Während dieser Zeit kann eine andere Systemkomponente den Systembus benutzen. (Im weiteren Verlauf der Vorlesung wird das am Beispiel des direkten Speicherzugriffs (Direct Memory Access DMA), einer Methode zum schnellen Datentransfer zwischen Speicher und Peripheriegerät, beschrieben.)
Viele Prozessoren besitzen einen Eingang (z.B. BERR - Bus Error - genannt), der die Reaktion auf verschiedene prozessorexterne Fehler des Systems erlaubt, die mit dem augenblicklich durchgeführten Zugriff auf den Systembus im Zusammenhang stehen (s. Abschnitt 2.2). Dazu gehören insbesondere Paritätsfehler auf dem Datenbus, Zugriffe auf geschützte Datenbereiche oder das Ausbleiben von Quittungssignalen bestimmter Komponenten. Das Vorliegen einer solchen Fehlersituation muß durch eine spezielle externe Schaltung festgestellt und in ein BERR-Signal umgesetzt werden. Solange dieses Signal aktiv ist, geht der Prozessor in den oben beschriebenen Haltezustand. Wird das Signal zurückgesetzt, wird z.B. in Abhängigkeit vom aktuellen Zustand des HALT-Einganges eine von zwei Ausnahmebehandlungen durchgeführt:
Weitere Beispiele für spezielle Error-Signale:
Durch periphere Geräte oder Systemsteuerbausteine können asynchron zum Programmablauf über spezielle Eingänge Unterbrechungssignale ((Hardware) Interrupts) an den Prozessor abgegeben werden. Gründe dafür können zum Beispiel das Vorliegen eines Datums in einem Eingabegerät oder eines bestimmten Zustandes ('Operation ausgeführt', Fehler etc.) sein. Einer Interruptanforderung wird vom Prozessor frühestens nach der vollständigen Beendigung des in Bearbeitung befindlichen Befehls stattgegeben. Die vom Prozessor als Reaktion gestarteten Ausnahmeroutinen werden Interruptroutinen genannt. Die meisten Mikroprozessoren können über die im Unterabschnitt 2.2.2.4 beschriebenen Statusinformationen den Systemkomponenten mitteilen, daß sie im Augenblick eine Interruptroutine durchführen. Dazu muß der Zustand der Prozessor-Statussignale (z.B. FC0,..,FC2 - Function Code) von den Komponenten decodiert werden. Diese Information ist insbesondere für die Komponente wichtig, die die Unterbrechung angefordert hat.
Das oben beschriebene Retten des Prozessor-Zustandes vor der Ausführung eines Interrupts dauert bei zeitkritischen Anwendungen oft unvertretbar lange. Auch bei modernen µPs liegt die Zeit im Bereich einiger Mikrosekunden, z.B. 20 µs. Deshalb bieten einige Prozessoren spezielle Befehle an, mit denen sie in einen Zustand versetzt werden können, in dem sie auf den nächsten Interrupt warten. Diese Befehle, meist mit WAI, WAIT (Wait for Interrupt) oder SYNC (Synchronize) bezeichnet, sorgen teilweise selbst für das vorzeitige Retten des Prozessor-Zustandes im Stack. Bei anderen Prozessortypen muß der Programmierer dies durch Speicherbefehle explizit vornehmen. Nach dem Auftreten des Interrupts muß dann nur noch der Inhalt des Programmzählers ausgetauscht werden. Oft kann der Wartezustand nicht nur durch einen Interrupt verlassen werden, sondern es besteht die Möglichkeit, durch einen weiteren Prozessoreingang oder durch ein kurzes Triggersignal am Interrupteingang das Programm mit dem auf WAIT folgenden Befehl fortzusetzen, ohne eine Interruptroutine durchzuführen. (Natürlich darf in dieser Realisierung der Prozessor-Zustand nicht durch den WAIT-Befehl vorher auf den Stack gerettet werden.)
Interrupts können maskierbar oder nicht maskierbar sein. Für beide Typen stehen (meist) getrennte Eingänge zur Verfügung. Der Prozessoreingang für maskierbare Interrupts wird häufig mit INT, INTR bzw. IRQ (Interrupt Request), der für nicht maskierbare fast einheitlich mit NMI (Non-maskable Interrupt) bezeichnet.
Nicht maskierbare Interrupts (NMI) werden nach Abschluß des gerade ausgeführten Befehls unbedingt durchgeführt. Diese Tatsache zeigt schon, daß diese Interrupts nur für wirklich wichtige Ausnahmesituationen reserviert sein sollten. Dazu gehören insbesondere Fehler, die die Funktionsfähigkeit des Systems ernsthaft gefährden, wie z.B. der Zusammenbruch der Betriebsspannung. In diesem Fall kann die Interruptroutine die Aufgabe haben, die aktuellen Registerinhalte in einen (permanenten) Speicher zu retten, eine Not-Spannungsversorgung einzuschalten oder einen Alarm auszulösen. Während der Behandlung einer NMI-Routine wird kein weiterer (maskierbarer oder nicht maskierbarer) Interrupt zugelassen. Einige Prozessoren speichern jedoch diese zwischenzeitlich eintreffenden Anforderungen und bearbeiten sie unmittelbar nach Abschluß der aktuellen Interruptroutine. Diese Anforderungen können aber durch den Programmierer auch während der NMI-Bearbeitung gezielt zugelassen werden.
2.3.3 Prozessorinterne Ursachen für Ausnahmesituationen |
Wie bereits gesagt, treten diese Ursachen fast immer synchron zum Programmablauf auf. Ausnahmen liegen z.B. bei den Prozessoren vor, die auf dem Chip selbst interruptfähige Komponenten besitzen, wie z.B. serielle oder parallele Schnittstellen, Zeitgeber etc. Für diese Interrupts gelten die oben angestellten Betrachtungen, so daß sie hier nicht wiederholt werden müssen. Die programmsynchronen, internen Unterbrechungen werden durch Software-Interrupts und Traps hervorgerufen.
Software-Interrupts werden durch besondere Befehle aufgerufen. Diese Befehle tragen oft die Bezeichnungen SWI n (Software Interrupt) oder INT n, wobei die Nummer n die Auswahl unter einer vorgegebenen Menge von Ausnahmeroutinen erlaubt. In ihrer Wirkung entsprechen Software-Interrupts dem Aufruf eines Unterprogramms, dessen Startadresse jedoch an einer bestimmten Speicherstelle festgelegt ist und deshalb nicht im Befehl angegeben werden muß. Gegenüber einem Unterprogrammaufruf besitzen sie daher die Vorteile, daß sie mit weniger Speicherzellen für den Maschinencode auskommen (1 oder 2 Byte Befehle) und in der Regel den gesamten Prozessor-Zustand automatisch im Stack ablegen. In Betriebssystemen für Mikrorechner werden sie hauptsächlich benutzt, um die peripheren Komponenten des Systems anzusprechen. Die von diesen Komponenten benötigten oder ermittelten Parameter werden als Registerinhalte im Stack übergeben.
Software-Interrupts bieten darüber hinaus die Möglichkeit, die Ausnahmeroutinen der Hardware-Interrupts zu Testzwecken ohne externe Stimulierung durchzuführen. Da aber dieser Aufruf synchron zum Programm geschieht, können natürlich nicht alle Situationen getestet werden, die beim entsprechenden Hardwareaufruf vorliegen können.
Traps (Fallen) sind Ausnahmesituationen, in die der Prozessor nach dem Auftreten bestimmter Ereignisse kommt, die synchron zum Programmablauf auftreten. Diese Ereignisse stehen in direkter Beziehung zu den aktuell ausgeführten Befehlen bzw. Operationen. Sie werden deshalb auch Instruction Exceptions genannt. Traps haben in der Mehrzahl prozessorinterne Ursachen; sie können aber auch durch externe Ereignisse hervorgerufen werden, die dem Steuerwerk durch spezielle Signale mitgeteilt werden. Bei ihnen kann es sich um einen Fehler oder einen anderen "anomalen" Prozessorzustand handeln. Sie können einerseits vor, andererseits aber auch nach Ausführung einer Operation eintreten. Ereignisse, die vor der Ausführung auftreten, werden häufig auch Faults (Fehler) genannt. In Abhängigkeit von der Art des Ereignisses wird eine spezielle Ausnahmeroutine des Betriebssystems ausgeführt.
Traps (im engeren Sinne) treten nach der Ausführung eines Befehls auf und führen in der Regel zum Abbruch (Abort) dieses Befehls, ohne daß eine Wiederholung versucht wird. In diesem Fall zeigt die Rücksprungadresse aus der Ausnahmeroutine auf den ersten Befehl nach dem Befehl, der die Ausnahmesituation hervorgerufen hat.
Bei einem Fault wird in der Regel die Operation wiederholt, die zur Ausnahmesituation führte. Dazu muß zunächst durch die Ausnahmeroutine die Bedingung beseitigt werden, die zum Auslösen des Faults führte. Die Rücksprungadresse aus der Ausnahmeroutine zeigt in diesem Fall auf den Befehl, der die Ausnahmesituation hervorgerufen hat. Ein wichtiges Beispiel dafür ist ein sog. Seitenfehler (Page Fault), d.h. ein Zugriff auf eine bestimmte Speicherseite, die noch nicht im Hauptspeicher vorliegt. Durch die Ausnahmeroutine des Betriebssystems wird die gewünschte Seite vom Peripheriespeicher in den Arbeitsspeicher geladen.
Moderne Mikroprozessoren besitzen wenigstens zwei verschiedene Arbeitsweisen: den Benutzermodus und den geschützten, privilegierten Betriebssystem-Modus. Bei diesen Prozessoren werden Traps häufig auch als Systemaufrufe (Supervisor Call SVC) bezeichnet, da sie einen Übergang vom Benutzer- in den Betriebssystem-Modus bewirken. Typische Ursachen für Traps sind:
2.3.4 Ermittlung der Startadresse für die Ausnahmeroutinen |
8-bit-Prozessoren bieten meist nur eine eingeschränkte Ausnahmebehandlung. Insbesondere unterstützen sie keine Traps. Die Anzahl der Software-Interrupts ist sehr begrenzt (z.B. drei). Aus diesem Grund kommen diese Prozessoren mit einer kleinen Tabelle im Speicher aus, die die Startadressen der Ausnahmeroutinen enthält. Diese Startadressen werden üblicherweise als Vektoren (Exception Vectors) bezeichnet. Die Vektortabelle ist meist in einem Festwertspeicher des Mikrorechner-Systems unter den höchstwertigen Adressen abgelegt. Beim Auftreten einer bestimmten Ausnahmesituation lädt das Steuerwerk des Prozessors die Startadresse der zugehörenden Ausnahmeroutine aus der ihr zugeordneten Speicherzelle in den Programmzähler.
Tabelle 2.3-1 zeigt als Beispiel die Vektortabelle des Motorola MC6809. Dieser Prozessor besitzt einen 8-bit-Datenbus und einen 16-bit-Adreßbus, so daß jeder Vektor byteweise in zwei aufeinanderfolgenden Speicherzellen abgelegt werden muß. (Üblicherweise werden diese Bytes mit H-Byte und L-Byte bezeichnet; H=high, L=low.)
Wir müssen hier nur noch den 'schnellen' maskierbaren Interrupt erklären. Der FIRQ (Fast Interrupt Request) rettet lediglich den Programmzähler und das Statusregister in den Stack. Nur darin unterscheidet er sich vom IRQ, der sämtliche Registerinhalte abspeichert. Dementsprechend geschieht das "Umschalten" auf die FIRQ-Ausnahmeroutine erheblich schneller als auf die IRQ-Routine.
| Speicheradressen H-Byte L-Byte |
Ausnahmesituation | ||
| $FFFE | $FFFF | RESET | Rücksetzen |
| $FFFC | $FFFD | NMI | nicht maskierbarer Interrupt |
| $FFFA | $FFFB | SWI1 | Software-Interrupt 1 |
| $FFF8 | $FFF9 | IRQ | maskierbarer Interrupt |
| $FFF6 | $FFF7 | FIRQ | schneller maskierbarer Interrupt |
| $FFF4 | $FFF5 | SWI2 | Software-Interrupt 2 |
| $FFF2 | $FFF3 | SWI3 | Software-Interrupt 3 |
| $FFF0 | $FFF1 | reserviert) | |
2.3.5 Die Behandlung mehrerer Interruptquellen |
In einem komplexen System gibt es in der Regel viele Komponenten, die eine Unterbrechungsanforderung an den Prozessor stellen können. Da die Anzahl der Anschlußstifte des Gehäuses möglichst klein gehalten werden muß, kann der Prozessor nicht jeder Quelle einen eigenen Interrupteingang zur Verfügung stellen. Daher sind - im Minimalfall - alle Komponenten, die einen Interrupt auslösen können, über eine gemeinsame Leitung entweder am IRQ- oder am NMI-Eingang des Prozessors angeschlossen. Daraus ergibt sich für den Prozessor das Problem, beim Auftreten eines Interrupts festzustellen, welche Quelle die Unterbrechung angefordert hat.
Die einfachste Methode, wie sie bei den 8-bit-Prozessoren bevorzugt angewendet wird, wird mit Polling bezeichnet. (Deutsche Begriffe wie "Abfrageverfahren", "Wählverfahren" haben sich nicht durchgesetzt.) Bei diesem Verfahren fragt der Prozessor zu Beginn der Interruptroutine nach einer fest vorgegebenen Reihenfolge alle Komponenten ab, die einen Interrupt auslösen können. Diese Abfrage besteht im wesentlichen darin, das Statusregister der Komponente zu lesen und darin ein bestimmtes Bit zu überprüfen. Dieses Bit wird Interrupt Flag (IF) genannt. Es wird von der Komponente immer dann gesetzt, wenn sie ihren Interruptausgang aktiviert hat. Sobald der Prozessor eine Komponente mit gesetztem Interrupt Flag findet, bricht er die Abfrageroutine ab und ruft eine spezifische, der Interruptquelle zugeordnete Ausnahmeroutine auf. Nach Ausführung der Anforderung wird die Interruptroutine (über den Befehl RTI) wieder verlassen.
Eine gewisse Zeit nach der Abarbeitung eines Interrupts werden in der Regel erneut Interruptanforderungen ausgelöst. Andererseits können aber auch schon während der Abarbeitung des letzten Interrupts weitere Anforderungen aufgetreten sein. Es gibt zwei gebräuchliche Alternativen, wie der Prozessor mit diesen Interruptanforderungen verfahren kann. Beide Varianten sind im Bild 2.3-1 skizziert.
Bild 2.3-1: Zwei verschiedene Varianten des Polling-Verfahrens,
a) faire Zuteilung, b) Zuteilung mit festen Prioritäten
Der größte Nachteil des Polling-Verfahrens ist die Tatsache, daß durch die zyklische Abfrage aller möglichen Komponenten u.U. unvertretbar viel Zeit gebraucht wird, bis die Interruptquelle identifiziert ist. Dieser Zeitverlust ist bei den modernen 16/32-bit-Prozessoren nicht mehr zu vertreten. Bei ihnen hat man deshalb das folgende Verfahren entwickelt, um die Quelle eines Interrupts möglichst schnell ermitteln zu können. Die Startadressen aller Ausnahmeroutinen werden in einer Tabelle zusammengefaßt, die wir verkürzend mit (Ausnahme-)Vektortabelle bezeichnen wollen. Im Englischen sind dafür die Begriffe Exception Vector Table und (vereinfachend) Interrupt Vector Table üblich. Typisch sind Tabellen mit bis zu 256 Einträgen. Dem entspricht eine Länge der Vektornummern von 8 bit. Die Tabelle 2.3-2 stellt ein Beispiel solch einer Vektortabelle dar. Die letzte Spalte der Tabelle zeigt die relative Adresse jedes Eintrags, bezogen auf den Wert des Basisregisters, wenn ein Eintrag (beispielsweise) 4 byte lang ist. Sie berechnet sich aus dem Produkt von Index und Eintragslänge. Im betrachteten Fall umfaßt die gesamte Vektortabelle 1024 byte.
| Index | Ausnahmesituation | rel. Adresse | |
| 0 | Divide by 0 | Division durch 0 | $000 |
| 1 | Overflow | Zahlenbereichsüberschreitung | $004 |
| 2 | Array Bound Check | Indexbereichsüberschreitung | $008 |
| 3 | Invalid Opcode | illegaler Befehlscode | $00C |
| 4 | SVC (Supervisor Call) | Betriebssystem-Aufruf | $010 |
| 5 | Privilege Violation | unerlaubter Aufruf einer privilegierten Operation | $014 |
| 6 | Trace | Einzelschritt-Modus | $018 |
| 7 | .... | $01C | |
| .... | (weitere Traps) | ||
| i | .... | (i*4) | |
| i+1 | RESET | Rücksetzen | |
| i+2 | BERR | Busfehler | |
| i+3 | NMI | nicht maskierbarer Interrupt | |
| - | .... | ||
| k | ..... | (weitere Ausnahmesituationen) | (k*4) |
| k+1 | Error | Coprozessor-Fehler | |
| - | .... | (weitere Coprozessor-Meldungen, | |
| l | z.T. über spezielle Statusleitungen) | (l*4) | |
| l+1 | Page Fault | Seitenfehler | |
| - | .... | (weitere Fehler der Speicherverwaltung) | |
| m | .... | (m*4) | |
| m+1 | .... | (reserviert für zukünftige Erweiterungen | |
| - | .... | und für Testzwecke des Herstellers) | |
| n | .... | (n*4) | |
| n+1 | User Vectors | (durch Systementwickler frei zuzuordnende, | |
| - | .... | maskierbare Interrupts) | |
| 255 | .... | $3FC | |
Diese Tabelle ist häufig in einer bestimmten, meistens der untersten Speicherseite abgelegt, d.h. unter den niederstwertigen Adressen. Bei vielen Prozessoren kann sie aber auch an beliebiger Stelle im Speicher untergebracht werden. Diese Prozessoren besitzen dazu ein spezielles Basisadreß-Register (Vector Base Register, s. Abschnitt 2.6.1), das die Basisadresse der Tabelle enthält. Jeder Ausnahmeursache wird als Vektornummer der Index zugeordnet, unter dem die Startadresse, auch Vektor oder Zeiger (Pointer) genannt, ihrer Behandlungsroutine in der Tabelle gespeichert ist. Durch Einschreiben eines neuen Wertes in das Basis-Register, kann jederzeit (durch das Betriebssystem) auf eine andere Vektortabelle umgeschaltet und dadurch jeder Ausnahmeursache (Exception) eine neue Behandlungsroutine zugewiesen werden.
Für die Ausnahmesituationen, die die Überwachung des Systems steuern, wie Traps, RESET, und NMI, werden meist die ersten Tabellenplätze reserviert. Es folgen einige Gruppen von Ausnahmesituationen, die durch spezielle Komponenten verursacht werden, wie Coprozessoren und Speicherverwaltungsbausteine. Für jede der eben erwähnten Unterbrechungen werden die Tabellenplätze vom Steuerwerk fest vorgegeben und die Vektoren prozessorintern erzeugt.
Die maskierbaren Interrupts belegen meist die letzten Tabellenplätze. Der Systementwickler kann im Prinzip jeder Interruptquelle einen dieser Tabellenplätze frei zuordnen. Nur wenn auf dem Mikrorechner ein universelles Betriebssystem laufen soll, ist er aus Kompatibilitätsgründen gezwungen, sich an die vom Betriebssystem vorgegebene Zuteilung der Tabellenplätze zu halten.
Immer wenn ein (maskierbarer) Interrupt auftritt, prüft das Steuerwerk des Prozessors zunächst, ob das Interrupt Enable Bit (IE) in seinem Steuerregister gesetzt ist (s. Abschnitt 2.2). Nur wenn das der Fall ist, führt es einen speziellen Buszyklus zur Identifizierung der Interruptquelle durch (Interrupt Acknowledge Cycle). Ein Beispiel dafür ist im Bild 2.3-2 als Zeitdiagramm dargestellt.
Bild 2.3-2: Zyklus zur Identifikation der Interruptquelle
In Phase 1 des Zyklus teilt der Prozessor über seine Statussignale zunächst allen Komponenten mit, daß er eine Interrupt-Anforderung bearbeiten will (z.B. FC0=..=FC2=1). Diese Information wird von allen Komponenten decodiert. Bei anderen Prozessortypen erfolgt diese Mitteilung über ein spezielles Ausgangssignal INTA (Interrupt Acknowledge). Das Ausgangssignal des Decoders bzw. INTA aktiviert in der Komponente, die die Interrupt-Anforderung gestellt hat, ein Register, in dem die zugeordnete Interrupt-Vektornummer (IVN) gespeichert ist. (Anstelle des Registers kann auch ein Schaltnetz vorhanden sein, in dem der Vektor fest verdrahtet ist.)
In der Phase 2 wird nun der Registerinhalt auf den (unteren Teil des) Datenbus gegeben und vom Prozessor eingelesen. Damit ist der Prozessor in der Lage, die Quelle eindeutig zu identifizieren, die Startadresse der entsprechenden Ausnahmeroutine aus der Vektortabelle zu ermitteln und diese Routine auszuführen.
Zur Unterscheidung der beiden Phasen benutzt der Prozessor in unserem Beispiel das Adreßsignal A2. Gibt die ausgewählte Komponente am Ende der Phase 1, die ja prozessorseitig einen Lesezyklus darstellt, Daten auf den Systembus, so werden diese vom Prozessor ignoriert.
Wie die Ermittlung der Startadresse vor sich geht, ist im Bild 2.3-3 angedeutet. Darin sieht man, daß sich die Startadresse aus der Addition des Inhalts des Basisadreß-Registers und der relativen Adresse des indizierten Eintrags der Vektortabelle ergibt. Wie oben beschrieben, berechnet sich die relative Adresse durch die Skalierung der Vektornummer IVN, wobei der konstante Skalierungsfaktor durch die Anzahl der Bytes pro Tabelleneintrag gegeben ist.
Wie bereits gesagt, hängen in einem komplexen Mikrorechner-System viele mögliche Interruptquellen an einem gemeinsamen Eingang (IRQ, INT). In diesem Fall muß durch einen Interrupt-Controller bei gleichzeitigen Unterbrechungsanforderungen festgestellt werden, welche Quelle zunächst bedient werden soll und ihre IVN an den Prozessor liefern darf. (Auf Interrupt Controller gehen wir weiter unten ausführlich ein.)

Bild 2.3-3: Die Berechnung der Startadresse einer Interruptroutine
Software-Interrupts
Durch den oben beschriebenen Software-Interrupt INT n wird das Steuerwerk veranlaßt, den Eintrag mit dem Index n aus der Vektortabelle in den Programmzähler zu laden und danach die entsprechende Ausnahmeroutine auszuführen. Mit diesem Befehl ist der Zugriff zu allen Unterbrechungsroutinen möglich.
2.3.6 Prioritäten bei mehrfachen Unterbrechungsanforderungen |
Wie oben erwähnt, werden Unterbrechungsanforderungen vom Steuerwerk des Prozessors i.d.R. erst nach der Ausführung der aktuellen Operation erfüllt. Natürlich kann es passieren, daß während einer Befehlsausführung mehrere Anforderungen gleichzeitig oder kurz hintereinander auftreten. Am Ende der Befehlsausführung stellt das Steuerwerk des Prozessors dann das simultane Vorliegen dieser Anforderungen fest. In diesem Fall muß der Prozessor die Ausnahmesituationen in einer gewissen Reihenfolge behandeln. Diese Reihenfolge ist bei den Mikroprozessoren in der Regel fest vorgegeben. Durch sie werden den verschiedenen Anforderungen bestimmte Prioritäten zugeordnet. Der oben beschriebene Einsatz des nicht maskierbaren Interrupts (NMI) zur Erkennung von Ausfällen der Versorgungsspannung verlangt beispielsweise, daß der NMI stets vor den maskierbaren Interrupts (IRQs) ausgeführt wird.
Zu beachten ist jedoch, daß durch diese Prioritäten nur die Reihenfolge vorgegeben ist, in der die Behandlung der Interrupts begonnen wird. Werden in einer Ausnahmeroutine nicht alle anderen Unterbrechungen gesperrt, so kann es passieren, daß noch vor dem ersten Befehl der Routine eine gleichzeitig vorliegende Ausnahmesituation mit niedrigerer Priorität behandelt wird. Dies ist z.B. bei den Traps der Fall, die in der Regel die Interrupteingänge nicht sperren. Vor der Ausführung der Trap-Routine kann daher beispielsweise noch ein maskierbarer Interrupt (IRQ) ausgeführt werden.
Die Vergabe der Prioritäten ist bei allen Mikroprozessor-Herstellern unterschiedlich. Gemeinsam ist allen nur, daß das Rücksetzen (RESET) und die Traps in der Regel hohe Prioritäten zugewiesen bekommen.
Tabelle 2.3-3 zeigt beispielhaft die Prioritäten bei den Prozessoren der Firma Intel.
Durch die beschriebene Vergabe unterschiedlicher Prioritäten ist noch nicht das Problem gelöst, wie der Prozessor "gleichzeitig" auftretende maskierbare Interrupts (IRQs) behandeln soll. Eine Möglichkeit, das Polling, wurde bereits weiter oben beschrieben. Wie bereits gesagt, ist dieses Verfahren jedoch sehr zeitaufwendig. Weiter unten wird ein Spezialbaustein beschrieben, der die Aufgabe hat, die gleichzeitig vorliegenden IRQs in eine bestimmte Reihenfolge zu bringen. Dieser Interrupt Controller löst diese Aufgabe hardwaremäßig und damit sehr viel schneller.
| Priorität | Ausnahmesituation | |
| 0 | RESET | Rücksetzen, Initialisieren des Systems |
| 1 | TRAPS | Ausnahmesituation bei der Befehlsausführung |
| INT | als Spezialfall: Software-Interrupt | |
| 2 | TRACE | Einzelschritt-Ausführung |
| 3 | NMI | nicht maskierbarer Interrupt |
| 4 | ... | Coprozessor-Fehler |
| 5 | IRQ | maskierbarer Interrupt |
2.3.7 Fallstudie: Interruptkontrolle der Prozessoren 680x0 von Motorola |
Anhand der Motorola-Prozessoren 680x0 (x=0,..,4) soll hier schon kurz auf eine Realisierungsmöglichkeit eines Interrupt-Controllers eingegangen werden. Dieser ist bereits auf dem Chip der Prozessoren integriert.
Die Prozessoren besitzen drei Interruptanschlüsse
,
,
(Interrupt Priority Level, vgl. Bild 2.3-4). Alle interruptfähigen Komponenten sind mit diesen Anschlüssen verbunden. Wird von keiner Komponente ein Interrupt gewünscht, so liegen alle drei Eingänge auf H-Potential, sind also logisch 1. Jede Komponente, die einen Interrupt auslösen will, legt eine bestimmte, ihr fest zugeordnete Bitkombination (¹
111) auf die Anschlußleitungen
-
.
Den Anschlüssen sind im Status-/Steuerregister SR des Prozessors die drei Bits I2, I1, I0 als Interruptmaske (Interrupt Priority Mask) zugeordnet. Diese drei Bits, aufgefaßt als Dualzahlen, definieren 23=8 Prioritätenebenen. Von diesen wird die Ebene 0 nicht benutzt, da sie den Fall repräsentiert, daß kein Interrupt vorliegt, also dem Eingangszustand
=..=
=1 entspricht.
Jede Interruptanforderung wird durch ihre Eingangsbelegung
-
in eine Prioritätenklasse eingeteilt. Diese wird bestimmt durch die als Dualzahl aufgefaßte negierte Information (IPL2, IPL1, IPL0) der Interrupteingänge. Diese Bitkombination bestimmt die Priorität der Komponente nur gegenüber denjenigen Komponenten, die eine andere Bitkombination anlegen.
Einer Interruptanforderung wird nur dann stattgegeben, wenn sie einer Klasse angehört, deren Nummer größer ist als die durch die Statusbits I2-I0 vorgegebene Ebenen-Nummer. Eine Ausnahme bildet die Klasse 7 [(IPL2, IPL1, IPL0)=111], die für den nicht maskierbaren Interrupt (NMI) benutzt wird. In diesem Fall werden die Statusbits I2-I0 nicht ausgewertet und die Interruptroutine unbedingt ausgeführt. Die Klassen 1-6 umfassen die maskierbaren Interrupts. Durch diese Vorgabe bekommt die Klasse 7 die höchste Priorität, die Klasse 1 die niedrigste.
Beispiele
Tabelle 2.3-4 zeigt in aufsteigender Reihenfolge die Prioritäten, den entsprechenden Zustand der Statusbits I2, I1, I0 sowie die möglichen Kombinationen der Interruptsignale
-
für alle zugelassenen Interruptklassen.
| Priorität Ebene |
Statusbits I2I1I0 |
zugelassene Int.-Klassen |
Eingangskombinationen |
| 0 | 0 0 0 | 1 - 7 | 000 - 110 |
| 1 | 0 0 1 | 2 - 7 | 000 - 101 |
| 2 | 0 1 0 | 3 - 7 | 000 - 100 |
| 3 | 0 1 1 | 4 - 7 | 000 - 011 |
| 4 | 1 0 0 | 5 - 7 | 000 - 010 |
| 5 | 1 0 1 | 6 - 7 | 000 - 001 |
| 6 | 1 1 0 | 7 (nur NMI) | 000 |
| 7 | 1 1 1 | keine | --- |
Die von der Komponente ausgegebene Bitkombination muß stets solange an den Anschlüssen
-
anliegen, bis der Prozessor über seine Statusleitungen FCO2-FCO0 (durch die Bitkombination '111') anzeigt, daß er der Interruptanforderung stattgegeben hat (vgl. Abschnitt 2.2). Gleichzeitig gibt er über die Adreßleitungen A1-A3 die Nummer der akzeptierten Interruptklasse aus. Anhand dieser Nummer kann jede Komponente feststellen, ob der Prozessor ihre Interruptanforderung oder aber eine eventuell gleichzeitig vorliegende höher privilegierte Anforderung bearbeitet.
Zu Beginn der Interruptbearbeitung werden die Steuerbits I2I0 im Steuerregister automatisch auf die Prioritätsebene des aktuellen Interrupts gesetzt. Dadurch sind während der Ausführung der Interruptroutine nur noch Interrupts mit höherer Priorität zugelassen. Wie bereits gesagt, hat der NMI die höchste Priorität 7 und kann daher alle (maskierbaren) Interrupts der Klassen 1-6 unterbrechen. Wird aktuell gerade eine NMI-Routine abgearbeitet, d.h. I2I1I0=111, so sind ohne weiteres keine anderen Unterbrechungen zugelassen. Jedoch kann in diesem Fall, wie auch bei der Abarbeitung eines maskierbaren Interrupts, der Anwender durch bestimmte (privilegierte) Befehle das Steuerregister gezielt mit einer speziellen Interruptmaske I2I0 laden und dadurch das Steuerwerk auch Interruptanforderungen niedrigerer Priorität akzeptieren lassen. Jede Interruptroutine wird mit dem Befehl RTE (Return from Exception) beendet. Dabei wird wieder die vor ihrer Ausführung gültige Interruptmaske ins Statusregister geladen, so daß die Abarbeitung des nächsten Interrupts mit höherer Priorität ermöglicht wird.
| Selbsttestaufgabe S2.3-1: (–> Lösungsvorschlag) |
|---|
|
Durch das Betriebssystem werde die Interruptmaske im Steuerregister SR zunächst auf den Wert 2 gesetzt. Nun trete ein Interrupt der Klasse 3 auf. Während der Bearbeitung dieses Interrupts werden weitere Interrupts der Klassen 1, 3 und 4 angefordert. Während der Bearbeitung des zweiten Interrupts der Klasse 3 soll der Reihe nach ein NMI sowie ein Interrupt der Klasse 5 auftreten. Geben Sie alle Zustände der Maskenbits I2-I0 an. |
Werden mehr als 7 Interruptquellen in einem System eingesetzt, müssen diese auf die Klassen 1 - 7 aufgeteilt werden. Innerhalb der einzelnen Klassen muß nun wieder nach einem geeigneten Verfahren eine Auswahl stattfinden, z.B. softwaremäßig durch das oben beschriebene Polling-Verfahren.
Ein häufig benutztes Hardware-Verfahren ist das Daisy Chaining (Daisy Chain: Kette aus Gänseblümchen). Es soll hier für den MC680x0 skizziert werden.

Bild 2.3-4: Daisy Chaining beim Motorola 680x0
Alle Komponenten Ki der gleichen Prioritätsklasse stellen ihre Interruptanforderung INTi durch ein L-Signal auf der gemeinsamen Leitung INT. An dieser sind sie z.B. über Open-Collector-Gatter angeschlossen. Das INT-Signal wird auf einen der acht Eingänge eines Prioritäten-Decoders gegeben. Die Nummer dieses Decoder-Einganges legt die Klassennummer (hier z.B. 5) fest. Der Decoder erzeugt entsprechend dieser Nummer die Information der Prozessor-Eingänge
-
, im Beispiel also (
,
,
)=010. Liegen an mehreren Eingängen des Decoders gleichzeitig Anforderungssignale, muß er nach fest vorgegebenen Prioritäten genau einen dieser Eingänge auswählen. Diese Prioritäten-Reihenfolge kann zwar, sie muß aber nicht mit der auf den Prioritätenklassen des Prozessors vorgegebenen übereinstimmen. Insgesamt erhält man nun eine dreistufige Auswahl unter den Interruptquellen:
Der Prozessor zeigt die Annahme der Interruptanforderung über seine Statussignale FCO2-FCO0, genauer durch FCO2=..=FCO0=1. Über die Adreßleitungen A3,..,A1 wird gleichzeitig die Prioritätsebene der Unterbrechung ausgegeben. (Im Beispiel: A3A2A1=1012=510). Aus diesen Signalen erzeugt die NAND-Schaltung das Quittungssignal
. Dieses wird nun "verkettet" mit den Interrupt-Anforderungssignalen INTi - sukzessiv zu den Komponenten Ki geführt, und zwar leitet die Komponente Ki das Signal
über das ODER-Gatter nur dann an Ki+1 weiter, wenn sie selbst keinen Interrupt angefordert hat. Auf diese Weise hat (innerhalb der festen Prozessor-Prioritätsklasse) jede Komponente eine um so höhere Priorität, je "näher" sie dem Prozessor ist.
| Inhaltsverzeichnis | |||||
| Übersicht Kapitel 2 | |||||
| |||||