MN1613


MN1610の後継として1981年に発表されたものがMN1613です。MN1610の上位互換で、メモリ空間を拡張し演算の高速化を実現したものです。クロックはMN1610が2 MHzだったものを13.3 MHzとし、命令の先読みを行うようにしたため、レジスタ間演算が最短0.3 usで行えるようになりました(MN1610では3 us)。メモリ空間はセグメントレジスタを併用した拡張がなされ、トータルで256 KWordになっています。

MN1613 and MN1613A CPU top view
MN1613とMN1613A。上のMN1613は40 pinですが、下のMN1613Aは42 pinパッケージです。単に高速化されたものではなく、ピン数まで異なるとは。簡単なテストから得た想像ですが、MN1613Aは1番と42番ピン以外の40本がMN1613と共通で、その2本は何らかの出力専用端子のようでした。

上から見ると、変哲のないセラミックパッケージですね。ところで、このMN1613やMN1613Aをひっくり返してみると、こんなです。この金属板はヒートスプレッダか何かだと思いますが、実際のところはどうなのでしょうか。なお、PFL-16AシリーズのMN1613以外の石の裏面は、普通のセラミックだけのパッケージです。

MN1613 bottom view
MN1613の裏面。

MN1613はMN1610とバイナリ上位互換です。リセット直後の動作など特別なところを除けば、MN1610のコードがそのまま動作します。また、ハードウエア面でもそれなりの互換性があり、入出力デバイスなどはそのまま接続することもできます。ただし、メモリ拡張用のセグメントレジスタなど特殊レジスタが追加され、クロックジェネレータやインターバルタイマなどMN1640の機能の一部が内蔵され、MN1610の未定義命令を拡張し2語命令も許容することによって32 bit浮動小数点演算を含む命令の拡張が行われています。アドレッシングモードも拡張されたアドレス空間を利用しやすくするため強化されていますが、追加されたアドレッシングモードを利用する命令は従来のものとは別命令扱いになっていることもあって、MN1610では33種の基本命令が97種にまで、およそ3倍に増やされています。また、コンソールパネル機能の実現方法もMN1610とは異なり、コンソールパネル機能を実現するプログラムを特殊なアドレス空間に配置できるようになっています。

内蔵しているレジスタ類は、このようになっています。
MN1613 registers
網掛け部は未使用ビットで、常に0が入っています。
図の中で赤枠で囲っている汎用レジスタ・命令カウンタはMN1610と共通の部分です。MN1610には赤枠内のレジスタしか存在しませんでした。ただし、命令の拡張に応じて、R1, R2, R3, R4が特別なアドレッシングモードに利用されたり、R0とR1が連結されて32 bit整数や浮動小数点用のアキュムレータDR0として利用されるなど、MN1610にはなかった特別な機能も加わっています。
セグメントベースレジスタは、略してベースレジスタと呼ばれることもありますが、アドレス拡張用のレジスタで、用途により4種類ありますが、それぞれ4 bit幅です。MN1613の物理アドレスは、基本的にはMN1610と同じか拡張されたアドレッシングモードで求められた16 bit論理アドレスに、このセグメントベースレジスタの内容を14 bit左シフトして加算して求めます。加算の際の桁上がりは無視され、最終的に得られる物理アドレスは18 bit幅となります。
Current Segment Base Registor (CSBR)は一般の命令実行に関して利用されるベースレジスタです。Stack  Segment Base Register (SSBR)はサブルーチン呼び出しやスタックへのPush/Popのようなスタック参照時に使用されるベースレジスタです。ブロック転送命令など特別な命令の実行時に使用されるのがTemporary Segment Base Register 0, 1であるTSR0とTSR1です。普通はCSBR、ただしスタック領域だけはSSBRが使用されると理解しておけば、ほぼ問題ないでしょう。マルチタスクモニタで複数のタスクを並行動作させる場合、特権モードの類はありませんから完全なメモリ保護はできませんが、複数のタスク間でのゼロページ領域の干渉や不足がMN1610で問題になりますが、CSBRによって個別のタスクごとに固有のゼロページ領域(とその他の領域)を持たせることができます。
割り込み時には、CSBRの内容が割り込みレベルに対応したベース退避レジスタにコピーされ、その後にCSBRの内容が0クリアされてMN1610と同様の割り込みシーケンスが始まります。つまり、割り込みサービスルーチンが物理アドレス空間の先頭64 KWord内に存在する必要がある以外はMN1610と互換性を持つようになっています。割り込みレベルは0から2までなので、OSRは0から2までしか必要ないはずですが、OSR3も用意されていてソフトウェア的に利用できます。
特殊レジスタのうちNew Program Status Word Pointer (NPP)は、他のマイクロプロセッサの割り込みベクタ領域に相当するNPSWの先頭アドレスを指示するポインタで、上位8 bitだけが有効です。NPSWを読み出すときにはCSBRは0クリアされているので、先頭64 KWord内の256 Word境界にNPSW領域を割り当てることが可能です。リセット時には1が入るので、MN1610と互換性があります。
Internal Interrupt Status Register (IISR)は未定義命令が実行されレベル0の割り込みが発生したことを通知するためのレジスタで、該当条件が成立した場合に1がセットされます。
CSBR Buffer (SBRB)とIC Buffer (ICB)はコンソール処理プログラムからのみ利用できるレジスタで、プロセッサがコンソール処理プログラムの実行を開始する直前のCSBRとICがそれぞれSBRBとICBにコピーされ、逆に通常の実行状態に遷移する際にはSBRBとICBの内容がそれぞれCSBRとICにコピーされます。
MN1613にはMN1640に内蔵されていたのと似ているインターバルタイマ機能が内蔵されていて、その制御を行うのがタイマレジスタです。また、単純なシフトレジスタを用いたシリアル入出力機能も内蔵されていて、その制御用のレジスタが直列入出力レジスタです。

アドレッシングモードはMN1610と共通のものに、さらに数種類追加されています。MN1613はMN1610とバイナリ互換がありますから、MN1610と共通の命令ではまったく同じアドレッシングモードが使えます。追加されたアドレッシングモードを使う命令は、すべて専用のMN1613に新設された命令で、アセンブリ言語レベルでもニーモニックから異なります。ただし、MN1610と共通のアドレッシングモードにおいては、スタックアクセスを除き、CSBRの内容が14 bit左シフトして加算されることが異なります。スタックアクセスの場合にはSSBRがセグメントベースレジスタとして使われます。
追加されているアドレッシングモードは以下の6種です。

16 bit直接番地指定は必ず2語命令になり、2語目の16 bitの値がそのままセグメント内アドレスとなります。その値にCSBRが加算されて、実際の物理アドレスとなります。
レジスタ間接番地指定は、R1, R2, R3, R4のどれかのレジスタの内容がセグメント内アドレスとなり、その値にCSBRが加算されて、実際の物理アドレスとなります。R0は使用できません。MN1613で追加された命令のうちメモリ参照が必要なもので、もっとも一般的に使用されるモードです。
レジスタ間接拡張番地指定では、使用するセグメントベースレジスタを4種類のうちから指定できることを除き、レジスタ間接番地指定と同一です。
直接拡張番地指定も、使用するセグメントベースレジスタを4種類のうちから指定できることを除き、16 bit直接番地指定と同一です。
間接拡張番地指定は2語命令の2語目の16 bit値をセグメント内アドレスと解釈し、そこから2語読み出します。その最初の1語をCSBRにロードし、新しいCSBRと第2の16 bit値を加算して、目的アドレスを計算します。特別な形式の分岐命令にだけ使用可能です。このモードが使用されると、それ以降のCSBRが書き換わってしまいます。セグメントをまたいだ分岐に使われます。
レジスタ2重間接拡張番地指定も間接拡張番地指定と同じで、指示されたレジスタの指すメモリから2語読み出して、CSBRを書き換えるとともに目的アドレスを計算します。同じく特別な分岐命令用です。
なお、レジスタ間接拡張番地指定を用いたメモリ・レジスタ間データ転送命令については、ポインタとして使用するレジスタのポストインクリメント機能やプリデクリメント機能がありますが、これはその命令にのみ可能で、他の命令では利用できませんから、アドレッシングモードではなく命令機能の方に分類されています。

以下に全命令の一覧を示します。
意味                               アセンブリ言語表記
Load                               L     R, Addr
Load Direct                       *LD    R[, BRn], Exp
Load Register Indirect            *LR    R[, BRn], {(Ri) | (Ri)+ | -(Ri)}
Store                              ST    R, Addr
Store Direct                      *STD   R[, BRn], Exp
Store Register Indirect           *STR   R[, BRn], {(Ri) | (Ri)+ | -(Ri)}
Move                               MV    Rd, Rs[, Skip]
Move Word Register Indirect       *MVWR  R0, (Ri)[, Skip]
Move Word Immediate               *MVWI  Rd, Exp[, Skip]
Move Byte                          MVB   Rd, Rs[, Skip]
Move Byte Register Indirect       *MVBR  R0, (Ri)[, Skip]
Byte Swap                          BSWP  Rd, Rs[, Skip]
Byte Swap Register Indirect       *BSWR  R0, (Ri)[, Skip]
Digit Swap                         DSWP  Rd, Rs[, Skip]
Digit Swap Register Indirect      *DSWR  R0, (Ri)[, Skip]
Push                               PUSH  R
Push Multi                        *PSHM
Pop                                POP   R
Pop Multi                         *POPM
Move Immediate                     MVI   R, Exp
Add                                A     Rd, Rs[, Skip]
Add Word Register Indirect        *AWR   R0, (Ri)[, Skip]
Add Word Immediate                *AWI   Rd, Exp[, Skip]
Add Immediate                      AI    R, Exp[, Skip]
Subtract                           S     Rd, Rs[, Skip]
Subtract Word Register Indirect   *SWR   R0, (Ri)[, Skip]
Subtract Word Immediate           *SWI   Rd, Exp[, Skip]
Subtract Immediate                 SI    R, Exp[, Skip]
Compare                            C     Rd, Rs[, Skip]
Compare Word Register Indirect    *CWR   R0, (Ri)[, Skip]
Compare Word Immediate            *CWI   Rd, Exp[, Skip]
Compare Byte                       CB    Rd, Rs[, Skip]
Compare Byte Register Indirect    *CBR   R0, (Ri)[, Skip]
Compare Byte Immediate            *CBI   Rd, Exp[, Skip]
Nagate with Carry                 *NEG   Rd[, C][, Skip]
Add Double with Carry             *AD    DR0, (Ri)[, C][, Skip]
Subtract Double with Carry        *SD    DR0, (Ri)[, C][, Skip]
Multiply                          *M     DR0, (Ri)[, Skip]
Divide                            *D     DR0, (Ri)[, Skip]
Decimal Adjust
 Addition with Carry              *DAA   R0, (Ri)[, C][, Skip]
Decimal Adjust
 Subtraction with Carry           *DAS   R0, (Ri)[, C][, Skip]
Load Adjust Part                   LAD   Rd, Rs[, Skip]
Load Adjust Part
 Register Indirect                *LADR  R0, (Ri)[, Skip]
Load Adjust Part Immediate        *LADI  Rd, Exp[, Skip]
Floating Add                      *FA    DR0, (Ri)[, Skip]
Floating Subtract                 *FS    DR0, (Ri)[, Skip]
Floating Multiply                 *FM    DR0, (Ri)[, Skip]
Floating Divide                   *FD    DR0, (Ri)[, Skip]
Fix                               *FIX   R0, DR0[, Skip]
Float                             *FLT   DR0, R0[, Skip]
Logical And                        AND   Rd, Rs[, Skip]
Logical And Register Indirect     *ANDR  R0, (Ri)[, Skip]
And Immediate                     *ANDI  Rd, Exp[, Skip]
Inclusive Or                       OR    Rd, Rs[, Skip]
Inclusive Or Register Indirect    *ORR   R0, (Ri)[, Skip]
Inclusive Or Immediate            *ORI   Rd, Exp[, Skip]
Exclusive Or                       EOR   Rd, Rs[, Skip]
Exclusive Or Register Indirect    *EORR  R0, (Ri)[, Skip]
Exclusive Or Immediate            *EORI  Rd, Exp[, Skip]
Increment Memory
 and Skip if Result is Zero        IMS   Addr
Decrement Memory
 and Skip if Result is Zero        DMS   Addr
Branch                             B     Addr
Branch Direct                     *BD    Exp
Branch Long                       *BL    (Exp)
Branch Register Indirect          *BR    (Ri)
Branch and Link                    BAL   Addr
Branch and Link Direct            *BALD  Exp
Branch and Link Long              *BALL  (Exp)
Branch and Link Register Indirect *BALR  (Ri)
Return                             RET
Return Long                       *RETL
Load Program Status Word           LPSW
Test Bit                           TBIT  R, Exp[, Skip]
Set Bit                            SBIT  R, Exp[, Skip]
Reset Bit                          RBIT  R, Exp[, Skip]
Test and Set                      *TSET  Rs, Exp[, Skip]
Test and Reset                    *RSET  Rs, Exp[, Skip]
Search Bit Position               *SRBT  R0, Rs
Decode Bit Position               *DEBP  Rd, R0
Shift Right 1 bit                  SR    R[, Set][, Skip]
Shift Left 1 bit                   SL    R[, Set][, Skip]
Move Data Block                   *BLK   (R2), (R1), R0
Read                               RD    R, Exp
Read Register Indirect            *RDR   R, (Ri)
Write                              WT    Rs, Exp
Write Register Indirect           *WTR   R, (Ri)
Load Base Register                *LB    BRd, Exp
Load Special Register             *LS    SRd, Exp
Store Base Register               *STB   BRs, Exp
Store Special Register            *STS   SRs, Exp
Copy Base Register                *CPYB  Rd, BRs
Copy Special Register             *CPYS  Rd, SRs
Copy Hardware Control Register    *CPYH  Rd, HRs
Set Base Register                 *SETB  Rs, BRd
Set Special Register              *SETS  Rs, SRd
Set Hardware Register             *SETH  Rs, HRd
Halt                               H
アセンブリ言語表記で、[]内は省略可能であることを示します。スキップ条件、Eレジスタ操作、キャリー操作が省略可能です。また、{}内で|をデリミタとして並べた項目は、その中のどれかひとつを選択できることを意味します。ポストインクリメント間接およびプリデクリメント間接指定が選べるところに使われています。また、ニーモニックの先頭に*が付けられている命令は、MN1613で新設された命令です。付けられていないものはMN1610と互換であることを意味します。
オペランド部分で、AddrはMN1610と共通のアドレッシングモードを記入することを意味します。Expは数式を意味し、定数、セグメント内16 bitアドレスなどに使われています。Rはレジスタ、BRはベースレジスタ、Riは間接アドレス用レジスタ、SRは特殊レジスタ、HRはハードウエア制御レジスタを意味します。レジスタのポストフィックスとして使われているsはソースレジスタを、dはディスティネーションレジスタを意味します。
レジスタ間接アドレッシング系の命令の大部分は、一方のオペランドとしてR0かDR0だけが使用可能で、一種のアキュムレータとして利用されていることがわかります。
16 bit整数演算命令にはレジスタ間接アドレッシングのほか、イミディエートモードができて便利になりました。MN1610ではルーチンの切れ目に定数置き場を作って、直接相対で参照するしかありませんでしたから。
乗除算および浮動小数点演算はレジスタ間接アドレッシングのものばかりです。これらの命令にもスキップ条件を付けられるのは、ちょっと驚きです。命令実行時間は乗算命令が8.4 us、除算命令が17.4 us、浮動小数点加算が15.6 - 22.8 us、浮動小数点減算が16.2 - 24.0 us、浮動小数点乗算が52.2 - 58.2 us、浮動小数点除算が73.5 - 88.5 usとなっています。内蔵のマイクロプログラムで処理するので、これくらい必要なのはわかるのですが、この命令実行時間の間は割り込みを受け付けられないはずです。MN1610と比べて、割り込みルーチンの最短応答時間は悪くなっていますね。
分岐命令にはセグメントレジスタも同時に変更するものが追加されています。サブルーチン呼び出しも同じで、セグメントと16 bitアドレスをスタックにプッシュするものが追加され、それに対応したリターン命令も新設されています。
ビット操作では、マルチプロセッサ用、あるいは単一プロセッサでもセマフォの実装用に便利な命令が追加されたほか、グラフィックス表示関係で便利なこともある命令が追加されています。
BLK命令はブロック転送で、R0の内容で示された語数のデータを転送します。セグメント間転送も可能ですし、命令実行途中に割り込みを受け付けることもできます。
入出力命令にはレジスタ間接アドレッシングが可能なものが新設されました。この命令では、16 bit I/Oアドレス空間を扱うことができます。従来の入出力命令では、上位8 bitが0に固定された256語分のI/O空間だけをアクセスできます。
それ以降は内蔵の新しいレジスタを参照するための命令です。

データ転送系の命令から詳細を見ていきます。
命令  オペコード         2語目 EV  動作
L     11MMM RRR dddd dddd            R <- (EA)
LD    00100 111 00BB 1RRR  AD16      R <- (EA)
LR    00100 RRR mmBB 00ii            R <- ((Ri)), modify indirect register
ST    10MMM RRR dddd dddd            EA <- (R)
STD   00100 111 01BB 1RRR  AD16      EA <- (R)
STR   00100 RRR mmBB 01ii            (Ri) <- (R), modify indirect register
MV    01111 ddd kkkk 1sss            Rd <- (Rs), skip
MVWR  01111 111 kkkk 10ii            R0 <- ((Ri)), skip
MVWI  01111 ddd kkkk 1111  IM16      Rd <- IM, skip
MVB   01111 ddd kkkk 0sss            Rd_L <- (Rs)_L, skip
MVBR  01111 111 kkkk 00ii            R0_L <- ((Ri))_L, skip
BSWP  01110 ddd kkkk 1sss            Rd_L <- (Rs)_U, Rd_U <- (RS)_L, skip
BSWR  01110 111 kkkk 10ii            R0_L <- ((Ri))_U, R0_U <- ((Ri))_L, skip
DSWP  01110 ddd kkkk 0sss            Rd <- digit swap(Rs), skip
DSWR  01110 111 kkkk 00ii            Rd <- digit swap((Ri)), skip
PUSH  00100 RRR 0000 0001            (SP--) <- (R)
PSHM  00010 111 0000 1111            (SP--) <- (R0) (R1) (R2) (R3) (R4)
POP   00100 RRR 0000 0010            R <- ((++SP))
POPM  00010 111 0000 0111            R4 R3 R2 R1 R0 <- ((++SP))
MVI   00001 RRR dddd dddd            R_L <- IM8
オペコード部分は2進数表示です。MN1613のオペコードのフィールドに応じて、5, 3, 4, 4 bitのグループに分けています。MMM, RRR, dddddddd, BB, mm, ii, ddd, sss, kkkkには、それぞれ次の表の意味があります。
MMMとddddddddの意味
MMM ddddddddの意味 モード 実効論理アドレス
000 無符号整数D ゼロページ直接 D
001 符号付き整数d 相対 (IC) + d
010 無符号整数D ゼロページ間接 [D]
011 符号付き整数d 相対間接 [(IC) + d]
100 無符号整数D 直接インデックス0 (X0) + D
101 無符号整数D 直接インデックス1 (X1) + D
110 無符号整数D 間接インデックス0 (X0) + [D]
111 無符号整数D 間接インデックス1 (X1) + [D]

RRR, ddd, sssは汎用レジスタを意味するフィールドです。
RRR, ddd, sss レジスタ
000 R0
001 R1
010 R2
011 R3またはX0
100 R4またはX1
101 SP
110 STR(L, LD, L, ST, STD, STR, RDR, WTR命令では禁止)
111 禁止

BBはセグメントベースレジスタを意味するフィールドです。
BB セグメントベースレジスタ
00 CSBR
01 SSBR
10 TSR0
11 TSR1

mmは間接レジスタに関する動作モードを指定するフィールドです。
mm 動作モード
01 (Ri)
10 -(Ri)
11 (Ri)+
mmが01なら普通のレジスタ間接拡張番地指定ですが、10なら指定された間接レジスタを使用する前にデクリメントを行います。11なら間接レジスタを使用してからインクリメントを行います。00は指定できません。

iiは間接レジスタを指定するフィールドです。
ii 間接レジスタ
00 R1
01 R2
10 R3
11 R4

kkkkはスキップ条件を指定するフィールドです。
kkkk 記号 意味
0000 -- スキップせず
0001 SKP 無条件スキップ
0010 M 結果が負
0011 PZ 結果が正または零
0100 ZまたはE 結果が零
0101 NZまたはNE 結果が零でない
0110 MZ 結果が負または零
0111 P 結果が正
1000 EZ Eレジスタが零
1001 ENZ Eレジスタが零でない
1010 OZ Vが零
1011 ONZ Vが零でない
1100 LMZ 結果が等しいまたは小
1101 LP 結果が大
1110 LPZ 結果が大または等しい
1111 LM 結果が小
M, PZ, MZ, Pは符号付きデータの比較で意味を持ち、LMZ, LP, LPZ, LMは無符号正数データの比較に使われます。

これらのフィールドは、これ以降の命令詳細のオペコード欄に現れた場合も同じ意味を持ちます。
2語目は2 word命令の第2語目の意味を示します。AD16はセグメント内アドレスを意味し、IM16は16 bit定数を意味します。
EVはEフラグとオーバーフローを意味するVフラグの変化を意味します。何も記入されていなければ変化なし、0か1が書かれていれば命令実行時に強制的にその値にされる、*なら命令の実効結果に応じて変化する、-なら不定であることを意味します。

LD, STD命令は16 bit直接番地指定でセグメント内の任意のアドレスのメモリとのデータ転送を行います。
LR, STR命令は任意のセグメントベースレジスタを用いて全アドレス空間のメモリとデータ転送を行うほか、間接レジスタのプリデクリメント、ポストインクリメント機能もあって、連続したデータを操作しやすくなっています。セグメントをまたいだブロック転送にも便利そうですが、単純なブロック転送なら専用の特殊命令としてBLK命令があります。
MV命令はレジスタ間転送命令ですが、レジスタの内容を判断するための純粋なスキップ判定命令として使用することもあります。その場合、MV R, R, SkipCondのように、判定したいレジスタをソースとディスティネーションの両方に書きます。
MVWR命令はメモリからレジスタへのデータ転送ですから、本来はロード命令の範疇に入りそうなものです。レジスタ間接アドレッシングのため、ディスティネーションはR0に限られています。LR命令との使い分けは微妙なところですね。
MVWI命令は16 bit定数をレジスタにロードする命令で、これまでMN1610になくて少し不便なところがありました。コードのワード数は実質的には変わりませんが、ルーチンの切れ目の離れた場所に定数を定義しておいて、それを相対アドレッシングのL命令で読み込むしかできませんでしたから。
MVB命令はレジスタの下位8 bitだけの転送です。上位8 bitは変化しません。
MVBR命令は、メモリから1 Byteだけ読み込める命令ですが、やはり下位バイトに限られます。
BSWP命令は上位8 bitと下位8 bitを入れ換えながらレジスタ間データ転送を行います。ソースとディスティネーションに同じレジスタを指定すれば、単にレジスタの上下バイトを入れ換える命令としても利用できます。
BSWR命令はメモリからレジスタにデータを読み込みながら上下バイトを入れ換えます。
DSWP命令はレジスタ間のデータ転送時にビット4 - 7とビット8 - 11を入れ換えます。これとBSWP命令を併用すれば、任意のデジットをレジスタの下位4 bitに配置することができるわけで、BCDデータ処理などに応用できるでしょう。
DSWR命令はメモリからレジスタにデータを読み込みながらデジット入れ換えを行います。
PUSH命令とPOP命令はスタックとレジスタ間のデータのやりとりを行います。MN1613のスタックポインタは常に空のメモリを指しているので、PUSHした後にデクリメント、インクリメントした後にPOPという関係になります。LR, STR命令のプリデクリメント、ポストインクリメントと逆になっています。
PSHM命令とPOPM命令はR0 - R4をまとめてスタックにPUSH, POPします。PUSHはR0が最初に行われ、POPはR4が最初に行われます。割り込み時のコンテキスト切り替えなどに便利そうです。
MVI命令は8 bit定数値をレジスタの下位8 bitに読み込みます。上位8 bitは変化しません。
データ転送系の命令ではEフラグもVフラグも変化しません。

次に整数演算命令です。
命令  オペコード         2語目 EV  動作
A     01011 ddd kkkk 1sss        **  Rd <- (Rd) + (Rs), skip
AWR   01011 111 kkkk 10ii        **  R0 <- (R0) + ((Ri)), skip
AWI   01011 ddd kkkk 1111  IM16  **  Rd <- (Rd) + IM16, skip
AI    01001 rrr kkkk DDDD            R <- (R) + IM4, skip
S     01011 ddd kkkk 0sss        **  Rd <- (Rd) - (Rs), skip
SWR   01011 111 kkkk 00ii        **  R0 <- (R0) - ((Ri)), skip
SWI   01011 ddd kkkk 0111  IM16  **  Rd <- (Rd) - IM16
SI    01000 rrr kkkk DDDD            R <- (R) - IM4, skip
C     01010 ddd kkkk 1sss            (Rd) - (Rs), skip
CWR   01010 111 kkkk 10ii            (R0) - ((Ri)), skip
CWI   01010 ddd kkkk 1111  IM16      (Rd) - IM16, skip
CB    01010 ddd kkkk 0sss            (Rd)_L - (Rs)_L
CBR   01010 111 kkkk 00ii            (R0)_L - ((Ri))_L
CBI   01010 ddd kkkk 0111  IM16      (Rd)_L - IM16_L
NEG   00011 111 kkkk cddd        *   Rd <- -(Rd) - (E), skip
AD    01001 111 kkkk c1ii        **  DR0 <- (DR0) + ((Ri), (Ri)+1) + (E), skip
SD    01000 111 kkkk c1ii        **  DR0 <- (DR0) - ((Ri), (Ri)+1) - (E), skip
M     01111 111 kkkk 11ii        00  DR0 <- (R0)*((Ri)), skip
D     01110 111 kkkk 11ii        0*  R0 <- (DR0)/((Ri)), R1 <- (DR0)%((Ri)), skip
DAA   01011 111 kkkk c1ii        *   R0 <- (R0)_BCD + ((Ri))_BCD + (E), skip
DAS   01010 111 kkkk c1ii        *   R0 <- (R0)_BCD - ((Ri))_BCD - (E), skip
LAD   01101 ddd kkkk 0sss            Rd <- LAD((Rd), (Rs)), skip
LADR  01101 111 kkkk 00ii            R0 <- LAD((Rd), ((Ri))), skip
LADI  01101 ddd kkkk 0111  IM16      Rd <- LAD((Rd), IM16), skip
上の表で、DDDDは0から15までを表す定数値です。
また、NEG, AD, SD, DAA, DAS命令の中のcフィールドの意味は、次のようになっています。
c 意味
0 演算にキャリー(E)を含める
1 演算にキャリー(E)を含めない

A, AWR, AWI, AI命令は2進整数の加算命令です。MN1610ではレジスタ間加算のA命令と0から15までの定数値をレジスタに加算するAI命令しかありませんでしたが、レジスタ間接アドレッシングとイミディエートアドレッシングの命令が追加され、特にイミディエート命令では任意の16 bit定数の加算が可能になってコードを書きやすくなりました。AI命令は一般のプロセッサのレジスタインクリメント命令の機能強化版で、そのためかフラグには影響を与えません。
S, SWR,SWI, SI命令は2進整数の減算命令です。Eフラグは桁借りにしたがってセットされます。
これらの加減算命令には、キャリーを演算に含める機能はありません。
C, CWR, CWI命令は比較命令で、減算を行って(その結果は捨てるけれども)スキップ条件判定を行います。
CB, CBR, CBI命令はレジスタ下位8 bitに関する比較命令で、実際はふたつの数値の下位8 bitを取り出して上位8 bitは0に置き換えた数値に対しての比較となります。符号拡張は行わず、実質的に0から255までの正数値としての比較です。
NEG命令は2の補数を求める命令です。キャリー指定があれば、キャリー込み、つまりEが1の時には本来の2の補数より1少ない数が求められます。この命令は単項演算命令となっていて、元データの入っていたレジスタが書き換えられます。
AD命令とSD命令は2 word整数の加減算命令です。R0がMSB側、R1がLSB側となり、メモリ上の2 wordとの加減算が行われ、フラグも通常の加減算と同じようにセットされます。また、スキップ条件判定も結果の2 wordを正しく判定します。キャリー指定も可能なので、必要に応じて多倍長の加減算を実行可能です。逆に1 word長のA, S命令にはキャリー込みはできません。MN1610ではスキップ条件指定とAI, SI命令などを組み合わせて桁上がりの処理を行わなくてはなりませんでした。
M命令は無符号16 bit数値の乗算を行います。R0の内容とRiで指されたメモリの内容の積をとり、R0とR1に格納します。クロック周波数13.3 MHzのときに8.4 usかかります。112クロック分ですね。一般のレジスタ間整数演算は最短0.3 us、4クロックかかるということを考えると、メモリ上のデータアクセスのために4クロックは必要ということを考えても長い実行時間です。
D命令は無符号32 bitデータを無符号16 bitデータで割る命令です。R0, R1に納められた32 bitの数値とRiで指されたメモリの内容との除算を行い、商をR0、剰余をR1に格納します。除数が0ないし商が16 bit数値の範囲を越えた場合にVフラグがセットされます。Vフラグがセットされたときの演算結果は保証されません。この除算命令はクロック周波数13.3 MHzのときに17.4 usかかるということで、232クロック消費されます。
DAA, DAS命令はBCDデータに対する加減算命令です。キャリー指定も可能で、多倍長演算も簡単に記述できます。MN1613ではLAD命令とA, S命令を組み合わせて少々複雑なコードを書かなくてはならなかったのが、容易にコーディングできるようになりました。
LAD, LADR, LADI命令はMN1610のLAD命令にアドレッシングのバリエーションを増やしたもので、やはりBCD加減算のための補正命令です。LAD命令では補正のためのテストデータを前もって空いたレジスタにロードしなくてはならなかったのが、LADI命令では不要となります。ただ、DAA, DAS命令が使えれば、互換性のためのLAD命令を除いて、使用する場面はかなり少なくなりそうです。

単精度相当で基本的なものしかありませんが、次の浮動小数点数演算命令が新設されています。
命令  オペコード         2語目 EV  動作
FA    01101 111 kkkk 11ii        0*  DR0 <- (DR0) + ((Ri), (Ri)+1), skip
FS    01101 111 kkkk 01ii        0*  DR0 <- (DR0) - ((Ri), (Ri)+1), skip
FM    01100 111 kkkk 11ii        0*  DR0 <- (DR0) * ((Ri), (Ri)+1), skip
FD    01100 111 kkkk 01ii        0*  DR0 <- (DR0) / ((Ri), (Ri)+1), skip
FIX   00011 111 kkkk 1111        0*  R0 <- Int((DR0)), skip
FLT   00011 111 kkkk 0111        0-  DR0 <- Float((R0)), skip
これらの命令で使用される浮動小数点データの形式は次のとおりです。
1語目(R0) SEEE EEEE MMMM MMMM
2語目(R1) MMMM MMMM MMMM MMMM
2進数表現で命令と同じく左端がMSBとなります。Sは仮数部の符号ビットで、0が正、1が負を意味します。EEEEEEEの7 bitが指数部で、40H(16進数)の下駄履き表現が使われています。MMMMの6桁が仮数部で、合計2 word分の32 bitデータです。小数点位置はEとMの間にあります。ここまでは、比較的普通の浮動小数点形式なのですが、最近のマイクロプロセッサの表現法と異なり、指数部は16を基底としていて、仮数部は4 bit単位でひとつの桁を表します。
具体的には、指数部が40Hなら16の0乗、41Hなら16の1乗、42Hなら16の2乗、7FHなら16の63乗を、逆に3FHなら16の-1乗、3EHなら16の-2乗、00Hなら16の-64乗という意味になり、仮数部の小数点位置は4 bit単位でずらされることになります。仮数部はデータの値が0.0以外なら正規化されていなければなりませんが、16進表現ということですから1語目の第8 bitが1という条件ではなく、第8から第11 bitが0以外という形が正規化フォーマットとなります。なお数値の0.0は全32 bitが0で表現されます。
この形式で表現されるデータ範囲は、16進表現なら±0.100000H 16**-64から±0.FFFFFFH 16**63まで、10進数表示で約±5.4E-79から±7.2E75の範囲です。精度は仮数部の最上位桁が0001というビットパターンのときに実質的に仮数部が21 bitしか使用されませんから、21 * log 2 = 6.3桁の精度を持ちます。
指数部の基底に2を用いた形式より、有効数字は減りますが、最大値と最小値の幅はこちらのほうが広く取れます。どちらかというとマイクロプロセッサでは珍しい形式ですが、大型コンピュータで使われることのあった形式です。
MN1613では、このような浮動小数点データの四則演算、および浮動小数点形式と整数形式の変換命令を用意しています。
四則演算では、演算結果が表現範囲を越えた場合にVフラグをセットし、その場合の結果は保証されません。当然ながら0での除算もVフラグがセットされます。アンダーフローについては強制的に結果を0にします。
FIX命令はDR0内の浮動小数点データを符号付き16 bit整数値に変換してR0に入れます。16 bit整数で表現できない数値だった場合にはVフラグがセットされ、結果は保証されません。
FLT命令はFIX命令の逆で、R0に納められた符号付き16 bit整数値を浮動小数点データに変換してDR0に格納します。こちらは必ず正常に変換できるはずで、Vフラグは無関係のはずですが、実際には不定となっています。
FIX命令もFLT命令も任意の数値を相互変換するには機能不足ですが、それなりに四則演算命令などと組み合わせれば数値の文字列表現から浮動小数点データへの変換やその逆も行えます。また、12 bit A/Dコンバータから入力を読み込んで浮動小数点表示に変換し、それなりに複雑な計算を行ってから、12 bit D/Aコンバータに出力して制御を行うような場合なら、これらのFIX, FLT命令をそのまま利用することができます。
さて、演算速度ですが、FA命令で15.6 - 22.8 us、FS命令で16.2 - 24.0 us、FM命令で52.2 - 58.2 us、FD命令で73.5 - 88.5 usとなっています。FD命令の最悪時で1180クロックですね。確かに整数演算命令を組み合わせたコードよりは1桁くらい高速になっていますが、別格といってよいほど長い命令実行時間です。これらの浮動小数点演算命令実行中の割り込み要求は命令終了まで待たされるはずですから、リアルタイム応用に関する割り込み応答時間はかなり悪いプロセッサとなってしまいそうです。
ただ、当時、コプロセッサとか拡張用マイクロプログラムROMを外付けせずに浮動小数点演算命令をシングルチップで実装していた例はほとんどありません。実行速度も、さすがに8086 + 8087よりは遅いですが、Am9511よりは命令単体でもそれなりに高速ですし、データの入出力の手間まで考えればかなり有利となります。計測データのリニアライズ処理とか高速フーリエ変換の計算、あるいは測定データから何らかの複雑な計算を行って制御量を求めるとか、特にその途中の演算結果が固定小数点処理では桁落ちの危険が大きいばあいには、便利なマイクロプロセッサだと考えられます。

論理演算およびその他の演算命令については、MN1610の命令にアドレッシングのバリエーションが増やされただけです。
命令  オペコード         2語目 EV  動作
AND   01101 ddd kkkk 1sss            Rd <- (Rd) & (Rs), skip
ANDR  01101 111 kkkk 10ii            R0 <- (R0) & ((Ri)), skip
ANDI  01101 ddd kkkk 1111  IM16      Rd <- (Rd) & IM16, skip
OR    01100 ddd kkkk 1sss            Rd <- (Rd) | (Rs), skip
ORR   01100 111 kkkk 10ii            R0 <- (R0) | ((Ri)), skip
ORI   01100 ddd kkkk 1111  IM16      Rd <- (Rd) | IM16, skip
EOR   01100 ddd kkkk 0sss            Rd <- (Rd) ^ (Rs), skip
EORR  01100 111 kkkk 00ii            R0 <- (R0) ^ ((Ri)), skip
EORI  01100 ddd kkkk 0111  IM16      Rd <- (Rd) ^ IM16, skip
IMS   11MMM 110 dddd dddd            EA <- (EA) + 1, if result = 0, skip inst.
DMS   10MMM 110 dddd dddd            EA <- (EA) - 1, if result = 0, skip inst.
AND命令からEORI命令まではビットごとの論理積、論理和、排他的論理和を求める命令です。
IMS命令は、メモリ内のデータをインクリメントして、その結果が0ならスキップを行う命令です。またDMS命令は、インクリメントでなくてデクリメントを行い、その結果が0ならスキップを行う命令です。ループ制御に使用します。レジスタやフラグの内容に影響を与えないので、便利な命令です。

分岐命令にはこのようなものが用意されています。
命令  オペコード         2語目 EV  動作
B     11MMM 111 dddd dddd            IC <- EA
BD    00100 110 0000 0111  AD16      IC <- EA
BL    00100 111 0000 1111  AD16      CSBR <- (EA), IC <- (EA+1)
BR    00100 111 0000 01ii            CSBR <- ((Ri)), IC <- ((Ri)+1)
BAL   10MMM 111 dddd dddd            (SP--) <- (IC), IC <- EA
BALD  00100 110 0001 0111  AD16      (SP--) <- (IC), IC <- EA
BALL  00100 111 0001 1111  AD16      (SP--) <- (IC) (CSBR), CSBR <- (EA), IC <- (EA+1)
BALR  00100 111 0001 01ii            (SP--) <- (IC) (CSBR), CSBR <- ((Ri)), IC <- ((Ri)+1)
RET   00100 000 0000 0011            IC <- ((++SP))
RETL  00111 111 0000 0111            CSBR IC <- ((++SP))
LPSW  00100 000 0000 01LL            STR <- (L*2), IC <- (L*2+1), CSBR <- (OSR(L))
B, BD, BL, BR命令は無条件分岐です。というか、条件分岐命令はMN1613には存在しません。条件分岐を行うには、演算命令のスキップ機能で無条件分岐命令をスキップするという方法を用います。なお、MN1613のスキップ機能は、1語命令だけでなく2語命令も正しくスキップできるようになっています。BL命令とBR命令はメモリ上に確保された拡張アドレスデータをCSBRとICに読み込み、セグメント間分岐を可能にしています。
BAL, BALD, BALL, BALR命令はサブルーチン呼び出し命令で、スタックに戻りアドレスを保存してから分岐します。特にBALL, BALR命令は拡張アドレスデータを用いてセグメントを越えたサブルーチンを呼び出すことができますが、その際はスタックにICだけでなくCSBRの内容も保存して、戻ってこれるようにしています。
RET命令はセグメント内サブルーチン呼び出しのBAL, BALD命令用のサブルーチンリターン命令です。
RETL命令はセグメント間サブルーチン呼び出しのBALL, BALR命令用の、CSBRとICの内容を復元するリターン命令です。
LPSW命令は割り込みサービスルーチンからのリターン命令で、保存されているPSW情報の場所が割り込みレベルごとに異なるため、割り込みレベルLLを指定します。LLを表にまとめると次のようになります。
LL 割り込みレベル STRアドレス ICアドレス
00 レベル0 0000H 0001H
01 レベル1 0002H 0003H
10 レベル2 0004H 0005H
11 割り込みと無関係 0006H 0007H

この表で、STRアドレスのメモリから割り込み以前のSTRの内容を、ICアドレスのメモリから割り込み以前のICの内容を、復元します。MN1613の割り込みは3レベルですが、LPSW命令では4番目のレベルに相当する値をLLに指定しても未定義命令としては扱われず、それなりに動作し、一種の間接分岐命令のように利用できます。

ビット命令とシフト命令については4種類が新設されています。
命令  オペコード         2語目 EV  動作
TBIT  00101 rrr kkkk DDDD            (R) & Bit(D), skip
SBIT  00111 rrr kkkk DDDD            R <- (R) | Bit(D), skip
RBIT  00110 rrr kkkk DDDD            R <- (R) & ~Bit(D), skip
TSET  00010 111 kkkk 1sss  AD16      (EA) & (Rs), skip, EA <- (EA) | (Rs)
TRST  00010 111 kkkk 0sss  AD16      (EA) & (Rs), skip, EA <- (EA) & ~(Rs)
SRBT  00111 111 0111 0sss            R0 <- Fisrt bit pos.(Rs), reset the bit
DEBP  00111 111 1111 0ddd            Set bit pos.(R0) of Rd
SR    00100 rrr kkkk 10EE        *   Shift Right with Modified E, skip
SL    00100 rrr kkkk 11EE        *   Shift Left with Modified E, skip
SR, SL命令のEEフィールドはEレジスタ操作を意味するフィールドで、次の表のような操作が行われます。
EE 記号 操作
00 -- 変化なし
01 RE E <- 0, リセット
10 SE E <- 1, セット
11 CE E <- ~(E), 反転

TBIT, SBIT, RBIT命令はMN1610と同一動作で、DDDDで指定したビット番号のビットをそれぞれ、テスト、セット、リセットします。SBIT命令やRBIT命令でも、実効結果に応じてスキップを行います。ビット番号はMSBが0でLSBが15という規則で割り振られています。
TSET, TRST命令はMN1613で新設された命令で、マルチプロセッサないしマルチタスク環境下での排他制御に利用するための命令です。要はビットのテストと変更を不可分なバスサイクルで実行する命令です。16 bit直接番地指定でアドレッシングされたメモリからデータを読み込み、指定されたレジスタとの論理積を取り、スキップ条件をセットします。さらに、TSET命令の場合はレジスタの値と読み出した値の論理和を取り、レジスタのビットが1になっている場所をセットした上で、メモリに書き戻します。TRST命令の場合にはレジスタのビットが1になっている場所をリセットして、メモリに書き戻します。メモリの読み出しと書き込みは不可分なサイクルとなっていて、途中に割り込みが入る場合はもちろん、マルチプロセッサの場合でも、読み出しと書き込みの間に別のメモリアクセスが入らないようになっています。このしくみによって、メモリの初期値を0、レジスタに1を入れてスキップ条件にZを与えたTSET命令を使うなどすれば、クリティカルセクションの排他制御に使われるセマフォの実装などが可能になります。ただ、この命令の面倒な点は16 bit直接番地指定というところにあって、ユーザープロセスが直接TSET命令でセマフォを実装するわけにはいきません。異なるセグメントで実行されているプロセス同士でセマフォ用のメモリを共有できませんから。もちろん、すべてのセマフォ管理はオペレーティングシステムのシステムコールに任せるようにして、OS側でセマフォ用のメモリ割り当てまで管理すればよいだけのことで、セマフォを使うシステムなら一般的な設計に準じるだけのことだけです。
SRBT命令もMN1613で新設された命令で、指定されたレジスタの内容をMSBから調べていき、最初に1となっているビットを見つけたら、そのビット番号をR0に書きこむと共に、そのビットを0にリセットする命令です。すべて0の場合には10HがR0に入ります。ビットマップディスプレイとかキースキャンの類で使われるかもしれません。
DEBP命令もMN1613で新設されたもので、R0の下位4 bitをビット番号と解釈し、指定されたレジスタの、そのビット番号で指示されたビットを1にセットします。R0の上位12 bitは無視されます。やはりビットマップディスプレイとかキースキャンのような状況で利用可能な命令です。
SR命令とSL命令は指定されたレジスタとEレジスタを連結したうえでシフト(というよりローテート)を行う命令です。シフトに先立って、EEフィールドで指示されたEレジスタ操作が行われます。実質的にEレジスタ操作を与えなければローテート命令、REを指定すれば論理シフト命令となります。

最後に特殊命令を紹介します。
命令  オペコード         2語目 EV  動作
BLK   00111 111 0001 0111            While (R0) !=0 {(R1++) <- ((R2++)), R0--}
RD    00011 rrr dddd dddd            R <- (IM8_IO)
RDR   00100 rrr 0001 01ii            R <- ((Ri)_IO)
WT    00010 sss dddd dddd            IM8_IO <- (Rs)
WTR   00100 rrr 0001 00ii            (Ri)_IO <- (R)
LB    00001 111 0bbb 0111  AD16      BRd <- (EA)
LS    00001 111 0ppp 1111  AD16      SRd <- (EA)
STB   00001 111 1bbb 0111  AD16      EA <- (BRs)
STS   00001 111 1ppp 1111  AD16      EA <- (SRs)
CPYB  00001 111 1bbb 0ddd            Rd <- (BRs)
CPYS  00001 111 1ppp 1ddd            Rd <- (SRs)
CPYH  00111 111 1hhh 0ddd            Rd <- (HRs)
SETB  00001 111 0bbb 0sss            BRd <- (Rs)
SETS  00001 111 0ppp 1sss            SRd <- (Rs)
SETH  00111 111 0hhh 0sss            HRd <- (Rs)
H     00100 000 0000 0000            CPU Stop
ここでbbbフィールドはセグメントベースレジスタを指定するものです。
bbb レジスタ(W) レジスタ(R)
000 --- CSBR
001 SSBR SSBR
010 TSR0 TSR0
011 TSR1 TSR1
100 OSR0 OSR0
101 OSR1 OSR1
110 OSR2 OSR2
111 OSR3 OSR3
(W)は書き込み時、(R)は読み出し時を意味しています。要はCSBRだけをプログラムから直接書き換えると、普通は暴走してしまうので禁止されているわけです。

pppフィールドは特殊レジスタを意味していて、次のようになっています。
ppp レジスタ
000 SBRB
001 ICB
010 NPP

hhhフィールドはハードウエア制御レジスタを指定します。
hhh レジスタ(W) レジスタ(R)
000 TCR TCR
001 TIR TIR
010 TSR TSR
011 SCR SCR
100 SSR SSR
101 SOR SIR
110 IISR IISR

BLK命令はメモリのブロック転送を行う命令で、R1とTSR0で指定されるアドレスからR2とTSR1で指定されるアドレスへ、R0で指定される語数のデータを転送します。独立したセグメントレジスタを使えるので、任意の物理アドレス間の転送が可能です。理屈の上では転送語数に応じてms単位の実行時間が必要な場合もありますが、この命令では1回の転送サイクルの区切りごとに割り込みを受け付けるので、割り込み応答時間には悪影響を与えません。
RD命令とRDR命令は入力ポートからの読み込みを行います。MN1613はメモリとは独立したI/O空間を備えていて、16 bitでアドレッシングされます。RD命令はMN1610と互換性のある命令で、MN1610のI/O空間は256語しかなかったので8 bitで全I/O空間を指定していました。MN1613ではI/Oアドレスの上位8 bitが0で補われて、いわばI/O空間のゼロページにだけ参照します。RDR命令はレジスタ間接アドレッシングで全I/O空間を参照可能としています。
WT命令とWTR命令は出力ポートへ書き込みを行う以外はRD, RDR命令と同一です。
LB命令はメモリからセグメントベースレジスタへのデータ転送を行います。ただしCSBRについて直接書き換えることは禁止されていて、無理にbbbフィールドに000を指定すると未定義命令扱いされます。一般のセグメントベースレジスタのほか、割り込み時にCSBRを退避させるOSRxレジスタも扱うことができます。
STB命令はLB命令の逆を行うもので、ベースレジスタ類をメモリに退避させることができます。OSRxの退避と復帰ができるので、適切に使用すればOPSW領域の退避と復帰を合わせて多重割り込みも可能となります。後述のコンソール処理プログラムからはCSBRの退避を行おうとしても、正しい値が得られないことがあります。
LS, STS命令は特殊レジスタに対してLB, STB命令と同じことを行います。表にはpppフィールドの意味としてSBRB, ICBも含まれていますが、これらのレジスタ操作に関しては後述のコンソール処理プログラムでのみ可能で、通常の実行状態では未定義命令扱いされます。
CPYB, CPYS, SETB, SETS命令は、それぞれセグメントベースレジスタないし特殊レジスタと汎用レジスタ間の転送命令です。注意点も同じです。
CPYH, SETH命令はハードウエア制御レジスタ(IISRを含む)とレジスタ間のデータ転送を行うための命令です。内蔵のタイマや直列入出力機能に関するレジスタはI/O空間には割り当てられずに、このような特殊命令でのみアクセス可能となっています。ちなみにhhhフィールドに111を指定すると、それぞれDEBP, SRBT命令のビットパターンとなってしまいます。
H命令はプロセッサを停止状態に遷移させる命令です。
ちなみに、00000 000 0000 0000というビットパターンは未定義命令、11111 111 1111 1111というビットパターンはB命令として解釈されます。NOPが必要なら、MV R0, R0などの命令を代用します。
未定義命令を実行すると、レベル0内部割り込みが発生し、IISRのビット15が1にセットされます。
 
 

パナファコムはMN1613のあと、浮動小数点演算命令を強化した?MN1617を開発しています。

Return to Collection