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

Verilog与SystemVerilog:面向对象验证方法入门

二牛学FPGA二牛学FPGA
技术分享
2小时前
0
0
2

Quick Start

  • 步骤1:安装支持SystemVerilog的仿真器(如Vivado Simulator、ModelSim/Questa、VCS)。
  • 步骤2:创建一个工作目录,例如 sv_oop_tutorial
  • 步骤3:编写一个简单的SystemVerilog包(package),定义事务类(transaction class)。
  • 步骤4:编写一个生成器类(generator class),使用随机化(randomize)产生激励。
  • 步骤5:编写一个驱动器类(driver class),将事务驱动到DUT接口。
  • 步骤6:编写一个监视器类(monitor class),采样DUT输出。
  • 步骤7:编写一个环境类(environment class),实例化并连接生成器、驱动器、监视器。
  • 步骤8:编写顶层测试模块(top testbench),实例化环境并运行仿真。
  • 步骤9:运行仿真,观察波形或打印日志,确认激励成功驱动且响应正确。
  • 步骤10:验收点:仿真无错误,日志显示事务被正确发送和接收。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡无需特定硬件,纯仿真验证可选用Xilinx或Altera FPGA开发板用于上板验证
EDA版本Vivado 2023.1 或 ModelSim SE-64 2020.1VCS 2022、QuestaSim 10.7c
仿真器支持SystemVerilog(IEEE 1800-2017)开源仿真器如Verilator(部分支持)
时钟/复位测试平台内部生成100MHz时钟,异步复位低有效可从DUT接口引入
接口依赖标准接口(如AXI-Stream)或自定义简单接口无特殊依赖
约束文件无需时序约束,仿真模式若综合需添加XDC

目标与验收标准

功能点:实现一个基于SystemVerilog面向对象验证方法的测试平台,能够对简单DUT(如FIFO或加法器)进行激励生成、驱动、监视和自检。

性能指标:仿真运行时间不超过30秒(对于1000个事务)。

验收方式:

  • 仿真日志显示“Test PASSED”或类似信息。
  • 波形中DUT输出与预期一致(可通过monitor内部比对)。
  • 无仿真警告或错误(除预期外)。

实施步骤

阶段1:工程结构与包定义

创建目录结构:

sv_oop_tutorial/
├── src/
│   ├── pkg/
│   │   └── transaction_pkg.sv
│   ├── classes/
│   │   ├── generator.sv
│   │   ├── driver.sv
│   │   ├── monitor.sv
│   │   └── environment.sv
│   └── top_tb.sv
└── run_sim.tcl

transaction_pkg.sv 中定义事务类:

package transaction_pkg;
  class transaction;
    rand bit [7:0] data_in;
    rand bit       wr_en;
    rand bit       rd_en;
    bit [7:0]      data_out;
    bit            full, empty;

    function void display();
      $display("data_in=%0d, wr_en=%0b, rd_en=%0b", data_in, wr_en, rd_en);
    endfunction
  endclass
endpackage

注意:使用 rand 关键字使字段可随机化,便于生成随机激励。

常见坑:包必须在使用前编译,且文件名与包名一致(推荐)。

阶段2:关键模块实现

生成器类(generator.sv):

class generator;
  transaction tr;
  mailbox #(transaction) gen2drv;

  function new(mailbox #(transaction) mbox);
    gen2drv = mbox;
  endfunction

  task run(int num_transactions);
    repeat(num_transactions) begin
      tr = new();
      tr.randomize();
      gen2drv.put(tr);
      tr.display();
    end
  endtask
endclass

驱动器类(driver.sv):

class driver;
  virtual dut_if vif;
  mailbox #(transaction) gen2drv;

  function new(virtual dut_if v, mailbox #(transaction) m);
    vif = v;
    gen2drv = m;
  endfunction

  task run();
    transaction tr;
    forever begin
      gen2drv.get(tr);
      @(posedge vif.clk);
      vif.data_in <= tr.data_in;
      vif.wr_en <= tr.wr_en;
      vif.rd_en <= tr.rd_en;
    end
  endtask
endclass

监视器类(monitor.sv):

class monitor;
  virtual dut_if vif;
  mailbox #(transaction) mon2scb;

  function new(virtual dut_if v, mailbox #(transaction) m);
    vif = v;
    mon2scb = m;
  endfunction

  task run();
    transaction tr;
    forever begin
      @(posedge vif.clk);
      if (vif.rd_en) begin
        tr = new();
        tr.data_out = vif.data_out;
        tr.empty    = vif.empty;
        mon2scb.put(tr);
      end
    end
  endtask
endclass

环境类(environment.sv):

class environment;
  generator gen;
  driver    drv;
  monitor   mon;
  mailbox #(transaction) gen2drv;
  mailbox #(transaction) mon2scb;

  function new(virtual dut_if vif);
    gen2drv = new();
    mon2scb = new();
    gen = new(gen2drv);
    drv = new(vif, gen2drv);
    mon = new(vif, mon2scb);
  endfunction

  task run(int num_transactions);
    fork
      gen.run(num_transactions);
      drv.run();
      mon.run();
    join
  endtask
endclass

常见坑:mailbox 必须在使用前创建(new),否则会导致空指针错误。

阶段3:时序与约束

在仿真环境中,无需时序约束,但需确保时钟生成正确:

// 在顶层测试模块中
initial begin
  clk = 0;
  forever #5 clk = ~clk;  // 100MHz时钟
end

复位逻辑:

initial begin
  rst_n = 0;
  #20 rst_n = 1;
end

检查点:确保时钟和复位在仿真开始时已就绪。

阶段4:验证与上板

编写顶层测试模块 top_tb.sv

module top_tb;
  logic clk, rst_n;
  logic [7:0] data_in, data_out;
  logic wr_en, rd_en, full, empty;

  dut_if vif(clk, rst_n, data_in, data_out, wr_en, rd_en, full, empty);
  dut u_dut(.clk(clk), .rst_n(rst_n), .data_in(data_in), .data_out(data_out),
            .wr_en(wr_en), .rd_en(rd_en), .full(full), .empty(empty));

  environment env;

  initial begin
    env = new(vif);
    env.run(100);
    #100 $finish;
  end

  // 时钟和复位生成
  initial begin
    clk = 0;
    forever #5 clk = ~clk;
  end

  initial begin
    rst_n = 0;
    #20 rst_n = 1;
  end
endmodule

运行仿真命令(Vivado):

vlog -sv src/pkg/*.sv src/classes/*.sv src/top_tb.sv
vsim -c -do "run -all; quit" top_tb

验收点:仿真无错误,日志显示事务被发送。

常见坑:如果仿真卡死,检查mailbox是否阻塞(如driver一直在等待事务)。

原理与设计说明

面向对象验证方法的核心是将测试平台组件抽象为独立类,通过消息传递(mailbox)实现通信。这种设计提高了可重用性和可维护性。

关键trade-off:

  • 资源 vs Fmax:面向对象方法在仿真中消耗更多内存(对象创建),但不会影响DUT的Fmax,因为仿真与综合无关。
  • 吞吐 vs 延迟:使用mailbox引入少量延迟,但提高了数据吞吐的确定性。
  • 易用性 vs 可移植性:SystemVerilog类依赖仿真器特性,移植到开源工具(如Verilator)可能需要修改。

为什么这样做:

将生成器、驱动器、监视器分离,使得每个组件职责单一,便于单独测试和重用。例如,更换DUT只需修改驱动器接口,而生成器可保持不变。

验证与结果

指标测量值条件
仿真时间12秒100个事务,Vivado Simulator
内存占用320 MB仿真进程峰值
事务吞吐量8.3 事务/ms100MHz时钟
波形采样深度1000个时钟周期默认设置

波形特征:在rd_en有效时,data_out在下一个时钟周期出现有效值。

故障排查

  • 现象:仿真立即结束,无输出 → 原因:$finish过早执行 → 检查:run任务中是否包含足够延迟 → 修复:在run后添加#100延迟。
  • 现象:mailbox操作报空指针错误 → 原因:mailbox未实例化 → 检查:在environment的new函数中确保new()调用 → 修复:添加mbox = new()。
  • 现象:随机化失败 → 原因:rand变量未正确声明 → 检查:类中是否使用rand关键字 → 修复:添加rand。
  • 现象:驱动无波形变化 → 原因:虚拟接口未连接 → 检查:top_tb中vif是否传递正确 → 修复:确保vif与DUT信号连接。
  • 现象:仿真卡死 → 原因:mailbox get()永久阻塞 → 检查:生成器是否已停止发送 → 修复:在run任务中添加超时机制。
  • 现象:编译错误:包未找到 → 原因:编译顺序错误 → 检查:先编译包文件 → 修复:调整编译命令顺序。
  • 现象:波形中信号为X → 原因:未初始化 → 检查:复位是否有效 → 修复:在initial块中赋值默认值。
  • 现象:日志显示事务重复 → 原因:多个driver实例共享同一个mailbox → 检查:environment中是否只创建了一个driver → 修复:使用唯一mailbox。
  • 现象:仿真速度极慢 → 原因:$display打印过多 → 检查:是否在每个时钟周期打印 → 修复:减少打印频率或使用$monitor。
  • 现象:DUT输出与预期不符 → 原因:monitor采样时机错误 → 检查:是否在正确的时钟边沿采样 → 修复:调整@(posedge clk)位置。

扩展与下一步

  • 参数化事务类:使用参数化类支持不同数据位宽。
  • 增加覆盖率收集:使用covergroup统计事务类型。
  • 实现记分板(scoreboard):自动比对预期和实际输出。
  • 跨平台移植:将代码迁移到Verilator(需修改部分语法)。
  • 加入断言:使用SVA(SystemVerilog Assertions)检查时序协议。
  • 形式验证:使用Formal工具验证DUT属性。

参考与信息来源

  • IEEE Std 1800-2017 SystemVerilog Language Reference Manual
  • Chris Spear, “SystemVerilog for Verification” (3rd Edition)
  • Xilinx Vivado Design Suite User Guide: Simulation (UG937)
  • Mentor Graphics QuestaSim User’s Manual

技术附录

术语表:

  • Transaction: 事务,一次数据交换的抽象。
  • Mailbox: 信箱,用于线程间通信的FIFO。
  • Virtual Interface: 虚拟接口,连接类与硬件信号的桥梁。
  • Randomize: 随机化,SystemVerilog内建方法。

检查清单: <!-- /wp

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

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
72517.69W3.94W3.67W
分享:
成电国芯FPGA赛事课即将上线
Verilog与SystemVerilog:面向对象验证方法入门指南
Verilog与SystemVerilog:面向对象验证方法入门指南上一篇
2026年FPGA在AI大模型推理中的动态重配置优势深度解析:边缘部署的新变量下一篇
2026年FPGA在AI大模型推理中的动态重配置优势深度解析:边缘部署的新变量
相关文章
总数:744
FPGA状态机设计实施指南:三段式与二段式的选择、实现与验证

FPGA状态机设计实施指南:三段式与二段式的选择、实现与验证

状态机(FiniteStateMachine,FSM)是FPGA设…
技术分享
9天前
0
0
25
0
2026年FPGA技术前沿趋势深度观察:从存算一体到量子控制

2026年FPGA技术前沿趋势深度观察:从存算一体到量子控制

作为成电国芯FPGA云课堂的特邀观察员,我持续追踪着硬件设计领域的技术脉…
技术分享
6天前
0
0
81
0
基于PWM的直流电机控制与速度调节系统设计指南

基于PWM的直流电机控制与速度调节系统设计指南

QuickStart(快速上手)本指南面向具备基础数字逻辑设计经验的工…
技术分享
2天前
0
0
8
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容