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

SystemVerilog浮点比较器Testbench输出始终为x问题排查求助

问题描述

我实现了一个遵循IEEE 764标准的浮点数比较模块compare_fp,输出规则为:相等时输出2,A>B时输出1,A<B时输出0。参考文档编写结构化SystemVerilog Testbench后,输出compareRes始终为x;但手动指定输入的简易Testbench可正常运行,怀疑是Testbench数值传递存在问题,请求调试建议。

相关代码

浮点数比较模块compare_fp

// IEEE 764: FP[31] = 符号位, FP[30:23] = 指数位, FP[22:0] = 尾数位
module compare_fp(input [31:0] floatA,
                  input [31:0] floatB,
                  output reg [1:0] compareRes);
  
  // 相等: 2, A>B: 1, A<B: 0
  
  assign compareRes[1] = (floatA == floatB); // 相等时设置输出MSB为1
  // A>B时设置输出LSB为1
  // 1. A>0, B<0 
  // 2. 符号相同,比较指数
  // 3. 符号和指数相同,比较尾数
  assign compareRes[0] = ((!floatA[31]) && floatB[31]) || 
    (((floatA[31] & floatB[31]) == 1) && (floatA[30:23] < floatB[30:23])) ||
    (((floatA[31] | floatB[31]) == 0) && (floatA[30:23] > floatB[30:23])) ||
    (((floatA[31] & floatB[31]) == 1) && (floatA[30:23] == floatB[30:23]) && (floatA[22:0] < floatB[22:0])) ||
    (((floatA[31] | floatB[31]) == 0) && (floatA[30:23] == floatB[30:23]) && (floatA[22:0] > floatB[22:0]));
    
endmodule

结构化SystemVerilog Testbench

// 事务类
class transaction;
 
  randc bit [31:0] floatA;
  randc bit [31:0] floatB;
  logic [1:0] compareRes;
  
  // 实际浮点数值
  shortreal float_A;
  shortreal float_B;  
  
  function void display(string name);
    $display("---------");
    $display("%s",name);
    $display("a = %0f, b = %0f, result = %0d", float_A, float_B, compareRes);
    $display("a = %0b, b = %0b, result = %0d", floatA, floatB, compareRes);
    $display("---------");
    
  endfunction
  
endclass

// 生成器类
class generator;
  rand transaction trans;
  mailbox gen2drv;
  event ended;
  int generateCount; // 测试用例数量
  
  function new(mailbox gen2drv);
    this.gen2drv = gen2drv;
  endfunction
  
  task main();
    
    repeat(generateCount) begin
        // 创建并随机化事务
        trans = new();
        if( !trans.randomize()) $fatal("gen: 事务随机化失败");
        // 转换为实际浮点数
        trans.float_A = $bitstoshortreal(trans.floatA);
        trans.float_B = $bitstoshortreal(trans.floatB);
        gen2drv.put(trans);  
    end
    -> ended; // 生成结束
  endtask
  
endclass

// 接口定义
interface intf;
  bit [31:0] floatA;
  bit [31:0] floatB;
  logic [1:0] compareRes;
endinterface

// 驱动器类
class driver;
  int transaction_count;
  mailbox gen2drv;
  virtual intf vif;
  
  // 构造函数
  function new(virtual intf vif, mailbox gen2drv);
    this.vif = vif;
    this.gen2drv = gen2drv;
  endfunction
  
  task main;
    forever begin
      transaction trans;
      gen2drv.get(trans);
      vif.floatA = trans.floatA;
      vif.floatB = trans.floatB;
      trans.display("[ Driver ]");
      transaction_count++;
    end
    
  endtask
  
endclass

// 环境类
class environment;
  generator gen;
  driver drv;
  mailbox gen2drv;
  virtual intf vif;
  
  //构造函数
  function new(virtual intf vif);
    this.vif = vif;
    gen2drv = new();
    gen = new(gen2drv);
    drv = new(vif, gen2drv);
  endfunction
  
  task test();
    fork
      gen.main();
      drv.main();
    join_any
  endtask
  
  task post_test();
    wait(gen.ended.triggered);
    wait(gen.generateCount == drv.transaction_count);
  endtask
  
  task run;
    test();
    post_test();
    $finish;
  endtask
  
endclass

// 测试程序
program test(intf intf);
  
  environment env;
  
  initial begin
    env = new(intf);
    env.gen.generateCount = 3;
    env.run();
  end

endprogram

// 测试顶层模块
module tb;
  
  intf intf1();
  
  test t1(intf1);
  
  compare_fp dut (.floatA(intf1.floatA), .floatB(intf1.floatB), .compareRes(intf1.compareRes));
  
endmodule

可正常运行的简易Testbench

// 接口定义
interface test;

  logic [31:0] floatA;
  logic [31:0] floatB;
  logic [1:0] compareRes;

endinterface

// 测试顶层模块
module tb;
    test st();
    shortreal float_A;
    shortreal float_B;

  
  compare_fp dut(.floatA(st.floatA), .floatB(st.floatB), .compareRes(st.compareRes));
  
    
    initial begin
      #10 st.floatA = 32'b11000000010101001100000001011001;
      #10 st.floatB = 32'b01000000010101000111101011100001;
      #10 float_A = $bitstoshortreal(st.floatA);
      #10 float_B = $bitstoshortreal(st.floatB);

      #10 $display("%f %f is %0d", float_A, float_B, st.compareRes);
    end
  

endmodule
调试建议

1. 修复compare_fp模块的输出驱动错误

模块中compareRes声明为reg类型,却使用assign语句驱动,这是SystemVerilog的非法语法:reg类型只能在always/initial等过程块中赋值,assign仅用于驱动wire类型。该错误会直接导致驱动冲突,输出始终为x。

修改模块输出类型:

module compare_fp(input [31:0] floatA,
                  input [31:0] floatB,
                  output wire [1:0] compareRes); // 将reg改为wire
  // 其余代码不变
endmodule

2. 修正Testbench中compareRes的采样逻辑

结构化Testbench中,transaction类的compareRes从未被赋值,且driver设置输入后直接调用display,此时DUT输出尚未稳定,也未将接口的compareRes传递到事务对象中。

修改driver的main任务:

task main;
  forever begin
    transaction trans;
    gen2drv.get(trans);
    // 设置输入信号
    vif.floatA = trans.floatA;
    vif.floatB = trans.floatB;
    // 等待DUT输出稳定
    #1;
    // 将DUT输出采样到事务对象中
    trans.compareRes = vif.compareRes;
    // 此时打印结果才正确
    trans.display("[ Driver ]");
    transaction_count++;
  end
endtask

3. 移除generator类中多余的rand修饰

generator类中rand transaction trans;的rand修饰完全多余,transaction类本身已包含随机变量,该修饰会引发不必要的随机化问题,直接移除即可:

class generator;
  transaction trans; // 移除rand修饰
  // 其余代码不变
endclass

4. 可选优化:初始化接口信号

接口intf中的floatA/floatB为bit类型,初始值为0,随机化后会被覆盖,但可在driver中添加初始值设置,避免仿真初期的不确定状态:

task main;
  // 初始化接口信号
  vif.floatA = 0;
  vif.floatB = 0;
  forever begin
    // 其余代码不变
  end
endtask
验证修改效果

完成上述修改后重新仿真,结构化Testbench的compareRes应能正确显示DUT的输出结果,与简易Testbench表现一致。

内容的提问来源于stack exchange,提问作者Zoey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:24:50