Search code examples
vhdlquartusintel-fpga

Output 'X' instead of '1' or '0' in VHDL


I am working on a code convertor using multiplexors and I am facing issues when testing it on ModelSim. Basically it outputs X where there should output 1.

I found out that the error may be where I put others >= '0' as when I changed it to 1; the opposite occurred where the X appeared where there should be a 0.

Here's my code:

use IEEE.std_logic_1164.all;

entity mux8x1 is
port( s : in std_logic_vector(2 downto 0);
i : in std_logic_vector(7 downto 0);
m2b:out std_logic);
end;

architecture behave of mux8x1 is

begin

m2b <= i(0) when s="000" else
       i(1) when s="001" else
       i(2) when s="010" else
       i(3) when s="011" else
       i(4) when s="100" else
       i(5) when s="101" else
       i(6) when s="110" else
       i(7);

end;

and

use IEEE.std_logic_1164.all;

entity mux_example is
port( A : in std_logic;
       B : in std_logic;
       C : in std_logic;
       D : in std_logic;
       W : out std_logic;
       X : out std_logic;
       Y : out std_logic;
       Z : out std_logic);
end;

architecture struct of mux_example is
  
begin

  -- Mux instantiations

  mux1: entity work.mux8x1
    port map (
      s => "000",
      i => (others => '0'),
      m2b => W
    );

  mux2: entity work.mux8x1
    port map (
      s => "001",
      i => (others => '0'),
      m2b => X
    );

  mux3: entity work.mux8x1
    port map (
      s => "011", 
      i => (others => '0'), 
      m2b => Y
    );

  mux4: entity work.mux8x1 
    port map (
      s => "100", 
      i => (others => '0'), 
      m2b => Z
    );

  -- Combinatorial logic

  W <= (A and not B and C) or 
       (A and C and not D) or 
       (A and B and not C and D) or 
       (not A and B and C and D) or 
       (not A and not B and not C and D);
  X <= (B and not C and not D) or 
       (not B and not C and D) or 
       (not A and B and C) or 
       (not B and C and not D);
  Y <= (A and B and not C) or
       (not C and D) or
       (not A and D);
  Z <= (not A and not B and D) or
       (B and not D);
  
end architecture;

Solution

  • The 'X' value of std_logic means "unknown," and it arises in simulation when there's a tug-of-war between multiple drivers of a single std_logic signal driving conflicting values, i.e. one concurrent assignment is driving '0' at the same time another is driving '1'. This is what's happening in your code - let's consider just one mux:

    architecture mixed of mux_example is
    
    begin
    
      -- This entity instantiation statement is a concurrent statement that
      -- connects the signal W to the m2b port of the mux. When the design
      -- is compiled, you're telling your tool to drive W with the
      -- assignment inside the mux entity to m2b. Because you're setting i
      -- to all zeroes for your example code, no matter what, this concurrent
      -- assignment to W will give W a driver and make it drive '0'.
      mux1: entity work.mux8x1 port map (s => "000", i => (others => '0'), m2b => W);
    
      -- This concurrent assignment statement is separate from the one above.
      -- Because it assigns to W, it will also create a driver for W.
      W <= (A and not B and C) or
        (A and C and not D) or
        (A and B and not C and D) or
        (not A and B and C and D) or
        (not A and not B and not C and D);
    
    end architecture;
    

    So you have two drivers driving values to W because you have two concurrent statements that assign values to it. For a std_logic type, since it is a resolved type, this will trigger your simulator to use the resolution function to settle on a value. Thus:

    • If the logic for the second assignment to W yields '0', then the drivers agree and the resolution is simply '0'.

    • If the logic for the second assignment to W yields '1', then the simulator has no reason to choose one driver over the other, so the conflict resolves to 'X' - unknown.

    When you flipped the value of the others assignment, this is why it flipped to 'X' where you expect '0' - it's the same process but with the logic inverted.

    This answers the question you raise in the title - why you're seeing 'X' instead of what you expect - but, as others have pointed out, your inputs A, B, C, and D are doing nothing so far as your muxes are concerned, and the muxes themselves, I assume for the sake of example to reproduce the unknown driver resolution, are not doing anything functional. You need to decide whether you want the combinatorial logic or the mux driving W and the other outputs, but that's a separate design consideration.

    One practice you might consider is using std_ulogic rather than std_logic for wires that are not intentionally driven by multiple sources. Because std_ulogic is unresolved (hence the "u"), the compiler will throw an error rather than use a resolution function to handle the drivers.

    Another point to consider is that your architecture struct isn't purely structural, as you've mixed behavioral logic with your instantiations. Some designers prefer to avoid mixed architectures, both for readability and modularity considerations and to avoid potential pitfalls like this one.