Prozessorgrundlagen: Von-Neumann-Architektur, Teil 3

15.06.2004 von PROF. DR. CHRISTIAN SIEMERS 
Im letzten Teil der Serie geht es unter anderem um die verschiedenen Adressierungsarten und das Interrupt-Konzept. Wer sich mit Mikroprozessoren beschäftigt, kommt ohne dieses grundlegende Wissen nicht aus.

Damit ein Mikroprozessor ein allgemeines, berechenbares Problem lösen kann, muss er einen Befehls- beziehungsweise Instruktionssatz anbieten, mit dem es sich beschreiben lässt. Dieser Befehlssatz muss Folgendes beinhalten:

Es wurde bewiesen, dass im Prinzip ein einziger (zusammengesetzter) Befehl genügt, um dem Kriterium der Universalität zu genügen. Dieser Befehl heißt

SUBBEQ X, Y, Z

(subtract and branch if equal) und besteht darin, X = X-Y auszuführen und an Z zu springen, wenn das Ergebnis 0 ist. Die Universalität wird hierbei durch die Subtraktionsoperation in Verbindung mit der bedingten Verzweigung auf Z beziehungsweise dem sequenziellen Weiterlauf im Programmfluss bei einem Ergebnis ungleich 0 erreicht, wobei die Adressierung insbesondere von Y ebenfalls eine Rolle spielt: Y kann die Adresse einer Speicherstelle oder aber eine direkte Konstante bedeuten.

Serie: Prozessorgrundlagen: Von-Neumann-Architektur

Teil 1

Bussysteme und Speicherarten

Teil 2

Leit-/Rechenwerk und Registermodell

Teil 3

Befehlssatz, Adressierungsarten und Interrupt-Konzept

Diesen Artikel und eine ganze Reihe weiterer Grundlagenthemen zu Prozessoren finden Sie auch in unserem tecCHANNEL-Compact "Prozessor-Technologie". Die Ausgabe können Sie in unserem Online-Shop versandkostenfrei bestellen. Ausführliche Infos zum Inhalt des tecCHANNEL-Compact "Prozessor-Technologie" finden Sie hier.

Befehlssatz

In der Praxis existiert kein Mikroprozessor mit nur einem Befehl. Minimal ausgelegte Befehlssätze liegen bei zirka 30 Instruktionen. Im Rahmen der CISC-Philosophie (Complex Instruction Set Computing) wurden sogar Befehlssätze mit möglichst vielen, dann auch komplexen Befehlen favorisiert. Dagegen geht die RISC-Philosophie von einfachen, reduzierten Befehlssätzen in Kombination mit schneller Ausführung der einzelnen Instruktionen aus.

Für die Befehlssätze werden im Allgemeinen folgende Gruppen von verschiedenen Instruktionen genutzt:

Adressierungsarten im Von-Neumann-Prozessor

Die Bearbeitung von Befehlen im Von-Neumann-Prozessor benötigt Operanden, in denen der Bezug zu den Daten hergestellt wird. Hierzu existiert eine Vielzahl von Möglichkeiten, auf diese Daten zuzugreifen. Grundsätzlich sollte dabei deutlich sein, dass abgesehen von einigen Ausnahmen wie NOP (No Operation), WAIT und STOP alle Befehle Operandenzugriff in irgendeiner Form benötigen, häufig sogar mehrere.

Eine grobe Einteilung der Operandenadressierung ist dadurch möglich, dass man implizite und explizite Angaben in der Befehlskodierung vorsieht. Eine implizite Kodierung liegt dann vor, wenn der Operand bereits eindeutig in dem Befehl bestimmt wird. Dies trifft beispielsweise auf Instruktionen wie CLC (Clear Carry Flag) zu. In allen anderen Fällen sind die Operanden jedoch explizit anzugeben. In dieser Kategorie kann man wiederum grob dahingehend einteilen, ob die Daten in internen Registern des Prozessors oder im externen Speicher- sowie Ein-/Ausgabebereich liegen.

Für eine weiter gehende Analyse ist dann die Interpretation der Daten notwendig. Gemäß dem Von-Neumann-Modell können die Daten nicht a priori in ihrer syntaktischen Bedeutung identifiziert werden; dies erfolgt ausschließlich im Kontext des Programmflusses, so auch im Sinne der Adressierung. Beispielsweise sind die Assembler-Kodierungen für die beiden Befehle

LD AX, #10
LD AX, 10

nahezu identisch. Im ersten Fall soll die Zahl 10 in den Akkumulator AX geladen werden. Das bedeutet, dass der Prozessor nach der Dekodierung des Befehls einen Operandenzugriff auf die zu kopierende Zahl benötigt. Im zweiten Fall ist der eigentliche Operand 10 nicht als Zahl zu interpretieren, sondern als Adresse für die Speicherstelle, wo ein Wert zur Kopie in den Akkumulator zu finden ist. Konsequenterweise sind nun auch zwei Operandenzugriffe notwendig, da der erste nur die Adresse und damit die Referenz für den zweiten Zugriff lädt und das benötigte Datum erst hiermit erhältlich ist.

Für eine formale und informelle Beschreibung der wichtigsten Adressierungsarten ist folgende Definition sehr hilfreich:

Definition

Abkürzungen und Schreibweisen für die formale Beschreibung des Operandenzugriffs [1].

reg: PC

Internes Register wird adressiert, PC als Program Counter (spezielles Register)

adr:

Referenzadresse auf eine externe Speicherzelle im Speicher- beziehungsweise Ein-/Ausgabebereich

dat:

Datum (Inhalt einer Speicherzelle oder eines Registers)

()

Indirektion (Inhalt einer Speicherzelle oder eines Registers wird als Adresse interpretiert)

++

Inkrement (Pre- oder Postinkrement, je nach Stellung zum Operanden hin)

--

Dekrement (Pre- oder Postdekrement, je nach Stellung zum Operanden hin)

->

Kopieroperator (Operand links wird auf Operand rechts kopiert)

Die Adressierungsarten im Einzelnen

Die folgende Auflistung der Adressierungsarten ist keineswegs vollständig, da häufig noch spezielle Formen der Adressbildung hinzukommen. Im Rahmen dieses Artikels können wir darauf aber nicht zu detailliert eingehen.

Zu diesen Fällen zählen beispielsweise Adressbildungen für Algorithmen der digitalen Signalverarbeitung (Bit-Reverse Shuffling). Für weitere Studien hierzu ist [2] empfehlenswert.

Implizite Adressierung

Die implizite Adressierung (implicit) ist eine einfache, dennoch weit verbreitete Adressierungsart.

Der Operationscode selbst bestimmt eindeutig das Ziel des Zugriffs, so dass die Load-Phase für diese Adressierungsart entfallen kann.

Beispiel:

SEC (Set Carry), LDAA (Load Accumulator A)

Formale Beschreibung:

"1" -> (reg: Status.Carryflag)

(...) -> (reg: Akkumulator)

In letzterem Beispiel allerdings ist nur ein Teil der gesamten Adressierung implizit. Der LDAA-Befehl benötigt zwei Operanden, eine Quelle und ein Ziel. Das Ziel ist implizit im Operationscode enthalten, die Quelle hingegen ist anschließend noch explizit anzugeben.

Registerdirekte Adressierung

Ist im Gegensatz zum Beispiel LDAA der Registeroperand nicht implizit festgelegt, so muss das Register durch Angabe explizit bestimmt werden. Dies wird registerdirekte Adressierung (register direct, implied) genannt.

Die Kodierung des jeweiligen Registers ist meist so kompakt möglich, dass dies als Teil des Befehlscodes erfolgt. Hierdurch kann wiederum die Load-Phase entfallen oder durch die interne Adressierung in ihrem Zeitbedarf stark minimiert werden.

Beispiel:

MOV AX, BX; (MOVE, Datenkopie)

Formale Beschreibung:

(reg: BX) -> (reg: AX) Dieses Beispiel zeigt eine zweifache registerdirekte Adressierung.

Registerindirekte Adressierung

Mit Hilfe eines Adressregisters lassen sich innerhalb des Prozessors Referenzen speichern, die zur Adressierung der eigentlichen Speicherstelle genutzt werden können.

Dies ist eine Indirektion auf Basis von internen Registern, die registerindirekte Adressierungsart (register indirect) heißt.

Beispiel:

MOV AX, (BP); (MOVE, Datenkopie)

Formale Beschreibung:

(adr:(reg:BP)) -> (reg: AX)

Die Verwendung des zweiten Operanden (BP, Base Pointer) erfolgt in diesem Fall in der beschriebenen Art. Der Datenwert in BP wird in der Decode-Phase des Befehlsablaufs als Referenzadresse auf den Speicherbereich interpretiert und während der Load-Phase als Adresswert am Adressbus ausgegeben. Der Inhalt der entsprechenden Speicherzelle wird in das AX-Register kopiert.

Unmittelbare Adressierung

Programmkonstanten stehen bereits zur Übersetzungszeit fest und lassen sich daher auch im Programmteil speichern. Diese Programmkonstanten werden zur Befehlsbearbeitung dann als Datenwert direkt in ein Register geladen oder anderweitig verwendet.

Die Interpretation eines Wertes im Programmspeicher als konstantes Datum nennt man unmittelbare Adressierung (immediate, literal).

Beispiel:

MOV AX, #10; (Lade in AX die Zahl 10)

Formale Beschreibung:

dat: (reg: PC++) -> (AX)

Die Adressierung des zweiten Operanden erfolgt unmittelbar. Der Zugriff auf diesen Operanden findet während der Load-Phase statt, wobei die Adresse durch den Inhalt des Program Counters festgelegt ist. Im Anschluss daran muss der Programmzähler inkrementiert werden.

Speicherdirekte Adressierung

Das auf den Befehlscode folgende Maschinenwort wird bei dieser Adressierungsart als Referenz, das heißt Adresse auf die externe Speicherstelle gewertet, in der das eigentliche Datum steht. Die Adresse muss daher zur Übersetzungszeit bekannt sein, der Inhalt nicht.

Die speicherdirekte Adressierung (direct) entspricht somit dem Zugriff auf einfache Variablen zum Beispiel aus Hochsprachen.

Beispiel:

MOV DX, 200h; (Kopiere in DX den Inhalt der Speicherstelle 200h, dezimal 512)

Formale Beschreibung:

(adr: (reg: PC++)) -> (DX)

Diese Adressierung hat zur Folge, dass zur Load-Phase zwei Speicherzugriffe notwendig sind. Der erste Zugriff lädt die Adresse in ein internes Adressierungsregister, der zweite Zugriff erfolgt dann auf das eigentliche Ziel, zum Beispiel, um das Datum in den Prozessor zu kopieren.

Speicherindirekte Adressierung

Eine nochmalige Indirektion liegt bei der speicherindirekten Adressierung (indirect) vor.

Das dem Befehlscode folgende Maschinenwort wird nunmehr als eine Adresse interpretiert, die auf eine Speicherstelle zeigt, die wiederum eine Adresse enthält. Die zweite Referenz weist dann schließlich auf das Datum.

Beispiel:

ADD BX, (100h); (Addiere zu BX den Inhalt der Speicherstelle, auf die die Adresse verweist, die an der Speicherstelle 100h, dezimal 256 gespeichert ist)

Formale Beschreibung:

(reg: BX) + (adr: (adr: (reg: PC++))) -> (reg: BX)

Die erweiterte Indirektion ergibt einen weiteren Zugriffszyklus während der Load-Phase. Der Grund dafür ist, dass zweimalig auf Adressen und erst im dritten Zyklus auf das Datum zugegriffen werden kann. Als wesentliche Konsequenz ist eine Verlängerung der Load-Phase zu erwähnen, so dass Software-Entwickler von dieser Adressierungsart häufig absehen.

Im Vergleich zu Hochsprachen sind indirekte Adressierungen bei Referenzierungen über Zeiger (Pointer) notwendig. Um die Verlängerung durch zusätzliche Speicherzugriffszyklen zu vermeiden, wird jedoch häufig auf die registerindirekte Adressierung zurückgegriffen.

Indizierte Adressierung

Die indizierte Adressierung (indexed) wird meist als zusätzliche Modifizierung einer anderen Adressierung eingeführt, beispielsweise als speicherdirekte Adressierung mit Index.

Die Ermittlung der Zugriffsadresse erfolgt dementsprechend zuerst wie in dem jeweiligen Basisverfahren, vor dem letztendlichen Datenzugriff wird ein in einem Register befindlicher Indexwert zur Adresse hinzugezählt.

Beispiel:

MOV AX, 100h (BX); (Kopiere in AX das Datum, das sich an der Stelle 100h zuzüglich des momentanen Inhalts von BX befindet)

Formale Beschreibung:

(adr: (reg: PC++)+(reg: BX)) -> (reg: AX)

Die indizierte Adressierung ist für Tabellenbearbeitungen gut geeignet, da sich die Basisadresse hierbei nicht ändern muss, sondern nur der Zugriffsindex variiert wird. Die Anzahl der Speicherzyklen erhöht sich nicht, falls sich der Index wie in diesem Beispiel in einem internen Register befindet.

Absolute Adressierung

Die absolute Adressierung (absolute, auch absolute long) wird im Rahmen von Kontrollflussbefehlen wie Sprungbefehlen benutzt und besitzt große Ähnlichkeiten zur unmittelbaren Adressierung für Datenzugriffe.

Das auf das Befehlswort folgende Maschinenwort wird in der entsprechend benötigten Wortbreite als absolute Adresse aufgefasst und damit der Program Counter neu geladen.

Beispiel:

JUMP C000h; (Springe an die Stelle C000h, dezimal 49152)

Formale Beschreibung:

adr: (reg: PC++) -> (PC)

Die absolute Adressierung benötigt exakt einen Speicherzugriff, um den Operanden zu laden. Der Ablauf am Bus entspricht damit der unmittelbaren Adressierung für Daten, wobei die Interpretation des Operanden im Rahmen von Kontrollflussbefehlen natürlich abweicht. Eine Variation liegt in der verkürzten absoluten Adressierung (absolute short) vor. Hier wird nur ein Teil der PC-Adresse ersetzt, während die oberen Bits ab einer fest definierten Adresse erhalten bleiben. Der Vorteil dieser Adressierung liegt darin, dass die Speicherung der Sprungadresse weniger Platz benötigt. Nachteilig ist, dass mit Hilfe der verkürzten absoluten Adressierung nur ein Teil des Programmspeichers erreichbar ist.

Absolut indirekte Adressierung

Das auf das Befehlswort folgende Maschinenwort wird im Rahmen der absolut indirekten Adressierung (absolute indirect) als diejenige Adresse interpretiert, an der der Operand gespeichert ist.

Dies bedeutet die gleiche Indirektion wie im Fall der speicherdirekten Adressierung.

Beispiel:

JUMP (400h); (Springe an die Adresse, die an der Speicherstelle 400h, dezimal 1024 gespeichert ist)

Formale Beschreibung:

adr: (adr: (reg: PC++)) -> (PC)

Absolut indirekte Adressierung ist beispielsweise für Sprungtabellen notwendig. Die Tabelle enthält dabei die Zieladressen für die weiteren Programmteile, der Sprung dorthin lässt sich über den Inhalt der Speicherzelle berechnen.

Relative Adressierung

Die relative Adressierung (relative) kommt für Kontrollflussbefehle, insbesondere Verzweigungsbefehle, zum Einsatz.

Das auf den Befehlscode folgende Maschinenwort wird so interpretiert, den Program Counter von seinem momentanen Wert um den dort angegebenen Betrag zu variieren, wobei das Maschinenwort als vorzeichenbehafteter Integerwert zum PC addiert wird.

Beispiel:

BRA 40; (Verzweige um 40 Adressen)

Formale Beschreibung:

adr: {reg: PC + adr: (reg: PC++)} -> (reg: PC)

Das tatsächliche Format im Operanden ist vom jeweiligen Prozessor abhängig. Meistens ist ein 8-Bit-Format die Wahl, um zwecks Verkürzung der Zugriffszei-ten einen möglichst kurzen Operanden im Speicher zu halten. Die Addition ist vorzeichenbehaftet, um die Möglichkeit für Vor- und Rückwärtssprünge zu gewährleisten. Die relative Adressierung ist auf Grund des Lokalitätsprinzips von Programmen außerordentlich effektiv.

Minimaler Satz von Adressierungen

Insbesondere für RISC-Konzepte, die neben der Reduktion der Instruktionsvielfalt auch die Adressierungsarten beschränken, ist es interessant, welche Sätze von Adressierungsarten als vollständig gelten. Die implizite Adressierung ist dabei immer integriert, sie ergibt sich sozusagen automatisch.

Für Kontrollflussbefehle ist ausschließlich die (lange) absolute Adressierung notwendig, wahlweise auch die absolut indirekte Adressierung. Die Nutzung von relativer Adressierung ist nicht zwingend. Sie ist in der Praxis allerdings sehr nützlich, da sie eine kompakte Speicherung ohne zusätzlichen Ladeaufwand in die Adressregister erlaubt.

Für Datenadressierungen ist in jedem Fall die unmittelbare Adressierung (Datenkonstanten) notwendig, ferner eine Adressierung mit Speicheradresse. Hierbei ist die direkte Adressierung alleine ungünstig, weil so zum Beispiel Datenfelder (Arrays) in Schleifen nur über selbstmodifizierenden Code angesprochen werden können. Besser ist die Wahl der indizierten Adressierung oder der registerindirekten Adressierung. Beide bieten gute Möglichkeiten zur Array-Bearbeitung.

Im RISC-Modell MPM3 in Kapitel 4 wird die Kombination {unmittelbar, regis-terindirekt, relativ, absolut-indirekt, implizit} gewählt. Diese Menge ist nicht ganz minimal, jedoch ein guter Kompromiss zwischen Minimalität und praktischen Einsatzpunkten.

Phasen der Befehlsbearbeitung

Zum weiteren Verständnis der Befehlsbearbeitung teilen wir alle Befehle in vier Klassen ein:

Eine Analyse der Abläufe in diesen Befehlen beziehungsweise Befehlsklassen kann anhand der folgenden Aufzählung erfolgen:

1. Die Fetch-Phase: Der erste Zugriff im Ablauf der Befehlsbearbeitung erfolgt, um den eigentlichen Befehlscode in interne Register zu laden. Maßgebend für die Adresse ist der aktuelle Stand des Programmzählers, der am Ende dieser Phase inkrementiert wird. Diese Phase ist für alle Befehle gleich.

2. Die Decode-Phase: Der im internen Register geladene Befehl wird nun dekodiert, um weitere Aktionen entsprechend einleiten zu können. Diese Dekodierung umfasst die Analyse des Befehls selbst, beispielsweise um Informationen zur Befehlsklasse sowie zu Art und Anzahl der benötigten Operanden und deren Adressierungsformat zu erhalten.

3. Die Load-Phase: Die Operanden, die zur Ausführung des Befehls notwendig sind, werden gegebenenfalls in interne Register geladen. Die Phase ist bereits sehr von der Interpretation des Befehls abhängig:

4. Die Execute-Phase: Nach dem Laden aller Operanden kann der Befehl schließlich ausgeführt werden. Maßgebend hierfür ist der geladene Operationscode im internen Befehlsregister.

Die Execute-Phase unterscheidet sich erheblich für die vier Befehlsklassen und ist für jede Instruktion gesondert zu definieren. Arithmetisch-logische Befehle führt die ALU aus, während Kontrollflussbefehle die Register im Leitwerk beeinflussen.

5. Die Write-back-Phase: Die letzte Phase besteht in dem Zurückschreiben des Ergebnisses, etwa in den Akkumulator, in andere interne Register oder in den externen Speicher. Diese Phase steht in engem Zusammenhang mit der Exe-cute-Phase, so dass die Trennung gelegentlich willkürlich erscheinen kann.

Die Unterteilung in fünf auszuführende Phasen im Rahmen der Befehlsbearbeitung ist durchaus variierbar, und zwar begründbar in beide Richtungen. Weniger Phasen sind gleichbedeutend mit einer geringeren Anfälligkeit gegenüber Datenabhängigkeiten im Kontrollfluss [1]. Bei mehr Phasen ist die einzelne einfacher und schneller durchführbar, so dass eine Beschleunigung der Ausführung die Folge sein kann. Die Einteilung in die Ausführungsphasen ist in jedem Fall maßgeblich vom Design des Prozessors bestimmt.

Interrupt-Konzept im Von-Neumann-Prozessor

Die bisherige Darstellung der Details umfasst den Von-Neumann-Prozessor in seiner ursprünglichen Definition. Im Laufe der Weiterentwicklung, insbesondere in Richtung Prozessrechner, hat sich die Notwendigkeit zu verschiedenen Erweiterungen ergeben, die die Kopplung zwischen Rechner und Außenwelt betreffen.

Definition

Prozessoren, die in Prozessen mit Kontakt zur Außenwelt eingesetzt werden, müssen auf Ereignisse reagieren können, die in keinem synchronisierbaren Zeitverhältnis zum sequen-ziellen Programmverlauf stehen. Diese Ereignisse nennt man Interrupt Requests (IRQs, Unterbrechungsanforderungen). Die Erweiterung des Von-Neumann-Prozessors umfasst die Möglichkeit zur Reaktion auf derartige externe Ereignisse.

Diese Definition enthält die Unterbrechungsanforderungen im engeren Sinn, die zur asynchronen Kopplung zwischen Außenprozessen und dem Rechner führen (können). Dieses Konzept wurde durch die Einführung von Software-Interrupts und Exception Handling (Ausnahmebehandlung) erweitert.

Software-Interrupts sind durch spezielle Befehle (etwa SWI, Software-Interrupt oder TRAP) möglich. Sie sind eine gewollte, synchrone Unterbrechung des bisherigen Programmflusses, die wie die asynchronen Hardware-Interrupts behandelt werden. Software-Interrupts nutzt man zum Beispiel zur Kopplung von Programmen mit Betriebssystemaufrufen, da so nicht bekannt sein muss, an welcher Adresse im Programmspeicher diese Betriebssystemroutine gespeichert ist.

Ausnahmen entstehen, wenn im Programmfluss nicht behebbare Rechenfehler (zum Beispiel Division durch 0, Zugriff auf nicht vorhandene Speicherbereiche et cetera) auftreten. Diese Unterbrechungen sind synchron, allerdings nicht gewollt. Die aufgerufene Unterbrechungsroutine soll in diesem Fall die entstandene Situation klären und den Rechner in einen sicheren Betriebszustand überführen.

Unabhängig vom Typ, werden Unterbrechungen alle im gleichen Konzept zur Unterbrechungsbehandlung integriert.

Konzept der Behandlung von Interrupts

Fast alle Prozessoren besitzen eine Möglichkeit zur Integration von Interrupts in ihre Programmierung und ihr Hardware-Interface. Zwischen den verschiedenen Prozessortypen lassen sich große Gemeinsamkeiten im Konzept finden. Unter der Annahme einer einzigen Interrupt-Quelle lässt sich die Behandlung einer Unterbrechung sehr einfach in einen Hardware- und einen Software-Teil gliedern.

Das eigentliche Interrupt-Signal ist zumeist als Bitleitung in den Prozessor realisiert, der im Allgemeinen das Signal zwischenspeichern kann. Man unterscheidet zudem flanken- und zustandssensitive Eingänge, wobei die Unterschiede im Folgenden irrelevant sind.

Das zwischengespeicherte Signal wird spätestens im Rahmen der nächstfolgenden Fetch-Phase ausgewertet. Das heißt, der Prozessor führt den gerade im Ablauf befindlichen Befehl noch komplett aus, um einen sicheren Zustand der CPU zu gewährleisten. Bis zu diesem Zeitpunkt ist die Behandlung des Interrupts hängend (pending). Das Bild "Unterbrechung" zeigt die weitere Bearbeitung in dieser Phase unter Berücksichtigung der möglichen Unterbrechung.

Ist das IRQ-Signal gesetzt, wird anstelle des Fetch auf den nächsten Operationscode der momentane Stand des Programmzählers gesichert, zumeist auf dem Stack. Dieses minimale Maß der Zustandssicherung ist notwendig, um am Ende der Interrupt-Behandlung den alten Bearbeitungsstand wiederherstellen zu können. Häufig werden an dieser Stelle weitere Register (beispielsweise das Statusregister) mit den Flags gespeichert.

Das IRQ-Signal wird gegebenenfalls an dieser Stelle zurückgesetzt und der Programmzähler mit einem für den Prozessor definierten Wert geladen. Dieser Wert zeigt auf die Stelle im Adressraum, an der sich die Software-Routine zur eigentlichen Reaktion auf die Unterbrechung befindet.

Interrupt Service Routine

Im Software-Teil wird die Interrupt Service Routine wie ein normales Programm durchlaufen. Der einzige Unterschied besteht gegebenenfalls in dem Rücksprungteil, wo die zwischengespeicherten Register zu restaurieren sind. Im einfachsten Fall entspricht dies dem Laden des Programmzählers mit dem zwischengespeicherten Wert.

Bei automatischer Speicherung weiterer Register ist hier ein spezieller Befehl RETI (Return from Interrupt) notwendig, der diese bei Rücksprung wiederherstellt.

Dieses Basiskonzept lässt sich auf zwei Arten erweitern:

1. Die Ausführung der Interrupt Service Routine sollte gegebenenfalls unterbindbar sein, um spezielle Software-Teile vor Unterbrechungen zu schützen, deren zusammenhängende Ausführung kritisch ist. Das Unterbinden der Routine ist durch ein Interrupt Enable Flag (beziehungsweise Disable Flag) realisierbar, das Software-gesteuert Phasen zusammenhängender Ausführung ermöglicht.

2. Bei mehreren Interrupt-Quellen sind zwei Probleme zu lösen:

Hierfür sind mehrere Lösungsmethoden denkbar (für Details hierzu siehe [3]). Verschiedenen Interrupt-Quellen werden als Erweiterung des einfachen Enable Flags feste oder wechselnde Prioritäten zugeordnet. So ist eine Unterbrechung nur möglich, wenn die Priorität einen momentanen Wert überschreitet. Die zugehö-rige Service-Routine wird in modernen Prozessorsystemen in einem mehrteiligen Interrupt-Acknowledge-Verfahren durch eine an die Quelle gebundene Vektornummer übermittelt.

Anwendungen

Für Interrupts existiert eine Vielzahl von Anwendungen, auch außerhalb der Kopplung zwischen externen Ereignissen und Programmablauf. Als wichtigste Gebiete sind hier zu nennen:

Ein- und Ausgabe

Anwendungen im Bereich der Ein- und Ausgabe zählen zu den aus der Prozessrechnerwelt stammenden Aufgaben, die die Interrupt-Verarbeitung generiert haben. Sie dienen zur Synchronisierung des Prozessors mit den angeschlossenen Peripheriegeräten. Alternativ wäre ein zyklisches Abfrageverfahren zu erwähnen (Polling), das jedoch zu einem großen zeitlichen Aufwand führen würde.

Betriebssysteme

Für Betriebssysteme stellen Interrupts zwei wichtige Mechanismen zur Verfügung. Zum einen lässt sich in Multitasking-Systemen über Timer-gesteuerte Interrupts die Umschaltung zwischen Tasks realisieren. Ein Time-Slice-Verfahren gestattet die zeitliche Periodizität der Umschaltung mit einer gerechten Zuteilung von Rechenzeit.

Weiterhin können Interrupts in einigen Prozessorarchitekturen auch durch Software-Befehle ausgelöst werden. In diesem Fall ist zwar der ursprüngliche Anwendungsbereich der Service-Routine, die Kopplung asynchroner Peripherie an den Prozessor, nicht mehr gegeben. Dennoch bieten die Software-Interrupts einen wesentlichen Vorteil gegenüber Unterprogrammaufrufen. Der Aufruf eines Interrupts erfolgt ausschließlich mit einer Nummer (dem Vektor), die Implementierungs-Details sind unwesentlich, insbesondere die Startadressen von Routinen werden durch den Prozessor bestimmt.

Fehlerbehandlung

Hard- und Software-Fehler - hierzu zählen etwa unerlaubte Zustände bei Operationen wie Division durch 0 oder unbekannte Operationscodes - lassen sich durch ein erweitertes Interrupt-System so behandeln, dass der Prozessor weiterhin in einem definierten Zustand bleibt beziehungsweise diesen wieder erreicht.

Diese besonderen Interrupts werden häufig als Exceptions (Ausnahmen) oder Traps (Fallen) bezeichnet und mit besonderen Vektornummern sowie hoher Priorität ausgestattet. Die Trap Service Routine muss sich durch eine hohe Stabilität gegenüber den Fehlerquellen auszeichnen. Das heißt, sie muss alle Fehler erzeugenden Zustände mit Sicherheit beseitigen.

Notwendige Erweiterungen im Prozessor

Wie aus dem Bild "Unterbrechung" ersichtlich ist, muss ein Prozessor zur Integration von Interrupts drei Erweiterungen in der Hardware bieten:

Für die Integration einer einfachen Interrupt-Quelle kann man noch auf die Integration eines Stacks verzichten. In diesem Fall ist der momentane Stand des Programmzählers anderweitig zu speichern, etwa in einem speziellen Schattenregister. Zusätzlich darf der Interrupt zum Zeitpunkt der Behandlung nicht ein zweites Mal auftreten, da ansonsten der gespeicherte Wert überschrieben würde.

Neben diesen Basiselementen sind für die weiter führenden Konzepte erhebliche Erweiterungen des Prozessors notwendig. Insbesondere sollte man bei mehrfach möglichen Unterbrechungen nicht mehr auf einen Stack verzichten. Die Einteilung in Prioritäten hingegen, gegebenenfalls weiter führende Maskierungen und die Bestimmung der Vektornummer, wird häufig in besondere Einheiten integriert. Diese Interrupt-Request-Controller werden als Peripherie-Elemente betrachtet und sind damit nicht mehr Bestandteil des Prozessors.

Serie: Prozessorgrundlagen: Von-Neumann-Architektur

Teil 1

Bussysteme und Speicherarten

Teil 2

Leit-/Rechenwerk und Registermodell

Teil 3

Befehlssatz, Adressierungsarten und Interrupt-Konzept

Diesen Artikel und eine ganze Reihe weiterer Grundlagenthemen zu Prozessoren finden Sie auch in unserem tecCHANNEL-Compact "Prozessor-Technologie". Die Ausgabe können Sie in unserem Online-Shop versandkostenfrei bestellen. Ausführliche Infos zum Inhalt des tecCHANNEL-Compact "Prozessor-Technologie" finden Sie hier.

Literatur

[1] Christian Siemers: Prozessorbau - München, Wien: Carl Hanser Verlag, 1999

[2] Beierlein, Th., Hagenbruch, O. (Hrsg.): Taschenbuch Mikroprozessortechnik - 2. Auflage - Fachbuchverlag Leipzig im Carl Hanser Verlag, München Wien, 2001

[3] Oberschelp, W.; Vossen, G.: Rechneraufbau und Rechnerstrukturen - 8. Auflage - München, Wien: R. Oldenbourg-Verlag, 2000