2014-03-28 8 views
1

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 @(w,y),이 업데이트 된 y을 50mHz로 수신한다고 가정합니다. 단추를 눌렀다 놓을 수있는 것보다 훨씬 빠릅니다. 상태가 S2 인 동안 B 버튼을 누르면 상태가 지속적으로 업데이트되어 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 

마지막 항상 블록의 상태를 "샘플링"하려고합니다. 과거에이 방법을 사용했지만 여기서는 효과가없는 것 같습니다. 단추를 누를 때마다 상태가 변경되지 않습니다. 이것이 타이밍 문제인지 지금 궁금합니다.

+1

상태가 시계의 가장자리에서 바뀌어야합니다. 조합 코드가 아닙니다. – Morgan

+0

코드를 다시 살펴본 후 이것이 무엇을하는지 믿습니다. 조합 블록은 다음 상태 인 'Y'를 정의하고 클록 에지에서 현재 상태 'y'를 업데이트한다. – Mlagma

+0

아니요,이 책에서는 'Y'(명료하게하기 위해 * nextState * 또는 * next_state *라고도 함)가 조합 적으로 변경되고 있음을 보여줍니다. 그러나 * nextState * 값은 다음 클럭 에지에만 등록됩니다. 'always @ (posedge clk) ... y <= Y;' – smci

답변

3

버튼 입력이 테스트 자극이 아닌 스위치로 전환되면 비동기 적이므로 메타 안정성 플립 플롭 2 개를 통과해야합니다. 단추 당 하나의 상태를 변경하려면 가장자리 감지를 만듭니다.

에지 감지는 1 클럭주기의 와이드 펄스를 생성하여 프레스 당 1 전환이 발생합니다.

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를 사용합니다.

+0

고마워, 나는 이것의 뒤에 장군을 사용하고 아주 잘 작동했다. – Mlagma

+0

"general * idea" – Mlagma

+0

@Mlagma 우리가 도울 수있어서 기쁩니다. 시끄러운 버튼의 경우 디 바운싱을 찾아 볼 수도 있습니다. 버튼의 변경된 상태가 일정 시간 지속되었다는 것을 기본적으로 확인함으로써 스위치 접촉의 기계적 튀어 오름이 여러 버튼 누름으로 감지되는 가능성을 줄였습니다. 꽤 많은 FPGA가 이것을 처리합니다. – Morgan