nlp16
NLP-16は、ちぇりーたくあん様が開発したNAND(74HC00)だけで作る16bitCPUである。
NAND(74HC00)だけで16bitCPUを作る[NLP-16]
NLP-16は、以下のレジスタを持つ。
「名前」はMikeAssemblerのオペランドで用いる名前であり、大文字・小文字は区別しない。
名前 | ID | 説明 |
---|---|---|
ir1 | 0 | IR1 |
ir2 | 1 | IR2 |
ir3 | 3 | IR3 |
flag | 4 | Flag |
a | 5 | RegA |
b | 6 | RegB |
c | 7 | RegC |
d | 8 | RegD |
e | 9 | RegE (Serial I/O) |
serial | 9 | RegE (Serial I/O) |
ram | 10 | RAM (Device) |
device | 10 | RAM (Device) |
ua | 11 | Upper Address |
la | 12 | Lower Address |
ip | 13 | Program pointer |
sp | 14 | Stack pointer |
zero | 15 | Zero register |
レジスタも即値も指定できるオペランドにおいてレジスタ名が指定された場合、レジスタとして扱う。
例えば識別子a
の値を即値として用いたい場合は、+a
などとする。
命令の後ろに以下の接尾辞をつけることで、実行する条件(Flagフィールド)を指定できる。
大文字・小文字は区別しない。
接尾辞 | 実行する条件 |
---|---|
_nop | NOP |
_c | Cが立っているときに実行 |
_v | Vが立っているときに実行 |
_z | Zが立っているときに実行 |
_s | Sが立っているときに実行 |
(なし) | 常に実行 |
_nc | Cが立っていないときに実行 |
_nv | Vが立っていないときに実行 |
_nz | Zが立っていないときに実行 |
_ns | Sが立っていないときに実行 |
MikeAssemblerは、通常は即値の大きさに応じて自動で8bitか16bitかを決定する。
命令の後ろに8
をつけると、強制的に8bit即値を用いる。
命令の後ろに16
をつけると、強制的に16bit即値を用いる。
これらは、実行する条件を表す接尾辞を用いる場合はその前に指定する。
例えば、16bit即値を用い、Cが立っているときに実行するADD命令は add16_c a, b, 10
のように書く。
即値を2個用いる場合、通常は8bit即値と16bit即値の両方を用いる。
この指定を行うと2個とも同じ即値を用い、値が違う場合はエラーとなる。
MikeAssemblerでは、以下の命令に対応している。
命令の大文字・小文字は区別しない。
演算命令 | |
---|---|
命令 | 意味 |
add 出力先, 入力A, 入力B | ADD |
sub 出力先, 入力A, 入力B | SUB |
addc 出力先, 入力A, 入力B | ADD with carry |
subc 出力先, 入力A, 入力B | SUB with carry |
or 出力先, 入力A, 入力B | OR |
not 出力先, 入力A | NOT |
xor 出力先, 入力A, 入力B | XOR |
and 出力先, 入力A, 入力B | AND |
inc 出力先, 入力A | INC |
dec 出力先, 入力A | DEC |
incc 出力先, 入力A | INC with carry |
decc 出力先, 入力A | DEC with carry |
slr 出力先, 入力A | SLR |
sll 出力先, 入力A | SLL |
sar 出力先, 入力A | SAR |
sal 出力先, 入力A | SAL |
ror 出力先, 入力A | ROR |
rol 出力先, 入力A | ROL |
転送命令 | |
命令 | 意味 |
mov 転送先, 転送元/即値 | MOV / 即値代入 |
JMP命令 | |
命令 | 意味 |
jmp レジスタ/即値 | 8bit絶対番地 / 16bit絶対番地 / レジスタ間接 |
jmpr アドレス(即値) | 自己相対(加算/減算) 加算か減算かはアドレスに応じて自動で決定する。 レジスタや生の即値をオペランドとするには、 jmpadd |
jmpadd 入力A, 入力B | レジスタ同士で計算して指定(加算) |
jmpsub 入力A, 入力B | レジスタ同士で計算して指定(減算) |
スタック操作 | |
命令 | 意味 |
push PUSH元Reg | PUSH |
pop POP先Reg | POP |
サブルーチン命令 | |
命令 | 意味 |
call レジスタ/即値 | CALL 8bit絶対番地 / 16bit絶対番地 / レジスタ間接 |
callr アドレス(即値) | CALL 自己相対(加算/減算) 加算か減算かはアドレスに応じて自動で決定する。 レジスタや生の即値をオペランドとするには、 calladd |
calladd 入力A, 入力B | CALL レジスタ同士で計算して指定(加算) |
callsub 入力A, 入力B | CALL レジスタ同士で計算して指定(減算) |
ret | RET |
iret | 割り込みRET |
メモリ操作 | |
命令 | 意味 |
load LOAD先, レジスタ/即値 | LOAD 8bit絶対番地 / 16bit絶対番地 / レジスタ間接 |
loadr LOAD先, アドレス(即値) | LOAD 自己相対(加算/減算) 加算か減算かはアドレスに応じて自動で決定する。 レジスタや生の即値をオペランドとするには、 loadadd |
loadadd LOAD先, 入力A, 入力B | LOAD レジスタ同士で計算して指定(加算) |
loadsub LOAD先, 入力A, 入力B | LOAD レジスタ同士で計算して指定(減算) |
store STORE元, レジスタ/即値 | STORE 8bit絶対番地 / 16bit絶対番地 / レジスタ間接 |
storer STORE元, アドレス(即値) | STORE 自己相対(加算/減算) 加算か減算かはアドレスに応じて自動で決定する。 レジスタや生の即値をオペランドとするには、 storeadd |
storeadd STORE元, 入力A, 入力B | STORE レジスタ同士で計算して指定(加算) |
storesub STORE元, 入力A, 入力B | STORE レジスタ同士で計算して指定(減算) |
比較命令 | |
命令 | 意味 |
cmp 入力A, 入力B | CMP |
疑似命令 | |
命令 | 意味 |
nop | 1ワードのNOP (ret_nop )実行する条件の指定・即値サイズ指定には対応しない。 |
worddata 値 [, 値 [, ...]] | 指定の値を各2バイトで順に配置する。 実行する条件の指定・即値サイズ指定には対応しない。 文字列データの配置には対応しない。 |
命令のフォーマットやオペコードは、以下を参照のこと。
NLP-16ではワード(2バイト)単位のアドレスを扱う一方、MikeAssemblerではバイト単位のアドレスを扱う。
そこで、NLP-16固有の命令においては、ラベルの値を自動的に2で割り、ワード単位に変換する。
ラベルの値が奇数の場合はエラーとなる。
なお、define
で定義した識別子は変換しない。
一方、org
、define
、data
系などのMikeAssembler共通の疑似命令においては、この変換を行わない。
そのため、以下の対応が必要である。
org
においては、ワード単位のアドレスを2倍してバイト単位に変換する。define
やdata
系でラベルを用いてワード単位のアドレスを定義/配置する場合は、明示的に2で割る。
なお、worddata
疑似命令はNLP-16固有であり、この明示的な変換は不要である。
target nlp16
; ラベルが自動でワード単位のアドレスに変換される
load a, data_label
; ラベルは自動で変換されるが、置かれているデータは変換されない
load b, addr_label
; bに格納したアドレス (data_label) から読み込む
load c, b
addr_label:
; ラベルを明示的に2で割ってワード単位のアドレスに変換する
dataw data_label / 2
data_label:
dataw 0