概要
windowsでiverilogやってみた。
cpuなverilog見つけたので、やってみた。
テストベンチ、書いてみた。
参考にしたページ
cpuの仕様
レジスタマシン
-
レジスタ(4bit)
Aレジスタ
Bレジスタ
OUTレジスタ
プログラムカウンタ(PC)
フラグレジスタ キャリーフラグ(1bit)
算術論理演算装置(ALU) 4bit+4bitの加算演算のみ -
命令メモリ
8bit16バイト -
入出力
4bit入力ポート
4bit出力ポート(OUTレジスタ接続) -
命令セット
8bit固定長
上位4bitが命令、下位4bitが即値 -
命令一覧
(A => Aレジスタ、B => Bレジスタ、OUT => OUTレジスタ、PC => プログラムカウンタ、 IN => 入力ポート、 IM => 即値)
命令 | ニモニック | 意味 |
---|---|---|
0000 | ADD A, Im | A + 即値(Im)をAに代入 (A + Im => A) |
0001 | MOV A, B | BをAに代入(B + 0000 => A) |
0010 | IN A | 入力ポートの値をAに代入(IN + 0000 => A) |
0011 | MOV A, Im | 即値(Im)の値をAに代入(Im + 0000 => A) |
0100 | MOV B, A | AをBに代入 (A + 0000 => B) |
0101 | ADD B, Im | B + 即値(Im)をBに代入 (B + Im => B) |
0110 | IN B | 入力ポートの値をBに代入 (IN + 0000 => B) |
0111 | MOV B, Im | 即値(Im)の値をBに代入 (Im + 0000 => B) |
1001 | OUT B | BをOUTレジスタに代入 (B + 0000 => OUT) |
1011 | OUT Im | 即値(im)をOUTレジスタに代入 (Im + 0000 => OUT) |
1110 | JNC Im | キャリーフラグが立っていないならImにジャンプ (Im + 0000 => PC if carry) |
1111 | JMP Im | Imにジャンプ (Im + 0000 => PC) |
投入したコード
rom[0] <= 8'b1011_0011; // OUT 3
rom[1] <= 8'b1011_0110; // OUT 6
rom[2] <= 8'b1011_1100; // OUT 12
rom[3] <= 8'b1011_1000; // OUT 8
rom[4] <= 8'b1011_1000; // OUT 8
rom[5] <= 8'b1011_1100; // OUT 12
rom[6] <= 8'b1011_0110; // OUT 6
rom[7] <= 8'b1011_0011; // OUT 3
rom[8] <= 8'b1011_0001; // OUT 1
rom[9] <= 8'b1111_1001; // JMP 9
rom[10] <= 8'b0000_0000; // NOP
rom[11] <= 8'b0000_0000;
rom[12] <= 8'b0000_0000;
rom[13] <= 8'b0000_0000;
rom[14] <= 8'b0000_0000;
rom[15] <= 8'b0000_0000;
サンプルコード
module test;
reg clock = 1'b0;
reg reset_n = 1'b0;
reg [3:0] reg_in = 4'b0000;
wire [7:0] opcode;
wire [3:0] out_port;
wire [3:0] pc_out;
wire [3:0] alu_data;
TD4 u(clock, reset_n, reg_in, pc_out, opcode, out_port, alu_data);
initial
begin
clock = 1'b0;
forever
begin
#1 clock = ~clock;
end
end
initial
begin
reset_n = 1'b0;
#1
reset_n = 1'b1;
#100
$finish;
end
initial
begin
$dumpfile("test.vcd");
$dumpvars(0, test);
$monitor("%t: pc = %h, opcode = %h, in_port = %h, out_port = %h, alu_data = %h", $time, pc_out, opcode, reg_in, out_port, alu_data);
end
endmodule
実行結果
>vvp a.out
VCD info: dumpfile test.vcd opened for output.
0: pc = 0, opcode = b3, in_port = 0, out_port = 0, alu_data = 3
2: pc = 1, opcode = b6, in_port = 0, out_port = 3, alu_data = 6
4: pc = 2, opcode = bc, in_port = 0, out_port = 6, alu_data = c
6: pc = 3, opcode = b8, in_port = 0, out_port = c, alu_data = 8
8: pc = 4, opcode = b8, in_port = 0, out_port = 8, alu_data = 8
10: pc = 5, opcode = bc, in_port = 0, out_port = 8, alu_data = c
12: pc = 6, opcode = b6, in_port = 0, out_port = c, alu_data = 6
14: pc = 7, opcode = b3, in_port = 0, out_port = 6, alu_data = 3
16: pc = 8, opcode = b1, in_port = 0, out_port = 3, alu_data = 1
18: pc = 9, opcode = f9, in_port = 0, out_port = 1, alu_data = 9
td4.v:170: $finish called at 101 (1s)
以上。