Inhaltsverzeichnis
  Übersicht Kapitel 2
2.5 Das Adreßwerk       2.7 Die Systembus-Schnittstelle

2.6 Der Registersatz


2.6.1 Registertypen

Unter einem Register versteht man eine Speicherzelle mit minimaler Zugriffszeit, die ihren Inhalt ohne große Verzögerung zur Verfügung stellt. Dies wird einerseits dadurch erreicht, daß die Register meist auf dem Chip untergebracht sind. Dadurch entfällt das zeitraubende Umschalten der externen Adreß- und Datenwege. Andererseits kann wegen der relativ kleinen Anzahl von Registern ihre Auswahl durch individuelle Steuerleitungen geschehen, wodurch wiederum die Zeit der Adreßdecodierung entfällt. Die Menge der Register eines Prozessors wird als Registersatz (Register Set) bezeichnet.
Durch die Verwendung getrennter Ein- und Ausgänge können die Register zwischen zwei verschiedene interne Busse (Eingangsbus, Ergebnisbus) des Prozessors gehängt werden. Dies verkürzt wiederum die Zugriffszeit und erlaubt das Schreiben eines Registers gleichzeitig zum Lesen eines zweiten Registers. Insbesondere ist dadurch die Übertragung eines Registerinhaltes in ein anderes Register in einem Taktzyklus möglich.
Größere Registersätze müssen hingegen als Schreib-/Lesespeicher mit zusätzlichem Adreßdecoder realisiert werden, der zur eindeutigen Auswahl eines Registers dient. In diesem Fall spricht man auch von einem Registerspeicher oder Registerblock (Register File). In der einfachen Form kann zu jedem Zeitpunkt höchstens ein Register selektiert werden. Hier benötigt der angesprochene Registertransfer wenigstens zwei Taktzyklen und ein Hilfsregister zum Zwischenspeichern des transferierten Registerinhaltes. Bei den zum Abschluß dieses Abschnitts beschriebenen Multiport-Registersätzen sind die Adreßdecoder mehrfach ausgelegt, so daß "gleichzeitig", d.h. in einem Zyklus, mehr als ein Register zum Schreiben oder Lesen selektiert werden kann.
Oft besitzen einige der Register spezielle Funktionen, die durch Steuerleitungen aktiviert werden. Dazu gehören z.B. das Rücksetzen auf den Wert 0, das Inkrementieren bzw. Dekrementieren um 1 oder das Verschieben des Inhalts um ein Bit vorwärts, d.h. zu höheren Wertigkeiten, oder rückwärts.

Selbsttestaufgabe S2.6-1:  (–>Lösungsvorschlag)

Skizzieren Sie den Aufbau eines universellen Registers, das alle erwähnten Funktionen ausführen kann: Rücksetzen, Vorwärts/Rückwärts-Schieben, Vorwärts/Rückwärts-Zählen.

Bild 2.6-1 zeigt den typischen Registersatz eines Mikroprozessors. Die Register können unterschieden werden in Datenregister, Adreßregister und Spezialregister.


Bild 2.6-1:  Registersatz eines Mikroprozessors


Datenregister

Die Datenregister (Data Register) dienen zur Zwischenspeicherung der Operanden bei allen arithmetischen und logischen Operationen. Zu ihnen gehören insbesondere die Akkumulatoren, die als "Sammelregister" für die ALU bei den meisten Operationen einen Eingabeoperanden und alle Ausgabeoperanden aufnehmen (vgl. Abschnitt 2.4.1). 16/32-bit-Mikroprozessoren besitzen meist keine spezialisierten Akkumula toren mehr, sondern statt dessen Datenregister, die alle in identischer Weise benutzt werden können. Die Breite der Datenregister stimmt in der Regel mit der Verarbeitungsbreite des Integer-Rechenwerks überein.


Adreßregister

Die Adreßregister (Address Register) enthalten die Adressen oder Teile davon, die zur Auswahl eines Operanden oder eines Befehls im Speicher herangezogen werden. Dabei unterscheidet man noch weiter zwischen Basis- und Indexregistern (s. Bild 2.6-2). Diese Unterscheidung ist oft jedoch nur durch die Verwendung der Register in den Befehlen, nicht jedoch durch unterschiedliche Hardware erklärbar.


Bild 2.6-2:  Zur Funktion von Basis- und Indexregister


Bild 2.6-3:  Zur automatischen Modifikation von Indexregistern


Bei der ersten Variante (in Bild 2.6-3a) wird nach der Benutzung des Registerwertes dieser um den Wert n erhöht und in das Register eingetragen. Man spricht deshalb von einer Post-Inkrementierung. Bei der zweiten Variante (in Bild 2.6-3b) wird der Wert des Indexregisters vor der Adressierung einer Speicherzelle um n erniedrigt. Dieser erniedrigte Wert wird dann in das Register zurückgeschrieben. Man spricht hier von einer Pre-Dekrementierung. Die Größe n bestimmt den Anfang des nächsten adressierbaren Datums im Speicherbereich. Sie muß im Befehl angegeben werden. Für sie gilt typischerweise n=1, 2, 4, 8, je nach der Länge (in byte) der Daten im Speicherbereich.
Im Bild 2.6-3c ist ein Symbol für ein Register gezeichnet, das beide Modifikationen erlaubt. Vereinfachend spricht man von einem Autoinkrement/Autodekrement-Register. Natürlich ist es auch möglich, den Zeitpunkt der Inkrementierung bzw. Dekrementierung zu vertauschen, und so zu einer Pre-Inkrementierung bzw. Post-Dekrementierung zu kommen.
Im Bild 2.6-4 ist eine weitere, bei modernen 16/32-bit-Prozessoren gebräuchliche Methode skizziert, den Wert eines Indexregisters zu modifizieren. Sie wird Skalierung genannt. Bei ihr kann der Inhalt des Indexregisters vor der Auswertung mit einem skalaren Faktor n multipliziert werden. Für n sind, wiederum in Abhängigkeit von der aktuellen Länge der Daten (in byte), die Werte n=1, 2, 4, 8 üblich. In diesem Fall kann man sich zur Selektion des nächsten Datums darauf beschränken, den Registerinhalt jeweils nur um den Wert 1 zu inkrementieren bzw. zu dekrementieren. Die Länge des Registers wird dadurch effektiver genutzt.


Bild 2.6-4:  Register mit Skalierung


Universelle Register

Bei vielen 16/32-bit-Prozessoren, insbesondere den RISC-Prozessoren, wird nicht mehr zwischen den Daten- und Adreßregistern unterschieden. Dort spricht man dann von universellen Registern (General Purpose Register), die wahlweise als Adreß- oder Datenregister benutzt werden können.


Spezialregister Darüber hinaus besitzt jeder Prozessor noch eine mehr oder weniger große Anzahl von Spezialregistern (Special Purpose Registers). Einige von ihnen werden als Systemregister bezeichnet, da sie nur Hilfsfunktionen im Prozessor ausführen und nicht gezielt vom Programm her angesprochen werden können. Dazu zählen zum einen die Hilfsregister der ALU, die wir im Abschnitt 2.4.1 beschrieben haben. Andererseits gehören dazu insbesondere der Programmzähler (Program Counter - PC, Instruction Pointer - IP), der zu jedem Zeitpunkt auf die im nächsten Programmschritt anzusprechende Speicherzelle zeigt, sowie der Adreßpuffer und der Datenbuspuffer.

Obwohl letztgenannte Register funktional zu anderen Komponenten des Prozessors, wie dem Adreßwerk, der Systembus-Schnittstelle oder dem Steuerwerk, gehören, werden sie der Vollständigkeit halber meist bei der Darstellung des Registersatzes mit aufgeführt.
Andere Spezialregister können durch Maschinenbefehle direkt adressiert werden. Dazu gehören z.B.:

Neben den hier erwähnten Registern besitzen die meisten Prozessoren noch eine Reihe weiterer (System-)Register, deren Funktion jedoch so speziell ist, daß sie hier nicht dargestellt werden können. Auf sie wird an entsprechender Stelle eingegangen.
Die benutzerzugänglichen Register, d.h. die vom Programm direkt ansprechbaren Register, mit ihrer Struktur und festgelegten Funktion werden häufig als Programmiermodell des Prozessors bezeichnet, denn diese fassen alle für den (Assembler-)Programmierer wesentlichen Eigenschaften der Prozessor-Hardware zusammen.
Mikroprozessoren stellen dem Benutzer zwischen 4 und einigen hundert Register zur Verfügung. Eine untere Grenze lieferte der Prozessor TMS 9900 der Firma Texas Instruments. Dieser enthielt auf dem Chip lediglich zwei Adreßregister (Workspace Pointer), die auf einen bestimmten Speicherbereich zeigten. Die ersten 16 Wörter dieses Speicherbereiches wurden dann jeweils als Prozessorregister benutzt.
Bei einigen Prozessoren kann man in einem Maschinenbefehl mehrere interne Register zu einem längeren zusammenfassen oder aber auch nur einen Teil eines Registers (z.B. ein 16-bit-Wort oder ein Byte) getrennt ansprechen. Dies wird in abschließenden Fallstudien gezeigt. Dazu haben wir Beispiele ausgewählt, die im Rahmen der Mikroprozessor-Geschichte eine gewisse Bedeutung erlangt ahben.

2.6.2 Der Stack

Der Stack (Kellerspeicher) ist ein besonderer Speicherbereich, der hauptsächlich zur Ablage des Prozessor-Status und des Programmzählers vor der Ausführung von Unterprogrammen oder Unterbrechungsroutinen dient, aber auch zur Übergabe von Parametern an diese Routinen und zur kurzzeitigen Lagerung von Daten als Zwischenergebnisse benutzt werden kann. Er ist normalerweise im Arbeitsspeicher angelegt (Software Stack). Einige der ersten Mikroprozessoren, aber auch neuere Entwicklungen und DSPs, besitzen jedoch auf dem Prozessorchip selbst einen Kellerspeicher (Hardware Stack) mit einer notwendigerweise sehr beschränkten Kapazität. Als Vorteil hat er jedoch eine erheblich kürzere Zugriffszeit als ein Software-Stack.
Moderne Prozessoren erlauben die gleichzeitige Verwaltung mehrerer getrennter Kellerspeicher im Arbeitsspeicher. Diese können z.B. einerseits dem Betriebssystem (System Stack), andererseits den Anwenderprogrammen (User Stack) oder ihren Daten (Data Stack) zugeordnet sein. Das Prinzip des Stacks besteht im wesentlichen darin, daß das zuletzt dort eingetragene Datum als erstes wieder gelesen und dabei aus ihm entfernt wird. Man spricht deshalb von einem Last-In-First-Out-Speicher (LIFO). Diese Verarbeitungsdisziplin erinnert an die übliche Behandlung eines Aktenstapels, so daß man auch den Ausdruck Stapelspeicher benutzt.
Das Stackregister (Stack Pointer - SP) enthält einen Zeiger auf das zuletzt in den Stack eingetragene Datum. Im Vorgriff auf Abschnitt 3.2, sei hier schon erwähnt, daß es im Befehlssatz des Prozessors spezielle Befehle zur Datenübertragung in den bzw. aus dem Stack gibt: Durch den Befehl PUSH wird der Inhalt eines oder mehrerer Register in den Stack übertragen, durch den Befehl PULL (manchmal auch mit POP bezeichnet) von dort geladen. Bei jedem Zugriff zum Kellerspeicher über das Stackregister wird dessen Inhalt in Abhängigkeit von der ausgeführten Operation automatisch erhöht oder erniedrigt. Üblicherweise ist ein PUSH-Befehl mit der Erniedrigung des Stackregisters verbunden, so daß der Stack "nach unten wächst". Dabei sind für ein Befehlspaar PUSH/PULL beide der bei den Indexregistern beschriebenen Möglichkeiten "predekrement/postinkrement" oder "postdekrement/preinkrement" möglich. Im Bild 2.6-5 ist die erstgenannte Alternative der Verwaltung des Stackregisters skizziert. Damit wollen wir die Beschreibung des Stacks beenden.


Bild 2.6-5:  Verwaltung des Stackregisters



2.6.3 Registersätze realer Mikroprozessoren

In diesem Abschnitt wollen wir in einigen Fallstudien die Registersätze wichtiger Mikroprozessor-Familien darstellen.


Fallstudie 2.6-1: Das Programmiermodell der x86-Prozessoren


Im Bild 2.6-6 sind die wesentlichen Register der x86-Prozessoren dargestellt. (Bis auf wenige Abweichungen und Ergänzungen stimmen die Registersätze aller dieser Prozessoren überein.) Der x86-Registersatz ist eine "Aufwärts"-Entwicklung der Registersätze der Intel-Prozessoren 8080 und 8086. Der 8080 besaß die im dargestellten Registersatz integrierten 8-bit-Register AL, DH, DL, CH, CL, BH, BL (nicht AH!) sowie das 16-bit-Stackregister SP (Stack Pointer) und den 16-bit-Programmzähler IP (Instruction Pointer). Wie im Bild 2.6-6 angedeutet ist, konnten die 8-bit-Register teilweise durch spezielle Befehle als verkettete 16-bit-Register benutzt werden, die im Bild die Bezeichnungen DX, CX, BX tragen. In diesen Befehlen wurde das Register AL mit dem Statusregister (Flag Register) zu einem 16-bit-Register PSW (Processor Status Word) zusammengefaßt.
Beim Übergang zum 16-bit-Prozessor 8086 wurden nun alle Register als 16-bit-Register ausgeführt. Sie tragen im Bild das Postfix ..X. Um aber auf diesem Prozessor auch Programme für den 8080 laufen lassen zu können und zur Unterstützung von byte-orientierten Problemen (z.B. der Zeichenverarbeitung) kann man beim 8086 und seinen Nachfolgern (80186, 80286) jedes Register weiterhin byteweise ansprechen. Dies geschieht in Assemblernotation durch das Anhängen der Buchstaben ..H (höherwertiges Byte, High Byte) bzw. ..L(niederwertiges Byte, Low Byte).
Die Erweiterung zu den 32-bit-Prozessoren führte dann zu 32-bit-Registern, die im Bild 2.6-6 durch das Präfix E.. (extended) gekennzeichnet sind.
Obwohl grundsätzlich alle Register zum Zwischenspeichern von Daten und Adressen dienen können, wird ihnen doch durch bestimmte Befehle eine spezielle Funktion zugewiesen, an die der in ihrem Namen unterstrichene Buchstabe erinnern soll:

  • Das EAX-Register dient hauptsächlich als Akkumulator für die Ergebnisse von arithmetischen und logischen Operationen.
  • Das EDX-Register wird als Datenregister (Data Register) in Ein-/Ausgabe-Operationen benutzt.
  • Das ECX-Register dient als Zählregister (Count Register) für die Abarbeitung von Schleifen.
  • Die beiden Register EBX und EBP werden als Basisregister (Base Register) benutzt.
  • Die Register ESI, EDI sind Indexregister (S für Source - Quelle, D für Destination - Ziel).
  • Das ESP-Register ist als Stackregister (Stack Pointer) vorgesehen.

Bild 2.6-6:  Der Registersatz der Intel-x86-Prozessoren


Spezialregister Durch den 32-bit-Programmzähler (IP) können bis zu 232 Speicherzellen (4 Gbyte) physikalisch adressiert werden.
Von den Flags des Statusregisters (Flag Register - EFR), die nicht bereits in diesem Abschnitt beschrieben wurden, sollen hier nur noch die Flags PF und DF erklärt werden. Auf die Erklärung der anderen muß aus Platzgründen verzichtet werden.
  • Das Paritätsbit PF (Parity Flag) zeigt an, ob die Anzahl der '1'-Bits im niederstwertigen Byte des Operanden gerade ist. Dieses wird zur Erkennung von Fehlern benutzt, die bei der Übertragung von Datenbytes zwischen dem Mikroprozessor und Peripheriegeräten auftreten (vgl. Selbsttesteaufgabe 2.4.1.)

  • Das Richtungsbit DF (Direction Flag) gibt an, ob lange Datenblöcke (Zeichenketten, Strings) im Speicher in aufsteigender oder absteigender Ordnung bearbeitet werden sollen. (Im Kapitel 3 werden diese Blöcke bzw. die Befehle zu ihrer Verarbeitung näher beschrieben.)

Die 16-bit-Segmentregister dienen der Verwaltung des Arbeitsspeichers. Hier soll nur erwähnt werden, daß sie die Nummern verschiedener Speicherabschnitte (Segmente) enthalten und vom Adreßwerk dazu benutzt werden, aus der in einem Befehl vorgegebenen logischen Adresse eine physikalische (Speicher-)Adresse zu berechnen. Die Segmentregister werden für jedes in Ausführung befindliche Programm mit individuellen Werten geladen. Die Segmente enthalten logisch unterscheidbare Teile des Programms, und zwar

  • das Code-Segment CS
den Maschinencode,
  • das Stack-Segment SS
den Kellerspeicher,
  • die Daten-Segmente DS, ES, FS, GS
die Daten.

Neben den bisher erklärten Registern besitzt der Prozessor noch eine Reihe weiterer spezieller Systemregister, die einerseits der Fehlersuche und dem Testen (Debug and Test) in Programmen, andererseits der Auftragsverwaltung in Multitasking-Betriebssystemen dienen, also solchen Betriebssystemen, die (quasi-)gleichzeitig verschiedene Programme ausführen können. Hier soll nur kurz auf das letzte im Bild 2.6-6 dargestellte Register eingegangen werden. Es trägt die Bezeichnung CR0 (Control Register 0) und wird häufig auch als Maschinenstatuswort MSW bezeichnet. In ihm werden die Zustandsflags gehalten, die sich nicht auf ein spezielles Programm (einen speziellen Auftrag) beziehen, sondern den Zustand des gesamten Systems beschreiben. (Diese Flags sollen hier nur erwähnt werden, ohne daß wir näher auf ihre Funktion eingehen können.)

  • Das Paging (Enabled) Flag PG aktiviert eine bestimmte Art der Speicherverwaltung, die als Seitenwechselverfahren (Paging) bezeichnet wird.

  • Mit dem Processor Extension Flag ET wird der Typ eines (von zwei möglichen) im System integrierten Coprozessors für arithmetische Aufgaben festgelegt.

  • Die drei Flags
    • TS: Task Switched Flag,
    • EM: Emulate Coprocessor Flag,
    • MP: Monitor Coprocessor Flag
    bestimmen das unterschiedliche Verhalten des Systems in Abhängigkeit davon, ob ein Coprozessor vorhanden ist oder nicht.

  • Das Protection Enable Flag PE entscheidet über die Art der Speicherverwaltung: virtuell (Protected Mode) oder nicht virtuell (Real Mode). (Im virtuellen Modus werden die im Programm angegebenen Adressen zunächst als logische Adressen interpretiert und dann durch die Speicherverwaltung in physikalische Adressen umgewandelt. Darauf wird im Rahmen dieser Vorlesung nicht näher eingegangen.)

Im Bild 2.6-7 sind die Register der Gleitpunkt-Einheiten (Floating-Point Unit - FPU) der x86-Prozessoren dargestellt.


Bild 2.6-7:  Die Gleitpunkt/MMX-Register der x86-Prozessoren

Jedes Floating-Point-Register besitzt 64 Bits für die Mantisse, 15 Bits für den positiven Exponenten und 1 Bit für das Mantissen-Vorzeichen. Die unteren 64 Bits der Register werden alternativ auch von der MMX-Einheit (Multimedia Extension, s. Abschnitt 2.4.3) mitbenutzt. Für die FPU existieren drei Spezialregister. Die Register der FPU werden in Form eines kleinen Hardware-Stacks verwaltet. Jede zweistellige Operation wirkt stets auf die beiden zuletzt eingeschriebenen Werte im Registersatz. Das Statusregister enthält dazu - neben den im Abschnitt 2.4.4 beschriebenen Statusflags - in zwei Bits TOP (Top of Stack) das "Stackregister", also den Zeiger auf den "jüngsten" Eintrag. Für jedes Datenregister enthält das Tag-Wort zwei Bits, in denen codiert abgelegt ist, ob das entsprechende Register leer ist oder der Eintrag eine gültige bzw. ungültige Zahl (NaN - Not a Number) oder die Zahl 0 enthält.
Zu den dargestellten Registern der FPU kommt noch ein Speicher, das Konstanten-ROM, in dem einige Dutzend wichtige Gleitpunkt-Konstanten abgelegt sind (vgl. Abschnitt 2.4.3).


Fallstudie 2.6-2: Das Programmiermodell der Motorola-680x0-Prozessoren
Im Bild 2.6-8 ist der Teil des Registersatzes des Motorola MC680x0 dargestellt, der bei allen Mitgliedern der Familie realisiert ist. Darüber hinaus stimmt er weitgehend mit dem Registersatz der erfolgreichen Familie von 32-bit-Mikrocontrollern der Firma Motorola überein. Er entspricht sehr gut unserem allgemeinen Modell in Bild 2.6-1.

Bild 2.6-8:  Der Registersatz des Motorola MC680x0

  • In den 8 Datenregistern können 8, 16 oder 32 bit breite Informationen angesprochen werden (Byte, Wort, Doppelwort), und zwar in den Bitpositionen, wie es durch die senkrechten Trennstriche angedeutet ist. Sie können neben ihrer Funktion als Datenregister auch als Indexregister benutzt werden.

  • Die Adreßregister A0 - A6 werden als Basisregister, aber auch als Indexregister eingesetzt.

  • Die drei Stackregister A7, A7', A7" werden unter derselben "Registeradresse" angesprochen. Abhängig vom Betriebszustand des Prozessors ist jeweils genau eines von ihnen aktiv. Sie entsprechen den folgenden Typen des aktuell bearbeiteten Programms:
    • A7:     User Stack Pointer (USP):         Benutzerprogramm
    • A7':    Interrupt Stack Pointer (ISP):    Unterbrechungsroutine
    • A7":   Master Stack Pointer -MSP:       Betriebssystemroutine

Die Adreß- und Stackregister können auch als Datenregister benutzt werden. In diesem Fall werden aber in Abhängigkeit von einer ausgeführten Operation keine Flags im Statusregister geändert. Außerdem sind nur 16- oder 32-bit-Datenverarbeitung (Wort bzw. Doppelwort) möglich. Bei der Abspeicherung eines Wortes werden die oberen 16 Bits vorzeichenrichtig ergänzt (Sign Extension), d.h. das Wort W wird für
  • W aus {$0000,...,$7FFF}  zu  $0000 W,
  • W aus {$8000,...,$FFFF}  zu  $FFFF W  erweitert.
Das Vector Base Register ist das oben erwähnte Basisregister für die Interruptvektor-Tabelle im Speicher (vgl. Abschnitt 2.3).
Die beiden Cache-Register CACR (Cache Control Register) und CAAR (Cache Address Register, nur MC68020) steuern die Benutzung eines kleinen, schnellen Zwischenspeichers im Mikroprozessor, in dem wenige Maschinenbefehle gespeichert sind (Instruction Cache). (Auf sie und die Realisierung eines Cache-Speichers wird später ausführlich eingegangen.)
Das Statusregister SR enthält neben den Zustandflags im CCR (Condition Code Register) sieben weitere Flags:
  • Die Flags T1/T0 sind Trace Flags, die die Abarbeitung eines Programms in Einzelschritten (in zwei verschiedenen Modi) steuern.

  • Das Supervisor/User Flag S zeigt an, ob der Prozessor im Betriebssystem- oder Benutzermodus arbeitet, insbesondere also, ob eines der Stackregister A7', A7" oder aber das Stackregister A7 aktiv ist.
    Läßt das Supervisor/User Flag erkennen, daß der Betriebssystem-Modus vorliegt, so zeigt das Master/Interrupt Flag M an, ob eine Interruptroutine mit dem Stackregister A7' oder eine Betriebssystemroutine mit dem Stackregister A7" ausgeführt wird.

  • Die Interrupt Flags I2 - I0 legen fest, welche Priorität eine Unterbrechungsanforderung mindestens haben muß, damit ihr stattgegeben wird. (Auf diese Flags waren wir im Abschnitt 2.3 näher eingegangen.)
Das "Top-Modell" der Familie, der MC68040, enthält bereits eine integrierte FPU. Deren Registersatz umfaßt - wie die FPU der Intel-Prozessoren - ebenfalls acht 80-bit-Datenregister, ein Status- und ein Steuerregister. Jedoch werden die Datenregister nicht als Hardware-Stack verwaltet, sondern sind gezielt selektierbar.


Fallstudie 6-9-3: Das Programmiermodell der PowerPC-Prozessoren
Als drittes Beispiel wollen wir nun den Registersatz eines typischen RISC-Prozessors vorstellen. Dazu haben wir die PowerPC-Familie der Firmen Motorola und IBM ausgewählt. Wir beschränken uns dabei auf die Register, die dem Benutzer (im User Mode) zugänglich sind. Neben den dargestellten Registern besitzen die Mitglieder dieser Prozessorfamilie eine unterschiedliche große Anzahl von Registern, die nur im Betriebssystem-Modus (Supervisor Mode) angesprochen werden können und insbesondere der Ausnahmebehandlung und der Speicherverwaltung dienen.
Der Benutzer-Registersatz ist im Bild 2.6-9 dargestellt. Er besteht im wesentlichen aus zwei Registerspeichern (Register Files):
  • Der Speicher der universellen Register GPR31 - GPR0 (General Purpose Registers) besteht aus 32 Register der Länge 32 bit, die zur Zwischenablage von Integer-Daten und Adressen dienen. Das 32-bit-Bedingungsregister CR (Condition Code) enthält acht 4 bit breite Felder CRi (i=0,..,7) zur Aufnahme der Statusflags nach arithmetisch/logischen Operationen und den Ergebnissen von Vergleichsoperationen.
    • CR0 zeigt für Integer-Operationen an, ob das Ergebnis kleiner (less than - LT), größer (greater than - GT) oder gleich 0 (equal - EQ) ist. Ein weiteres Flag SO (Summary Overflow) wird gesetzt, wenn wenigstens eine Teiloperation einer komplexen zusammengesetzten Operation einen Überlauf ergab.
    • CR1 enthält Flags, die das Auftreten von Ausnahmesituationen in der FPU anzeigen, und zwar für die folgenden Fälle: Überlauf, ungültige Operation, beliebige Ausnahmesituation aufgetreten, mindestens eine aktivierte Ausnahmesituation (s.u. FPSCR) aufgetreten.
    • CR2 - CR7 (aber auch CR0, CR1) können in Maschinenbefehlen wahlfrei als Bitfeld für die Aufnahme der Ergebnisse von Vergleichsbefehlen angegeben werden mit den für CR0 (s.o.) angegebenen Bedingungen - hier aber für Integer- oder Gleitpunkt-Operationen. Die wahlfreie Festlegung der Vergleichsflags erlaubt es dem Programmierer, die Ermittlung der Bits durch Vergleichsbefehle und ihre Auswertung durch Verzweigungsbefehle zu entkoppeln - ohne die Gefahr, diese Bits durch zwischendurch ausgeführte Befehle zu überschreiben.

    Bild 2.6-9:  Registersatz der PowerPC-Familie (Ausschnitt)

  • Der 2. Registerspeicher FPR31 - FPR0 (Floating-Point Registers) umfaßt 32 Register der Länge 64 bit und dient zur Aufnahme von doppelt-genauen Gleitpunktzahlen nach dem IEEE-754-Standard. Das FPSCR-Register (Floating-Point Status and Control Register) enthält 2 Dutzend Flags zur Anzeige von Ausnahmesituationen der FPU. Mit 5 Bits kann festgelegt werden, welche der Situationen "ungültige Operation", "Überlauf", "Unterlauf", "Division durch 0" oder "Ergebnis gerundet" zu einem Programmunterbrechung führen soll (aktiviert - enabled). In einem weiteren Bitfeld kann eine der vier Rundungsweisen nach IEEE-754 ausgewählt werden.

  • Das XER-Register enthält in den drei höchstwertigen Bits das Übertragsbit (Carry Flag), Überlaufbit (Overflow Flag) und das oben beschriebene Summary Overflow Flag SO. Die 7 niederwertigen Bits stellen einen Zähler dar für Befehle, die eine Folge von Bytes (String) in den GPR-Registersatz laden bzw. von dort in den Speicher transferieren. Alle anderen Bits sind unbenutzt (0).

  • Das Register CTR (Count) dient als Zählregister für einen kombinierten Verzweigungsbefehl, der den Inhalt von CTR dekrementiert und nur dann einen Sprung ausführt, wenn CTR=0 erreicht ist.



2.6.4 Registerspeicher


6.8.4.1 Aufbau eines Registerspeichers

Bereits zu Beginn der Mikroprozessor-Geschichte versuchte man, durch den Einsatz großer Registerspeicher auf dem Prozessor-Chip den hemmenden Einfluß zu verringern, der durch den Unterschied zwischen der (relativ hohen) Prozessorgeschwindigkeit und dem langsamen Hauptspeicher auftrat. So besaß bereits Mitte der 70er Jahre der F8-Prozessor der Firma Fairchild einen Registerblock aus 64 Registern (der Länge 8 bit), der als "Notizbuch-Speicher" (Scratchpad Registers) für die kurzzeitige Aufnahme häufig benutzter Daten (Operanden) und Adressen diente. Auch bei den Mikrocontrollern gibt es seit vielen Jahren Registerblöcke mit bis zu 256 Registern. Bei den seit Anfang der 80er Jahre auf dem Markt erscheinenden RISC-Prozessoren gehört ein großer Registerblock (mit wenigstens 32 Registern) zu den charakterisierenden Eigenschaften.
Dennoch ist auffällig, daß die Größe der implementierten Registerspeicher in keinem Verhältnis steht zu den bei modernen Mikroprozessoren auf dem Chip integrierten (Cache-)Speichern. Ein Grund liegt darin, daß ein großer Registerspeicher eine lange Adresse zur Selektion eines bestimmten Registers benötigt und diese Adresse im Befehlscode (OpCode) untergebracht werden muß.

Ein weiterer Grund, der die Komplexität großer Registerspeicher sehr stark anwachsen läßt, wird aus der bereits erwähnten Tatsache deutlich, daß in modernen Prozessoren nicht nur eine Komponente, sondern mehrere Komponenten gleichzeitig auf den Registerspeicher zugreifen müssen. Daher müssen die Registerblöcke als Multiport-Registerspeicher ausgelegt sein. Man findet heute Registerblöcke mit bis zu 16 Ein-/Ausgabeports. Da typische Rechenwerks-Operationen zwei Eingabeoperanden zu einem Ausgabeoperanden verarbeiten, sind meist mehr Ausgabeports als Eingabeports vorhanden. Im Bild 2.6-10 ist beispielhaft ein 4-Port-Registerspeicher skizziert.


Bild 2.6-10:  Aufbau eines Multiportspeichers


Der Multiport-Registerspeicher erlaubt das gleichzeitige Auslesen und Einschreiben mehrerer Register. Dazu verfügt er über mehrfache Schnittstellen zu unterschiedlichen internen Bussen des Prozessors, die mit dem Begriff Port bezeichnet werden. Zur Selektion der beteiligten Register besitzt der Speicher einen vervielfältigten Adreßdecoder. Die technische Realisierung der Register, z.B. aus Master-Slave-Flipflops, erlaubt es sogar, im selben Taktzyklus dasselbe Register sowohl als Eingabe- wie auch als Ausgaberegister anzusprechen.

Über einen Ein-/Ausgabeport E/A (s. Bild 2.6-10) können die Register aus dem Hauptspeicher, einem internen (Cache-)Speicher oder einer Schnittstellenkomponente geladen bzw. ihre Inhalte dorthin ausgegeben werden. Über die beiden Ausgabeports A0, A1 werden zwei Registerinhalte als Operanden an die ALU übergeben. Das Ergebnis der ALU-Operation wird über den Eingabeport E in den Registerblock (zurück-)geschrieben (Write back).
Die im Bild 2.6-10 gezeigte Komponente Scoreboard ("Anzeigetafel") verhindert, daß Datenabhängigkeiten zwischen mehreren Operationen, die momentan ausgeführt werden, zu falschen Ergebnissen führen. Ein Register, das in einem in Ausführung befindlichen Befehl als Ergebnisregister selektiert wurde, wird z.B. im Scoreboard solange gekennzeichnet, bis das neue Ergebnis dort eingetragen wurde. Dadurch kann vermieden werden, daß nachfolgende Befehle vorzeitig auf den alten, ungültigen Registerwert zugreifen. Das Scoreboard ist im Bild vereinfacht als Bitvektor am Registerblock angehängt. Seine Realisierung benötigt in Realität eine aufwendige Schaltung mit umfangreichen Tabellen. Darauf wollen wir im Rahmen dieses Kurses jedoch nicht näher eingehen.
Wenn die ALU nach Bild 2.6-10 einen Operanden verarbeiten muß, der noch nicht im Registerspeicher vorliegt, so muß dieser zunächst (über den Port E/A) in einem Register abgelegt und kann frühestens einen Taktzyklus später zur ALU weitergeleitet werden. Um diese Verzögerung zu vermeiden, verfügen Registerspeicher häufig über einen Bypass (" Umgehungsbus"), über den der Operand - gleichzeitig mit seiner Ablage im Registerspeicher - auch an einen der Eingänge der ALU gelegt werden kann. Diese Übertragung des Operanden wird als Load Forwarding bezeichnet.
Eine ähnliche Situation tritt auf, wenn das Ergebnis einer ALU-Operation bereits in der folgenden Operation als Operand benötigt wird. In diesem Fall tritt eine Verzögerung (um wenigstens einen Taktzyklus) dadurch auf, daß das Ergebnis zunächst in den Registerspeicher (zurück-)geschrieben werden muß und erst im folgenden Takt von dort an einen ALU-Eingang gelegt werden kann. Auch zur Vermeidung dieser Verzögerung wird ein Bypass verwendet, der das Ergebnis unmittelbar an einen der ALU-Eingänge zurückkoppelt. So kann es gleichzeitig mit seiner Ablage im Registerblock bereits durch den folgenden Befehl verarbeitet werden. Diese Rückkopplung des Ergebnisses wird Result Forwarding genannt.


2.6.4.2 Verwaltung großer Registerspeicher

Zu den Registern, die durch die Maschinenbefehle eines Anwendungsprogramms angesprochen werden müssen, gehören neben den universellen Registern auch bestimmte Status- und Konstanten-Register. Die einfachste Art, eine große Anzahl von Registern zu verwalten, ist, sie als homogenen (unstrukturierten) Satz von Registern zu realisieren, die über eindeutige (absolute) Adressen selektiert werden. Auf die Probleme, die langen Registeradressen im Befehlscode unterzubringen, wurde bereits im Unterabschnitt 2.6.4.1 eingegangen. Ein weiterer Nachteil besteht darin, daß hardwaremäßig keinerlei Zuordnung von bestimmten Registern zu den aktiven Programmstrukturen (Hauptprogramme, Unterprogramme, Interruptroutinen usw.) vorgenommen werden kann.
Zur Vermeidung beider genannter Nachteile wurden Mechanismen zur strukturierten Verwaltung großer Registersätze entwickelt. Bei ihnen wird der gesamte Registerspeicher in mehrere Registerbänke unterteilt, die den o.g. Programmstrukturen dynamisch zugewiesen werden können. Dies ist im Bild 2.6-11 dargestellt.


Bild 2.6-11:  Strukturierter Registerspeicher


Der Registerspeicher umfaßt (im unteren Adreßbereich) eine Registerbank, die die Konstanten-Register und alle globalen Register enthält, d.h. die Register, die für alle Programmstrukturen wichtig sind (z.B. das Statusregister). Die (restlichen) universellen Register sind in (n+1) gleich große, disjunkte Registerbänke unterteilt. Jeder der o.g. aktiven Programmstrukturen wird eine dieser Bänke (durch das Betriebssystem) zugewiesen, auf die sie exklusiv zugreifen darf. Durch diese Einteilung entsteht für jede Programmstruktur ein Registerfenster, das die "private" Registerbank und alle globalen und Konstanten-Register umfaßt. Die Adressierung eines privaten Registers im Registerfenster kann nun relativ geschehen: Beim Umschalten auf ein anderes Registerfenster wird die Anfangsadresse der zugehörigen Registerbank in ein spezielles Basisregister geladen. Im OpCode des Befehls muß nun lediglich eine kurze Registernummer angegeben werden, die als Index zum Basiswert addiert wird.

Ein Nachteil der beschriebenen Verwaltung des Registerspeichers tritt zu Tage, wenn z.B. von einem Unterprogramm Parameter an das aufrufende Hauptprogramm übergeben werden sollen, da diese (vom Betriebssystem) zeitaufwendig von einer Registerbank in eine andere kopiert werden müssen. In den folgenden Fallstudien werden Varianten der Verwaltung großer Registerspeicher gezeigt, die diesen Nachteil vermeiden. Die erste Variante benutzt überlappende Registerbänke einheitlicher Länge; die zweite hingegen läßt variable Längen von überlappenden oder disjunkten Bänken zu.


Fallstudie 2.6-4: Die Registerverwaltung der SPARC-Prozessoren


Im Bild 2.6-12 ist die Registerverwaltung bei den SPARC-Prozessoren (Scalable Processor Architecture) der Firma SUN dargestellt. Bei ihr sind die universellen Register (im Unterschied zum oben dargestellten) in überlappenden, gleich großen Bänken aus jeweils 24 Registern angeordnet, so daß jeweils die oberen und unteren 8 Register jeder Bank mit den Registern der angrenzenden Bänke übereinstimmen. Der Satz der globalen und Konstanten-Register enthält 8 Register. Diese Prozessor-Architektur unterstützt bis zu 32 Registerbänke, insgesamt also maximal 520 Register. Reale SPARC-Prozessoren besitzen jedoch nur 8 Bänke mit zusammen 136 Registern.


Bild 2.6-12:  Registerverwaltung der SPARC-Prozessoren


Die Verwaltung der Registerbänke wird durch zwei Register vorgenommen: Das CWP-Register (Current Window Pointer) zeigt auf die Bank der momentan aktiven Programmstruktur. Beim Aufruf eines Unterprogramms wird der CWP auf den Beginn der nachfolgenden Bank gesetzt; beim Rücksprung aus dem Unterprogramm auf die Bank des aufrufenden Programms zurückgesetzt. Wie im Bild 2.6-12 angedeutet, ist die Folge der Registerbänke zyklisch geschlossen, d.h. von der Bank n wird auf die Bank 0 umgeschaltet (und umgekehrt).
Wird bei der Neuzuteilung keine freie Registerbank mehr gefunden, muß eine vorher belegte auf den Stack im Hauptspeicher ausgelagert werden. Das Register SWP (Saved Window Pointer) zeigt auf die letzte ausgelagerte Registerbank. Es wird benötigt, um bei der Freigabe von Bänken die ausgelagerte Bank aus dem Stack zu restaurieren.

Die unteren 8 Register jeder Bank werden als Eingabebereich (EPi), die oberen 8 als Ausgabebereich (APi) benutzt. Die mittleren 8 Register sind für das zugeteilte Programm als privater Bereich (PDi) reserviert. Jedes Programm (Haupt-, Unter-, Interruptprogramm) hat Zugriff auf ein Registerfenster, das wiederum aus der zugeteilten Registerbank und den globalen bzw. Konstanten-Registern besteht. Die Adressierung eines universellen Registers in der Registerbank geschieht auch hier durch die Angabe einer (relativen) Registernummer als Index, der zum (skalierten) CWP-Wert addiert wird. Durch die Überlappung der Bänke gestaltet sich jedoch die Parameterübergabe an ein aufrufendes oder aufgerufenes Programm effizienter: Das aufrufende Programm schreibt die Übergabeparameter in seinen Ausgabebereich. Nach dem Umschalten auf die Registerbank des Unterprogramms stehen sie (ohne zusätzlichen Transport) im Eingabebereich des Unterprogramms zur Verfügung. Das Unterprogramm seinerseits schreibt seine Ergebnisse in den eigenen Eingabebereich, wo sie nach dem Zurückschalten im Ausgabebereich des aufrufenden Programms zur Verarbeitung bereit stehen.




Fallstudie 2.6-5: Die Registerverwaltung des Am29000


Der Am29000 von AMD (Advanced Micro Devices) war ein 32-bit-RISC-Prozessor, der - obwohl als universeller Prozessor konzipiert - hauptsächlich im Bereich der eingebetteten Anwendungen eingesetzt wurde und dort eine sehr weite Verbreitung fand. Dazu gehörten insbesondere Steuerungen von Laser-Druckern, Kopierern, Kommunikationsgeräten und anderen Ein-/Ausgabegeräten. Der Prozessor besaß einen Registerspeicher mit 192 universellen Registern, der im Bild 2.6-13 skizziert ist. Jedes Register konnte als Adreßregister oder als Datenregister für Integer- und 32-bit-Gleitpunkt-Operanden benutzt werden. 64-bit-Gleitpunkt-Operanden belegten zwei hintereinander liegende Register. (Neben dem dargestellten Registerspeicher besaß der Prozessor noch eine große Anzahl von Spezialregistern, auf die wir hier nicht eingehen können.)


Bild 2.6-13:  Registerverwaltung des Am29000 von AMD


Der Registerspeicher unterstützt eine sehr flexible Adressierung und Auswahl der Register:

  • Die Selektion eines Registers geschieht durch die Angabe einer 8-bit-Registernummer (0,..,255) im OpCode.
  • Die 64 globalen Register werden absolut adressiert, d.h. die angegebenen Registernummern werden keinen zusätzlichen Berechnungen oder Umwandlungen unterzogen. Ihre Adressen sind durch eine '0' in der höchstwertigen Bitposition gekennzeichnet. Die restlichen Bits bestimmen dann die eigentliche Nummer (0,..,127) des selektierten Registers. Die Register mit der Nummer 2 bis 63 sind dabei nicht implementiert.
  • Die 128 lokalen Register werden relativ zu einer Basisadresse angesprochen, die im Register 0 (Stack Pointer) eingetragen ist. Sie besitzen an der höchstwertigen Bitposition der 8-bit-Registernummer im OpCode eine '1' und werden durch die restliche 7-bit-Nummer (0,...,127) ausgewählt. Die Selektion eines Registers geschieht dadurch, daß bei jedem Zugriff diese 7-bit-Nummer zum Inhalt des Stack Pointers (Register 1) addiert wird. Die unteren 7 Bits des Ergebnisses bilden, mit einer vorangestellten '1', die absolute Registernummer. (Im Anschluß auf diese Aufzählung gehen wir ausführlicher auf die Registerverwaltung mit Hilfe des Stack Pointers ein.)
  • Jedes Register kann indirekt angesprochen werden. Dazu existieren für jeden der (bis zu) zwei Eingabeoperanden und dem Ergebniswert jeweils ein Spezialregister (Indirect Pointer A,B,C), das als Zeiger die Adresse des gewünschten Registers enthält. Die Auswahl der indirekten Adressierung für einen Operanden oder das Ergebnis geschieht dadurch, daß an den entsprechenden Stellen im OpCode das globale Register 0 angegeben wird. Jeder Zugriff auf dieses Register 0 (Indirect Pointer Access) wird auf das im zugeordneten Spezialregister A, B oder C angegebene Register umgeleitet.
Registerfenster-Verwaltung: Überlappende Registerbänke mit variablen Längen

Beim Umschalten auf eine neue Programmstruktur (Hauptprogramm, Unterprogramm, Interruptroutine usw.) setzt das Betriebssystem den Stack Pointer auf einen neuen Basiswert. Dieser besteht aus der absoluten Adresse (Nummer) eines lokalen Registers. Auf ihn werden - wie oben beschrieben - die relativen Registeradressen (0,...,..) der Programmstruktur bezogen. Prinzipiell kann so der gesamte Bereich der lokalen Register ab der Basisadresse oder aber ein kleinerer Teil davon der Programmstruktur zugewiesen werden. Auf die beschriebene Weise entstehen Registerbänke mit unterschiedlichen Längen (vgl. Bild 2.6-14).


Bild 2.6-14:  Registerfenster-Verwaltung beim Am29000

Das Betriebssystem kann den Wert des Stack Pointers, z.B. eines aufgerufenen Unterprogramms, in den Bereich des aufrufenden Programms setzen. Auf diese Weise überlappen sich die Registerbänke der Programmstrukturen. Es ist dadurch möglich, jede Registerbank (wie beim SPARC) in Eingabe-/Ausgabebereiche und private Datenbereiche zu strukturieren. Die aktive Programmstruktur hat Zugriff auf ein Registerfenster, wie es im Bild 2.6-14 rechts skizziert ist. Auf diese Fenster wird auf die beschriebenen Arten zugegriffen: auf alle globalen Register durch absolute Adressen (Nummern), auf die lokalen Register relativ, bezogen auf den Stack Pointer. (Zur Adressierung wird der Inhalt von Register 1, Stack Pointer genannt, zunächst in ein Spezialregister kopiert, das im Bild ebenfalls als Stack Pointer bezeichnet ist.)


  Inhaltsverzeichnis
  Übersicht Kapitel 2
2.5 Das Adreßwerk       2.7 Die Systembus-Schnittstelle