Dokumentation
Prozessorentwurfspraktikum WS 2002/2003
Gruppe 6

Patrick Röder, Matrikelnummer XXXXXX
Marko Mähner, Matrikelnummer XXXXXX
Eduard Singer, Matrikelnummer XXXXXX

Inhalt

  1. Einleitung
  2. CPU
  3. Steuerwerk
  4. Register
  5. Registersatz
  6. SRAM
  7. ALU
  8. Opcode in Alu_Operation umwandeln
  9. Testumgebung
  10. Befehlssatz
  11. Optimierungen
  12. Weitere Verbesserungen
  13. Benchmarks
  14. Feedback zum PeP
  1. Terminologie
  2. Abbildungen
  3. Tabellen

1. Einleitung


Die Aufgabe des diesjährigen Prozessorentwurfs-Praktikumes war es einen 16 Bit RISC-Prozessor mit 8 Registern zu entwerfen. Ausgehend von der Aufgabenstellung analysierten wir welche Komponenten benötigt werden. Wir versuchten dabei, einen möglichst modularen Aufbau zu erhalten. Durch das Zusammenfassen von vielen kleineren Bauteilen zu komplexeren Einheiten haben wir dieses Ziel erreicht und auch zur Übersicht des ganzen Projektes beigetragen. Die Module, die es zu realisieren galt, umfassen eine Einheit, die Lese- und Schreibzugang zu den 8 Registern bereitstellt, eine ALU, die in der Lage ist zwei Operanden unter Anwendung einer festlegbaren Operation zu einem Ergebnis zu verknüpfen. Weiterhin wird ein Register benötigt, das den Programmzähler realisiert. Dieses sollte eine Möglichkeit haben, um es direkt (also ohne Berechnung über die ALU) um eins zu inkrementieren. Schliesslich muss der Prozessor auch über einen Speicherbaustein verfügen. Die bisher genannten Komponenten wurden von uns zu einem Operationswerk zusammengefasst. Eine kritische Frage war nun, was der geschickteste Weg ist, die genannten Einheiten zu verbinden. Eine einfache Möglichkeit alle Komponenten an einen gemeinsamen Bus anzuschliessen hat den entscheidenden Nachteil, dass nur ein Datentransfer zwischen zwei Einheiten parallel möglich ist. Diesen Nachteil könnte man durch geziehlte Verwendung mehrerer Busse umgehen. Man müsste sich dabei ansehen, wieviel und welche Transfers parallel möglich sind und dementsprechend die Busse entwerfen. Bei diesem Ansatz geht dann allerdings die Einfachheit und Eleganz der Ein-Bus-Lösung verloren. Wir haben uns dafür entschieden, alle Komponenten, die miteinander kommunizieren müssen, durch direkte Verbindungen zu koppeln. Die Auswahl des zu benutzenden Datenpfades wird über Multiplexer gesteuert. Der Nachteil gegenüber dem Ansatz mit einem Bus ist sicherlich ein höherer Verdrahtungsaufwand und eine höhere Komplexität, aber um ein Maximum an Parallelität zu gewährleisten, haben wir uns für diese Lösung entschieden.
Das eben beschriebene Operationswerk ist selbst nur der passive Teil unseres Prozessors. Es wird vom aktiv handelden Steuerwerk gesteuert. Eine weitere Designfrage war die Art der Kommunikation zwischen diesen beiden Teilen. Ein erster Ansatz von uns war, alle sinnvollen Kombinationen von internen Steuersignalen aufzulisten und zu Mikrocodes zusammenzufassen. Man würde in dieser Lösung nur den Mikrocode vom Steuerwerk aus anlegen und diese OPW-intern wieder in die korrekten Steuersignale zu dekodieren. Da wir im voraus nicht vorhersehen konnten, welche Kombinationen sinvoll sind, haben wir uns vorerst nicht für diese Variante entschieden uns aber den Weg dafür offengehalten. In unserer Lösung sind alle internen Steuersignale und der aktuelle Opcode ans Steuerwerk geführt.
Weiterhin haben wir uns Gedanken gemacht, welche Steueraufgaben wir intern im Steuerwerk schon erledigen können. Dadurch reduziert sich etwas die Komplexität des Steuerwerks und die Anzahl der nötigen Steuerleitungen. Details zu diesen Massnahmen sind unter dem Punkt Optimierungen zu finden.
Die Einzelheiten/Funktionalitäten der einzelnen Komponenten werden in den jeweiligen Abschnitten beschrieben.

2. CPU

Unsere Komponente CPU setzt sich aus den folgenden Komponenten (Verilog-Files) zusammen:

Abb. 2.1: Layout des Prozessors

Layout des Prozessors als PDF-Datei






Für eine grössere Darstellung auf das Bild klicken


3. Steuerwerk

Im Steuerwerk (STEUERWERK.V) findet sich das "Gehirn" unseres Prozessors wieder.
Das Steuerwerk ist ein Zustandsautomat vom Typ Moore. Als Eingabe erhält es vom Operationswerk den Opcode und die Statusflags der Alu. Diese sind im Operationswerk in Registern gepuffert. Als Ausgaben produziert es einen ganzen Vektor von Steuersignalen der an das Operationswerk weitergereicht wird und den nächsten Zustand in den es wechseln wird. Es gibt einen initialen Zustand (S0) der nur einmal nach dem Reset verwendet. Klassisch folgen dann die Zustände für das Holen eines Befehls (S1) und das Dekodieren (S2). Schon früh in der Entwicklungsphase des Prozessors erkannten wir, dass es durch die Wahl von parallelen Datenpfaden im Operationswerk möglich ist, auch in der letzten Phase eines Befehls, durch setzen der richtigen Signale, den nächsten Befehl zu laden. Dadurch haben wir eine Art von "Command prefetch" implementiert. Normalerweise muss zunächst im Zustand S4 der PC inkrementiert werden und etwas gewartet werden, bis der Speicher auf die neu angelegte Adresse reagiert. Erst dann wird in den Zustand S1 zum eigentlichen Holen des Befehls verzweigt. Die meisten Befehle inkrementieren den PC, durch setzen des Steuersignals inc_pc schon in ihrer letzten Phase und können so den Zustand S4 überspringen und gehen gleich zu S1. Dieses Prinzip des Überlappen von Ausführungsphasen eines Befehls haben wir dann kontinuierlich im ganzen Steuerwerk verwendet. Schon im Zustand S2 (Dekodieren) werden nach dem Dekodieren die passenden Steuersignale für Befehle die den Speicher verwenden gesetzt. Abhängig vom Opcode werden auch noch einige andere Steuersignale passend gesetzt. Durch die Überlappung von Phasen wurden die einzelnen Zustände etwas komplexer, da es hierfür nötig war noch einmal Fallunterscheidungen zu machen. Durch die geschickte Realisierung des Operationswerkes war es möglich alle arithmetischen Befehle und compare durch die gleiche Zustandsfolge abzuarbeiten. Die Quell- und Zielregister werden vom OPW automatisch am Registersatz ausgewählt. Weiterhin wird aus dem Opcode durch das Schaltnetz "OPC_to_Alu_OP" der richtige Befehlscode für die Alu erzeugt. Mit diesen Mechanismen war es nicht mehr nötig von Seiten des Steuerwerks zwischen verschiedenen Arithmetischen Befehlen zu unterscheiden. Alle Befehle haben es gemeinsam, dass zunächst die Operanden an die Alu angelegt werden. Im Falle von monadischen Operationen wird der zweite einfach ignoriert. In der nächsten Phase rechnet die Alu und darauf wird das Ergebnis der Alu zurückgeschrieben. Dies bereitet uns etwas Probleme beim Befehl comp, der nur zwei Operanden vergleichen soll und keine Register verändern soll. Als kleine Kunstkniff wurde hierfür die Aluoperation zum ausgeben von Operand A hinzugefügt und dieser Alu-Opcode automatisch beim Befehl comp durch OPC_to_Alu_OP erzeugt. Dafür dauert comp einen Takt länger als eigentlich nötig, aber es wurden einige Zustände gespart und das Design etwas vereinheitlicht. Nach diesen Prinzipien des Zusammenfassen von Zuständen und des Wiederbenutzen von Zustandsfolgen arbeitet das gesamte Steuerwerk und kommt deswegen mit verhältnismässig wenig Zuständen aus. Beispielsweise verwendet der Befehl JSR (Jump to Subroutine) nachdem er die Rücksprungadresse auf den Stack gerettet hat die gleiche Zustandsfolge wie der Befehl bra (unbedingter Sprung). Ebenso verzweigen alle bedingten Sprungbefehle nach erfolgreichem Prüfen ihrer Bedingung in die gleiche Zustandsfoge. Mit diesen Prinzipien haben wir die gebotene mögliche Parallelität des OPW weitestgehends ausgenutzt. In den meisten Fällen war eine höhere Parallelität nicht möglich, da auf den Speicher gewartet werden muss. Durch diese bereits vorhandenen Massnamen erschien uns der Nutzen einer Pipeline verhältnismässig gering. Einen sicherlich grösseren Vorteil hätten Cachespeicher mit sich gebracht.
Kurze Zusammenfassung der Signale:

Tab. 3.1: Eingänge des Steuerwerks
Bezeichnung Breite Datentyp Beschreibung
opc 6 Bit Opcode Von außen angelegter Operationscode für die nächste Instruktion
alu_flags 4 Bit Steuerung Angelegte boolesche Flags der Recheneinheit
mode 4 Bit Steuerung Der aktuelle Mode, welcher angibt, wie die zu verarbeitenden Werte geladen werden

Tab. 3.2: Ausgänge des Steuerwerks
Bezeichnung Breite Datentyp Beschreibung
inc_pc 1 Bit Steuerung erhöht den Programmzähler um eins
load_pc 1 Bit Steuerung der Programmzähler wird aus dem Memory Data Register geladen
ld_mdr 1 Bit Steuerung Das Memory Data Register wird aktiviert (enabled)
ld_ir 1 Bit Steuerung Das Instruction Register wird aktiviert (enabled)
ld_reg 1 Bit Steuerung Der Registersatz wird aktiviert
mem_cs 1 Bit Steuerung Chipselect (Aktivierung) des Speichers
mem_wr 1 Bit Steuerung Der Speicher wird in den Lese- bzw. den Schreibmodus versetzt
mem_sflag 1 Bit Steuerung Der Speicherinhalt wird in eine Datei geschrieben
sel_reg_a_src 1 Bit Steuerung Dieses Signal steuert den Multiplexer, welcher für die Auswahl des Dateneinganges des Registersatzes verantwortlich ist.
sel_op_a, sel_op_b 1 Bit Steuerung Diese beiden Signale steuern die beiden Multiplexer, welche die beiden Operanden (a und b) für die Recheneinheit ALU zur Verfügung stellen.
alu_go 1 Bit Steuerung Dieses Signal aktiviert die ALU. Sie ist somit nicht getaktet.
clock 1 Bit Steuerung Angelegter Takt
set_sel_a 1 Bit Steuerung Mithilfe dieses Signales kann der Wert eines Registers des Registersatzes direkt beschrieben werden (Signal new_sel_a=1).
sel_mem_addr 2 Bit Steuerung Durch dieses Signal wird der für die Speicher-Adressauswahl (adr des Speichers SRAM) verantwortliche Multiplexer gesteuert.
new_sel_a 3 Bit Steuerung Dieses Signal dient der Steuerung des Multiplexers, der für die Auswahl des anzusteuernden Registers a im Registersatz zuständig ist.

4. Register

Die Komponente Register (REGISTER.V) beschreibt ein 16 Bit breites Tri-State-Register. Von außen angelegte Daten werden nach einer Zeitdauer von 10 ns zum Ausgang do durchgeschaltet. Der Ausgang selbst befindet sich anfangs in einem hochohmigen Zustand, nach Aktivierung des Registes (load-Signal) aber liefert es die zuvor übernommenen Daten.
Der Zustand des Ausgangs richtet sich nach dem LOAD-Signal. Ist es während einer ansteigenden Flanke auf Eins gesetzt, so wird der Ausgang do aktiv und liefert so lange Daten, bis das LOAD-Signal an einer ansteigenden Flanke auf Null gesetzt ist.
Die Signale des Registers sind im einzelnen:

Tab. 4.1: Eingänge des Registers
Bezeichnung Breite Datentyp Beschreibung
clock 1 Bit Takt Angelegter Takt
load 1 Bit Steuerung Das LOAD-Signal steuert den Zustand des Ausgangs do. Ist das ENABLE-Signal während einer ansteigenden Flanke auf Eins, so wird für die Dauer des nächsten Taktes ein Datum am Register-Ausgang do anliegen. Andernfalls behält der Ausgang den zuvor geladenen Wert.
di 16 Bit Daten Angelegte Daten, welche bei einer steigenden Flanke übernommen werden, sofern das LOAD-Signal auf Eins ist. Die Daten liegen frühestens nach 10 ns am Ausgang do an.

Tab. 4.2: Ausgänge des Registers
Bezeichnung Breite Datentyp Beschreibung
do 16 Bit Daten Register-Ausgang, der sich entweder im hochohmigen Zustand befindet oder aber Daten ausgibt. Der Zustand des Ausgangs richtet sich nach dem ENABLE-Signal, mit welchem man an jeder ansteigenden Flanke den Zustand ändern kann.

5. Registersatz

Die Komponente Registersatz (Registersatz.v) dient als Kapselung der acht vorgegebenen einzelnen Register. Der Registersatz erhält seine Daten entweder vom Memory Data Register oder alternativ als Berechnungsergebnis des Rechenwerkes (der ALU). Durch Multiplexer können alle acht internen Register einzeln ausgelesen bzw. kann in jedes der Register ein Wert geschrieben werden. Der Registersatz liefert die Opernanden für die Recheneinheit (ALU). Diese beiden zu wählenden Operanden sind ebenfalls durch Multiplexer wählbar.

Tab. 5.1: Eingänge des Registersatzes
Bezeichnung Breite Datentyp Beschreibung
clock 1 Bit Takt Angelegter Takt
load 1 Bit Steuerung Das LOAD-Signal steuert die Datenspeicherung des Registersatzes bzw. der darin enthaltenen acht Register. Ist das LOAD-Signal während einer ansteigenden Flanke auf Eins, so wird für die Dauer des nächsten Taktes das am Registersatz anliegende Datum a_in in das durch sel_a ausgewählte Register geschrieben. Andernfalls behalten die Register die zuvor geladenen Werte.
a_in 16 Bit Daten 16 Bit-Dateneingang des Registersatzes, welcher bei aktivem load-Signal in ein ausgewähltes Register geschrieben wird.
sel_a, sel_b 3 Bit Steuerung Diese Signale dienen der Auswahl der im Registersatz enthaltenen Register. Im Falle des Schreibens (load-Signal = 1) des am Registersatz anliegenden Datums in ein Register, wählt man mit sel_a das Register aus, in welches dieses Datum gespeichert werden soll. Möchte man die Werte einzelner Register an die beiden Ausgänge a_out und b_outschalten, so wählt man mit diesen beiden Signalen diejenigen Register für die Durchschaltung aus.

Tab. 5.2: Ausgänge des Registersatzes
Bezeichnung Breite Datentyp Beschreibung
a_out, b_out 16 Bit Daten Registersatz-Ausgänge, die bei einer ansteigenden Flanke des Taktes die Werte der durch sel_a und sel_b gewählten Register am den jeweiligen Ausgang (sel_a für Ausgang a_out bzw. sel_b für b_out) annehmen.

6. SRAM

Die Komponente SRAM (SRAM.V) wurde von uns aus den Praktikumsvorgaben übernommen.

Tab. 6.1: Eingänge des Speichers
Bezeichnung Breite Datentyp Beschreibung
CS 1 Bit Steuerung Active Hi Chip select
WR 1 Bit Steuerung Active High write control
ABUS 16 Bit Adresse 16 Bit Adress-Bus
SFLAG 1 Bit Steuerung Signal, um den Speicher in eine Datei zu schreiben

Tab. 6.1: Ein- und Ausgang des Speichers
Bezeichnung Breite Datentyp Beschreibung
DATABUS 16 Bit Daten 16 Bit Daten-Bus

7. ALU

Die ALU (ALU.V) übernimmt, sobald der Befehlscode (Tab. 7.4) nicht ALUOP_NOP ist, alle anliegenden Daten an A, B, OP und FLAGMASK in die internen Register. Anschließend wird die Berechnung gestartet. Diese dauert ???. Je nach Opcode werden gleichzeitig die Flags OVERFLOW und CARRY berechnet. Im Takt nach der eigentlichen Berechnung werden noch NEGATIVE und ZERO ermittelt und die Flags wiederum durch die FLAGMASK ausmaskiert, sodass nur die gewählten Flags geändert werden.

Tab. 7.1: Eingänge der ALU
Bezeichnung Breite Datentyp Eigenschaften Beschreibung
a 16 bit Daten Register Daten: Operand A für die arithmetische Berechnung
b 16 bit Daten Register Daten: Operand B für die arithmetische Berechnung
op 4 bit Steuerung Daten ALU Befehlscode
alu_go 1 bit Steuerung Signal Mithilfe dieses Signales wird die Recheneinheit aktiviert (enabled)

Tab. 7.2: Ausgänge der ALU
Bezeichnung Breite Datentyp Eigenschaften Beschreibung
result 16 bit Daten Tristate Ergebnis der Berechnung
flags 4 bit Status Register Flags (Tab. 7.3) für das Steuerwerk

Tab. 7.3: Statusflags der ALU
BezeichnungBeschreibung
OverflowMeldet einen Überlauf bei einer Berechnung mit vorzeichenbehafteten Integers.
Carry Signalisiert einen Überlauf bei einer Berechnung mit vorzeichenlosen Zahlen.
NegativDas Ergebnis ist negativ.
ZeroDas Ergebnis ist, unabhängig von der Berechnung, Null.

Tab. 7.4: Befehle der ALU
Bezeichnung Wert Parameter Flags Beschreibung
ALUOP_NOP 0- ---- Signalisiert der ALU, dass kein Befehl anliegt.
ALUOP_AND 1SU: A --NZBitweises Und
ALUOP_OR 2SU: A --NZBitweises Oder
ALUOP_NOT 3SU: A --NZBitweises Nicht
ALUOP_XOR 4SU: A --NZ Bitweises exklusives Oder
ALUOP_ADD 5SU: A, BOCNZ Addition zweier 16 bit Zahlen ohne Carry
ALUOP_SUB 6SU: A, BOCNZ Subtraktion ohne Carry
ALUOP_MULH7-U? A, BO-NZ*) Oberer Teil des Ergebnisses der Multiplikation einer vorzeichenlosen 16 bit Zahl
ALUOP_MULL8-U? A, BO-NZ*)Unterer Teil
ALUOP_DIV 9-U? A, BO-NZ*)Division
ALUOP_MOD A-U? A, BO-NZ*) Modulo, Rest der Division
ALUOP_NEG BS-: A O-NZ Umkehren des Vorzeichens
ALUOP_COMPCSU: A, BOCNZ Mithilfe dieses Befehles werden die Flags berechnet, als Ausgabe der ALU wird der Operand A durchgeschaltet
ALUOP_INC_A BSU: A --NZ Der Wert des Operanden A wird um eins erhöht
ALUOP_B BSU: B --NZ Der Wert des Operanden B wird unverändert zum Ausgang durchgeschaltet.
ALUOP_DEC_A BSU: A --NZ Der Wert des Operanden A wird um eins vermindert
SU Signalisiert, ob die Parameter der Berechnung vorzeichenbehaftet oder -los sein müssen.
OCNZ Welche Flags können von diesem Befehl auf eins gesetzt werden?
*) Das Overflow Flag repräsentiert hier nicht den klassischen Überlauf, da der in diesen Fällen nicht auftreten kann, sondern zeigt an, ob das Ergebnis des zugehörigen Befehls (MULH zu MULL, bzw. DIV zu MOD und umgekehrt) ungleich Null ist.
? Wir haben in diesen Fällen noch keine expliziten Überlegungen angestellt, inwieweit die Befehle sowohl mit vorzeichenbehafteten als auch -losen Integers korrekt rechnen können. Vermutlich funktionieren sie nur mit vorzeichenlosen.

8. Opcode in Alu-Operation umwandeln (opc_to_alu_op)

Diese Komponente (opc_to_alu_op) dient der Entlastung des Steuerwerkes. Durch die automatische Umsetzung von Opcodes, welche vom Instruction Register kommen und direkt in Alu-Operationen umgesetzt werden können, erspart man sich den umständlichen und zeitintensiven Weg über das Steuerwerk. Ein weiterer erreichter Optimierungsvorteil ist die Reduzierung der Steuerleitungen.
Diese Maßnahmen haben dazu geführt, dass alle Befehle, welche von der ALU berechnet werden (arithmetische Befehle), völlig identisch abgearbeitet werden können, was zu einer deutlichen Vereinfachung und Entlastung führt.

Tab. 8.1: Eingänge von opc_to_alu_op
Bezeichnung Breite Datentyp Beschreibung
opc 6 Bit Opcode Der am Eingang der Komponente anliegende Opcode aus dem Instruction Register

Tab. 8.2: Ausgänge von opc_to_alu_op
Bezeichnung Breite Datentyp Beschreibung
alu_op 4 Bit Opcode Aus dem am Eingang anliegenden Opcode wird ein für die ALU verwendbarer Operationsbefehl erzeugt, welcher dann am Ausgang alu_op anliegt.

9. Testumgebung

Die Assembler-Testprogamme in \ASM\ beschränken sich darauf, die korrekte Arbeitsweise für einige beispielhafte Fälle zu überprüfen:

10. Befehlssatz

Tab. 10.1: Befehlsformat Binär
Bits  15 14 13 12 11 10   9 8 7 6   5 4 3   2 1 0 
Feld OpcodeModeRegister ARegister B
Breite 6433


Tab. 10.2: Adressierungsarten Assembler
AdressierungFormatBeispiel
MAAdress (or identifier)LDA 55, LDA EMIL
MRLITReg # LiteralSHR R1 #3
MRAReg Adress (or identifier)MOV R2 55, MOV R2 EMIL
MRRReg RegAND R1 R2
MRRIReg (Reg)AND R1 (R2)

Bei unserer Implementierung haben wir die fünf oben aufgeführten, von uns unterstützten, Adressierungsarten (Tab. 10.2) gewählt. Ein Assemblerbefehl besteht also immer aus einem Parameter für die Bedingungen. Darauf folgt eine Adresse, Konstante oder die Bitmaske, die das Setzen der Flags kontrolliert.

Tab. 10.3: Befehlssatz
MnemonicKlasseCodeParameterBeschreibung
nop Steuerbefehle0 - Keine Operation
stop Steuerbefehle1 Bedingung Simulation beenden
jsr Steuerbefehle2 Bedingung Unterprogrammaufruf
ret Steuerbefehle3 Bedingung Rückkehr aus Unterprogramm
bra Steuerbefehle4 Bedingung, Sprungadresse Unbedingter Sprung
beq Steuerbefehle5 Bedingung, Sprungadresse Branch Equal
bgt Steuerbefehle6 Bedingung, Sprungadresse Branch Greater Than
blt Steuerbefehle7 Bedingung, Sprungadresse Branch Less Than
boo Steuerbefehle8 Bedingung, Sprungadresse Branch On Overflow
boc Steuerbefehle9 Bedingung, Sprungadresse Branch On Carry
add Arithmetische Befehle16Bedingung, Flag-Maske Addition
sub Arithmetische Befehle17Bedingung, Flag-Maske Subtraktion
multh Arithmetische Befehle18Bedingung, Flag-Maske Untere 16 Bit einer Multiplikation
multl Arithmetische Befehle19Bedingung, Flag-Maske Obere 16 Bit einer Multiplikation
div Arithmetische Befehle10Bedingung, Flag-Maske Division
mod Arithmetische Befehle21Bedingung, Flag-Maske Rechnen mit Rest (modulo)
neg Arithmetische Befehle22Bedingung, Flag-Maske Negation
comp Arithmetische Befehle23Bedingung, Flag-Maske Vergleich
nicht Logische Befehle32Bedingung, Flag-MaskeNegation
und Logische Befehle33Bedingung, Flag-MaskeUnd
oder Logische Befehle34Bedingung, Flag-MaskeOder
xoder Logische Befehle37Bedingung, Flag-MaskeEntweder Oder
load Transferbefehle48Bedingung, Flag-MaskeLaden in Register
store Transferbefehle49Bedingung, Flag-MaskeSchreiben in Register

Wir haben eine umfassende Palette von Befehlen erstellt (Tab. 10.3), wenn auch noch einige fehlen. Es existieren viele Stackbefehle, da beispielsweise ein DEL zum Löschen des obersten Stackdatums etwa 100 mal schneller ist, als ein Workaround mittels POP in den Speicher. Wir haben nur die nötigsten ALU-Befehle, auch wenn dies möglicherweise Gweschwindigkeitsverlust bedeutet. ALLE arithmetischen und logischen Befehle kann man nicht implementieren. Für Sprünge konnten wir aus auf drei Befehle beschränken, da Bedingungen ja bereits berücksichtigt sind und relative Sprünge aufgrund des Befehlsformats (eine Adresse ist immer als zweites 16 bit Wort kodiert) nicht sinnvoll sind.

11. Optimierungen

Wie es schon in der Einleitung erwähnt wurde, haben wir teilweise die Steueraufgaben im Operationswerk erledigt. Als weitere Optimierungsmaßnahme haben wir auf Grund von der Analyse, die wir durchgeführt haben, Zustände, die zusammengefügt werden können, zusammengebaut. Das hat uns erlaubt, das ganze Struktur zu vereinfachen. Da wir unsere Komponenten direkt miteinander verbunden haben, haben wir hier einen großen Grad an Parallelität gewonnen. Ferner wird bei uns Prefetch realisiert, indem in manchen Zustände schon Steuersignale für die nächsten Zustände vorbereitet werden und PC Weiterschaltung erfolgt.

12. Weitere Verbesserungen

Eine sicherlich sehr effektive Massnahme wäre die Verwendung von Caches. Der groesste Engpass in unserer CPU ist der Speicher. Bei der Abarbeitung von Befehlen wird der grossteil der Zeit damit verbracht auf den Speicher zu warten. Deswegen ist dadurch ein hoher Grad an Beschleunigung zu erwarten. Allerdings erfordert die Verwendung von Caches einige Modifikationen des Steuerwerks. Im jetzigen Steuerwerk sind feste Wartezustaende fuer den Speicher vorgesehen. Ein Cache ohne Anpassung des Steuerwerks wuerde hier keine Beschleunigung bringen.
Mit eingebauten Caches wuerde auch eine Pipeline wieder Beschleunigung bringen. Mit der jetzigen Architekur (ohne Cache) ist die Parallelitaet nahezu ausgereizt. Weiterhin koennte man noch den Befehlssatz ausbauen und weitere Adressierungsarten unterstuetzen. Dadurch wuerde sich die Codegroesse signifikant verringern und dadurch zu einem besseren Durchsatz fuehren.

13. Prozessor Benchmarks

Sortieren von 15 vorzeichenbehafteten Zahlen : 408960
rekursive Berechnung der Summe der Zahlen von 1..100 : 291950
Ermittlung des GGT nach Euklid (1482, 646) : 18660

14. Feedback zum PeP

Als Tipp koennen wir nachfolgenden Generationen empfehlen den mitgelieferten Assembler von Anfang an zu benutzen. Kritik moechten wir an dem Tool "Verilogger" ueben. Die 1000 Zeilenbeschraenkung ist sehr stoerend und auch die Pruefung der Syntax ist mangelhaft. Hier waere ein besseres Tool wuenschenswert.

A. Terminologie

In den Tabellen über Signalleitungen verwenden wir diverse Bezeichnungen zur Charakterisierung der Interface-Eigenschaften. So beschreibt der Datentyp Für die Eigenschaft eines Interfaces bedeutet

B. Abbildungen

Abb. 2.1: Layout der CPU als Bild
Abb. 2.1: Layout der CPU als PDF-Datei

C. Tabellen

Tab. 3.1: Eingänge des Steuerwerks
Tab. 3.2: Ausgänge des Steuerwerks
Tab. 4.1: Eingänge des Registers
Tab. 4.2: Ausgänge des Registers
Tab. 5.1: Eingänge des Registersatzes
Tab. 5.2: Ausgänge des Registersatzes
Tab. 7.1: Eingänge der ALU
Tab. 7.2: Ausgänge der ALU
Tab. 7.3: Statusflags der ALU
Tab. 7.4: Befehle der ALU
Tab. 8.1: Eingänge von opc_to_alu_op
Tab. 8.2: Ausgänge von opc_to_alu_op
Tab. 10.1: Befehlsformat Binär
Tab. 10.2: Befehlsformat Assembler
Tab. 10.3: Befehlssatz