我试图做的综合是在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是中间寄存器,用于保存我们正在检查的数字&#34;如果&#34;声明,
Aint_reg和Bint_reg是在操作之后保持寄存器的中间值的寄存器,仅在时钟上升时将它们发送回A_reg和B_reg,
行动决定机器是否开启&#34;开启&#34;模式并可以执行算法
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:似乎我忘记了一个基本的事情 - 不要在两个不同的&#34;总是&#34;中分配相同的变量。块,但我想不出足够好的解决方案将线A,B分配给寄存器而不是在顺序块中再分配给它
答案 0 :(得分:1)
您在识别代码中的主要问题时是正确的,即您没有正确处理寄存器和组合逻辑。无论何时你有一个寄存器(寄存器,而不是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的时间将被延迟,那么如果需要立即从组合块中推出一个值,则可以始终绕过寄存器。根据我的理解,你可能在重置期间遇到加载问题,这是可以理解的,只要reset(nrst
)被置位(即0),什么都不会加载。这是重置的整个点,用于将系统保持在已知状态直到它被提升。因此,在nrst
置为无效之前,您的模块不应执行任何操作。其他几点:
begin..end
州的最后一个块中似乎缺少IDLE
begin..end
你的街区,它会避免这么多的错误reg [31:0]
,但只是使用31位的31'd
来分配它们。使用'0
语法将填充为零填充。'x
并不理想,您应该让寄存器保持其状态(就像您对寄存器值和下一个寄存器值所做的那样)。希望这能为你澄清事情。