Zahlen Test --> gerade oder ungerade in Assembler

Kirby.exe

Top Contributor
Alsooo wir sollen ein Programm in Assembler schreiben, dass eine ganze Zahl einließt und überprüft ob diese Zahl gerade oder ungerade ist. Soweit so gut, jedoch bekomme ich bei meinem Code eine Endlosschleife und sehe ehrlich gesagt meinen Fehler nicht :( Könnte mir jemand auf die Sprünge helfen?

Hier ist eine Liste mit allen Befehlen:

12781
12782

Mein Code:

Code:
#Einlesen einer Zahl
addi zero t0 1
sysmove exc t0
syscall

#Zahl nach a0 kopieren
sysmove a0 I[0]

#Prüfen ob Zahl gerade ist
ldd t1 zero 0
ldd t2 zero 0
ldd t3 zero 1 #Register mit Inhalt 1
ldd t4 zero 0 #Register mit 0

#divide:
subi a0 t2 2 # Subtraktion  mit 2
ldd t2 a0 0 #Move nach a0
beq a0 t3 11 #Vergleich a0 mit 1
beq a0 t4 13 #Vergleiche a0 mit 0
jmp 6

#ungerade:
cout ungerade
syscall

#gerade:
cout gerade
syscall
 

mihe7

Top Contributor
Mir ist die Syntax noch nicht klar. Wie viele Bytes haben die Befehle? Sind die Zahlen 8 Bit breit? Wie funktioniert cout? Usw. Da fehlt die Häfte der Doku. Aber das Prinzip wäre IMO:
Code:
# Prüfen, ob Zahl gerade ist
xor t0 t0 t0   # t0 := 0
addi t0 t1 1   # t1 := t0+1 = 1
and a0 t1 t0  # t0 := a0 & 1
beq t0 t1 ungerade # if t0 == t1 (also 1), dann weiter mit ungerade, sonst mit gerade
#gerade:
cout gerade
syscall

#ungerade:
cout ungerade
syscall
 

Kirby.exe

Top Contributor
Mir ist die Syntax noch nicht klar. Wie viele Bytes haben die Befehle? Sind die Zahlen 8 Bit breit? Wie funktioniert cout? Usw. Da fehlt die Häfte der Doku.
Also die größe der Befehle ist mir ehrlich gesagt unbekannt :( Ich kann dir mal die Documentation des Assemblers schicken :)

Ich glaube jedoch dass xor t0 t0 t0 # t0 := 0 gegen die Konvention verstößt, da nur ein Befehl pro Zeile ausgeführt werden darf wegen lesen und schreiben ins selbe Register, dass wurde mir zumindest in der letzten Übungsserie angestrichen

Wie funktioniert cout?
So wie ich das verstanden habe ist count einfach ein print Befehl :)

# Prüfen, ob Zahl gerade ist
xor t0 t0 t0 # t0 := 0
addi t0 t1 1 # t1 := t0+1 = 1
and a0 t1 t0 # t0 := a0 & 1
beq t0 t1 ungerade # if t0 == t1 (also 1), dann weiter mit ungerade, sonst mit gerade
Was macht xor genau? In der Dokumentation steht bitweises Exklusiv-Oder, jedoch kann ich mir nicht wirklich vorstellen was es genau tut. Warum addierst du auf t0? Habe ich vielleicht etwas falsch verstanden bei der division in assembler? Ich dachte man müsste subtrahieren.
 

Anhänge

  • pHILOs_manual.pdf
    1,3 MB · Aufrufe: 5
Zuletzt bearbeitet:

mihe7

Top Contributor
Was macht xor genau? In der Dokumentation steht bitweises Exklusiv-Oder, jedoch kann ich mir nicht wirklich vorstellen was es genau tut.
XOR = Antivalenz = entweder oder :)

Wertetabelle:
Code:
A | B | A XOR B
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0

Bitweises XOR:
Code:
10101010
01010101 
-------- XOR
11111111
Dagegen
Code:
10101010
00001111
-------- XOR
10100101

Ein XOR zweier gleicher Zahlen liefert also 0.
Warum addierst du auf t0?
Um eine 1 in t1 zu erhalten :) In den Befehlen habe ich keinen gefunden, mit dem ich ein Register mit einem Immediate (Wert) setzen hätte können. Wo ein Immediate zugelassen ist: addi (darum auch das i am Ende).

Habe ich vielleicht etwas falsch verstanden bei der division in assembler? Ich dachte man müsste subtrahieren.
Könnte man, muss man aber nicht. Eine Binärzahl ist ungerade, wenn das 1er-Bit gesetzt ist :)
 

Kirby.exe

Top Contributor
Ahhhh jetzt fühle ich mich um einiges schlauer xD

Ich bin trotzdem verwirrt ob der xor Befehl der Konvention entspricht xD:

Konvention:
  • Pro Zeile darf höchstens 1 Befehl stehen.
  • Befehlsname und die jeweiligen Argumente müssen mit mindestens einem Leerzeichen oder einem
    Tabulator getrennt sein. Vor dem Befehlsnamen darf kein Leerzeichen stehen.
  • Bei den reinen Maschinenbefehlen wird nicht zwischen Majuskeln und Minuskeln, also Groß- und Kleinschreibung, unterschieden. Das gilt insbesondere für die Registernamen.
  • Neben den oben aufgezählten Maschinenbefehlen dürfen noch beliebig viele Pseudoinstruktionen benutzt werden. Diese müssen im Reiter „Systemeinstellungen“ deklariert und realisiert worden sein.
  • Bei allen Instruktionen müssen die Registernamen benutzen werden, die im Reiter „Register- und Speicherbelegung“ in der Registerbanktabelle aufgeführt sind.
  • Ein-/Ausgaberegister können nicht als Operanden von Maschinenbefehlen dienen, sondern nur als
    Operanden von Systembefehlen, da sie sich nicht in der Registerbank des Prozessors befinden.
 

mihe7

Top Contributor
Sehe zwar kein Problem mit der Konvention, aber dann halt per Addition... (ich wusste vor der Doku nicht, was es mit zero auf sich hat) Und: der Assembler kann Labels :)
Code:
# Einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]

# Prüfen, ob Zahl gerade ist
addi zero t0 0
and a0 t1 t0 
beq t0 t1 ungerade 

# gerade
cout gerade
jmp ende

# ungerade
ungerade:
cout ungerade

# ende
ende:
sysmove exc zero
syscall
 

Kirby.exe

Top Contributor
Danke für deine Hilfe :) Ich muss sagen das hat gerade mein Wissen bezogen auf den Uni Assembler um einiges geboostet xD Du bist einfach ein Master of Everything xD
 

Kirby.exe

Top Contributor
@mihe7 Ich hätte noch eine Frage, wenn ich jetzt zwei Zahlen einlesen möchte und prüfen will ob die zweite Zahl in den Natürlichen Zahlen liegt muss ich doch einfach prüfen ob 0 größer als das Speicher Register der Zahl ist ?

Also wie folgt:

Code:
# Einlesen Zahl 1
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]

# Einlesen Zahl 2
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[1]
bgt zero a1 einlesen
 

mihe7

Top Contributor
Natürlichen Zahlen liegt muss ich doch einfach prüfen ob 0 größer als das Speicher Register der Zahl ist ?
Deine Idee ist also, wenn 0 > x gilt, dann ist x keine natürliche Zahl. Das ist mathematisch richtig, wenn man die 0 als natürliche Zahl zählt, ob der Vergleich so funktioniert, ist eine andere Sache - und davon würde ich nicht ausgehen.

Für den Prozessor ist ein Register einfach Wort mit einer bestimmen Länge, hier 8 Bit. Was diese 8 Bit darstellen, weiß der Prozessor nicht (es könnte spezielle Prozessorbefehle geben, was hier aber nicht der Fall ist, wie ich meine).

Werden zwei Register verglichen, passiert das über eine logische Schaltung. So lange die Bits der beiden Register - vom höchstwertigen Bit ausgehend - gleich sind, sind die Register gleich. An der ersten Position, an der das nicht mehr zutrifft, weiß man, welches Register größer ist:
Code:
r1  11100000
r2  11110000
    ^^^^
    ===<
Hier wäre also r1 < r2.

Die Frage ist jetzt, was die Register darstellen. Das können Zahlen ohne Vorzeichen sein, dann hat man je Register einen Wertebereich von 0 bis 255. In dem Fall stimmt der Vergleich: 00000001 < 11111111 (binär) entspricht 1 < 255 (dezimal).

Wenn es Zahlen mit Vorzeichen sind, dann ist die Frage, wie diese dargestellt werden. Üblicherweise wird das Zweierkomplement verwendet. Um eine Zahl zu negieren, werden die Bits invertiert und anschließend wird eine 1 addiert.

Wenn wir Beispielsweise die 1 negieren wollen, um -1 zu erhalten:
Code:
00000001    # 1 binär
11111110    # invertiert
11111111    # 1 addiert
-1 wird im Zweierkomplement also binär mit 11111111 dargestellt.

Klar ist jetzt, dass der Vergleich nicht das gewünschte Ergebnis liefert, denn 00000001 < 11111111 (binär) würde jetzt dezimal 1 < -1 entsprechen.

Tatsächlich lässt sich viel einfacher feststellen, ob eine Zahl negativ ist, denn das 8. Bit ist das Vorzeichen. Daher lassen sich Zahlen von -128 bis +127 darstellen.

Wenn Du also eine Zahl im Zweierkomplement hast, brauchst Du nur zu testen, ob das 8. Bit gesetzt ist. Falls ja, hast Du eine negative Zahl.
 

Kirby.exe

Top Contributor
Danke für deine Hilfe um die Uhrzeit :) Nehmen wir mal an dass wir die Natürlichen Zahlen ohne die 0 haben wollen, dann müsste man doch einfach prüfen bei 8 bit Zahlen ob 1 (011111111 im ZK) > Register X ist und wenn true dann geht er weiter und wenn nicht kommt die Eingabeaufforderung erneut ?
 

mihe7

Top Contributor
ob 1 (011111111 im ZK)
1 ist im ZK auch 00000001. 01111111 wäre 127 - ganz normal. Nur die negativen Zahlen werden anders dargestellt.

Nachtrag: und ja, wenn 01111111 > registerX ist, dann liegt registerX im Bereich von 0 bis 127. Wenn Du die 0 nicht haben willst, musst Du nochmal explizit auf 0 prüfen.
 
Zuletzt bearbeitet:

Kirby.exe

Top Contributor
1 ist im ZK auch 00000001. 01111111 wäre 127 - ganz normal. Nur die negativen Zahlen werden anders dargestellt.

Nachtrag: und ja, wenn 01111111 > registerX ist, dann liegt registerX im Bereich von 0 bis 127. Wenn Du die 0 nicht haben willst, musst Du nochmal explizit auf 0 prüfen.
Okee Dankeschön :) ja gut ich glaube nach dem Pensum an Mathe heute in der Uni hatte mein Gehirn da scheinbar ein Timeout xD
1 ist im ZK auch 00000001
War das nicht die 1 im Einerkomplement oder verwirre ich mich gerade selber :) ?
 
Zuletzt bearbeitet:

mihe7

Top Contributor
War das nicht die 1 im Einerkomplement oder verwirre ich mich gerade selber :) ?
Letzteres: positive Zahlen werden immer gleich dargestellt. Unterschiede gibt es in der Darstellung negativer Zahlen. Ist das höchstwertige Bit eine 0, dann unterscheiden sich vorzeichenlose Ganzzahlen nicht von vorzeichenbehafteten Ganzzahlen.
 

Kirby.exe

Top Contributor
@mihe7 könntest du mir eventuell nochmal für dumme erklären, wie ich es mir vorstellen kann wenn register verglichen werden. Also in dem Befehlsatz PHILO's...Ich hatte and sowas gedacht:

t3 ist einfach ein Register das die Zahl 0 enthält. Ich möchte prüfen ob die Ziffer größer als 0 ist und wenn nicht, dann neu einlesen.

Code:
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[1]
bgt t3 a1 einlesen
 

mihe7

Top Contributor
Der Vergleich ist ganz einfach. Du hast zwei vorzeichenlose binäre Zahlen und die werden nicht anders verglichen dezimale Zahlen: 0 < 1 < 10 < 11 < 100 < 101 < 110 < 111 < 1000 usw.

Das einzige Problem ist, dass die Befehle keine negativen Zahlen kennen. Es gibt keine Zahl kleiner 0. Es obliegt dem Programmierer, wie er negative Zahlen darstellt. Der Programmierer des "Betriebssystems" in PHILO hat festgelegt, dass bei Eingabe (syscall) einer negativen Zahl das Zweierkomplement verwendet wird.

Ein Vergleich zweier negativen Zahlen ist somit auch kein Problem: denn -2 < -1, was unmittelbar auch in ZK-Darstellung 11111110 < 11111111 zutrifft.

Problematisch ist der Vergleich einer negativen und einer nicht-negativen Zahl, der Befehl weiß ja nicht, ob eine Zahl negativ oder positiv ist. Was Du machen kannst: Du kannst fragen, ob eine Zahl größer als 127 (01111111) ist. Dann nämlich ist das 8. Bit, das Vorzeichenbit, gesetzt.

Code:
addi zero t3 127
einlesen: ...
...
bgt a1 t3 einlesen     # falls a1 > 127, also Vorzeichenbit gesetzt, dann weiter mit einlesen
 

Kirby.exe

Top Contributor
Also ich habe mal meinen Code etwas überarbeitet etc. Es sollen halt eine ganze Zahl durch eine Natürliche Zahl(ohne 0) geteilt werden.

Das Problem ist es kommen sehr witzige Werte heraus die nicht wirklich etwas mit dem eigentlichen Wert zu tun haben

Mein Code dazu:

Code:
#Clear Register
addi zero t3 0
addi zero t6 1

#Erste Zahl einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]
bgt t3 a0 multiplyT

#Zweite Zahl einlesen
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[0]
bgt t3 a1 einlesen

laeuft:
addi a3 a3 1 #zähler wird erhöht

divide:
sub a0 a1 a0
bgt a0 a1 laeuft
beq t6 t4 mover

print:
sysmove O[0] a3
#cout Das Ergebnis lautet
addi zero t5 6
sysmove exc t5
syscall

end:
sysmove exc zero
syscall

multiplyT:
addi zero t4 1
sub t3 a0 a0
jmp einlesen

multiplyB:
addi zero t4 1
sub t3 a0 a0
jmp print

mover:
add zero a3 a0
jmp multiplyB
 

Kirby.exe

Top Contributor
Der Vergleich ist ganz einfach. Du hast zwei vorzeichenlose binäre Zahlen und die werden nicht anders verglichen dezimale Zahlen: 0 < 1 < 10 < 11 < 100 < 101 < 110 < 111 < 1000 usw.

Das einzige Problem ist, dass die Befehle keine negativen Zahlen kennen. Es gibt keine Zahl kleiner 0. Es obliegt dem Programmierer, wie er negative Zahlen darstellt. Der Programmierer des "Betriebssystems" in PHILO hat festgelegt, dass bei Eingabe (syscall) einer negativen Zahl das Zweierkomplement verwendet wird.

Ein Vergleich zweier negativen Zahlen ist somit auch kein Problem: denn -2 < -1, was unmittelbar auch in ZK-Darstellung 11111110 < 11111111 zutrifft.

Problematisch ist der Vergleich einer negativen und einer nicht-negativen Zahl, der Befehl weiß ja nicht, ob eine Zahl negativ oder positiv ist. Was Du machen kannst: Du kannst fragen, ob eine Zahl größer als 127 (01111111) ist. Dann nämlich ist das 8. Bit, das Vorzeichenbit, gesetzt.

Code:
addi zero t3 127
einlesen: ...
...
bgt a1 t3 einlesen     # falls a1 > 127, also Vorzeichenbit gesetzt, dann weiter mit einlesen
Ich glaube das könnte der Grund für die komischen Werte sein xD
 

Kirby.exe

Top Contributor
Könntest du dir mal meinen Code anschauen, ich glaube das steht einiges an Bullshit xD :)

Ich habe gemerkt das mein Zähler register gar nicht 0 ist, jedoch kommt jetzt bei jeder Iteration der Wert 0 als Ergebnis :(

Code:
#Clear Register
addi zero t3 0
addi zero t6 1
addi zero a3 0

#Erste Zahl einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]
bgt t3 a0 negative

#Zweite Zahl einlesen
einlesen:
addi zero t1 1
sysmove exc t1
syscall
sysmove a1 I[0]
beq a1 t3 einlesen
bgt t3 a1 einlesen

divide:
sub a0 a1 a0
bgt a0 a1 laeuft
beq t6 t4 mover

print:
sysmove O[0] a3
#cout Das Ergebnis lautet
addi zero t5 6
sysmove exc t5
syscall

end:
sysmove exc zero
syscall

negative:
addi zero t4 1
sub t3 a0 a0
jmp einlesen

multiplyB:
sub t3 a0 a0
jmp print

mover:
add zero a3 a0
jmp multiplyB

laeuft:
addi a3 a3 1 #zähler wird erhöht
jmp divide
 
Zuletzt bearbeitet:

Kirby.exe

Top Contributor
Also ich glaube das mein Programm bereits funktioniert, jedoch ist der Counter(Ergebnis was gesprintet wird) immer um 1 zu niedrig :( Ich sehe nur leider den Fehler nicht
 

Kirby.exe

Top Contributor
Ich schicke es dir mal per PN :) Brauchst du Unix oder Windows?

Ich kann dir keine PN schreiben lul, dann müsstest du mich eben anschreiben :)
 

mihe7

Top Contributor
Ach, jetzt sehe ich das erst, das Ding hat 32-Bit Register, verwenden intern vermutlich ein Java int und die Befehle arbeiten im Zweierkomplement... OK, dann ist alles klar.
 

Kirby.exe

Top Contributor
Ich glaube ich habe die Lösung :) ich habe nicht den Fall im Label divide abgedeckt wenn a0 und a1 gleich sind xD Ich glaube es läuft :) finally :)

Danke für deine Hilfe
 

mihe7

Top Contributor
LOL, ok :) Aber einen habe ich noch, in multiplyB müsste es

Code:
sub t3 a0 a3
heißen.
 

Neue Themen


Oben