System verilog systemverilog中的组合逻辑“IF”和“assign”语句

System verilog systemverilog中的组合逻辑“IF”和“assign”语句,system-verilog,alu,System Verilog,Alu,我在设计我的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} +

我在设计我的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代表零,它在输出结果的值为0时设置。如果我用这些代码来描述Z的行为

always_comb
begin 

 if (Result == 0)   Z = 1;
 else   Z = 0;
模拟结果是错误的,Z某个时间为1,某个时间为0,看起来根本不依赖于结果的值

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

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

然而,我昨天花了一下午的时间试图找出如何修复这个bug,我发现如果我使用assign语句而不是if语句,那么模拟会给出正确的行为。分配Z=Result==0?1:0;

我认为这两个版本的描述Z应该是一样的!在我使用

assign Z = (Result ==0 )? 1:0;
合成结果仍然和我上面展示的图片一样

有人能告诉我发生了什么事吗?
非常感谢

我认为问题在于你的操作顺序。始终按程序自上而下执行梳齿块。在模拟中,Z首先使用上次执行always块时的结果的现有值进行更新。将更新结果,并且不会重新计算Z。结果不是灵敏度列表的一部分,因为它是一个左侧值。因此,在分配结果的信号改变之前,Z不会得到更新

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

我强烈反对,因为它很容易错过一个必要的信号,不必要的信号浪费了模拟时间,造成了零时间无限循环的风险,而且你仍然没有得到RTL和合成之间的保证函数等价物。

我相信问题在于你的操作顺序。始终按程序自上而下执行梳齿块。在模拟中,Z首先使用上次执行always块时的结果的现有值进行更新。将更新结果,并且不会重新计算Z。结果不是灵敏度列表的一部分,因为它是一个左侧值。因此,在分配结果的信号改变之前,Z不会得到更新

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

我非常不鼓励,因为它很容易错过一个必要的信号,不必要的信号浪费了模拟时间,造成了零时间无限循环的风险,而且你仍然没有得到RTL和合成之间的函数等价物。

很抱歉我的英语不好,希望我的问题对你们有意义。在测试台上,我通过加两个零,减去两个相同大小的变量,将结果的值设置为1。第一个结果Z是0,第二个结果Z是1。对不起,我的英语不好,希望我的问题对你们有意义。在testbench中,我通过加两个零,减去两个相同大小的变量,将结果的值设置为1。对于第一个结果Z是0,对于第二个结果Z是1。Z赋值也可以放在一个单独的always块中。@Morgan,是的,它可以。我更喜欢将同一域中的所有comb loigc保存在一个始终块中。它使RTL更加抽象,我看到它给出了
一些合成器在寻找等待其他约束的共享逻辑时有更大的灵活性,模拟器倾向于给我更好的运行时性能。这是我从事大型设计的经验。一个单独的总是块是更好的解决方案,而不是手动灵敏度列表。哦,我的上帝,你的答案太棒了!谢谢你的帮助,这对我帮助很大!值得注意的是,IEEE标准1800的相关部分™-2012年为9.2.2.2.1。结果不在隐式敏感度列表中,因为它属于第二个例外:也写在块中或在块中调用的任何函数中的任何表达式Z赋值也可以放在单独的always块中。@Morgan,是的,它可以。我更喜欢将同一域中的所有comb loigc保存在一个始终块中。它使RTL更加抽象,我已经看到它为一些合成器提供了更大的灵活性,可以在等待其他约束的情况下查找共享逻辑,并且模拟器倾向于为我提供更好的运行时性能。这是我从事大型设计的经验。一个单独的总是块是更好的解决方案,而不是手动灵敏度列表。哦,我的上帝,你的答案太棒了!谢谢你的帮助,这对我帮助很大!值得注意的是,IEEE标准1800的相关部分™-2012年为9.2.2.2.1。结果不在隐式敏感度列表中,因为它属于第二个例外:也写在块内或块内调用的任何函数内的任何表达式
always @(ALU_control or adder_rlt or add_rlt or or_rtl or xor_rtl or Result)