2016-07-11 5 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 MHzでクロックされています。それは

enter image description here

:私の理解あたり以下のように、私のステートマシンは状態間で進行する必要があります

enter image description here

しかし、私は私が私のロジック・アナライザは、次のされてフックアップ時に見えるものあたかも状態マシンが送信と送信の確認状態を1回だけ交互にしているかのように見えますが、これは11回とは対照的です。理由は分かりません。

+0

にラップすることなく、1クロック時間で確実に11の上方xm_indexの値をプッシュするのに十分であることを推測かもしれません 'XMStateMachine'クロックプロセス。 – Thanushan

答えて

1

あなたはXM_INDEX信号を作る場合、あなたのXMStateMachineClockプロセスにラッチし、その後XM_INDEX_NEXT <= XM_INDEX + 1XM_INDEX := XM_INDEX + 1に変更されXM_INDEX_NEXTを持っています。私はこれがあなたの問題を解決すると信じています。 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の可能な値を波及するゲート発振器になります。加算遅延は、1つのclk25にxm_index> 11を与えるように見えます。機密性リストにxm_indexがなければ、明らかに正しくシミュレートされます。合成ツールは、一般的にコンビナトリアルループを報告します。 – user1155120

+0

また、xm_indexをクロック式プロセス 'xm_current_state = TRANSMIT_CHAR_CONFIRM、次にxm_index <= xm_index + 1;で指定した信号に割り当てることもできます。 xm_index <11以外にxm_indexを使用していないことに注意してください。rising_edge(clk25)でインクリメントすることは、他の用途には安全とみなす必要があります。 Brian Drummondがここでポップアップし、これらの問題がシングルプロセスステートマシンで発生することはあまりありません。 – user1155120

+0

シミュレーションの場合、xm_indexはオーバーフローから保護する必要があります(または、符号なし配列タイプの値にし、MCVEがないという呪いのような他の用途に変換してください)。 – user1155120

1

例のコードは競合しておらず、共有変数からxm_indexをchaningすると、複数のプロセスがそれに書き込むべきである場合、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変更し、彼の答えにオールデンにより示唆されるように次の値を含みます。これは、それに書き込むプロセスが1つしかない限り機能します。 xm_indexもリセット時に0に設定されるようになりました。さらに、xm_currrent_stateのcase文のTRANSMIT_CHAR_CONFIRMでは、もちろん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

を。

元のコードが正常にシミュレートされたが、原因combinatoricalループに取り組んデザインに合成されていないように見えます:

ラッチが有効とxm_loopが状態TRANSMIT_CHAR_CONFIRMため、おそらく1つの熱い状態表現によってラッチされ
XM_INDEX := XM_INDEX + 1; 

シミュレーションでは、xm_indexがない感度リストは、加算器がxm_indexをリップルさせることを防止します。 xm_indexがプロセスの機密性リストに含まれていた場合は、100に達した後に割り当てに対して境界チェック違反が発生します(整数型はモジュール化されていないため、ラップされず、オーバーフローに対して校正されません)。

合成において

コンソール出力を見ることなく、我々はripply時間はあなたが作るべき11未満

関連する問題