我在设计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是所有反转结果信号的AND门,当Result == 0时,输出Z应为1.
但是,我昨天整个下午都试着弄清楚如何修复这个错误,我想说如果我使用assign
语句而不是使用if
语句,那么模拟会给出正确的行为。 assign Z = (Result ==0 )? 1:0;
我认为这两个版本描述Z应该是一样的!我使用
修改代码后assign Z = (Result ==0 )? 1:0;
合成结果仍与上图所示相同......
有人可以告诉我发生了什么事吗? 非常感谢!!!
答案 0 :(得分:4)
我认为问题在于您的操作顺序。 always_comb
块从上到下以程序方式执行。在模拟中,Z
首先使用现有值Result
进行更新(从上一次执行always块开始)。 Result
已更新,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)
我 高度劝阻 因为很容易错过必要的信号,unessary信号浪费模拟时间,造成零时无限循环的风险,你仍然没有获得RTL和综合之间的保证功能等价物。