なんも説明もしてなかった気がするので
とりあえず少し書いておくと、まず第1回で書いたようにROMは作れた。
A0 0 0 A1 0 0 A2 0 0 ... Ae 0 0 Af 1 1 ## こんな感じにADDR <- 0x7FFF みたいに、アドレスをセットして ## ROMのコードに突っ込むと ## BEGIN ROM if (ADDR-- == 0) { DATA <- 'H'; } if (ADDR-- == 0) { DATA <- 'e'; } if (ADDR-- == 0) { DATA <- 'l'; } ... if (ADDR-- == 0) { DATA <- '\n'; } ## END ROM ## ここで DATA に対応するバイトが読まれてる
次にCPUを作る。
PC <- 0x0000 # プログラムカウンタを0に # リセット完了 LOOP1: LOOP2: ADDR <- PC # プログラムカウンタをアドレスレジスタにコピー ROMを実行する DATAをデコードする PC++ なんか実行する if (出力命令でもHLT命令でもない) goto LOOP1; 出力する if (HLT命令じゃない) goto LOOP2;
大枠はこんな感じ。あとは命令セットを決めて実装すればよい。Quineを作るだけなので簡単な命令だけでよくて
// 8bitレジスタ A // 16bitレジスタ HL // 16bitレジスタ SAVED_PC op = read_rom(PC); if (op & 0x80) { if (op & 0x40) { oprand, eom = read_rom(HL); // オペランドをフェッチする。HLがメモリの終端を指してたらeom=1 if (op & 0x20) { // INC_HL_AND_JUMP_UNLESS_EOM HL++; if (!eom) { PC = SAVED_PC; } } else { // LD A, (HL) A = oprand; } } else { if (op & 0x20) { // SHIFT_PUTC 命令 putchar('0' + (A & 1)); A >>= 1; } else { if (op & 0x10) { // HLT 命令 hlt(); } else { // SAVE_PC命令 SAVED_PC = PC; } } } } else { // PUTC 命令 putchar(op & 0x7F); }
というルールでデコードして実行する。オペランドをフェッチするところをCPUに足すのは簡単にできるからこれで完成。
定数文字を出力する命令が一番多いので、7ビット目が立ってない命令はそのまま出力にしてある。