仿真程序如下:
`timescale 1ns/1ns
`define PERIOD 100
module cpu_top;
reg clk;
reg rst_n;
reg [(3*8):0]mnemonic;
reg [12:0]PC_addr,IR_addr;
wire [7:0]data;
wire [12:0]addr;
wire rd,wr,halt,ram_sel,rom_sel;
wire fetch;
integer test;
wire [12:0]ir_addr,pc_addr;
wire [2:0]opcode;
//将cpu与RAM、ROM连接起来
cpu cpu(
.clk(clk),
.rst_n(rst_n),
.halt(halt),
.rd(rd),
.wr(wr),
.addr(addr),
.data(data),
.opcode(opcode),
.fetch(fetch),
.ir_addr(ir_addr),
.pc_addr(pc_addr)
);
addr_decode addr_decode(
.addr(addr),
.ram_sel(ram_sel),
.rom_sel(rom_sel)
);
ram ram(
.data(data),
.addr(addr),
.ena(ram_sel),
.read(rd),
.write(wr)
);
rom rom(
.data(data),
.addr(addr),
.read(rd),
.ena(rom_sel)
);
initial begin
clk=1;
$timeformat(-9,1,"ns",12);//时间打印格式
display_debug_message;//调用任务
asyn_rst;
test1;
$finish;
end
task display_debug_message;
begin
$display("\n**************************");
$display("load test");
$display("***************************\n");
end
endtask
task asyn_rst;
begin
rst_n=1;
#(`PERIOD*0.7)
rst_n=0;
#(`PERIOD*1.5)
rst_n=1;
end
endtask
task test1;
begin
test=0;
disable MONITOR;
$readmemb("D:/Study_FPGA/CPU/test_pro.txt",rom.memory_rom);//读取ROM
$display("rom loaded successfully!");
$readmemb("D:/Study_FPGA/CPU/test_dat.txt",ram.memory_ram);//读取RAM
$display("ram loaded successfully!");
#1 test=1;
#14800;
asyn_rst;
end
endtask
always@(test)begin:MONITOR
$display("\n***running test1");
$display("\n TIME FN1 FN2 FN3 TEMP");
$display(" ----- ---- ---- ---- -----");
while(test==1)
begin
wait (cpu.opcode==3'h1)
$strobe("%t %d %d %d %d",$time,ram.memory_ram[13'h1800],ram.memory_ram[13'h1801],ram.memory_ram[13'h1802],ram.memory_ram[13'h1804]);
wait (cpu.opcode!=3'h1);
end
end
always@(posedge halt)begin
#200;
$display("\n*************************");
$display("**a HALT instruction was processed");
$display("**************************\n");
end
always #(`PERIOD/2) clk=~clk;
always@(cpu.opcode)begin//显示当前指令
case(cpu.opcode)
3'b000:mnemonic="HLT";
3'b001:mnemonic="SKZ";
3'b010:mnemonic="ADD";
3'b011:mnemonic="AND";
3'b100:mnemonic="XOR";
3'b101:mnemonic="LDA";
3'b110:mnemonic="STO";
3'b111:mnemonic="JMP";
default:mnemonic="???";
endcase
end
endmodule
ROM中的值,用txt文件保存程序代码:
@0000
111_00000 //00 begin: JMP TST_JMP
0011_1100
000_00000 //02 HLT //JMP did not work at all
0000_0000
000_00000 //04 HLT //JMP did not load PC,it skipped
0000_0000
101_11000 //06 JMP_OK: LDA DATA_1
0000_0000
001_00000 //08 SKZ
0000_0000
000_00000 //0a HLT //SKZ or LDA did not work
0000_0000
101_11000 //0c LDA DATA_2
0000_0001
001_00000 //0e SKZ
0000_0000
111_00000 //10 JMP SKZ_OK
0001_0100
000_00000 //12 HLT //SKZ or LDA did not work
0000_0000
110_11000 //14 SKZ_OK: STO TEMP //store non-zero vaule in TEMP
0000_0010
101_11000 //16 LDA DATA_1
0000_0000
110_11000 //18 STO TEMP //store zero vaule in TEMP
0000_0010
101_11000 //1a LDA TEMP
0000_0010
001_00000 //1c SKZ //check to see if STO worked
0000_0000
000_00000 //1e HLT //STO did not work
0000_0000
100_11000 //20 XOR DATA_2
0000_0001
001_00000 //22 SKZ //check to see XOR worked
0000_0000
111_00000 //24 JMP XOR_OK
0010_1000
000_00000 //26 HLT //XOR did not work at all
0000_0000
100_11000 //28 XOR_OK: XOR DATA_2
0000_0001
001_00000 //2a SKZ
0000_0000
000_00000 //2c HLT //XOR did not switch all bits
0000_0000
000_00000 //2e END: HLT //CONGRATULATIONS-TEST1 PASSED!
0000_0000
111_00000 //30 JMP BEGIN //run test again
0000_0000
@3c
111_00000 //3c TST_JMP: JMP JMP_OK
0000_0110
000_00000 //3e HLT //JMP is broken
RAM中的值,用txt文件保存数据文件:
@1800
00000000 //1800 DATA_1: //constant 00(hex)
11111111 //1801 DATA_2: //constant FF(hex)
10101010 //1802 TEMP: //variable - starts with AA(hex)
仿真图像如下:
指令功能:
HLT:停机操作
SKZ:如果累加器的输出accum为0,则跳过下一条语句,否则继续执行
ADD:将累加器中的值与地址所指的ram中的数据相加
ANDD:相与
XORR:相异或
LDA:将指令中给出地址的数据放入累加器
STO:将累加器中的数据放入指令中给出的地址
JMP:无条件跳转语句,跳转指令给出目的地址,继续执行