2016-07-11 3 views
0

Я разрабатываю машину состояний в VHDL, и она, похоже, не работает должным образом. Конструкция показана ниже:Состояние машины VHDL пропускает состояния

SHARED VARIABLE XM_INDEX : NATURAL RANGE 0 TO 99 := 0; 
SIGNAL XM_STATE_INDICATOR : STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000000"; 
TYPE XM_STATE_TYPE IS (EMPTY, IDLE, POWER_UP, POWER_UP_CONFIRM, 
         CHANNEL_SELECT, CHANNEL_SELECT_CONFIRM, VOLUME_CHANGE, 
         VOLUME_CHANGE_CONFIRM, TRANSMIT_CHAR, TRANSMIT_CHAR_CONFIRM, 
         COMPLETED); 
SIGNAL XM_CURRENT_STATE : XM_STATE_TYPE := EMPTY; 
SIGNAL XM_NEXT_STATE : XM_STATE_TYPE := EMPTY; 

XMStateMachineClock: PROCESS (CLK25, SYS_RST) IS 
BEGIN 
    IF (SYS_RST = '1') THEN 
     XM_CURRENT_STATE <= EMPTY; 
    ELSIF (RISING_EDGE(CLK25)) THEN 
     XM_CURRENT_STATE <= XM_NEXT_STATE; 
    END IF;    
END PROCESS XMStateMachineClock; 

XMStateMachine: PROCESS (XM_CURRENT_STATE) IS 
BEGIN 
    -- Pend on current XM state 
    CASE XM_CURRENT_STATE IS 

     -- Empty: Debug only 
     WHEN EMPTY => 
     XM_NEXT_STATE <= IDLE; 
     XM_STATE_INDICATOR <= "00000001"; 

     -- Idle: Idle state 
     WHEN IDLE => 
     IF XM_POWER_UP = '1' THEN 
      XM_INDEX := 0; 
      XM_NEXT_STATE <= POWER_UP; 
      XM_STATE_INDICATOR <= "00000010"; 
     ELSE 
      -- Remain in idle 
      XM_NEXT_STATE <= IDLE; 
      XM_STATE_INDICATOR <= "00000001"; 
     END IF; 

     WHEN POWER_UP => 
     XM_NEXT_STATE <= TRANSMIT_CHAR; 
     XM_STATE_INDICATOR <= "00000100"; 

     WHEN TRANSMIT_CHAR => 
     IF (XM_INDEX < 11) THEN 
      XM_NEXT_STATE <= TRANSMIT_CHAR_CONFIRM; 
      XM_STATE_INDICATOR <= "00001000"; 
     ELSE 
      XM_NEXT_STATE <= COMPLETED; 
      XM_STATE_INDICATOR <= "00000000"; 
     END IF; 

     WHEN TRANSMIT_CHAR_CONFIRM => 
     XM_INDEX := XM_INDEX + 1; 
     XM_NEXT_STATE <= TRANSMIT_CHAR; 
     XM_STATE_INDICATOR <= "00000100"; 

     WHEN COMPLETED => 
     XM_NEXT_STATE <= COMPLETED; 
     XM_STATE_INDICATOR <= "00000000"; 

     -- Default 
     WHEN OTHERS => 

    END CASE; 
END PROCESS XMStateMachine; 

Головной аппарат работает на частоте 25 МГц. За мое понимание, мое состояние машины должны прогрессировать между состояниями следующим образом:

enter image description here

Однако то, что я вижу, когда я подключить мой логический анализатор состоит в следующем:

enter image description here

Это кажется, что машина состояния только чередуется между состояниями подтверждения передачи и передачи один раз, в отличие от 11 раз, которые должны, и я не могу понять, почему.

+0

Вы должны сделать 'XMStateMachine' синхронизированный процесс. – Thanushan

ответ

1

Если вы XM_INDEX сигнал есть XM_INDEX_NEXT, который защелкивается в вашем XMStateMachineClock процессе, а затем изменить XM_INDEX := XM_INDEX + 1 к XM_INDEX_NEXT <= XM_INDEX + 1. Я считаю, что это решит вашу проблему. XMStateMachine также должен быть чувствительным к XM_INDEX.

+0

Отсутствие [MCVE] (http://stackoverflow.com/help/mcve), объяснение. Если TRANSMIT_CHAR_CONFIRM безопасно использовать в качестве защелки, xm_index: = xm_index + 1; будет непрерывно изменяться, когда TRANSMIT_CHAR_CONFIRM истинно, есть комбинаторный цикл. xm_index становится замкнутым генератором, колеблющимся через возможные значения xm_index. Задержка сумматора дает вам xm_index> 11 в одном clk25. Без xm_index в списке чувствительности он даже имитировал бы, по-видимому, правильно. Инструменты синтеза обычно сообщают о комбинаторных циклах. – user1155120

+0

Вы также можете сделать xm_index сигнал, назначенный в синхронизированном процессе 'if xm_current_state = TRANSMIT_CHAR_CONFIRM, а затем xm_index <= xm_index + 1; end if; 'Обратите внимание, что никакое другое использование xm_index не было показано иначе, чем xm_index <11. Приращение его на raise_edge (clk25) должно считаться безопасным для любых других целей. Брайан Драммонд может появиться здесь, и упоминание этих проблем возникает нечасто в машинах с одним процессом. – user1155120

+0

Для моделирования xm_index следует защитить от переполнения (или получить значение типа без знака и преобразовать для других видов использования, которые не показаны - проклятие отсутствия MCVE). – user1155120

1

Пример кода не конкурирует, и существует некоторая вероятность перебора xm_index из общей переменной, которая может нарушить некоторые планы ее использования, если к ней нужно написать несколько процессов. Вы могли заметить, что пользователь отвечает за контроль над эксклюзивным доступом в -1993 общих переменных.

Создание MCVE путем предоставления полной сущности и архитектуры пары:

library ieee; 
use ieee.std_logic_1164.all; 

entity xm_sm is 
    port (
     clk25:    in std_logic; 
     sys_rst:   in std_logic; 
     xm_power_up:  in std_logic 
    ); 
end entity; 

architecture foo of xm_sm is 

    -- shared variable xm_index: natural range 0 to 99 := 0; 
    signal xm_index:   natural range 0 to 99 := 0; -- CHANGED to SIGNAL 
    signal xm_index_nxt:  natural range 0 to 99; -- ADDED 
    signal xm_state_indicator: std_logic_vector (7 downto 0) := "00000000"; 

    type xm_state_type is  (EMPTY, IDLE, POWER_UP, POWER_UP_CONFIRM, 
           CHANNEL_SELECT, CHANNEL_SELECT_CONFIRM, 
           VOLUME_CHANGE, VOLUME_CHANGE_CONFIRM, 
           TRANSMIT_CHAR, TRANSMIT_CHAR_CONFIRM, 
           COMPLETED); 
    signal xm_current_state: xm_state_type := EMPTY; 
    signal xm_next_state:  xm_state_type := EMPTY; 

begin 

xmstatemachineclock: 
    process (clk25, sys_rst) is 
    begin 
     if sys_rst = '1' then 
      xm_current_state <= EMPTY; 
      xm_index <= 0; -- ADDED 
     elsif rising_edge(clk25) then 
      xm_current_state <= xm_next_state; 
      xm_index <= xm_index_nxt; -- ADDED 
     end if;    
    end process xmstatemachineclock; 

xmstatemachine: 
    process (xm_current_state, xm_power_up) is 
    begin 
     -- pend on current xm state 
     case xm_current_state is 

      -- empty: debug only 
      when EMPTY => 
       xm_next_state <= IDLE; 
       xm_state_indicator <= "00000001"; 

      -- idle: idle state 
      when IDLE => 
       if xm_power_up = '1' then 
        xm_index_nxt <= 0; 
        xm_next_state <= POWER_UP; 
        xm_state_indicator <= "00000010"; 
       else 
        -- remain in idle 
        xm_next_state <= IDLE; 
        xm_state_indicator <= "00000001"; 
       end if; 

      when POWER_UP => 
       xm_next_state <= TRANSMIT_CHAR; 
       xm_state_indicator <= "00000100"; 

      when TRANSMIT_CHAR => 
       if xm_index < 11 then 
        xm_next_state <= TRANSMIT_CHAR_CONFIRM; 
        xm_state_indicator <= "00001000"; 
       else 
        xm_next_state <= COMPLETED; 
        xm_state_indicator <= "00000000"; 
       end if; 

      when TRANSMIT_CHAR_CONFIRM => 
       if xm_index = 99 then -- protect again overflow -- ADDED 
        xm_index_nxt <= 0; 
       else 
        xm_index_nxt <= xm_index + 1; -- CHANGED 
       end if; 
       -- xm_index_nxt <= xm_index + 1; 
       xm_next_state <= TRANSMIT_CHAR; 
       xm_state_indicator <= "00000100"; 

      when COMPLETED => 
       xm_next_state <= COMPLETED; 
       xm_state_indicator <= "00000000"; 

      -- default 
      when others => 

     end case; 
    end process xmstatemachine; 
end architecture; 

Это меняет xm_index на сигнал и в том числе следующее значение, как было предложено Олден в своем ответе. Это работает, пока есть только один процесс, который пишет ему. xm_index также теперь устанавливается на 0 во время сброса. Кроме того, в TransSMIT_CHAR_CONFIRM оператора xm_currrent_state xm_index защищен от переполнения, как само собой разумеющееся. Диапазон xm_index (от 0 до 99) может быть ограничен максимальным значением (11). Это вызывает подозрения, что мы не видим весь дизайн.

Добавление тестового стенда:

library ieee; 
use ieee.std_logic_1164.all; 

entity xm_sm_tb is 
end entity; 

architecture foo of xm_sm_tb is 
    signal clk25:  std_logic := '0'; 
    signal sys_rst:  std_logic := '0'; 
    signal xm_power_up: std_logic := '0'; 
begin 
DUT: 
    entity work.xm_sm 
     port map (
      clk25 => clk25, 
      sys_rst => sys_rst, 
      xm_power_up => xm_power_up 
     ); 
CLOCK: 
    process 
    begin 
     wait for 50 ns; 
     clk25 <= not clk25; 
     if now > 3.1 us then 
      wait; 
     end if; 
    end process; 
STIMULI: 
    process 
    begin 
     wait for 100 ns; 
     sys_rst <= '1'; 
     wait for 100 ns; 
     sys_rst <= '0'; 
     wait for 200 ns; 
     xm_power_up <= '1'; 
     wait for 100 ns; 
     xm_power_up <= '0'; 
     wait; 
    end process; 
end architecture; 

и мы получаем:

xm_sm_tb_fixed.png

Где мы видим, мы проходим через все значения индекса до окончания.

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

XM_INDEX := XM_INDEX + 1; 

, где xm_loop фиксируется с помощью предположительно одного горячего состоянием представления для государственной TRANSMIT_CHAR_CONFIRM в качестве защелки позволит ,

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

В синтезе, не видя консольный вывод мы можем предположить, что волнообразное время достаточно нажать значение xm_index выше 11 надежно в одно времени часов без упаковки менее чем 11.

Смежные вопросы