概要
windowsでiverilogやってみた。
8bitのcpu書いてみた。
cpu仕様
レジスタマシン
8bit CPU(汎用レジスタが8bit8本)
マシン語は16bit固定長
命令は、ロード、ストア、代入、加算、減算、xor、大きい、小さいの11種類
命令に4bit、レジスタ指定に3bit、8bitを値に
15:12 | 11 | 10:8 | 7:0 |
---|---|---|---|
命令 | フラグ | レジスタ | 値 |
レジスタは3bitなので8コ、最後レジスタをプログラムカウンタr7
条件判定用のフラグはゼロフラグだけ、フラグによるスキップ
出力はメモリにマッピング(RAMは16bit x 32word、最後の32番目を出力に接続)
アセンブラの説明
r2 9 //r2に9を代入。
r1 0 //r1に0を代入。
r1 + 1 //r1をインクリメント。
out r1 //r1を出力。
r2 - 1 //r2をデクリメント。
jz 2 //ゼロならアドレス2へジャンプ。
jp 6 //アドレス6へジャンプ。
サンプルコード
module cpu8(input clk, input rst, output [7:0] outport);
reg [7:0] r[7:0];
reg [15:0] mem[31:0];
reg zeroflg;
wire [15:0] code;
wire skipflgz;
wire [3:0] op;
wire [2:0] rega;
wire [7:0] opland;
assign code = mem[r[7]];
assign op = code[15:12];
assign skipflgz = code[11];
assign rega = code[10:8];
assign opland = code[7:0];
assign outport = mem[31][7:0];
task init_blink;
begin
mem[0] <= 16'h02_09; //r2 9
mem[1] <= 16'h01_00; //r1 0
mem[2] <= 16'h31_01; //r1 + 1
mem[3] <= 16'h21_1f; //out
mem[4] <= 16'h52_01; //r2 - 1
mem[5] <= 16'h0f_02; //jz 2
mem[6] <= 16'h07_06; //jp 6
end
endtask
task init_reg;
begin
r[0] <= 16'h0;
r[1] <= 16'h0;
r[2] <= 16'h0;
r[3] <= 16'h0;
r[4] <= 16'h0;
r[5] <= 16'h0;
r[6] <= 16'h0;
r[7] <= 16'h0;
zeroflg = 1'b0;
end
endtask
always @(posedge clk, negedge rst)
begin
if (!rst)
begin
init_blink;
init_reg;
end
else
begin
if (skipflgz && zeroflg)
r[7] <= r[7] + 1;
else
begin
case (op)
4'h0://let
r[rega] <= opland;
4'h1:// load mn
r[rega] <= mem[opland];
4'h2:// save mn
mem[opland] <= r[rega];
4'h3:// + n
r[rega] <= r[rega] + opland;
4'h4:// a + b
r[rega] <= r[rega] + r[opland];
4'h5:// - n
begin
r[rega] <= r[rega] - opland;
zeroflg <= r[rega] == 0;
end
4'h6:// < n
begin
r[rega] <= r[rega] < opland;
zeroflg <= r[rega] == 0;
end
4'h7:// > n
begin
r[rega] <= r[rega] > opland;
zeroflg <= r[rega] == 0;
end
4'h8:// xor
r[rega] <= r[rega] ^ r[opland];
4'h9:// load mb
r[rega] <= mem[r[opland]];
4'ha:// save mb
mem[r[opland]] <= r[rega];
endcase
if (rega != 7)
r[7] <= r[7] + 1;
end
end
end
initial
begin
$monitor("%d", outport);
end
endmodule
module test2(input clk, input rst, output led2);
wire [7:0] outport;
assign led2 = outport[0];
cpu8 u(.clk(clk), .rst(rst), .outport(outport));
endmodule
module test;
reg clk,
rst;
test2 t(.clk(clk), .rst(rst), .led2(led2));
initial
begin
//$monitor("%d", led2);
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.
x
1
2
3
4
5
6
7
8
9
10
以上。