VCS 调试基础
VCS调试方法
- Verilog/SV 的系统函数 (如 display、moniter 语句等)
- VSC UCLI ( User Command Line)命令行调试模式 (不建议使用)
- VCS DVE (GUI) 图像化界面调试 ( Verdi 是用于调试的工具,该工具不会进行编译和仿真)
(Verdi是一个功能强大的 debug工具,可以配合不同的仿真软件进行debug,很多企业常用的就是 VCS+Verdi 的方式进行代码的仿真与检查。Verdi使用情形主要是IC验证工程师(Debug),IC设计工程师(Review)。)
Verilog System Task for Debugging
Debug visibility:
$display
:Prints formatted message to console$strobe
:Like$ display
except printing is delayed until all events in the current time step have executed$monitor
:Monitor signals listed and prints formatted message whenever one of the listed signals changes$time
:Returns current simulation time as a 64bits integer
(在VCS中,display 和 monitor 所处的仿真队列是不同的,display 输出的是变量在赋值前的值,而 moniter 输出的是变量赋值后的值)
Stopping simulation:
$stop
:Halts simulation like a breakpoint$finish
:Halts simulation and terminated the simulation session
Simulation stimulus and reference:
$readmemh
:Reads ASCII data from a disk file. Each digit is hexadecimal.$readmemb
:Reads ASCII data from a disk file.Each digit is binary.
(用于RAM、ROM 或者是 FIFO,将文件中的内容读入到这些存储单元中,用作初始化数据)
UCLI debugger
DVE
DVE ,Discovery Visual Environmental
基本界面
启动命令
Interactiove mode下的启动:
# Method 1
$ vcs source.v -R -gui -debug_all
# -R Starts DVE immediately after compliation(optional)
# -gui Enables DVE
# -debug_all Enables command line debug including line tracing
# Method 2
$ ./simv -gui
# -gui Starts DVE from existing simulation executable
Post-Process Mode下的启动:
VCD,Value Change Dump (Dump是输出、转存的意思)是波形文件,其数据量很大,vpd 是在 vcd 的基础上进行压缩,使得波形文件占用的内存空间更小。
Verdi 使用的波形文件格式是 fsdb(Fast Singnal Database),也是一种压缩格式的波形文件。
Modelsim 的波形文件则是 WLF格式(Wave Log File)
信号比较功能
读入两个波形文件,然后进行比较,会显出不同的地方。
Bus Builder Tool
以总线的形式显示信号:
比如,一个计数器的输出是 4bit,每个 bit 一条信号线单独显示的时候,不容易判断其输出值到底是多少,这个时候就可以将其设为总线,就可以看到输出的值。
Lab示例
源文件
基础的源文件是 fsm_moore.v 和 fsm_top.v,其中后者是 testbench。
//----------------------------
//FileName : fsm_moore.v
//Author : JinYawei
//Date : 2023-07-21
//----------------------------
//`define INC_COUNTER
//`include "global_define.vh"
`timescale 1ns/1ns
module fsm_moore(
// Inputs
input clk,
input rst_n,
// Outputs
output reg [3:0] dout,
output reg [2:0] q
);
//------ Parameter define ------------
parameter [1:0] idle = 2'd0,
s1 = 2'd1,
s2 = 2'd2,
s3 = 2'd3;
reg [1:0] state,next;
//-------------------------------------
//------- State convert ---------------
always @ (posedge clk,negedge rst_n)
if (!rst_n) state <= idle;
else state <= next;
//-------------------------------------
//------- State decode & output -------
always @ (*) begin
next = idle;
dout = 4'd0;
case (state)
idle: begin
dout = 4'd0;
next = s1;
end
s1: begin
dout = 4'd1;
next = s2;
end
s2: begin
dout = 4'd2;
next = s3;
end
s3: begin
dout = 4'd9;
next = idle;
end
endcase
end
// counter
always @ (posedge clk,negedge rst_n) begin
if (!rst_n) q <= 3'd0;
`ifdef INC_COUNTER
else q <= q + 3'd1;
`else
else q <= q - 3'd1;
`endif
end
//-------------------------------------
endmodule
//---------------------------------------------
//File Name : fsm_top.v (fsm_moore.sv)
//Data : 2023-07-21
//---------------------------------------------
`timescale 1ns/1ns
module fsm_top;
reg clk;
reg rst_n;
wire [3:0] dout;
wire [2:0] q;
// Define the run number with initial parameter
integer run_num = 20;
// Define an array
reg [7:0] mem [0:15];
integer i;
// Generate clk
initial begin
clk = 1'b0;
forever #5 clk = ~clk;
end
// Generate rst_n
initial begin
// if {$value$plusargs("run_num=%0d", run_num)} begin
// $display ("The run_num is %0d ",run_num );
// end else begin
// $display(Sorry! Can not ger run_num");
// end
// Call task
print_message();
rst_n = 1'b1;
repeat (2) @ (posedge clk);
rst_n = 1'b0; // After 2 posedge clk,rst_n = 0
repeat (2) @ (posedge clk);
rst_n = 1'b1;
repeat (run_num) @ (posedge clk);
$display("Finish Simulation @ [%0t]", $time);
$finish;
end
//$readmemh{} test
//initial begin
// $readmemh{"./src,txt",mem}
//
// for(i=0;i<10;i=i+1) begin
// $dislpay{"mem[%2d] = %0d",i, mem[i]}
// end
//end
// DPI test
import "DPI" function void hello(string str);
initial begin
hello("hello SystemVerilog");
end
// Instance the DUT
fsm_moore fsm_moore(
.clk (clk ),
.rst_n(rst_n),
.dout (dout ),
.q (q )
);
// Dump vpd file
initial begin
$vcdplusdeltacycleon();
$vcdplusglitchon();
`ifdef DUMP_ON
$vcdpluson();
//$vcdpluson(fsm_top,fsm_moore);
//$vcdpluson(0,fsm_top);
//$vcdpluson(1,fsm_top);
//$vcdpluson(2,fsm_top);
`endif
end
task automatic print_message;
reg [3:0] a, b;
begin
a = 1;
$display("a = %0d",a);
b = 2;
$display("b = %0d",b);
end
endtask
endmodule // fsm_moore
基本编译和运行
编译指令:
vcs ./fsm_moore.v ./fsm_top.v +v2k -debug_all -gui
# -gui 表示run的时候可以使用DVE图形化界面 (Enable DVE at runtime)
仿真指令:
./simv -gui &
打开DVE,添加波形之后的界面如下:
可以看到没有波形信号,因为还没有执行仿真。
F5执行仿真之后得到的内容如下:
timescale问题
第一次编译的时候存在的一个问题:
在 fsm_moore 设计文件中添加了 timescale
之后,就没有该问题的,这应该是和编译器本身有关,使用 Modelsim 的时候就不需要这样做。
这里如果不想再源代码中定义,也可以在编译的时候作为一个编译选项。后续基于 Makefile 的实现就将其放在了 vcs
编译指令中。
DVE界面操作
参考线
分组
查找信号值
信号比较
对比结果如下:
单步调试
set bus
选中信号线,然后右键 >> set bus
波形显示结果如下:
调用 C 程序
在VCS中,DPI(Direct Programming Interface)是一种机制,用于在Verilog和C/C++代码之间进行互操作。DPI允许从Verilog代码中直接调用C/C++函数,并允许C/C++代码直接访问Verilog模块的内部信号和状态。
DPI的主要用途是为仿真器提供更高级别的功能和控制,并将仿真器与其他软件工具进行集成。使用DPI,用户可以通过C/C++代码实现复杂的仿真和调试功能,并将其集成到仿真器中。DPI还可以用于与其他工具进行交互,例如从仿真器中调用外部库或程序,或将仿真器的结果传输到其他工具中进行分析。
在VCS中,DPI函数定义在C/C++代码中,并通过特殊的DPI导出声明与Verilog代码进行关联。这使得Verilog代码可以直接调用DPI函数,而C/C++代码可以访问Verilog模块的内部信号和状态。
PLI(Programming Language Interface)的功能和DPI一样,但是DPI是SystemVerilog中的新机制,而PLI是Verilog中的旧机制。DPI提供了更多的功能和灵活性,而PLI则比较受限制,DPI更适合于处理多个实例的仿真和调试问题。
- C语言函数如下:
#include<stdio.h>
#include"svdpi.h" // 使用DPI功能必须包含的头文件
void hello(char* str)
{
printf {"%s\n",str};
}
-
Verilog中调用该函数:
import
关键字告诉编译器通过DPI调用外部函数。 -
编译指令
vcs ./fsm_top.v ./hello.c ./fsm_moore.v -sverilog +v2k -debug_all
# 增加C语言的源文件
# 增加 -sverilog 选项,因为DPI是SV的功能
- 执行仿真