FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

手把手教你用SystemVerilog,为FPGA验证搭个智能裁判(记分板)

FPGA小白FPGA小白
技术分享
2天前
0
0
14

在FPGA开发的世界里,功能验证就像是给设计做“全面体检”,是确保一切运行如意的关键。当设计越来越复杂,靠人工一个个去核对输出?那简直是大海捞针,效率低还容易看花眼。这时候,基于约束的随机验证(CRV)就成了我们的主力军,而记分板(Scoreboard),就是这支军队里最公正的“智能裁判”。

它能够自动比对设计的实际输出和预期结果,让验证效率飙升,可靠性也大大增强。今天,我们就一起用SystemVerilog,动手在FPGA验证环境中搭建一个既简单又实用的记分板,感受一下自动化验证的魅力。

一、为什么我们需要一个“记分板”?

想象一下,你在验证一个数据通路(比如FIFO、DMA或者图像处理流水线)。测试平台(Testbench)会像连珠炮一样,向待测设计(DUT)发送海量的随机数据。如果每个输出都得你瞪大眼睛看波形,或者在一堆打印信息里手动查找,那得多累啊,而且保不准就会出错。

记分板就是来解放你的!它的核心价值有三点:

  • 自动化比较:实时或事后自动对比“实际输出”和“预期模型输出”,完全不用你操心。
  • 错误精确定位:一旦发现不匹配,立刻报告错误发生的时间、具体数据和上下文,调试效率直接拉满。
  • 覆盖率驱动:它可以和功能覆盖率模型联手,指导随机测试的生成,确保你的验证能覆盖到各种边边角角。

二、用SystemVerilog打造记分板,需要哪些“零件”?

一个典型的记分板,我们可以利用SystemVerilog面向对象(OOP)的特性,像搭积木一样把它构建出来。主要包含三部分:

  • 预测模型(Reference Model):你可以把它理解为一个“黄金标准”或“参考答案”。它接收和DUT一样的输入,然后用更高抽象级别的方式,计算出DUT应该输出的结果。
  • 数据容器(Mailbox或Queue):用来临时存放预测模型算好的“预期数据”。SystemVerilog提供的mailbox或者queue特别好用,能轻松搞定线程之间的数据传递和同步问题。
  • 比较器(Comparator):这是记分板的核心“大脑”。它从容器里取出“预期数据”,再和从DUT那里监测到的“实际数据”进行比对,然后给出“对”或“错”的判决。

三、实战开始:给一个简易AXI-Stream FIFO配个裁判

理论说再多,不如动手敲一敲。假设我们有一个带延迟的AXI-Stream接口FIFO模块,现在就来为它量身定制一个记分板,验证数据传得对不对。

步骤1:定义“事务”类——数据的基本单元

在验证环境中,数据通常被打包成“事务”来处理。我们先定义好它长什么样:

class axi_stream_transaction;
    rand bit [31:0] tdata;  // 数据本身
    rand bit [3:0]  tkeep;  // 字节有效指示
    rand bit        tlast;  // 包结束标志
    int             id;     // 给事务加个ID,方便调试跟踪

    function void display(string prefix="");
        $display("%sTime=%0t, ID=%0d, DATA=0x%h, LAST=%b",
                 prefix, $time, id, tdata, tlast);
    endfunction
endclass

步骤2:构建“记分板”类——我们的智能裁判

重头戏来了,我们来搭建裁判本体:

class scoreboard;
    // 用两个“邮箱”分别存预期和实际的事务。参数‘0’表示邮箱无限大。
    mailbox #(axi_stream_transaction) exp_mbx;
    mailbox #(axi_stream_transaction) act_mbx;
    int match_count, mismatch_count; // 记录对比结果

    // 构造函数,初始化一切
    function new();
        exp_mbx = new();
        act_mbx = new();
        match_count = 0;
        mismatch_count = 0;
    endfunction

    // 任务:把预测模型算好的事务,放进“预期邮箱”
    task put_expected(axi_stream_transaction exp_tr);
        exp_mbx.put(exp_tr);
    endtask

    // 任务:把从DUT监测到的事务,放进“实际邮箱”
    task put_actual(axi_stream_transaction act_tr);
        act_mbx.put(act_tr);
    endtask

    // 核心比较任务!通常它会作为一个独立的线程一直运行
    task run();
        axi_stream_transaction exp_tr, act_tr;
        forever begin
            // 等待两个邮箱里都有数据(这里假设数据顺序一致)
            // 注意:如果DUT会乱序输出,就需要更复杂的匹配机制,比如用ID来配对。
            exp_mbx.get(exp_tr);
            act_mbx.get(act_tr);
            compare(exp_tr, act_tr);
        end
    endtask

    // 具体的比较函数
    function void compare(axi_stream_transaction exp, act);
        if (exp.tdata === act.tdata && exp.tlast === act.tlast) begin
            match_count++;
            `uvm_info("SCOREBOARD", $sformatf("Match! ID=%0d, EXP_DATA=0x%h, ACT_DATA=0x%h",
                                               exp.id, exp.tdata, act.tdata), UVM_LOW)
        end else begin
            mismatch_count++;
            `uvm_error("SCOREBOARD",
                       $sformatf("Mismatch! Time=%0t, ID=%0dn", $time, exp.id) +
                       $sformatf("  Expected: DATA=0x%h, LAST=%bn", exp.tdata, exp.tlast) +
                       $sformatf("  Actual:   DATA=0x%h, LAST=%b", act.tdata, act.tlast))
        end
    endfunction

    // 测试结束后,打印一份漂亮的最终报告
    function void report();
        $display("n=== SCOREBOARD FINAL REPORT ===");
        $display("Total Comparisons: %0d", match_count + mismatch_count);
        $display("Matches: %0d", match_count);
        $display("Mismatches: %0d", mismatch_count);
        if (mismatch_count == 0) begin
            $display("*** TEST PASSED ***");
        end else begin
            $display("*** TEST FAILED ***");
        end
        $display("============================n");
    endfunction
endclass

步骤3:在测试平台中集成——让裁判开始工作

最后,我们需要在顶层的Testbench里实例化记分板,并把它和监测器(Monitor)连接起来:

module tb_axi_fifo();
    // ... 这里省略DUT实例、接口声明、时钟生成等代码 ...
    scoreboard sb; // 声明我们的记分板裁判

    initial begin
        sb = new(); // 创建裁判实例

        fork
            sb.run(); // 启动比较线程(裁判开始工作)

            // 启动驱动、监测器等线程
            begin
                input_monitor_task(); // 输入监测器,会调用 sb.put_expected(...)
                output_monitor_task(); // 输出监测器,会调用 sb.put_actual(...)
            end

            // 主测试序列
            run_test_sequence();
        join

        // 等待测试结束
        #100ns;
        sb.report(); // 打印最终裁决报告
        $finish;
    end

    // 输入监测器任务示例
    task input_monitor_task();
        axi_stream_transaction tr;
        forever begin
            // 捕捉DUT输入接口上的事务...
            @(posedge vif.clk iff (vif.tvalid && vif.tready));
            tr = new();
            tr.tdata = vif.tdata;
            tr.tlast = vif.tlast;
            tr.id = some_id++; // ID自增
            // 将事务送入记分板的预期队列
            sb.put_expected(tr);
        end
    endtask
    // 输出监测器任务类似,调用 sb.put_actual(tr)
    // ...
endmodule

四、还想更厉害?这些进阶技巧了解一下

  • 处理乱序与延迟:上面的简易记分板假设数据顺序不变。如果你的DUT可能会打乱顺序输出,就需要在事务类里加入唯一ID(比如序列号),然后记分板内部使用关联数组,按照ID来存储和匹配预期数据。
  • 拥抱UVM框架:对于大型项目,强烈推荐使用UVM。它内置了强大的uvm_scoreboarduvm_in_order_comparator等组件,以及uvm_tlm_analysis_fifo用于通信,能让你搭记分板事半功倍,复用性也极高。
  • FPGA环境特别考量:在FPGA原型验证时,你可能会想把部分验证组件(比如比较器)用可综合的代码实现,并放到FPGA里做实时检查。这时候,可一定要注意你的代码风格必须是可综合的哦!
  • 关注性能与内存:如果是长时间、大数据量的测试,要注意管理邮箱或队列的深度,别把内存撑爆了。可以考虑把比较结果实时记录到文件里,而不是全部缓存在内存中。

五、总结一下

看,记分板其实就是构建自动化、自检型验证环境的基石。通过今天的学习,我们利用SystemVerilog的OOP特性,从零开始搭建了一个用于AXI-Stream FIFO的简易记分板,涵盖了事务定义、数据传递、比较逻辑和结果报告的全流程。

掌握了这个基础框架,你就可以举一反三,根据具体设计(比如要处理乱序、多通道或者更复杂的协议)去扩展和优化你的“智能裁判”了。

在成电国芯的FPGA高级验证课程中,我们会带你更深入地探索如何基于UVM搭建工业级的验证平台,涵盖覆盖率收集、断言(SVA)、寄存器模型(RAL)等高级主题。我们的目标是帮助你从一名FPGA设计者,成长为能应对复杂芯片验证挑战的验证专家。期待与你一起,在验证的领域里玩出更多花样!

标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/29354.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
19418.52W7.05W34.38W
分享:
成电国芯FPGA赛事课即将上线
SystemVerilog for FPGA:面向对象编程在验证中的高效应用
SystemVerilog for FPGA:面向对象编程在验证中的高效应用上一篇
解放双手!用自动生成搞定FPGA的AXI4-Lite接口下一篇
解放双手!用自动生成搞定FPGA的AXI4-Lite接口
相关文章
总数:194
FPGA基础及CPLD与FPGA核心差异解析

FPGA基础及CPLD与FPGA核心差异解析

一、FPGA是什么FPGA是可编程逻辑门阵列(Field-Pro…
技术分享, 行业资讯
2个月前
0
0
138
0
I2C, UART和SPI 三种串口

I2C, UART和SPI 三种串口

基本理论知识i. 并行通信/串行通信ii.&n…
技术分享, 资源分享
8个月前
0
0
351
0
成电国芯 FPGA 专题课 | 光纤 GTP+PCIe 高速接口课程上线了,赶快来约课吧

成电国芯 FPGA 专题课 | 光纤 GTP+PCIe 高速接口课程上线了,赶快来约课吧

——成电国芯FPGA专题课|光纤GTP+PCIe高速接口课程…
技术分享
1年前
0
0
651
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容