由于时钟更新当前状态的问题,此 FSM 机器中的状态变化太快 [英] The states in this FSM machine are changing too quickly due to an issue with the clock updating the present state

查看:16
本文介绍了由于时钟更新当前状态的问题,此 FSM 机器中的状态变化太快的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 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 按钮,状态会快速变为 S3S4 和然后到 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆