• Keine Ergebnisse gefunden

Zwischenbilanz der MIPS‐Architektur

N/A
N/A
Protected

Academic year: 2022

Aktie "Zwischenbilanz der MIPS‐Architektur"

Copied!
32
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Weitere Arithmetik

(2)

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

(3)

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 Das ist sinnvoll für madd und msub. Beispiele:

madd $s1,$s2 # (hi,lo)=(hi,lo)+$s1*$s2 msub $s1,$s2 # (hi,lo)=(hi,lo)-$s1*$s2

(4)

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.

(5)

Zwischenbilanz der MIPS‐Architektur

CPU

$0 . . .

$31 Arithmetic

Unit

Multiply Divide Registers

Lo Hi

Memory

Neu

(6)

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).

(7)

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)

(8)

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)

(9)

Zwischenbilanz der MIPS‐Architektur

CPU Coprocessor 1 (FPU)

$0 . . .

$31 Arithmetic

Unit

Multiply Divide

$f0 . . .

$f31

Arithmetic Unit Registers Registers

Lo Hi

Memory

Neu

(10)

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.

mov.s, mov.d mov.s $f1, $f2 Verschieben der Inhalte von $f0,...,$f31

(11)

Einfaches Quiz

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

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

0 Eingabe

4 5.0

8 9.0

12 32.0

Adresse

Inhalt (Word)

Speicher

Tipp: wir brauchen:

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

(12)

Branches und Jumps

(13)

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 der Program‐Counter von der CPU auf die

nächste Instruktion gesetzt, d.h.  $pc = $pc + 4.

Zur Abarbeitung einer Instruktion zeigt der $pc schon auf die nachfolgende Instruktion.

Der Program‐Counter ist ein weiteres Register, genannt $pc.

(14)

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

(15)

Start: ...

beq register1, register2, Label3 ...

bne register1, register2, Label1 ...

j Label2 ...

Label1: ...

...

Label2: ...

...

Label3: ...

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“ 

gefolgt von einem „:“.

(16)

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

(17)

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) j Exit # gehe nach Exit

Else: sub $s0,$s1,$s2 # f = g – h (bei i==j übersprungen) Exit:

(18)

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 …

(19)

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:

(20)

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

(21)

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?

(22)

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...

(23)

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)?

c.le.s $f2,$f3 # $f2 <= $f3?

(24)

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: ...

(25)

Condition‐Flags

CPU Coprocessor 1 (FPU)

$f0 . . .

$f31

Arithmetic Unit Registers Memory

0 0 0 1 0 0 1 0 0 1 2 3 4 5 6 7

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:

c.eq.s 2 $f2,$f3 # Setze Cond.-Flag

# 2, wenn $f2=$f3.

bc1t 2 Lab # springe nach Lab

# wenn Cond.-Flag

# 2 gesetzt ist.

(26)

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)

(27)

Quiz

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

loop: ...

j loop continue: ...

Tipp: wir brauchen beq, slt und bne

(28)

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

(29)

Prozeduren

(30)

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! ?

(31)

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 0x004002c : 1000 ... 1011 0x0040030 : 0001 ... 1100 0x0040034 : 1001 ... 1111 0x0040038 : 1001 ... 1111

Startadresse des Hauptprogramms Aufruf der Prozedur

Register $pc

Prozedur Fakultät

Rücksprung aus der Prozedur

Adresse Maschineninstruktion

Register $ra

(32)

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

Referenzen

ÄHNLICHE DOKUMENTE

Die Bestätigung durch die Enter-Taste kann man zwar wie den Start eines neuen Versuches an- sehen, aber sicherer ist es, bei einem neuen Versuch über Menu – Daten – Alte

Die Untersuchung von Lade- und Entladevorgängen am Kondensator ist Standard in der Oberstufe. Dazu wird der Kondensator über einen Widerstand auf- und wieder

(1) Stellen Sie eine begründete Vermutung zum zeitlichen Verlauf der Entladespannung über dem Kondensator auf und überprüfen Sie Ihre Vermutung

(1) Stellen Sie eine begründete Vermutung zum zeitlichen Verlauf der Entladespannung über dem Kondensator auf und überprüfen Sie Ihre Vermutung im

Tragen Sie für einen bestimmten Widerstand und verschiedene Kondensatoren (Kapazitäten) die Zeit ein, bis die Spannung auf einen von Ihnen festzulegenden Prozentsatz gesunken ist.

(1) Formulieren Sie eine begründete Hypothese für den zeitlichen Verlauf der Spannung über dem Kondensator beim Entladen.. (2) Wählen Sie einen Kondensator und einen

Vorschlag für ein Messprotokoll Zu (8): Tragen Sie für die verschiedenen Widerstände die halbe Entladedauer ein (Zeit, in der die Spannung auf den halben. Zu (9): Tragen Sie für

Vorschlag für ein Messprotokoll Zu (8): Tragen Sie für die verschiedenen Widerstände die halbe Entladedauer ein (Zeit, in der die Spannung auf den halben Wert gesunken ist). Zu