第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
addr_decode t_addr_decode (.addr(addr),.ram_sel(ram_sel),.rom_sel(rom_sel));
//------------------------------------------------------------------------------ initial begin
clock=1;
//display time in nanoseconds
$timeformat ( -9, 1, \ display_debug_message; sys_reset; test1; $stop; test2; $stop; test3; $stop; end
task display_debug_message; begin
$display(\ $display(\ $display(\ $display(\ $display(\
$display(\ end endtask
task test1; begin
test = 0;
disable MONITOR;
$readmemb (\ $display(\ $readmemb(\
$display(\ #1 test = 1; #14800 ; sys_reset; end endtask
task test2; begin
test = 0;
disable MONITOR;
$readmemb(\ $display(\ $readmemb(\
$display(\ #1 test = 2; #11600; sys_reset;
191
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
end endtask
task test3; begin
test = 0;
disable MONITOR;
$readmemb(\ $display(\ $readmemb(\
$display(\ #1 test = 3; #94000; sys_reset; end endtask
task sys_reset; begin
reset_req = 0;
#(`PERIOD*0.7) reset_req = 1; #(1.5*`PERIOD) reset_req = 0; end endtask
always @(test) begin: MONITOR case (test)
1: begin //display results when running test 1
$display(\ $display(\ $display(\ while (test == 1)
@(t_cpu.m_adr.pc_addr)//fixed
if ((t_cpu.m_adr.pc_addr%2 == 1)&&(t_cpu.m_adr.fetch == 1))//fixed begin
# 60 PC_addr <=t_cpu.m_adr.pc_addr -1 ; IR_addr <=t_cpu.m_adr.ir_addr;
# 340 $strobe(\
%h\T-CPU-M-REGISTER.DATA end
end
2: begin $display(\RUNNING CPUtest2 - The Advanced CPU Diagnostic Program ***\ $display(\ $display(\ while (test == 2)
@(t_cpu.m_adr.pc_addr)
192
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
if ((t_cpu.m_adr.pc_addr%2 == 1)
&& (t_cpu.m_adr.fetch == 1)) begin
# 60 PC_addr <= t_cpu.m_adr.pc_addr - 1 ; IR_addr <= t_cpu.m_adr.ir_addr;
# 340 $strobe(\
mnemonic, IR_addr, data ); end
end
3: begin
$display(\ $display(\ $display(\ $display( \ while (test == 3) begin
wait ( t_cpu.m_alu.opcode == 3'h1) // display Fib. No. at end of program loop $strobe(\ wait ( t_cpu.m_alu.opcode != 3'h1); end
end endcase end
//------------------------------------------------------------------------------------
always @(posedge halt) //STOP when HALT instruction decoded begin
#500
$display(\ $display(\
$display(\ end
always #(`PERIOD/2) clock=~clock; always @(t_cpu.m_alu.opcode)
//get an ASCII mnemonic for each opcode case(t_cpu.m_alu.opcode) 3'b000 : mnemonic =\ 3'h1 : mnemonic = \ 3'h2 : mnemonic = \ 3'h3 : mnemonic = \ 3'h4 : mnemonic = \ 3'h5 : mnemonic = \ 3'h6 : mnemonic = \ 3'h7 : mnemonic = \ default : mnemonic = \ endcase
endmodule
193
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
针对程序做如下说明:测试程序中用`include” “ 形式包含了“ rom.v ”,“ ram.v”和“addrdecode.v”三个外部模块,它们都是检测RISCCPU时必不可少虚拟设备。代表RAM ,ROM和地址译码器,对于RISCCPU,已将它做成一个独立的模块“cpu.v”。具体程序如下: //--------------------------------------------------------------------- `include \`include \`include \`include \
`include \`include \`include \`include \`include \
module cpu(clk,reset,halt,rd,wr,addr,data); input clk,reset;
output rd,wr,addr,halt; inout data;
wire clk,reset,halt; wire [7:0] data; wire [12:0] addr; wire rd,wr;
wire clk1,fetch,alu_clk; wire [2:0] opcode;
wire [12:0] ir_addr,pc_addr; wire [7:0] alu_out,accum;
wire zero,inc_pc,load_acc,load_pc,load_ir,data_ena,contr_ena;
clk_gen m_clk_gen (.clk(clk),.clk1(clk1),.fetch(fetch),
.alu_clk(alu_clk),.reset(reset));
register m_register (.data(data),.ena(load_ir),.rst(reset),
.clk1(clk1),.opc_iraddr({opcode,ir_addr}));
accum m_accum (.data(alu_out),.ena(load_acc),
.clk1(clk1),.rst(reset),.accum(accum));
alu m_alu (.data(data),.accum(accum),.alu_clk(alu_clk),
.opcode(opcode),.alu_out(alu_out),.zero(zero));
machinect1 m_machinec1(.ena(contr_ena),.fetch(fetch),.rst(reset));
machine m_machine (.inc_pc(inc_pc),.load_acc(load_acc),.load_pc(load_pc), .rd(rd), .wr(wr), .load_ir(load_ir), .clk1(clk1), .datactl_ena(data_ena), .halt(halt), .zero(zero), .ena(contr_ena),.opcode(opcode));
datactl m_datactl (.in(alu_out),.data_ena(data_ena),.data(data));
adr m_adr (.fetch(fetch),.ir_addr(ir_addr),.pc_addr(pc_addr),.addr(addr));
counter m_counter (.ir_addr(ir_addr),.load(load_pc),.clock(inc_pc),
194
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
.rst(reset),.pc_addr(pc_addr));
endmodule
其中 contr_ena 用于machinect1与machine之间的ena的连接。cputop.v 中用到下面两条语句需要解释一下:
$readmemb ( \和 $readmemb ( \
即可把编译好的汇编机器码装人虚拟ROM,把需要参加运算的数据装人虚拟RAM就可以开始仿真。上面语句中的第一项为打开的文件名,后一项为系统层次管理下的ROM模块和RAM模块中的存储器memory和ram。
下面清单所列出是用于测试RISC_CPU基本功能而分别装人虚拟ROM和RAM的机器码和数据文件,其文件名分别为test1.pro,test1.dat,test2.pro,test2.dat,test3.pro,test3.pro和调用这些测试程序进行仿真的程序cputop.v文件:
//----------------- 文件 test1.pro ----------------------------------------- /****************************************************************************** * Test1 程序是用于验证RISC_ CPU的功能, 是设计工作的重要环节
* 本程序测试RISC_ CPU的基本指令集,如果RISC_ CPU的各条指令执行正确, * 它应在地址为2E(hex)处,在执行HLT时停止运行。
* 如果该程序在任何其他地址暂停运行,则必有一条指令运行出错。 * 可参照注释找到出错的指令。
*****************************************************************************/
机器码 地址 汇编助记符 注释
//------------------------------- test1.pro开始 --------------------------------------------------------------------- @00 //address statement 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 value in TEMP 0000_0010
101_11000 // 16 LDA DATA_1
195