1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

俺cpuAdvent Calendar 2020

Day 1

windowsでiverilog その18

Last updated at Posted at 2020-06-14

#概要

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

#参考にしたページ

#命令セットを作る。

##俺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:    

#シミュレータ作る。

#ハンドアセンブル

		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





以上。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?