由于时钟更新当前状态的问题,此 FSM 机器中的状态变化太快 [英] The states in this FSM machine are changing too quickly due to an issue with the clock updating the present state
问题描述
我正在用 verilog 实现有限状态机,但遇到了一个问题.不过,我知道问题出在哪里,但我不知道如何解决.
I'm in the process of implementing a finite state machine in verilog, and I've encountered an issue. However, I know what the problem is, but I'm not sure how to fix it.
这是我当前的代码:
module moore_SM(clk, rstn, btn, z, rstLED, state);
//Port Assignments
input clk, rstn;
input [2:0] btn;
output z;
output reg rstLED;
output reg [5:0] state;
//Internal Port Assignments
reg [1:0] w, x; //NOTE: This is typically the input in FSM,
//but it is internal because there is a conversion from btn to w.
reg [2:0] y, Y; //Present state and next state respectively
reg [2:0] pstBtn;
reg [31:0] cnt;
//Define some parameters
//Input Type (i.e. A, B or C)
parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10; //DC => don't care - shouldn't affect FSM
//State (i.e. S1, S2, S3, S4, S5 or S6)
parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101;
initial begin
state = 0;
end
//Determine which button is active
always @(*)
begin
case(btn)
3'b110: begin w = A; end
3'b101: begin w = B; end
3'b011: begin w = C; end
// default: w = DC;
endcase
end
//Define the next state and output combinational circuits
always @(w,y)
begin
case(y)
S1: begin
state = 6'b000001;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
S2: begin
state = 6'b000010;
if(w == B) begin Y = S3; end
else begin if(w == A) begin Y = S2; end
else Y = S1; end
end
S3: begin
state = 6'b000100;
if(w == A) begin Y = S2; end
else begin if(w == B) begin Y = S4; end
else Y = S1; end
end
S4: begin
state = 6'b001000;
if(w == A) begin Y = S5; end
else begin Y = S1; end
end
S5: begin
state = 6'b010000;
if(w == A) begin Y = S2; end
else begin if(w == B) begin Y = S3; end
else Y = S6; end
end
S6: begin
state = 6'b100000;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
//default: Y = 3'b111;
endcase
end
//assign z = (Y == S2);
//Define the sequential block
always @(posedge clk)
begin
y <= Y;
end
endmodule
此代码应该用于识别模式 ABBAC.我相信逻辑实现了这个目的.
This code is supposed to identify the pattern ABBAC. I believe the logic accomplishes this purpose.
但是,我遇到了一个问题.当我按下三个按钮中的一个时,第一个总是阻止 - always @(*)
- 执行并评估更改.按钮的状态被编码并保存到w.
同时,下一个always块——always@(w,y)
——感知变化并确定在居住在哪个州.正如我所料,如果我发送输入 A
,机器就会从 S1
移动到 S2
.
However, I've encountered a problem. When I press one of the three buttons, the first always block - always @(*)
- executes and evaluates the change. The state of the button is encoded and saved into w.
At the same time, the next always block - always @(w,y)
- senses a change and determines in which state to reside. Like I expected, if I send input A
, the machine moves from S1
into S2
.
现在,如果我发送输入B
,机器会回到状态S1
.在我改变了一些事情之后,我确定了我认为是问题所在.注意最后一个 always 块:always @(posedge clk).
这个 always 块不断更新当前状态,y.
当我按下一个按钮时,我假设发生的事情是第二个总是阻塞,always @(w,y),
正在以 50mHz 接收更新的 y
(在我的情况下),这显然比我可以按下的要快得多并释放一个按钮.假设我在 S2
状态下按下 B
按钮,状态会快速变为 S3
到 S4
和然后到 S1
因为不断更新.
Now if I send input B
, the machine moves back into state S1
. After I changed a few things around, I identified what I believe to be the problem. Note the last always block: always @(posedge clk).
This always block continuously updates the present state, y.
When I press a button, I assume what is happening is that the second always block, always @(w,y),
is receiving an updated y
at 50mHz (in my case), which is obviously much faster than I can press and release a button. Assuming I'm pressing the B
button while in state S2
, the state quickly changes to S3
to S4
and then to S1
because of the continuous update.
也就是说,我在想出解决此问题的方法时遇到了一些麻烦.我基本上需要某种方法来改变每次按下按钮的一种状态.
That said, I'm having some trouble coming up with a way to fix this issue. I basically need some way to change only one state per button press.
请注意,我主要是在实验板上测试此代码.我确实写了一个测试平台,但模拟似乎与我在设计板上看到的不符.如果有人想看测试台代码,我把它贴在下面:
Note that I'm primarily testing this code on an experimental board. I did write a testbench, but the simulation does not seem to match what I'm seeing on the design board. In case anyone wants to see the testbench code, I posted it below:
`timescale 1ns/1ns
module moore_SM_TB();
reg clk;
reg [2:0] btn;
wire [5:0] state;
wire z;
wire rstLED;
initial begin
clk = 1;
#0 btn = 3'b111;
#50 btn = 3'b110;
#50 btn = 3'b111;
#50 btn = 3'b101;
#50 btn = 3'b111;
#50 btn = 3'b011;
#50 btn = 3'b111;
end
always begin
#20 clk = ~clk;
end
//MUT
moore_SM MUT (clk, 0, btn, z, rstLED, state);
endmodule
注意:我相信解决方案最终将涉及修改按钮的处理方式.当我释放一个按钮时,这也记录为一个变化.因此,我不得不注释掉默认情况,因为它也会弄乱机器所处的状态.
NOTE: I believe the solution will ultimately involve modifying how the buttons are handled. When I release a button, this also registers as a change. Hence, I had to comment out the default case because it would also mess up which state the machine is in.
更新:我编写了上面发布的 FSM 的简化版本,以尝试调试代码.它试图检测序列 AB.
UPDATE: I wrote a reduced version of the FSM I posted above to try and debug the code. It tries to detect the sequence AB.
module moore_SM(clk, btn, rstN, state, rstLED);
//Port assignments
input clk;
input rstN;
input [2:0] btn;
output reg rstLED;
output reg [5:0] state;
//Internal Port Assignments
reg [1:0] w;
reg [2:0] y, Y;
reg [2:0] pstBtn;
//Define some parameters
parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10;
parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101;
//Initialize some values to prevent Quartus from doing
initial
begin
y = S1;
Y = y;
state = 0;
rstLED = 0;
end
always @(*)
begin
if(btn == pstBtn) begin w = DC; end
else begin
case(btn)
3'b110: w = A;
3'b101: w = B;
3'b011: w = C;
default: w = DC;
endcase
end
end
always @(*)
begin
case(y)
S1: begin
state = 6'b000001;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
S2: begin
state = 6'b000010;
if(w == B) begin Y = S3; end
if(w == DC) begin Y = S2; end
else begin Y = S1; end
end
S3: begin
state = 6'b000100;
if(w == DC) begin Y = S3; end
else begin Y = S1; end
end
default: begin state = 6'b100000; Y = S1; end
endcase
end
//Update state and check for reset signal
always @(posedge clk, negedge rstN)
begin
pstBtn <= btn;
if(rstN == 0) begin y <= S1; rstLED <= 1; end
else begin y <= Y; rstLED <= 0; end
end
endmodule
请注意,我正在尝试对最后一个 always 块中的按钮状态进行采样".我过去使用过这种方法,但在这里似乎不起作用.每当我按下按钮时,状态都没有变化.我想知道这是否是时间问题.
Note that I'm trying to "sample" the button state in the last always block. I've used this method in the past, but it does not seem to work here. Whenever I press a button, there is no change in state. I'm wondering if this is a timing issue now.
推荐答案
如果按钮输入是开关而不是测试刺激,它将是异步的,因此应该通过 2 个元稳定触发器.要更改每个按钮的一种状态,请创建边缘检测.
If the button input is coming a switch rather than test stimulus it will be asynchronous and so should be put through 2 meta-stability flip-flops. To change one state per button press create an edge detection.
边缘检测将创建 1 个时钟周期宽的脉冲,从而导致每次按下 1 次转换.
Edge detection will create a 1 clock period wide pulse, resulting in 1 transition per press.
reg [2:0] btn0_meta;
always @(posedge clk or negedge rstN) begin
if (~rstN) begin
btn0_meta <= 'b0;
end
else begin
btn0_meta <= {btn0_meta[1:0], btn[0]};
end
end
reg btn0_posedge;
always @* begin
btn0_posedge = btn0_meta[1] & ~btn_meta[2];
end
对所有按钮输入执行此操作,并在状态机中使用 btnX_posedge.
Do this for all button inputs and use the btnX_posedge in your state machine.
这篇关于由于时钟更新当前状态的问题,此 FSM 机器中的状态变化太快的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!