Skip navigation

ARES


Page Content:

Besonderheiten der MARS-CPU

Der "Prozessor", der die Core War Programme ausführt, unterscheidet sich etwas von herkömmlichen Prozessoren. So ein Prozessor ist nie wirklich gebaut worden, der MARS-Computer existiert nur als virtuelle MaschineExternal Link, die speziell für das Spiel erdacht wurde. Das Redcode-Instruction Set ist für bestimmte Aufgaben optimiert und die Speicherorganisation eines MARS ist ebenfalls anders aufgebaut, als es bei echten Computern der Fall ist. Ein wesentlicher Unterschied zu herkömmlichen Rechnern ist, daß Redcodeprogramme nur auf Daten zugreifen können, die sich im Hauptspeicher befinden. Es gibt also keine Arbeitsregister, die dem Programmierer zur Verfügung stehen würden und Redcode-Programme können auch keine PeripheriegeräteExternal Link ansteuern, weil schlichtweg keine vorhanden sind. Die Aufgabe der Register wird in Redcode von den DAT-Befehlen übernommen - Befehle wie ADD oder CMP (Compare) beziehen sich meistens auf Werte, die in DAT-Befehlen gespeichert sind.

Adressierung

Programme, die für den Krieg der Kerne geschrieben werden, unterliegen bestimmten Einschränkungen. Die übliche absolute Adressierung von Zellen des Hauptspeichers über deren Adresse ist nicht erlaubt, Redcode-Programme dürfen nur relativ adressieren. Adressen von Speicherzellen werden durch einen Offset zum aktuellen Instruction Pointer beschrieben, also durch den Abstand zum aktuellen Befehl. Das folgende "Programm" verwendet nur relative Adressen:
  "Endlos-Schleife" mit relativer Adressierung:
JMP +1 Adresse des nächsten Befehls (Current IP + 1) in den IP kopieren
JMP -1 Adresse des vorigen Befehls (Current IP - 1) in den IP kopieren
In einem "echten" Assembler könnte man das Programm aber auch absolute Adressen benutzen lassen:
  "Endlos-Schleife" mit absoluter Adressierung:
&0234 JMP &0235 Den Wert 235 in den IP kopieren
&0235 JMP &0234 Den Wert 234 in den IP kopieren

Speicherorganisation

Ein weiterer Unterschied zu einem richtigen Computer ist, daß jeder Befehl mitsamt allen zusätzlichen Angaben immer in genau einer einzigen Speicherzelle abgelegt wird. Um Speicher zu sparen, können normalerweise verschieden komplexe Maschinenbefehle auch verschieden viele Speicherzellen belegen. Ein Befehl wie JMP &001234 würde etwa als Zahlenfolge 83,00,12,34 gespeichert werden, ein Befehl wie ADD X, Y würde dagegen nur durch eine Zahl (zB. 77) repräsentiert. (ADD X, Y benötigt keine weiteren Parameter - die entsprechende Schaltung der ALU ist direkt mit den Registern X und Y verdrahtet.) Beispiel: Disassembly von Notepad.exe.

Der Speicher eines MARS besteht aus Zellen, die jeweils eine komplette Instruktion speichern können. Eventuell unbenutzte Teile werden dabei freigelassen bzw. ignoriert. Eine Speicherzelle des MARS besteht aus sechs "Feldern":

  1. Opcode (Operation Code) - dieser Wert erklärt, was eigentlich getan werden soll, z. B. add, mov, jmp usw.
  2. Opcode Modifier - dieser Wert beschreibt, welche Felder der adressierten Speicherbereiche angesprochen werden sollen. Das kann die gesamte Zelle (.I) sein , oder nur ein bestimmtes Feld (.A, .B) darin. So würde der Befehl mov.i -1, +1 die komplette Instruktion der Zelle darüber (-1) in die Zelle darunter (+1) kopieren, mov.a -1, +1 würde dagegen nur den Wert "A-Number" übertragen.
  3. Adress Mode A - Beschreibt, wie die Zahl des Feldes "A-Value" gemeint ist: Konkreter Wert, Relative Speicheradresse, usw.
  4. A-Number - Der erste "Parameter" eines Befehls. Beschreibt oft, woher die Daten genommen werden sollen ("Source").
  5. Adress Mode B - Beschreibt die Adressierungsart für den Wert von "B-Value".
  6. B-Number - der zweite "Parameter". Häufig eine Speicheradresse, an die das Ergebnis geschrieben werden soll.

Ringförmiger Speicher

Da Redcode nur relative Adressierung erlaubt, kann es vorkommen, daß ein Befehl versucht, eine Zelle zu adressieren, die sich hinter dem Ende des Speichers befinden müßte. In diesem Fall wird einfach am Anfang des Speichers weitergezählt (Genauer gesagt wird jede Adresse moduloExternal Link CORESIZE gerechnet). Das ähnelt einer Addition mit Übertrag, wobei in unserem Fall der Übertrag auf die nächste Stelle einfach verworfen wird. Man kann sich vorstellen, daß sich der Anfang des Speichers gleich hinter dessen Ende befindet, der Speicher ist quasi ringförmig.

Zwei getrennte Task Queues

Im Gegensatz zu einem realen Computer verwendet ein MARS nicht nur eine Task Queue, sondern jeweils eine eigene für jeden Spieler. Der MARS teilt die Rechenzeit auch nicht in Zeitscheiben ein, sondern wechselt nach jedem ausgeführten Befehl zur Queue des anderen Spielers. Auf diese Weise ist sichergestellt, daß beide Programme gleich viel Rechenzeit erhalten, egal wieviele (Unter-)Prozesse ein einzelnes Kampfprogramm starten mag.

Wie die MARS-CPU arbeitet

Alle Prozessoren haben selbst einen vorgegebenen Ablauf von Einzelhandlungen. Dieser Abschnitt erklärt das Mikroprogramm einer MARS-Control-Unit, also die Einzelschritte, in denen ein MARS-Prozessor Core War-Programme zur Ausführung bringt.

Der folgende Vorgang wird für jeden einzelnen Befehl des Kampfprogrammes durchgeführt:

  1. Der oberste Instruction Pointer wird aus der Task Queue des aktuellen Spielers "gezogen" - Er wird in ein Arbeitsregister kopiert und aus der Queue entfernt.
  2. Die Speicherzelle an der Adresse IP wird ausgelesen und komplett in ein weiteres Arbeitsregister ("C-Register") kopiert, sie beinhaltet nun die "Current Instruction".
  3. Der Inhalt des C-Registers wird weiter analysiert. Die absoluten Adressen der Speicherzellen, auf die sich A-Value und B-Value beziehen, werden berechnet. Diese Adressen werden in den Registern "A-Pointer" und "B-Pointer" abgelegt.
  4. Die entsprechenden Speicherzellen werden jeweils in die Register "A-Instruction" und "B-Instruction" kopiert.
  5. Der Opcode im C-Register wird verwendet, um zu entscheiden, wie mit den Daten in A-Instruction und B-Instruction vorgegangen werden soll. Die Veränderungen werden dabei direkt in diesen beiden Registern vorgenommen.
  6. Die Inhalte von A-Instruction und B-Instruction werden wieder in den Hauptspeicher zurückgeschrieben. Dazu werden die Werte der Register A-Pointer und B-Pointer benutzt.
  7. Wenn der Befehl im C-Register ein erlaubter Befehl war, dann wird aktuelle Instruction Pointer inkrementiert (um eins erhöht) und von unten in die aktuelle Task Queue "hineingschoben". War der Befehl ungültig (z. B. eine DAT-Anweisung oder eine Division durch Null), dann wird der IP einfach verworfen - das Programm "stirbt".
  8. Nun wird dieser gesamte Vorgang für den obersten Befehl der anderen Task Queue erneut durchgeführt.
Das Ganze geht im Grunde endlos so weiter. Für das Spiel Core War ist jedoch noch anzumerken, daß der MARS die Simulation beendet, sobald eine der beiden Task Queues leer ist. Daraus kann erkennen, daß ein Kampfprogramm alle Prozesse seines Gegners "töten" muß.

Zusammenfassung

Redcode-Programme dürfen Speicherzellen nicht direkt ansprechen, Quell- und Zieladressen von Speicheroperationen werden immer relativ zur Position der ausgeführten Anweisung angegeben. Der Core-Speicher wird dabei als ringförmig verstanden; Zugriffe über eines der Enden hinaus werden am anderen Ende des Speichers weitergezählt. Das Multitasking ist in einem MARS mit zwei getrennten Task Queues umgesetzt, wobei nach jedem einzelnen Befehl auf die Task Queue des anderen Spielers umgeschaltet wird. Der Kampf ist zu Ende, wenn eine der beiden Task Queues leer wird.

Programmschleifen

Content Management:

μCMS α1.6