windowsでiverilog その18

#概要

windowsでiverilogやってみた。
cpuを書いてみる。

#参考にしたページ

http://www.cs.hiroshima-u.ac.jp/~nakano/wiki/


#命令セットを作る。

##俺cpuニーモニック

|ニーモニック	|意味	|stackの状態|code|
|:---|:--|:--|:--|
|%	|stack-1,stackの剰余を求める。	|1個減る||
|+	|stack-1,stackの加算を求める。	|1個減る|f000|
|/	|stack-1,stackの除算を求める。	|1個減る||
|*	|stack-1,stackの乗算を求める。	|1個減る|f002|
|-	|stack-1,stackの減算を求める。	|1個減る|f001|
|=	|stack-1,stackの等しいを求める。	|1個減る|f00a|
|>	|stack-1,stackの大小を求める。	|1個減る|f00e|
|push 1	    |stackに整数1を積む。	        |1個増える|1001|
|set i	    |変数iにstackを入れる。	|1個減る|300i|
|get i	    |stackに、変数iの値を入れる。	|1個増える|200i|
|out 	    |stackを数値で印字する。	|1個減る|e000|
|if i	    |stackが真ならiへ飛ぶ。       |1個減る|500i|
|if! i	    |stackが偽ならiへ飛ぶ。       |1個減る|600i|
|jp i	    |無条件でiへ飛ぶ。		|変化無し|400i|
|end        |停止                        |変化無し|0000|

##俺cpu命令セット

|ニーモニック|bit15	|bit14	|bit13	|bit12	|bit10	|bit9	|bit8	|bit7	|bit6	|bit5	|bit4	|bit3	|bit2	|bit1	|bit0	|16進	|
|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|end	|0	|0	|0	|0	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|0000	|
|push I|0	|0	|0	|1	|I	|I	|I	|I	|I	|I	|I	|I	|I	|I	|I	|1000+I	|
|get A	|0	|0	|1	|0	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|2000+A	|
|set A	|0	|0	|1	|1	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|3000+A	|
|jp A	|0	|1	|0	|0	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|4000+A	|
|if A	|0	|1	|0	|1	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|5000+A	|
|if! A	|0	|1	|1	|0	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|A	|6000+A	|
|IN	|1	|1	|0	|1	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|D000	|
|out	|1	|1	|1	|0	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|-	|E000	|
|+	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|0	|0	|0	|F000	|
|-	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|0	|0	|1	|F001	|
|*	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|0	|1	|0	|F002	|
|SHL	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|0	|1	|1	|F003	|
|SHR	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|1	|0	|0	|F004	|
|BAND	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|1	|0	|1	|F005	|
|BOR	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|1	|1	|0	|F006	|
|BXOR	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|0	|1	|1	|1	|F007	|
|AND	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|0	|0	|0	|F008	|
|OR	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|0	|0	|1	|F009	|
|=	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|0	|1	|0	|F00A	|
|NE	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|0	|1	|1	|F00B	|
|GE	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|1	|0	|0	|F00C	|
|LE	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|1	|0	|1	|F00D	|
|>	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|1	|1	|0	|F00E	|
|LT	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|0	|1	|1	|1	|1	|F00F	|
|NEG	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|1	|0	|0	|0	|0	|F010	|
|BNOT	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|1	|0	|0	|0	|1	|F011	|
|NOT	|1	|1	|1	|1	|-	|-	|-	|-	|-	|-	|1	|0	|0	|1	|0	|F012	|


#サンプルコード


```
  push  0
  set  x
loop:
  get  x
  push  1
  +
  set  x
  get  x
  out    
  push  10
  >
  if  loop
  end
x:    
```

#シミュレータ作る。

https://embed.plnkr.co/plunk/gWMvSeCageR1JZQE

#ハンドアセンブル


```
		mem[0] = 16'h1000;//push 0
		mem[1] = 16'h300e;//set x
		mem[2] = 16'h200e;//get x
		mem[3] = 16'h1001;//push 1
		mem[4] = 16'hf000;//+
		mem[5] = 16'h300e;//set x
		mem[6] = 16'h200e;//get x
		mem[7] = 16'he000;//out
		mem[8] = 16'h200e;//get x
		mem[9] = 16'h1009;//push 9
		mem[10] = 16'hf00e;//>
		mem[11] = 16'h5002;//if 2
		mem[12] = 16'h0000;//end
		mem[13] = 16'h400c;//jp 12
		mem[14] = 16'h0008;//x
```

#iverilog実行結果


```


test
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10


```

#俺cpuサンプルコード


```


`define		IDLE	3'b000
`define		FETCHA	3'b001
`define		FETCHB	3'b010
`define		EXECA	3'b011
`define		EXECB	3'b100

`define		ADD		5'b00000
`define		SUB		5'b00001
`define		MUL		5'b00010
`define		SHL		5'b00011
`define		SHR		5'b00100
`define		BAND	5'b00101
`define		BOR		5'b00110
`define		BXOR	5'b00111
`define		AND		5'b01000
`define		OR		5'b01001
`define		EQ		5'b01010
`define		NE		5'b01011
`define		GE		5'b01100
`define		LE		5'b01101
`define		GT		5'b01110
`define		LT		5'b01111
`define		NEG		5'b10000
`define		BNOT	5'b10001
`define		NOT		5'b10010

`define		HALT	4'b0000
`define		PUSHI	4'b0001
`define		PUSH	4'b0010
`define		POP		4'b0011
`define		JMP		4'b0100
`define		JZ		4'b0101
`define		JNZ		4'b0110
`define		IN		4'b1101
`define		OUT		4'b1110
`define		OP		4'b1111

module counter(clk, rst, load, inc, d, q);
	parameter N = 16;
	input clk,
		rst,
		load,
		inc;
	input [N - 1:0] d;
	output [N - 1:0] q;
	reg [N - 1:0] q;
	always @(posedge clk or negedge rst)
		if (!rst)
			q <= 0;
		else if (load)
			q <= d;
		else if (inc)
			q <= q + 1;
endmodule

module stack(clk, rst, load, push, pop, d, qtop, qnext);
	parameter N = 8;
	input clk,
		rst,
		load,
		push,
		pop;
	input [15:0] d;
	output [15:0] qtop,
		qnext;
	reg [15:0] q[0:N - 1];
	assign qtop = q[0];
	assign qnext = q[1];
	always @(posedge clk or negedge rst)
		if (!rst)
			q[0] <= 0;
		else if (load)
			q[0] <= d;
		else if (pop)
			q[0] <= q[1];
	integer i;
	always @(posedge clk or negedge rst)
		for (i = 1; i < N - 1; i = i + 1)
			if (!rst)
				q[i] <= 0;
			else if (push)
				q[i] <= q[i - 1];
			else if (pop)
				q[i] <= q[i + 1];
	always @(posedge clk or negedge rst)
		if (!rst)
			q[N - 1] <= 0;
		else if (push)
			q[N - 1] <= q[N - 2];
endmodule

module ram(clk, load, addr, d, q);
	parameter DWIDTH = 16,
		AWIDTH = 12,
		WORDS = 4096;
	input clk,
		load;
	input [AWIDTH - 1:0] addr;
	input [DWIDTH - 1:0] d;
	output [DWIDTH - 1:0] q;
	reg [DWIDTH - 1:0] q;
	reg [DWIDTH - 1:0] mem[WORDS - 1:0];
	always @(posedge clk)
	begin
		if (load)
			mem[addr] <= d;
		q <= mem[addr];
	end
	initial
	begin
		mem[0] = 16'h1000;//push 0
		mem[1] = 16'h300e;//set x
		mem[2] = 16'h200e;//get x
		mem[3] = 16'h1001;//push 1
		mem[4] = 16'hf000;//+
		mem[5] = 16'h300e;//set x
		mem[6] = 16'h200e;//get x
		mem[7] = 16'he000;//out
		mem[8] = 16'h200e;//get x
		mem[9] = 16'h1009;//push 9
		mem[10] = 16'hf00e;//>
		mem[11] = 16'h5002;//if 2
		mem[12] = 16'h0000;//end
		mem[13] = 16'h400c;//jp 12
		mem[14] = 16'h0008;//x
	end
endmodule

module alu(a, b, f, s);
	input [15:0] a,
		b;
	input [4:0] f;
	output [15:0] s;
	reg [15:0] s;
	wire [15:0] x,
		y;
	assign x = a + 16'h8000;
	assign y = b + 16'h8000;
	always @(a or b or x or y or f)
		case (f)
		`ADD:
			s = b + a;
		`SUB:
			s = b - a;
		`MUL:
			s = b * a;
		`SHL:
			s = b << a;
		`SHR:
			s = b >> a;
		`BAND:
			s = b & a;
		`BOR:
			s = b | a;
		`BXOR:
			s = b ^ a;
		`AND:
			s = b && a;
		`OR:
			s = b || a;
		`EQ:
			s = b == a;
		`NE:
			s = b != a;
		`GE:
			s = y >= x;
		`LE:
			s = y <= x;
		`GT:
			s = y > x;
		`LT:
			s = y < x;
		`NEG:
			s = -a;
		`BNOT:
			s = ~a;
		`NOT:
			s = !a;
		default:
			s = 16'hxxxx;
		endcase
endmodule

module state(clk, rst, cont, halt, cs);
	input clk,
		rst,
		run,
		cont,
		halt;
	output [2:0] cs;
	reg [2:0] cs;
	always @(posedge clk or negedge rst)
		if (!rst)
			cs <= `IDLE;
		else
			case (cs)
			`IDLE:
				cs <= `FETCHA;
			`FETCHA:
				cs <= `FETCHB;
			`FETCHB:
				cs <= `EXECA;
			`EXECA:
				if (halt)
					cs <= `IDLE;
				else if (cont)
					cs <= `EXECB;
				else
					cs <= `FETCHA;
			`EXECB:
				cs <= `FETCHA;
			default:
				cs <= 3'bxxx;
			endcase
endmodule

module tinycpu(clk, rst, pcout, out);
	input clk,
		rst;
	output [15:0] out;
	reg [15:0] in;
	wire [2:0] cs;
	wire [15:0] irout,
		qtop,
		dbus;
	output [11:0] pcout;
	wire [15:0] qnext,
		ramout,
		aluout;
	reg [11:0] abus;
	reg halt,
		cont,
		pcinc,
		push,
		pop,
		abus2pc,
		dbus2ir,
		dbus2qtop,
		dbus2ram,
		dbus2obuf,
		pc2abus,
		ir2abus,
		ir2dbus,
		qtop2dbus,
		alu2dbus,
		ram2dbus,
		in2dbus;
	counter #(12) pc0(.clk(clk), .rst(rst), .load(abus2pc), .inc(pcinc), .d(abus), .q(pcout));
	counter #(16) obuf0(.clk(clk), .rst(rst), .load(dbus2obuf), .inc(0), .d(dbus), .q(out));
	counter #(16) ir0(.clk(clk), .rst(rst), .load(dbus2ir), .inc(0), .d(dbus), .q(irout));
	state state0(.clk(clk), .rst(rst), .cont(cont), .halt(halt), .cs(cs));
	stack stack0(.clk(clk), .rst(rst), .load(dbus2qtop), .push(push), .pop(pop), .d(dbus), .qtop(qtop), .qnext(qnext));
	alu alu0(.a(qtop), .b(qnext), .f(irout[4:0]), .s(aluout));
	ram ram0(.clk(clk), .load(dbus2ram), .addr(abus[11:0]), .d(dbus), .q(ramout));
	assign dbus = ir2dbus ? {{4{irout[11]}}, irout[11:0]} : 16'hzzzz;
	assign dbus = qtop2dbus ? qtop : 16'hzzzz;
	assign dbus = alu2dbus ? aluout : 16'hzzzz;
	assign dbus = ram2dbus ? ramout : 16'hzzzz;
	assign dbus = in2dbus ? in : 16'hzzzz;
	always @(pc2abus or ir2abus or pcout or irout)
		if (pc2abus)
			abus <= pcout;
		else if (ir2abus)
			abus <= irout[11:0];
		else
			abus <= 12'hxxx;
	always @(cs or irout or qtop)
	begin
		halt = 0;
		pcinc = 0;
		push = 0;
		pop = 0;
		cont = 0;
		abus2pc = 0;
		dbus2ir = 0;
		dbus2qtop = 0;
		dbus2ram = 0;
		dbus2obuf = 0;
		pc2abus = 0;
		ir2abus = 0;
		ir2dbus = 0;
		qtop2dbus = 0;
		alu2dbus = 0;
		ram2dbus = 0;
		in2dbus = 0;
		if (cs == `FETCHA)
		begin
			pcinc = 1;
			pc2abus = 1;
		end
		else if (cs == `FETCHB)
		begin
			ram2dbus = 1;
			dbus2ir = 1;
		end
		else if (cs == `EXECA)
			case (irout[15:12])
			`PUSHI:
			begin
				ir2dbus = 1;
				dbus2qtop = 1;
				push = 1;
			end
			`PUSH:
			begin
				ir2abus = 1;
				cont = 1;
			end
			`POP:
			begin
				ir2abus = 1;
				qtop2dbus = 1;
				dbus2ram = 1;
				pop = 1;
			end
			`JMP:
			begin
				ir2abus = 1;
				abus2pc = 1;
			end
			`JZ:
			begin
				if (qtop == 0)
				begin
					ir2abus = 1;
					abus2pc = 1;
				end
				pop = 1;
			end
			`JNZ:
			begin
				if (qtop != 0)
				begin
					ir2abus = 1;
					abus2pc = 1;
				end
				pop = 1;
			end
			`IN:
			begin
				in2dbus = 1;
				dbus2qtop = 1;
				push = 1;
			end
			`OUT:
			begin
				qtop2dbus = 1;
				dbus2obuf = 1;
				pop = 1;
			end
			`OP:
			begin
				alu2dbus = 1;
				dbus2qtop = 1;
				if (irout[4] == 0)
					pop = 1;
			end
			default:
				halt = 1;
			endcase
		else if (cs == `EXECB)
			if (irout[15:12] == `PUSH)
			begin
				ram2dbus = 1;
				dbus2qtop = 1;
				push = 1;
			end
		end
endmodule

module test;
	reg clk,
		rst;
	wire [15:0] out;
	wire [11:0] pcout;
	tinycpu u(.clk(clk), .rst(rst), .pcout(pcout), .out(out));
	initial
	begin
		clk = 0;
		rst = 0;
		#10
			rst = 1;
		#4000
			$finish;
	end
	always
	begin
		#5
			clk = ~clk;
	end
	initial
	begin
		$display("test");
		//$monitor("%d %d", pcout, out);
		$monitor("%d", out);
	end
endmodule





```

以上。