2016-07-11 16 views
0

Ich entwickle eine Zustandsmaschine in VHDL und es scheint nicht zu funktionieren. Das Design ist unten gezeigt:VHDL-Zustandsmaschine überspringt Zustände

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; 

Die Zustandsmaschine wird mit 25 MHz getaktet. Per meinem Verständnis sollte meine Zustandsmaschine zwischen den Zuständen Fortschritt wie folgt:

enter image description here

Doch was ich sehe, wenn ich meine Logikanalysator Haken ist die folgende:

enter image description here

Es Es scheint so, als ob die Zustandsmaschine nur einmal zwischen den Sende- und Sendebestätigungszuständen wechselt, im Gegensatz zu dem 11-fachen, das es sein sollte, und ich kann nicht herausfinden, warum.

+0

Sie sollten 'XMStateMachine' machen genügt ein getakteter Prozess. – Thanushan

Antwort

1

Wenn Sie XM_INDEX ein Signal zu machen haben eine XM_INDEX_NEXT dass in Ihrem XMStateMachineClock Prozess zwischengespeichert und dann XM_INDEX := XM_INDEX + 1-XM_INDEX_NEXT <= XM_INDEX + 1 ändern. Ich glaube, dass dies Ihr Problem beheben wird. XMStateMachine muss auch empfindlich auf XM_INDEX sein.

+0

Fehlen eines [MCVE] (http://stackoverflow.com/help/mcve), eine Erklärung. Wenn TRANSMIT_CHAR_CONFIRM sicher als Latch-Aktivierung verwendet werden kann, gilt Folgendes: xm_index: = xm_index + 1; wird fortlaufender Änderungswert, wenn TRANSMIT_CHAR_CONFIRM wahr ist, gibt es eine kombinatorische Schleife. xm_index wird zu einem gegateten Oszillator, der durch die möglichen Werte von xm_index rippelt. Die Addierverzögerung scheint Ihnen xm_index> 11 in einem clk25 zu geben. Ohne xm_index in der Empfindlichkeitsliste würde es sogar scheinbar korrekt simulieren. Synthesewerkzeuge melden im Allgemeinen kombinatorische Schleifen. – user1155120

+0

Sie könnten auch xm_index ein Signal setzen, das im getakteten Prozess zugewiesen wurde. 'If xm_current_state = TRANSMIT_CHAR_CONFIRM, dann xm_index <= xm_index + 1; end if; 'Beachten Sie, dass keine andere Verwendung von xm_index als xm_index <11 angezeigt wurde. Die Erhöhung auf" rising_edge "(clk25) muss als sicher für andere Verwendungen angesehen werden. Brian Drummond könnte hier auftauchen und erwähnen, dass diese Probleme in Einzelprozessstatusmaschinen seltener auftreten. – user1155120

+0

Für die Simulation sollte xm_index vor einem Überlauf geschützt werden (oder zu einem unsignierten Array-Typ-Wert gemacht und für andere nicht gezeigte Zwecke konvertiert werden - der Fluch eines fehlenden MCVE). – user1155120

1

Der Beispielcode ist nicht konkurrieren und es gibt eine Chance chaning xm_index von einer gemeinsamen Variablen könnte einige Pläne für die Verwendung stören, sollte mehr als ein Prozess zu schreiben. Sie können feststellen, dass der Benutzer für die Kontrolle des exklusiven Zugriffs in gemeinsam genutzten Variablen von -1993 verantwortlich ist.

Erstellen eines MCVE durch eine komplette Einheit und Architektur Paar bereitstellt:

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; 

Dies ändert xm_index auf ein Signal ist und einen nächsten Wert von Alden in seiner Antwort vorgeschlagen. Dies funktioniert, solange nur ein Prozess darauf schreibt. xm_index wird jetzt beim Zurücksetzen ebenfalls auf 0 gesetzt. Zusätzlich ist in der TRANSMIT_CHAR_CONFIRM der Case-Anweisung xm_currrent_state xm_index selbstverständlich gegen Überlauf geschützt. Der Bereich von xm_index (0 bis 99) kann auf den maximalen Wert (11) begrenzt werden. Es entsteht der Verdacht, dass wir nicht das ganze Design sehen.

Hinzufügen eines Prüfstandes:

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; 

und wir erhalten:

xm_sm_tb_fixed.png

Wo wir sehen, wir gehen durch alle Indexwerte vor der Fertigstellung.

Der ursprüngliche Code erfolgreich simuliert aber scheint haben zu einem Arbeitsentwurf aufgrund der kombinatorischen Schleife nicht synthetisiert:

XM_INDEX := XM_INDEX + 1; 

wo xm_loop durch eine vermutlich einen heißen Zustand Darstellung für den Zustand TRANSMIT_CHAR_CONFIRM als Latch zwischengespeichert ermöglichen .

In der Simulation würde die Empfindlichkeitsliste, die keinen xm_index enthält, verhindern, dass der Addierer eine Welligkeit aufweist, die xm_index inkrementiert. Wenn sich xm_index in der Liste der Prozesssensitivität befunden hätte, hätte dies nach Erreichen von 100 eine Grenzwertüberprüfungsverletzung bei der Zuweisung verursacht. (Ganzzahlarten sind nicht modular, sie werden nicht umgebrochen und sind nicht gegen einen Überlauf geschützt).

In Synthese, ohne die Ausgabe der Konsole zu sehen, könnten wir davon ausgehen, dass die ripply Zeit den Wert von xm_index über 11 zuverlässig in einer Taktzeit zu schieben, ohne Verpackung auf weniger als 11.