FSM Verilog - 1 кнопка для запуска и остановки

Итак, я новичок в Verilog и пытаюсь написать простой FSM.

Ввод a — это кнопка, нажатие на которую запускает машину. Но любое другое следующее состояние после первоначального нажатия a приводит к возврату к начальному/начальному состоянию.

input clk, reset;
input a,b,c;

reg [1:0] state;
reg [1:0] nextstate;

parameter = START=2b'0,
            STATE1=2b'1,
            STATE2=2b'11;

always @(posedge clk)
 if(reset) state <= START;
 else state<=nextstate;

always @(state, a)
 case (state)
   START: begin if(a) nextstate<=STATE1; else nextstate<=START; end
   STATE1: begin if(a) nextstate<=START; else if(b) nextstate<=STATE2; else nextstate<=STATE1; end
   STATE2: begin if(a) nextstate<=START; else if(c) nextstate<=STATE1; else nextstate<=STATE2; end
 endcase

Удержание пальца на a теперь означает, что мое состояние чередуется между STATE1 и START при каждом положительном фронте clk. Как это исправить?


person Bude    schedule 31.12.2015    source источник
comment
Я считаю, что значения должны быть указаны с помощью 2'b11 тика до b, а не после.   -  person Morgan    schedule 01.01.2016
comment
О, да. Ты прав. Это было сделано только для того, чтобы продемонстрировать мою проблему, а не реальный код.   -  person Bude    schedule 01.01.2016


Ответы (1)


Простое решение — отслеживать «край» кнопки, а не текущее состояние. Например:

reg aPressed, aPrev;
always @(posedge clk)
    aPrev<=a;

always@(*)
    if (a&&!aPrev) // a is high now, but was low last cycle
        aPressed = 1;
    else
        aPressed = 0;

В этом коде aPressed утверждается только тогда, когда a был низким в прошлом цикле, а сейчас стал высоким (т.е. он был только что нажат). Если вы замените a на aPressed в логике следующего состояния, пользователю потребуется отпустить a как минимум на один цикл, прежде чем aPressed снова сработает.

always @(*)
    case (state)
        START: begin 
            if(aPressed) nextstate=STATE1; 
            else nextstate=START;
         end
        STATE1: begin 
            if(aPressed) nextstate=START; 
            else if(b) nextstate=STATE2;
            else nextstate=STATE1; 
        end
        STATE2: begin 
            if(aPressed) nextstate=START; 
            else if(c) nextstate=STATE1; 
            else nextstate=STATE2; 
        end
     endcase

Примечание: рекомендуется использовать always@(*) для комбинационной логики, а не указывать список конфиденциальности (always@(state,a))

person wilcroft    schedule 31.12.2015
comment
Вот аналогичная тема вашего ответа: Правильный способ обнаружения края сигнала в Верилог - person e19293001; 01.01.2016