1

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?

Tawpik Talat
  • 55
  • 1
  • 8
  • *could this be a timing issue?* No. Provide a [mcve], your problem can't be replicated by your readers without orgate and the testbench. A generate statement represents one or more block statements. You've tied some of the outputs of these blocks together. The declaration of `and_result` should be moved from being an architecture block declarative item to the and_gate_assignment generate statements block declarative region (where you'll need a following `begin` to separate declarations from the generate statement part). –  Dec 12 '20 at 00:16
  • The reason is probably hidden in your testbench which you haven't shown. –  Dec 12 '20 at 13:24
  • 1
    No, the problem shows up in mux41where the various and gates in three generated blocks have their output's tied together by using a common declaration for `and_result`. The fix is to move the declaration into the block declarative region for each generated block so the connections between andgates and orgate are not shared between the three one bit 4:1 mulitplexers. –  Dec 12 '20 at 18:17

1 Answers1

1

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.