1.testbench的主要模块构成
(1)头文件
#include <iostream>
#include <stdlib.h>
verilator附带的两个头文件,访问verilator的内容,把波形写入vcd文件:
#include <verilated.h>
#include <verilated_vcd_c.h>
包含我们的Verilated ALU模块的顶级类:
#include "Valu.h”
Valu___024unit.h”包含typedef枚举的Verilated版本:
#include "Valu___024unit.h”
(2)参数定义
仿真的最长时间:
#define MAX_SIM_TIME 300
开始验证的起始时间(需要在复位完成之后):
#define VERIF_START_TIME 7
表示仿真的时间(注意不是真实的时间):
vluint64_t sim_time = 0;
表示上升沿的计数器: vluint64_t posedge_cnt = 0;
(3)main 函数 int main(int argc, char argv, char** env)** {
用于产生随机数:
Verilated::commandArgs(argc, argv);
调用Valu.h中的内容:
*Valu dut = new Valu;
导出VCD波形需要加此语句:
Verilated::traceEverOn(true);
调用verilated_vcd_c.h里面的内容:
*VerilatedVcdC m_trace = new VerilatedVcdC;
dut->trace(m_trace, 5); 打开vcd:
m_trace->open("waveform.vcd");
main函数中设定主循环:
只有当**(sim_time < MAX_SIM_TIME)** 才进入循环。
主循环中执行的主要内容:
(1)通过异或的方式生成时钟信号:
dut->clk ^= 1;
(2)计算当前循环的输出结果:
dut->eval();
(3)时钟上升沿计数器赋值:
if (dut->clk == 1)
{ posedge_cnt++;
}
(4)复位信号的产生:
采用函数的形式产生:
函数:dut_reset(dut, sim_time);
复位函数:将例化的dut指针传递给函数,以及sim_time 指针传递给函数
void dut_reset (Valu *dut, vluint64_t &sim_time)
{
dut->rst = 0;
if(sim_time >= 3 && sim_time < 6)
{
dut->rst = 1;
dut->a_in = 0;
dut->b_in = 0;
dut->op_in = 0;
dut->in_valid = 0;
}
}
(5)把sim_time传递给m_trace
**m_trace->dump(sim_time);**
(6)该时间内完成所有任务之后,sim_time自加
sim_time++;
(7)对输入信号施加激励,于此同时,验证输出结果的正确性。采用switch case 的语句进行:
switch (posedge_cnt){
case 10:
dut->in_valid = 1;
dut->a_in = 5;
dut->b_in = 3;
dut->op_in = Valu___024unit::operation_t::add;
break;
case 12:
if (dut->out != 8)
std::cout << "Addition failed @ " << sim_time << std::endl;
break;
case 20:
dut->in_valid = 1;
dut->a_in = 5;
dut->b_in = 3;
dut->op_in = Valu___024unit::operation_t::sub;
break;
case 22:
if (dut->out != 2)
std::cout << "Subtraction failed @ " << sim_time << std::endl;
break;
(8)in_valid信号随机生成函数
通过随机函数生成:set_rnd_out_valid(dut, sim_time);
void set_rnd_out_valid(Valu *dut, vluint64_t &sim_time){ if (sim_time >= VERIF_START_TIME) { dut->in_valid = rand() % 2; }
(9)out_valid信号检查函数
通过函数检查正确性:check_out_valid(dut, sim_time);
void check_out_valid(Valu *dut, vluint64_t &sim_time){
static unsigned char in_valid = 0; //in valid from current cycle
static unsigned char in_valid_d = 0; //delayed in_valid
static unsigned char out_valid_exp = 0; //expected out_valid value
if (sim_time >= VERIF_START_TIME) {
out_valid_exp = in_valid_d;
in_valid_d = in_valid;
in_valid = dut->in_valid;
if (out_valid_exp != dut->out_valid) {
std::cout << "ERROR: out_valid mismatch, "
<< "exp: " << (int)(out_valid_exp)
<< " recv: " << (int)(dut->out_valid)
<< " simtime: " << sim_time << std::endl;
}
}
通过比对理想值和真实值从而检测出正确性
结束循环!!!
结束循环之后,在main函数中:
关闭:m_trace:
m_trace->close();
删除: dut : delete dut;
成功退出: exit(EXIT_SUCCESS)
代码源文件:
// Norbertas Kremeris 2021
#include <stdlib.h>
#include <iostream>
#include <cstdlib>
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Valu.h"
#include "Valu___024unit.h"
#define MAX_SIM_TIME 300
#define VERIF_START_TIME 7
vluint64_t sim_time = 0;
vluint64_t posedge_cnt = 0;
void dut_reset (Valu *dut, vluint64_t &sim_time){
dut->rst = 0;
if(sim_time >= 3 && sim_time < 6){
dut->rst = 1;
dut->a_in = 0;
dut->b_in = 0;
dut->op_in = 0;
}
}
void check_out_valid(Valu *dut, vluint64_t &sim_time){
static unsigned char in_valid = 0; //in valid from current cycle
static unsigned char in_valid_d = 0; //delayed in_valid
static unsigned char out_valid_exp = 0; //expected out_valid value
if (sim_time >= VERIF_START_TIME) {
out_valid_exp = in_valid_d;
in_valid_d = in_valid;
in_valid = dut->in_valid;
if (out_valid_exp != dut->out_valid) {
std::cout << "ERROR: out_valid mismatch, "
<< "exp: " << (int)(out_valid_exp)
<< " recv: " << (int)(dut->out_valid)
<< " simtime: " << sim_time << std::endl;
}
}
}
void set_rnd_out_valid(Valu *dut, vluint64_t &sim_time){
if (sim_time >= VERIF_START_TIME) {
dut->in_valid = rand() % 2;
}
}
int main(int argc, char** argv, char** env) {
srand (time(NULL));
Verilated::commandArgs(argc, argv);
Valu *dut = new Valu;
Verilated::traceEverOn(true);
VerilatedVcdC *m_trace = new VerilatedVcdC;
dut->trace(m_trace, 5);
m_trace->open("waveform.vcd");
while (sim_time < MAX_SIM_TIME) {
dut_reset(dut, sim_time);
dut->clk ^= 1;
dut->eval();
if (dut->clk == 1){
dut->in_valid = 0;
posedge_cnt++;
switch (posedge_cnt){
case 10:
dut->in_valid = 1;
dut->a_in = 5;
dut->b_in = 3;
dut->op_in = Valu___024unit::operation_t::add;
break;
case 20:
dut->in_valid = 1;
dut->a_in = 5;
dut->b_in = 3;
dut->op_in = Valu___024unit::operation_t::sub;
break;
}
check_out_valid(dut, sim_time);
}
m_trace->dump(sim_time);
sim_time++;
}
m_trace->close();
delete dut;
exit(EXIT_SUCCESS);
}