实验目的:
【1】使用Verilog系统任务调用调试现有的Verilog设计
【2】使用VCS UCLI特性调试现有的Verilog设计
在partA中,您将在设计文件中插入Verilog系统任务调用,然后编译、模拟和解释Verilog系统任务调用输出,以尝试锁定错误。您将重复此过程,直到找到并纠正错误为止
在B部分中,您将使用启用的UCLI调试器进行编译。您将使用UCLI交互式模拟控制来逐步执行代码并定位错误的来源。您将纠正错误,并模拟以确认纠正是有效的。
一.使用Verilog系统任务调用调试现有的Verilog设计
二.实验步骤:
2.1使用VCS编译Verilog源文件
2.2通过执行simv启动仿真
2.3在错误点停止仿真
2.4确定错误来源
2.5修正错误源代码
2.6编译仿真以确保修改正确
VCS -h
这个命令将为您提供一个常用的VCS编译时和运行时开关列表,以及它们的功能的简要说明。
parta代码如下:
fa.v
module fa(a, b, cin, sum, cout);
input a, b, cin;
output sum, cout;
assign {cout, sum} = a + b;
endmodule
add4.v
module add4(a, b, cin, sum, cout);
input [3:0] a, b;
input cin;
output cout;
output [3:0] sum;
wire [3:1] c;
fa u1(a[0], b[0], cin, sum[0], c[1]);
fa u2(a[1], b[1], c[1], sum[1], c[2]);
fa u3(a[2], b[2], c[2], sum[2], c[3]);
fa u4(a[3], b[3], c[3], sum[3], cout);
endmodule
add8.v
module add8(a, b, cin, sum, cout);
input [7:0] a, b;
input cin;
output cout;
output [7:0] sum;
wire c4, c8_0, c8_1;
wire [7:4] sum_0, sum_1;
add4 u1(a[3:0], b[3:0], cin, sum[3:0], c4);
add4 low_add(a[7:4], b[7:4], 1'b0, sum_0, c8_0);
add4 high_add(a[7:4], b[7:4], 1'b1, sum_1, c8_1);
assign sum[7:4] = c4?sum_1:sum_0;
assign cout = c4?c8_1:c8_0;
endmodule
addertb.v
module addertb;
reg [7:0] a_test, b_test;
wire [7:0] sum_test;
reg cin_test;
wire cout_test;
reg [17:0] test;
add8 u1(a_test, b_test, cin_test, sum_test, cout_test);
initial
if (!$test$plusargs("monitoroff"))
$monitor ($time, " %h + %h = %h; cin = %h, cout = %h",
a_test, b_test, sum_test, cin_test, cout_test);
initial
begin
for (test = 0; test <= 18'h1ffff; test = test +1) begin
cin_test = test[16];
a_test = test[15:8];
b_test = test[7:0];
#50;
if ({cout_test, sum_test} !== (a_test + b_test + cin_test)) begin
$display("***ERROR at time = %0d ***", $time);
$display("a = %h, b = %h, sum = %h; cin = %h, cout = %h",
a_test, b_test, sum_test, cin_test, cout_test);
$finish;
end
#50;
end
$display("*** Testbench Successfully completed! ***");
$finish;
end
endmodule
adder.f
addertb.v
add8.v
add4.v
fa.v
在终端输入以下命令:
vcs -f adder.f -R
注:-f指定编译的源文件,-R开关表示编译后,立即仿真。
在调试过程中,必须能够通过设计跟踪错误。如果选择仅使用Verilog系统任务调用进行调试,则通常有两种跟踪错误的方法,您可以直接在rtl模块中插入Verilog系统任务调用,或者您可以在testbench中添加Verilog系统任务调用。
最好在testbench中添加调试语句。这样做有两个原因:第一,testbench通常是您进行结果检查的地方。使用Verilog系统任务调用和结果检查例程可以有效地提供断点功能。第二,出于性能原因,您希望避免重新编译。通过只将调试语句放在testbench中,您可以将重新编译限制在testbench文件中。
1.在终端输入下列代码,可以看到程序:
more addertb.v
2.最好的插入点是在检测到错误之后。在这里插入更多的$display system任务调用,以便跟踪设计层次结构中的错误。首先看看add8模块中发生了什么。
$display(“\nIn add8(u1)”);
$display(“a = %b, b = %b, sum = %b; cin = %b, cout = %b”,
u1.a, u1.b, u1.sum, u1.cin, u1.cout);
3.运行代码:
vcs –f adder.f -R
打印了错误位置的信息,如图:
正确结果,a=00000001,b=00000001,那么sum=00000010,我们进入进入add4(u1)看看发生了什么事情。
4.在图示所在的位置添加代码,代码如下:
$display(“\nIn add4(u1)”);
$display(“a = %b, b = %b, sum = %b; cin = %b, c = %b, cout = %b”,
u1.u1.a, u1.u1.b, u1.u1.sum, u1.u1.cin, u1.u1.c, u1.u1.cout);
5.将$finish改为 $stop.
通过这个修改,每次检测到错误时, $display中列出的结果将被打印出来,并且testbench将在这个时间步停止。再次编译并运行测试工作台
6.编译程序
vcs –f adder.f -R
当VCS遇到我们嵌入的$stop系统任务调用时,它会将您放入CLI调试器。您将看到uCLI提示符UCLI%。
最低位看起来没问题,第二个最低位有问题,他看起来没有加进位。继续仿真到下一个错误点,看看是否可以推断出这确实是一个问题。请用“run”继续仿真。在继续之前,尝试其他一些UCLI命令,看看它们是否有效。
一直运行.run命令,结果如下
a = 0001, b = 0001, sum = 0000; cin = 0, c = 001, cout = 0 #a,b最低位相加,注意sum最低位,这里lsb没有进位
a = 0001, b = 0011, sum = 0010; cin = 0, c = 001, cout = 0 #a,b最低俩位相加,最低位没进位,问题大致确定,最低位相加无法进位,以下结果分析相同
a = 0001, b = 0101, sum = 0100; cin = 0, c = 001, cout = 0
a = 0001, b = 0111, sum = 0110; cin = 0, c = 001, cout = 0
a = 0001, b = 1001, sum = 1000; cin = 0, c = 001, cout = 0
a = 0001, b = 1011, sum = 1010; cin = 0, c = 001, cout = 0
a = 0001, b = 1101, sum = 1100; cin = 0, c = 001, cout = 0
a = 0001, b = 1111, sum = 1110; cin = 0, c = 001, cout = 0
退出Ucli模式,命令如下:
ucli% quit
终端输入下列命令:
more fa.v
代码如上图:我们发现问题所在,我们把进为输入信号cin落下了。
修改文件后,重新编译,结果正确,如图:
10.使用monitoroff 参数重新仿真。这将告诉VCS跳过测试台上的$monitor行
终端输入下列的命令:
simv +monitoroff
从上图可以看出来,$monitor的内容被跳过了,没有打印出来。
拓展知识:
这是仿真命令,监控你需要的变量。
二.使用VCS UCLI特性调试现有的Verilog设计
1.进入partb目录,编译。
/home/zwj/文档/IC验证/VCS学习/VCS指导手册/vcs_lab.cn_vcs_lab/lab2/partb/
vcs -f adder.f -R
出现如下错误:
重新编译,这次启用UCLI调试器。
1.首先,在addertb.v中添加一个硬断点,即将$finish改为 $stop.
2.使用UCLI进行编译和仿真
在终端输入下面的命令:
vcs –f adder.f –R –debug_all -ucli
VCS遇到我们嵌入的$stop系统任务调用时,它会将您放入UCLI调试器。你会看到UCLI的提示:
可以在这里看到错误的详细信息。2:1 mux应该选择sum_0的和值0,但是它选择了sum_1的和值1。这可能就是问题所在.
打开add8.v程序
more add8.v
注意:在这里虚线显示了源代码实现的内容。预期的实现是实线。
3.在不离开UCLI环境的情况下模拟更正。如果将sum 0加法器的carry-in更改为1,sum 1加法器的carry-in更改为0,那么问题就得到了有效的纠正,如图:
4.使用ucli命令显示特定信号的信号值
进入到u1模块层
ucli% scope u1
显示特定信号的信号值
ucli% show zero_add_cin one_add_cin -value
使用命令,更改 zero_add_cin和one_add_cin 的值,命令如下:
force zero_add_cin 1 #强制将zero_add_cin赋值为1,注意force为强制赋值信号/变量
force one_add_cin 0 #强制将zero_add_cin赋值为0
信号值已经修改。再次查看信号值
ucli% vars zero_add_cin one_add_cin
仿真运行10s
ucli% run 10s
返回到上一层模块
ucli% scope -up
展示该模块的信号值
ucli% show a_test b_test cin_test cout_test sum_test –
value
在add8模块中C4信号上升沿(0->1)设置断点,代码如下:
stop -posedge u1.c4
仿真:
ucli% run
从运行结果来看,我们已经将仿真时间由60增加到26400s而没遇到任何错误。我们在来看下值。
ucli% show a_test b_test cin_test cout_test sum_test –
value
VCS遇到了c4从“ 0”到“ 1”的过渡,并在以下位置停止了模拟
那一点。 但是,除了这些事件之外,可能还有其他事件
尚未遇到。 在这种情况下4bitMSB(sum_1 in.addertb.u1) 在u1.c4信号转换后进行加法运算。因此,sum test的当前值还没有更新。您看到的是之前的值总和测试,需要至少将推进到下一个时间步,以查看当前时间步中所有事件的完整效果。
终端输入下面的命令,将仿真时间推迟1s:
ucli% run 1
再次查看仿真结果:
ucli% show a_test b_test cin_test cout_test sum_test –
value
a=1,b=8,sum=9
输入下面的命令,显示当前设置的断点:
ucli% stop
可以通过删除断点号的编号来删除断点,命令如下:
ucli% stop -delete 1
重新编译:
ucli % run
成功地检测到错误并在模拟中解决了它。如果厌倦了反复输入相同的命令,可以使用日志文件作为参考来生成脚本文件。这将简化调试命令条目。生成了一个脚本文件。在这个脚本文件中,定义了常用的别名,并执行模拟的carry-in fix命令.
注意:请记住,这不是一个真正的修复!它只允许模拟在不离开UCLI环境的情况下继续进行
5.使用脚本重新编译
输入以下命令:
simv -ucli -i test.s
运行tb
ucli% tb
开始仿真。
ucli% run
退出UCLI并查看模拟日志文件。日志文件应该显示您在模拟会话期间完成的所有操作。
在终端输入:
more ucli.key
参考文献:
【1】VCS_workshop