Search code examples
vhdlsimulationvivado

VHDL Vivado's behavioral simulation returns unknown (red X) over output assignment operation


I have written this simple process. It's supposed to accumulate ((b-a)/n)*yi terms, where yi is an input that is updated per every clock cycle, and then output the result of the sum.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; 
entity Integrator is
    Port ( a : in STD_LOGIC_VECTOR(7 downto 0);
           b : in STD_LOGIC_VECTOR(7 downto 0);
           n : in STD_LOGIC_VECTOR(7 downto 0);
           yi : in STD_LOGIC_VECTOR (15 downto 0);
           start : in std_logic;
           clk : in std_logic;
           output : out signed (15 downto 0);
           done : out STD_LOGIC);
end Integrator;

architecture Integrator_arch of Integrator is
signal do : std_logic;
signal i : unsigned(7 downto 0);
signal tmp1, tmp2, tmp3, res : signed(15 downto 0);
begin
    process(clk)
    begin
        if(clk'event and clk='1') then
            if(start='1') then
                do <= '1';
                i <= (others=>'0');
                done <= '0';
                res <= (others=>'0');
            elsif(do='1' and done='0') then   
                if(i=unsigned(n)) then
                    output <= res;
                    do <= '0';
                    done <= '1';
                else                    
                    tmp1 <= resize(signed(b)-signed(a),16);
                    tmp2 <= resize(tmp1/signed(n),16);
                    tmp3 <= resize(tmp2*signed(yi),16);
                    res <= res + tmp3;
                    i <= i+1;
                end if;
            end if;  
        end if;         
    end process;
end Integrator_arch;

And this is the testbench:

architecture Behavioral of Integrator_Testbench is
signal start : std_logic;
signal clk, done : std_logic;
signal yi : std_logic_vector(15 downto 0);
signal O : signed(15 downto 0);
begin
    uut: entity work.integrator(integrator_arch)
            port map(a=>"11111110", b=>"00000010", n=>"00000100", yi=>yi
                ,start=>start, clk=>clk, done=>done, output=>O);
    process
    begin
        clk<='0';
        start<='1';
        wait for 200ns;
        
        clk<='1';
        wait for 200ns;
        
        start<='0';
        clk<='0';
        yi<=x"0003";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0003";
        wait for 200ns;
        
        clk<='0';
        yi<=x"0001";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0001";
        wait for 200ns;
        
        clk<='0';
        yi<=x"0000";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0000";
        wait for 200ns;
        
        clk<='0';
        yi<=x"0002";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0002";
        wait for 200ns;
        
        clk<='0';
        yi<=x"0000";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0000";
        wait for 200ns;
        
        clk<='0';
        yi<=x"0000";
        wait for 200ns;
        
        clk<='1';
        yi<=x"0000";
        wait for 200ns;
    end process;
end Behavioral;

But here's the problem, the output is always reported as unknown (red Xs) when I run a behavioral simulation. What's more weird is that it runs completely fine in a debug session, and by running a line-by-line debug session I was able to get the correct output, which is x"0006"!!!

Result of behavioral simulation

After two hours of attempting to find the issue, I finally decided to ask. Specially since it runs completely fine and outputs the correct result in a line-by-line debug so I have no idea why the simulation keeps acting out.

Thanks a lot for your time.


Solution

  • Found my own answer by more trial and error

    It seems that the result of one line of numeric_std expression takes one clock cycle to settle down, so when I tried to make it more readable by writing

    tmp1 <= resize(signed(b)-signed(a),16);
    tmp2 <= resize(tmp1/signed(n),16);
    tmp3 <= resize(tmp2*signed(yi),16);
    res <= res + tmp3;
    

    It took 4 clock cycles to settle down and before these 4 clock cycles are done, the port is set to unknown. So I shortened all of those lines into one line

    res <= res + resize((resize(b-a,16)/signed(n))*yi,16);
    

    And now the result is ready for me in 1 clock cycle just as it should be.