2014年7月1日火曜日

突如として仮想CPUを考える

久々に学研4ビットマイコンに電池を入れて遊んだ。といってもこれ自体が別のマイコン上でかつての学研電子ブロックFXで使われていた4ビットマイコンを模しているエミュレータなのだった。


















これで遊んでいるうちに、自分でも簡単なエミュレータを作ってみようと思い立った。

まずは仕様を決めた。4ビットでは小さすぎて却って使いにくいので、ロングセラーZ80と同じ8ビットにすることとした。

次に演算や処理のデータを置いておくレジスターだが、まずAとBという2つの汎用レジスターを用意した。この2つでキャッチボールすれば最低限の演算はできるだろう。

次に計算結果を示すフラグとして0かそれ以下になったことを示すゼロフラグと、計算結果が大きすぎて桁あふれになったことを示すキャリーフラグを考えた。あとはいまアドレスのどこにいるかを示すプログラムカウンター(PC)も必要だ。

次に命令だが、自分のおおざっぱな理解では、CPUの命令は、データ転送、演算、比較、それにCPUの制御の4種類に大別できると思っている。ということで命令セットもシンプルに考えた。

まずデータ転送だが、レジスター同士のやり取り、レジスターからメモリ、メモリからレジスターへのやり取りを想定した。メモリからメモリもあり得るが、それはメモリからレジスターに転送し、次にレジスターから指定先のメモリに移せばいいので、割愛した。以下のような命令になる。

LD A B
LD B A
LD A (メモリ番地)
LD (メモリ番地) A
**LDはLoadを意味する

次に演算だが、レジスター同士の足し算(加算)と引き算(減算)を考えた。掛け算(乗算)と割り算(除算)は割り切れば何回も加算・減算をすれば実現できるので、シンプルCPUには実装しないこととした。

ADD A B (結果はレジスターAに格納される)
MIN A B (結果はレジスターAに格納される)

次は比較だが、2つのレジスターの値を比較し、その結果によってゼロフラグやキャリーフラグの状態を変えることになる。ちなみに先ほどの演算の結果も、フラグの状態に影響を及ぼす。

CMP A B
**Compareの意味

このとき(A-B)がゼロかマイナスになると、ゼロフラグがセットされる。

そして、それらの結果によって、以下のように指定した番地に飛ぶ命令が必要になってくる。

JZ (メモリ番地)
JNZ (メモリ番地)
**Jump Zero もしくはJump Non-Zeroの意味

これはゼロフラグの状態によって特定の処理をさせたい場合に使う命令だ。

ほかにも何も処理しない時間稼ぎの命令とか、リセットとかいくつか想定するべきだが、何だか面倒になってきたので、プログラムの練習がてら、Rubyで書いてみようと思う。

0 件のコメント:

コメントを投稿