====== 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 ++++