4004

投稿者: 芦田和毅. Posted in MCS-4

インストラクション

ここでは,4004に備わる45個のインストラクションについて1つずつ説明していきます.


マシン命令群

NOP(No OPeration)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 0 0 0 0 0 0

このインストラクションを行うと,CPUは何もしません.このため,ウェイトをするときに用いられます.


JCN(Jump CoNdition)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 0 1 C1 C2 C3 C4
A2 A2 A2 A2 A1 A1 A1
A1

このインストラクションを実行すると,プログラマによって書かれた条件によって分岐をします.条件は下表の6種類で,いずれかに当てはまるとジャンプします.C1はC2C3C4の条件を反転させます.たとえばC3(キャリが0の場合ジャンプ)が1のときにC1が1であれば,キャリが1の場合にジャンプすることを意味します.ジャンプ先アドレスであるA3A3A3A3A2A2A2A2A1A1A1A1(12[bit])のうちA2A2A2A2A1A1A1A1はJCN命令にあるものであり,A3A3A3A3はJCN命令が存在するアドレスの上位4ビットです.したがってJCN命令では違うROMにあるアドレスにはジャンプできません.

条件 C1が0の場合 C1が1の場合
C2 アキュムレータの値が0の場合にジャンプします アキュムレータの値が1の場合にジャンプします
C3 キャリが1の場合ジャンプします キャリが0の場合ジャンプします
C4 テスト端子の信号がLow(=-15V)の場合ジャンプします テスト端子の信号がHigh(=0V)の場合ジャンプします

FIM(Fetch IMmediate)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 1 0 R R R 0
D2 D2 D2 D2 D1 D1 D1
D1

この命令は,ROMにある8[bit]のデータD2D2D2D2D1D1D1D1を取ってきて,レジスタ対RRRに代入するときに用いられます.ROMからデータを取ってくることをFetchといい,それをすぐに行うことから,Fetch Immediateというニーモニックになります.取ってきたD2D2D2D2とD1D1D1D1がレジスタRRR0とRRR1のどちらにはいるかということはデータシートに書かれていませんので,ここではD2D2D2D2をRRR0に,D1D1D1D1をRRR1に代入することとします.


SRC(Send Register Control)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 1 0 R R R 1

この命令について説明するのに先立ち,上記の表にあるRRRについて説明します.これはインデックスレジスタ対を表しており,例えばRRR=110だとするとインデックスレジスタ1100と1101に入っている8ビットのデータを表しています.

この命令には2種類の用途があります.一つ目はRAMのアドレスを指定するときに用いられます.RAMアドレスはX2とX3のサイクルで送られ,X2の上位2[bit]でチップ番号,下位2[bit]でRAMアレイ番号,X3でメインメモリ文字のアドレスを指定します.指定されたアドレスをRAMは記憶しておき,このあと行われるRAMに対する読み書き命令で用います.

もうひとつの用途として,ROMのチップを指定するときに用いられます.ROMに備わる入出力端子を指定するとき,ROMの指定をあらかじめしておく必要があります.その指定するとき使われるのです.ROMは4001が16個で構成されていますから4[bit]あればよく,従いましてX2サイクルで4001のA3(アドレスの上位4[bit])を送ります.なお,X3サイクルに送られてくる情報をROMは無視します.


FIN(Fetch INdirect)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 1 1 R
R
R
0

この命令は,インデックスレジスタ0000の値をROMアドレスのA1A1A1A1(下位4[bit])とし,同じくインデックスレジスタ0001の値をROMアドレスのA2A2A2A2(中位4ビット)とした時のROMの値を取ってきて,レジスタ対RRRに入れます.ROMアドレスにはA3A3A3A3がありますが,この値はFIN命令のあるアドレスと同じものを用います.従いまして,FIN命令で取得できる値は同じROMチップ(4001)内に限られます.FIN命令は主に定数のテーブルをROMに格納しておき,それを参照するときに用いられます.

FIN命令は,一見すると1インストラクションサイクルのように見えますが,FIN命令を実行するインストラクションサイクル内だけで完結しません.なぜなら,ROMからデータを取ってくるのは次のインストラクションサイクルで行われるからです.FIN命令によってROM内のデータを取ってくるまでの流れを下に示します.

  1. ROMからFIN命令自体を取ってきます.このインストラクションサイクルでは,ROMからデータを取って来ずに終わります.
  2. 次に実行するインストラクションサイクルにおいて,A1およびA2をインデックスレジスタ0000と0001に置き換えます.なお,A3はプログラムカウンタにある値をそのまま用います.
  3. M1およびM2サイクルでROMからデータを取ってきて,X1サイクルでレジスタ対RRRに格納します.
  4. プログラムカウンタをFIN命令があったものの次のものにします.

JIN(Jump INdirect)

D3 D2 D1 D0 D3 D2 D1 D0
0 0 1 1 R
R
R
1

この命令は,レジスタ対RRRにある8[bit]の値をROMのアドレスA1A2としてジャンプします.A3はJIN命令のあるアドレスと同じです.従いまして,ジャンプ先は同じROMチップ(4001)内に限られます.なお,FINとJINは同じOPRであるため,OPAのD0で区別します.


JUN(Jump UNconditional)

D3 D2 D1 D0 D3 D2 D1 D0
0 1 0 0 A3 A3 A3 A3
A2 A2 A2 A2 A1 A1 A1
A1

この命令は,指定されたアドレスA3A3A3A3A2A2A2A2A1A1A1A1へ無条件にジャンプします.ジャンプしたのち,もとのアドレスへ戻ってくることを想定していません.


JMS(JuMp Subroutine)

D3 D2 D1 D0 D3 D2 D1 D0
0 1 0 1 A3 A3 A3 A3
A2 A2 A2 A2 A1 A1 A1
A1

この命令は,指定されたアドレスA3A3A3A3A2A2A2A2A1A1A1A1へジャンプします.ただし,ジャンプしたのちに再びもとのアドレスへ戻ってくることを想定しているため,もとのアドレスをプログラムカウンタのスタックに格納します.なお,もとのアドレスに戻るにはBBLを用います.


INC(INCrement)

D3 D2 D1 D0 D3 D2 D1 D0
0 1 1 0 R
R
R
R

この命令は,インデックスレジスタRRRRにある値を1増やします.


ISZ(Increment and go Same rom if Zero)

D3 D2 D1 D0 D3 D2 D1 D0
0 1 1 1 R R R R
A2 A2 A2 A2 A1 A1 A1
A1

この命令は,インデックスレジスタRRRRの値を1増やし,その結果,0でなかったらプログラムカウンタをA3A3A3A3A2A2A2A2A1A1A1A1にし,0であったら通常と同様にプログラムカウンタを1増やして次の命令を行うようにします.A3A3A3A3はISZの命令があるROMのアドレスと同じですので,同じ4001チップ内しかジャンプすることはできません.ISZ命令は主に繰り返し処理を行うときに用いられ,インデックスレジスタが4ビットであるため最大16回繰り返すことができます.もし,それ以上の繰り返し処理を行う場合には,多重ループにする等をして対処する必要があります.


ADD(ADD)

D3 D2 D1 D0 D3 D2 D1 D0
1 0 0 0 R
R
R
R

この命令は,インデックスレジスタRRRRの値とアキュムレータの値,またキャリが立っていた場合にはさらに1を足し合わせ,結果をアキュムレータに入れます.もしけた上がりが発生した場合には,キャリに1が立ちます.


SUB(SUBtract)

D3 D2 D1 D0 D3 D2 D1 D0
1 0 0 1 R
R
R
R

この命令は,アキュムレータの値 + インデックスレジスタRRRRの値を反転したもの + キャリを反転したものを行い,結果をアキュムレータとキャリに入れます.これはアキュムレータ-インデックスレジスタRRRRを表しています.ただし,キャリ(この場合には桁借りが発生している=1)の場合にはその数から1を減らします.また桁借りが発生した場合にはキャリには0が設定され,反対に桁借りが発生しなかった場合には1が設定されます.

分かりづらいので4個の例を挙げて説明します.

例1:アキュムレータの値=7,インデックスレジスタの値=5,キャリ=1(下からの桁借りあり)とすると,0b0111+0b1010+0b0000=0b10001となり,アキュムレータの値が0b0001(=1),キャリが1となります.つまり,7-5-1=1で桁借り無しであったことを表しています.

例2:アキュムレータの値=7,インデックスレジスタの値=5,キャリ=0(下からの桁借り無し)とすると,0b0111+0b1010+0b0001=0b10010となり,アキュムレータの値が0b0010(=2),キャリが1となります.つまり,7-5=2で桁借り無しであることを表しています.

例3:アキュムレータの値が5,インデックスレジスタの値=7,キャリ=1(下からの桁借りあり)とすると,0b0101+0b1000+0b0000=0b01101となり,アキュムレータの値が0b1101,キャリが0となります.つまり5-7-1=-3(2の補数表記では1101)で桁借りありであることを表しています.

例4:アキュムレータの値が5,インデックスレジスタの値=7,キャリ=0(下からの桁借り無し)とすると,0b0101+0b1000+0b0001=0b01110となり,アキュムレータの値が0b1110,キャリが0となります.つまり,5-7=-2(2の補数表記では1110)で桁借りありであることを表しています.


LD(LoaD)

D3 D2 D1 D0 D3 D2 D1 D0
1 0 1 0 R
R
R
R

この命令は,インデックスレジスタRRRRの値をアキュムレータに代入します.


XCH(eXCHange)

D3 D2 D1 D0 D3 D2 D1 D0
1 0 1 1 R
R
R
R

この命令は,インデックスレジスタRRRRの値とアキュムレータの値を入れ替えます.


BBL(Branch Back and Load)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 0 0 D
D
D
D

この命令は,サブルーチンを呼び出すときスタックに格納しておいたアドレスをポップし,プログラムカウンタへ格納します.ポップした結果,スタックの位置は1段階上がります.また,アキュムレータに値DDDDを格納します.多くの場合,サブルーチンの計算結果(つまり戻り値)をインデックスレジスタに格納していますので,そのインデックスレジスタのアドレスをDDDDとしておけば計算結果を得ることができます.


LDM(LoaD Memory)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 0 1 D
D
D
D

この命令は,アキュムレータに値DDDDを代入します.


入出力・RAM命令群

WRM(Write Ram Main memory character)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
0
0
0

この命令は,アキュムレータに書かれている値をRAMのメインメモリ文字へ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


WMP(Write raM output Port)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
0
0
1

この命令は,4002(RAM)に備わる出力ポートからアキュムレータの値を出力します.このRAMはSRC命令とDCL命令であらかじめ指定しておく必要があります.


WRR(WRite output port in Rom)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
0 1 0

この命令は,4001(ROM)に備わる出力ポートからアキュムレータの値を出力します.このROMはSRC命令であらかじめ指定しておく必要があります.


WR0(WRite status character 0)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
1
0
0

この命令は,アキュムレータに書かれている値をRAMのステータス文字0へ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


WR1(WRite status character 1)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
1
0
1

この命令は,アキュムレータに書かれている値をRAMのステータス文字1へ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


WR2(WRite status character 2)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0 1 1 0

この命令は,アキュムレータに書かれている値をRAMのステータス文字2へ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


WR3(WRite status character 3)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 0
1
1
1

この命令は,アキュムレータに書かれている値をRAMのステータス文字3へ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


SBM(SuBtract Main memory character)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
0
0
0

この命令は,アキュムレータからRAM内のメインメモリ文字の値を引き,結果をアキュムレータに代入します.もし桁借りが発生した場合にはキャリが1になります.


RDM(ReaD Main memory character)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
0
0
1

この命令は,RAMのメインメモリに書かれている値をアキュムレータへ書き込みます.RAMのメインメモリはSRC命令とDCL命令であらかじめ指定しておく必要があります.


RDR(ReaD Rom input port)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
0
1
0

この命令は,ROMに備わる入力端子情報をアキュムレータへ書き込みます.ROMはSRC命令であらかじめ指定しておく必要があります.ROMの端子は出力端子にすることもできますが,その端子についてどのようになるかデータシートには書かれていませんのでここでは0と読み込まれることとします.


ADM(ADd Main memory character)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
0
1
1

この命令は,メインメモリ文字の値とアキュムレータの値を足し,結果をアキュムレータに代入します.もし桁上りが発生した場合にはキャリが1になります.


RD0(ReaD status character 0)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
1
0 0

この命令は,RAM内のステータス文字0の値を読み込み,アキュムレータに代入します.


RD1(ReaD status character 1)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
1
1 0

この命令は,RAM内のステータス文字1の値を読み込み,アキュムレータに代入します.


RD2(ReaD status character 2)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
1
1 0

この命令は,RAM内のステータス文字2の値を読み込み,アキュムレータに代入します.


RD3(ReaD status character 3)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 0 1
1
1 1

 この命令は,RAM内のステータス文字3の値を読み込み,アキュムレータに代入します.


アキュムレータグループ命令群

CLB(CLear Both accumulator and carry)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
0
0 0

この命令は,アキュムレータとキャリの値を0にします.


CLC(CLear Carry)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
0
0 1

この命令は,キャリを0にします.


IAC(Increase ACcumulator)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
0
1 0

この命令は,アキュムレータの値を1増やします.桁上がりが発生した場合にはキャリが1となります.


CMC(CoMplement Carry)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
0
1 1

この命令は,キャリを反転させます.


CMA(CoMplement Accumulator)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
1
0 0

この命令は,アキュムレータの値を反転させます.


RAL(Rotate Accumulator Left)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
1
0 1

この命令は,キャリを最上位ビットとした,アキュムレータと連結したもの(5[bit])を循環左シフトします.


RAR(Rotate Accumulator Right)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
1
1 0

この命令は,キャリを最上位ビットとした,アキュムレータと連結したもの(5[bit])を循環右シフトします.


TCC(Transmit Carry to accumulator and Clear Carry)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 0
1
1 1

この命令は,キャリをアキュムレータに入れたのち,キャリを0にします.


DAC(Decrement ACcumulator)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
0
0 0

この命令は,アキュムレータの値を1減らします.


TCS(Transfer Carry Subtract)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
0
0 1

この命令は,キャリが1ならアキュムレータを10,キャリを0にし,キャリが0ならアキュムレータを9にします.これにより,10進数の引き算を簡単に行うことができます.ある桁の引き算でマイナスになると上位から10を借りてきて引き算をしますが,その下の桁で桁借りがある場合は9と引き算することになります.このときTCS命令は大変役立ちます.


STC(SeT Carry)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
0
1 0

この命令はキャリを1にします.


DAA(Decimal Adjust Accumulator)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
0
1 1

この命令は,アキュムレータの値をBCD(Binary Coded Dicimal)にするときに使用します.BCDとは,十の位と一の位のに分けて表現するものです.このうち,一の位のみにしてくれるのがDAAなのです.例えば十進数で12という値であれば,2にしてくれるのです.このためには,10以上の値の場合には6を足し,10未満の場合特に何もしません.先ほどの例の12を例にとると,12+6=18となりますので,二進数では10010となりますが,最上位ビットはアキュムレータからあふれるため,結果として「2」となります.


KBP(KeyBoard Process)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
1
0 0

この命令は,キーボードが押された結果をRDR命令によってアキュムレータに格納されていることを前提に,それを数値化します.アキュムレータが4[bit]であるため,スイッチ押下の有無は4種類しかありません.また,同時に複数のスイッチが押下されることをそうていしていません.従いまして,KBP命令を実行するとアキュムレータは下表のように変化します.

実行前 実行後 
0000  0000 
0001 0001 
0010 0010 
0100 0011
1000 0100
上記以外 1111

DCL(Designate Command Line)

D3 D2 D1 D0 D3 D2 D1 D0
1 1 1 1 1
1
0 1

この命令は,アキュムレータに書かれているワンホット(ひとつのビットだけ1となっており,他のビットは0となっている値のこと)の値に基づきCM-RAM0~3の信号を制御します.最下位ビットがCM-RAM0,最上位ビットがCM-RAM3というように割り当てられています.