Hochschule Bremen University of Applied Sciences Projektbericht

Werbung
Hochschule Bremen
University of Applied Sciences
Projektbericht
Titel:
Implementierung eines
Single Instruction Computers in VHDL
Autor:
Roul Oldenburger
Zeitraum:
Wintersemester 2001/2002
Projektleitung:
Prof. Dr. Thomas Risse
Prof. Dr. Sven Simon
Projektbericht
Single Instruction Computer
Inhaltsverzeichnis
1.
2.
3.
Einleitung ............................................................................3
Projektaufgabe und –ziel ...................................................5
Technischer Hintergrund und Kontext ............................5
3.1
3.2
3.3
4.
5.
Grundlagen zum SIC .................................................................... 5
Hardware........................................................................................ 7
Software.......................................................................................... 8
Vorgehensweise...................................................................9
Der Single Instruction Computer......................................9
5.1
5.2
5.3
5.4
6.
Blockschaltbild............................................................................. 12
Beschreibung in VHDL............................................................... 13
Programme in SBN ..................................................................... 16
Daten für Programme in SBN.................................................... 18
Simulation und Test des SIC ...........................................19
6.1
7.
Testbench...................................................................................... 19
SBN Assembler .................................................................22
7.1
7.2
7.3
8.
Übersetzungs-Hierarchie ............................................................ 22
Pseudo-Befehle............................................................................. 25
Konzept für einen Assembler in Perl......................................... 26
Ergebnisse und Diskussion ..............................................28
8.1
8.2
Zusammenfassung ....................................................................... 29
Letzter Stand................................................................................ 30
9. Ausblick.............................................................................31
10. Kurzanleitung ...................................................................33
10.1
10.2
10.3
10.4
10.5
WebPACK Projekt Manager.................................................. 33
ModelSim Simulator................................................................ 35
Pin-Zuweisung / UCF-Editor .................................................. 36
Download auf das FPGA ......................................................... 37
Anwendung des Assemblers.................................................... 39
11. Bibliographie und Referenzen.........................................40
11.1
11.2
11.3
Bücher ....................................................................................... 40
Webseiten.................................................................................. 40
Andere Quellen......................................................................... 40
Anhang .......................................................................................41
Verwendete Hardware und Software .................................................. 41
Synthese- / Compiler-Berichte in Auszügen........................................ 41
Inhalt des Projektverzeichnisses „Projekt_SIC“................................ 44
VHDL Quellcode des SIC ..................................................................... 47
VHDL Quellcode der Testbench .......................................................... 51
Perl Quellcode des „Assemblers“ ......................................................... 53
-2-
Projektbericht
Single Instruction Computer
1. Einleitung
Seit der Entwicklung der ersten praktikablen Computer auf einem Chip liegen die
Hersteller und Designer im Wettstreit um die CPU mit der besten Performance. Die
Komplexität dieser Prozessoren stieg enorm an. Immer mehr Instruktionen für teilweise
sehr spezielle Aufgaben und verschiedenste Adressierungsmodi wurden angeboten, um
hochsprachlichen Konstrukten möglichst nahe zu kommen und damit z.B. bestimmte
Datenstrukturen, Schleifen und Funktionsaufrufe möglich zu machen. Umfangreiche
und komplexere Anwendungen sind in einer Hochsprache leichter umzusetzen als in
einer, nur ein Dutzend Instruktionen umfassenden, Maschinensprache.
In den 80’er Jahren wurden jedoch Stimmen laut, die die Meinung vertraten, eine auf
wesentliche Instruktionen beschränkte Architektur könne bei gleichen oder gar
geringerem Hardwareaufwand genauso leistungsfähig sein wie hochkomplexe
Architekturen. Solche Computer nennt man „Reduced Instruction Set Computer“
(RISC), ihre Counterparts hingegen „Complex Instruction Set Computer“ (CISC).
Viele zum Teil „überspezialisierte“ Instruktionen lassen sich durch Sequenzen von einer
oder mehreren einfachen Anweisungen ersetzen. Der dadurch in der ProzessorArchitektur eingesparte Platz kann z.B. für breitere Bussysteme oder mehr CacheSpeicher verwendet werden. Diese einfachen Anweisungen sind kürzer und nicht so
aufwendig zu dekodieren und damit wesentlich schneller abgearbeitet. Die Architekten
entdeckten, dass sie mit einfachen RISC-Architekturen hochoptimierte Prozessoren mit
sehr hohen Taktraten bauen konnten.
Compiler-Bauer sehen diese Entwicklung zunächst unter dem Aspekt, dass das
Programmieren wieder aufwändiger und unbequemer wird, denn die hochsprachlichen
Konstrukte müssen nun wieder durch eine Reihe von nicht komplexen Instruktionen
ersetzt werden. Dass sich RISC-Architekturen dennoch erfolgreich bewähren konnten,
lag zum Teil daran, dass die Entwicklung von Hochsprachen und deren Compiler stark
voran geschritten war und sich damit das Problem, (unbequem und aufwändig) in
Maschinensprache für eine RISC-Architektur zu programmieren, erübrigte.
Heutzutage gibt es jedoch Punkte, an denen die Philosophien miteinander verschmelzen
und es schwer wird, einen Prozessor klar als RISC oder CISC einzuordnen. Neben der
gängigen Charakterisierung eines RISC-Prozessors mit fixem Instruktions-Format,
einfachem Load-Store-Befehlssatz, festverdrahteter Ablaufsteuerung (kein MikroProgramm) und intensivem Einsatz von Pipelining, gibt es Vorschläge diese anders zu
definieren. Da es z.B. RISC-Prozessoren gibt, die für ihre Gleitkomma-Arithmetik doch
auch wieder mikro-programmiert sind, schlägt Giloi die Bezeichnung Pipeline-SkalarProzessor vor [RSTSK].
Wie weit kann nun der Befehlssatz eines Prozessors reduziert werden ohne die
Funktionalität zu beschränken? Könnte ein Prozessor mit so wenigen Instruktionen wie
möglich, bei einer entsprechenden Taktung, nicht genauso leistungsfähig aber
kostengünstiger sein als eine ausgereifte CISC-CPU?
-3-
Projektbericht
Single Instruction Computer
Diese und ähnliche Fragen entstehen, wenn man sich die Vorteile, die RISCArchitekturen haben und damit wirtschaftlich und wissenschaftlich interessant machen,
vor Augen führt.
Theoretisch ist es möglich, einen Computer zu entwerfen, der nur eine einzige
Instruktion hat und dennoch alle grundlegenden Operationen ausführen kann, die ein
„normaler“ Computer auch ausführt. Wie soll diese alleskönnende Anweisung
aussehen? Immerhin muss der Computer grundlegende arithmetische und logische
Funktionen ausführen, Daten im Speicher transportieren und den Verlauf eines
Programms kontrollieren können. Es ist schwer sich vorzustellen, dass all dies durch
eine einzige Anweisung möglich sein soll.
Eine solche Instruktion ist die SBN-Anweisung. SBN steht für „Subtract and Branch if
Negative“. Sie ist üblicherweise aus drei Argumenten aufgebaut, die allesamt Wörter im
Speicher adressieren. Die an den ersten beiden Adressen enthaltenen Werte werden
voneinander subtrahiert und sollte dass Ergebnis negativ sein wird das Programm an der
dritten angegebenen Adresse, sonst an der nächstfolgenden Adresse fortgesetzt.
Die Anweisung
SBN A, B, C
Wie sie ausgeführt wird
Mem[A] := Mem[A] – Mem[B]
if (Mem[A] < 0) then
PC := C
else
PC := PC + 1
Wie oben beschrieben (s. [NOSIC]), basiert das System auf der grundsätzlichen
Verlagerung der Intelligenz in Assembler und Compiler. Wo sonst ein hochentwickelter
Compiler die hochsprachlichen Programmanweisungen z.B. eines C++ Programms in
die verschiedenen komplexen Instruktionen eines Computers übersetzt und nach
Möglichkeit optimiert, muss hier zunächst ein Assembler eingesetzt werden, der diese
Maschinensprachen-Befehle (Kap. 7.2 Pseudo-Befehle) in Konstrukte aus SBNAnweisungen übersetzt. Ein beliebtes Beispiel ist die MOVE- oder COPY-Anweisung,
durch die der Inhalt einer Adresse im Speicher in eine andere kopiert wird:
oder
MOV B, A
CP B, A
ADD $B, $0, $A
sind Beispiele für Anweisungen, die bewirken,
dass der Inhalt der Adresse oder des Registers A
nach B kopiert wird.
Ein entsprechendes SBN-Konstrukt könnte z.B. so aussehen [NOSIC]:
start:
SBN
T, T, .+1
SBN
SBN
SBN
T, A, .+1
B, B, .+1
B, T, .+1
# Mem[T] := Mem[T] – Mem[T] also wird
# Mem[T] := 0 gesetzt
# Mem[T] := 0 – Mem[A] = –Mem[A]
# wie oben Mem[B] wird = 0 gesetzt
# Mem[B] := 0 – Mem[T] = - - Mem[A] =Mem[A]
Hierbei meint die Notation „ .+1“ die jeweils nächste Adresse; der PC wird in jedem
Fall inkrementiert. Somit ist also in Folge dieser vier SBN Anweisungen der Inhalt der
Adresse A nach Adresse B kopiert worden. [THSIC] [URISC] [NOSIC]
-4-
Projektbericht
Single Instruction Computer
2. Projektaufgabe und –ziel
Unter den in der Einleitung genannten Aspekten, erscheint der SIC (Single Instruction
Computers) als eine interessante Prozessor-Architektur. Daher soll diese im Rahmen
des RST-Labors näher untersucht und Versuche damit durchgeführt werden.
Das Ziel dieses Projektes ist es, den Studenten und anderen Interessierten die
Möglichkeit zu geben, am live existierenden Versuchsaufbau, Tests und
Untersuchungen an einem SIC durchzuführen.
Dafür ist angedacht, eine „Experimentier-Umgebung“ des Digitaltechnik-Labors zu
nutzen, den SIC in VHDL zu realisieren und auf einem FPGA (Field Programmable
Gate Array) „unterzubringen“. Ferner soll eine Entwicklungsumgebung entstehen, die
das Programmieren des SIC in einer geeigneten Maschinensprache ermöglicht. Dazu ist
ein Assembler notwendig, der die „komplexen“ Assembler-Anweisungen in Folgen und
Kombinationen von SBN-Anweisungen übersetzt. Um volle Funktionalität des SIC zu
erreichen, gilt es, möglichst für alle anzuwendenden Assembler-Anweisungen
entsprechende Konstrukte zu finden.
Es ist wünschenswert die „Experimentier-Umgebung“ des Digitaltechnik-Labors so
nutzen, dass das FPGA wie eine übliche CPU auf Programme und Daten aus dem
externen (nicht im FPGA angelegten) Speicher zugreift und die Daten bzw. der
Datenspeicher nach Ablauf des Programms auslesbar ist. Dazu ist auch die Verwendung
der auf dem Experimentier-Bord vorhandenen Schnittstellen und dazugehöriger Einund Ausgabegeräte möglich.
Die Entwicklungsumgebung könnte in einem ausgebauten Zustand einen
Hochsprachen-Compiler samt Debugger und Assembler unter einer grafischen
Oberfläche umfassen und somit das Programmieren des SIC z.B. in PASCAL
ermöglichen.
Die Aufgabe dieser Arbeit ist es, eine Grundlage für das oben beschriebene Projektziel
zu geben und ein System soweit vorzubereiten, dass erste Versuche mit einem SIC
möglich sind und damit der Zyklus „programmiern-synthetisieren-simulierendownladen-testen“ wenigstens einmal erfolgreich durchlaufen und dokumentiert wird.
3. Technischer Hintergrund und Kontext
3.1 Grundlagen zum SIC
Die Prozessor-Architektur des SIC benötigt nur wenige der sonst üblichen
Komponenten eines Prozessors. Zunächst wird nur ein Register benötigt. Dies ist der
Programmzähler (PC). Die sonst übliche ALU (Arithmetic Logic Unit) wird auf die
Fähigkeit 2’er-Komplemente bilden und addieren zu können beschränkt. Je nach Art der
Umsetzung könnte dies z.B. einen Carry-Ripple-Adder enthalten; ohne dies jedoch
konkret festzulegen, wird das von der Synthese-Software bestimmt. Außerdem werden
ein Programm- und ein Datenspeicher benötigt, deren Größe und Breite zunächst durch
den verwendeten FPGA-Baustein begrenzt und durch das verwendete Befehlsformat,
-5-
Projektbericht
Single Instruction Computer
sowie den zugelassenen Wertebereich festgelegt werden. Schlussendlich wird eine
Steuereinheit benötigt, die den Programmcode auswertet und dementsprechend über die
Wahl der Adressen und die Änderung des Programmzählers bestimmt.
Befehlssatz:
Da der Befehlssatz des SIC nur aus der SBN Anweisung besteht, legt diese auch die
Prozessor-Architektur weitgehend fest. Es werden keine Stacks zur Abarbeitung der
Programme oder ein dediziertes Register (Akkumulator) eingesetzt. Die Operation wird
direkt auf den verwendeten Adressen ausgeführt und solange nur FPGA-interner
Speicher verwendet wird, ist der Zugriff auf den Speicher mit dem auf einem Feld von
Registern vergleichbar.
Da es nur einen Befehl gibt, braucht dieser auch nicht durch einen OP-Code kodiert zu
werden. Was also von dem in der Einleitung vorgestellten SBN Befehl bleibt, sind die
drei absoluten Speicheradressen. Dementsprechend wird eine Anweisung aus der
dreifachen Anzahl an Bits bestehen, die nötig sind, um den gewünschten
Speicherbereich zu adressieren. Dies kann unter Umständen bei einem großen Speicher
zu einer sehr breiten Anweisung führen und dementsprechend viel Programmspeicher
benötigen. Ob jedoch die Sprungadresse absolut oder relativ angegeben wird, bedeutet
für die Hardware keinen großen Unterschied. Die Befehlsbreite verringert sich und
könnte damit zu Einsparungen an Programmspeicher führen, allerdings wird ein
entsprechender Addierer benötigt, der den Programmzähler um mehr als 1 erhöhen
kann. Auf der anderen Seite bedeutet dies einen Mehraufwand für den Assembler. Die
tatsächliche Adresse nach einem Sprung ist explizit zu ermitteln und bei Zielen, die
außerhalb der Sprungweite liegen, muss das Programm um entsprechend viele SBN
Anweisungen erweitert werden. Dies führt natürlich wieder zu einem Mehrbedarf an
Speicherplatz und einem eventuell erheblich höheren Zeitbedarf für die Ausführung
eines weiten relativen Sprunges im Gegensatz zu einem weiten absoluten Sprung.
Dennoch ist der SBN Befehl zunächst mit einer relativen Sprungweite als drittem
Argument implementiert.
Datenpfad:
Als erstes Element bestimmt der Inhalt des Programmzählers die Adresse der aktuellen
Anweisung im Programmspeicher. Die ersten beiden Argumente der Instruktion
enthalten die Adressen der beiden Operanden im Datenspeicher, das dritte Argument
enthält die relative Sprungweite. Die Inhalte der beiden angegebenen Adressen im
Datenspeicher werden voneinander subtrahiert. Das Ergebnis wird an die erste
angegebene Adresse zurückgeschrieben und bestimmt, ob der Wert des
Programmzählers inkrementiert oder ihm die relative Sprungweite hinzu addiert werden
soll. Der aktuelle Wert des Programmzählers und eine 1 oder die relative Sprungweite
werden dazu auf einen Addierer gegeben. Es sind Sprünge in beide Richtungen
möglich, daher wird die Sprungweite im 2’er Komplement angegeben.
Steuerung:
Die voneinander zu subtrahierenden Operanden sind aus dem Datenspeicher zu
entnehmen. Dazu müssen zunächst ihre Adressen ermittelt und diese abgefragt werden.
Die ersten beiden Argumente der SBN Anweisungen können hierbei direkt zur
Adressierung des Datenspeichers dienen. Sie bilden also zusammen mit der
-6-
Projektbericht
Single Instruction Computer
Ansteuerung des Speichers die erste Komponente der Steuereinheit. Die Operanden
werden auf einen Subtrahierer gegeben und die Differenz gebildet. Liegt die Differenz
im 2’er Komplement vor, so gibt das MSB (Most Significant Bit) an, ob das Ergebnis
negativ oder positiv ist. Somit kann das MSB direkt als Steuerbit eingesetzt werden und
bestimmen, ob der Programmzähler inkrementiert oder ihm die Sprungweite
hinzuaddiert wird.
Speicher-Aufbau und –Zugriff:
Daten- und Programmspeicher werden als zwei voneinander getrennte Speicher
behandelt. Dies ermöglicht eine flexiblere Handhabung und Nutzung des insgesamt
vorhandenen Speichers, da Befehlswort- und Datenwortbreiten unabhängig voneinander
sind. Wie oben im Abschnitt „Befehlssatz“ beschrieben, sind die SBN Anweisungen mit
zwei oder drei Adress-Argumenten stark adressorientiert. Ihre Breite bestimmt sich
letztlich aus dem verwendeten Adressbereich und der dazu notwendigen Anzahl an Bits.
Die Breite des Datenspeichers hingegen richtet sich nach dem für die Operanden
verwendetem Zahlenbereich.
Die tatsächliche Implementierung der Speicher dieses SIC ist jedoch zunächst anders
gewählt (ab Kap. 5.1). Das Programm wird als festverdrahtete Logik implementiert und
bietet damit zeitliche Vorteile. Dies entspricht aber nicht der Zielvorstellung eines
Programmspeichers, der bei laufendem Betrieb mit unterschiedlichen Programmen
geladen und abgearbeitet werden kann. Es ist jedoch zunächst die praktikabelste
Lösung, da es sich einfacher handhaben lässt.
Zunächst werden Programm- und Datenspeicher direkt auf dem FPGA angelegt.
Dementsprechend richtet sich der Speicherumfang nach dem verwendeten Baustein und
der Größe der durch die SIC-Schaltung belegten Chipfläche. Näheres zu den Daten des
verwendeten Spartan2 Chips von Xilinx ist in der Dokumentation im Projektverzeichnis
../Andere_Quellen/Spartan_FPGA_Doku zu finden.
Üblicherweise werden Speicher immer byte- oder wortweise angesprochen und sind
dahingehend organisiert und optimiert. Innerhalb eines FPGAs gibt es hier keine
Vorgaben. Grenzen sind nur durch die verwendete Hardware gegeben. Speicher ließe
sich bitweise aufbauen und ansteuern oder aber in beliebiger Anzahl von Bits.
Hierarchische Speicherstrukturen sind möglich, ebenso wie einfach organisierter
Speicher. Eine einfache Lösung ist es zum Beispiel, die Speicher als Felder von
Bitvektoren aufzubauen, deren Breite der benötigten Befehlswortbreite oder dem
benötigten Wertebereich entspricht.
Wenn zu einem späteren Zeitpunkt externer Speicher verwendet wird, sind diese
Parameter möglicherweise an diesen anzupassen und der interne Speicher könnte zu
einem Cache umfunktioniert werden.
3.2 Hardware
Als Hardware-Basis dient ein „FPGA Prototyping Kit“ der Firma Burch Electronic
Designs. Dieses umfasst zunächst ein Experimentier-Bord (eine Platine) zusammen mit
einem FPGA Chip Spartan2 der Firma Xilinx. Das FPGA (Field Programmable Gate
Array) ist ein hochintegrierter Baustein auf Siliziumbasis und besteht aus einer großen
-7-
Projektbericht
Single Instruction Computer
Anzahl gleichmäßig angeordneter, universeller elektronischer Schaltungsblöcke. Diese
Schaltungsblöcke können viele verschiedene Funktionen übernehmen. Je nachdem wie
sie miteinander verbunden werden und welche Anschlüsse von ihnen genutzt werden,
können sie zu den verschiedenen Formen von Flip-Flops und Logik-Gattern
konfiguriert werden. Die Kombination vieler solcher konfigurierter Blöcke können
komplizierte Schaltungen nachbilden. Die Blöcke sind durch ein umfassendes Netzwerk
an Leitungen über den ganzen Baustein hinweg miteinander verbunden. Teile dieses
Netzwerkes können als Busse ausgelegt werden. Auf jeden Fall aber verbinden sie die
einzelnen Blöcke untereinander und mit den Anschlusspins des FPGAs.
Da FPGAs frei programmierbar sind, bieten sie für eine Vielzahl von Anwendungen
innerhalb von digitalen Schaltungen im experimentellen Bereich und in der Lehre eine
kostengünstige und flexible Lösung. Sie können in Massen produziert werden, ohne
dass vorher etwas über ihre spätere Verwendung bekannt sein muss und gleichzeitig
bieten sie die Möglichkeit, eigene, ganz spezielle Designs umzusetzen. Durch den
Einsatz von FPGAs wird die Entwicklung sogenannter 1-Offs wesentlich
kostengünstiger. Die Datenblätter zu dem verwendeten Baustein sind unter
../Andere_Quellen/Spartan_FPGA_Doku zu finden.
Ähnlich wie Speicherbausteine (RAM) verlieren FPGAs ihre Programmierung nach
dem Abschalten oder Verlust der Versorgungsspannung. Damit erübrigt sich einerseits
ein spezieller Löschvorgang, allerdings kommen sie dadurch auch nicht für jede
Anwendung in Frage. Speziell diese Eigenschaft macht es notwendig, das FPGA in der
Experimentier-Umgebung bei jeder Änderung des SIC-Programms oder Veränderung
am SIC neu zu programmieren.
Um gerade für den experimentellen Bereich und die Lehre eine vielseitige und leicht zu
nutzende Umgebung zu bieten, gibt es für das Experimentier-Bord, das mit
herausgeführten Anschlüssen und Schnittstellen versehen ist, eine Reihe von
Zusatzplatinen. Diese bieten z.B. externen Speicher, 7-Segment-Anzeigen und eine
Reihe LEDs (Light Emitting Diodes). Sie können leicht über die dafür vorgesehenen
Anschlüsse und Flachbandkabel mit der Hauptplatine verbunden werden.
Abbildungen und nähere Angaben sind im Projektverzeichnis unter
.../SpartanBoardPläne/Burch Electronic Designs.htm oder aktuell unter der
angegebenen Quelle [BURSB] zu finden.
3.3 Software
Die Firma Xilinx bietet zur Entwicklung digitaler Schaltungen und zum Programmieren
ihrer FPGA eigens Software an. Das Argument der Kundenbindung hat die größeren
Hersteller von digitalen Schaltkreisen dazu veranlasst, selber Software anzubieten, die
auf ihre Produkte optimiert oder nur für ihre Produkte nutzbar sind. Die in diesem Fall
verwendete Software „WebPACK“ stellt eine komplette Entwicklungsumgebung dar.
Sie unterstützt die Entwicklung digitaler Schaltungen in VHDL (VHSIC Hardware
Description Language – Very High Speed Integrated Circuit) oder Verilog für eine
bestimmte Auswahl an Xilinx Produkten. VHDL und Verilog sind Hardware
Beschreibungssprachen. Sie sind sich in vielen Elementen mit höheren
Programmiersprachen ähnlich, haben aber den entscheidenden Unterschied , dass die
Beschreibung wirklich gleichzeitig ablaufender Aktionen nicht nur möglich sondern
-8-
Projektbericht
Single Instruction Computer
grundlegendes Element ist. Die Entwicklungsumgebung bietet eine Vielzahl an in die
Oberfläche eingebundenen Werkzeugen an, von denen hier nur beispielhaft
Formatumwandler, Routing-Tools und vor allem ein Simulator (ModelSim) genannt
werden. Wesentlich sind: Der Editor zum Schreiben der Programme in den HDLs, der
Compiler zum Übersetzen des Programmcodes, der Debugger zum Prüfen des
Programms auf seine Korrektheit und ein Programm zur Erzeugung der FPGAProgrammier-Datei, die letztlich in den Baustein geladen wird. Alle diese Komponenten
sind unter einem Projektmanagement zusammengefasst.
Dieses sehr umfangreiche Software-Paket steht auf der Xilinx Homepage
www.xilinx.com frei zum Download zur Verfügung. Die innerhalb dieses Projektes
verwendeten Versionen sind im Projektverzeichnis unter ../Software/ zu finden.
4. Vorgehensweise
An dieser Stelle soll kurz die Vorgehensweise zu Bearbeitung dieses Projektes
beschrieben werden. Der Ablauf entspricht dabei grob der angegebenen Reihenfolge.
Teilweise können Aufgaben oder Vorhaben aber auch parallel zu anderen stattfinden.
1. Hintergrundwissen verschaffen bzw. auffrischen
a. SIC, Prozessor-Architekturen
b. VHDL
c. Verwendete Hard- und Software
d. Perl
2. Einarbeitung in die verwendeten Werkzeuge
a. WebPACK (4.0 / 4.1)
b. ModelSim (5.1 / 5.5)
c. ActivePerl (5.6 für Windows)
3. Funktionsweise der SBN Anweisung klären, festlegen
4. Datenpfad und Steuerung zur Umsetzung der SBN Anweisung entwickeln
5. Umsetzung in VHDL – dazu Tests und Simulation des SIC mit ModelSim
6. Test auf dem Experimentier-Bord
7. Entwicklung eines Konzepts für einen Assembler
8. Erste Umsetzung eines Assemblers für einen SIC in Perl
9. Test des erstellten Codes
10. Test des assemblierten Codes in der Entwicklungsumgebung und dem Simulator
11. Test auf dem Experimentier-Bord
5. Der Single Instruction Computer
Die Art und Weise, in der der SIC implementiert wird, lässt die Darstellung des Ablaufs
in Form eines Ablaufdiagramms als nicht sinnvoll erscheinen. Insbesondere ist hierfür
die Umsetzung des Programmcodes (SBN Anweisungen) in ein Schaltnetz
verantwortlich. Dieses Schaltnetz (Logik) erhält als Eingangssignal den Wert des
Programmzählers und liefert die entsprechende SBN Anweisung in Form eines BitVektors zurück. Die Auswertung definierter Bereiche dieses Vektors ergibt dann wieder
die drei Argumente der SBN Anweisung. Die oberen zwei Bereiche dieses Vektors
liefern die Adressen (Steuersignale A, B) im Datenspeicher, die zur Ansteuerung der
-9-
Projektbericht
Single Instruction Computer
Multiplexer A und B dienen. Sie wählen in dem vorhandenen Adressbereich die
gewünschten Speicheradressen aus und schalten ihre Inhalte (die Operanden) auf den
Subtrahierer. Dort wird die Differenz gebildet und an die erste Quelladresse gelegt. Zur
darauffolgenden Taktflanke (Schaltwerk) wird das Ergebnis zurückgeschrieben. Im
selben Moment entscheidet das MSB des Ergebnisses (Steuersignal) darüber ob der
Programmzähler inkrementiert wird oder ihm das dritte Argument (Sprungweite C)
hinzuaddiert wird. Dieses Steuersignal wird von dem dritten Multiplexer ausgewertet,
der je nach Wert des MSB einen zweiten Summanden (1 ⇒ C wird addiert, 0 ⇒ 1 wird
addiert) auf den Addierer schaltet. Das Ergebnis dieser Addition wird zur selben
Taktflanke in den PC geschrieben, wie das Ergebnis der Subtraktion in das
entsprechende Quellregister geschrieben wird. Das folgende Prinzip-Schaltbild soll den
Zusammenhang zwischen Schaltnetz und Schaltwerk verdeutlichen. Als Bezug darauf
sind die Komponenten des Schaltwerkes (Flip-Flops) im Blockschaltbild mit „Register“
bezeichnet.
X (Mealy)
PCn
PCn
SN
X’ (Mealy)
PCn+1
SW
PCn+1
Takt
Abbildung 1: Mealy- und Moore-Signale an einem Schaltnetz
Abbildung 1 zeigt, dass die Schaltung insgesamt aus einem Schaltnetz (SN) und einem
Schaltwerk (SW) aufgebaut ist. Der wesentliche Unterschied zeigt sich in den Ein- und
Ausgangssignalen. Während Mealy-Ausgangssignale eines Schaltnetzes (X’) nur
abhängig sind von den Eingangssignalen des Schaltnetzes und dessen Funktion, sind
Moore-Ausgangssignale (PCn+1) zusätzlich abhängig von dem Taktsignal, das an dem
Schaltwerk anliegt. Das Mealy-Ausgangssignal stellt sich ohne Zeitverzögerung durch
den Takt ein. Moore-Ausgangssignale erfahren erst mit dem Takt eine Änderung. Die
im Schaltwerk enthaltenen Flip-Flops ändern ihre Zustände in Abhängigkeit vom
Moore-Ausgangssignal (PCn+1) des Schaltnetzes erst zum nächsten Taktzyklus.
- 10 -
Projektbericht
Single Instruction Computer
Bezogen auf den SIC, beschreibt Abbildung 2 den Zusammenhang. Der Wert (Zustand)
des Programmzählers (PC) und der Wert des Datenspeichers (Quelladresse A) sind die
einzigen Moore-Signale. Während alle anderen Signale abzüglich ihrer Laufzeiten
sofort zur Verfügung stehen, bekommen der Programmzähler und der Datenspeicher
erst mit dem nächsten Takt ihre neuen Werte zugeschrieben.
MSB
1
PCn
a
b
C
SN
(a-b)=Diff= a n+1
PCn+1
A
B
C
SW
Takt
Abbildung 2: Mealy- und Moore-Signale im SIC
- 11 -
PCn
a
b
Projektbericht
Single Instruction Computer
5.1 Blockschaltbild
Die Signale A, B und C sind farblich gestaltet worden, damit nicht der Eindruck
entsteht, sie wäre mit einander verbunden oder würden sich tatsächlich auf diese Weise
kreuzen. „...“ in der Darstellung der Speicher soll andeuten, dass weitere Abschnitte
oder Register vorhanden sein können, die hier nicht dargestellt sind.
- 12 -
Projektbericht
Single Instruction Computer
5.2 Beschreibung in VHDL
Der vollständige Code, zur Beschreibung dieses SIC in VHDL, ist im Anhang zu
finden. Die Quelldatei befindet sich im Projektverzeichnis unter .../Software/ .
Zunächst drei allgemeine Hinweise: Die Verwendung des Datentyps „STD_ULOGIC“
bzw. „STD_ULOGIC_VECTOR“ ist wann immer möglich vorzuziehen, da dieser
aufgrund seiner Struktur Kurzschlüsse und damit die Zerstörung der verwendeten
Hardware unter Umständen verhindern kann. VHDL ist strikt typisiert, d.h. es werden
keine Typumwandlungen oder Anpassungen automatisch oder auf Verdacht
vorgenommen. Des weiteren sei zur Wahl der Namensgebung gesagt, das die Endungen
_s für Signale, _o für Ausgangssignale, _i für Eingangssignale und _c für Konstanten
verwendet werden.
Allgemein ist die Struktur der VHDL Dateien wie folgt aufgebaut:
Einleitend findet sich ein Programmkopf bestehend aus Kommentaren. Kommentare
werden in VHDL grundsätzlich durch „--" einen doppelten Bindestrich eingeleitet und
reichen dann bis zum Ende der Zeile. Als nächstes finden sich Hinweise und
Anweisungen zum Verwenden von Bibliotheken (LIBRARY, USE) und vordefinierter
Komponenten. Daraufhin beginnt der eigentliche Inhalt der VHDL Datei mit der
„ENTITY“. Sie beschreibt wie die Schaltung von außen her „aussieht“ und was für Einund Ausgänge sie hat. Das eigentliche Innenleben und die tatsächliche Funktionsweise
der Schaltung wird dann unter „ARCHITECTURE“ beschrieben.
Wenn man sich vor Augen führt, dass ein Schaltnetz, das irgendwelche logischen
Funktionen enthält, diese im Prinzip ohne Verzögerung ausführt (abgesehen von den
Laufzeiten der elektrischen Signale), dann muss es einen Bereich innerhalb des VHDL
Codes geben, in dem die Reihenfolge, in der die Beschreibung steht keinen Einfluss auf
die Abarbeitung dieser Logik hat. In der Regel ist man es gewohnt Programme in
sequentieller Weise zu durchdenken und zu beschreiben. Da man hier aber auf die
direkte Beschreibung der Hardware abzielt, muss hier anders vorgegangen werden.
Als „Concurrent Statements“ werden zunächst alle in der Architecture angegebenen
Beschreibungen betrachtet und später im Prinzip gleichzeitig ausgeführt. Um nun
dennoch sequentielle Abläufe beschreiben zu können gibt es den „PROCESS“. Prozesse
sind selber insgesamt ein „Concurrent Statement“, dennoch wird die innerhalb eines
Prozesses beschriebene Funktion sequentiell abgearbeitet.
- 13 -
Projektbericht
Single Instruction Computer
Im Folgenden werden die wichtigsten Komponenten des SIC anhand des VHDL Codes
erläutert:
-- SBN Anweisungen im Programmspeicher
CONSTANT Program : Program_type := Program_type'(
"00111001110001", --> 1
"00111001010001", --> 2
"00011000110001", --> 3
"00011001110001", --> 4
"00111001110001", --> 5
"00111001100001", --> 6
"00100001000001", --> 7
"00100001110001", --> 8
"00001000100000" --> 9
);
Der komplette SBN-Programmcode ist als konstante innerhalb der Architecture
angelegt. Das heißt zunächst, dass während des Betriebes keine Veränderungen an dem
Programm vorgenommen werden können. Um ein Programm auf diese Weise angeben
zu können, ist die Konstante als ein Feld von Bitvektoren definiert. Näheres zur
Interpretation dieser Vektoren im Abschnitt 5.3 . Wichtig ist zunächst, dass diese
Konstante in keiner Abhängigkeit zu einem Taktsignal steht und daher als Teil des
Schaltnetzes synthetisiert wird.
SIGNAL data_reg_s
: data_reg_t;
Allein diese Anweisung stellt zunächst den kompletten Datenspeicher (data_reg_t ist
auch als ein Feld von Bitvektoren definiert) als Signale zur Verfügung, die aber erst
später durch ihre Initialisierung und das Beschreiben in Abhängigkeit vom Taktsignal
als Flip-Flops synthetisiert werden.
-- Naechste SBN Anweisung
instruction_s <= Program(pc_s);
Das Anlegen des aktuellen Wertes des Programmzählers an das Schaltnetz liefert den
dazugehörigen Bitvektor und damit die nächste SBN Anweisung.
Mit der Initialisierung durch den Reset beginnt der Programmzähler automatisch bei 1
und damit liegt die erste Instruktion vor.
-- Die naechsten moeglichen Programmzaehler
pc_incr_s <= pc_s + 1;
pc_jmp_s <= pc_s + jmp_range_s;
In jedem Falle bestimmt das Schaltnetz die nächsten möglichen Werte des
Programmzählers. Dies ist dadurch möglich, dass der aktuelle Wert des
Programmzählers gegeben, 1 eine Konstante und die Sprungweite
- 14 -
Projektbericht
Single Instruction Computer
-- Sprungweite bei negativem Ergebnis
jmp_range_s <= conv_integer (SIGNED(instruction_s
(instr_argl3_c - 1 downto 0)));
aus der Instruktion heraus bekannt ist. Da aus der Instruktion heraus die auszuwertenden
Adressen des Datenspeichers ebenfalls bekannt sind,
-- Adressen im Datenpeicher
adr_a_s <= conv_integer
(UNSIGNED(instruction_s(instr_wl_c - 1 downto
instr_wl_c – instr_argl1_c)));
adr_b_s <= conv_integer
(UNSIGNED(instruction_s(instr_wl_c - instr_argl1_c - 1 downto
instr_wl_c - instr_argl1_c - instr_argl2_c)));
können auch direkt die zu subtrahierenden Operanden ermittelt werden.
-- Daten aus Datenspeicher
op_a_s <= conv_integer (SIGNED(data_reg_s(adr_a_s)));
op_b_s <= conv_integer (SIGNED(data_reg_s(adr_b_s)));
Zur Erklärung: Die Funktion „conv_integer“ wandelt einen als „SIGNED“ (mit
Vorzeichen) oder „UNSIGNED“ (ohne Vorzeichen) deklarierten Bitvektor in einen
Integer-Wert um. Mit „X downto Y“ findet eine Nummerierung statt und legt damit den
Bereich des Bitvektors fest, der gewandelt werden soll. „instruction_s“ wiederum ist das
Signal, das den Bitvektor der SBN Anweisung enthält.
Da auch die Operanden selber bekannt sind, kann auch die dazugehörige Differenz
durch das Schaltnetz ermittelt werden.
-- Ergebnis
diff_s <= op_a_s - op_b_s;
diff_vec_s <= STD_ULOGIC_VECTOR(conv_std_logic_vector
(diff_s, data_wl_c));
Zur Erklärung:
Die Funktion „conv_std_logic_vector“ wandelt einen Integerwert in einen Bitvektor des
Typs Standard-Logic einer bestimmten angegebenen Länge (data_wl_c) um. Die
darüber gesetzte Umkonvertierung „STD_ULOGIC_VECTOR“, wandelt diesen Vector
dann in einen Bitvektor des speziellen Typs Standard-Ulogic um.
Aus dem Ergebnis selber bestimmt sich dann wieder (durch das MSB) welcher der
möglichen Folgewerte des Programmzählers in frage kommt und zum nächsten Takt in
das Programmzähler-Register geschrieben wird.
-- Neuer Programmzaehler
IF diff_s < 0 THEN pc_s <= pc_jmp_s;
ELSE pc_s <= pc_incr_s;
END IF;
- 15 -
Projektbericht
Single Instruction Computer
Dies ist wiederum Teil des Schaltwerkes, da es innerhalb des Prozesses steht. Der
Prozess wird jeweils zur nächsten positiven Taktflanke ausgeführt.
ELSIF (clk_i'EVENT AND clk_i='1') THEN
Das ´EVENT beschreibt den Moment, in dem sich das angegebene Signal verändert,
verknüpft mit der Bedingung, dass es dann 1 sein soll, entspricht der Bedingung eine
positive Flanke des Signals zu erwarten.
Der taktabhängige Prozess soll nun im noch einmal übergreifend dargestellt werden:
reg : PROCESS (clk_i, reset_i)
Begin
IF reset_i = '0' THEN
.
.
.
ELSIF (clk_i'EVENT AND clk_i='1') THEN
.
.
.
END IF;
End PROCESS;
Zunächst gibt die „Sensitivity List“ (clk_i, reset_i) an, dass wann immer eine
Veränderung im Zustand dieser Signale auftritt, der Prozess „angestoßen“ werden soll.
Das heißt, sowohl bei negativen als auch positiven Flanken des synchronen Taktsignals
und des asynchronen Resetsignals. Um dies sinnvoll umzusetzen, wird für den ersten
Abschnitt des Prozesses die Bedingung „reset_i = ´0’“ aufgestellt und für den zweiten
Abschnitt die bereits beschriebene Bedingung einer positiven Taktflanke. Dies hat zur
Wirkung, dass die Initialisierung des SIC aufgrund des Löschen des Resetsignals
passiert und das Zurückschreiben des Ergebnisses in den Datenspeicher sowie das
setzen des Programmzählers auf seinen neuen Wert zu jeder positiven Taktflanke
durchgeführt wird.
5.3 Programme in SBN
Das implementierte Beispiel-Programm führt zwei Kopieranweisungen in der Weise
durch, wie sie in der Einleitung beschrieben ist. Eine, als temporäres Register gewählte
Adresse, wird zweimal in Folge gelöscht, erhält den negierten Wert des Quellregisters
und wird dann selber zum Quellregister. Das Zielregister erhält dann von dort den
zweimal negierten Wert, der ursprünglich kopiert werden sollte.
Bei der genauen Ermittlung der SBN Anweisungen, sind ihre Aufteilung und die damit
verbundenen Parameter zu beachten. So geben diese vier Konstanten,
- 16 -
Projektbericht
Single Instruction Computer
-- Befehlswortlaenge
CONSTANT instr_wl_c
: INTEGER :=
instr_argl1_c + instr_argl2_c + instr_argl3_c;
-- 1. Argument in Instruktion hat n Bit
CONSTANT instr_argl1_c
: INTEGER := 5;
-- 1. u 2. Arg => maxAnz addrbare Datenworte
CONSTANT instr_argl2_c
: INTEGER := 5;
-- 3. Argument => max Sprungweite +/CONSTANT instr_argl3_c
: INTEGER := 4;
an wie breit eine Anweisung insgesamt und ihre drei Argumente für sich sind. Da es
sich bei den ersten beiden Argumenten um absolute Adressen handelt, müssen ihre
Breiten der Anzahl der zur Verfügung stehenden Datenregister
-- Anz. Datenworte im Datenspeicher
CONSTANT reg_nr_c
: INTEGER := 32;
entsprechen, um alle adressieren zu können. Wie viele Programmzeilen möglich sind
und welche Wertebereich dementsprechend der Programmzähler haben darf, wird durch
-- Anz. Befehlsworte im Programmspeicher
CONSTANT line_nr_c
: INTEGER := 9;
bestimmt. Unter diesen Bedingungen lässt sich das folgende Programm so
interpretieren:
A
B
C
Programmzeile
"00111 00111 0001", --> 1
"00111 00101 0001", --> 2
"00011 00011 0001", --> 3
"00011 00111 0001", --> 4
"00111 00111 0001", --> 5
"00111 00110 0001", --> 6
"00100 00100 0001", --> 7
"00100 00111 0001", --> 8
"00001 00010 0000" --> 9
Zeile 1 löscht den Inhalt von Adresse 7 und enthält eine Sprungweite von +1. Da das
Ergebnis der Subtraktion nicht negativ ist, wird der Programmzähler inkrementiert. Die
Sprungweite von +1 bewirkt ein inkrementieren des Programmzählers auch bei
negativen Ergebnissen. Das Programm wird also unabhängig vom Vorzeichen der
ermittelten Differenzen Schritt für Schritt bis Zeile 9 abgearbeitet. Zeile 2 bewirkt, dass
der negierte Inhalt von Adresse 5 nach Adresse 7 geschrieben wird. Zeile 3 löscht den
Inhalt von Adresse 3. Zeile 4 schreibt nun den zweimal negierten Inhalt von Adresse 5
aus Adresse 7 nach Adresse 3. Zeile 5 bewirkt ein erneutes Löschen des Inhaltes der
Adresse 7. Zeile 6 schreibt den negierten Inhalt von Adresse 6 nach Adresse 7. Zeile 7
löscht den Inhalt der Adresse 4. Zeile 8 schreibt nun den zweimal negierten Inhalt von
- 17 -
Projektbericht
Single Instruction Computer
Adresse 6 aus Adresse 7 nach Adresse 4 und Zeile 9 bewirkt eine Endlosschleife auf
dieser Anweisung und damit eine theoretische „HALT“ Anweisung.
Dies wird dadurch erreicht, dass die Inhalte der Adressen 1 und 2 fest auf 0 und 1
definiert sind und bei einem Reset so initialisiert werden.
-- Datenregister 1,2 fuer HALT initialisiert
data_reg_s (1) <= "0000000000000000";
data_reg_s (2) <= "0000000000000001";
Sehen sie hierzu auch den „VHDL Quellcode des SIC“ im Anhang. Diese Adressen
können für die festen Werte 0 und 1 verwendet werden. Sie dürfen aber nie
überschrieben werden, was durch ein bedingtes Zurückschreiben der Ergebnisse
erreicht wird:
IF i > data_reg_reserv_nr_c THEN
data_reg_s(adr_a_s) <= diff_vec_s;
data_reg_s(0) <= diff_vec_s; -- Ergebnis zur Ausgabe
END IF;
Die Konstante „data_reg_reserv_nr_c“ enthält dabei die höchste, für derartige Zwecke
reservierte Adresse und schließt diese und alle darunter vom Zurückschreiben des
Ergebnisses aus. Dies wiederum bedingt, dass alle reservierten Adressen von 0 an
aufsteigend definiert werden. In diesem SIC ist zusätzlich die Adresse 0 als Standard
Ergebnis-Register definiert. Diese Adresse ist zum Zwecke der Visualisierung mit einer
Reihe von LEDs verknüpft.
5.4 Daten für Programme in SBN
Um dem SBN Programm einen Sinn zu geben, sind definierte, nicht zufällige Daten
innerhalb des Datenspeichers notwendig. Um dies zu erreichen wird der Datenspeicher
beim einem Reset komplett initialisiert. Die Initialisierung läuft dabei in drei
Abschnitten ab. Als erstes wird der Datenspeicher, abgesehen von den unteren, für fest
definierte Werte reservierten Adressen, mittels einer Schleife gelöscht. Dann werden die
Werte für die reservierten Adressen gesetzt und im letzten Schritt werden die
eigentlichen Programmdaten gesetzt:
-- Datenspeicher loeschen
FOR i IN data_reg_reserv_nr_c + 1 TO reg_nr_c - 1 LOOP
data_reg_s(i) <= (OTHERS => '0');
END LOOP;
-- Die Register 0, 1 und 2 sind per Definition reserviert
-- Standard Ergebnis-Register (0) initialisieren
data_reg_s (0) <= "1010101010101010";
-- Datenregister 1,2 fuer HALT initialisiert
data_reg_s (1) <= "0000000000000000";
data_reg_s (2) <= "0000000000000001";
- 18 -
Projektbericht
Single Instruction Computer
-- Alle weiteren Register sind abhaengig vom Programminhalt
-- Programmdaten initialisieren
data_reg_s (5) <= "0000000000011111";
data_reg_s (6) <= "0000000000000001";
data_reg_s (7) <= "0011110010000111";
Diese Vorgehensweise ist so gewählt, damit die fest definierten Adressen nicht unnötig
zweimal gesetzt werden und damit möglichst unzweideutige Initialisierungen erreicht
werden. Im Falle der Programmdaten ist dies jedoch zunächst unpraktisch, da jedes
Programm andere Adressen mit anderen Inhalten verwenden kann.
Aus dem oben gezeigten Abschnitt ist zu erkennen, dass das Standard Ergebnis-Register
mit dem Wert –21846 initialisiert wird. Dieser Wert (1, 0 Wechsel) ist lediglich wegen
seiner Auffälligkeit zum leichteren Identifizieren bei der Simulation und beim Testen
gewählt. Die Register 1 und 2 werden mit den Werten 0 und 1 initialisiert, so dass eine
SBN Anweisung 1,2,0 (00001 00010 0000), die diese Register in dieser Reihenfolge
verwendet immer zu einem negativen Ergebnis führt und einen Sprung bewirken wird.
Bei einer Sprungweite von 0 wird dann eine Endlosschleife bewirkt. Dem aktuellen
Wert des Programmzählers wird eine 0 hinzuaddiert und die gleiche Anweisung wird
erneut ausgeführt. Diese Anweisung in Kombination mit diesen fest definierten
Adressen im Datenspeicher wird hier als HALT Anweisung bezeichnet.
Schlussendlich werden die Adressen 5 bis 7 mit Programmdaten initialisiert. Adresse 5
erhält dabei den Wert 31 und Adresse 6 den Wert 1. Diese beiden Werte sollen im
Verlauf des Programms in die Adressen 3 und 4 kopiert werden. Adresse 7 enthält
einen Wert, der zufällig gewählt ist, um die Notwendigkeit des Löschens von Adressen,
die als temporäre Register verwendet werden sollen, zu verdeutlichen.
6. Simulation und Test des SIC
Neben den üblichen Schreibtischtests, ist die Simulation mit einer entsprechenden
Software essentiell (hier ModelSim von Model Technology Inc.), um die Funktionalität
und den Ablauf zu überprüfen. ModelSim bietet eine Fülle von Informationen,
verschiedene Möglichkeiten zur Präsentation des Models und der Daten, sowie die
Möglichkeit den Ablauf schrittweise, abschnittsweise oder komplett zu simulieren. Die
Simulation benötigt Testdaten in Form von zu simulierenden Eingangssignalen. Diese
können manuell oder über eine Testbench eingestellt werden.
6.1 Testbench
Eine Testbench kann man sich wie eine Experimentier-Schaltung vorstellen, in die die
zu untersuchende Schaltung eingesetzt wird. Die Testbench kann Eingangssignale für
die zu testende Schaltung erzeugen, die Ausgangssignale und internen Signale der
Schaltung aufzeichnen und mit vorgegebenen Daten vergleichen. Hierzu besteht auch
die Möglichkeit auf Dateien zuzugreifen oder aufgezeichnete Daten in Dateien zu
speichern. Durch Meldungen kann während des Ablaufs der Simulation die gedachte
Korrektheit oder Falschheit der Ergebnisse bekannt gegeben werden. Mittels einer
- 19 -
Projektbericht
Single Instruction Computer
Testbench kann also eine komplexe, voll automatische Testumgebung geschaffen
werden. Eine solche Testbench ist jedoch von ihrem Schwierigkeitsgrad und von ihrem
Aufwand her ein eigenes Projekt und wird daher hier nicht erstellt.
Die Testbench, die hier verwendet wird, dient lediglich der Erzeugung der notwendigen
Eingangssignale Clock (clk_i) und Reset (reset_i).
An dieser Stelle soll nur der gewünschte Verlauf der Eingangssignale beschrieben
werden. Der VHDL Code der Testbench selber ist im Anhang zu finden und die
dazugehörige Datei befindet sich im Projektverzeichnis unter .../Software/ .
Die in diesem Fall verwendeten Parameter erzeugen für eine Gesamtlaufzeit von 334,1
µs ein symmetrisches Taktsignal mit einer Periodendauer von 20 ns (entsprechend 50
MHz). Das Taktsignal beginnt mit einer logischen 0 und ändert dann seinen Zustand zu
logisch 1 nach 10 ns. Das Resetsignal ist mit Beginn der Simulation für 25 ns auf 0
gesetzt. Es wird danach auf 1 gesetzt und wird bis zum Ende der Simulation gehalten.
Abbildung 3: ModelSim – Wave Fenster (Signalverlauf der Simulation)
Abbildung 3 zeigt den Signalverlauf innerhalb des SIC für die ersten 45 ns. Es wird das
in 5.3 beschriebene Programm zum Kopieren zweier Adressen mit den angegebenen
Werten, zusammen mit der oben beschriebenen Testbench, verwendet. ModelSim bietet
an, die im Signalverlauf darzustellenden Signale explizit auszuwählen. Hier sind
zunächst alle vorhandenen Signale dargestellt. Im weiteren Verlauf wird auf ein paar
Signale, die zur Beschreibung des Ablaufs nicht erforderlich scheinen verzichtet. Die
Signalnamen, die ganz links mit einem + gekennzeichnet sind, sind Vektoren von
Signalen oder fassen gar mehrere Vektoren zu einer Gruppe zusammen. Dies ist an dem
- 20 -
Projektbericht
Single Instruction Computer
data_reg_s Signal zu erkennen. Es stellt den Inhalt des Datenspeichers dar und wird
zunächst als ein Signal abgebildet. Ein Klick auf das Plus-Symbol klappt die darunter
enthaltenen Vektoren bzw. Register auf. Jedes einzelne wiederum ( (0) bis (7) ) kann
weiter aufgelöst werden, bis die Signale jedes einzelnen beteiligten Bits dargestellt sind.
Sind Signale von vorneherein als Integer angelegt, so werden ihre Werte auch direkt
dezimal angegeben (z.B. pc_s). Per Menü oder einem Rechts-Klick auf ein Signal
können auch andere Darstellungsformen/ Basen gewählt werden. So ist für den
Bitvektor diff_vec_s eine binäre Darstellung die Voreinstellung (weil als
STD_ULOGIC_VECTOR definiert), unter RADIX kann jedoch z.B. eine dezimale
Darstellung gewählt werden. Dies gilt in diesem Fall für das dazugehörige Signal
diff_s. Es sei noch erwähnt, dass für die Wiedergabe in diesem Bericht eine andere
Farbgebung gewählt wurde. ModelSim stellt die Signalverläufe normalerweise in grün
auf schwarzem Hintergrund dar.
In Abbildung 3 sind zunächst die initialisierten Werte und der Einfluss des Resets zu
erkennen. Durch die Initialisierung des Programmzählers mit dem Wert 1, sind die
Adressen, Operanden und das Ergebnis der Subtraktion, sowie der folgende
Programmzählerstand von vornherein bekannt. Im realen Verlauf sollte die
Initialisierung jedoch erst mit der ersten Änderung des Taktes (hier nach 10 ns)
geschehen und danach würden alle diese Werte „bekannt“ sein. Da der Simulator jedoch
mit einer eigenen Initialisierung (i.d.R. der kleinste Wert im zugelassenen
Wertebereich) arbeitet, steht der Programmzähler bereits zu Beginn der Simulation auf
eins.
Nach 25 ns endet der Reset und das Signal wird auf logisch 1 gesetzt. Mit der nächsten
positiven Taktflanke ( bei 30 ns) wird damit die erste Instruktion umgesetzt. Das
Ergebnis wird zurückgeschrieben (data_reg_s (7)) und in das Standard ErgebnisRegister data_reg_s (0) geschrieben. Außerdem erhält der Programmzähler (pc_s = 2)
seinen neuen Wert. Damit werden die nächsten Adressen im Datenspeicher (adr_a_s =
7, adr_b_s = 5) ermittelt, die neuen Operanden bestimmt (op_a_s = 0, op_b_s = 31)
und das neue Ergebnis errechnet (diff_s = -31, diff_vec_s = 1111111111100001). Die
möglichen Folgewerte für den Programmzähler (pc_inc_s = 3, pc_jmp_s = 3) sind
ebenfalls bereits ermittelt.
Abbildung 4: Simulation am Ende des SBN-Programms
- 21 -
Projektbericht
Single Instruction Computer
Abbildung 4 zeigt die Ausführung der Programmzeilen 8 und 9, sowie die erste
Wiederholung von Zeile 9. Die vorletzte Instruktion (instruction_s) sagt dabei aus, dass
die Operanden aus den Adressen 4 und 7 voneinander subtrahiert werden sollen und bei
einem negativen Ergebnis dem Programmzähler 1 hinzuaddiert werden soll.
Dementsprechend wird als nächstes Anweisung 9 ausgeführt. Das Ergebnis aus 8, also
der Wert 1, wird dann in Adresse 4 und das Standard Ausgabe-Register (Adresse 0)
geschrieben. Folglich wird auch auf den Ausgabeport der Wert 1 gegeben und lediglich
eine LED sollte leuchten.
Folgend wird die HALT Anweisung wiederholt bis zum Abbruch der Simulation
ausgeführt. Die Instruktion in Programmzeile 9 besagt, dass die Werte der
vordefinierten Adressen 1 und 2 voneinander zu subtrahieren sind und bei einem
negativen Ergebnis der Programmzähler unverändert bleiben soll; womit die selbe
Instruktion erneut ausgeführt wird. Da in den Adressen 1 und 2 die Werte 0 und 1
abgelegt sind, ist das Ergebnis der Subtraktion immer –1 und damit negativ. Da die
vordefinierten Adressen vom Zurückschreiben des Ergebnisses ausgeschlossen sind,
bleibt das Standard Ergebnis-Register unverändert und es leuchtet auch weiterhin nur
eine LED. Der Signalverlauf gibt diesen Umstand in sofern wieder, als dass sich die
Signalzustände auch mit der nächsten positiven Taktflanke nicht mehr ändern.
Nach zufriedenstellendem Abschluss der Simulation der Schaltung, wird die FPGAProgrammier-Datei erzeugt und auf das FPGA geladen. Vorausgesetzt ein Taktsignal
mit nicht zu hoher Frequenz, eine Betriebsspannung und alle weiteren Ein- und
Ausgangssignale (Reset-Schalter und LEDs) sind korrekt angeschlossen, sollte nach
einem Reset das Programm in Kürze abgelaufen sein. Da der Inhalt des Speichers zu
diesem Zeitpunkt noch nicht ausgelesen werden kann, ist die Anzeige durch die LEDs
die einzige Möglichkeit der Verifikation. Diese sollten den jeweils zuletzt in eine nicht
reservierte Adresse zurückgeschriebenen Bitvektor anzeigen. Entsprechend der
gewählten Pinbelegung (siehe User Constraints File 10.3) sind die Zustände der LEDs
in entsprechender Reihenfolge zu interpretieren; hier ist das LSB an led_o(0) an Pin 48
zu finden, das MSB an led_o(15) an Pin 29.
7. SBN Assembler
Wie eingangs erwähnt, soll eine Entwicklungsumgebung entstehen, die es möglich
machen soll einen SIC auf Assembler- oder Hochsprachen-Ebene zu programmieren.
Für den Abschluss dieser Projektaufgabe ist die Planung und Umsetzung eines
Assemblers vorgesehen, der nach Möglichkeit als Basis für die Weiterentwicklung oder
einer Erweiterung zu einer Entwicklungsumgebung dienen soll.
7.1 Übersetzungs-Hierarchie
Eine allgemeine Beschreibung der Vorgehensweise und der typischerweise in der
Übersetzung vorkommenden Abläufe wird hier dargestellt. Die folgende Grafik ist aus
[CPOAD] Kapitel 3.9 entnommen und beschreibt den Weg eines HochsprachenProgramms von der Programmierung bis zur tatsächlichen Ausführung durch eine CPU.
Im Anschluss an die Erläuterungen der einzelnen Komponenten wird das Modell auf
- 22 -
Projektbericht
Single Instruction Computer
diese Aufgabe reflektiert und dabei erläutert welche Komponenten derzeit betrachtet
werden können und welche gegebenenfalls zu erweitern oder einzuschränken sind:
Hochsprachen
Programm
z.B. „C“ Code
Compiler
Programm in
Maschinensprache
Assembler
Objekt:
Maschinensprachen Modul
Objekt: Bibliothek Routinen
(Maschinensprache)
Linker
Ausführbar: Maschinensprachen Programm
Loader
Programmspeicher
Abbildung 5: Starting a program
- 23 -
Projektbericht
Single Instruction Computer
Compiler
o Umsetzung eines Hochsprachen-Programms (ein paar Zeilen) in ein
Maschinensprachen-Programm – eine symbolische Form von dem, das die
Maschine „versteht“ (viel mehr Zeilen)
Assembler
o Primäre Aufgabe eines Assemblers ist es den Maschinensprachen Code in
einen Maschinen-Code umzusetzen bzw. aus dem Maschinensprachen
Programm eine Objekt Datei zu machen. Diese umfasst
Maschinen Befehle
Daten
Informationen, die nötig sind, um die Befehle im Speicher
später richtig zu platzieren
o Der Assembler muss zu allen verwendeten Sprungmarken (Labels)
die korrekte Adresse ermitteln. Diese Information wird dann in der
Symbol Tabelle (Symbol Table) festgehalten.
o Eine Objekt-Datei eines UNIX Systems z.B. enthält:
Header – Größe und Position eventueller anderer Teile der
Objekt-Datei
Text Abschnitt – Maschinensprachen Code
Daten Abschnitt – Statische und dynamische Daten
Zuordnungsinformationen (Relocation information) – Befehle
und Daten, die von absoluten Adressen im Speicher abhängig
sind
Symbol Tabelle – Bisher nicht aufzulösende, nicht definierter
Sprungmarken
Debugging Information – Informationen zur
Fehlerbearbeitung / darüber wie die Module übersetzt wurden
o Pseudo-Befehle – gängige Variationen von Maschinensprachen Befehlen,
die nicht in Hardware implementiert werden müssen
o Z.B. stellt die MIPS Hardware sicher, dass Register $zero immer den Wert 0
enthält und dieser nicht geändert werden kann
⇒ Durch die Verwendung dieses Registers sind Befehle umsetzbar, die
gar nicht in der Architektur implementiert sind; häufig genanntes
Beispiel dafür ist die move-Anweisung:
move $t0, $t1 wird umgesetzt in add $t0, $zero, $t1
Register $t0 erhält damit den Wert 0 + den Wert in Register $t1, dies
entspricht der Anweisung move $t0, $t1.
⇒ Pseudo-Befehle bereichern den Satz an Maschinensprachen Befehlen,
den die Maschine kennt. Im obigen Beispiel lediglich auf Kosten eines
einzelnen Registers, dass reserviert ist.
⇒ Der Assembler akzeptiert Pseudo-Befehle und maschinen-spezifische
Befehle.
o Assembler sind in der Lage Zahlen und Wertangaben in einer Reihe von
Basen zu erkennen – typischerweise werden dezimale, hexadezimale und
binäre Zahlen erkannt.
- 24 -
Projektbericht
Single Instruction Computer
Linker
o Unabhängig voneinander kompilierte und assemblierte Prozeduren werden
durch den Linker miteinander verknüpft und zu einem Ganzen
zusammengesetzt.
o Module werden symbolisch im Speicher platziert.
o Adressen von Daten- und Befehls-Marken werden ermittelt.
o Interne und externe Referenzen werden gepatched:
o Die Zuordnungsinformationen und Symbol Tabellen jedes Objekt
Moduls werden benutzt um alle unbestimmten Marken zu bestimmen
(alte Adressen werden mit neuen aktualisiert).
o Es werden alle Speicherbereiche ermittelt, die die Module belegen
werden.
o Alle absoluten Referenzen müssen neu zugeordnet werden um ihre
wahre Position zu reflektieren.
o Erzeugt eine ausführbare Datei. Sie hat das gleiche Format wie eine ObjektDatei, bis auf dass keine ungelösten Referenzen, Zuordnungsinformationen,
Symbol Tabellen oder Debugging Informationen mehr enthalten sind.
Loader
o Das Betriebssystem liest die ausführbare Datei in den Speicher ein
1. Lesen des Exe-File Kopfes – ermitteln der Größen von Text und
Daten Segment
2. Adressbereich erzeugen
3. Anweisungen und Daten kopieren
4. Parameter des Hauptprogramms auf den Stack kopieren
5. Initialisierung der Register und Setzen des Stack-Pointers auf die
erste freie Position
6. Sprung zu einer „Start-Up“ Routine, die die Parameter kopiert und
dann das Hauptprogramm aufruft. Nachdem das Hauptprogramm
zurückkehrt, beendet die „Start-Up“ Routine das Programm mit
einem „exit system call“.
7.2 Pseudo-Befehle
Bei den folgend aufgeführten Pseudo-Assembler Anweisungen, wird davon
ausgegangen, dass die Speicheradressen 0 bis 2 per Definition nicht beschrieben werden
können und die Adressen 1 und 2 die Werte 0 und 1 enthalten. Darüber hinaus wird
davon ausgegangen, dass Speicheradresse 0 das Standard Ergebnis-Register ist und
immer dann mit dem Ergebnis der zuletzt ausgeführten Subtraktion neu beschrieben
wird, wenn die erste Quelladresse nicht eine der Adressen 0 bis 2 ist.
Die in den SBN Anweisungen verwendeten Adressen 0 bis 2 sind absolute Angaben, A
und B sind beliebige andere absolute Adressen und „tmp“ steht für eine zur Zeit frei
verfügbare Adresse, die als temporäre Adresse genutzt werden kann. Die Sprungweite
ist entweder direkt und absolut angegeben oder als Argument C dargestellt. Für C soll 1
angenommen werden, wenn nicht explizit angegeben.
- 25 -
Projektbericht
Single Instruction Computer
PseudoBefehl
Umsetzung in SBN
Anweisungen
Beschreibung und Synonyme
HLT
SBN 1, 2, 0
ADD
SBN tmp, tmp, 1
SBN tmp, B, 1
SBN A, tmp, C
SBN A, B, C
Endlosschleife des Programms an dieser
Programmzeile // HALT, HLD, HOLD
Inhalt von B wird zu dem Inhalt von A nach
A addiert //
SUB
NOP
MOV
INC
DEC
SBN 2, 1, 1
SBN tmp, tmp, 1
SBN tmp, B, 1
SBN A, A, 1
SBN A, tmp, C
SBN tmp, tmp, 1
SBN tmp, 2, 1
SBN A, tmp, C
SBN A, 2, C
Inhalt von B wird von dem Inhalt von A nach
A subtrahiert //
SBN ohne Rückschreiben und ohne Sprung //
Inhalt von B wird nach A kopiert, der Inhalt
von A wird überschrieben // MOVE, CP,
COPY
Inhalt von A wird inkrementiert // INCR
Inhalt von A wird dekrementiert // DECR
Tabelle 1: Umsetzung von Pseudo-Befehlen in SBN (so far)
7.3 Konzept für einen Assembler in Perl
Das hier vorgestellte Konzept ist ein erster Vorschlag zur Umsetzung eines Assemblers,
der gängige Assembler-Befehle (hier Pseudo-Befehle) in SBN Anweisungen übersetzt
und diese schlussendlich in eine, für den SIC verständliche, Form bringt.
Bei gegenwärtigem Stand (Speicher wird FPGA-intern realisiert) sind wesentliche
Unterschiede zu einer späteren Version des Systems zu berücksichtigen. Ziel ist es den
SIC auf dem FPGA als CPU einzusetzen, Programm- und Datenspeicher stehen extern
daneben über ein Bussystem zur Verfügung und können variabel mit unterschiedlichen
Programmen und Daten geladen werden, ohne dass ein neuer SIC auf das FPGA
geladen werden muss. Dies sollte beim Programmieren eines Assemblers beachtet
werden. Die Assembler-Produkte sollten daher so erstellt werden, dass eine Anpassung
des Assemblers an eine spätere Version des SIC nicht ein komplett neues Programm
erfordern.
Wesentliche Aufgaben des Assemblers sind:
1.
2.
3.
4.
5.
Parametrierung des SIC
Übersetzung des Pseudo-Codes
Erstellung des Daten-Files
Erstellung des Programm-Files
Einbindung der Files in den statischen VHDL-Code bzw.
Erstellung der vollständigen VHDL-Datei
- 26 -
Projektbericht
Single Instruction Computer
Wesentliche Ein- und Ausgabedateien sind:
I. Datei mit statischem VHDL Code
II. Assembler Quelldatei mit Pseudo-Code
III. Datei mit dynamischem VHDL Code
IV. Vollständige VHDL-Datei zur Erzeugung des Programmier-Files mit
WebPACK
VHDL Datei
(dynamisch)
Parameter
SIC
Parametrieren
SIC
Parameter
VHDL Datei
(statisch)
Programmund Daten-File
Pseudo-Code
übersetzen
PseudoAssembler
Programm
zusammenführen
Bericht
VHDL Datei
(SIC vollständig)
Diagramm 1: Datenfluss durch den Assembler
Das Datenfluss-Diagramm zeigt die wesentlichen Ein- und Ausgabedaten und die
Reihenfolge, in der sie verarbeitet oder erstellt werden. Das Assemblieren des PseudoCodes stellt einen sequentiellen Prozess dar, der im Diagramm widergespiegelt wird.
Soweit dieser Vorgang erfolgreich verläuft, wird diese Folge eingehalten.
Eingabefehler, unlesbare oder nicht auffindbare Dateien, sowie syntaktische Fehler
innerhalb des Pseudo-Codes sollten selbstverständlich berücksichtigt werden und führen
zu Abbrüchen dieser Sequenz. Es können aus jedem Prozess im Prinzip drei Pfade zu
einem Abbruch des Vorgangs führen. Eingabe, Verarbeitung und Ausgabe sind diese
drei „Austrittstellen“. So sollten z.B. unsinnige Parameter-Eingaben abgefangen
werden, die Datei mit dem Pseudo-Assembler Programm muss vorhanden sein, beim
Übersetzen des Pseudo-Codes muss die Syntax stimmen und die Ausgabedateien
müssen sich erzeugen lassen können.
Zunächst werden die Daten benötigt, nach denen der SIC dimensioniert werden soll. An
dieser Stelle kann eine Standard-Konfiguration angeboten werden, die bekanntermaßen
funktionstüchtig ist. Diese Daten fließen sozusagen als Kopf-Daten zusammen mit dem
Pseudo-Code in den Übersetzungsprozess ein. Sie können auch optional bereits in
dieser Datei enthalten sein. Nach der Übersetzung stehen die veränderbaren Inhalte des
SIC-VHDL-Codes fest und können mit den feststehenden Bereichen des SIC-VHDL- 27 -
Projektbericht
Single Instruction Computer
Codes zusammengeführt werden. Ein abschließender Bericht kann Auskunft über den
Erfolg des Vorganges geben und die vollständige SIC-VHDL Datei steht dann zur
Weiterverarbeitung durch WebPACK zur Verfügung.
8. Ergebnisse und Diskussion
Im Verlauf der Arbeit an dem SIC stellt sich an mehreren Stellen heraus, dass besonders
die unterschiedlichen Abstraktionsebenen ein hohes Maß an Hintergrundwissen
erfordern, um Zwischenergebnisse und Endprodukt richtig deuten zu können.
Angefangen mit der Deutung der SBN Anweisung und ihrer Umsetzung in VHDL
Code, bedient man sich, der Einfachheit und Verständlichkeit halber, eines
hochsprachlichen Ansatzes. Es zeigt sich aber bald, dass Synthese- und
Implementierungs-Prozess diesen vom Verständnis her nicht 1 zu 1 umsetzen. Zu
diesem Zeitpunkt ist es entscheidend, die Bedeutung von „Concurrent Statements“ und
den Unterschied zwischen Schaltnetzen und Schaltwerken verstanden zu haben. Die
zeitlichen Abfolgen der „Geschehnisse“ im FPGA und ihre Darstellung in VHDL sind
nicht einfach auf die gewohnten, größtenteils linearen Strukturen eines HochsprachenProgramms zu übertragen.
Fährt man nun mit der Simulation fort, muss man einfach wissen, dass ModelSim alle
verwendeten Signale zunächst für sich initialisiert. Dies ist wiederum abhängig von der
Einschränkung der Wertebereiche der Signale. Ist ein Signal z.B. einfach als Integer
ohne Angaben zum Wertebereich definiert, so nimmt die Software einen 32-Bit-Wert
an. Bei der Initialisierung wird dann immer der kleinste gültige Wert angenommen oder
bei STD_LOGIC Signalen „U“ wie undefined. Diese Initialisierung findet völlig
unabhängig vom weiteren gedachten Ablauf statt. Erst danach startet die Simulation und
führt gegebenenfalls den vorgesehenen Reset durch und initialisiert die Schaltung dann
wunschgemäß, doch bis dahin können schon die ersten Probleme entstanden sein. Wenn
z.B. der Programmzähler nicht auf den korrekten Bereich (nämlich aller möglichen
Programmzeilen im „Programmspeicher“) eingeschränkt ist, dann wird dieser auf einen
Wert initialisiert, der auf eine nicht vorhandene Programmzeile verweist. Auf der
anderen Seite ist diese erste Initialisierung, die ModelSim für sich ausführt, später nicht
in der Hardware wiederzufinden. Sie ist nicht angelegt oder vorgesehen und
bekanntermaßen befinden sich alle Flip-Flops einer digitalen Schaltung nach dem
Einschalten in einem undefinierten Zustand. Dies ist auch der Grund dafür, warum der
Datenspeicher beim Reset komplett gelöscht bzw. initialisiert werden muss. Des
weiteren fällt auf, dass ModelSim bei dem Umfang an Informationen und der
verschiedenen Möglichkeiten der Darstellung (viele Fenster, verschiedene
Darstellungsformen, RADIX-Einstellung für Signale) ein wenig die Übersichtlichkeit
verloren geht. Man braucht Zeit um sich einzugewöhnen und gute Augen um mit den
teilweise sehr kleinen Darstellungen zurecht zu kommen. Hat man dann das System
verstanden und findet sich auch zurecht, würde man z.B. gerne die Signalverläufe auf
einfach Weise kommentieren und speichern. Diese Möglichkeit ist jedoch leider nicht
gegeben. Etwas Abhilfe schaffen da die Möglichkeiten sich nur die interessanten
Signale auszusuchen, eine geeignete Basis (RADIX) für die Wertangaben zu wählen,
bestimmte Farben zu vergeben und sogenannte „Bookmarks“ einzufügen. Diese
Bookmarks können betitelt werden und beziehen sich auf einen frei auswählbaren
Abschnitt des Signalverlaufs, können aber auch keine Kommentare enthalten.
- 28 -
Projektbericht
Single Instruction Computer
Überschaut man alle Abschnitte dieser Arbeit, so stellt man fest, dass zumindest unter
Einbeziehung eines Assemblers, sehr verschiedene Bereiche in diese Aufgabe mit
einfließen. Angefangen bei der Verwendung einer umfangreichen
Entwicklungsumgebung, verschiedener Software und Programmiersprachen, bis hin
zum Einsatz von Hardware. Dies alles ist trotz der zunächst einfach erscheinenden
Fragestellung eine umfangreiche Aufgabe.
Mir hat die Arbeit an diesem Thema aber auf jeden Fall Spaß gemacht, auch da es so
abwechslungsreich ist und die Arbeit für sich als abgeschlossener Schritt eine „runde
Sache“ darstellt. Ich hoffe, das sie als Grundlage für weitere Arbeiten zum Thema SIC
hilfreich ist.
8.1 Zusammenfassung
Das Reduzieren des Befehlssatzes eines Prozessors auf nur eine einzige Instruktion
unter Beibehaltung ausreichender Funktionalität ist möglich. Der genaue Umfang dieser
Funktionalität ist durch weitere Untersuchungen und die Entwicklung weiterer PseudoBefehle zu ermitteln. Der für diese Reduktion erforderliche Aufwand in Software, ist
der Faktor, der diesem „Gewinn“ in Hardware gegenübersteht. Auch hier sind weitere
Untersuchungen nötig, um Aussagen darüber treffen zu können, welche Größen diese
„Gegengewichte“ haben.
Die Anzahl der bereits zu diesem Thema durchgeführten Arbeiten (s. Quellen und
SIC_Sites) zeigt, dass dieses Thema wissenschaftlich interessant ist und im Bereich der
Lehre gute Möglichkeiten bietet durch Experimente neue Erkenntnisse zu gewinnen
oder zu vertiefen.
Der während dieser Arbeit erstellte SIC kann durch folgende Eckdaten beschrieben
werden:
Parameter
•
•
Datenwortlänge bzw. Anzahl der Bits für Datenwörter
Befehlswortlänge bzw. Anzahl der Bits für SBN Anweisungen
zusammengesetzt aus:
Anzahl der Bits für das 1. Befehlsargument (A)
Anzahl der Bits für das 2. Befehlsargument (B)
Anzahl der Bits für das 3. Befehlsargument (C)
• Nummer des letzten reservierten Registers (beginnend bei Datenwort Adresse 0)
Architektur
•
•
•
•
Getrennter Daten- und Programmspeicher
Teilweise Implementierung von Pseudo-Befehlen durch Verwendung fest
definierter Daten Adressen mit fest definierten Inhalten
Fest definiertes Standard Ergebnis Register (Adresse im Datenspeicher) mit
direkt verbundener Ausgabe auf LEDs als Anzeige
Definierter Start von Programmen durch Reset, stabiler „Stopzustand“ durch
HALT
- 29 -
Projektbericht
Single Instruction Computer
Synthese Ergebnisse
Macro Statistics
# Registers
16-bit register
4-bit register
1-bit register
# Multiplexers
15-bit 8-to-1 multiplexer
2-to-1 multiplexer
# Adders/Subtractors
15-bit subtractor
4-bit adder
# Comparators
15-bit comparator less
: 77
:1
:1
: 75
: 49
:2
: 47
:3
:1
:2
:1
:1
Minimum period: 16.704ns (Maximum Frequency: 59.866MHz
Dies sind die wesentlichen Synthese-Ergebnisse bei der Verwendung des SyntheseProgramms von WebPACK Version 4.1 unter den nach der Installation gültigen
Einstellungen und der Synthese des hier verwendeten VHDL-Codes.
8.2 Letzter Stand
Im Verlauf der Tests und letzten Änderungen an dem VHDL Code stellt sich heraus,
dass die verwendete Version der Entwicklungsumgebung bzw. des SyntheseProgramms und ihrer Einstellungen erheblichen Einfluss auf die Ergebnisse haben. So
wird z.B. das von mir als „widersprüchlich“ bezeichnete Schleifen-Konstrukt im
zweiten Abschnitt des Prozesses (zurückschreiben des Ergebnisses) unnötig, wenn die
von mir privat eingesetzte Version 4.1 von WebPACK verwendet wird. Diese Version
synthetisiert dann ohne Fehlermeldungen und Warnungen.
Auf der anderen Seite sind die Ergebnisse für die maximalen Taktraten der Schaltungen
nach der Synthese auf meinem PC deutlich geringer als die, die mit der älteren Version
von WebPACK im Digitaltechniklabor erreicht werden. Dies ist jedoch möglicherweise
auf unterschiedliche Konfigurationen des Synthese-Prozesses zurückzuführen.
Eine letzte Änderung des VHDL Codes ergibt, dass der Programmspeicher bereits
durch geringfügige Änderungen als änderbarer Speicher angelegt werden kann, der bei
einem Reset ähnlich dem Datenspeicher initialisiert wird. Eine entsprechende Datei mit
dem Namen „sip_prog_mem.vhd“ befindet sich im Projektverzeichnis unter
.../Software/ .
- 30 -
Projektbericht
Single Instruction Computer
9. Ausblick
Projekt „SIC“
Die nächste wesentliche Aufgabe innerhalb dieses Projektes ist es, den SIC so
einzurichten, dass eine Kommunikation mit einem PC z.B. über den Parallelport
stattfinden kann. Ziel ist es die SIC-Programme flexibler zu wechseln und getrennt von
der SIC Architektur in das FPGA zu laden und den Datenspeicher nach der Ausführung
eines SIC-Programms auszulesen. Um dies zu erreichen wird folgendes Konzept
vorgeschlagen:
Es sind drei Teilaufgaben zu bearbeiten:
1. Anpassen der SIC Architektur an den Vorgang des Datenaustausches
2. Erstellen einer Software, die das Laden der SIC-Programme und Auslesen des
Datenspeichers von einem PC aus ermöglicht
3. Anpassen des Assemblers zur Erzeugung von „SICexe“ Files, die nur noch den
direkten binären Programmcode enthalten
Es ist bekannt, dass im Rahmen des DGT-L bereits Versuche durchgeführt wurden, die
eine Kommunikation zwischen PC-Tastatur und Experimentier-Bord per Parallelport
beinhalteten. Soweit bekannt ist, wurde dabei ein „Parallelport-Protokoll“ auf dem
FPGA implementiert, dass die ankommenden Daten angenommen und zur Anzeige
gebracht hat. Diese Arbeit könnte einen wesentlichen Teil der Aufgabe 1 darstellen. Es
wäre denkbar, dass nach einem Reset automatisch versucht wird eine Verbindung zu
einer „Download-Software“ (Aufgabe 2) herzustellen, die nach einem Handshake die
Programmdaten zur Verfügung stellt und nach Programm-Ende die Daten aus dem
Datenspeicher wieder entgegennimmt.
SIC Design
Der SIC in der vorliegenden Fassung lässt die Frage offen, wie eventuelle
Fehlergebnisse behandelt werden sollen. Im einzelnen sind damit der Überlauf bzw. das
Verlassen des gültigen Wertebereichs und ein Grenzwertproblem gemeint, das bei der
Verwendung des 2’er-Komplements auftreten kann. In einem 16-Bit
vorzeichenbehafteten Wertebereich ist der Bitvektor des Wertes –32768 identisch mit
dem seines 2’er-Komplements. Bei folgender Subtraktion ist dieses Problem leicht zu
erkennen: 32767 – (-)32768 = 65535 ergibt bei der Verwendung der üblichen Methode
zur Subtraktion (Addition des 2’er-Komplements) folgende Bitvektoren:
0111 1111 1111 1111bin (32767dez)
1000 0000 0000 0000bin (-32768dez)
wird umgesetzt zu seinem 2’er Komplement
⇒
+
=
und dann zum ersten Operanden addiert
+
1000 0000 0000 0000bin (-32768dez)
=
1111 1111 1111 1111bin (-1dez)
- 31 -
1000 0000 0000 0000
0111 1111 1111 1111
0000 0000 0000 0001
1000 0000 0000 0000
Projektbericht
Single Instruction Computer
Eine Möglichkeit wäre es, den Assembler die sich ergebenden Differenzen auf ihre
Korrektheit hin überprüfen zu lassen. Da dies in direktem Zusammenhang mit der
Datenwortbreite steht, müsste diese Überprüfung ebenfalls durch diesen Parameter
anpassbar sein. Hierbei würde sich das oben beschriebene Problem durch eine einfache
Überwachung der Einhaltung des gültigen Wertebereichs erübrigen. Der Assembler
bzw. Debugger könnte den Assemblier-Vorgang unterbrechen und alle fragwürdigen
Wertepaare / Zeilen ausgeben oder markieren und dabei angeben, dass die gewünschten
Ergebnisse außerhalb des gültigen Wertebereichs liegen.
Eine wenn auch nur bedingt sinnvolle Lösung in Hardware wäre es, eine einfache
Überprüfung der Bedingung für einen Overflow (Minuend und Subtrahend haben
gleiches Vorzeichen, das Vorzeichen der Differenz ist verschieden dazu) mit
darauffolgendem Sprung auf eine HALT-Anweisung durchzuführen, falls ein Overflow
festgestellt würde. Dies würde jedoch nur indirekt darauf aufmerksam machen, dass ein
Problem besteht.
Eine Überprüfung des Programmzählerstandes könnte ebenfalls hinzugefügt werden.
Die momentane Fassung beschränkt sich darauf zu hoffen, dass das Programm als letzte
Anweisung einen Sprung auf sich selbst (HALT) enthält oder aber der Ablauf sich zu
einer anderen Endlosschleife mit gültigen PC-Werten entwickelt.
Der VHDL Code stellt eine funktionale Beschreibung dar, die tatsächliche Umsetzung
in Hardware ist daraus nicht direkt abzulesen. Es ist daher nicht sofort ersichtlich, auf
welche Art und Weise das Synthese-Programm z.B. den Subtrahierer bildet. Eine
eventuelle Design-Optimierung ist weniger durch eine Änderung des VHDL Codes als
durch eine Änderung der Synthese-Vorgaben zu erreichen, jedoch können strukturelle
Änderungen der Beschreibung auch Einfluss auf die Umsetzung haben (siehe dazu auch
die verschiedenen Quellen bezüglich VHDL – z.B. afirstlo.pdf Kap. 9 unter
.../Andere_Quellen/VHDL/ im Projektverzeichnis).
Der Assembler
Die gewählten Parameterwerte des SIC liegen innerhalb bestimmter Grenzen. Diese
Grenzen werden zunächst durch die Hardware bestimmt. In welchen Grenzen sich
jedoch diese Werte bewegen können, ist möglicherweise empirisch zu ermitteln. Diese
Grenzwerte sollten dann zur Überprüfung der verwendeten Werte neuer Designs durch
den Assembler herangezogen werden.
Aus den angegebenen Parametern ergibt sich auch der zulässige Wertebereich. Bei der
Verwendung absoluter Werte, sollte der Assembler die Zulässigkeit überprüfen. Ebenso
wie die einzelnen Operanden können die Ergebnisse der Subtraktionen oder in der
Abstraktion darüber liegenden Berechnungen den zulässigen Wertebereich verlassen.
Grundsätzlich sind auch Datenabhängigkeiten zu beachten.
Für Sprünge deren Sprungweite die der maximalen Sprungweite (Argument C)
überschreiten, ist eine geeignete Methode zur Erweiterung eines großen Sprunges zu
mehreren kleinen zu finden. Auch hierbei ist die Abhängigkeit zu den SIC Parametern
zu beachten.
- 32 -
Projektbericht
10.
Single Instruction Computer
Kurzanleitung
Diese Kurzanleitung stellt nicht den Anspruch der Vollständigkeit. Sie soll aber die
wesentlichen Schritte, die zur Erstellung der Datei führen, die zur Programmierung des
FPGA verwendet wird, beschreiben. Dabei wird davon ausgegangen, dass
1. WebPACK (Version 4.1) und ModelSim XE (Version 5.5b) korrekt
installiert sind.
2. In WebPACK ein Projekt korrekt angelegt ist
- Device Family = Spartan2
- Device = xc2s200-5pq208
- Design Flow = XST VHDL
und
3. In ModelSim ebenfalls ein Projekt korrekt angelegt ist
- VHDL Datei des SIC dem Projekt hinzugefügt
- VHDL Datei der Testbench dem Projekt hinzugefügt
- VHDL Dateien nur mit der Endung „.vhd“ verwendet werden
10.1
WebPACK Projekt Manager
Abbildung 6: Die WebPACK Entwicklungsumgebung
- 33 -
Projektbericht
Single Instruction Computer
Das zunächst größte Fenster (auf der rechten Seite) des Projektmanagers ist der Editor
zum editieren des VHDL Codes. Hier können Änderungen direkt an dem VHDL
Quellcode vorgenommen werden. Der Projektmanager verfolgt Veränderungen am
Quellcode und reagiert automatisch auf das Speichern von Änderungen oder das Starten
von z.B. dem Implementierungsprozess ohne vorher gespeichert zu haben. Folglich
werden die Zustandsanzeigen (Haken, Ausrufungszeichen oder Kreuze) für die
einzelnen Prozesse im „Process View“ wieder aktualisiert.
Der „Process View“ bietet die vier übergeordneten Punkte/ Prozesse „Design Entry
Utilities“ (für weitere Werkzeuge), „Synthesize“ (zur Synthese der gewünschten
Hardware Komponenten), „Implement Design“ (Anpassung an das verwendete FPGA)
und „Generate Programming File“. Prozesse bzw. ausführbare Entwicklungsschritte
(ausführbare Teilprogramme) sind als zirkulierende Pfeile dargestellt. Ein Doppelklick
auf einen solchen Pfeil startet den dazugehörigen Prozess.
Solange an dem VHDL Code direkt gearbeitet wird ist es zunächst ausreichend die
Syntax zu checken und bei größeren Veränderungen wiederholt die Synthese komplett
zu starten. Ob das gewünschte Design in oder zu dem gewählten Baustein passt wird
das Starten des Implementierungs-Prozesses beantworten.
Verlaufen beide Hauptprozesse fehlerfrei, kann der Prozess zur Erzeugung der
Programmier-Datei eingestellt und dann gestartet werden. Ein Rechtsklick auf diesen
Prozess öffnet ein Menü, das unter dem Punkt „Properties“ die Eigenschaften und
Einstellungen dieses Prozesses anzeigt. Unter den „General Options“ sollte zunächst nur
„Run Design Rules Checker (DRC)“ und „ASCII Configuration File“ abgehakt sein.
Dieser Prozess wird dann die Programmier-Datei „sip.rbt“ erzeugen.
- 34 -
Projektbericht
10.2
Single Instruction Computer
ModelSim Simulator
Abbildung 7: Alle Ansichten des ModelSim Simulators
Nachdem die VHDL Dateien dem Projekt hinzugefügt worden sind, ist es wichtig sie in
der richtigen Reihenfolge zu kompilieren. Dazu wird unter dem Menüpunkt „Projekt“
das Fenster „Compile Order“ geöffnet. Hier ist die Reihenfolge der Projektdateien so zu
sortieren, dass der Code des SIC zuerst und der Code der Testbench danach kompiliert
wird. Anschließend kann unter dem Menüpunkt „Projekt“ mit „Compile All“ der
Kompiliervorgang gestartet werden.
Nachdem der VHDL Code kompiliert wurde, werden im kleinen Projektfenster oben
links unter dem Reiter „Library“ die angelegten Bibliotheken angezeigt. Mit einem
Doppelklick auf das Symbol der Testbench, wird das komplette Design geladen.
Anschließend wird unter dem Menüpunkt „View“ mit dem Punkt „All“ die in
Abbildung 7 gezeigte Ansicht geöffnet.
Da das Design nun geladen ist, erscheint der Reiter „sim“ im Projektfenster. Hier ist die
„dut“ auszuwählen, woraufhin sich der Inhalt der beteiligten Fenster ändert.
- 35 -
Projektbericht
Single Instruction Computer
Um bei der Simulation den Signalverlauf angezeigt zu bekommen, müssen aus dem
Fenster „Signals“ alle Signale, deren Signalverlauf von Interesse ist, ausgewählt und in
das Fenster „Wave“ gezogen werden. Dies kann z.B. nach Drag & Drop Manier
geschehen.
Als letzter Schritt ist die Simulation unter dem Menüpunkt „Run“ mittels „Run –all“ zu
starten. Zur leichteren Analyse des Signalverlaufs sollte das „Wave“ Fenster auf volle
Größe gestellt werden. Des weiteren ist die Einstellung des Zooms und des gewählten
Zeitabschnittes im Fenster zu beachten.
10.3
Pin-Zuweisung / UCF-Editor
Als letzten Schritt vor der endgültigen Erzeugung der Programmier-Datei, ist die PinZuweisung vorzunehmen. Ohne eine konkrete Pin-Zuweisung werden die Ein- und
Ausgangsports der VHDL-Entity auf unbestimmte Pins verteilt. Damit man also weiß
an welches Pin z.B. das Clock-Signal anzuschließen ist, sollte mit dem UCF-Editor eine
Zuweisung stattfinden. Dabei sind die durch die Hardware gegebenen Einschränkung zu
beachten (s. a. Projektverzeichnis .../Andere_Quellen/SpartanBoardPläne/
PinBelegungen/), denn nicht jedes Pin kann z.B. für das Clock-Signal verwendet
werden.
Mittels eines einfachen Editors oder aber des User Constraints File Editors kann dann
eine UC-Datei erstellt werden, die das konkrete Mapping der Ports zu den Pins
beschreibt.
Der Editor, der in Abbildung 8 gezeigt wird, kann über WebPACK aufgerufen werden.
Dazu ist unter der Toolbox „Design Entry Utilities“ im „Process View“ der Eintrag
„User Constraints“ aufzuklappen und dann per Doppelklick auf „Edit Implementation
Constraints (Constraints Editor)“ das Programm zu starten.
- 36 -
Projektbericht
Single Instruction Computer
Abbildung 8: Constraints Editor
Ist die Ansicht der Ports ausgewählt (Abbildung 8 Mitte links), dann sind alle in der
Entity angegebenen Ports sichtbar. Durch einfaches Editieren des Feldes „Location“,
kann für jeden Port ein bestimmter Pin des FPGA angegeben werden. Die Einträge sind
so wie in der Abbildung zu sehen vorzunehmen. Mit einem großen „P“ und der
Pinnummer direkt dahinter. Der Eintrag ist erst gültig, wenn entsprechend dem Eintrag
eine Zuweisungszeile z.B. „ NET ``led_o<12>`` LOC = ``P33``; “angezeigt wird. Dazu
ist einfach ein weiteres Location Feld anzuklicken oder mit Enter zu bestätigen.
Dieses Ergebnis (UCF Datei) muss gespeichert werden. Nach dem Schließen des
Editors wird man von WebPACK aufgefordert die bisherigen Projektergebnisse und
Einstellung teilweise zurückzusetzen. Nach dem Reset ist dann der
Übersetzungsvorgang zu wiederholen und das Starten des „Generate Programming File“
Programms erzeugt eine Datei zum Programmieren des FPGA, dass jetzt die neue PinZuweisung beachtet.
10.4
Download auf das FPGA
Für den Download auf das FPGA wird ein separates Programm verwendet. Dieses
Programm ist die „BEDLOAD.exe“, die sich der Vollständigkeit halber in dem
Projektverzeichnis unter .../Software/Bedload/ befindet. Dieses Programm verwendet
den Parallelport des PC zum Programmieren des FPGA. Es wurde lediglich auf dem PC
im Digitaltechnik Labor eingesetzt, deswegen können an dieser Stelle keine näheren
- 37 -
Projektbericht
Single Instruction Computer
Informationen zur Installation oder Konfiguration gegeben werden, sofern dies
notwendig sein sollte.
Abbildung 9: Das BEDLOAD Interface
Nach dem Start der BEDLOAD.exe, wird das in Abbildung 9 gezeigt Fenster geöffnet.
Bei der Verwendung des Experimentier-Bords und der dazugehörigen ProgrammierEinheit, ist die Parallelport-Adresse 378 hex einzustellen. Unter dem Menüpunkt File,
ist dann die von WebPACK erstellte Programmier-Datei „sip.rbt“ zu laden. Bevor nun
der Download ausgeführt wird, muss man sich noch vergewissern, dass das
Experimentier-Bord mit Betriebsspannung versorgt ist (grüne LED leuchtet) und
korrekt mit der Programmier-Einheit verbunden ist. Des weiteren muss der
Frequenzteiler des Quarzoszillators auf eine nicht zu hohe Frequenz eingestellt sein.
Nun kann durch klicken auf Download der Programmier-Vorgang gestartet werden.
BEDLOAD quittiert den Vorgang mit einer Meldung, die Auskunft darüber gibt, ob
erfolgreich programmiert wurde oder ob es Fehler gegeben hat. Praktisch sofort nach
Abschluss des Downloads, startet der Programmablauf innerhalb des FPGA.
Entsprechend der Betätigung des Reset-Tasters und der Beschaltung mit dem
Taktsignal, kann nun das SIC-Programm gestartet werden.
Die Erfahrung im Umgang mit BEDLOAD hat gezeigt, dass fehlerhafte
Programmierungen vermieden werden können, wenn das Programm für jeden
Programmier-Vorgang erneut gestartet und eingestellt wird.
- 38 -
Projektbericht
10.5
Single Instruction Computer
Anwendung des Assemblers
Zunächst sollte der Perl Interpreter, der unter .../Software/Perl/ zu finden ist, installiert
sein. Des weiteren sind alle anderen Dateien, die in diesem Verzeichnis liegen,
notwendig: „SIC_ASS.pl“ ist das Perl-Skript, das den Assembler darstellt.
„stat_sic.vhd“ ist die VHDL Datei mit dem statischen Anteil des SIC (sozusagen dem
Gerüst) und „source.txt“ ist eine Textdatei mit Pseudo-Code, der als Beispiel für ein
SIC-Assembler-Programm dienen soll.
Alle diese Dateien müssen sich im gleichen Verzeichnis befinden. Dieses Verzeichnis
muss entweder den Perl Interpreter enthalten oder er muss im Pfad des Systems
eingetragen sein.
Die Vorgehensweise ist dann wie folgt:
Zunächst erstellt man eine Textdatei mit dem gewünschten Pseudo-Code. Dazu kann
ein Textverarbeitungsprogramm oder ein einfache Editor verwendet werden. Der
Pseudo-Code muss im Normalfall einen Eintrag für eine temporär verwendbare Adresse
im Datenspeicher, verschiedene Einträge zur Initialisierung des Datenspeichers und das
Programm selber enthalten. Einträge zur Parametrierung des SIC sind zunächst
optional. Es kann aber auch die Beispieldatei verwendet werden.
Um den Pseudo-Code dann zu assemblieren, startet man den Assembler, in dem man
einfach das Skript „SIC_ASS.pl“ ausführt. Im Laufe der Abarbeitung des Skripts, wird
der „Source-Code“ übersetzt und in das VHDL Gerüst eingesetzt. Das Ergebnis ist dann
anhand der vom Assembler erstellten VHDL Datei „sic_ass.vhd“ zu begutachten.
Diese Datei wird dann für die Erzeugung der FPGA Programmierdatei verwendet und
in den weiter oben beschriebenen Kompiliervorgang mit WebPACK eingesetzt.
Das Perl-Skript selber wird im einzelnen folgende Schritte abarbeiten:
Als erstes wird der Name der Quelldatei erfragt. Dieser muss vollständig mit Endung
und gegebenenfalls Pfad angegeben werden. Anschließend erfragt das Skript, ob die
Quelldatei die Parameter für den SIC enthält oder nicht. Wird hier mit nein (n/N)
geantwortet, so werden die Werte aller notwendigen Parameter folgend einzeln erfragt.
Andernfalls ermittelt das Skript die Parameter aus der Datei.
Im nächsten Abschnitt bestimmt das Skript alle weiteren Komponenten, die notwendig
sind um eine vollständige Beschreibung eines SIC in VHDL zu erhalten: Die temporäre
Adresse des Datenspeichers, die für alle notwendigen Zwischenschritte verwendet wird,
die Daten zur Initialisierung des Datenspeichers und die Pseudo-Befehle.
Diese Komponenten werden in den entsprechenden VHDL Code übersetzt und in das
VHDL Gerüst eingesetzt. Abschließend wird die Zieldatei erzeugt und der komplette
VHDL Code hinein geschrieben.
- 39 -
Projektbericht
Single Instruction Computer
11.
Bibliographie und Referenzen
11.1
Bücher
[CPOAD]
David A. Patterson, John L. Hennessy, Computer Organization and
Design – The Hardware / Software Interface, 2. Edition, Morgan
Kaufmann Publishers, San Mateo, (1998), ISBN: 155860491X
[CPOAA]
William Stallings, Computer Organization and Architecture, 5. Edition,
Prentice Hall, Upper Saddle River, (2000), ISBN: 0-13-085263-5
[SWENG]
Ian Sommerville, Software Engineering, 6. Edition, Addison-Wesley,
(2001), ISBN: 0-201-39815-X
11.2
Webseiten
[URISC]
Douglas W. Jones, The Ultimate RISC,
http://www.cs.uiowa.edu/~jones/arch/risc/, University of Iowa,
(Nov 2001)
[THSIC]
Sarah Mount, The Single Instruction Computer,
http://www.infradead.org/~snim2/Undergrad/SIC/documents/Proposal/Pr
oposal.html, (Okt 1999/ Nov 2001)
[NOSIC]
Single Instruction Computer,
http://www.cas.mcmaster.ca/~cs1md3/topics/topics-sic.html, (Nov 2001)
[BURSB]
Burch Electronic Designs, Making FPGA Prototyping Easy,
http://www.burched.com.au/, (Nov 2001)
11.3
Andere Quellen
[RSTSK]
Prof. Dr. Thomas Risse, Rechner-Strukturen, Skript zur Vorlesung RST
des Fachbereichs Elektrotechnik/Informatik der Hochschule Bremen,
www.weblearn.hs-bremen.de/risse/rst/, (2000)
[FPGAV]
Carsten Thiele, Klaus Bicker, Bericht zum Vortrag FPGA, Vortrag im
Rahmen des RST-Labors des Fachbereichs Elektrotechnik/Informatik der
Hochschule Bremen, www.weblearn.hsbremen.de/risse/RST/SS01/FPGA/FPGA.pdf, (Sep 2001)
- 40 -
Projektbericht
Single Instruction Computer
Anhang
Verwendete Hardware und Software
Die verwendete Hardware besteht im Kern aus einem FPGA Chip der Firma Xilinx:
Spartan II XC2S200, die genaue Bezeichnung des im Entwicklungstool verwendeten
Bausteins ist xc2s200-5pq208-XST.
Als Experimentier-System wird das B3-Spartan2+ FPGA Board der Firma Burch
Electronic Designs verwendet. Nähere Informationen sowie Abbildungen sind in
[BURSB] zu finden.
Die Pinbelegungen des FPGA und des Experimentierbords sind unter /Andere_Quellen/
SpartanBoardPläne/PinBelegungen und ../ Spartan_FPGA_Pläne / zu finden.
Synthese- / Compiler-Berichte in Auszügen
Auszüge aus dem Synthese-Bericht:
---- Source Options
.
.
RAM Style
: Auto
Mux Style
: Auto
.
.
Diese Synthese Einstellungen geben unter anderem an, dass die Art und Weise, wie
RAM und Multiplexer synthetisiert werden sollen, automatisch durch den Compiler
bestimmt werden.
---- General Options
Optimization Criterion : Speed
Optimization Effort
:1
.
.
Unter den allgemeinen Einstellungen ist z.B. das Optimierungs-Kriterium (hier
Geschwindigkeit der resultierenden Schaltung) und der dazu angesetzte Aufwand zu
finden.
Synthesizing Unit <sip>.
Related source file is C:/xilinx_webpack/bin/FN_SIP/fn_sip/fn_sip.vhd.
WARNING:Xst:646 - Signal <instruction_s<13>> is assigned but never used.
WARNING:Xst:646 - Signal <instruction_s<12>> is assigned but never used.
.
.
Im Verlauf der Synthese werden unter Umständen Fehlermeldungen, die unbedingt zu
beheben sind und Warnungen ausgegeben. Speziell die oben angegebenen Warnungen
- 41 -
Projektbericht
Single Instruction Computer
stellen jedoch kein Problem dar. Aufgrund der verwendeten Daten und SBN
Anweisungen, kann es sein, dass z.B. eine Befehlswortbreite von 16 Bit notwendig ist,
einzelne Bits davon aber innerhalb dieses Programms nie abgefragt werden. Sie werden
gegebenenfalls bei der Optimierung entfernt.
Summary:
inferred
inferred
inferred
inferred
95 D-type flip-flop(s).
3 Adder/Subtracter(s).
1 Comparator(s).
95 Multiplexer(s).
In der Zusammenfassung werden die gefundenen Grundbausteine und ihre Anzahl
angegeben.
Macro Statistics
# Registers
16-bit register
4-bit register
1-bit register
# Multiplexers
15-bit 8-to-1 multiplexer
2-to-1 multiplexer
# Adders/Subtractors
15-bit subtractor
4-bit adder
# Comparators
15-bit comparator less
: 77
:1
:1
: 75
: 49
:2
: 47
:3
:1
:2
:1
:1
Die Macro Statistik gibt dann Aufschluss darüber, welche Komponenten durch die
Verknüpfung der in der Zusammenfassung aufgezählten Grundbausteine synthetisiert
werden.
Timing Summary:
--------------Speed Grade: -5
Minimum period: 16.704ns (Maximum Frequency: 59.866MHz)
Minimum input arrival time before clock: 10.460ns
Maximum output required time after clock: 8.449ns
Maximum combinational path delay: No path found
Die Timing-Zusammenfassung gibt Informationen über die wahrscheinlich maximal zu
verwendende Taktfrequenz an. Diese Information ist wichtig für die spätere Einstellung
des Frequenzteilers des Quarzoszillator auf dem Experimentier-Bord.
Auszüge aus dem Übersetzungs-Bericht:
Checking timing specifications ...
Checking expanded design ...
- 42 -
Projektbericht
Single Instruction Computer
NGDBUILD Design Results Summary:
Number of errors: 0
Number of warnings: 0
Der Übersetzungs-Prozess überprüft unter anderem wie das Synthese-Ergebnis zur
gewählten Hardware passt. Sollten die Spezifikationen des gewählten Bausteins nicht
eingehalten werden, so würden hier Warnungen oder Fehlermeldungen ausgegeben
werden.
Auszüge aus dem Mapping-Bericht:
Section 6 - IOB Properties
-------------------------+-------------------------------------------------------------------------------------------------------+
| IOB Nam| Type | Direction | IO Standard | Drive | Slew | Reg (s) | Resistor | IOB |
|
|
|
|
| Strength | Rate |
|
| Delay |
+-------------------------------------------------------------------------------------------------------+
| clk_i
| GCLKIOB | INPUT | LVTTL
|
|
|
|
|
|
| led_o<0> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<10>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<11>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<12>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<13>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<14>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<15>| IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<1> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<2> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<3> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<4> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<5> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<6> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<7> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<8> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| led_o<9> | IOB | OUTPUT | LVTTL
| 12
| SLOW |
|
|
|
| reset_i
| IOB | INPUT | LVTTL
|
|
|
|
|
|
+-------------------------------------------------------------------------------------------------------+
Der Mapping-Bericht gibt z.B. Auskunft über die verwendeten Ports.
- 43 -
Projektbericht
Single Instruction Computer
Inhalt des Projektverzeichnisses „Projekt_SIC“
Quellen
o Andere_Quellen
DLXSim
M17einMISC-Dateien
PIC18C
RST_Assembler_einfachProz-Dateien
Spartan_FPGA_Pläne
SpartanBoardPläne
SurveyStackComputersAuchM17-Dateien
VHDL
WebPackTutorial
XilinxISEtutorial
o CtBerichte
o FPGA_Bericht
o SIC_sites
Final year CST projects suggestions.htm
GNOME_IDE_SIC_Manual-Dateien
Homework.htm
Lab-CIS 577 Computer Architecture.htm
Part II Project A Single Instruction Computer-Dateien
Single Instruction Computer-Dateien
The Single Instruction Computer-Dateien
The Ultimate RISC
o Weiterf_Quellen
Control.jpg
Datapath.jpg
DLX_script.pdf
CPU-Design-HOWTO-html.tar
dv_Vorles_fhAugsb.pdf
fpgacpu_org - FPGA CPU News.htm
proz-4.pdf
Software
o Perl
Doku
o Warp_52
o webPack_alt
o WebPack4
Beschreibung:
-
DLXSim
Projektbericht als HTML-Dokument über einen DLX-Simulator.
-
M17einMISC
Ausschnitt einer Auflistung spezieller Prozessor-Architekturen – speziell
M17 als ein Minimum Instruction Set Computer.
-
PIC18C
- 44 -
Projektbericht
Single Instruction Computer
Teile des Referenz Manuals zum PIC 18 C Mikrocontrollers als pdfDokumente – Beispiel für einen „einfachen“ Mikroprozessor, der
mehrfach für den Einstieg in µProzessor-Architekturen empfohlen
wurde.
-
RST_Assembler_einfachProz
Homepage der Vorlesung „Hardwarearchitektur“ von Dr. Karl Bühler
(Uni Freiburg) – speziell Kapitel 6 als Beschreibung zur Realisierung
eines „einfachen Prozessors“.
-
Spartan_FPGA_Pläne
Dokumentation und Schaltpläne zur Spartan-II FPGA Familie.
-
SurveyStackComputersAuchM17
Eine Übersicht zu Computern mit Stack-Hardware Unterstützung –
speziell auch der als MISC geltende M17 (s.o.).
-
VHDL
Verschiedene Quellen zur Programmiersprache VHDL (Manuals,
Cookbooks, Links und diverse Bibliotheken). Speziell „The VHDL
Resource Page.htm“ ist eine reichhaltige Quelle.
-
WebPackTutorial
Tutorials zu der Xilinx Entwicklungsumgebung „WebPack“.
-
XilinxISEtutorial
Tutorial zu der Xilinx Entwicklungsumgebung „ISE“.
-
CtBerichte
Artikel zum Thema MISC der Ausgabe 07/91.
-
FPGA_Bericht
Bericht im Rahmen des RST-Labors über das XC4010XL FPGA von
XILINX. Speziell die Beschreibung der Komponenten des FPGA und der
Implementierung einer CPU darauf sind hilfreich.
-
GNOME_IDE_SIC_Manual
Manual für eine SIC-Entwicklungsumgebung (IDE).
-
Homework.htm
Aufgabenblatt mit Fragen zum SIC.
-
Final year CST projects suggestions.htm
Vorschläge zu Projektthemen – speziell SIC.
-
Lab-CIS 577 Computer Architecture.htm
Beschreibung zu einer Laboraufgabe zu einem SIC.
-
Part II Project A Single Instruction Computer
Homepage zu einem Projekt über einen SIC.
- 45 -
Projektbericht
Single Instruction Computer
-
Single Instruction Computer
Ein HTML-Dokument das den SIC und die sbn-Instruktion einführend
gut erläutert.
-
The Single Instruction Computer
Weitere HTML-Dokumente zu einem SIC-Projekt.
-
The Ultimate RISC
Beschreibung einer ultimativen RISC Architektur.
-
Control.jpg
Ein Entwurf von mir für eine Multicycle Steuereinheit (nach [CPOAD]).
-
Datapath.jpg
Ein Entwurf von mir für einen Multicycle Datenpfad (nach [CPOAD]).
-
DLX_script.pdf
Kurzes Skript zur Architektur der DLX.
http://www.inf.tu-dresden.de/~ap3/PAMP/DLX_script.pdf
-
CPU Design HOW-TO
Dieses HOW-TO ist ein HTML-Dokument, das einen Einblick in die
Themen CPU Design und CPU Architekturen gibt.
-
dv_Vorles_fhAugsb.pdf
Skript zur Vorlesung „Datenverarbeitungssysteme“ von Prof. Stark (FH
Augsburg).
-
fpgacpu_org - FPGA CPU News.htm
Webseite zum Thema Prozessor-Design auf FPGAs von GRAY Research
LLC.
-
proz-4.pdf
Unterlagen der BTU Cottbus zum Thema Prozessor-Architekturen.
-
ActivePerl-5.6.1.626-MSWin32-x86-multi-thread.msi
Installationspaket für die Skript-Sprache Perl auf einer MS Windows
Umgebung.
-
Perl Tutorial.htm
Ein Tutorial zu Perl als HTML-Dokument vom National Center for
Supercomputing Applications (NCSA).
-
pickingUpPerl.pdf
Ein Tutorial zu Perl, das als pdf-Dokument und als HTML-Dokument
vorliegt. Es ist nach der GNU Free Documentation License lizenziert.
Als leichte Kost zum Einstieg geeignet.
-
Robert's Perl Tutorial.htm
Noch ein Tutorial zu Perl, das als HTML-Dokument vorliegt. Nicht so
übersichtlich, aber etwas breiter angelegt.
- 46 -
Projektbericht
Single Instruction Computer
-
WARP_52
Entwicklungsumgebung für VHDL.
-
webPack_alt und WebPack4
Entwicklungsumgebung inklusive Simulator für VHDL und VERILOG.
VHDL Quellcode des SIC
--####################################################
--#
--# R. Oldenburger
--# T. Risse
--# S. Simon
--#
--# Version 1.3.0 31. Januar 2002
--# Datei "sip.vhd"
--# SIP -> Single Instruction Processor
--#
--#####################################################
--#####################################################
--#
--# Change log
--# Letzte Aenderung 6. Februar 2002
--#
--# Erlaeuterungen hinzugefuegt
--#
--# Dies ist die korrekte Art und Weise einen Prozess
--# mit Takt und Reset zu verknüpfen, um Flip-Flops zu
--# erzeugen. Desweiteren sind jetzt alle nicht takt--# abhaengigen Elemente als Concurrent Statements ausgefuehrt.
--#
--######################################################
--######################################################
--#
--# Kommentare:
--#
--# Es fehlt weiterhin eine Ergebniskontrolle, die die
--# Weiter-Verarbeitung des Programms nach einem Overflow
--# verhindert.
--#
--#######################################################
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_SIGNED.ALL;
- 47 -
Projektbericht
Single Instruction Computer
ENTITY sip IS
PORT (clk_i
: IN STD_ULOGIC;
reset_i
: IN STD_ULOGIC;
led_o
: OUT STD_ULOGIC_VECTOR(15 downto 0)
-- LED-Ausgabeport auf LED leiste zu mappen
);
END;
-- Parameterliste
ARCHITECTURE rtl OF sip IS
-- Datenwortlaenge
CONSTANT data_wl_c
: INTEGER := 16;
-- Anz. Datenworte im Datenspeicher
CONSTANT reg_nr_c
: INTEGER := 8;
-- Anz. Befehlsworte im Programmspeicher
CONSTANT line_nr_c
: INTEGER := 9;
-- 1. Argument in Instr hat n Bit
CONSTANT instr_argl1_c
: INTEGER := 5;
-- 1. u 2. Arg => maxAnz addrbare Datenworte
CONSTANT instr_argl2_c
: INTEGER := 5;
-- 3. Argument => max Sprungweite +/CONSTANT instr_argl3_c
: INTEGER := 4;
-- Nr. des obersten/letzten reservierten Registers
CONSTANT data_reg_reserv_nr_c : INTEGER := 2;
-- Befehlswortlaenge
CONSTANT instr_wl_c
: INTEGER :=
instr_argl1_c + instr_argl2_c + instr_argl3_c;
-- groesste Sprungweite vorwaerts
CONSTANT MAX_jmp_c
: INTEGER := 2 ** (instr_argl3_c - 1) - 1;
-- groesste Sprungweite rueckwaerts
CONSTANT MIN_jmp_c
: INTEGER := 2 ** (instr_argl3_c - 1) * (-1);
-- Groesster Operandenwert
CONSTANT MAX_value_c
: INTEGER := 2 ** (data_wl_c - 1) - 1;
-- Kleinster Operandenwert
CONSTANT MIN_value_c
: INTEGER := 2 ** (data_wl_c - 1) * (-1);
-- Datenspeicher Definition
TYPE data_reg_t IS ARRAY (NATURAL RANGE 0 TO reg_nr_c-1) OF
STD_ULOGIC_VECTOR (data_wl_c-1 DOWNTO 0);
-- Programmspeicher Definition
TYPE Program_type IS ARRAY (1 TO line_nr_c) OF
STD_ULOGIC_VECTOR (instr_wl_c-1 DOWNTO 0);
- 48 -
Projektbericht
Single Instruction Computer
-- SBN Anweisungen im Programmspeicher
CONSTANT Program : Program_type := Program_type'(
"00111001110001", --> 1
"00111001010001", --> 2
"00011000110001", --> 3
"00011001110001", --> 4
"00111001110001", --> 5
"00111001100001", --> 6
"00100001000001", --> 7
"00100001110001", --> 8
"00001000100000" --> 9
);
SIGNAL instruction_s : STD_ULOGIC_VECTOR (instr_wl_c-1 DOWNTO 0);
SIGNAL diff_vec_s
: STD_ULOGIC_VECTOR (data_wl_c-1 DOWNTO 0);
SIGNAL data_reg_s : data_reg_t;
-- Programmzaehler hat nur Werte von 1 bis ..
SIGNAL pc_s
: INTEGER RANGE 1 TO line_nr_c;
SIGNAL pc_incr_s
: INTEGER RANGE 1 TO line_nr_c;
SIGNAL pc_jmp_s
: INTEGER RANGE 1 TO line_nr_c;
-- Diff., Op. haben nur Werte zwischen .. und ..
SIGNAL diff_s
: INTEGER RANGE MIN_value_c TO MAX_value_c;
SIGNAL op_a_s
: INTEGER RANGE MIN_value_c TO MAX_value_c;
SIGNAL op_b_s
: INTEGER RANGE MIN_value_c TO MAX_value_c;
SIGNAL adr_a_s
: INTEGER RANGE 0 TO reg_nr_c-1;
SIGNAL adr_b_s
: INTEGER RANGE 0 TO reg_nr_c-1;
SIGNAL jmp_range_s : INTEGER RANGE MIN_jmp_c TO MAX_jmp_c;
BEGIN
-- concurrent statements
-- Naechste SBN Anweisung
instruction_s <= Program(pc_s);
-- Adressen im Datenpeicher
adr_a_s <= conv_integer
(UNSIGNED(instruction_s(instr_wl_c - 1 downto
instr_wl_c - instr_argl1_c)));
adr_b_s <= conv_integer
(UNSIGNED(instruction_s(instr_wl_c - instr_argl1_c - 1 downto
instr_wl_c - instr_argl1_c - instr_argl2_c)));
-- Sprungweite bei negativem Ergebnis
jmp_range_s <= conv_integer (SIGNED(instruction_s
(instr_argl3_c - 1 downto 0)));
- 49 -
Projektbericht
Single Instruction Computer
-- Daten aus Datenspeicher
op_a_s <= conv_integer (SIGNED(data_reg_s(adr_a_s)));
op_b_s <= conv_integer (SIGNED(data_reg_s(adr_b_s)));
-- Ergebnis
diff_s <= op_a_s - op_b_s;
diff_vec_s <= STD_ULOGIC_VECTOR(conv_std_logic_vector
(diff_s, data_wl_c));
-- Die naechsten moeglichen Programmzaehler
pc_incr_s <= pc_s + 1;
pc_jmp_s <= pc_s + jmp_range_s;
-- Ausgabe auf LEDs
led_o <= data_reg_s (0);
-- clocked process
reg : PROCESS (clk_i, reset_i)
Begin
IF reset_i = '0' THEN
-- Datenspeicher loeschen
FOR i IN data_reg_reserv_nr_c + 1 TO reg_nr_c - 1 LOOP
data_reg_s(i) <= (OTHERS => '0');
END LOOP;
-- Die Register 0, 1 und 2 sind per Definition reserviert
-- Standard Ergebnis-Register (0) initialisieren
data_reg_s (0) <= "1010101010101010";
-- Datenregister 1,2 fuer HALT initialisiert
data_reg_s (1) <= "0000000000000000";
data_reg_s (2) <= "0000000000000001";
-- Alle weiteren Register sind abhaengig vom Programminhalt
-- Programmdaten initialisieren
data_reg_s (5) <= "0000000000011111";
data_reg_s (6) <= "0000000000000001";
data_reg_s (7) <= "0011110010000111";
-- Programmzaehler initialisiert
pc_s <= 1;
-- Dies ist der eigentliche Prozess
ELSIF (clk_i'EVENT AND clk_i='1') THEN
- 50 -
Projektbericht
Single Instruction Computer
-- Alle Register aktualisieren,
-- zweifelsfrei Abhaengigkeit zum Taktsignal schaffen
-- und damit kompletten Datenspeicher als Flip-Flops zu synthetisieren.
-- Vorgehensweise ohne diese (widerspuerchliche) Schleife schafft
-- Missverstaendnisse bei der Interpretation des Datenspeichers
-- durch das Synthese Programm bei Versionen aelter als 4.1.
FOR i IN 0 TO reg_nr_c - 1 LOOP
IF adr_a_s = i THEN
-- Ergebnis zurueckschreiben (nur nicht in reservierte Register)
IF i > data_reg_reserv_nr_c THEN
data_reg_s(adr_a_s) <= diff_vec_s;
data_reg_s(0) <= diff_vec_s; -- Ergebnis zur Ausgabe
END IF;
END IF;
END LOOP;
-- Neuer Programmzaehler
IF diff_s < 0 THEN pc_s <= pc_jmp_s;
ELSE pc_s <= pc_incr_s;
END IF;
END IF;
End PROCESS;
END rtl;
VHDL Quellcode der Testbench
--####################################################
--#
--# R. Oldenburger
--# T. Risse
--# S. Simon
--#
--# Version 1.1 23. Januar 2002
--# Datei "sip_tb.vhd"
--# SIP -> Single Instruction Processor
--# TB -> TestBench
--#
--#####################################################
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_SIGNED.ALL;
- 51 -
Projektbericht
Single Instruction Computer
ENTITY sip_tb IS
-- keine Ports fuer Testbench noetig
END sip_tb;
ARCHITECTURE rtl OF sip_tb IS
-- Clock und Reset Parameter
CONSTANT ClkStartVal : STD_ULOGIC := '0';
CONSTANT ClkDelay : TIME := 10 NS;
CONSTANT ClkWidth : TIME := 10 NS;
CONSTANT ClkPeriod : TIME := 20 NS;
CONSTANT ClkStop
: TIME := 20*16705 NS;
CONSTANT resDelay : TIME := 25 NS;
-- Bekanntmachen des Testobjekts (einzusetzende Komponente)
COMPONENT sip
PORT (
clk_i
: IN STD_ULOGIC;
reset_i
: IN STD_ULOGIC;
led_o : OUT STD_ULOGIC_VECTOR(15 downto 0)
);
END COMPONENT;
SIGNAL clk_i, reset_i : STD_ULOGIC;
SIGNAL led_o
: STD_ULOGIC_VECTOR(15 downto 0);
begin
-- Design Under Test
DUT : sip
-- Port Map verbindet Ein- und Ausgaenge des DUT
-- mit denen der Testbench
PORT MAP (
clk_i => clk_i,
reset_i => reset_i,
led_o => led_o
);
clkGen : PROCESS
variable counter : integer;
- 52 -
Projektbericht
Single Instruction Computer
-- Prozess erzeugt Clock- und Resetsignal
BEGIN
clk_i <= ClkStartVal; -- so beginnt der Clock
reset_i <= '0','1' after resDelay; -- so verlaeuft der Reset
ClkLoop : WHILE now < ClkStop LOOP -- Clock bis dahin erzeugen
-- Dies erzeugt das Taktsignal
clk_i <= TRANSPORT NOT ClkStartVal AFTER ClkDelay,
ClkStartVal AFTER ClkWidth + ClkDelay;
WAIT FOR ClkPeriod;
END LOOP ClkLoop;
-- Abbruch und Ausgabe einer Meldung nach Ende der Signalerzeugung
ASSERT false
REPORT "Clockgeneration was stopped due to ClkStop"
SEVERITY ERROR;
WAIT;
END PROCESS ClkGen;
END rtl;
Perl Quellcode des „Assemblers“
###############################################
#
# Roul Oldenburger
# Thomas Risse
# Sven Simon
#
# Version 1.0 12. Februar 2002
#
# SIC_ASS -> Single Instruction Computer Assembler
#
###############################################
###############################################
#
# Change log
# Letzte Änderung 12.Februar 2002
#
###############################################
- 53 -
Projektbericht
Single Instruction Computer
###############################################
#
# Kommentare:
#
# Es war geplant den Assemble-Vorgang in ein
# Unterprogramm zu fassen. Es gelang mir jedoch
# nicht beim Unterprogramm-Aufruf Arrays zu
# uebergeben.
#
# Es ist nur wenig Code enthalten, der Eingaben,
# Werte, etc. überprüfen. Hier besteht Nach# besserungsbedarf!
#
# Der Code wurde inkrementell auf seine Funk# tionalitaet getestet. Teilweise sind auch
# Grenzwerte getestet worden. Hier besteht
# ebenfalls Nachbesserungsbedarf!
#
###############################################
# Alle Fehlermeldungen und Warnungen
use strict;
use warnings;
# Deklarationen Parameter
my $datenwortbreite = 16;
my $anz_datenworte = 8;
my $anz_befehlsworte = 9;
my $arg1 = 5;
my $arg2 = 5;
my $arg3 = 4;
my $nr_reserv_reg = 2;
# Deklarationen Skript
my $anz_par = 7;
my $temp_adr = undef;
my $eingabe = undef;
my $temp = undef;
my $pline = undef;
my $line = undef;
my @programm = undef;
my @parameter = undef;
my @target = undef;
my @daten = undef;
- 54 -
Projektbericht
Single Instruction Computer
# Deklarationen Dateinamen
my $vhdl_code = "stat_sic.vhd";
my $target_code = "sic_ass.vhd";
my $source_code = undef;
# Begrüßung
print "\n\nHallo !\nDies ist der SIC Assembler.\n\n\n";
print "Bitte geben sie den Namen der Quelldatei ein: ";
chomp($source_code = <STDIN>);
# SIC-Parameter jetzt eingeben oder in Pseudo-Code enthalten?
print "Sind die Parameter des SIC in der Assembler-Datei enthalten? (j/n/a)";
do {
$eingabe = <STDIN>;
chomp $eingabe;
if ($eingabe =~ /^(a|A)$/) {
print "Abbruch!\n\n";
die;
}
} until ($eingabe =~ /^(j|J|y|Y|n|N)$/);
if ($eingabe =~ /^(j|J|y|Y)$/) {
print "\nDie SIC Parameter werden zusammen mit dem Pseudo-Code
eingelesen.\n";
# Unterprogrammaufruf zum Auslesen der Parameter aus der Quelldatei
@parameter = setpar ($source_code);
# Unterprogrammaufruf zum Auslesen der temporaeren Adresse
$temp_adr = settemp ($source_code);
# Unterprogrammaufruf zum Auslesen Daten-Initialisierung
@daten = setdat ($source_code);
# Unterprogrammaufruf zum Auslesen und Uebersetzens des Pseudo-Codes
@programm = translate ($source_code);
# "Programm" und Parameter in den VHDL-Code einbauen
- 55 -
Projektbericht
Single Instruction Computer
open (FILE, "<$vhdl_code") or die "VHDL-Code kann nicht geoeffnet werden";
while ($line = <FILE>) {
if ($line =~ /^ *-- Parameterliste/) {
push (@target, "\-\- Parameterliste\n");
foreach $pline (@parameter) {
print $pline;
push (@target, "$pline");
}
} elsif ($line =~ /^ *-- Programm in Programmspeicher laden/) {
push (@target, "\-\- Programm in Programmspeicher laden\n");
foreach $pline (@programm) {
print $pline;
push (@target, "$pline");
}
} elsif ($line =~ /^ *-- Programmdaten initialisieren/) {
push (@target, "\-\- Programmdaten initialisieren\n");
foreach $pline (@daten) {
print $pline;
push (@target, "$pline");
}
} else {
push (@target, "$line");
}
}
close (FILE);
print "\nStatischer und dynamischer VHDL-Code zusammengefuegt.\n\n";
# Zurueckschreiben der Ergebnisdatei
open (FILE, ">$target_code") or die "Zieldatei kann nicht erstellt werden";
print FILE @target;
close (FILE);
print "\nZieldatei ($target_code) geschrieben.\n\n";
} else {
# SIC-Parameter eingeben
print "\nDie SIC Parameter koennen jetzt eingegeben werden.\n";
print "Datenwortbreite ($datenwortbreite Bit beibehalten = 'enter'): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$datenwortbreite = $temp;
}
print "\nDatenwortbreite sind $datenwortbreite Bits.\n\n";
print "\nBreite des 1. Befehlsarguments ($arg1 Bit): ";
- 56 -
Projektbericht
Single Instruction Computer
chomp($temp = <STDIN>);
if ($temp ne "") {
$arg1 = $temp;
}
print "\n1. Argument hat $arg1 Bit.\n\n";
print "\nBreite des 2. Befehlsarguments ($arg2 Bit): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$arg2 = $temp;
}
print "\n2. Argument hat $arg2 Bit.\n\n";
print "\nBreite des 3. Befehlsarguments ($arg3 Bit): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$arg3 = $temp;
}
print "\n3. Argument hat $arg3 Bit.\n\n";
print "\nAnzahl der Datenworte (Groesse des Datenspeichers
$anz_datenworte Worte): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$anz_datenworte = $temp;
}
print "\nDatenspeicher soll $anz_datenworte Datenworte umfassen.\n\n";
print "\nAnzahl der Befehlsworte im Programmspeicher ($anz_befehlsworte
Befehle): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$anz_befehlsworte = $temp;
}
print "\nProgrammspeicher umfasst $anz_befehlsworte SBNAnweisungen.\n\n";
print "\nReservierte Adressen im Datenspeicher (bis Register Nr.
$nr_reserv_reg): ";
chomp($temp = <STDIN>);
if ($temp ne "") {
$nr_reserv_reg = $temp;
}
print "\nRegister 0 bis $nr_reserv_reg sind reserviert.\n\n";
# Uebersetzung in VHDL und Zusammenfassung der Parameter
push (@parameter, "CONSTANT data_wl_c : INTEGER :=
$datenwortbreite;\n");
- 57 -
Projektbericht
Single Instruction Computer
push (@parameter, "CONSTANT reg_nr_c : INTEGER :=
$anz_datenworte;\n");
push (@parameter, "CONSTANT line_nr_c : INTEGER :=
$anz_befehlsworte;\n");
push (@parameter, "CONSTANT instr_argl1_c : INTEGER := $arg1;\n");
push (@parameter, "CONSTANT instr_argl2_c : INTEGER := $arg2;\n");
push (@parameter, "CONSTANT instr_argl3_c : INTEGER := $arg3;\n");
push (@parameter, "CONSTANT data_reg_reserv_nr_c : INTEGER :=
$nr_reserv_reg;\n");
# Unterprogrammaufruf zum feststellen der temporaeren Adresse
$temp_adr = settemp ($source_code);
# Unterprogrammaufruf zum Auslesen Daten-Initialisierung
@daten = setdat ($source_code);
# Unterprogrammaufruf zum Auslesen und Uebersetzens des Pseudo-Codes
@programm = translate ($source_code);
# "Programm" und Parameter in den VHDL-Code einbauen
open (FILE, "<$vhdl_code") or die "VHDL-Code kann nicht geoeffnet werden";
while ($line = <FILE>) {
if ($line =~ /^ *-- Parameterliste/) {
push (@target, "\-\- Parameterliste\n");
foreach $pline (@parameter) {
print $pline;
push (@target, "$pline");
}
} elsif ($line =~ /^ *-- Programm in Programmspeicher laden/) {
push (@target, "\-\- Programm in Programmspeicher laden\n");
foreach $pline (@programm) {
print $pline;
push (@target, "$pline");
}
} elsif ($line =~ /^ *-- Programmdaten initialisieren/) {
push (@target, "\-\- Programmdaten initialisieren\n");
foreach $pline (@daten) {
print $pline;
push (@target, "$pline");
}
} else {
push (@target, "$line");
}
- 58 -
Projektbericht
Single Instruction Computer
}
close (FILE);
print "\nStatischer und dynamischer VHDL-Code zusammengefuegt.\n\n";
# Zurueckschreiben der Ergebnisdatei
open (FILE, ">$target_code") or die "Zieldatei kann nicht erstellt werden";
print FILE @target;
close (FILE);
print "\nZieldatei ($target_code) geschrieben.\n\n";
}
#Ende des Hauptprogramms
###############################################################
# Temporaere Adresse fuer SBN-Sequenzen ermitteln
sub settemp {
my $source = shift;
my $temp_reg = undef;
open (FILE, "<$source") or die "Quelltext kann nicht geoeffnet werden";
while ($line = <FILE>) {
if ($line =~ /^TMP +([0-9]+) */) {
print "TMP\n";
print "Temporaere Adresse : $1\n\n";
$temp_reg = dez2bin ($arg1, $1);
}
}
if ($temp_reg eq "") {
die "Keine Temporaere Adresse angegeben\n";
}
print "Temporaere Adresse festgelegt.\n\n";
return $temp_reg;
}
# Programm-Daten für die Initialisierung auslesen
sub setdat {
my $source = shift;
my @dat = undef;
open (FILE, "<$source") or die "Quelltext kann nicht geoeffnet werden";
- 59 -
Projektbericht
Single Instruction Computer
while ($line = <FILE>) {
if ($line =~ /^DAT +([0-9]+) *, *(\-[0-9]+|[0-9]+) */) {
print "DAT\n";
print "Adresse : $1\n";
print "Wert : $2\n\n";
if ($2 > (2**($datenwortbreite-1)-1) or $2 < (2**($datenwortbreite-1)*(-1))) {
print "Wertebereich : ";
print (2**($datenwortbreite-1)-1);
print " bis ";
print (2**($datenwortbreite-1)*(-1));
die "\nDatum ausserhalb des gueltigen Wertebereichs\n";
}
my $val = dez2bin ($datenwortbreite, $2);
if ($1 <= $nr_reserv_reg) {
die "Es wird versucht eine der reservierten Adressen ($1) zu
beschreiben\n";
} elsif ($1 > ($anz_datenworte-1)) {
die "Adresse $1 liegt ausserhalb des gueltigen Bereichs (0 bis
$anz_datenworte-1)\n";
}
push (@dat, "data_reg_s ($1) <= \"$val\";\n");
}
}
close (FILE);
print "Daten-Initialisierung erstellt.\n\n";
return @dat;
}
# Pseudo-Code uebersetzen
# Dieses Unterprogramm fuer weitere Pseudo-Befehle erweitern !!!
sub translate {
my $source = shift;
my @prog = undef;
my $line_cnt = 1;
my $line = undef;
open (FILE, "<$source") or die "Quelltext kann nicht geoeffnet werden";
while ($line = <FILE>) {
print "Zeile: $line";
# MOV Befehl auswerten
if ($line =~ /^(MOV|CP|MOVE|COPY) +([0-9]+) *, *([0-9]+) *(,| *) *([0-9]*) */) {
print "MOV\n";
- 60 -
Projektbericht
Single Instruction Computer
print "Adresse 1: $2\n";
print "Adresse 2: $3\n";
print chk_adr($2);
my $adr1 = dez2bin ($arg1, $2);
my $adr2 = dez2bin ($arg2, $3);
my $sprung1 = dez2bin ($arg3, 1);
my $sprung = undef;
if ($4 ne ",") {
$sprung = $sprung1;
print "\n";
} else {
$sprung = dez2bin ($arg3, $5);
print "Sprung : $5\n\n";
}
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${temp_adr}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${adr2}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <= \"${adr1}${adr1}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <=
\"${adr1}${temp_adr}${sprung}\";\n");
$line_cnt ++;
# ADD Befehl auswerten
} elsif ($line =~ /^ADD +([0-9]+) *, *([0-9]+) *(,| *) *([0-9]*) */) {
print "ADD\n";
print "Adresse 1: $1\n";
print "Adresse 2: $2\n";
print chk_adr($1);
my $adr1 = dez2bin ($arg1, $1);
my $adr2 = dez2bin ($arg2, $2);
my $sprung1 = dez2bin ($arg3, 1);
my $sprung = undef;
if ($3 ne ",") {
$sprung = $sprung1;
print "\n";
} else {
$sprung = dez2bin ($arg3, $4);
print "Sprung : $4\n\n";
}
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${temp_adr}${sprung1}\";\n");
$line_cnt ++;
- 61 -
Projektbericht
Single Instruction Computer
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${adr2}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <=
\"${adr1}${temp_adr}${sprung}\";\n");
$line_cnt ++;
# SUB Befehl auswerten
} elsif ($line =~ /^SUB +([0-9]+) *, *([0-9]+) *(,| *) *([0-9]*) */) {
print "SUB\n";
print "Adresse 1: $1\n";
print "Adresse 2: $2\n";
print chk_adr($1);
my $adr1 = dez2bin ($arg1, $1);
my $adr2 = dez2bin ($arg2, $2);
my $sprung = undef;
if ($3 ne ",") {
$sprung = dez2bin ($arg3, 1);
print "\n";
} else {
$sprung = dez2bin ($arg3, $4);
print "Sprung : $4\n\n";
}
push (@prog, "program_s($line_cnt) <= \"${adr1}${adr2}${sprung}\";\n");
$line_cnt ++;
# HLT Befehl auswerten
} elsif ($line =~ /^(HLT|HALT|HOLD) */) {
print "HLT\n\n";
my $adr1 = dez2bin ($arg1, 1);
my $adr2 = dez2bin ($arg2, 2);
my $sprung = dez2bin ($arg3, 0);
push (@prog, "program_s($line_cnt) <= \"${adr1}${adr2}${sprung}\";\n");
$line_cnt ++;
# NOP Befehl auswerten
} elsif ($line =~ /^NOP */) {
print "NOP\n\n";
my $adr1 = dez2bin ($arg1, 2);
my $adr2 = dez2bin ($arg2, 1);
my $sprung = dez2bin ($arg3, 1);
push (@prog, "program_s($line_cnt) <= \"${adr1}${adr2}${sprung}\";\n");
$line_cnt ++;
- 62 -
Projektbericht
Single Instruction Computer
# DEC Befehl auswerten
} elsif ($line =~ /^(DEC|DECR) +([0-9]+) *(,| *) *([0-9]*) */) {
print "DEC\n\n";
print chk_adr($2);
my $adr1 = dez2bin ($arg1, $2);
my $adr2 = dez2bin ($arg2, 2);
my $sprung = undef;
if ($3 ne ",") {
$sprung = dez2bin ($arg3, 1);
print "\n";
} else {
$sprung = dez2bin ($arg3, $4);
print "Sprung : $4\n\n";
}
push (@prog, "program_s($line_cnt) <= \"${adr1}${adr2}${sprung}\";\n");
$line_cnt ++;
# INC Befehl auswerten
} elsif ($line =~ /^(INC|INCR) +([0-9]+) *(,| *) *([0-9]*) */) {
print "INC\n\n";
print chk_adr($2);
my $adr1 = dez2bin ($arg1, $2);
my $adr2 = dez2bin ($arg2, 2);
my $sprung1 = dez2bin ($arg3, 1);
my $sprung = undef;
if ($3 ne ",") {
$sprung = $sprung1;
print "\n";
} else {
$sprung = dez2bin ($arg3, $4);
print "Sprung : $4\n\n";
}
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${temp_adr}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <=
\"${temp_adr}${adr2}${sprung1}\";\n");
$line_cnt ++;
push (@prog, "program_s($line_cnt) <=
\"${adr1}${temp_adr}${sprung}\";\n");
$line_cnt ++;
}
}
close (FILE);
if ($line_cnt > ($anz_befehlsworte + 1)) {
$line_cnt --;
- 63 -
Projektbericht
Single Instruction Computer
die "Nicht genuegend Programmspeicher:\nEs stehen $anz_befehlsworte
Zeilen zur Verfuegung, $line_cnt Zeilen werden benoetigt\n";
}
print "\nSBN-Programm erstellt.\n\n";
return @prog;
}
# Parameter auslesen und setzen
sub setpar {
my $source = shift;
my @par = undef;
my $par_cnt = 0;
my $line = undef;
open (FILE, "<$source") or die "Quelltext kann nicht geoeffnet werden";
while ($line = <FILE>) {
# Parameter einlesen
if ($line =~ /^PAR +/) {
print "$line";
if ($line =~ /^PAR +data_wl_c := *([0-9]+) *;/) {
print "PAR\n";
print "Datenwortbreite: $1\n\n";
$datenwortbreite = $1;
push (@par, "CONSTANT data_wl_c : INTEGER := $1;\n");
$par_cnt ++;
} elsif ($line =~ /^PAR +reg_nr_c := *([0-9]+) *;/) {
print "PAR\n";
print "Anzahl Datenworte: $1\n\n";
$anz_datenworte = $1;
push (@par, "CONSTANT reg_nr_c : INTEGER := $1;\n");
$par_cnt ++;
} elsif ($line =~ /^PAR +line_nr_c := *([0-9]+) *;/) {
print "PAR\n";
print "Anzahl Befehlsworte: $1\n\n";
$anz_befehlsworte = $1;
push (@par, "CONSTANT line_nr_c : INTEGER := $1;\n");
$par_cnt ++;
} elsif ($line =~ /^PAR +instr_argl1_c := *([0-9]+) *;/) {
print "PAR\n";
print "Breite Argument 1: $1\n\n";
$arg1 = $1;
push (@par, "CONSTANT instr_argl1_c : INTEGER := $1;\n");
- 64 -
Projektbericht
Single Instruction Computer
$par_cnt ++;
} elsif ($line =~ /^PAR +instr_argl2_c := *([0-9]+) *;/) {
print "PAR\n";
print "Breite Argument 2: $1\n\n";
$arg2 = $1;
push (@par, "CONSTANT instr_argl2_c : INTEGER := $1;\n");
$par_cnt ++;
} elsif ($line =~ /^PAR +instr_argl3_c := *([0-9]+) *;/) {
print "PAR\n";
print "Breite Argument 3: $1\n\n";
$arg3 = $1;
push (@par, "CONSTANT instr_argl3_c : INTEGER := $1;\n");
$par_cnt ++;
} elsif ($line =~ /^PAR +data_reg_reserv_nr_c := *([0-9]+) *;/) {
print "PAR\n";
print "Nummer des hoehsten reservierten Registers: $1\n\n";
$nr_reserv_reg = $1;
push (@par, "CONSTANT data_reg_reserv_nr_c : INTEGER := $1;\n");
$par_cnt ++;
}
}
}
if ($par_cnt != $anz_par) {
die "Anzahl der gefundenen Parameterstimmt nicht\n";
}
print"\nParameter-Liste erstellt.\n\n";
return @par;
}
# Zieladresse gegen reservierte Adressen pruefen
sub chk_adr{
my $target_adr = shift;
my $msg = undef;
if ($target_adr <= $nr_reserv_reg) {
$msg = "WARNUNG : Es wird versucht Adresse $target_adr zu modifizieren
!\nDies kann einen Fehler im Programmablauf verursachen.\n\n";
} else {
$msg = "";
}
return $msg;
}
- 65 -
Projektbericht
Single Instruction Computer
# Umwandeln von Dezimalzahlen in Dualzahlen
# dez2bin (anzahlbits, zahl);
sub dez2bin {
my $bits = shift;
my $zahl = shift;
my $cur_bit = 2**$bits;
my $bin = "";
do {
$cur_bit /= 2;
if (($zahl & $cur_bit) != 0) {
$bin .= "1";
} else {
$bin .= "0";
}
} while ($cur_bit > 1);
return $bin;
}
- 66 -
Herunterladen