Question

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;
Was it helpful?

Solution

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.

OTHER TIPS

There actually are two issues here: (1) On what you are trying to build; (2) On the code itself.

1) On what you are trying to build:

You are trying to build a T-type flip-flop. This is usually built with a D-type flip-flop by simply connecting an inverted version of its output back to its input. In your case, you also want a "toggle enable" signal (called T in your code), to allow stopping the TFF when T=0. This means that the TFF input must go through an XOR gate, nothing else.

Such XOR gate can be constructed as you did (AND-OR layers) or using directly an XOR gate. Because the DFFs in FPGAs are already constructed with an enable port (XOR functionality internal to the DFF), it is better to use the XOR option, saving logic and operating faster. But the other option will also function, obviously.

2) Regarding the code:

  • Q is buffer, not inout
  • Include "and clk='1'" (-> rising_edge(clk))
  • Eliminate variables hold1, hold2
  • Use Q <= T xor Q instead of Q <= (T and notQ) or (not T and Q)

library ieee;
use ieee.std_logic_1164.all;
--------------------------------------------
entity T_FF is
  port (
    T, clk: in std_logic;
    Q : buffer std_logic); 
end T_FF;
--------------------------------------------
architecture behv of T_FF is
begin
  process (clk) is
  begin
    if rising_edge(clk) then
      Q <= (T and not Q) or (not T and Q);
      --Q <= T xor Q; --preferred option
    end if;
  end process;
end behv;
--------------------------------------------
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top