IM6100CCPLで、鈴木様よりの頂きものです。
しかし、そのアーキテクチャは初期のミニコンピュータの、できる限り単純な回路でそれなりの性能を引き出そうとするための、最近のマイクロプロセッサには見られない特徴が多く存在します。
IM6100には最高クロック周波数の点で3種類のバージョンがあります。IM6100は5 V動作で最高クロック周波数4 MHzで、IM6100Aは10 V動作可能でその場合に最高クロック周波数8 MHz、IM6100Cは5 V動作で最高クロック周波数3.3 MHzとなっています。内部回路はスタティック設計となっていますので、クロック周波数を低くする方は自由で停止することも可能です。
IM6100のプログラマから見たレジスタモデルはこのようになっています。
なんというか、非常にシンプルなレジスタセットとなっています。レジスタや命令のビット番号の割り当ては、ミニコンピュータでよく見られた最上位ビット(MSB)が0で最下位ビット(LSB)が11という形式になっているのに注意してください。プログラマが意図的に操作できるレジスタは12
bitレジスタが3本に1 bitのフラグが2個だけです。
ACはアキュムレータで演算の中心となります。基本的にアキュムレータとメモリの間で演算が行われます。MQはテンポラリレジスタで、アキュムレータの内容を一時退避したりするためのレジスタです。
PCはプログラムカウンタで、やはり12 bit幅となっています。このことからわかるように、特にメモリ拡張ハードウエアを用意しない場合にはIM6100のメモリ空間は12
bitで指示できる4096語のサイズです。
Lはリンクフラグで、シフト・ローテート命令の際にACと接続して使用したり、加減算のキャリーが入ります。一般的なマイクロプロセッサではキャリーと呼ばれているフラグですね。
IEは割り込みイネーブルフラグです。割り込みを用いた入出力時に操作する場合があります。
インデックスレジスタやスタックポインタの類が見当たりません。IM6100ではサブルーチン呼び出しはスタックを使わない方式となっています。また、メモリ間接アドレッシングが扱えるので、インデックスレジスタやユーザプログラムによるスタックデータ構造はメモリ上に確保したポインタを利用します。
次にメモリ構成ですが、メモリ拡張ハードウエアを使用しない場合4096語が全アドレス空間になりますが、この4096語は128語を1ページとする32ページに分割されています。実行中の命令が存在するページをカレントページと呼び、32ページ中の先頭の(アドレスの小さな)ページを普通に0ページと呼びます。メモリ参照命令では、0ページかカレントページのどちらかについて、直接参照、あるいは間接参照を行うことができるようになっています。0ページについては全メモリ空間の任意の位置の命令から参照できますから、ここをスクラッチパッドレジスタやひんぱんに使用されるグローバル変数として使用すれば、プログラムの短縮につながります。
なお、0ページの08Hから0FHまでの8語に対する間接参照については、自動的にプリインクリメントされます。つまり、このアドレス範囲のメモリをポインタとして使用すると、メモリ内容の検索やコピーが容易になります。
なお、標準的なメモリ拡張ハードウエアが存在する場合も以上の内容にはかわりありませんが、4096語の全体がフィールドと呼ばれる単位で管理され、システムで参照できるアドレス空間は8フィールドから構成されます。つまり32
K語までのアドレス拡張が行われます。
入出力機器のアドレス空間はメモリとは別に存在し、最大64種の入出力機器を利用できます。
では命令体系に取り組みましょう。
IM6100の命令は、6種のメモリ参照命令、3種の演算(OPR)命令、1種の入出力転送(IOT)命令から構成されます。すべて1語命令です。メモリ参照命令はアキュムレータかプログラムカウンタとメモリの間で何かを実行する命令です。OPR命令は内部レジスタに対する演算を実行する命令で、IOT命令は入出力機器とのデータ転送を行う命令です。たった10種の命令なのですが、OPR命令にはそれぞれ演算操作を指示するビットが複数存在し、その組み合わせによって多様なアキュムレータに対する演算を指示できます。IOT命令はプロセッサ側では1種類だけの命令で、デバイスアドレスと動作指定コードを外部に出力するだけの命令ですが、入出力機器側からプロセッサに対し特別な制御信号を与えることによって実際の入出力動作を行いますので、多様な入出力動作が可能となっています。
この命令種別はオペコードの上位3 bitによって明確に区分されていて、その3
bitが0 - 5までがメモリ参照命令、6がIOT命令、7がOPR命令です。
まずはメモリ参照命令で、オペコードは一般的に次のような形式となっています。
0 1 2 3 4 5 6 7
8 9 10 11
Op Op Op IA MP A5 A6 A7 A8 A9 A10 A11
ビット0 - 2の上位3 bitは、すでに述べたように命令種別を表します。逆に下位のビット5
- 11の7 bitはページ内アドレスオフセットを意味します。IM6100は128語が1ページとなり、語単位でアドレスが割り振られていますから、7
bitでページ内オフセットを表現できます。ビット4のMPはメモリページの略で、このビットが0なら0ページを参照、1ならカレントページを参照という意味となります。ビット3のIAは間接アドレッシングビットで、このビットが0なら直接アドレッシング、1なら間接アドレッシングとなります。0ページの08Hから0FHまでの8語に対する間接アドレッシングについては、プリインクリメントが行われます。つまり、間接参照を行う前に1だけ加算されて書き戻され、その加算後のアドレスを用いて参照が行われます。
具体的に考えると、Op部がすべて0の命令はAND命令ですが、000Hという命令なら、オペランドは0ページのアドレス0に格納された値となります。082HならMPが1ですからカレントページのオフセット2の内容がオペランドで、123Hなら0ページのアドレス23Hに納められているアドレスによって指されたメモリの内容がオペランドとなります。108Hというオペコードで、アドレス008Hのメモリの内容が234Hだったとしたら、アドレス008Hの内容が235Hに書き換えられて、アドレス235Hのメモリの内容が取り出されてオペランドとなります。
具体的な命令表はこのようになっています。
Mne. Code
Cycles 動作
AND 000I PAAA AAAA 10/15/16 (AC) <- (AC) &
(Op)
TAD 001I PAAA AAAA 10/15/16 (AC) <- (AC) +
(Op)
ISZ 010I PAAA AAAA 16/21/22 (Op)++; If (Op) ==
0, (PC)++
DCA 011I PAAA AAAA 11/16/17 (Op) <- (AC);
(AC) <- 0
JMS 100I PAAA AAAA 11/16/17 (Op) <- (PC),
(PC) <- Op + 1
JMP 101I PAAA AAAA 10/15/16 (PC) <- Op
Mne.は命令ニーモニックで、Codeは2進数で表示したオペコードです。ただしIは間接アドレッシングビット、Pはメモリページビット、Aはページ内オフセットを意味します。Cyclesは命令実行サイクル数で、3種類の数値が並んでいます。Iが0の直接アドレッシングの場合が左、Iが1の間接アドレッシングの場合が中央、間接アドレッシングでもプリインクリメント付きのものなら右のサイクル数が適用されます。4
MHzクロックのIM6100の場合、1サイクルは500 nsとなります。3.3 MHzクロックなら600
nsです。動作の欄は簡単に命令動作を示しています。ここでOpはメモリオペランドアドレスを意味します。
AND命令はACとオペランドの論理積を行う命令で、TAD命令はACとオペランドのバイナリ加算命令です。
ISZ命令はIncrement and Skip if Zeroの略で、オペランドをインクリメントして、その結果が0なら直後の命令をスキップする命令です。ループ制御などに使えますね。
DCA命令はDeposit and Clear the ACの略で、オペランドの位置にACの内容を格納した後、ACを0クリアします。
JMS命令はJump to Subroutineの略で、サブルーチン呼び出し、JMP命令はジャンプ命令ですね。
これらのメモリ参照命令を眺めると、思い切った命令の省略が行われていることに気づくと思います。AND命令はあってもOR命令は存在しません。加算はあっても減算はありません。DCA命令でストアはできてもロードする命令はありません。OR演算はOPR命令の中にACとMQのORがありますし、減算はOPR命令の中にACの2の補数を求める命令があるので、加算命令と組み合わせれば可能となります。しかし、ロード命令が存在しないというのはずいぶんと思い切ったものです。
ACにメモリの内容をロードできないようだと、まともなプログラムを書けそうにありません。それを解決する鍵がストアを行うDCA命令です。DCA命令はメモリにACの内容を書き込んだ後、ACを0クリアするという変わった仕様になっています。この0になったACにTAD命令でメモリの内容を加算すれば、メモリの内容がそのままACに格納されたことになります。そもそも、ACにメモリの内容をロードする場合、それまでのACの内容が上書きされて消えてしまいます。ACには、それまでの演算結果が入っているはずで、普通なら演算結果が消えてしまうのは困るため、メモリに保存してから別の値をロードするでしょう。つまりストアとロードは連続して使用する場面が多いと考えられます。それならTAD命令でロードの代用を行える、このDCA命令の仕様と割り切りは見事なものです。ただ、一連の計算の途中結果を後で使用するためにメモリに保存しておき、さらにACに対しての演算を行うようなことはできなくなります。こんな場合はいちいちACの内容をMQレジスタに退避させたりする必要があります。逆に、条件判定のためにACの内容を使用し、そのままACにメモリのデータをロードしたい場合、DCA命令がロードの直前に存在しない場合があります。このような場合、OPR命令でACの内容を0クリアする必要があります。
このように、IM6100というかPDP-8の命令体系は判じ物的な、一見奇妙な定石のようなテクニックを多用しないとプログラミングできない傾向が見られます。しかし、PDP-8のアーキテクチャが開発されたのは1965年です。初期のICを利用できるかどうかという時代で、1ゲートあたりのコストが千円以上といった頃に低価格コンピュータを実現しなければならなかったわけで、多様な命令を実装できるはずもありません。いかに単純な少数の命令で、それなりのプログラムを書けるようなアーキテクチャを設計するか、その挑戦の成果が、このような命令の割り切りに出たわけです。
サブルーチン呼び出しも変わった形式となっています。オペランドで指定されたサブルーチンの先頭アドレスに戻りアドレスを格納し、PCにはサブルーチンの先頭ではなく、その次のアドレスが書きこまれます。つまり、実際のサブルーチンのコードは指示されたアドレスの次のアドレスから始まるのです。こうすることによって、スタックポインタが存在しないIM6100で、サブルーチンを実現しているわけです。サブルーチンから戻るには、サブルーチンの先頭アドレスを間接参照するJMP命令を使用します。このような方式なので、そのままでは再帰可能なサブルーチンとはなりません。サブルーチンの先頭とリターンする場所が同一のページに存在しないと、何らかの対応策をプログラミングしない限りカレントページ内の間接参照JMP命令が使えませんから、面倒なことになります。なにより、このような方式ではプログラムをROM化できません。なにしろ、サブルーチンの先頭部分は書き込み可能でなくてはならないのですから。
もっともPDP-8開発時にはこれらはそれほどの問題ではありませんでした。もともと小さなプログラムを動かすための小型コンピュータで、ビット単価が数百円の時代でメモリもそれほど実装できませんから、サブルーチンが1ページに納まる方が普通でしょう。当時の高級言語はFORTRANやCOBOLで再帰呼出しなどできませんでしたし、アセンブリ言語によるプログラミングテクニックとしてもほとんど使われていませんでした。しかも、当時の一般的なメモリはコアメモリで、不揮発性で書き換え可能というメモリでした。磁気的に記憶するため、電源を切断しても内容は消えませんし、コンピュータプログラムから自由に書き換え可能ですから、ROM代わりにアプリケーションプログラムを格納したまま電源を切断しておけば、次の日に電源を投入してそのままメモリに残されたプログラムを実行することができます。自然とターンキーシステムになってしまうのです。書き換え可能なので、PDP-8方式のサブルーチン呼び出しでも別に問題にはなりません。
IM6100の場合には、時代的にコアメモリを採用しにくいでしょうから、プログラムのROM化ができないのでは困ります。詳細は後で触れますが、IM6100には制御パネルメモリ空間が存在し、その制御パネルメモリ空間の小さなブートストラップローダによって同じ制御パネルメモリ空間内のROMからメインメモリにプログラムを自動的にコピーすることができます。そのようにして、メインメモリが揮発性の一般的な半導体RWMで構成されていても、ROMに格納されたアプリケーションプログラムを実行できます。
OPR命令は命令コードの上位3 bitが7であるような命令で、主に内部レジスタの間の演算に用いられます。
0 1 2 3 4 5 6 7 8 9 10 11
1 1 1 a * * * * * * * b
上の命令コードのビットパターンのaとbの値によって、3種類のグループ命令に分類されます。残りの*のビットで、どのような演算を行うかが決められます。個々の*のビットにはそれぞれマイクロ命令が割り当てられています。そのマイクロ命令を組み合わせることによって、多数の演算を実行できるようになっています。たとえば、ACを反転させるマイクロ命令とACをインクリメントさせるマイクロ命令のビットを1にすれば、ACの内容の2の補数を求められます。
a | b | グループ |
0 | - | グループ1(ACとLの操作) |
1 | 0 | グループ2(条件スキップ) |
1 | 1 | グループ3(ACとMQの操作) |
グループ1マイクロ命令フォーマットは次のようになっています。
0 1 2 3 4 5 6 7
8 9 10
11
1 1 1 0 CLA CLL CMA CML RAR/RTR RAL/RTL SEL IAC
ここで、各ビットはこのような演算を表します。
CLA Clear AC
CLL Clear Link
CMA Complement AC
CML Complement Link
RAR Rotate AC Right
RTR Rotate Two Right
RAL Rotate AC Left
RTL Rotate Two Left
SEL ビット8, 9の役割を選択する
IAC Increment AC
CLAとCLLはそれぞれACとリンクフラグを0クリアする命令で、CMAとCMLは同じくビット反転させる命令です。
ビット8と9には2種類のマイクロ命令が割り当てられていますが、どちらが使われるか選択するのがビット10のSELビットです。このビットが0ならビット8,
9はそれぞれRAR, RAL命令に、1ならそれぞれRTR, RTL命令となります。なお、例外的にビット8,
9共に0でビット10が1の場合には、BSWマイクロ命令の意味になります。BSW命令はByte
Swapの略で、ACの上下6 bitを入れ換えます。1文字を6 bitで表現しているので、
Byteといっても6 bit単位なんですよね。
RAR命令とRAL命令は、それぞれACのMSBとLSBの間にLフラグを入れて1 bit分の右回転ないし左回転させる命令です。RTR命令とRTL命令は、同じく右回転と左回転ですが2
bit分行うところが異なります。単純なシフト命令はありませんが、CLLマイクロ命令とRTR,
RTL命令を併用すれば、0をつめていくシフト命令を実現できます。
IACはACを1だけインクリメントする命令です。
以上のマイクロ命令が複数選択されたときに実行される順序は決まっていて、このような優先順位に従います。
1 - CLA, CLL
2 - CMA, CML
3 - IAC
4 - RAR, RAL, RTR, RTL, BSW
したがって、CMAとIACをセットしておけば2の補数表示での符号反転ができて、CLAとRTLの組み合わせでLの内容をACのLSBに移動する命令となります。
このような合成命令も含めて、意味のありそうな命令には次のようなものがあり、中には新たにニーモニックが与えられているものもあります。
Mnemonic Code
Cycles 動作
NOP 1110 0000 0000 10
No Operation
IAC 1110 0000 0001 10
Increment AC
RAL 1110 0000 0100 15
Rotate AC Left
RTL 1110 0000 0110 15
Rotate Two Left
RAR 1110 0000 1000 15
Rotate AC Right
RTR 1110 0000 1010 15
Rotate Two Right
BSW 1110 0000 0010 15
Byte Swap
CML 1110 0001 0000 10
Complement Link
CMA 1110 0010 0000 10
Complement AC
CIA 1110 0010 0001 10
Complement and Increment AC
CLL 1110 0100 0000 10
Clear Link
CLL RAL 1110 0100 0100 15 Clear Link, Rotate
AC Left
CLL RTL 1110 0100 0110 15 Clear Link, Rotate
Two Left
CLL RAR 1110 0100 1000 15 Clear Link, Rotate
AC Left
CLL RTR 1110 0100 1010 15 Clear Link, Rotate
Two Left
STL 1110 0101 0000 10
Set Link
CLA 1110 1000 0000 10
Clear AC
CLA IAC 1110 1000 0001 10 Clear AC, Increment
AC
GLK 1110 1000 0100 15
Get Link
CLA CLL 1110 1100 0000 10 Clear AC and Link
STA 1110 1010 0000 10
Set AC
マイクロ命令のビットがひとつもセットされていなければ、マイクロ命令をひとつも実行しないわけですからNOP命令ということになります。
マイクロ命令単独の命令を飛ばすと、次はCIA命令ですね。CIA命令はACのビット反転後にインクリメントを行いますから、ACの2の補数を得る命令となります。これと加算命令を組み合わせれば、減算が可能になります。
CLLと組み合わせたローテート命令は、0をつめていくシフト命令として使えます。
STL命令は、一度Linkをクリアしてから反転させますから、Lに1をセットする命令となるわけです。
CLA IAC命令は、ACに1をロードする命令ですね。
GLK命令はLフラグをACのLSBに転送する命令です。結果的にLフラグはクリアされます。
CLA CLL命令はACとLを同時にクリアする命令です。
STA命令はACを0クリアしてから反転させますから、ACのすべてのビットが1になります。符号付き整数として考えれば-1なので、これと加算命令を組み合わせればデクリメントに使えるかもしれません。
グループ2マイクロ命令は、このようなビット割り当てが行われています。
0 1 2 3 4 5
6 7 8
9 10 11
1 1 1 1 CLA SMA/SPA SZA/SNA SNL/SZL SEL OSR HLT 0
ここで、各ビットの記号はこのような操作を表します。
CLA Clear AC
SMA Skip on Minus AC
SPA Skip on Positive AC
SZA Skip on Zero AC
SNA Skip on Non-zero AC
SNL Skip on Non-zero Link
SZL Skip on Zero Link
SEL ビット5, 6, 7の役割を選択する
OSR Or with Switch Register
HLT Halt
CLAはグループ1と共通でACを0クリアする命令です。
SMA, SPA, SZA, SNA, SNL, SZLはスキップ動作を指示するマイクロ命令で、それぞれACの内容が負、ACが正、ACが0、ACが0以外、Lが0以外、Lが0という条件でスキップします。条件が成立すると、この命令の次の命令をひとつ飛ばして、その先の命令を実行するわけです。
SELビットは条件の選択と複合条件の成立に関係するビットです。SELビットが0ならビット5,
6, 7はSMA, SZA, SNLの役割を果たし、1ならSPA, SNA, SZLの役割となります。また、SELビットが0の場合にビット5,
6, 7の複数が1となっていれば、条件のひとつが成立しただけでスキップが生じます。つまりOR条件となります。逆にSELビットが1だとAND条件となり、指定された条件のすべてが成立しないとスキップしません。こういったマイクロ命令の仕様により、多様な条件判定命令を実現できます。
OSRマイクロ命令はスキップ動作とは無関係で、スイッチレジスタを読み込んでACの内容とORした結果をACに入れる命令です。スイッチレジスタとは、ミニコンピュータタイプのコンピュータのコンソールパネルにある、メモリにデータを書き込むためのデータスイッチをモデル化したもので、このマイクロ命令の実行時に特別な信号がバスに出力されて、スイッチの状態が読み込まれるようになっています。IM6100では、そういったコンソールパネルの機能を制御パネルメモリ空間という特別なメモリ空間に配置したモニタプログラムで実装できるように工夫されていて、そのモニタプログラムで使用することもできますし、普通のプログラムの中で単純な入力ポートとして利用することもできるでしょう。
HLTマイクロ命令はプログラム実行を停止させる命令です。HLTと同時にスキップマイクロ命令やOSRマイクロ命令が指示されていると、それらの実行を終えてから停止します。
マイクロ命令間の優先順位は、次のようになっています。
1 - SMA or SZA or SNL / SPA and SNA and SZL
2 - CLA
3 - OSR, HLT
スキップ条件判定が最初に行われて、それからアキュムレータのクリアとOSRやHLTが続くわけですね。この順序ならCLAとOSRを組み合わせて、単にスイッチレジスタの内容をACにロードすることも可能です。また、スキップ判定を行ってからACを0にすることもできます。この組み合わせを使うと、次にTAD命令でACに別の値をロードできて効率的です。
そういったグループ2マイクロ命令の合成命令には、次のようなものがあります。
Mnemonic Code
Cycles 動作
NOP 1111 0000 0000 10
No Operation
HLT 1111 0000 0010 10
Halt
OSR 1111 0000 0100 15
OR with Switch Register
SKP 1111 0000 1000 10
Skip (always)
SNL 1111 0001 0000 10
Skip on Non-zero Link
SZL 1111 0001 1000 10
Skip on Zero Link
SZA 1111 0010 0000 10
Skip on Zero AC (AC == 0)
SNA 1111 0010 1000 10
Skip on Non-zero AC (AC != 0)
SZA SNL 1111 0011 0000 10 Skip on Zero AC or
Non-zero Link
SNA SZL 1111 0011 1000 10 Skip on Non-zero AC
and Zero Link
SMA 1111 0100 0000 10
Skip on Minus AC (AC < 0)
SPA 1111 0100 1000 10
Skip on Positive AC (AC >= 0)
SMA SNL 1111 0101 0000 10 Skip on Minus AC or
Non-zero Link
SPA SZL 1111 0101 1000 10 Skip on Positive AC
and Zero Link
SMA SZA 1111 0110 0000 10 Skip on Minus AC or
Zero AC (AC <= 0)
SPA SNA 1111 0110 1000 10 Skip on Positive AC
and Non-zero AC (AC > 0)
SMA SZA SNL 1111 0111 0000 10 Skip on Minus AC or Zero
AC or Non-zero Link
SPA SNA SZL 1111 0111 1000 10 Skip on Positve AC and
Non-Zero AC and Zero Link
CLA 1111 1000 0000 10
Clear AC
LAS 1111 1000 0100 15
Load AC with Switch Register
SZA CLA 1111 1010 0000 10 Skip on Zero AC then
Clear AC
SNA CLA 1111 1010 1000 10 Skip on Non-Zero AC
then Clear AC
SMA CLA 1111 1100 0000 10 Skip on Minus AC then
Clear AC
SPA CLA 1111 1100 1000 10 Skip on Positive AC
then Clear AC
グループ1マイクロ命令と同じニーモニックと機能でビットパターンの異なる命令が存在しますね。たいていのマイクロ命令には説明不要でしょう。
表の4番目のSKP命令は常にスキップする命令です。SELビットで条件のORを指定して、具体的な条件を指定しないと、無条件にスキップが成立します。
LASはスイッチレジスタを1命令でACに読み込む命令で、最後の4種はスキップ動作の後でACをクリアします。SZA
CLAでACが0か判定してからACを0にするのは無駄なようですが、ACのクリアはスキップが行われた場合も行われなかった場合にも実行されますから、実際に意味があります。
グループ3マイクロ命令は、MQマイクロ命令という呼び方もされ、MQレジスタ関係の操作を行います。具体的にはこのようなビット割り当てが行われています。
0 1 2 3 4 5 6 7 8 9 10 11
1 1 1 1 CLA MQA * MQL * * * 1
*のビットは無視されます。意味のあるビットは3種だけで、その記号はこのような操作を表します。
CLA Clear AC
MQA OR MQ register into AC
MQL MQ register Load from AC
MQAはMQレジスタとACの内容をビットごとのOR演算を行ってACに結果を入れます。MQLはACの内容をMQレジスタに転送する命令です。CLAは今までと同じACのクリアです。
マイクロ命令間の優先順位は、次のようになっています。
1 - CLA
2 - MQA, MQL
MQA単独でもメモリ参照命令には存在しなかったビットごとの論理演算であるORが可能になりますし、CLAとMQAを組み合わせればMQからACへのデータ転送が行えます。
そういった合成命令には、このようなものがあります。
Mnemonic Code
Cycles 動作
NOP 1111 0000 0001 10
No Operation
MQL 1111 0001 0001 10
MQ register Load (MQ <- AC)
MQA 1111 0100 0001 10
MQ register into AC (AC <- AC | MQ)
SWP 1111 0101 0001 10
Swap AC and MQ register (MQ <-> AC)
CLA 1111 1000 0001 10
Clear AC
CAM 1111 1001 0001 10
Clear AC and MQ register (MQ, AC <- 0)
ACL 1111 1100 0001 10
Clear AC and Load MQ register into AC (AC <- MQ)
CLA SWP 1111 1101 0001 10 Clear AC and Swap AC
and MQ (AC <- MQ, MQ <- 0)
有効なビットが3 bitですから、すべての組み合わせは8種類。NOPとCLAはグループ1や2にもありました。MQLやMQAは単純なマイクロ命令ですから、もう説明の必要はありませんね。
SWP命令はMQAとMQLを組み合わせたもので、単純な組み合わせでは入れ換えにならないはずですが、とにかく入れ換え動作となっています。
CAMはACをクリアしてからMQへも転送しますから、ACとMQの両方に0が入ります。
ACLはACをクリアしてからMQとのORをとりますから、単純なMQからACへのデータ転送の意味になります。
CLA SWP命令はACをクリアしてからMQとACを入れ換えますから、結局MQをACに転送すると同時にMQを0クリアすることになります。
残るはIOT命令だけです。この、入出力機器とのデータ転送を行う命令は、次のようなただ1種類しかありません。
0 1 2 3 4 5 6 7 8 9 10 11
1 1 0 d d d d d d c c c
ここでdはデバイス選択コード、まぁI/Oポートアドレスといってもかまわないのですが、を表します。cは動作指定コードで、指定したデバイスが何を行うべきか指示するためのものです。デバイス選択コードのビット幅から最大64個の入出力機器を接続できることがわかります。ただし後で触れますが、プロセッサ自身も特殊な入出力機器としてデバイス選択コード0が割り当てられて、プロセッサ固有の制御が行われます。なお、IOT命令は17サイクルの命令実行時間を消費します。
この命令には、入力を行うのか出力を行うのかといった具体的な動作を表すものはまったくありません。デバイスを識別する選択コードと、デバイスごとに自由に決められる動作指定コードだけです。では、動作を決定する方法はどのようになっているのかというと、IM6100のIOT命令特有のバスサイクルと特殊な制御信号によります。
IM6100はIOT命令をフェッチした後の実行サイクルで、アドレスの代わりにフェッチしたIOT命令そのものを出力して、メモリ用のストローブ信号の代わりにデバイス用のストローブ信号DEVSELをアサートします。したがって、デバイス側ではDEVSEL信号がアサートされたときのアドレス3
- 8にデバイス選択コード、アドレス9 - 11に動作指定コードがあるとして、自分が選択されたか、そしてその時の動作指示は何かを読み取ることができます。そのDEVSEL信号で選択されたデバイスは、いきなりデータ転送を行うのではなく、まずC0,
C1, C2, SKPという特別な制御線に指示を行います。この指示に従って、プロセッサが次の動作を行うのです。つまり、IOT命令で何を行うのか指示を出すのは、プロセッサ側ではなくてデバイス側です。
C0, C1, C2の意味は、次のようになっています。
C0 | C1 | C2 | 動作 | 説明 |
H | H | H | Dev <- AC | ACの内容をデバイスへ出力 |
L | H | H | Dev <- AC, CLA | ACの内容をデバイスへ出力した後ACをクリア |
H | L | H | AC <- AC | Dev | デバイスから入力した値とACの論理和を求める |
L | L | H | AC <- Dev | デバイスからACへ入力する |
* | H | L | PC <- PC + Dev | PCにデバイスから送られてきた値を加算、相対ジャンプ |
* | L | L | PC <- Dev | PCにデバイスから送られてきた値を入れ、絶対ジャンプ |
SKP制御線がアサートされていると、プロセッサに次の命令をスキップさせる効果があります。このスキップ動作はC0,
C1, C2によって指定された動作が完了してから行われます。ジャンプ指示の場合なら、ジャンプしてからスキップが行われるわけです。
たとえば、プリンタインターフェースのようなものを考えてみましょう。デバイスの初期化、バッファが空かの判定、データ出力の3種類の動作が必要だとします。動作指定コード0を送った場合に特に初期化用のコマンド不要で自動的に初期化が行われるとすれば、その際の応答は0オフセットの相対ジャンプを指示すれば良いわけです。データバッファが空か、つまり次のデータを送ってよいかどうかの判定は、普通のプロセッサならステータスレジスタからの入力を行ってAND演算で必要なビットをマスクして条件判定となりますが、IM6100の場合なら動作指定コード1を送った場合がバッファ空判定の意味になるとして、0オフセットの相対ジャンプを指定すると同時にバッファが空ならSKPをアサートして空でなければネゲートするようなインターフェース回路を製作すれば、そのIOT命令がバッファが空のときにスキップする命令となります。プログラムでAND演算や条件判定を行う必要がなくなるわけです。プログラムを格納するメモリが高価な時代のアーキテクチャとしては合理的ですね。ハードウエア的にはステータスレジスタを用意して、それが読み出されたらデータバスにステータスビットを出力するのと、SKP制御信号にステータスビットを出力するのでは、それほど回路に違いがあるわけではありませんから。最後にデータ出力動作を動作指定コードの2にでも割り当てて、その場合にはC0,
C1, C2にすべてHを指定すれば単純なデータ出力動作を実現できます。ついでに動作指定コード3の場合の応答として、C0,
C1, C2にL, H, Hを出力するようにしておけば、出力動作の後でACをクリアしますから、プログラムのほうで次の値をロードしやすくなります。
このように、プロセッサとデバイスが協調しながらデバイス固有の入出力命令を定義して実行するのが、IM6100というかPDP-8の入出力動作です。PDP-8/Eとの互換性を保つには、こういった入出力機能もPDP-8/Eシステムと互換になるようなインターフェース回路を設計して外付けする必要があります。別のコンピュータでソフトウェア開発を行う際のクロスコンパイラやクロスアセンブラを利用したり、演算ライブラリの流用などを考えるだけなら、入出力回路は単純な独自設計のものでかまわないでしょうけど。
プロセッサ自身の割り込みイネーブルフラグなどの操作にもIOT命令が使用されます。プロセッサにはデバイス番号0が割り当てられていて、その0番への動作指定コードで
Mnemonic Code
Cycles 動作
SKON 1100 0000 0000 17 Skip
if Interrupt On
ION 1100 0000 0001 17
Interrupt Turn On
IOF 1100 0000 0010 17
Interrupt Turn Off
SRQ 1100 0000 0011 17
Skip if Interrupt Request
GTF 1100 0000 0100 17
Get Flags
RTF 1100 0000 0101 17
Restore Flags
SGT 1100 0000 0110 17
(Skip if Greater Than Flag)
CAF 1100 0000 0111 17
Clear All Flags
SKON命令は割り込みイネーブルフラグが有効ならスキップします。そうして、無条件に割り込み禁止とします。
ION命令とIOF命令はそれぞれ割り込みの許可と禁止です。正確にはION命令の次の命令の実行後に割り込みが許可されます。SRQ命令は外部回路の割り込み要求がアサートされている場合にスキップする命令です。
GTF命令は、ACのビット0にLinkフラグ、2に外部の割り込み状態、4に割り込みイネーブルフラグを読み込みます。RTF命令はその逆で、ACのビット0がLinkフラグに、4が割り込みイネーブルフラグにセットされます。実際の割り込みイネーブルが変更されるのは、RTF命令の次の命令が実行終了してからですが。残りのビットはIM6100単体では無視されます。ただし、メモリ拡張ハードウエアなどが存在する場合には、使用される場合があります。
SGT命令はPDP-8/E互換とするためにニーモニックが割り当てられて、外部回路で利用されることがありますが、IM6100単体では無視されます。
CAF命令は、ACとLinkとIEがすべてクリアされ、その結果として割り込みも禁止されます。
IM6100のハードウエア面についてはごく簡単にふれます。
ピン配置は、このようになっています。
VCC 1
40 DATAF
RUN 2
39 INTGNT
DMAGNT 3 38 CPSEL*
DMAREQ* 4 37 MEMSEL*
CPREQ* 5 36 IFETCH
RUN/HLT* 6 35 SKP*
RESET* 7 34 C2*
INTREQ* 8 33 C1*
XTA 9
32 C0*
LXMAR 10 31 SWSEL*
WAIT* 11 30 DEVSEL*
XTB 12 29
LINK
XTC 13 28
DX11
CLOCK 14 27 DX10
CLOCK* 15 26 GND
DX0 16 25
DX9
DX1 17 24
DX8
DX2 18 23
DX7
DX3 19 22
DX6
DX4 20 21
DX5
VCCとGNDが電源です。
CLOCKとCLOCK*がクロック発振回路で、水晶発振子を外付けしてクロックを生成できます。外部回路で生成したクロック信号を入力したい場合はCLOCKの方がTTLレベル入力です。
DX0 - DX11がデータやアドレスがマルチプレクスされたバスで、XTA, LXMAR,
WAIT, XTB, XTC, DEVSEL*, MEMSEL*がバスとメモリやI/Oとのデータ転送に関するタイミング信号となります。
C0*, C1*, C2*, SKP*はIOT命令のところで説明した入出力制御用の信号です。
RESET*はリセット信号で、PCに0FFFH、つまり全ビットがすべて1となる値をロードし、CPUを停止状態に遷移させます。したがって、プログラムで最初に実行される命令はアドレス0FFFHに納められたものになります。普通はここに間接ジャンプ命令を置いて、本来のコールドスタート地点にジャンプします。
さて、リセット後はCPUが停止状態ですから、実行状態に遷移させなくてはプログラムの実行が始まりません。それを行うのがRUN/HLT*信号で、ここにLパルスを与えるたびにそのポジティブエッジで交互に停止状態と実行状態が入れ代わります。CPUがどちらの状態にあるかを示すのが、RUN出力信号で、この端子がHなら実行状態です。RUNがLのときには外部回路をパワーダウンするといった、CMOSプロセッサならではの使いみちもあります。
割り込みに関係するのはINTREQ*とINTGNTです。INTREQ*が割り込み要求信号で、INTGNT信号が割り込み応答出力信号となります。IM6100では割り込みを受け付けるとPCの内容をアドレス000Hのメモリに書き込み、001Hから命令フェッチを開始します。あたかもアドレス000Hへのサブルーチン呼び出しのような処理が行われます。INTGNTは通常は不要ですが、メモリ拡張ハードウエアを装備している場合、正しく割り込みサービスルーチンの存在するメモリをアクセスできるようにするため、使われます。なんらかのIOT命令が実行されると、INTGNTはネゲートされます。
特別な割り込みとして、CPREQ*とCPSEL*信号が制御パネル割り込みの要求信号とサービス中を示す出力信号として用意されています。ミニコンピュータタイプのコンソールパネルを実現するのに、この制御パネル割り込みが使用されます。制御パネル割り込みでも、アドレス000HへとPCが格納されますが、新しいPCは0FFFHにセットされます。しかも制御パネル割り込みルーチンのメモリアクセスストローブ信号としてCPSEL*信号が出力されているため、そのタイミングで特別なメモリを読み書きすることによって、通常のメモリには影響を与えずに特別な制御パネルルーチンを実行することができます。ただし例外があって、間接アドレッシングを用いたTAD,
ISZ, DCA命令のオペランドの読み書きには通常通りMEMSEL*信号が出力されます。そのため、通常メモリ空間のメモリにも制御パネル割り込みルーチンからアクセスできます。制御パネル割り込みルーチンの実行中はDMAも通常の割り込みも受け付けられません。特別な命令列を実行することにより、制御パネル割り込みルーチンを終了して通常のプログラム実行を継続することができます。
DMAREQ*とDMAGNTがDMA用の信号で、DMAREQ*を与えると実行中の命令処理が終わってからDX信号をスリーステート状態にしてDMAGNTをアサートします。その状態で、外部回路によって安全にメモりアクセスが可能となります。DMAREQ*をネゲートすれば、CPUの内部状態に同期してからDMAGNTをネゲートして、通常の命令実行処理が再開されます。
IFETCHとDATAFは外部回路のメモリ拡張ハードウエアによって利用される信号です。それぞれ命令フェッチと間接アドレッシングのTAD,
ISZ, DCA命令のオペランドの読み書きを意味して、メモリ拡張ハードウエアで特別に解釈すべき命令がフェッチされたか、あるいはデータ用のメモリ空間をアクセスするのか、判定するのに用いられます。
LINK信号はLINKフラグの内容がそのまま出力されます。
かなり手短な説明となりましたが、ハードウエア面はこのようなものに仕上がっています。コンソールパネル用の機能が組み込まれていたり、PDP-8/Eと同様にミニコンピュータ的システムを構成する工夫がされています。単純な組み込み用として使用する場合も、メモリ拡張をしなければそれほど複雑な外付け回路は要りません。逆にPDP-8/Eと完全互換にしようとするなら、主要な命令は互換性があるとしてもIOT命令まで互換動作となるように入出力インターフェース回路を製作する必要があり、結構面倒だと思います。
Return to IC Collection