1

我在设计我的 ALU 时发现了一个非常奇怪的行为,希望有人可以看看它并告诉我发生了什么。

这是代码

module adder (
output logic signed[31:0] y,
output logic Cout,
input logic signed[31:0] a, b,
input logic Cin, sub
);

logic [31:0] adder_b;

assign adder_b = b ^ {32{sub}};
assign {Cout, y} = {a[31],a} + {adder_b[31],adder_b} +Cin;

endmodule

////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////



module andlogic (
output logic [31:0] y,
input logic [31:0] a, b
);

assign y = a & b;

endmodule



////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////

module orlogic (
output logic [31:0] y,
input logic [31:0] a, b
);

assign y = a | b;

endmodule

////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////


module xorlogic (
output logic [31:0] y,
input logic [31:0] a, b
);

assign y = a ^ b;

endmodule


///////////////////////////////////////////////////
///////////////////////////////////////////////////
///////////////////////////////////////////////////

module ALU(
output logic signed[31:0] Result,
output logic N,Z,C,V,
input logic signed[31:0] a, b,
input logic [2:0] ALU_control
);

wire [31:0] adder_rlt, and_rlt, or_rlt, xor_rlt;
logic Cin;


adder adder (
        .y (adder_rlt),
    .a (a),
    .b (b),
    .Cin (Cin),
    .Cout (Cout),
    .sub (sub)
);

andlogic andlogic (
        .y (and_rlt),
    .a (a),
    .b (b)
);

orlogic orlogic (
        .y (or_rlt),
    .a (a),
    .b (b)
);

xorlogic xorlogic (
        .y (xor_rlt),
    .a (a),
    .b (b)
);


assign C = Cout;
assign sub = ALU_control[1];
assign Cin = ALU_control[1];
assign N = Result[31];
//assign Z = (Result ==0 )? 1:0;
assign V = {{~a[31]} & {~b[31]} & Result[31]}|{a[31] & b[31] & {~Result[31]}};

always_comb
begin 

 if (Result == 0)   Z = 1;
 else   Z = 0;

 case(ALU_control)

 3'b001:  Result = adder_rlt;

 3'b010:  Result = adder_rlt;

 3'b011:  Result = and_rlt;

 3'b100:  Result = or_rlt;

 3'b101:  Result = xor_rlt;

 default: Result = 0;

 endcase

end

endmodule   

前 4 个模块是我的 ALU 的各个功能,加法器包含加法和减法。然后这是奇怪的事情:

我的 ALU 有 4 个标志,Z 代表零,它在输出Result值为 0 时设置。如果我用这些代码来描述 Z 的行为

always_comb
begin 

 if (Result == 0)   Z = 1;
 else   Z = 0;

模拟结果是错误的,Z有的时候是1,有的时候是0,看起来完全不依赖于的值Result

更奇怪的是合成结果的结果。这里的图片显示了我的 synplify 合成结果的一部分。

综合结果

门电平看起来是正确的,Z 是所有反转 Result 信号的与门,当 Result == 0 时,输出 Z 应该是 1。

但是,我昨天整个下午都在试图弄清楚如何修复这个错误,我发现如果我使用assign语句而不是使用if语句,那么模拟会给出正确的行为。assign Z = (Result ==0 )? 1:0;

我认为这两个版本的描述 Z 应该是相同的!在我使用修改我的代码之后

assign Z = (Result ==0 )? 1:0;

合成结果还是和我上图一样……

有人可以告诉我发生了什么吗?非常感谢!!!

4

1 回答 1

4

我相信问题在于您的操作顺序。always_comb块按程序执行,从上到下。在模拟中,首先使用(从上一次执行 always 块开始)Z的现有值进行更新。ResultResult更新Z且未重新评估。Result不是敏感度列表的一部分,因为它是一个左值。因此,在分配更改Z的信号之前不会更新。Result

综合不同,它连接了可能导致异步反馈的等效逻辑门。逻辑等价物与功能等价物不同。这就是为什么综合给你逻辑上想要的东西,而 RTL 模拟给你功能上写的东西。解释差异的原因超出了这个问题的范围。

在编写 RTL 组合块时,只需做一点自我检查并问自己:

  • 这个总是阻塞的单次传递结束时的值是否是预期的最终值?如果不是,请重新排列您的代码。
  • 是否会使用此始终块中的任何当前值在下一次传递中分配任何值?如果是,请重新排列您的代码或与触发器同步。

在 ALU 的情况下, tt 很容易解决。改变:

always_comb begin
  if (Result==0) Z = 1;  // <-- Z is evaluated using the previous value of Result
  else Z = 0;

  /*Logic to assign Result*/ // <-- change to Result does not re-trigger the always 
end

至:

always_comb begin
  /*Logic to assign Result*/  // <-- update Result first

  if (Result==0) Z = 1; // <-- Z is evaluated using the final value of Result
  else Z = 0;
end

另一种解决方案(我强烈反对)是always_comb用 IEEE1364-1995 组合逻辑样式替换 。手动定义敏感度列表的位置。您可以在此处添加Result以获取反馈更新:

always @(ALU_control or adder_rlt or add_rlt or or_rtl or xor_rtl or Result)

非常不鼓励,因为它很容易错过必要的信号,不必要的信号浪费仿真时间,产生零时间无限循环的风险,并且您仍然无法在 RTL 和综合之间获得保证功能等效。

于 2015-02-27T17:59:43.940 回答