在 verilog 合成中接收来自外部源的输入时出现多驱动问题
multiple drive issue when receiving inputs from external source in verilog synthesis
我正在尝试进行的综合是在使用 "subtract if bigger" 方法工作的 GCD 算法有限状态机上进行的。我将附上代码并尝试提出一个体面的问题。
module GCD_R (A,B,out,nrst,act,clk,fla_g);
input [31:0] A, B;
input clk, act, nrst;
output reg fla_g;
output reg [31:0] out;
reg [3:0] state, next_state;
reg [31:0] A_reg, B_reg, Aint_reg, Bint_reg, out_reg;//2 registers will keep intermediate numbers+out, and next numbers
parameter IDLE = 3'b001;
parameter ABIG = 3'b010;
parameter BBIG = 3'b100;
reg next_flag;
always @(*)
case (state)
IDLE: begin
$display("start");
if(act == 0) begin
A_reg = A; //A,B are wires that contain numbers from an external source
B_reg = B; //first assign to A_reg and B_reg
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
end
if(act == 1)
if(A_reg==0) begin
out_reg = B_reg;
next_flag = 1'b1; //testbench will know when we stopped
Aint_reg = A_reg; //taking care not to infer latches
Bint_reg = B_reg;
next_state = IDLE;
end
else if (B_reg==0) begin
out_reg = A_reg;
next_flag = 1'b1;
Aint_reg = A_reg; //taking care not to infer latches
Bint_reg = B_reg;
next_state = IDLE;
end
else if (A_reg >= B_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
Aint_reg = A_reg;
Bint_reg = B_reg;
next_state = ABIG;
end
else begin
out_reg = 4'bxxx;
next_flag = 1'b0;
Aint_reg = A_reg;
Bint_reg = B_reg;
next_state = BBIG;
end
else
begin
Aint_reg = A_reg;
Bint_reg = B_reg;
out_reg = 4'bxxx;
next_flag = 1'b0;
next_state = 4'bx;
end
end
ABIG: begin
if (A_reg==0 | B_reg==0) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else if (B_reg > A_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = BBIG;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = ABIG;
Aint_reg = A_reg - B_reg;
Bint_reg = B_reg;
end
end
BBIG: begin
if (A_reg==0 | B_reg==0) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else if (A_reg > B_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = ABIG;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = BBIG;
Aint_reg = A_reg;
Bint_reg = B_reg - A_reg;
end
end
default: begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = 4'bx;
Aint_reg = A_reg;
Bint_reg = B_reg;
$display("%t: State machine not initialized/n",$time);
end
endcase
always @(posedge clk or negedge nrst)
if (~nrst) begin
state <= IDLE;//we get the new values by resetting first
out <= 4'bx;//we don't want anything there at the reset
fla_g <= 1'b0;
end
else begin
state <= next_state;//otherwise, get the next state and the next registers to the intermediate ones
A_reg <= Aint_reg;// 2nd assign to A_reg and B_reg- that's the problem
B_reg <= Bint_reg;
out <= out_reg;
fla_g <= next_flag;
end
endmodule
首先,A 和 B 是电线,它们将通过外部源(测试台中的某个文本文件)接收要比较的数字列表。
A_reg 和 B_reg 是中间寄存器,用于保存我们正在检查 "if" 语句的数字,
Aint_reg和Bint_reg是寄存器,在操作后保留寄存器的中间值,只在时钟上升时将它们发送回A_reg和B_reg ,
act 决定机器是否处于 "on" 模式并且可以执行算法
nrst 是负复位切换
问题是怎么形成的:
可以看到开头有一个if(act == 0)
条件。它被放在那里是为了确保 A、B 线的值(从外部接收)将进入那里的寄存器,而不是在我们处于 if(~nrst)
条件时将它们输入到顺序块中,因为输入没有意义重置时的动态值。
这将我们带到当前的问题 - 我知道在顺序块和组合块中为 A 和 B 赋值是造成问题的原因,但我找不到替代方案。
p.s。我正在使用 A_reg = A
的事实创建了锁存器,因为我没有在其他任何地方分配给 A_reg
,这是自编写
以来的另一个问题
Aint_reg = A_reg;
A_reg = Aint_reg;
满足闩锁并不适合我。
p.s.2。我试着调查网站上的类似问题,但由于我对这个问题缺乏足够的了解,我无法将我的问题与其他问题联系起来
我很乐意得到任何帮助,谢谢
编辑: 我删除了 if(~nrst) 顺序块中的非阻塞赋值,以免在那里多重赋值 A_reg <= 0
和 A_reg = A
在组合块中,但多重赋值问题仍然以某种方式存在问题
EDIT2: 似乎我忘记了一件基本的事情——不要在两个不同的 "always" 块中分配同一个变量,但我就是想不通一个足够好的解决方案,将电线 A、B 分配给一个寄存器,而不是在顺序块中再次分配给它
您确定代码中的主要问题是您没有正确处理寄存器和组合逻辑是正确的。每当你有一个寄存器(寄存器,而不是 reg
类型,它们是不一样的,这会让 Verilog 新手感到困惑),你需要以特定的方式定义它,以便综合和仿真工具可以处理它。最安全的做法是在组合逻辑和顺序存储(即实际寄存器)之间创建一个清晰的分离。您开始使用 Aint_reg
、Bint_reg
、out_reg
等;但是您需要对所有值来自组合块的注册值执行此操作。因此,所有这些想法共同产生了一个代码结构,如下所示(不完全是您的代码,而是类似的代码):
input [31:0] A, B;
output reg [31:0] out;
reg [31:0] regA, regB;
reg [3:0] state, nextState;
always @(posedge clk or negedge rst) begin
if (~rst) begin
regA <= '0;
regB <= '0;
state <= IDLE;
end
else begin
regA <= nextA;
regB <= nextB;
state <= nextState;
end
end
always @(*) begin
// Default; I always do this here to ensure there are no cases in which I dont assign a combinational value for this block
// it always helps me keep track of which variables are assigned in which block
nextA = regA;
nextB = regB;
nextState = state;
out = '0;
case (state)
// In here is your case body, where you can reassign nextA, nextB, nextState and out
// where the assignments are only dependent on A, B, regA, regB and state (ie, the values NOT assigned in this block)
endcase
end
考虑到这一点,您只需要在组合块中包含 Aint_reg
、Bint_reg
等;所以你不需要在组合块中分配 A_reg
、Breg
等。还要注意,如果这意味着输出的时间将被延迟,那么如果您需要立即从组合块中推出一个值,您总是可以绕过寄存器。据我了解,您可能在重置期间遇到加载问题,这是可以理解的,只要重置 (nrst
) 被断言(即 0),就不会加载任何内容。这就是重置的全部要点,将系统保持在已知状态,直到它被解除。所以在 nrst
被置低之前,你的模块不应该做任何事情。其他几点:
- 正确格式化您的代码非常重要,确保您的代码始终干净,因为它有助于发现错误。我重新格式化它,在
IDLE
状态 的最后一个块中似乎缺少 begin..end
- 总是
begin..end
你的块,它会避免很多错误
- 注意事物的大小,我看到您将变量声明为 32 位
reg [31:0]
但仅使用 31 位的 31'd
分配它们。使用 '0
语法对任何尺寸进行零填充。
- 将寄存器设置为
'x
并不理想,您应该让寄存器保持它们的状态(就像您对寄存器值和下一个寄存器值所做的那样)。
希望这能为您澄清一些事情。
我正在尝试进行的综合是在使用 "subtract if bigger" 方法工作的 GCD 算法有限状态机上进行的。我将附上代码并尝试提出一个体面的问题。
module GCD_R (A,B,out,nrst,act,clk,fla_g);
input [31:0] A, B;
input clk, act, nrst;
output reg fla_g;
output reg [31:0] out;
reg [3:0] state, next_state;
reg [31:0] A_reg, B_reg, Aint_reg, Bint_reg, out_reg;//2 registers will keep intermediate numbers+out, and next numbers
parameter IDLE = 3'b001;
parameter ABIG = 3'b010;
parameter BBIG = 3'b100;
reg next_flag;
always @(*)
case (state)
IDLE: begin
$display("start");
if(act == 0) begin
A_reg = A; //A,B are wires that contain numbers from an external source
B_reg = B; //first assign to A_reg and B_reg
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
end
if(act == 1)
if(A_reg==0) begin
out_reg = B_reg;
next_flag = 1'b1; //testbench will know when we stopped
Aint_reg = A_reg; //taking care not to infer latches
Bint_reg = B_reg;
next_state = IDLE;
end
else if (B_reg==0) begin
out_reg = A_reg;
next_flag = 1'b1;
Aint_reg = A_reg; //taking care not to infer latches
Bint_reg = B_reg;
next_state = IDLE;
end
else if (A_reg >= B_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
Aint_reg = A_reg;
Bint_reg = B_reg;
next_state = ABIG;
end
else begin
out_reg = 4'bxxx;
next_flag = 1'b0;
Aint_reg = A_reg;
Bint_reg = B_reg;
next_state = BBIG;
end
else
begin
Aint_reg = A_reg;
Bint_reg = B_reg;
out_reg = 4'bxxx;
next_flag = 1'b0;
next_state = 4'bx;
end
end
ABIG: begin
if (A_reg==0 | B_reg==0) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else if (B_reg > A_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = BBIG;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = ABIG;
Aint_reg = A_reg - B_reg;
Bint_reg = B_reg;
end
end
BBIG: begin
if (A_reg==0 | B_reg==0) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = IDLE;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else if (A_reg > B_reg) begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = ABIG;
Aint_reg = A_reg;
Bint_reg = B_reg;
end
else begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = BBIG;
Aint_reg = A_reg;
Bint_reg = B_reg - A_reg;
end
end
default: begin
out_reg = 31'bx;
next_flag = 1'b0;
next_state = 4'bx;
Aint_reg = A_reg;
Bint_reg = B_reg;
$display("%t: State machine not initialized/n",$time);
end
endcase
always @(posedge clk or negedge nrst)
if (~nrst) begin
state <= IDLE;//we get the new values by resetting first
out <= 4'bx;//we don't want anything there at the reset
fla_g <= 1'b0;
end
else begin
state <= next_state;//otherwise, get the next state and the next registers to the intermediate ones
A_reg <= Aint_reg;// 2nd assign to A_reg and B_reg- that's the problem
B_reg <= Bint_reg;
out <= out_reg;
fla_g <= next_flag;
end
endmodule
首先,A 和 B 是电线,它们将通过外部源(测试台中的某个文本文件)接收要比较的数字列表。
A_reg 和 B_reg 是中间寄存器,用于保存我们正在检查 "if" 语句的数字,
Aint_reg和Bint_reg是寄存器,在操作后保留寄存器的中间值,只在时钟上升时将它们发送回A_reg和B_reg ,
act 决定机器是否处于 "on" 模式并且可以执行算法
nrst 是负复位切换
问题是怎么形成的:
可以看到开头有一个if(act == 0)
条件。它被放在那里是为了确保 A、B 线的值(从外部接收)将进入那里的寄存器,而不是在我们处于 if(~nrst)
条件时将它们输入到顺序块中,因为输入没有意义重置时的动态值。
这将我们带到当前的问题 - 我知道在顺序块和组合块中为 A 和 B 赋值是造成问题的原因,但我找不到替代方案。
p.s。我正在使用 A_reg = A
的事实创建了锁存器,因为我没有在其他任何地方分配给 A_reg
,这是自编写
以来的另一个问题
Aint_reg = A_reg;
A_reg = Aint_reg;
满足闩锁并不适合我。
p.s.2。我试着调查网站上的类似问题,但由于我对这个问题缺乏足够的了解,我无法将我的问题与其他问题联系起来
我很乐意得到任何帮助,谢谢
编辑: 我删除了 if(~nrst) 顺序块中的非阻塞赋值,以免在那里多重赋值 A_reg <= 0
和 A_reg = A
在组合块中,但多重赋值问题仍然以某种方式存在问题
EDIT2: 似乎我忘记了一件基本的事情——不要在两个不同的 "always" 块中分配同一个变量,但我就是想不通一个足够好的解决方案,将电线 A、B 分配给一个寄存器,而不是在顺序块中再次分配给它
您确定代码中的主要问题是您没有正确处理寄存器和组合逻辑是正确的。每当你有一个寄存器(寄存器,而不是 reg
类型,它们是不一样的,这会让 Verilog 新手感到困惑),你需要以特定的方式定义它,以便综合和仿真工具可以处理它。最安全的做法是在组合逻辑和顺序存储(即实际寄存器)之间创建一个清晰的分离。您开始使用 Aint_reg
、Bint_reg
、out_reg
等;但是您需要对所有值来自组合块的注册值执行此操作。因此,所有这些想法共同产生了一个代码结构,如下所示(不完全是您的代码,而是类似的代码):
input [31:0] A, B;
output reg [31:0] out;
reg [31:0] regA, regB;
reg [3:0] state, nextState;
always @(posedge clk or negedge rst) begin
if (~rst) begin
regA <= '0;
regB <= '0;
state <= IDLE;
end
else begin
regA <= nextA;
regB <= nextB;
state <= nextState;
end
end
always @(*) begin
// Default; I always do this here to ensure there are no cases in which I dont assign a combinational value for this block
// it always helps me keep track of which variables are assigned in which block
nextA = regA;
nextB = regB;
nextState = state;
out = '0;
case (state)
// In here is your case body, where you can reassign nextA, nextB, nextState and out
// where the assignments are only dependent on A, B, regA, regB and state (ie, the values NOT assigned in this block)
endcase
end
考虑到这一点,您只需要在组合块中包含 Aint_reg
、Bint_reg
等;所以你不需要在组合块中分配 A_reg
、Breg
等。还要注意,如果这意味着输出的时间将被延迟,那么如果您需要立即从组合块中推出一个值,您总是可以绕过寄存器。据我了解,您可能在重置期间遇到加载问题,这是可以理解的,只要重置 (nrst
) 被断言(即 0),就不会加载任何内容。这就是重置的全部要点,将系统保持在已知状态,直到它被解除。所以在 nrst
被置低之前,你的模块不应该做任何事情。其他几点:
- 正确格式化您的代码非常重要,确保您的代码始终干净,因为它有助于发现错误。我重新格式化它,在
IDLE
状态 的最后一个块中似乎缺少 - 总是
begin..end
你的块,它会避免很多错误 - 注意事物的大小,我看到您将变量声明为 32 位
reg [31:0]
但仅使用 31 位的31'd
分配它们。使用'0
语法对任何尺寸进行零填充。 - 将寄存器设置为
'x
并不理想,您应该让寄存器保持它们的状态(就像您对寄存器值和下一个寄存器值所做的那样)。
begin..end
希望这能为您澄清一些事情。