PDP-8

PDP-8は、世界で初めて商業的に成功した12ビットミニコンピュータであり、1960年代にディジタル・イクイップメント・コーポレーション (DEC) が製造した。1965年3月22日に登場し、5万システムを売り上げ、DECのPDPシリーズでも当時最も成功したコンピュータとなった。最初のPDP-8の設計を指揮したエドソン・デ・カストロは、後にデータゼネラルを創業した。PDP-8 は、PDP(Programmed Data Processor)シリーズとしては、 の後継である。
最初のPDP-8機種（非公式に "Straight-8" と呼ばれている）は diode-transistor logic (DTL) を採用した基板で構成されており、小型冷蔵庫ほどの大きさだった。
その後、デスクトップ型とラックマウント型のPDP-8/Sが登場。1ビット直列ALU実装で、小型化と低価格化を実現したが、最初のPDP-8に比べると性能がかなり低い。PDP-8/Sに接続可能な唯一のストレージがDF32というディスク装置（容量32Kワード）だった。
その後のシステム（PDP-8/I、/L、/E、/F、/M、/A）は並列実装で高速になった（元に戻った）が、TTLICを使用し、DTLより安価になっている。現存するPDP-8の多くはこの世代の機種である。中でもPDP-8/Eは豊富な各種周辺機器が接続可能で、よく使われていた。汎用コンピュータとしてもよく使われていた。
1975年、安価なマイクロプロセッサを使った Altair 8800 などの初期のパーソナルコンピュータが登場し、その後 TRS-80 や Apple II が登場すると、小型汎用コンピュータの市場はそれらに奪われることになった。
1979年にリリースされた PDP-8 の最後の機種は特製のCMOSマイクロプロセッサを使用しており、"CMOS-8s" などと呼ばれた。価格は他のマイクロプロセッサを使ったコンピュータと競合するような設定ではなく、市場には受け入れられなかった。1981年に登場した IBM PC がCMOS-8sにとどめを刺した。インターシルがこの集積回路を1982年まで として販売していた。CMOSであるため低電力であり、いくつかの軍用組み込みシステムに採用された。
概要.
技術史的観点からもPDP-8は重要な位置を占めている。入出力機構、ソフトウェア開発、オペレーティングシステム設計などに影響を与えた。Apple IIのようなマイクロコンピュータが一般化するまで、PDP-8は世界で最も販売台数の多いコンピュータであった。
PDP-8はいくつかの12ビット機の先例を参考にしており、特に と が設計したLINCに影響を受けている。LINC自体は、シーモア・クレイが設計したミニコンピュータ に影響を受けている。
単純な (PIO) バスを備え、それに加えてDMAチャネルがある。PIOバスは、プリンター、テレタイプ端末、紙テープパンチ/リーダーといった低速から中速の周辺機器を接続するのが一般的で、一方DMAはライトペン付きのブラウン管スクリーン、アナログ-デジタル変換回路、デジタル-アナログ変換回路、磁気テープドライブ、ディスクドライブなどで使用する。
ワード長は12ビットで、符号なし整数で0から4095までの範囲を扱え、単純な機械の制御には十分である。また、符号付整数なら -2048 から +2047 まで扱える。これは計算尺より高精度だし、多くのアナログコンピュータにも引けを取らない。12ビットはまた、ASCIIのサブセットを6ビットで表せば、1ワードに2文字を格納できる。
コスト削減のため、他のコンピュータならフリップフロップで構成するレジスタも安価な主記憶を使う設計になっていた。
PDP-8の基本構成では、主記憶容量は4,096ワードで、オプションのメモリ拡張ユニットでさらに拡張する場合は、後述のIOT命令でバンク切り換えをして使用する。
当初、ソフトウェアから見てPDP-8は8種類の命令しかなく、レジスタも2本（12ビットのアキュムレータ AC とキャリービットに相当するリンクレジスタ L）しか持たない。主記憶は磁気コアメモリでクロックサイクルは1.5μ秒である。典型的には1命令で命令とデータにアクセスするため2サイクルかかり、性能は0.333MIPSとなる。1974年の Pocket Reference Card では基本命令実行時間は1.2μ秒、メモリ参照命令の場合は2.6μ秒となっている。後期の機種では新たなレジスタが追加され(積/商レジスタ、MQ)、乗算命令と除算命令が追加された。
PDP-8は設計の単純さを重視して設計が最適化されている。直列化ALUを採用したPDP-8/Sでは、論理ゲートを519個しか使っていない。2008年現在、最も規模の小さいマイクロコントローラでも1万5千ゲート以上使っている。他のマシンと比較すると必須ではない部分がそぎ落とされ、可能な限り論理回路を共用する設計になっている。命令は自動インクリメントや自動クリアや間接アクセスを利用して性能向上を図りつつメモリ使用量を削減している。PDP-8のCPUには12ビットレジスタが4本しかない（アキュムレータ、プログラムカウンタ、メモリバッファレジスタ、メモリアドレスレジスタ）。これらのレジスタは処理サイクルの各時点で様々な用途に使われている。例えば、メモリバッファレジスタは算術演算のオペランドを供給し、磁気コアメモリに書き出すべきデータを一時的に保持する（また、磁気コアメモリからの読み出しで破壊されたデータを書き戻すのにも使われる）。このように基本は単純にも関わらず、モジュールを小型化するために価格は高くなった。PDP-8/Sは電源電圧を2種類使っているが、これは diode-transistor logic (DTL) でのファンアウト数を大きくする安価な技法である。
PDP-8のバージョン.
PDPシリーズのベストセラーPDP-8ファミリーの正確な総売上台数を表すデータは存在しないが、50,000台程度であろうと推定されている。
PDP-8を含む12bitのコンピュータとして、以下のような機種が製造された。
後の実装例.
PDP-8のアーキテクチャは非常に単純なので、それをエミュレートするのは容易である。愛好家がPDP-8全体を1個のFPGAで実装した例もある。
インターネット上にはPDP-8をシミュレート/エミュレートするソフトウェアもいくつか存在する。うまく実装されたものはDECのOSや診断プログラムを実行可能である。後期のPDP-8に可能な限りの周辺機器を接続した状態をシミュレートすることが多い。そこまでしても、現代のパーソナルコンピュータのリソースのほんの一部しか占めない。
入出力.
I/O（入出力）システムはPDP-8の頃に大きな変化を迎えた。初期のPDP-8の入出力は、フロントパネル、紙テープリーダー、テレタイププリンタ（ASR-33/KSR-33）、そしてオプションの紙テープパンチャーで構成されていた。その後、磁気テープ、RS-232Cなどによるダム(dumb)端末、パンチカードリーダー、固定ヘッド式磁気ディスク装置などが追加されていった。最後のころにはフロッピーディスクやハードディスクが一般的になっていた。最近の愛好家はIDEアダプターを（本物あるいはシミュレートされた）PDP-8に接続している。
I/Oは以下のようないくつかの手段でサポートされている:
基本的なDMA方式 (three-cycle data break) がサポートされている。これにはプロセッサの支援が必要だった。本来ならば各I/Oデバイスが持つべき回路を共通化してプロセッサ側に置き、プロセッサがDMAアドレスレジスタとワードカウントレジスタを設定する。その後の3メモリサイクルでプロセッサはワードカウントを更新し、転送アドレスを更新し、最後に実際のI/Oデータワードをやりとりする。初期のPDP-8から備えられていた機能であるが、PDP-8/Eのころにはこの回路は非常に安価になったので、"one-cycle data break"が一般化した。これは個々のI/Oデバイス側にハードウェアによるDMAアドレスレジスタとワードカウントレジスタを持たせ、ディスクドライブや磁気テープなど高速I/Oデバイスとメモリ間でプロセッサを介さず直接メモリへの読み・書きをするDMAを行うものであり、実質3倍の転送性能となった。
プログラミング環境.
PDP-8の最も基本的なソフトウェア開発システムは、機械語をバイナリ形式でフロントパネルから入力するものであった。その後、PAL-8アセンブリ言語のソースコードを紙テープに格納し、メモリにロードし、紙テープにセーブし、紙テープからアセンブルされてメモリに格納されるようになった。紙テープ方式のプログラミング言語としては他に インタプリタや 4K FORTRANコンパイラなどがある。最終的には OS/8 や COS-310 といったオペレーティングシステムによって、ラインエディタやコマンドラインコンパイラといった開発システムが構築された。サポート言語としては、PAL-IIIアセンブリ言語、FORTRAN、BASIC、などがある。
初期のPDP-8システムにはオペレーティングシステムがなく、フロントパネルのスイッチしかなかった。様々な紙テープ式「オペレーティングシステム」が開発されたが、いずれもシングルユーザー方式であった。最後期には先進的なRTOSやプリエンプティブ・マルチタスク/マルチユーザーシステムが利用可能となった。例えば RTOSの RTS-8、マルチユーザーシステムの COS-300 や COS-310、シングルユーザー用ワードプロセッシングシステム WPS-8 などがある。
タイムシェアリングシステム も使用可能であった。TSS-8 では複数のユーザーが110ボーの端末からシステムにログインすることができ、プログラムのエディット/コンパイル/デバッグが同時にできた。言語としては、BASICの特別バージョン、FORTRANのサブセット(サブルーチンを書けない)、ALGOLのサブセット版、FOCAL、PAL-Dアセンブラなどが利用可能である。
 (Digital Equipment Computer User Society) はPDP-8用にユーザーが寄贈した相当量のソフトウェアを保有している。
命令セット.
12ビットの命令ワードの先頭3ビット（ビット0から2）が命令コードである。ビット5から11までの7ビットのオフセット部でアクセスするメモリを示す。ビット4がセットされていたら、プログラムカウンタ (PC) の上位5ビットとオフセットを連結してアドレスを完成させる。そのビットがゼロならアドレスの上位はゼロとする。ビット3は間接かどうかを示す。セットされていたら、それまでに得られたアドレスはメモリ上にある実効アドレスのある位置を示していることになる。JMP命令は、間接指定されていない場合はメモリワードを読み込むわけではないが、命令のフォーマットは同じである。
メモリページ.
このように命令はアドレスの下位7ビットだけを直接指定するので、4,096ワードのメモリは128ワードの「ページ」に分割されることになり、命令のビット4でカレントページかページ0（アドレス範囲を八進法で示すと 0000 から 0177）を指定する。ページ0に変数を置くと、どのページを実行中でもそれにアクセスできるため、ページ0のメモリは特別である。また、アドレス 0000 は割り込み処理ルーチンのスタートアドレスでもある。また、アドレス 0010 から 0017 までは自動インクリメント機構という特殊性がある。
標準的アセンブラは算術用定数をカレントページに置く。同様に、ページ間ジャンプやサブルーチンコールはカレントページ内から間接アドレス指定で行う（つまりアドレスがカレントページ内に置かれている）。
ページをまたいだ参照や分岐は余分なワードを必要とするため、ルーチンを128ワードのページ境界に収まるように書くか、なるべくページからページへの移行が少なくなるように書くことが重要だった。そのため、何ワードかをいかに節約するかに頭を悩ませることが多かった。PCのインクリメントで自動的に次のページに移行できるため、プログラムを意図的にページの最後尾に置くことが多かった。
IOT（入出力転送）命令.
PDP-8はIOT命令をほとんど定義せず、単に枠組みを提供している。多くのIOT命令がどう作用するかは個々の周辺機器によって異なる。
OPR (OPeRate) 命令.
条件付き操作のほとんどを含め、多くの操作はOPR命令として実行される。OPR命令ではメモリ位置をアドレスで示すということがない。条件付き操作は1命令をスキップするか否かを判断する命令であり、通常はその1命令をJMP命令とすることで条件分岐として機能させる。
OPR命令はマイクロコード化されている。これはマイクロプログラム方式だということを意味しているのではなく、命令語の各ビットがそれぞれ特定の動作に対応しており、複数のビットをセットすることでそれらを1命令で実行できる場合があることを意味している。アセンブリ言語で記述する際には複数のニーモニックを並列に書く。するとアセンブラがそれらのコードをORして1命令にする。上述のIOT命令も周辺機器がマイクロコード化している。
マイクロコード化された動作の実行順序は決まっており、多くの組合せが最も便利になるような順序で実行される。
OPR命令にはいくつかのグループがある。ビット3、ビット8、ビット11 でグループが識別され、異なるグループのマイクロコード化操作は1命令で指定できない。
グループ1.
 00 01 02 03 04 05 06 07 08 09 10 11
 ___________________________________
 | 1| 1| 1| 0| | | | | | | | |
 |__|__|__|__|__|__|__|__|__|__|__|__|
 |CLA CMA RAR BSW
 CLL CML RAL IAC
 Execution order 1 1 2 2 4 4 4 3
多くの場合操作は順次行われ、多くの組合せが最も便利な形で可能である。例えば CLA (CLear Accumulator) と CLL (CLear Link) と IAC (Increment ACcumulator) を組み合わせると、まずACとLINKをクリアし、次にアキュムレータをインクリメントするので、ACの値は1になる。これにさらに RAL を加えると、アキュムレータをクリアし、インクリメントし、左にローテートするので、ACの値は2になる。このようにしてアキュムレータに小さい整数定数を1命令で置くことができる。
CMAとIACを組み合わせると、アセンブラではこれをCIAと略記できるが、ACの値を算術的に符号反転できる（つまり、2の補数）。PDP-8には減算命令がなく符号付加算命令 (TAD) しかないので、2つの数の差を求めるには一方の数の符号を反転させるしかない。
グループ1のOPR命令で、マイクロコード化されたビットを全くセットしない場合、何も行われない。そういった命令をNOP命令として使用することができる。
グループ2、Orグループ.
 00 01 02 03 04 05 06 07 08 09 10 11
 ___________________________________
 | 1| 1| 1| 1| | | | | 0| | | 0|
 |__|__|__|__|__|__|__|__|__|__|__|__|
 |CLA SZA OSR
 SMA SNL HLT
 2 1 1 1 3 3
ビット8がセットされていない場合、指定された条件のいくつかが真ならばスキップを行う（条件はORされる）。例えば、"SMA SZA" 命令コード 7540 の場合、AC ≤ 0 ならスキップする。
グループ2のOPR命令もマイクロコード化ビットが全くセットされていない場合、NOP命令として扱われる。
グループ2、Andグループ.
 00 01 02 03 04 05 06 07 08 09 10 11
 ___________________________________
 | 1| 1| 1| 1| | | | | 1| | | 0|
 |__|__|__|__|__|__|__|__|__|__|__|__|
 |CLA SNA OSR
 SPA SZL HLT
 2 1 1 1 3 2
ビット8がセットされている場合、スキップ条件はOrグループのときと逆であり、いずれかの条件が真でないときスキップは行わない。つまり、指定された条件が全て真となる必要がある（条件はANDされる）。例えば "SPA SNA" 命令コード 7550 は AC > 0 のときスキップする。ビット5からビット7が全くセットされない場合、無条件でスキップする。
グループ3.
これまでのグループで使われていないビットの組合せのOPR命令はグループ3に分類され、多くは MQ (Multiplier/Quotient) レジスタに関連する。
 00 01 02 03 04 05 06 07 08 09 10 11
 ___________________________________
 | 1| 1| 1| 1| | | | | | | | 1|
 |__|__|__|__|__|__|__|__|__|__|__|__|
 |CLA SCA \_ _/
 | MQA MQL CODE
 1* 2 2 2 3
通常、CLAとMQAを組み合わせてMQの中身をACに転送する。MQAとMQLの組合せも便利で、ACとMQの中身を交換する。
ビット8からビット10までの3ビットで以下のいずれかの命令が実行される。
メモリ制御.
12ビットワードは4,096種類の値をとることができ、それは最初のPDP-8がワードポインタで間接的にアドレス指定できる最大のワード数でもあった。プログラムが複雑化し、メモリ価格が下落してくると、この制限を拡張することが望ましくなってきた。
既存プログラムとの互換性を保つため、当初設計になかった新ハードウェアはプログラムが生成する実効アドレスにさらに上位のビット群を追加した。メモリ拡張コントローラはアドレス指定範囲を8倍にし、32,768ワードまで扱えるようにした。当時の磁気コアメモリは1ワード当たり50セントのコストであり、32Kワードを実装するとCPUと同程度のコストになるため、この程度の拡張で十分だとされた。
4Kワードぶんのメモリをフィールドと呼ぶ。メモリ拡張コントローラは、DF (Data Field) と IF (Instruction Field) という2つの3ビットレジスタを備えている。それらのレジスタはデータアクセスや命令フェッチの際にどのフィールドにアクセスするかを指定するもので、アドレスは実質15ビットに拡張される。IFレジスタは命令フェッチと直接メモリ参照の際のフィールドを指定する。DFレジスタは間接データアクセスの際のフィールドを指定する。あるフィールドで動作中のプログラムは、直接アドレッシングでは同じフィールドにアクセスし、間接アドレッシングでは別のフィールドにアクセスできる。
IOT命令の 6200 から 6277 までの範囲がメモリ拡張コントローラに対応しており、DFレジスタとIFレジスタへのアクセスが可能である。62X1 命令 (CDF, Change Data Field) はDFレジスタの値をXにする。同様に62X2 (CIF) 命令はIFレジスタの値をXに、62X3 命令は両方をXにセットする。既存プログラムはCIFもCDFも実行しない。DFもIFも同じフィールドを指すので、既存プログラムは単一フィールドだけで動作する。CIF命令の効果は、次のJMPまたはJMS命令まで遅延されるので、CIF命令によって即座にジャンプするわけではない。
フィールド境界とDF/IFレジスタの関係を考えると、複数フィールドを使うプログラムはさらに複雑化する。単純に15ビットのアドレスを生成するのではなく、12ビット・アーキテクチャとの一貫性と互換性を保つよう設計されているためである。後の Intel 8086 では、Intel 8080 で16ビットだったアドレスを20ビットに拡張したが、拡張部分はセグメントレジスタで指定する方式だった。
このメモリ拡張方式により、既存のプログラムを少し修正するだけで扱えるメモリ範囲を拡大することができた。例えば、4K は、自身のコードが3Kあってユーザープログラムやデータに使えるメモリは1Kしかなかった。そのFOCALに若干パッチを当てるだけで、ユーザープログラムとデータに別の4Kフィールドを割り当てることができる。さらに、4Kフィールドを別のユーザーに割り当てることもでき、マルチユーザーのタイムシェアリングシステムを構成できる。
仮想化.
PDP-8/Eとその後の機種では、メモリ拡張コントローラは仮想化も可能なように拡張された。PDP-8の全リソースを使用するようなプログラムが1台のPDP-8上に複数並存でき、仮想機械マネージャの制御下で動作可能だった。このマネージャは（メモリ拡張コントローラの操作も含む）全IO命令に対してトラップが可能である（割り込みを起こしてマネージャがそれを処理できる）。そのようにしてマネージャがデータや命令のフィールドのマッピングを制御でき、入出力を他のデバイスにリダイレクトできる。それぞれのゲストプログラムは、マネージャが提供する「仮想機械」への完全なアクセスを持つ。
新たなIOT命令で、メモリ拡張コントローラのDF/IFレジスタの現在値を読み出すことができ、トラップ前後のマシンの状態をセーブ/リストアできる。しかし、CIF命令の効果が遅延している状態（CIF命令を実行後、最初の分岐を行うまでの状態）かどうかは判別できない。マネージャは完全なPDP-8エミュレータを含んでいる必要がある（8命令のマシンなので難しくはない）。CIF命令をトラップした際、マネージャは次のジャンプ命令までの命令列をエミュレートする必要がある。実際、ジャンプ命令はCIF命令の直後にあるのが一般的で、エミュレーションで性能が大きく低下することはないが、小さな設計上の欠陥への対策としては大きい。
PDP-8/Aのころメモリ価格はさらに下落し、32Kワード以上も可能なレベルとなった。そこでPDP-8/Aでは8フィールド以上を扱える新たな命令群が追加された。フィールド番号は命令にハードコーディングされるのではなく、ACで指定できるようになった。しかし、そのころにはPDP-8は市場から消えつつあり、この新機能を使うよう修正された主要ソフトウェアはごく一部だけだった。
コーディング例.
PDP-8のアセンブリ言語プログラムを例として示す。以下のコード例はPAL-IIIアセンブラによる。
2つの数の比較.
単に2つの数を比較するだけでどれだけのコードが必要となるかを示したコード断片。
codice_1
見ての通り、PDP-8の典型的なプログラムは作者が意図したアルゴリズムよりも低レベルな機構に集中する傾向がある。また、可読性を損なうもう1つの問題として、条件分岐部分のコーディングがある。上の例で判るとおり条件判断命令（JMP命令をスキップしている命令）は、注目している条件とは反対の条件判断をしなければならない。
文字列出力.
PDP-8で "Hello, world" をテレタイプ端末に出力するアセンブリ言語のプログラム。
codice_2
サブルーチン.
PDP-8では汎用スタックをアーキテクチャ上サポートしていないため、サブルーチンを呼び出すときや割り込みが発生したときのコンテキスト(プログラムカウンタやACなどのレジスタ値)をセーブする方法が確立されていない。その代わり、リターンアドレスとしてのプログラムカウンタ値がターゲットサブルーチンの先頭ワードに格納される。従って、間接ジャンプ命令でサブルーチンから戻ることができる。
以下のプログラムはサブルーチンを使うように改造した "Hello world" である。JMS命令でサブルーチンに飛び込むと、OUT1:の位置にある0が書き換えられる。
codice_3
リエントラント性や再帰呼び出しを実現しようとすると、プログラマは自分でコールスタックを用意し、リターンアドレスをスタックにセーブしなければならない。また、ROMを使うのも困難である(プログラムが書き換え可能でないとサブルーチンを使えないため)。ROMにプログラムを格納する場合、以下のような回避方法があった。
codice_4
JMS命令を使用するとデバッグが難しくなる。例えば、リターンアドレスの書き換えによって無限ループに陥ることもあるし、サブルーチンのアドレスを間違うとサブルーチンの先頭ではないワードをリターンアドレスで書き換えてしまうこともある。こういった誤りは実行してみないとわからないこともある。
ソフトウェアスタック.
PDP-8 はスタックをハードウェアでサポートしていないが、ソフトウェアでの実装は可能である。以下はPUSHとPOPというサブルーチンの実装例だが、単純化するためスタックのオーバーフローやアンダーフローはチェックしていない。
codice_5
以下は、"Hello World" を "OUT" というサブルーチンとこのスタックを使って実装したものである。
codice_6
連結リスト.
PDP-8での連結リストの実装例。
codice_7
割り込み.
PDP-8の入出力バスには1本の割り込みラインがあり、割り込みが発生すると割り込み不可状態となって 0番地のサブルーチンを呼び出すように動作する。サブルーチンと同様、割り込みもリエントラント性は無く、割り込みを不可とした状態で割り込みハンドラが動作し、codice_8 命令で割り込まれた箇所に戻るとき割り込み可とする。
I/Oバスの割り込みラインが1本なので、割り込み発生源が何かということは分からない。そのため、割り込み処理ルーチンは順に各デバイスのステータスをポーリングしてチェックし、割り込み元を識別した。この処理は条件スキップ命令が並ぶので "skip chain" と呼ばれた。skip chain の最後まで実行しても割り込み元が見つからないことは珍しいことではなかった。相対的な割り込みの優先順位は skip chain でチェックする順番で決定され、先に見つかった割り込みの処理が優先される。