#概要
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
以上。