RETROF-16 機械語命令一覧

#RETROF-16 機械語命令一覧

全ての命令を13クロックで実行します。（停止命令のみ10クロックで実行）
クロックは16MHｚですので、本機は本記事の命令を1秒間に123万命令実行できます。

###表中の略語
* mnim ： ニモニック
* opr ： オペランドを要する命令か否か（〇 要、― 不要）　
* flg ： フラグが変化する命令か否か（〇 変化する、― 変化しない）
* Acc ： アキュムレータ
* Memory[op] ： オペランドをアドレスとする主メモリの値　
* VRAM[op] ： オペランドをアドレスとするビデオメモリの値　
* *xx* :オペランド。以下の4通りの書き方がある。
 
|書式|意味|補足|
|---|---|---|---|
| 数値 |数値をそのまま参照する|数値は0～255(または#00～#FF)|
| $数値 |n番レジスタの値を参照する|nが数値。0～255(または#00～#FF)|
| %数値 |n番レジスタが示すメモリの値<br>を参照する|nが数値。0～255(または#00～#FF)|
|数値|数値をそのままop参照する<br>この書式は2ワード命令となる|数値は256～65535<br>(または#0100～#FFFF)|

###命令一覧

|機械語|mnim|opr|flg|機能|注|
|-----|----------|---|---|---|---|
|0000_00xx |jmp *xx* |〇|―|絶対アドレス分岐する|
|0001_00xx |jb *xx* |〇|―|LCD表示回路が水平帰還時なら（以下同上）|*1
|0010_00xx |jnf *xx* |〇|―|演算結果が0xFFFF以外なら（以下同上）|
|0011_00xx |jf *xx* |〇|―|演算結果が0xFFFFなら（以下同上）|
|0100_00xx |jnc *xx* |〇|―|加算にキャリーが無ければ（以下同上）|*2
|0101_00xx |jc  *xx* |〇|―|加算にキャリーがあれば（以下同上）|*2
|0110_00xx |jm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
|0111_00xx |jnm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
||||||
|0000_01xx |fj *xx* |〇|―|opの値分、前方へ相対アドレス分岐する|*3
|0001_01xx |fb *xx* |〇|―|LCD表示回路が水平帰還時なら（以下同上）|*1
|0010_01xx |fnf *xx* |〇|―|演算結果が0xFFFF以外なら（以下同上）|
|0011_01xx |ff *xx* |〇|―|演算結果が0xFFFFなら（以下同上）|
|0100_01xx |fnc *xx* |〇|―|加算にキャリーが無ければ（以下同上）|*2
|0101_01xx |fc  *xx* |〇|―|加算にキャリーがあれば（以下同上）|*2
|0110_01xx |fm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
|0111_01xx |fnm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
||||||
|0000_10xx |bj *xx* |〇|―|opの値分、後方へ相対アドレス分岐する|*3
|0001_10xx |bb *xx* |〇|―|LCD表示回路が水平帰還時なら（以下同上）|*1
|0010_10xx |bnf *xx* |〇|―|演算結果が0xFFFF以外なら（以下同上）|
|0011_10xx |bf *xx* |〇|―|演算結果が0xFFFFなら（以下同上）|
|0100_10xx |bnc *xx* |〇|―|加算にキャリーが無ければ（以下同上）|*2
|0101_10xx |bc  *xx* |〇|―|加算にキャリーがあれば（以下同上）|*2
|0110_10xx |bm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
|0111_10xx |bnm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
||||||
|0000_11xx |hlt *xx* |〇|―|opの値を基板のLEDに表示し停止する|
|0001_11xx |hb *xx* |〇|―|LCD表示回路が水平帰還時なら（以下同上）|*1
|0010_11xx |hnf *xx* |〇|―|演算結果が0xFFFF以外なら（以下同上）|
|0011_11xx |hf *xx* |〇|―|演算結果が0xFFFFなら（以下同上）|
|0100_11xx |hnc *xx* |〇|―|加算にキャリーが無ければ（以下同上）|*2
|0101_11xx |hc  *xx* |〇|―|加算にキャリーがあれば（以下同上）|*2
|0110_11xx |hm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
|0111_11xx |hnm *xx* |〇|―|演算結果のMSBが1なら（以下同上）|
||||||
|1000_00xx |ldi *xx* |〇|〇|opの値をAccに格納する|
|1000_01xx |add *xx* |〇|〇|Acc+opをAccに格納する|
|1000_10xx |sub *xx* |〇|〇|Acc-opをAccに格納する|
|1000_11xx |ldn *xx* |〇|〇|opの反転値をAccに格納する|
|1001_00xx |and *xx* |〇|〇|Acc&opをAccに格納する|
|1001_01xx |or  *xx* |〇|〇|Acc&#124;opをAccに格納する|
|1001_10xx |xor *xx* |〇|〇|Acc^opをAccに格納する|
|1001_11xx |add *xx* |〇|〇|Acc^opの反転値をAccに格納する|
||||||
|1100_00xx |stm *xx* |〇|―|Memory[op]にAcc値をストアする|
|1100_01xx |ldm *xx* |〇|〇|Memory[op]の値をAcc値をロードする|
|1100_10xx |stv *xx* |〇|―|VRAM[op]にAcc値をストアする|
|1100_11xx |ldv *xx* |〇|〇|VRAM[op]の値をAcc値をロードする|
|1101_00xx |out *xx* |〇|―|Accの値を下段、op値を上段LEDに表示する|
|1101_01xx |lpc *xx* |―|〇|プログラムカウンタの値をAccに格納する|*4
|1101_10xx |sft *xx* |―|〇|Accを右シフトする。MSBには0が入る|
|1101_11xx |ina *xx* |―|―|入力ポートAの値をAccに格納する|
|1111_11xx |inb *xx* |―|―|入力ポートBの値をAccに格納する|

(&#42;1) 「水平帰還時」に関しては、ここでは詳細説明は割愛。「水平帰還信号」「水平ポーチ信号」「水平ブランキング機関」等で検索のこと。
(&#42;2)　減算時はjncが「ボローがあれば分岐」、jcが「ボローが無ければ分岐」となる。
(&#42;3)　相対分岐はlpc命令の次の命令が起点。自分自身への分岐は「bj 1」もしくは「ff 65535」。
(&#42;4)　Accに格納される値はlpc命令の次の命令のアドレスとなる。

### ldv命令とstv命令に関する補足

* ldv（load from video-RAM）=> オペランドで決まる位置のドットの色をAccに読み込む
* stv（store to video-RAN）=> オペランドで決まる位置にAcc値で決まる色のドットを描画する

「オペランドで決まる位置」とは、画面上の左上が0x0000、右下が0xFFFFとなります。
![WS2019_000823.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/5643880e-71ba-8314-1c14-8e736c9ba918.jpeg)
本機は16bitマシンですが、画像データバスは6bitです。従ってldv命令の実行直後はAccの上位10bitは「不定」となります。また、stv命令実行時はAccの上位10bitは意味を持ちません。
![WS2019_000822.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/4faeb5b2-5347-cd72-693b-123d8be8dc79.jpeg)
RGBの3色は各々2bit（4階調）です。青色を例にとると、この2bitと明度の関係は以下となります（赤や緑も同様です）。

* XXXX_XXXX_XX00_0011 ⇒　青 
* XXXX_XXXX_XX00_0010 ⇒　やや暗い青 
* XXXX_XXXX_XX00_0001 ⇒　とても暗い青 
* XXXX_XXXX_XX00_0011 ⇒　黒 




### ldi命令とldm命令の差異に関する補足

本機は主メモリの0~255番地を汎用レジスタ領域としているため、例えば「主メモリの100番地の値」と「100番レジスタの値」は同義となる。
このためldiとldm命令はアドレッシングモードによっては全く同じ動作をする命令となることがある。

* ldi（load immediate）  =>  値（オペランド）を直接ACCに格納する
* ldm（load from memory）=>  値をアドレスとし、メモリ値をACCに格納する

以下は、4つのアドレッシングモードを加味したldiとldm命令の比較である。

||記述例|対応する機械語命令|機能|
|---|-----|----------|---|
|A|ldi 5 |1000_0000_0000_0101|数値5がAccに格納される|
|B|ldi $5|1000_0001_0000_0101|5番レジスタの内容がAccに格納される|
|C|ldi %5|1000_0010_0000_0101|5番レジスタの内容をアドレスとした<br>主メモリの内容がAccに格納される|
|D|ldi 255 |1000_0000_0000_0000<br>0000_0001_0000_0000|数値256がAccに格納される<br>（数値が256以上は2ワード命令となる）|
||||
|E|ldm 5 |1000_0000_0000_0101|5番レジスタの内容がAccに格納される|
|F|ldm $5|1000_0001_0000_0101|5番レジスタの内容をアドレスとした<br>主メモリの内容がAccに格納される|
|G|ldm %5|1000_0010_0000_0101|5番レジスタの内容をアドレスとした<br>主メモリの値を、更にアドレスとして<br>その主メモリの値がAccに格納される|
|H|ldm 255 |1000_0000_0000_0000<br>0000_0001_0000_0000|256番地の内容がAccに格納される<br>（数値が256以上は2ワード命令となる）|

この表で判るように「BとE」及び「CとF」は全く同じ命令となる。
どちらを使用しても問題は無いが、immediate（即値）と言う言葉を意識するのであれば、、即値代入以外はldi命令と称するのは好ましくない。このため運用上の制限ではあるが「BとC」は使わない事とする。