windowsでiverilog その68

# 概要　

windowsでiverilogやってみた。
cpuのテストベンチ書いてみた。

# 参考にしたページ

https://fukuno.jig.jp/2253

# cpu仕様

レジスタマシン
32bit CPU（汎用レジスタが32bit）
マシン語は32bit固定長
命令は、ロード、ストア、代入、加算、減算、or、and、xor、左シフト、右シフト、掛け算の11種類
命令に4bit、レジスタ指定に4bit x 2、16bitを値に
レジスタは4bitなので16コ、最後レジスタをプログラムカウンタr15
条件判定用のフラグはゼロフラグだけ、フラグによるスキップ、フラグ更新するか否か、16bitの値の符号
出力はメモリにマッピング（RAMは32bit x 32word、最後の31番目を出力に接続）

|31	|30|29|	28|		27-24|	23-20|		19-16|		15-0|
|:--|:--|:--|:--|:--|:--|:--|:--|
|ゼロフラグ0の時スキップ|	ゼロフラグ1の時スキップ|	フラグ更新|	値が負|	命令|	レジスタA|	レジスタB|	値|

# アセンブラ

1から９９を出力する。


```
r1 0    // r1 <- 1
r2 99   // r2 <- 99
r1 + 1  // r1 <- r1 + 1
out r1  // out r1
r2 - 1  // r2 <- r2 - 1
jz 2    // if zero then jump 2

```

#ハンドアセンブル


```
    mem[0] <= 32'h0_2_1_0_0000; 	//r1 0
    mem[1] <= 32'h0_2_2_0_0063; 	//r2 99
    mem[2] <= 32'h0_3_1_0_0001; 	//r1 + 1
    mem[3] <= 32'h0_1_1_0_001f; 	//out r1
    mem[4] <= 32'h2_5_2_0_0001; 	//r2 - 1
    mem[5] <= 32'h4_2_f_0_0002; 	//jz 2

```

#サンプルコード


```

module tf32cpu_r1(input clk, input rst, output [7:0] outport);
	reg [31:0] r[0:15];
	reg [31:0] mem[0:31];
	reg zeroflg;
	wire [31:0] code;
	wire skipflgnz;
	wire skipflgz;
	wire flgchg;
	wire minusim;
	wire [3:0] op;
	wire [3:0] rega;
	wire [3:0] regb;
	wire [31:0] opland;
	wire [15:0] im;
	assign code = mem[r[15]];
	assign skipflgnz = code[31];
	assign skipflgz = code[30];
	assign flgchg = code[29];
	assign minusim = code[28];
	assign op = code[27:24];
	assign rega = code[23:20];
	assign regb = code[19:16];
	assign im = code[15:0];
	assign opland = r[regb] + (minusim ? -im : im);
	assign outport = mem[31][7:0];
	task init_blink;
	begin
		mem[0] <= 32'h0_2_1_0_0000; 	//r1 0
		mem[1] <= 32'h0_2_2_0_0063; 	//r2 99
		mem[2] <= 32'h0_3_1_0_0001; 	//r1 + 1
		mem[3] <= 32'h0_1_1_0_001f; 	//out r1
		mem[4] <= 32'h2_5_2_0_0001; 	//r2 - 1
		mem[5] <= 32'h4_2_f_0_0002; 	//jmp 2
	end
	endtask
	task init_reg;
	begin
		r[0] <= 32'h0;
		r[1] <= 32'h0;
		r[2] <= 32'h0;
		r[3] <= 32'h0;
		r[4] <= 32'h0;
		r[5] <= 32'h0;
		r[6] <= 32'h0;
		r[7] <= 32'h0;
		r[8] <= 32'h0;
		r[9] <= 32'h0;
		r[10] <= 32'h0;
		r[11] <= 32'h0;
		r[12] <= 32'h0;
		r[13] <= 32'h0;
		r[14] <= 32'h0;
		r[15] <= 32'h0;
		zeroflg <= 1'b0;
	end
	endtask
	always @(posedge clk, negedge rst)
	begin
		if (!rst)
		begin
			init_blink;
			init_reg;
		end
		else
		begin
			if (skipflgnz && !zeroflg || skipflgz && zeroflg)
				r[15] <= r[15] + 1;
			else
			begin
				case (op)
				4'h0:// load
					r[rega] <= mem[opland];
				4'h1:// save
					mem[opland] <= r[rega];
				4'h2://let
					r[rega] <= opland;
				4'h3:// + n
					r[rega] <= r[rega] + opland;
				4'h4:// a + b
					r[rega] <= r[rega] + r[regb];
				4'h5:// - n
					r[rega] <= r[rega] - opland;
				4'h6:// and
					r[rega] <= r[rega] & opland;
				4'h7:// xor
					r[rega] <= r[rega] ^ opland;
				4'h8:// <<
					r[rega] <= r[rega] << opland;
				4'h9:// >>
					r[rega] <= r[rega] >> opland;
				4'hA:// *
					r[rega] <= r[rega] * opland;
				endcase
				if (flgchg)
					zeroflg <= r[rega] == 0;
				if (rega != 15)
					r[15] <= r[15] + 1;
			end
		end
	end
endmodule

module test;
	reg clk,
		rst;
	wire [7:0] outport;
	tf32cpu_r1 t(.clk(clk), .rst(rst), .outport(outport));
	initial
	begin
		$monitor("%d", outport);
		clk = 0;
		rst = 1;
		#2
			rst = 0;
		#2
			rst = 1;
		#900
			$finish;
	end
	always
		#1
			clk = ~clk;
	initial
	begin
		$dumpfile("test.vcd");
		$dumpvars(0, test);
	end
endmodule


```

#iverilog実行結果


```

VCD info: dumpfile test.vcd opened for output.
  x
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100


```

#機能拡張してみた。

レジスタでメモリー間接アドレッシングできるようにした。
hello worldやってみた。


```


module tf32cpu_r1(input clk, input rst, output [7:0] outport);
	reg [31:0] r[0:15];
	reg [31:0] mem[0:31];
	reg zeroflg;
	wire [31:0] code;
	wire skipflgnz;
	wire skipflgz;
	wire flgchg;
	wire minusim;
	wire [3:0] op;
	wire [3:0] rega;
	wire [3:0] regb;
	wire [31:0] opland;
	wire [15:0] im;
	assign code = mem[r[15]];
	assign skipflgnz = code[31];
	assign skipflgz = code[30];
	assign flgchg = code[29];
	assign minusim = code[28];
	assign op = code[27:24];
	assign rega = code[23:20];
	assign regb = code[19:16];
	assign im = code[15:0];
	assign opland = r[regb] + (minusim ? -im : im);
	assign outport = mem[31][7:0];
	task init_blink;
	begin
		mem[0] <= 32'h0_2_1_0_0007; //r1 7
		mem[1] <= 32'h0_2_2_0_000c; //r2 12
		mem[2] <= 32'h0_3_1_0_0001; //r1 + 1
		mem[3] <= 32'h0_6_3_1_0001; //r3 [r1]
		mem[4] <= 32'h0_1_3_0_001f; //out r3
		mem[5] <= 32'h2_5_2_0_0001; //r2 - 1
		mem[6] <= 32'h4_2_f_0_0002; //jz 2
		mem[7] <= 32'h0_2_f_0_0004; //jmp 4
		mem[8] <= 32'h000000_68; 	//'h'
		mem[9] <= 32'h000000_65; 	//'e'
		mem[10] <= 32'h000000_6c; 	//'l'
		mem[11] <= 32'h000000_6c; 	//'l'
		mem[12] <= 32'h000000_6f; 	//'o'
		mem[13] <= 32'h000000_20; 	//''
		mem[14] <= 32'h000000_77; 	//'w'
		mem[15] <= 32'h000000_6f; 	//'o'
		mem[16] <= 32'h000000_72; 	//'r'
		mem[17] <= 32'h000000_6c; 	//'l'
		mem[18] <= 32'h000000_64; 	//'d'
		mem[19] <= 32'h000000_21; 	//'!'
	end
	endtask
	task init_reg;
	begin
		r[0] <= 32'h0;
		r[1] <= 32'h0;
		r[2] <= 32'h0;
		r[3] <= 32'h0;
		r[4] <= 32'h0;
		r[5] <= 32'h0;
		r[6] <= 32'h0;
		r[7] <= 32'h0;
		r[8] <= 32'h0;
		r[9] <= 32'h0;
		r[10] <= 32'h0;
		r[11] <= 32'h0;
		r[12] <= 32'h0;
		r[13] <= 32'h0;
		r[14] <= 32'h0;
		r[15] <= 32'h0;
		zeroflg <= 1'b0;
	end
	endtask
	always @(posedge clk, negedge rst)
	begin
		if (!rst)
		begin
			init_blink;
			init_reg;
		end
		else
		begin
			if (skipflgnz && !zeroflg || skipflgz && zeroflg)
				r[15] <= r[15] + 1;
			else
			begin
				case (op)
				4'h0:// load mn
					r[rega] <= mem[opland];
				4'h1:// save mn
					mem[opland] <= r[rega];
				4'h2://let
					r[rega] <= opland;
				4'h3:// + n
					r[rega] <= r[rega] + opland;
				4'h4:// a + b
					r[rega] <= r[rega] + r[regb];
				4'h5:// - n
					r[rega] <= r[rega] - opland;
				4'h6:// load mb
					r[rega] <= mem[r[regb]];
				4'h7:// save mb
					mem[r[regb]] <= r[rega];
				4'h8:// <<
					r[rega] <= r[rega] << opland;
				4'h9:// >>
					r[rega] <= r[rega] >> opland;
				4'hA:// *
					r[rega] <= r[rega] * opland;
				endcase
				if (flgchg)
					zeroflg <= r[rega] == 0;
				if (rega != 15)
					r[15] <= r[15] + 1;
			end
		end
	end
endmodule

module test;
	reg clk,
		rst;
	wire [7:0] outport;
	tf32cpu_r1 t(.clk(clk), .rst(rst), .outport(outport));
	initial
	begin
		$monitor("%s", outport);
		clk = 0;
		rst = 1;
		#2
			rst = 0;
		#2
			rst = 1;
		#900
			$finish;
	end
	always
		#1
			clk = ~clk;
	initial
	begin
		$dumpfile("test.vcd");
		$dumpvars(0, test);
	end
endmodule


```

#実行結果


```


VCD info: dumpfile test.vcd opened for output.

h
e
l
o

w
o
r
l
d
!



```

以上。