MIPS Assembler Quelltext

Benutzeravatar
davidvajda.de
Site Admin
Beiträge: 1424
Registriert: Di Jul 18, 2023 8:36 pm
Wohnort: D-72072, Tübingen
Kontaktdaten:

MIPS Assembler Quelltext

Beitrag von davidvajda.de »

Ich schreibe einen Multiplizierer, danach einen Dividierer

Das Multiplizieren und das Dividieren soll alleine von Shiften und von Addition und Subtraktion statt finden.

Man schaue sich zunächst folgende Fall an:

Ich dividiere durch

Code: Alles auswählen

100100b div 10b
Das geht mit

Code: Alles auswählen

100100b >> 1
Ich dividiere eine Zahl durch 4

Code: Alles auswählen

100100b >> 2
100100b >> 10b
Ich erhalte einen Rest

Code: Alles auswählen

100111b / 4
100111b >> 2
1001b (Ergebnis)
Das rausgeschiftete 11b Rest

Jetzt multipliziere ich zahlen

Code: Alles auswählen

*2 ^== << 1
*4 ^== << 2
*8 ^== << 3
Wenn ich mit 

3 multpliziere ist das

x << 1 + x << 0

Ich multiplziere mit 1011b

x * 1000b + x * 10 b + x * 1b
^==
x << 3 + x << 1 + x << 0
Das lässt sich nachher bei der division umgekehrt verwenden

Ziel unseres MIPS Assembler Programms ist eine Zahl und eine Zahl aus dem RAM zu laden. Zu dividieren und das Ergebnis in zu speichern


Weitere Ziele werden sein
  1. Arithmetisches Mittel bilden
  2. Geometrisches
  3. Reihen berechnen
  4. Einsen zählen
Also, es sind jetzt zwei Dinge.
  1. Zum einen müssen wir Labels einführen - wir brauchen das, weil wir aus dem RAM laden
  2. Zum anderen müssen wir beim geometrischen Mittel, die Wurzel 2 anwenden. Dafür brauchen wir das Intervallhalbierungsverfahren. Es ist in der Mathematischen Einführung der Universität in Tübingen zu finden
  3. An dieser Stelle fällt es mir auf - dass es mit dem arithmetischen Mittel schwer wird. Jetzt brauchen wir nämlich fliesskommazahlen, aber wir können uns drum bemühen.
Also, zunächst müssen wir ganzzahlige Werte im RAM definieren. Das erste Programm was ich schreibe, teilt durch 4, 8, 16 und so weiter

Wir brauchen ein Datensegment und ein Textsegment. Die Labels definieren wir wie üblich

Code: Alles auswählen

.data
a:		.word 71283		; dividend
b: 		.word 4			; divisor
c:		.word 0x00		; quotient
r:		.word 0x00		; rest
.text
So wäre der Programmquelltext erst Mal richtig

Code: Alles auswählen

.data
a:		.word 0x1321		# dividend
b: 		.word 0x4		# divisor
c:		.word 0x00		# quotient
r:		.word 0x00		# rest
.text

lw $t0, a
lw $t1, b

sll $t2, $t0, $t1  

sw c, $t2
Weil, wir verwenden keine Strichpunkte. Das nächste ist, dass die Operation falsch ist. Wir können nicht, um Registeren Shiften. so oder so stimmt das nicht.

Wenn wir durch
teilen, müssen wir um

Code: Alles auswählen

3 Bit
Shiften. Das heisst um

Code: Alles auswählen

lg_2(divisor)
Wenn wir das gemacht haben, können wir immer noch nicht durch die Zahl dividieren. Aber, was wir machen können ist folgendes. Wir könnnen um 1 Bit nach Links shiften. Und in einer Zählschleife das ganze abarbeiten. So kommen wir auch von Anfang an, auf unseren Divisor. Wir multiplizieren 1 immer wieder mit 2.

Dies können wir auch ohne Multiplikation erreichen. Denn unser Links Shift ist an sich die Multiplikation. Ich stelle den Code vor

Code: Alles auswählen

.data
a:		.word 0x1321		# dividend
b: 		.word 0x4		# divisor
c:		.word 0x00		# quotient
r:		.word 0x00		# rest
.text

lw $t0, a
lw $t1, b
li $t2, 1

sll $t3, $t0, 1 

sw $t3, c
Man sieht, ich habe hier einen schwerwiegenden Fehler gemacht. Das war für mich bereits ein Thema in den Übungen, zur Fernuni Hagen. Bei steht der Zieloperand an 2. Stelle.

In diesem Falle ist eine Multiplikation statt gefunden

Code: Alles auswählen

.data
a:		.word 0x1321		# dividend
b: 		.word 0x4		# divisor
c:		.word 0x00		# quotient
r:		.word 0x00		# rest
.text

lw $t0, a
lw $t1, b

loop1:
sll $t0, $t0, 1 
sll $t1, $t1, 1
beqz $t1 loop1

sw $t0, c
Bild

Was wir sehen sind im Arbeitsspeicher

Code: Alles auswählen

0x00001321
0x00002642
Es hat eine Multiplikation mit 2 stattgefunden. Das ist allerdings falsch.

So wäre das Programm richtig

Code: Alles auswählen

.data
a:		.word 0x1321		# dividend
b: 		.word 0x4		# divisor
c:		.word 0x00		# quotient
r:		.word 0x00		# rest
.text

lw $t0, a
lw $t1, b

loop1:
srl $t0, $t0, 1 
srl $t1, $t1, 1
bnez $t1, loop1

sw $t0, c
Als Ergebnis erhalten wir

Code: Alles auswählen

0x00001321
0x00000264
Rechnen wir nach. Am Besten mit dme Taschenrechner

Zunächst wandeln wir die Zahlen ins Dezimalsystem um

Code: Alles auswählen

0x00001321
0x00000264
Wir haben ein Mal zu viel geteilt

Code: Alles auswählen

0x00001321/0x00000264 = 0x4c8
Die Hälfte davon sind

Code: Alles auswählen

0x264
Der Fehler ist das

Code: Alles auswählen

bnez
Wir müssen schon bei einer
aufhören zu dividieren.

Eine andere Möglichkeit, anstatt mit
zu vergleichen. Bestünde darin, die Rechts Shift Operation am Anfang vor der Schleife schon ein Mal aus zu führen

So ist der Programmquelltext richtig

Code: Alles auswählen

.data
a:		.word 0x1321		# dividend
b: 		.word 0x4		# divisor
c:		.word 0x00		# quotient
r:		.word 0x00		# rest
.text

lw $t0, a
lw $t1, b

srl $t1, $t1, 1
loop1:
srl $t0, $t0, 1 
srl $t1, $t1, 1
bnez $t1, loop1

sw $t0, c

Allerdings geht das nur solange, man durch einen Wert

Code: Alles auswählen

0x02
0x04
0x08
...
Teilt. Der nächste Springende Punkt ist folgender. Wir multiplizieren.

Indem wir mit

Code: Alles auswählen

0b100100011100011
Multiplizieren, addieren wir

Code: Alles auswählen

1 * q
+ 10 * q
+ 100000 * q
+ ...
Auch dies können wir mit Shift Operationen machen. Wir schiften den Multiplikator. Jedes Mal, wenn wir auf eine 1 treffen. Multiplizieren wir mit einer entsprechend geshifteten 1 und addieren das Ergebnis zu dem alten

Nein, das war falsch. Wir müssen nicht mit dem geshifteten Multiplizieren. Wir müssen das Ergebnis bereits shiften. Aber wir müssen es inzwischen speichern, um zum alten Wert dazu zu addieren.

Ich habe das Programm zur Multiplikation so eben geschrieben

Code: Alles auswählen

.data 

a: .word 1231	# Muliplikant
b: .word 17	# Multiplikator
c: .word 0x00 	# Product

.text 

lw $t0, a 
lw $t1, b 
li $t2, 0 

loop1:
and $t3, $t1, 1 
beqz $t3, notadd1
add $t2, $t2, $t0
notadd1:
sll $t0, $t0, 1
srl $t1, $t1, 1 
bnez $t1, loop1

sw $t2, c
Das Ergebnis von

Code: Alles auswählen

0x4CF * 0x11 = 51BF
wie das Programm richtig ausgibt.
Antworten