I recently added 'X' propagation to my RT-Level VHDL designs, to detect early whenever operations take place on unknown ('X') or uninitialized ('U') values. The latter may come from registers, which I forgot to reset, or from memory which cannot be reset at all. Unknown values may come from logic operations on uninitialized values. I do not care about unknown or uninitialized values as long as they do not lead to undefined behavior, e.g., undefined state changes in a finite state machine (FSM). I do not distinguish between 'X', 'U' or any other meta-value, all are treated as 'X'.
I'm familiar with applying 'X' propagation to data paths, but I struggle to apply it to FSMs because the code is getting much more complex and readability is decreasing. Here is a stripped-down example, how my FSMs with 'X' propagation look like:
library ieee; use ieee.std_logic_1164.all; entity fsm is port ( clock : in std_logic; reset : in std_logic; input : in std_logic_vector(1 downto 0); output : out std_logic); -- mealy output end entity fsm; architecture rtl of fsm is type states is (RUNNING, WAITING, UNKNOWN); signal state : states -- synthesis translate_off := UNKNOWN -- synthesis translate_on ; signal next_state : states; begin -- architecture rtl process(state, input) begin next_state <= state; output <= '0'; case state is when RUNNING => case input(1) and not input(0) is -- some complex condition when '1' => next_state <= WAITING; when '0' => output <= '1'; when others => next_state <= UNKNOWN; output <= 'X'; end case; when WAITING => next_state <= RUNNING; when UNKNOWN => output <= 'X'; end case; end process; process(clock) begin if rising_edge(clock) then case to_x01(reset) is when '1' => state <= RUNNING; when '0' => state <= next_state; when others => state <= UNKNOWN; end case; end if; end process; end architecture rtl;
case statements to check inputs for some condition, so that, I don't have to repeat the condition as with
if (input(1) and not input(0)) = '1' then next_state <= WAITING; elsif (input(1) and not input(0)) = '0' then -- repeated condition output <= '1'; else next_state <= UNKNOWN; output <= 'X'; end if;
I do not find the
case statement very readable because without 'X' propagation, the condition would be much more clearer:
if input(1) = '1' and input(0) = '0' then next_state <= WAITING; else output <= '1'; end if;
Another problem is to keep track when mealy outputs will be unknown. In the example above
output will be unknown when the condition is undetermined.
So my questions are:
Should I propagate 'X' values (to the FSM state and mealy outputs) or should I just
Is there a more readable code template to test complex conditions as in the example above?
Is there a better method to check wether a correct reset has been applied? (Note: the state should still be unknown until the first rising clock-edge!)
All after all: the code must be synthesizable. (Due to the synthesis guard, the state UNKNOWN will never be reached in real HW and is thus optimized away.)