6.5 MMIX Befehle 291
In folgendem Programmcode wird XXX XXXXXXXX als Platzhalter für einen einzelnen
Befehl verwendet:
LOC Data_SegmentGREG @
A OCTA #FFFF FFFF FFFF FFFFB TETRA #8765 4321
LOC #100Main LDTU $0,B
XXX XXXXXXXXTRAP 0,Halt,0
c) Geben Sie für das oben gezeigte Programm den Inhalt des 64 Bit breiten Wortes
an, welches durch die Marke A adressiert wird, wenn XXX XXXXXXXX durch folgende
Befehle ersetzt wird:
STB $0,A:
STTU $0,A:
STT $0,$254,6:
T d) Geben Sie für das oben gezeigte Programm den Inhalt des 64 Bit breiten Wortes
an, welches durch die Marke A adressiert wird, wenn XXX XXXXXXXX durch folgende
Befehle ersetzt wird:
STW $0,A:
STWU $0,A:
STT $0,A:
STO $0,A:
STB $0,$254,5:
STW $0,$254,1:
ST0 $0,$254,5:
:a iii. ,
:
⇒→
_o←:;fff÷±t→
o.O$oi¥oeaFi( 321 FFF . -
-FFFF
k32n FFF r. FFFF
87654324 FF . . .
F
ITOH 8+654327←
TO FFFF FFFF FFH FFFF
0~ 432N FFFF . - - .
FFFF
own 0000.060 8765434
292 6 MMIX-Prozessor
e) Geben Sie hexadezimal das 32 Bit breite Befehlswort des Befehls STBU $0,A an,
wenn dieser in obigem Programmcode den Platzhalter XXX XXXXXXXX ersetzt.
T f) Geben Sie die Befehle an, mit denen Sie
• an Adresse 0x2000 0000 0000 0000 ein 64 Bit breites Datum anlegen,
• dieses Datum über die Marke Data ansprechbar machen und
• das Datenwort mit 0x1234 5678 initialisieren;
• an Adresse 0x100 ein Programm beginnen und
• das an Adresse Data gespeicherte Datenwort in Register 1 einlesen,
• Bits 7 ... 0 des Registers 1 an Adresse Data schreiben,
• Bits 7 ... 0 des Registers 1 an Adresse 0x2000 0000 0000 0002 schreiben,
• Bits 31 ... 0 des Registers 1 an Adresse 0x2000 0000 0000 000A schreiben.
0→
-
→
.0O
O
( OC #Zo . - .0
Dose GREG @
→ Data OCTA Fm 345678
Loc #zou
Main LDO $1 , Data
STD $1 ,Data
STB$1 ,
Base ,2
STT $7,
Base ,#A
6.5 MMIX Befehle 293
Gegeben ist der folgende Programmcode:
LOC Data_SegementGREG @
Label OCTA #1234 5678
LOC #100Main LDO $0,Label
STB $0,LabelLDA $2,LabelSTB $0,$2,2STT $0,$2,10
T g) Zeichnen Sie byteweise den Inhalt des Speichers von Adresse 0x20 ... 00 bis
0x20 ... 00F, der sich nach Ausführung des o.g. Programms ergibt.
f &
←
o$oFto2234J6T|
÷zips-
-
0ssae se §
0×20 . - - -
-00 do 78 78 78
0×20 - --
07 oo00 oe oo
-7 .. -
-
02' - 00 78 28
. -- -03
,
' ' 00 oo oo
. , -04 1-Z 22?Z22
. .
.-
05 ) 4 34 34 34
, . . -06 56 56 JG oz
..
-
-07 78 78 7f As
e-.
.
08 ? ? ? ? 22 ¢
.. -
-09 2 ? ?
I
34
.
.-
.
OA ? ? ? of
.- -
VOB ? ?? 28
7 ? ?,
✓-
icierOD ? ?
'
z
? ? . I
.
. -OE
, 7.
1 7
. ✓ -OF
iii 7
~,
10 l c(
296 6 MMIX-Prozessor
Zugriff auf Spezialregister
Befehl Operanden Name/Aktion Definition
GET $X,Z Get value of special purpose register $X S(Z)
PUTX,$Z Put value to special purpose register S(X) $ZX,Z Put immed. value to spec. purp. reg. S(X) u
064(u(Z))
T a) Tragen Sie in nachfolgender Befehlssequenz Befehle zur Berechnung der Fest-
kommadivisioni dividend/divisor ein und speichern Sie das Ergebnis an der
Marke Quotient und den Divisionsrest an der Marke Remainder ab.
LOC Data_SegmentGREG @
Dividend OCTA 7Divisor OCTA 3Quotient OCTARemainder OCTA
dividend IS $0divisor IS $1quotient IS $2remainder IS $3
LOC #100Main LDO dividend,Dividend
LDO divisor,Divisor
TRAP 0,Halt,0
→
DIU quotient ,dividend ,
divisor
GET reminder .RR
STO quotient ,Quotient
ffo reminder ,Reminder
6.5 MMIX Befehle 301
T e) Geben Sie den MMIX-Code an, der nachfolgenden C-Code implementiert:
C-Code: int a, b;
...
if(a > 0 && b < 0){
a = 1;}else if(a > 0 || b == 0){
a = 2;}else{
a = 3;}
MMIX-Code:
:oz'
302 6 MMIX-Prozessor
Befehle für Funktionsaufrufe
Befehl Operanden Name/Aktion Definition
GO$X,$Y,$Z Go to location
$X u
064( u(@) + 4) );
@ u
064( u($Y)+u($Z) )
$X,$Y,Z Go to location immediate$X u
064( u(@) + 4) );
@ u
064( u($Y) + u(Z) )
T a) Was ist der Haupt-Unterschied zwischen dem JMP-Befehl und dem GO-Befehl?
T b) Wo speichern GO-Befehle die Rücksprungadresse ab?
T c) Was ist die ‘‘Rücksprungadresse’’?
T d) Wenn GO Absolute Adressierung verwendet: Wie wird die Abolute Adresse (64 Bit)
im 32 Bit breiten Befehlswort abgelegt?
e) Geben Sie den Befehl an, mit dem Sie die Funktion fkt aufrufen und die Rück-
sprungadresse in Register 0 ablegen.
TMP -1 relative Adressieouy ( nah hinter lnad
GO → Absolute Adigiuuag ,
Vonuqoringn ,relakvAtpudm Speicher t die
w ioh guede bin )
Ridspruyadiesse ( Jup - Nichtl
In Register ×
Die tossed . nidyk Befehlswort .
Wenn
Go an einu durch via teilban Adresx a ist,
dawn ist die R.s. a a*4.
$Y =) Basioediesx ,in Reg . Ygspeidwt
7 / $7 ⇒ offset
6.5 MMIX Befehle 303
Namensräume - der PREFIX-Befehl
Der PREFIX-Befehl ist ein Assembler-Befehl. Er wird verwendet, um in einem Pro-
gramm vorkommenden Namen vom Assembler-Präprozessor durch Voranstellen einer
Zeichenkette automatisiert ändern zu lassen. Dazu wird der PREFIX-Befehl mit der
voranzustellenden Zeichenkette als Operand aufgerufen.
PREFIX Zeichenkette
Ab dieser Anweisung setzt der Assembler-Präprozessor vor jeden Namen die angege-
bene Zeichenkette. Hat beispielsweise die Zeichenkette den Wert ‘‘abc:’’, dann wird ein
Name ‘‘def’’ in ‘‘abc:def’’ geändert.
Fügt man vor jede Funktion einen PREFIX-Befehl mit dem Funktionsnamen als Zeichen-
kette ein, erzeugt man automatisch für jede Funktion einen eigenen Namensraum. Eine
Variable i in der Funktion fkt bekommt dann den (globalen) Namen fkti und eine Variable
i in der Funktion fkt2 den Namen fkt2i. Auf diese Weise kann der Assembler beide
Variable als unterschiedliche Variable erkennen und es kommt zu keinem Konflikt, wenn
der Assembler beispielsweise i sowohl durch $1 ersetzen soll (für die Funktion fkt1) als
auch durch $2 (für die Funktion fkt2).
Um den Funktionsnamen besser vom Variablennamen abgrenzen zu können, bietet es
sich an, an die Prefix-Zeichenkette noch ein markantes Zeichen anzuhängen, beispiels-
weise einen Bindestrich oder einen Doppelpunkt.
Um einen Namensraum zu beenden, d.h. um den Assembler-Präprozessor anzuweisen,
vorkommenden Namen die Zeichenkette nicht mehr voranzustellen, wird der PREFIX-
Befehl mit einem Doppelpunkt als Operand aufgerufen.
PREFIX :
Will man innerhalb eines Namensraums verhindern, dass der Assembler-Präprozessor
einen Namen ändert, schreibt man vor den betreffenden Namen einen Doppelpunkt,
z.B. ‘‘:def’’ statt ‘‘def’’. Auf diese Weise kann man auf globale Namen wie z.B. den
Stackpointer SP zugreifen.
a) Geben Sie die Anweisung an, mit denen Sie den Namensraum ‘‘Main:’’ eröffnen
und in diesem Namensraum die globale Marke ‘‘Main’’ definieren.
:0
304 6 MMIX-Prozessor
b) Wie kann man einen Namensraum beenden, d.h. wie kann man den Assembler
anweisen, Marken/Namen nicht mehr umzuwandeln?
c) Wie kann man – innerhalb eines Namensraums – verhindern, dass der Assembler
einer bestimmten Marke bzw. einem bestimmten Namen die im PREFIX-Befehlangegebene Zeichenkette voranstellt?
T d) Wozu dient der PREFIX-Befehl?
T e) Welche Auswirkung hat der Befehl PREFIX mein_prefix auf darauf folgendeMMIX-
Anweisungen?
Genneiwuyu
.Naumoraiwne
→ low,
global ?
( Variable .Fkt . )
→ def ( Nemeu .
Variable )
↳ nein . prefixdeef
( Rein Textuxttuy )
6.5 MMIX Befehle 305
T f) Geben Sie die Anweisungen an, mit denen Sie den Namensraum ‘‘Fkt:’’ eröffnen
und die globale Marke ‘‘Fkt’’ anlegen.
Funktionsaufrufe
Mit Funktionen werden logisch zusammengehörige Befehle zur Bereitstellung einer
Gesamt-Funktionalität zusammengefasst und durch Funktionsaufrufe von beliebigen
Stellen im Programm abrufbar. Durch diese Struktur gebende Maßnahme werden
Programme übersichtlicher und kürzer:
• Übersichtlicher, da der Programm-Code die Zerlegung eines großen Problems
in kleinere Probleme durch Funktionsaufrufe widerspiegelt, und
• kürzer, da eine Funktionalität (viele Befehle) nur einmal aus Befehlen zusam-
mengesetzt werden muss und durch Sprünge in die Funktion (wenige Befehle)
beliebig oft verwendet werden kann.
Beispiel: Email-Adresse von Personen aus einer csv-Datei (csv = comma separated
values =Werte durch Komma getrennt) extrahieren und jeder Person ein Email schreiben:
• Aufruf einer Funktion, welche den Namen der csv-Datei als Parameter überge-
ben bekommt und den Inhalt der Datei in den String s einliest.
• Aufruf einer Funktion, welche den String s sowie das Zeichen \n als Parameter
übergeben bekommt, den String an den Zeichen \n in Teil-Stings s1, s2, ... auf-
trennt und als Ergebnis ein Array von Zeigern auf die Teil-Strings zurückliefert.
• Für jeden Teilstring s
i
: Aufruf einer Funktion, welche den String s
i
und das
Komma-Zeichen als Parameter übergeben bekommt, den String an den Kom-
mas in Teilstrings s
i
j
auftrennt und als Ergebnis ein Array von Zeigern auf die
Teil-Strings zurückliefert.
• Auswahl des Teil-Strings s
i
j
, in dem die EMail-Adresse gespeichert ist.
• Für jede Email-Adresse s
i
j
: Aufruf einer Funktion, die als Parameter die Email-
Adresse und den Email-Text bekommt und den Email-Text an die angegebene
Email-Adresse verschickt.
PREFIX Fkt :
:Fkt.
.-
6.5 MMIX Befehle 321
T i) Was ist der Stack?
T j) Wo beginnt der Stack und in welche Richtung wächst er?
T k) Was ist der Stack-Pointer?
T l) Wie werden Daten adressiert, die auf dem Stack liegen?
Beih in Avbeitsspidw .
Es ulhilt
.locale Vi
iegiesiclwkRegistertoR
. s ,
a .
( Richoprungadreosen )
Ended . Datugmnts und waihst Ridingkleiner er Adresom .
Ein Register ,da , die Ad= do xhttt
aef dm State atgelyk Elements entlidt.
TMAER its den S . P C Skd . Pointe )
adroit
322 6 MMIX-Prozessor
T m) Welche Operationen muss man ausführen um die Werte zweier Register (acht Byte
breite Datenworte) auf dem Stack abzulegen?
T n) Wie wird der Stack bei Funktionsaufrufen verwendet?
@ Substratum : 2-8--206 ( 2 Bytes )
@ n.
Datuwwt gespidut and :c Wwe d. SP
2 .Dale wort
' '
' '' '
' '
d. SP
← 8
Bin Afefd .Feet .
° Parmeter ⇒ Stack
In.
Ikt .
. R.s.ae ⇒ Stade
• diejmige Register ,d :& von der aufgrufue
Fkt . geeidut under ⇒ in Stack sicken .
. Raitt Stach
.Parmeter . .
. Ergebnis !
. Ergebnis ⇒ Slade
a giaidwte Reg .in Stach =) wieduheroklbn
• Stack =) Rs .a( auslesa )
a RP ..
. .
auf Ergbrisvon Fktu tedgm
.
GO - Befell e) FonkhionsowfrufuNaeh Ruekw ⇒ Ergetn
'
's⇐ Slack ( asluof
6.5 MMIX Befehle 323
T o) Geben Sie den Befehl an mit dem Sie für den Stack-Pointer ein globales Register
reservieren und dieses mit 0x4000 00000000 0000 initialisieren.
T p) Warum initialisieren wir den Stack-Pointer mit 0x4000 00000000 0000, d.h. mit
dem Beginn des Poolsegments, und nicht mit dem Ende des Datensegments?
T q) Geben Sie die MMIX-Befehle an, mit denen Sie Register $1 und $2 auf den Stack
schreiben und dann die Funktion fkt aufrufen. Nehmen Sie an, dass Ihr Code im
Namensraum Main: steht und fkt im Namensraum Fkt: unter dem Namen :fktangelegt wurde. Sichern Sie die Rücksprungadresse in Register 0.
SP GREG #4o . -- o
Ven Schreiber : Wet ✓ .
S - P veroiyat
It Oleta ± SP - 8 =) # ZEFFF . . .F8
(Datnoymat )
FUB :S ,P,
:SP ; 2*8
HE sto $n ,
: sad
JTO $2 ,:SP
,
1×8
60 $0 ,:tht
324 6 MMIX-Prozessor
Nehmen Sie an, dass Sie eine Funktion im Namensraum Fkt: implementieren.
T r) Geben Sie die MMIX-Befehle an, mit denen Sie die Register 0, 1, 2 und 3 auf den
Stack sichern und anschließend zwei acht Byte breite Parameter vom Stack in die
Register 1 und 2 einlesen.
T s) Zeichnen Sie, wie der Stack nach diesen Operationen aussieht.
SUB '
.SP
,
-
- SD,
4*18
~STO $0 ,
:SP,
0
STO $7,
: sp ,a←8
~
STO $2 ,
'
' SP,
22.8~
SIZ $3,
'
.
SP,
3.8
( DO
$1,750, 4.8←
( Do $2 , isp, 5.8
→FDoa¥:#=p
6.5 MMIX Befehle 325
T t) Im Hauptprogramm wurden die Parameter in die Register 1 und 2 geschrieben.
Im Unterprogramm wurden Register 1 und 2 dann auf den Stack gesichert und
dann dieselben Werte wieder vom Stack in Register 1 und 2 geladen, obwohl
sich die Werte von Register 1 und 2 in der Zwischenzeit nicht geändert hatten.
Warum haben wir und diesen Schritt nicht gespart sondern dieselben Werte, die
in Registern 1 und 2 waren, nochmal reingeschrieben?
T u) Warum speichert man die Rücksprungadresse auf dem Stack?
T v) Was würde passieren, wenn der Stack so groß wird, dass er mit den Daten
zusammenstößt, die am Beginn des Datensegments liegen?
CHAOS
326 6 MMIX-Prozessor
T w) Geben Sie die MMIX-Befehle an, mit denen Sie den Inhalt von Register 3 als
Ergebnis auf dem Stack ablegen, dann die Register 0, 1, 2 und 3 wiederherstellen
und anschließend zurück zum Funktionsaufrufer springen.
T x) Nehmen Sie an, Sie sind wieder im Hauptprogramm. Geben Sie die Befehle an mit
denen Sie das Ergebnis der Funktion vom Stack in das Register 1 einlesen.
T y) Warum muss der Stack-Pointer angepasst werden nachdem das Ergebnis vom
Stack geladen wurde?
STO $3 ,:SP ,
5.8
LDO $0 ,, SP
,0
( Do $1 ,:S ?
,
a .8
LDU $2 /:Sp ,2.8
LDO $3 ,:SP ,
3 . 8
ADD :SP, :s@ ,
5.8
60 $01 $010
. ( D 0 $7 , " SP,
0
ADD : SP ,: SD ,
7.8
Dorit as w :c antufayaisoiuhf
#f@