Frage in Assembler Code mit MIPS
-
Hallo an Alle,
Lerne grad Assemblerprogrammierung mit dem MIPS-Simulator und versuche ein kleines Prog zu schreiben, leider komme ich nicht weiter.
Mein Ziel ist ein kleines prog zu schreiben, was Zahlen richtig sortiert. Später will ich auf die sortierte Zahlen zugreifen können. Der Benutzer soll solange Zahlen eingeben, bis er die 0 tippt.
Nachdem das passert ist sollen die Zahlen richtig sortiert werden.
Da ich in C/C++ schon mal programmiert habe und da einwenig erfahrung hab, versuche ich den Bubble-sort-algo in assembler umzusetzen.
Hier der Code..:.text main: addi $s0,$s0,0 # register $s0 bekommt die 0 zugewiesen ($s0=0) # brauche das zum zählen der eingabe addi $s2,$s2,1 # $s2 = 0 - brauche das für sort addi $s3,$s3,0 # $s3 = 0 - brauche das für print loop_str: la $a0,input_1 # lade adresse von input_1 an register $a0 li $v0,4 # print Zeichenkete von register $a0 syscall li $v0,5 # Zahl von Konsole lesen und an register $v0 speichern syscall move $s1,$v0 # Zahl die von Konsole gelesen $v0 zu $s1 verschieben beq $s1,0, sort # wenn die zahl gleich 0 ist --> gehe zu sort sw $s1, ($sp) # speichere die zahl im stack addi $s0,$s0,1 # $s0 um 1 erhöhen, da der user eine eingabe gemacht hat addi $sp,$sp,-4 # zeiger(stack-pointer) zeigt eine stelle weiter im stack j loop_str # wiederhole das ganze nochmal --> gehe zu loop_str sort: mul $t0,$s0,4 # $t0 = $s0 * 4 - Anzahl der Elemente mal 4 add $sp,$sp,$t0 sort_loop: beq $s2,$s0,print # wenn $s2 gleich $s0, dann gehe zu sort lw $t1,($sp) # erste zahl wird in $t1 gespeichert addi $sp,$sp,-4 # zeiger zeigt auf die zweite zahl lw $t2,($sp) # zweite zahl wird in $t2 gespeichert addi $s2,$s2,1 # $s2 += 1 blt $t2,$t1,replace # wenn $t2 < $t1, dann vertausche die zahlen j sort_loop # ...und das ganze nochmal replace: addi $sp,$sp,4 # zeiger zeigt wieder auf der ersten zahl sw $t2, ($sp) # $t2 kommt an der ersten stelle addi $sp,$sp,-4 # zeiger zeigt auf die zweite zahl sw $t1, ($sp) # $t1 kommt an der zweiten stelle j sort_loop # gehe zu sort_loop print: la $a0,print_txt # lade adresse von nl an register $a0 li $v0,4 # print zeichenkette von $a0 --> also print syscall mul $t0,$s0,4 # $t0 = $s0 * 4 - Anzahl der Elemente mal 4 add $sp,$sp,$t0 addi $sp,$sp,-4 # zeiger zeigt auf die erste zahl print_loop: lw $a0, ($sp) # lade die erste zahl vom stack und übergebe die an $a0 li $v0,1 # print dezimalzahl von $a0 syscall addi $s3,$s3,1 # $s3 += 1 la $a0,nl # lade adresse von nl an register $a0 li $v0,4 # print zeichenkette von $a0 --> also \n syscall beq $s3,$s0, Exit # wenn $s3=$s0 ist ---> gehe zu Exit addi $sp,$sp,-4 # zeiger eine stelle zurücksetzen j print_loop # das ganze wiederholen... Exit: li $v0,10 # EXIT syscall .data input_1: .asciiz "Bitte eine Zahl eingeben..:" nl: .asciiz "\n\n" print_txt: .asciiz "\nPRINT..:\n"
Von Zeile 9-20 ist der Code der für die Eingabe erfordelich ist.
Die Zeilen 45-61 sind die Zeilen, die die Zahlen in der Console ausgeben.
Die Zahlen werden im Stack gespeichert (weiss nicht ob das, das beste ist???).
Die Zeilen 22-43 sind die Zeilen die dem folgenden Code entsprechen sollen..:int i,temp; while(elemente--) for(i = 1; i <= elemente; i++) if(array[i-1] > array[i]) { temp=array[i]; array[i]=array[i-1]; array[i-1]=temp; }
...allerdings, und hier ist mein Problem, kann ich
while(elemente--)
nicht umsetzen, und das ist mein eigentliches Problem, also habe ich bis jetzt nur die for-Schleife umgesetzt..!
Das heisst, wenn ich das Programm ausführe und z.B. 9, 3, 1, 0 eingebe, also die Zahlen 9,3 und 1 - dann sortiert er die NICHT richtig, ich bekomme das Ergebnis 3 - 1 - 9, anstatt das gesuchte 1-3-9.
Das passiert so, weil die while-schleife nicht ausgeführt wird.(da ich das nicht umsetzen kann).Hoffe ihr versteht mein Problem, bin für jede Antwort offen, auch wenn ihr mir nen anderen Assembler-Code als meinen anbietet. (Bin sicher, das mein Code nicht der beste für diese Prob. ist, da ich ja anfänger bin..!)
Danke schon im voraus für euere Antworten..!
-
was genau ist das problem dabei? du kannst es der einfachheit halber ein wenig zerlegen
also statt
while(elemente--) { }
dann
int Tmp=elemente; elemente=elemente-1; if(Tmp!=0) { do { Tmp=elemente; elemente=elemente-1; }while(Tmp!=0) }
btw. bist du dir sicher dass das korrekter mips assembler code ist? ich sehe da nirgens etwas was darauf hindeutet, dass du dir des branch delay slots bewust bist. oder ist der simulator ne spezielle abart von mips?
-
Erstmal thx für deine Antwort..!
Ja, ich bin mir sicher, dass das korrekter MIPS Assembler Code ist (Also Code für den MIPS-Simulator).
Dass jetzt der Code richtig ist bin ich mir nicht sicher, auf jeden Fall funktioniert er so (benutze PCSpim 6.5), natürlich ohne den while-Befehl, da ich das noch nicht geschafft habe zu implentieren.Ich versuche dir mal mein Gedanken, die zu diesem Code geführt haben zu erleutern, vielleicht verstehst du dann mein Problem.
Ich suchte eine Möglichkeit die vom User eingegebene Zahlen zu speichern, also habe ich mir überlegt das so zu machen:sw $s1, ($sp) # speichere die zahl im stack addi $sp,$sp,-4 # zeiger(stack-pointer) zeigt eine stelle weiter im stack
Die erste Zahl wird im Stack gespeichert, der Stack-Pointer um ein Wort erhöht, damit ich ja die nächste Zahl speichern kann. Das passiert in eine schleife, bis der User die 0 getippt hat...wenn das passiert versuche ich die Zahlen zu sortieren (das ist der nächste Schritt).
Damit ich weiss wieviele Zahlen der User eingetippt hat, erhöhe ich den register $s0, der am Anfang 0 ist, bei jeder Eingabe immer um 1.addi $s0,$s0,1 # $s0 um 1 erhöhen, da der user eine eingabe gemacht hat
Wenn jetzt der User die 0 getippt hat gehe ich mittels
beq $s1,0, sort # wenn die zahl gleich 0 ist --> gehe zu sort
zu dem zweiten Schritt, der Sort heisst.
Weil jetzt der Stack-pointer auf der letzten Zahl zeigt multipliziere ich $s0 (also die Anzahl der Zahlen, dei der User getippt hat) mit der 4 mit folgendem Befehlmul $t0,$s0,4 # $t0 = $s0 * 4 - Anzahl der Elemente mal 4
und addiere das ergebnis mittels
add $sp,$sp,$t0
mit dem Zeiger, so das jetzt der Stack-pointer wieder am Anfang zeigt(also auf der ersten eingegebenen Zahl)
Diese Zahl speichere ich in $t1, erhöhe den Zeiger um ein Wort weiter, sodas er auf die zweite zahl zeigt, speichere die nachfolgende Zahl in $t2, vergleiche ob die Zahlen verschieden sind und wenn $t2 < $t1, dann vertausche ich die Zahlen und speichere die wieder im Stack (Zeile 36-43).
Hier erhöhe ich noch den register $s2 (ist am anfang 0) um eins. (Den brauche ich um die sort_loop schleife zu verlassen)
Dann vergleiche ich die nächsten beiden Zahlen usw usw. Das ganze passiert so oft bis $s2 = $s0 ist..:beq $s2,$s0,print # wenn $s2 gleich $s0, dann gehe zu print
Wenn das passiert sollte eigentlich die sort_loop nochmal laufen und zwar so oft wie die Anzahl der eingegebene Zahlen, also so oft wie $s0.
Der Zeiger sollte eigentlich an der letzten Zahl zeigen und ich sollte dann mit dem Befehl
mul $t0,$s0,4 # $t0 = $s0 * 4 - Anzahl der Elemente mal 4 add $sp,$sp,$t0
den Zeiger wieder auf der ersten Zahl zeigen lassen.
Leider passiert das ja nicht, weil wie du bei print siehst muss ich erst
mul $t0,$s0,4 # $t0 = $s0 * 4 - Anzahl der Elemente mal 4 add $sp,$sp,$t0 # NORMAL
und dann
addi $sp,$sp,-4 # NICHT NORMAL
also den Zeiger noch eine Stelle weiter zeigen lassen.
Ich glaube hier liegt mein Problem.Sonst könnte ich while so schreiben
while: beq $s4,$s0,print # wenn $s4=$s0, dann wurde while n mal ausgeführt # also gehe zu print (n: Anzahl der Zahlen) addi $s2,$s2,$zero # $s2=0, damit die sort_loop schleife wieder n mal läuft addi $s4,$s4,1 # $s4 += 1 j sort_loop sort_loop: # alles bleibt gleich, nur der befehl "beq $s2,$s0,print" ändert sich in beq $s2,$s0, while # da ich ja die while-schleife wiederholen will
Hoffe du hast mein Problem verstanden..!
MFG Bonafide..!