Verilog带符号数编写、测试bench输入及8位2补码加法器溢出问题排查
Verilog带符号数编写、测试bench输入及8位2补码加法器溢出问题排查
Hey Jason,我仔细看了你编写的8位2补码加法器代码和遇到的测试问题,咱们逐个击破:
一、测试Bench中负数显示为无符号数值的问题
你提到测试时负数(比如-23)被显示成无符号的233,这其实是仿真工具显示格式或者缺少带符号打印语句导致的——你已经用了reg signed [7:0]定义变量,变量本身是带符号的,只是没正确输出/显示而已。
解决方法很简单:在测试bench的initial块里添加带格式的$display语句,明确指定用带符号十进制格式打印,比如:
// 在每个#10之后添加打印逻辑 // Test 1 A = 5; B = 10; carry_in = 0; #10; $display("Test 1: A = %0d, B = %0d, Sum = %0d, Overflow E = %b", A, B, S, E); // Test 2 A = 87; B = -23; carry_in = 0; #10; $display("Test 2: A = %0d, B = %0d, Sum = %0d, Overflow E = %b", A, B, S, E); // 后续测试用例同理添加
这里的%0d是Verilog中带符号十进制的格式符,工具会正确解析signed变量的数值,不会把二进制按无符号数转换。另外,如果你用波形窗口观察,也可以手动设置变量的显示格式为「带符号十进制」或者「2补码」,不同仿真工具的操作略有差异,但都支持这个功能。
二、加法器核心代码的致命错误(进位链连接错误)
你的ripple_adder模块里,全加器的进位输入完全接错了!从FA1到FA6,你都把顶层的carry_in(初始进位)作为输入,而不是前一级全加器的carry_out,这导致整个加法器根本不是行波进位加法器,计算结果完全错误。
修正后的ripple_adder模块代码:
module ripple_adder (A, B, carry_in, sum, carry_out, E); input signed [7:0] A; input signed [7:0] B; input carry_in; output signed [7:0] sum; output carry_out; output E; wire [6:0] carry; // 正确的进位链连接:每一级的carry_in是前一级的carry_out Full_Adder FA0(A[0], B[0], carry_in, sum[0], carry[0]); Full_Adder FA1(A[1], B[1], carry[0], sum[1], carry[1]); // 替换为前一级进位carry[0] Full_Adder FA2(A[2], B[2], carry[1], sum[2], carry[2]); // 替换为前一级进位carry[1] Full_Adder FA3(A[3], B[3], carry[2], sum[3], carry[3]); // 替换为前一级进位carry[2] Full_Adder FA4(A[4], B[4], carry[3], sum[4], carry[4]); // 替换为前一级进位carry[3] Full_Adder FA5(A[5], B[5], carry[4], sum[5], carry[5]); // 替换为前一级进位carry[4] Full_Adder FA6(A[6], B[6], carry[5], sum[6], carry[6]); // 替换为前一级进位carry[5] Full_Adder FA7(A[7], B[7], carry[6], sum[7], carry_out); // 替换为前一级进位carry[6] // 溢出判断逻辑是正确的:最高位进位和次高位进位异或 assign E = ((carry_out & ~carry[6]) | (~carry_out & carry[6])); endmodule
三、全加器模块的小优化
你的Full_Adder模块里,把carry_in和carry_out定义成signed是没必要的——单bit信号在Verilog里signed和unsigned没有区别,改成普通input/output即可,不影响功能但更规范:
module Full_Adder (A, B, carry_in, sum, carry_out); input signed A, B; input carry_in; // 去掉signed修饰 output signed sum; output carry_out; // 去掉signed修饰 assign sum = (A^B^carry_in); assign carry_out = ((A&B) | (B&carry_in) | (carry_in&A)); endmodule
四、验证溢出功能的测试用例补充
你可以添加专门测试溢出/下溢的用例,确保E信号能正确触发:
- 正数相加溢出:
A = 127,B = 1(8位2补码最大正数是127,加1会溢出到-128) - 负数相加下溢:
A = -128,B = -1(8位2补码最小负数是-128,减1会下溢到127)
备注:内容来源于stack exchange,提问作者Jason Nababan




