NECオリジナルの初の4 bit CPUがuPD751です。n-MOSプロセスで2500素子を集積、単相1 MHzクロックで動作し55種類の命令を装備、1命令を5 - 10 usで実行します。データバスとアドレスバスが分離して出力されていて、すべての信号がTTLレベルなので、外付け回路の設計が容易になっています。しかも、メモリの一部をスクラッチパッドレジスタとして使う構造になっているため、命令実行を中断させてメモリ内容を調べるだけでレジスタの内容を調べられ、アマチュアがなかなかモニタプログラムをROMに書き込めなかった時代には、デバッグが容易なアーキテクチャになっていました(その分遅いけど)。
また、拡張性重視の8 bitシステムと異なり、4 bitのマイクロプロセッサは当初より小規模の組み込み専用に使われていたため、早い時期からROMやI/Oなどまで同じチップ上に集積したシングルチップマイクロコンピュータに進化していく傾向がありました。しかしuPD751は単体CPUであり、専用のメモリやI/Oを接続する設計になっていましたが数個のICで汎用のメモリなどを接続できて、8 bit系のシステム価格が充分に低下するまでは小規模の少量生産にも向いていました。その面では他の4 bit CPUと比べても抜きんでていました。なにせ4004や4040の2倍の速度で命令を実行し、汎用メモリやI/O素子を使用する場合の回路規模は数分の1になりますから。一応、本来は電子キャッシュレジスタ用のマイクロプロセッサです。
1976年頃出版された、「つくるシリーズ2 つくるコンピュータ」トランジスタ技術編集部編の中に製作記事が載っていました。当時まだ8 bit CPUを使ったコンピュータを作ろうとすると部品代だけで相当のコストになるので、外付け回路も少なくメモリの量も半分で済む安価なコンピュータとして紹介されています。4004や4040と比べれば、ハードウェア面ではMC6800にずっと近く、8080Aを使うよりも簡単な回路になります。命令体系も、4040よりは普通よりです(が、しょせん4 bitですし、普通の方法だと4レベルしかサブルーチンがネストできないなどの制限も多い)。
左は角型キャップの後期型セラミックパッケージで小島様よりいただいたものです。右はプラスチックパッケージのもの。
ピン配置はこうなっています。
VGG 1 28 VDD CK 2 27 A11 CTF 3 26 A10 IF 4 25 A9 SA 5 24 A8 R*/W 6 23 A7 G/H* 7 22 A6 RES* 8 21 A5 CDF 9 20 A4 D3 10 19 A3 D2 11 18 A2 D1 12 17 A1 D0 13 16 A0 VSUB 14 15 GND
ここでVGGが+12 V電源、VDDが+5 V電源、VSUBが-5 V電源です。
CKはクロック信号で0.1 MHzから1 MHzの間のデューティ50 %の信号で動作します。CTFはコントロール出力でCDFはコンデション入力です。それぞれ1 bitの出力ポートと入力ポートと見なして構いません。RES*はリセット信号で、G/H*はゴー/ホールト入力でCPUを停止状態にできる信号、A0 - A11がアドレスバスでD0 - D3がデータバスです。
これからわかるように、メモリ空間は12 bit分の4096語あり、CPUが外部とデータを入出力するのは4 bit単位になります。ただし、プログラム用メモリとデータ用メモリは厳密に区分され、しかもデータ用メモリは4 bitが1 Wordなのに対し、プログラム用メモリは8 bitが1 Wordになっています。プログラム用メモリからの命令列は4 bitずつ2回に分けて読み込まれます。
このため、データとプログラムを区別するのがIF信号で、IF信号が1ならインストラクションフェッチサイクルを表し、0ならデータ入出力サイクルを表します。さらにインストラクションフェッチサイクルは4 bitずつの2回に別れますが、上位ニブルか下位ニブルかどちらを読み込むかを示すのがサブアドレスSA信号です。
バスサイクルはすべてCK信号が基準となる同期バスの一種ですが、スライディングウィンドウ的なバスサイクルを行うのが特徴です。つまり、クロックの立ち下がりでアドレスなどを出力し、読み込みが行われるのはクロックの次の次の立ち上がりになっています。これだけなら2クロックで1バスサイクルに見えますが、次の次のクロックの立ち上がりのひとつ手前の次のクロックの立ち上がりでは別のデータの読み込みを行ってしまうのです。実例で考えて見ましょう。ck0, ck2のようなckに偶数のタイミングがクロック信号の立ち下がりを、ck1, ck3のような奇数番号が付けられたものがクロック信号の立ち上がりタイミングを示すとして、クロック信号がck0, ck1, ck2, ck3...と変化していくとします。ちょうどck0のタイミングからアドレス000の命令をフェッチするサイクルが始まったとします。ck0ではアドレスバスに000の信号が出されると同時にIFが1でSAが0になります。これでアドレス0のサブアドレス0(上位ニブル)から命令を読み込むことを示します。ck1では何も起こりません。ck2では、アドレスバスに000が、IFは1のままでSAが1に変化した信号が出力されます。つまり同じアドレスの下位ニブルを読み込むようCPUが指令を出したことになります。ck3ではアドレス0の上位ニブルをデータバスから読み込みます。この瞬間もCPUが出しているサブアドレスは1で下位ニブル読み込み指令のままです。ck4では何も行いません。ck5になってアドレス0の下位ニブルをCPUがデータバスから読み込みます。このように、1クロック分、CPUの出す指令とデータバスからの読み込みのタイミングがずれた形で読み込みが行われます。おそらく、専用メモリが遅かったための対策だと思われますが、汎用の(アクセスタイムが500 nsより速い)メモリを使用する場合は1クロック分のタイミングずらし用にICが1個よけいに必要になります。
ただ、それを除けば、比較的単純なバスサイクルだということがわかるでしょう。
ダイ写真を撮影しました。撮影はNikon CoolPix990に照明としてNikon SL-1を併用しただけで、それ以上の特別な機材を使用していません。実物は約4 mm角なので、表示装置などによって現在見ている画像の大きさは多少異なるでしょうが、約30倍の倍率で見ていることになると思います。顕微鏡を使わずにここまで見えるのは少々驚きです。ただし普通にダイの拡大観察を行うための特別な顕微鏡を使用していないため、メーカーの提供するようなダイ写真とは見え方がかなり違います。
これは先に掲載したパッケージ写真とは別のチップを、20年以上前に開けたものです。開封したまま部品箱に眠っていたので、ボンディングワイヤーが取れていたり、少しゴミもありますけど、雰囲気はわかるでしょう。左下にはNEC D751の文字も読み取れますね。ダイの上部は類似パターンが12個並んでいることから、プログラムカウンタやインデックスレジスタなどのアドレス関係の回路だと思われます。中央部は命令デコーダでしょう。右下の方がアキュムレータやALUなどのデータ演算回路だと思われます。ボンディングパッドと端子の割り当てですが、右下角のものがD2端子で左上がA10端子、VSUBはサブストレートに直接接続されているのでボンディングパッドが存在しないことに留意すれば、対応付けはわかると思います。
ソフトウェア側から見たアーキテクチャについてですが、残念なことに私の手元にはNECの詳細な資料がないので、以下の記述は前に挙げた「つくるシリーズ2 つくるコンピュータ」トランジスタ技術編集部編の中の、松本吉彦氏による「uCOM-4を用いたMYCOM-4の製作」という記事を参考にしています。氏は当時の状況を反映して手書きのハンドアセンブルを行ったり小さなアセンブラが作りやすいようにニーモニックなどをNECのオリジナルから変更しているようです。そのため、NEC表記とは異なるはずですが、まぁ、どうせNECが使用していたアセンブラなど手に入るはずもなく、uPD751の全命令が説明されているのは確かですし、プログラム開発には充分でしょう。もちろん、初期の4 bitマイクロプロセッサの一例としてアーキテクチャをふりかえる目的にも。そんなわけで、NECオリジナルとは異なる説明である部分も存在するという点だけは心に留めておいてください。
内部レジスタセットはこんな形です。
4 bit幅のアキュムレータとテンポラリレジスタがあり、12 bit幅のインデックスレジスタとプログラムカウンタがあります。ここだけ見ると、ビット幅は異なりますがMC6800と似ているような感じもしますね。テンポラリレジスタはアキュムレータの内容の一時退避が主な役目ですが、特別な用途に使用する命令もあります。PCはプログラムメモリ空間を指しますが、プログラムメモリは前述のように12 bit空間で1語8 bitです。インデックスレジスタは基本的にデータメモリ空間を指しますが、こちらも12 bit空間ですからインデックスレジスタも12 bitです。ただし、1語は4 bitです。また、インデックスレジスタは4 bit単位に区切られて、別々にアキュムレータとの間で内容を転送することができます。このとき、上位からXH, XM, XLと表記します。
Zはゼロフラグで、Cはキャリーフラグです。CDFとCTFはフラグのように書きましたが、uPD751のピンと直結していて、CDFピンの状態がCDFに反映されたり、CTFの内容がCTFピンに出力されます。Cフラグ、Zフラグ、CDFの3種のフラグは、それぞれ状態をプログラム動作に反映できるように条件分岐命令が用意されています。セット状態とリセット状態のどちらかで分岐するか、2通りの命令がありますから、全部で条件分岐命令は6種類ですね。
一般に演算はアキュムレータが中心になって行われます。インデックスレジスタに関してはインクリメントとデクリメントしかできません。演算には加減算と論理演算、シフト、加算時のBCD補正と減算時のBCD補正命令などがあり、意外と充実しています。
上の図で内部レジスタセットと表現したのは理由があります。外部にもスクラッチパッドレジスタ、あるいはワーキングレジスタが定義されているためです。思いっきりアドレス範囲を限定したゼロページアドレッシングのようなもので、0から7までのレジスタ番号が使えます。このワーキングレジスタはアキュムレータやテンポラリレジスタに対応する4 bit幅のレジスタが8個、インデックスレジスタとプログラムカウンタに対応する12 bit幅のレジスタが別に8個、データメモリ上に定義されています。1 Byte命令でインデックスレジスタの内容をワーキングレジスタに退避したり、復帰したりできますから、結構便利に使える機能です。以下に表でレジスタ番号とデータメモリアドレスの対応関係を示します。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 bitレジスタは上位・中位・下位の3語がひとまとまりで操作されます。4 bit幅のレジスタはアキュムレータの内容の退避に使えるほか、加減算ではこのレジスタとアキュムレータの間で演算を行うことも可能で、ループカウンタとしても使えます。また12 bitレジスタの4から7までは、サブルーチン呼び出し時の戻りアドレスを保持するスタックとしても使用されます。これらのワーキングレジスタは、きわめて小さなゼロページと呼ぶか、TMS9900のようにマイクロプロセッサ外部に配置されたレジスタと見るべきか、微妙なところですね。
では、個別の命令を、いくつかの種類に分けて説明します。
最初にアキュムレータのロードとストアについて。
動作 ニーモニック ビットパターン クロック数 Load Accumulator Immediate LAI 0111 XXXX 5 Load Accumulator from Reg. LAR 0110 0RRR 7 Load Accumulator Direct Ix. LAD 0110 1000 7 Load Accumulator Modify Ix. LAM 0110 1MMM 7 Store Accumulator to Reg. SAR 1000 0RRR 5 Store Accumulator Direct Ix. SAD 1000 1000 5 Store Accumulator Modify Ix. SAM 1000 1MMM 5
以上の7種類の命令が含まれます。この中には、uPD751の代表的なアドレッシングモードが4種類含まれています。最初のものはイミディエートモードで、命令中の下位4 bit、ビットパターンのXXXXで示したデータを操作対象とします。LAI命令の場合はアキュムレータにXXXXというデータをロードするわけです。LAR命令とSAR命令で使われているのがワーキングレジスタアドレッシングで、ワーキングレジスタのレジスタ番号をコードのRRRの部分で指定します。LARやSARは4 bit幅のアキュムレータが主役ですから、使用されるワーキングレジスタも4 bitレジスタに限られ、もちろんレジスタ番号は0から7までが使用できます。
次はLAD命令とSAD命令のダイレクトインデックスアドレッシングで、インデックスレジスタの内容をデータメモリアドレスとして扱い、インデックスレジスタの指すメモリが対象となります。オフセットなどは指定できません。最後がモデファイドインデックスアドレッシングですが、普通に想像するようにオフセットで修飾するモードではありません。インデックスレジスタのビット4からビット6の3 bitを、命令中に指定されたMMMというビットパターンで置き換えてしまうというモードです。置換であって加算ではありません。また、MMMには1から7までが使用できます。0を指定してしまうとダイレクトインデックスアドレッシングモードと区別がつかなくなることがわかるでしょう。このモードを使えば、インデックスレジスタを変更せずに16語の整数倍だけ離れたデータメモリにアクセスできます。16桁までのBCD表示の数を二つ用意して、それを加算して別の16桁のメモリに書き込むような、いかにも電卓っぽい計算が可能になるわけです。
以上でアキュムレータ関係のロードとストアは終わりです。次はインデックスレジスタのロードとストアを紹介します。
動作 ニーモニック ビットパターン クロック数 Load indeX Immediate LXI 0100 XXXX XXXX XXXX 8 Load indeX from Register LXR 0011 0RRR 10 Load indeX from R. with iNc. LXN 0011 1rrr 10 Store indeX to Register SXR 0010 0RRR 7 Store indeX iNcremented to R. SXN 0010 1rrr 7
LXI命令はイミディエートアドレッシングで定数をインデックスレジスタにロードするもので、このグループでは唯一の2 Byte命令です。12 bitの定数値が命令コードの中に含まれます。LXR命令とSXR命令は12 bitワーキングレジスタとインデックスレジスタの内容を転送するもので、0から7までのレジスタ番号を指定できます。ロードやストアのときにインクリメント動作を追加したものが、LXN命令とSXN命令です。LXN命令はワーキングレジスタの内容に1を加えてからインデックスレジスタにロードしますが、指定したワーキングレジスタの内容は変化しません。SXN命令はインデックスレジスタをインクリメントしてからワーキングレジスタに入れます。このLXN命令とSXN命令の場合には、rrrの部分に0から6までのレジスタ番号が使用できます。7番のレジスタを指定すると別の命令コードになってしまうため、レジスタ7は指定できません。
次はアキュムレータの演算関係です。
動作 ニーモニック ビットパターン クロック数 OR Logical pointed index ORL 1001 1001 7 AND logical pointed index AND 1001 1010 7 Exclusive OR pointed index EOR 1001 1100 7 ADd Register (with carry) ADR 1010 0RRR 7 ADd pointed Direct index ADD 1010 1000 7 ADd pointed Modify index ADM 1010 1MMM 7 SuB Register (with carry) SBR 1011 0RRR 7 SuB pointed Direct index SBD 1011 1000 7 SuB pointed Modify index SBM 1011 1MMM 7 CLear Accumulator CLA 1111 0010 5 CoMprement Accumulator CMA 1111 0101 5 Rotate Accumulator Left RAL 1111 0110 5 Rotate Accumulator Right RAR 1111 0111 5 INcrement Accumulator INA 1111 1010 5 DEcrement Accumulator DEA 1111 1011 5 Decimal Adjust Add DAA 1111 1100 5 Decimal Adjust Sub DAS 1111 1101 5 Transfer Accumulator to TR TAT 1110 1011 5 Transfer TR to Accumulator TTA 1110 1111 5 CLear Carry CLC 1111 0001 5 CoMprement Carry CMC 1111 0100 5 CLear Both Acc. and carry CLB 1111 0000 5
テンポラリレジスタとの転送やキャリーフラグ操作も含まれていますが、たいていは見慣れた演算ですね。論理演算が含まれていますが、Intelの4004などには含まれていませんから、ある意味画期的ともいえる強力な演算能力だったのです。ワーキングレジスタを指定できるのは加減算だけで、RRRには0から7までのレジスタ番号を指定します。同じく加減算にはモデファイドインデックスアドレッシングも可能です。例によって命令コードのMMMには1から7までを指定できます。また、原則として2項演算はアキュムレータとダイレクトインデックスアドレッシングで指定されたメモリとの間で行われます。単項演算はアキュムレータに対してだけしか実行できません。
加減算については、すべての命令においてキャリーフラグも同時に加減算が行われます。つまり、ADR, ADD, ADMの各命令では、命令実行前にキャリーフラグが1なら、その1も同時に加算され、SBR, SBD, SBMの各命令ではキャリーの分も引かれます。そのため、キャリーフラグの状態を無視して加減算を行う場合には、その命令に先立ってCLC命令を実行しなくてはなりません。場合によってはCLB命令を使うと効率的な場面もあるかもしれません。キャリーフラグに影響を与えるのは、これらの6命令のほか、INA, DEAのインクリメントやデクリメントを行う命令や、DAA, DASといったBCD補正命令、そしてRALとRARのローテート命令です。
RAL命令はアキュムレータとキャリーフラグを接続した5 bit幅のレジスタを左へ、つまりMSBの向きへ回転させます。アキュムレータのMSBがキャリーフラグに入り、それ以前のキャリーフラグの内容がアキュムレータのLSBに入ります。RAR命令は回転する方向が逆になります。
ゼロフラグは、アキュムレータ演算で必ず変化します。そのため、EOR命令でビットパターンの一致を、AND命令で特定のビットの状態を、判定できます。uPD751のI/Oポートはデータメモリ空間にマップされますから、I/Oポートをインデックスレジスタで指しておいて、テスト用のビットパターンをアキュムレータにLAI命令でロードしてからEORやAND命令を実行すれば、I/Oポートのフラグ状態の判定が可能になります。もちろん、フラグが4 bitの中のMSBやLSBに配置されていれば、アキュムレータにフラグの状態をロードしてからRALやRAR命令を使うこともできます。このときはキャリーフラグで条件判定するわけですね。
インデックスレジスタへの操作や内部転送命令には以下のものがあります。
動作 ニーモニック ビットパターン クロック数 INcrement indeX INX 1110 0100 5 DEcrement indeX DEX 1110 0101 5 Transfer PC to indeX TPX 1110 0010 5 Transfer index-H to Acc. THA 1110 1110 5 Transfer index-M to Acc. TMA 1110 1101 5 Transfer index-L to Acc. TLA 1110 1100 5 Transfer Acc. to index-H TAH 1110 1010 5 Transfer Acc. to index-M TAM 1110 1001 5 Transfer Acc. to index-L TAL 1110 1000 5
まぁ、インクリメントとデクリメント以外は転送系なんですけど。12 bit幅のレジスタのインクリメントやデクリメントですが、4 bit幅のアキュムレータのインクリメントなどと同じクロック数しか消費しないのは意外に高速であるように思われます。TPX命令はプログラムカウンタをインデックスレジスタに入れる命令ですが、何のためにあるのか、これまでの命令の説明ではわかりにくいと思います。後で説明するように、12 bitで表現されるプログラムメモリのアドレス空間の全域にジャンプするための命令は、インデックスレジスタの内容をプログラムカウンタにロードするJPX命令しかありません。LXI命令と組み合わせて、絶対ジャンプを実現できます。JPX命令で行っていることはTransfer indeX to PCということでTXP命令と呼んでもおかしくない命令で、この逆方向の転送を行うのがTPX命令というわけです。うまく使えばコールバックのようなことも実現可能だろうと思いますが、単におまけとして付けただけの命令かもしれません。
その他の6命令はアキュムレータとの間で転送を行う命令です。アキュムレータは4 bit幅しかないのにインデックスレジスタは3倍の12 bit幅なので、上中下に分けてそれぞれに専用の命令があります。インデックスレジスタの内容をアキュムレータに移動してから加減算を行って正規のインデックス修飾のようなこともできないわけではありませんが、桁上げやらのことを考えると面倒ですね。
ではプログラムカウンタ関係を。
動作 ニーモニック ビットパターン クロック数 BRanch Always BRA 0101 1000 XXXX XXXX 8 Branch conDition Set BDS 0101 0001 XXXX XXXX 8/5 Branch conDition Clear BDC 0101 1001 XXXX XXXX 8/5 Branch Carry Set BCS 0101 0010 XXXX XXXX 8/5 Branch Carry Clear BCC 0101 1010 XXXX XXXX 8/5 Branch Zero Set BZS 0101 0100 XXXX XXXX 8/5 Branch Zero Clear BZC 0101 1100 XXXX XXXX 8/5 JumP indeX JPX 1110 0001 5 Jump index to SubRoutine JSR 1110 0011 5 SubRoutine Head SRH 0010 1111 7 ReTurn from Subroutine RTS 0011 1111 10
Branch系の命令は、プログラムカウンタの下位8 bitにXXXX XXXXの部分で指定した数値をロードします。上位4 bitは変化しません。その結果、256 Byteを1ページと数えたときに、同一のページ内へ絶対ジャンプします。ページ境界を越えて分岐する場合には、JPX命令を使用します。BDS命令とBDC命令はCDFピンの状態によって分岐が生じたり生じなかったりします。どれも分岐する場合には8クロック、分岐しない場合には5クロックを消費します。
JPX命令は前述の通り、インデックスレジスタの内容をプログラムカウンタに転送します。JSR命令は、インデックスレジスタの内容とプログラムカウンタの内容を交換します。これは本当に単なる交換であって、スタックへプログラムカウンタの内容を退避させるといった動作は行いません。交換した結果、命令実行前にインデックスレジスタに入っていたアドレスへ分岐し、リターンアドレスがインデックスレジスタに入っているわけです。1レベルのサブルーチン呼び出ししか必要なければ、リターンするときにJPX命令を実行するだけで、呼び出した場所に復帰できます。もちろんサブルーチンの中でインデックスレジスタを使用する場合は、ワーキングレジスタに退避する必要があります。
ではサブルーチンがネストする場合にはどうしたらよいでしょうか。その答がSRH命令とRTS命令です。SRH命令はインデックスレジスタの内容を、レジスタ番号4から7のどれかのワーキングレジスタに退避します。どれに退避するかは、2 bitの内部的なスタックポインタで決定されます。このスタックポインタはCPUのリセット時にクリアされ、最初にSRH命令が実行されるとレジスタ番号4のワーキングレジスタにインデックスレジスタの内容が退避され、さらにネストして使われると次は5番という具合になります。まさにワーキングレジスタの4から7までがスタック領域になっているわけです。RTS命令はスタックに退避されている値をポップしてインデックスレジスタに入れ、それをさらにプログラムカウンタにロードします。インデックスレジスタが破壊されてしまうので注意してください。SRH命令はサブルーチンの先頭に配置しなければいけない命令なので、サブルーチンヘッドと呼ばれているのですね。RTS命令は逆にサブルーチンの末尾に配置します。
ただし、これはuPD751でサブルーチンを簡単に使えるようにするための命令ですから、使用しないことも可能です。その場合、JSR命令で呼び出されたサブルーチンの先頭で何らかの方法でインデックスレジスタをデータメモリに退避しておき、サブルーチンの末尾ではその逆の操作を行って退避したデータをメモリからインデックスレジスタに持ってきてからJPX命令を実行します。
単一の命令でプログラムカウンタの書き換えと以前のプログラムカウンタの値をメモリに退避するようになっていないのは、単に風変わりだというだけでなく、実はプログラムを書く上で相当に手間を増やしています。なんたって最初にプログラムカウンタの値が退避されるのが、1本しかないインデックスレジスタですから、インデックスレジスタを使ってサブルーチンに値を渡すことができません。また、サブルーチンからインデックスレジスタに何かを入れて戻ってくることもできません。インデックスレジスタに定数のロードをしたり、内容の退避と復旧をしたり、という場面が、いやになるほど出てきます。この点は、少々つらいですね。
さて、最後にこれまでに説明していない命令をまとめて紹介します。表引きやループ制御などの複雑なものも含まれています。
動作 ニーモニック ビットパターン クロック数 Increment, Skip if Zero ISZ 1100 0RRR 9/8 Decrement, Skip if Zero DSZ 1100 1RRR 9/8 Load Acc. and TM from Table LAT 1101 XXXX 8 No Operation NOP 0000 0000 5 SoftWare Halt SWH 0000 1111 5 Set ConTrol flip flop SCT 0001 1111 5 Clear ConTrol flip flop CCT 0001 0000 5
ISZ命令とDSZ命令は少々ややこしい動作をします。RRRで指定されたワーキングレジスタからデータをテンポラリレジスタにロードし、それが0かどうかを判定します。0ならプログラムカウンタをもうひとつインクリメントして、ISZ命令やDSZ命令の直後の1 Byte命令をスキップします。0以外ならテンポラリレジスタをインクリメントないしデクリメントして、その内容を元のワーキングレジスタに戻します。15回までのループを制御することができます。ただし、説明したように命令実行時に指定のワーキングレジスタ以外にテンポラリレジスタの内容が書き変わってしまいますので、注意してください。クロック数はスキップしない場合に9クロック、スキップした場合に8クロックです。
LAT命令はプログラムメモリに入っている定数表からデータを取り込むための命令です。インデックスレジスタの指すプログラムメモリ8 bitのうち、上位4 bitがテンポラリレジスタに、下位4 bitがアキュムレータにロードされます。ただしインデックスレジスタの上位4 bitのXHは使用されず、代わりに命令コードの中のXXXXが使われます。インデックスレジスタの8 bitデータからテンポラリレジスタとアキュムレータの8 bitデータへの、表を用いた写像が得られます。一気に8 bitのデータを扱えますから、文字コード変換なども可能です。
NOPは何もしないで時間を消費してプログラムカウンタを進めるだけの命令。SWHはプログラムを停止する命令で、G/H*端子を一度LにしてからHに戻すと、SHW命令の次の命令から実行再開します。ただ停止するだけでなく、I/Oの処理待ちに使用することができます。つまりI/Oの完了割り込みに相当する信号をG/H*に接続しておいて、入出力直後にSWH命令を実行すれば、I/Oが処理を終えるまで待つことができるというわけです。
SCT命令はCTFをセットしてCTF端子にHレベルを出力する命令で、CCT命令はその逆にLレベルを出力します。
以上がuPD751の全命令です。NECのドキュメントでは異なるニーモニックとアセンブラ文法で説明されていると思いますが、命令のビットパターンが同じなら同じ動作をするわけですから、こちらの表記でも当然ながら完全なプログラムを書くことができます。
全体的に、データメモリの読み書きにも、ジャンプやサブルーチン呼び出し時にも、とにかく1本しかないインデックスレジスタが必要となりますから、インデックスレジスタとインデックスレジスタ用の事実上4本しかない(残り4本はスタック領域)ワーキングレジスタをいかに上手に使うかがコツになります。集積できる回路規模が小さかったためにハードウェアに制約の多い当時のマイクロプロセッサではあたりまえでしたが、今となってはパズルの世界と感じられることでしょう。しかし、数百ゲート規模の回路で、それなりにプログラミングできるマイクロプロセッサが作成されていたわけですから、がんばっていたというべきでしょうか。ハードウェア系の技術者の方なら理解できると思いますが、小さめのFPGAどころか現在なら中規模のCPLDで実現できるかもしれない回路規模ですからね。もっとも、そんなもので実装したら100 MHzクロック相当でも動作可能なuPD751ができあがってしまいそうですけど(内部レジスタ間の転送に50 nsも必要?もっと速いかも)。
Return to IC Collection