3. Die Assemblersprache

3.1 Aufbau der Assemblersprache

Als typischer Vertreter einer einfachen Registermaschine hat die Minimaschine einen Akkumulator, der bei Rechenoperationen vor der jeweiligen Operation den ersten Operanden und nach Ausführung der Operation das Ergebnis beinhaltet. Bei Speicheroperationen ist er Ziel oder Quelle. Entsprechend ist die Maschine als Ein-Adress-Maschine konzipiert, d. h. die Befehle haben einen Adressteil (in der Regel Speicheradresse oder direkt verwendete Zahl); bei speziellen Befehlen wird der Adressteil nicht benutzt.

Der Assembler erlaubt sowohl absolute Adressierung, d. h. Angabe betroffener Speicherzellen als konkrete Zahlenwerte, als auch symbolische Adressierung. Dabei wird als Adressteil eine Marke (Bezeichner) angegeben; diese Marke ist an anderer Stelle (Programm oder Daten) vereinbart. Der Assembler berechnet dann die Adresse automatisch.

Die Adressierungsarten im Detail:

Durch das Einschalten der Erweiterungen werden neben dem Stackpointerregister und zusätzlichen Befehlen auch weitere Adressierungsarten um Zugriff auf auf dem Stack gespeicherte Werte ermöglicht.

3.2 Programmaufbau

Assemblerprogramme haben einen sehr einfach strukturierten Aufbau. Ein Assemblerprogramm besteht aus einer Folge von Befehlszeilen. Jede Befehlszeile besteht aus einer optionalen Marke, dem Befehl und einem optionalen (vom Befehl abhängenden) Adressteil. Leere Zeilen oder Zeilen, die nur eine Marke enthalten, sind ebenfalls möglich.

Das Zeichen "#" leitet einen Kommentar ein. Kommentare gehen grundsätzlich bis zum Ende der Zeile.

# Algorithmus, um ein Produkt mittels wiederholter Addition zu berechen.
    LOADI   0
    STORE   Produkt        # Ergebnis vorbesetzen
Start:                     # Start der Wiederholung
    LOAD    Faktor1
    JMPNP   Ende           # Beenden, wenn der Zähler kleiner als 0 geworden ist
    SUBI    1              # Zähler erniedrigen
    STORE   Faktor1
    LOAD    Produkt
    ADD     Faktor2
    STORE   Produkt        # Ergebnis erhöhen
    JMP     Start
Ende:
    HOLD                   # Maschine anhalten
# Datenteil
Faktor1:    WORD    5      # Der erste Faktor dient als Zähler für die Wiederholung der Addition
Faktor2:    WORD    4      # Der zweite Faktor wird fortwährend addiert
Produkt:    WORD    0      # Platz für das Ergebnis

3.3 Syntax der Assemblersprache

In EBNF lässt sich die Syntax der Assemblersprache kurz zusammenfassen. Die Erweiterungen sind kursiv dargestellt.

Programm            = {Zeile} . 
Zeile               = [Markenvereinbarung] [Befehl] . 
Markenvereinbarung  = Marke ":" . 
Marke               = ( "A" .. "Z" | "a" .. "z" ) { "A" .. "Z" | "a" .. "z" | "0" .. "9" | "_" | "$" } . 
Befehl              = Operation [ Adresse | "(" Adresse ")" | $Adresse | Adresse(SP) | @Adresse(SP) | $Adresse(SP) ].
Operation           = OperationGroß | OperationKlein .
OperationGroß       = "HOLD" | "RESET" | "NOOP" | "LOAD" | "LOADC" | "STORE" |
                      "ADD" | "SUB" | "MUL" | "DIV" | "DIVU" | "MOD" | "MODU" | "CMP" | "MULH" | "MULHU" |
                      "AND" | "OR" | "XOR" | "NOT" | "SHL" | "SHR" | "SHRA" |
                      "JMPP" | "JMPNN" | "JMPN" | "JMPNP" | "JMPZ" | "JMPNZ" | "JMPV" | "JMPC" | "JMP" |
                      "JGT" | "JGE" | "JLT" | "JLE" | "JEQ" | "JNE" | "JHI" | "JHS" | "JLO" | "JLS" |
                      "ADDI" | "SUBI" | "MULI" | "DIVI" | "DIVUI" | "MODI" | "MODUI" | "CMPI" | "MULHI" | "MULHUI" | "LOADI" |
                      "ANDI" | "ORI" | "XORI" | "SHLI" | "SHRI" | "SHRAI" |
                      "JSR" | "RTS" | "PUSH" | "POP" | "RSV" | "REL" | "CALL" | "RETURN" |
                      "WORD" .
OperationKlein      = "hold" | "reset" | "noop" |  "load" | "loadc" | "store" |
                      "add" | "sub" | "mul" | "div" | "divu" | "mod" | "modu" | "cmp" | "mulh" | "mulhu" |
                      "and" | "or | "xor | "not | "shl | "shr | "shra" |
                      "jmpp" | "jmpnn" | "jmpn | "jmpnp" | "jmpz" | "jmpnz" | "jmpv" | "jmpc" | "jmp |
                      "jgt" | "jge" | "jlt" | "jle" | "jeq" | "jne" | "jhi" | "jhs" | "jlo" | "jls" |
                      "addi" | "subi" | "muli" | "divi" | "divui" | "modi" | "modui" | "cmpi" | "mulhi" | "mulhui" | "loadi" |
                      "andi" | "ori" | "xori" | "shli" | "shri" | "shrai" |
                      "jsr" | "rts" | "push" | "pop" | "rsv" | "rel" | "call" | "return" |
                      "word" .
Adresse             = Marke | Zahl | HexZahl . 
HexZahl             = "0" ("x" | "X" ) ( "0" .. "9" | "A" .. "F" | "a" .. "f" ) { "0" .. "9" | "A" .. "F" | "a" .. "f" } . 
Zahl                = ( "0" .. "9" ) { "0" .. "9" } . 

Die mit "#" eingeleiteten Kommentare treten im Syntaxdiagramm nicht auf, da sie entsprechend den Leerzeichen, Tabulatoren oder Zeilenwechseln bereits bei der Zerlegung des Quelltextes in Terminalsymbole abgearbeitet werden.

3.4 Befehlsübersicht

Die folgende Tabelle beschreibt die Befehle der Minimaschine geordnet nach Funktionsgruppen. Wiedergegeben sind nur die großgeschriebenen Varianten der Befehlsmnemonics.

Speicherbefehle
LOAD adresseLädt den Wert von der angegebenen Adresse in den Akkumulator.
LOADI zahlLädt die angegebene Zahl in den Akkumulator, negative Werte sind möglich, Adressen sind nicht zulässig.
STORE adresseSpeichert den Wert im Akkumulator an der angegebenen Adresse.

Arithmetikbefehle
ADD adresseAddiert den Wert von der angegebenen Adresse zum Akkumulator.
SUB adresseSubtrahiert den Wert der angegebenen Adresse vom Akkumulator.
MUL adresseMultipliziert den Wert von der angegebenen Adresse zum Akkumulator.
DIV adresseDividiert den Wert im Akkumulator durch den Wert der angegebenen Adresse.
MOD adresseDividiert den Wert im Akkumulator durch den Wert der angegebenen Adresse und speichert den Rest im Akkumulator.
DIVU adresseDividiert den Wert im Akkumulator durch den Wert der angegebenen Adresse vorzeichenlos.
MODU adresseDividiert den Wert im Akkumulator durch den Wert der angegebenen Adresse vorzeichenlos und speichert den Rest im Akkumulator.
MULH adresseMultipliziert den Wert von der angegebenen Adresse zum Akkumulator und speicher die oberen 16 Bit im Akkumulator.
MULHU adresseMultipliziert den Wert von der angegebenen Adresse zum Akkumulator vorzeichenlos und speicher die oberen 16 Bit im Akkumulator.
CMP adresseVergleicht den Wert der angegebenen Adresse mit dem Akkumulator und setzt Null- und Negativflag entsprechend.
ADDI zahlAddiert den angegebenen Wert zum Akkumulator.
SUBI zahlSubtrahiert den angegebenen Wert vom Akkumulator.
MULI zahlMultipliziert den angegebenen Wert zum Akkumulator.
DIVI zahlDividiert den Wert im Akkumulator durch den angegebenen Wert.
MODI zahlDividiert den Wert im Akkumulator durch den angegebenen Wert und speichert den Rest im Akkumulator.
DIVUI zahlDividiert den Wert im Akkumulator durch den angegebenen Wert vorzeichenlos.
MODUI zahlDividiert den Wert im Akkumulator durch den angegebenen Wert vorzeichenlos und speichert den Rest im Akkumulator.
MULHI zahlMultipliziert den angegebenen Wert zum Akkumulator und speicher die oberen 16 Bit im Akkumulator.
MULHUI zahlMultipliziert den angegebenen Wert zum Akkumulator vorzeichenlos und speicher die oberen 16 Bit im Akkumulator.
CMPI zahlVergleicht den angegebenen Wert mit dem Akkumulator und setzt Null- und Negativflag entsprechend.

Bitmanipulationsbefehle
AND adresseBitweise logische Und-Verknüpfung des Werts der angegebenen Adresse mit dem Akkumulator.
OR adresseBitweise logische Oder-Verknüpfung des Werts der angegebenen Adresse mit dem Akkumulator.
XOR adresseBitweise logische Exklusiv-Oder-Verknüpfung des Werts der angegebenen Adresse mit dem Akkumulator.
NOTBitweise logische Invertierung des Werts im Akkumulator.
SHL adresseDie Bitfolge im Akkumulator wird um die unter der angegebenen Adresse gespeicherten Anzahl Bits nach links geschoben.
Frei werdende Bits werden mit 0-Werten belegt.
SHR adresseDie Bitfolge im Akkumulator wird um die unter der angegebenen Adresse gespeicherten Anzahl Bits nach rechts geschoben.
Frei werdende Bits werden mit 0-Werten belegt.
SHRA adresseDie Bitfolge im Akkumulator wird um die unter der angegebenen Adresse gespeicherten Anzahl Bits nach rechts geschoben.
Frei werdende Bits werden mit dem ursprünglich vordersten Bit belegt (Vorzeichenerhalt).
ANDI zahlBitweise logische Und-Verknüpfung der angegebenen Zahl mit dem Akkumulator.
ORI zahlBitweise logische Oder-Verknüpfung der angegebenen Zahl mit dem Akkumulator.
XORI zahlBitweise logische Exklusiv-Oder-Verknüpfung der angegebenen Zahl mit dem Akkumulator.
SHLI zahlDie Bitfolge im Akkumulator wird um die angegebene Anzahl Bits nach links geschoben.
Frei werdende Bits werden mit 0-Werten belegt.
SHRI zahlDie Bitfolge im Akkumulator wird um die angegebene Anzahl Bits nach rechts geschoben.
Frei werdende Bits werden mit 0-Werten belegt.
SHRAI zahlDie Bitfolge im Akkumulator wird um die angegebene Anzahl Bits nach rechts geschoben.
Frei werdende Bits werden mit dem ursprünglich vordersten Bit belegt (Vorzeichenerhalt).

Sprungbefehle
JMPP adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation positiv (> 0) war, d. h. weder N noch Z-Flag sind gesetzt.
JMPNN adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht negativ (≥ 0) war, d. h. das N-Flag ist nicht gesetzt.
JMPN adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation negativ (< 0) war, d. h. das N-Flag ist gesetzt.
JMPNP adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht positiv (≤ 0) war, d. h. das N-Flag oder das Z-Flag ist gesetzt.
JMPZ adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation null (= 0) war, d. h. das Z-Flag ist gesetzt.
JMPNZ adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht null (≠ 0) war, d. h. das Z-Flag ist nicht gesetzt.
JMPV adresseSpringt zur angegebenen Adresse, wenn die letzte Operation einen vorzeichenbehafteten Überlauf verursacht hat, d. h. das V-Flag ist gesetzt.
JMPC adresseSpringt zur angegebenen Adresse, wenn die letzte Operation einen vorzeichenlosen Überlauf verursacht hat, d. h. das C-Flag ist gesetzt.
JMP adresseSpringt zur angegebenen Adresse.

Alternative Notation der Sprungbefehle
JGT adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation positiv (> 0) war, d. h. weder N noch Z-Flag sind gesetzt.
JGE adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht negativ (≥ 0) war, d. h. das N-Flag ist nicht gesetzt.
JLT adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation negativ (< 0) war, d. h. das N-Flag ist gesetzt.
JLE adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht positiv (≤ 0) war, d. h. das N-Flag oder das Z-Flag ist gesetzt.
JEQ adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation null (= 0) war, d. h. das Z-Flag ist gesetzt.
JNE adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht null (≠ 0) war, d. h. das Z-Flag ist nicht gesetzt.
JOV adresseSpringt zur angegebenen Adresse, wenn die letzte Operation einen vorzeichenbehafteten Überlauf verursacht hat, d. h. das V-Flag ist gesetzt.
JOC adresseSpringt zur angegebenen Adresse, wenn die letzte Operation einen vorzeichenlosen Überlauf verursacht hat, d. h. das C-Flag ist gesetzt.

Bedingte Sprungbefehle für vorzeichenlose Arithmetik
JHI adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation positiv (> 0) war, d. h. weder C noch Z-Flag sind gesetzt.
JHS adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht negativ (≥ 0) war, d. h. das C-Flag ist nicht gesetzt.
JLO adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation negativ (< 0) war, d. h. das C-Flag ist gesetzt.
JLS adresseSpringt zur angegebenen Adresse, wenn das Ergebnis der letzen Operation nicht positiv (≤ 0) war, d. h. das C-Flag oder das Z-Flag ist gesetzt.

Sonstige Befehle
HOLDHält den Prozessor an. Dieser Befehl hat keine Adresse.
RESETSetzt den Prozessor auf den Startzustand zurück. Dieser Befehl hat keine Adresse.
NOOPTut einfach nichts (NO OPeration). Dieser Befehl hat keine Adresse.
LOADCLädt den Wert des Carry-Flags in den Akkumulator (1 für WAHR, 0 für FALSE). Dieser Befehl hat keine Adresse.

Den Stackpointer verändernde Befehle
JSRSpringt zu der angegebenen Adresse und speichert den Folge-PC auf dem Stack (Unterprogrammaufruf).
Der Stackpointer wird dazu um 1 erniedrigt.
RTSSpringt zu der Adresse in der Speicherzelle, auf dei der Stackpointer zeigt (Unterprogamrücksprung).
Der Stackpointer wird anschließend um 1 erhöht.
PUSHErniedrigt den Stackpointer um 1 und speichert den Akkumulatorwert an der nun durch den Stackpointer gegebenen Adresse.
POPLädt den Inhalt der durch den Stackpointer gegebenen Adresse in den Akkumulator und erhöht den Stackpointer um 1.
RSVErniedrigt den Stackpointer um den im Adressteil gegebenen Wert (Platz reservieren).
RELErhöht den Stackpointer um den im Adressteil gegebenen Wert (Platz freigeben).
CALLAlternative Notation zu JSR.
RETURNAlternative Notation zu RTS.

Speicherorganisation
WORD zahlBesetzt eine Speicherzelle mit der angegebenen Zahl, negative Werte sind möglich.