• Keine Ergebnisse gefunden

Arithmetik LadenSpeichern

N/A
N/A
Protected

Academic year: 2022

Aktie "Arithmetik LadenSpeichern"

Copied!
145
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Grundlagen der Rechnerarchitektur

MIPS‐Assembler

(2)

Übersicht

• Arithmetik, Register und Speicherzugriff

• Darstellung von Instruktionen

• Logische Operationen

• Weitere Arithmetik

• Branches und Jumps

• Prozeduren

• 32‐Bit‐Konstanten und Adressierung

• Synchronisation

• Exceptions

• Pseudoinstruktionen, Direktiven und Makros

(3)

Motivation

(4)

Warum ein Assembler‐Kurs?

• Wir wollen etwas über Rechnerarchitektur lernen. 

Assembler ist ein Teil davon.

• Nach dem Erlernen von Assembler eines Systems,  lernt man Assembler anderer Rechner kinderleicht

• Während wir uns mit Assembler beschäftigen 

lernen wir auch generelle Konzepte kennen, wie 

die Hardware in Computern und eingebetteten 

Systemen organisiert ist

(5)

Vor‐ und Nachteile von Assembler

• Wann sollte man Assembler programmieren?

Code‐Größe oder Geschwindigkeit sollen bis auf das äußerste  ausgereizt werden

Verwendung  spezieller Maschineninstruktionen, die ein Compiler  nicht nutzt  (in der Regel bei CISC) 

Es gibt für die Computer‐Hardware keine höhere Sprache

• Meist wird ein hybrider Ansatz gewählt

Man programmiert das meiste in einer High‐Level‐Sprache

Nur kleine Teile des gesamten Codes werden direkt in Assembler  optimiert

• Nachteil von Assembler

Programme laufen nur für den Hardwaretyp für den diese  programmiert sind

(6)

Assembler am Beispiel der MIPS‐Architektur

• Frühere Einsatzgebiete MIPS

– Silicon Graphics Unix‐Workstations (z. B. SGI Indigo2)  – Silicon Graphics Unix‐Server (z. B. SGI Origin2000) 

– DEC Workstations (z.B. DECstation‐Familie und DECsystem) – Siemens bzw. SNI Server der RM‐Serie

– Control Data Corporation Computer des Typs CDC 4680 

• Heutiger Einsatz von MIPS in eingebetteten Systemen

– Cobalt‐Server bis RaQ/Qube2 – BMW‐Navigationssysteme

– die Fritz!Box

– Satellitenreceiver – Dreambox

– Konica Minolta DSLRs 

– Sony‐ und Nintendo‐Spielkonsolen

(7)

Warum gerade MIPS (und nicht Intel x86)?

• MIPS‐Instruktionssatz ist klar und einfach (RISC)

• Sehr gut in Lehrbüchern beschrieben

• Sehr ähnlich zu vielen modernen Prozessoren (z.B. ARM; schauen  wir uns eventuell auch noch kurz an)

• MIPS ist eine kommerziell relevante Instruktionssatzarchitektur. 

(z.B. 2002 wurden fast 100 Millionen MIPS Prozessoren  hergestellt)

(8)

Begleitend: SPIM‐ und MARS‐Simulator

Programmieren lernt man nicht durch zuschauen!

Alle Konzepte sollte man hier selber ausprobieren!

(9)

Arithmetik, Register und Speicherzugriff

(10)

Arithmetik und Zuweisungen

C Programm:

a = b + c;

d = a – e;

MIPS Instruktionen:

Einfache Arithmetik mit Zuweisung

C Programm:

f = (g + h) – (i + j);

MIPS Instruktionen (verwende temporäre  Variablen t0 und t1):

Komplexere Arithmetik mit Zuweisung

(11)

Die Operanden sind Register

C Programm:

f = (g + h) – (i + j);

Sei hierbei:

g in Register $s1 gespeichert h in Register $s2 gespeichert i in Register $s3 gespeichert j in Register $s4 gespeichert f in Register $s0 gespeichert

MIPS Instruktionen (verwende temporäre  Register $t0 und $t1):

add $t0, $s1, $s2 # t0=g+h add $t1, $s3, $s4 # t1=i+j sub $s0, $t0, $t1 # f=t0-t1 Voriges Beispiel: Komplexere Arithmetik mit Zuweisung

MIPS Registergröße = 32 Bit

(12)

Speicher‐Operanden

C Programm:

g = h + A[8];

Sei hierbei:

g in Register $s1 gespeichert h in Register $s2 gespeichert

Basisadresse von A in Register $s3

MIPS Instruktionen (verwende temporäres  Register $t0):

(13)

Alignment‐Restriction

Zugriff auf A[8], wenn Basisadresse von A in Register $s3 gespeichert?

(14)

Laden und Speichern

C Programm:

A[12] = h + A[8];

Sei hierbei:

Basisadresse von A in Register $s3  und h in Register $s2 gespeichert

MIPS Instruktionen (verwende temporäre  Register $t0):

(15)

Laden und Speichern von Bytes

C Programm:

A[12] = h + A[8];

Sei hierbei:

Basisadresse von A in Register $s3 h in Register $s2 gespeichert

MIPS Instruktionen (verwende temporäre  Register $t0):

Sei A[8] = 01110010. Was passiert im obigen Beispiel bei lb mit $t0 genau?

LSB

$t0 MSB

(16)

Weitere Befehle zum Laden und Speichern

Laden von Byte ohne Sign‐Extension:

lbu { Beispiel: lbu $t0, 27($s3) }

Was passiert im obigen Beispiel mit $t0, wenn 27($s3) = 11001000?

LSB

$t0 MSB

Laden von Halfword mit Sign‐Extension:

lh { Beispiel: lh $t0, 22($s3) } Laden von Halfword ohne Sign‐Extension:

lhu { Beispiel: lhu $t0, 22($s3) } Speichern von Halfword:

sh { Beispiel: sh $t0, 22($s3) }

(17)

Addieren und Laden von Konstanten

C Programm:

x = x + 4;

Sei hierbei:

x in Register $s3 gespeichert

MIPS Instruktion:

MIPS erlaubt negative Konstanten und braucht damit kein ‚subi‘.

MIPS hat ein spezielles Register $zero, welches 0 ‘hart verdrahtet‘ speichert.

C Programm:

x = 42;

MIPS Instruktion:

(18)

Zwischenbilanz der MIPS Architektur

CPU

$0 . . .

$31 Arithmetic

Unit

Registers

Memory

Name Nummer Verwendung

$zero 0 Konstante 0

$at 1

$v0‐$v1 2‐3

$a0‐$a3 4‐7

$t0‐$t7 8‐15 Temporäre Register

$s0‐$s7 16‐23 „saved“ temporäre Reg.

$t8‐$t9 24‐25 Temporäre Register

$k0‐$k1 26‐27

$gp 28

$sp 29

$fp 30

$ra 31

(19)

Zusammenfassung der behandelten Instruktionen

Instruktion Bedeutung

Arithmetik add rd, rs, rt Register rd = Register rs + Register rt

addi rt, rs, imm Register rt = Register rs + Konstante imm sub rd, rs, rt Register rd = Register rs –Register rt

Laden

lb rt, address Lade Byte an der Adresse address in Register rt.

Das Byte ist sign‐extended.

lbu rt, address Lade Byte an der Adresse address in Register rt.

lh rt, address Lade Half‐Word an der Adresse address in Register rt.

Das Half‐Word ist sign‐extended.

lhu rt, address Lade Half‐Word an der Adresse address in Register rt.

lw rt, address Lade Word an der Adresse address in Register rt.

(20)

Quiz

addi $s0, $zero, 4 # lw $s1, 0($s0) # lw $s2, 4($s0) # add $s1, $s1, $s1 # add $s1, $s1, $s2 # addi $s1, $s1, 1 # sw $s1, 0($s0) #

0 421

4 12

8 4

12 33

Adresse

Inhalt (Word)

Speicher zu Beginn

0 4 8 12

Adresse

Inhalt (Word)

Speicher nach Instruktionsdurchlauf

(21)

Darstellung von Instruktionen

(22)

Übersetzung aus Assembler in Maschinensprache

add $t0, $s1, $s2

0 17 18 8 0 32

6 Bit Opcode

5 Bit Source1

5 Bit Source2

5 Bit Dest

5 Bit Shamt

6 Bit Funct

00000010001100100100000000100000

Assembler‐

Instruktion

Maschinen‐

Instruktion

Name Nr

$t0 8

$t1 9

$t2 10

$t3 11

$t4 12

$t5 13

$t6 14

$t7 15 Name Nr

$s0 16

$s1 17

$s2 18

$s3 19

$s4 20

$s5 21

$s6 22

$s7 23

(23)

Notwendigkeit für andere Instruktionsformate

op rs rt rd shamt funct

6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit

add $t0, $s1, $s2

lw $t0, 32($s3)

?

R‐Typ

(24)

Zwischenbilanz

Instruktion Format op rs rt rd shamt funct

add R 0 reg reg reg 0 32

sub R 0 reg reg reg 0 34

addi (immediate) I 8 reg reg constant

lw (load word) I 35 reg reg offset

sw (store word) I 43 reg reg offset

6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit

16 Bit

(25)

Beispiel: A[300] = h + A[300]

$t1 sei Basisadresse von A und h in $s2 gespeichert. Assembler‐Code?

Maschinen‐Code (der Einfachheit halber mit Dezimalzahlen)?

op rs rt rd adr/shamt funct Name Nr

$t0 8

$t1 9

$t2 10 Name Nr

$s0 16

$s1 17

$s2 18

$s3 19

$s4 20

$s5 21

$s6 22

$s7 23

(26)

Logische Operationen

(27)

Erinnerung: Logischer Shift. Beispiel:

Logischer Links‐ und Rechts‐Shift

Links‐Shift um 4 Stellen Rechts‐Shift um 4 Stellen MIPS‐Shift‐Instruktionen sll und srl, sllv, srlv:

sll $t2,$s0,4 # $t2 = $s0 << 4 Bits srl $t2,$s0,7 # $t2 = $s0 >> 7 Bits sllv $t2,$s0,$s1 # $t2 = $s0 << $s1 Bits srlv $t2,$s0,$s1 # $t2 = $s0 >> $s1 Bits

Beispiel: Maschineninstruktion für obige sll Assembler‐Instruktion:

(28)

Erinnerung: Arithmetischer Rechts‐Shift. Beispiel mit 8‐Bit:

0011 0000 1101 0111

Arithmetischer Rechts‐Shift

Rechts‐Shift um 4 Stellen Rechts‐Shift um 3 Stellen

Arithmetischer Rechts‐Shift in MIPS:

sra $t2,$s0,4 # $t2 = $s0 arithmetisch

# um 4 Bits geshiftet srav $t2,$s0,$s1 # $t2 = $s0 arithmetisch

# um $s1 Bits geshiftet

(29)

Erinnerung: AND.

AND, OR, NOR und XOR

MIPS‐Instruktionen (R‐Typ), Beispiel:

and $t0,$t1,$t2 # $t0 = $t1 AND $t2 or $t0,$t1,$t2 # $t0 = $t1 OR $t2 nor $t0,$t1,$t2 # $t0 = $t1 NOR $t2 xor $t0,$t1,$t2 # $t0 = $t1 XOR $t2

Erinnerung: OR. Erinnerung NOR. Erinnerung XOR.

(30)

Es gibt gar kein NOT?!

Erinnerung NOT (auf Folie zu Zweierkomplement kurz eingeführt):

Beobachtung:

Wie kann man also „NOT($t0)“ in MIPS realisieren?

(31)

Zusammenfassung der behandelten Instruktionen

Instruktion Bedeutung

Shift

sll rd, rs, shamt Register rd = Register rs logisch links um den Wert shamt geshiftet.

sllvrd, rt, rs Register rd = Register rs logisch links um den in Register rs gespeicherten Wert  geshiftet.

srl rd, rs, shamt Register rd = Register rs logisch rechts um den Wert shamt geshiftet.

srlv rd, rt, rs Register rd = Register rs logisch rechts um den in Register rs gespeicherten Wert  geshiftet.

srard, rs, shamt Register rd = Register rs arithmetisch rechts um den Wert shamt geshiftet.

sravrd, rt, rs Register rd = Register rs arithmetisch rechts um den in Register rs gespeicherten Wert geshiftet.

rknüpfung

andrd, rs, rt Register rd = Register rs AND Register rt.

or rd, rs, rt Register rd = Register rs AND Register rt.

nor rd, rs, rt Register rd = Register rs AND Register rt.

(32)

MIPS‐Assemblercode um folgende Funktion zu berechnen:

$s1 = die ersten 8 Bits von 4 * NOT($s1 AND $s2)

Schwieriges Quiz

Tipp: wir brauchen  and, nor und sll

(33)

Weitere Arithmetik

(34)

Die speziellen Register lo und hi

Erinnerung: ganzzahliges Produkt von zwei n‐Bit‐Zahlen benötigt bis  zu 2n Bits.

Eine MIPS‐Instruktion zur ganzzahligen Multiplikation von zwei  Registern der Länge 32‐Bits benötigt damit ein Register der Länge  64 Bit, um das Ergebnis abzuspeichern.

MIPS hat für die ganzzahlige Multiplikation zwei spezielle Register, lo und hi, in denen das Ergebnis abgespeichert wird:

lo : Low‐Order‐Word des Produkts hi : Hi‐Order‐Word des Produkts.

Zugriff auf lo und hi erfolgt mittels mflo und mfhi. Beispiel:

mflo $s1 # lade Inhalt von lo nach $s1 mfhi $s2 # lade Inhalt von hi nach $s2

(35)

Ganzzahlige Multiplikation und Division

Ganzzahlige Multiplikation. Beispiel:

mult $s1, $s2 # (hi,lo) = $s1 * $s2 Ganzzahlige Division. Beispiel:

div $s1, $s2 # berechnet $s2 / $s1

# lo speichert den Quotienten

# hi speichert den Rest

Register hi und lo können auch beschrieben werden. Beispiel:

mtlo $s1 # Lade Inhalt von $s1 nach lo mthi $s2 # Lade Inhalt von $s2 nach hi

(36)

Ganzzahlige Multiplikation ohne hi und lo

Es gibt eine weitere Instruktion, zur Multiplikation, die kein hi und lo verwendet:

mul $s1, $s2, $s3 # $s1 = die low-order 32

# Bits des Produkts von

# $s2 und $s3.

(37)

Zwischenbilanz der MIPS‐Architektur

CPU

$0 . . .

$31 Arithmetic

Unit

Multiply Divide Registers

Lo Hi

Memory

Neu

(38)

Die speziellen Register $f01 bis $f31

MIPS unterstützt mit einem separaten FPU‐Coprozessor 

Gleitkommaarithmetik auf Zahlen im IEEE 754‐Single‐Precision (32‐

Bit) und Double‐Precision‐Format (64 Bit).

Die MIPS‐Floating‐Point‐Befehle nutzen die speziellen 32‐Bit‐

Floating‐Point‐Register (die Register des FPU‐Coprozessors):

$f0, $f1, $f3, ..., $f31

Single‐Precision‐Zahlen können in jedem der Register gespeichert  werden (also $f0, $f1, ..., $f31).

Double‐Precision‐Zahlen können nur in Paaren von aufeinander  folgenden Registern ($f0,$f1), ($f2,$3), ..., ($f30,$f31) gespeichert  werden. Zugriff erfolgt immer über die geradzahligen Register (also 

$f0, $f2, ..., $f30).

(39)

Floating‐Point‐Befehle

Laden/speichern von Daten in die Register $f0,...,$f31 am Beispiel:

mtc1 $s1,$f3 # $f3 = $s1 mfc1 $s1,$f3 # $s1 = $f3

lwc1 $f3,8($s1) # $f3 = Memory[8+$s1]

ldc1 $f2,8($s1) # ($f2,$f3) = Memory[8+$s1]

swc1 $f3,8($s1) # Memory[8+$s1] = $f3

sdc1 $f2,8($s1) # Memory[8+$s1] = ($f2,$f3) Verschieben von Registerinhalten von $f0,...,$f31 am Beispiel:

mov.s $f6,$f3 # $f6 = $f3

mov.d $s4,$f6 # ($f4,$f5) = ($f6,$f7)

(40)

Floating‐Point‐Befehle

Die MIPS‐Single‐Precision‐Operationen am Beispiel:

add.s $f1,$f2,$f3 # $f1 = $f2 + $f3 sub.s $f1,$f2,$f3 # $f1 = $f2 - $f3 mul.s $f1,$f2,$f3 # $f1 = $f2 * $f3 div.s $f1,$f2,$f3 # $f1 = $f2 / $f3 Die MIPS‐Double‐Precision‐Operationen am Beispiel:

add.d $f2,$f4,$f6 # ($f2,$f3) = ($f4,$f5) + ($f6,$f7) sub.d $f2,$f4,$f6 # ($f2,$f3) = ($f4,$f5) - ($f6,$f7) mul.d $f2,$f4,$f6 # ($f2,$f3) = ($f4,$f5)

* ($f6,$f7) div.d $f2,$f4,$f6 # ($f2,$f3) = ($f4,$f5) / ($f6,$f7)

(41)

Zwischenbilanz der MIPS‐Architektur

CPU Coprocessor 1 (FPU)

$0 . . .

$31 Arithmetic

Unit

Multiply Divide

$f0 . . .

$f31

Arithmetic Unit Registers Registers

Lo Hi

Memory

(42)

Arithmetische Operationen zusammengefasst

Instruktion Beispiel Bemerkung

Ganzzahlig

mult, div, madd, msub

mult $s1, $s2 Ergebnis wird in den speziellen Registern lo und hi  abgelegt.

add , sub add $s1, $s2, $s3 Operieren auf den 32 standard CPU‐Registern addi addi $s1, $s2, 42 Ein Parameter ist eine Konstante

mflo, mfhi, mtlo, mthi

mflo $s1 ZumLaden und Speichern der Inhalte von lo‐ und  hi‐Register

mul mul $s1, $s2, $s3 $s1 = 32 Low‐order Bits von $s2 * $s3

Gleitkomma

add.s, sub.s,  mul.s, div.s, 

add.s $f0, $f1, $f2 Instruktionen arbeiten auf den speziellen Registern 

$f0,...,$f31. Single‐Precision.

add.d, sub.d,  mul.d, div.d

add.d $f0, $f1, $f2 Instruktionen arbeiten auf den speziellen Registern  ($f0,$f1),...,($f30,$f31). Double‐Precision.

lwc1, swc1, ldc1, sdc1

lwc1 $f0, 4($s1) Zum Laden und Speichern der Inhalte von 

$f0,...,$f31 über den Speicher.

mfc1, mtc2 mtc1 $s1, $f0 Zum Laden und Speichern der Inhalte von 

$f0,...,$f31 über die standard CPU‐Register.

(43)

Einfaches Quiz

MIPS‐Assemblercode, um die Eingabe in Single‐Precision aus  Fahrenheit in Celsius umzurechnen:

$f0 = (5.0 / 9.0) * (Eingabe – 32.0)

12 32.0

esse

Inhalt (Word)

Tipp: wir brauchen:

lwc1 zum laden und div.s, sub.s, mul.s

(44)

Branches und Jumps

(45)

Der Program‐Counter

CPU Coprocessor 1 (FPU)

$0 . . .

$31 Arithmetic

Unit

Multiply Divide Registers

Lo Hi

Memory

PC

Unsere bisherigen Assemblerprogramme waren rein sequentiell. Beispiel:

0x4000000 : addi $s0, $zero, 4 0x4000004 : lw $s1, 0($s0)

0x4000008 : lw $s2, 4($s0) 0x400000c : add $s1, $s1, $s1 0x4000010 : ...

Welche nächste Instruktion abgearbeitet werden soll, steht im Program‐Counter. 

Zur Abarbeitung der nächsten Instruktion wird

(46)

Aus der Sequentiellen Abarbeitung springen

0x4000100 : addi $s0, $zero, 4 0x4000104 : lw $s1, 0($s0)

0x4000108 : lw $s2, 4($s0) 0x400010c : add $s1, $s1, $s1 0x4000110 : add $s1, $s1, $s2 0x4000114 : addi $s1, $zero, 1 0x4000118 : sw $s1, 0($s0)

0x40000204 : mult $s1, $s2 0x40000208 : div $s1, $s2 0x4000020c : mtlo $s1

0x40000210 : mthi $s2

0x40000214 : madd $s1,$s2 Gilt $s1 < $s2? ja

nein

Program‐Counter $pc

0x40000004 : addi $s1, $s1, 42 0x40000008 : addi $s2, $s2, 24

(47)

Start: ...

beq register1, register2, Label3 ...

bne register1, register2, Label1 ...

j Label2 ...

Label1: ...

...

Label2: ...

...

Bedingte Sprünge und unbedingte Sprünge

Ein Label (oder Sprungmarke zu deutsch)  ist eine mit einem Namen markierte 

Stelle im Code, an die man per Branch bzw. Jump hin springen möchte.

Assembler‐Syntax: „Name des Labels“ 

(48)

Formate für Sprungbefehle

Bedingte Sprünge beq und bne haben das Format I‐Typ (Immediate):

beq $s1, $s2, Label

4 18 17 Label

Opcode 6 Bit

Source 5 Bit

Dest 5 Bit

Konstante oder Adresse 16 Bit

I‐Typ

Unbedingter Sprung hat das Format J‐Typ (Jump‐Format):

j addr # Springe nach Adresse addr

2 addr

Opcode 6 Bit

Adresse 26 Bit

J‐Typ

(49)

Anwendungsbeispiel if‐then‐else

if (i == j) then f = g + h;

else

f = g - h;

Es sei f,…,j in $s0,…,$s4 gespeichert:

bne $s3,$s4,Else # gehe nach Else wenn i!=j

add $s0,$s1,$s2 # f = g + h (bei i!=j übersprungen)

(50)

Anwendungsbeispiel while

while (safe[i] == k) i += 1;

Es sei i und k in $s3 und $s5 gespeichert und die Basis von safe sei $s6: Loop: sll $t1,$s3,2 # Temp-Reg $t1 = i * 4

add $t1,$t1,$s6 # $t1 = Adresse von safe[i]

lw $t0,0($t1) # Temp-Reg $t0 = save[i]

bne $t0,$s5,Exit # gehe nach Exit, wenn save[i]!=k addi $s3,$s3,1 # i = i + 1

j Loop # gehe wieder nach Loop Exit:

safe[i]

b0 b1 b2 b3 b4 b5 …

(51)

Test auf Größer und Kleiner?

slt $t0, $s3, $s4 # $t0 = 1 wenn $s3 < $s4 slti $t0, $s2, 10 # $t0 = 1 wenn $s2 < 10

Beispiel: springe nach Exit, wenn $s2 < 42 ...

slti $t0, $s2, 42

bne $t0, $zero, Exit ...

Exit:

(52)

Signed und unsigned Vergleiche 

Registerinhalt von $s0 sei:

1111 1111 1111 1111 1111 1111 1111 1111 Registerinhalt von $s1 sei:

0000 0000 0000 0000 0000 0000 0000 0001

Was ist der Wert von $t0 nach Ausführung der folgenden Zeile:

slt $t0, $s0, $s1 # Signed-Vergleich $s0<$s1

Was ist der Wert von $t1 nach Ausführung der folgenden Zeile:

sltu $t0, $s0, $s1 # Unsigned-Vergleich $s0<$s1

(53)

Beispiel: Test auf 0 <= $s0 < $s1 in einer Code‐Zeile

Umständlicher Test in zwei Zeilen:

slti $t0, $s0, 0 # $t0=1 wenn $s0<0 sonst $t0=0

bne $t0, $zero, OutOfBound # gehe nach OutOfBound wenn $t0!=0 slt $t0, $s0, $s1 # $t0=1 wenn $s0<$s1 sonst $t0=0 beq $t0, $zero, OutOfBound # gehe nach OutOfBound wenn $t0==0 ...

OutOfBound:

Test in einer Zeile wenn $s1 immer größer oder gleich 0 ist?

(54)

Unterstützung von Jump‐Tables

Assembler‐Code:

Label_1: ...

...

Label_2: ...

...

Label_n: ...

Nr Label Adresse 0 Label_1 0x05342120 1 Label_2 0x05443004

... ...

n‐2

n‐1 Label_n 0x06756900 Jump‐Table

# Gewünschter Label sei in $s0 gespeichert und

# Startadresse der Jump-Table sei in $s1

# Lade Adresse für gewünschtes Label in $t0 sll $t0, $s0, 2

add $t0, $t0, $s1 lw $t0, 0($t0)

# Springe an die in $t0 gespeicherte Adresse jr $t0

Maschinen‐Code:

0x05342120: 1011010110...

...

0x05443004: 0001011101...

...

0x06756900: 0000111000...

(55)

Floating‐Point und Branches

MIPS‐Floating‐Point‐Instruktionen erlauben Vergleiche der Form:

c.x.s $f2,$f3 # Vergleiche Single $f2 mit $f3 c.x.d $f2,$f4 # Vergleiche Double $f2 mit $f4 Hierbei kann x in c.x.s bzw. c.x.d stehen für:

eq = equal

lt = less than

le = less or equal Beispiele:

c.eq.s $f2,$f3 # $f2 = $f3 ?

c.lt.d $f2,$f4 # ($f2,$f3) < ($f4,$f5)?

(56)

Und dann findet der Branch wie statt?

Instruktion bc1t und bc1f nach dem Floating‐Point‐Vergleich:

bc1t Label # springe nach Label, wenn der

# vorige Floating-Point-Vergleich

# erfüllt ist

bc1f Label # springe nach Label, wenn der

# vorige Floating-Point-Vergleich

# nicht erfüllt ist

(Bemerkung c1 steht für Coprozessor 1; Erinnerung: die FPU ist dort) Beispiel:

c.lt.d $f2,$f4 # ($f2,$f3) < ($f4,$f5)?

bc1t Label # springe nach Label, wenn

# ($f2,$f3) < ($f4,$f5) gilt.

...

Label: ...

(57)

Condition‐Flags

CPU Coprocessor 1 (FPU)

$f0 . . .

$f31

Arithmetic Unit Registers Memory

Condition‐Flags Die Floating‐Point‐Vergleichsbefehle c.x.s und 

c.x.d setzen Default‐mäßig das Condition‐Flag 0.

Die Floating‐Point‐Sprungbefehle bc1tund bc1f springen, wenn das Flag 0 gesetzt bzw. nicht gesetzt  ist.

Alternativ kann man auch die anderen Flags  verwenden. Dann gibt man diese mit den  Instruktionen an. Beispiel:

(58)

Zusammenfassung der Sprung‐Instruktionen

Instruktion Beispiel Bedeutung des Beispiels

Ganzzahlig

beq, bne beq $s1, $s2, x Springe nach x wenn $s1 = 

$s2

j j label Springe immer nach 

„label“

jr jr $s1 Springe nach in $s1 

gespeicherte Adresse slt, slti, sltu, sltiu slt $s1,$s2,$s3 $s1=1 wenn $s2<$s3 

(signed)

Floating‐Point bc1t, bc1f bc1t label Springe nach „label“ wenn  letzter Floating‐Point‐

Vergleich true ergab c.x.s (x=eq, lt, le), 

c.x.d (x=eq, lt, le)

c.eq.s $f1, $f2 Teste auf $f1=$f2 (single precision)

(59)

Quiz

Im folgenden Codeabschnitt soll nach continue gesprungen werden,  wenn $s1 kleiner gleich $s2 ist:

loop: ...

(60)

Und noch ein Quiz

Annahme:

$s1 = 0xFFFFFFFF

$s2 = 0x00000001

In welchem der beiden Code‐Abschnitte wird gesprungen?

...

slt $t0,$s1,$s2

bne $t0,$zero, lab ...

...

lab: ...

...

...

sltu $t0,$s1,$s2 beq $t0,$zero, lab ...

...

lab: ...

Sprung: ...

ja nein

Sprung:

ja nein

(61)

Prozeduren

(62)

Das Prinzip von Prozeduren

Hauptprogramm:

. . .

x = 2*fakultät(10) .

. . Programm‐

abarbeitung

Prozedur mit dem  Namen fakultät

. .

Berechne n!

. . Prozeduraufruf

mit Parameter n=10

Prozedurrücksprung mit Ergebnis n!

Randbemerkung: was ist n! ?

(63)

Programmzähler und Rücksprungadresse

0x0040000 : 0011 ... 1001 0x0040004 : 0001 ... 1000 0x0040008 : 1001 ... 1111 0x004000c : 1011 ... 0001 0x0040010 : 0011 ... 1000 0x0040014 : 1001 ... 1111 0x0040018 : 0001 ... 0001 0x004001c : 1011 ... 0011 0x0040020 : 1011 ... 1100 0x0040024 : 0101 ... 1001 0x0040028 : 1000 ... 0011

Startadresse des Hauptprogramms Aufruf der Prozedur

Register $pc

Prozedur Fakultät Adresse Maschineninstruktion

(64)

Assembler‐Beispiel

Hauptprogramm: ...

0x004000c addi $a0,$zero,10 # setze $a0 auf 10 0x0040010 jal Fakultaet # rufe Prozedur auf 0x0040014 sll $v0,2 # Berechne Rückgabe*2

...

Fakultaet:

# Die Prozedur Fakultaet

# erwartet den Übergabeparameter in $a0

# gibt das Ergebnis in $v0 zurück

0x0040024 ... # Berechnung der Fakultät ... # Das Ergebnis sei in $a0 0x004002c add $v0,$a0,$zero # speichere Ergebnis in $v0 0x0040030 jr $ra

Register $pc Register $ra Register $a0 Register $v0

(65)

Problem

Hauptprogramm:

. .

$s0 = 42 vor Aufruf

. .

x = 2*fakultät(10) .

.

Annahme immer  noch $s0=42 !?!

. . Programm‐

abarbeitung

Prozedur mit dem  Namen fakultät

. .

Berechne n!

Überschreibe dabei 

$s0 mit 114 .

. Prozeduraufruf

mit Parameter n=10

(66)

Lösung

Hauptprogramm:

. .

$s0 = 42 vor Aufruf

.

x = 2*fakultät(10) .

.

Es gilt immer  noch $s0=42 !!!

. .

Prozedur mit dem  Namen fakultät

Rette Inhalt von $s0  auf dem Stack

.

Berechne n!

($s0 wird dabei  überschrieben) Restauriere Inhalt  von $s0 mittels Stack

. Register $s0 .

0x7fffffff : ...

0x7ffffffe : ...

0x7ffffffd : ...

0x7ffffffc : ...

0x7ffffffb : ...

0x7ffffffa : ...

0x7ffffff9 : ...

0x7ffffff8 : ...

0x7ffffff7 : ...

0x7ffffff6 : ...

0x7ffffff5 : ...

0x7ffffff4 : ...

0x7ffffff3 : 0x7ffffff2 : 0x7ffffff1 : 0x7ffffff0 : 0x7fffffef : 0x7fffffee : 0x7fffffec :

. .

Register $sp

Stack

(67)

Assembler‐Beispiel

Fakultaet: addi $sp, $sp, -4 # erhöhe Stack-Pointer um ein Word sw $s0, 0($sp) # rette $s0 auf Stack

# berechne Fakultät

# $s0 wird dabei überschrieben

lw $s0, 0($sp) # restauriere $s0 vom Stack addi $sp, $sp, 4 # dekrementiere Stack-Pointer jr $ra # Springe zurück zum Aufrufer

...

0x7ffffff7 : ...

0x7ffffff6 : ...

0x7ffffff5 : ...

0x7ffffff4 : ...

0x7ffffff3 : 0x7ffffff2 :

Register $sp

(68)

Registerkonvention

Name Nummer Verwendung Wird über Aufrufgrenzen bewahrt?

$zero 0 Konstante 0 n.a.

$at 1 nein

$v0‐$v1 2‐3 Prozedur‐Rückgabe nein

$a0‐$a3 4‐7 Prozedur‐Parameter nein

$t0‐$t7 8‐15 Temporäre nein

$s0‐$s7 16‐23 Temporär gesicherte ja

$t8‐$t9 24‐25 Temporäre nein

$k0‐$k1 26‐27 nein

$gp 28 ja

$sp 29 Stack‐Pointer ja

$fp 30 ja

$ra 31 Return‐Adresse ja

(69)

Rekursive Prozeduren

Hauptprogramm:

. . .

x = 2*fakultät(10) .

. .

Prozedur mit dem  Namen fakultät

. .

Berechne n!

. Prozeduraufruf

Letzter Rücksprung mit Gesamtergebnis

Wenn Rekursionsende noch nicht erreicht, dann erneuter Prozeduraufruf

(„mit kleinerem Parameter“)

(70)

Verwendung des Stacks

Haupt‐

programm

Fakultät

Fakultät

Fakultät

Rekursionsende Stack

$sp

Fakultät

(71)

Assembler‐Beispiel

Auf der nächste Folie wollen wir die Fakultät n! nach folgendem  Algorithmus berechnen

int fact (int n) { if (n < 1) {

return 1;

}

else {

return n * fact(n-1);

}

(72)

Assembler‐Beispiel

# Berechnung der Fakultät von n (also n!)

# Eingabeparameter n ist in $a0 gespeichert

# Rückgabeparameter der Berechnung ist $v0

fact: addi $sp, $sp, -8 # push Stack-Pointer um zwei Word sw $ra, 4($sp) # rette Rücksprungadresse auf Stack sw $a0, 0($sp) # rette Eingabeparameter auf Stack slti $t0, $a0, 1 # teste n < 1

beq $t0, $zero, L1 # wenn n >= 1 dann gehe nach L1 addi $v0, $zero, 1 # es wird 1 zurückgegeben

addi $sp, $sp, 8 # pop Stack-Pointer um zwei Word jr $ra # Rücksprung zum Prozedur-Aufrufer L1: addi $a0, $a0, -1 # setze Argument auf n-1

jal fact # rufe fact rekursiv mit n-1 auf

lw $a0, 0($sp) # restauriere Eingabeparam vom Stack lw $ra, 4($sp) # restauriere Rücksprungadr vom Stack addi $sp, $sp, 8 # pop Stack-Pointer um zwei Word

mul $v0, $a0, $v0 # es wird n * fact(n-1) zurück gegeben

(73)

Procedure‐Frame und Frame‐Pointer

Null bis vier Argument‐

Register ($a0‐$a3) Return‐Adresse $ra Null bis acht Saved‐

Register ($s0‐$s7) Möglicher zusätzlicher 

Speicher der während  der Ausführung der 

Prozedur  benötigt  wird und nach 

Hohe Adresse Frame‐Pointer $fp

Benutzer Stack‐Speicher

Procedure‐Frame

Argument 5 Argument 6

(74)

Speicherbelegungskonvention

Reserviert

Text (d.h. das Programm  in Form von Maschinen‐

instruktionen) Statische Daten (z.B. 

Konstanten oder  statische Variablen)

Stack

Der Heap speichert alle  dynamischen (d.h. 

während der Laufzeit  angelegten) Daten.

Heap

0x00400000 0x10000000 0x10008000 0x7ffffffc

0x00000000

$pc

$sp

$gp

(75)

Die Sprunginstruktionen zusammengefasst

Instruktion Beispiel Beduetung

j j Label $pc = Sprungadresse

jal jal Label $ra = $pc+4, $pc = Sprungadresse jr jr $s1 $pc = Registerinhalt

(76)

Schwieriges Quiz

Rmul: addi $sp, $sp, -4 # rette Rücksprungadresse sw $ra, 0($sp) #

add $t0, $a0, $zero # $t0 = n addi $a1, $a1, -1 # m = m - 1

beq $a1, $zero, End # wenn m=0, dann Ende jal Rmul # $v0 = Rmul(n,m-1) add $t0, $t0, $v0 # $t0 = $t0 + $v0 End: add $v0, $t0, $zero # $v0 = $t0

lw $ra, 0($sp) # springe zurück addi $sp, $sp, 4 #

jr $ra #

Rekursive Berechnung von n*m in der Form Rmul(n,m) = n+Rmul(n,m‐1) Eingabeparameter: $a0 für n und $a1 für m>0

Rückgabeparameter: $v0 Temporäre Berechnung: $t0

$a0, $a1, $v0, $t0 brauchen  nach Registerkonvention alle  nicht über Aufrufgrenzen  bewahrt zu werden.

(77)

Registerkonvention, dass ein Register über Aufrufgrenzen nicht  bewahrt wird bedeutet:

• Register darf nach belieben überschreiben werden.

• Register muss vor dem Rücksprung nicht restauriert werden.

• Prozedur muss aber das Register für sich selbst sichern!

• Beispiel:

Verwendung von $t0 Sichern von $t0

Aufruf einer anderen Prozedur Restaurieren von $t0

•Ausnahme: wir wissen genau, dass das Register in keiner der

Bemerkung zu vorigem Quiz

(78)

32‐Bit‐Konstanten und Adressierung

(79)

Immediate kann nur 16‐Bit lang sein

Erinnerung: Laden einer Konstante in ein Register addi $t0, $zero, 200

Als Maschinen‐Instruktion:

001000 00000 01000 0000000011001000 addi $zero $t0 200

Inhalt von $t0 nach Instruktionsausführung:

00000000|00000000|00000000|11001000 Byte 3 Byte 2 Byte 1 Byte 0

(80)

Lösung: Load‐Upper‐Immediate

Aufgabe: Lade folgende 32‐Bit‐Konstante in Register $s0

0000 0000 0011 1101 0000 1001 0000 0000 Neuer Befehl: Lade 16‐Bit‐Wert in obere 16 Bits von Register $s0

lui $s0, 61 # 61 dezimal = 0000 0000 0011 1101 binär Registerinhalt von $s0 ist danach:

0000 0000 0011 1101 0000 0000 0000 0000 Füge anschließend die unteren 16 Bits ein:

ori $s0, $s0, 2304 # 2304 dez = 0000 1001 0000 0000 bin Registerinhalt von $s0 ist danach:

0000 0000 0011 1101 0000 1001 0000 0000

(81)

Immediate in Branches sind nur 16 Bit lang

Erinnerung: Bedingter Sprung

bne $s0, $s1, Exit # gehe nach Exit, wenn $s0!=$s1 Als Maschinen‐Instruktion (I‐Typ):

000101 10001 10000 1010001011001000 bne $s1 $s0 Exit (immediate) Also, nur 16‐Bit für die Branch‐Adresse verfügbar!

Konsequenz, wenn Exit eine absolute Adresse wäre:

0x00000000 : ...

(82)

Lösung: Branches sind PC‐Relativ

Betrachte folgendes Beispiel (Adressen seien Dezimal dargestellt):

80012 : bne $s0, $s1, Exit 80016 : addi $s3,$s3,1

80020 : j Loop 80024 : Exit:

Label Exit könnte doch nur die Sprungdifferenz 80024‐80012 = 12 codieren, d.h.

80012 : bne $s0, $s1, 12 80016 : addi $s3,$s3,1 80020 : j Loop

80024 : Exit:

Noch besser, codiere nur die Anzahl zu überspringender Befehle (also 3 = 12/4):

80012 : bne $s0, $s1, 3 80016 : addi $s3,$s3,1 80020 : j Loop

80024 : Exit:

(Erinnerung: Instruktionen haben immer Word‐Länge, also 32‐Bit)

(83)

Lösung: Branches sind PC‐Relativ

Sei der Program‐Counter $pc= 80012 und $s0!=$s1 sei erfüllt:

80012 : bne $s0, $s1, 3 80016 : addi $s3,$s3,1 80020 : j Loop

80024 : Exit:

Auf welchen Wert muss der Program‐Counter als nächstes gesetzt werden?

Achtung: obiges Beispiel ist nicht korrekt. MIPS setzt $pc=$pc+4 schon vor  Abarbeitung des Befehls. Wie muss damit Zeile 80012 korrekt lauten?

(84)

Immediate in Jumps sind nur 26 Bit lang

Erinnerung: Unbedingter Sprung

j Exit # spinge immer nach Exit Als Maschinen‐Instruktion (J‐Typ):

000010 10001100001010001011001000 j Exit (address)

Also, nur 26 Bit für die Adresse verfügbar! Also folgender Adressbereich:

von 0x00000000 bis 0x03FFFFFF Konsequenz, wenn Exit eine absolute Adresse wäre:

0x10000000 : j 0x10000010 # ?!?

...

0x10000010 : ...

(85)

Lösung: Jumps sind Pseudo‐Direkt

Betrachte voriges Beispiel aber mit korrektem 26‐Bit Adressfeld:

0x10000000 : j 0x10 # 00 0000 0000 0000 0000 0001 0000 0x10000004 : ...

...

0x10000010 : ...

Der Program‐Counter sei $pc=0x10000004. Wie kommt man nach  0x10000010?

(0x10000004 = 0001 0000 0000 0000 0000 0000 0000 0100

(86)

Lösung: Jumps sind Pseudo‐Direkt

Auch hier wieder, nutze die Tatsache, dass Befehle immer 4 Bytes lang sind:

0x10000000 : j 0x4 # 00 0000 0000 0000 0000 0000 0100 0x10000004 : ...

...

0x10000010 : ...

Der Program‐Counter sei $pc=0x10000004. Wie kommt man nach  0x10000010?

(0x10000004 = 0001 0000 0000 0000 0000 0000 0000 0100 0xF0000000 = 1111 0000 0000 0000 0000 0000 0000 0000 0x00000004 = 00 0000 0000 0000 0000 0000 0100 0x00000010 = 0000 0000 0000 0000 0000 0001 0000 0x10000010 = 0001 0000 0000 0000 0000 0000 0001 0000)

(87)

Achtung: Programm‐Address‐Boundary

Berachte folgendes Beispiel:

0x10EFFF10 : j Label ...

0x20000000 : Label: ...

Wie vorher hergeleitet muss das Label folgendes erfüllen:

$pc = ($pc AND 0xF0000000) OR (Label LSHIFT 2) Wie muss das Label übersetzt werden?

(0x10EFFF14 = 0001 0000 1110 1111 1111 1111 0001 0100 0xF0000000 = 1111 0000 0000 0000 0000 0000 0000 0000 0x20000000 = 0010 0000 0000 0000 0000 0000 0000 0000)

(88)

Achtung: Programm‐Address‐Boundary

Allgemein: Sprünge in der Form beschränkt auf die 256MB Speicherblöcke 0x00000000 bis 0x0FFFFFFF

0x10000000 bis 0x1FFFFFFF ...

0xF0000000 bis 0xFFFFFFFF

Und wenn man doch über Blockgrenzen springen will?

Beispiel: Sprung aus beliebigem Speicherbereich nach 0x20002000:

(89)

Zusammenfassung der neuen Befehle

Instruktion Beispiel Beduetung

lui lui $s1, 61 Lade 16‐Bit‐Wert in obere 16 Bits  von Register $s1

(90)

Quiz

80000 : Loop: sll $t1,$s3,2 # Temp-Reg $t1 = i * 4

80004 : add $t1,$t1,$s6 # $t1 = Adresse von safe[i]

80008 : lw $t0,0($t1) # Temp-Reg $t0 = save[i]

80012 : bne $t0,$s5,Exit # gehe nach Exit, wenn save[i]!=k 80016 : addi $s3,$s3,1 # i = i + 1

80020 : j Loop # gehe wieder nach Loop 80024 : Exit:

Adresse Opcode rs rt rd shamt Funct

80000 0 0 19 9 2 0

80004 0 9 22 9 0 32

80008 35 9 8 0

80012 5 8 21

80016 8 19 19 1

80020 2

80024 ...

Was steht hier?

(91)

Synchronisation

(92)

Data‐Race

Prozessor 1:  berechne x = x + 2

lw $t0, 0($s0) # lade x nach $t0 addi $t0, $t0, 2 # $t0 = $t0 + 2

sw $t0, 0($s0) # speichere $t0 nach x

Gemeinsamer Speicher

Variable x Prozessor 2:  berechne x = x – 1

lw $t0, 0($s0) # lade x nach $t0 addi $t0, $t0, -1 # $t0 = $t0 – 1

sw $t0, 0($s0) # speichere $t0 nach x

Es gelte zu Beginn: x=10 Gilt nach Durchlauf beider  Code‐Abschnitte immer  x=11?

(93)

Problem: Zugriff auf x ist nicht atomar

Prozessor 1:  berechne x = x + 2

lw $t0, 0($s0) # lade x nach $t0 addi $t0, $t0, 2 # $t0 = $t0 + 2

sw $t0, 0($s0) # speichere $t0 nach x

Prozessor 2:  berechne x = x – 1

lw $t0, 0($s0) # lade x nach $t0 addi $t0, $t0, -1 # $t0 = $t0 – 1

sw $t0, 0($s0) # speichere $t0 nach x

Inhalt von x 10

(94)

Mögliche Lösung: Atomic‐Swap

Speicher

Variable lock 1.) Speicherinhalt lock in Register $t1 kopieren

2.) Alten Wert von $t1 nach lock kopieren

swap $t1, lock

Beispiel

$t1 lock

Vor Ausführung von swap 1 0

Nach Ausführung von swap 0 1

MIPS‐ISA hat kein swap, dennoch gibt es andere ISAs die so einen Befehl haben.

Also, zunächst ein Beispiel, wie man mittels swap synchronisieren kann.

swap ist hierbei atomar, d.h. während des swap wird jeglicher Speicherzugriff anderer  Prozesse verzögert bis swap vollständig ausgeführt wurde!

(95)

Mögliche Lösung: Atomic‐Swap

Prozessor 1:  berechne x = x + 2

addi $t1, $zero, 1 # setze $t1 auf 1

loop: swap $t1, lock # tausche $t1 und lock bne $t1, $zero, loop # nochmal wenn $t1!=0 lw $t0, 0($s0) # lade x nach $t0

addi $t0, $t0, 2 # $t0 = $t0 + 2

sw $t0, 0($s0) # speichere $t0 nach x swap $t1, lock # gib lock wieder frei

Gemeinsamer Speicher

Variable x

Variable lock (initial=0) Prozessor 2:  berechne x = x – 1

addi $t1, $zero, 1 # setze $t1 auf 1

loop: swap $t1, lock # tausche $t1 und lock

# nochmal wenn $t1!=0

(96)

Mögliche Lösung: Atomic‐Swap

Prozessor 1:  berechne x = x + 2

addi $t1, $zero, 1 # setze $t1 auf 1

loop: swap $t1, lock # tausche $t1 und lock bne $t1, $zero, loop # nochmal wenn $t1!=0 lw $t0, 0($s0) # lade x nach $t0

addi $t0, $t0, 2 # $t0 = $t0 + 2

sw $t0, 0($s0) # speichere $t0 nach x swap $t1, lock # gib lock wieder frei Prozessor 2:  berechne x = x – 1

addi $t1, $zero, 1 # setze $t1 auf 1

loop: swap $t1, lock # tausche $t1 und lock bne $t1, $zero, loop # nochmal wenn $t1!=0 lw $t0, 0($s0) # lade x nach $t0

addi $t0, $t0, -1 # $t0 = $t0 – 1

sw $t0, 0($s0) # speichere $t0 nach x swap $t1, lock # gib lock wieder frei

Zeit x 10 lock

0

(97)

Weitere Lösung: Load Linked und Store Conditional

Speicher

Variable lock Lade den Inhalt der Speicherstelle 0($s1) in das 

Register $t1 

ll $t1, 0($s1) # load linked

sc $t0, 0($s1) # store conditional 1. Wenn seit dem letztem load linked keiner 

auf den Speicherblock zugegriffen hat , dann  Speichere den Inhalt von Register $t0 auf die  Speicherstelle 0($s1) und setze $t0 auf 1.

2. Sonst lasse den Speicherblock unberührt  und setze $t0 auf 0.

(98)

Weitere Lösung: Load Linked und Store Conditional

Prozessor 1:  berechne x = x + 2

loop: ll $t0, 0($s0) # $t0 = x

addi $t0, $t0, 2 # $t0 = $t0 + 2 sc $t0, 0($s0) # x = $t0

beq $t0, $zero, loop # nochmal bei failure

Gemeinsamer Speicher

Variable x

Prozessor 2:  berechne x = x – 1

loop: ll $t0, 0($s0) # $t0 = x

addi $t0, $t0, -1 # $t0 = $t0 – 1 sc $t0, 0($s0) # x = $t0

beq $t0, $zero, loop # nochmal bei failure

(99)

Weitere Lösung: Load Linked und Store Conditional

Prozessor 1:  berechne x = x + 2

loop: ll $t0, 0($s0) # $t0 = x

addi $t0, $t0, 2 # $t0 = $t0 + 2 sc $t0, 0($s0) # x = $t0

beq $t0, $zero, loop # nochmal bei failure

Prozessor 2:  berechne x = x – 1

loop: ll $t0, 0($s0) # $t0 = x

x 10

Referenzen

ÄHNLICHE DOKUMENTE

Das diesem Dokument zugrundeliegende Vorhaben wurde mit Mitteln des Bundesministeriums für Bildung und Forschung.. unter dem Förderkennzeichen

• Register Allocation: Determine which variables are implemented by registers at which positions.. • Register Assignment: Determine which register implements which variable at

These included compile-time and link-time schemes for allocating 52 registers, and register window schemes using 128 registers organized into fixed-size or variable-sized

© Copyright: Department for Northern European Studies Berlin and authors.. Die Geschichte eines

sllv rd, rt, rs Register rd = Register rs logisch links um den in Register rs gespeicherten Wert  geshiftet.. srl rd, rs, shamt Register rd = Register rs

addi rt, rs, imm Register rt = Register rs + Konstante imm sub rd, rs, rt Register rd = Register rs

addi rt, rs, imm Register rt = Register rs + Konstante imm sub rd, rs, rt Register rd = Register rs

sllv rd, rt, rs Register rd = Register rs logisch links um den in Register rs gespeicherten Wert  geshiftet.. srl rd, rs, shamt Register rd = Register rs