概要
windowsでiverilogやってみた。
8bit CPU、書いてみた。
8bitCPUで、何ができる。
fizzbuzzを100まで、数えることができる。
1. 基本命令一覧
引数(opland)がない命令は、下位8ビットを8'h00(00000000)として処理するのが一般的です。
| ニーモニック | 動作説明 | スタック変化 | 機械語 (2進数 [11:0]) | 機械語 (16進数) |
|---|---|---|---|---|
| HALT | プログラムの実行を停止(PCを固定) | なし | 0000_00000000 | 12'h000 |
| PUSH v | 8ビット即値 v をスタックに積む | [ → v ] | 0010_vvvvvvvv | 12'h2vv |
| ADR a | ジャンプ先アドレス a(6bit)をセット | なし | 0011_00aaaaaa | 12'h3aa |
| JEQ | q[0]==1 以外なら adr へジャンプ、実行後ポップ | [ q[0] → ] | 0100_00000000 | 12'h400 |
| OUT | スタックトップの値を外部出力し、ポップ | [ q[0] → ] | 0101_00000000 | 12'h500 |
| DUP | スタックトップの値を複製(EXT 8'h20 と同等) | [ → q[0] ] | 1000_00000000 | 12'h800 |
| DROP | スタックトップの値を1つ破棄(EXT 8'h21 と同等) | [ q[0] → ] | 1001_00000000 | 12'h900 |
2. 条件付きジャンプ拡張命令
仕様書によると、op = 4'h4(JEQ)の挙動が下位8ビット(opland)によって以下のように変化・拡張されます。
| ニーモニック | 動作説明 | スタック変化 | 機械語 (2進数 [11:0]) | 機械語 (16進数) |
|---|---|---|---|---|
| IF0 | q[0] == 0 なら adr へジャンプ、実行後ポップ | [ q[0] → ] | 0100_00000000 | 12'h400 |
| IF1 | q[0] == 1 なら adr へジャンプ、実行後ポップ | [ q[0] → ] | 0100_00000001 | 12'h401 |
| jmp | 無条件で adr へジャンプ、実行後ポップ | [ q[0] → ] | 0100_00001111 | 12'h40F |
3. 拡張演算・システム命令一覧(EXT: op = 4'hF)
上位4ビットが 4'hF(1111)となり、下位8ビット(opland)で具体的な演算を指定する命令群です。
算術・論理演算
| ニーモニック | 動作説明 | スタック変化 (前 → 後) | 機械語 (2進数 [11:0]) | 機械語 (16進数) |
|---|---|---|---|---|
| + | 加算(q[1] + q[0]) | [ q[1], q[0] ] → [ 答 ] | 1111_00000000 | 12'hF00 |
| - | 減算(q[1] - q[0]) | [ q[1], q[0] ] → [ 答 ] | 1111_00000001 | 12'hF01 |
| * | 乗算(q[1] * q[0]) | [ q[1], q[0] ] → [ 答 ] | 1111_00000010 | 12'hF02 |
| / | 除算(q[1] / q[0])※0除算は0 | [ q[1], q[0] ] → [ 答 ] | 1111_00000011 | 12'hF03 |
| mod | 剰余(q[1] % q[0])※0除算は0 | [ q[1], q[0] ] → [ 答 ] | 1111_00000100 | 12'hF04 |
| = | 比較(等しければ1、違えば0) | [ q[1], q[0] ] → [ 1 or 0 ] | 1111_00001111 | 12'hF0F |
| < | 比較(q[1] < q[0] なら1、違えば0) | [ q[1], q[0] ] → [ 1 or 0 ] | 1111_00010000 | 12'hF10 |
| > | 比較(q[1] > q[0] なら1、違えば0) | [ q[1], q[0] ] → [ 1 or 0 ] | 1111_00010001 | 12'hF11 |
| max | 大きい方の値を選択 | [ q[1], q[0] ] → [ 最大値 ] | 1111_00010012 | 12'hF12 |
| min | 小さい方の値を選択 | [ q[1], q[0] ] → [ 最小値 ] | 1111_00010013 | 12'hF13 |
| and | ビット論理積(q[1] & q[0]) | [ q[1], q[0] ] → [ 答 ] | 1111_00010100 | 12'hF14 |
| or | ビット論理和(q[1] | q[0]) | [ q[1], q[0] ] → [ 答 ] | 1111_00010101 |
| invert | ビット反転(※ポップなし) | [ q[0] ] → [ ~q[0] ] | 1111_00010110 | 12'hF16 |
スタック操作(Forth互換)
| ニーモニック | 動作説明 | スタック変化 (前 → 後) | 機械語 (2進数 [11:0]) | 機械語 (16進数) |
|---|---|---|---|---|
| dup | スタックトップを複製して積む | [ q[0] ] → [ q[0], q[0] ] | 1111_00100000 | 12'hF20 |
| drop | スタックトップを1つ削除 | [ q[0] ] → [ ] | 1111_00100001 | 12'hF21 |
| swap | 上位2つの値を入れ替える | [ q[1], q[0] ] → [ q[0], q[1] ] | 1111_00100010 | 12'hF22 |
| over | 上から2番目の値を複製して一番上に積む | [ q[1], q[0] ] → [ q[1], q[0], q[1] ] | 1111_00100011 | 12'hF23 |
| rot | 上位3つの値を回転(q[2]が最上位へ) | [ q[2], q[1], q[0] ] → [ q[1], q[0], q[2] ] | 1111_00100100 | 12'hF24 |
コンソール出力・デバッグ・特殊
| ニーモニック | 動作説明 | スタック変化 | 機械語 (2進数 [11:0]) | 機械語 (16進数) |
|---|---|---|---|---|
| . | q[0] を「10進数数値」として出力、ポップ | [ q[0] → ] | 1111_00110000 | 12'hF30 |
| emit | q[0] を「ASCII文字」として出力、ポップ | [ q[0] → ] | 1111_00110001 | 12'hF31 |
| cr | 改行(\n)を出力 | なし | 1111_00110010 | 12'hF32 |
| space | 半角スペースを出力 | なし | 1111_00110013 | 12'hF33 |
| .s | 現在のスタック(q[0]~q[5])を一覧表示 | なし | 1111_00110100 | 12'hF34 |
| random | 0〜255のランダムな数値を積む | [ → 乱数 ] | 1111_01000000 | 12'hF40 |
サンプルコード
// ROM PROGRAM: FizzBuzz (1 to 100)
rom[0] <= 12'h2_00; // PUSH 0 (ループカウンター初期値)
// --- [アドレス1] ループ先頭 ---
rom[1] <= 12'h2_01; // PUSH 1
rom[2] <= 12'hF_00; // + [Stack: Count] (インクリメント)
// --- 101終了判定 ---
rom[3] <= 12'hF_20; // dup [Stack: Count, Count]
rom[4] <= 12'h2_65; // PUSH 101 [Stack: 101, Count, Count]
rom[5] <= 12'hF_0F; // = [Stack: (Count==101), Count]
rom[6] <= 12'h3_3A; // ADR 58 (終了処理アドレス 58 = 16進数3A)
rom[7] <= 12'h4_01; // JNE (IF1) (Count==101 なら終了処理へ)
// --- FizzBuzz (15の倍数) 判定 ---
rom[8] <= 12'hF_20; // dup
rom[9] <= 12'h2_0F; // PUSH 15
rom[10] <= 12'hF_04; // mod [Stack: (Count%15)]
rom[11] <= 12'h3_25; // ADR 37 (FizzBuzz出力アドレス 37 = 16進数25)
rom[12] <= 12'h4_00; // JEQ (IF0) (余り0ならジャンプ、違えば直進)
// --- Fizz (3の倍数) 判定 ---
rom[13] <= 12'hF_20; // dup
rom[14] <= 12'h2_03; // PUSH 3
rom[15] <= 12'hF_04; // mod [Stack: (Count%3)]
rom[16] <= 12'h3_1B; // ADR 27 (Fizz出力アドレス 27 = 16進数1B)
rom[17] <= 12'h4_00; // JEQ (IF0) (余り0ならジャンプ、違えば直進)
// --- Buzz (5の倍数) 判定 ---
rom[18] <= 12'hF_20; // dup
rom[19] <= 12'h2_05; // PUSH 5
rom[20] <= 12'hF_04; // mod [Stack: (Count%5)]
rom[21] <= 12'h3_2F; // ADR 47 (Buzz出力アドレス 47 = 16進数2F)
rom[22] <= 12'h4_00; // JEQ (IF0) (余り0ならジャンプ、違えば直進)
// --- 通常の数値表示 (どの倍数でもなかった場合) ---
rom[23] <= 12'hF_20; // dup
rom[24] <= 12'hF_30; // . (数値を表示&消費)
rom[25] <= 12'h3_37; // ADR 55 (共通改行アドレス 55 = 16進数37)
rom[26] <= 12'h4_FF; // JMP (改行処理へ無条件ジャンプ)
// --- [アドレス27] Fizz出力処理ブロック ---
rom[27] <= 12'h2_46; // PUSH 'F'
rom[28] <= 12'hF_31; // emit
rom[29] <= 12'h2_69; // PUSH 'i'
rom[30] <= 12'hF_31; // emit
rom[31] <= 12'h2_7A; // PUSH 'z'
rom[32] <= 12'hF_31; // emit
rom[33] <= 12'h2_7A; // PUSH 'z'
rom[34] <= 12'hF_31; // emit
rom[35] <= 12'h3_37; // ADR 55 (共通改行アドレス 55 = 16進数37)
rom[36] <= 12'h4_FF; // JMP
// --- [アドレス37] FizzBuzz出力処理ブロック ---
rom[37] <= 12'h2_46; // PUSH 'F'
rom[38] <= 12'hF_31; // emit
rom[39] <= 12'h2_69; // PUSH 'i'
rom[40] <= 12'hF_31; // emit
rom[41] <= 12'h2_7A; // PUSH 'z'
rom[42] <= 12'hF_31; // emit
rom[43] <= 12'h2_7A; // PUSH 'z'
rom[44] <= 12'hF_31; // emit
rom[45] <= 12'h3_2F; // ADR 47 (そのままBuzz出力 47 = 16進数2F へ合流)
rom[46] <= 12'h4_FF; // JMP
// --- [アドレス47] Buzz出力処理ブロック ---
rom[47] <= 12'h2_42; // PUSH 'B'
rom[48] <= 12'hF_31; // emit
rom[49] <= 12'h2_75; // PUSH 'u'
rom[50] <= 12'hF_31; // emit
rom[51] <= 12'h2_7A; // PUSH 'z'
rom[52] <= 12'hF_31; // emit
rom[53] <= 12'h2_7A; // PUSH 'z'
rom[54] <= 12'hF_31; // emit
// ※次のアドレス55が共通改行なので、BuzzからはJMPを省略してそのまま直進(フォールスルー)
// --- [アドレス55] 共通改行&ループバック処理 ---
rom[55] <= 12'hF_32; // cr (改行を出力)
rom[56] <= 12'h3_01; // ADR 1 (ループ先頭へ)
rom[57] <= 12'h4_FF; // JMP (ループ先頭アドレス1へ無条件ジャンプ)
// --- [アドレス58] 終了処理 ---
rom[58] <= 12'hF_21; // drop (残ったカウンターを破棄)
rom[59] <= 12'h0_00; // HALT
実行結果
>vvp a.out
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
FizzBuzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
FizzBuzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
stack12.v:309: $finish called at 6740 (1ns)
以上。