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 schickeAfährt die Maschine abS1 inS2.

Nun wenn ich Input schickeBfä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.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage