Electronic – vhdl strange output flickering with test bench

vhdlvivadoxilinx

i'm new to vhdl and fpga. I'm currently working with a basys3 board programmed in vhdl using vivado. I made a 3(binary) to 8(decimal) dencoder with a for loop.
My test bench is also with a for loop. What i now notice is strange output flickering between my normal output changes. Could somebody give me a reason for this problem?

main:

entity bindec38 is
Port ( sw : in STD_LOGIC_VECTOR (2 downto 0) := (others => '0');
       led : out STD_LOGIC_VECTOR (7 downto 0)  := (others => '0'));
end bindec38;

architecture Behavioral of bindec38 is
begin
process (sw)
variable int : integer := 0; 
begin

    int := to_integer(unsigned(sw));
    for j in 0 to 7 loop
        if (int = j) then
           led(int) <= '1'; -- correct schrijven deze led hoog
        else  
           led(j) <= '0'; -- schrijven de andere dan laag tijdens de loop
        end if;
    end loop;
end process;

end Behavioral;

test bench:

entity simdec is
--  Port ( );
end simdec;

architecture Behavioral of simdec is

component bindec38 is
    Port ( sw : in STD_LOGIC_VECTOR (2 downto 0);
       led : out STD_LOGIC_VECTOR (7 downto 0));
end component bindec38;

-- input signal
signal sw : STD_LOGIC_VECTOR (2 downto 0) := (others => '0');
-- output singal
signal led : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
begin

UUT: bindec38
Port Map (sw => sw, led => led);

-- sim process
sim_pro: process begin   
for i in 0 to 7 loop
sw <= std_logic_vector(to_unsigned(i, 3));
wait for 100 ns;    
end loop;

wait;
end process;            

end Behavioral;

see the simulation output
simulation
it only happens in 2 out of 8 transitions.

Best Answer

You have designed an asynchronous one of n decoder, and carried out a post-implementation or timing simulation.

Because a timing simulation uses the real timing of your placed and routed design, each signal will have fractionally different timing, even if the signals are part of the same logical element, for example sw in your case.

Whatever logic your FPGA uses to implement the circuit, because it is asynchronous, if the signals arrive at the input to that logic at different times, the output will transition through intermediate states in some cases when your logical element only transitions once. As the other answer points out, these race conditions create runt pulses in the output.

Taking the transition of sw from 3 to 4 as an example, the possible transitions in the binary signals that represent this number, depending on the detailed routing of these signals in the FPGA are:

"011" > "111" > "110" > "100" = 3 > 7 > 6 > 4
"011" > "111" > "101" > "100" = 3 > 7 > 5 > 4
"011" > "010" > "110" > "100" = 3 > 2 > 6 > 5
"011" > "010" > "000" > "100" = 3 > 2 > 0 > 4
"011" > "001" > "000" > "100" = 3 > 1 > 0 > 4
"011" > "001" > "101" > "100" = 3 > 1 > 5 > 4
"011" > "101" > "100" = 3 > 5 > 4
"011" > "110" > "100" = 3 > 6 > 4
"011" > "100" = 3 > 4

As you can see, depending on the routing and resulting timing, your one of n decoder could see a variety of inputs during the transition in sw, and so produce a corresponding variety of outputs. Note that the intermediate transitions occur over a very short space of time, typically under 1 nanosecond in a modern FPGA.

Let's compare this to one of the transitions that does not show runts in the output, when sw goes from 4 to 5. The possible transitions are:

"100" > "101" = 4 > 5

Since only one bit changes, there is only one possible transition. As a result, you won't see any runts on this transition, no matter how the signals are routed.

Now let's think about how the tools will actually implement your circuit. You can check in the implemented schematic, but each led output should be driven by a separate Look Up Table (LUT) element. You can use the tools to view the logic equation of each LUT, but essentially they will be looking to see if the 3-bit sw input corresponds to that particular led. Where the other answer is wrong is that just because the logic is implemented in a single LUT, it does not mean that these race conditions are a simulation artifact only.

Relating this back to the 3 to 4 transition, because each led output is implemented in a different LUT, the timing seen by each LUT will be different. We see runt pulses on the 1, 2, 6, and 7 outputs. From this we can deduce that the LUT for led(1) saw either 3 > 1 > 0 > 4 or 3 > 1 > 5 > 4, led(2) saw either 3 > 2 > 6 > 5 or 3 > 2 > 0 > 5, and so on.

The common way to avoid runts is to use a synchronous design, i.e. one that uses a clock. Note that for this to work reliably, the input (sw in this case) must also be synchronous to clk.

process(clk)
begin
  if (rising_edge(clk)) then
    led <= (others => '0');
    led(to_integer(unsigned(sw)) <= '1';
  end if;
end process;

Now, the one of n decoder will still see the varying transitions on the LUT inputs, and have corresponding runts on the LUT outputs, but these outputs then feed a register. Since in a synchronous system that has met timing, the transitions will all have completed by the time the clock edge occurs, the final output will not have any runt pulses.

Another option is to decide that you don't care about these runt pulses. In a design that simply drives some LEDs, you probably don't care if there's a chance of the wrong LED illuminating for 0.5 nanoseconds.

The most important point in all this is that these are not just simulation artifacts, and could cause real world problems in a design.

Related Topic