我在用Verilog實現有限狀態機的過程是,我遇到了一個問題。但是,我知道問題是什麼,但我不知道如何解決問題。在這個FSM機的狀態變化太快由於與時鐘的問題,更新當前狀態
這是我當前的代碼:
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。我相信這個邏輯可以達到這個目的。
但是,我遇到了一個問題。當按下三個按鈕中的一個時,第一個總是阻止 - always @(*)
- 執行並評估更改。該按鈕的狀態被編碼並保存到w.
同時,下一個始終阻止 - always @(w,y)
- 感知更改並確定要駐留在哪個狀態。如我所料,如果我發送輸入A
,機器從S1
移動到S2
。
現在如果我發送輸入B
,機器將回到狀態S1
。在我改變了一些事情之後,我確定了我認爲是問題的東西。注意最後總是塊:always @(posedge clk).
這總是阻止不斷更新目前的狀態,y.
當我按下一個按鈕,我認爲正在發生的事情是,第二always塊,always @(w,y),
被接收在50MHz更新y
(在我的情況),其中顯然比我按下並釋放按鈕要快得多。假設我按下按鈕B
而在狀態S2
,狀態變化快於S3
到S4
再到S1
因爲持續更新的。
這麼說,我遇到一些麻煩來了一個辦法來解決這個問題。我基本上需要一些方法來改變每個按鈕按下只有一個狀態。
請注意,我主要在實驗板上測試此代碼。我寫了一個測試臺,但仿真看起來與我在設計板上看到的不一樣。如果有人想看看測試平臺的代碼,我張貼如下:
`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
注:我相信該解決方案將最終涉及修改按鍵的處理方式。當我釋放一個按鈕時,這也會被註冊爲一個改變。因此,我必須將默認情況註釋掉,因爲它也會弄亂機器處於哪種狀態。
更新:我寫了一個縮減版本的FSM,我在上面貼出來嘗試和調試代碼。它試圖檢測序列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
請注意,我試圖「取樣」在最後總是塊的按鈕狀態。過去我使用過這種方法,但在這裏似乎並不奏效。每當我按下一個按鈕,狀態就不會改變。我想知道現在是否是時機問題。
狀態應該改變時鐘邊緣,不combinatorialy – Morgan
我再次查看我的代碼後,我相信這是它在做什麼。組合模塊定義下一個狀態「Y」,然後在時鐘邊沿更新當前狀態「y」。 – Mlagma
不,這本書顯示'Y'(爲了清晰起見,我們通常稱之爲* nextState *或* next_state *)正在發生組合變化。然而,* nextState *值只能在下一個時鐘邊註冊:'always @(posedge clk)... y <= Y;' – smci