我正在尝试进行的综合是在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 决定机器是否处于"开启"模式并可以执行算法
NRST 是负复位开关
问题是如何形成的:
你可以看到,一开始,有一个if(act == 0)
条件。它被放在那里是为了确保 A,B 线(外部接收)上的值将进入那里的寄存器,而不是在我们处于if(~nrst)
条件时将它们输入顺序块,因为在重置时输入动态值是没有意义的。
这将我们带到当前的问题 - 我知道在顺序和组合块中为 A 和 B 分配值是造成问题的原因,但我只是找不到替代方案。
附言我正在使用A_reg = A
创建锁存器的事实,因为我没有分配给其他任何地方A_reg
,这是另一个问题,因为编写Aint_reg = A_reg;
A_reg = Aint_reg;
来满足闩锁不适合我。
附言2. 我尝试在网站上查看类似的问题,但由于我对这个主题缺乏足够的了解,我无法将我的问题与那里的问题联系起来
我很高兴收到任何帮助,谢谢
编辑:我删除了if(~nrst)顺序块中的非阻塞赋值,以免在组合块中A_reg <= 0
多个赋值和A_reg = A
,但多重赋值问题仍然以某种方式困扰着它
EDIT2:似乎我忘记了一个基本的事情 - 不要在两个不同的"总是"块中分配给同一个变量,但我只是想不出一个足够好的解决方案将电线 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
等。另请注意,如果这意味着 out 的时序将被延迟,因此如果您需要立即从组合块中推出值,您可以随时绕过寄存器。据我了解,您可能会在重置期间遇到加载问题,这是可以理解的,只要断言重置(nrst
)(即 0),就不会加载任何内容。这就是重置的全部意义,将系统保持在已知状态,直到它被抬起。因此,在取消断言nrst
之前,您的模块不应执行任何操作。其他几点:
- 正确格式化代码非常重要,请确保您的代码始终干净,因为它有助于发现错误。我重新格式化了它,
IDLE
状态的最后一个块中似乎缺少begin..end
- 始终
begin..end
你的块,它将避免这么多错误 - 注意事情的大小,我看到你声明你的变量是 32 位
reg [31:0]
但只使用 31 位31'd
分配它们。使用'0
语法对任何大小进行零填充。 - 将寄存器设置为
'x
并不理想,您应该让寄存器保留其状态(就像您对寄存器值和下一个寄存器值执行的操作一样)。
希望这能为您澄清事情。