My old PDP-11 emulator

This page is about a program that I wrote in 1988 when I studied mathematics and computer science at the University of Hannover.

As a part of our exams during our 2nd year, we often had to write little assembler programs on a PDP-11. Unfortunately, we could use the PDP-11 only for a few hours per week. Therefore I wrote this program that emulated the PDP-11 on my Atari 1040 ST. It was written in C and 68000 assembler code and it provided me and my friends (which also had Atari computers) with a sufficient environment for writing, testing, and deploying our PDP-11 programs at home.

I don't think that anybody will have any use for this program, but you can download it here (source code, binaries, documentation, and the PDP-11 programs from our exams) if you want. You can do with it whatever you want, but if you're really using it, I'd be glad if you could send me a short note.

Following is the documentation that I wrote in 1988:


1. Allgemeines

Das PDP-11-Emulationspaket (hohoho...) besteht aus drei Programmen: Alle Programme sind so konzipiert, daß sie von einer Text-Shell, wie z.B. der DOS-Shell von MichTron, aus gestartet werden sollten. Sie können jedoch auch durch Anlicken vom GEM-Desktop aus aufgerufen werden, wobei dann, wie bei TTP-Programmen üblich, die Parameter über eine Dialog-Box übergeben werden müssen.

Bei keinem der Programme sollte man versuchen Ein- oder Ausgabe umzulenken. Dies wird i.d.R. zu Bomben führen, da MEGAMAX-C nicht die Redirection-Mechanismen des GEMDOS benutzt. Es gibt allerdings auch keinen Grund für die Anwendung der I/O-Redirection.

Alle drei Programme erwarten als Parameter Filenamen. Dabei gelten folgende Konventionen: Source-Files für den Assembler enden auf '.S', der Assembler produziert Objektfiles mit dem Suffix '.O', und der Linker erzeugt Programme für den Interpreter, deren Namen auf '.PDP' enden.

Bei der Angabe dieser Filenamen in der Kommandozeile (also beim Start des jeweiligen Programms) dürfen diese Endungen NICHT mit angegeben werden. Um also z.B. den Source-Text 'D:\PRGS.PDP\HANOI.S' zu assemblieren, muß man 'ASS D:\PRGS.PDP\HANOI' eingeben.

Einzige Ausnahme von dieser Regel ist der (optionale) zweite Filename beim Assembler (s.u.).

2. Der Assembler

Der Assembler wird aufgerufen mit
  ASS file1 [file2]
Der Parameter <file1> muß angegeben werden und ist der Name (ohne Suffix, s.o.) eines Source-Files, das assembliert werden soll. Der Assembler erzeugt, falls keine Fehler auftreten, ein Objektfile mit den gleichen Namen und dem Suffix '.O'.

Wird der Parameter <file2> angegeben, erzeugt der Assembler ein Listing und eine Symboltabelle und schreibt beide auf dieses File. Für <file2> können insbesondere auch 'CON:' (Bildschirm) und 'PRT:' (Drucker) angegeben werden.

Der Assembler versteht im wesentlichen die Sprache MACRO11, in dem Umfang, der im Umdruck 'PDP-11 Maschinensprache und Assemblersprache MACRO11' des Instituts für Informatik beschrieben wird. Eine Beschreibung der Abweichungen folgt:

3. Der Linker

Der Linker wird gestartet mit
  LINK file1 { filen}
Die Files (durch Spaces, nicht durch Kommata getrennt) werden in der angegebenen Reihenfolge zusammengebunden. Das vom Interpreter ausführbare Programm erhält den Namen von <file1> mit dem Suffix '.PDP'. Die Startadresse wird ebenfalls von <file1> übernommen.

4. Der Debugger

Der Debugger wird aufgerufen durch
  DEBUG file
Das angegebene PDP11-Programm wird geladen und man erhält den Prompt '>', d.h., man befindet sich in der Kommando-Ebene. Der Debugger versteht die folgenden Ein-Buchstaben-Kommandos:
  q - Verlassen des Debuggers,
  r - Anzeige des Registersatzes R0 bis R7 sowie der condition code bits,
  p - Rücksetzen des PC (R7) auf seinen Startwert,
  s - Einzelschrittausführung und
  g - kontinuierliche Ausführung.
Die Einzelschrittausführung beginnt immer beim momentan PC-(R7-)Stand. Beim Start von DEBUG ist dies die og. Start-Adresse. In disassemblierter Form wird der nächste auszuführende Befehl angezeigt. Nach Drücken einer beliebigen Taste (außer ESC oder CTRL-C) wird dieser Befehl ausgeführt. Falls er irgendwelche Teile des Speichers modifiziert hat, werden diese angezeigt. Danach werden alle Register angezeigt und der Zyklus beginnt wieder von vorne. Mit ESC verläßt man diese Einzelschrittabarbeitung.

Die kontinuierliche Ausführung beginnt ebenfalls beim PC-Stand. Diese Form der Ausführung kann nur unterbrochen werden durch das Drücken der ESC-Taste, einen Fehler oder den HALT-Befehl, der deshalb auch immer am Ende eines Programmes stehen sollte. Außerdem wird in diesem Modus (jedoch nicht im Einzelschrittmodus!) das Teletype emuliert (siehe Gill, S. 12ff.), d.h., man kann den Hardware-Registersatz 177560 (keyboard status) bis 177566 (printer data) im Zusammenhang mit Tastatur und Bildschirm benutzen.

Desweiteren gibt es einige Befehle, denen man VOR dem Befehlsbuchstaben einen Speicherbereich angibt, und zwar in der Form

  [start][.end][c]
<start> und <.end> sind optional. Wird <start> nicht angegeben, wird die letzte Endadresse angenommen. Wird <.end> nicht angegeben, wird <end>=<start> gesetzt. <c> kann sein:
  l - disassembliert den Speicherbereich oder
  c - zeigt den Bereich byteweise an.
Wird kein Buchstabe angegeben, so wird der Bereich wortweise angezeigt. Beispiel:
  3.10c          { zeigt die Bytes 3 bis 10 an }
  .14c           { zeigt die Bytes 11 bis 14 an }
  c              { zeigt Byte 15 an }
  .20            { zeigt die Words 16 bis 20 an }
Mit dem Befehl
  [start]: [w1] [w2] ...
kann man den Speicher ab Adresse <start> wortweise ändern. Ebenso ändert
  r: [w0] [w1] ... [w7]
den Registersatz ab R0 bis (natürlich) höchstens R7. Register, deren Inhalt nicht geändert werden soll, werden durch '~' markiert. Beispiel:
  r: 12 ~ 23     { R0:=12, R2:=23, R1 bleibt unverändert }.
Um lediglich den PC (R7) zu ändern, kann man statt
  r: ~ ~ ~ ~ ~ ~ ~ [w]
auch einfach
  p: [w]
eingeben.

Allgemein ist noch zu sagen, daß der Debugger keinen besonders pfiffigen Parser hat. Das hat unter anderem zur Folge, daß jede Eingabezeile nur soweit gelesen wird, bis der Debugger meint, ein korrektes Kommando verstanden zu haben. Außerdem können falsch plazierte Leerzeichen durchaus verwirrend sein. Ein letztes Beispiel:

  100.120 c      { wird wegen des Leerzeichens zwischen 120 und c nicht verstanden }
  r: 1,3         { R0:=1, danach Abbruch wegen des Kommas }
Zum Schluß sei darauf hingewiesen, daß alle Register (also auch der Stack-Pointer) am Anfang mit 0 initialisiert werden. Alle Programme, die den Stack benutzen (zum Beispiel tun dies auch JSR und RTS), müssen sich also einen eigenen Stack-Bereich anlegen (z.B. mit .BLKW), da ansonsten der SP nach dem ersten Push auf 177776, also das Condition Register, zeigt.

$Header: /usr/local/cvsrep/weitz.de/pdp.html,v 1.4 2004/12/25 21:26:02 edi Exp $

BACK TO MY HOMEPAGE