L-16Aの評価用キットとして発売されたLKit-16は、当時珍しい16 bit CPUが使われていたことで評判でした。
で、これがそのCPUであるMN1610。パッケージ違いの2種類を掲載します。MN1610は2 MHzの2相クロックで動作しますが、4 MHz版もMN1610Aとして後に製造されています。こちらも持っているけど、写真省略。
下はMN1613と類似のパッケージで、後期型と思われます。
なんか、型番やマークから、製造は松下なんだなぁと、思えてしまいますね。
レジスタは汎用レジスタが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語命令というシンプルさです。以下に全命令を示します。
意味 アセンブリ言語表記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命令はレジスタの下位バイトに定数をロードします。
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, EAAdd 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, SkipOperate 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, SkipLoad 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
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ページ間接インデックス |
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命令を指定すれば、あらかじめそのメモリに入っていた数値に従ってループするコードになります。
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で桁上がり補正を行う必要のある場合、補正用の定数を変更して少々コードを追加をすると実現できます。
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を行えば算術右シフトになります。
Return to IC Collection