====== Aufgaben D: Branch mit LMC ======
==== Aufgabe D1: It's the final countdown ====
**Ziel:** einen Countdown ($10$ bis $0$) mit dem LMC programmieren.
Dokumentiere die Aufgabe, z.B. auf OneNote. Mache dazu eine neue Seite.
1) Programmiere zuerst den Countdown mit Python mit einer `while`-Schleife. Es sollen also einfach der Reihe nach die Zahlen von $10$ bis $0$ ausgegeben werden. Füge den Code als Screenshot in die Dokumentation ein.
++++Lösungen|
i = 10
while i >= 0:
print(i)
i = i - 1
++++
2) *Notiere* in deiner Dokumentation: Mache einen Plan, wie du das mit dem LMC umsetzen willst. Welchen der drei Branch-Befehle verwendest du?
++++Lösungen|
Mit der while-Schleife wollen wir den Codeblock solange wiederholen, wie die Bedingung `i >= 0` erfüllt ist. Der Branch-Befehl `BRP` ist sehr ähnlich: Dieser springt solange, wie der Wert im Akkumulator $\ge 0$ ist.
Plan:
1. Startwert $10$ in Speicher schreiben und in Akkumulator laden
1. Anzeigen
1. subtrahieren: $-1$
1. Falls Akkumulator $\ge 0$ (an richtige Position) nach oben springen
1. Falls nicht: Programm beenden
++++
3) Programmiere den Countdown mit LMC. Der Output soll also sein:
{{ :gf_informatik:computerarchitektur_sca:lmc_countdown_output.png?nolink&100 |}}
Screenshot in Dokumentation einfügen.
++++Lösungen|
**Lösung 1:** Speichere Startwert an Speicherposition 99 und Schrittweite ($1$) an Position 98
LDA 99
OUT
SUB 98
BRP 1
HLT
++++
4) Am Code von der letzten Aufgabe ist etwas sehr mühsam: Man muss immer zuerst die beiden Zahlen (Startwert $10$ und Schrittgrösse $1$) von Hand in den Speicher schreiben. Ansonsten gibt der Code keinen Countdown aus. Hier gibt es einen Ausweg: Mithilfe des Befehls `DAT` kann man Daten über den Assemblercode in den Speicher schreiben, z.B.:
...
HLT
FIVE DAT 5
Im RAM wird dann direkt nach dem `000` von `HLT` der Wert $5$ gespeichert. Auf die Adresse von Wert $5$ kann man dann über den angegebenen Namen, also hier `FIVE` zugreifen, z.B. `ADD FIVE`.
Passe deinen Countdown-Code an, indem du die beiden benötigten Werten (Startwert & Schrittweite) auf diese Weise speicherst und verwendest. Screenshot in Dokumentation einfügen.
++++Lösung|
LDA TEN
OUT
SUB ONE
BRP 1
HLT
ONE DAT 1
TEN DAT 10
++++
5) Im Befehl `BRP 1` geben wir an, dass wir (falls Akkumulator $\ge 0$) zu Zeile $1$ des Programms springen wollen. Diese Notation wird bei etwas komplexeren Codes schnell mühsam. Denn wenn sich der Code ändert, *ändern sich auch die Zeilenreferenzen*. Passt man also seinen Code an, muss man ständig die Zeilenreferenzen überprüfen und gegebenenfalls anpassen. Dieses Problem umgehen kann man mit **Labels**:
Kennzeichne eine Zeile Code, du der du springen möchtest, mit einem Label, z.B. wird Zeile 1 im Code hier von `OUT` zu `LOOP OUT`. Mit ` LOOP` können wir nun jederzeit zu dieser Zeile Code springen, auch wenn sich ihre Position verschiebt. Anstelle von `LOOP` kann man natürlich jedes beliebige Wort verwenden. Beim Übersetzen des Assembler-Programms in Maschinensprache werden die Labels mit den tatsächlichen Zeilennummern der Instruktion ersetzt.
Implementiere dies in deinem Code. Screenshot in Dokumentation einfügen.
++++Lösung|
LDA START // Lade Startwert in Akk.
LOOP OUT
SUB ONE
BRP LOOP // Falls Akk. > 0, Countdown also noch nicht fertig springe nach oben (zu LOOP)
HLT
ONE DAT 1
START DAT 10
Der grosse Unterschied in der Logik zwischen dem Python- und Assemblercode ist:
* Python: Zuerst wird Bedingung (`x >= 0`) überprüft und erst *nachher* wird der Codeblock (`print(x), x = x - 1`) ausgeführt.
* Assemblercode: Genau anders herum. Zuerst wird Codeblock (`OUT, SUB ONE`) ausgeführt und erst nachher wird die Bedingung (Akkumulator $\geq 0$) überprüft und gegebenenfalls nach oben gesprungen.
Man kann seinen Assemblercode aber auch so schreiben, dass er näher an der Logik des Python-Codes ist. Allerdings wird er dann etwas komplizierter:
LDA START
JMP BRP LOOP // springe zum Codeblock des Loops
BRA END // springe zum Ende, falls Loop fertig (Ziel erreicht)
LOOP OUT // Anfang Codeblock des Loops
SUB ONE
BRA JMP // Ende des Codeblocks, springe zur Überprüfung der Bedingung
END HLT // Beende Programm
START DAT 10
ONE DAT 1
Eine weitere Lösung:
LDA START
LOOP OUT
BRZ END
SUB ONE
BRA LOOP
END HLT
START DAT 10
ONE DAT 1
++++
==== Aufgabe D2: Maximum ====
**Ziel:** Die Benutzerin soll nacheinander zwei Zahlen eingeben. Es soll dann die grössere der beiden Zahlen ermittelt und ausgegeben werden.
1) Programmiere das Programm zuerst mit Python. Verwende dazu eine `if`-`else`-Verzweigung.
++++Lösung|
a = input()
b = input()
if b > a:
print(b)
else:
print(a)
Alternativ (besser für LMC)
a = input()
b = input()
if b - a > 0:
print(b)
else:
print(a)
++++
2) Mache einen Plan: Wie kannst du das Programm mit dem LMC schreiben?
3) Implementiere es mit dem LMC.
==== Aufgabe D3: 3er-Reihe ====
**Ziel:** Der Benutzer soll eine Zahl $n$ eingeben. Es werden dann die ersten $n$ Zahlen der 3-er Reihe ausgegeben: $3,6,9,\ldots$.
1) Programmiere das Programm zuerst mit Python. Dabei dürfen nur die mathematischen Operationen $+$ und $-$ verwendet werden.
++++Lösung|
n = input()
x = 3
while n > 0:
print(x)
x = x + 3
n = n - 1
++++
2) Mache einen Plan: Wie kannst du das Programm mit dem LMC schreiben?
3) Implementiere es mit dem LMC.
===== Lösungen =====
++++Lösungen|
== Maximum ==
INP
STO A
INP
STO B
SUB A
BRP ELSE
LDA A
OUT
HLT
ELSE LDA B
OUT
HLT
A DAT 0
B DAT 0
== 3er-Reihe ==
INP
STO N
LOOP LDA N
BRZ END // jump to end if N=0
SUB ONE
STO N
LDA X
OUT
ADD STEP
STO X
BRA LOOP
END HLT
N DAT 0
X DAT 3
STEP DAT 3
ONE DAT 1
++++