SystemC 允许将仿真结果保存为 VCD 格式,该格式是目前最流行的波形格式之一
SystemC 波形跟踪有以下特点
只有在整个仿真期间都存在的信号和变量才能被跟踪
任何类型的信号和变量包括标量、数组和其他聚合类型都可以被跟踪
不同格式的波形文件可以在同一次仿真过程中同时产生,任何一个信号和变量都可以在不同格式的波形文件中不限制次数的被跟踪
创建波形跟踪文件
sc_trace_file *sc_create_vcd_trace_file(const char* name);
这里的 name 是要保存的文件名,函数的返回值是一个指向 sc_trace_file 类型的指针,比如下面的代码将生成一个 wave.vcd 文件
sc_trace_file* tf = sc_create_vcd_trace_file("wave);
关闭波形跟踪文件
void sc_close_vcd_trace_file( sc_trace_file* tf );
添加跟踪信号
void sc_trace(sc_trace_file* tf, const sc_in& port, const std::string& name);
添加端口跟踪
sc_in in_value;
sc_out out_value;
sc_trace(tf, in_value, "in_value");
sc_trace(tf, out_value, "out_value");
添加结构体跟踪
struct Color {
sc_uint<8> r;
sc_uint<8> g;
sc_uint<8> b;
sc_uint<8> a;
};
为了跟踪结构体,需要重载 sc_trace 函数,在重载函数中单独跟踪每一个结构体成员
void sc_trace(sc_trace_file* tf, const Color& color, const std::string& NAME) {
sc_trace(tf, color.r, NAME + ".r");
sc_trace(tf, color.g, NAME + ".g");
sc_trace(tf, color.b, NAME + ".b");
sc_trace(tf, color.a, NAME + ".a");
}
首先,我们实现一个半加器,通过打印观察输出
class HalfAdd : public sc_module {
public:
SC_HAS_PROCESS(HalfAdd);
HalfAdd(sc_module_name ins_name) : sc_module(ins_name) {
SC_METHOD(Add);
sensitive << number_a << number_b;
dont_initialize();
}
~HalfAdd() {
}
void Add() {
sum = number_a ^ number_b;
carry = number_a & number_b;
std::cout << number_a << " " << number_b << " " << (number_a ^ number_b) << " " << (number_a & number_b) << std::endl;
}
public:
sc_in number_a;
sc_in number_b;
sc_out sum; // 和
sc_out carry; // 进位
};
class Driver : public sc_module {
public:
SC_HAS_PROCESS(Driver);
Driver(sc_module_name ins_name) : sc_module(ins_name) {
SC_THREAD(GenData);
}
void GenData() {
number_a = 0; number_b = 0; wait(20, SC_NS);
number_a = 0; number_b = 1; wait(20, SC_NS);
number_a = 1; number_b = 0; wait(20, SC_NS);
number_a = 1; number_b = 1; wait(20, SC_NS);
}
public:
sc_out number_a;
sc_out number_b;
};
int sc_main(int argc, char* argv[]) {
sc_signal number_a;
sc_signal number_b;
sc_signal sum;
sc_signal carry;
HalfAdd half_add("half_add");
half_add.number_a(number_a);
half_add.number_b(number_b);
half_add.sum(sum);
half_add.carry(carry);
Driver driver("driver");
driver.number_a(number_a);
driver.number_b(number_b);
sc_start(200, SC_NS);
return 0;
}
我们打印发现,输出如下
0 1 1 0
1 0 1 0
1 1 0 1
这里并没有打印 0,0,这组数据,是因为初始值就是 0,0,传入 0,0 时,sc_signal 并没有改变,所以敏感列表并不会触发。这里将 sc_signal 改成 sc_buffer,这个时候就会发现打印正常了
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1
接下来将打印输出代码调整为下面这样
std::cout << number_a << " " << number_b << " " << sum << " " << carry << std::endl;
打印输出会变成下面这样
0 0 0 0
0 1 0 0
1 0 1 0
1 1 1 0
可以看到写完 sum 和 carry 时,它们的值没有立马更新,还是上一次的值,这里没有更新的原因是因为 delta 延时造成的
接下来使用波形文件跟踪
代码如下所示
int sc_main(int argc, char* argv[]) {
sc_buffer number_a;
sc_buffer number_b;
sc_buffer sum;
sc_buffer carry;
HalfAdd half_add("half_add");
half_add.number_a(number_a);
half_add.number_b(number_b);
half_add.sum(sum);
half_add.carry(carry);
Driver driver("driver");
driver.number_a(number_a);
driver.number_b(number_b);
sc_trace_file* tf = sc_create_vcd_trace_file("wave");
sc_trace(tf, number_a, "number_a");
sc_trace(tf, number_b, "number_b");
sc_trace(tf, sum, "sum");
sc_trace(tf, carry, "carry");
sc_start(200, SC_NS);
sc_close_vcd_trace_file(tf);
return 0;
}
波形如下所示
波形跟踪和实际打印的区别是,波形跟踪不受 delta 延时影响,可以更好的看见效果
在 Windows 上可以使用 gtkwave 查看波形
在 LInux 上使用 dve -full64 -vpd wave.vcd 查看波形