2008-12-21 3 views
12

Ich muss einen Assembler für eine CPU-Architektur bauen, die ich gebaut habe. Die Architektur ist ähnlich wie MIPS, aber das ist nicht wichtig.Einen Assembler erstellen

Ich begann mit C#, obwohl C++ besser geeignet wäre. (C# bedeutet schnellere Entwicklungszeit für mich).

Mein einziges Problem ist, dass ich nicht mit einem guten Design für diese Anwendung kommen kann. Ich baue einen 2-Pass Assembler. Ich weiß, was ich in jedem Durchlauf tun muss. \

Ich habe den ersten Durchlauf implementiert, und ich erkannte, dass, wenn ich Linien Assembly-Code auf der gleichen Linie haben ... kein Fehler geworfen wird.Dies bedeutet nur eine Ding schlechte Parsing-Techniken.

Also allmächtige Programmierer, Väter von Assembler erleuchten mich, wie ich fortfahren sollte. Ich muss nur Symbole und Datendeklaration unterstützen. Anweisungen haben eine feste Größe.

Bitte lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.

+0

Ist das eine Hausaufgabenfrage? – ConcernedOfTunbridgeWells

Antwort

11

Ich habe drei oder vier einfache Assembler geschrieben. Ohne einen Parser-Generator zu verwenden, was ich tat, die S-C assembler Modell war, dass ich für 6502 am besten kannte

Um dies zu tun, habe ich eine einfache Syntax - eine Linie, war eine der folgenden Möglichkeiten:

nothing 
[label] [instruction] [comment] 
[label] [directive] [comment] 

A Label war ein Buchstabe gefolgt von einer beliebigen Anzahl von Buchstaben oder Zahlen.

Eine Anweisung war <Leerzeichen> <mnemonic> [Operanden]

Eine Richtlinie war <Leerzeichen> .XX [Operanden]

Ein Kommentar war ein * aus Linie zu beenden.

Operanden abhängig von der Anweisung und der Direktive.

Richtlinien enthalten .EQ zur Definition Konstanten gleichzusetzen

.OR gesetzt Ursprungsadresse von Code

.HS hex Bytefolge

.AS ASCII- Zeichenfolge von Bytes - jeder Begrenzer außer Leerraum - was auch immer begann es für die Ausgabe

.TF Zieldatei beendet.BS n Reserveblockspeicher von n Bytes

Als ich es schrieb, schrieb ich einfache Parser für jede Komponente. Immer wenn ich auf ein Etikett stieß, legte ich es in eine Tabelle mit seiner Zieladresse. Immer wenn ich auf ein Etikett stieß, das ich nicht kannte, markierte ich den Befehl als unvollständig und legte das unbekannte Etikett mit einem Verweis auf den Befehl, der repariert werden musste, an.

Nachdem alle Quellzeilen übergeben worden waren, schaute ich durch die "zu beheben" -Tabelle und versuchte einen Eintrag in der Symboltabelle zu finden, wenn ich das tat, flickte ich die Anweisungen. Wenn nicht, dann war es ein Fehler.

Ich behielt eine Tabelle mit Befehlsnamen und allen gültigen Adressierungsmodi für Operanden. Als ich eine Anweisung bekam, versuchte ich jeden Adressierungsmodus zu analysieren, bis etwas funktionierte.

Angesichts dieser Struktur sollte es einen Tag oder zwei Tage dauern, um das Ganze zu machen.

+0

Vielen Dank für Ihre Antwort. Schau, ich habe folgendes Problem: LOOP1: SCHLEIFE2: LOOP3: ADD R1, R2 JMP LOOP1 Die Art, wie ich den Assembler schrieb es auf die Linie springen, die enthält SCHLEIFE2 und es sollte an die ADD-Anweisung springen. Ich analysiere Zeile für Zeile. Haben Sie den gesamten Code als eine einzige Zeile behandelt? – John

+0

Sie müssen die Adresse des nächsten auszuführenden Befehls als Wert für das Label speichern. Das bedeutet, dass Sie alle Beschriftungen verfolgen, in Ihrem Fall Loop (1,2,3) und wenn Sie zur nächsten tatsächlichen Anweisung kommen (addieren), dann kennen Sie den Wert der Beschriftungen, also gehen Sie zurück und füllen Sie sie im. – Bearddo

4

Schauen Sie sich das Kit Assembler Entwicklung von Randy Hyde Autor des berühmten "The Art of Assembly Language":

The Assembler Developer's Kit

+0

Der Link funktioniert nicht mehr. – NilsB

2

Der erste Durchlauf eines Zwei Pass-Assembler assembliert den Code und setzt Platzhalter für die Symbole (weil Sie nicht wissen, wie groß alles ist, bis Sie den Assembler ausgeführt haben). Der zweite Durchlauf füllt die Adressen aus. Wenn der zusammengefügte Code anschließend mit externen Referenzen verknüpft werden muss, ist dies die Aufgabe des gleichnamigen Linkers.

1

Wenn Sie einen Assembler schreiben wollen, der einfach funktioniert, und eine Hex-Datei ausspuckt, die auf einen Mikrocontroller geladen werden soll, kann es einfach und leicht sein. Ein Teil meiner CIFORTH-Bibliothek ist ein vollständiger Pentium-Assembler, um Inline-Definitionen von etwa 150 Zeilen hinzuzufügen. Es gibt einen Assembler für die 8080 von ein paar Dutzend Zeilen.

Das Prinzip ist erklärt http://home.hccnet.nl/a.w.m.van.der.horst/postitfixup.html. Es entspricht der Anwendung des Blackboard-Entwurfsmusters auf das Problem. Sie beginnen mit der Festlegung der Anweisung und lassen Löcher für alle Operanden. Dann füllen Sie die Löcher aus, wenn Sie auf die Parameter stoßen.
Es gibt eine strikte Trennung zwischen dem generischen Tool und dem Befehlssatz.

Wenn der Assembler, den Sie benötigen, nur für Sie selbst gedacht ist und keine Anforderungen an die Benutzerfreundlichkeit (keine Hausaufgabe) besteht, können Sie eine Beispielimplementierung in http://home.hccnet.nl/a.w.m.van.der.horst/forthassembler.html haben. Wenn Sie Forth nicht mögen, gibt es auch eine Beispielimplementierung in Perl. Wenn der Pentium-Befehlssatz zu viel zu kauen ist, müssen Sie immer noch in der Lage sein, das Prinzip und den generischen Teil zu verstehen. Es wird empfohlen, zuerst die Datei asi8080.frt zu betrachten. Dies ist 389 WOC (Words Of Code, nicht Codezeilen). Ein erfahrener Forther, der mit dem Unterricht vertraut ist, kann einen solchen Assembler an einem Abend austesten. Der Pentium ist eine Schlampe.