title: VHDL FSM not changing states
body: <p>Hey I'm a beginner when it comes to VHDL and currently I'm trying to write a protocol decoder for the open pixel control (OPC) protocol: <a href="http://openpixelcontrol.org/" rel="nofollow noreferrer">http://openpixelcontrol.org/</a></p>
  
  <p>I have implemented a FSM in VHDL to decode the OPC messages by reading bytes from a serial/RS232 receiver. 
  The RX module outputs the received byte as a std_logic_vector and creates a data ready pulse that is one gclk cycle long.</p>
  
  <p>In my top level entity I have connected the RX and the decoder modules to the same global clock net. The data ready pulse from the RX module is directly connected to the i_dataready input of the FSM in question.</p>
  
  <p>Although I have checked  the code for this FSM multiple times in the last couple of days and also searching a fair bit I couldn't find out why my FSM won't change states.</p>
  
  <p>The thing that puzzles me is that two other modules, a serial TX and another module change states just fine upon receiving the data ready signal from the RX module, it's just this FSM that doesn't work.</p>
  
  <p>This is the code that I have written:</p>
  
  <p>EDIT: okay I've done some more simulation of my complete top level entity:
  The system is currently running at 2MHz (I know very slow but it's all I can do right now).</p>
  
  <p>According to simulation in Active-HDL the system <em>should</em> work as expected.</p>
  
  <p>Here is my top level entity:</p>
  
  <pre><code>library IEEE;
  use IEEE.STD_LOGIC_1164.all;
  
  entity serial_test is 
      port(
          i_gclk: in std_logic;
          i_rx: in std_logic;
          o_tx: out std_logic;
          o_go: out std_logic;
          o_newdata: out std_logic;
          o_ws: out std_logic;
          o_leds: out std_logic_vector(2 downto 0)
      );
  end serial_test;
  
  architecture rtl of serial_test is
  
      signal txact, txdone: std_logic;
  
      signal rxdata: std_logic_vector(7 downto 0);
      signal rgbdata: std_logic_vector(7 downto 0);
      signal opc_chan: std_logic_vector(7 downto 0);
      signal go: std_logic;
      signal opc_state: std_logic_vector(2 downto 0);
      signal newrgb: std_logic;
  
  begin
  
      opcdec_inst: entity work.opc_decoder
          port map(i_gclk =&gt; i_gclk, i_dataready =&gt; go, i_rawdata =&gt; rxdata, o_channel =&gt; opc_chan, o_rgbdata =&gt; rgbdata, o_state =&gt; opc_state, o_newdata =&gt; newrgb);
  
      urx_inst: entity work.uart_rx    
          port map(i_clk =&gt; i_gclk, i_rx_serial =&gt; i_rx, o_rx_dv =&gt; go, o_rx_byte =&gt; rxdata);
  
      utx_inst: entity work.uart_tx    
          port map(i_clk =&gt; i_gclk, i_tx_dv =&gt; go, i_tx_byte =&gt; rxdata, o_tx_active =&gt; txact, o_tx_serial =&gt; o_tx, o_tx_done =&gt; txdone);
  
      wsdrv_inst: entity work.ws2812_driver
          port map(i_gclk =&gt; i_gclk, i_rgbdata =&gt; rgbdata, i_newdata =&gt; newrgb, o_serial =&gt; o_ws);
  
      -- output FSM state to LEDs 
      o_leds &lt;= opc_state;
  
      -- output go signal for signal analyzer
      o_go &lt;= go;
      o_newdata &lt;= newrgb;
  
  end rtl;
  </code></pre>
  
  <p>My testbench for the top level entity</p>
  
  <pre><code>LIBRARY ieee;
  USE ieee.std_logic_1164.ALL;
  USE ieee.numeric_std.ALL;
  
  ENTITY testbench IS
  END testbench;
  
  ARCHITECTURE behavior OF testbench IS 
  
      COMPONENT serial_test
      PORT(
          i_gclk : IN std_logic;
          i_rx : IN std_logic;
          o_tx: OUT std_logic;
          o_go : OUT std_logic;
          o_newdata : OUT std_logic;
          o_ws : OUT std_logic;
          o_leds : OUT std_logic_vector(2 downto 0)
          );
      END COMPONENT;
  
      SIGNAL i_gclk :  std_logic := '1';
      SIGNAL i_rx :  std_logic := '1';    
      SIGNAL o_tx : std_logic;
      SIGNAL o_go :  std_logic;
      SIGNAL o_newdata :  std_logic;
      SIGNAL o_ws :  std_logic;
      SIGNAL o_leds :  std_logic_vector(2 downto 0);
  
  BEGIN
  
  -- Please check and add your generic clause manually
      uut: serial_test PORT MAP(
          i_gclk =&gt; i_gclk,
          i_rx =&gt; i_rx,    
          o_tx =&gt; o_tx,
          o_go =&gt; o_go,
          o_newdata =&gt; o_newdata,
          o_ws =&gt; o_ws,
          o_leds =&gt; o_leds
      );
  
      p_GCLK: process
      begin
          i_gclk &lt;= not i_gclk;
          wait for 250ns;
      end process p_GCLK;
  
      p_RX: process
      begin  
          --wait for 375ns;
          wait for 1ms;
          -- first byte: 0x01  (CHANNEL)
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          -- second byte: 0x00  (COMMAND)
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          -- third byte 0x00(LENGTH MSB)
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          -- fourth byte 0x03 (LENGTH LSB)
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          -- fifth byte 0xCD
          i_rx &lt;= '0';
          wait for 104us;
  
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          i_rx &lt;= '1';
          wait for 104us;
  
          -- sixth byte 0xBA
          i_rx &lt;= '0';
          wait for 104us;
  
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          i_rx &lt;= '1';
          wait for 104us;
  
          -- seventh byte 0xFE
          i_rx &lt;= '0';
          wait for 104us;
  
          i_rx &lt;= '0';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
          i_rx &lt;= '1';
          wait for 104us;
  
          i_rx &lt;= '1';
          wait for 104us;
  
          wait for 10ms;
  
      end process p_RX;
  
  END;
  </code></pre>
  
  <p>Here you can see the waveforms that the simulator produces. It clearly shows that at least in simulation the FSM does indeed change states and even o_newdata works as expected.
  eliaselectronics.com/wp-content/uploads/2014/08/opc_dec_simulation.jpg
  (sorry I can't yet post images on StackOverflow, uploaded them to my webiste instead)</p>
  
  <p><img src="https://i.stack.imgur.com/2nzWg.jpg" alt="opc_dec_simulation.jpg"></p>
  
  <p>This screenshot shows the signals from the Lattice CPLD that were actually measured with the logic analyzer. 
  In this case we can see that there is no change in states, o_ws and o_newdata don't change either.
  eliaselectronics.com/wp-content/uploads/2014/08/opc_dec_measured.png</p>
  
  <p><img src="https://i.stack.imgur.com/qkptN.png" alt="opc_dec_measured.png"></p>
  
  <p>Now knowing that my FSM code <em>should</em> be okay, I presume this has something to do with the actual synthesis into hardware, maybe things like excessive propagation delay or clock skew. Is there a way to get around this in some way?</p>
  
  <p>This is the FSM code in question</p>
  
  <pre><code>library IEEE;
  use IEEE.STD_LOGIC_1164.all;
  use IEEE.NUMERIC_STD.all;
  
  entity opc_decoder is 
      port(
          i_gclk: in std_logic;                           -- global system clock
          i_dataready: in std_logic;                      -- data ready signal from previous block (length: 1 gclk cycle)
          i_rawdata: in std_logic_vector(7 downto 0);     -- raw byte received by previous block
          o_channel: out std_logic_vector(7 downto 0);    -- output channel address for output MUX
          o_rgbdata: out std_logic_vector(7 downto 0);    -- decoded OPC data byte (R|G|B)
          o_state: out std_logic_vector(2 downto 0); 
          o_newdata: out std_logic                        -- data synchronization signal for next block
      );
  end opc_decoder;
  
  architecture rtl of opc_decoder is
  
      type t_OPC_SM is (s_IDLE, s_OPC_CMD, s_OPC_LEN_HI, s_OPC_LEN_LO, s_OPC_DATA);
  
      signal r_OPC_SM: t_OPC_SM := s_IDLE;
  
      signal r_OPC_CHANNEL: std_logic_vector(7 downto 0); -- decoded channel number/address
      signal r_OPC_COUNT: unsigned(15 downto 0);  -- number of actual RGB data bytes to be received
  
  begin
  
      p_OPC_SM: process(i_gclk) is
      begin   
          if(rising_edge(i_gclk)) then
              o_newdata &lt;= '0';
  
              case r_OPC_SM is
  
                  when s_IDLE =&gt;
  
                      r_OPC_CHANNEL &lt;= (others=&gt;'0');
                      r_OPC_COUNT &lt;= (others=&gt;'0');
  
                      if(i_dataready = '1') then
                          r_OPC_CHANNEL &lt;= i_rawdata;
                          r_OPC_SM &lt;= s_OPC_CMD;
                      else
                          r_OPC_SM &lt;= s_IDLE;
                      end if;
  
                  when s_OPC_CMD =&gt;
  
                      if(i_dataready = '1') then
                          r_OPC_SM &lt;= s_OPC_LEN_HI;
                      else
                          r_OPC_SM &lt;= s_OPC_CMD;
                      end if;
  
                  when s_OPC_LEN_HI =&gt;
  
                      if(i_dataready = '1') then
                          r_OPC_COUNT &lt;= unsigned(i_rawdata) &amp; r_OPC_COUNT(7 downto 0);
                          r_OPC_SM &lt;= s_OPC_LEN_LO;
                      else
                          r_OPC_SM &lt;= s_OPC_LEN_HI;
                      end if;
  
                  when s_OPC_LEN_LO =&gt;
                      if(i_dataready = '1') then
                          r_OPC_COUNT &lt;= r_OPC_COUNT(15 downto 8) &amp; unsigned(i_rawdata);
                          r_OPC_SM &lt;= s_OPC_DATA;
                      else
                          r_OPC_SM &lt;= s_OPC_LEN_LO;
                      end if;
  
                  when s_OPC_DATA =&gt;
  
                      if(i_dataready = '1') then
                          if (r_OPC_COUNT &gt; 0) then
                              o_rgbdata &lt;= i_rawdata;
                              o_newdata &lt;= '1';
                              r_OPC_COUNT &lt;= r_OPC_COUNT - 1;
                              r_OPC_SM &lt;= s_OPC_DATA;
                          else
                              r_OPC_SM &lt;= s_IDLE;
                          end if;
                      else
                          r_OPC_SM &lt;= s_OPC_DATA;
                      end if;
  
                  when others =&gt;
                      r_OPC_SM &lt;= s_IDLE;
  
              end case;
          end if;
      end process p_OPC_SM;
  
      -- output state information 
      with r_OPC_SM select
          o_state &lt;= "001" when s_IDLE,
                     "010" when s_OPC_CMD,
                     "011" when s_OPC_LEN_HI,
                     "100" when s_OPC_LEN_LO,
                     "101" when s_OPC_DATA,
                     "000" when others;
  
      o_channel &lt;= r_OPC_CHANNEL;
  
  end rtl;
  </code></pre>
  
  <p>Thanks a lot, 
  Elia</p>