Verilog算术单元模块输出为'Z'而非数值的问题排查求助
Verilog算术单元输出'Z'问题排查与修复
核心错误点
全加器逻辑实现错误
原full_adder用两个半加器级联的方式完全错误,输出的sum和carry不符合全加器的数学逻辑,导致加法计算彻底失效。加法链布线逻辑混乱
- 全加器端口映射错误:原代码将前一级的
sum作为下一级全加器的输入,而非将前一级的进位输出作为下一级的进位输入,完全违背加法器级联的基本逻辑。 - 共享进位信号引发多驱动冲突:所有加法单元共用同一根
carry_outwire,多个模块同时驱动同一线网会导致信号冲突,出现不确定值或高阻态。
- 全加器端口映射错误:原代码将前一级的
sum数组大量位悬空
sum[3]到sum[14]没有任何逻辑驱动,这些位处于高阻'Z'状态,导致整个sum总线包含'Z',赋值给result后输出自然为'Z'。difference信号未定义
difference仅声明但未实现任何减法逻辑,若选择减法操作(2'b01)同样会输出'Z'。fa16连接错误
将sum[15]同时作为全加器的输入和输出,造成线网短路,逻辑完全无效。
修正后的完整代码
1. 半加器(逻辑正确,保留)
module half_adder ( input a, input b, output sum, output carry ); assign sum = a ^ b; assign carry = a & b; endmodule
2. 修正全加器逻辑
module full_adder ( input a, input b, input c_in, output sum, output carry ); // 符合数学逻辑的全加器实现 assign sum = a ^ b ^ c_in; assign carry = (a & b) | (a & c_in) | (b & c_in); endmodule
3. 重构算术单元模块
module arithmetic_unit ( input [15:0] a, input [15:0] b, input [1:0] operation, output reg [31:0] result ); wire [15:0] sum, difference; wire [15:0] add_carry; // 加法链的每一级进位信号 // 16位加法器级联实现 half_adder ha_add0 (a[0], b[0], sum[0], add_carry[0]); genvar i; generate for(i=1; i<16; i=i+1) begin : add_stages full_adder fa_add (a[i], b[i], add_carry[i-1], sum[i], add_carry[i]); end endgenerate // 补码减法实现:a - b = a + (~b + 1) wire [15:0] b_neg = ~b + 1'b1; wire [15:0] sub_carry; half_adder ha_sub0 (a[0], b_neg[0], difference[0], sub_carry[0]); generate for(i=1; i<16; i=i+1) begin : sub_stages full_adder fa_sub (a[i], b_neg[i], sub_carry[i-1], difference[i], sub_carry[i]); end endgenerate // 组合逻辑使用阻塞赋值更规范 always @* begin case(operation) 2'b00: result = {16'b0, sum}; // 将16位结果扩展为32位输出 2'b01: result = {16'b0, difference}; 2'b10: result = a * b; // Verilog原生支持乘法,自动处理位数匹配 2'b11: result = a / b; default: result = 32'b0; endcase end endmodule
4. 增强测试平台(覆盖多场景)
module test_arithmetic_unit; reg [15:0] a, b; reg [1:0] operation; wire [31:0] result; arithmetic_unit au (a, b, operation, result); initial begin // 加法测试 a <= 10; b <= 5; operation <= 2'b00; #10; $display("加法: %d + %d = %d", a, b, result); // 减法测试 a <= 10; b <= 5; operation <= 2'b01; #10; $display("减法: %d - %d = %d", a, b, result); // 乘法测试 a <= 10; b <= 5; operation <= 2'b10; #10; $display("乘法: %d * %d = %d", a, b, result); // 除法测试 a <= 10; b <= 5; operation <= 2'b11; #10; $display("除法: %d / %d = %d", a, b, result); $finish; end endmodule
关键说明
- 用
generate语句实现16位加法/减法链,避免重复代码,确保每一位都被正确驱动,无悬空信号。 - 减法通过补码方式复用加法器,减少逻辑冗余。
- 组合逻辑
always @*块使用阻塞赋值=,符合Verilog编码规范,避免不必要的时序问题。 - 将16位运算结果扩展为32位输出,避免位数截断导致的错误。
内容的提问来源于stack exchange,提问作者Ayman Eid
相关产品推荐
相关产品推荐

