Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in...

56
Vorlesungen ¨ uber Rechner-Technik Karl Stroetmann 5. Mai 2004 Inhaltsverzeichnis 1 Programmierung in Mikro-Assembler 1 1.1 ¨ Uberblick ......................................... 1 1.2 Die Mikro-Assembler-Sprache .............................. 1 1.3 Vorbereitung zur Programmierung in Mikro-Assembler ................ 5 1.3.1 Installation des Simulators mic1 ........................ 7 1.3.2 Installation des schnellen Simulators ...................... 7 1.4 Ein einf¨ uhrendes Beispiel ................................ 8 1.4.1 Mathematische Analyse des Problems ..................... 8 1.4.2 Erstellen eines C-Programms zur bitweisen Exklusiv-Oder-Verkn¨ upfung .. 9 1.4.3 Erstellen eines mikro-assembler-¨ahnlichen C-Programms ........... 9 1.4.4 Zuordnung der verwendeten Variablen zu den Registern ........... 10 1.4.5 Implementierung in Mikro-Assembler ...................... 10 1.4.6 Interaktives Arbeiten im Mic-1 -Simulator ................... 12 1.5 Implementierung der Multiplikation in Mikro-Assembler ............... 19 1.5.1 Mathematische Analyse ............................. 19 1.5.2 Erstellung eines mikro-assembler-¨ ahnlichen Programms ........... 20 1.5.3 Erstellung des Mikro-Assembler-Programms .................. 22 2 Speicher und Cache 26 2.1 Speicher .......................................... 26 2.1.1 Multiplexer .................................... 26 2.1.2 Dekoder ...................................... 29 2.1.3 Speicher-Zellen .................................. 30 2.1.4 Speicher-Strukturen ............................... 33 2.2 Cache ........................................... 39 2.2.1 Ein einfacher Cache ............................... 40 2.2.2 Modellierung des Haupt-Speichers in Verilog ................. 45 2.2.3 Modellierung eines Cache-Controller in Verilog ................ 48 2.2.4 Die write-back -Strategie ............................. 49 Literatur-Verzeichnis ................................................................. 55 1

Transcript of Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in...

Page 1: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Vorlesungen uber Rechner-Technik

Karl Stroetmann

5. Mai 2004

Inhaltsverzeichnis

1 Programmierung in Mikro-Assembler 1

1.1 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Die Mikro-Assembler-Sprache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 Vorbereitung zur Programmierung in Mikro-Assembler . . . . . . . . . . . . . . . . 5

1.3.1 Installation des Simulators mic1 . . . . . . . . . . . . . . . . . . . . . . . . 71.3.2 Installation des schnellen Simulators . . . . . . . . . . . . . . . . . . . . . . 7

1.4 Ein einfuhrendes Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.4.1 Mathematische Analyse des Problems . . . . . . . . . . . . . . . . . . . . . 81.4.2 Erstellen eines C-Programms zur bitweisen Exklusiv-Oder-Verknupfung . . 91.4.3 Erstellen eines mikro-assembler-ahnlichen C-Programms . . . . . . . . . . . 91.4.4 Zuordnung der verwendeten Variablen zu den Registern . . . . . . . . . . . 101.4.5 Implementierung in Mikro-Assembler . . . . . . . . . . . . . . . . . . . . . . 101.4.6 Interaktives Arbeiten im Mic-1-Simulator . . . . . . . . . . . . . . . . . . . 12

1.5 Implementierung der Multiplikation in Mikro-Assembler . . . . . . . . . . . . . . . 191.5.1 Mathematische Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191.5.2 Erstellung eines mikro-assembler-ahnlichen Programms . . . . . . . . . . . 201.5.3 Erstellung des Mikro-Assembler-Programms . . . . . . . . . . . . . . . . . . 22

2 Speicher und Cache 26

2.1 Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.1.1 Multiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.1.2 Dekoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.1.3 Speicher-Zellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302.1.4 Speicher-Strukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.2 Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392.2.1 Ein einfacher Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402.2.2 Modellierung des Haupt-Speichers in Verilog . . . . . . . . . . . . . . . . . 452.2.3 Modellierung eines Cache-Controller in Verilog . . . . . . . . . . . . . . . . 482.2.4 Die write-back -Strategie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

Literatur-Verzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

1

Page 2: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 Programmierung in Mikro-Assembler

1.1 Uberblick

In diesem Kapitel behandeln wir die Programmierung in Mikro-Assembler. Mikro-Assembler ist dieSprache, mit der wir die Kontrolle des Prozessors Mic-1 implementieren konnen. Mikro-Assembler-Programme werden dazu von einem als Mikro-Assembler 1 bezeichneten Programm in sogenanntenMikro-Code ubersetzt. Dieser Mikro-Code besteht aus 512 Wortern, die eine Lange von 36 BitsBits haben. Diese Worte werden im Mikro-Programmspeicher der Mic-1 abgelegt. Am Anfangjedes Taktzyklus wird ein Wort aus dem Mikro-Programmspeicher in das Mikro-Instruktions-Register MIR geladen. Dieses Register steuert den Datenfluß des Prozessors Mic-1. Die Frage,welches Wort aus dem Mikro-Programmspeicher in das Register MIR geladen wird, wird dabeivon dem 9-Bit-Register MPC beantwortet. Der Name MPC steht fur micro program counter. Der indiesem Register gespeicherte Wert gibt die Adresse im Mikro-Programmspeicher an, deren Wertdann in das Register MIR geschrieben wird. Abbildung 1 zeigt den Prozessor Mic-1 aus dem Buchvon Andrew Tanenbaum [2].

1.2 Die Mikro-Assembler-Sprache

Wir stellen zunachst die Grammatik der Sprache MAL vor. Die Abkurzung MAL steht fur micro

assembly language. Die Grammatik ist in Abbildung 2 auf Seite 3 wiedergegeben. Wir haben dabeidie folgenden Konventionen benutzt:

1. Die terminalen Symbole, die wortlich so wie angegeben im MAL-Programm stehen mussen,sind in Schreibmaschinen-Schriftgesetzt und zusatzlich in doppelten Anfuhrungs-Stricheneingeschlossen.

2. Alle anderen terminalen Symbole sind fett gesetzt. Die MAL-Grammatik enthalt nur zweisolche terminalen Symbole:

(a) Identifier steht fur ein Wort, das nur aus Buchstaben und Ziffern besteht, und daszusatzlich mit einem Buchstaben beginnt. Ein Identifier ist ein Name, der als symbo-

lische Sprungadresse dient.

(b) HexNumber steht fur eine Hexadezimal-Zahl, deren Wert zwischen 0 und 29−1 = 511liegen muß. Eine solche Hexadezimal-Zahl wird als Adresse im Mikro-Programmspeicherinterpretiert.

3. Die Nicht-Terminale der Grammatik sind in geneigter Schrift angegeben.

4. Das Start-Symbol der Grammatik ist das Nicht-Terminal Program.

Wir diskutieren nun die Bedeutung der einzelnen nicht-terminalen Symbole der Grammatik.

1. Program bezeichnet ein vollstandiges Mikro-Programm. Ein solches Mikro-Programm be-steht aus drei Teilen:

(a) Einer Liste von Sprungadress-Definitionen. Eine Sprungadress-Definition wird durchdas Nicht-Terminal LabelDcl bezeichnet und hat die Form

.label Identifier HexNumber.

Eine solche Sprungadress-Definition spezifiziert die hexadezimale Adresse, die der sym-bolischen Sprungadresse Identifier entspricht.

Beispiel: Die Sprungadress-Definition

.label nop1 0x00

1Wir bezeichnen sowohl die Programmier-Sprache, als auch das Programm, das in dieser Sprache geschriebene

Programme in Mikro-Code ubersetzt, mit dem Begriff Mikro-Assembler. Aus dem Kontext geht jeweils hervor, ob

wir von dem Mikro-Assembler-Programm oder von der Mikro-Assembler-Sprache reden.

1

Page 3: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

H

Shifter

ALU

2

N

B bus

6

ALUcontrol

Controlsignals

Memory control signals (rd, wr, fetch)

EnableontoB bus

WriteC busto register

Z

C bus

SP

LV

CPP

TOS

OPC

PC

MDR

MAR

MBR

9

O

512 × 36-Bitcontrol storefor holding

the microprogram

3

8

4-to-16Decoder

2

8

4

MPC

MIRAddr J ALU C M B

1-bit flip–flop

Highbit

JMPC

JAMN/JAMZ

Abbildung 1: Der Mic-1 Prozessor.

legt fest, dass der Mikro-Befehl mit der symbolischen Sprungadresse nop1 an der hexa-dezimalen Adresse 0x00 im Mikro-Programm-Speicher abgelegt wird.

(b) Einem Default-Eintrag, der an all den Adressen im Mikro-Programm-Speicher abgelegtwird, an denen sonst keine Befehle stehen wurden. In der Praxis hat dieser Eintrag diefolgende Form:

.default goto err1

Hier ist err1 eine symbolische Sprungadresse. An dieser Adresse steht ein Mikro-Programm, das den String “ERROR” ausgibt.

2

Page 4: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Program → LabelDclList DefaultDcl InstrList

LabelDclList → LabelDcl LabelDclList

| ε

LabelDcl “.label” Identifier HexNumber

DefaultDcl “.default” CmdList

InstrList → Instruction InstrList

| ε

Instruction → Identifier CmdList

| CmdList

CmdList → Cmd “;” CmdList

| Cmd “;”| Cmd

| ε

Cmd → Assignment

| CntrlCmd

| IoCmd

| “nop”

Assignment → Register “=” Assignment

| Expr

CntrlCmd → IfCmd

| BranchCmd

| GotoCmd

IfCmd → “if” “(” Condition “)” “goto” Identifier “;” “else” “goto” Identifier

Condition → “N” | “Z”

BranchCmd → “goto” “(” “MBR” “)”

GotoCmd → “goto” Identifier

IoCmd → “rd” | “wr” | “fetch”

Expr → Operation

| Operation “>> 1”| Operation “<< 8”

Operation → Register “AND” Register

| Register “OR” Register

| “NOT” Register

| Register “+” Register

| Register “+” Register “+” “1”| Register “-” Register

| Register “-” “1”| “-” Register

| Register

| “-1”| “0”| “1”

Register → “MAR” | “MDR” | “PC” | “SP” | “LV” | “CPP” | “TOS” | “OPC” | “H”| “MBR” | “MBRU” | “N” | “Z”

Abbildung 2: Die Grammatik der Sprache MAL.

(c) Einer Liste von Mikro-Instruktionen. Der Mikro-Assembler ubersetzt jede Mikro-Instruktionen

3

Page 5: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

in ein 36-Bit-Wort. Diese Worte werden dann im Mikro-Programm-Speicher abgelegt.

2. InstrList bezeichnet die Liste der Mikro-Instruktionen.

3. Instruction bezeichnet eine einzelne Mikro-Instruktion. Die einzelnen Mikro-Instruktionenmussen durch Zeilenumbruche von einander getrennt sein. Innerhalb einer Mikro-Instruktionselbst darf kein Zeilenumbruch mehr auftreten. Jede Mikro-Instruktion hat die folgendeStruktur:

Identifier Assignment IoCmd CntrlCmd

Die einzelnen Komponenten haben dabei die folgende Bedeutung:

(a) Identifier bezeichnet eine symbolische Sprungadresse, die dazu dient, dass andereMikro-Instruktionen zu dieser Mikro-Instruktion verzweigen konnen.

(b) Assignment spezifiziert den Datenweg. Dazu sind folgende Dinge festzulegen:

• das Register, das auf den B-Bus geschrieben werden soll,

• die Funktion, die von der ALU berechnet werden soll,

• die Register, in die das von der ALU berechnete Ergebnis geschrieben werden soll.

Wir werden die Struktur des Nicht-Terminals Assignment weiter unten genauer erlautern.

(c) IoCmd kontrolliert die Schnittstelle zum Speicher und legt fest, welche der drei Signalerd, wr und fetch gesetzt werden. Das IoCmd entfallt, wenn keines der Signale rd, wrund fetch gesetzt wird. Da auch mehrere dieser Signale gleichzeitig gesetzt werdenkonnen, kann eine Mikro-Instruktion auch mehrere IoCmds enthalten.

(d) CntrlCmd spezifiziert die als nachstes auszufuhrende Mikro-Instruktion.

In einer Mikro-Instruktion mussen nicht alle diese Komponenten vorhanden sein. Beispiels-weise kann das Assignment fehlen, wenn das Ergebnis der ALU in kein Register geschriebenwird und wenn zusatzlich die 1-Bit Register N und Z nicht abgefragt werden.

Ein einfaches Beispiel fur eine Mikro-Instruktion ist folgendes:

iadd3 MDR = TOS = MDR + H; wr; goto Main1

Diese Mikro-Instruktion hat die symbolische Sprungadresse “iadd”. Das Assignment

MDR = TOS = MDR + H

legt fest, dass die ALU die Inhalte der Register MDR und H addieren soll und dass das Ergebnisdieser Addition sowohl in dem Register TOS als auch in dem Register MDR abgespeichertwerden soll. Das IoCmd “wr” spezifiziert, dass das Signal wr gesetzt werden soll, der Inhaltdes Registers MDR wird also in den Haupt-Speicher geschrieben, und zwar an die durch dasRegister MAR spezifizierte Adresse. Das CntrlCmd “goto Main1” legt fest, dass die nachsteMikro-Instruktion die Instruktion mit der symbolischen Adresse “Main1” ist.

4. Assignment hat die Form

Reg1 = · · · = Regn = Expr

Hierbei sind Reg1, · · ·, Regn die Register, in die das Ergebnis der ALU geschrieben werdensoll. Expr legt drei Dinge fest:

(a) Es wird spezifiziert, welches Register auf den B-Bus geschrieben werden soll. Der B-Busist mit dem rechten Eingang der ALU verbunden, vergleiche Abbildung 1. Der linkeEingang der ALU ist immer mit dem Register H verbunden und braucht daher nichtspezifiziert werden.

(b) Es wird spezifiziert, welche Funktion die ALU ausfuhren soll.

(c) Es wird spezifiziert, welche Funktion der Shifter durchfuhren soll.

Bei der Angabe von Expr ist darauf zu achten, dass die durch die ALU und die durch denAnschluß der ALU an A-Bus und B-Bus gegebenen Einschrankungen eingehalten werden.

4

Page 6: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

(a) Werden bei einer binaren Operation zwei Register als Argumente verwendet, so musseines der Register immer das Register H sein, denn dieses Register ist permanent mitdem linken Eingang der ALU verbunden.

(b) Ein Subtraktions-Befehl kann nur die Form

Reg - H

angegeben werden, denn die ALU kann nur den am linken Eingang anliegenden Wertsubtrahieren.

(c) Die einzigen Konstanten, die von der ALU erzeugt werden konnen, sind die Zahlen“-1”, “0” und “1”. Werden andere Konstanten benotigt, so mussen diese mittels arith-metischer oder logischer Operationen aus diesen Konstanten erzeugt werden.

5. CntrlCmd spezifiziert die nachste auszufuhrende Mikro-Instruktion. Es gibt drei verschiedeneMoglichkeiten, diese festzulegen:

(a) Ein IfCmd hat die Form:

if (Condition) goto Label1; else goto Label2

Hierbei hat Condition entweder den Wert “N” oder “Z”. Im ersten Fall wird getestet,ob das Ergebnis der ALU negativ ist, im zweiten Fall wird uberpruft, ob das Ergebnisder ALU 0 ist. Ist die Uberprufung der Bedingung Condition positiv, so verzweigt derKontrollfluß zu der symbolischen Adresse Label1, andernfalls wird zur symbolischenAdresse Label2 verzweigt. Auch wenn Label2 auf die nachste Instruktion verweist,darf der else-Zweig nicht fehlen.

(b) Ein BranchCmd hat die Form:

goto (MBR)

Nach einem solchen Kommando verzweigt das Programm an die im Register MBR spe-zifizierte Stelle. Das Register MBR ist vorher vom Haupt-Speicher mit einem Byte ge-laden worden. Das in MBR geladene Byte spezifiziert einen der Byte-Codes der IJVM.Die Codes der einzelnen Befehle sind in Abbildung 1 auf Seite 6 angegeben. Damitim Mikroprogramm-Speicher genau an der durch diese Codes spezifzierten Stelle auchtatsachlich genau der fur die Abarbeitung dieser IJVM-Assembler-Befehle zustandi-ge Mikro-Code liegt, muss dem Assembler mitgeteilt werden, dass bestimmte Mikro-Instruktionen an festen Stellen im Mikroprogramm-Speicher abgelegt werden mussen.Beispielsweise muss der erste Befehl des Mikro-Codes, der den IJVM-Befehl iadd inter-pretiert, an der Stelle 0x60 im Mikroprogramm-Speicher liegen, den der IJVM-Befehliadd hat den Byte-Code 0x60. Dies wird durch eine Sprungadress-Definition der Form

.label iadd1 0x60

sichergestellt, wenn die erste Mikro-Instruktion, die zur Abarbeitung des IJVM-Befehlsiadd dient, die symbolische Sprungadresse iadd1 hat.

(c) Ein GotoCmd hat die Form:

goto Label

Hierbei ist die Label eine symbolische Sprungadresse, die festlegt, an welcher Stelle dieAbarbeitung des Mikroprogramms fortgesetzt wird.

Per Default wird das Mikroprogramm mit der im Programm-Text folgenden Mikro-Instruktionfortgesetzt. In diesem Fall braucht die Instruktion kein CntrlCmd enthalten.

1.3 Vorbereitung zur Programmierung in Mikro-Assembler

In diesem Abschnitt beschreiben wir, welche Werkzeuge installiert werden mussen, damit wir inder Lage sind, in Mikro-Assembler zu programieren. Wir werden zwei verschiedene Werkzeugebenutzen:

5

Page 7: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Byte Kommando Kurz-Beschreibung

0x60 IADD Ersetze die zwei obersten Worte auf dem Stack durchdie Summe ihrer Werte.

0x64 ISUB Ersetze die zwei obersten Worte auf dem Stack durchdie Differenz ihrer Werte.

0x7E IAND Ersetze die beiden obersten Worte auf dem Stack durchihre bitweise Boole’sche Und-Verknupfung.

0x80 IOR Ersetze die beiden obersten Worte auf dem Stack durchihre bitweise Boole’sche Oder-Verknupfung.

0x10 BIPUSH Byte Lege Byte auf Stack.0x15 ILOAD VarNum Lege die durch VarNum spezifizierte Variable auf den Stack.0x36 ISTORE VarNum Entferne den obersten Wert vom Stack und speichere diesen

Wert in der durch VarNum spezifizierten Variablen.0x13 LDC W Index Lege Konstante aus dem Konstanten-Pool auf den Stack.0x84 IINC VarNum Const Addiere Const zu der durch VarNum spezifizierten Variablen.0x57 POP Entferne das oberste Wort auf dem Stack.0x59 DUP Dupliziere das oberste Wort auf dem Stack.0x5F SWAP Vertausche die beiden obersten Worte auf dem Stack.0x00 NOP Tue gar nichts.0xA7 GOTO Offset Erhohe PC um Offset.0x99 IFEQ Offset Entferne das oberste Wort vom Stack und verzweige,

falls dieses Wort gleich 0 ist.0x9B IFLT Offset Entferne das oberste Wort vom Stack und verzweige,

falls dieses Wort kleiner als 0 ist.0x9F IF ICMPEQ Offset Entferne die beiden obersten Wort vom Stack und verzweige,

falls diese gleich sind.0xB6 INVOKEVIRTUAL Idx Aufruf einer Prozedur.0xAC IRETURN Ruckkehr von einer Prozedur.

Tabelle 1: IJVM-Assembler-Befehle mit Byte-Code.

1. Den Simulator mic1 von Ray Ontko and Dan Stone. Dieser Simulator kann unter

http://www.ontko.com/mic1/1 0e/mic1.tar.gz

aus dem Netz geladen werden. Eine lokale Version befindet sich unter

http://www.ba-stuttgart.de/~stroetma/mic1.tar.gz

auf meiner Web-Seite.

2. Den von Thomas Kutzer im Rahmen einer Semester-Arbeit implementierten Mic-1-Simulator.Eine β-Version finden Sie im Netz unter:

http://www.ba-stuttgart.de/~stroetma/CT/simulator.zip

Die nachfolgenden Unterabschnitte beschreiben die Installation dieser Werkzeuge unter Linux.Beide Werkzeuge lassen sich auch unter den verschiedenen Varianten von Microsoft WindowsTM

installieren. Am einfachsten funktioniert das, wenn auf dem Rechner Cygwin installiert ist. DiesesProdukt kann unter

http://www.cygwin.com

aus dem Netz geladen werden. Schließlich ist es auch moglich, die Programme direkt unter Micro-

soft Windows einzusetzen. Dieser Fall wird allerdings durch die unten angegebene Beschreibungnicht abgedeckt.

6

Page 8: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1.3.1 Installation des Simulators mic1

Um den Simulator mic1 zu installieren, gehen Sie wie folgt vor:

1. Erzeugen Sie ein Verzeichnis mit dem Namen Mic1.

2. Schieben Sie die Datei mic1.tar.gz in dieses Verzeichnis.

3. Offnen Sie in diesem Verzeichnis eine Shell und geben Sie dort folgende Befehle ein:

(a) gunzip mic1.tar.gz

(b) tar xf mic1.tar

4. Setzen Sie die Umgebungs-Variable CLASSPATH so, dass dort sowohl das Verzeichnis Mic1

als auch die in diesem Verzeichnis vorhandene Datei classes.zip auftreten. Wenn sie alsDefault-Shell die bash verwenden und wenn Sie zusatzlich annehmen, dass Sie das VerzeichnisMic1 in dem Verzeichnis ~/CT angelegt haben, dann wird dies durch hinzufugen der folgendenZeile in der Datei ~/.bashrc erreicht:

export CLASSPATH=$CLASSPATH:~/CT/Mic1:~/CT/Mic1/classes.zip

Ist die Installation erfolgreich verlaufen, so stehen jetzt vier in JavaTM implementierte Werkzeugezur Verfugung:

1. ijvmasm ist ein Assembler, der in IJVM -Assembler geschrieben Programme in Byte-Codeumsetzt.

2. mic1asm ist ein Mikro-Assembler, der in der Sprache MAL geschriebene Mikro-Assembler-Programme in Mikro-Code umsetzt.

3. mic1dasm ist der dazugehorige MAL-Disassembler. Er wird benotigt um die Korrespondenzzwischen den symbolischen Sprungadressen und den hexadezimalen Sprungadressen im vomMikro-Assembler erzeugten Mikro-Code herauszufinden.

4. mic1sim ist ein Simulator fur die Mic-1 , der mit einer graphischen Benutzeroberflache ausge-stattet ist. Leider ist die Performanz dieses Simulators so gering, dass er fur den praktischenEinsatz kaum zu gebrauchen ist.

1.3.2 Installation des schnellen Simulators

Um den schnellen Simulator zu installieren, gehen Sie wie folgt vor:

1. Erzeugen Sie ein Verzeichnis mit dem Namen CT.

2. Verschieben Sie die Datei simulator.zip in dieses Verzeichnis.

3. Offnen Sie in diesem Verzeichnis eine Shell und geben Sie dort folgende Befehle ein:

(a) unzip simulator.zip

Es sollte nun ein Unterverzeichnis mit dem Namen “Simulator” entstehen.

(b) cd Simulator

Mit diesem Befehl wechseln Sie in dieses Unterverzeichnis.

(c) make

Mit diesem Befehl starten Sie die Ubersetzung. Damit diese erfolgreich durchgefuhrtwerden kann, ist es erforderlich, dass Sie die folgenden Werkzeuge der Entwicklungs-Umgebung installiert haben.

• g++. Dies ist der C++-Compiler des Gnu-Projektes.

• gmake.

Ist die Ubersetzung erfolgreich, so entsteht in dem Ordner “Simulator” eine ausfuhr-bare Datei mit dem Namen “mic1sim.exe”. Dies ist der Simulator, den wir in dieserVorlesung benutzen wollen.

7

Page 9: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1.4 Ein einfuhrendes Beispiel

Wir beschreiben die Erstellung eines Mikro-Assembler-Programmsan Hand eines einfachen, einfuhren-den Beispiels. Da das Programmieren in Mikro-Assembler wesentlich diffiziler ist als das Program-mieren in einer Hochsprache, ist es wichtig, fur diesen Zweck eine geeignete Methodik zu entwick-len. Wir werden daher bei der Entwicklung eines Mikro-Assembler-Programms immer in folgendenSchritten vorgehen:

1. Mathematische Analyse des Problems.

In dieser Phase analysieren wir das Problem und erarbeiten einen Algorithmus.

2. Erstellen eines C-Programms, das die gestellte Aufgabe lost.

Hier setzen wir den vorher erarbeiteten Algorithmus zunachst in ein C-Programm um. Dieshat den Vorteil, dass wir den Algorithmus bereits in einer fruhen Phase testen konnen.

3. Erstellen eines mikro-assembler-ahnlichen C-Programms, das die gestellte Aufgabe lost. Wirnennen ein C-Programm dabei mikro-assembler-ahnlich, wenn es nur Operationen durchfuhrt,die auch von der ALU der Mic-1 durchgefuhrt werden konnten.

4. Zuordnung der verwendeten Variablen zu den Registern der Mic-1 . Falls bestimmte Varia-blen nicht in Registern abgelegt werden konnen, mussen wir uns uberlegen, welche dieserVariablen wir auf dem Stack zwischenspeichern.

In dieser Phase schreiben wir das mikro-assembler-ahnliche C-Programm so um, dass alsVariablen nur noch die in der Mic-1 tatsachlich vorhandenen Register benutzt werden. DiesesC-Programm simuliert dann bereits den Datenfluß in der Mic-1 .

5. Umsetzen des letzten mikro-assembler-ahnlichen C-Programms in Mikro-Assembler.

Es sollte selbstverstandlich sein, dass wir nach jedem der obigen Schritte das erzeugte Programmauch testen, denn es ist wesentlich einfacher, einen Fehler in einem C-Programm zu finden als ineinem Mikro-Assembler-Programm.

Das einfuhrende Beispiel, das wir behandeln wollen, ist die Implementierung einer IJVM-Instruktion IXOR in Mikro-Assembler. Die Instruktion IXOR soll folgendes Verhalten haben:

1. Die beiden zuoberst auf dem Stack liegenden Werte sollen vom Stack entfernt werden.

2. Anschließend werden diese beiden Werte bitweise exklusiv-oder-verknupft.

3. Das so erhaltene Ergebnis wird auf den Stack gelegt.

Wir losen die gestellte Aufgabe jetzt mit der oben skizzierten Methodik und zeigen dabei gleich-zeitig, wie die verschiedenen Software-Werkzeuge eingesetzt werden.

1.4.1 Mathematische Analyse des Problems

Wir wollen die exklusive Oder-Verknupfung zweier Werte a und b mit a ⊕ b bezeichnen. Es laßtsich wie folgt auf die uns zur Verfugung stehenden Operationen AND, OR, NOT (∨, ∧, ¬) zuruckfuhren:

a ⊕ b ⇔ (a ∨ b) ∧ ¬(a ∧ b).

Da die ALU der Mic-1 die Operationen bitweise Konjunktion (AND), bitweise Disjunktion (OR)und bitweise Negation (NOT) zur Verfugung stellt, ist die algorithmische Seite des Problems damitbereits gelost.

8

Page 10: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1.4.2 Erstellen eines C-Programms zur bitweisen Exklusiv-Oder-Verknupfung

Abbildung 3 auf Seite 9 zeigt die Umsetzung der oben skizzierten Idee. Die Funktion xor, die inden Zeile 4 bis 6 implementiert ist, lost das Problem. Der zusatzliche Code dient nur dem Testen.Zum Testen haben wir dabei ausgenutzt, dass in C der Operator “^” zur Verfugung steht, derseine Operanden bitweise exklusiv-oder-verknupft. Ubersetzen wir das Programm und fuhren esaus, so wird die dort implementierte Funktion ixor 10 000 000 mit verschiedenen Zufahlszahlenaufgerufen und mit dem in C direkt berechneten Ergebnis verglichen.

1 #include <stdlib.h>

2 #include <assert.h>

3

4 unsigned ixor(unsigned a, unsigned b) {

5 return (a | b) & ~ (a & b);

6 }

7

8 int main () {

9 unsigned i, n = 10000000;

10 for (i = 0; i < n; ++i) {

11 unsigned a, b;

12 a = random();

13 b = random();

14 assert((a ^ b) == ixor(a, b));

15 }

16 }

Abbildung 3: Implementierung des exklusiven Oders in C.

1.4.3 Erstellen eines mikro-assembler-ahnlichen C-Programms

Ein erster Ansatz, das Programm aus Abbildung 3 in mikro-assembler-ahnlichen Code zu uber-setzen, fuhrt zu dem in Abbildung 4 gezeigten Programm. Wir haben hier nur die Funktion xor

abgebildet, der Rest des Programms andert sich nicht. Wir haben dabei den komplexen Ausdruck

(a | b) & ~ (a & b)

in eine Folge von Anwendungen von Operatoren ubersetzt, denn die ALU der Mic-1 kann in jedemSchritt hochstens eine Operation durchfuhren.

1 unsigned xor(unsigned a, unsigned b) {

2 unsigned x, y, r;

3 x = a | b;

4 y = a & b;

5 y = ~y;

6 r = x & y;

7 return r;

8 }

Abbildung 4: Implementierung des exklusiven Oders in mikro-assembler-ahnlichen C.

9

Page 11: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1.4.4 Zuordnung der verwendeten Variablen zu den Registern

Zunachst sollten wir versuchen, mit den Registern TOS, MDR, OPC und H auszukommen, denn wennwir eines Register LV, CPP, SP oder PC benutzen wurden, mußten wir zu Beginn der Operation denalten Wert dieses Registers auf dem Stack sichern und am Ende der Operation wiederherstellen.Das C-Programm aus Abbildung 4 verwendet insgesamt funf Variablen: a, b, x, y und r. Wennwir es dabei belassen wurden, dann wurden naturlich die vier Register TOS, MDR, OPC und H nichtausreichen, zumal wir ja die zusatzliche Beschrankung haben, dass das H-Register bei jeder binarenOperation einer der Operanden ist. Die Losung des Problems besteht in der Bemerkung, dass dieWerte von a und b nicht mehr benotigt werden, sobald die Operationen

x = a | b;

y = a & b;

in den Zeilen 3 und 4 ausgefuhrt worden sind. Das folgende verfeinerte mikro-assembler-ahnlicheC-Programm zeigt eine mogliche Register-Zuordnung. Das Programm ist in Abbildung 5 auf Seite10 abgebildet. Wir haben dort den Parameter a durch mdr ersetzt, denn dieser Parameter liegtauf dem Stack und muss erst gelesen werden. Wenn dieser Parameter gelesen wird, befindet ersich zunachst in dem Register MDR. Der Parameter b liegt oben auf dem Stack. Wir konnen alsodavon ausgehen, dass der Wert sich zusatzlich in dem Register TOS befindet. Wir verschiebendiesen Wert in das Register H, wo wir ihn brauchen, wenn wir ihn als erstes Element der ALUverwenden wollen. Das Ergebnis der ersten Und-Verknupfung konnen wir dann in dem RegisterOPC abspeichern, wahrend wir fur das Ergebnis der Oder-Verknupfung das Register H verwendenkonnen, da wir den bis jetzt dort befindlichen Wert nicht mehr benotigen. Dies ist auch deshalbvorteilhaft, weil wir das Ergebnis dieser Oder-Verknupfung ja anschließend negieren mussen unddafur ist es zweckmaßig, wenn das Ergebnis sich bereits im Register H befindet. Schließlich habenwir in Zeile 7 das Ergebnis der Verknupfung h & opc sowohl an die Variable tos als auch an dieVariable mdr zugewiesen. In der Variablen tos brauchen wir dieses Ergebnis um die Invariante,dass im Register TOS am Ende jeder Instruktion immer auch der Wert liegt, der oben auf dem Stackliegt, aufrecht zu erhalten. Im Register MDR brauchen wir dieses Ergebnis, denn wir wollen es aufden Stack schreiben und das geht nur uber das Register MDR. Das Ergebnis all dieser Uberlegungenist in Abbildung 5 gezeigt.

1 unsigned xor(unsigned mdr, unsigned tos) {

2 unsigned h, opc;

3 h = tos;

4 opc = h | mdr;

5 h = h & mdr;

6 h = ~h;

7 tos = mdr = h & opc;

8 return mdr;

9 }

Abbildung 5: Zuordnung der Register.

1.4.5 Implementierung in Mikro-Assembler

Die Umsetzung in Mikro-Assembler ist nun nicht mehr schwer. Wir kopieren uns zunachst dieDatei mic1ijvm.mal aus dem Verzeichnis Simulator in eine Datei, die wir mic1ijvm-xor.mal

nennen. Am Beginn dieser Datei stehen die Sprungadress-Definitionen. Dort fugen wir die Zeile

.label ixor1 0x75

ein. Der Wert 0x75 ist hier weitgehend willkurlich, wir haben nur darauf geachtet, dass dieserByte-Code von keiner bereits vorhandenen Instruktion verwendet wird. Anschließend fugen wir

10

Page 12: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

die in Abbildung 6 gezeigten Zeile an das Ende der Datei mic1ijvm-xor.mal an. Beachten Sie,dass das Register H hier immer als zweites Argument verwendet wird. In Zeile 1 lesen wir den

1 ixor1 MAR = SP = SP - 1; rd

2 ixor2 H = TOS

3 ixor3 OPC = MDR OR H

4 ixor4 H = MDR AND H

5 ixor5 H = NOT H

6 ixor6 TOS = MDR = OPC AND H; wr; goto Main1

Abbildung 6: Implementierung in Mikro-Assembler.

zweiten auf dem Stack liegenden Wert. Dazu mussen wir MAR auf SP - 1 setzen. Da außerdem amEnde des IXOR-Befehls ein Element weniger auf dem Stack liegt als zu Beginn, setzen wir auchden Wert von SP auf SP - 1. In Zeile 2 ist der in 1 gelesene Wert noch nicht aus dem Speicherangekommen. Wir nutzen daher die Zeit um das H-Register mit dem in TOS enthaltenen Wert zuladen. In den Zeilen 3 bis 6 findet nun die eigentliche Berechnung statt. Zusatzlich wird Zeile 6 dasErgebnis noch mit wr auf den Stack geschrieben. Das funktioniert, weil wir in Zeile 1 MAR bereitsauf den richtigen Wert gesetzt haben.

Als nachstes mussen wir diese Datei mit dem Mikro-Assembler in Mikro-Code ubersetzen. Dieserreichen wir durch den folgenden Befehl:

java mic1asm mic1ijvm-xor.mal mic1ijvm-xor.mic1

Dieser Befehl erzeugt die binare Datei mic1ijvm-xor.mic1. Um spater uberprufen zu konnen,wo bestimmte Mikro-Instruktionen im Mikroprogramm-Speicher liegen, disassemblieren wir dieseDatei mit fogendem Kommando:

java mic1dasm mic1ijvm-xor.mic1 > mic1ijvm-xor.dasm

Dieser Befehl erzeugt die Datei mic1ijvm-xor.dasm. Diese Datei hat genau 512 Zeilen. Jededieser Zeilen enthalt eine Mikro-Instruktion. Die fur uns interessanten Zeilen sind in Abbildung 7wiedergegeben. Wir sehen, dass die Mikro-Instruktionen nicht direkt hintereinander geschriebenwerden. Dies ist auch nicht erforderlich, da am Ende jeder Mikro-Instruktion mit Hilfe eines gotozu der logisch folgenden Mikro-Instruktion gesprungen werden kann.

1

...

2 0x75: SP=MAR=SP-1;rd;goto 0x92

3

...

4 0x92: H=TOS;goto 0x93

5 0x93: OPC=H OR MDR;goto 0x94

6 0x94: H=H AND MDR;goto 0x95

7 0x95: H=NOT H;goto 0x96

8 0x96: TOS=MDR=H AND OPC;wr;goto 0x2

9

...

Abbildung 7: Das disassemblierte Mikro-Programm zur Berechnung von IXOR.

Um den Mikro-Code testen zu konnen, erstellen wir als nachstes ein einfaches IJVM-Assembler-Programm, das den Befehl IXOR aufruft. Abbildung 8 zeigt ein solches Programm. Wir legen dieWerte 3 (binar 011) und 6 (binar 110) mit BIPUSH auf den Stack und rufen anschließend denBefehl IXOR auf. Das Ergebnis dieser Operationen sollte 5 (binar 101) sein. Um das zu uberprufen,legen wir anschließend noch die Zahl 48 auf den Stack, den das ist der ASCII-Code der Ziffer ’0’.

11

Page 13: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Wir addieren diese Zahl mit IADD zu unserem Ergebnis und geben das Resultat als Ziffer mit demBefehl OUT auf dem Bildschirm aus. Als Ergebnis sollte am Bildschirm die Ziffer ’5’ ausgegebenwerden.

1 .main

2 BIPUSH 3

3 BIPUSH 6

4 IXOR

5 BIPUSH 48

6 IADD

7 OUT

8 HALT

9 .end-main

Abbildung 8: Das disassemblierte Mikro-Programm zur Berechnung von IXOR.

Damit wir unser Test-Programm assemblieren konnen, mussen wir allerdings zunachst einmaldem IJVM-Assembler mitteilen, dass wir der IJVM-Sprache einen neuen Byte-Befehl hinzugefugthaben. Dies geschieht uber die Datei ijvm.conf, die sich in dem Verzeichnis befindet, in dem wirden Simulator mic1 installiert haben. Diese Datei ist in Abbildung 8 gezeigt. In dieser Datei fugenwir noch die Zeile

0x75 IXOR // Pop two words from stack; push Boolean XOR

hinzu. Nachdem dies geschehen ist, konnen wir den IJVM-Assembler mit dem Befehl

java ijvmasm xor-test.jas

aufrufen. Dieser Befehl erzeugt die Datei “xor-test.ijvm”, die den Byte-Code enthalt.Jetzt sind wir in der Lage, den Simulator fur die Mic-1 aufzurufen. Dies geschieht mit dem Befehl

mic1sim.exe mic1ijvm-xor.mic1 xor-test.ijvm

Dieser Aufruf setzt naturlich voraus, dass die Datei mic1sim.exe im Suchpfad liegt. Nach demder Befehl abgeschickt worden ist, erhalten wir folgenden Prompt:

Welcome to the mic1sim!

Type ’help’ to get more information.

mic1sim>

Wir geben hier das Kommando “run” ein und erhalten dann wie erwartet die folgende Ausgabe:

5

mic1sim: End of run (0 ms)

1.4.6 Interaktives Arbeiten im Mic-1-Simulator

Das eben vorgestellte Beispiel der Implementierung war realitatsfremd, denn hier hat alles vonAnfang an funktioniert. Ein solches Verhalten ist in der Praxis die Ausnahme. Normalerweiseschleichen sich Fehler ein, die es dann zu finden gilt. Wir stellen daher nun die interaktivenBefehle des Mic-1-Simulators vor. Zunachst gibt es das Kommando help, dass die Hilfe-Dateireadme.txt anzeigt. In dieser Datei sind alle Befehle mit einer Kurz-Beschreibung zusammengefaßt. Im einzelnen stellt der Simulator die folgenden Befehle zur Verfugung:

1. help

Zeigt die Hilfe-Datei readme.txt an.

12

Page 14: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 // configuration file for IJVM Assembler

2 0x10 BIPUSH byte // Push byte onto stack

3 0x59 DUP // Copy top word on stack; push onto · · ·4 0xA7 GOTO label // Unconditional jump

5 0x60 IADD // Pop two words from stack; push their · · ·6 0x75 IMUL // Pop two words from stack; push their · · ·7 0x7E IAND // Pop two words from stack; push Boolean · · ·8 0x75 IXOR // Pop two words from stack; push Boolean · · ·9 0x99 IFEQ label // Pop word from stack; branch if it is zero

10 0x9B IFLT label // Pop word from stack; branch if it is · · ·11 0x9F IF_ICMPEQ label // Pop two words from stack; branch if equal

12 0x84 IINC varnum const // Add a constant to a local variable

13 0x15 ILOAD varnum // Push local variable onto stack

14 0xB6 INVOKEVIRTUAL offset // Invoke a method

15 0x80 IOR // Pop two words from stack; push Boolean OR

16 0xAC IRETURN // Return from method with integer value

17 0x36 ISTORE varnum // Pop word from stack; store in local · · ·18 0x64 ISUB // Pop two words from stack; push their · · ·19 0x13 LDC_W index // Push constant from constant pool onto · · ·20 0x00 NOP // Do nothing

21 0x57 POP // Delete word on top of stack

22 0x5F SWAP // Swap the two top words on the stack

23 0xC4 WIDE // Prefix instruction; next instruction · · ·24 0xFF HALT // halt the simulator

25 0xFE ERR // print ERROR and halt

26 0xFD OUT // Pop a word from the stack and use the · · ·27 0xFC IN // Read a character from standard input · · ·

Abbildung 9: Die Datei ijvm.conf.

2. run

Startet den Simulator, der dann bis zum Programmende oder bis zum nachsten Halte-Punktlauft.

3. step [n]

Fuhrt n Mikro-Instruktionen aus. Der Parameter n ist optional. Falls der Parameter n weg-gelassen wird, wird eine Mikro-Instruktion ausgefuhrt.

4. reset

Setzt den Simulator in den Ausgangs-Zustand zuruck.

5. set [-x] Register Wert

Setzt das spezifizierte Register auf den angegebenen Wert. Falls die Option “-x” angegebenwird, wird Wert als Hexadezimal-Zahl interpretiert, sonst ist Wert eine Dezimal-Zahl.

6. setmemory [-x] Adresse Wert

Setzt das Wort an der spezifizierten Adresse auf den gegebenen Wert. Der Speicher wirddabei byteweise adressiert und Adresse wird hexadezimal angegeben.

Falls die Option “-x” angegeben wird, wird Wert als Hexadezimal-Zahl interpretiert, sonstist Wert eine Dezimal-Zahl.

13

Page 15: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

7. break Adresse

Setzt einen Halte-Punkt an der angegebenen Adresse im Mikro-Programm. Adresse wirddabei als Hexadezimal-Zahl interpretiert. Das Programm stoppt dann, sobald der Mikro-Programm-Counter MPC den Wert Adresse annimmt.

8. break [-x] Register=Wert

Setzt einen bedingten Halte-Punkt fur das spezifizierte Register. Sobald Register den ange-gebenen Wert annimmt, stoppt das Programm.

Falls die Option “-x” angegeben wird, wird Wert als Hexadezimal-Zahl interpretiert, sonstist Wert eine Dezimal-Zahl.

9. rmbreak

Dieses Kommando listet alle Halte-Punkte und alle bedingten Halte-Punkte auf. Der Benut-zer kann dann einen oder mehrere Halte-Punkte auswahlen und loschen.

10. show Register

Zeigt den Inhalt des spezifizierten Registers an.

11. show all

Zeigt die Inhalte aller Register an.

12. dump Start Stop

Zeigt den Inhalt des Haupt-Speichers zwischen den Adressen Start und Stop an. Falls imHaupt-Speichers in diesem Bereich ein IJVM-Byte-Code Programm liegt, wird dieses disas-sembliert. Die Adressen Start und Stop werden als Hexadezimal-Zahlen interpretiert. DieseAdressen sprechen den Speicher byteweise an.

13. trace Register

Dieser Befehl bewirkt, dass das spezifizierte Register nach jedem Schritt angezeigt wird.

14. trace all Register

Dieser Befehl bewirkt, dass nach jedem Schritt alle Register angezeigt werden.

15. untrace Register

Dieser Befehl macht den entsprechenden trace-Befehl ruckgangig.

16. untrace all

Dieser Befehl macht alle trace-Befehle ruckgangig.

17. exit

Dieser Befehl beendet den Simulator.

Wir wollen diese Befehle jetzt an Hand des im letzten Unterabschnitt vorgestellten Beispielesdemonstrieren. Wir starten also den Simulator wieder mit

mic1sim.exe mic1ijvm-xor.mic1 xor-test.ijvm

und lassen uns zunachst mit “show all” die Werte aller Register ausgeben.

mic1sim> show all

MAR 0 | 0x00000000

MDR 0 | 0x00000000

PC -1 | 0xFFFFFFFF

SP 32768 | 0x00008000

LV 49152 | 0x0000C000

14

Page 16: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

CPP 16384 | 0x00004000

TOS 0 | 0x00000000

OPC 0 | 0x00000000

H 0 | 0x00000000

ALU 0 | 0x00000000

SHIFTER 0 | 0x00000000

MPC 0 | 0x00000000

MBR 0 | 0x00

CYCLE 0 | 0x00000000

MIR (cur) reset

MIR (next) goto 0x2

localstack: program is not in a method call

Neben den uns bekannten Registern werden hier noch einige sogenannte Pseudo-Register ausge-geben:

1. ALU zeigt das von der ALU produzierte Ergebnis.

2. SHIFTER zeigt das vom Shifter produzierte Ergebnis.

3. CYCLE zahlt die Anzahl der Takt-Zyklen seit dem Start der Simulation.

4. localstack zeigt den Inhalt des Teils des Stacks an, der bei einem Prozedur-Aufruf Teilder lokalen Prozedur ist. Das sind die Werte, die zwischen den von LV und SP spezifiziertenAdressen liegen.

Falls noch kein Methoden-Aufruf erfolgt ist, wird hier nichts angezeigt.

Da wir nicht jedesmal den Befehl “show all” eingeben wollen, stellen wir mit dem Befehl “traceall” sicher, dass alle Register beobachtet werden. Bis auf CYCLE sind die Pseudo-Register furunser Beispiel zunachst uninteressant. Mit dem untrace-Befehl

untrace ALU

schalten wir daher die Beobachtung des Registers ALU aus. In der selben Weise schalten wir dieBeobachtung der Register SHIFTER, localstack, LV und CPP ab.

Wir betrachten zunachst die Werte, die die einzelnen Register beim Start des Rechners haben.Bis auf die Register PC, SP, LV und CPP sind alle Register mit 0 initialisiert. Dies gilt insbesondereauch fur das Register MIR. Da MIR auch kontrolliert, was im nachsten Takt-Zyklus in dem RegisterMPC steht, wird dort auch im nachsten Schritt der Wert 0x0 stehen. Da im Mikro-Programm-Speicher an der Stelle 0x0 die Instruktion “0x0: goto 0x2” abgespeichert ist, wird danach dieseInstruktion in das Register MIR geladen. Wir konnen die uberprufen, indem wir mittels des Kom-mando step einen Schritt durchfuhren. Wir erhalten folgendes Ergebnis:

MAR 0 | 0x00000000

MDR 0 | 0x00000000

PC -1 | 0xFFFFFFFF

SP 32768 | 0x00008000

TOS 0 | 0x00000000

OPC 0 | 0x00000000

H 0 | 0x00000000

MPC 2 | 0x00000002

MBR 0 | 0x00

CYCLE 1 | 0x00000001

MIR (cur) goto 0x2

MIR (next) PC=PC+1;fetch;goto (MBR)

mic1sim: 1 steps

15

Page 17: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Jetzt enthalt das Register MPC den Wert 0x2. Ein Blick in die Datei mic1ijvm-xor.dasm zeigtuns, dass an dieser Stelle die Mikro-Instruktion

0x2: PC=PC+1;fetch;goto (MBR)

liegt. In dem eigentlichen Mikro-Assembler-Programm mic1ijvm-xor.mal steht dort die Mikro-Instruktion

Main1 PC = PC + 1; fetch; goto (MBR)

Wir fuhren diese Instruktion mit einem step-Befehl aus. Dann haben wir folgende Situation:

MAR 0 | 0x00000000

MDR 0 | 0x00000000

PC 0 | 0x00000000

SP 32768 | 0x00008000

TOS 0 | 0x00000000

OPC 0 | 0x00000000

H 0 | 0x00000000

MPC 0 | 0x00000000

MBR 0 | 0x00

CYCLE 2 | 0x00000002

MIR (cur) PC=PC+1;fetch;goto (MBR)

MIR (next) goto 0x2

Der aktuelle Befehl springt zunachst einmal zu der Stelle im Mikro-Programm, die durch dasRegister MBR spezifiziert ist. Dort steht aber der Wert 0x0. Im Mikro-Programm steht dort, wiegerade schon beobachtet, die Anweisung “goto 0x2”. Wenn wir mit step einen Schritt ausfuhren,erhalten wir:

MAR 0 | 0x00000000

MDR 0 | 0x00000000

PC 0 | 0x00000000

SP 32768 | 0x00008000

TOS 0 | 0x00000000

OPC 0 | 0x00000000

H 0 | 0x00000000

MPC 2 | 0x00000002

MBR 16 | 0x10

CYCLE 3 | 0x00000003

MIR (cur) goto 0x2

MIR (next) PC=PC+1;fetch;goto (MBR)

Wichtig ist, dass nun der fetch-Befehl, der in der vorletzten Anweisung enthalten war, ausgefuhrtworden ist und das erste Byte unseres Programms aus dem Hauptspeicher in das Register MBR

geladen hat. Die aktuelle Anweisung “goto 0x2” fuhrt uns wieder zu der Anweisung

0x2: PC=PC+1;fetch;goto (MBR)

Fuhren wir abermals das step-Kommando aus, so haben wir folgende Situation.:

MAR 0 | 0x00000000

MDR 0 | 0x00000000

PC 1 | 0x00000001

SP 32768 | 0x00008000

TOS 0 | 0x00000000

OPC 0 | 0x00000000

H 0 | 0x00000000

16

Page 18: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

MPC 16 | 0x00000010

MBR 16 | 0x10

CYCLE 4 | 0x00000004

MIR (cur) PC=PC+1;fetch;goto (MBR)

MIR (next) MAR=SP=SP+1;goto 0x16

Jetzt kann die eigentliche Programm-Bearbeitung beginnen, denn als nachstes wird das Programman die im Register MBR angegebene Adresse 0x10 verzweigen. Um zu verstehen, warum ausgerechnetdieser Wert in das Register MBR geladen wurde, betrachten wir den Byte-Code unseres Programms.Dazu geben wir den Befehl

dump 0x0 0x8

ein. Als Ergebnis erhalten wir die folgende Ausgabe:

0000000 BIPUSH 3

0000002 BIPUSH 6

0000004 0x75

0000005 BIPUSH 48

0000007 IADD

0000008 OUT

Der Wert 0x10 ist gerade der Byte-Code des IJVM-Befehls BIPUSH. Fur die Stelle mit der Adresse0000004 wird der Wert nicht symbolisch sondern hexadezimal ausgegeben, denn der Befehl IXORist ja kein gultiger IJVM-Befehl sondern eine Erweiterung der IJVM. Daher kann der im Simulatorintegrierte Disassembler nicht wissen, dass der Byte-Code 0x75 dem Befehl IXOR entspricht.

Da es ziehmlich muhselig ware, das Programm im Einzel-Schritt-Modus zu verfolgen, bis derIXOR-Befehl erreicht ist, setzen wir statt dessen mit dem Kommando

break PC=4

einen Haltepunkt und lassen den Simulator mit dem Befehl run bis zu diesem Haltepunkt laufen.Wir finden dann folgende Situation vor:

MAR 32770 | 0x00008002

MDR 3 | 0x00000003

PC 4 | 0x00000004

SP 32770 | 0x00008002

TOS 3 | 0x00000003

OPC 0 | 0x00000000

H 0 | 0x00000000

MPC 23 | 0x00000017

MBR 6 | 0x06

CYCLE 10 | 0x0000000A

MIR (cur) PC=PC+1;fetch;goto 0x17

MIR (next) MDR=TOS=MBR;wr;goto 0x2

mic1sim: conditional breakpoint stopped microprogram

PC 4 | 0x00000004

Um dies besser verstehen zu konnen, betrachten wir zunachst einmal die Werte, die auf dem Stackliegen. Dazu geben wir die entsprechenden Stellen im Hauptspeicher mit folgendem dump-Befehlaus:

dump 20000 20008

An dieser Stelle sei nochmals darauf hingewiesen, dass die Speicher-Adressen beim dump-Befehlbyteweise angegeben werden. Daher haben wir den Wert 0x8002, der im Register SP steht, nochmit 4 multipliziert. Der dump-Befehl liefert:

17

Page 19: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

0020000 0

0020004 3

0020008 0

Das Ergebnis verblufft im ersten Moment, denn wir haben in unserem Programm ja die Zahlen3 und 6 auf den Stack gelegt. Die Zahl 3 ist da, die Zahl 6 aber nicht. Der Grund ist, dass derentsprechende write-Befehl eben erst ausgefuhrt worden ist und die Zahl 6 noch nicht angekommenist. Fuhren wir zwei step-Kommandos aus und wiederholen dann den obigen dump-Befehl, soerhalten wir

0020000 0

0020004 3

0020008 6

Die Register haben jetzt die folgenden Werte:

MAR 32770 | 0x00008002

MDR 6 | 0x00000006

PC 5 | 0x00000005

SP 32770 | 0x00008002

TOS 6 | 0x00000006

OPC 0 | 0x00000000

H 0 | 0x00000000

MPC 117 | 0x00000075

MBR 117 | 0x75

CYCLE 12 | 0x0000000C

MIR (cur) PC=PC+1;fetch;goto (MBR)

MIR (next) MAR=SP=SP-1;rd;goto 0x92

Im nachsten Schritt wird jetzt also die Abarbeitung des Befehls IXOR begonnen. Wir wollen nunbis zum Ende der Mikro-Instruktionen springen, die den Befehl IXOR abarbeiten. Die Betrachtungder disassemblierten Datei mic1ijvm-xor.dasm in Abbildung 7 zeigt uns, dass der letzte Befehlan der Stelle 0x96 liegt. Wir setzen mit

break 96

an dieser Stelle einen Haltepunkt. Nach einem run-Kommando stoppt der Simulator mit folgenderAusgabe:

MAR 32769 | 0x00008001

MDR 3 | 0x00000003

PC 5 | 0x00000005

SP 32769 | 0x00008001

TOS 6 | 0x00000006

OPC 7 | 0x00000007

H -3 | 0xFFFFFFFD

MPC 150 | 0x00000096

MBR 16 | 0x10

CYCLE 17 | 0x00000011

MIR (cur) H=NOT H;goto 0x96

MIR (next) MDR=TOS=H AND OPC;wr;goto 0x2

mic1sim: microprogram stopped at address 0x96

Nach einem weiteren step-Kommandos ist die Abarbeitung des IXOR-Befehls beendet und dieAbarbeitung des nachsten Befehl beginnt. Die Situation, die wir dann haben, ist

18

Page 20: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

MAR 32769 | 0x00008001

MDR 5 | 0x00000005

PC 5 | 0x00000005

SP 32769 | 0x00008001

TOS 5 | 0x00000005

OPC 7 | 0x00000007

H -3 | 0xFFFFFFFD

MPC 2 | 0x00000002

MBR 16 | 0x10

CYCLE 18 | 0x00000012

MIR (cur) MDR=TOS=H AND OPC;wr;goto 0x2

MIR (next) PC=PC+1;fetch;goto (MBR)

Das Register TOS hat jetzt bereits den Ergebnis-Wert 5, der im nachsten Schritt auf den Stackgeschrieben werden wird.

Wir haben nun die wichtigsten Befehle, die uns der Simulator mic1sim zur Verfugung stellt,im Einsatz gesehen und konnen uns daher einem komplexeren Beispiel zuwenden.

1.5 Implementierung der Multiplikation in Mikro-Assembler

Unser Ziel in diesem Abschnitt ist es, eine IJVM-Instruktion IMUL zu implementieren, die diebeiden obersten Werte auf dem Stack durch das Produkt dieser Werte ersetzt. Die Instruktion istalso ganz ahnlich aufgebaut wie die Instruktion IADD, nur dass am Ende jetzt das Produkt undnicht die Summe der beiden obersten Werte auf dem Stack liegen soll. Wir folgen der weiter obenskizzierten Methodik. Der erste Schritt besteht in der mathematischen Analyse des Problems.

1.5.1 Mathematische Analyse

Wir haben das Produkt a ∗ b zweier naturlicher Zahlen a und b zu berechnen. Die beiden Zahlenliegen im Zweier-System vor und sind jeweils durch einen Bitvektor der Lange 32 gegeben. DerWert von b hat dann die Form

b =31∑

i=0

bi ∗ 2i

Hierbei bezeichnet bi den Wert des i-ten Bits der Zahl b im Zweier-System. Wenn wir die obigeGleichung mit a multiplizieren, erhalten wir

a ∗ b = a ∗31∑

i=0

bi ∗ 2i =31∑

i=0

bi ∗ (a ∗ 2i),

wobei wir den Ausdruck schon so geklammert haben, wie wir ihn hinterher ausrechnen wollen.Den Wert von a ∗ 2i konnen wir leicht dadurch erhalten, indem wir a i-mal um ein Bit nach linksschieben. Je nach dem, ob bi gleich 1 ist oder nicht mussen wir den Wert a∗2i dann zum Ergebnisdazu addieren oder nicht. Diese Uberlegung fuhrt zu dem in Abbildung 10 auf Seite 20 gezeigtenProgramm.

Das Programm enthalt zusatzlich eine Funktion main, in der die Funktion multiply aufgerufenund getestet wird. Da es bei der Multiplikation von zwei 32-Bit-Zahlen bei der Addition in Zeile8 zu einem Uberlauf kommen kann, rufen wir die Funktion multiply nur mit Zahlen der Lange16-Bit auf. Dies erreichen wir, indem wir die von der Funktion random() erzeugten Zufahlszahlenmit dem Wert 0xFFFF bitweise verunden, denn die Zahl 0xFFFF hat im Zweier-System die Form

1111111111111111︸ ︷︷ ︸

16 Einsen

.

19

Page 21: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 #include <stdlib.h>

2 #include <assert.h>

3

4 unsigned multiply(unsigned a, unsigned b) {

5 unsigned i, product = 0;

6 for (i = 0; i < 32; ++i) {

7 if ((b & 1) == 1) {

8 product = product + a;

9 }

10 a = a << 1;

11 b = b >> 1;

12 }

13 return product;

14 }

15

16 int main() {

17 unsigned zahl1, zahl2, i, number_tests = 1000;

18 for (i = 0; i < number_tests; ++i) {

19 zahl1 = random() & 0xFFFF; // truncate to 16 bits

20 zahl2 = random() & 0xFFFF; // truncate to 16 bits

21 assert( zahl1 * zahl2 == multiply(zahl1, zahl2) );

22 }

23 return 0;

24 }

Abbildung 10: Ein einfaches Programm zur Multiplikation.

1.5.2 Erstellung eines mikro-assembler-ahnlichen Programms

Wenn wir den in dem Programm aus Abbildung 10 verwendeten Algorithmus in Mikro-Assemblerimplementieren wollen, so sind drei Dinge zu tun:

1. Die Kontroll-Strukturen for und if stehen in dieser Form in Mikro-Assembler nicht zurVerfugung und mussen ersetzt werden.

2. Bei der Durchfuhrung von binaren Operationen mussen wir die Einschrankungen der ALUberucksichtigen.

3. Die ALU kann nur die Konstanten 0, 1 und -1 produzieren, alle anderen Konstanten mussendurch Rechnungen erzeugt werden.

In dem Programm in Abbildung 10 verwenden wir die Konstante 32. Prinzipiell konnten wir diesedurch iterierte Addition aus der Konstante 1 erzeugen. Wir werden aber stattdessen das Programmso umschreiben, dass die Konstante 32 gar nicht mehr benotigt wird. Dazu bemerken wir, dasssich die Variable product dann nicht mehr andern kann, wenn die Variable b einmal den Wert 0angenommen hat, denn dann liefert der Test (b & 1) == 1 in Zeile 4 immer den Wert “false”.Außerdem wird der Betrag von b bei jedem Schleifen-Durchlauf in Zeile 8 halbiert, so dass nachmaximal 32 Schleifen-Durchlaufen b den Wert 0 haben muss. Daher konnen wir die for-Schleifein Zeile 3 durch eine while-Schleife ersetzen, in der getestet wird, ob b von 0 verschieden ist. Derdann entstehende Algorithmus ist außerdem noch effizienter als der ursprungliche Algorithmus,da die while-Schleife nur log2(b) + 1-mal durchlaufen wird. Fur alle moglichen Werte von b giltlog2(b) + 1 ≤ 32, denn b ist eine 32-Bit-Zahl. Falls die oberen Bits von b verschwinden, kann derWert sogar deutlich kleiner als 32 sein. Das fuhrt zu dem in Abbildung 11 auf Seite 21 gezeigten

20

Page 22: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Algorithmus. Wir haben hier nur die Implementierung der Funktion multiply gezeigt, denn dieFunktion main() andert sich nicht.

1 unsigned multiply(unsigned a, unsigned b) {

2 unsigned product = 0;

3 while (b != 0) {

4 if ((b & 1) == 1) {

5 product = product + a;

6 }

7 a = a << 1;

8 b = b >> 1;

9 }

10 return product;

11 }

Abbildung 11: Das verbesserte Programm zur Multiplikation.

Als nachstes eliminieren wir die hoheren Kontroll-Strukturen. Dies fuhrt zu dem in Abbildung12 auf Seite 21 gezeigten Programm. Beachten Sie, dass wir hier die Tests aus Abbildung 11 inden Zeilen 3 und 4 genau umgedreht haben. Aus b != 0 wurde b == 0 und aus (b & 1) != 0

wurde (b & 1) == 0. Dies fuhrt zu einem einfacheren Kontrollfluß.

1 unsigned multiply(unsigned a, unsigned b) {

2 unsigned product = 0;

3 loop:

4 if (b == 0) goto finish;

5 if ((b & 1) == 0) goto next;

6 product = product + a;

7 next:

8 a = a << 1;

9 b = b >> 1;

10 goto loop;

11 finish:

12 return product;

13 }

Abbildung 12: Das Programm ohne hohere Kontroll-Strukturen.

Das Programm in Abbildung 12 ist noch nicht mikro-assembler-ahnlich. Wir versuchen jetzt,den Datenfluß, den wir in der Mic-1 haben, abzubilden. Dazu ordnen wir zunachst den verwendetenVariablen a, b und product Register zu:

1. Die Variable a liegt auf dem Stack unter der Variable b. Wir werden diese Variable zunachstaus dem Hauptspeicher lesen mussen. Dann wird der gelesene Wert in dem Register MDR

liegen. Daher ordnen wir die Variable a diesem Register zu:

a 7→ MDR.

2. Die Variable b liegt oben auf dem Stack. Damit liegt sie aber auch in dem Register TOS. Esbietet sich daher an, die Variable b diesem Register zuzuordnen:

b 7→ TOS.

3. Fur die Variable product bleibt jetzt noch das Register OPC ubrig, denn neben dem Register Hist dieses Register das einzige von den verbleibenden Registern, was wir ohne Einschrankun-

21

Page 23: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

gen benutzen konnen. Das Register H konnen wir schlecht verwenden, denn wir brauchen es,um die ALU bei Operationen wie a = a + a mit Argumenten zu versorgen. Wir treffen alsofolgende Zuordnung:

product 7→ OPC.

Es bleibt noch zu uberlegen, wie die Operationen, die wir in dem Programm in Abbildung 12durchfuhren, in der Mic-1 umgesetzt werden konnen:

1. Der Test b == 0 kann unmittelbar von der ALU uber das 1-Bit-Register Z durchgefuhrtwerden.

2. Der Test b & 1 == 0 muss in zwei Schritte zergliedert werden. Zunachst mussen wir die Kon-stante 1 in das Hilfsregister H schreiben. Erst dann konnen wir mit der ALU den Ausdruckb & 1 berechnen und das Ergebnis dem 1-Bit-Register Z zuweisen.

3. Die Zuweisung a = a << 1 uberfuhren wir zunachst in a = a + a. Diesen Ausdruck berech-nen wir, indem wir den Wert von a zusatzlich im Hilfsregister H abspeichern und dann dieAddition durchfuhren.

4. Die Zuweisung b = b >> 1 kann unmittelbar von der ALU ausgefuhrt werden.

Als Ergebnis erhalten wir nun das in Abbildung 13 auf Seite 22 gezeigte Programm.

1 unsigned multiply(unsigned mdr, unsigned tos) {

2 unsigned z, h, opc = 0;

3 loop:

4 z = tos;

5 if (z == 0) goto finish;

6 h = 1;

7 z = tos & h;

8 if (z == 0) goto next;

9 h = mdr;

10 opc = opc + h;

11 next:

12 h = mdr;

13 mdr = mdr + h;

14 tos = tos >> 1;

15 goto loop;

16 finish:

17 return opc;

18 }

Abbildung 13: Das mikro-assembler-ahnliche Programm zur Multiplikation.

1.5.3 Erstellung des Mikro-Assembler-Programms

Wir konnen den in Abbildung 13 gezeigten Code unmittelbar in Mikro-Assembler umsetzen. Dasfuhrt zu dem in Abbildung 14 auf Seite 23 gezeigten Programm. In Zeile 1 lesen wir die erste zumultiplzierende Zahl, die an zweiter Stelle auf dem Stack liegt. Gleichzeitig erniedrigen wir denStack-Pointer, denn der zu implementierende Befehl entfernt ja zwei Zahlen vom Stack und legtnur eine Zahl wieder drauf. In der letzten Zeile sorgen wir dafur, dass das berechnete Ergebnis,das im Register OPC zur Verfugung steht, in das Register TOS und auf den Stack geschrieben wird.

Das Mikro-Assembler-Programm assemblieren wir mit dem Befehl

java mic1asm mic1ijvm-mult.mal mic1ijvm-mult.mic1

22

Page 24: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

und disassemblieren den erzeugten Mikro-Code mit dem Befehl

java mic1dasm mic1ijvm-mult.mic1 > mic1ijvm-mult.dasm.

1 imul1 MAR = SP = SP - 1; rd

2 imul2 OPC = 0

3 loop Z = TOS; if (Z) goto finish; else goto imul4

4 imul4 H = 1

5 imul5 Z = TOS AND H; if (Z) goto next; else goto imul6

6 imul6 H = MDR

7 imul7 OPC = OPC + H

8 next H = MDR

9 imul9 MDR = MDR + H

10 imul10 TOS = TOS >> 1; goto loop

11 finish MDR = TOS = OPC; wr; goto Main1

Abbildung 14: Das Mikro-Assembler Programm zur Multiplikation.

Um dieses Programm testen zu konnen, schreiben wir ein kurzes IJVM-Assembler-Programm, daszwei Zahlen auf den Stack legt und diese addiert. Ein solches Programm ist in Abbildung 15 zusehen. Dieses Programm wird mit dem Befehl

java ijvmasm mult-test1.jas

ubersetzt. Mit dem Befehl

mic1sim.exe mic1ijvm-mult.mic1 mult-test1.ijvm

konnen wir das ganze erfolgreich testen.

1 .main

2 BIPUSH 37

3 BIPUSH 18

4 IMULT

5 HALT

6 .end-main

Abbildung 15: Ein IJVM-Assembler-Programm zum Testen der Multiplikation.

Zum Abschluss wollen wir die Mikro-Assembler-Implementierung der Multiplikation verglei-chen mit einer Implementierung in IJVM-Assembler. Wir setzen dazu dass Programm aus Ab-bildung 12 auf Seite 21 in assembler-ahnliches C um. Wir nehmen zusatzlich an, dass wir einenIJVM-Befehl SRA1 zur Verfugung haben, der das oberste Wort auf dem Stack um 1 Bit nachrechts schiebt. Einen solchen Befehl konnen wir in Mikro-Assembler in den folgenden zwei Zeilenimplementieren:

sra1 MAR = SP;

sra2 TOS = MDR = TOS >> 1; wr; goto Main1

Dann ist in dem Programm aus Abbildung 12 lediglich die Zeile Nr. 8, die dort die Form

a = a << 1;

hat, abzuandern in:

a = a + a;

Die resultierende Funktion laßt sich sofort in eine IJVM-Methode umsetzen, wie dies in Abbildung16 gezeigt ist. Die in Abbildung 16 implementierte Methode konnen wir mit dem in Abbildung

23

Page 25: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

17 gezeigt Code testen. Fuhren wir diesen Test aus, und lassen uns anschließend den Wert desPseudo-Registers CYCLE anzeigen, so erhalten wir den Wert 536. Demgegenuber benotigt der Testder Implementierung in Mikro-Assembler nur 51 Zyklen. Dieser Unterschied wird sogar noch deut-licher, wenn wir berucksichtigen, dass am Anfang zwei BIPUSH-Befehle ausgefuhrt werden, derenZyklen man eigentlich nicht mitrechnen darf. Wir finden dann, dass bei der Implementierung derMultiplikation in Mikro-Assembler fur die eigentliche Multiplikation 40 Takt-Zyklen benotigt wer-den, wahrend fur die Berechnung des selben Produktes bei der in IJVM-Assembler implementiertenMultiplikation 525 Takt-Zyklen benotigt werden. Das ist ein Faktor von mehr als 13, den die Mul-tiplikation in Mikro-Assembler schneller ist und damit ist klar, dass sich der zugegebenermaßenerhebliche Aufwand der Programmierung in Mikro-Assembler durchaus lohnen kann.

1 .method multiply( a, b )

2 .var

3 product

4 .end-var

5 BIPUSH 0x00

6 ISTORE product

7 loop: ILOAD b

8 IFEQ finish

9 ILOAD b

10 BIPUSH 1

11 IAND

12 IFEQ next

13 ILOAD product

14 ILOAD a

15 IADD

16 ISTORE product

17 next: ILOAD a

18 DUP

19 IADD

20 ISTORE a

21 ILOAD b

22 SRA1

23 ISTORE b

24 goto loop

25 finish: ILOAD product

26 IRETURN

27 .end-method

Abbildung 16: Ein IJVM-Assembler-Programm zum Testen der Multiplikation.

24

Page 26: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 .constant

2 OBJREF 0x40

3 .end-constant

4

5 .main

6 LDC_W OBJREF

7 BIPUSH 37

8 BIPUSH 18

9 INVOKEVIRTUAL multiply

10 HALT

11 .end-main

Abbildung 17: Ein IJVM-Assembler-Programm zum Testen der in IJVM-Assembler implementier-ten Multiplikation.

25

Page 27: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

2 Speicher und Cache

In diesem Abschnitt diskutieren wir die Organisation des Speichers eines Rechners. Wir wer-den dabei versuchen, die wesentlichen Strukturen in Verilog zu modellieren. Bisher waren dieSchaltungs-Beschreibungen, die wir in Verilog erstellt haben, rein strukturell. Da eine rein struk-turelle Beschreibung der Schaltungen, die wir in diesem Abschnitt vorstellen wollen, zu muhseligware, werden wir zusatzlich neue Elemente der Sprache Verilog einfuhren. Diese neuen Elementewerden eine verhaltens-basierte Beschreibung von Schaltungen ermoglichen.

2.1 Speicher

Speicher besteht im wesentlichen aus drei Elementen:

1. Multiplexern

2. Dekodern

3. Speicher-Zellen

Wir haben alle diese Elemente bereits im ersten Teil der Vorlesung kennengelernt und strukturell

in Verilog beschrieben. Wir wollen diese Elemente nun noch einmal diskutieren, diesmal aberverhaltens-basierte Beschreibungen angeben.

2.1.1 Multiplexer

Ein n-Bit-Multiplexer kann wie folgt beschrieben werden:

1. Es gibt zwei Eingange und einen Ausgang.

(a) Der erste Eingang data hat eine Breite von 2n Bit und wird als Daten-Eingang be-zeichnet.

(b) Der zweite Eingang select hat eine Breite von n Bit und wird als Selektor-Eingang

bezeichnet.

(c) Der Ausgang out hat eine Breite von einem Bit.

2. Es gilt out = data[select], der Eingang select wahlt also das Bit aus, das auf den Ausganggelegt wird.

In Abbildung 18 auf Seite 27 sehen wir den Schaltplan eines Multiplexers, der aus einem 8 Bit brei-ten Daten-Eingang mit Hilfe eines 3 Bit breiten Selektor-Eingangs ein Bit auswahlt. In Abbildung19 auf Seite 28 ist diese Schaltung in Verilog ubersetzt worden.

Der Schaltplan und die Umsetzung entsprechen sich genau. Jedes logische Gatter in demSchaltplan hat ein Pendant in der Verilog-Beschreibung. Eine solche Beschreibung einer Schal-tung in Verilog bezeichnen wir als eine strukturelle Beschreibung der Schaltung. Oft ist einestrukturelle Beschreibung einer Schaltung zu aufwendig. Die Sprache Verilog erlaubt daher auchSchaltungs-Beschreibungen auf einer hoheren Abstraktions-Ebene. Wir fuhren Elemente dieserhoheren Abstraktions-Ebene jetzt anhand des Multiplexers ein. Abbildung 20 auf Seite 29 zeigteine verhaltens-basierte Beschreibung eines Multiplexers in Verilog. Diese Beschreibung enthalteinige neue Elemente der Sprache Verilog, die wir nun diskutieren:

1. Die ersten beiden Zeilen enthalten Parameter-Definitionen. Diese beginnen mit dem Zeichen“`”2 gefolgt von dem Schlusselwort “define”. Es handelt sich dabei um Makro-Definitionen,

2Der Backquote “‘” hat den ASCII-Code 96. In Verilog wird dieses Zeichen auch als Backtick

bezeichnet. Bedauerlicherweise ist der typografische Unterschied zwischen einem gewohnlichenHochkomma und einem Backtick nur sehr gering. Wir werden den Backtick daher nicht durch dasZeichen “‘”, sondern durch das Zeichen “`” darstellen. Typografisch ist das nicht ganz korrekt,denn das Zeichen, was Sie bei der Eingabe benutzen mussen, erscheint am Bildschirm normaler-weise als “‘”. Um die Verwirrung komplett zu machen ist die Taste, die Sie zur Erzeugung desBackticks drucken mussen, mit dem Zeichen “`” beschriftet.

26

Page 28: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

F

D0

D1

D2

D3

D4

D5

D6

D7

A B C

A A B CB C

Abbildung 18: Ein 8-Bit-Multiplexer.

mit deren Hilfe wir die Makros SLCT WIDTH und DATA WIDTH definieren. Die allgemeine Syntaxist folgende:

`define name value

Durch eine solche Makro-Definition wird im folgenden Verilog-Programm-Text jede Instanzvon name, der ein Backtick vorangeht, durch value ersetzt. Das Konzept ist dabei das selbewie bei einer in der Sprache C mit #define eingeleiteten Makro-Definition.

2. In Zeile 2 haben wir dem Makro “DATA WIDTH” den Wert “(1 << `SLCT WIDTH)” zugewiesen.Die Klammern sind notwendig, weil die Makro-Expansion string-basiert durchgefuhrt wird:Jedes Auftreten von “DATA WIDTH” wird durch den String “(1 << 5)” ersetzt. Dieser Stringwird vor der Einsetzung nicht zu der Zahl 32 ausgewertet. Die Auswertung erfolgt erst spaterdurch den Verilog-Compiler. Falls die Verilog-Beschreibung daher einen Ausdruck der Form“DATA WIDTH -1” enthalt, so wird dieser jetzt zu

(1 << 5) - 1

ausgewertet. Wurden die Klammern fehlen, wurde der Ausdruck zu

1 << 5 - 1

27

Page 29: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module multiplex(out, select, data);

2 output out;

3 input [2:0] select;

4 input [7:0] data;

5 wire [7:0] w;

6

7 and( w[0], ~ select[2], ~ select[1], ~ select[0], data[0] );

8 and( w[1], ~ select[2], ~ select[1], select[0], data[1] );

9 and( w[2], ~ select[2], select[1], ~ select[0], data[2] );

10 and( w[3], ~ select[2], select[1], select[0], data[3] );

11 and( w[4], select[2], ~ select[1], ~ select[0], data[4] );

12 and( w[5], select[2], ~ select[1], select[0], data[5] );

13 and( w[6], select[2], select[1], ~ select[0], data[6] );

14 and( w[7], select[2], select[1], select[0], data[7] );

15

16 or (out, w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]);

17 endmodule

Abbildung 19: Umsetzung des Schaltplans aus Abbildung 18 in Verilog.

ausgewertet. Das ware aber falsch, weil der Operator “-” starker bindet als der Operator“<<”. Der Ausdruck “1 << 5 - 1” hat also den Wert 16, wahrend die Auswertung desAusdrucks “(1 << 5) - 1” den Wert 31 ergibt.

3. In Zeile 7 und 8 werden die oben definierten Makros benutzt: “`SLCT WIDTH” wird durch“5” ersetzt und “`DATA WIDTH” wird durch “(1 << 5)” ersetzt.

4. Zeile 10 leitet einen always-Block ein, der durch die Schlusselworter “begin” und “end”eingeschlossen wird. Der always-Block selber beginnt mit dem Schlusselwort “always”. Inunserem Beispiel wird dieses Schlusselwort von der Sensitivitats-Liste des always-Blocksgefolgt. In unserem Beispiel hat die Sensitivitats-Liste die Form

(data or select)

Bei einer kombinatorischen Schaltung (das ist eine Schaltung ohne Speicher-Elemente) mussenin der Sensitivitats-Liste alle Eingange der Schaltung auftreten. Die einzelnen Elemente derListe werden durch das Schlusselwort “or” getrennt.

Die Semantik eines always-Blocks ist folgende: Immer wenn sich eines der in der Sensiti-vitats-Liste auftetenden Signale andert, werden die Befehle im innern des always-Blocks derReihe nach ausgefuhrt.

5. Zeile 12 enthalt eine sogenannte prozedurale Zuweisung : der Wert der rechten Seite wirdberechnet und dann der Variablen auf der linken Seite zugewiesen, ganz wie in einer proze-duralen Programmier-Sprache.

Die verhaltens-basierte Beschreibung des Multiplexers ist trivial. Das liegt daran, dass dieSprache Verilog den Auswahl-Operator “·[ · ]” zur Verfugung stellt. Fur zwei Bit-Vektoren x undy liefert der Ausdruck “x[y]” das Bit Nummer y aus dem Vektor x.

Wir haben oben die Beschreibung des Dekoders mit Hilfe der Makros “SLCT WIDTH” und“DATA WIDTH” parametrisiert. Wollen wir jetzt statt eines 5-zu-32 Dekoders einen 4-zu-16 De-koder bauen, so konnen wir dies, indem wir die Werte dieser beiden Makros entsprechend andern.Wir konnen Module aber auch direkt parametrisieren. Dadurch erhalten wir noch mehr Flexi-bilitat. Abbildung 21 auf Seite 30 zeigt eine parametrisierte Beschreibung eines Dekoders. Wirhaben hier in den Zeilen 2 und 3 die Parameter “slct width” und “data width” definiert. Wir

28

Page 30: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 `define SLCT_WIDTH 5

2 `define DATA_WIDTH (1 << ‘SLCT_WIDTH) // 2 ** 5

3

4 module multiplexor(out, data, select);

5 output out;

6 reg out;

7 input [`DATA_WIDTH - 1:0] data;

8 input [`SLCT_WIDTH - 1:0] select;

9

10 always @(data or select)

11 begin

12 out = data[select];

13 end

14 endmodule

Abbildung 20: Verhaltens-basierte Beschreibung eines Multiplexers in Verilog.

konnen diese Parameter nun bei der Verwendung dieses Moduls instantiieren. Wir haben das Mo-dul “multiplexor” in den Zeilen 24 und 25 instantiiert. Die erste Instantiierung verwendet dieDefault-Werte fur die beiden Parameter. Bei der zweiten Instantiierung in Zeile 28 setzen wir denersten Parameter “slct width” auf den Wert 4 und den zweiten Parameter “data width” auf denWert 16. Die Syntax zur Instantiierung eines Moduls m mit n Parameter ist wie folgt:

m #(v1, · · ·, vn) name(· · ·)

Hier werden die Parameter in der Reihenfolge, wie sie in dem Modul m definiert werden, mitden Werten v1 bis vn belegt. name ist dabei der Name der Instanz des Moduls. Die Verwen-dung von Parameter hat gegenuber der Verwendung von Makros den Vorteil, dass ein Modul mitverschiedenen Werten instantiiert werden kann, wie das Beispiel in Abbildung 21 zeigt.

2.1.2 Dekoder

Ein n-nach-2n Dekoder kann wie folgt beschrieben werden:

1. Es gibt einen Eingang select, der eine Breite von n Bits hat.

2. Es gibt einen Ausgang out, der eine Breite von 2n Bits hat.

3. Genau eine der 2n Ausgangs-Leitungen out[i] hat den Wert 1, alle anderen Leitungen habenden Wert 0. Es gilt

out[i] = 1 ⇔ i = select.

Abbildung 22 auf Seite 31 zeigt den Schaltplan eines 3-nach-8 Dekoders. Die Implementierungdieser Schaltung in Verilog ist in Abbildung 23 auf Seite 31 zu sehen.

Abbildung 24 auf Seite 32 zeigt eine verhaltens-basierte Beschreibung eines Dekoders in Verilog.Diese Beschreibung zeigt zwei neue Kontroll-Konstrukte:

1. Zeile 12 leitet eine for-Schleife ein. Die Syntax und die Sematik ist ganz ahnlich wie bei derProgrammier-Sprache C. Es gibt allerdings zwei Unterschiede:

(a) In dem Update-Befehl haben wir “i = i + 1” schreiben mussen, denn einen Inkrement-Operator, der es uns erlaubt hatte, dort “++i” zu schreiben, gibt es nicht.

(b) Hatten wir innerhalb der for-Schleife mehrere Befehle gehabt, so hatten wir diese inden Schlussel-Wortern “begin” und “end” einschließen mussen. Dem Schlussel-Wort“begin” entspricht in C die offnende geschweifte Klammer “{”, dem Schlussel-Wort“end” entspricht in C die schließende geschweifte Klammer “}”.

29

Page 31: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module multiplexor(out, data, select);

2 parameter slct_width = 5;

3 parameter data_width = 32;

4

5 output out;

6 reg out;

7 input [data_width - 1:0] data;

8 input [slct_width - 1:0] select;

9

10 always @(data or select)

11 begin

12 out = data[select];

13 end

14 endmodule

15

16 module testMultiplexor;

17 reg [31:0] data_a;

18 reg [4:0] select_a;

19 reg [15:0] data_b;

20 reg [3:0] select_b;

21 wire out_a, out_b;

22 integer i;

23

24 multiplexor test_a (out_a, data_a, select_a);

25 multiplexor #(4, 16) test_b (out_b, data_b, select_b);

26

27 initial

28 begin

29

...

30 end

31 endmodule

Abbildung 21: Parametrisierte Beschreibung eines Multiplexers.

Beachten Sie auch, dass wir in Zeile 9 die Zahlvariable “i” mit dem Schlussel-Wort “integer”deklariert haben. Dem Verilog-Daten-Typ “integer” entspricht in C der Daten-Typ “int”.

2. Zeile 13 leitet eine if-Abfrage ein. Hier ist das Verhalten identisch mit dem Verhalten in C.Sollen in einem der beiden Zweige der if-Abfrage mehrere Befehle ausgefuhrt werden, mussendiese (wie bei for-Schleifen) von den Schlussel-Wortern “begin” und “end” eingeklammertwerden.

2.1.3 Speicher-Zellen

Eine Speicher-Zelle ist eine Struktur, die ein Bit abspeichern kann. Technologisch konnen Speicher-Zellen auf zwei verschiedene Arten realisiert werden:

1. Durch Ruckkopplung logischer Gatter kann ein Flip-Flop erzeugt werden. Speicher, der aufdiese Art erzeugt wird, bezeichnet man als SRAM. Das “S” steht dabei fur statisch.

2. Eine Speicher-Zelle kann durch Kombination eines Transistors mit einem Kondensator er-zeugt werden. Speicher, der so erzeugt wird, bezeichnet man als DRAM. Das “D” steht dabeifur dynamisch.

30

Page 32: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

D0

D1

D2

D3

D4

D5

D6

D7

A

C

B

A

B

C

B

C

A

Abbildung 22: Ein 3-nach-8 Dekoder.

1module decode(out, select);

2 output [7:0] out;

3 input [2:0] select;

4

5 and( out[0], ~ select[2], ~ select[1], ~ select[0] );

6 and( out[1], ~ select[2], ~ select[1], select[0] );

7 and( out[2], ~ select[2], select[1], ~ select[0] );

8 and( out[3], ~ select[2], select[1], select[0] );

9 and( out[4], select[2], ~ select[1], ~ select[0] );

10 and( out[5], select[2], ~ select[1], select[0] );

11 and( out[6], select[2], select[1], ~ select[0] );

12 and( out[7], select[2], select[1], select[0] );

13endmodule

Abbildung 23: Umsetzung der Schaltung aus Abbildung 22 nach Verilog.

Der Kondensator verliert mit der Zeit seine Ladung und muss daher periodisch wieder aufge-laden werden. Daher wird diese Art von Speicher als dynamisch bezeichnet, im Gegensatz zu

31

Page 33: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module decoder(out, select);

2 parameter slct_width = 5;

3 parameter data_width = 32;

4

5 output [data_width - 1:0] out;

6 reg [data_width - 1:0] out;

7 input [slct_width - 1:0] select;

8

9 integer i;

10

11 always @(select)

12 for (i = 0; i < data_width; i = i + 1)

13 if (select == i)

14 out[i] = 1;

15 else

16 out[i] = 0;

17 endmodule

Abbildung 24: Verhaltens-basierte Beschreibung eines Dekoders in Verilog.

dem statischen Speicher, der die gespeicherten Werte solange behalt, solange die Versogungs-Spannung anliegt.

Zwischen DRAM und SRAM gibt es folgende Unterschiede:

1. Eine SRAM-Speicher-Zelle besteht aus mindestens 4 Transistoren, wohingegen eine DRAM-Speicher-Zelle nur aus einem Transistor und einem Kondensator besteht. Daher benotigenSRAM-Speicher-Chips etwa doppelt so viel Platz wie DRAM-Speicher-Chips.

2. SRAM-Speicher-Chips sind etwa 10 mal so teuer wie DRAM-Speicher-Chips.

3. SRAM-Speicher-Chips sind etwa 10 mal schneller als DRAM-Speicher-Chips.

4. SRAM-Speicher-Chips verbrauchen wesentlich mehr Strom als DRAM-Speicher-Chips undproduzieren daher auch mehr Abwarme.

Aus diesen Grunden wird der in einem Rechner vorhandene Speicher haufig in zwei (oder mehr)Hierarchie-Ebenen eingeteilt. Die erste Hierarchie-Ebene ist dabei relativ klein und wird mit teu-rem, aber sehr schnellen SRAM-Speicher bestuckt. Die zweite Hierarchie-Ebene ist großer undbesteht aus DRAM-Speicher-Chips.

Abbildung 25 auf Seite 33 zeigt eine verhaltens-basierte Beschreibung einer Speicher-Zelle. Fallsder Eingang reset auf 1 gesetzt wird, wird die Speicher-Zelle auf 0 gesetzt. Falls der Eingangenable aktiviert ist, wird bei jeder steigenden Flanke des Signals clk der am Eingang data

anliegende Wert abgespeichert und gleichzeitig auch ausgegeben. Schalten wir enable ab, behaltdie Zelle den gespeicherten Wert. In diesem Fall bleibt der Ausgang out hochohmig, die Schaltunggibt dann also ein z aus.

Die Verilog-Beschreibung enthalt in Zeile 6 ein neues Element, “posedge”. Den Elementen derSensitivitats-Liste ist das Schlusselwort “posedge” vorangestellt. Dies bedeutet, dass die Befehle indem always-Block nur bei einer steigenden Flanke der entsprechenden Signale ausgefuhrt werden.

Die Verilog-Beschreibung der Speicher-Zelle mischt eine verhaltens-basierte Beschreibung miteiner strukturellen Beschreibung. Der always-Block, der sich von Zeile 6 bis Zeile 11 erstreckt,stellt eine verhaltens-basierte Beschreibung dar. Demgegenuber ist die Instantiierung des bufif1-Gatters strukturell.

32

Page 34: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module memory_cell(out, clk, reset, enable, data);

2 output out;

3 reg q;

4 input clk, reset, enable, data;

5

6 always @(posedge clk or posedge reset)

7 if (reset)

8 q = 0;

9 else

10 if (enable)

11 q = data;

12

13 bufif1(out, q, enable);

14 endmodule // memory_cell

Abbildung 25: Verhaltens-basierte Beschreibung einer Speicher-Zelle in Verilog.

2.1.4 Speicher-Strukturen

Nachdem wir oben die einzelnen Bestandteile vorgestellt haben, aus denen Speicher aufgebautwird, zeigen wir nun, wie diese zusammengeschaltet werden. Abbildung 26 auf Seite 34 zeigt eineneinfachen Speicher, der aus 4 Wortern besteht. Die Worter sind in diesem Beispiel nur 2 Bitgroß. Der Speicher ist aufgebaut aus einem 2-zu-4 Dekoder, der eine 2-Bit-Adresse als Eingabeerhalt und mit dieser 2-Bit Adresse eines der 4 Worter auswahlt, indem er das enable Signal furdieses Wort setzt. Die zwei Bits des ausgewahlten Wortes werden dann auf die Ausgange gelegt.Zusatzlich werden die vom Dekoder erzeugten Signale noch mit dem Signal “write” und mit demTaktsignal “clk” logisch und-verknupft. (Das Taktsignal wurde in der Abbildung unterdruckt.)Das Resultat dieser Verknupfung steuert das clk-Signal der einzelnen Speicher-Zellen an.

Abbildung 27 auf Seite 34 zeigt eine Implementierung des 4×2 SRAMs in Verilog. Die Verilog-Beschreibung weicht an zwei Stellen von dem in Abbildung 26 gezeigten Schaltplan ab:

1. Das Signal “reset” wurde in dem Schaltplan unterdruckt. Speicher-Chips haben aber ubli-cherweise ein Signal “reset”, mit dem sich der Speicher auf einen definierten Zustand setzenlaßt.

2. Das Signal “clk” wurde ebenfalls in dem Schaltplan unterdruckt. Ohne ein clk-Signal kannein SRAM Speicher-Chip aber gar nicht funktionieren, weil die Daten-Eingange immer nurbei einer steigenden clk-Flanke eingelesen werden.

Bewachten Sie, dass die for-Schleife in Zeile 11 eine Turbo-Type for-Schleife ist. Das liegt dar-an, dass unsere Verilog-Beschreibung des SRAMs eine strukturelle Beschreibung ist und auf derstrukturellen Ebene gibt es in Verilog keine for-Schleife.

Die in den letzten beiden Abbildungen vorgestellte Struktur ist ausreichend, um kleinere Spei-cher zu realisieren. Beispielsweise konnen die Register in einem Prozessor uber eine solche Struk-tur implementiert werden. Fur großere Speicher ist eine solche Struktur aber zu aufwendig, weilder dann benotigte Dekoder zu groß wurde. Großere Speicher-Bausteine werden daher mit einerzweistufigen Struktur realisiert. Abbildung 28 auf Seite 35 zeigt eine solche Struktur. In dieserSchaltung werden 8 SRAMs der Große 512 × 64 parallel geschaltet und uber die oberen 9 Pinsder Adress-Leitung angesteuert. Jedes dieser 8 SRAMs liefert ein 64 Bit Wort. Aus jedem dieser 8Worter wird mit Hilfe von Multiplexern, die uber die ersten 6 Pins der Adress-Leitung angesteuertwerden, ein Bit selektiert.

Wir wollen nun versuchen, die in der Abbildung 28 gezeigte Speicher-Struktur in Verilog zu mo-dellieren. Wir beginnen damit, dass wir ein Modul implementieren, das 512×64 Bits speichert. Wir

33

Page 35: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

D latch Q

DCEnable

2-to-4 decoder

Write enable

Address

Din[0]Din[1]

Dout[1] Dout[0]

0

1

2

3

Abbildung 26: Ein 8-Bit Speicher.

1 module memory_4x2(Dout, Address, Din, write, clk, reset);

2 output [1:0] Dout;

3 input [1:0] Address;

4 input [1:0] Din;

5 input write, clk, reset;

6

7 wire [3:0] decoderOut;

8

9 decoder #(2, 4) dcdr (decoderOut, Address);

10

11 for (i = 0; i < 4; i = i + 1) {12 memory_cell m_0_$i (Dout[0], write & decoderOut[$i] & clk,

13 reset, decoderOut[$i], Din[0]);

14 memory_cell m_1_$i (Dout[1], write & decoderOut[$i] & clk,

15 reset, decoderOut[$i], Din[1]);

16 }17 endmodule // memory_4x2

Abbildung 27: Implementierung eines 4 × 2 SRAMs in Verilog.

konnten versuchen, dieses Modul mit Hilfe des Moduls “memory cell” strukturell zu beschreiben.Eine solche Beschreibung mußte 512∗64 = 32 768 Instanzen des Moduls “memory cell” enthalten.

34

Page 36: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

512 × 64 SRAM

Mux

Dout7

512 × 64 SRAM

Mux

Dout6

512 × 64 SRAM

Mux

Dout5

512 × 64 SRAM

Mux

Dout4

512 × 64 SRAM

Mux

Dout3

512 × 64 SRAM

Mux

Dout2

512 × 64 SRAM

Mux

Dout1

512 × 64 SRAM

Mux

Dout0

9-to-512 decoder

Address [14–6]

64

512

Address [5–0]

Abbildung 28: Struktur eines 32K× 8 SRAM.

Unter Benutzung von Turbo-Type ware es zwar moglich, eine entsprechende Verilog-Datei zu er-zeugen. Die Datei ware aber riesengroß und die Ubersetzung mit dem uns zur Verfugung stehendenVerilog-Compiler wurde unverhaltnismaßig lange dauern. Daher geben wir in Abbildung 29 eineverhaltens-basierte Implementierung eines solchen Speichers an. Diese Implementierung enthalt inZeile 7 eine Neuerung: Wir haben dort den eigentlichen Speicher mit Hilfe der zweidimensiona-len Struktur “mem” implementiert. Die allgemeine Syntax zur Definition einer zweidimensionalenSpeicher-Struktur in Verilog ist wie folgt:

reg [msb:lsb] name [first:last]

Die Bedeutung der einzelnen Parameter ist dabei wie folgt:

1. name ist der Name, mit dem auf die Struktur Bezug genommen werden kann.

2. msb steht fur most significand bit.

3. lsb steht fur least significand bit.

4. first steht fur den Index des ersten Wortes.

5. last steht fur den Index des letzten Wortes.

Insgesamt wird durch die obige Deklaration eine Speicher-Matrix definiert, die aus last− first + 1Worten besteht. Jedes der Worte besteht aus msb − lsb + 1 Bits.

Insgesamt besteht die Implementierung aus einem verhaltens-basierten Anteil und einem struk-turellen Anteil. Der verhaltens-basierte Anteil besteht aus dem always-Block, der von Zeile 9 bis11 reicht. Der strukturelle Anteil besteht aus dem assign-Befehl in Zeile 13. Hier ist zu beachten,dass die Gleichheitszeichen in den Zeilen 11 und 13 unterschiedliche Bedeutungen haben:

1. Die Zuweisung in Zeile 11 innerhalb des always-Blocks ist eine sogenannte prozedurale

Zuweisung. Sie wird genau dann ausgefuhrt, wenn der Simulator den Befehl in Zeile 11ausfuhrt. Andert sich der Wert des Signals Din spater noch einmal, so hat dies auf den Wertmem[Address] keine Auswirkung mehr. Diese Zuweisung hat also den selben Character wieeine Zuweisung in einer prozeduralen Programmier-Sprache.

2. Bei der Zuweisung in Zeile 13 innerhalb des assign-Befehls handelt es sich um eine standige

Zuweisung3: Immer, wenn die rechte Seite mem[Address] sich andert, wird automatisch auchdie linke Seite geandert. Einer standigen Zuweisung entspricht in der Schaltung ein Draht.

3Im Englischen spricht man von einem continuous assignment. Dieser Begriff kann auch als stetige Zuweisung

ubersetzt werden.

35

Page 37: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module memory_512x64(Dout, Address, Din, write, clk, reset);

2 output [63:0] Dout;

3 input [8:0] Address;

4 input [63:0] Din;

5 input write, clk, reset;

6

7 reg [63:0] mem [0:511];

8 integer i;

9

10 always @(posedge clk)

11 if (reset)

12 for (i = 0; i < 512; i = i + 1)

13 mem[i] = 64’b0;

14 else

15 if (write)

16 mem[ Address ] = Din;

17

18 assign Dout = mem[ Address ];

19 endmodule

Abbildung 29: Verhaltens-basierte Implementierung eines 512× 64 SRAMs in Verilog.

Mit Hilfe des Moduls “memory 512x64” konnen wir nun die in Abbildung 28 gezeigte Strukturimplementieren. Sobald wir mit der Implementierung beginnen, merken wir, dass die Abbildung28 eine Frage offenlaßt: Wie wird ein 8-Bit-Wort in die gezeigte Speicher-Matrix geschrieben?Das Problem ist, dass wir in die Module “memory 512x64” immer nur 64-Bit-Worter schreibenkonnen. Die 8 Multiplexern, die unten in der Abbildung 28 auftauchen, helfen uns an dieser Stellenicht weiter, denn mit Hilfe dieser Multiplexern konnen wir zwar aus einem 64-Bit-Wort ein Bitselektieren, aber der umgekehrte Weg funktioniert nicht, denn wie sollten wir die fehlenden 63Bits erraten? Da wir Sie nicht raten konnen, bleibt als Alternative nur, die einzelnen 64-Bit-Worter vorher zu lesen. Dann konnen wir mit Hilfe von Multiplexern das zu andernde Bit setzenund anschließend schreiben wir die so geanderten 64-Bit-Worter wieder in die 512 × 8 Speicher-Struktur.

Abbildung 30 auf Seite 37 zeigt eine Implementierung dieser Idee in Verilog. Diese Implemen-tierung besteht aus einem strukturellen und einem verhaltens-basierten Anteil. Der strukturelleAnteil erstreckt sich von Zeile 14 bis nach Zeile 19. Hier werden uber eine Turbo-Type for-Schleifezunachst 8 Instanzen des Moduls “memory 512x64” gebildet. Die Daten-Eingange dieser Instanzenhaben die Namen wini mit i = 0, · · · , 7, die Daten-Ausgange heißen entsprechend wouti.

Der verhaltens-basierte Anteil besteht aus dem always-Block, der sich von Zeile 21 bis 42ersteckt. Dieser always-Block besteht aus einer Fallunterscheidung:

1. Falls das write-Signal gesetzt ist, mussen wir zunachst aus den Instanzen des Moduls“memory 512x64” die durch die ersten 6 Bits von Address spezifizierten 64-Bit-Worte lesen.Die gelesenen Worter speichern wir in Zeile 27 in der Hilfs-Variablen aux reg ab. In Zeile28 andern wir dann das zu schreibende Bit in diesem 64-Bit-Wort ab und setzen den Ein-gang wini des i-ten memory 512x64-Moduls auf das so geanderte 64-Bit-Wort. Um diesesWort nun tatsachlich zu speichern, mussen wir am clk-Signal des Moduls memory 512x64

eine steigende Flanke erzeugen. Die erreichen wir dadurch, dass wir in Zeile 24 das Signal“aux clk” auf 0 setzen und in Zeile 32 dann auf 1.

2. Falls das write-Signal nicht gesetzt ist, selektieren wir in Zeile 40 die einzelnen Bits aus den64-Bit-Wortern wouti und schreiben Sie in das interne Register q, das in Zeile 19 uber einestandige Zuweisung mit dem Ausgang verknupft ist.

36

Page 38: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module memory_32Kx8(Dout, Address, Din, write, clk, reset);

2 output [7:0] Dout;

3 input [14:0] Address;

4 input [7:0] Din;

5 input write, clk, reset;

6

7 reg [63:0] win0, win1, win2, win3, win4, win5, win6, win7;

8 wire [63:0] wout0, wout1, wout2, wout3, wout4, wout5, wout6, wout7;

9

10 reg [7:0] q;

11 reg [63:0] aux_reg;

12 reg aux_write, aux_clk;

13

14 for (i = 0; i < 8; i = i + 1) {15 memory_512x64 m$i (wout$i, Address[14:6], win$i, aux_write,

16 aux_clk, reset);

17 }18

19 assign Dout = q;

20

21 always @(posedge clk)

22 if (write)

23 begin

24 aux_clk = 0;

25 aux_write = 0;

26 for (i = 0; i < 8; i = i + 1) {27 aux_reg = wout$i;

28 aux_reg[ Address[5:0] ] = Din[$i];

29 win$i = aux_reg;

30 }31 aux_write = 1;

32 aux_clk = 1;

33 end

34 else

35 begin

36 aux_clk = 0;

37 aux_write = 0;

38 for (i = 0; i < 8; i = i + 1) {39 q[$i] = wout$i[ Address[5:0] ];

40 }41 end

42 endmodule

Abbildung 30: Implementierung des 32K× 8 SRAMs in Verilog.

Zum Abschluß zeigen wir noch, wie das Modul “memory 512x64” mit Hilfe in diesem Abschnittvorgestellten Verilog-Konstrukte getestet werden kann. Abbildung 31 auf Seite 38 zeigt eine Test-bench. Nach der Initialisierung der Variablen in den Zeilen 15 bis 19 werden alle Speicher-Worterin der for-Schleife, die sich von Zeile 20 bis nach Zeile 36 erstreckt, getestet. Dazu wird zunachst inder inneren for-Schleife, die sich von Zeile 24 bis 27 erstreckt, die Speicher-Worter an den Adres-sen von i bis i + 255 mit verschiedenen Werten beschrieben. Anschließend werden diese Worter inder for-Schleife, die in Zeile 28 beginnt und in Zeile 35 endet, ausgelesen. In Zeile 32 wird dann

37

Page 39: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

uberpruft, ob der gelesene Wert mit dem ursprunglich gespeicherten Wert ubereinstimmt. Fallsdies nicht der Fall ist, wird mit dem $display-Befehl in Zeile 33 eine Fehlermeldung ausgegeben.

1 module testMemory;

2 reg [14:0] Address;

3 reg [7:0] Din;

4 reg write, reset;

5 wire [7:0] Dout;

6 wire clk;

7

8 integer i, j;

9

10 tick_tack rolex (clk);

11 memory_32Kx8 test (Dout, Address, Din, write, clk, reset);

12

13 initial

14 begin

15 Address = 0;

16 Din = 0;

17 write = 0;

18 reset = 1;

19 #1 reset = 0;

20 for (i = 0; i < 32512; i = i + 256)

21 begin

22 $display("Testing %d", i);

23 #2 Address = i; write = 1;

24 for (j = 0; j < 256; j = j + 1)

25 begin

26 #2 Address = i + j; Din = j;

27 end

28 for (j = 0; j < 256; j = j + 1)

29 begin

30 #2 Address = i + j;

31 #2

32 if (Dout != j)

33 $display("ERROR: Address = %d, Dout = %d",

34 Address, Dout);

35 end

36 end

37 $display("done");

38 end

39

40 endmodule // testMemory

Abbildung 31: Testbench fur das Modul memory 512x64.

38

Page 40: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

2.2 Cache

Als IBM 1981 den IBM PC einfuhrte, war dieser mit einem Intel 8088 Prozessor ausgestattet, des-sen Taktfrequenz bei 4,77 MHz lag. Der damals zur Verfugung stehende DRAM Speicher konntemit dieser Taktfrequenz betrieben werden. In den folgenden Jahren wurde die Taktfrequenz derIntel-Prozessoren wesentlich starker gesteigert als die Frequenzen, mit den DRAM betrieben wer-den konnten. Daher wurde der Zugriff auf den Haupt-Speicher zum Flaschenhals. Um das Problemzu losen, wurden zwei Maßnahmen ergriffen: Zum einen werden Prozessoren mit einer immer große-ren Zahl an Registern ausgestattet. Beispielsweise verfugt der UltraSparc-Prozessor von Sun uber32 general purpose Register und zusatzlich uber 32 floating point Register. Zum anderen wirdin einem modernen Rechner Cache integriert. Beim Cache handelt es sich um schnellen SRAMSpeicher. Der Cache hat eine wesentlich kleinere Speicher-Kapazitat als der Haupt-Speicher unddient dazu solche Daten abzulegen, die haufig benutzt werden. Abbildung 32 zeigt einen Prozessor,der uber einen Cache auf den Haupt-Speicher zugreift.

Cache

Bus

Haupt -Speicher

CPU

Abbildung 32: Einsatz von Cache.

Die Grundidee ist wie folgt: Benotigt der Prozessor Daten aus dem Haupt-Speicher, so wirdzunachst gepruft, ob diese Daten bereits im Cache vorhanden sind. Ist dies der Fall, so werdendie Daten aus dem Cache genommen und der langsame Haupt-Speicher braucht nicht aktiviertwerden. Nur dann, wenn die benotigten Daten sich nicht im Cache befinden, werden Sie aus demHaupt-Speicher geholt, an den Prozessor weitergereicht und zusatzlich im Cache abgelegt, so dassdiese Daten dann beim nachsten Zugriff schnell gefunden werden konnen.

Dieses Verfahren wurde dann wenig bringen, wenn der Prozessor in vollig zufalliger Art undWeise auf den Haupt-Speicher zugreifen wurde, denn dann ware die Wahrscheinlichkeit gering, dassdie benotigten Daten im Cache liegen. In der Praxis genugen Speicher-Zugriffe aber dem zeitlichen

Lokalitats-Prinzip: In der Regel greift der Prozessor innerhalb eines kleinen Zeitintervals nur aufeinen geringen Bruchteil des Haupt-Speichers zu und zusatzlich werden die meisten Daten, auf

39

Page 41: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

die zugegriffen wird, auch mehrfach benotigt. Neben dem zeitlichen Lokalitats-Prinzip gibt esnoch das raumliche Lokalitats-Prinzip: Dieses besagt, dass Speicher-Zellen, auf die zugegriffenwerden, oft nah beieinander liegen. Sowohl das zeitliche wie auch das raumliche Lokalitats-Prinziphaben ihren Ursprung in der strukturierten Programmierung. Wir erlautern die Prinzipien aneinem Beispiel. Abbildung 33 zeigt im linken Teil eine IJVM-Methode zur Multiplikation zweiernaturlicher Zahlen. Im rechten Teil dieser Abbildung sehen wir den Stack zu dem Zeitpunkt, andem der Programm-Counter auf die Anweisung in Zeile 14 zeigt.

1 .method multiply( a, b )

2 .var

3 result ~ ~

4 .end-var | |

5 BIPUSH 0x00 +--------+

6 ISTORE result | |

7 loop: ILOAD b +--------+

8 IFEQ finish | |

9 ILOAD b +--------+

10 BIPUSH 1 | |

11 IAND |--------|

12 IFEQ next SP -> | a |

13 ILOAD result |--------|

14 PC −→ ILOAD a | result |

15 IADD |--------|

16 ISTORE result | Old LV |

17 next: ILOAD a |--------|

18 DUP | Old PC |

19 IADD +- |--------|

20 ISTORE a lokale Variable -> | | result |

21 ILOAD b +- |--------|

22 SRA1 | | b |

23 ISTORE b Parameter -> + |--------|

24 goto loop | | a |

25 finish: ILOAD result +- |--------|

26 IRETURN | |

27 .end-method ~ ~

Abbildung 33: Multiplikation zweier Zahlen in IJVM-Assembler.

Soeben ist die lokale Variable a mit dem Befehl “ILOAD a” oben auf den Stack gelegt worden.Dazu waren zwei Speicher-Zugriffe notwendig: Zunachst mußte die Variable a aus dem Haupt-Speicher gelesen werden, anschließend wurde diese Variable an eine andere Stelle im Haupt-Speicher geschrieben. Das ganze findet in einer Schleife statt, die sich von Zeile 7 bis Zeile 24erstreckt und die 32 mal durchlaufen werden kann. Bei jedem Schleifen-Durchlauf gibt es Zugriffeauf die lokalen Variable result und auf die beiden Parameter a und b. Auf die Speicher-Zellen,wo diese Variablen abgelegt sind, wird also innerhalb relativ kurzer Zeit mehrfach zugegriffen.Zusatzlich wird auch der Programm-Code, der dieser Schleife entspricht, mehrfach gelesen.

2.2.1 Ein einfacher Cache

Wir wollen nun zeigen wie ein einfacher Cache aufgebaut ist und zu diesem Zweck eine verhaltens-basierte Beschreibung eines Caches in Verilog konstruieren. Dazu sind zunachst folgende Fragenzu klaren:

1. Wie legen wir Daten im Cache ab, so dass wir Sie schnell wiederfinden konnen.

40

Page 42: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

2. Welche Daten entfernen wir aus dem Cache bei Platzmangel.

Abbildung 34 auf Seite 41 zeigt die Speicher-Struktur eines ganz einfachen Caches.

Index Valid Address Data

0

1

2

3

4

1023

Abbildung 34: Ein einfacher Cache.

Der Speicher besteht aus 1024 Zeilen. Jeder dieser Zeilen hat drei Komponenten:

1. Das Valid-Bit zeigt an, ob die in der Zeile gespeicherten Daten gultig sind.

2. Das Feld Address speichert die Adresse, unter der die die Daten im Haupt-Speicher abge-speichert sind.

3. Das Feld Data beinhaltet die eigentlichen Daten.

Wie konnen wir Daten im Cache wiederfinden? Falls eine Adresse a gegeben ist, von der Datenaus dem Haupt-Speicher gelesen werden sollen, so konnten wir einfach alle Adress-Felder aus demCache mit a vergleichen. Finden wir dabei eine Zeile unseres Caches, so dass die dort eingetrageneAdresse den Wert a hat, so sind die in dieser Zeile gespeicherten Daten die Daten, die wir suchen.

Das oben geschilderte Verfahren hat einen entscheidenden Haken: Wenn wir die einzelnenAdress-Felder sequentiell nacheinander vergleichen, dauert das wesentlich langer als wenn wir dieDaten direkt aus dem Haupt-Speicher lesen wurden. Der einzige Ausweg besteht in der Verwen-dung einer kombinatorischen Schaltung, die parallel alle Adress-Felder mit der gegebenen Adressea vergleicht und die im Erfolgsfall den Index der Zeile zuruck liefert, fur die der Vergleich erfolg-reich war. Eine solche Schaltung ist aber sehr aufwendig und kann daher nur fur einen kleinenCache realisiert werden. Einen nach diesem Verfahren konstruierten Cache bezeichnet man alsassoziativen Speicher.

Die in der Realitat benutzte Architektur fur einen Cache ist eine andere. Anstatt Daten ir-gendwo im Cache abzulegen, benutzen wir die Bits Nummer 11 bis 2 der Adresse als Index undlegen die Daten in der durch diesen Index bezeichneten Zeile im Cache ab. Der Index unter demein Datum mit der Adresse a abgelegt wird, berechnet sich also nach folgender Formel:

index = (a & 12’b11111111111︸ ︷︷ ︸

10

00) >> 2

Wieso werden die untersten 2 Bits der Adresse nicht berucksichtigt? Der Grund liegt darin, dassSpeicher-Adressen aus historischen Grunden Byte-Adressen sind. In unserem Cache speichern wiraber Worte ab, die eine Große von 4 Bytes haben. Die letzten beiden Bits der Adresse unterschei-den nur zwischen den 4 Bytes eines Wortes und werden fur die Adressierung des Wortes selbstnicht benotigt. Auf einem Pentium Rechner wird Speicher nur wortweise ausgelesen, die letztenbeiden Bits der Adresse sind also immer auf 0 gesetzt.

41

Page 43: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Wenn wir den Index, unter dem wir ein Wort im Cache ablegen, wie oben beschrieben berech-nen, dann ist es nicht erforderlich, die vollstandige Adresse abzuspeichern, denn die Bits Nummer11 bis 2 der Adresse sind ja schon durch den Zeilen-Index bekannt und die untersten beiden Bitssind 0. Es reicht also, die obersten 20 Bits als sogenanntes Tag abzuspeichern. Ist die Adresse a,so kann dieses Tag nach folgender Formel berechnet werden:

tag = a >> 12

Abbildung 35 auf Seite 42 zeigt die Speicher-Struktur eines Caches mit Tags. Der einzige Unter-schied zu der vorherigen Abbildung 34 besteht darin, dass pro Zeile 12 Bits eingespart wordensind.

Index Valid Tag Data

0

1

2

3

4

1023

Abbildung 35: Ein Cache mit Tags.

Wir zeigen nun, wie sich ein solcher Cache implementieren laßt. Dazu betrachten wir zunachstdie Schaltung in Abbildung 36 auf Seite 43. Die Abbildung zeigt, dass die Bits der Adresse einesDatums in drei Gruppen eingeteilt werden.

1. Die ersten beiden Bits adressieren die Bytes innerhalb eines Wortes und sind immer 0, weilwir nur Worte adressieren.

2. Die nachsten 10 Bits geben den Index der Zeile an, in der ein Datum im Cache abgelegtwird.

3. Die restlichen 20 Bits werden als Tag zusammen mit dem Datum abgespeichert.

Die Abbildung zeigt den Teil der Schaltung, der zum Lesen eines Wortes benotigt wird. BeimLesen wird zunachst der Index der Zeile berechnet unter dem das Wort abgelegt ist, wenn essich denn im Cache befindet. Der Tag, der sich in dieser Zeile befindet, wird mit den obersten 20Bits der Adresse verglichen. Wird bei diesem Vergleich eine Ubereinstimmung festgestellt, so mußnoch uberpruft werden, ob das Valid-Bit gesetzt ist. Falls dies der Fall ist, wird das Hit-Signalgesetzt. Zusatzlich werden die in der ausgewahlten Zeile abgespeicherten Daten am Ausgang Data

ausgegeben.Wir zeigen nun, wie sich der oben dikutierte Cache in Verilog realisieren laßt. Abbildung 37

auf Seite 44 zeigt die Realisierung eines Caches in Verilog. Wir diskutieren zunachst das Interfacedes Moduls cache.

1. Dout steht fur data out. Auf diesem Bus werden die im Cache gefundenen Daten ausgegeben.

2. hit wird gesetzt, wenn das Tag der gefundenen Daten mit dem aus der Adresse berechnetenTag ubereinstimmt und wenn zusatzlich das valid-Bit gesetzt ist. Bei einem Lesevorgangbedeutet dies, dass die gesuchten Daten im Cache vorhanden sind.

42

Page 44: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Address (showing bit positions)

20 10

Byte offset

Valid Tag DataIndex012

102110221023

Tag

Index

Hit Data

20 32

31 30 13 12 11 2 1 0

Abbildung 36: Ein einfacher Cache.

Die restlichen Signale sind Eingaben.

3. Address gibt die Adresse an, unter der die Daten im Haupt-Speicher abgelegt werden.

4. Din steht fur data in. Bei einem Schreibvorgang enthalt dieser Bus die abzuspeicherndenDaten.

5. rd wird gesetzt, wenn Daten aus dem Cache gelesen werden sollen.

6. wr wird gesetzt, wenn Daten in den Cache geschrieben werden sollen.

7. clk bezeichnet das Takt-Signal.

8. reset loscht alle Daten im Cache.

Den Ausgabe-Signalen Dout und hit entsprechen die internen Register DoutReg und hitReg.Wir benotigen diese Register, weil wir den Cache verhaltens-basiert beschreiben wollen. Bei einersolchen Beschreibung mussen wir den Ausgabe-Signalen Werte zuweisen. In Verilog muss das Zieleiner prozeduralen Zuweisung immer ein Register sein.

Das Modul cache ist parametrisiert. Der erste Parameter ls gibt die Zahl der Bits an, diezur Darstellung des Index benotigt werden. Diese Zahl ist der Zweier-Logarithmus der Große desCaches. Diese Große wird in dem zweiten Parameter size spezifiziert. Diese beiden Parameternmussen folglich in der Beziehung

2ls = size bzw. ls = log2(size)

stehen. In den Zeilen 14 bis 16 definieren wir den eigentlichen Speicher, den wir zur Implementie-rung des Caches verwenden. Der verwendete Speicher besteht, wie in den Abbildungen ersichtlich,

43

Page 45: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

aus dem Array valid, dessen Elemente ein Bit enthalten, aus dem Array tag, dessen Elementeeine Breite von 20 Bits haben und aus dem Array data, dessen Elemente 32 Bit groß sind. InZeile 17 definieren wir das Register index, das spater den Index der Zeile angibt, in der Datenabgespeichert werden sollen. In Zeile 18 definieren wir i als integer. Dieses Register wird alsZahlvariable beim Reset des Caches benotigt.

1 module cache(Dout, hit, Address, Din, rd, wr, clk, reset);

2 parameter ls = 10; // ls is log2(1024)

3 parameter size = 1 << ls; // size = 1024

4

5 output [31:0] Dout;

6 output hit;

7 input [31:0] Din;

8 input [31:0] Address;

9 input rd, wr, clk, reset;

10

11 reg [31:0] Dout;

12 reg hit;

13

14 reg valid [0:size-1];

15 reg [29-ls:0] tag [0:size-1];

16 reg [31:0] data [0:size-1];

17 reg [ls-1:0] index;

18 integer i;

19

20 always @(posedge clk or posedge reset)

21 begin

22 if (reset)

23 for (i = 0; i < size; i = i + 1)

24 begin

25 data [i] = 0;

26 tag [i] = 0;

27 valid[i] = 0;

28 end

29 else

30 begin

31 index = Address[ls+1:2];

32 hit = (Address[31:ls+2] == tag[index] && valid[index]);

33 if (wr)

34 begin

35 data [ index ] = Din;

36 tag [ index ] = Address[31:ls+2];

37 valid [ index ] = 1;

38 end

39 else if (rd)

40 Dout = data[ index ];

41 end

42 end

43 endmodule

Abbildung 37: Implementierung eines Caches in Verilog.

44

Page 46: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Die verhaltens-basierte Beschreibung des Caches erfolgt durch den always-Block, der sichvon Zeile 20 bis zum Ende des Moduls erstreckt. Zunachst prufen wir ab, ob das reset-Signalgesetzt ist. In diesem Fall setzen wir mit einer for-Schleife die Daten aller Cache-Zeilen auf denWert 0. Andernfalls berechnen wir in zunachst den Zeilen-Index, der fur ein Abspeichern oderAufsuchen von Daten in Frage kommt und setzen dann das Register hit, indem wir zunachst dentag der durch index spezifizierten Zeile mit den oberen 20 Bits der Adresse vergleichen und dannnachprufen, ob das valid-Bit der Zeile gesetzt ist. Falls das Signal wr gesetzt ist und also eineSchreib-Aufforderung vorliegt, speichern wir die Daten in der durch index spezifizierten Zeile ab,schreiben in das tag-Feld die obersten 20 Bits der Adresse und setzen das valid-Bit, denn dieDaten in dieser Zeile sind ja jetzt gultig. Falls das Signal rd gesetzt ist und folglich eine Lese-Aufforderung vorliegt, holen wir die Daten aus der Zeile, deren Index wir berechnet haben undund schreiben sie in das Register Dout.

2.2.2 Modellierung des Haupt-Speichers in Verilog

Wir haben bisher nur die Struktur des Caches selber beschrieben. Viel interessanter ist aber derCache-Controller. Anfragen vom Prozessor werden zunachst an den Cache-Controller geschickt.Dieser pruft dann, ob die benotigten Daten im Cache liegen. Wenn dies der Fall ist, werdendiese Daten aus dem Cache gelesen und zum Prozessor weitergeleitet. Andernfalls liest der Cache-Controller die Daten aus dem Haupt-Speicher. Um den Cache-Controller modellieren zu konnen,benotigen wir also zusatzlich ein Modell des Haupt-Speichers.

Abbildung 38 auf Seite 46 zeigt, wie Haupt-Speicher in Verilog modelliert werden kann. Wirdiskutieren zunachst das Interface dieses Moduls.

1. Dout steht fur data out und liefert die gelesenen Daten.

2. done zeigt an, dass der Haupt-Speicher seine Arbeit beendet hat. Bei einer Lese-Anforderungheißt dies, dass die angeforderten Daten am Ausgang Dout zur Verfugung stehen, bei einemSchreib-Vorgang ist die Bedeutung, dass die Daten in den Speicher geschrieben worden sind.

Im allgemeinen kann nicht vorhergesagt werden, wie lange beispielsweise ein Lese-Zyklusdauern wird. Dies liegt daran, dass der Haupt-Speicher selbst noch einen second level Cachebeinhalten kann. Je nach dem, ob die Daten dort liegen oder ob sie sich im echten Haupt-Speicher befinden dauert der Lese-Zyklus naturlich unterschiedlich lange. Aus diesem Grundeist das Signal done notwendig.

Alle weiteren Signale sind Eingaben.

3. Address spezifiziert die Adresse im Haupt-Speicher, von der entweder Daten gelesen werdensollen, oder an der Daten abgelegt werden sollen. Da es sich hierbei um eine Byte-Adressehandelt, auf den Speicher aber immer nur worteweise zugegriffen wird, sind die letzten beidenBits von Address immer auf 0 gesetzt.

4. Din steht fur data in. Dieses Signal ist nur fur einen Schreib-Vorgang von Bedeutung undenthalt dann die zu schreibenden Daten.

5. rd ist gesetzt, wenn Daten aus dem Haupt-Speicher gelesen werden sollen.

6. wr ist gesetzt, wenn Daten in den Haupt-Speicher geschrieben werden sollen.

7. clk ist das Takt-Signal.

8. reset setzt den Haupt-Speicher auf 0.

Uber die drei Signale done, rd und wr wird ein Hand-Shake-Protokoll realisiert. Das Protokollbesteht aus folgenden Regeln, an die sich der Haupt-Speicher und ein Benutzer des Haupt-Speichershalten mussen. Wir erlautern dieses Protokoll zunachst fur den Lese-Vorgang.

45

Page 47: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module memory(Dout, done, Address, Din, rd, wr, clk, reset);

2 parameter size = 1 << 14; // 64 KB memory

3

4 output [31:0] Dout;

5 output done;

6 input [31:0] Address;

7 input [31:0] Din;

8 input rd;

9 input wr;

10 input clk;

11 input reset;

12

13 reg [31:0] mem [0:size-1];

14 reg [31:0] Dout;

15 reg done;

16

17 integer i;

18

19 always @(posedge clk or posedge reset)

20 begin

21 if (reset)

22 begin

23 done = 0;

24 for (i = 0; i < size; i = i + 1)

25 mem[i] = 0;

26 end

27 else

28 begin

29 if (rd & !done)

30 begin

31 #10 Dout = mem[Address[31:2]];

32 done = 1;

33 end

34 else if (wr & !done)

35 begin

36 #10 mem[Address[31:2]] = Din;

37 done = 1;

38 end

39 else if (!rd & !wr & done)

40 #2 done = 0;

41 end

42 end

43 endmodule

Abbildung 38: Modellierung des Haupt-Speichers in Verilog.

1. Das Signal rd darf an den Speicher nur angelegt werden, wenn der Ausgang done den Wert0 annimmt.

2. Wenn das Signal rd angelegt ist, bleibt es solange auf 1, bis der Haupt-Speicher das Signaldone setzt und damit signalisiert, dass die Daten am Ausgang Dout zur Verfugung stehen.

3. Wenn das Signal done auf 1 gesetzt ist, kann der Benutzer die Daten vom Ausgang Dout

46

Page 48: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

abholen. Nachdem der Benutzer diese Daten gelesen hat, setzt er das Signal rd auf 0 undsignalisiert damit dem Haupt-Speicher, dass er die Daten nicht langer am Ausgang Dout

bereit halten muss.

4. Nachdem das Signal rd auf 0 gesetzt worden ist, schaltet der Haupt-Speicher das Signal donezuruck auf 0. Damit signalisiert der Haupt-Speicher, dass er fur die nachste Anforderungbereit ist.

Fur den Schreib-Vorgang lauten die Regeln ganz ahnlich:

1. Das Signal wr darf an den Speicher nur angelegt werden, wenn der Ausgang done den Wert0 annimmt.

2. Wenn das Signal wr angelegt ist, bleibt es solange auf 1, bis der Haupt-Speicher das Signaldone setzt und damit signalisiert, dass die Daten, die am Eingang Din angelegt wurden, vomHaupt-Speicher geschrieben worden sind.

3. Nachdem das Signal done auf 1 gesetzt worden ist, darf der Benutzer des Haupt-Speichersdas Signal wr auf 0 zuruck setzen. Damit wird dem Haupt-Speicher signalisiert, dass dieserdas Signal done zuruck setzen kann.

4. Nachdem das Signal wr auf 0 gesetzt worden ist, setzt der Haupt-Speicher das Signal donezuruck auf 0 und signalisiert so, dass der Haupt-Speicher fur die nachste Anforderung bereitist.

Wir betrachten nun die Details der Implementierung. Zeile 13 enthalt die Definition des eigentli-chen Speichers. Das Verhalten des Speichers wird durch den always-Block, der in Zeile 19 beginnt,beschrieben. Zunachst wird dort uberpruft, ob das Signal reset anliegt. Wenn dem so ist, wirdder gesamte Speicher mit 0 initialisiert. Andernfalls gibt es funf Falle:

1. Das Signal rd ist gesetzt und das Register done steht noch auf 0, die Lese-Anforderungwurde also noch nicht erfullt. Dann werden die Daten aus dem Haupt-Speicher mit einerVerzogerung von 10 Zeit-Einheiten gelesen. Hierbei ist wichtig zu sehen, dass der Haupt-Speicher nur mit den obersten 29 Bits der Adresse adressiert wird. Das liegt an der obenschon erwahnten Tatsache, dass die Adresse, die in dem Signal Address anliegt, eine Byte-Adresse ist. Nachdem die Daten in Dout abgelegt sind, wird das Signal done auf 1 gesetzt.

2. Das Signal wr ist gesetzt und das Register done steht noch auf 0, die Schreib-Anforderungwurde also noch nicht erfullt. Dann werden die Daten mit einer Verzogerung von 10 Zeit-Einheiten im Haupt-Speicher abgelegt. Anschließend wird das Signal done auf 1 gesetzt.

3. Wenn das Register done den Wert 1 hat aber weder wr noch rd gesetzt sind, dann konnennwir schließen dass der Haupt-Speicher die Lese- bzw. Schreib-Anforderung, die vorher ange-legen hat erfullt hat. Da aber nun die Anforderung zuruck genommen worden ist, kann derHaupt-Speicher seinerseits das Signal done auf 0 setzen.

4. Desweiteren kann es sein, dass zwar done schon auf 1 gesetzt ist, der Klient des Haupt-Speichers aber noch nicht signalisiert hat, dass er die Daten abgeholt hat. In diesem Fallist nichts zu tun, der Haupt-Speicher wartet dann, bis die Lese- bzw. Schreib-Anforderungverschwindet.

5. Schließlich ist es auch moglich, dass die Signale rd, wr und done alle den Wert 0 haben. Auchin diesem Fall ist nichts zu tun, der Haupt-Speicher warten dann, bis eine Lese- bzw. Schreib-Anforderung eintrifft.

47

Page 49: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

2.2.3 Modellierung eines Cache-Controller in Verilog

Wir zeigen nun, wie ein Cache-Controller in Verilog modelliert werden kann. Bevor wir eine Mo-dellierung angeben konnen mussen wir die Frage klaren, welche Strategie wir beim Schreibenverwenden wollen. Prinzipiell gibt es zwei Moglichkeiten:

1. Die write-through-Strategie schreibt Daten immer direkt in den Hauptspeicher.

2. Die write-back -Strategie schreibt Daten zunachst in den Cache. Daten werden erst dannzuruck in den Haupt-Speicher geschrieben, wenn der von den Daten im Cache belegte Platzfur andere Daten benotigt wird.

Die write-through-Strategie ist einfacher zu implementieren als die write-back -Strategie. Daherbetrachten wir in Abbildung 39 auf Seite 50 zunachst einen Cache-Controller, der die write-through-Strategie implementiert.

Wir verwenden zur Modellierung des Cache-Controllers das selbe Interface wie bei der Model-lierung des Haupt-Speichers und verweisen auf die dort gemachten Ausfuhrungen. Unser Modelldes Cache-Controllers besteht aus einem strukturellen Anteil und aus einem verhaltens-basiertenAnteil. Der strukturelle Anteil ist in den Zeilen 10 bis 12 zu sehen: Dort instantiieren wir denCache und den Haupt-Speicher. Um diese Schaltungen ansprechen zu konnen, sind eine Reihezusatzlicher interner Drahte und Register notwendig:

1. DinCache ist ein 32-Bit Register, das mit dem Cache Modul als Eingabe dient.

2. rdMem steuert, ob der Haupt-Speicher gelesen werden soll.

3. wrMem steuert, ob der Haupt-Speicher geschrieben werden soll.

4. rdCache steuert, ob der Cache gelesen werden soll.

5. wrCache steuert, ob der Cache geschrieben werden soll.

6. memDone signalisiert, dass der Haupt-Speicher eine Anforderung (Lesen oder Schreiben)erfullt hat.

7. DoutMem ist das Daten-Ausgabe-Signal des Haupt-Speichers.

8. DoutCache ist das Daten-Ausgabe-Signal des Caches.

Der verhaltens-basierte Anteil der Schaltung besteht aus einer always-Schleife. Falls das Signalreset gesetzt ist, werden in Zeile 16 alle Anforderungs-Signale an Cache und Haupt-Speicher auf0 gesetzt. Weiterhin wird in dieser Zeile done auf 0 gesetzt um nach außen zu signalisiern, dassder Cache-Controller bereit ist. Falls reset nicht gesetzt ist, unterscheiden wir funf Falle:

1. Falls das Signal rd gesetzt ist, aber das Register done noch den Wert 0 hat, liegt eineLese-Anforderung vor, die noch nicht befriedigt werden konnte. Zunachst versuchen wir,die benotigten Daten aus dem Cache zu lesen und setzen dazu das Signal rdCache. Wirgehen bei unserer Modellierung davon aus, dass der Cache diese Anfrage innerhalb einesTakt-Zykluses beantwortet. Wir warten also in Zeile 23 auf die nachste steigende Flanke desTakt-Signals. Falls der Cache dann durch Setzen des hit-Signals anzeigt, dass die Daten imCache vorhanden sind, schreiben wir diese Daten in das Register Dout und setzen das Signaldone auf 1 um anzuzeigen, dass wir die Daten gefunden haben.

Falls die Daten nicht im Cache gefunden werden konnten, mussen wir die Daten aus demHaupt-Speicher lesen. Wir warten zunachst, bis der Haupt-Speicher durch Setzen des SignalsmemDone auf 0 anzeigt, dass er fur Anforderungen bereit ist. Normalerweise konnen wir hierdavon ausgehen, dass memDone schon auf 0 steht. Dann setzen wir das Signal rdMem auf 1und geben dem Haupt-Speicher damit eine Lese-Anforderung. Danach mussen wir warten,bis der Haupt-Speicher durch setzen des Signals memDone anzeigt, dass die Daten am Ausgang

48

Page 50: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

DoutMem zur Verfugung stehen. Wir kopieren diese Daten in das Register Dout und ebenfallsin das Register DinCache, weil wir als nachstes die Daten im Cache speichern. Außerdemsetzen wir das Signal rdMem zuruck, so dass dem Speicher signalisiert wird, dass er die Datennicht langer am Ausgang DoutMem zur Verfugung stellen muss. Durch Setzen von wrCache

werden dann die Daten in den Cache geschrieben und wir signalisieren durch Setzen vondone, dass die Lese-Anforderung erfullt worden ist.

2. Falls das Signal wr gesetzt ist, aber das Register done noch den Wert 0 hat, liegt eine Schreib-Anforderung vor, die noch nicht befriedigt werden konnte. Wir schreiben die Daten sowohlin den Haupt-Speicher als auch in den Cache.

3. Falls keines der Signale rd oder wr anliegt, aber done noch auf 1 steht, lag eine Anforderungvor, die bereits befriedigt worden ist. Da nun keine Anforderung mehr vor liegt, kann jetztdas Signal done zuruck gesetzt werden.

4. Außerdem kann es noch sein, dass eine Anforderung vorliegt, also eines der Signale rd oderwr gesetzt ist, die wir bereits erfullt haben, sprich das Signal done ist gesetzt. Da der Klientdie Anforderung aber noch nicht zuruck genommen hat, mussen wir das Signal done solangeauf 1 halten, bis der Klient die Daten abgeholt hat. Da in diesem Fall kein Signal geandertwerden muss, findet sich dieser Fall im Code der Abbildung 39 nicht wieder.

5. Der letzte Fall ist wieder der, dass keines der Signale rd, wr, oder done gesetzt ist. Dann istnichts zu tun. Daher wird auch dieser Fall im Code nicht berucksichtigt.

2.2.4 Die write-back-Strategie

Bei der oben diskutierten write-through-Strategie werden die Daten immer sowohl in den Cacheals auch in den Haupt-Speicher geschrieben. Ein Cache, der mit dieser Strategie arbeitet, kannden Daten-Bus beim Schreiben nicht entlasten. Als Alternative wird daher im Cache-Controlleroft eine write-back -Strategie implementiert. Bei dieser Strategie werden die Daten zunachst nurin den Cache geschrieben. Das geht so lange gut, bis die im Cache befindlichen Daten von einemSchreib-Befehl mit Daten uberschrieben werden, die im Haupt-Speicher an einer anderen Adressestehen. Solche Daten mussen naturlich in den Haupt-Speicher zuruck geschrieben werden (write-

back) bevor sie uberschrieben werden.An dieser Stelle kann der Prozeß noch optimiert werden, denn es mussen nur solche Daten

zuruck geschrieben werden, die auch tatsachlich geandert worden sind. Um festzustellen ob Datengeandert worden sind, wird mit den Daten ein zusatzliches Flag abgespeichert, das immer danngesetzt wird, wenn die Daten im Cache abweichen von den Daten, die unter der entsprechen-den Adresse im Haupt-Speicher liegen. Wir bezeichnen dieses zusatzliche Bit als das Dirty-Bit.Abbildung 40 zeigt die Speicher-Struktur, die in so einem Fall verwendet wird.

Abbildung 41 auf Seite 52 zeigt die Implementierung eines Caches, der fur die write-back -Strategie ausgelegt ist. Zunachst fallt auf, dass das Interface großer geworden ist.

1. wb steht fur write back. Das Ausgabe-Signale wb wird gesetzt, wenn das Dirty-Bit in derZeile gesetzt ist, aus der Daten gelesen wurden.

2. AddressOut gibt die Adresse an, unter der die gelesenen Daten im Haupt-Speicher zu findensind. Falls das Signal hit nicht gesetzt ist, ist das eine andere Adresse als Address.

3. sd steht fur set dirty. Dieses Eingabe-Signal wird gesetzt, wenn fur die Zeile, in der Datenabgespeichert werden, das Dirty-Bit gesetzt werden soll.

Die Verhaltens-Spezifikation unterscheidet sich von der Spezifikation in Abbildung 37 auf Seite 44nur an zwei Stellen:

1. Beim Schreiben wird in Zeile 40 zusatzlich das Dirty-Bit so gesetzt, wie es das Signal sdangibt.

49

Page 51: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module cacheCntrl(Dout, done, Address, Din, rd, wr, clk, reset);

2 output [31:0] Dout;

3 output done;

4 input [31:0] Address, Din;

5 input rd, wr, clk, reset;

6 reg [31:0] Dout, DinCache;

7 reg done, rdMem, wrMem, rdCache, wrCache;

8 wire memDone, hit;

9 wire [31:0] DoutMem, DoutCache;

10 cache cch (DoutCache, hit,

11 Address, DinCache, rdCache, wrCache, clk, reset);

12 memory mry (DoutMem, memDone, Address, Din, rdMem, wrMem, clk, reset);

13 always @(posedge clk or posedge reset)

14 if (reset)

15 begin

16 rdMem = 0; wrMem = 0; rdCache = 0; wrCache = 0; done = 0;

17 end

18 else

19 begin

20 if (rd & !done)

21 begin

22 rdCache = 1;

23 @(posedge clk);

24 rdCache = 0;

25 if (hit)

26 begin

27 Dout = DoutCache; done = 1;

28 end

29 else

30 begin

31 wait(!memDone);

32 rdMem = 1;

33 wait(memDone);

34 Dout = DoutMem; DinCache = DoutMem;

35 rdMem = 0; wrCache = 1;

36 @(posedge clk);

37 wrCache = 0; done = 1;

38 end

39 end

40 else if (wr & !done)

41 begin

42 DinCache = Din;

43 wait(!memDone);

44 wrMem = 1; wrCache = 1;

45 wait(memDone);

46 wrMem = 0; wrCache = 0; done = 1;

47 end

48 else if (!rd & !wr & done)

49 #2 done = 0;

50 end

51 endmodule

Abbildung 39: Modellierung eines Cache-Controllers in Verilog.

50

Page 52: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Index Valid Tag Data Dirty

0

1

2

3

4

1023

Abbildung 40: Ein Cache mit Tags und Dirty-Bit.

2. Beim Lesen werden zusatzlich die Ausgaben AddressOut und wb gesetzt. AddressOut wirdin Zeile 45 berechnet, indem drei Bitvektoren aneinander gehangt werden.

(a) 2'b00: Das ist der Byte-Index. Weil wir nur Wort-Adressen haben, stehen hier zweiNullen.

(b) index: Gibt die untersten Bits der Adresse an, abzuglich des Byte-Indexes.

(c) tag[index]: Der Tag enthalt den Rest der Adresse.

Die Implementierung des Cache-Controllers ist auf zwei Abbildungen verteilt. Zunachst zeigtAbbildung 42 das Interface zusammen mit der Definition der Register und Drahte, die als Hilfs-Variablen benotigt werden. Das Interface selbst hat sich gegenuber dem Interface, das bei der write-

through-Strategie verwendet wurde, nicht geandert. Zusatzliche Hilfs-Variablen werden benotigt,weil sich die Schnittstelle des Moduls cache geandert hat.

Abbildung 43 auf Seite 54 zeigt die Beschreibung des Verhaltens. Hier gibt es zwei Verande-rungen gegenuber der write-through-Strategie:

1. Falls das Signal rd gesetzt ist und das Register done noch den Wert 0 hat, so lesen wirzunachst wie fruher die Daten aus dem Cache. Falls nun das Signal hit nicht gesetzt wird,mussen wir auf das Signal wb achten: Ist dies gesetzt, so durfen wir die Daten im Cache nichteinfach uberschreiben sondern mussen sie vorher im Haupt-Speicher sichern. Dies geschieht inZeile 18 bis 24. Anschließend konnen wir wie vorher die Daten, die durch Address spezifiziertwerden aus dem Haupt-Speicher lesen und in den Cache schreiben. In diesem Fall brauchtdas Dirty-Bit nicht gesetzt werden, denn die Daten im Cache stimmen ja mit den Daten ausdem Haupt-Speicher uberein.

2. Falls das Signal wr gesetzt ist und das Register done noch den Wert 0 hat, so mussen wirnun zuerst uberprufen, ob im Cache Daten liegen, die nicht uberschrieben werden durfen.Wenn dies der Fall ist, schreiben wir diese Daten in den Haupt-Speicher zuruck. Anschließendwerden die neuen Daten in den Cache geschrieben.

Die beschriebenen Implementierungen sind aus didaktischen Grunden stark vereinfacht worden.Die Implementierung realer Caches ist weit komplexer als hier dargestellt.

51

Page 53: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module cache(Dout, hit, wb, AddressOut,

2 Address, Din, rd, wr, sd, clk, reset);

3 parameter ls = 10; // ls is log2(1024)

4 parameter size = 1 << ls; // size = 1024

5 output [31:0] Dout;

6 output hit;

7 output wb; // write back is set when data is dirty

8 output [31:0] AddressOut; // needed for write back

9 input [31:0] Din;

10 input [31:0] Address;

11 input rd, wr, sd, clk, reset;

12 reg [31:0] Dout, AddressOut;

13 reg hit, wb;

14 reg valid [0:size-1];

15 reg [29-ls:0] tag [0:size-1];

16 reg [31:0] data [0:size-1];

17 reg dirty [0:size-1];

18 reg [ls-1:0] index;

19 integer i;

20

21 always @(posedge clk or posedge reset)

22 begin

23 if (reset)

24 for (i = 0; i < size; i = i + 1)

25 begin

26 data [i] = 0;

27 tag [i] = 0;

28 valid[i] = 0;

29 dirty[i] = 0;

30 end

31 else

32 begin

33 index = Address[ls+1:2];

34 hit = (Address[31:ls+2] == tag[index] && valid[index]);

35 if (wr)

36 begin

37 data [ index ] = Din;

38 tag [ index ] = Address[31:ls+2];

39 valid [ index ] = 1;

40 dirty [ index ] = sd;

41 end

42 else if (rd)

43 begin

44 Dout = data[ index ];

45 AddressOut = { tag[index], index, 2’b00 };46 wb = dirty[ index ];

47 end

48 end

49 end

50 endmodule

Abbildung 41: Implementierung eines Caches mit Dirty-Bit in Verilog.

52

Page 54: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 module cacheCntrl(Dout, done, Address, Din, rd, wr, clk, reset);

2 output [31:0] Dout;

3 output done;

4

5 input [31:0] Address;

6 input [31:0] Din;

7 input rd;

8 input wr;

9 input clk;

10 input reset;

11

12 reg [31:0] Dout;

13 reg done;

14

15 reg [31:0] AddressMem;

16 reg [31:0] DinMem, DinCache;

17 reg rdMem, wrMem, rdCache, wrCache, sd;

18

19 wire [31:0] DoutMem;

20 wire [31:0] DoutCache;

21 wire [31:0] AddressOut;

22 wire hit, wb, memDone;

23

24 cache cch (DoutCache, hit, wb, AddressOut,

25 Address, DinCache, rdCache, wrCache, sd, clk, reset);

26

27 memory mry (DoutMem, memDone,

28 AddressMem, DinMem, rdMem, wrMem, clk, reset);

29

Abbildung 42: write-back -Strategie: Interface, Register und Struktur.

53

Page 55: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

1 always @(posedge clk or posedge reset)

2 if (reset)

3 begin

4 rdMem = 0; wrMem = 0; rdCache = 0; wrCache = 0; done = 0;

5 end

6 else

7 begin

8 if (rd & !done)

9 begin

10 rdCache = 1;

11 @(posedge clk);

12 rdCache = 0;

13 if (hit)

14 begin Dout = DoutCache; done = 1; end

15 else

16 begin

17 if (wb)

18 begin

19 wait(!memDone);

20 DinMem = DoutCache; AddressMem = AddressOut;

21 wrMem = 1;

22 wait(memDone);

23 wrMem = 0;

24 end

25 wait(!memDone);

26 AddressMem = Address; rdMem = 1;

27 wait(memDone);

28 Dout = DoutMem; DinCache = DoutMem; rdMem = 0;

29 sd = 0; wrCache = 1;

30 @(posedge clk);

31 wrCache = 0; done = 1;

32 end

33 end

34 else if (wr & !done)

35 begin

36 rdCache = 1;

37 @(posedge clk);

38 if (!hit & wb)

39 begin

40 wait(!memDone);

41 DinMem = DoutCache; AddressMem = AddressOut;

42 wrMem = 1;

43 wait(memDone);

44 wrMem = 0;

45 end

46 DinCache = Din; sd = 1; wrCache = 1;

47 @(posedge clk);

48 wrCache = 0; done = 1;

49 end

50 else if (!wr & !rd & done) done = 0;

51 end

52 endmodule

Abbildung 43: write-back -Strategie: Beschreibung des Verhaltens.

54

Page 56: Vorlesungen ub er Rechner-Technik - DHBW Stuttgartstroetma/CT/ct.pdf · 1 Programmierung in Mikro-Assembler 1.1 Ub erblick IndiesemKapitelbehandeln wirdie ProgrammierunginMikro-Assembler.

Literatur

[1] John L. Hennessey and David A. Patterson: Computer Organization & Design, Second Edi-tion, Morgan Kaufmann, 1998.

[2] Andrew S. Tanenbaum: Structured Computer Organization, Fourth Edition, Prentice Hall,1999.

55