Back to Diane's HomePage
Diane's PDP-11 Page
English version
von
Diane Neisius
Aktualisiert: 29. Oktober 2009
Inhalt
Warum eine DEC PDP-11/03? (1 Bild)
Alte Hardware flottgemacht (3 Bilder)
Minimalsystem testen (1 Bild)
Alte Floppy emuliert (1 Bild)
Ein Betriebssystem besorgen (1 Screenshot)
Links
WIRD FORTGESETZT!
Warum eine DEC PDP-11/03?
Computer-Oldies besitze ich eine ganze Reihe. Eigentlich sammele ich 68000er der 1980er Jahre, aber es gibt soviele Seiten über Amigas, Atari STs,
Sinclair QLs und Apple Macs, daß ich nicht auch noch eine zu machen brauche. Immerhin hat die Architektur der PDP-11 die Entwicklung der
MC68000- Prozessoren so massiv beeinflußt, daß eine PDP durchaus Ehrenmitglied in meinem "Club 68k" werden darf.
Das erste Mal begnegnet bin ich einer PDP-11 zu Beginn meines Studiums. Programmierpraktika wurden auf der 11/34 des Institutes durchgeführt,
hier hatte ich zuerst Berührung mit Unix, Assembler und C. Das ist wahrscheinlich vielen Studenten meiner Altersgruppe so gegangen und vermutlich
mit dafür verantwortlich, daß Unix-Clones wie Linux sich bei Leuten wie mir so großer Beliebtheit erfreuen.
Leider sind PDPs heutzutage nicht mehr so einfach aufzutreiben wie Amigas oder Ataris. Sind ja auch schon etwas älter. Immerhin hat frau bei der
PDP-11/03 noch gewisse Chancen, die ist ab Mitte der 1970er massiv in Maschinensteuerungen verbaut worden. Heutzutage würde so etwas
als "Embedded Controler" bezeichnet werden. 11/03s sind übrigens in der Industrie zum Teil heute noch, nach 30 Jahren, in besagten Maschinensteuerungen
im Einsatz (ob die modernen Controler auch so lange durchhalten?).
Darin liegt die Chance, an Teile zu kommen - sie tauchen gelegentlich als Elektronikschrott auf, und wer bereit ist, etwas tiefer in die Tasche zu greifen,
ergattert die eine oder andere Platine noch bei einem der Händler, die Gebrauchtes als Ersatzteile einlagern.
Wem das zu teuer ist oder wer sich nicht den Griff zum Lötkolben zutraut - dann gibt es noch den SIMH Emulator (siehe Links), der unter vielen berühmten Computer-Oldies auch die PDP-11 in zahlreichen Varianten emuliert. Mit SIMH habe ich so aus Spaß wieder ein Unix V5 auf einer emulierten 11/45 und ein RT-11 V4 auf einer emulierten 11/03 mit RX01 Floppy zum Laufen bekommen.
|
Bild 1 - Mein erstes Stück echte PDP-11 Hardware war dieser Microcode-ROM des LSI-11 Chipsatzes. Er ist zugleich das älteste, denn das Herstellungsdatum ist
Mitte 1977. Stammt aus dem Elektronik-Schrotthandel - und funktioniert noch trotz einer kleinen Macke im Keramikgehäuse.
|
Technisch ist die ab 1975 gebaute PDP-11/03 übrigens deswegen interessanter als neuere Modelle, weil sie vom logischen Aufbau stärker als andere
der ersten PDP-11, der 11/20 von 1970, gleicht. Der Prozessor ist zwar nicht mehr aus diskreten Bausteinen aufgebaut, sondern besteht aus
4 oder 5 hochintegrierten Chips, aber das Fehlen der MMU, die Begrenzung des Adreßraumes auf 16 Bit und die Floating-Point Befehlsatzerweiterungen
des Hauptprozessors statt eines zusätzlichen FP-Coprozessors sprechen eine deutliche Sprache.
Über die kleine 11/03 gibt es nicht soviele Informationen im Web. Eine Menge Fans der PDP-11 haben einen der großen alten Klassiker, eine PDP-11/44
oder /45 vor dem Schrott gerettet und betreiben sie sowie ihre Webseiten mit großem Enthusiasmus (siehe Links). Auch die eine oder andere 11/23 ist
in so mancher Privatsammlung zu finden. Die PDP-11/03 taucht heutzutage, trotz ihrer großen Verbreitung in der Industrie, nicht so häufig auf. Deswegen
halte ich meine Erfahrungen bei der Restaurierung auf dieser Seite fest.
Alte Hardware flottgemacht
Mein ursprünglicher Plan war, den Elektronik- Schrotthandel regelmäßig nach Chips des LSI-11 Chipsatzes zu durchkämmen, um so einen vollständigen
Satz zusammenzubekommen. Da Adreß- und Datenbus gemultiplext sind, hätte sich mit ein paar meiner alten SRAM-Chips auf diese Weise vielleicht
ein ähnlich primitiver Rechner wie die auf dem Intel 8008 basierende Mark-8 (Bauanleitung von 1971) zusammenlöten lassen. Bevor ich soweit kam,
entdeckte ich die Qbus-Module und die Backplane, die ich jetzt benutze, habe aber trotzdem weitergesammelt - und verfüge jetzt über vier komplette
Sätze LSI-11 Bausteine, die alle noch funktionieren! Nachfolgend eine kleine Tabelle, die einen Vergleich der Typennummern vornimmt (alle aufgeführten
in meinem Besitz sind austauschbar):
| LSI-11 Chip | DEC Nr. | Western Digital Nr. | Prozessorfunktionen |
| 1611H Data Chip | 21-15579-00, 21-16890-00 | AB1611-A00 | interner Datenbus, ALU, Registersatz |
| 2007C Control Chip | 23-002C4-00, 23-003C4-00 | AB1621-A07 | State Machine, Befehlsdecoder |
| 3010D Microm 1 | 23-001B5-00, 23-008B5-00 | AC1631-A10 | Microcode für Standard- Befehlssatz Teil 1 |
| 3007D Microm 2 | 23-002B5-00, 23-007B5-00 | AC1631-A07 | Microcode für Standard- Befehlssatz Teil 2 |
| 3015D optional EIS/FIS | 23-003B5-00, 23-009B5-00 | AC1631-A15 | optionaler Microcode für "Extended Instruction Set"-
und "Floating-point Instruction Set"- Befehle |
|
Bild 2 -
Dies sind die Qbus-Module, die ich als funktionstüchtige Einzelteile ergattert habe. Von links nach rechts:
M7270 LSI-11/2 CPU (der optionale EIS/FIS- Microm fehlte ursprünglich, ist hier aber schon eingesetzt),
M8044 MSV11-D 64 kByte RAM,
M8017 DLV11-E serielles Interface; später gesellte sich dann noch ein
M7946 RXV11 Floppy Interface hinzu (ganz rechts).
Vorn die Backplane, ein H9281-BA mit vier doppelten Steckplätzen. An den Schraubanschlüssen ist hier schon ein PC- Netzteil- kompatibler Stecker angebracht.
|
Der Zusammenbau der Platinen ist dank ihrer Modularität nicht problematisch. Grundregel Nummer 1: die CPU steckt immer am Anfang der Backplane (so daß die
Chips vorne sichtbar sind, bei meiner Backplane ist das die Seite mit den Stromanschlüssen). Grundregel Nummer 2: es darf keine Lücken zwischen den Platinen
geben. Für den ersten Test habe ich also von vorn nach hinten CPU, RAM, serielle Schnittstelle eingesteckt und den letzten Steckplatz freigelassen.
Ein bißchen muß frau noch basteln, ehe diese absolute Minimal- Konfiguration einer PDP-11 Lebenszeichen von sich gibt. Die Stromversorgung kommt, wie schon
erwähnt, aus einem alten PC-Netzteil. Die LSI-11 CPU möchte allerdings einen bestimmten Einschaltzyklus haben, deswegen ist noch eine kleine externe Platine
notwendig, die auf den 10-pinnigen Anschluß der Backplane gesteckt werden muß. Der Schaltplan stammt in seinen Grundzügen aus dem PDP-11/03 Manual von DEC
[1]. Dort ist auch die Belegung des Anschlusses an der Backplane zu entnehmen.
Bild 3 -
Meine kleine Kontrollplatine mit je drei Schaltern und Anzeigedioden. Absolutes Minimum wären ein Schalter, der "HALT" auf Masse legt, und ein (entprellter!)
Schalter, der "DC OK" auf logisch High legt. Der dritte Schalter auf der Platine ist optional für die Line Time Clock. Die LEDs sind eher Luxus, meine
zeigen Netzteil- Power, das "SRUN"- Signal und "HALT" an. Die TTL-Chips besorgen das Entprellen der Schalter.
|
|
|
Bild 4 -
Noch eine Kleinigkeit fehlt, damit die 11/03 mit mir kommunizieren kann: der proprietäre DEC- Stecker an der Platine muß in einen seriellen Standard- Anschluß
überführt werden. Das besorgt dieses kleine Patchboard. Es werden nur drei Leitungen gebraucht, RxD, TxD und Masse. Ich habe sie auf einen Anschluß geführt,
wie er auch auf PC-Motherboards verwendet wird, um ein Standardkabel verwenden zu können.
|
Die Konfiguration der Seriellschnittstelle ist nicht ganz unproblematisch, sofern man nicht eine der alten erwischt hat, die schon als "console terminal"
vorkonfiguriert sind. Letztere muß zwingend den I/O-Port an der (oktalen) Adresse 177560 haben und den Interrupt- Vektor 60 benutzen. Auf den meisten Platinen
läßt sich das über Jumper einstellen, die verschiedenen Platinenrevisionen stimmen aber meist nicht überein - hier ist Detektivarbeit im Internet gefordert,
um das passende Manual herunterzuladen. Meine Seriellschnittstelle zum Beispiel war eine neuere Revision namens DLVE1, die in der PDP-11/23 und manchen VAXen
mit Qbus- Schnittstelle als Modem eingesetzt wurde, logisch aber mit der DLV11-E identisch ist. Es dauerte eine Weile, ehe ich dahinterkam.
Zusätzliche Schwierigkeiten machten die "Wire-Wrap"- Jumper - Werkzeug dafür ist heutzutage nicht mehr aufzutreiben. Glücklicherweise sind die Pins aber im
Rastermaß angeordnet, so daß sich aus einer normalen Sockelleiste Steckjumper geeigneter Breite improvisieren lassen.
Wenn frau schon mal am Jumpern ist, nicht vergessen: heutzutage ist der quasi-Standard für serielle Schnittstellen (die an PCs sind fast immer so
voreingestellt): 9600 Baud, 8 Bit, keine Parität, 1 Stoppbit, kein Handshaking.
Minimalsystem testen
Zum ersten Test sollte natürlich die Spannungsversorgung sichergestellt sein - kein Problem, falls ein modernes PC-Netzteil verwendet wird. Ältere Originale
sollten dagegen geprüft werden. Weiterhin bedarf es eines zweiten (moderneren) Rechners, auf dem ein Terminal- Emulator läuft - kaum jemand von uns dürfte wohl
noch ein echtes altes Terminal besitzen. Natürlich muß der Rechner mit dem Terminal- Emulator über ein Nullmodem- Kabel mit der 11/03 verbunden sein.
Vor dem Einschalten des Netzteiles werden beide Schalter an der Kontrollplatine auf "offen/aus" gestellt. Netzteil anschalten, dann "HALT" schließen und dann
"DC OK" einschalten. Als Antwort sollte der Terminal- Emulator etwas wie
000000
@
ausgeben. Wir befinden uns jetzt im sogenannten ODT (Octal Debugging Technique), dem Hardware- Debugger, der im Microcode der CPU eingebaut ist. Er ist
gewissermaßen eine moderne Variante der Tasten und Lampen, mit denen sich die alten Großrechner der 1960er und 1970er Jahre auf ihrem Frontpanel schmückten.
Es ist damit möglich, Speicherstellen und Register zu testen bzw. zu ändern, kurze Programmcodes einzutippen oder auch Urladeprogramme einzulesen (für
diejenigen, die noch einen Lochstreifenleser auftreiben können). Der Prozessor selbst arbeitet in diesem Moment kein Programm ab, d.h. sein Programmzähler
steht. Modernere Computer besitzen einen solchen Modus nicht mehr.
ODT ist etwas kryptisch zu bedienen. Er wartet nicht, bis die "Return"- Taste eine Zeile abschließt, sondern beäugt jedes getippte Zeichen mißtrauisch.
Jede Ziffer außerhalb des oktalen Bereiches 0-7 wird mit einem "?" als Fehlermeldung quittiert. Um Speicherstellen anzusehen und zu ändern, tippt frau die
oktale Adresse ein, gefolgt von "/". ODT gibt dann in derselben Zeile den Inhalt der Speicherzelle aus und wartet auf die Eingabe weiterer Ziffern - den
neuen Wert der Speicherzelle. Wird die Eingabe mit "Return" abgeschlossen, landet frau wieder bei dem "@"-Prompt. Ein "Linefeed" (moderne Tastaturen
besitzen dafür keine eigene Taste mehr, aber "Control-j" tut's auch) hingegen zeigt gleich das darauffolgende Speicherwort an. Werden keine
Ziffern eingegeben, bleibt der alte Wert erhalten. Statt oktaler Ziffer kann mit "R0" bis "R7" auch auf die Register des Prozessors zugegriffen werden.
Ein eingetipptes oktales Programm kann mit der Eingabe der Startadresse gefolgt von "G" (das muß ein großes g sein) gestartet werden. Zuvor sollte allerdings
der "HALT"- Schalter geöffnet werden.
|
Bild 4 -
Das erste Lebenszeichen meiner PDP-11/03 links hinten im Bild. Die LSI-11-Chips auf der Platine im ersten Steckplatz sind deutlich zu erkennen. Hinter dem
Rahmen der Backplane lugt das PC-Netzteil hervor. Im Vordergrund der Notebook meiner Freundin, auf dem der Terminal- Emulator läuft.
Als ich diesen Test durchführte, war der optionale FIS/EIS- Microm noch nicht eingesetzt.
|
Die Webseite "Hints on testing a dead PDP-11" (siehe Links) gibt nützliche Tips, wie die Funktionen von Prozessor und Speicher getestet werden können.
Das erste "Programm", daß ich ausprobiert habe, war oktal 5007 an Speicherstelle 0. Es ist ein "Clear PC" Befehl, d.h. der Programzähler wird auf 0 gesetzt,
was eine Endlosschleife ergibt. Ein 777 (Branch -2) tut das Gleiche, kann aber auf jeder Stelle im Speicher platziert werden.
Wenn's komplexer als diese einfachen Ein-Wort- Programme wird, sollte allerdings ein Teil Initialisierungsarbeit erfolgen - unter Umständen gibt es sonst
sehr irreführende Programmabbrüche. Bestimmte Fehlerbedingungen führen Traps (bestimmte festgelegte Interrupts) aus, deren Vektoren schon initialisiert
sein sollten. Gleiches gilt für den Stackpointer. Z.B. wird beim Versuch, einen nicht existenten Befehlscode auszuführen, ein "Illegal Opcode" initiiert -
Programmzähler und Statuswort werden auf dem Stack gesichert, und der Prozessor holt sich den neuen Programmzähler von Adresse 10. Falls der Stackpointer
aber uninitialisiert ist und irgendwo in einen nicht existenten Speicherbereich zeigt, löst der Versuch, PC und PS zu sichern aber vorher einen "Bus Error"
aus - was sehr hinderlich bei der Fehlersuche sein kann.
Der Prozessor wird stets dann stoppen, wenn er den Befehlscode 0 (Halt) einliest. Normalerweise ist das der letzte Befehl eines kurzen oktalen
Programmes, mit dem die Kontrolle wieder an ODT übergeben wird. Leere uninitialisierte Speicherzellen enthalten oft genug jedoch auch Nullen - ein Sprung
ins Nirgendwo, beispielsweise durch einen uninitialisierten Trapvektor, wird also auch zu einem Stop führen. (Verlassen würde ich mich da aber nicht drauf!) Mein Trick ist nun, den Programmzähler eines
Traps auf die Adresse des Traps minus 2 zu setzen und in diese 0 zu laden. ODT gibt dann genau die Adresse des Traps aus, der aufgetreten ist.
Das funktioniert jedoch nur dann, wenn der Stack in einem existenten Speicherbereich liegt. Also: SP (das ist R6) zum Beispiel auf 700 setzen. Für kurze
Programme reicht das meistens. Ab 1000 oktal können dann Programme eingetippt werden (der Stack wächst nach unten, d.h. zu kleineren Adressen hin).
Folglich ist das also meine Startkonfiguration:
000000 / 000000
000002 / 000000
000004 / 000002 <--- bus error
000006 / 000000
000010 / 000006 <--- illegal instruction
000012 / 000000
000014 / 000012 <--- T bit trap
und dazu kommt noch für Floating point:
000242 / 000000
000244 / 000242
und die Initialisierung des SP:
R6 / 000700
und damit kann es dann losgehen, zum Beispiel mit einem Speichertest- Programm (nach dem Abbruch mit einem Bus Error Trap steht die Adresse der ersten
nicht mehr existierenden Speicherzelle plus 2 in R0 und kann mit "R0 /" ausgelesen werden):
001000 / 005000
001002 / 005720
001004 / 000776
001006 / 000000
Auf ähnliche Weise können die FIS/EIS- Erweiterungen getestet werden. Falls der Microm nicht vorhanden bzw. kaputt ist, werden die entsprechenden
Befehlscodes einen "Illegal Instruction" oder "Floating Point" Trap auslösen. Sonst läuft das Programm weiter, wie bei diesem FIS-Befehl "Fadd (R1)" in einer Endlosschleife:
001000 / 075001
001002 / 000776
Eine Endlosschleife kann übrigens jederzeit durch Schließen des "HALT"- Schalters abgebrochen werden. Bei obigem Beispiel ist es außerdem wichtig,
R1 vorher auf irgendeinen Wert im Speicher zeigen zu lassen, etwa mit "R1 / 002000". Sonst gibt es wieder mal einen irreführenden Bus Error.
Dasselbe geht auch mit einem EIS-Befehl, zum Beispiel 070202 (Mul R2,R2), und dafür braucht R2 nicht mal mit irgendeinem sinnvollen Wert geladen sein.
Alte Floppy emuliert
Eine Reihe von Gründen hat mich bewogen, nicht mehr auf die Suche nach einem echten alten Diskettenlaufwerk zu suchen.
Zum einen mögen ja 30 Jahre alte Chips noch gut funktionieren, was sie in der CPU und dem Speicher auch tun, 30 Jahre alte
Mechanik ist mit Sicherheit schon etwas ausgenudelt. Zum anderen bedingt ein altes 8-Zoll- Laufwerk dann eben auch eine
passende 8-Zoll Systemdiskette. Die in lauffähigem Zustand aufzutreiben ist mit Sicherheit nicht so einfach wie sich Images
aus dem Internet zu ziehen. Beispielsweise ist die Erstellung eines bootfähigen Diskettenimages unter RT-11 auf dem SIMH-
Emulator eine ziemlich einfache Fingerübung. Und nicht zuletzt hab ich ja schließlich auch kein echtes VT100- Terminal mehr
hier rumstehen, sondern benutze einen Terminal- Emulator auf dem PC.
Eine Emulation des RX01- Diskettenlaufwerks für den PC mußte also her, und für diesen Zweck wird frau im Internet mit dem freien
"rxm" Emulator von Charles Dickman fündig [siehe unter "Links"]. Rxm emuliert ein RX01/RX02- Laufwerk über den Parallelport des PC, dieser
wird über eine kleine Adapterplatine mit dem Ausgang der Floppy-Interface- Karte in der PDP verbunden. Da rxm direkt auf
die Hardwareadresse des Ports zugreift, muß der PC aber noch über eine "echte" Parallelschnittstelle verfügen - ein USB-zu-
Parallel-Kabel tut's leider nicht.
Ich habe mir den Schaltplan heruntergeladen und mit ein paar kleinen Änderungen auf einer Lochrasterplatine zusammengelötet.
Die Änderungen betreffen die NAND-Gatter, ich habe die 74LS38 bzw. 74LS00 durch einen einzelnen 74LS04 Hex-Inverter-Chip
ersetzt (hatte ich gerade passend in meiner Bastelkiste). Die 180-Ohm- Widerstände habe ich alle weggelassen, ebenso einen
Teil der 390-Ohm- Pulldown- Widerstände. Nur an den Leitungen RX_INIT, RX_RUN, RX_DATA, RX_DONE, RX_TRANSFER_REQUEST und
RX_SHIFT habe ich sie belassen (aufgrund des "debuggings", das ich im folgenden noch beschreibe). Auf der Seite der Floppy-
Karte in der 11/03 habe ich wieder in kleines Patchboard (ähnlich dem an der Seriell-Karte) eingefügt und dieses über ein
vorkonfektioniertes 10-poliges Kabel mit dem Adapter verbunden.
Rxm habe ich mit gcc aus dem Source unter Debian Linux 5.0 übersetzt. Das Makefile zickte etwas, aber es war sehr einfach,
die passende Zeile einfach herauszukopieren und an der Shell einzugeben. Da direkte Hardware-Zugriffe unter Linux für normale
User verboten sind, muß das Binary als "root" gestartet werden. Praktischerweise wird das über Setuid erledigt (als root
einloggen, "chown root rxm" und "chmod 4755 rxm" eingeben, und schon klappt's auch von dem normaler User-Account aus).
Bild 5 - die Adapter- Platine für den rxm- Emulator zwischen PDP-11 und PC gestöpselt. Die Backplane der 11/03 ist hier von der Seite zu sehen.
Zwischenzeitlich hab ich mir auch ein etwas kleineres Netzteil besorgt (100 Watt reichen aus), das später in das Gehäuse paßt. Es geht im Kabelgewirr unter dem Adapter etwas unter.
|
|
Für die ersten Tests startet frau rxm am besten im höchsten Verbose-Modus mit "rxm -vvv -t RX01". Leere Disk-Images werden
automatisch erzeugt.
Am PDP-Terminal wurde zuerst das Vorhandensein der beiden Register des RXV11-Floppy- Interfaces getestet. Das Kontroll-
Register RXCS findet sich an der Adresse (oktal) 177170, das Datenregister RXDB an Adresse 177172.
Allererster rxm-Test war ein Init-Kommando. Dazu schreibt frau oktal 40000 in das RXCS, was auf der PC-Seite mit der Ausgabe
"RX_INIT request recieved" quittiert wird. An diesem Punkt funktionierte also wenigstens das Puffer- Flipflop auf der Platine schon
mal. Ein erneutes Auslesen des RXCS lieferte oktal 000040, das "done"-Bit war also ordnungsgemäß gesetzt.
Nächster Test: ein Funktionskommando. In RXCS wurde oktal 11 geschrieben (ein "NOP"). Das sollte auf dem PC eine "RX_RUN request recieved" Meldung
und die Angabe des Funktionscodes, sowie ob es sich um einen 8-Bit oder 12-Bit Code handelt,
erzeugen (RXV11 kann nur 8-Bit-Codes). Bei mir klappte das zuerst nicht und führte dazu, daß ich nach und nach die o.a.
Widerstände aus- und umgelötet habe. Falls alles klappt, sollte ein erneutes Auslesen des RXCS wieder 000040 "done" liefern.
Auf diese Weise lassen sich die Tests stückweise steigern. Ein Funktionscode 7 (das ist ein "read sector") in RXCS geschrieben
sollte einen "transfer request" auslösen (RXCS zeigt beim Auslesen oktal 000200). Nun kann in RXDB die Sektornummer (1-26
dezimal) geschrieben werden, letzeres wiederholt sich noch einmal für die Tracknummer (0-76).
Auf diese Weise können alle die Funktionscodes von Hand getestet werden, die im Manual [6,7] beschrieben sind. Bei einigen ist
das etwas mühselig, weil der Inhalt des Sektor-Puffers Byte für Byte durch RXDB geschleust wird, es lassen sich auf diese Weise
aber schon Testmuster auf dem Disk-Image speichern. (Letzeres läßt sich mit dem "od" Kommando von der Shell aus überprüfen.)
Der letzte Test, den ich gemacht habe, war den Bootcode in die 11/03 einzutippen, der in [7] und anderen Manuals abgedruckt ist.
Erwartungsgemäß wurde der erste Sektor nach Adresse 0 geladen, und dort blieb der Prozessor stehen, weil ja nur 128 Nullen
von dem leeren Disk-Image geladen worden waren.
Immerhin war damit die Funktionstüchtigkeit des Emulators erwiesen.
Ein Betriebssystem besorgen
Einführung
Wie ich oben schon erinnert habe, war in den 1980ern eine PDP-11 mit Unix drauf so ziemlich der Heilige
Gral des Hackers. Nun wäre das rechtlich kein Problem, da die alten Unix-Varianten heute für nicht-
kommerzielle Nutzung frei sind, allerdings möchte Unix eine MMU haben - die 11/03 hat leider keine.
Also kein Unix.
Die DEC-eigenen Betriebssysteme wie RT-11, RSX-11 etc., die auf der 11/03 auch gelaufen sind, gehören
seit 1999 einer Firma namens Mentec. Diese hat zwar auch eine Freigabe für nichtkommerzielle Nutzung
erteilt, allerdings streng genommen nur für den SIMH Simulator. Da Mentec seit 2006 nicht mehr zu
existieren scheint, ist auch niemand mehr da, den ich fragen könnte. Schade, denn die RX01- Disk- Images
lassen sich problemlos zwischen rxm Emulator und SIMH austauschen, wenn sie mit rxm in der richtigen
Größe von 256256 Bytes erzeugt worden sind. Ich bin mir sicher, daß ein mit SIMH und RT-11 erzeugtes
Image einer bootfähigen Diskette auch auf meiner 11/03 booten würde. Nur legal wäre das leider nicht.
Xinu
Also weiter auf die Suche nach freien Betriebssystemen. Unix wurde in den 1980ern einige Male geklont,
als AT&T die Verwendung des Source-Codes für Ausbildungszwecke untersagte. GNU, Minix, Xinu und
letztlich Linux sind auf diese Weise entstanden. Von diesen wollen alle außer Xinu auch eine MMU haben,
fallen also wiederum aus.
Xinu ist detailiert im Buch von Comer [9] beschrieben, das nebenbei bemerkt eines der besten Bücher
über Betriebssysteme ist, das ich kenne. Es wurde in der Urfassung für die PDP-11/03 geschrieben.
Xinu selbst ist eher als Embedded-Betriebssystem realisiert, für File-Zugriffe hat es umfangreiche
Netzwerk- Unterstützung. Letztere brauche ich nicht, weil ich keinen DEQNA- Adapter für meine 11 habe.
Dafür hab ich ein lokal emuliertes RX01- Laufwerk, das zunächst nicht unterstützt wird. Kann aber nicht
so schwer sein, dafür Treiber zu schreiben. Schließlich sind Übungsaufgaben dieser Art der ursprüngliche
Zweck von Xinu.
In der letzten Version gehört auch eine Shell zu Xinu, die alle notwendigen Befehle für ein etwas
User- Spielen schon enthält. Nebenbei bemerkt, ein bißchen erinnert mich das an die Zeit vor den
Live-Linux- CDs, an meine Versuche mit einem Minimal- Linux, das von Diskette zu booten
war und nur aus statisch compiliertem Kernel und der 'sash' Standalone-Shell bestand (beides zusammen
paßte gerade so auf eine normale PC-Diskette).
Aber
schließlich will ich ja auch nicht ernsthaft arbeiten mit meiner alten PDP-11, sondern nur ab und zu
mal ein kleines Programm drauf laufen lassen. Da ist so ein halbes Embedded-System mit Crosscompiler
auf dem Host schon ganz ok.
Der Xinu source tree war ursprünglich auch nur für die PDP-11 erhältlich und enthielt ein SDK in Form
von Crosscompiler etc. (das ist heute anders), dieser Zweig wird heute aber nicht mehr gepflegt.
Meine ersten Versuche gingen daher dahin, den Crosscompiler zu reanimieren. Da die alte SDK von Xinu
auf einem VAX-Host unter 4.3 BSD laufen sollte, war das aussichtslos - die Unterschiede zu Linux sind
dann bei allen gemeinsamen Wurzeln doch zu groß. Gerade einmal das 'nm11' wollte kompilieren, ob es
auch lief, weiß ich nicht einmal.
GCC toolchain
Aber eigentlich brauchte ich ja auch nur die Sourcen von Xinu selbst. Einen Crosscompiler beschaffen
ist auch aus anderen Quellen möglich. Der GNU C compiler kann z.B. als Crosscompiler gebaut werden,
auch wenn das so seine Tücken hat. Es gibt dazu inzwischen aber eine Reihe sehr hilfreicher
Webseiten, siehe Links.
Ich habe binutils-2.19.1 und gcc-core-4.3.3 verwendet. Beide mögen es nicht, wenn sie in ihren
Quellverzeichnissen gebaut werden, also habe ich für jedes Paket ein Arbeitsverzeichnis erstellt und
die Quellen dort in je ein Unterverzeichnis src/ entpackt. Binutils baut dann mit:
src/configure --target=pdp11-dec-bsd --disable-nls
make all
make install
(letzteres natürlich mit root-Rechten). Für gcc mußten auf meiner Debian-5.0- Installation noch die
Bibliotheken libgmp und libmpfr mitsamt devel-Dateien nachinstalliert werden. Libmpfr-dev ist nicht auf
der Debian-DVD dabei, die passende Version kann aber bei debian.org heruntergelagen werden.
Gcc baut dann wieder (in seinem eigen Arbeitsverzeichnis natürlich) mit:
src/configure --target=pdp11-dec-bsd --disable-nls --without-headers --enable-languages=c
make all-gcc
make install-gcc
(letzteres wieder als root). Ein kleineres Problem gibt es dabei mit der libgcc, die nicht bauen will
(mit "make all-libgcc").
Das scheint ein Problem der Assembler-Ausgabe von gcc zu sein, defaultmäßig ist nämlich unix-asm
eingestellt, der GNU Assembler aus den Binutils will aber dec-asm haben. Nennen Sie es Bug oder
Feature, ich wollte jedenfalls nicht auch noch den gcc patchen (ist mir nun wirklich zu "nerdy"),
sondern hab mir ohne libgcc geholfen (s.u.) und rufe gcc halt immer mit "-mdec-asm" auf, dann gibt es
keine Probleme.
{Nachsatz: leider mußte ich doch noch patchen, denn gcc übersetzt das logische UND "&" fälschlich in den
Assemblerbefehl "BIC" (vgl. [8])... den Patch und eine Anleitung finden Sie hier. Libgcc baut damit aber leider immer noch nicht.}
Alter Code und moderner Compiler
Die Sache mit der libgcc ist übrigens nicht so schlimm, wie es sich anhört. Jedenfalls nicht, wenn der
Code für eine PDP-11 mit EIS/FIS- Erweiterung übersetzt wird, gcc gibt dafür nämlich sehr viel schon
als nativen Code aus. Da der Xinu-Kernel ja schon getestet ist, sollte alles weitere notwendige sich in
den Xinu-Library Sourcen befinden.
Lediglich 32-bit signed und 16-bit unsigned Division und Modulo werden als Funktionsaufrufe "___divsi3",
"___modsi3", "___udivhi3" und "___umodhi3" vom Linker angemahnt, wenn versuchsweise die Xinu-Libraries
libsa.a und libxc.a gebaut werden und dann auch das beiliegende Standalone- Binary des "demo"-
Programmes gecrosslinkt wird. Für diese finden sich aber mit ldiv.s und lrem.s in den Libraries die passenden
Funktionen, es bleibt also nur noch, mit ein paar Zeilen Assembler einen Wrapper für die libgcc- Aufrufe
zu schreiben.
Dann wird nur noch "___main" vermißt, das frau getrost durch den Assemblerbefehl "rts pc"
liefern kann - schließlich ist hier alles statisch, wir brauchen keine Konstruktoren.
Anfangs nicht benötigt wurde die unsigned long Divison und Modulo- Funktion - hier läßt sich aber aus
dem Fundus des gcc-Source leicht die Funktion "udivmodsi4" ausborgen, der Vollständigkeit halber.
Float funktioniert leider überhaupt nicht, da gcc nur Code für die 11/40 FPU erzeugt - und da werden
Variablen schon mal nicht initialisiert, dieser Code sieht nicht sehr vertrauenerweckend aus... weil
auch die Option -mfis nicht funktionieren will, habe mir dann für die FIS-Befehle des LSI-11 Prozessors
eine kleine Library libfis.a geschrieben, um mit float arbeiten zu können.
Übrigens geht es in die schlammigen Tiefen von prä-ANSI-C, wenn es ans Übersetzen geht. Da sind
"=/" Operatoren zu finden (heute "/="), und um Funktionsprototypen scheint sich auch noch niemand gekümmert
zu haben. Diese Kleinigkeiten lassen sich aber glücklicherweise leicht beheben.
Auch die Assembler- Syntax hat sich in den letzen 25 Jahren etwas geändert - normal geschriebene Zahlen
werden heute als dezimal akzeptiert (nicht mehr mit einem Punkt am Ende), eine führende "0" weist
auf oktal hin.
Runterladen des Binaries
Eigentlich ist das ganz einfach, wenn frau sich erinnert, daß die "11en" ganz früher über Seriell-
Schnittstelle mit einem Fernschreibterminal (TTY) verbunden waren. Besagte Fernschreiber hatten nämlich
häufig einen eingebauten Lochstreifenleser. Nach dem Start der PDP wurde also über die Konsolenschalter
oder ODT ein kurzer Bootloader eingetippt, der dann den Binärcode vom Lochstreifen einlas. Das geht heute
fast genauso, nach dem Eintippen muß dazu nur der Bootloader gestartet werden (mit dem ODT "G" Kommando, s.o.),
über Shortcut der Terminal- Emulator beendet (bei minicom mit "Ctrl-A" und "Q"). Da nun der Bootloader
der PDP-11 an der Seriellschnittstelle "horcht", wird das Binary einfach auf die Schnittstelle kopiert:
cp demo.bin /dev/ttyS0
(soweit die notwendigen Zugriffsrechte auf /dev/ttyS0 gesetzt wurden).
Nun wird minicom wieder gestartet, der Bootloader mit der "Halt"-Taste an der 11/03 gestoppt, und dann
kann mit dem ODT- "G"-Befehl das gerade geladene Programm gestartet werden.
Kurze Lochstreifen- Bootloader zum Abtippen finden sich im Web, ich habe meinen auf der YAPP (siehe Links) gefunden.
Er ist vielseitig einsetzbar, die Adresse, an der das Binary im Speicher der 11 starten soll, kann in
157766 eingesetzt werden (für gelinkte Xinu-Binaries immer 0). Nach dem Laden steht in 157752 die Anzahl
der Bytes, die gelesen wurde, das ist eine nützliche Kontrolle. Der Wert kann auf dem Host z.B. mit
"od demo.bin" überprüft werden, um sicherzustellen, daß die Übertragung vollständig war. Der Bootloader
ist übrigens relozierbar, d.h. er kann in einen Speicherbereich eingetippt werden, der nicht überschrieben
wird, dann ist er nach Löschen von 157752 (oder dem Äquivalent im Speicher) wiederverwendbar.
157744 / 016701
157746 / 000026
157750 / 012702
157752 / 000000 <-- offset (counter)
157754 / 005211
157756 / 105711
157760 / 100376
157762 / 116162
157764 / 000002
157766 / 000000 <-- bank (RAM Start Adresse)
157770 / 005267
157772 / 177756
157774 / 000765
157776 / 177560
Debuggen mit ODT
Jetzt befindet sich also die Binärdatei im Speicher der 11, wird gestartet und - läuft natürlich nicht. Rudimentäres
Debuggen geht mit dem ODT direkt an der PDP-Konsole, ist aber etwas mühselig. Immerhin hab ich damit in
den Abgründen zwischen den Bits herausgefunden, daß die Xinu- Libraries andere Vorstellungen von den
Stackframes hatten als der gcc. Das läßt sich in csv.s beheben, hier wird einfach in der Funktion csv an der
richtigen Stelle 2 vom Stackpointer subtrahiert. Dann funktioniert die Sache mit den lokalen Variablen
jedenfalls schon mal.
Eine andere Sache betrifft den Zugriff auf Hardware- Adressen, bei denen Statusregister abgefragt werden.
Gcc optimiert hier gerne scheinbare Leerschleifen weg, wenn die entsprechenden Variablen nicht als
"volatile" deklariert werden.
Schlußendlich bekam ich das demo.c Programm zusammen mit libsa.a aber
wirklich zum laufen auf der Hardware meiner PDP-11/03. Damit habe ich also schon mal eine funktionierende
Toolchain, was ein wesentlicher Schritt vorwärts ist.
|
Bild 6 -
Sieht nicht nach viel aus, die Ausgabe von "Hello World" und ein paar Zahlen, hat es aber in sich. Immerhin läuft hier formatierte Ausgabe mit printf(), das doch eine recht komplexe Funktion innerhalb der C-Library ist.
|
WIRD FORTGESETZT!!!
Links
PDP11.org --
Dedicated to preserving the history and legacy of the
PDP-11 series of 16-bit minicomputers.
Wikipedia -- Die Wikipedia- Seite über die gute alte 11.
hampage.hu/pdp11 -- This page is intended as a tribute to one of the most famous computers: Digital Equipment Corporation's PDP-11 series.
bitsavers.org -- Bitsavers, ein reiches Reservoir an Software und Manuals alter Computer.
YAPP -- Yet another PDP page - enthält die "Hints on testing a dead PDP 11"
SIMH -- Der SIMH Emulator.
RXM -- Charles Dickman's RXM Emulator Seite.
Building gcc -- Seite über das Bauen von gcc als Crosscompiler.
*
Referenzen
[1] LSI-11, PDP-11/03 User's Manual. EK-LSI11-TM-002, Digital Equipment Corporation, Maynard, Massachuchets, 1975.
[2] M7270 LSI-11/2 Microcomputer Module User's Guide. Digital Equipment Corporation, Maynard, Massachuchets, 1976.
[3] MSV11-D, -E User's Manual. EK-MSV1D-OP-001, Digital Equipment Corporation, Maynard, Massachuchets, 1977.
[4] DLV11-E and DLV11-F Asynchronous Line Interface User's Manual. Digital Equipment Corporation, Maynard, Massachuchets, 1977.
[5] RX02 Floppy Disk System User's Guide. EK-RX02-UG-001, Digital Equipment Corporation, Maynard, Massachuchets.
[6] RX01/RX02 Pocket Service Guide. EK-RX02-UG-002, Digital Equipment Corporation, Maynard, Massachuchets.
[7] RX02 Floppy Disk System User Guide. EK-RX012-PS-001, Digital Equipment Corporation, Maynard, Massachuchets.
[8] Rapid Recall LSI-11, PDP-11/03, LSI-11/2 Reference Card
[9] Comer, D.: Operating System Design: the Xinu Approach, Prentice Hall 1984.
Created: 18.Apr.2009
© 2009 Diane Neisius