petomka

Curator
Donator
Nov. 1, 2017
6
Hallo,

Aus aktuellem Anlass im Studium, Interesse und auch aus der Laune heraus habe ich eine Registermaschine (genauer gesagt eine Random-Access-Machine) mit Java umgesetzt. Diese Maschine umfasst den ganzen Befehlssatz der RAM - die vier Grundrechenarten jeweils direkt, mit Konstanten oder mit indirekter Adressierung sowie bedingte und unbedingte Sprungbefehle.

Das Prinzip hinter der RAM ist relativ simpel. Aber zuerst einmal was zu den Registern:
- Ein Register enthält einen Wert (eine Zahl), der größer oder gleich 0 ist.
- Ein Register ist mit 0 initialisiert.

Die RAM ist nun aus diesen Komponenten aufgebaut:
- Ein Befehlszähler b
- Einem Akkumulator, im wesentlichen ein Register, wird adressiert mit c(0)
- Ein (unendlich großer) Speicher bestehend aus Registern welche ab Adresse 1 angesprochen werden können
- Ein Programm, aufgebaut aus einer endlichen Folge von einzelnen Befehlen aus dem Befehlssatz.

Diesem Prinzip bin ich mit meiner Implementierung so nahe wie möglich geblieben. Eine Registermaschine lässt sich sehr einfach instanzieren:
Java:
RegisterMachine machine = new RegisterMachine()

Dieses Registermaschinenobjekt verfügt nun auch über einen Befehlszähler (ProgramCounter), einen Akkumulator (Register), einem nur durch deine Hardware bzw. die JVM beschränkten Speicher (Memory) und einem anfangs leerem Programm (Program).

Auf den Speicher lässt sich zum Beispiel direkt zugreifen und hineinschreiben:
Java:
Memory memory = machine.getMemory();
memory.getRegister(1).setValue(1337);
memory.getRegister(2).setValue(420);

Register register = memory.getRegister(3);
register.setValue(register.getValue() + 1);
Für den Speicher existieren alle Register ab Index 1, d.h. wenn man das richtig benutzt bekommt man immer ein Register vom Speicher, welches man dann benutzen kann.

Das ganze wäre nun aber etwas wenig, wenn man diese Maschine nicht auch programmieren könnte. Das geht - vorausgesetzt, man weiß, wie man ein Registgermaschinenprogramm schreibt - recht einfach:
Java:
machine.compileProgram(new String[]{
    "LOAD 1", //Lade c(1) in den Akkumulator
    "ADD 2", //Akkumulator += c(2)
    "STORE 3", //c(3) = Akkumulator
    "END"
});
Dieses sehr überschaubare Programm lädt nun den Wert, welchen wir in Register 1 geschrieben haben in den Akkumulator, addiert den Wert aus Register 2 hinzu und speichert den ausgerechneten Wert in Register 3. Dann terminiert das Programm. Die Anweisung "END" ist wichtig.

Um das Programm nun auch zur Ausführung zu bringen, reicht nun folgendes aus:
Java:
while(!machine.isTerminated()) {
    machine.step();
}
Die Methode step() sorgt nun dafür, dass aus dem zuvor kompilierten Programm der Befehl entsprechend dem Wert des Befehlszählers geholt wird und ausgeführt wird. Dies soll solange wiederholt werden, bis die Registermaschine terminiert hat (nach dem Befehl "END").

Möchte man am Ende noch sehen, in welchem Zustand sich die Register befinden, kann man das sehr einfach mit einem Memory Dump machen:
Java:
System.out.println(machine.memDump(10));
Dieser Aufruf sorgt dafür, dass der Inhalt der ersten 10 Register (Akkumulator inbegriffen) auf die Standardausgabe ausgegeben werden. Möchte man mehr bzw. weniger sehen, muss der Parameter entsprechend angepasst werden.

So viel erstmal zum Code an sich, vielleicht baue ich irgendwann noch ein schönes GUI drumherum, wo man sein Programm dann auch bequemer eingeben, speichern und sogar wieder laden kann. Im Moment jedoch erstmal nicht. Den Code gibt es [hier], ein Beispielprogramm findet sich außerdem auch nochmal in der Hauptklasse, welche Befehle genau es gibt und wie sie aufgebaut sein müssen findet sich in der README.
 
  • Like
Reaktionen: Taminoful

Users who are viewing this thema