You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二进制转格雷码模块仿真验证失败:输出不匹配问题排查

问题:SystemVerilog测试平台中DUT输出与Scoreboard预期格雷码不匹配

基于SystemVerilog搭建了包含driver、monitor和scoreboard的测试平台环境,在Synopsys VCS仿真过程中,被测器件(DUT)输出的gray信号频繁与scoreboard计算的预期格雷码不匹配。

相关代码实现

Design Module

`timescale 1ns / 1ps
module binary_to_gray(input [3:0] binary, output [3:0] gray);
  assign gray[3] = binary[3];                  // MSB remains the same
  assign gray[2] = binary[3] ^ binary[2];      // XOR for bit 2
  assign gray[1] = binary[2] ^ binary[1];      // XOR for bit 1
  assign gray[0] = binary[1] ^ binary[0];      // XOR for bit 0
endmodule

Top_Testbench Module

`timescale 1ns / 1ps
`include "interface.sv"
`include "test"

module top_tb;             // Top-level testbench module
  intf i_intf(); // Interface instantiation
  test t1(i_intf); // Test instantiation

  // Instantiate the DUT (Device Under Test)
  binary_to_gray DUT(
    .binary(i_intf.binary),
    .gray(i_intf.gray)
  );
endmodule

Environment Module

`timescale 1ns / 1ps
`include "transaction.sv"
`include "generator.sv"
`include "driver.sv"
`include "monitor"
`include "scoreboard"
class environment;
  generator gen;
  driver driv;
  monitor mon;
  scoreboard scb;
  mailbox m1, m2;
  virtual intf vif;

  function new(virtual intf vif);
    this.vif = vif;
    m1 = new();
    m2 = new();
    gen = new(m1);
    driv = new(vif, m1);
    mon = new(vif, m2);
    scb = new(m2);
  endfunction

  task test();
    fork
      gen.main();
      driv.main();
      mon.main();
      scb.main();
    join
  endtask
endclass

Driver Module

`timescale 1ns / 1ps
class driver;
  virtual intf vif;
  mailbox gen2driv;

  function new(virtual intf vif, mailbox gen2driv);
    this.vif = vif;
    this.gen2driv = gen2driv;
  endfunction

  task main();
  transaction trans;
  repeat(5) begin
    gen2driv.get(trans);       // Receive transaction
    vif.binary = trans.binary; // Drive input to DUT
    #10;                       // Increased propagation delay
    trans.gray = vif.gray;     // Capture output
    trans.display("Driver");
  end
endtask
endclass

Generator Module

`timescale 1ns / 1ps
class generator;
  transaction trans;
  mailbox gen2driv;

  function new(mailbox gen2driv);
    this.gen2driv = gen2driv;
  endfunction

  task main();
    repeat(5) begin
      trans = new();
      if (!trans.randomize()) $error("Failed to randomize transaction!");
      trans.display("Generator");
      gen2driv.put(trans);       // Send transaction to driver
    end
  endtask
endclass

Interface Module

`timescale 1ns / 1ps
interface intf();
  logic [3:0] binary;
  logic [3:0] gray;
endinterface

Transaction Module

`timescale 1ns / 1ps
class transaction;
  rand bit [3:0] binary; // Randomizable binary input
  bit [3:0] gray;        // Output to store Gray code

  function void display(string name);
    $display("--------------------------");
    $display("%s", name);
    $display("--------------------------");
    $display("Binary = %b", binary);
    $display("Gray = %b", gray);
    $display("--------------------------");
  endfunction
endclass

Test Module

`timescale 1ns / 1ps
`include "environment.sv"

program test(intf i_intf);
  environment env;

  initial begin
    env = new(i_intf);
    env.test();
    $finish;
  end
endprogram

Monitor Module

`timescale 1ns / 1ps

class monitor;
  virtual intf vif;        // Virtual interface for DUT connections
  mailbox mon2scb;         // Mailbox to send transactions to the scoreboard

  // Constructor
  function new(virtual intf vif, mailbox mon2scb);
    this.vif = vif;
    this.mon2scb = mon2scb;
  endfunction

  // Main task to observe DUT behavior
task main();
  transaction trans;
  repeat(5) begin
    #10;                       // Increased propagation delay (align with Driver)
    trans = new();             // Initialize the transaction object
    trans.binary = vif.binary; // Capture binary input
    trans.gray = vif.gray;     // Capture Gray code output
    trans.display("Monitor");  // Display the transaction details
    mon2scb.put(trans);        // Send the transaction to the scoreboard
  end
endtask

endclass

Scoreboard Module

`timescale 1ns / 1ps
class scoreboard;
  mailbox mon2scb;
  logic [3:0] expected_gray; // Declare at the class level

  function new(mailbox mon2scb);
    this.mon2scb = mon2scb;
  endfunction

  task main();
    transaction trans;
    repeat(5) begin
      mon2scb.get(trans);        // Receive transaction
      expected_gray[3] = trans.binary[3];
      expected_gray[2] = trans.binary[3] ^ trans.binary[2];
      expected_gray[1] = trans.binary[2] ^ trans.binary[1];
      expected_gray[0] = trans.binary[1] ^ trans.binary[0];

      if (trans.gray == expected_gray)
        $display("PASS: Binary = %b, Gray = %b", trans.binary, trans.gray);
      else
        $error("FAIL: Binary = %b, Expected Gray = %b, DUT Gray = %b",
                trans.binary, expected_gray, trans.gray);
    end
  endtask
endclass

错误示例

FAIL: Binary = 1111, Expected Gray = 1000, DUT Gray = 1100
FAIL: Binary = 0001, Expected Gray = 0001, DUT Gray = 1100

补充信息:仿真工具为Synopsys VCS,所有模块通过虚拟接口实例化连接,错误在不同二进制输入下表现不一致。


问题根源分析

  1. Driver与Monitor的时序不同步:Driver先驱动输入,等待10ns后采样;而Monitor启动后直接等待10ns就采样,两者采样动作无同步机制。由于fork并行执行,Monitor的#10可能在Driver更新输入前触发,导致采到上一周期的DUT输出或未稳定信号。
  2. 竞态条件导致采样错误:Environment中四个任务(gen、driv、mon、scb)并行启动,Monitor采样与Driver驱动无依赖关系,无法保证采样的是当前输入对应的输出。
  3. DUT实现无问题:DUT的二进制转格雷码逻辑符合标准算法,Scoreboard预期值计算也正确,问题不在DUT本身。

修复方案

1. 用事件同步Driver与Monitor的采样动作

在接口中添加同步事件,Driver完成输入驱动并等待稳定后触发事件,Monitor等待该事件后再采样,确保采样时机正确。

修改Interface模块

`timescale 1ns / 1ps
interface intf();
  logic [3:0] binary;
  logic [3:0] gray;
  event drv_done; // 添加同步事件
endinterface

修改Driver的main任务

task main();
  transaction trans;
  repeat(5) begin
    gen2driv.get(trans);       // 接收事务
    vif.binary = trans.binary; // 驱动DUT输入
    #10;                       // 等待DUT输出稳定
    ->vif.drv_done;             // 触发事件通知Monitor可以采样
    trans.gray = vif.gray;     // 捕获输出
    trans.display("Driver");
  end
endtask

修改Monitor的main任务

task main();
  transaction trans;
  repeat(5) begin
    @(vif.drv_done);            // 等待Driver触发的同步事件
    trans = new();             // 初始化事务对象
    trans.binary = vif.binary; // 捕获当前输入
    trans.gray = vif.gray;     // 捕获对应稳定输出
    trans.display("Monitor");  // 显示事务信息
    mon2scb.put(trans);        // 发送到Scoreboard
  end
endtask

2. 可选:调整任务启动顺序(辅助优化)

在Environment的test任务中,先启动Generator确保第一个事务进入mailbox后,再启动Driver和Monitor,避免Driver初始阻塞:

task test();
  fork
    begin
      gen.main(); // 先启动Generator产生事务
    end
    begin
      driv.main();
      mon.main();
      scb.main();
    end
  join
endtask

修复效果说明

修改后,Monitor会严格在Driver完成输入驱动并等待DUT输出稳定后采样,确保每次采样的都是当前输入对应的正确格雷码输出,Scoreboard预期值与DUT输出将完全匹配,解决不匹配问题。

内容的提问来源于stack exchange,提问作者Kotupalli Venkata Siva Teja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:54:50