- DBIS Group

Transcription

- DBIS Group
Westfälische Wilhelms-Universität Münster
Institut für Wirtschaftsinformatik
Lehrstuhl für Informatik
Bachelor – Arbeit
zum Thema
Mikroprozessorarchitekturkonzepte
im Fach: Informatik
Themensteller: Prof. Dr. Gottfried Vossen
Betreuer: Prof. Dr. Gottfried Vossen
Ausgabetermin: 18.02.2002
Abgabetermin: 03.04.2002
vorgelegt von
Victor Pankratius
[email protected]
2
Abstract
Ziel der Arbeit ist eine Darstellung von allgemeinen Architekturkonzepten, die in
Mikroprozessoren zu finden sind. Dabei wird von technischen Details abstrahiert
und das Zusammenwirken von Teilkomponenten eines Mikroprozessors anhand von
Modellen erklärt. Ausgehend von den grundlegenden Prinzipien einer von-NeumannCPU werden Architekturerweiterungen vorgestellt. Nach einer Darstellung von CISCund RISC-Architekturen werden Konzepte der Speicherverwaltung und deren
Einfluss auf Mikroprozessorarchitekturen untersucht. Anschließend wird vorgestellt,
wie mit Hilfe von Pipelines und Branch Prediction die Performance verbessert
werden kann. Die Betrachtung wird bei superskalaren Architekturen fortgesetzt,
die Parallelitätskonzepte bei der Verarbeitung von Befehlen nutzen. Die im
Zusammenhang mit Pipelines beschriebenen Konzepte werden bei superskalaren
Pipelines wieder aufgegriffen und erweitert. Es werden out-of-order-Architekturen
vorgestellt, die Befehle außerhalb der Programmreihenfolge verarbeiten können.
Anhand von VLIW/EPIC- und Vektorarchitekturen werden weitere Möglichkeiten zur
Nutzung von Parallelität beschrieben. Danach wird auf Mikroprozessorarchitekturen
eingegangen, die für bestimmte Anwendungsgebiete optimiert sind. Behandelt
werden System-on-a-Chip-Ansätze wie Mikrocontroller und speziell für Signalverarbeitung optimierte DSP-Prozessoren. Nach einigen Beispielen von aktuellen
Mikroprozessorarchitekturen werden abschließend Schnittstellen zu Softwaresystemen und aktuelle Forschungstrends für zukünftige Architekturen gezeigt.
3
Inhaltsverzeichnis
1 Einführung ...................................................................................5
1.1 Grundbegriffe und Aufbau eines Computers ......................................8
1.2 Aufbau einer CPU und die Prinzipien von Neumanns .......................... 12
1.3 Historische Entwicklung ........................................................... 15
1.4 Designprozess von Mikroprozessoren............................................. 22
1.5 Klassifizierungsschemata .......................................................... 26
1.5.1 Klassifikation nach Flynn ................................................... 26
1.5.2 Erlanger Klassifikationssystem ............................................. 27
1.5.3 Klassifikation nach dem internen Speichermodell....................... 30
1.5.4 Klassifikation nach Befehlsformaten ...................................... 31
1.5.5 Fazit zur Klassifikation...................................................... 32
2 Mikroprozessorarchitektur ............................................................. 35
2.1 ISA-Varianten........................................................................ 37
2.1.1 CISC............................................................................ 37
2.1.2 RISC............................................................................ 42
2.1.3 Zusammenwachsen von CISC und RISC .................................... 46
2.2 Speicher.............................................................................. 47
2.2.1 Cache-Speicher .............................................................. 47
2.2.2 Paging und Segmentierung ................................................. 52
2.2.3 Translation Lookaside Buffer............................................... 54
2.2.4 Virtueller Speicher .......................................................... 54
3 Maßnahmen zur Performancesteigerung............................................. 56
3.1 Pipelines ............................................................................. 56
3.2 Branch Prediction und Spekulation............................................... 58
3.3 Superskalare Architekturen ....................................................... 61
3.3.1 Superskalare Pipelines ...................................................... 64
3.3.2 Out-of-order-Architekturen ................................................ 68
3.3.3 VLIW/EPIC-Architekturen ................................................... 71
3.3.4 Vektor-Architekturen........................................................ 73
4 Spezielle Architekturen ................................................................. 76
4.1 Mikrocontroller...................................................................... 76
4.2 DSP-Prozessoren .................................................................... 78
4
5 Aktuelle Mikroprozessoren ............................................................. 82
6 Softwaresysteme und Forschungstrends ............................................. 87
6.1 Compiler und Betriebssysteme .................................................... 87
6.2 Ausblick .............................................................................. 90
Anhang: Bilder von Mikroprozessoren .................................................. 95
Bibliographie ...............................................................................101
5
1 Einführung
Zweifellos hat in der Geschichte der Menschheit keine Maschine die Welt so
verändert wie der Computer. Um so erstaunlicher ist es, dass sich ein großer Teil
der Entwicklung des Computers in den letzten 60 Jahren vollzogen hat. Das ist
sowohl auf die technologische Entwicklung zurückzuführen als auch auf die
Entwicklung der zugrundeliegenden theoretischen Konzepte.
Ein Computer oder Rechner wird als „universell einsetzbares Gerät zur
automatischen Verarbeitung von Daten“ definiert [SDI91]. Realisiert werden
Computer heutzutage mit Hilfe binärer Digitaltechnik. Dass es Computer in fast
allen Lebensbereichen gibt, kann einerseits durch die geringen Fertigungskosten
und
andererseits
durch
die
universelle
Einsetzbarkeit
begründet
werden.
Universalität bedeutet, dass Computer frei programmierbar sind und ihre spezielle
Hardware-Struktur nicht für jede Aufgabe neu angepasst werden muss. Die
Untersuchung der allgemeinen Bauprinzipien und der Organisation von Rechnern ist
daher ein wichtiger Aspekt.
Computer sind modular aufgebaut, wobei der Kern von Mikroprozessoren
gebildet
wird.
Durch
die
Entwicklung
der
Halbleitertechnologie und der
Fertigungsprozesse ist auch eine Realisierung komplexer Mikroprozessoren möglich
geworden.
Sie
bestehen
mittlerweile
aus
sehr
vielen
Teilmodulen
und
Komponenten. Die Art und Weise, wie die Teilmodule organisiert sind, wirkt sich in
entscheidendem Maße auf Performance und Fertigungskosten aus. Die vorliegende
Arbeit soll den generellen Bebauungsplan, die „Architektur“ von Mikroprozessoren
auf konzeptioneller Ebene anhand von Modellen analysieren und allgemeine
Prinzipien aufzeigen. Dabei geht es z.B. um die Art und Anzahl der Register, den
Befehlssatz, das Speichermodell oder die benutzten Methoden, um Daten parallel
zu verarbeiten.
Die beschriebene universelle Einsetzbarkeit der Computer ist größtenteils auf
die Architektur des Mikroprozessors zurückzuführen. Diese kann für bestimmte
Einsatzbereiche optimiert werden, was auch an der heutigen Vielfalt an
verschiedenen Mikroprozessortypen zu sehen ist. Mikroprozessoren findet man
mittlerweile fast überall: in PCs, Handys, Fernsehern, Bankautomaten, Autos,
Waschmaschinen, Uhren, Elektrorasierern, Mikrowellen oder Aufzügen. Im Verlauf
6
der
Arbeit
soll
auch
deutlich
gemacht
werden,
welche
Mikroprozessor-
architekturkonzepte in welchen Anwendungssituationen bevorzugt zum Einsatz
kommen.
Die Arbeit wird zunächst einige wichtige Begriffe definieren, den groben
Aufbau eines Computers skizzieren und die Mikroprozessoren im Gesamtzusammenhang einordnen. Es werden die Prinzipien von Neumanns erläutert und
deren Beziehung zur universellen Einsetzbarkeit von Computern. Nach einem
kurzen historischen Rückblick folgt eine Darstellung des Designprozesses von
Mikroprozessoren. Die Einführung endet mit der Beschreibung einiger wichtiger
Klassifikationsmodelle für Mikroprozessoren.
Im zweiten Kapitel werden zunächst Basiskonzepte von Mikroprozessorarchitekturen anhand einer Prozessorarchitektur aus den 90er Jahren vorgestellt. In
diesem Zusammenhang werden Befehlssatzarchitekturen beschrieben. Danach wird
die
Auswirkung
von
Konzepten
bei
der
Speicherverwaltung
auf
die
Prozessorarchitektur untersucht.
Das dritte Kapitel befasst sich mit grundlegenden Konzepten, die für
Performancesteigerungen benutzt werden. Obwohl im weiteren Verlauf der Arbeit
Maßnahmen zur Performancesteigerung untersucht werden, werden die Methoden
zur Messung der Performance nicht näher erläutert. Dazu sei auf [HePa96] und
[BeiHag01] verwiesen. Im Hinblick auf zeitliche Parallelität wird zunächst auf
Pipelining
eingegangen.
Ergänzend
dazu
werden
Sprungvorhersagetechniken
betrachtet, die einige Nachteile von Pipelines ausgleichen sollen. Anschließend
wird
analysiert,
wie
superskalare
Architekturen
räumliche
Parallelität
zur
Ausführung mehrerer Befehle in einem Takt ausnutzen. Hierfür werden die
Pipelining-Konzepte bei superskalaren Pipelines wieder aufgegriffen und erweitert.
Es
werden
außerdem
out-of-order-Architekturen
beschrieben,
die
Befehle
außerhalb der Programmreihenfolge ausführen können. Als weitere Möglichkeiten
werden
VLIW/EPIC-Architekturen
Verarbeitungslogik
in
präsentiert,
Softwaresysteme
die
ausgliedern.
einen
großen
Schließlich
Teil
wird
der
noch
Parallelität auf Datenebene behandelt, die von Vektor-Architekturen genutzt wird.
Nach
der
Beschreibung
von
universell
einsetzbaren
Mikroprozessor-
architekturen, geht das vierte Kapitel auf Special-Purpose-Architekturen ein, die
für bestimmte Einsatzgebiete optimiert sind. Dabei werden Mikrocontroller, die ein
7
komplettes System auf einem Chip implementieren und DSP-Prozessoren, die auf
Signalverarbeitung optimiert sind, vorgestellt.
Das fünfte Kapitel zeigt beispielhaft, wie die besprochenen Konzepte in
aktuellen Mikroprozessorarchitekturen verwendet werden.
Das letzte Kapitel geht auf Schnittstellen zu Softwaresystemen ein und
erläutert Wechselwirkungen zwischen Mikroprozessorarchitektur und Softwaresystemen. Abschließend werden Konzepte vorgestellt, an denen zur Zeit geforscht
wird und die möglicherweise einen Einfluss auf zukünftige Mikroprozessorarchitekturen haben werden.
8
1.1 Grundbegriffe und Aufbau eines Computers
Programmspeicher
Eingabesystem
Zentrale
Verarbeitungseinheit
Ausgabesystem
Arbeitsspeicher
Abb. 1: Grundstruktur einer programmgesteuerten
Datenverarbeitungsanlage (Computer) nach [BeiHag01]
In Abb. 1 ist die Grundstruktur eines Computers (=Rechner) dargestellt. Durch
das Eingabesystem werden der zentralen Verarbeitungseinheit (Central Processing
Unit, CPU) Daten in digitaler Form zugeführt. Die CPU wendet genau definierte
Regeln (Algorithmen), die in Form eines Programms im Programmspeicher stehen,
auf die Daten an. Der Arbeitsspeicher dient zur Zwischenspeicherung von
Ergebnissen, bevor die verarbeiteten Daten an das Ausgabesystem weitergegeben
werden. Durch den Austausch des Programms im Programmspeicher kann der
Computer ohne Veränderung der Hardware für andere Aufgaben benutzt werden.
Häufig werden Daten und Programme in demselben Speicher abgelegt (vgl. vonNeumann-Architektur, Kap. 1.2). In einigen Anwendungsgebieten werden Arbeitsbzw. Datenspeicher und Programmspeicher allerdings getrennt, was als HarvardArchitektur bezeichnet wird (vgl. spezielle Architekturen, Kap. 4).
Ein Prozessor wird in [Clausing00] wie folgt definiert: „Jedes Objekt, dass in
steuerbarer Weise unterschiedliche Zustände annehmen kann. Das bedeutet, dass
es einen wohldefinierten Startzustand gibt, sowie Methoden, davon ausgehend den
Prozessor in andere Zustände zu versetzen. Ein Prozessor durchläuft sequenziell
(d.h. in diskreten Zeitschritten) eine Folge von Zuständen, bis er einen Endzustand
erreicht hat. Ein solcher Ablauf mit definiertem Anfang und Ende ist ein Prozess
9
(=Berechnung). Ein Prozessor heißt universell, wenn er die Operationen einer
Turingmaschine [..] emulieren kann.“ (vgl. auch [LewPap98]).
Eine auf einem einzigen Chip untergebrachte CPU eines Computers wird
Mikroprozessor genannt. Es gibt sowohl für den kompletten Rechner, also auch für
Mikroprozessoren allgemeine Bauprinzipien. Eine Rechnerarchitektur beschreibt
die Komponenten eines Rechners, deren Struktur und Zusammenwirken, den
Aufbau von Befehlen und den Ablauf von Operationen.
Die Sicht der Bauprinzipien lässt sich auch auf Mikroprozessoren einschränken.
Eine Mikroprozessorarchitektur abstrahiert vom genauen physikalischen Aufbau
von
Mikroprozessoren
und
definiert
deren
wesentlichen
Bestandteile
und
Beziehungen zueinander durch Bildung eines Modells. Ziel ist das Verständnis der
Organisation und Funktionsweise der Teileinheiten und des Ganzen. Dabei
verzichtet man auf genaue quantitative Aussagen. Ein Programmiermodell ist ein
Teil der Prozessorarchitektur und stellt das Prozessormodell aus Sicht des
Assemblerprogrammierers dar, wobei von den Einzelheiten der Ausführung
abstrahiert wird.
Die allgemeinen Ziele von Mikroprozessorarchitekturen werden von [BeiHag01]
darin gesehen, dass Programme möglichst performant ausgeführt werden, ohne das
Programmierparadigma der sequentiellen Bearbeitung des Befehlsstroms gegenüber
Anwendungsprogrammierern wesentlich zu verändern. Die interne (ggf. parallele)
Abarbeitung soll gegenüber der Befehlssequenz transparent sein.
Bei der Gestaltung von Rechnerarchitekturen unterscheiden [TanGo99]
zwischen verschiedenen Schichten, wobei höhere Schichten immer stärker von der
untersten Ebene abstrahieren und jede Schicht nur mit der jeweils darunter oder
darüber liegenden kommuniziert. Die Abstraktion soll die Komplexität des
Gesamtsystems reduzieren und beherrschbar machen.
10
Ebene 5
Problemorientierte Sprache
Übersetzung (Compiler)
Ebene der Assemblersprache
Ebene 4
Übersetzung (Assembler)
Ebene 3 Ebene der Betriebssystemmaschine
Teilinterpretation (Betriebssystem)
ISA (Instruction Set Architecture)
Ebene 2
Interpretation (Mikroprogramm)
oder direkte Ausführung
Mikroarchitektur
Ebene 1
Hardware
Ebene 0
Digitale Logik
Abb. 2: Struktur eines Computers mit sechs Ebenen (nach [TanGo99])
Auf Ebene 0 befindet sich die Hardware der Maschine. Hier werden logische
Gatter
analysiert,
die
binäre
Eingangssignale
in
binäre
Ausgangssignale
transformieren. Mit Hilfe von Gattern kann man auch Speicher realisieren, die 1 Bit
speichern können. Mehrere 1-Bit-Speicher werden zu Registern zusammengefasst.
Von der Art und Weise, wie Gatter genau mit Hilfe der Elektrotechnik realisiert
werden (z.B. mit Transistoren), wird abstrahiert.
Auf der Ebene 1 werden unter Benutzung der Ebene 0 Komponenten auf
einem höheren Aggregationsniveau betrachtet, wie z.B. Gruppen von Registern als
lokale Speicher, Pipelines zur Befehlsdekodierung (vgl. Kap. 3.1) oder eine ALU
(Arithmetic Logic Unit). Eine ALU ist mit Registern verbunden und kann
arithmetische Operationen auf Daten ausführen. Dabei müssen die Daten über
einen Bus aus den Registern in die ALU geholt werden und wieder zurück in die
Register geschrieben werden. Dieser als Datenwegzyklus bekannte Prozess ist
typisch für jeden Mikroprozessor. Die Steuerung des Datenwegzyklus kann fest in
der Hardware verdrahtet sein oder von einem sogenannten Mikroprogramm
gesteuert werden.
Die Ebene 2 (ISA-Ebene) legt Anzahl und Art der Instruktionen fest, die ein
Computer versteht. Diese Ebene stellt einen Teil des Programmiermodells dar,
welches zusätzlich zu allen ausführbaren Befehlen auch alle für den Programmierer
11
sichtbaren Register umfasst. Wie man bei CISC und RISC sehen wird (Kap. 2.1.1 und
2.1.2), hat diese Ebene einen entscheidenden Einfluss auf die Mikroprozessorarchitektur.
Das auf Ebene 3 vorhandene Betriebssystem ist ein Programm, das die
Nutzung des Rechners vereinfacht und komfortabler macht, verglichen mit der
direkten Nutzung der Hardware. Es kontrolliert die Hardware-Rressourcen und
deren
Aufteilung
zwischen
verschiedenen
Benutzern.
Das
Betriebssystem
abstrahiert so stark von der Hardware, dass sich Benutzer nicht um Details bei der
Ausführung der Programme kümmern müssen (vgl. auch Kap. 6.1).
Ab der Ebene 4 gelangt man von der Systemebene in den Bereich der
Anwendungsprogramme. Bis jetzt hat man in den darunter liegenden Ebenen die
Programme als Bitfolgen aufgefasst. Die Bitfolgen werden hier zu Symbolen
(=Befehle) eines Assemblerprogramms zusammengefasst. Durch Übersetzung kann
das Assemblerprogramm wieder in Bitfolgen für die darunter liegende Ebene
transformiert werden.
Die Ebene 5 betrachtet als letzte Ebene sogenannte Hochsprachen (z.B. C++,
Pascal), die für Anwendungsprogrammierer ausgelegt sind. In Hochsprachen gibt es
komplexere Sprachkonstrukte und Befehle als in Assemblersprachen. Mit Hilfe eines
Compilers (Kap. 6.1) werden Programme von Hochsprachen in Programme für die
Ebene 4 übersetzt.
Jede einzelne Schicht sieht nur eine einzige darunter liegende Schicht, die die
Funktionalität aller weiter unten gelegenen Schichten enthält. Deswegen kann eine
Schicht als virtuelle Maschine bezüglich der nächsthöheren Schicht aufgefasst
werden. Die Konsequenzen solch einer Abstraktion sind weitreichend: Hardware
kann für eine obere Schicht von der darunter liegenden Schicht simuliert werden,
so dass der Unterschied zwischen Hardware und Software verschwimmt. Daher ist
es unwichtig, ob ein Befehl von Hardware oder Software ausgeführt wird, was man
auch an der Mikroprogrammierung auf Ebene 1 sieht. Tanenbaum/Goodman
bezeichnen sogar Hardware und Software als logisch äquivalent [TanGo99].
Die vorliegende Arbeit wird sich überwiegend mit Ebene 1 und 2 befassen. Es
wird nicht auf die Einzelheiten der Realisierung von Mikroprozessoren mittels
Boolescher Logik eingegangen. Die verschiedenen Elemente eines Mikroprozessors
wie Register, ALU oder Pipelines werden als gegeben hingenommen und nur
hinsichtlich Zusammenwirken und Organisation analysiert. Details zur Realisierung
12
von Mikroprozessoren, Schaltnetzen und Schaltwerken finden sich in [HePa97],
[ObVossen00], [TanGo99].
1.2 Aufbau einer CPU und die Prinzipien von Neumanns
Das
obige
Kapitel
hat
erläutert,
welche
Rolle
eine
CPU
für
ein
Computersystem spielt. Dieser Abschnitt soll den grundsätzlichen Aufbau einer CPU
nach von Neumanns Konzepten näher beschreiben. Die Ideen von Neumanns zum
Aufbau eines Computers und einer CPU, die schon 1946 vorgestellt wurden,
beschreiben einen Universalrechner [BuGoNeu46].
CPU
Speicher
I/O
Datenbus
Steuerbus
Adressbus
Abbildung 3: Aufbau eines von-Neumann-Rechners
Der Computer nach von Neumann hat eine CPU, Speicher und Ein-/AusgabeGeräte (I/O). Die obige Abbildung zeigt, dass die CPU über ein Bussystem mit den
restlichen Komponenten verbunden ist. Das Bussystem ist in Daten-, Steuer-, und
Adressbus unterteilt. Der Datenbus überträgt nur Daten, der Steuerbus nur
Steuersignale (z.B. welcher Befehl ausgeführt werden soll) und der Adressbus
enthält die Adresse, auf die als nächstes zugegriffen wird. Alle Daten, Adressen und
Befehle werden binär kodiert. Die Auswahl eines Ein-/Ausgabe-Geräts erfolgt auch
über den Adressbus.
Der Speicher besteht aus Speicherzellen fester Größe (1 Speicherwort), die
alle über eine eindeutige Adresse angesprochen werden können. Programme und
Daten werden im selben Speicher abgelegt. Dadurch, dass Programme wie Daten
behandelt werden, können sich Programme zur Laufzeit selbst verändern. Der
Inhalt eines Speicherwortes kann Daten, Befehle oder Adressen repräsentieren,
wobei die Interpretation des Speicherinhalts vom Kontext abhängt. Der Rechner
13
kann durch Austauschen des Programms zur Lösung anderer Aufgaben verwendet
werden.
CPU
Steuerwerk
Rechenwerk
Register
IR
op2
op1
PC
ALU
Bus-Interface
MAR
MBR
Ergebnis
Datenbus
Steuerbus
Adressbus
Abbildung 4: Organisation einer CPU nach von Neumann
In Abb. 4 wird die Organisation der CPU nach von Neumann skizziert. Sie
besteht aus einem Steuerwerk, einem Rechenwerk und einem Bus-Interface.
Das Rechenwerk enthält die schon in Kapitel 1.1 erwähnte Arithmetic-LogicUnit (ALU), die arithmetische Befehle (z.B. Addition, Multiplikation) und logische
Befehle (z.B. and, or, not, shift) auf den Daten ausführen kann. Welche Operation
die ALU ausführen soll, bestimmt das Steuerwerk über einen internen Steuerbus.
Die Register sind schnelle Speicher, die auf dem gleichen Chip untergebracht sind
wie die CPU.
Das Steuerwerk (Control Unit, CU) steuert den Gesamtablauf des Systems.
Dabei wird immer genau ein Befehl zu einem Zeitpunkt ausgeführt. Das
Instruktions- bzw. Befehls-Register (IR) enthält die Bitfolge des Befehls, der
ausgeführt werden soll. Die Bitfolge besteht aus einem Adressteil und einem
Operationsteil (OpCode). Bei diesen sog. Ein-Adress-Befehlen (vgl. Kap. 1.5.4) gibt
der Operationsteil an, was zu tun ist und der Adress-Teil sagt, wo die zugehörigen
Operanden zu finden sind. Der Dekodierer erkennt den Befehl im Operationsteil
und führt ihn aus, indem er entsprechende Signale auf den Steuerbus setzt. Es gibt
zumindest arithmetische Befehle, logische Befehle, Transportbefehle zum Speicher
14
oder zur Ein-/Ausgabe, bedingte Sprünge und sonstige Befehle wie unterbrechen
oder warten. Für alle Befehle gibt es auch unterschiedliche Adressierungsarten
(vgl. Kap. 2.1.1), wie z.B. indirekte Adressierung, bei der man den Inhalt einer
referenzierten Speicherzelle als Adresse einer anderen Speicherzelle interpretiert,
die den gewünschten Wert enthält.
Das Program-Counter-Register (PC) enthält die Adresse des Befehls, der als
nächstes ausgeführt werden soll. Da sequenzielle Befehle eines Programms im
Speicher nacheinander stehen, erhöht das Steuerwerk nach Ausführung eines
Befehls den PC um 1. Sollen Sprünge im Programm ausgeführt werden, dann wird
die Zieladresse des Sprungs in den PC geschrieben.
Die CPU kommuniziert mit der Außenwelt über das Bus-Interface, welches das
Memory-Address-Register (MAR) und Memory-Buffer-Register (MBR) enthält. In das
MAR wird die Adresse geschrieben, auf die als nächstes zugegriffen wird. Das hat
zur Folge, dass dieser Wert auf den Adressbus gelegt wird. Nachdem das
Steuerwerk die Steuersignale auf den Steuerbus gelegt hat, erhält die CPU die
Daten im MBR. Von da aus können sie in die internen Register gelangen.
Bei der Ausführung eines Befehls wird von der CPU immer derselbe Zyklus
durchlaufen: Befehl holen (fetch), Befehl dekodieren (decode), Befehl ausführen
(execute).
In Pseudocode formuliert passiert dabei im Wesentlichen folgendes:
MAR
:= PC;
MBR
:= Inhalt_von_Adresse(MAR);
IR
:= MBR;
dekodiere IR;
fetch
decode
falls kein Sprungbefehl
dann {stelle Operanden bereit;
PC := PC + 1; }
execute
sonst{PC := Sprungzieladresse;}
Dieser Ablauf ist grob vereinfacht, da z.B. der Operand auch indirekt adressiert
werden könnte und dann noch eine Adressberechnung durchzuführen wäre.
15
Die Architektur der CPU nach von Neumann ist eine skalare Architektur, die
nicht mehrere Befehle in einem Takt ausführen kann. Die Phasen fetch, decode,
execute werden nacheinander ausgeführt, wobei die CPU zu einer bestimmten Zeit
immer nur eine der Phasen ausführt. Da die Zugriffszeiten auf den Speicher
wesentlich länger sind als die Ausführungszeit eines Befehls, entsteht die Situation,
dass die CPU häufig wartet, bis die Befehle und deren Operanden aus dem Speicher
gelesen wurden. Die Dauer der Phasen ist dadurch sehr unterschiedlich. Die
Kommunikation zwischen CPU und Speicher wird zum Engpass und als der „von
Neumannsche Flaschenhals“ bezeichnet. Details zur von-Neumannn-Architektur
findet man in [SDI99], [ObVossen00], [TanGo99].
Im Verlauf der Arbeit werden andere CPU-Architekturen vorgestellt, die
ausgehend von den Konzepten von Neumanns die verschiedenen Nachteile
ausgleichen sollen. Beispielsweise werden schnelle Pufferspeicher (Cache-Speicher)
beim Zugriff auf den Hauptspeicher verwendet, um die Zugriffszeit zu reduzieren
(vgl. Kap. 2.2.1). Andere Optimierungsmöglichkeiten setzen beim fetch-decodeexecute-Zyklus an, indem mit Hilfe von Pipelines verhindert werden soll, dass Teile
der CPU nicht beschäftigt sind (vgl. Kap. 3.1). Durch Sprungvorhersage versucht
man, den Kontrollfluß im Programm spekulativ zu berechnen, damit die
Bereitstellung der in Zukunft benötigten Daten und Befehle frühzeitig beginnen
kann (vgl. Kap. 3.2). Schließlich gibt es noch die Möglichkeit, Befehle parallel mit
mehreren ALUs zu bearbeiten (superskalare Architekturen, vgl. Kap. 3.3).
Rückblickend kann man sagen, dass die Entwicklung der Mikroprozessorarchitektur
evolutionär
stattgefunden
hat.
Das
nächste
Kapitel
erläutert
die
Entstehungsgeschichte.
1.3 Historische Entwicklung
Bevor auf die historische Entwicklung von Mikroprozessoren eingegangen wird,
folgt noch eine kurze geschichtliche Zusammenfassung der Zeit bis zum
Mikroprozessor, um zu zeigen, dass verschiedene Konzepte nicht erst mit der
Erfindung des Mikroprozessors entstanden sind, sondern schon lange vorher bekannt
waren. Gleichzeitig soll ein Bild vermittelt werden, welche weitreichenden
16
Auswirkungen
der
Einsatz
neuer
Technologien
(Halbleitertechnologie
und
Miniaturisierung) auf die Architektur eines Prozessors hat.
Schon lange Zeit vor dem Mikroprozessor verwendeten die Menschen
Hilfsmittel, um Berechnungen zu beschleunigen. Die Babylonier benutzten bereits
3000 v. Chr. den Abakus. Im Laufe der Geschichte wurden Rechenmaschinen auf
mechanischer Basis entwickelt. Pascal baute 1645 eine einfache mechanische
Addiermaschine für den Einsatz in der Finanzverwaltung. Die Rechenmaschine von
Leibniz konnte 1672 auch Multiplikationen und Divisionen durchführen. Durch die
Entwicklung der Naturwissenschaften entstand im 18. und 19. Jahrhundert ein
hoher
Bedarf
an
durchzuführenden
Berechnungen
für
mathematische
Tabellenwerke. Diese wurden für die Navigation in der Schifffahrt oder für
Zinsberechnungen
benutzt.
Die
hohe
Fehlerrate,
die
durch
die
manuelle
Berechnung der Zahlen zustande kam, veranlasste Charles Babbage im Jahre 1823
die Difference Engine zur Berechnung von Tabellen zu konzipieren, die aber wegen
der hohen mechanischen Komplexität nicht gebaut wurde. Im Jahre 1871 hatte
Babbage das Konzept der Analytical Engine fertig, die ein Vorläufer des heutigen
Universalrechners ist. Babbage hatte Speicher, Rechenwerk (ALU), Eingabewerk
und Ausgabewerk (I/O) getrennt und war in der Lage, durch Austausch des
Programms seine Maschine für andere Aufgaben zu benutzen. Die Programme
konnten Schleifen und bedingte Sprünge durchführen. Letzteres führt zur
interessanten Feststellung, dass die Analytical Engine universeller war (was die
Berechenbarkeit angeht) als viele Rechner in den 40er Jahren, die keine bedingten
Sprünge ausführen konnten. Leider wurde die Analytical Engine aus finanziellen und
technischen Gründen nicht gebaut. Die Ära mechanischer Rechner endet etwa 1936
mit Konrad Zuses Z1. Danach wurden Computer auf elektromechanischer Basis mit
Relais oder elektrotechnischer Basis mit Hilfe von Vakuumröhren realisiert. Viele
davon waren nicht programmierbar und damit nicht universell, da die Programme
fest verdrahtet waren. Ein Beispiel dafür war der 1943 von Turing gebaute Colossus
für die Entschlüsselung des deutschen Funkverkehrs im zweiten Weltkrieg.
Außerdem
waren
die
Computer
unglaublich groß und hatten häufig ein
Gesamtgewicht im zweistelligen Tonnenbereich. Im Laufe der Zeit erkannte man
auch, dass man durch Benutzung des binären statt des dezimalen Zahlensystems
die Komplexität des Aufbaus von Computern erheblich reduzieren konnte. Weitere
Details zur geschichtlichen Entwicklung finden sich in [Märtin01].
17
Die nächste Computergeneration sollte durch die Erfindung des Transistors bei
den Bell Labs von Bardeen, Brattain, Shockley im Jahre 1947 drastisch verändert
werden. Der Transistor, der durch Halbleitertechnik realisiert und für den Bau
logischer Gatter verwendet wurde, arbeitete zuverlässiger als Röhren, war kleiner,
billiger herzustellen und benötigte weniger Energie. Grundstoffe für die Fertigung
von Transistoren sind Silizium und Germanium. Im Jahre 1957 gründeten Moore und
Noyce die Firma Fairchild Semiconductor, bei der im Jahre 1959 der erste
integrierte Schaltkreis (integrated circuits, IC) entwickelt wurde. Auf einem
einzigen IC wird ein kompletter Schaltkreis mit vielen Transistoren mit Hilfe
photolithographischer Verfahren „gedruckt“ und in ein kleines Keramikgehäuse
„verpackt“ (vgl. [BeiHag01]). An einem IC gibt es Pins, über die er mit der
Außenwelt kommunizieren kann. Die Pins leiten elektrische Signale aus dem IC
heraus oder in den IC hinein. 1968 gründeten Moore und Noyce die Firma Intel, die
zunächst Speicher auf Halbleiterbasis fertigte. Der Mikroprozessor wurde geboren,
als die japanische Firma Busicom an Intel den Auftrag erteilte, zehn Spezialchips
für Tischrechner zu fertigen. Von Intel wurde stattdessen ein UniversalchipProzessor mit gleicher Funktionalität entwickelt.
Die erste CPU der Welt wurde im Jahre 1971 fertiggestellt. Die Intel 4004 CPU
hatte eine Verarbeitungsbreite von 4 Bit (d.h. Datenbus und Register waren 4 Bit
breit), eine Taktrate von 0,1 MHz und bestand aus 2300 Transistoren. Dazu gab es
einen 320-Bit-RAM-Speicher (Intel 4002), 2K-ROM (Intel 4001) und ein 10-Bit-I/OShiftregister (Intel 4003).
Für den Bau eines Mikrocomputers (= ein Rechner, bei dem Mikroprozessoren
zum Einsatz kommen) waren vier Bausteine von Intel nötig. Die Firma Texas
Instruments hatte einen Chip, den TMS1000 entwickelt, der die komplette
Funktionalität eines Mikrocomputers auf einem einzigen Chip vereinte und schuf
damit
den
ersten
Mikrocontroller
(Micro
Controller,
MC).
Dieser
wurde
anschließend in Taschenrechnern eingesetzt. Mikrocontroller sind vollständige
Mikrocomputersysteme auf einem Chip. Sie vereinen neben der CPU den Speicher
und die Peripheriekomponenten. Das Ziel ist nicht eine hohe Leistung bei der
Verarbeitung, sondern die Integration der einzelnen Komponenten und die geringen
Kosten des MC, weswegen sie auch heutzutage überwiegend in Embedded Systems
zu finden sind. Auf Mikrokontroller und deren Architektur wird in Kap. 4.1 genauer
eingegangen.
18
Die Entwicklung des Mikroprozessors ging rasant weiter. Moore formulierte
1965 einen Zusammenhang für die nächsten 10 Jahre, der anscheinend immer noch
anhält und als „Moores Gesetz“ bekannt ist. Danach verdoppelt sich die Anzahl der
Transistoren pro Chip etwa alle 2 Jahre. Die immer stärkere Verdichtung von
Bauteilen ist heutzutage auf Basis der Very-Large-Scale-Integration-Technologie
(VLSI) möglich [Kropf95]. Beispielsweise hat ein Pentium IV-Prozessor 42 Mio.
Transistoren.
Anz. Transistoren
100.000.000
Pentium IV
Pentium III
Pentium II
10.000.000
Pentium
486
1.000.000
386
286
100.000
8085
10.000
8080
8008
4004
1970
1000
1975
1980
1985
1990
1995
2000
Quelle: Intel 2002
Abbildung 5: Moores Gesetz
Im Jahre 1979 wurde von Intel ein anderer Typ eines spezialisierten
Mikroprozessors entwickelt, der Intel 2920. Er ist ein sogenannter digitaler
Signalprozessor (DSP) und wird bei der Signalverarbeitung zur sehr schnellen
Verarbeitung von mathematischen Befehlen eingesetzt. DSP-Prozessoren werden im
Kap. 4.2 ausführlicher beschrieben.
Erwähnenswert ist auch ein anderer Typ eines Mikroprozessors, nämlich der
1983 erstmals von Inmos entwickelte Transputer. Er war für den Aufbau von
Parallelrechnern gedacht und enthielt auf einem Chip eine CPU, RAM und
Kommunikationsschnittstellen
zur
Kopplung
an
mehrere
Transputer
[ObVossen00]). Diese Architektur hat sich allerdings nicht durchgesetzt.
(vgl.
19
Die Entwicklung der wesentlichen Typen von Mikroprozessoren geschah
größtenteils evolutionär, wobei sich im Laufe der Zeit bestimmte Trends
entwickelten. Dabei haben sich zwei wesentliche Prinzipien herauskristallisiert:
CISC (Complex Instruction Set Computer) und RISC (Reduced Instruction Set
Computer). Ein CISC-Prozessor wird mit umfangreicheren und komplexeren
Maschinenbefehlssätzen (Instruction Set Architecture) ausgestattet, die intern noch
durch Mikroprogramme interpretiert werden. RISC-Prozessoren verzichten dagegen
auf Mikroprogrammierung, reduzieren die Anzahl der Befehle, implementieren ein
einheitliches Befehlsformat und verlassen sich bei der Generierung des Codes stark
auf Compiler in den darüber liegenden Ebenen (vgl. Abb. 2). Diese Architekturkonzepte werden in den Kapiteln 2.1.1 und 2.1.2 noch ausführlich besprochen. Bei
modernen Mikroprozessoren (z.B. Pentium) verschwimmt allerdings die Grenze
zwischen
RISC
und
CISC.
Neuerdings
sind
bei
CISC-Architekturen
auch
Architekturelemente zu finden, die sonst nur bei RISC vorhanden waren. Es gibt
Prozessoren, die zwar nach außen eine CISC-Schnittstelle besitzen, aber intern die
CISC-Befehle in RISC-artige Befehle übersetzen, um die Hardwarekomplexität des
Decoders zu reduzieren. Die RISC-Architekturen enthalten mittlerweile auch CISCMerkmale, wie z.B. eine größere Anzahl von Befehlen. Das Kap. 2.1.3 beschreibt
die Konvergenz von CISC und RISC ausführlicher. In Abb. 6 sind die allgemeinen
Typen von Mikroprozessoren, sowie die Entwicklung von RISC und CISC als
Stammbaum dargestellt.
20
MP
Einführung der
Superskalartechnik
1995
RISC
MC
CISC
MC
~1990
DSP
CISC
RISC
MC
~ 1980
1979
1974
1971
MP
MP: Mikroprozessor
MC: Mikrocontroller
DSP: Digitaler signalprozessor
Abbildung 6: Stammbaum der Mikroprozessor-Entwicklung
(angelehnt an [SpEl94])
21
Verarbeitungsbreite
+ DEC Alpha AXP 21164
64 Bit
+ MIPS R12000
+ SUN UltraSPARC III
+ ARM Jaguar (MP)
+ Intel Itanium (MP)
+PowerPC620
+ MIPS R2000
+ PowerPC604 + Intel Pentium IV
+ PowerPC603
+ Intel Pentium III-Xeon
+ AMD Athlon XP
+ PowerPC 601
+ AMD Athlon
+ 68020 Motorola (MP)
+ Intel Pentium III
+ Intel 486
+ ACORN ARM
+ Intel Pentium II
+ Intel Pentium Pro
+ SUN SPARC
+ Intel Pentium (MP)
+ IMS T400 Inmos (erster Transputer)
+ 80386 Intel (MP)
+ HP PA-RISC
32 Bit
+ Intel 2920 (erster DSP)
+ 68000 Motorola (MP)
+ Z8000 Zilog (MP)
+ 80286 Intel (MP)
+ Intel 8088
+ 8086 Intel (MP)
+ TMS9000 Texas Instruments (MP)
16 Bit
+ 68HC11 Motorola (MC)
+ Intel 8085
+ 8051 Intel (MC)
+ 6805 Motorola (MC)
8 Bit
+ Z80 Zilog (MP)
+ 8748 Intel (MC mit EPROM)
+ Intel 8080
+ 6800 Motorola (MP)
+ Intel 8008
+ TMS1000 Texas
Instruments (erster MC)
4 Bit
MP: Mikroprozessor
MC: Mikrocontroller
DSP: Digitaler Signalprozessor
+ 4004 Intel
(erster MP)
1971
1974 1976
Fertigung ab etwa
1979
1983 1985
1990
Taktraten etwa 0,1 Mhz
Transistorgröße etwa 10 µm
1995
2001
Taktraten etwa 2 Ghz
Transistorgröße etwa 0,1 µm
Abbildung 7: Übersicht wichtiger Prozessoren
Die obere Grafik stellt abschließend in etwa die Zeitpunkte der Fertigung
sowie
die
Verarbeitungsbreite
bekannter
Mikroprozessoren
dar,
um
die
Gesamtentwicklung zu verdeutlichen.
Die Historie der Rechner und Mikroprozessoren wird detaillierter in
[Malone96], [TanGo99], [Märtin01] beschrieben.
22
1.4 Designprozess von Mikroprozessoren
Die dargestellte Entwicklung aus dem vorherigen Kapitel lässt schon erahnen,
welch atemberaubende Komplexität und Miniaturisierung die Mikroprozessoren
durch Einsatz von VLSI (vgl. [Kropf95]) mittlerweile erreichen. Ein strukturiertes
und systematisches Vorgehen beim Entwurf von Mikroprozessoren ist daher
unerlässlich.
Allgemein kann man beim Entwurf von VLSI-Schaltungen, zu denen auch
Mikroprozessoren gehören, verschiedene Entwurfssichten (Verhalten, Struktur,
Geometrie) und Entwurfshierarchien unterscheiden. Gajski-Walker fassen diese
Aspekte im sogenannten Y-Diagramm zusammen (Abb. 8), [Gajski83], [Walker85].
Systemebe ne
orit hmische Ebene
Al g
Verhalten
Struktur
e r- Tr an sf er- Ebe
gist
ne
Re
Systemspezifikation
Subsysteme, Busse
Module, Verbindungen
Gatter, Flipflops, Verbindungen
rei s- Eb
al tk
en
ch
e
S
Register-Transfer-Spezif.
Boolesche Gleichungen
CPU, Speicher
i k-Eb ene
Log
Algorithmen
Transistoren, Verbindungsstücke
Differentialgleichungen
Polygone
Zellen
Makros
Block
Chip
Geometrie
Abbildung 8: Y-Diagramm nach Gajski-Walker
Die Verhaltenssicht beschreibt, wie sich das System im laufe der Zeit verhält.
Die
Struktursicht
spezifiziert
die
Subsysteme,
aus
denen
das
System
zusammengesetzt wird, und deren Verbindung zueinander. Bei der Geometriesicht
interessiert man sich für die räumliche Lage der Subsysteme. Letztere nimmt einen
besonderen Stellenwert ein, da bei der hohen Integrationsdichte die Platzierung
der Subsysteme mit den entsprechenden Komponenten auf einem Chip, sowie
deren Verdrahtung, nicht mehr trivial ist.
23
Die Entwurfshierarchien sind im Y-Diagramm durch Kreise dargestellt, wobei
der Abstraktionsgrad nach innen hin abnimmt (vgl. [BeiHag01]). Außen auf der
Systemebene werden die Hauptelemente des Systems blockartig (z.B. Speicher,
Prozessor, Schnittstellen, I/O-Bausteine) mit den zugehörigen Kommunikationsprotokollen definiert. Man trifft Entscheidungen, was in Hardware und was in
Software realisiert werden soll (vgl. Kap. 1.1). Die Algorithmische Ebene
beschreibt allgemein mit Regeln, wie die Eingaben von Blöcken in Ausgaben
transformiert werden. Dabei spielt hier die Implementation noch keine Rolle. Die
darunter liegende Register-Transfer-Ebene beschreibt die Operationen und den
Datentransfer zwischen Register-Transfer-Modulen (d.h. Register, ALUs, Multiplexer, etc.). Daraus werden Gatter (nand, or, etc.) auf der Logik-Ebene erzeugt.
Die Gatter werden selbst wiederum aus Transistoren gebaut. Auf der SchaltkreisEbene erhält man die genaue Verschaltung der einzelnen Transistoren. Daraus kann
man Polygonzüge generieren, die mit Hilfe von photolithografischen Verfahren
(evtl. in mehreren Schichten) auf Silizium gebracht werden. Die beschriebenen
Entwurfsebenen werden in [Goser91] genauer erläutert.
Der Entwurfsablauf als Ganzes ist keineswegs streng top-down oder bottomup. Beim Entwurf fängt man auf dem höchsten Abstraktionsgrad mit der
Systemspezifikation
an
und
arbeitet
sich
schrittweise
nach
innen.
Die
Verhaltensspezifikation auf jeder Abstraktionsebene ermöglicht es, Simulationen
durchzuführen. Entsprechen die Ergebnisse nicht den Anforderungen, so kann man
zu einer höheren Ebene zurückkehren und das Design verändern. Aufgrund des
ständigen „Auf und Ab“ nennt man diese Entwurfsstrategie auch „Jo-Jo-Design“
(vgl. auch [GlaRau94]).
Der Entwurfsprozess legt das Vorgehen bei der Entwicklung von VLSISchaltungen
lediglich
strategisch
fest.
Der
Prozess,
der
aus
den
Verhaltensspezifikationen die Strukturen erzeugt (Synthese), bleibt kreativ. Wenn
beispielsweise für ein Addierwerk spezifiziert wird, dass es Zahlen addieren kann,
gibt es mehrere Implementierungsmöglichkeiten (z.B. Ripple-Carry-Adder, CarryLookahed-Adder, etc., vgl. [HePa97]), die alle unterschiedliche Vor- und Nachteile
haben (Trade-off zwischen Anzahl der Komponenten und Geschwindigkeit). Eine
vollständige
Automatisierbarkeit
der
Entwicklung
ist
daher
Prozessordesign bleibt daher sowohl Kunst als auch Wissenschaft.
nicht
möglich.
24
Für den rechnerunterstützten Entwurf von VLSI-Schaltungen hat man sog.
Hardware-Beschreibungssprachen
(Hardware
Description
Languages,
HDL)
entwickelt. Sie beschreiben in ähnlicher Notation wie eine Programmiersprache in
abstrakter und formaler Weise die Struktur und das Verhalten von Systemen. Auf
Basis
der
Hardware-Beschreibungssprachen
können
auch
Simulationen
und
Validierungen durchgeführt werden. Das folgende Beispiel aus [Kropf95] in VHDL
(Very High Speed Integrated Circuits Hardware Description Language, IEEEStandard seit 1987) zeigt, wie ein Hardwarebaustein zur Bestimmung des größten
gemeinsamen Teilers zweier Zahlen spezifiziert werden würde. Genauere Details zu
VHDL finden sich auch in [Siemers2000].
Spezifikation der Struktur:
ENTITY GCD IS
PORT (
In1, In2
: IN Integer;
Start
: IN Std_Logic;
Result
: OUT Integer;
Ready
: OUT Std_Logic);
END GCD;
Spezifikation des Verhaltens:
ARCHITECTURE Behavior OF GCD IS
BEGIN
PROCESS
VARIABLE Z1, Z2 : Integer;
BEGIN
WAIT UNTIL Start = ’1’ AND Start’EVENT;
Ready <= ’0’;
Z1 := In1;
Z2 := In2;
WHILE (Z1 /= Z2)
LOOP
IF (Z1>Z2)
THEN
Z1 := Z1 – Z2;
ELSE
Z2 := Z2 – Z1;
END IF;
END LOOP;
25
Result <= Z1;
Ready <= ’1’;
END PROCESS;
END Behavior;
Aufgrund der hohen Komplexität der Hardware ist das Testen der fertigen
Bausteine nicht mehr einfach. Es kann sogar sein, dass die Testkosten die
Herstellungskosten übersteigen [Runyon99]. Um das zu vermeiden, müssen beim
Entwurf der Architektur auch Testmöglichkeiten berücksichtigt werden. Hierbei
gibt es verschiedene Ansatzpunkte (vgl. [Märtin01]), von denen
die wichtigsten erwähnt werden:
•
Design Rule Checking soll Fehler schon präventiv während des Entwurfs
verhindern [Crouch99].
•
Design for Testability: Zusätzliche Hardware in Chips einbauen, die
spätere Tests vereinfacht [ABF95]. Dazu gehören beispielsweise
Testmustergeneratoren, zusätzliche Register und Pins, oder DebugAusführungsmodi (z.B. in den Intel Pentium CPUs vorhanden).
•
Beim Built-In Self Test (BIST) wird das Testverfahren komplett in den
Chip integriert [ABF95], [Wunderlich98]. BIST wird z.B. in manchen CPUs
oder in RAM-Speichern benutzt.
Die wesentlichen technischen Herausforderungen beim Designprozess bleiben
die Beherrschung der Komplexität, der geringe Energieverbrauch (weil dadurch
Taktraten gesteigert werden können) und das Handhaben des memory-latencyProblems (Speicher ist viel langsamer als CPU, so dass diese oft warten muss). Die
Entwicklungszeit eines Prozessors sollte so kurz wie möglich sein, um den
Herausforderungen des Marktes gerecht zu werden. Es ist oft nicht auszuschließen,
dass bis zur Fertigstellung eines Prozessors die Technologie bereits veraltet ist und
am Markt kein Bedarf mehr besteht.
26
1.5 Klassifizierungsschemata
Für die Vergleichbarkeit und Analyse von Rechnern sind Modelle notwendig,
die Rechner nach bestimmten Kriterien, wie z.B. Aufbau und Organisation,
klassifizieren. Die Modelle basieren prinzipiell immer darauf, dass erst alle
Kriterien identifiziert werden, die für die Unterschiede verantwortlich sind und die
Rechner damit in bestimmte Klassen eingeordnet werden. Rechner innerhalb einer
Klasse werden als äquivalent angesehen. Es ist allerdings hinzuzufügen, dass solche
Klassifikationen nicht immer eindeutig durchzuführen sind und auch die Wahl der
Kriterien nicht unumstritten ist. Generell wird bei der Klassifikation auch nicht
zwischen Rechner- oder Prozessorarchitektur unterschieden (vgl. [BeiHag01]).
1.5.1 Klassifikation nach Flynn
Das wohl berühmteste und am häufigsten gebrauchte Klassifikationsverfahren
ist das von Flynn (vgl. [Flynn72]). Es enthält 4 Klassen von Rechnerarchitekturen.
Als Kriterien werden das einfache oder mehrfache Auftreten von Befehls- und
Datenströmen verwendet.
Tabelle 1: Klassifizierung nach Flynn
einfacher Befehlsstrom (SI)
mehrfacher Befehlsstrom (MI)
einfacher
SISD
MISD
Datenstrom (SD)
(von-Neumann-Architektur)
(-)
mehrfacher
SIMD
MIMD
Datenstrom (MD)
(Vektorprozessoren)
(Mehrprozessorrechner)
Flynn geht davon aus, dass
•
zu einem Zeitpunkt entweder nur ein Befehl (Single Instruction, SI)
oder mehrere Befehle (Multiple Instructions, MI) ausgeführt werden
können
27
•
zu einem Zeitpunkt ein Rechner nur einen Datenwert (Single Data,
SD) oder mehrere Datenwerte (Multiple Data, MD) bearbeiten
kann.
SISD-Rechner entsprechen den klassischen von-Neumann-Rechnern, deren
Steuerwek Befehle zeitlich einzeln und nacheinander ausführt. Das Problem dieser
Klasse ist, dass alle Rechner, die genau ein Steuerwerk und ein Rechenwerk
besitzen in diese Klasse fallen und nicht weiter differenziert werden. Die
Klassifizierung ist also recht grob.
SIMD-Rechner sind eine Klasse, die ein Steuerwerk und mehrere Rechenwerke
besitzen, so dass sie einen Befehl (durch Instruction Broadcasting) gleichzeitig auf
mehrere Daten anwenden können.
MIMD-Rechner bestehen aus mehreren selbständigen Prozessoren. Auch diese
Einteilung ist nicht fein genug. So kann z.B. nicht zwischen eng gekoppelten
Systemen (alle Prozessoren haben einen gemeinsamen Adressraum) und lose
gekoppelten Systemen (jeder Prozessor hat einen eigenen Adressraum) unterschieden werden (vgl. [Märtin01]).
Die aus Symmetriegründen vorhandene Klasse MISD bleibt leer, da man ihr
keine bekannten Systeme zuordnen kann.
Insgesamt ist also die Klassifikation nach Flynn durch einen sehr hohen
Abstraktionsgrad gekennzeichnet. Es wird kritisiert, dass in eine Klasse sehr viele
Architekturen fallen und eine Klasse leer bleibt, weshalb die Güte der Klassifikation
in Frage gestellt wird. Bei modernen Superskalar-Architekturen oder Mischformen
verschiedener Architekturen ist die Klassifikation ebenfalls problematisch.
1.5.2 Erlanger Klassifikationssystem
Das Erlanger Klassifikationssystem (Erlanger Classification System, ECS) wurde
1975 von Händler vorgeschlagen [Händler75] und versucht mit einer möglichst
einfachen Darstellung auch die Parallelität in Rechnern zu beschreiben. Ein
Rechner wird dabei in die Ebenen Prozessorebene, Befehlsausführungsebene,
Verarbeitungsebene unterteilt und durch Tripel beschrieben:
tRechnertyp = (k * k’, d * d’, w * w’)
28
Dabei ist
Die
•
k die Anzahl der Steuerwerke
•
d die Zahl der Rechenwerke die einem Steuerwerk zugeordnet sind
•
w die Wortbreite des Rechners
Elemente
hinter
dem
Konkatenationsoperator
„*“
sollen
die
Beschreibungsgenauigkeit steigern und können auch weggelassen werden. Die
Zahlen k, d, w sollen als Maß für die Nebenläufigkeit und k’, d’, w’ als Maß für
Pipelining (vgl. Kap. 3.1) auf den verschiedenen Ebenen dienen.
Unter Nebenläufigkeit versteht man, dass k Prozesse unabhängig voneinander
bearbeitet werden können. Das optionale Element k’ stellt eine weitere
Spezialisierung des Steuerwerks dar und gibt den Grad des Makropipelinings an.
Beim Makropipelining gibt es mehrere Prozessoren, die den gleichen sequentiellen
Datenstrom bearbeiten, wobei aber jeder Prozessor eine andere Phase der
Ausführung bearbeitet.
Das Element d gibt an, dass eine Operation gleichzeitig von d Rechenwerken
ausgeführt werden kann. Die Zahl d’ gibt den Grad des Befehlspipelinings in einem
Rechenwerk an, d.h. dass maximal d’ sequenzielle Befehle gleichzeitig ausgeführt
werden können, wenn es keine Datenabhängigkeiten zwischen ihnen gibt und
genügend Funktionseinheiten für die Verarbeitung bereit stehen.
Auf der Wortebene (Mikroarchitekturebene) des Rechners gibt die Zahl w’ den
Grad des Phasenpipelinings an. Dabei wird die Ausführung eines Befehls zeitlich in
w’ Phasen unterteilt, wobei jede Verarbeitungseinheit der Pipeline eine Phase
bearbeitet.
Die folgende Abbildung fasst die Rechnertypen nach ECS überblicksartig zusammen.
29
Rechnerstrukturen
Serienrechner
Parallelrechner
Rechner mit
Nebenläufigkeit
Multiprozessor
k>1
Feldrechner Parallelwortrechner
d>1
w>1
Pipelinerechner
Rechner mit
Makropipelining
k’>1
Rechner mit
Befehlspipelining
d’>1
Rechner mit
Phasenpipelining
w’>1
Abbildung 9: ECS-Klassifikation von Prozessoren. Quelle: [BeiHag01]
Das ECS enthält auch weitere Operatoren, wie z.B. „+“, um Strukturen
darzustellen, die sich während der Verarbeitung gegenseitig ausschließen, oder
„v“, um variable, d.h. rekonfigurierbare Elemente darzustellen.
Es folgen nun ein paar einfache Beispiele für ECS-Tripel aus [Märtin01].
tBeispielrechner := (9000, 1, 32)
„Es handelt sich um einen Multiprozessor, dessen 9000 Prozessoren
über je ein Rechenwerk verfügen. Die Prozessoren besitzen die
Wortlänge 32 Bit.“ Entspricht etwa dem ASCI-Red Supercomputer.
tBeispielrechner2 := (1, 64, 64)
Es handelt sich um einen Rechner mit 1 Steuerwerk und 64 Rechenwerken der Wortlänge 64 Bit.
tBeispielrechner3 := (1 * 3, 1, 32)
„Ein Drei-Prozessor-System, das als Makropipe konfiguriert wurde, bei
dem jeder Prozessor ein nahezu identisches Teilprogramm ausführt.“
tPentium III := (1, 1 * 5, 32)
„Das bedeutet: Pro Takt können intern 5 bereits dekodierte Befehle
an Funktionseinheiten zur Ausführung übergeben werden.“
30
1.5.3 Klassifikation nach dem internen Speichermodell
Eine andere Möglichkeit, Prozessoren zu klassifizieren, ist das interne
Speichermodell (vgl. [BeiHag01]). Es spezifiziert den Zugriffsbereich des Prozessors
auf die Operanden bei der Ausführung von Operationen. Dabei gibt es folgende
Architekturklassen:
1. Stack-Architektur
Der Prozessor greift auf einen in Hardware implementierten Stack zu, wo
Quell- und Zieloperanden gespeichert werden. Vorteilhaft ist, dass die
Zugriffe auch implizit durch eine genau festgelegte Reihenfolge erfolgen
können. Damit entfällt die ständige Angabe der Operanden und es ergeben
sich kleinere OpCode-Längen. Allerdings sind Austauschoperationen für die
Datenübertragung zum und vom Stack nötig sowie Operationen für die
Datenumschichtung im Stack.
2. Akkumulator-Architektur
Hierbei gibt es ein spezielles Register, den Akkumulator, das implizit als
Quelle bzw. Ziel einer Operation benutzt werden kann. Die Architektur ist
damit zwar sehr einfach, aber der Akkumulator entwickelt sich zum Engpass
des Systems, weil er häufig gebraucht wird. Das erfordert auch, dass sein
Inhalt häufig zwischengespeichert wird.
3. (General-Purpose-)Register-Architektur
Bei dieser Architektur wird mindestens ein Operand aus einem internen
Register des Prozessors geholt, welches auch explizit angegeben werden
muss. Dabei gibt es zwei Varianten:
3.1 Register-Speicher-Architektur
Das Register und eine Speicheradresse werden explizit angegeben. Der
Vorteil ist, dass Daten direkt aus dem Speicher benutzt werden
können und nicht vorher alle in die Register geladen werden müssen.
Nachteilig ist die sehr unterschiedliche Zugriffszeit von Register und
Speicher.
31
3.2 Register-Register-Architektur (Load-Store-Architektur)
Operationen
durchgeführt.
werden
Zwischen
nur
auf
Register
internen
und
Prozesor-Registern
Speicher
findet
nur
Datenaustausch statt. Das führt dazu, dass Operationen sehr schnell
ausgeführt werden können, aber zusätzliche Ladezugriffe nötig
werden. Diese Architektur ist bei RISC-Prozessoren zu finden (vgl.
Kap. 2.1.2)
1.5.4 Klassifikation nach Befehlsformaten
Die letzte hier vorgestellte Klassifikationsmöglichkeit von Prozessoren
orientiert sich am Format der Instruktionen ([BeiHag01], [SDI99]). Wie in Kap.
1.2 bereits erläutert, bestehen Instruktionen aus einem Operationsteil, dem sog.
OpCode und einem dazugehörigen Adress-Teil, der die benötigten Operanden
lokalisiert. Je nach Anzahl der Operanden unterscheidet man zwischen:
1-Adress-Prozessoren
•
Der Adressteil enthält nur eine Adresse.
•
Weiter benötigte Operanden befinden sich im Akkumulator-Register
(vgl. 1.5.3), das auch die Ergebnisse aufnimmt. Daher sind diese
Prozessoren an eine Akkumulator-Architektur gebunden. Alternativ ist
auch die Benutzung einer Stack-Architektur denkbar.
•
Bsp:
ADD 10
bedeutet:
Akkumulator := Akkumulator + Inhalt der Speicherzelle 10
•
Beispiel-Prozessor: Intel 8080
2-Adress-Prozessoren
•
Der Adressteil enthält 2 Adressen für 2 Operanden. Einer der
Operanden wird durch das Ergebnis überschrieben.
•
Bsp: ADD 10, 20
bedeutet:
Inhalt Speicherzelle 10:=
Inhalt Speicherzelle 10
+ Inhalt Speicherzelle 20
32
•
Beispiel-Prozessor: Motorola 68000
3-Adress-Prozessoren
•
Der Adressteil enthält 3 Adressen, jeweils für das Ziel und für 2 Operanden
•
Bsp: ADD 10, 20, 30
bedeutet
Inhalt Speicherzelle 10 :=
Inhalt Speicherzelle 20
+ Inhalt Speicherzelle 30
•
Beispiel-Prozessor: SUN SPARC
Allgemein heißt ein Prozessor m-Adress-Prozessor, wenn pro Instruktion m
Adressen explizit genannt werden.
Bei
der
obigen
Betrachtung
wurden
immer
Operanden
fester
Länge
vorausgesetzt. Es gibt auch Architekturen, deren Operanden nicht auf eine
Speicherzelle beschränkt sind. Dabei enthält eine Instruktion neben dem
Operations- und Operandenteil noch zusätzliche Angaben über die Länge der
einzelnen Operanden.
Bei der Betrachtung der Befehlsformate kann eine Klassifikation auch
hinsichtlich der Komplexität des Befehlssatzes erfolgen, beispielsweise nach CISC
und RISC-Architekturen. Diese werden in den Kapiteln 2.1.1 und 2.1.2 in einem
größeren Zusammenhang genauer beschrieben.
1.5.5 Fazit zur Klassifikation
Trotz der beschriebenen Ansätze bleibt die Klassifikation von Rechnern und
Prozessoren nach wie vor problematisch. Manche Verfahren beschreiben gleiche
Sachverhalte aus unterschiedlicher Sicht, während andere disjunkt zueinander sind.
Deswegen
soll
hier
der
Versuch
unternommen
werden,
die
vorgestellten
Klassifikationsverfahren zusammenfassend darzustellen und deren Gemeinsamkeiten, Unterschiede und Lücken aufzuzeigen.
33
1) ECS:
Nebenläufigkeit,
Pipelining,
Wortgröße
4) Flynn:
Befehls- &
Datenströme
einfach/mehrfach
2) Speichermodell:
Zugriffsbereich des
Prozessors auf
Operanden
3) Befehlsformate:
Anzahl explizit
gennanter Adressen
in Instruktionen
Abbildung 10: Gesamtsicht auf Klassifikationsverfahren
Die Gemeinsamkeiten sollen kurz erläutert werden:
1) und 2): Bei Feldrechnern und Multiprozessorsystemen (durch ECS beschrieben)
kann sich der Zugriffsbereich für Operanden (durch Speichermodell
beschrieben) auf einen gemeinsamen oder mehrere getrennte Speicher
erstrecken.
1) und 3): Die von 1) beschriebene Wortgröße nimmt mit der Anzahl der explizit
genannten Instruktionen zu, die 3) spezifiziert.
2) und 3): Die
Befehlsformate
und
das
Speichermodell
beeinflussen
sich
gegenseitig. Beispielsweise kann beim Stack- oder Akkumulator-Modell
die Adressierung eines Operanden implizit erfolgen (vgl. Adressierungsarten in Kap. 2.1.1).
3) und 4): Befehlsformate aus 3) werden von Flynn indirekt durch einfache oder
mehrfache Befehls- und Datenströme festgelegt.
4) und 1): Parallelität wird im ECS durch Nebenläufigkeit und Pipelining erfasst.
Flynn beschreibt diesen Sachverhalt mit mehrfachen Befehls- und
Datenströmen.
Die Ansätze 2) und 4) haben keine gemeinsamen Aspekte, da die Befehls- und
Datenströme nicht implizieren, ob eine Stack-, Akkumulator- oder RegisterArchitektur vorhanden ist. Schließlich gibt es keinen Aspekt, den 1), 2), 3) und 4)
34
gleichzeitig beschreiben (was auch durch die Disjunktion der Ansätze 2) und 4)
begründet werden kann).
Die Problematik der Klassifikation kann am Beispiel des Intel Pentium IIIProzessors beschrieben werden:
1) ECS:
tPentium III := (1, 1 * 5, 32)
Pro Takt können intern 5 bereits dekodierte Befehle an Funktionseinheiten zur Ausführung übergeben werden [Märtin01].
2) Speichermodell:
Der Speicher wird sowohl in Akkumulator- als auch in Stack-Architektur (bei der FPU, vgl. Kap. 2) implementiert (vgl. [Intel99]). Da aber
CISC-Befehle intern in einfachere „µOps“ transformiert werden (vgl.
Kap. 2.1.3) und RISC-ähnliche Decoder vorhanden sind, wird intern
auch eine Load/Store-Architektur implementiert [Gwen95]. Die
Klassifikation ist nicht eindeutig.
3) Befehlsformate:
Die Anzahl der Operanden ist nicht fest, sondern variiert je nach
Befehlstyp und Adressierungsart [Intel99], [TanGo99], [Märtin01].
4) Flynn:
Aus externer Sicht des Programmierers: SISD. Diese Einteilung stimmt
aber auch nicht ganz, da intern Phasenpipelines eingesetzt werden
und Befehle zeitlich überlappt bearbeitet werden (vgl. Kap. 3.1). Bei
MMX-Befehlen ist auch eine SIMD-Verarbeitung möglich (vgl. Kap.
3.3.4).
35
2 Mikroprozessorarchitektur
Wie schon in Kapitel 1.2 dargestellt wurde, ist eine CPU nach von Neumann
auf viele Arten erweiterbar, um eine noch effizientere und schnellere Verarbeitung
der Befehle zu gewährleisten. In diesem Kapitel werden Architekturerweiterungen
der von-Neumann-CPU vorgestellt, wie sie auch häufig in heutigen CPUs
vorkommen. Es wird auf die im Laufe der Zeit entstandenen CISC und RISC–
Philosophien
genauer
eingegangen.
Anschließend
werden
Konzepte
der
Speicherverwaltung, Pipelining und Sprungvorhersage bei der Befehlsausführung
vorgestellt, die der Performanceverbesserung dienen sollen. Danach sind die
Grundlagen vorhanden, um superskalare Architekturen aus einer Gesamtsicht zu
verstehen.
Zunächst
soll
anhand
eines
Blockdiagramms
eine
Architektur
eines
Mikroprozessors aus den 90er Jahren erläutert werden (nach [Tabak91]), da viele
der hier verwendeten Konzepte in späteren Architekturen zu finden sind.
Prefetch Unit und
Instruction Queue
Systembus
Datenbus
Adressbus
Steuerbus
Dekodiereinheit
(Decoding Unit)
Data Interface
Cache
Address Interface
Control Interface
Instruction
Cache
Steuerwerk
(Control Unit, CU)
Data
Cache
Memory Management
Unit (MMU)
Translation
Lookaside
Buffer (TLB)
Paging Unit
Segmentation
Unit
Integer ALU
General
Purpose
Register
Floating Point Unit (FPU)
FPU-Register
Abbildung 11: Architektur eines Mikroprozessors (angelehnt an [Tabak91])
36
Ein Mikroprozessor heißt n-Bit-Mikroprozessor, falls die ALU, Register und der
interne Bus des Mikroprozessors n-Bit breit sind. Manche Prozessoren haben
mehrere interne Busse, deren Breite auch ein Vielfaches von n sein kann.
Die Bus Interface Unit (BIU) enthält Puffer, die zwischen Prozessor und der
Außenwelt geschaltet sind. Die BIU wird in Daten-, Adress- und Control-Interface
unterteilt. Das Dateninterface verbindet den Datenbus des Gesamtsystems mit dem
Mikroprozessor, damit Daten gelesen oder geschrieben werden können. Über das
Adressinterface werden die von der Memory Management Unit (MMU) generierten
Adressen für Befehle oder Daten auf den Adressbus gelegt. Das Control-Interface
kann Signale des Steuerbusses lesen oder setzen. Die zu setzenden Signale erhält es
vom Steuerwerk (Control Unit, CU).
Die Control Unit ist über Steuerleitungen auch mit anderen Einheiten
verbunden, von denen sie den Status abfragen oder die Verarbeitung steuern kann.
Üblicherweise ist die CU bei CISC-Architekturen mikroprogrammiert, während sie
bei RISC-Architekturen fest verdrahtet ist.
Die Prefetch Unit holt Befehle aus dem Speicher und legt sie in eine FIFOQueue. Die Befehle werden dann an die Dekodiereinheit geschickt, welche mit der
CU gekoppelt ist, so dass die für die Ausführung des Befehls nötigen Steuersignale
gesetzt werden können.
Der Cache-Speicher (vgl. Kap. 2.2.1) kann Daten und Instruktionen entweder
zusammen oder getrennt speichern. Der Instruction-Cache ist zwischen Prefetch
Unit und BIU geschaltet. Wenn die Prefetch Unit mehrmals den gleichen Befehl
holen will, dann ist er bereits im Cache zu finden. Der Instruction-Cache und der
Daten-Cache sind auch noch mit dem internen Mikroprozessorbus verbunden. Bei
manchen Mikroprozessoren gibt es noch zusätzliche Busse, die den Datencache mit
den Verarbeitungseinheiten (Integer ALU, FPU) einzeln verbinden.
Die Integer ALU, manchmal auch Integer Unit (IU) genannt, hat oft
spezialisierte Teileinheiten für Addition/Subtraktion und Multiplikation/Division,
die auf die Allzweckregister (General Purpose Registers) zugreifen.
Auch die Floating Point Unit (FPU) hat auch oft Teileinheiten für
Addition/Subtraktion und Multiplikation/Division für Gleitkommazahlen. Außerdem
gibt es spezielle Register für Gleitkommazahlen. Die Operationen, welche die FPU
durchführt, sind durch den IEEE-754 Standard festgelegt.
37
Die MMU übersetzt logische (vom Prozessor berechnete) Adressen in physikalische Adressen (auf die schließlich zugegriffen wird) und überträgt sie an die BIU.
Außerdem wird der Paging-Mechanismus, der Segmentation-Mechanismus und die
Implementation von virtuellem Speicher unterstützt. Der Translation Lookaside
Buffer (TLB) ist ein Cache-Speicher, der bei der Adressübersetzung eingesetzt wird.
Auf die Speicherverwaltung geht das Kapitel 2.2 genauer ein.
Der Intel 486-Prozessor (zur zeitlichen Einordnung vgl. Abb. 7) ist beispielsweise ein 32-Bit-Mikroprozessor und hat u.a. eine Integer-ALU, 8 General-PurposeRegister, eine FPU mit 8 FPU-Registern, einen 8 KByte großen Cache-Speicher und
einen TLB mit 32 Einträgen. Weitere Details siehe [Tabak91] und [Messmer00].
2.1 ISA-Varianten
Im Verlauf dieses Kapitels werden die aus der historischen Entwicklung (vgl.
Kap. 1.3) hervorgegangenen ISA-Varianten genauer erläutert. Eine ISA (vgl. Kap.
1.1) beeinflusst durch die Festlegung der Befehlstypen, Befehlsformate und der für
den Assemblerprogrammierer sichtbaren Register in entscheidendem Maße die
Mikroprozessorarchitektur und das Zusammenwirken mit Compilern und Betriebssystemen (vgl. Kap. 6.1). Zunächst folgt eine Darstellung der reinen CISC- und RISCPrinzipien. Anschließend wird auf Architekturen eingegangen, die gleichzeitig
sowohl CISC-, als auch RISC-Konzepte benutzen.
2.1.1 CISC
Nach der Entwicklung des ersten Mikroprozessors (vgl. Abb. 7) wurden
Mikroprozessoren mit immer mehr Befehlen ausgestattet. Diese wurden auch
zunehmend komplexer, d.h. dass mehr Informationen in einem Befehlswort
vorhanden waren. Die Gründe hierfür waren, dass die Zugriffszeiten auf den
Speicher, verglichen mit der Verarbeitungsgeschwindigkeit des Prozessors, sehr
langsam
waren
und
deswegen
zusammenhängende
Aktionen
auch
zusammenhängend kodiert wurden. Das hatte gleichzeitig zur Folge, dass man
durch kompakten Code Speicher gespart hatte. Rechner mit solchen ISAs hat man
Complex Instruction Set Computer (CISC) genannt. Einige (wenige) Beispiele für
38
CISC-Mikroprozessoren sind: AT&T WE32100, Zilog Z80, Motorola 68000 und die
Intel 80x86 Familie.
Ein
Merkmal
von
CISC-Rechnern
ist,
dass
sie Mikroprogrammierung
verwenden, die 1951 von Wilkes erfunden wurde. Gemäß [Giloi97] ist ein
Mikroprogramm „die Darstellung eines Hardware-Algorithmus eines Prozessors, d.h.
eines Algorithmus, der von den Funktionseinheiten der Prozessor-Hardware
ausgeführt wird und damit eine Maschinenoperation durchführt.“ Die Idee ist, dass
die Kontrolle der CPU durch ein Programm erfolgt. Ein Makro-Befehl, wie
<load AX,mem[5]> (lade Inhalt der mem-Adresse 5 in Akkumulator)
könnte beispielsweise so in Mikrooperationen zerlegt werden:
<schreibe 5 in MAR>,
<lade den Wert mem[MAR] in MBR>,
<schreibe MBR ins Akkumulator-Register>.
Ein
Mikroprogramm
Mikrooperationen.
Die
besteht
aus
Mikrooperationen
einer
sind
sequenziellen
eine
Bitfolge
Folge
mit
von
einem
Instruktionsteil und einem Adressteil, wobei letzterer die Adresse des nächsten
auszuführenden Mikrobefehls enthält. Mikroprogrammierung kann auf mehrere
Arten implementiert werden. Das Mikroprogramm kann einerseits auf dem
Prozessor fest verdrahtet sein oder in einem Mikroprogrammspeicher liegen. Beim
horizontalen Mikrobefehlsformat stellen die Bits im Instruktionsteil Steuersignale
für die Hardware (=Picobefehle) dar. Dieses Vorgehen kann noch beim quasihorizontalen Format durch eine Stufe (=Nanobefehlsebene) zwischen Mikrobefehl
und Steuersignalen erweitert werden, d.h. Mikrobefehle liegen in kodierter Form
vor. Hierbei stellt der Mikrobefehl einen Index dar, der als Einstiegspunkt in eine
Look-up-Tabelle dient, die für den Mikrobefehl die entsprechenden Steuersignale
enthält. Beim vertikalen Format wird schließlich der kodierte Instruktionsteil wie
ein OpCode behandelt, der erst dekodiert werden muss. Für eine ausführlichere
Darstellung der Mikroprogrammierung und der Arten der Mikroprogrammierung sei
auf
[BeiHag01]
verwiesen.
Durch
Mikroprogrammierung
ist
ein
flexibles
Prozessordesign möglich, so dass neue ISAs leicht anzupassen sind und Abwärtskompatibilität ohne großen Aufwand gewährleistet werden kann. Der Nachteil sind
39
die hohen Hardware-Kosten (da mehr Transistoren für die komplexe Dekodierlogik
benötigt werden) und die Langsamkeit der Ausführung von Befehlen.
Die Länge des Befehlswortes ist bei CISC-ISAs variabel (z.B. Pentium III: 1 bis
15 Bytes) und es gibt viele unterschiedliche Befehlstypen (etwa 480 bei der
Pentium
III
IA-32-ISA),
was
die
Dekodierung
erschwert
(vgl.
[Märtin01]).
Befehlstypen können sein: Daten-Movement-Befehle, Austauschbefehle, Befehle zur
Stack-Manipuation, Arithmetische Befehle, Logische Befehle, Verzweigungen,
Ein-/Ausgabe-Befehle, u.v.a.m. Die Dekodierung ist aufwändig, da die Grenzen des
Befehls, die über mehrere Bytes verteilten Opcodes und die Operanden erkannt
werden müssen. Für die Operanden können zusätzlich noch Adressberechnungen
erfolgen.
CISC-Rechner verfügen auch über eine große Anzahl an Adressierungsarten,
wovon hier einige vorgestellt werden sollen. Adressierungsarten beschreiben, wie
die physikalischen Adressen von Daten ermittelt werden. Ausgangspunkt ist dabei
die
Ermittlung
der
Operanden
einer
Instruktion.
Dabei
gibt
es
mehrere
Möglichkeiten, wo sich Operanden befinden können:
•
unmittelbar nach der Instruktion
•
in Registern
•
im Speicher
Bei impliziter Adressierung ist der Ort des Operanden bei Benutzung des
Befehls implizit bekannt und wird nicht angegeben (z.B. Operand im Akkumulator
bei Akkumulator-Architektur, oder auf oberster Stack-Ebene bei Stack-Architektur,
vgl. Kap. 1.5.3)
Register
Instruktion
Daten
Abbildung 12: Implizite Adressierung (implicit)
Bei der unmittelbaren Adressierung folgt der Operand unmittelbar dem
OpCode im Speicher:
40
Instruktion
Daten
Abbildung 13: Unmittelbare Adressierung (immediate)
Die registerdirekte Adressierung enthält im Operandenteil die Adresse eines
Registers, welches die Daten enthält:
Register
Instruktion
Adresse
Daten
Abbildung 14: Registerdirekte Adressierung (register direct)
Das kann noch zur registerindirekten Adressierung erweitert werden, so dass
im Register wieder eine Speicheradresse steht, die die Daten enthält:
Register
Speicher
Instruktion
Adresse
Adresse
Daten
Abbildung 15: Registerindirekte Adressierung (register indirect)
Bei
der
speicherdirekten
Adressierung
enthält
der
Adressteil
eine
Speicheradresse, wo die Daten zu finden sind:
Register
Speicher
Instruktion
Adresse
Daten
Abbildung 16: Speicherdirekte Adressierung (memory direct)
Auch das kann zur speicherindirekten Adressierung erweitert werden, so dass
der Inhalt der im Adressteil angegebenen Speicherzelle die Adresse des Operanden
darstellt:
41
Speicher
Speicher
Adresse
Daten
Instruktion
Adresse
Abbildung 17: Speicherindirekte Adressierung (memory indirect)
Schließlich
gibt
es
noch
indizierte
Adressierungsarten.
Bei
der
speicherdirekten, indizierten Adressierung wird noch ein Index aus einem
Indexregister auf die Adresse im Adressteil der Instruktion addiert, was für das
Durchlaufen zusammenhängender Speicherbereiche nützlich ist.
Register
Instruktion
Speicher
Index
Adresse
+
Daten
Abbildung 18: Speicherdirekte, indizierte Adressierung (memory direct,
indexed)
Von dieser Adressierungsart gibt es noch Varianten mit Postinkrement oder mit
Prädekrement, die den Inhalt des Indexregisters nach dem Zugriff um einen
konstanten Wert erhöhen bzw. vor dem Zugriff vermindern. Details gibt es in
[BeiHag01].
Ein zusätzliches Merkmal von CISC-Befehlssatz-Architekturen ist die geringe
Anzahl der Register. Beispielsweise hat die IA-32-Architektur von Intel (vgl.
[Intel00a]) acht 32-Bit breite Standardregister (EAX, EBX, ECX, EDX, ESI, EDI, EBP,
ESP). Die einzelnen Register haben dabei auch spezielle Funktionen, z.B. wird AX
als Akkumulator (vgl. Akkumulator-Architektur Kap. 1.5.3) oder Operanden-Register
verwendet und ECX für die Steuerung von Schleifen. Zusätzlich gibt es noch sechs
16-Bit breite Segment-Register (CS, SS, DS, ES, FS, GS), welche die Adressierung
von Programm-Segmenten unterstützen sollen und ein Flag-Register, dessen StatusBits z.B. einen erfolgten Übertrag oder ein negatives Vorzeichen signalisieren.
Weitere
Systemregister
erleichtern
die
Implementation
von
Paging
auf
Betriebssystemebene (vgl. Kap. 6.1) und enthalten u.a. auch den Befehlszähler
(PC). Schließlich existieren noch acht 80-Bit breite Gleitkomma-Register, die als
Stack organisiert sind (vgl. Stack-Architektur, Kap. 1.5.3) und acht 128-Bit Register
(ab Pentium III) für SIMD-Befehle auf Gleitkommadaten (vgl. Kap. 3.3.4). Es sei hier
42
noch darauf aufmerksam gemacht, dass die IA-32-Architektur dem Programmiermodell des Rechners entspricht, der sie implementiert (z.B. Pentium III).
2.1.2 RISC
Nach der rasanten Entwicklung von CISC-Prozessoren kam in den 70er Jahren
eine andere Philosophie auf. Man stellte fest, dass in 99% der Programmcodes nur
etwa 30 Befehle verwendet wurden [HePa96]. Diese Erkenntnis war die Geburtsstunde von RISC (Reduced Instruction Set Computer) [Pat85]. Merkmale der RISCArchitektur sind oft weniger als 150 Maschinenbefehle mit einheitlicher Länge,
wenig Befehlstypen (etwa 40-80) und der völlige Verzicht auf Mikroprogrammierung
(vgl. [BeiHag01]). Das hat zur Folge, dass zwar die Programmgröße wächst, aber
die Hardware und die Dekodierung der Befehle sehr vereinfacht werden. Da es
keine
Mikroprogramme
und
ein
einheitliches
Befehlsformat
gibt,
ist
die
Dekodierung fest verdrahtet und die Ausführungsgeschwindigkeit steigt. Ein
weiteres Merkmal von RISC-Prozessoren ist, dass pro Takt 1 Befehl ausgeführt wird
(1 CPI, 1 Clock per Instruction). Um das zu realisieren, werden Phasenpipelines
eingesetzt (vgl. 3.1). Bei der Reduktion der Befehle werden auch diejenigen
abgeschafft, die direkte Manipulationen im Speicher durchführen. Deswegen wird
bei RISC-Prozessoren eine Load-Store-Architektur mit vielen Registern (>32) implementiert (vgl. 1.5.3). Für eine Manipulation von Daten im Speicher müssen erst die
Daten in die Register übertragen werden, dort verändert und anschließend wieder
zurück in den Speicher geschrieben werden. Im Gegensatz zu CISC-Architekturen
gibt es oft weniger als 4 Adressierungs-Modi. Der RISC-Ansatz verlässt sich auch
darauf, dass Compiler optimierten Code generieren (vgl. Kap. 6.1). Beispiele für
bekannte RISC-CPUs sind: HP Precision Architecture, Fairchild Clipper, Berkeley
RISC, Stanford MIPS, AMD Am29000, Motorola 88000, Intel 80860, ARM (Advanced
RISC Machine), IBM RS/6000 (RS=Risc System), SUN SPARC, IBM POWER, DEC Alpha.
Rückblickend kann man die Entwicklung von RISC-Prozessoren in 3 Generationen unterteilen [ObVossen00]. In den 70er Jahren wurden RISC-Prozessoren zum
ersten Mal implementiert. Beispielsweise hatten die RISC-II-Prozessoren (Berkeley)
über 138 32-Bit-Register und einen Befehlssatz von 39 Instruktionen. Gleichzeitig
war die Hardware-Komplexität mit 20.000 bis 100.000 Transistorfunktionen gering.
Bei der 2. Generation gab es umfangreichere Befehlssätze (z.B. für Gleitkomma-
43
operationen) und zusätzlich in Hardware integrierte Funktionen, wie beispielsweise
eine MMU für die Adressübersetzung. Dabei lag die Komplexität unter 1 Mio.
Transistorfunktionen. Ein Prozessor dieser Generation ist beispielsweise der SUN
SPARC-Prozessor. Die 3. Generation ist noch zusätzlich um Parallelitätskonzepte
wie Superpipelining (vgl. Kapitel 3.1) und Superskalarität (vgl. Kapitel 3.3)
erweitert worden.
Im folgenden soll nun eine typische RISC-Architektur anhand des PowerPCMikroprozessors vorgestellt werden. Der PowerPC (Performance Optimization
With Enhanced RISC Performance Computing) basiert auf der Power-Architektur,
die von Apple, IBM und Motorola entwickelt wurde (vgl. [Weiss94]). Von diesem
Prozessor gab es mehrere 32-Bit Versionen: PowerPC 601 (1993), PowerPC 603
(Ende
1993,
geringerer
Energieverbrauch),
PowerPC
604
(1994,
höhere
Leistungsfähigkeit). Der PowerPC 620 (1994) hatte schließlich eine 64-BitArchitektur (vgl. Abb. 7 und [Ungerer95]).
Branch Processing Unit
instruction fetch
Condition-Register
Link-Register
Count-Register
instruction dispatch
Floating Point Unit
Integer Unit
..
32 doppelt genaue
FP-Register
32 Register
Adressen
IU-Daten
FPU-Daten
Speicher
Abbildung 19: Logische Sicht der POWER-Architektur (angelehnt an [Weiss94])
44
Die PowerPC-Architektur definiert aus logischer Sicht die Verarbeitungseinheiten Branch Processing Unit (BPU), Integer-Unit (IU) und Floating Point Unit
(FPU), welche parallel zueinander arbeiten können. Die BPU ist dafür zuständig,
Sprungbefehle zu bearbeiten, während die IU Integer-Befehle und die FPU
Gleitkommabefehle bearbeitet.
Die BPU enthält ein Link-Register, welches die Adresse eines Sprungziels oder
eine Rücksprungadresse aufnehmen kann und von bestimmten Befehlen bei der
Ausführung von Unterprogrammen benötigt wird. Für die Implementierung von
Schleifen gibt es ein Count-Register. Außerdem enthält die BPU noch ein ConditionRegister mit acht 4-Bit großen Bedingungsfeldern, die von vielen Befehlen gesetzt
werden können.
Die IU hat 32 allgemeine Register und einen Satz von Operationen für
Berechnung, Bitverschiebung und Speicherzugriff. Hier werden auch Adressberechnungen für Speicheroperationen durchgeführt und deren Ausführung gesteuert.
In der FPU gibt es 32 doppelt genaue Gleitpunkt-Register. Genauere Spezifikationen für die Realisierung der FPU werden nicht gemacht.
Nachdem jetzt die Grundelemente der POWER-Architektur bekannt sind, wird
nun überblicksartig die Architektur des PowerPC 601 als 32-Bit Implementierung
(2,8 Mio Transistoren, 50 MHz Taktfrequenz) der Power-Architektur genauer
beschrieben. Der PowerPC 601 hat über 200 Befehle, die alle 4 Byte lang sind und
in
die
Klassen
Integer-Befehle,
Prozessor-Kontroll-Befehle
Load/Store-Befehle,
eingeteilt
werden.
Pro
Floating-Point-Befehle,
Takt
können
durch
die
„Instruction Queue and Dispatch Logic“ (Befehlszuordnungseinheit) bis zu 3 Befehle
den Ausführungseinheiten IU, FPU, BPU zugeordnet werden. Die Befehlszuordnungseinheit kann auf einmal 8 Instruktionen aus dem Cache in eine interne
Befehlspuffer-Queue (Instruction Queue) holen. In einem Takt werden die 4 vordersten dieser Instruktionen auf Abhängigkeiten untersucht. Prinzipiell (es gibt
einige Einschränkungen) werden dann bis zu 3 Befehle aus der Queue auf BPU, IU
und FPU verteilt, je nach dem, ob es sich um Verzweigungs-, Integer-, oder
Gleitkommainstruktionen handelt.
45
Instruction Queue and Dispatch Logic
32
32
Sequencer
Unit
BPU
32
Reservation
Station (2)
IU
256
FPU
64
Instruction
Fetch Unit
MMU
Tags
32
32 K Cache
32
256
Memory Queue and Bus Interface
32
Adressen
64
Daten
Abbildung 20: PowerPC 601 (angelehnt an [Ungerer95])
Die „Instruction Fetch Unit“ (Befehlsbereitstellungseinheit) sorgt für die
Bereitstellung der Befehle vom Cache in den Befehlspuffer, wobei sie die Adressen
der Befehle von der BPU (bei Verzweigungsbefehlen) oder von der Sequencer-Unit
(bei Unterbrechungen/Synchronisationsereignissen) erhält. Dabei können auch
Sprungvorhersagetechniken verwendet werden (vgl. Kap. 3.2). Die Sequencer-Unit
entlastet andere Einheiten bei der Arbeit und unterstützt beispielsweise die IU bei
der Ausführung selten benutzter Befehle oder bei steuerintensiven Aufgaben und
überwacht die Ausführungsreihenfolge der Befehle. Die IU hat eine 4-stufige
Pipeline (vgl. Kap. 3.1) und implementiert arithmetische Operationen für IntegerBefehle. Außerdem findet hier die Adressberechnung für alle Lade- und
Speicherbefehle statt.
Die Reservation Station ist ein Befehlspuffer für 2 Befehle, der vor die FPUAusführungseinheit geschaltet ist. Durch diesen zusätzlichen Puffer kann die
Dispatch Logic schon Befehle zuordnen, wenn die FPU für die Ausführung eines
Befehls länger braucht oder wenn Operanden einer Instruktion noch nicht verfügbar
sind. Die FPU verarbeitet 64-Bit Gleitpunktbefehle in einer 4-stufigen Pipeline.
Die MMU übersetzt für Befehle und Daten die logischen Adressen in
physikalische Adressen. Der Cache ist 32 KByte groß und enthält sowohl Daten als
46
auch Instruktionen. Auf weitere Konzepte der Speicherverwaltung geht das Kapitel
2.2 ein.
Die Schnittstelle zur Außenwelt wird durch die Bus-Interface-Einheit gebildet,
die eine Memory-Queue enthält. Speicheranforderungen, die in der Memory-Queue
stehen, werden in Transaktionen der Busschnittstelle übersetzt.
Auch das Programmiermodell des PowerPC601 ist von der Power-Architektur
abgeleitet. Es enthält 32 allgemeine Register (GPR0-GPR31) in der IU, 32 Register
in der FPU (FPR0-FPR31), die speziellen Register Link-Register (LR), Count-Register
(CTR), Condition-Register (CR), Integer Exception Register (XER), Floating Point
Status and Control Register (FPSCR), Multiplikationsregister (MQ), Real Time Clock
Upper (RTCU), Real Time Clock Lower (RTCL). Diese Register stehen dem
Programmierer zur Verfügung und werden auch User-Register genannt. Schließlich
sei noch erwähnt, dass es noch etwa 60 weitere Register gibt, die für den
Programmierer nicht sichtbar und nur im sog. Supervisor-Modus verwendbar sind
(Details siehe [ObVossen00], [Staudt94]).
2.1.3 Zusammenwachsen von CISC und RISC
Seit den 90er Jahren (vgl. Abb. 6) verschwimmen die Grenzen zwischen CISC
und RISC, da Prozessoren vermehrt Konzepte aus beiden Philosophien verwenden.
Die Prozessorhersteller, die früher reine CISC-Architekturen realisiert hatten,
wurden von der zunehmenden Komplexität bei der Hardwareimplementierung
erschlagen. Die ISAs wurden immer umfangreicher, der Dekodieraufwand immer
größer und die Mikroprogrammierung immer aufwändiger,
was
zu
vielen
Fehlerquellen führte. Außerdem wurden Rechner nicht mehr in Assembler
programmiert. Der Maschinencode wurde zunehmend durch optimierende Compiler
erzeugt, die auf die Hardware abgestimmt waren (vgl. Kap. 6.1).
Aus diesen Gründen haben sich CISC-Architekturen dahingehend entwickelt,
dass nach außen hin CISC-Schnittstellen zur Verfügung stehen, aber intern ein nicht
so aufwändiger RISC-Kern existiert. Dazwischen gibt es Stufen, die CISC-Befehle in
das interne RISC-Format transformieren (vgl. Konzept der virtuellen Maschine aus
Kap. 1.1 und [Märtin01]). RISC-Architekturen sind leichter zu parallelisieren und die
Taktraten können stärker erhöht werden. Bei der P6-Architektur der Pentium-CPUs
erfolgt beispielsweise eine Vordekodierung der CISC-Befehle in sog. „µOps“ (≠
47
Mikroinstruktionen !). Dabei werden die Makrobefehle in eine Folge weniger
komplexer 3-Adress-Befehle (µOps) umgewandelt. Im Instruktionscache, der dann
als Trace-Cache (vgl. auch Kap. 6.2) bezeichnet wird, werden die bereits vordekodierten µOps gespeichert. Viele Compiler sind heutzutage in der Lage, für
Pentium-Prozessoren optimierten Code zu erzeugen.
Auf der Seite der RISC-Architekturen gibt es auch Veränderungen in CISCRichtung. In den Anfängen von RISC war die Anzahl der Befehle gering
(typischerweise weniger als 150). Mit der Zeit hat die Anzahl der Befehle
zugenommen (vgl. [BeiHag01]). Der Fokus bleibt aber nach wie vor auf der
Einfachheit der Hardware.
2.2 Speicher
Dieses Kapitel beschäftigt sich mit den Verbesserungsmöglichkeiten von
Architekturen auf der Seite des Speichers, um eine schnellere Befehlsausführung zu
unterstützen. Außerdem werden die Konzepte von Paging, Segmentierung und
virtuellen Speicher kurz erklärt, damit die Funktion und Notwendigkeit von MMUs in
Prozessoren verständlich wird. Im Laufe des Kapitels soll auch verdeutlicht werden,
warum man zwischen logischen bzw. virtuellen und physikalischen Adressen
unterscheidet.
Ausgangspunkt der Betrachtung ist das memory-latency-Problem. Die CPU
kann Befehle und Daten viel schneller verarbeiten, als der Speicher sie zur
Verfügung stellen kann. Dies ist das Resultat von verschiedenen technischen und
physikalischen Gegebenheiten. Man kann zwar kleinere und schnellere Speicher
herstellen, jedoch verursachen die derzeitigen technologischen Prozesse sehr hohe
Kosten. Aus diesen Gründen versucht man, die Mängel mit Hilfe der Architektur
auszugleichen. Die Architekturkonzepte, die nachfolgend vorgestellt werden, sind
stark von der gegenwärtigen Technologie beeinflusst (vgl. [Gwen95]).
2.2.1 Cache-Speicher
Das sog. Lokalitätsprinzip erlaubt eine Optimierung der Zugriffszeiten durch
die Architektur. Die Art und Weise der Programmierung (z.B. Unterprogramme mit
48
lokalen Variablen) wirkt sich auf Art und Häufigkeit der Speicherzugriffe aus.
Dadurch ergibt sich eine örtliche Lokalität, bei der die Adresse einer Speicherreferenz oft in der Nähe der Adresse einer alten Speicherreferenz liegt. Es gibt
auch eine zeitliche Lokalität, da die Zugriffe innerhalb eines Zeitintervalls in einem
eng abgegrenzten Adressbereich stattfinden.
Das sog. working set (vgl. [Denning80]) basiert auf dem Lokalitätsprinzip und
besteht aus der Menge aller Adressen, die ein Programm innerhalb einer
bestimmten Zeit t gebraucht hat. Adressen innerhalb des working sets werden oft
referenziert. Basierend auf dieser Erkenntnis versucht man, das working set in
einem kleinen, schnelleren aber auch teureren Zwischenspeicher zu halten. Da
dieser Pufferspeicher für den Prozessor beim Speicherzugriff transparent ist, nennt
man ihn Cache-Speicher (französisch: cacher = verstecken). Der Erwartungswert
der Zugriffszeit Tavg aus Sicht des Prozessors ergibt sich aus:
Tavg = p * TaccCache + (1-p) * TaccMem
TaccCache Zugriffszeit auf Cache
TaccMem Zugriffszeit auf Speicher
p
Wahrscheinlichkeit,dass
die gesuchte Adresse im
Cache ist
Die Wahrscheinlichkeit p ist, wenn die Größe des Cache-Speichers dem
working set entspricht, sehr hoch und kann durchaus 80-99% erreichen [HePa97].
Wegen
TaccCache <
TaccMem
senkt
der
Einsatz
eines
Cache-Speichers
die
durchschnittliche Zugriffszeit Tavg.
Wenn die Größe des Cache-Speichers wächst, nimmt gezwungenermaßen auch
die Zugriffszeit zu. Die Zugriffszeit ist aber immer noch geringer als beim direkten
Hauptspeicherzugriff. Deswegen haben sich Speicherhierarchiearchitekturen mit
mehreren Stufen („levels“) entwickelt. Auf der untersten Stufe befinden sich die
Register der CPU.
49
Prozessor
L1 Cache
T
avg
T
accL1
L2 Cache
Miss
L1
T
acc L2
Hauptspeicher
Miss
L2
T
accSpeicher
Abbildung 21: Darstellung einer Speicherhierarchie (angelehnt an [Dief99])
Speicherhierarchien dienen u.a. auch dafür, den sog. thrashing-Effekt (vgl.
[SG99]) zu reduzieren. Dieser Effekt tritt dann auf, wenn das working set größer als
der Cache-Speicher ist und deswegen der Aufwand bei der Cache-Verwaltung
größer wird als der eigentliche Nutzen. Das führt zur Verlangsamung der
Ausführung statt zur Beschleunigung.
Im Zusammenhang mit Speicherhierarchien gibt es sog. Dual-IndependentBus-Architekturen [Dief99]. Bei einem Speicherzugriff greift einer der Busse auf
den Cache zu, während der andere gleichzeitig auf den Speicher zugreift. Wenn die
gesuchten Daten nicht im Cache waren (cache miss), so hat man durch das frühere
Anstoßen beim Hauptspeicherzugriff Zeit gespart.
Aus Performancegründen teilt man bei manchen Architekturen die CacheSpeicher einer Ebene auf, beispielsweise in Daten- und Instruktions-Cache, die
über einzelne Busse angesprochen werden. Die Breite der Busse zwischen Prozessor
und Cache ist oft ein Vielfaches des Prozessor-Wortbreite, beispielsweise ist die
Busbreite zum L2-Cache oft 2-8 mal breiter als die Prozessor-Wortbreite (vgl.
[Märtin01]).
Auf Rechnerarchitekturebene hat die Speicherhierarchie aus technologischen
Gründen
noch
mehr
Stufen,
die
nach
dem
Hauptspeicher
folgen.
Die
Zwischenstufen würden alle entfallen, wenn es billige Hauptspeicher gäbe, die
einerseits genau so schnell arbeiten würden wie die CPU und andererseits die Daten
dauerhaft speichern könnten. Als nächstes soll kurz gezeigt werden, welche Arten
von Cache-Speicher es gibt und wie sie prinzipiell organisiert sind.
Die Organisation von Cache-Speichern basiert auf folgendem Modell (Abb. 22
und [TanGo99]):
50
Eintrag
StatusBits
Tag
Daten
Cache-Line
0
1
2
n
Abbildung 22: Cache-Speicher
Der Hauptspeicher wird in Blöcke fester Größer unterteilt (sog. Cache-Lines).
Im Cache befinden sich Kopien dieser Cache-Lines. Zu jeder Cache-Line existieren
sog. Tags, welche die Ursprungsadresse der Daten enthalten. Außerdem gibt es
noch Status-Bits, die Änderungen am Inhalt der Daten signalisieren und der
Konsistenzerhaltung im Hauptspeicher dienen. Bei jedem Hauptspeicherzugriff wird
überprüft, ob der gesuchte Inhalt bereits im Cache ist. Wenn ja (cache hit) werden
die Daten aus dem Cache gelesen. Sind die Daten nicht im Cache (cache miss),
dann wird eine Cache-Line aus dem Hauptspeicher gelesen, im Cache abgelegt und
anschließend an den Prozessor weitergegeben. Dieser Vorgang kann Ersetzungsstrategien erfordern, falls der Cache komplett belegt ist.
Eine typische Ersetzungsstrategie ist die Least Recently Used-Strategie (LRU).
Dabei wird derjenige Eintrag ersetzt, auf den am längsten nicht zugegriffen wurde.
Diese Strategie ist aber wegen der Suche nach Zeitstempeln aufwändig zu
implementieren, weswegen weniger komplexe Varianten gebräuchlich sind, wie
z.B. eine zufällige Ersetzung (vgl. [SGG99], [BeiHag01]).
Die Abbildung des Hauptspeichers auf den kleineren Cache-Speicher kann auf
mehrere Arten erfolgen (vgl. auch [BeiHag01]):
• direkt:
Die Adressen des Hauptspeichers werden modulo
Cache-Größe
auf
den
Cache
abgebildet.
Einem
Hauptspeicherblock ist damit eine feste Cache-Line
direkt zugeordnet. Kennt man die Speicheradresse, so
gibt es nur eine Stelle im Cache, wo man danach
51
suchen muss. Problematisch ist allerdings, dass zu
einer
Cache-Line
mehrere
Hauptspeicherblöcke
gehören können und der trashing-Effekt auftreten kann
[Märtin01].
• vollassoziativ:
Ein Hauptspeicher-Block kann auf einen beliebigen
Cache-Eintrag abgebildet werden, so dass die obigen
Konflikte vermieden werden. Um zu überprüfen, ob die
Daten einer Speicheradresse im Cache vorhanden sind,
wird durch die Hardware die Speicheradresse mit den
Adressen aus allen Cache-Lines gleichzeitig verglichen
(sog. assoziativer Vergleich). Diese Methode ist teuer
und aufwändig zu realisieren.
• n-fach-assoziativ: Soll
als
Kompromiss
zwischen
Flexibilität
und
Implementierbarkeit dienen. Pro Hauptspeichereintrag
gibt es jeweils n Cache-Einträge, in denen ein Eintrag
abgelegt werden kann. Dementsprechend müssen bei
der Suche nach einem Eintrag im Cache auch maximal
n Einträge geprüft werden.
Als Beispiel hat die Intel P6-Architektur auf Level 1 jeweils einen getrennten
Instruktions- und Daten-Cache. Beide haben eine Cache-Line-Größe von 32 Byte und
sind 8 KByte groß. Der Instruktions-Cache ist 4-fach-assoziativ und der Daten-Cache
2-fach-assoziativ. Der Cache auf Level 2 hat eine Cache-Line-Größe von 32 Byte, ist
insgesamt 256 KByte groß und 4-fach-assoziativ (Details siehe [Gwen95]).
Schreiboperationen auf eine Cache-Line können zu Inkonsistenzen zwischen
den Daten im Cache und denen im Hauptspeicher führen. Für die Aktualisierung
gibt es folgende Strategien:
• Write through:
Sowohl
die
zugehörige
Cache-Line
Block
im
im
Cache,
Speicher
als
werden
auch
der
aktualisiert
(„Durchschreiben“ auf die nächste Speicherebene).
52
• Write back:
Es wird nur die Cache-Line im Cache aktualisiert. Die
modifizierte Cache-Line wird erst dann in den Hauptspeicher zurückgeschrieben, wenn sie ersetzt wird.
Wenn bei einem Ladezugriff die gesuchten Daten nicht im Cache sind, können
Nicht-Blockierende-Cache-Speicher andere Cache-Zugriffe bedienen, während auf
die Daten vom Speicher gewartet wird. Dieses sog. hit-under-miss wird
beispielsweise in der Intel-P6-Architektur benutzt (vgl. [Gwen95]). Bei anderen
Maßnahmen zur Steigerung der Performance lagert man die Cache-Tags in die
darunter liegende Ebene der Speicherhierarchie aus, d.h. auf dem Prozessor
befinden sich die L1-Cache-Tags und die L2-Cache-Tags im L1-Cache (vgl. [Dief99]).
2.2.2 Paging und Segmentierung
Bei ungeschickter Verwaltung des Hauptspeichers kann es zur sog. externen
Fragmentierung (vgl. [SGG99]) kommen, so dass der gesamte Speicher in viele
kleine unzusammenhängende Teilbereiche zersplittert wird. Dies ist nicht
erwünscht und wird durch folgende Verfahren vermieden. Die logische Sicht ist
dabei die Sicht des Prozessors auf den Speicher. Die physikalische Sicht bezieht sich
auf die Perspektive des Speichers, der lediglich feststellen kann, dass auf eine
bestimmte physikalisch vorhandene Speicherzelle zugegriffen wird.
physikalische
Adresse
logische Adresse
CPU
d
f
d
Physikalischer
Speicher
p
f
Page-Table
Abbildung 23: Paging (angelehnt an [SGG99])
53
Beim Paging wird der logische Adressbereich des Hauptspeichers in Pages
fester Größe und der physikalische Adressbereich in Frames gleicher Größe
eingeteilt, um externe Fragmentierung zu vermeiden. Die Pages und Frames sind
durchnummeriert.
Eine
sog.
Page-Table
ordnet
jeder
Page-Nummer eine
bestimmte Frame-Nummer eines physikalischen Frames zu, wobei die Zuordnung
nicht kontinuierlich sein muss. Bei der Adressierung einer logischen Speicheradresse muss die Nummer der Page p und der Offset d innerhalb der Page bekannt
sein. Über die Page-Table wird die physikalische Anfangsadresse des Frames f
ermittelt und der Offset dazuaddiert, was zur gesuchten Speicherzelle führt. Durch
geschickte Wahl der Page-Größe kann die Adressübersetzung einer logischen
Adresse in Page-Nummer und Page-Offset erleichtert werden. Ist die Größe des
Adressraums 2m und die Größe einer Seite 2n, so ergeben die höherwertigen m-n
Bits einer logischen Adresse die Nummer der Page und die niederwertigen n Bits
den Offset.
Das Paging-Verfahren kann zur sog. internen Fragmentierung führen (Speicher
wird alloziert, der nicht gebraucht wird), wenn die Page-Größe zu groß gewählt
wird. Bei zu vielen kleinen Pages steigt der Verwaltungsaufwand unverhältnismäßig.
Die
sog.
Segmentierung
erlaubt eine Aufteilung des Speichers nach
inhaltlichen Kriterien. Der logische Adressraum wird in durchnummerierte
Segmente mit jeweils einer Anfangs- und Endadresse unterteilt. Der Unterschied
zum Paging ist, dass Segmente eine variable Länge haben können. Eine SegmentTabelle ordnet (ähnlich wie beim Paging) die logischen Segmente entsprechenden
physikalischen Segmenten zu. Die Adressierung verläuft auch ähnlich. Eine
Speicheradresse wird durch Segment-Nummer und Offset identifiziert.
Da die Segmentierung zwar die Semantik der Programme berücksichtigt aber
wieder zu externer Fragmentierung führt, wird ein Mischverfahren benutzt,
welches Paging auf die einzelnen Segmente anwendet. Bei der Adressierung müssen
Segment-Nummer, Page-Nummer innerhalb des Segments und Offset innerhalb der
Page bekannt sein. Beispielsweise benutzte der Intel 386-Prozessor Segmentierung
mit Paging für die Speicherverwaltung [SGG99].
Eine MMU führt die oben beschriebene Adressübersetzung durch und übernimmt die entsprechenden Verwaltungsfunktionen.
54
2.2.3 Translation Lookaside Buffer
Die oben beschriebenen Page- bzw. die Segment-Tabellen können sehr groß
werden. Da sie bei jedem Speicherzugriff benutzt werden, ist es sehr wichtig, dass
man eine effiziente Hardwareimplementierung benutzt. Eine Implementierung als
Register kommt bei großen Tabellen mit der derzeitigen Technologie aus
Kostengründen nicht in Frage. Lagert man die Tabelle im Hauptspeicher, so muss
für einen Hauptspeicherzugriff immer zweimal zugegriffen werden: einmal auf die
Tabelle, um die physikalische Adresse zu ermitteln, und einmal beim eigentlichen
Zugriff.
Glücklicherweise kann das Lokalitätsprinzip der Speicherzugriffe ausgenutzt
und Cache-Speicher eingesetzt werden (vgl. Kap. 2.2.1). Diese Cache-Speicher, die
als Translation Lookaside Buffer (TLB) bezeichnet werden, merken sich bei jedem
Speicherzugriff die zur Page-Nummer ermittelte Frame-Nummer. Wegen der
Schnelligkeit des Cache-Speichers und der hohen Trefferwahrscheinlichkeit steigt
die Zugriffszeit auf den Hauptspeicher nicht mehr auf das Doppelte an. Obwohl die
Zugriffszeit noch größer ist als bei nur einem Zugriff, nimmt man diesen Nachteil
wegen einer flexibleren Speicherverwaltung in Kauf. Details zur TLBs gibt es in
[SGG99].
Die Translation Lookaside Buffer gehören auch zur MMU. Bei der Intel IA-32Architektur gibt es beispielsweise mehrere TLBs mit Größen zwischen 4KB und 4MB
(siehe auch [Märtin01]).
2.2.4 Virtueller Speicher
Beim virtuellen Speicher schließt die Betrachtung noch eine Stufe Sneu der
Speicherhierarchie ein, die nach dem Hauptspeicher folgt. Die Größe des
Hauptspeichers ist dabei kleiner als Sneu. Mit Hilfe von Paging kann man Verfahren
implementieren, so dass auch Programme ausgeführt werden können, die größer als
der Hauptspeicher sind und nicht am Stück hineinpassen (vgl. [SGG99]). Die zu den
Pages aus dem Hauptspeicher gehörenden Frames befinden sich in Sneu.
Das sog. Demand Paging verfolgt die Strategie, Frames nur dann aus Sneu in
den Hauptspeicher zu laden, wenn sie bei einer Speicherreferenz gebraucht
werden. Beim Versuch, auf eine nicht vorhandene Page zuzugreifen wird die
55
Programmausführung suspendiert (page fault), der benötigte Frame in den Speicher
geladen und die Programmausführung an genau der gleichen Stelle wieder
fortgesetzt.
Sollte der Hauptspeicher beim Laden eines Frames komplett belegt sein, so
wird mit verschiedenen Ersetzungsstrategien (z.B. LRU, vgl. [SGG99]) eine Page
nach Sneu ausgelagert und an deren Stelle der neue Frame eingelagert. Beim Auslagern kann auch erst in einen Cache ausgelagert werden (victim cache).
Eine
MMU
kann
die
hardwaremäßig unterstützen.
beim
virtuellen
Speicher
benötigte
Verwaltung
56
3 Maßnahmen zur Performancesteigerung
Dieses Kapitel behandelt Architekturkonzepte, die ausgehend von der vonNeumann-Architektur die Performance noch weiter steigern sollen. Die hier
vorgestellten Maßnahmen konzentrieren sich im Wesentlichen darauf, Vorgänge bei
der Ausführung von Befehlen zu parallelisieren. Bei Pipelines wird zeitliche
Parallelität durch eine zeitlich überlappte Ausführung von Befehlen betont. Da in
bestimmten Situationen Pipelines nicht voll ausgelastet sein können, versucht man
durch Branch Prediction und Spekulation diesen Mangel zu beheben. Superskalare
Architekturen sind um räumliche Parallelität durch mehrfachen Einsatz gleicher
Komponenten erweitert, wie z.B. mehrere Pipelines.
3.1 Pipelines
Der Ansatzpunkt bei der Performancesteigerung mit Pipelines ist der fetchdecode-execute-Zyklus (vgl. Kap. 1.2). Der Nachteil der von-Neumann-Architektur,
dass zu einem Zeitpunkt nur eine der Phasen ausgeführt werden kann (ein Befehl
muss den Zyklus komplett durchlaufen, bis der nächste dran ist), kann mit Hilfe von
Pipelines ausgeglichen werden. Die Idee besteht darin, die Ausführung der Befehle
in Phasen einzuteilen, wobei jede Phase eine eigene Verarbeitungseinheit hat. Die
Verarbeitungseinheiten aller Phasen können gleichzeitig arbeiten. Man spricht
deshalb von Phasenpipelining. Bei der Ausführung wird dabei ein Befehl von einer
Verarbeitungsphase zur nächsten gereicht. Eine Pipeline kann als Analogie für ein
Fließband bei der Fertigung eines Autos gesehen werden, während bei der
Ausführung ohne Pipeline (nach von Neumann) die Fertigung eines neuen Autos erst
dann beginnt, wenn ein anderes komplett fertiggestellt ist.
S1
S2
S3
S4
S5
Instruktion
abrufen
Instruktion
dekodieren
Operanden
abrufen
Instruktion
ausführen
write-back
Abbildung 24: Fünfstufige Pipeline (angelehnt an [TanGo99])
57
Abb. 24 zeigt eine Pipeline mit 5 Stufen. Die Stufe S1 ruft einen Befehl aus
dem Speicher ab und lagert ihn, bis er gebraucht wird, in einen Puffer. Die Stufe S2
dekodiert im nächsten Takt den Befehl und bestimmt den Befehlstyp und die
Operanden, welche S3 aus dem Speicher (oder auch Register bzw. Cache, vgl. Kap.
1.5.3 und Kap. 2.2.1) abruft. Danach folgt im nächsten Takt die eigentliche
Ausführung des Befehls durch eine ALU (vgl. Kap. 1.1) in S4, d.h. der
Datenwegzyklus wird durchlaufen. Die letzte Stufe der Pipeline schreibt die
Ergebnisse an den vorgesehenen Zielort (z.B. Register).
Befehl
S1:
1
S2:
2
3
4
5
1
2
3
4
1
2
3
1
2
S3:
S4:
S5:
1
1
2
3
4
5
Zeit
Abbildung 25: Status jeder Stufe als Funktion der Zeit (angelehnt an [TanGo99])
Abb. 25 zeigt, warum mit einer Pipeline die Performance gesteigert werden
kann. Zum Zeitpunkt 1 wird Befehl 1 abgerufen. Zum Zeitpunkt 2 wird Befehl 1 dekodiert. Gleichzeitig wird aber schon Befehl 2 abgerufen. Zum Zeitpunkt 3 werden
für Befehl 1 die Operanden geholt, Befehl 2 dekodiert und Befehl 3 abgerufen.
Nach dem Ausführen zum Zeitpunkt 4 werden zum Zeitpunkt 5 die Ergebnisse von
Befehl 1 zurückgeschrieben, während die anderen Stufen an den darauf folgenden
Befehlen arbeiten.
Pipelines werden so konzipiert, dass alle Phasen in etwa die gleiche Zeit bei
der Verarbeitung benötigen. Diese Zeit sei mit t bezeichnet. Man versucht dabei,
die Länge eines Taktes an t anzugleichen (vgl. [BeiHag01]). Wenn eine Pipeline n
Stufen hat, so braucht ein Befehl t*n Zeiteinheiten, bis er die Pipeline durchlaufen
hat. Jeder Befehl in Abb. 25 braucht jeweils t*n Zeiteinheiten, bis er fertig
verarbeitet ist. Aus Sicht des Rechners steigt aber die Anzahl der verarbeiteten
58
Befehle pro Zeiteinheit, da alle t Zeiteinheiten ein Befehl die Pipeline verlässt (bei
voller Pipeline). Beim von-Neumann-Rechner würde nur alle t*n Zeiteinheiten ein
Befehl fertig verarbeitet sein.
Je nach Befehlsklasse können auch einzelne Phasen entfallen. Beim PowerPC
gibt es beispielsweise 4-stufige-Pipelines (vgl. Kap. 2.1.2). Die Firma Intel hatte
zum ersten Mal eine 5-stufige-Pipeline beim Intel486-Prozessor verwendet (vgl.
[TanGo99], [Messmer00]).
Eine besondere Form des Pipelining ist das sog. Superpipelining, bei dem die
einzelnen Stufen der Pipeline noch feiner unterteilt werden und intern mit einem
schnelleren Takt arbeiten. Die Länge einer Pipeline kann dabei insgesamt groß
werden. Beispielsweise hat eine Pentium-IV-Pipeline 20 Stufen (vgl. [Märtin01]).
Oft wird von Autoren Superpipelining gleichgesetzt mit dem Vorhandensein von
mehr als 5 Stufen in einer Pipeline, wie [Tabak95] bemerkt. Die Möglichkeiten von
Superpipelining sind durch exklusive Bus- und Speicherzugriffe, Kontrollfluss- und
Datenflussabhängigkeiten (vgl. [BeiHag01]), sowie durch physikalische Aspekte (vgl.
[Dief99]) begrenzt.
Bei superskalaren Architekturen werden mehrere Pipelines benutzt, die
teilweise auch gemeinsame Stufen haben. Die Organisation von superskalaren
Pipelines wird in Kapitel 3.3.1 behandelt.
3.2 Branch Prediction und Spekulation
Die Auslastung einer Pipeline kann u.U. durch Sprungbefehle sinken. Ein
Sprungbefehl wird wie jeder andere Befehl durch die Stufen einer Pipeline
weitergereicht. Erst in der letzten Phase (write-back) wird der Program Counter
(PC, vgl. Kap. 1.2) aktualisiert, so dass erst dann das tatsächliche Sprungziel
bekannt ist. Die Pipeline kann aber bis zum Zeitpunkt des Zurückschreibens des PC
keine weiteren Befehle holen und verarbeiten, da nicht bekannt ist, welche
Instruktionen als nächste im Programm folgen (control hazard, vgl. 3.3.1). Bei
bedingten Sprüngen müssten deswegen bis zum Zeitpunkt der Aktualisierung des PC
Wartezyklen eingelegt werden. Das führt zu erheblichen Performanceeinbußen, da
in einem Programm häufig jeder fünfte Befehl ein bedingter Sprung ist (vgl.
[Dief99]).
59
Andererseits könnte eine Pipeline bereits Befehle verarbeiten, die nach dem
Sprungbefehl folgen (spekulative Ausführung). Diese werden aber u.U. nicht
gebraucht, falls der Kontrollfluss anderswo hin verzweigt. Sollte das der Fall sein,
so muss die Pipeline geleert (Pipeline Flush), die Verarbeitung rückgängig gemacht
(Rollback) und die Pipeline mit den richtigen Befehlen wieder gefüllt werden. Die
Kosten im Sinne von Verarbeitungsaufwand (mispredict penalties) sind bei einer
falschen Sprungvorhersage hoch, insbesondere wenn die Pipeline viele Stufen hat
(vgl. Superpipelining, Kap. 3.1). Beispielsweise können sich beim Alpha 21264Prozessor bereits 20 oder mehr Nachfolgebefehle in der Pipeline befinden, bevor
klar wird, ob sie überhaupt benötigt werden (vgl. [Märtin01]).
Die Performance könnte dadurch gesteigert werden, dass man die Pipeline mit
den richtigen Befehlen füllt, noch bevor das Sprungziel bekannt ist. Da man aber
nicht in die Zukunft schauen kann, werden Sprünge mit heuristischen Methoden
vorausgesagt. Diese Methoden versuchen, die Wahrscheinlichkeit einer richtigen
Sprungvorhersage zu maximieren und die einer falschen Sprungvorhersage zu
minimieren.
Bei statischer Sprungvorhersage enthält ein Befehlswort für Sprungbefehle
noch zusätzliche Bits (static predictors), über die ein Compiler der Hardware
mitteilen kann, ob ein Sprung voraussichtlich durchgeführt wird oder nicht.
Beispielsweise wird bei einer for-Schleife fast immer ein Sprung an den Anfang der
Schleife durchgeführt, was vom Compiler erkannt und entsprechend signalisiert
wird. Lediglich beim Beenden der Schleife wäre die Sprungvorhersage falsch, was
zum Flush der Pipeline führt. Die Performance wäre aber insgesamt gesteigert, weil
der
Rücksprung
an
den
Anfang
viel
öfter
vorkommt.
Mit
statischen
Sprungvorhersagetechniken werden Trefferquoten von 65-85% erreicht (vgl.
[Dief99]).
Mit Hilfe dynamischer Sprungvorhersage kann die Trefferwahrscheinlichkeit
noch weiter auf 98% erhöht werden [Dief99]. Eine einfache Methode für
dynamische Sprungvorhersage ist die Branch History Table (BHT). Dabei handelt es
sich um einen Cache-Speicher (vgl. Kap. 2.2.1), der die Adressen von
Sprunginstruktionen und zugehörige History-Bits (dynamic predictors) enthält.
Während Sprünge stattfinden, werden Cache und History-Bits aktualisiert.
In einer ersten Variante gibt es nur ein Bit in der History, das für ein
Sprungbefehl angibt, ob beim letzten Mal der Sprung durchgeführt wurde oder
60
nicht. Es wird wird angenommen, dass nun der Sprung in die gleiche Richtung führt
wie beim letzten Mal. Bei falscher Vorhersage wird das History-Bit entsprechend
geändert. Dieses Verfahren ist bei Schleifen oft erfolgreich, da häufig an deren
Anfang gesprungen wird. Bei mehreren verschachtelten Schleifen wird aber beim
Beenden einer inneren Schleife eine falsche Voraussage getroffen, was zum
unnötigen Flush der Pipeline führt.
kein Sprung
Sprung
Sprung
00
Sprung
kein Sprung
vorhergesagt
kein Sprung
kein Sprung
01
10
Zweites Mal
kein Sprung
vorhergesagt
Ein zweites Mal
Sprung
vorhergesagt
11
Sprung
vorhergesagt
Sprung
kein Sprung
Abbildung 26: Sprungvorhersage mit 2 History-Bits. Quelle: [TanGo99]
In einer zweiten Variante wird die Effizienz des obigen Verfahrens mit Hilfe
eines zusätzlichen History-Bits gesteigert. Bei einem einmaligen Fehler wird die
Vorhersage nicht sofort, sondern erst bei zweifach falscher Voraussage geändert
(vgl. Abb. 26). Dadurch wird die Vorhersage bei verschachtelten Schleifen
verbessert.
Dieses
Verfahren
ist
entsprechend
auf
mehrere
History-Bits
erweiterbar.
Zu den obigen Methoden wurden eine Reihe von verbesserten Verfahren
vorgestellt. Die Methode von Yeh/Patt [YehPatt91], erweitert beispielsweise den
Automaten aus Abb. 26 und hat eine 4-Bit-Historie. Weitere Verbesserungsvorschläge sind z.B. Korrelations-Prädiktoren [PanRan92], GShare-Prädiktoren
[McFarling93] und Zuverlässigkeits-Prädiktoren [Grun98].
Das Problem der BHT ist, dass im Falle einer Verzweigung zusätzliche
Informationen besorgt werden müssen, was zu weiteren Verzögerungen führt.
Deswegen wird in einem sog. Branch Target Buffer (BTB) zusätzlich zur
Sprunghistorie der Verzweigungstyp (bedingt, unbedingt), die zuletzt verwendete
61
Sprungzieladresse (Taken Address) und ggf. die sequenzielle Nachfolgeadresse des
Sprungbefehls (Fall-through Address) gespeichert. Wenn nur Sprungzieladressen,
aber keine History-Informationen gespeichert werden, so spricht man von einem
Branch Target Address Cache (BTAC). An Stelle eines BTAC verwenden machen
Prozessoren einen sog. Branch Target Instruction Cache (BTIC), der statt der
Sprungzieladressen einige Instruktionen nach dem vorausgesagten Sprungziel
enthält, um die Pipeline zu füllen. Für Rücksprungadressen von Unterprogrammaufrufen wird manchmal auch ein Return Address Stack (RAS) implementiert.
Bei der Intel P6-Architektur hat beispielsweise der BTB 512 Einträge und ist als
4-fach-assoziativer Cache organisiert [Gwen95]. Für die Sprungvorhersage wird die
Methode von [YehPatt91] verwendet.
3.3 Superskalare Architekturen
Dieses Kapitel wird näher auf Performancesteigerungen durch superskalare
Techniken eingehen, wobei verschiedene Architekturelemente aus den bisherigen
Kapiteln aufgegriffen werden.
Ein superskalarer Prozessor ist ein Prozessor, der mit Hilfe entsprechender
interner Einheiten mehr als einen Befehl pro Takt ausführen kann (CPI < 1)
[BeiHag01]. Diese Forderung bedeutet, dass intern zwei oder mehr Befehle in
echter Nebenläufigkeit zueinander verarbeitet werden müssen. Die Restriktion der
Befehlssequentialität bei von-Neumann-Rechnern wird aufgrund von Performanceforderungen zu Ergebnissequentialität gelockert, d.h. es wird nicht mehr
festgelegt, in welcher genauen Reihenfolge etwas berechnet wird, sondern nur wie
etwas berechnet wird. Die berechneten Befehle eines Programms müssen dabei
denjenigen entsprechen, die von einem Prozessor mit Instruktionssequentialität
berechnet werden.
Der Aufbau eines superskalaren Prozessors (vgl. [Ungerer01]) ist in Abb. 27
dargestellt.
62
Instruction-Cache
BHT
RAS
Branch
Unit
MMU
BTAC
Instruction Fetch
Unit
Instruction Decode and
Register Rename Unit
Instruction Buffer
Instruction Issue Unit
Reorder Buffer
Load/
Store
Unit(s)
FloatingPoint
Unit(s)
Integer
Unit(s)
MultimediaUnit(s)
Retire
Unit
FloatingPoint
Registers
General
Purpose
Registers
MultimediaRegisters
Rename
Registers
Bus
Interface
Unit
MMU
Data-Cache
Abbildung 27: Komponenten eines superskalaren Prozessors. Quelle:
[Ungerer01]
Ein superskalarer Prozessor hat eine Instruktionsabrufeinheit (InstructionFetch-Unit), eine Dekodiereinheit (Instruction Decode Unit) mit Registerumbenennung (vgl. Kap. 3.3.2), eine Befehlszuordnungseinheit (Instruction Issue
Unit), mehrere Ausführungseinheiten (Floating Point Units, Integer Units,
Multimedia Units) und eine Rückordnungseinheit (Retire Unit, vgl. Kap. 3.3.2). Die
Zahl der Ausführungseinheiten kann bei verschiedenen Prozessoren variieren, es
muss aber wegen der Nebenläufigkeitsforderung mindestens zwei geben, die
parallel zueinander arbeiten können [Ungerer95].
Daten- und Instruktions-Cache werden aus Performancegründen getrennt und
sind über die Busschnittstelle (Bus Interface Unit) mit dem Hautpspeicher (bzw.
einem externen Cache-Speicher) verbunden. Es gibt noch interne Puffer, wie den
Instruction Buffer und den Reorder Buffer, dessen Zusammenhang mit out-of-orderexecution noch erläutert wird (vgl. Kap. 3.3.2).
63
Die Load-Store-Unit lädt Werte aus dem Daten-Cache in die Register (Floating
Point Register, General Purpose Register, Multimedia Register) oder schreibt
berechnete Werte zurück in den Daten-Cache. Die MMU unterstützt die
Adressumsetzung von logischen in physikalische Adressen (vgl. Kap. 2.2.2). Bei
Cache-Fehlzugriffen wird eine neue Cache-Line (vgl. Kap. 2.2.1) über die Bus
Interface Unit aus dem Speicher geladen.
Es können eine oder mehrere Integer-Units vorhanden sein, die arithmetische
und logische Befehle auf den General-Purpose-Registern ausführen können. Diese
Einheiten können einstufig oder pipelineartig implementiert sein.
Floating-Point-Units sind meist pipelineartig organisiert und speziell für
Gleitkommaoperationen
nach
dem
IEEE754-Standard zuständig. Gleitkomma-
operationen werden ausschließlich auf Floating-Point-Registern angewendet.
Eine oder mehrere Multimedia-Units führen auf den Multimedia-Registern
Befehle nach dem SIMD-Prinzip (vgl. Kap. 1.5.1) aus, die meist maskierender oder
konvertierender Art sind. Dabei wird der selbe Befehl auf mehrere Daten simultan
angewendet. Beispielsweise kann eine Farbänderung für mehrere Pixel gleichzeitig
durchgeführt werden (Details siehe Kap. 3.3.4).
Die Befehlszuordnung zu den Ausführungseinheiten geschieht dynamisch zur
Laufzeit und wird durch die Befehlszuordnungseinheit (Instruction Issue Unit,
manchmal auch als Instruction Dispatch Unit bezeichnet) durchgeführt. Ein
Prozessor wird n-fach-superskalar genannt, falls die Befehlszuordnungseinheit pro
Takt n Befehle zuordnen kann [Ungerer95].
Die Branch Unit überwacht die Ausführung von Sprungbefehlen, holt mittels
einer
dynamischen
Sprungsvorhersagetechnik
die
nach
einem
Sprungbefehl
vermuteten Instruktionen aus dem Speicher und führt sie spekulativ aus. Hierfür
benutzt sie einen Branch Target Address Cache (BTAC), eine Branch History Table
(BHT) und einen Return Address Stack (RAS), deren Funktion im Zusammenhang mit
Sprungvorhersagetechniken im Kapitel 3.2 ausführlich erläutert wurde. Die Branch
Unit ist außerdem für die Aktualisierung der oben erwähnten Sprungvorhersagetabellen zuständig. Im Falle einer Fehlspekulation muss sie auch die falsch
ausgeführten Befehle wieder rückgängig machen.
64
3.3.1 Superskalare Pipelines
Bei superskalaren Architekturen wird räumliche Parallelität durch den
Einsatz mehrerer Pipelines (Kap. 3.1) bei der Verarbeitung betont.
S1
S2
S3
S4
S5
Instruktion
dekodieren
Operanden
abrufen
Instruktion
ausführen
write-back
Instruktion
dekodieren
Operanden
abrufen
Instruktion
ausführen
write-back
Instruktion
abrufen
Abbildung 28: Fünfstufige Pipelines mit gemeinsamer Instruktionsabrufeinheit.
Quelle: [TanGo99]
In Abb. 28 sind 2 Pipelines mit gemeinsamer Instruktionsabrufeinheit
dargestellt. Die Instruktionsabrufeinheit ruft jeweils 2 Befehle ab und ordnet jeden
Befehl einer Pipeline zu. Da jede Pipeline eine Ausführungseinheit mit eigener ALU
hat, können Befehle parallel ausgeführt werden. Bei dieser Architektur können
Konflikte (sog. Hazards) bei der Nutzung der Ressourcen, bei Daten- und
Kontrollflussabhängigkeiten entstehen. Hazards werden am Ende des Kapitels
genauer betrachtet.
Der Intel Pentium besitzt 2 fünfstellige Pipelines, die ähnlich wie in Abb. 28
aufgebaut sind. Allerdings kann eine der Pipelines nicht alle Befehle, sondern nur
einfache Integer-Instruktionen ausführen. Anhand komplexer Regeln überprüft eine
Paarungslogik, ob zwei Instruktionen parallel ausgeführt werden können. Wenn das
nicht möglich ist, wird nur eine der Instruktionen ausgeführt und die andere mit
der nächsten gepaart. Details sind in [Messmer00] zu finden. Compiler können
optimierten Code so generieren, dass besonders viele Befehle gepaart werden
können (vgl. Kap. 6.1).
65
S3
Reservation
Station
(Operanden
abrufen)
Reservation
Station
S1
Instruktion
abrufen
S2.1
S2.2
Instruktion
dekodieren
Issue
(Operanden
abrufen)
Reservation
Station
(Operanden
abrufen)
Reservation
Station
(Operanden
abrufen)
Reservation
Station
(Operanden
abrufen)
S4
ALU
ALU
S5
Laden
retire and
write-back
Speichern
Fließkomma
Abbildung 29: Superskalare Pipeline mit 5 Funktionseinheiten (angelehnt an
[TanGo99] und [Ungerer01])
Bei mehr als 2 Pipelines werden in der Praxis nicht mehr alle Stufen der
Pipelines einzeln implementiert, da dies zur unnötigen Vervielfachung der
Hardware führt (vgl. [TanGo99]). Die Architektur wird dabei so verändert, dass
zwar nur mit einer Pipeline gearbeitet wird, diese aber mehrere Funktionseinheiten
für die Ausführungsphase zur Verfügung hat (Abb. 29). Eine Instruction Issue Unit
ordnet dabei Befehle den Ausführungseinheiten zu. In der Stufe S4 kann es
durchaus auch mehrere ALUs geben. Realisiert werden solche Pipelines dann, wenn
in der Stufe S4 die Befehle wesentlich langsamer verarbeitet werden als sie von
den Stufen S1 bis S2.2 bereitgestellt werden können.
Die Stufe S3 wird durch Reservation Stations (vgl. Kap. 2.1.2) realisiert. In
diesen Puffern können Instruktionen auf ihre Operanden warten, bevor sie in S4
verarbeitet werden. Die Reservation Stations können einerseits dezentral für jede
Funktionseinheit vorhanden sein. Andererseits kann es zentrale Reservation
Stations geben, die gleichzeitig mehreren Funktionseinheiten dienen [Dief99]. Ein
weiterer Vorteil der Reservation Stations ist, dass S2.2 schon Befehle zuordnen
kann, während S4 noch arbeitet (vgl. [Ungerer95]).
Eine superskalare Pipeline kann u.U. Befehle außerhalb ihrer Programmreihenfolge ausführen (vgl. Kap. 3.3.2) und gliedert sich dann in 3 Abschnitte
[Ungerer01]:
66
•
Die Stufen S1 und S2.1 bilden eine in-order-Sektion. Wenn die
Befehle von S2.2 in Programmreihenfolge zugewiesen werden,
gehört sie auch noch zur in-order-Sektion, ansonsten zur darauf
folgenden out-of-order-Sektion.
•
Die Ausführungsstufen S3 und S4 bilden eine out-of-order-Sektion.
Hier werden Resultate ggf. außerhalb der Programmreihenfolge
erzeugt.
•
In der danach folgenden in-order-Sektion S5 werden die Resultate
gemäß der Programmreihenfolge zurückgeordnet und zurückgeschrieben.
Eine Architektur ähnlich Abb. 26 ist beispielsweise beim Pentium II
anzutreffen (vgl. Kap. 3.3.2, [TanGo99]).
Oft kann man die erhoffte Performancesteigerung durch Pipelines nicht
realisieren, da Datenabhängigkeiten (data hazards), Änderungen im Kontrollfluss
(control hazards), Ressourcenkonflikte der Hardware (structural hazards) die
unabhängige Ausführung von aufeinanderfolgenden Befehlen verhindern oder die
Pipeline zum Stillstand bringen (pipeline stall). Bei der Konzeption von Pipelines
halten manche Architekturen deshalb die Zahl der Phasen klein, um diese
Abhängigkeiten besser behandeln zu können (vgl. [BeiHag01]).
Bei einem data hazard (vgl. auch [HePa97]) geht es um Timingaspekte, wobei
folgende Fälle unterschieden werden können:
•
Read-After-Write-Hazard (RAW):
Bei dieser Abhängigkeit versucht ein Befehl B2 Daten aus einem Register
zu lesen, bevor sie von einem anderen Befehl B1 geschrieben werden.
Deswegen müssen Wartezyklen eingefügt werden, bis B1 fertig ist. Diese
Hazards treten häufig auf und müssen bei der Konzeption einer
Architektur berücksichtigt werden. Teilweise kann man die Anzahl der
Wartezyklen durch data forwarding verringern. Dabei kann B1 nach
seiner execute-Phase (und noch vor der write-back-Phase) schon
Zwischenergebnisse an die wartende Operanden-Abruf-Phase des Befehls
B2 übergeben, der bis zu dem Zeitpunkt schon geholt und dekodiert
wurde. Für data forwarding werden im Prozessor zusätzliche Datenpfade
67
benötigt.
•
Write-After-Write-Hazard (WAW):
Hierbei wird gefordert, dass die Reihenfolge der Schreiboperationen
entsprechend dem sequenziellen Befehlsstrom eingehalten wird. Diese
Abhängigkeit kommt bei Pipelines vor, bei denen die Ausführung
verschiedener Befehlstypen unterschiedlich lange dauert (z.B. Integer vs.
Floating Point-Befehle) und mehrere write-back-Stufen existieren (vgl.
Abb. 25). Diese Hazards können mit Hilfe von Compilern verhindert
werden.
•
Write-After-Read-Hazard (WAR):
Ein Schreibzugriff wird auf einem Register durchgeführt, dessen Inhalt
zuvor von einem anderen Befehl ausgelesen werden soll. Solche
Abhängigkeiten
können
bei
paralleler
oder
bei
Befehlsausführung
außerhalb der Programmfolge auftreten.
Control hazards treten häufiger auf als data hazards (vgl. [BeiHag01]). Das
Problem dieser Hazards ist, dass ein Sprungbefehl den Program Counter erst in der
letzten Phase (write-back) der Pipeline aktualisiert. Die Pipeline kann aber bis zum
Zeitpunkt des Zurückschreibens keine weiteren Befehle holen und verarbeiten, da
nicht bekannt ist, welche Instruktionen als nächste im Programm folgen. Bei
bedingten Sprüngen müssen bis zum Zeitpunkt der Aktualisierung Wartezyklen
eingelegt werden. Zur Reduktion dieser Hazards gibt es beispielsweise folgende
Möglichkeiten:
•
Sprünge in der Befehlsholstufe vorhersagen (vgl. Kap. 3.2)
•
Berechnung
des
Sprungziels
bereits
in
der
Dekodierphase
durchführen. Dafür wird für diese Phase ein zusätzlicher Addierer
bereitgestellt (weitere Details dazu und zu Control Hazards siehe
[HePa96] und [BeiHag01]).
Struktur-Hazards treten auf, wenn einige der Funktionseinheiten nicht
vollständig Pipeline-implementiert sind und nur eine exklusive Nutzung möglich ist.
68
Es entstehen Ressourcenkonflikte aufgrund einer nicht ausreichender Duplizierung
der Hardware. Bei Speicherarchitekturen ist deshalb oft eine Harvard-Architektur
(vgl. Kap. 1.1) zu finden. Beispielsweise werden Instruktions- und Datencache (vgl.
Abb. 11 und Kap. 2.2.1) oft getrennt. Weitere Details sind in [HePa97] und
[Ungerer95] zu finden.
3.3.2 Out-of-order-Architekturen
Dieser
Architekturtyp,
bei
dem
Instruktionen
auch
außerhalb
der
sequenziellen Programmreihenfolge ausgeführt werden können, hat sich bei
Superskalararchitekturen immer mehr durchgesetzt [Märtin01]. Eine out-of-orderArchitektur
basiert
auf
der
vorgestellten
Architektur
eines
superskalaren
Prozessors. Sie beinhaltet eine Fetch/Decode–Unit (zusammen auch als InstructionUnit bezeichnet), eine Dispatch-Unit, mehrere nebenläufig arbeitende ExecutionUnits und eine Retirement-Unit (auch als Commit- oder Completion-Unit
bezeichnet). Das generelle Prinzip ist in Abb. 30 skizziert. Diese Architektur ist nur
dann sinnvoll, wenn der Aufwand bei der Wiederherstellung der Programmreihenfolge geringer ist als der bei der out-of-order-Execution und damit eine Zeitersparnis erreicht wird.
Programm
instruction fetch/decode
&branch prediction
instruction dispatch
execution
reorder &
commit
Abbildung 30: Skizze zur out-of-order-Ausführung (angelehnt an [SmSohi95])
69
Die Fetch-Unit holt eine feste oder variable Anzahl von Befehlen vom CodeCache in einen Puffer.
Die Decode-Unit, die häufig mehrere parallel arbeitende Dekodierer enthält,
greift auf diesen Puffer zu und versucht in einem Takt mehrere Befehle zu
dekodieren, wobei aber die Programmreihenfolge eingehalten wird (in-order). Beim
Erkennen eines Sprungbefehls während der Dekodierung werden mit Hilfe einer
Branch Unit die Nachfolgebefehle des Sprungs bereits in den Code-Cache geladen.
Die Befehle gelangen nach ihrer Dekodierung in die Dispatch-Unit. Diese prüft
erst auf eventuell vorhandene Datenabhängigkeiten und ob genug Platz im
Ergebnispuffer (Reorder Buffer, ROB, machmal auch Instruction Pool genannt) der
Retirement-Unit vorhanden ist, um die Ergebnisse aufzunehmen. Erst dann ordnet
sie die Befehle ggf. out-of-order einer der Execution-Units zur Verarbeitung zu. Für
jeden zugeteilten Befehl wird ein Eintrag in einer Hardware-Tabelle (sog.
Scoreboard) erzeugt, die den Bearbeitungszustand eines bereits dekodierten
Befehls festhält. Sie dient u.a. dazu, die Ergebnisse später im ROB wieder nach der
Programmreihenfolge ordnen zu können. Details siehe [Märtin01].
Bei der Ausführung in einer Execution-Unit können scheinbare Datenabhängigkeiten (vgl. data hazards, Kap. 3.3.1, [Ungerer01]) auftreten, die durch
die dynamische Veränderung der Befehlsreihenfolge bei der Ausführung entstehen.
Um Pipeline-Stalls (vgl. Kap. 3.1) durch Datenabhängigkeiten zu verhindern,
werden die logisch vorhandenen ISA-Register über eine Register-Renaming-Tabelle
auf zusätzlich vorhandene physikalische Register (sog. Schattenregister) abgebildet
(Register Renaming, vgl. [BeiHag01]). Die Anzahl der Schattenregister übersteigt
dabei die der ISA-Register. Durch diese Duplizierung der Hardware sollen die WAR
und WAW -Hazards (vgl. Kap. 3.1) vermieden werden. Operationen in der ExecutionPhase werden dann ausschließlich auf den Schattenregistern durchgeführt.
Anschließend landen die Ergebnisse ggf. out-of-order im ROB.
Die Retirement-Unit schreibt den Inhalt der Ergebnis-Schattenregister nach
verschiedenen Gültigkeits-Checks in die ISA-Register. Es wird eine in-ordercompletion sichergestellt, d.h. das Ergebnis der Ausführung wird mit dem Ergebnis
einer sequenziellen Ausführung identisch sein.
70
Ergebnis 1
t=4
Ergebnis 2
t=1
Ergbenis 3 Ergebnis 4
t=3
t=2
commit
Abbildung 31: Reorder Buffer der Retirement Unit
Abb. 31 zeigt, wie eine Retirement Unit die zu unterschiedlichen Zeiten outof-order angekommenen Befehle in einen Reorder Buffer ablegt. Die Retirement
Unit erkennt, wann die logisch korrekte Reihenfolge vorliegt und die Befehle
weggeschrieben werden können.
Als Beispiel für eine out-of-order-Architektur soll die 3-fach superskalare Intel
Pentium-III-Architektur dienen (Abb. 32), die auf der Intel-P6-Architektur basiert
[Märtin01], [Intel99b].
Bus Interface Unit
Instr. Fetch Unit
Instr. Decode Unit
Instruction Decoder
Simple
Instruction
Decoder
Simple
Instruction
Decoder
Next IP Unit
Complex
Instruction
Decoder
Memory
Reorder
Buffer
Branch Target Buffer
µOp
Instruction
Sequencer
Register Alias Table
Data Cache
Unit (L1)
Retirement Unit
Retirement Register
File (IA-Registers)
Reorder Buffer (Instr. Pool)
Reservation Station
SSE
Unit
MMX
Unit
FPU
Unit
Integer
Unit
Integer
Unit
Memory
Interface
Unit
Internal Data-Results Buses
Abbildung 32: Pentium-II-Implementierung der P6-Mikroarchitektur (nach
[Intel99b], [Märtin01])
71
Wie schon in Kap. 2.1.3 erwähnt wurde, übersetzen Pentium-Prozessoren nach der
P6-Architektur intern die CISC-Befehle der ISA erst in RISC-ähnliche 3-AdressBefehle (von Intel „µOps“ genannt, ≠ Mikrooperationen), die ein Load/Store-Modell
verwenden (vgl. 1.5.3). Nach Holen, Sprungvorhersage und Dekodierung der CISCBefehle in 3 oder mehr µOps werden diese in-order an die Register Alias Table
(RAT) weitergegeben, wo sie jeweils freien internen Registern zugeordnet werden.
Es stehen 40 interne Register für das Register Renaming zur Verfügung, in die
später auch die Ergebnisse geschrieben werden. Nach dieser Zuordnung gelangen
die µOps erst in den Reorder Buffer (Instruction Pool), um weiterverarbeitet zu
werden. Im Reorder Buffer können bis zu 40 µOps gleichzeitig verwaltet werden. In
manchen Fällen können µOps ihre Operanden auch aus dem Reorder Buffer holen.
Für alle Funktionseinheiten steht eine zentrale Reservation Station zur Verfügung,
über
die
der
out-of-order-Kern
des
Prozessors
die
µOps
den
freien
Funktionseinheiten (SSE Unit, MMX Unit, FPU Unit, 2 Integer Units, Memory
Interface Unit) zuteilt. Auf SSE und MMX geht das Kapitel 3.3.4 ein. Die von den
Funktionseinheiten bearbeiteten µOps werden als bearbeitet markiert und wieder
in den Reorder Buffer gespeichert. Die Retirement-Einheit überprüft dann, welche
Instruktionen bereits ohne Datenabhängigkeiten fertig ausgeführt sind und stellt
die Programmreihenfolge wieder her. In einem Taktzyklus entfernt sie dann
maximal 3 µOps, die in der logisch korrekten Reihenfolge vorliegen und schreibt die
Ergebnisse in die Register. Der Memory Reorder Buffer sorgt dafür, dass eventuelle
Speicheroperationen in der logisch korrekten Reihenfolge stattfinden. Weitere
Details sind in [Märtin01] und [Intel99b] zu finden.
3.3.3 VLIW/EPIC-Architekturen
Eine weitere Architektur, die hier vorgestellt werden soll, ist die in der Mitte
der 80er Jahre entstandene VLIW-Architektur (Very Long Instruction Word)
[HePa96]. Diese Architektur basiert auf der Idee, dass ein Compiler eine bestimmte
Anzahl voneinander unabhängiger und parallel auszuführender Befehle in ein
Instruktionswort fester Länge packt. Der Vorgang der Parallelisierung wird von der
Hardware in den Compiler verlagert, was dazu führt, dass die Komplexität der
Hardware abnimmt und die des Compilers zunimmt. Wegen der geringen Hardware-
72
flexibilität und den hohen Anforderungen an die Compilertechnologie haben sich
reine VLIW -Architekturen nicht durchgesetzt [Märtin01].
Die VLIW -Architektur enthält wie bei superskalaren Architekturen eine
bestimmte Anzahl von nebenläufig arbeitenden Funktionseinheiten, wobei aber
keine out-of-order-Ausführung stattfindet. Die in einem VLIW -Wort enthaltenen
Befehle werden gleichzeitig geholt, dekodiert, ausgeführt und zurückgeschrieben.
Sollten Befehle nicht parallel ausführbar sein, so ist im VLIW -Wort nur eine
Instruktion enthalten. Die restlichen Stellen sind vom Compiler durch NOPs (no
operation, kein Befehl) gefüllt. Obwohl beim Compilieren das gesamte Programm
bekannt ist und global optimiert werden kann, ist durch die feste Zuordnung von
Instruktionen
zu
einem
VLIW -Wort
die
Optimierung
nur
statischer
Art.
Beispielsweise kann bei eventuellen Fehlzugriffen auf einen Cache-Speicher zur
Laufzeit nicht so flexibel wie bei dynamischer Befehlszuordnung reagiert werden.
VLIW -Architekturen sind manchmal bei Signalprozessoren (vgl. Kap. 4.2) zu finden
[Ungerer01].
Einige der VLIW -Prinzipien sind in der von Intel und HP gemeinsam
entwickelten IA-64-Architektur zu finden [CrHuck97]. Das Befehlsformat des IA-64Befehlssatzes wurde als EPIC (Explicit Parallel Instruction Computing) bezeichnet
und ähnelt einem Dreibefehls-VLIW -Format. Ein EPIC-Wort ist flexibler als ein
VLIW -Wort und enthält zusätzliche Informationen in Form sogenannter TemplateBits, die voneinander unabhängige Instruktionen markieren. Die Template-Bits
beziehen sich sowohl auf Instruktionen innerhalb eines EPIC-Worts, als auch auf
benachbarte EPIC-Wörter. Mit dem EPIC-Format können auch VLIW -Formate mit
variabler Wortlänge realisiert werden. Details sind in [Ungerer01] und [Märtin01] zu
finden.
Zusätzlich zu den in Kapitel 3.2 behandelten Sprungvorhersagemethoden mit
spekulativer Ausführung verwendet die IA-64-Architektur die sog. Prädikation
(Predication). Darunter versteht man die Ausführung eines Befehls in Abhängigkeit
eines zugeordneten Prädikats [Intel00b]. Die Ergebnisse eines Befehls werden
verworfen oder der Befehl nicht ausgeführt, falls das zugehörige Prädikat false ist,
ansonsten werden sie als gültig anerkannt. Der Sinn besteht darin, etwa beim
bedingten
Verzweigen
Verzweigungen
des
auszuführen
Kontrollflusses
obwohl
die
(z.B.
Bedingung
switch-Anweisung)
noch
alle
nicht vollständig
ausgewertet ist. Nach der Auswertung der Bedingung werden die Prädikate so
73
geändert, dass nur die richtigen Ergebnisse beibehalten werden (vgl. Beispiel in
Kap. 6.1).
3.3.4 Vektor-Architekturen
Dieses Kapitel erläutert die Möglichkeiten einer Performancesteigerung
mittels Vektorarchitekturen. Das grundlegende Prinzip von Vektorarchitekturen
basiert auf Parallelismus auf Datenebene. Ein Befehl wird in SIMD-ähnlicher
Anwendung (vgl. Kap. 1.5.1) auf mehrere linear angeordnete Zahlenfelder
gleichzeitig angewendet. Eine Menge solcher Zahlenfelder bildet dabei einen
Vektor.
Eingabevektoren
Vektor-ALU
Abbildung 33: Vektor-ALU (nach [TanGo99])
Die Abb. 33 zeigt eine mögliche Architektur einer Vektor-Maschine. Zwei
Vektoren, die jeweils aus n Elementen bestehen und sich in Vektor-Registern
befinden, werden mit Hilfe einer Vektor-ALU verarbeitet. Die Vektor-ALU besteht
aus n ALUs (manchmal auch Verarbeitungseinheiten oder Processing Elements
genannt), die die einzelnen Elemente eines Vektors parallel manipulieren. Es gibt
allerdings nur ein Steuerwerk, welches den aktuell durchzuführenden Befehl durch
74
Instruction Broadcasting an die einzelnen ALUs weiterleitet. Beispielsweise könnten
bei einer Vektoraddition die i-ten Elemente von zwei Eingabevektoren für alle i
gleichzeitig addiert und in das i-te Element eines Ausgabevektors abgelegt werden.
Das Ergebnis, welches wiederum ein Vektor ist, kann in den Speicher oder zurück in
ein
Vektor-Register geschrieben werden. Vektor-ALUs müssen nicht immer
2 Vektoren verrechnen. Sie können auch skalare Operationen gleichzeitig auf alle
Elemente eines Vektors anwenden.
Solche Architekturen sind insbesondere für Anwendungen geeignet, wo viele
Zahlen verarbeitet werden („number crunching“). Häufig wird die Organisation
aus Abb. 33 um Pipelining (vgl. Kap. 3.1) erweitert. Die Verarbeitung von Befehlen
auf
Gleitkomma-Zahlen
Exponenten
einstellen,
lässt
sich
Operation
in
Phasen
ausführen,
einteilen
(Operanden
Ergebnis
normalisieren,
holen,
vgl.
[TanGo99]). Um die Performance durch zeitliche Überlappung der Phasen zu
steigern, wird sog. arithmetisches Pipelining auf einer höheren Ebene als der
Maschinenbefehlsebene eingesetzt. Als Beispiel sei der Rechner Cray-1 der Firma
Cray Research (1976) erwähnt, der eine Vektorarchitektur mit parallel arbeitenden,
pipelineartig organisierten Funktionseinheiten implementiert. Weitere Details zu
Vektorarchitekturen und zu Cray-1 sind in [ObVossen00] ausführlich nachzulesen.
Vektor-Architekturen haben sich bei Funktionseinheiten von Mikroprozessoren
durchgesetzt, welche die Verarbeitung von Multimedia-Daten (Bild-, Audio-,
Video-Daten) unterstützen (auch Grafikkarten). In diesen Anwendungsgebieten
muss häufig der gleiche Befehl auf feldartige Datenstrukturen angewendet werden.
Häufig auftretende Befehle sind arithmetischer, maskierender, auswählender,
umordnender oder konvertierender Art. Beispielsweise kann eine Farbänderung auf
mehrere Pixel simultan durchgeführt werden (siehe auch Abb. 34). Durch hardwaremäßige
erzielt.
SIMD-Unterstützung
werden
erhebliche
Performancesteigerungen
75
x3
x2
x1
x0
y3
y2
y1
y0
f
f
f
f
f(x3,y3) f(x2,y2) f(x1,y1) f(x0,y0)
Abbildung 34: SIMD-Betrieb bei MMX (nach [Märtin01])
Verschiedene Firmen haben für die SIMD-Verarbeitung von Multimedia-Daten
Synonyme entwickelt: MMX (Multi Media eXtension, Intel), 3DNOW! (AMD), AltiVec
(Motorola). Dabei gibt es in den jeweiligen Mikroprozessoren Funktionseinheiten,
die solche Erweiterungen implementieren. Die Firma Intel hat ab dem Pentium III
mit den Streaming SIMD Extensions (SSE) sogar noch eine zusätzliche Erweiterung
für SIMD-Gleitkommaverarbeitung entwickelt [Intel99b]. Weitere Details zu
Vektorarchitekturen aktueller Prozessoren finden sich in [Bleul00] und [Märtin01].
76
4 Spezielle Architekturen
In den vorherigen Kapiteln wurden General-Purpose-Architekturen von
Prozessoren dargestellt, die möglichst universell einsetzbar waren. Aus verschieden
Gründen (z.B. Kosten, Performance) sind Special-Purpose-Architekturen für
spezifische Anwendungsbereiche entstanden. Zwei wichtige Special-PurposeArchitekturen sollen kurz vorgestellt werden. Mikrocontroller konzentrieren sich
auf die Integration möglichst vieler Komponenten auf einem Chip (CPU mit der
gesamten Peripherie), wobei geringe Kosten und weniger eine hohe Performance
im Vordergrund stehen. Im Gegensatz dazu sind DSP-Architekturen auf die
Steigerung der Performance speziell bei der Signalverarbeitung ausgerichtet.
4.1 Mikrocontroller
Bei Mikrocontrollern handelt es sich um komplette Computersysteme auf
einem
Chip. Ziel ist nicht eine hohe Verarbeitungsleistung, sondern die
größtmögliche funktionelle Integration von Mikrocontrollerkern (Core), Speicher,
Peripheriekomponenten und Interruptsteuerung zu geringen Kosten [BeiHag01].
Wegen ihrer Programmierbarkeit sind Mikrocontroller universell einsetzbar.
Häufig sind sie in Systemen wie PDAs (Personal Digital Assistant), industriellen
Steuerungen, Taschenrechnern, Fernsteuerungen oder digitalen Uhren zu finden.
Aufgrund einer Massenproduktion sind die Kosten pro Chip auch entsprechend
gering.
Die Abb. 35 zeigt die grundsätzliche Architektur eines Mikrocontrollers.
77
Core
(CPU)
InterruptSystem
interner Bus
ProgrammSpeicher
DatenSpeicher
PeripherieKomponenten
Abbildung 35: Architektur eines Mikrocontrollers (nach [BeiHag01])
Der Mikrocontrollerkern beinhaltet eine CPU mit Rechenwerk, Steuerwerk,
Registern und einer Bus-Interface-Unit (vgl. Kap. 1.2). Die Bus-Interface-Unit ist
programmierbar, damit externe Komponenten leicht hinzugefügt werden können.
Häufig werden für den Mikrocontrollerkern bereits entwickelte Mikroprozessor-CPUs
genommen und geringfügig angepasst, so dass die CPU-Architektur fast gar nicht
verändert wird. Mikrocontrollerkerne können CISC, RISC oder auch superskalare
Architekturen besitzen. In speziellen Fällen werden auch DSP-Architekturen (vgl.
Kap. 4.2) integriert.
Beim Speicher werden Programm- und Datenspeicher getrennt (vgl. Kap. 1.1).
Auf dem gleichen Chip können Taktgeber und Peripheriekomponenten wie I/OPorts, Analog-Digital-Umsetzer, Digital-Analog-Umsetzer, serielle und parallele
Interfaces o.ä. integriert sein. Hierbei ist noch erwähnenswert, dass die
Architektur Komponenten enthält, die die Systemverfügbarkeit mittels in Hardware
realisierten Zählern (Timer) überprüfen sollen. Ein Watchdog-Timer ist ein
laufender Zähler, der kurz vor dem Überlauf durch die Software zurückgesetzt
wird. Fehlfunktionen der Software können dadurch erkannt werden, dass der Timer
nicht zurückgesetzt wurde.
Beispiele für Mikrocontroller sind Texas Instruments TMS1000, Philips 80X51,
Siemens Tricore, Motorola HC12, NEC V850, AMD Elan, Intel MCS251. Weitere
Details sind in [BeiHag01] zu finden.
78
4.2 DSP-Prozessoren
Bei der digitalen Signalverarbeitung (Digital Signal Processing) werden
analoge Signale abgetastet, in digitale Daten umgewandelt, numerisch verarbeitet
und wieder zurück in analoge Signale transformiert. Durch dieses Vorgehen können
Signaleigenschaften verändert oder analysiert werden. Die Anwendungen sind
vielfältig, wie z.B. Filterung, Rauschunterdrückung, Frequenzanalyse (auch für
Spracherkennung oder Sprachausgabe). Digitale Signalprozessoren (Digital Signal
Processor, DSP) sind spezielle Mikroprozessoren, deren Architektur für die
Signalverarbeitung optimiert ist (vgl. [BeiHag01]). Sie werden beispielsweise
eingesetzt in: HiFi-Anlagen, Telefonen, Handys, Spielzeugen, Modems, Autos,
Ultraschallgeräten, Radargeräten (siehe auch [BDT98]). Da hohe Datenmengen an
Quell- und Ergebnisdaten anfallen, können sie aus Performancegründen nicht wie
bei General-Purpose-Architekturen lokal in Prozessorregistern gehalten werden, so
dass Busse mit sehr hohen Bandbreiten zwischen DSP-Prozessor und Speicher
erforderlich sind. Auch die ISA-Architektur unterscheidet sich deswegen bei DSPProzessoren
erheblich
von
General-Purpose-Prozessoren
[BeiHag01].
Selbst
zwischen verschiedenen DSP-Prozessoren variieren die Befehlssätze aufgrund der
spezialisierten Architekturen sehr stark.
DSP-Prozessoren haben eine Harvard-Architektur (vgl. Kap. 1.1) und besitzen
physikalisch getrennte Programm- und Datenspeicher, wobei auch mehrere
Datenspeicher vorhanden sein können (Abb. 36). Durch ein umfangreiches
Bussystem kann der Prozessorkern parallel auf Programm- und Datenspeicher
zugreifen, so dass pro auszuführendem Befehl Daten aus jedem Daten-Speicher
gleichzeitig ausgelesen werden können.
79
Prozessorkern
Code-Speicher
Daten-Speicher 1
Daten-Speicher 2
Adressbus 1
Datenbus 1
Adressbus 2
Datenbus 2
Adressbus 3
Datenbus 3
Abbildung 36: Harvard-Architektur von DSP-Prozessoren (angelehnt an
[BeiHag01])
Die ALU von DSP-Prozessoren kann arithmetische und logische Befehle ausführen. Es gibt aber auch weiter eingeschränkte Varianten, die nur mit IntegerWerten rechnen oder keine Divisionen durchführen können [BeiHag01]. Die
Architektur eines DSP-Prozessors ist hauptsächlich darauf ausgerichtet, sog.
multiply-accumulate-Operationen
(MAC)
durchzuführen
[EyBier98].
Hierbei
handelt es sich um Berechnungen der Art
Ergebnis(n) = Ergebnis(n-1) + Xn * Yn,
die bei der Bildung von Vektor-Skalarprodukten benötigt werden. MAC-Operationen
werden von Algorithmen zur Filterung von Signalen oft ausgeführt [EyBier98]. Die
folgende Abbildung zeigt die dafür speziell angepasste Architektur.
80
X Datenbus
Y Datenbus
Y0
OperandenRegister
Y1
X0
X1
Multiplizierer
ALU
AkkumulatorRegister
A
B
Abbildung 37: Datenpfad bei einem DSP-Prozessor (angelehnt an [BDT98])
Die Multiplikation zweier Werte und deren Addition zum vorherigen Zwischenergebnis ist gleichzeitig in einem Takt möglich. Die ALU und der Multiplizierer sind
in Hardware realisiert und benutzen keine Mikroprogrammierung. Manche DSPProzessoren besitzen sogar mehrere unabhängige MAC-Einheiten.
Um
Speicherzugriffe
zu
beschleunigen,
werden
in
DSPs
für
die
Adressberechnung eigene ALUs implementiert, die parallel zu den MAC-Einheiten
arbeiten. Die Adressierungsarten werden auch an spezifische Algorithmen der
Signalverarbeitung, wie die Fourier-Transformation (vgl. [BeiHag01]), angepasst.
Anzutreffen sind u.a. Register-indirekte Adressierung mit post-Inkrement (vgl. Kap.
2.1.1), Bitreverse-Adressierung (nur für Fourier-Transformation brauchbar, vgl.
[Brig95]). Die Modulo-Adressierung basiert auf der Register-indirekten Adressierung
mit post-Inkrement, wobei immer modulo n inkrementiert wird (vgl. [BeiHag01]).
81
Die Modulo-Adressierung ist bei Zugriffen auf einen Ringspeicher nützlich, wo
gleichzeitig eine Bereichsbegrenzung sichergestellt werden muss.
In manchen DSP-Prozessoren werden für weitere Performancesteigerungen
auch kurze, meist 3-stufige Pipelines mit weniger komplexen Sprungvorhersagemethoden (vgl. Kap. 3.2) eingesetzt [BeiHag01], [Märtin01].
Die Softwareentwicklung für DSP-Prozessoren ist nicht einfach. Aufgrund der
unterschiedlichen Architekturen von verschiedenen DSP-Prozessoren wird der Code
häufig in Assembler geschrieben, um alle Möglichkeiten auszureizen. Der von
Compilern generierte Code liefert im Vergleich zur manuellen Codierung eine viel
schlechtere Performance. Hinzu kommt die Komplexität des Befehlssatzes, die eine
intuitive Programmierung erschwert (Details vgl. [EyBier98]).
DSP-Prozessoren haben sich trotzdem in Anwendungsbereichen durchgesetzt,
wo der Einsatz von General-Purpose-Prozessoren hohe Kosten verursacht. Durch die
extreme Spezialisierung können DSP-Prozessoren zu niedrigen Preisen gefertigt
werden [BDT00]. Mittlerweile wird aber auch in General-Purpose-Prozessoren DSPFunktionalität integriert (vgl. Kap. 5).
Beispiele
für
DSP-Prozessoren
sind
Analog
Devices
ADSP-2100, Texas
Instruments TMS320C5000, NEC µPD77100, Lucent DSP16000, Motorola DSP56000,
Motorola MSC8102. Details zu DSP-Prozessoren sind in [BeiHag01] nachzulesen.
82
5 Aktuelle Mikroprozessoren
In diesem Kapitel sollen abschließend einige Beispiele aktueller Mikroprozessoren vorgestellt werden. Die Darstellung wird überwiegend architekturrelevante Merkmale erwähnen und soll dabei ein Bild vermitteln, inwieweit die
Vorgestellten Konzepte tatsächlich in der Praxis eingesetzt werden. Teilweise
werden auch schon Ansätze von Konzepten implementiert, an denen zur Zeit noch
geforscht
wird,
wie
z.B.
Simultaneous
Multithreading
(SMT)
oder
Chip-
Multiprozessoren (vgl. Kap. 6.2).
Bei der folgenden Darstellung ist zu berücksichtigen, dass von Herstellern oft
grundlegende Konzepte aufgegriffen, geringfügig modifiziert und mit verkaufsfördernden Schlagworten benannt werden. Ebenso ist zu berücksichtigen, dass
aufgrund der starken Konkurrenz auf dem Mikroprozessormarkt viele Hersteller
wichtige Details der Mikroprozessorarchitektur nur teilweise oder gar nicht
veröffentlichen, so dass die Darstellung an dieser Stelle unvollständig bleibt.
Intel Pentium 4
Der Intel Pentium 4 Mikroprozessor (Nov. 2000) arbeitet mit Taktfrequenzen
von 1.3 – 2.2 GHz. Bei der 32-Bit Architektur handelt es sich um eine superskalare
out-of-order-Architektur. Da die Dekodierung von ISA-Befehlen sehr aufwändig ist,
werden sie intern erst in sog. „µOps“ übersetzt, um die restliche Hardware zu
vereinfachen. Der Begriff „µOps“ ist ein von Intel geprägtes Schlagwort, wobei es
sich um RISC-ähnliche 3-Adress-Befehle handelt. Bei der 20-stufigen, mit
Prozessorfrequenz betriebenen superskalaren Pipeline (vgl. Kap. 3.3.1) nutzt Intel
eine Superpipelining-Architektur (von Intel „Hyper Pipelined Technology“ genannt).
Damit die Pipeline ständig ausgelastet bleibt, wird eine gute Sprungvorhersage mit
einem 4000 Einträge großen BTB (vgl. Kap. 3.2) implementiert. Unter den 6 Ausführungseinheiten gibt es 2 Integer-ALUs, die mit doppelter Taktfrequenz arbeiten.
Sie stellen arithmetische und logische Befehle in nur einem halben Prozessortakt
fertig. Der ROB (vgl. Kap. 3.3.2) hat eine Kapazität von 100 µOps. Auf dem Chip ist
ein 8K großer L1-Daten-Cache integriert, jedoch fehlt ein L1-Code-Cache.
Stattdessen wurde ein Trace-Cache implementiert (vgl. Kap. 2.1.3 und 6.2), der
83
12.000
µOps
enthalten
kann
und
eng
mit
der
Fetch/Decode-Unit
zusammenarbeitet. Bei Trace-Cache-Misses wird auf den 256KB-512KB großen OnChip-L2-Cache (von Intel „Advanced Transfer Cache“ genannt) zugegriffen. Der L2Cache ist ein nicht-blockierender, 8-fach-assoziativer Cache (vgl. 2.2.1). Die FPUFunktionseinheiten
unterstützen
Multimediaanwendungen
durch
MMX/SSE-
Funktionalität (vgl. Kap. 3.3.4). Der Registersatz ist mit dem der IA-32-Architektur
(vgl. Kap. 2.1.1) kompatibel. Erwähnenswert ist auch die zusätzlich im Chip
implementierte Hardware, die das Testen der Funktionsfähigkeit des Prozessors
unterstützen soll (vgl. Kap. 1.4). Weitere Details gibt es in [Märtin01], [Intel02a].
Intel Pentium Xeon
Dieser Prozessor (2000) basiert auf dem Pentium III und imlementiert die
schon in Kap. 3.3.2 besprochene P6-Architektur. Im Gegensatz zum Pentium 4
wurde er für den Einsatz in Servern konzipiert. Er arbeitet mit Taktfrequenzen bis
zu 1.6 GHz und hat eine 3-stufige Cache-Hierarchie. Auf Level 1 befindet sich ein 8
KB großer Daten-Cache und ein 12.000 Einträge umfassender Trace Cache, auf
Level 2 ein 256KB großer Cache und auf Level 3 ein 512KB-1MB großer Cache. Der
Intel Xeon unterstützt Thread-Level-Parallelism auf Hardwareebene durch eine
SMT-Architektur (vgl. Kap. 6.2), die von Intel „Hyper-Threading“ genannt wird. Die
übrigen Merkmale sind dem Pentium 4 ähnlich. Details zum Xeon-Prozessor sind in
[Intel02b] und zu Hyper-Threading in [Marr02] zu finden.
Intel Itanium
Der Intel Itanium-Prozessor (2001) implementiert die in Kap. 3.3.3 behandelte
IA-64-Architektur. Es handelt sich um einen mit 800MHz getakteten 64-bitProzessor mit 9 nebenläufigen Funktionseinheiten. Das Prozessordesign zielt nicht
nur auf eine weitere Verbesserung bzw. Duplizierung der Hardware ab, sondern
versucht die Performance auf Mikroarchitekturebene durch Kooperation mit
Compilern zu steigern. Dieser Ansatz wurde als Explicit Parallel Instruction
Computing (EPIC, vgl. Kap. 3.3.3) bezeichnet und soll eine Alternative zu SMTArchitekturen (vgl. Kap. 6.2) darstellen [Märtin01]. Der Itanium besitzt 3 BranchUnits für die Sprungvorhersage (vgl. Kap. 3.2), 4 Integer- und Multimedia-Units und
84
2 Floating-Point-Units, die auch SIMD-Multimedia-Befehle (vgl. Kap. 3.3.4) und DSPähnliche MAC-Befehle (vgl. Kap. 4.2) unterstützen. Die Cache-Hierarchie ist 3stufig, wobei die ersten 2 Stufen auf dem Prozessorchip implementiert sind. Der
L3-Cache kann bis zu 4 MB groß sein. Details sind in [Intel00b], [Intel00c],
[Märtin01], [Intel02c] spezifiziert.
AMD Athlon XP
Der Athlon XP (2001, 1.67 GHz Taktfrequenz) besitzt eine 9-fach-superskalare
out-of-order Mikroarchitektur (vgl. Kap. 3.3.2). Darin enthalten sind 3 parallel
arbeitende Decoder. Insgesamt sind 9 Ausführungseinheiten vorhanden: 3 IntegerUnits, 3 Floating-Point-Units mit SIMD-Unterstützung für Multimedia-Anwendungen
(vgl. Kap. 3.3.4) und 3 Address-Calculation Units. Die Ausführungseinheiten sind
intern pipelineartig aufgebaut. Zusätzlich integriert dieser Prozessor DSPFähigkeiten (vgl. Kap. 4.2) für die Aufbereitung von Dolby-Surround-Sound und für
MP3-Anwendungen. Der L1-Cache besteht aus einem 64KB Daten- und 64KB
Instuktions-Cache. Ebenfalls auf dem Prozessorchip ist auch ein 256KB großer L2Cache integriert. Mehr Informationen sind in [AMD01], [AMD02] zu finden.
SUN MAJC 5200
Der Ende 1999 vorgestellte MAJC-Prozessor (Microprocessor Architecture for
Java Computing, MAJC, ausgesprochen „magic“) ist eine Implementierung einer
SMT- und Chip-Multiprozessor-Architektur (vgl. Kap. 6.2). Dabei sind 2 mit 500 MHz
getaktete Prozessoren auf einem Chip vereinigt. Hierdurch können mehrere Arten
von Parallelität genutzt werden: Parallelität auf Datenebene durch SIMD-ähnliche
Befehle, Parallelität auf Instruktionsebene durch mehrere Funktionseinheiten auf
einem Prozessor und Parallelität auf Thread-Ebene (vgl. Kap. 6.1). Im Vordergrund
steht eine schnelle Unterstützung von Java-Compilern. Zusätzlich werden für
Multimedia-Anwendungen DSP-ähnliche Befehle bereitgestellt (vgl. Kap. 4.2). Ein
16 KB großer, 4-fach-assoziativer Daten-Cache wird von beiden Prozessoren auf
dem Chip benutzt. Zusätzlich hat jeder Prozessor einen eigenen 16 KB großen, 2fach-assoziativen Daten-Cache. Der MAJC-Prozessor ist für den Einsatz in den
Bereichen Grafik- und Audioverarbeitung, Internetworking oder Verschlüsselung
85
gedacht. Ausführlichere Informationen findet man in [SUN99a], [Subram99],
[Tremb99], [SUN02a].
SUN UltraSPARC III
Dieser im Jahr 2001 vorgestellte 4-fach superskalare 64-Bit Mikroprozessor ist
eine
Implementierung
Taktfrequenzen
bis
zu
der
SUN
1050
SPARC
MHz.
Er
V9-Architektur
hat
6
und
pipelineartig
arbeitet
mit
organisierte
Ausführungseinheiten: 2 Integer-Units, 2 Floating-Point-Units, 1 Load/Store-Unit,
und 1 Addressing-Unit. Auf Level 1 gibt es einen 32KB großen Daten- und 64KB
großen Instruktions-Cache, die jeweils 4-fach-assoziativ sind. Der externe L2-Cache
kann bis zu 8MB groß sein. Die Cache-Tags des L2-Cache befinden sich auf dem
Prozessor-Chip. Für mehr Informationen sei auf [SUN02b] und [SUN02c] verwiesen.
Motorola Dragonball MX1
Die Firma Motorola hat speziell für den Embedded-Systeme-Bereich die
Dragonball-Serie entwickelt. Haupteinsatzgebiete sind PDAs oder Smartphones. Aus
dieser Serie soll beispielhaft der zur Zeit neueste Prozessor (MC9328MX1,
vorgestellt im Jahr 2001) beschrieben werden. Obwohl er von Motorola als
Mikroprozessor bezeichnet wird, ist er aufgrund des integrierten Prozessorkerns
und der integrierten Peripheriekomponenten auf dem gleichen Chip eher als
Mikrocontroller zu klassifizieren (vgl. Kap. 4.1). Der Prozessorkern basiert auf der
von der Firma ARM entwickelten ARM9-Architektur, die eine 32-bit-RISC-Architektur
ist. Die Prozessorkern kann mit bis zu 200 MHz getaktet sein, hat einen 16KB
großen Daten-Cache, einen 16KB großen Instruktions-Cache und unterstützt
virtuellen Speicher (vgl. Kap. 2.2.4) mittels einer Virtual Memory Management
Unit. Auf den gleichen Chip sind ein LCD-Display-Support, ein Touch-Panel-Support,
ein Watchdog-Timer, ein Interrupt-Controller, ein Video-Port, ein Power-ControlModul und verschiedene Schnittstellen eingebaut. Der eingebaute MultimediaAccelerator unterstützt DSP-ähnliche Operationen (vgl. Kap. 4.2). Weiterführende
Informationen gibt es in [Motorola02].
86
Motorola MSC8102
Mit diesem Prozessor (2001) soll beispielhaft ein Vertreter der DSPProzessoren (vgl. Kap. 4.2) vorgestellt werden. Es handelt sich um einen mit 300
MHz getakteten Prozessor, der für die Ausführung von MAC-Operationen 16 ALUs
und 4 Coprozessoren für spezielle Filteroperationen enthält. Ebenfalls auf dem
gleichen Chip sind 1436 KByte RAM-Speicher integriert. Genaueres über diesen
Prozessor ist in [Motorola02b] zu finden.
ZILOG eZ80 Webserver
Dieser spezielle als System-on-a-Chip konzipierte 8-Bit-Mikrocontroller (vgl.
Kap. 4.1) ist in der Lage, über ein TCP/IP-Netzwerk Web-Seiten zur Verfügung zu
stellen. Der eZ80 ist seit 2001 verfügbar und ist mit 50 MHz getaktet. Er besitzt auf
dem gleichen Chip 8K RAM, einen Taktgeber und kann 16MB Speicher direkt
adressieren. Zusätzlich ist ähnlich einem DSP-Prozessor eine MAC-Unit (vgl. Kap.
4.2) eingebaut, um Algorithmen für den Aufbau sicherer Verbindungen im Internet
zu unterstützen. Haupteinsatzgebiete sind beispielsweise Verkaufsautomaten,
Online Information Kiosks, Industrial Control oder Remote Monitoring. Der eZ80 ist
ein Musterbeispiel dafür, dass nicht immer höchste Performance benötigt wird und
auch Einfachheit gefragt sein kann. Weitere Details sind in [Zilog01] beschrieben.
87
6 Softwaresysteme und Forschungstrends
Dieses Kapitel fasst die Abhängigkeiten und Wechselwirkungen zwischen
Mikroprozessorarchitektur und Softwaresystemen (Ebenen 3,4,5, vgl. Abb. 2) in
einem kurzen Überblick zusammen. Es werden die Schnittstellen zu Compilern
bezüglich des generierten Maschinencodes und zu Betriebssystemen, die durch
spezielle
Hardwarearchitekturen
unterstützt
werden
können,
beschrieben.
Abschließend werden Architekturkonzepte vorgestellt, an denen zur Zeit noch
geforscht wird und die möglicherweise die Entwicklung zukünftiger Mikroprozessorarchitekturen beeinflussen werden.
6.1 Compiler und Betriebssysteme
Wie schon in Kap. 1.1 erläutert, können Compiler in Hochsprachen
geschriebene
Programme
in
Assemblersprachen übersetzen. Die Wahl der
Hochsprachen ist meistens von deren kommerziellen Bedeutung zum Zeitpunkt der
Markteinführung
eines
Prozessors
abhängig.
Die
Assemblersprachen
werden
dagegen von der ISA- und Mikroarchitektur-Ebene (vgl. Abb. 2) beeinflusst.
Compiler sind für den Erfolg einer Prozessorarchitektur in hohem Maße
mitverantwortlich. Sie dienen der Softwareerstellung oder der Portierung bereits
bestehender Software auf eine bestimmte Prozessorarchitektur. Optimierende
Compiler ermöglichen durch Veränderung der Code- und Datenstruktur, jedoch
unter Beibehaltung der Programmsemantik, eine bestmögliche Ausnutzung aller
Architekturmerkmale. Bei einer Low-Level-Optimierung wird die Optimierung im
Compilierprozess erst sehr spät durchgeführt. Eine Mixed-Model-Optimierung
transformiert die Hochsprache erst in eine Zwischensprache, die anschließend
optimiert und in eine Assemblersprache übersetzt wird [Muchnik97]. Durch das
letztere Vorgehen können Hersteller die Compiler leichter an neue Prozessorarchitekturen anpassen.
Die Optimierung kann unterschiedliche Aspekte umfassen. Ein Compiler kann
möglichst wenig Overhead produzieren oder niemals aufgerufenen Code entfernen
(Dead Code Elimination). Schleifenkonstrukte können durch „Loop Unrolling“
88
optimiert werden, indem der Schleifenkörper mehrmals vervielfältigt und
aneinandergereiht wird, wobei die Schleifenparameter entsprechend angepasst
werden. Dadurch soll die Zahl der Rückwärtssprünge an den Schleifenanfang
vermindert werden. Gleichzeitig wird damit versucht, bei Pipelinearchitekturen
(vgl. Kap. 3.1) die Pipelines besser auszulasten und Pipeline-Hazards zu vermeiden
[Märtin01].
Des
weiteren
kann
ein
Compiler
für
Superskalararchitekturen
ein
Befehlsscheduling durchführen und Befehle so anordnen, dass eine Dispatch-Unit
(vgl. Kap. 3.3) sie möglichst effizient verteilen kann. Auch die Sprungvorhersage
(vgl. Kap. 3.2) kann durch Status-Bits bei Sprungbefehlen unterstützt werden, da
ein Compiler das wahrscheinliche Ausführungsverhalten eines Programms im Voraus
abschätzen kann [Muchnik97]. Ebenso kann das Lokalitätsverhalten abgeschätzt
werden. Bestimmte Befehle und Daten können dann durch Prefetching bereits vor
der Ausführung in den Cache geholt werden (vgl. Kap. 2.2.1).
Die Compiler bei VLIW/EPIC-Architekturen (vgl. Kap. 3.3.3) haben einen noch
größeren Stellenwert, da Hardwarefunktionalität in die Compiler ausgelagert wird.
Diese Compiler müssen den Befehlsstrom eines Programms auf unabhängige Befehle
untersuchen und sie so in Wörter gruppieren, dass die darin enthaltenen Befehle
parallel ausführbar sind. Durch besonders geschickte Gruppierung kann die
Performance erheblich gesteigert werden (vgl. [Märtin01]).
Bei EPIC-Architekturen können sich in einem EPIC-Wort auch Befehle befinden,
die nicht parallel ausführbar sind. Jedes EPIC-Wort enthält zusätzliche Status-Bits
für die Angabe, welche der enthaltenen Befehle parallel ausführbar sind
[Ungerer01]. Eine weitere Besonderheit bei EPIC-Architekturen ist die Nutzung von
Predication (vgl. Kap. 3.3.3). Hierbei werden bestimmten Befehlen Prädikate
zugeordnet. Die Ergebnisse der Befehle werden nur dann als gültig anerkannt,
wenn das zugehörige Prädikat den Wert true hat. Diese Technik wird eingesetzt,
um die Ausführung bedingter Sprünge zu optimieren. Der folgende in Pseudocode
formulierte Code-Abschnitt
switch(Bedingung) {
case 1:
A = B + C; break;
case 2:
A = E + F; break;
89
case 3:
A = H – I; break;
}
würde transformiert werden in:
(p1)
A = B + C;
(p2)
A = E + F;
(p3)
A = H – I;
Dabei sind p1, p2, p3 die zugehörigen Prädikate. Die komplette switch-Anweisung
kann zusammen mit der Auswertung der Bedingung parallel in einem Takt
ausgeführt werden. Eventuelle Konflikte bei der Ausführung (hier ist A jedes Mal
Ziel der Operationen) werden durch Register Renaming (vgl. Kap. 3.3.2) gelöst.
Danach wird das Prädikat auf true gesetzt, auf das die Bedingung der switchAnweisung zutrifft. Weitere Details zu Compilern findet man in [Muchnik97] und
[Märtin01].
Ein Betriebssystem (vgl. Kap. 1.1) kann von einer Mikroprozessorarchitektur
bei
den
Verwaltungsaufgaben
unterstützt
werden.
Viele
Betriebssysteme
verwenden Paging, Segmentierung und virtuellen Speicher (vgl. [SGG99]).
Mikroprozessoren können mit MMUs die Adressumsetzung von logischen in
physikalische Adressen hardwaremäßig unterstützen und beschleunigen (vgl. Kap.
2.2).
Bei Multi-Tasking-Betriebssystemen kann es mehrere ausführende Prozesse
geben, zwischen denen das Betriebssystem zur Laufzeit umschaltet. Hierbei sind
ständig Daten zur Zustandsbeschreibung eines Prozesses in einen sog. Process
Control Block (PCB) zu protokollieren: Registerinhalte, Program Counter, Stack,
verbrauchte CPU-Zeit, Prozess-ID, sowie die Prozess-Umgebung. Zwei Prozesse
können
pseudoparallel
ausgeführt
werden,
indem
ein
Prozess
angehalten
(suspendiert), der PCB gesichert, der PCB des nächsten Prozesses geladen und
dessen Ausführung fortgesetzt wird. Nach einer bestimmten Zeit kann das
Betriebssystem die Kontrolle in der gleichen Weise an den ersten Prozess
zurückgeben. Dieser Vorgang wird als Context-Switch bezeichnet und erfordert
90
wegen
Speicherzugriffen
verhältnismäßig
viel
Zeit,
was
die
Performance
beeinträchtigt.
Manche
Prozessorarchitekturen
unterstützen
einen
Context-Switch
mit
zusätzlicher Hardware, z.B. mit zusätzlichen Registern. Bei der SUN-SPARCArchitektur bestehen beispielsweise die Register aus zirkulär angeordneten
Registersätzen. Das Betriebssystem verwaltet einen Zeiger, der auf den aktuell für
das System sichtbaren Registersatz zeigt. Für einen ausführenden Prozess ist nur
ein Registersatz im sog. Register-Fenster sichtbar. Bei einem Context-Switch kann
das Betriebssystem den Zeiger zirkulär weitersetzen und braucht nicht mehr so
viele Daten im PCB zu verwalten, was die Ausführung beschleunigt. Weitere Details
beschreibt [Märtin01].
Die Zeit für einen Context-Switch kann auch dadurch reduziert werden, dass
sich
sog.
Threads
eine
Programmumgebung
(Code,
Daten
und
Betriebssystemressourcen) teilen. Die Verwaltungsinformationen für einen Thread
beschränken
sich
auf
Registerinhalte,
Program
Counter
und
Stack.
Die
Performancesteigerung durch einen schnelleren Context-Switch wird allerdings
durch ein zusätzliches Konfliktpotenzial zwischen Threads erkauft. Neuere
Mikroprozessorarchitekturen versuchen die Parallelität auf Thread-Ebene in der
Architektur auszunutzen (Simultaneous Multithreading, SMT, vgl. Kap. 5 und 6.2).
Bei der parallelen Ausführung von Prozessen sind oft Synchronisationsmechanismen zur Sicherung der Determiniertheit nötig. Hierfür können atomare
Lese- und Schreiboperationen oder lock-Mechanismen unterstützend von der
Architektur
vorgesehen
werden.
In
[SGG99]
werden
Betriebssysteme
und
zugehörige Konzepte ausführlicher besprochen.
6.2 Ausblick
In
diesem
Kapitel
sollen
mögliche
Entwicklungen
von
zukünftigen
Mikroprozessorarchitekturen vorgestellt werden, an denen zur Zeit noch geforscht
wird. Trotz der langsam erreichten Grenzen der Verarbeitungsleistung bei aktuellen
Prozessorarchitekturen [Ungerer01], bleibt die Forderung nach noch mehr
Performance bestehen. Diese kann einerseits durch die zugrunde liegenden
Technologien (z.B. Fortschritte bei VLSI) oder durch die Erweiterung der
91
Architekturkonzepte um mehr Parallelität bei der Ausführung erfüllt werden.
Grundsätzlich lassen sich vier Entwicklungsrichtungen identifizieren [SiUnRo00]:
•
Die Prinzipien der von-Neumann-Architektur, insbesondere die Ergebnissequenzialität, werden beibehalten. Die interne Ausführung der Befehle
geschieht allerdings parallel. Aktuelle Mikroprozessoren nutzen überwiegend Parallelität auf Befehlsebene (Instruction Level Parallelism, ILP) und
Parallelität durch Spekulation aus (vgl. Kap. 3.2). Neuere Forschungsansätze dieser Klasse sind: Superspekulative [LiShe97], Multiskalare
[Frank93], Trace-Prozessoren [RJSS97] und Datenskalare Prozessoren
[BuKaGo97].
•
Das SISD-Prinzip der von-Neumann-Architektur wird zum SIMD-Prinzip
erweitert, so dass ein Befehl mehrere Daten gleichzeitig manipuliert.
Hierbei soll Parallelität auf Datenebene ausgenutzt werden. Beispiele für
solche Architekturen sind Vektor- oder VLIW/EPIC-Architekturen (vgl.
Kap. 3.3.3 und 3.3.4).
•
Es wird zusätzlich die Parallelität auf Thread-Ebene ausgenutzt. Dabei
sollen Prozessoren in der Lage sein, hardwaremäßig Threads (vgl. Kap.
6.1) parallel auszuführen. Bei der Ausführung eines Threads werden die
von-Neumann-Prinzipien eingehalten. Zu dieser Klasse gehören SingleChip-Multiprozessoren [PPEFS97] und Simultaneous-MultithreadedProzessoren [TuEgLev95].
•
Die
von-Neumann-Architektur wird komplett verlassen. Dazu zählt
beispielsweise der Processor-In-Memory-Ansatz [PaAnCa97].
Aufgrund der Vielzahl unterschiedlicher Forschungsansätze werden in diesem
Kapitel nur die wichtigsten erläutert. Alle anderen Architekturprinzipien sind in
[SiRoUn99] ausführlich beschrieben.
Die direkten Weiterentwicklungen der superskalar-Architekturen („Advanced
Superscalar Microprocessors“) konzentrieren sich noch intensiver auf die
Ausnutzung der Parallelität auf Befehlsebene (ILP). Dabei versucht man, die Zahl
92
der ausführenden Funktionseinheiten noch weiter zu erhöhen, die Cache-Speicher
zu vergrößern und die Sprungvorhersage durch unterschiedliche Algorithmen für
jede Klasse von Programmsprüngen zu verbessern (Hybrid Predictors, [EvCP96],
[McFarling93]). Die Instruktions-Cache-Speicher werden zu Trace-Cache-Speichern
erweitert, indem sie in einer Cache-Line nicht mehr einzelne Instruktionen
zwischenspeichern, sondern zur Laufzeit aufgetretene Befehlssequenzen (Traces).
Die Idee ist dabei folgende: Sollte die gleiche Befehlssequenz vom Programm öfter
ausgeführt werden (z.B. bei Schleifen), so kann auf eine erneute Sprungvorhersage
verzichtet und die frühere Befehlssequenz direkt aus dem Trace-Cache geholt
werden.
Ein weiterer Ansatzpunkt ist die Verbesserung der Spekulation. Basierend auf
der Beobachtung, dass die berechneten Werte in Programmen (z.B. Adressen oder
Werte von Operanden) aufgrund des Lokalitätsprinzips vorhersehbar sind, werden
weitere Möglichkeiten wie Datenabhängigkeits- und Wertespekulation erforscht.
Programme werden in Teile unterteilt, die Werte produzieren („Producer“) und
Teile,
die
Werte
benutzen
(„Consumer“).
Superspekulative
Prozessoren
versuchen die von den Consumern benötigten Werte spekulativ zu schätzen, noch
bevor sie von den Producern erzeugt wurden. Dieses Parallelitätspotenzial soll für
Performancesteigerungen
ausgenutzt
werden.
Weitere
Details
gibt
es
in
[SiUnRo00].
Die Fokussierung auf Befehlsebenenparallelität wird bei MultithreadedArchitekturen aufgegeben. Ein Multithreaded-Prozessor ist dabei in der Lage, die
Befehle von zwei oder mehr Threads in Hardware gleichzeitig (oder überlappt
parallel) auszuführen. Für jeden Thread gibt es eigene Registersätze, in denen
Kontextinformationen abgelegt werden können (vgl. Kap. 3.2). Die Kombination
von Mehrfädigkeit und Superskalartechnik werden in Simultaneous-MultithreadingArchitekturen (SMT) vereint. Solche Prozessoren können in einem Taktzyklus
Befehle mehrerer Threads an Ausführungseinheiten zuordnen. SMT-Architekturen
werden in [TuEgLev95] und [SiUn96] genauer beschrieben.
Es gibt mehrere Möglichkeiten für die Erzeugung von Threads. Bei
parallelisierten Betriebssystemen oder Programmen sind Threads durch die
Software bereits spezifiziert, so dass sie nur noch auf die Hardware abgebildet
werden müssen. Es wird aber zusätzlich die Möglichkeit untersucht, aus einem
sequenziellen Befehlsstrom innerhalb des Prozessors Threads zu erzeugen und
93
spekulativ auszuführen. Die Thread-Erzeugung kann dynamisch zur Laufzeit
(Dynamic Multithreading) oder statisch mit Unterstützung eines Compilers erfolgen.
Letzterer Ansatz soll ein wenig genauer beschrieben werden.
Bei Multiskalaren Prozessoren teilt zuerst ein Compiler ein sequentielles
Programm in sog. Tasks auf, die den Ausführungseinheiten (processing elements)
des Prozessors zugeteilt und spekulativ ausgeführt werden. Dabei wird so
vorgegangen, dass der nichtspekulative Teil eines Programms einer bestimmten
Ausführungseinheit zugewiesen wird. Tasks, die im Programm später folgen,
werden von einem Sequenzer auf alle anderen Ausführungseinheiten verteilt. Deren
Ergebnisse werden verworfen, wenn das Programm einen anderen Verlauf annimmt
als
erwartet
(Fehlspekulation).
Am
Problem
der
eventuell
auftretenden
Datenabhängigkeiten wird noch geforscht. Genaueres zu Multiskalaren Prozessoren
findet sich in [SoBrVi95], [SiUnRo00], [Ungerer01].
Erwähnenswert ist auch der Ansatz von Chip-Multiprozessoren [Kahle99]. Die
Architektur von Chip-Multiprozessoren wird maßgeblich von der vorhandenen
Technologie beeinflusst. Hierbei werden mehrere Prozessoren auf einem Chip
vereinigt. Einige der Speicher auf dem Chip (z.B. Cache) werden von allen CPUs
gemeinsam genutzt. Dadurch sollen Signallaufzeiten und Speicherlatenzzeiten
reduziert und die Kommunikation zwischen den CPUs erleichtert werden. ChipMultiprozessoren
können
auch
mit
Multithreading-Architekturen
kombiniert
werden, was die Firma Sun Microsystems im SUN-MAJC-5200-Prozessor realisiert hat
(vgl. Kap. 5 und [Märtin01]).
Der Architekturansatz der Prozessor-Speicher-Integration (auch Processor-InMemory, Intelligent RAM, IRAM) entfernt sich stark von der Architektur nach vonNeumann. Im Zentrum der Betrachtung steht nicht mehr die CPU, sondern der
Speicher. Man versucht dabei, CPU und kompletten Speicher auf einem Chip zu
integrieren, um für Speicherzugriffe die Bandbreite zu erhöhen und die Latenzzeit
zu reduzieren. Dieser Ansatz könnte dabei Cache-Speicher überflüssig machen.
Beim derzeitigen Stand der VLSI-Technologie ist eine solche Integration allerdings
noch mit technischen Problemen verbunden. Weitere Details sind in [Ungerer01] zu
finden.
Schließlich sei noch erwähnt, dass auch an ganz unterschiedlichen Paradigmen
geforscht wird, die eine radikal andere Sicht auf Berechnungen haben. Dabei
benutzt man für die Repräsentation von Daten nicht mehr elektrische, digitale
94
Signale, sondern beispielsweise chemische Reaktionen (DNA-Computing) oder
quantenmechanische Vorgänge (Quantum Computing). Detailliertere Informationen
zu DNA-Computing findet man in [Adleman94], [GBGMP01], zu Quantum-Computing
in [Shor94], [GBGMP01].
95
Anhang: Bilder von Mikroprozessoren
96
Intel 4004 (1971)
Quelle: Intel
97
Intel 486 (1991)
Quelle: Intel
98
Motorola PowerPC 601 (1992)
Quelle: Motorola
99
Intel Pentium (1993)
Quelle: Intel
100
Intel Pentium 4 (2001)
Quelle: Intel
101
Bibliographie
[ABF95]
Abramovici,
Breuer,
Friedman,
Digital
Systems
Testing
& Testable Design, IEEE Press, 1995
[Adleman94]
Adleman, Molecular computation of solutions to combinatoral
problems. Science 266, pp. 1024-1024, 1994
[AMD01]
ADVANCED MICRO DEVICES, INC., One AMD Place, Sunnyvale, CA
94088, QuantiSpeed™ Architecture, White Paper, September 7,
2001
[AMD02]
http://athlonxp.amd.com/overview/keyFeatures.jsp,
21.03.2002
[BDT98]
Berkeley Design Technology Inc., PowerPoint-Folien, 2107
Dwight Way, California, USA, http://www.BDTI.com,
1998
[BDT00]
Berkeley Design Technology Inc., Choosing a DSP Processor,
2107 Dwight Way, California, USA, http://www.BDTI.com,
2000
[BeiHag01]
Thomas
Beierlein,
Olaf
Hagenbruch,
Taschenbuch
der
Mikroprozessortechnik, Fachbuchverlag Leipzig, 2. Auflage 2001
[Bleul00]
Bleul,
Jonglierwettbewerb.
Vektorarchitekturen
aktueller
Prozessoren im Vergleich. c’t, Heft 4, 2000, pp. 314-323
[Brig95]
Brigham,
FFT:
Schnelle
Fourier-Transformation,
München,
Oldenbourg-Verlag, 1995
[BuKaGo97]
Burger,
Kaxiras,
Goodman,
Datascalar
Architectures,
in:
Proceedings of the ISCA 24, Denver, CO, 1997, pp. 338-349.
[BuGoNeu46]
Burks, Goldstine, von Neumann, Preliminary discussion of the
logical design of an electronic computing instrument. Report to
the US Army Ordonance Department, 1946. Reprint in: Aspray,
Burks (Eds.), Papers of John von Neumann, MIT Press,
Cambridge, MA, 1987, pp. 97-146.
[Clausing00]
Clausing, Skript zu Informatik IV, Institut für Informatik WWU
Münster, 2000
102
[CrHuck97]
Crawford, Huck, Motivations and Design Approach for the IA-64
64-Bit Instruction Set Architecture. Microprocessor Forum, San
Jose, Calif. Oct 14, 1997
[Crouch99]
Crouch, Design for Test for Digital ICs and Embedded Core
Systems, Prentice-Hall New Jersey, 1999
[Denning80]
Denning, Working Sets Past And Present, IEEE Transactions on
Software Engineering, Volume SE-6, Number 1, Jan 1980, pp.
64-84.
[Dief99]
Diefendorff,
PC
Processor
Microarchitecture,
Microdesign
Resources, Microprocessor Report, July 12, 1999
[EvCP96]
Evers, Chang, Patt, Using hybrid branch predictors to improve
branch prediction accuracy in the presence of context
switches, in: Proceedings of the ISCA 23, Philadelphia, PA,
1996, pp. 3-11.
[EyBier98]
Eyre, Bier, DSP Processors Hit the Mainstream, Berkeley Design
Technology Inc, 2107 Dwight Way, Berkeley, CA, 1998
[Flynn72]
Flynn, Some Computer Organizations and Their Effectiveness,
IEEE Trans. on Computers C-21, 9. Sept 1972
[Frank93]
Franklin, The multiscalar architecture, Computer science
Technical Report No. 1196, University of Wisconsin-Madison,
WI, 1993
[Gajski83]
Gajski, Kuhn, Guest Editor’s Intruduction: New VLSI Tools. IEEE
Computer, 6(12): 11-14, 12 1983
[GBGMP01]
Gramß, Bornholdt, Groß, Mitchell, Pellizzari, Non-StandardComputation, Wiley, 2001
[Giloi97]
Giloi, Rechnerarchitektur, Springer-Verlag, 3. Auflage 1997
[GlaRau94]
Glaser,
beim
Rauch,
Ablaufstrategien
Mikrosystementwurf.
und
Rechnerunterstützung
Abschlußbericht
des
Verbund-
projekts „Untersuchungen zum Entwurf von Mikrosystemen“,
Reihe: Innovationen in der Mikrosystemtechnik, Band 19,
November 1994
[Goser91]
Goser, Großintegrationstechnik. Teil 2: von der Grundschaltung
zum VLSI-System. Heidelberg: Hüthig Buch Verlag, 1991,
103
erschienen in der Reihe ELTEX Studientexte Elektrotechnik,
Hrsg: Reinhold Pregla, Fernuniversität Hagen
[Grun98]
Grunwald, Klauser, Manne, Pleszkun, Confidence Estimation for
Speculation Control. 25th Annual International Symposium on
Computer Architecture, Barcelona, Juni/Juli 1998, pp. 122-131
[Gwen95]
Gwennap, Microprocessor Report, Intel’s P6 Uses Decoupled
Superscalar Design, Vol 9, No.2, Feb. 16, 1995
[Händler75]
Händler, On Classification Schemes for Computer Systems in
the Post-von-Neumann-Era. GI Jahrestagung 1974, Siefkes,
G. (Ed), Lecture Notes in Computer Science, Vol. 26, Springer
Verlag, 1975, pp. 439-452.
[HePa97]
Hennessy, Patterson, Computer Organizatin and Design: the
Hardware/Software Interface, Morgan Kaufmann 1997
[HePa96]
Hennessy, Patterson, Computer Architecture: A Quantitative
Approach. Second Edition, Morgan Kaufmann 1996
[Intel99]
Intel
Architecture
Software
Developer’s
Manual
Vol.
1-4 (Pentium III), Intel Corp. 1999
[Intel99b]
Intel Architecture Optimization Reference Manual. Intel Corp.,
1999
[Intel00a]
IA-32 Intel Architecture Software Developer’s Manual With
Preliminary Willamette Architecture Information Vol. 1-2
[Intel00b]
Intel IA-64 Architecture Software Developer’s Manual. Vol.
1-5 Intel Corp., 2000
[Intel00c]
Itanium Processor Microarchitecture Reference for Software
optimization. Intel Corp., March 2000
[Intel02a]
http://www.intel.com/design/Pentium4/prodbref/,
21.03.2002
[Intel02b]
http://www.intel.com/design/xeon/xeonmp/prodbref/
index.htm, 21.03.2002
[Intel02c]
http://www.intel.com/design/itanium/itanium.htm,
21.03.2002
[Kahle99]
Kahle, Power4: A Dual-CPU Processor Chip. Microprocessor
Forum, Oktober 1999
[Kropf95]
Thomas Kropf, VLSI-Entwurf, Thomson Publishing, 1995
104
[LewPap98]
Lewis, Papadimitriou, Elements of the Theory of Computation,
Prentice-Hall International Inc., 1998
[LiShe97]
Lipasti, Shen, Superspeculative microarchitecture for beyond
AD 2000, Computer 30 (1997), pp. 59-66.
[Malone96]
Malone, Der Mikroprozessor: Eine ungewöhnliche Biographie,
Springer 1996
[Marr02]
Marr, Binns, Hill, Hinton, Koufaty, Miller, Upton, HyperThreading Technology Architecture and Microarchitecture, Intel
Technology Journal Q1,2002
[Märtin01]
Märtin, Rechnerarchitekturen, Fachbuchverlag Leipzig, 2001
[McFarling93]
MyFarling, Combining Branch Predictors. DEC WRL Technical
Note TN-36, DEC Western Research Laboratory,1993
[Messmer00]
Messmer, PC Hardwarebuch, Addison-Wesley, 2000
[Motorola02]
Motorola Product Brief, MC9328MX1P/D, Rev. 2, 2/2002,
http://e-www.motorola.com/webapp/sps/site/
prod_summary.jsp, 21.03.2002
[Motorola02b]
MSC8102, THE PERFORMANCE DSP, Motorola Fact Sheet, 2002
[Muchnik97]
Muchnik, Advanced Compiler Design and Implementation,
Morgan Kaufmann,1997
[ObVossen00]
Oberschelp, Vossen, Rechneraufbau und Rechnerstrukturen,
Oldenburg, 2000
[PanRan92]
Pan, Ranneh, Improving the Accuracy of Dynamic Branch
Prediction
Using
Conference
on
Branch
Correlation.
Architectural
Support
5th
International
for
Programming
Languages and Operating Systems (ASPLOS), pp. 76-84, Boston,
April 1992
[Pat85]
Patterson, Reduced Instruction Set Computers. Comm. ACM, V.
28, Nr. 1, 1985, pp. 8-21.
[PaAnCa97]
Patterson, Anderson, Cardwell et. al, A Case for Intelligent
RAM. IEEE Micro, March/April 1997, pp. 34-43.
[PPEFS97]
Patt, Patel, Evers, Friendly, Stark, Billion Transistors, One
Uniprocessor, One Chip, Computer 30 (1997), pp. 51-57.
[Reilly99]
Matt Reilly, Designing an Alpha Microprocessor, IEEE 1999
105
[RJSS97]
Rotenberg, Jacobson, Sazeides, Smith, Trace processors, in:
Proceedings of the MICRO-30, Research Triangle Park, NC,
1997, pp. 138-148.
[Runyon99]
Runyon, Testing Big Chips Becomes An Internal Affair, IEEESpectrum 36(4), 1999, pp. 49-55.
[SDI91]
Schüler-Duden-Informatik, Meyers Lexikonverlag, 1991
[SG99]
Silberschatz, Galvin, Operating Systems Concepts, Wiley, Fifth
Edition 1999
[Shor94]
Shor, Algorithms for Quantum Computation: Discrete Log and
Factoring. Proc. 35th Annual Symposium on Foundations of
Computer Science, Nov. 20-22, 1994, Santa Fe, New Mexico,
IEEE Computer Society Press, pp. 124-134.
[Siemers2000]
Siemers C., Hardwaremodellierung, Hanser-Verlag, 2000
[SiRoUn99]
Silc, Robic, Ungerer, Processor Architecture, Springer, Berlin,
1999
[SiUn96]
Sigmund, Ungerer, Evaluating a Multithreaded Superscalar
Microprocessor
Versus
a
Multiprocessor
Chip.
4th
PASA
Workshop on Parallel Systems and Algorithms. Jülich, April
1996, pp. 147-159.
[SiUnRo00]
Silc, Ungerer, Robic, A survey of new research directions in
microprocessors, Elsevier Microprocessors and Microsystems
24 (2000), pp. 175-190.
[SmSohi95]
Smith, Sohi, The Microarchitecture of Superscalar Processors,
Department
of
Electrical
and
Computer
Engineering,
1415 Johnson Drive, Madison, WI53706, 1995
[SoBrVi95]
Sohi, Breach, Vijaykumar, Multiscalar Processors. 22nd Ann.
Int. Symp. on Computer Architecture, Santa Margherita Ligure,
Italien, July 22-24, 1995, pp. 414-425.
[SpEl94]
Spoerle Electronic: Distribution Live – Mikrocontroller Special,
10/94
[Staudt94]
von Staudt, Das professionelle PowerPC Buch, Franzis 1994
[Subram99]
Subramania Sudharsanan, MAJC5200: A High Performance
Microprocessor for Multimedia Computing, Sun Microsystems
Inc., Palo Alto, CA, 1999
106
[SUN99a]
MAJC Architecture Tutorial. White Paper. Sun Microsystems,
1999
[SUN02a]
http://www.sun.com/processors/whitepapers/majcintro.html,
21.03.2002
[SUN02b]
http://www.sun.com/sparc/UltraSPARC-III/index.html,
21.03.2002
[SUN02c]
http://www.sun.com/processors/UltraSPARCIII/USIIITech.html, 21.03.2002
[Tabak91]
Tabak, Advanced Microprocessors, McGraw-Hill 1991
[Tabak95]
Tabak, Advanced Microprocessors, McGraw-Hill 1995
[TanGo99]
Tanenbaum, Goodman, Computerarchitektur, Prentice Hall,
4. Auflage 1999
[Tremb99]
Tremblay,
MAJC-5200.
AVLIW
Convergent
MPSOC.,
Microprocessor Forum, 1999
[TuEgLev95]
Tullsen, Eggers, Levy, Simultaneous multithreading: maximizing
on-chip parallelism, in: Proceedings of the ISCA 22, Santa
Margherita Ligures, Italy, 1995, pp. 392-403
[Ungerer95]
Ungerer, Mikroprozessortechnik, Thomson Publishing 1995
[Ungerer01]
Ungerer, Mikroprozessoren. Stand der Technik und Forschungstrends, Informatik-Spektrum, 24.02.2001
[Weiss94]
Weiss, POWER and PowerPC, Morgan-Kaufmann, 1994
Walker, A Model of Design Representation and Synthesis, 22nd
Design Automation Conference, Las Vegas, 1985
[Wunderlich98]
Wunderlich, BIST for Systems-on-a-Chip in Integration, The VLSI
Journal, 1998
[YehPatt91]
Tse-Yu Yeh, Yale Patt, „Two-Level Adaptive Training Branch
Prediction“,
24th
International
Symposium
Microarchitecture (Nov. 1991), p. 51-61
[Zilog01]
Introduction to Embedded Webservers, Zilog, 2001,
http://www.zilog.com/products/partdetails.asp, 21.03.2002
on
107
Erklärung
Ich
versichere
hiermit,
dass
„Mikroprozessorarchitekturkonzepte“
ich
meine
selbständig
und
Bachelor-Abschlußarbeit
ohne
fremde
Hilfe
angefertigt habe, und dass ich alle von anderen Autoren wörtlich übernommenen
Stellen wie auch die sich an die Gedankengänge anderer Autoren eng anlegenden
Ausführungen meiner Arbeit besonders gekennzeichnet und die Quellen zitiert
habe.
Münster, den
(Unterschrift)