Seung Jin Lee
Seung Jin Lee

Reputation: 155

Concatenating STD_LOGIC to STD_LOGIC_VECTOR within testbench in VHDL

enter image description here

This is my simple Schematic of 4 to 1 MUX. and I have trouble with concatenating LOGIC to LOGIC_VECTOR...

here is my testbench code. I just want to show performance of MUX for all possible inputs. It is compiled well, but it isn't working as I expected. I guess newly declared vector "X" and "I" isn't linked with real inputs of Schematic

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
LIBRARY UNISIM;
USE UNISIM.Vcomponents.ALL;
ENTITY MUX_SCHE_MUX_SCHE_sch_tb IS
END MUX_SCHE_MUX_SCHE_sch_tb;
ARCHITECTURE behavioral OF MUX_SCHE_MUX_SCHE_sch_tb IS 

   COMPONENT MUX_SCHE
   PORT( X3 :   IN  STD_LOGIC; 
          X2    :   IN  STD_LOGIC; 
          X1    :   IN  STD_LOGIC; 
          X0    :   IN  STD_LOGIC; 
          I0    :   IN  STD_LOGIC; 
          I1    :   IN  STD_LOGIC; 
          Y :   OUT STD_LOGIC);
   END COMPONENT;

   SIGNAL X3    :   STD_LOGIC := '0';
   SIGNAL X2    :   STD_LOGIC := '0';
   SIGNAL X1    :   STD_LOGIC := '0';
   SIGNAL X0    :   STD_LOGIC := '0';
   SIGNAL I0    :   STD_LOGIC := '0';
   SIGNAL I1    :   STD_LOGIC := '0';
   SIGNAL Y : STD_LOGIC;

    ---------- New Variable ----------
    SIGNAL X : STD_LOGIC_VECTOR(3 downto 0);
    SIGNAL I : STD_LOGIC_VECTOR(1 downto 0);
    SIGNAL j : integer := 0;
    SIGNAL k : integer := 0;

BEGIN

    X <= X3 & X2 & X1 & X0;
    I <= I1 & I0;
    UUT: MUX_SCHE PORT MAP(
        X3 => X3, 
        X2 => X2, 
        X1 => X1, 
        X0 => X0, 
        I0 => I0, 
        I1 => I1, 
        Y => Y
   );

-- *** Test Bench - User Defined Section ***
   tb : PROCESS
   BEGIN
    X <= "0000";
    I <= "00";
        while(j<4) loop
            while(k<8) loop
                X <= X + '1'; WAIT FOR 10 NS;
            end loop;
            I <= I + '1'; WAIT FOR 10 NS;
       end loop;

   END PROCESS;
-- *** End Test Bench - User Defined Section ***

END;

Upvotes: 2

Views: 4875

Answers (2)

user1155120
user1155120

Reputation:

As Brian notes the assignments to X (and I) are incorrect.

There's also the case that X is always all 'X's, there are two drivers. The concurrent signal assignment to X and the assignments in the unlabeled process. Further the unlabeled process would unsuccessfully initializes X because there is no intervening suspension of the process between the first assignment to "0000" and the first assignment in the inner while loop.

You could also note there is no assignment to j and k meaning you'll never finish the inner while loop and provide a different value of I.

Overcoming the problems in the present testbench can also involve simplification:

library ieee;
use ieee.std_logic_1164.all;

entity mux_sche_tb is
end entity mux_sche_tb;

architecture foo of mux_sche_tb is 
    use ieee.numeric_std.all;
    component mux_sche
        port ( 
           x3:   in  std_logic; 
           x2:   in  std_logic; 
           x1:   in  std_logic; 
           x0:   in  std_logic; 
           i0:   in  std_logic; 
           i1:   in  std_logic; 
           y:    out std_logic
        );
    end component;

   -- signal x3:       std_logic := '0';
   -- signal x2:       std_logic := '0';
   -- signal x1:       std_logic := '0';
   -- signal x0:       std_logic := '0';
   -- signal i0:       std_logic := '0';
   -- signal i1:       std_logic := '0';
    signal y:  std_logic;

    -- ---------- new variable ----------
    signal x:  unsigned(3 downto 0);
    signal i:  unsigned(1 downto 0);
    -- signal j:  integer := 0;
    -- signal k:  integer := 0;

begin

    -- x <= x3 & x2 & x1 & x0;
    -- i <= i1 & i0;

uut: 
    mux_sche 
        port map (
            x3 => x(3), 
            x2 => x(2), 
            x1 => x(1), 
            x0 => x(0), 
            i0 => i(0), 
            i1 => i(1), 
            y => y
        );

tb:  
   process
   begin
    -- x <= "0000";
    -- i <= "00";
        wait for 10 ns; -- show initial state
        for j in 0 to 3 loop
            I <= to_unsigned(j, 2);
            for k in 0 to 15 loop
                X <= to_unsigned(k, 4);
                wait for 10 ns;
            end loop;
        end loop;
        wait;
       --  while(j < 4) loop
       --      while(k < 8) loop
       --          x <= x + '1';
       --          wait for 10 ns;
       --      end loop;
       --      i <= i + '1';
       --      wait for 10 ns;
       -- end loop;

   end process;
end architecture;

Instead of while loops for iteration schemes are used in loop statements. Brian's suggestion of assigning elements of X are extended to I and only a single assignment to either is provided eliminating multiple drivers.

The use clause making the declarations in package ieee.numeric_std visible is moved to the architecture allowing the original architecture to be analyzed (and it's use clause allowing declarations found in the Synopsys package ieee.std_logic_unsigned is moved to it's architecture declarative region).

The for loop iterators are variables implicitly declared in the loop statement iteration scheme and are converted from their default type of integer to unsigned X and I.

The unsigned X and I have elements that have the same base type as the std_logic formal ports for mux_sche and can be used as actuals (as Brian recommends).

To provide a Minimal, Complete and Verifiable example a compatible mux_sche must be provided:

library ieee;
use ieee.std_logic_1164.all;

entity mux_sche is
    port (
        X3: in  std_logic;
        X2: in  std_logic;
        X1: in  std_logic;
        X0: in  std_logic;
        I0: in  std_logic;
        I1: in  std_logic;
        Y:  out std_logic
    );
end entity;

architecture foo of mux_sche is

begin
    process (X3, X2, X1, X0, I0, I1)
    variable I: std_logic_vector (1 downto 0);
    begin
        I := TO_X01(I1 & I0);
        case I is
            when "00" =>
                Y <= TO_X01(X0);
            when "01" =>
                Y <= TO_X01(X1);
            when "10" =>
                Y <= TO_X01(X2);
            when "11" =>
                Y <= TO_X01(X3);
            when others =>
                Y <= 'X';
        end case;
    end process;
end architecture;

When that's analyzed before the testbench and the testbench is analyzed, elaborated and simulated we end up with:

changed.png

Showing no X's and incremented X and I.

This testbench version relies on the numeric_std package to_unsigned conversion from natural range integers noting X and I have the range specified in the loop iteration scheme implicit declarations.

Is it possible to use the original testbench? Not with the threshold tests for j and k in place. What will occur is k will go through 8 iterations followed by j going through 4 iterations:

enter image description here

Using while loops with signal iterators is a bit tougher than using for loops with variable iterators.

Upvotes: 1

rainer
rainer

Reputation: 7099

There are two issues in your code: first, X <= X3 & X2 & X1 & X0; concatenates X3 to X0 and assigns the result to X. In the process tb, you're again assigning to X, creating what is usually referred to as "multiple drivers", ie. multiple parts of code driving (possibly different) values to the same signal. This is rarely what you want in well-written VHDL code.

VHDL deals with multiple drivers by using a resolution function: a function is applied to all values driven to the signal and its output is then written to the signal; see this for the resolution table that is used.

I'd stronly advice against using resolved types such as std_logic or std_logic_vector and go for their unresolved pendants std_ulogic and std_ulogic_vector (note the u); if you had used those, your error would have been caught during elaboration.

Second, as mentioned in the comments, X3 to X0 are never assigned any values, leaving them as U.

Upvotes: 0

Related Questions