Die Zustände in dieser FSM-Maschine ändern sich zu schnell, da die Uhr den aktuellen Zustand nicht aktualisiert
Ich bin gerade dabei, eine Finite-State-Maschine in Verilog zu implementieren, und bin auf ein Problem gestoßen. Ich weiß jedoch, wo das Problem liegt, bin mir aber nicht sicher, wie ich es beheben soll.
Das ist mein aktueller Code:
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
Dieser Code soll das Muster ABBAC identifizieren. Ich glaube, die Logik erfüllt diesen Zweck.
Ich bin jedoch auf ein Problem gestoßen. Wenn ich eine der drei Tasten drücke, blockiert die erste immer -always @(*)
- führt die Änderung aus und wertet sie aus. Der Status der Schaltfläche wird verschlüsselt und in gespeichertw.
Gleichzeitig blockiert der nächste immer -always @(w,y)
- spürt eine Änderung und bestimmt, in welchem Zustand er sich befindet. Wie ich erwartet habe, wenn ich Input schickeA
fährt die Maschine abS1
inS2
.
Nun wenn ich Input schickeB
fährt die Maschine wieder in den ZustandS1
. Nachdem ich ein paar Dinge geändert hatte, identifizierte ich, was ich für das Problem halte. Beachten Sie den letzten immer Block:always @(posedge clk).
Dieser Block aktualisiert ständig den aktuellen Zustand,y.
Wenn ich einen Knopf drücke, gehe ich davon aus, dass der zweite immer blockiert,always @(w,y),
erhält eine aktualisiertey
bei 50 MHz (in meinem Fall), was offensichtlich viel schneller ist, als ich einen Knopf drücken und loslassen kann. Angenommen, ich drücke dieB
Taste im ZustandS2
ändert sich der Zustand schnell zuS3
zuS4
und dann zuS1
wegen des kontinuierlichen Updates.
Trotzdem habe ich Probleme, dieses Problem zu beheben. Grundsätzlich brauche ich eine Möglichkeit, um nur einen Status pro Tastendruck zu ändern.
Beachten Sie, dass ich diesen Code hauptsächlich auf einem Experimentierboard teste. Ich habe einen Testbench geschrieben, aber die Simulation scheint nicht mit dem übereinzustimmen, was ich auf der Entwurfstafel sehe. Falls jemand den Testbench-Code sehen möchte, habe ich ihn unten gepostet:
`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
HINWEIS: Ich glaube, dass die Lösung letztendlich eine Änderung der Handhabung der Schaltflächen beinhalten wird. Wenn ich eine Taste loslasse, wird dies ebenfalls als Änderung registriert. Daher musste ich den Standardfall auskommentieren, da dies auch den Status der Maschine verfälschen würde.
UPDATE: Ich habe eine reduzierte Version des oben veröffentlichten FSM geschrieben, um zu versuchen, den Code zu debuggen. Es wird versucht, die Sequenz AB zu erkennen.
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
Beachten Sie, dass ich versuche, den Schaltflächenstatus im letzten Block immer abzutasten. Ich habe diese Methode in der Vergangenheit verwendet, aber es scheint hier nicht zu funktionieren. Immer wenn ich eine Taste drücke, ändert sich der Status nicht. Ich frage mich, ob dies jetzt ein Timing-Problem ist.