L-16A CPU

パナファコムは同社のミニコンピュータの経験を活かして、それをマイクロコンピュータ化した形で、1975年4月にL-16Aを発表しています。パナファコムの頭文字をつけてPFL-16Aと呼ぶ場合もあるようです。1 Wordで構成される単純な33種の命令セット、間接アドレッシングなどを含む当時としては強力なアドレッシング機能、I/Oチャネルを介して行われる入出力、CPUすらバス使用権要求を出して使用許可が出るまでバスを使えないとかSEND-ACK信号による制御を行うミニコン的なバスなど、ミニコン直系の匂いがします。

L-16Aの評価用キットとして発売されたLKit-16は、当時珍しい16 bit CPUが使われていたことで評判でした。

で、これがそのCPUであるMN1610。パッケージ違いの2種類を掲載します。MN1610は2 MHzの2相クロックで動作しますが、4 MHz版もMN1610Aとして後に製造されています。こちらも持っているけど、写真省略。

MN1610 CPU
下はMN1613と類似のパッケージで、後期型と思われます。
なんか、型番やマークから、製造は松下なんだなぁと、思えてしまいますね。

アーキテクチャ概論

16 bitの命令やデータを用い、メモリアドレスも16 bitですが、主流の8 bitマイクロプロセッサと同じ40ピンです。アドレスとデータの信号線を、同じ端子を時分割で使用して共用しています。メモリアドレスはワード単位で付けられていて、バイト単位の読み書きをハードウェア的に行う方法はありません(バイト単位のDMAを使用する場合はDMACから制御線をバスに追加しバイト単位の読み書きを行えるようにするがCPU自身はワード単位のデータ転送しかできないのは変わらない)。バイト単位のデータ操作を行うには複数の命令を組み合わせてワードデータから上位バイトか下位バイトを抜き出したり、逆にはめ込んだりするようにプログラムする必要があります。
電源が+12 V, +5 Vの他、-3 Vという少し半端な電源電圧を要求します。

レジスタは汎用レジスタがR0 - R4の5個、他にスタックポインタとステータスレジスタがあります。命令カウンタも含めてすべて16 bit幅です。
 
レジスタ名 役割
R0 汎用レジスタ
R1 汎用レジスタ
R2 汎用レジスタ
R3 または X0 汎用レジスタ兼インデックスレジスタ
R4 または X1 汎用レジスタ兼インデックスレジスタ
SP スタックポインタ
STR ステータスレジスタ
IC 命令カウンタ

汎用レジスタのR3とR4はインデックスレジスタとしても使用できます。
ICまでR7として汎用レジスタ扱いすると美しくなりそうですが、さすがにDECの特許に抵触するためか特殊レジスタ扱いになっています。ただし、L-16Aの分岐命令のビットパターンを読んでみると、R7へのロード命令と解釈できる構造になっていたりしますけど。
STRのビット割り当ては次のようになっています。
E 0 OVF 0  0 M0 M1 M2  Pk Pk Pk Pk  Pk Pk Pk Pk
ビット0 (MSB)のEは拡張レジスタで、加減算とシフト命令で16 bit以上の演算を実現するために使われます。またビット2のOVFはオーバーフローフラグで加減算命令のオーバーフロー検出で変化し、それ以外の命令では変化しません。後述しますが、L-16Aの条件判定は演算の直後に演算命令の一部として実装されているため、これ以外のフラグに相当するビットは存在しません。EとOVFだけはスキップ条件判定とは別に後で使用できるようにした方がプログラムが書きやすいという理由で取り入れられたのでしょう。ちゃんと結果が負であるとか0であるとかはプログラムで検出できますからご安心ください。M0, M1, M2は割り込みマスクで0なら割り込み禁止、1なら割り込み許可の意味になります。これからわかるようにL-16Aの割り込みは3レベルです。ちなみにM0に相当するレベル0割り込みがもっとも優先順位が高く、M2が最低順位のレベル2割り込みです。マスク不可割り込みはありません。レベル0割り込みは一般にバス閉塞検出やメモリパリティエラー、電源異常検出などに使われて事実上のマスク不可割り込みに相当します。レベル1とレベル2が一般の入出力やタイマ割り込みに使われます。STRのビット8からビット15 (LSB)までの8 bitはプログラムキーと呼ばれ、プログラマが任意の用途に使えます。通常は何らかのフラグとして使われることでしょう。

アドレッシング命令は8種類。0ページ直接、相対直接、8 bit定数を用いたX0へのインデックス修飾、同じくX1へのインデックス修飾の4種類の直接アドレッシングと、0ページ間接、相対間接、0ページ参照で得られた値によるX0へのインデックス修飾、同じくX1へのインデックス修飾という間接アドレッシング系4種類の合計8種類です。命令中のアドレス定数に与えられた情報は8 bitしかないため、たとえば相対アドレッシングではプログラムカウンタの内容に-128から+127の数値を加えた範囲のアドレスしか指定できません。0ページの範囲でもなく相対アドレッシングでもない場所をアクセスするためには、実行中のコードの近傍にアドレス定数を定義しておき、そこへの相対間接アドレッシングで参照するのが普通です。また、インデックス修飾で8 bit定数の範囲で修飾するなら直接系のインデックス修飾を使えますが、16 bit定数を使う場合にはその定数を0ページのどこかに格納して、間接系のインデックス修飾を使用することになります。
これらのアドレッシングを使用できるのは、ロードやストア、分岐などのメモリ参照命令に限られます。通常の演算命令はレジスタ−レジスタ間演算が基本です。
演算命令にはスキップ条件というものが指定できます。これは、演算後のフラグの状態によって次の命令をひとつスキップするという機能で、たとえば演算結果が0だったらスキップというような指定になります。L-16Aには条件分岐命令はなく、無条件分岐命令1種類だけになっていますので、このスキップ条件でスキップされるかもしれない場所に無条件分岐命令を配置することによって普通の条件分岐命令と同じことを実現します。
L-16Aの基本命令は33種類だけ、すべて1語命令というシンプルさです。以下に全命令を示します。

  意味                 アセンブリ言語表記
Load                     L    R, EA
Store                    ST   R, EA
Branch                   B    R, EA
Branch and Link          BAL  R, EA
Increment Memory and
Skip if Result is Zero   IMS  R, EA
Decrement Memory and
Skip if Result is Zero   DMS  R, EA

Add                      A    Rd, Rs, Skip
Subtract                 S    Rd, Rs, Skip
Compare                  C    Rd, Rs, Skip
Compare Byte             CB   Rd, Rs, Skip
Move                     MV   Rd, Rs, Skip
Move Byte                MVB  Rd, Rs, Skip
Byte Swap                BSWP Rd, Rs, Skip
Digit Swap               DSWP Rd, Rs, Skip
Load Adjust Part         LAD  Rd, Rs, Skip
And                      AND  Rd, Rs, Skip
Or                       OR   Rd, Rs, Skip
Exclusive or             EOR  Rd, Rs, Skip

Operate on E and
Shift Left 1 bit         SL   R, EM, Skip
Operate on E and
Shift Right 1 bit        SR   R, EM, Skip
Set Bit                  SBIT R, I4, Skip
Reset Bit                RBIT R, I4, Skip
Test Bit                 TBIT R, I4, Skip
Add Immediate            AI   R, I4, Skip
Subtract Immediate       SI   R, I4, Skip

Load Program Status Word LPSW I2
Halt                     H
Push the Stack           PUSH R
Pop the Stack            POP  R
Return                   RET
Read                     RD   R, I8
Write                    WT   R, I8
Move Immediate           MVI  R, I8

L命令からDMS命令までの6命令がメモリ操作用の命令で、EAでアドレッシングモードと修飾定数を示します。Rは対象レジスタを指定します。メモリ操作用命令の場合、RにはR0からR4(X0, X1の表記も可)とSPが指定できます。それ以外の命令のRやRd, Rsの指定では、さらにSTRも指定できます。次のA命令からEOR命令までの12命令が2項演算命令で、レジスタレジスタ間の演算を行った後でスキップ条件判定を行い、それによってスキップ動作を行います。SLとSRがシフト命令で、1 bitのEレジスタ(拡張レジスタ)にEMで指定される{何もしない、リセットする、セットする、反転する}の操作を行った後で、Eレジスタと指定レジスタを接続したレジスタを回転します。EM指定によって算術シフトやローテートなどが行えます。SBIT, RBIT, TBIT命令はビット操作で、指定されたビットを操作した後でスキップ判定動作を行います。AIとSI命令は指定されたレジスタに0から15までの任意の値を加減算してからスキップ判定動作を行います。LPSWは割り込みからの復帰命令で、割り込みレベルに応じて0から2までの値を指定します。HからRETまでは文字どおりの命令ですね。RDとWTはI/Oポートへの操作で、I/Oポートアドレスは8 bitの定数値で表されます。MVI命令はレジスタの下位バイトに定数をロードします。
 

命令詳細

メモリ操作

ではメモリ操作用命令の詳細について見ていきましょう。
メモリ操作用命令にはL, ST, B, BAL, IMS, DMSが含まれます。これらのビットパターンは
1 X M M  M R R R  D D D D  D D D D
という形になっています。ビット0 (MSB)は必ず1で、ビット1は命令によって0か1になります。MMMは3 bitでアドレッシングモードを表して、次のような意味になります。
 
MMM EA 意味
0 0 0 D ゼロページ直接
0 0 1 (IC) + d 相対直接
0 1 0 [D] ゼロページ間接
0 1 1 [(IC) + d] 相対間接
1 0 0 (X0) + D 定数インデックス
1 0 1 (X1) + D 定数インデックス
1 1 0 (X0) + [D] 0ページ間接インデックス
1 1 1 (X1) + [D] 0ページ間接インデックス
ここでDは8 bitの符号なし定数、dは8 bitの符号付き定数。

RRRはレジスタ指定で、次のようになっていますが、L, ST命令ではSTRを指定できません。また、B, BAL, IMS, DMSではレジスタ指定ではなくて命令を特定するビットパターンになっています。
 
RRR レジスタ名
0 0 0 R0
0 0 1 R1
0 1 0 R2
0 1 1 R3 あるいは X0
1 0 0 R4 あるいは X1
1 0 1 SP
1 1 0 STR
1 1 1 使用せず

ビット8からビット15までのDDDDDDDDは8 bitの定数を表し、相対アドレッシングのときだけ符号付きと解釈されます。
では個々の命令の説明です。

L命令とST命令
L命令のビットパターンは
1 1 M M  M R R R  D D D D  D D D D
という形です。
同じくST命令のビットパターンは
1 0 M M  M R R R  D D D D  D D D D
という形です。
MMMとRRRは上記のとおりで、STR以外のレジスタに対して値のロードやストアができます。STRが保存できないのは一見不便かもしれませんが、PUSH/POPは可能ですし、割り込み時には自動的に保存・復帰が行われますから、特に困ることはありません。どうしても特定のアドレスにSTRを格納したりしたい場合には、MV R0, STRのように別のレジスタに転送してからそのレジスタの内容を格納することになります。

B命令
B命令のビットパターンは
1 1 M M  M 1 1 1  D D D D  D D D D
という形です。指定されたアドレスにジャンプします。相対アドレッシングができますから、8 bitの範囲内(- 128から+ 127)には簡単に分岐できます。しかし、それを越える範囲にジャンプするには、近くのメモリにアドレス定数を格納しておいて、そこへの相対間接アドレッシングを利用します。可変長命令なら直接アドレッシングで16 bit定数を扱うような設計にできたでしょうが、すべての命令が16 bit固定長のため、こんな形になっています。

BAL命令
BAL命令のビットパターンは
1 0 M M  M 1 1 1  D D D D  D D D D
という形です。
Branch and Linkという名称がミニコンピュータ的な呼び方ですね。サブルーチン呼び出し命令ですが、Linkをスタック上に残しておいてRET命令で呼び出した場所へとLinkをたどって戻ることができるようになっているわけです。

IMS命令とDMS命令
IMS命令のビットパターンは
1 1 M M  M 1 1 0  D D D D  D D D D
という形です。
DMS命令のビットパターンは
1 0 M M  M 1 1 0  D D D D  D D D D
という形です。
L命令やST命令のレジスタ指定をSTRにした形になっています。ま、だからこそ、L命令やST命令に限ってはSTRを指定することができなかったのですが。これは特定のメモリアドレスをループカウンタとして使用する命令です。IMS命令は指定されたメモリの内容をインクリメントして、その結果が0ならば次の命令をひとつだけスキップします。DMS命令は指定されたメモリ内容をデクリメントする点がIMSと異なります。スキップする命令にB命令を指定すれば、あらかじめそのメモリに入っていた数値に従ってループするコードになります。

2項演算命令

2項演算命令には12種類の命令があります。すべてレジスタ−レジスタ間演算です。一般化命令ビットパターンは
0 1 X X  X Rd Rd Rd  S S S S  X Rs Rs Rs
という形です。Xのビットは命令によって変化する部分でRdがディスティネーションレジスタ、Rsがソースレジスタを表します。一般にRd <- Rd op Rsという形の演算で、原則的にRdが書き変わります(CとCB命令が例外)。特徴的なのはSで表したスキップ条件で、演算結果がスキップ条件を満たすと、次の命令がスキップされます。L-16Aでは一般の条件分岐命令が存在せず、演算命令に付随して+1の相対条件ジャンプがあるような形だと言えるでしょうか。当然、普通の条件分岐を行うにはスキップを行う命令にB命令を指定します。もちろん任意の命令が書けますから、条件に応じてサブルーチンを呼び出すならBAL命令を、条件に応じて別のレジスタをインクリメントするならAI R0, 1などといった命令を配置することになります。
スキップ条件には以下の表のように16種類があります。アセンブリ言語で演算命令はOP Rd, Rs, Skipというように最後にスキップ条件を指定しますが、OP Rd, Rsのように省略することもでき、その場合は0000のスキップせずという意味になります。
 
SSSS 記号 意味
0 0 0 0 スキップせず
0 0 0 1 SKP 無条件スキップ
0 0 1 0 M 結果が負
0 0 1 1 PZ 結果が正または零
0 1 0 0 ZまたはE 結果が零
0 1 0 1 NZまたはNE 結果が零でない
0 1 1 0 MZ 結果が負または零
0 1 1 1 P 結果が正
1 0 0 0 EZ Eレジスタが零
1 0 0 1 ENZ Eレジスタが零でない
1 0 1 0 OZ OVFが零
1 0 1 1 ONZ OVFが零でない
1 1 0 0 LMZ 結果が等しいまたは小
1 1 0 1 LP 結果が大
1 1 1 0 LPZ 結果が大または等しい
1 1 1 1 LM 結果が小

A, S, AND, OR, EOR命令
では2項演算命令の各論に入ります。まずは代表的な加減算と論理演算をまとめて。
A    0 1 0 1  1 Rd Rd Rd  S S S S  1 Rs Rs Rs
S    0 1 0 1  1 Rd Rd Rd  S S S S  0 Rs Rs Rs
AND  0 1 1 0  1 Rd Rd Rd  S S S S  1 Rs Rs Rs
OR   0 1 1 0  0 Rd Rd Rd  S S S S  1 Rs Rs Rs
EOR  0 1 1 0  0 Rd Rd Rd  S S S S  0 Rs Rs Rs
加減算のA命令とS命令ではEとOVFが正しくセットされ、すべてのスキップ条件が使用できます。2項演算命令のうちAとS以外ではEもOVFも変化せず、その前のAかS命令の結果が保存されていますから、AND R0, R1, EZなどとEを用いたスキップ条件を指定すると、その前に実行したA, S命令の結果によってスキップが生じます。また、A, S命令以外では桁上がりも変化しませんから、大小判定に関するスキップ条件は意味を持たないことに注意してください。レジスタの特定のビットがセットされているかどうかを判定するには、後述のビット操作命令を使用するとよいでしょう。なお、定石ですが、EOR R0, R0のようにEORでRdとRsに同じレジスタを指定すれば、そのレジスタの内容を0にできます。LKit-16のアセンブラではCLR Rnという命令が定義されていて、自動的にEOR Rn, Rnのビットパターンを出力します。

比較命令
C    0 1 0 1  0 Rd Rd Rd  S S S S 1 Rs Rs Rs
CB   0 1 0 1  0 Rd Rd Rd  S S S S 0 Rs Rs Rs
この二つの命令はRd - Rsを行った結果によってスキップ判定を行います。RdもRsも、さらにEもOVFも変化しません。ただ、大小判定や零判定は正しく動作します。Cがレジスタの内容16 bit全部、CBがレジスタの下位8 bitだけについて、比較を行います。

移動命令
MV   0 1 1 1  1 Rd Rd Rd  S S S S 1 Rs Rs Rs
MVB  0 1 1 1  1 Rd Rd Rd  S S S S 0 Rs Rs Rs
この命令はRsの内容をRdに転送します。MV命令はレジスタの内容すべて、MVB命令はレジスタの下位8 bitのみを転送します。結果に応じてスキップ判定が行われます。RdとRsに同じレジスタを指定すればレジスタの内容が変化しませんから、MV R0, R0ならNOP命令と同じ意味になります。また、たとえばEレジスタが0か1かを判定するには、MV R0, R0, EZなどと記述すればよく、特定のレジスタの下位バイトの内容が0かどうかを判定するにはMVB Rn, Rn, Zと記述することができます。EやOVFの内容判定にはSTRに対するビット操作命令を使用することもできますが、MV命令の方がスキップ条件にEやOVF判定の意図を明示しやすいので、マクロ命令を使えない場合にはわかりやすいかもしれません。

スワップ命令
BSWP 0 1 1 1  0 Rd Rd Rd  S S S S 1 Rs Rs Rs
DSWP 0 1 1 1  0 Rd Rd Rd  S S S S 0 Rs Rs Rs
これらの命令は一種のMV命令で、Rsの内容をRdへ転送しますが、その際に一部のビット位置を入れ替えるのが特徴です。BSWP命令はRsの下位バイトがRdの上位バイトへ、Rsの上位バイトがRdの下位バイトへ転送されます。DSWP命令はRsのビット0からビット3までとビット12からビット15まではそのままRdに移動しますが、Rsのビット4からビット7がRdのビット8からビット11に、Rsのビット8からビット11がRdのビット4からビット7へと転送されます。つまり、第1デジットから第4デジットに16 bitデータを区分すると、第2デジットと第3デジットを入れ替えて転送する命令です。L-16Aではメモリとレジスタ間のデータ転送はL命令とST命令で行いますが、常に16 bitで行われます。メモリアドレスは16 bitワード単位で割り振られ、バイトアドレスマシンではありません。ですから1 Byte単位のデータ処理を行う場合はBSWP命令で上位バイトと下位バイトを入れ替えながらMVB命令などと組み合わせて遂行することになります。

10進補正命令
LAD  0 1 1 0  1 Rd Rd Rd  S S S S 0 Rs Rs Rs
LAD命令は少々変わった命令で、Rd + Rsを試しに行って、桁上がりが発生したデジットに6を、発生しないデジットには0を、ロードする命令です。BCD演算を行う際に、A命令やS命令と組み合わせて10進補正を行うためのものです。16 bit演算のため、デジットごとの桁上がりをフラグで表現すると補助キャリーが3個必要になるため、8 bit CPUのようなハーフキャリーを使用する補正命令を実現しにくかったのでしょうか。たとえばR0とR1でBCDの加算を行う場合、
        L    R2, C6
        A    R2, R0 ; R0にはBCDの数値が入っているのでここで桁上がりはない
        LAD  R2, R1 ; ここでR2に補正値が設定される。
        A    R0, R2
        A    R0, R1
;
C6:     DC   X'6666'  ; 16進数で6666、補正用の定数
などとします。減算は補正用の定数が不要で少し簡単になります。パズルだと思って考えてみてください。同じBCD演算でも時計のように特定の桁が6で桁上がり補正を行う必要のある場合、補正用の定数を変更して少々コードを追加をすると実現できます。

シフト命令

シフト命令には左シフトを行うSL命令と右シフトを行うSR命令があります。ビットパターンはそれぞれ、このようになっています。
SL   0 0 1 0  0 R R R  S S S S  1 1 E E
SR   0 0 1 0  0 R R R  S S S S  1 0 E E
RRRの部分がレジスタ指定でSSSSがスキップ条件なのは2項演算命令と変わりません。特有なのはEEのEレジスタ操作指定で、次の表のようにEレジスタを操作して、その後に指定レジスタのビット0とビット15の間にEレジスタを挟み込んでローテートします。つまりSL命令ならEレジスタの内容が指定レジスタのビット15に入り、指定レジスタのビット0の内容がEに入ります。
 
EE 記号 動作
0 0 Eレジスタ操作なし
0 1 RE 0 -> E
1 0 SE 1 -> E
1 1 CE not(E) -> E

シフト命令といいながら実際はローテートになっていますが、RE指定を行えば0を詰め込む単純なシフト命令になります。レジスタ内容の正負を判定してからSR Rn, REかSR Rn, SEを行えば算術右シフトになります。

ビット操作命令と定数加減算命令

ビット操作命令と定数加減算命令は4 bitの定数を扱うという点で同じ命令パターンになっています。すべての命令パターンを並べてみましょう。
SBIT 0 0 1 1  1 R R R  S S S S  N N N N
RBIT 0 0 1 1  0 R R R  S S S S  N N N N
TBIT 0 0 1 0  1 R R R  S S S S  N N N N
AI   0 1 0 0  1 R R R  S S S S  N N N N
SI   0 1 0 0  0 R R R  S S S S  N N N N
SBIT命令はRRRで指定したレジスタのNNNN番目のビットをセットし、その後にスキップ判定を行います。RBITは指定ビットのリセットで、TBITは指定ビットのテストです。たとえばR0のビット3が1か0かはTBIT R0, 3, Zで判定できます。AIは指定レジスタに0から15までの定数を加算します。SIは同様に0から15までの定数を減算します。

入出力命令とMVI命令

RD, WT, MVIの各命令は8 bitの定数を使用する点で似ています。
RD   0 0 0 1  1 R R R  N N N N  N N N N
WT   0 0 0 1  0 R R R  N N N N  N N N N
MVI  0 0 0 0  1 R R R  N N N N  N N N N
RD命令はNNNNNNNNで指定されたI/Oアドレスに配置されている入力装置から値を読み込んでレジスタに格納します。WT命令は逆にレジスタの内容を指定I/Oアドレスに書き込みます。MVI命令はNNNNNNNNで指定された8 bit定数を指定レジスタの下位8 bitにロードします。上位8 bitは変化しません。

その他

以上に挙げた命令以外にLPSW, H, PUSH, POP, RET命令があります。
LPSW 0 0 1 0  0 0 0 0  0 0 0 0  0 1 L L
H    0 0 1 0  0 0 0 0  0 0 0 0  0 0 0 0
PUSH 0 0 1 0  0 R R R  0 0 0 0  0 0 0 1
POP  0 0 1 0  0 R R R  0 0 0 0  0 0 1 0
RET  0 0 1 0  0 0 0 0  0 0 0 0  0 0 1 1
LPSW命令は割り込みからの復帰命令です。LLは割り込みレベルを表し、00, 01, 10の3種類を指定できます。ただし11を指定しても対応する割り込みレベルは存在しませんが動作してしまい、アドレス0006 - 0007の内容をSTRとICにロードしてしまいます。H命令はプロセッサを停止状態に遷移させます。停止状態のCPUはSTRT*信号によってのみ動作状態へ遷移します。PUSHとPOPはスタックにレジスタを保存・復元するための命令です。RET命令はBAL命令で呼び出されたサブルーチンからのリターンに使用します。なお、未定義の命令はH命令と解釈されます。

ハードウェア詳細

さて、気分を変えてハードウェア的な面から眺めてみます。
まずはお決まりのピン配置と信号の意味を。
VBG   1       40 WRT
BS15  2       39 ADSD
BS14  3       38 ISYC*
BS13  4       37 ADAK*
BS12  5       36 BSRQ*
VSS   6       35 BSAV
BS11  7       34 CP2
BS10  8       33 CP1
BS09  9       32 DTAK*
BS08 10       31 DTSD
BS07 11       30 FSYC*
BS06 12       29 IOP
BS05 13       28 RST*
BS04 14       27 HALT*
BS03 15       26 CSRQ*
BS02 16       25 IRQ2*
BS01 17       24 IRQ1*
BS00 18       23 IRQ0*
VDD  19       22 MANU*
VGG  20       21 STRT*
電源はVBG, VDD, VGGの3種類。VGGが+12 VでVDDが+5 Vなのはよいとして、VBGは-3 Vと、少々半端な値です。もっともVBGはバイアス用電圧で、電流はほとんど流れませんから、-5 Vや-12 Vの一般的な負電圧電源から抵抗で分圧して作成することもできます。
BS15 - BS00がバス信号になります。アドレスとデータが時分割で入出力されます。ただし、BS00がMSB(最上位ビット)でBS15がLSB(最下位ビット)となっています。この辺、IntelやMotorolaやDECのビット番号の割り当てと逆なので注意してください。これはビット操作命令のビット番号も同じです。国産のミニコンピュータを始め、マイクロプロセッサでもTMS9900シリーズのようにビット0がMSBというコンピュータだっていくつもありました。こんなのは約束ですから。1の位、2の位、4の位、というように、右側の桁ほど小さな重みという意味ではLSBをビット0にする意味もあるでしょうし、2進数を図示するときに左側から順に番号をふるというのも自然でしょう。要は、マニュアル類の中で統一されていれば良いわけです。
CP1とCP2はクロック信号で8080Aのように12 V振幅が必要です。IOPが1ならI/Oバスサイクルで、0ならメモリバスサイクルです。WRTが1ならCPUから書き込みが行われ、0なら読み込みです。RST*はリセット信号で、IRQ0*, IRQ1*, IRQ2*は割り込み要求信号、HALT*はCPUが動作しているか停止しているかを示します。このあたりはどのCPUにもありますから、いいでしょう。
バスサイクルを表す信号で特徴的なのは、BSRQ*, BSAV, ADSD, ADAK*, DTSD, DTAK*です。この6本の信号、実は2本ずつの対になっている3組ですが、これでバスとハンドシェークを行ってデータ転送を行います。まずCPUがバスサイクルを開始しようとするとき、BSRQ*を出力してバス使用要求を表明します。バスコントローラからBSAV信号が返ってきてバスの使用許可が出ると、ADSDを出力してBS15 - BS00にアドレスを出力します。バス側のすべてのデバイスがアドレスを受け取ったという信号がADAK*で、これをCPUが確認すると、やっとDTSDを出力します。データの読み込みならそれだけですが、データの書き込みなら、DTSDと同時にBS15 - BS00にデータも出力します。先にアドレスで指定されたデバイスがDTSDを受け取ると、読み書きに充分な時間が経過した後でDTAK*を出力します。CPUがDTAK*を受け取ると、やっと1回分のバスサイクルが完了したことになります。必ずアクノレッジ信号を待ちますから、非同期バスです。なお、ファミリLSIのMN1640には、DTAK*信号が一定時間内に返ってこないのを検出して、CPUへと仮のDTAK*を送るのと同時にバス閉塞割り込みを発生させる回路が内蔵されています。
1回のバスサイクルで3回もハンドシェークを行うので、それほど高速のバスサイクルは実行できません。逆に、SCSIみたいに強力なバッファでバスを駆動する場合は、任意の時間をかけてバスサイクルを確実に実行できますから、バスの総延長を10 mくらい延ばしたって確実なデータ転送を行えます。1970年頃は、磁気テープ駆動装置やディスクサブシステムなんかは冷蔵庫並みの大きさがあったりしましたから、バスが短いと高速の周辺機器が接続できません。そんな時代を引きずった、いかにもミニコン時代のバスサイクルです。高速といっても、せいぜい1.5 MByte/sくらいの転送速度ですけどね(ワード単位の転送サイクルで考えると1 Mcycle/sもいかない)。アドレスとデータを時分割で転送する仕組みも、バスのケーブルが長くなるなら、電線の本数を減らしてコストダウンに役立ちます。電線やコネクタのコストだけでなく、電線を駆動する高価な高性能バスバッファの回路数を、アドレスとデータを別々に伝送するより減らせますから。そう考えると、合理的な仕組みに見えてきます。バスサイクル開始前にBSRQ*でバス使用要求を必ず出すのも、マルチバスマスタや密結合マルチプロセッサのシステム向きですね。逆に、プリント基板1枚に全システムが搭載されてCPU以外にバスマスタなんか存在しないような小規模な組み込みシステムへの応用には、おおげさすぎる仕組みですけど。
STRT*とMANU*は起動モードを指定する信号です(少々不正確かな)。FSYCは命令フェッチサイクルを、ISYC*は割り込みサイクルを示します。
最後に残ったCSRQ*は、いかにもミニコンピュータ的な使い方をするための信号です。これはConSole ReQuestの略で、CPUが停止状態のときのみに有効です。この信号が有効な状態でHからLへと遷移したのをCPUが検出すると、I/O空間のアドレス0から1語をCPUが読み込み、それを命令として実行します。これがなぜミニコンピュータ的な信号か、わかりにくいかもしれません。ミニコンピュータのメモリが少なく、デバッガとかをメモリに常駐させてデバッグが行えなかったような頃、1命令ずつ機械語を実行して、そのたびにメモリやレジスタの内容を調べてデバッグしていました。このような作業は、コンソールパネルに並んだ多数のスイッチとランプを操作して行います。コンピュータがトランジスタや簡単なICで作成されていた頃、レジスタの内容を調べるには、その値を保持しているICやデバイスから電線を延ばして、コンソールパネルのランプに接続すればよかったわけです。しかしLSI化されてしまうと、LSI内部のレジスタから電線を引っ張ってくることはできません。そこで、I/O空間アドレス0にたとえばWT R0, 1という命令に相当するビットパターンを入れてCSRQ*パルスをCPUに与えると、このCPUはR0の内容をI/Oポートのアドレス1に書き込みます。そこにLEDでも接続しておけば、一発でR0の内容が表示されます。コンソールパネルにレジスタ表示の切り替えスイッチを用意しておいて、それに応じてI/Oポートのアドレス0からWT R0, 1とかWT R1, 1とかWT X1, 1とかの命令がCPUに読み込まれるようにしておけば、すべてのレジスタの内容を必要に応じてコンソールに表示することができます。逆に、I/Oポートのアドレス1をCPUが読み込んだときにコンソールパネルの特定のスイッチ群の内容を読み込むようにしておけば、CSRQ*信号と共にRD R0, 1とかRD R2, 1のような命令を読み込ませて、レジスタに任意の値を設定できます。また、B命令(分岐命令)を読み込ませれば、次にCPUが動作状態になったときに特定のアドレスからプログラムを実行させられます。このようなことを、1 bitもモニタプログラムを使わずにハードウェア的に実行することができるのは、マイクロコンピュータとしては特異なものだといえると思います。ミニコンピュータ的なコンソールパネルを実現するための機能がわざわざ入っているわけですから。
実はIntel社製の8080を使用したMITS社のAltair 8800bでも同様のことを実現していますが、L-16Aで行うよりはるかに複雑な回路とROMを使用しています。Altair 8800bでは、ある意味、ユーザのメモリ空間からは見えない空間にモニタプログラムを配置しているわけで、まぁ面倒なことをしているわけですが、大半のマイクロコンピュータがコンソールパネルなど不要な応用に使用されることを考えれば、L-16Aの方が無駄な回路を内蔵しているとも言えるでしょう。とにかく、おもしろいハードウェアです。

割り込みメカニズム

L-16Aの割り込みはすでに説明したように3レベルあります。割り込み信号が受け付けられると、CPUはICとSTRの内容を保存して割り込みルーチン用のICとSTRのデータを読み込みます。ICとSTRのペアをプログラムステータスワード(PSW)と呼ぶので、Old PSW (OPSW)を保存しNew PSW (NPSW)を読み込むと言い換えることもできます。L-16AはOPSWをスタックにではなく、メモリの特定のアドレスに格納します。また、NPSWもベクタ読み込みで決めるわけでなく割り込みレベルに応じたメモリの特定アドレスから読み込みます。OPSW領域とNPSW領域だけが64 KWordのメモリ空間でCPUに特別な意味を持つアドレスといえるでしょう(0ページもアドレッシング上特別な意味を持つといえるが)。
OPSW領域はアドレス0から始まります。
0000  レベル0 STR退避用
0001  レベル0 IC退避用
0002  レベル1 STR退避用
0003  レベル1 IC退避用
0004  レベル2 STR退避用
0005  レベル2 IC退避用
NPSW領域は0ページが終わって1ページ目の先頭にあります。アドレスは16進数表記です。
0100  レベル0 STR情報
0101  レベル0 IC情報
0102  レベル1 STR情報
0103  レベル1 IC情報
0104  レベル2 STR情報
0105  レベル2 IC情報
レベル0のNPSW情報は自動スタート時にも参照されます。このNPSW領域のIC部分に割り込みサービスルーチンのアドレスを用意しておき、STR部分には適切な割り込みマスクを施しておけば、割り込み信号によって異常な多重割り込みが生じないようにして割り込みサービスルーチンが呼び出されます。スタック構造でないので、同一レベルの多重割り込みはこのままでは実現できません。仮に同一レベルの多重割り込みが必要なら、OPSW領域に記録されたPSW情報を割り込みサービスルーチンの先頭でスタック状のデータ構造に退避して、その後で割り込みマスクを許可状態にセットする必要があります。もちろんこの場合、LPSW命令の前に退避しておいたPSW情報を復元します。
割り込みで自動退避されるのはPSWだけですから、割り込みサービスルーチンで必要なら他の汎用レジスタも退避しなくてはなりません。
割り込み要求信号は3本なので、実用的には複数の割り込み信号源の出力をワイヤードORして割り込みを受け付けます。なお、MN1640 RSCの機能を用い、割り込みステータスレジスタから個別の割り込み要求情報を読み込むことで、各レベルにつき16種類以下の割り込み信号源のどれが実際に割り込み要求を行ったのか、調べることができます。

Return to IC Collection