windowsでiverilog その88

#概要　

windowsでiverilogやってみた。
avrのcpu書いてみた。
AVRstudioでアセンブラをコンパイルし、intelHEXフォーマットからバイナリを取り出し、実行してみた。

#参考にしたページ

https://github.com/nazarov-yuriy/someAVR

#アセンブラ

```
ldi r31, 'H'
ldi r31, 'e'
ldi r31, 'l'
ldi r31, 'l'
ldi r31, 'o'
ldi r31, ' '
ldi r31, 'w'
ldi r31, 'o'
ldi r31, 'r'
ldi r31, 'l'
ldi r31, 'd'
ldi r31, '!'

```
#サンプルコード

```

module avr(clk, rst, porta);
	parameter CMD_ADD  = 16'b000011xxxxxxxxxx;
	parameter CMD_ADC  = 16'b000111xxxxxxxxxx;
	parameter CMD_SUB  = 16'b000110xxxxxxxxxx;
	parameter CMD_SBC  = 16'b000010xxxxxxxxxx;
	parameter CMD_AND  = 16'b001000xxxxxxxxxx;
	parameter CMD_EOR  = 16'b001001xxxxxxxxxx;
	parameter CMD_OR   = 16'b001010xxxxxxxxxx;
	parameter CMD_MOV  = 16'b001011xxxxxxxxxx;
	parameter CMD_CP   = 16'b000101xxxxxxxxxx;
	parameter CMD_LSR  = 16'b1001010xxxxx0110;
	parameter CMD_LDI  = 16'b1110xxxxxxxxxxxx;
	parameter CMD_SUBI = 16'b0101xxxxxxxxxxxx;
	parameter CMD_BREQ = 16'b111100xxxxxxx001;
	parameter CMD_BRNE = 16'b111101xxxxxxx001;
	parameter CMD_BRCS = 16'b111100xxxxxxx000;
	parameter CMD_BRCC = 16'b111101xxxxxxx000;
	input wire clk;
	input wire rst;
	output wire [7:0] porta;
	reg [15:0] rom[15:0];
	reg [7:0] pc;
	reg [7:0] registers[16:31];
	reg I,
		T,
		H,
		S,
		V,
		N,
		Z = 0,
		C = 0;
	wire [15:0] opcode;
	wire [4:0] src;
	wire [4:0] dest;
	wire [6:0] k;
	wire [7:0] K;
	wire [7:0] Rs = registers[src[4:0]];
	wire [7:0] Rd = registers[dest[4:0]];
	wire [7:0] R = Rd + (opcode[10] & opcode[12] & ~C | ~opcode[10] & ~opcode[12] & C ? 0 : 1) + (opcode[10] ? Rs : ~Rs);
	wire [7:0] Rsi = registers[{1'b1, dest[3:0]}];
	wire [7:0] Ri = Rsi - K;
	assign opcode = rom[pc];
	assign porta = registers[31];
	assign src = {opcode[9], opcode[3], opcode[2], opcode[1], opcode[0]};
	assign dest = {opcode[8], opcode[7], opcode[6], opcode[5], opcode[4]};
	assign k = {opcode[9], opcode[8], opcode[7], opcode[6], opcode[5], opcode[4], opcode[3]};
	assign K = {opcode[11], opcode[10], opcode[9], opcode[8], opcode[3], opcode[2], opcode[1], opcode[0]};
	always @(posedge clk, negedge rst)
	begin
		if (!rst)
		begin
			rom[0] <= 16'hE4F8;
			rom[1] <= 16'hE6F5;
			rom[2] <= 16'hE6FC;
			rom[3] <= 16'hE6FC;
			rom[4] <= 16'hE6FF;
			rom[5] <= 16'hE2F0;
			rom[6] <= 16'hE7F7;
			rom[7] <= 16'hE6FF;
			rom[8] <= 16'hE7F2;
			rom[9] <= 16'hE6FC;
			rom[11] <= 16'hE6F4;
			rom[12] <= 16'hE2F1;
			rom[13] <= 16'h0000;
			rom[14] <= 16'h0000;
			rom[15] <= 16'h0000;
			pc <= 0;
		end
		else
		begin
			if (opcode[15:10] == CMD_ADD[15:10])
			begin
				registers[dest[4:0]] <= R;
				Z <= ~| R;
				C <= Rs[7] & ~R[7] | Rd[7] & ~R[7] | Rs[7] & Rd[7];
			end
			if (opcode[15:10] == CMD_ADC[15:10])
			begin
				registers[dest[4:0]] <= R;
				Z <= ~| R;
				C <= Rs[7] & ~R[7] | Rd[7] & ~R[7] | Rs[7] & Rd[7];
			end
			if (opcode[15:10] == CMD_SUB[15:10])
			begin
				registers[dest[4:0]] <= R;
				Z <= ~| R;
				C <= Rs[7] & ~Rd[7] | R[7] & ~Rd[7] | Rs[7] & R[7];
			end
			if (opcode[15:10] == CMD_SBC[15:10])
			begin
				registers[dest[4:0]] <= R;
				Z <= ~| R;
				C <= Rs[7] & ~Rd[7] | R[7] & ~Rd[7] | Rs[7] & R[7];
			end
			if (opcode[15:10] == CMD_AND[15:10])
			begin
				registers[dest[4:0]] <= registers[dest[4:0]] & registers[src[4:0]];
			end
			if (opcode[15:10] == CMD_EOR[15:10])
			begin
				registers[dest[4:0]] <= registers[dest[4:0]] ^ registers[src[4:0]];
			end
			if (opcode[15:10] == CMD_OR[15:10])
			begin
				registers[dest[4:0]] <= registers[dest[4:0]] | registers[src[4:0]];
			end
			if (opcode[15:10] == CMD_MOV[15:10])
			begin
				registers[dest[4:0]] <= registers[src[4:0]];
			end
			if (opcode[15:12] == CMD_LDI[15:12])
			begin
				registers[{1'b1, dest[3:0]}] <= K;
			end
			if (opcode[15:12] == CMD_SUBI[15:12])
			begin
				registers[{1'b1, dest[3:0]}] <= Ri;
				Z <= ~| Ri;
			end
			if ({opcode[15:11], opcode[2:0]} == {CMD_BREQ[15:11], CMD_BREQ[2:0]})
			begin
				if (Z ^ opcode[10])
				begin
					pc <= pc + {k[6], k} + 1;
				end
				else
				begin
					pc <= pc + 1'd1;
				end
			end
			else
			begin
				pc <= pc + 1'd1;
			end
		end
	end
	initial
	begin
		//$monitor("%h  %h  %h  ", pc, opcode, K);
	end
endmodule

module test;
	reg clk,
		rst;
	wire [7:0] outport;
	avr u(.clk(clk), .rst(rst), .porta(outport));
	initial
	begin
		$monitor("%s", outport);
		clk = 0;
		rst = 1;
		#2
			rst = 0;
		#2
			rst = 1;
		#40
			$finish;
	end
	always
		#1
			clk = ~clk;
endmodule





```

#実行結果


```


H
e
l
o

w
o
r
l
d
!


```

#考察

FPGAの開発を容易にするには、２つの方向性がある。
CPU化と高位合成だ。
自作CPUにしても、アセンブラとコンパイラ、インタープリターの開発にとまどる。
既存の資産（gccとか）を活用できれば、捗る。


以上。