16位ALU故障:操作码alu_code变更后输出C始终不变
问题
编写16位ALU时,代码编译成功,但操作码alu_code变更时,输出结果C始终保持首次运算结果,不随操作变化。相关代码如下:
ALU代码
module ALU ( input [15:0] A, B, input [4:0] alu_code, output reg [15:0] C, output reg overflow ); wire [1:0] over; wire signed [15:0] As, Bs, Bs2s; wire signed [15:0] C_add, C_sub; wire [15:0] C_addu, C_subu; wire [15:0] B2s; wire overflow_temp; assign B2s = ~B + 1; assign As = A; assign Bs = B; assign Bs2s = ~Bs + 1; CLA add(.A(As), .B(Bs), .Sum(C_add), .overflow(overflow_temp)); CLA addu(.A(A), .B(B), .Sum(C_addu), .overflow(overflow_temp)); CLA sub(.A(As), .B(Bs2s), .Sum(C_sub), .overflow(overflow_temp)); CLA subu(.A(A), .B(B2s), .Sum(C_subu), .overflow(overflow_temp)); always @(alu_code or A or B) begin case(alu_code) 00000 : C = C_add; 00001 : C = C_addu; 00010 : C = C_sub; 00011 : C = C_subu; endcase end assign over = {overflow_temp, C[15]}; always @(*) begin if (over == 2'b01) overflow = 1; else overflow = 0; end endmodule module CLA ( input [15:0] A, B, output [15:0] Sum, output overflow ); wire c1, c2, c3; CLA4bit CLA1 (.A(A[3:0]), .B(B[3:0]), .Cin(1'b0), .Sum(Sum[3:0]), .Cout(c1)); CLA4bit CLA2 (.A(A[7:4]), .B(B[7:4]), .Cin(c1), .Sum(Sum[7:4]), .Cout(c2)); CLA4bit CLA3(.A(A[11:8]), .B(B[11:8]), .Cin(c2), .Sum(Sum[11:8]), .Cout(c3)); CLA4bit CLA4(.A(A[15:12]), .B(B[15:12]), .Cin(c3), .Sum(Sum[15:12]), .Cout(overflow)); endmodule module CLA4bit( input [3:0] A, B, input Cin, output [3:0] Sum, output Cout ); wire [3:0] P, G, C; assign P = A ^ B; assign G = A & B; assign C[0] = Cin; assign C[1] = G[0] | (P[0] & C[0]); assign C[2] = G[1] | (P[1] & G[0]) | P[1] & P[0] & C[0]; assign C[3] = G[2] | (P[2] & G[1]) | P[2] & P[1] & G[0] | P[2] & P[1] & P[0] & C[0]; assign Cout = G[3] | (P[3] & G[2]) | P[3] & P[2] & G[1] | P[3] & P[2] & P[1] & G[0] | P[3] & P[2] & P[1] & P[0] & C[0]; assign Sum = P ^ C; endmodule
测试平台代码
module tbALU(); reg [15:0] A, B; reg [4:0] alu_code; wire [15:0] C; wire overflow; ALU uut(A, B, alu_code, C, overflow); initial begin A = 8'hAA; B = 8'hAA; #50; alu_code = 0; #50; alu_code = 1; #50; alu_code = 2; #50; alu_code = 3; end endmodule
波形显示C确实不会随操作码的变更而改变。
问题分析与解决方案
核心问题点
- 信号冲突:四个
CLA实例同时驱动同一个overflow_temp信号,硬件层面会出现线与/线或冲突,导致信号值不确定,进而干扰后续逻辑。 - 敏感列表不完整:第一个
always块仅监听alu_code、A、B,但C_add、C_addu等运算结果变化时无法触发块执行,C自然不会更新。 - 溢出逻辑错误:用同一个
overflow_temp处理四种运算的溢出,逻辑完全失效,每种运算的溢出状态需要独立判断。
修改方案
- 给每个
CLA实例分配独立的溢出信号,避免信号冲突。 - 将第一个
always块改为@(*)自动敏感列表,确保所有相关信号变化时都能触发更新。 - 针对不同运算类型,在
case分支里直接绑定对应运算的溢出信号。 - 修正
CLA4bit中运算优先级的括号缺失问题,避免逻辑错误。
修改后的完整代码
module ALU ( input [15:0] A, B, input [4:0] alu_code, output reg [15:0] C, output reg overflow ); wire signed [15:0] As, Bs, Bs2s; wire signed [15:0] C_add, C_sub; wire [15:0] C_addu, C_subu; wire [15:0] B2s; // 为每个CLA实例分配独立的溢出信号 wire overflow_add, overflow_addu, overflow_sub, overflow_subu; assign B2s = ~B + 1; assign As = A; assign Bs = B; assign Bs2s = ~Bs + 1; // 每个CLA实例连接独立的溢出输出 CLA add(.A(As), .B(Bs), .Sum(C_add), .overflow(overflow_add)); CLA addu(.A(A), .B(B), .Sum(C_addu), .overflow(overflow_addu)); CLA sub(.A(As), .B(Bs2s), .Sum(C_sub), .overflow(overflow_sub)); CLA subu(.A(A), .B(B2s), .Sum(C_subu), .overflow(overflow_subu)); // 使用@(*)自动敏感列表,覆盖所有输入信号 always @(*) begin case(alu_code) 5'b00000 : begin C = C_add; overflow = overflow_add; end 5'b00001 : begin C = C_addu; overflow = overflow_addu; end 5'b00010 : begin C = C_sub; overflow = overflow_sub; end 5'b00011 : begin C = C_subu; overflow = overflow_subu; end default : begin // 增加默认分支,避免综合警告 C = 16'h0; overflow = 1'b0; end endcase end endmodule module CLA ( input [15:0] A, B, output [15:0] Sum, output overflow ); wire c1, c2, c3; CLA4bit CLA1 (.A(A[3:0]), .B(B[3:0]), .Cin(1'b0), .Sum(Sum[3:0]), .Cout(c1)); CLA4bit CLA2 (.A(A[7:4]), .B(B[7:4]), .Cin(c1), .Sum(Sum[7:4]), .Cout(c2)); CLA4bit CLA3(.A(A[11:8]), .B(B[11:8]), .Cin(c2), .Sum(Sum[11:8]), .Cout(c3)); CLA4bit CLA4(.A(A[15:12]), .B(B[15:12]), .Cin(c3), .Sum(Sum[15:12]), .Cout(overflow)); endmodule module CLA4bit( input [3:0] A, B, input Cin, output [3:0] Sum, output Cout ); wire [3:0] P, G, C; assign P = A ^ B; assign G = A & B; assign C[0] = Cin; assign C[1] = G[0] | (P[0] & C[0]); // 补充括号明确运算优先级 assign C[2] = G[1] | (P[1] & G[0]) | (P[1] & P[0] & C[0]); assign C[3] = G[2] | (P[2] & G[1]) | (P[2] & P[1] & G[0]) | (P[2] & P[1] & P[0] & C[0]); assign Cout = G[3] | (P[3] & G[2]) | (P[3] & P[2] & G[1]) | (P[3] & P[2] & P[1] & G[0]) | (P[3] & P[2] & P[1] & P[0] & C[0]); assign Sum = P ^ C; endmodule
优化后的测试平台(可选)
添加$monitor实时打印信号,方便观察运算结果变化:
module tbALU(); reg [15:0] A, B; reg [4:0] alu_code; wire [15:0] C; wire overflow; ALU uut(A, B, alu_code, C, overflow); initial begin $monitor("Time=%0t, alu_code=%b, A=%h, B=%h, C=%h, overflow=%b", $time, alu_code, A, B, C, overflow); A = 16'h00AA; B = 16'h00AA; // 扩展为16位,避免高位默认0的歧义 #50; alu_code = 5'b00000; #50; alu_code = 5'b00001; #50; alu_code = 5'b00010; #50; alu_code = 5'b00011; #50; $finish; end endmodule
内容的提问来源于stack exchange,提问作者JarvisLYu1
相关产品推荐
相关产品推荐

