
Verilog HDL数字系统设计与其应用_09测试与仿真.ppt
40页第9章 测 试 与 仿 真,9.1 测试与仿真的流程 9.2 测试举例,9.1 测试与仿真的流程 对已设计模块的测试与仿真通常可分为以下三个步骤: (1) 产生输入向量,包括输入向量的初始化与产生测试波形 (2) 将输入向量添加到已设计模块并给出相应的输出结果 (3) 将输出结果与设计要求相比较9.1.1 产生输入向量 对输入向量的初始化可通过initial过程块来实现 【例9-1】输入向量的初始化 initial begin clk = 1'b0; globalReset = 1'b1; in = 1'b1; end 在上面的例子中,将二进制表示形式的0值赋给变量clk实际上,对于值0与1,没有必要采用二进制表示形式1'b0与1'b1,直接用0与1给出即可 当给输入向量赋值时,可以利用一定的延迟时间来控制测试与仿真程序(参见下面的例子)例9-2】带延迟的向量赋值 #100 globalReset = 0; #100 in = 0; #100 in = 1; #300 in = 0; 经过100个时间单位的延迟后将变量globalReset的值置为0,再经过100个时间单位的延迟把变量in变为0,依次类推。
这里需要注意的是,时延是一个相对的概念,即相对于上一条语句执行完后的时刻而言,并非相对于仿真的起始时间 如果测试模块中没有控制仿真结束时刻的语句,那么当对测试模块进行仿真实验时,程序就会陷入死循环通过在initial过程块中加入带有延迟的系统任务$finish或$stop,就可轻易解决该问题例9-3】仿真结束语句的应用 initial begin #100 globalReset = 0; #100 in = 0; #100 in = 1; #300 in = 0; #400 $finish end 采用always过程块可以很容易实现时钟信号,下面是一个产生某测试模块的时钟信号的例子例9-4】时钟信号的产生 always begin #10 clk = ~clk; end 该例用来产生一个周期为20个时间单位的时钟信号 如果输入信号的值有规律地变化时,例如按相同的延迟重复出现n次,那么就可以通过repeat循环语句来实现 【例9-5】repeat循环语句的例子 repeat(10) begin #40 in = 0; #20 in = 1; end,9.1.2 测试模块 【例9-6】4选1多路选择器的功能模块与测试模块。
//功能模块部分 module multiplexor4_1 (out, in1, in2, in3, in4, cntrl1, cntrl2); output out; input in1,in2,in3,in4,cntrl1,cntrl2; reg out; always @(in1 or in2 or in3 or in4 or cntrl1 or cntrl2) case ({cntrl1,cntrl2}) 2'b00:out = in1; 2'b01:out = in2; 2'b10:out = in3; 2'b11:out = in4; default:$display(“Please check control bits“); endcase endmodule,//测试模块部分 module muxstimulus; reg IN1,IN2,IN3,IN4,CNTRL1,CNTRL2; wire OUT; multiplexor4_1 mux1_4(OUT,IN1,IN2,IN3,IN4,CNTRL1,CNTRL2); initial begin IN1 = 1;IN2 = 0;IN3 = 1;IN4 = 0; $display(“Initial arbitrary values“); #0 $display(“input1 = %b,input2 = %b,input3 = %b,input4 = %b\n“, IN1,IN2,IN3,IN4); {CNTRL1,CNTRL2} = 2'b00; #1 $display(“cntrl1=%b,cntrl2=%b,output is %b“,CNTRL1, CNTRL2, OUT); {CNTRL1, CNTRL2} = 2'b01;,#1 $display(“cntrl1=%b,cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); {CNTRL1,CNTRL2} = 2'b10; #1 $display(“cntrl1=%b,cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); {CNTRL1,CNTRL2} = 2'b11; #1 $display(“cntrl1=%b,cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); end endmodule,测试模块与功能模块相类似,都是以关键字module开头的。
但由于测试模块只是为了进行仿真验证,因而不需要端口列表,也不能被其它模块调用而功能模块则必须有端口列表 由于测试模块没有端口列表,因而不需进行端口声明为了对功能模块的参数进行赋值,测试模块中也需进行数据类型的说明,即 reg IN1,IN2,IN3,IN4,CNTRL1,CNTRL2; wire OUT;,接下来就是调用功能模块的部分: multiplexor4_1 mux1_4(OUT,IN1,IN2,IN3,IN4,CNTRL1,CNTRL2); 可以看出,其调用格式如下: (port list); 其中代表已设计的功能模块的名字;是不能省略的,且调用部分的端口列表必须与功能模块的端口列表(包括端口的个数与排列顺序)相对应测试模块的主体部分包含在initial过程块中,即 initial begin IN1 = 1;IN2 = 0;IN3 = 1;IN4 = 0; $display(“Initial arbitrary values“); #0 $display(“input1 = %b,input2 = %b,input3 = %b,input4 = %b\n“, IN1,IN2,IN3,IN4); {CNTRL1,CNTRL2} = 2'b00; #1 $display(“cntrl1=%b,cntrl2=%b,output is %b“,CNTRL1,CNTRL2,OUT); {CNTRL1,CNTRL2} = 2'b01; #1 $display(“cntrl1=%b, cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); {CNTRL1,CNTRL2} = 2'b10;,#1 $display(“cntrl1=%b, cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); {CNTRL1,CNTRL2} = 2'b11; #1 $display(“cntrl1=%b, cntrl2=%b output is %b“,CNTRL1,CNTRL2,OUT); end,首先对输入向量进行赋值,并通过系统任务$display显示其结果, IN1 = 1;IN2 = 0;IN3 = 1;IN4 = 0; $display(“Initial arbitrary values“); #0 $display(“input1 = %b,input2 = %b,input3 = %b,input4 = %b\n“, IN1,IN2,IN3,IN4); 延迟表示#0是为了保证当给输入变量赋值后立即显示。
然后通过给变量CNTRL1与 CNTRL2赋值并用连接符号{ }将它们连接起来作为一个整体判决条件,来验证已设计模块的输出与设计要求是否吻合9.2 测 试 举 例 通过上一节对测试与仿真流程的介绍,我们已对测试模块有了一个清晰的认识在此基础上,本节给出一些常用电路的功能模块与测试模块的例子,以供读者参考 【例9-7】模为16的增1计数器 // 4位二进制增1计数器 module counter4_bit(q,d,increment,load_data,global_reset,clock); output [3:0] q; input [3:0] d; input load_data,global_reset,clock,increment; wire t1,t2,t3; //内部连线 wire see15,reset;//内部连线,//内部连线用来在模块间传递信息, //它们可被当作临时变量,用来储存 //某个门的输出并输入另一个门 et_ff etff0(q[0],d[0],increment,load_data,reset,clock); et_ff etff1(q[1],d[1],t1,load_data,reset,clock); et_ff etff2(q[2],d[2],t2,load_data,reset,clock); et_ff etff3(q[3],d[3],t3,load_data,reset,clock); and a1(t1,increment,q[0]); and a2(t2,t1,q[1]); and a3(t3,t2,q[2]); recog15 r1(see15,q); or or1(reset,see15,global_reset); endmodule,module et_ff(q,data,toggle,load_data,reset,clock); output q; input data,toggle,load_data,reset,clock; wire m1,m2; mux mux0(m1,~q,q,toggle); mux mux1(m2,data,m1,load_data); dff dff0(q,m2,reset,clock); endmodule,module mux(out,in1,in2,cntrl); output out; input in1,in2,cntrl; assign out = cntrl ? in1:in2; //这是一个连续赋值,任一操作数的改变,输出将相应地改变此语句相当于if (cntrl==1) out = in1,else out = in2. endmodule,module dff(q,data,reset,clock); output q; input data,reset,clock; reg q; always @(posedge clock) //在时钟的上升沿,如果reset为1,q复位 if (reset == 1) //成0,否则q等于data q = 0; else q = data; endmodule,module recog15(flag,in); input [3:0] in; output flag; assign flag = (in == 4'b1111) ? 1:0; // 如果输入为15 ,则flag 被设置为1, // 否则为0 endmodule,module stumulus; wire [3:0] q; reg [3:0] d; reg load_data,global_reset,clk,increment; counter4_bit mod1 (q,d,increment,load_data,global_reset,clk); initial begin global_reset = 0; clk = 0; increment = 0; load_data = 0; d = 4‘b0010; #10 global_reset = 1; #20 global_reset = 0; #20 load。












