VHDL Define a signal when undefined

Cameron Simpson picture Cameron Simpson · Nov 4, 2013 · Viewed 8k times · Source

So, I've been working on some VHDL homework and I'm having some trouble with my testbench. Basically, my testbench is running through the different possibilities for a number of flip-flops. However, I keep getting 'U' as a result from one of the flip-flops, and while I know exactly why, I have no idea how to fix it.

Basically, what is happening is that for my T flip-flop, since Q isn't set when I perform the XOR operation, the program never ends up assigning a value to Q after the XOR operation. So basically, I need a way of setting Q to, say, 0, iff Q has not been defined.

Just for reference, here is my code for the T-flipflop

library ieee;
use ieee.std_logic_1164.all;

entity T_FF is
  port (
        T, clk : in std_logic;
        Q : inout std_logic);
end T_FF;

architecture behv of T_FF is
begin
  process (clk) is
    variable hold1, hold2 : std_logic;
    begin
      if (clk'event) then
        hold1 := Q and (not T);
        hold2 := T and (not Q);
        Q <= hold1 or hold2;
      end if;
  end process;
end behv;

And the testbench:

library ieee;
use ieee.std_logic_1164.all;

entity tb is
end tb;

architecture behv of tb is
  -- Component declaration
  component T_FF is 
    port (
        T, clk : in std_logic;
        Q : inout std_logic);
  end component;

  signal sT : std_logic :='0';
  signal sclk : std_logic :='0';

  signal sQT : std_logic :='0';

  for TFF : T_FF use entity work.T_FF(behv);

  begin
    TFF: T_FF port map (T=>sT, clk=>sclk, Q=>sQT);

    sclk <= not sclk after 50 ns;
    sT <= not sT after 100 ns;

end;

Answer

user1155120 picture user1155120 · Nov 4, 2013

My apologies to Chris Laplante, but your question appears to be very much a valid VHSIC Hardware Description Language (VHDL) question. (VHSIC in an acronym for Very High Scale Integrate Circuit). Despite well intended Wiki descriptions VHDL is not a general purpose programming language. Execution is bounded by either simulation time or in an implementation dependent manner, number of consecutive delta cycles. To borrow a turn of phrase from Harry Harrison, VHDL is hardware. All that said the electronics.stackexchange.com vhdl tag could use the traffic.

Your test bench already provides a default value for sT, the actual for the formal T in your instantiated T_FF. From the unlabeled process we see variables hold1 and hold 2 are products of T and Q, so the issue is having a known value of Q for the AND Table or NOT Table look up in package body std_logic_1164 to produced some value besides 'U':

-- truth table for "not" function
CONSTANT not_table: stdlogic_1d :=
--  -------------------------------------------------
--  |   U    X    0    1    Z    W    L    H    -   |
--  -------------------------------------------------
     ( 'U', 'X', '1', '0', 'X', 'X', '1', '0', 'X' );

-- truth table for "and" function
CONSTANT and_table : stdlogic_table := (
--      ----------------------------------------------------
--      |  U    X    0    1    Z    W    L    H    -         |   |
--      ----------------------------------------------------
        ( 'U', 'U', '0', 'U', 'U', 'U', '0', 'U', 'U' ),  -- | U |
        ( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ),  -- | X |
        ( '0', '0', '0', '0', '0', '0', '0', '0', '0' ),  -- | 0 |
        ( 'U', 'X', '0', '1', 'X', 'X', '0', '1', 'X' ),  -- | 1 |
        ( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ),  -- | Z |
        ( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ),  -- | W |
        ( '0', '0', '0', '0', '0', '0', '0', '0', '0' ),  -- | L |
        ( 'U', 'X', '0', '1', 'X', 'X', '0', '1', 'X' ),  -- | H |
        ( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' )   -- | - |
);

From the two tables we see that inputs must be one of '0', '1', 'H', or 'L' to deliver something other than 'U' or 'X'. (The horizontal axis represents one input, the vertical axis represents the other for a two input AND function, the resulting value is found in the array of values intersecting one or both axis).

So Q has to be initialized to one of those four values. There are two ways to do so, either reflecting initialization in an FPGA that provides a natural bias towards a set or reset condition, or through applying an active reset to Q. (See the answer to the related question VHDL - Asynchronous up/down counter).

Because you've chosen to make the Q port mode inout and use it directly in feed back your best choice is to provide a reset. There's also a design error in your T_FF where you operate on both clock edges to which can be resolved by qualifying the clk'event with clk = '1' to operate only on one edge (the rising edge):

  process (clk, RESET) is
    variable hold1, hold2 : std_logic;
    begin
        if RESET = '1' then
            Q <= '0';
        else 
            if (clk'event AND clk = '1') then
                hold1 := Q and (not T);
                hold2 := T and (not Q);
                Q <= hold1 or hold2;
            end if;
        end if;
  end process;

(The 'failure mode using both edges is to generate an output that is the right frequency but only valid for the low baud of the clock, try it).

So with adding an asynchronous RESET to the port in T_FF, component declaration and instantiation statement in tb, as well as adding sRESET to tb, and initializing it to true, making if false after some interval the T_FF simulation looks like:

t_ff simulation with added RESET and qualified clock event

There's an IEEE Standard on synthesis compliant VHDL, IEEE Std 1076.6-2004, titled IEEE Standard for VHDL Register Transfer Level (RTL) Synthesis, which describes the constructs used here, see 6.1.3 Modeling edge-sensitive storage elements. Note that RESET has been added to the unlabeled process statement's sensitivity list in T_FF.