- 编译工程时候的顺序:首先自下而上编译设计文件,之后编译tb文件。
- 编译完毕后就会在默认的work库中产生对应的文件。
- 右键tb文件,选中运行无逻辑优化的仿真
- 仿真时候不小心关闭了某窗口,可以自layout菜单先重置一下,之后选中simulation模式。
- 仿真中的单个initial块中是顺序执行的,但是多个initial不是顺序执行
- 开始运行之前可以先在命令行中输入log -r /*,这样运行后得到的仿真波形就可以被保存,之后添加信号到波形窗口也可看到信号波形。否则必须先添加信号到波形窗口才能保存。
- 将dut的顶层信号波形添加,在波形窗口左下角可以将信号路径隐藏,如图:
- 带有随机化的仿真命令
vsim -novopt -solvefaildebug -sv_seed 0 work.tb1
//-solvefaildebug.是为了调试随机变量的,,若有随机化的错误会告知原因,而-SV seed NUM 则是为了传递随机的种子
vsim -novopt -solvefaildebug -sv seed random work.tb1
// 随机种子也可以random,那么每次仿真产生的激励都会不同
vsim -novopt -classdebug -solvefaildebug -sv_seed 0 +TESTNAME=mcdf_data_consistence_basic_test -l mcdf_data_consistence_basic_test.log work.tb
-classdebug,这是为了提供更多的 SV 类调试功能
-solvefaildebug,这是为了在 SV 随机化失败之后有更多的信息提供出来
-sv_seed 0,暂时给固定的随机种子 0
+TESTNAME=mcdf_data_consistence_basic_test,这是指定仿真选择的调试
-| mcdf_data_consistence_basic_test_sim.log,这是让仿真的记录保存在特定的测试文件名称中
例1:delta-cycle的作用
`timescale 1ns/1ns
module race1;
bit clk1, clk2,clk3,clk4;
bit rstn;
logic[7:0] d1;
initial begin
forever #5 clk1 <= !clk1;
end
always @(clk1) clk2 <= clk1;
always @(clk1) clk3 <= clk1;
assign clk4 = clk1;
initial begin
#10 rstn <= 0;
#20 rstn <= 1;
end
always @(posedge clk1, negedge rstn) begin
if(!rstn) d1 <= 0;
else d1 <= d1 + 1;
end
always @(posedge clk1) $display("%0t ns d1 value is 0x%0x", $time, d1);
always @(posedge clk2) $display("%0t ns d1 value is 0x%0x", $time, d1);
always @(posedge clk3) $display("%0t ns d1 value is 0x%0x", $time, d1);
always @(posedge clk4) $display("%0t ns d1 value is 0x%0x", $time, d1);
endmodule
注意:光标定位的位置Msgs显示的是所有delta-cycle完成之后各个信号的值,如下所示:
但是实际上,由两个时钟采样d1得到的值是,可见与上图显示的并不符合。
- 通过显示采样模式并且设置仅在光标处激活显示。可见,clk1是最先拉高的,一个delta-cycle后d1+1,又经过一个delta-cycle后clk2拉高并采样了d1.
以同样的方式插入clk3,采样结果如下:
可见一个delta-cycle只能完成一个任务,即一个@或者assign。assign的优先级高于@(下图clk4是clk1 assign得到的)。
例2:变量赋值(0时刻)
- 0时刻模拟的是一个系统刚刚上电的过程。另外关于复位模块的验证也常常关注0时刻。
- 功能仿真很少见到X,门级仿真、mem仿真更常见。如mem为0就是没有赋初值的表现。
module simstart1;
logic a1=0;
logic a2, a3, a4, a5 ,a6,a7;
bit rstn, clk;
assign a2 = a1; // assign
initial begin // initial
a3 = a1;
end
always @(posedge clk, negedge rstn) begin // sequential logic
if(rstn === 'b0) a4 <= 0;
else a4 <= a1;
end
always @(a1) begin // combination logic
a5 <= a1;
a6 <= a1;
a7 <= a5;
end
initial begin
#10ns rstn <= 0;
#20ns rstn <= 1;
end
initial forever #5ns clk <= !clk;
endmodule
在初始阶段(work中运行无优化的仿真,但是没有run),二值逻辑bit有确定的值,四值逻辑logic除非有明确地赋初值,否则初始值为x。如下图所示:
run 0后(相当于走过无穷多个delta-cycle),经过assign 和 initial赋值的变量的值得到更新
代码中没有修改a1的描述,但是可以在仿真工具中强制修改:
在当前时间基础上再过7ns,将值设为1
force -freeze sim:/simstart1/a1 1'h1 7ns
run 7ns
a456已经被赋值,a7的值等待下次a1变化才能被赋予;
a2被重新赋值,assign其赋值优先级是最高的:
a3仍然维持原值,说明initial只在仿真开始时执行一次。
例3: 设置断点
- 在project界面双击代码文件可在PC编辑器中(notepad++等)打开,在sim界面双击会在questa中打开并设置断点。
module breakpoint1;
int val1;
int val2;
int result;
function int incr_static(input int a);
result = a + 1;
return result;
endfunction
function automatic int incr_dynamic(input int a);
int result;
result = a + 1;
return result;
endfunction
initial begin
val1 = 0;
val1 = incr_static(val1);
val1 = incr_static(val1); // breakpoint line8 result == ?
end
initial begin
val2 = 0;
val2 = incr_dynamic(val2);
val2 = incr_dynamic(val2); // breakpoint line14 result == ?
end
endmodule
view->locals,object线上硬件变量,而locals显示的是软件的过程变量。运行后,框图中将自动显示所有过程软件变量。
右击显示代码行数的空白处,编辑所有断点可以选择断点的使能。
例4: 快速测量时钟频率
在波形窗口中,插入新cursor