vhdlghdlgtkwave

vhdl and gate returning unknown value


I was implementing a multiplexer, but and gate returning "x" for no reason, pls help. As you can see in screenshot, result just became "x" from "1". i did a testbench for and gate, it works fine on its own. It should have been a 3 bit 4:1 multiplexer. this is the problem

This is source, i am using ghdl.

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;

ENTITY mux41 IS
    PORT (
        i1 : IN std_logic_vector(2 DOWNTO 0); 
        i2 : IN std_logic_vector(2 DOWNTO 0);
        i3 : IN std_logic_vector(2 DOWNTO 0);
        i4 : IN std_logic_vector(2 DOWNTO 0);
        sel : IN std_logic_vector(1 DOWNTO 0); 
        y : OUT std_logic_vector(2 DOWNTO 0)
        );
END mux41;


  
ARCHITECTURE rtl OF mux41 IS

COMPONENT andgate
PORT (
    input1 : IN std_logic;
    input2 : IN std_logic;
    input3 : IN std_logic;
    and_output : OUT std_logic
    );
END COMPONENT;

COMPONENT orgate
  PORT (
    input1 : IN std_logic;
    input2 : IN std_logic;
    input3 : IN std_logic;
    input4 : IN std_logic;
    or_output : OUT std_logic
  );
END COMPONENT;

signal not_sel : std_logic_vector(1 DOWNTO 0); 
signal and_result : std_logic_vector(3 DOWNTO 0);
signal or_result : std_logic_vector(2 DOWNTO 0);

BEGIN
    
    not_sel <= not sel;
    
    and_gate_assignment : for i in 0 to 2 generate
        and_output1: andgate port map(input1=>i1(i), input2=>not_sel(1), input3=>not_sel(0), and_output=>and_result(0));
        and_output2: andgate port map(input1=>i2(i), input2=>not_sel(1), input3=>sel(0), and_output=>and_result(1));
        and_output3: andgate port map(input1=>i3(i), input2=>sel(1), input3=>not_sel(0), and_output=>and_result(2));
        and_output4: andgate port map(input1=>i4(i), input2=>sel(1), input3=>sel(0), and_output=>and_result(3));
        or_output: orgate port map(input1=>and_result(0), input2=>and_result(1), input3=>and_result(2), input4=>and_result(3), or_output=>or_result(i));
    end generate and_gate_assignment;
    y <= or_result;
END rtl;

Here is the and gate;

library ieee;
use ieee.std_logic_1164.all;

entity andgate is
  port (
    input1 : in std_logic;
    input2 : in std_logic;
    input3 : in std_logic;
    and_output : out std_logic
  );
end andgate;

architecture rtl of andgate is
signal and1 : std_logic;
signal and2 : std_logic;
begin
    and1 <= input1 and input2;
    and2 <= and1 and input3;
    and_output <= and2;
end rtl;

there is not much to this really, could this be a timing issue?


Solution

  • Adding orgate's entity and architecture

    use ieee.std_logic_1164.all;
    
    entity orgate is
        port (
            input1:     in  std_logic;
            input2:     in  std_logic;
            input3:     in  std_logic;
            input4:     in  std_logic;
            or_output:  out std_logic
        );
    end entity;
    
    architecture foo of orgate is
    begin
        or_output <= input1 or input2 or input3 or input4;
    end architecture;
    

    and a testbench

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity mux41_tb is
    end entity;
    
    architecture foo of mux41_tb is
        signal i1:     std_logic_vector(2 downto 0); 
        signal i2:     std_logic_vector(2 downto 0);
        signal i3:     std_logic_vector(2 downto 0);
        signal i4:     std_logic_vector(2 downto 0);
        signal sel:    std_logic_vector(1 downto 0);
        signal y:      std_logic_vector(2 downto 0);
    begin
        
    DUT:
        entity work.mux41
            port map (
                i1 => i1,
                i2 => i2,
                i3 => i3,
                i4 => i4,
                sel => sel,
                y => y
            );
    
    STIMULI:
        process
        begin
            for i in 0 to 7 loop
                i1 <= std_logic_vector(to_unsigned(i, 3));
                for j in 0 to 7 loop
                    i2 <= std_logic_vector(to_unsigned(j, 3));
                    for k in 0 to 7 loop
                        i3 <= std_logic_vector(to_unsigned(k, 3));
                        for m in 0 to 7 loop
                            i4 <= std_logic_vector(to_unsigned(m, 3));
                            for n in 0 to 3 loop
                                sel <= std_logic_vector(to_unsigned(n,2));
                                wait for 10 ns;
                            end loop;
                        end loop;
                    end loop;
                end loop;
            end loop;
            wait;
        end process;
    end architecture;
    

    allows you readers to replicate your problem. Adding more signals may help to understand the problem:

    expanded waveform showing driver conflict

    'X's come from driver conflict. Here there are multiple drivers connected to and_result(3 downto 0) across the generated blocks. When all the drivers are '0' the signal is resolved to '0'. When there is a conflict there's an 'X'.

    The solution is to move the and_result declaration to the generate statement block declarative region (with a following begin separating declarations from statements):

    
    signal not_sel : std_logic_vector(1 DOWNTO 0); 
    -- signal and_result : std_logic_vector(3 DOWNTO 0); -- MOVE FROM HERE
    signal or_result : std_logic_vector(2 DOWNTO 0);
    
    BEGIN
        
        not_sel <= not sel;
        
        and_gate_assignment : for i in 0 to 2 generate
            signal and_result : std_logic_vector(3 DOWNTO 0); -- TO HERE
            BEGIN        -- AND ADD A FOLLOWING BEGIN
            and_output1: andgate port map(input1=>i1(i), input2=>not_sel(1), input3=>not_sel(0), and_output=>and_result(0));
    

    And that gives you

    fixed

    the intended result.

    The generate statement represents zero or more block statements in elaboration. Here each of the three block statement contains a 4 to 1 multiplexer for a std_logic element of a slice.

    An individual multiplexer has signal nets connecting the output of each of four andgate instantiations to an orgate instantiation. By relying on a common declaration for and_result you've shorted the andgate outputs together across all three blocks.

    Moving the and_result declaration into the generate statement block declarative region results in it being replicated for each generated block statement. Because a block statement is a declarative region those three declarations of and_result aren't visible outside each generated block due to scope and visibility rules which match them being local to each block in a hierarchical block diagram - the three and_result elements are no longer connected to all three blocks. This eliminates multiple drivers.