systemverilog中的组合逻辑"IF"和"assign"语句

Combinational logic "IF" and "assign" statement in systemverilog

我在设计我的 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;

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

谁能告诉我这是怎么回事? 非常感谢!!!

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

Synthesis则不同,它连接的是等效的逻辑门,可能导致异步反馈。逻辑等价物与功能等价物不同。这就是为什么综合给你逻辑上想要的东西,而 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

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

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

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