testbench的框架编写

本文介绍了使用Verilog进行硬件设计验证的testbench构造,包括头文件的包含,参数定义,主函数的设置。主要内容涉及如何生成时钟和复位信号,调用Verilated库进行VCD波形记录,以及通过main函数中的循环对模块进行激励并验证输出结果的正确性。同时,文中还展示了如何检查out_valid信号的匹配性,确保设计的功能正确性。
摘要由CSDN通过智能技术生成

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);
}


To resolve the error reported by Verilator, you need to add a final `end` statement at the end of the testbench after `$finish`. This statement will signal to Verilator that all simulation processes have completed successfully. Additionally, you need to change the comparison operator in each of the `if` statements from `!==` to `!=`, as Verilator does not support the `!==` operator. Here's the modified code: ``` module DW01_add_tb; // Declare inputs and outputs reg clk; reg [3:0] A; reg [3:0] B; reg CI; wire [3:0] SUM; wire CO; // Instantiate design under test DW01_add dut( .A(A), .B(B), .CI(CI), .SUM(SUM), .CO(CO) ); // Initialize inputs initial begin A = 4'b0000; B = 4'b0000; CI = 0; clk=0; end // Adder test case task test_adder; // Test case 1: 0 + 0 with carry-in of 0 A = 4'b0000; B = 4'b0000; CI = 0; //#10; if (SUM != 4'b0000 || CO != 1'b0) $display("Test failed! 0 + 0 should be 0 with carry-out of 0"); // Test case 2: 7 + 3 with carry-in of 0 A = 4'b0111; B = 4'b0011; CI = 0; //#10; if (SUM != 4'b1010 || CO != 1'b0) $display("Test failed! 7 + 3 should be 10 with carry-out of 0"); // Test case 3: 5 + 11 with carry-in of 1 A = 4'b0101; B = 4'b1011; CI = 1; //#10; if (SUM != 4'b0001 || CO != 1'b1) $display("Test failed! 5 + 11 should be 16 with carry-out of 1"); // Test case 4: 15+15 with carry-in of 1 A = 4'b1111; B = 4'b1111; CI = 1; //#10; if (SUM != 4'b1110 || CO != 1'b1) $display("Overflow!!!"); endtask // Run test cases initial begin test_adder(); $finish; end end // add final end statement ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kevin_wuminghao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值