Electronic – Weird behavior when simulating decoder using modelsim

digital-logichardwarevhdl

In my introductory Digital System design course. We were asked to simulate a 4 to 16 decoder using VHDL and modelSim.Everything compiled correctly. However, when I try to test bench my program, I get a weird error that even my instructor couldn't pinpoint the problem.

–Code for 4 to 16 decoder

    library ieee;
use ieee.std_logic_1164.all;
entity decoder4to16 is
port
    (
     X: in STD_LOGIC_VECTOR(3 downto 0);
     EN: in STD_LOGIC;
     Y: out STD_LOGIC_VECTOR (0 TO 15));

     end decoder4to16;


architecture decoder4to16_arch of decoder4to16 is
signal Y_t: STD_LOGIC_VECTOR (0 TO 15);
begin
process(X,EN)
begin
case X is
when "0000" => Y_t<="0111111111111111";
when "0001" => Y_t<="1011111111111111";
when "0010" => Y_t<="1101111111111111";
when "0011" => Y_t<="1110111111111111";
when "0100" => Y_t<="1111011111111111";
when "0101" => Y_t<="1111101111111111";
when "0110" => Y_t<="1111110111111111";
when "0111" => Y_t<="1111111011111111";
when "1000" => Y_t<="1111111101111111";
when "1001" => Y_t<="1111111110111111";
when "1010" => Y_t<="1111111111011111";
when "1011" => Y_t<="1111111111101111";
when "1100" => Y_t<="1111111111110111";
when "1101" => Y_t<="1111111111111011";
when "1110" => Y_t<="1111111111111101";
when "1111" => Y_t<="1111111111111110";
when others => Y_t<="1111111111111111";
end case;
if(EN)='0' then Y<=Y_t;
else Y<="1111111111111111";
end if;
end process;
end decoder4to16_arch;

— and here is the code for my test bench

library ieee;
use ieee.std_logic_1164.all;
entity decoder4to16_tb is
end decoder4to16_tb;
architecture  decoder4to16_tb of decoder4to16_tb is
component decoder4to16
port
    (
     X: in STD_LOGIC_VECTOR(3 downto 0);
     EN: in STD_LOGIC;
     Y: out STD_LOGIC_VECTOR (0 TO 15));

     end component;
signal X: STD_LOGIC_VECTOR (3 downto 0):="0000";
signal E: STD_LOGIC:='0';
signal Y: STD_LOGIC_VECTOR (0 TO 15);
begin
U0: decoder4to16 port map (X,E,Y);
process
begin
E<='1'; X<="0000"; wait for 100 ns;
E<='0'; X<="0000"; wait for 100 ns;
X<="0001"; wait for 100 ns;
X<="0010"; wait for 100 ns;
X<="0011"; wait for 100 ns;
wait;
end process;

end decoder4to16_tb;

Now the weird part, when I try to simulate the test bencha and display the waveforms, it's like there is a delay for inputs "0001" and above.

it's like there is some delay of some sort

To make sure that this "delay" is there

Thank you.

Best Answer

You might do a better job in your question describing what's wrong with the results, instead of providing a picture.

It becomes apparent if you look at the process:

    process(X,EN)
    begin
        case X is
            when "0000" => Y_t<="0111111111111111";
            when "0001" => Y_t<="1011111111111111";
            when "0010" => Y_t<="1101111111111111";
            when "0011" => Y_t<="1110111111111111";
            when "0100" => Y_t<="1111011111111111";
            when "0101" => Y_t<="1111101111111111";
            when "0110" => Y_t<="1111110111111111";
            when "0111" => Y_t<="1111111011111111";
            when "1000" => Y_t<="1111111101111111";
            when "1001" => Y_t<="1111111110111111";
            when "1010" => Y_t<="1111111111011111";
            when "1011" => Y_t<="1111111111101111";
            when "1100" => Y_t<="1111111111110111";
            when "1101" => Y_t<="1111111111111011";
            when "1110" => Y_t<="1111111111111101";
            when "1111" => Y_t<="1111111111111110";
            when others => Y_t<="1111111111111111";
        end case;
        if EN ='0' then 
            Y <= Y_t;
        else 
            Y <= "1111111111111111";
        end if;
    end process;

You have a process that's sensitive to X and EN but (rightly so) not Y_t.

VHDL signal assignments are queued to a projected output waveform.

A signal assignment can be of the form (IEEE Std 1076-2008, 10.5.2 Simple signal assignments):

simple_waveform_assignment ::=          
    target <= [ delay_mechanism ] waveform ;

Where a waveform:

waveform ::=
      waveform_element { , waveform_element }
    | unaffected

can be a waveform element which can have an after time expression:

waveform_element ::=
      value_expression [ after time_expression ]
    | null [ after time_expression ]

which specifies when in relative simulation time the update is available. (see 10.5.2.2 Executing a simple assignment statement):

The base type of the time expression in each waveform element shall be the predefined physical type TIME as defined in package STANDARD. If the after clause of a waveform element is not present, then an implicit “after 0 ns” is assumed. It is an error if the time expression in a waveform element evaluates to a negative value.

A signal value is never updated when any process statement is pending for execution in the current simulation cycle.

An assignment without an after time expression, meaning assignment to the current simulation time is guaranteed to incur a delta cycle (a simulation cycle without a change to simulation time).

And because the value of the newly assigned value of Y_t is not available in the current simulation cycle in which Y is assigned you'll get a delay based not on updating the value of Y_t but waiting until the end of the simulation cycle, suspending and waiting for an event on a signal in the process sensitivity list.

Simulation cycle
The VHDL standard can be hard for someone just starting out to understand, it requires among other thing inculcation in the vocabulary of VHDL and curricula don't always do that.

There's a couple of paragraphs in Peter Ashenden's book The Designer's Guide to VHDL that can help with understanding what VHDL does in simulation:

The simulation starts with an initialization phase, followed by repetitive execution of a simulation cycle. During the initialization phase, each signal is given an initial value, depending on its type. The simulation time is set to zero, then each process instance is activated and its sequential statements executed. Usually, a process will include a signal assignment statement to schedule a transaction on a signal at some later simulation time. Execution of a process continues until it reaches a wait statement, which causes the pro- cess to be suspended.

During the simulation cycle, the simulation time is first advanced to the next time at which a transaction on a signal has been scheduled. Second, all the transactions scheduled for that time are performed. This may cause some events to occur on some signals. Third, all processes that are sensitive to those events are resumed and are allowed to continue until they reach a wait statement and suspend. Again, the processes usually execute signal assignments to schedule further transactions on signals. When all the processes have sus- pended again, the simulation cycle is repeated. When the simulation gets to the stage where there are no further transactions scheduled, it stops, since the simulation is then complete.

Elaboration
Everything in an elaborated VHDL design is driven by signal events which are scheduled in the projected output waveform for each signal.

Concurrent statements are devolved into processes or block statements providing hierarchy and processes during elaboration. Function calls are expressions and sequential procedure calls are statements. (Concurrent procedure call statements become processes containing sequential procedure call statements when elaborated).

So What does this means to your model?
Signal events drive execution of the model. Your design model is missing a signal event on Y_t causing a process to resume execution.

Sensitivity lists in a process prevent the inclusion of an explicit wait statement and implicitly provide:

wait on sensitivity_list ;

as the last statement of the process, which means among other things execution resumes with the first statement.

Now if we simply added Y_t to the sensitivity list our process would have feed back and potentially endless delta cycles because we'd update Y_t which would schedule and event to which the process would be sensitive.

To cure this you can leave the sensitivity list alone and either move the assignment to Y outside this process, or eliminate the signal Y_t and assign to Y directly in the case statement which you can embed in the following if statement where the assignment of the value of Y_t occurs.

You could potentially concatenate EN with X to a named variable and require the element position of the variable used as a case statement expression representing EN be '0', the others choice would cover every case when Y should be all '1's and you could eliminate the if statement.

That might then look like:

    process(X,EN)
        variable case_exp: std_logic_vector (4 downto 0);
    begin
        case_exp := EN & X;  -- EN is the leftmost position
        case case_exp is
            when "00000" => Y <= "0111111111111111";
            when "00001" => Y <= "1011111111111111";
            when "00010" => Y <= "1101111111111111";
            when "00011" => Y <= "1110111111111111";
            when "00100" => Y <= "1111011111111111";
            when "00101" => Y <= "1111101111111111";
            when "00110" => Y <= "1111110111111111";
            when "00111" => Y <= "1111111011111111";
            when "01000" => Y <= "1111111101111111";
            when "01001" => Y <= "1111111110111111";
            when "01010" => Y <= "1111111111011111";
            when "01011" => Y <= "1111111111101111";
            when "01100" => Y <= "1111111111110111";
            when "01101" => Y <= "1111111111111011";
            when "01110" => Y <= "1111111111111101";
            when "01111" => Y <= "1111111111111110";
            when others  => Y <= "1111111111111111";
        end case;
    end process;

When the leftmost position of case_exp is a '1' EN is invalid and no Y element position is a '0'.

Related Topic