命令セット
一つ前のブログから命令周りを大幅に変更しました。命令の数は全部で16個でちょうど16進数一桁で4bitで表すことができる数です。演算命令は思い切って加算器を使うもののみにしました。足し算、引き算、比較だけです。論理演算は一切ないですが代わりにCALL命令とRETURN命令をねじ込みました。スタックを持っているのでCALL命令は欲しいですよね。以下命令のリストです。
命令は3つの要素で構成される。(命令、値1、値2)である。命令によっては値1や値2のみ使用するものがあるが、その場合使用しない値にはダミーを置く。必ず連続した3つのアドレス先に格納されプログラムカウンタは命令毎に+3される。なおメモリには値2、値1、命令の順番で格納される。 下記の命令詳細に用いている略語は表下部に記述。←は値のコピーを示す。また()で示すものは括弧内をアドレスとして用いて、その示す先。
命令 | 機械語 | ニーモニック | 命令全体 | 詳細 |
---|---|---|---|---|
move | 0 | MOV | MOV, STA, LDA | ストアアドレス、ロードアドレスを指定して、ロードアドレス先の内容をストアアドレス先にコピーする。 ロードアドレス先の内容は変化しない。 (STA) ← (LDA) |
move immediate C register | 1 | MVIC | MVIC, IM, — | 即時データをCレジスタに格納する。 C ← IM |
move immediate D register | 2 | MVID | MVID, IM, — | 即時データをDレジスタに格納する。 D ← IM |
addition | 3 | ADD | ADD, STA, LDA | ストアアドレス、ロードアドレスを指定して、それぞれの内容を加算しストアアドレス先に格納する。 ロードアドレス先の内容は変化しない。 フラグレジスタが更新される。 (STA) ← (STA) + (LDA) FR ← FR |
subtraction | 4 | SUB | SUB, STA, LDA | ストアアドレス、ロードアドレスを指定して、ストアアドレス先の内容からロードアドレス先の内容を減算した値をストアアドレス先に格納する。 ロードアドレス先の内容は変化しない。 フラグレジスタが更新される。 (STA) ← (STA) – (LDA) FR ← FR |
Comparison | 5 | CMP | SUB, STA, LDA | ストアアドレス、ロードアドレスを指定して、ストアアドレス先の内容からロードアドレス先の内容を減算した値でもってフラグレジスタを更新する。 ストアアドレス先の内容、ロードアドレス先の内容は変化しない。 フラグレジスタが更新される。 FR ← FR |
address jump | 6 | ADJP | ADJP, –, LDA | ロードアドレスを指定して、ロードアドレス先の内容をプログラムカウンタに格納する。 ロードアドレス先の内容は変化しない。 PC ← (LDA) |
jump | 7 | JMP | JMP, IM, — | 即時データをプログラムカウンタに格納する。 PC ← IM |
jump carry | 8 | JC | JC, IM, — | キャリーフラグが1の時即時データをプログラムカウンタに格納する。 PC ← IM (Cflag == 1) |
jump not carry | 9 | JNC | JNC, IM, — | キャリーフラグが0の時即時データをプログラムカウンタに格納する。 PC ← IM (Cflag == 0) |
jump zero | A | JZ | JZ, IM, — | ゼロフラグが1の時即時データをプログラムカウンタに格納する。 PC ← IM (Zflag == 1) |
jump not zero | B | JNZ | JNZ, IM, — | キャリーフラグが0の時即時データをプログラムカウンタに格納する。 PC ← IM (Cflag == 0) |
push | C | PUSH | PUSH, –, LDA | ロードアドレスを指定して、ロードアドレス先の内容をスタックポインタが示す先に格納する。 格納後スタックポインタはデクリメントされる。 ロードアドレス先の内容は変化しない。 (SP) ← (LDA) SP ← SP-1 |
pop | D | POP | POP, STA, — | スタックポインタをインクリメントする。 インクリメント後、指定したストアアドレス先にスタックポインタが示す先の内容を格納する。 ストアアドレスにはレジスタのみ指定できる。 SP ← SP+1 (STA) ← (SP) |
call | E | CALL | CALL, IM, — | プログラムカウンタの内容をスタックポインタが示す先に格納する。 格納後スタックポインタはデクリメントされ、即時データをプログラムカウンタに格納する。 プッシュされるプログラムカウンタの内容は内部処理の関係上、現在実行中のアドレス(CALL命令が書かれているアドレス)より+1された値となる。 (SP) ← PC SP ← SP-1 PC ← IM |
return | F | RET | RET, –, — | スタックポインタをインクリメントする。 インクリメント後、プログラムカウンタにスタックポインタが示す先の内容を格納する。 SP ← SP+1 PC ← (SP) |
STA ストアアドレス LDA ロードアドレス IM 即時データ C Cレジスタ D Dレジスタ FR フラグレジスタ PC プログラムカウンタ SP スタックポインタ
命令デコーダ
上の表にある機械語の欄の通り、今までのややこしいものから分かりやすくなりました。先駆者のホームページや本から学ばせて頂きました。やっぱり順番に並んでいた方が分かりやすいですし命令デコーダもアドレスデコーダを使えまばすごく楽に作ることができます。いままでややこしく作っていたのが恥ずかしいです。
論理演算について
CPUとして論理演算がないのはつらいです。しかしながら前作のTTM4ではAND,OR,XORを実行可能でしたが加算器を使った演算に比べて使用頻度が低かったです。また、論理演算するならこの3つの命令では不十分で右シフトはやっぱりあったほうがいいでしょう。こうなると全部で16命令という制限を大分圧迫してしまうので割り切りました。このCPUは追加で外部にレジスタを持てるように設計しているので、足りない命令を補うような動作をするレジスタを外付けできるようにする予定です。
スタックポインタを少し変更
スタックポインタはスタックに格納した最新のデータの保存先のアドレスを示す。
から
スタックポインタは次に格納するデータの保存先のアドレスを示す。
に変更。
自分のメモのつもりで書きます。スタックポインタはスタックを構成する領域のデータを管理するためのレジスタだが、私はスタックポインタはPUSHした最新のデータの格納した先を示すと習った。が、次のデータ格納先を示す場合もあるらしい。私は最初前者で設計していたが、CALL命令を実装するにあたって。前者であれば、先にスタックポインタをデクリメントしその後スタックポインタが示す先にプログラムカウンタの値を格納してさらにプログラムカウンタにジャンプ先のアドレスを格納する。これだとどうしても命令実行に3クロックが必要になる。後者であれば先にスタックポインタが示す先にプログラムカウンタの値を格納する。次にスタックポインタのインクリメントとプログラムカウンタにジャンプ先のアドレスを格納する。この操作は同時に行う事ができる。スタックポインタのインクリメントはデータバスを占領しないので、スタックポインタのインクリメントと同時にプログラムカウンタの更新を行うことでCALL命令が2クロックで実行できるようになる。このため”スタックポインタは次のデータ格納先を示す”に変更した。