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 和综合之间获得等效的保证功能。
我在设计我的 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 和综合之间获得等效的保证功能。