Държавна машина; защо само последното състояние работи?

Имам държавна машина с 6 състояния (3 основни състояния). Само последното състояние работи, но първите 2 не (от 3). Само последното състояние работи. Открих проблема, когато премахна веригата за блокиране, тя работи, но имам нужда от веригата за премахване на удари. Взех схемата за премахване на отскок от интернет. Ще се радвам ако някой може да помогне.

 type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2,
                          state_column_3, scan_col_3);
 signal my_state     : SM_STATES                   := state_column_1;

По-долу е държавната машина:

scanner_sm : process (clk)
begin  -- process key_scanner
  if clk'event and clk = '1' then

  if state_inc = '1' then -- clock divider finished counting down 100000

    -- reset scan_complete
    scan_complete <= '0';

case my_state is

  when state_column_1 =>
    scanned_val  <= (others => '0');
    original_col   <= "110";
    my_state <= scan_col_1;

  when scan_col_1 =>
    case bcd_val is
      when "1110" => scanned_val <= "1100100";  -- 1 wrong
      when "1101" => scanned_val <= "1100010";  -- 2 wrong
      when others => scanned_val <= "0010000";
    end case;
    my_state <= state_column_2;

  when state_column_2 =>
    original_col   <= "011";
    my_state <= scan_col_2;

  when scan_col_2 =>
    case bcd_val is
      when "1110" => scanned_val <= "1011011";  -- 5 wrong
      when "1101" => scanned_val <= "1011111";  -- 6 wrong
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_3;

  when state_column_3 =>
    original_col   <= "101";
    my_state <= scan_col_3;

  when scan_col_3 => -- Reading S1 // The only working state
    case bcd_val is
      when "1110" => scanned_val <= "1100000";  -- 9/ 1
      when "1101" => scanned_val <= "0111110";  -- X/ 2
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_1; -- ************ Error might be here
    scan_complete <= '1'; -- ********** Error might be here

  when others => scanned_val <= "0000000";
end case;

      end if;
  end if;
end process scanner_sm;

debounce: process (CLK) is 
begin 
 if (CLK'event and CLK = '1') then  
  Q0 <= scannel_val; 

  Q1 <= Q0; 

  Q2 <= Q1; 

 end if; 

end process; 

Final_val <= Q0 and Q1 and (not Q2);

end Behavioral; 

person Anarkie    schedule 02.05.2014    source източник
comment
Защо публикувате това както в Stackoverlow, така и в Stackexchange? Няма достатъчно изходен код за отговор, демонстрирайте как Само последното състояние работи, но първите 2 не (от 3). Или включете работещ тестов стенд, или покажете (надявам се, с висока разделителна способност) изображение на формата на вълната.   -  person    schedule 03.05.2014
comment
Добавих пълния си процес. Имам само top_level и го написах с примери от интернет още първия, който написах. Не мога да напиша пълния изходен код. Знам, че тогава няма смисъл, но не мога...   -  person Anarkie    schedule 03.05.2014


Отговори (2)


Вашият код досега е непълен - вие директно присвоявате в оператора си case на сигнала my_state, който се оценява от машината за състояния. За да разберем проблема с това, трябва да знаем как работи симулаторът:

В сравнение с действителния хардуер, симулаторът трябва да обработва кода с последователен CPU в последователен процес. Това работи чрез преминаване през кода отново и отново в безкрайно малки времеви разстояния - така нареченото Делта забавяне - докато всички зависимости не бъдат разрешени, т.е. нищо вече не се променя.

Обърнете внимание, че не е минало реално време по време на тези повторения. При правилно написан дизайн симулаторът сега изчаква до настъпването на следващото събитие - обикновено причинено от тиктакането на часовник, което отново рестартира последователните повторения.

Вашият пример по същество прилича на безкраен цикъл: промяна на my_state винаги предизвиква следващата промяна на my_state и по този начин симулаторът никога не се установява на стойност - докато не достигне твърдо кодиран лимит на итерация, който случайно във вашия случай е третото състояние.

И така, как да поправя това? Трябва да въведем часовник и трябва да направим прехода на състоянието в зависимост от действителното време на симулация, обикновено чрез изчакване на часовниково събитие. Най-добрата практика е да разделите комбинаторните и последователните части на два различни процеса, както е показано в този минимален пример на вашата машина за състояния:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture bar of foo is
  type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2, state_column_3, scan_col_3);
  signal my_state, my_state_next : SM_STATES;
  signal bcd_val                 : std_logic_vector(3 downto 0) := "1110";
  signal clk                     : std_logic                    := '1';
  signal nRST                    : std_logic                    := '0';
  signal scanned_val             : std_logic_vector(6 downto 0);
  signal original_col            : std_logic_vector(2 downto 0);
  signal scan_complete           : std_logic;
begin  -- architecture bar

  comb : process (my_state, bcd_val) is
  begin  -- process baz
    case my_state is

      when state_column_1 =>
        scanned_val   <= (others => '0');
        original_col  <= "110";
        my_state_next <= scan_col_1;

      when scan_col_1 =>
        case bcd_val is
          when "1110" => scanned_val <= "1100100";  -- 1 wrong
          when "1101" => scanned_val <= "1100010";  -- 2 wrong
          when others => scanned_val <= "0010000";
        end case;
        my_state_next <= state_column_2;

      when state_column_2 =>
        original_col  <= "011";
        my_state_next <= scan_col_2;

      when scan_col_2 =>
        case bcd_val is
          when "1110" => scanned_val <= "1011011";  -- 5 wrong
          when "1101" => scanned_val <= "1011111";  -- 6 wrong
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_3;

      when state_column_3 =>
        original_col  <= "101";
        my_state_next <= scan_col_3;

      when scan_col_3 =>                -- Reading S1 // The only working state
        case bcd_val is
          when "1110" => scanned_val <= "1100000";  -- 9/ 1
          when "1101" => scanned_val <= "0111110";  -- X/ 2
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_1;  -- ************ Error might be here
        scan_complete <= '1';           -- ********** Error might be here

      when others => scanned_val <= "0000000";
    end case;
  end process comb;

  process (clk, nRST) is
  begin  -- process
    if nRST = '0' then                  -- asynchronous reset (active low)
      my_state <= state_column_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      my_state <= my_state_next;
    end if;
  end process;

  -- this clock and reset signal would usually be supplied from the outside
  clk  <= not clk after 10 ns;
  nRST <= '1'     after 101 ns;
end architecture bar;

Ако стартираме този файл сега в рамките на симулатор, можем да видим превключването на състоянията с всеки тактов цикъл:

Симулация на фиксиран код.

person iterationbound    schedule 02.05.2014
comment
Всъщност нямам бутон за нулиране на моята верига... мога ли без него? Добавих пълния си изходен код на процеса към въпроса, имам часовник и разделител на часовника, така че мисля, че часовникът ми трябва да обработва превключвателя на състоянието, който имахте предвид, но ми липсва my_next_state. Ще се концентрирам върху внедряването на my_next_state. Нямам FPGA през уикенда, в понеделник ще се опитам да дам обратна връзка за отговора, благодаря много за съветите! - person Anarkie; 03.05.2014
comment
Също така, можете ли да споделите своя test_bench? - person Anarkie; 03.05.2014
comment
След втори размисъл мисля, че мога да използвам един от бутоните на FPGA за нулиране, но ако има начин да се реши това без нулиране, бих искал да избера този начин. - person Anarkie; 03.05.2014

Можете да мислите за това като за изграждане на отговора на iterationbound.

Внедрих вашия пълен процес на държавна машина:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture fum of foo is

    type SM_STATES is ( 
        state_column_1, scan_col_1, 
        state_column_2, scan_col_2, 
        state_column_3, scan_col_3
    );

    signal my_state:        SM_STATES;  -- defaults to SM_STATES'LEFT

    signal state_inc:       std_logic := '0';

    signal bcd_val:         std_logic_vector(3 downto 0) := "1110";
    signal clk:             std_logic := '0';

    signal scanned_val:     std_logic_vector(6 downto 0);
    signal original_col:    std_logic_vector(2 downto 0);
    signal scan_complete:   std_logic;

begin

scanner_sm: 
    process (clk)
    begin
        if clk'event and clk = '1' then

            if state_inc = '1' then

                scan_complete <= '0';

                case my_state is

                    when state_column_1 =>
                        scanned_val  <= (others => '0');
                        original_col   <= "110";
                        my_state <= scan_col_1;

                    when scan_col_1 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1100100";  -- 1 wrong
                            when "1101" => scanned_val <= "1100010";  -- 2 wrong
                            when others => scanned_val <= "0010000";
                        end case;
                        my_state <= state_column_2;

                    when state_column_2 =>
                        original_col   <= "011";
                        my_state <= scan_col_2;

                    when scan_col_2 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1011011";  -- 5 wrong
                            when "1101" => scanned_val <= "1011111";  -- 6 wrong
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_3;

                    when state_column_3 =>
                        original_col   <= "101";
                        my_state <= scan_col_3;

                    when scan_col_3 => -- Reading S1 // The only working state
                        case bcd_val is
                            when "1110" => scanned_val <= "1100000";  -- 9/ 1
                            when "1101" => scanned_val <= "0111110";  -- X/ 2
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_1; -- ************ Error might be here
                        scan_complete <= '1'; -- ********** Error might be here

                    when others => scanned_val <= "0000000";
                end case;

          end if;
      end if;
    end process scanner_sm;

CLOCK:
    process 
    begin
       wait for 10 ns;
       clk <= not clk;
       if Now > 200 ns then
           wait;
       end if;
    end process;

STIMULUS:
    process
    begin
        wait for 30 ns;
        state_inc <= '1';
        wait;
    end process;

end architecture;

Виждате, че няма следващо състояние. Познайте какво работи.

Забавих state_inc с един часовник, преди да заявя, за да покажа защо трябва да нулирате:

foo_tb вълнова форма

Можете да видите състоянието на scan_complete, scanned_val и original_col първоначално са неизвестни, докато не бъдат записани. Можете също така да нулирате my_state.

Можете да видите както от горната симулация, така и от итерациите, че вашата държавна машина преминава през всичките шест състояния. Ако се забие някъде, бихте очаквали state_inc да не е валиден (и също така не е очевидно какво го прави невалиден от вашия процес).

Освен че нямате нулиране, очевидно нищо не е наред с вашата машина за състояние, проблемът изглежда е другаде или е свързан с операция на границата на състоянието, спираща възникването на state_inc.

Бих имал обаче, че може да се нуждаете от допълнително състояние за сигнализиране на завършеното сканиране и стартиране на следващото сканиране, в противен случай всеки state_inc, който все още е валиден, ще предизвика следващия кръг от преходи на състояния. (Между scan_col3 и state_column_1, в съответствие с вашите коментари „************ Тук може да е грешка“).

Добавянето на нулиране и допълнително състояние (име - завършено?), което продължава само един часовник, може да се направи от:

 if state_inc = '1' or my_state = complete then

където настоящето

  if state_inc = '1' then

is.

Това би дало какъвто и да е шанс да реагира на scan_complete, преди да премине към state_column_1. Може да проверите дали завършено трябва да се наименува start_or_complete и да бъде първото състояние.

Единственото нещо, което направих с вашия процес, беше да променя отстъпа, за да е по-лесно да се види къде в инструкциите if пада всичко.

(И ние ви предупредихме, че бихме искали да видим повече от вашия модел)

person Community    schedule 03.05.2014
comment
Можете ли да споделите файла си test_bench? - person Anarkie; 04.05.2014
comment
Копирайте и поставете горния VHDL изходен код във файл, анализирайте, разработете и симулирайте. Има една общо разпознаваема характеристика на тестовия стенд на VHDL, липсата на порт интерфейс в декларацията на обекта. Тестовият стенд също ще съдържа източник на часовник, ако е необходимо, както и стимул за упражняване на спецификацията на дизайна на VHDL. Това, което е уникално за този, е, че сте предоставили само процес, така че няма инстанциране на компонент, по-скоро вашият процес е включен директно. - person ; 04.05.2014
comment
Най-накрая разбрах защо превключването не работи поради моята верига за премахване на отскок. Когато изтрия веригата за отблъскване, тя работи. Копирах този debounce от интернет. Логиката има смисъл за мен, но защо не работи, не знам. Добавих моята верига за премахване на отскок към въпроса. - person Anarkie; 06.05.2014