PDP-8: Adressierungsmodi und Seitengrössen

Die PDP-8 CPU kennt zwei Adressierungsmodi: “direct” und “indirect”. Sie sind einfach zu verstehen; allerdings gibt es einige Dinge, die sich erst auf den zweiten Blick erschliessen.

Die CPU kennt nur 6 Befehle, die jeweils ein Argument erwarten, nämlich die Adresse einer Speicherzelle:

AND  0000  logical AND
TAD  1000  2's complement add
ISZ  2000  increment and skip if zero
DCA  3000  deposit and clear AC
JMS  4000  jump to subroutine
JMP  5000  jump

Schauen wir uns dazu an, wie der Assembler folgenden Code übersetzt. Diese Routine wandelt ein 6-bit-Zeichen in ASCII um und gibt es aus:

PAGE 2             / same as: * 0400
/ ... mehr Code
put6c, 0           / return addr
       AND K77     / keep 6 bits
       CLL         / proper adding
       TAD KM40    / -40 
       SPA         / Skip next on positive Accu
       TAD K100    /  if 40..77, add 100 
       TAD K40     / restore original value
       JMS putc    / print it
       JMP I put6c / return
/ ... noch mehr Code

Wer schon Assembler auf anderen CPU geschrieben hat könnte verleitet sein zu denken, dass die Argumente  als weitere Datenworte im Binärcode landen.

Das ist aber nicht der Fall: Die Befehle sind immer 1 Wort (12 Bit) breit. Das erste Triple definiert den Opcode (z.B. TAD mit 1xxx). Somit bleiben für die Codierung des Arguments 9 Bits.

Adressierungsmodi

Mit 9 Bits lassen sich 512 Werte abbilden (2^9, Wertebereich 0..511), was nur einen kleinen Teil des Speichers ausmacht (min. 4k Worte). Schlimmer noch: Es stehen nur 7 Bits für die Adresse zu verfügung. Aber erst mal der Reihe nach… 🙂

In der DEC Literatur ist die Befehlscodierung so dargestellt:

 _0___1___2_ _3_ _4_ _5___6___7___8___9___10__11
|           |   |   |                           |
|OP CODE 0-5| IA| MP|          ADDRESS          |
|___|___|___|___|___|___|___|___|___|___|___|___|

Dabei bedeuten:

  • IA: Indirect Addressing (0: direct; 1: indirect)
  • MP: Memory Page (0: Page 0, 1: current page)
  • Address: relative address

Memory Pages

Durch diese Adressierung ergibt sich ein Konzept von Speicherseiten, die jeweils 128 Bytes gross sind (2^7 bits). Wenn wir den Programmcode auf Seite 2 legen (Oktal 0400, dezimal 256), erzeugt der Assembler folgenden Binärcode:

00420  0000  put6c, 0
00421  0204  AND K77
00422  7100  CLL
00423  1200  TAD KM40
00424  7510  SPA
00425  1205  TAD K100
00426  1202  TAD K40
00427  4206  JMS putc
00430  5620  JMP I put6c

Direkte Adressierung

Das Mnemonic AND  mit dem “Argument” K77 (meine anderswo defnierte Konstante 0077) wird als 0204 codiert, nämlich:

 _0___1___2_ _3_ _4_ _5___6___7___8___9___10__11
|           |   |   |                           |
| 0   0   0 | 0 | 1 | 0   0   0   0   1   0   0 |
|___|___|___|___|___|___|___|___|___|___|___|___|

|---- 0 ----|---- 2 ----|---- 0 ----|---- 4 ----|

Der AND Befehl lädt also meine Konstante K77 direkt aus dem Speicher (IA:0) aus der aktuellen Seite (MP:1) von Adresse 4. Da der Code in Seite 2 ab 0400 platziert ist, befindet sich der Wert der Konstante also an absoluter Adresse 0404. Schauen wir uns das in simh an:

sim> ex -m 420-430
420:	AND 0
421:	AND 404
422:	CLL
423:	TAD 400
424:	SPA
425:	TAD 405
426:	TAD 402
427:	JMS 406
430:	JMP I 420
sim> ex 404
404:	0077

Wäre hier das MP Bit gesetzt, würde statt dessen aus der ersten Seite (Zero Page) gelesen, an absoluter Adresse 4.

Indirekte Adressierung

Im Code schliesst die Subroutine mit einem indirekten Sprung (JMP I) ab. Das Assembler Listing verrät uns, dass dieser Befehl als 5620 codiert ist:

 _0___1___2_ _3_ _4_ _5___6___7___8___9___10__11
|           |   |   |                           |
| 1   0   1 | 1 | 1 | 0   0   2   0   0   0   0 |
|___|___|___|___|___|___|___|___|___|___|___|___|

|---- 5 ----|---- 6 ----|---- 2 ----|---- 0 ----|

Damit liegt das Sprungziel nicht an Adresse 0 020 000 (Oktal 20, Dezimal 16), sondern an dieser Adresse ist das Sprungziel hinterlegt, und dieses wird angesprungen.

Exkurs: Unterprogramme

Beim Aufruf der Subroutine (JMS Mnemonic) wird die Adresse des Aufrufers in diese Speicherstelle geschrieben; Subroutinen werden immer auf diese Weise verlassen.

Die PDP-8 hat keinen Stack; die Entwickler haben sich da was schönes ausgedacht um Code wieder verwertbar zu machen. Allerdings ist dieser Code nicht re-entrant, darf sich also niemals selbst aufrufen, auch nicht geschachtelt!

Exkurs: Programm-Listing

Der macro8x Assembler aus dem simh Paket erzeugt automatisch ein Listing. Die Option -d fügt ausserdem eine Symboltabelle am Ende des Listings ein.l

Zusammenfassung

  • Was wie ein Argumente eines Mnemonics aussieht wird direkt ins Befehlswort codiert.
  • Es gibt nur 7 Adressbits in einem Befehl und dadurch eine logische Einteilung des Speichers in Seiten zu 128 Worten.
  • Über direkte und indirekte Adressierung ist trotzdem der gesamte Speicher adressierbar.
  • Die Zero Page ist aus allen anderen Seiten erreichbar.
  • Der Assembler nimmt einem die Berechnung der 7-Bit-Offsets ab und zeigt Fehler an, wenn Sprungziele oder Daten ausserhalb der aktuellen Seite liegen.
  • Das vom Assembler generierte Listing ist seihr hilfreich, um diese Zusammehänge und Fehlermeldungen zu verstehen.

In diesem Sinn: Happy Hacking! 🙂