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
相关产品推荐
相关产品推荐

