UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor cmhicks
Visitor
1,924 Views
Registered: ‎03-10-2011

Suspected VHDL compiler/simulator bug

I am very cautious about accusing a compiler of containing a bug, but the VHDL code below produces results I cannot explain. Naturally, it looks a bit odd because I have reduced it to a self-contained minimal example.

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

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

architecture Behavioral of tb_func is

    constant nfrc : integer := 3;
    
    function f1(p : signed(7 downto 0)) return signed is
        constant MULP_NFRC : integer := 3;
        variable mt : signed(7 downto 0) := (others=>'0');
        variable xt : signed(5 downto 0) := (others=>'0');
    begin
        if nfrc > MULP_NFRC then                -- when this condition fails...
            mt := p;
        else
            mt := p;                            -- ... this assignment should be executed, but doesn't seem to be.
        end if;
        xt := resize(mt, xt'length);
        return xt;
    end f1;

    function f2(p : signed(7 downto 0)) return signed is
        variable mt : signed(7 downto 0) := (others=>'0');
        variable xt : signed(5 downto 0) := (others=>'0');
    begin
        if nfrc > 3 then                        -- when this condtion fails...
            mt := p;
        else
            mt := p;                            -- ... this assignment seems to be executed correctly.
        end if;
        xt := resize(mt, xt'length);
        return xt;
    end f2;

    signal pc : signed(7 downto 0) := (others=>'1');
    signal x1, x2 : signed(5 downto 0) := (others=>'0');

begin

process begin
    wait for 1 ns;
    x1 <= f1(pc);
    x2 <= f2(pc);
    assert (x1 = x2) report "f1() and f2() should return identical results." severity error;
end process;

end Behavioral;

The only difference between f1() and f2() is the use of the literal 3 in the condition in f2(), versus the use of a constant integer of value 3 in f1(). The condition should fail in both cases, so the 'else' clause should be executed in both cases.

 

When I simulate this in Vivado 2017.4 the two functions behave differently. Called with 11111111 (as they are) both functions should surely return 111111.  In f1() however, it appears that no assignment from p to mt occurs and f1() returns '000000' (actually, it returns whatever mt is initialised to, resized to 6 bits).

Any comments?

(the project target part is a Zynq, and I'm running on Ubuntu 16 LTS 64-bit,  if that makes any difference)

 

Small update:

If in f1() I change 

constant MULP_NFRC : integer := 3;

to 

variable MULP_NFRC : integer := 3;

then the behaviour of f1() changes to be identical to f2() - which I believe to be correct.


 

Tags (1)
13 Replies
Scholar austin
Scholar
1,894 Views
Registered: ‎02-27-2008

Re: Suspected VHDL compiler/simulator bug

So how do you verify what does, and does not get executed (:= assigned)?

 

Looks like there is no difference what the condition is (true or false).

 

I see no clock, so is this a testbench? (hint:  there is no 'wait' in synthesizable code).  I get this is a snippet to demonstrate your case.  But, what if it actually was something you could synthesize, place and route (implement)?

Austin Lesea
Principal Engineer
Xilinx San Jose
0 Kudos
Scholar richardhead
Scholar
1,884 Views
Registered: ‎08-01-2012

Re: Suspected VHDL compiler/simulator bug

You need to post the real code. In this example, the assertion will take place comparing x1 and x2 from the previous ns as there is no wait between the assignments and the assert. So at time 1ns, both x1 and x2 should be 0.

 

Also, both statements in the if/else clauses are identical?

 

Please post real code.

0 Kudos
Visitor cmhicks
Visitor
1,868 Views
Registered: ‎03-10-2011

Re: Suspected VHDL compiler/simulator bug

Thanks for the replies. Yes, both branches of the if-then-else-endif are identical, yet in f1() neither of them seems to happen. That's the whole point.

It was originally a synthesisable design, but I reduced it to a minimal case in the course of debugging. Here is a synthesisable version (test_func.vhdl) and a testbench to demonstrate the problem (tb_func.vhdl).

I've made the if-then-else branches different. The only difference between f1() and f2() is that m is declared variable in one, constant in the other. As written, f1() and f2() should both add either 1 or 2 to the signed argument passed to them. With the values of n and m as they are, they should both add 2.


f2() does indeed add 2, and returns 5 when called as shown. However, f1() returns 6, the value to which its return value, y, has been initialised (and this is neither x+1 nor x+2, showing that the effect is as if neither branch of the if-then-else has been executed).

Playing with different values of n and m it appears that in f1(), if the test (n>m) returns true, then the 'if' branch is executed correctly, but if the test returns false then the 'else' branch is ignored. In all cases I have tried, f2() behaves as it should

Thanks for your help.

CH
==

PS Incidentally, I have noticed something else slightly odd, but probably unrelated. The initialisation of x, y1 and y2 in line 20 of tb_func.vhdl should, as far as I know, initialise all three signals to 0. However, the simulator wave display indicates that y1 and y2 are uninitialised. 

 

0 Kudos
Scholar richardhead
Scholar
1,864 Views
Registered: ‎08-01-2012

Re: Suspected VHDL compiler/simulator bug

Ive run it with ActiveHDL 10.5, and no assertion failure, with both Y1 and Y2 being 5 at the time of assertion.

 

Same code in 2017.4, and Y1=6 and Y2=5

Oh dear. Adding some extra debug, all values of n and m are as expected:

 

Note: n(f1) = 3
Time: 10 ns Iteration: 1 Process: /tb_func/eut/line__49 File: D:/C_DRIVE/Projects/play_area/testfunc/test_func.vhdl
Note: m(f1) = 3
Time: 10 ns Iteration: 1 Process: /tb_func/eut/line__49 File: D:/C_DRIVE/Projects/play_area/testfunc/test_func.vhdl
Note: n(f2) = 3
Time: 10 ns Iteration: 1 Process: /tb_func/eut/line__49 File: D:/C_DRIVE/Projects/play_area/testfunc/test_func.vhdl
Note: m(f2) = 3
Time: 10 ns Iteration: 1 Process: /tb_func/eut/line__49 File: D:/C_DRIVE/Projects/play_area/testfunc/test_func.vhdl
Note: y1 = 6
Time: 30 ns Iteration: 0 Process: /tb_func/line__31 File: D:/C_DRIVE/Projects/play_area/testfunc/tb_func.vhdl
Note: y2 = 5
Time: 30 ns Iteration: 0 Process: /tb_func/line__31 File: D:/C_DRIVE/Projects/play_area/testfunc/tb_func.vhdl
Error: f1() and f2() should return identical results.

 

Seems like a fairly fundamental bug, needs high priority fix!

Intel provide modelsim for free if you dont need Xilinx IP.

Visitor cmhicks
Visitor
1,858 Views
Registered: ‎03-10-2011

Re: Suspected VHDL compiler/simulator bug


@richardhead wrote:

Ive run it with ActiveHDL 10.5, and no assertion failure, with both Y1 and Y2 being 5 at the time of assertion.

 


Thanks - a useful confirmation I am not completely crazy. I also tried an online vhdl simulator which confirmed the result I was expecting. One thing I am not 100% sure about is whether f1() and f2() are technically pure functions as they depend on the (external) value n. However, declaring them impure makes no difference. 


Seems like a fairly fundamental bug, needs high priority fix!



I agree. Either my syntax or an assumption of mine is wrong (eg the pure/impure thing - although I've tested for that) and the compiler should complain, or one or other branch of the if/else should be executed, preferably the correct one :-)

I'm not sure yet whether the synthesised output is correct or not as I don't have a suitable hardware platform to try it on, but there is so much commonality in the toolchains for creating both the synthesised output and the simulator model that I am distinctly worried.

CH
==

0 Kudos
Scholar richardhead
Scholar
1,848 Views
Registered: ‎08-01-2012

Re: Suspected VHDL compiler/simulator bug

@cmhicks the distinction between pure and impure in the LRM is that impure functions may have a different result when called multiple times with the same paramters. So if all you read is a constant, then it can remain pure. But if you are reading a signal or variable from outside of the function, then technically it should be an impure function. In addition, impure functions are allowed to modify objects from outside of their scope, so you are allowed to do things like assign external signals or variables. The normal case where you must have an impure function is if you ever write to OUTPUT from a function.

In your case, as all you are reading from outside of the function is a constant, then it is a pure function.

PS Incidentally, I have noticed something else slightly odd, but probably unrelated. The initialisation of x, y1 and y2 in line 20 of tb_func.vhdl should, as far as I know, initialise all three signals to 0. However, the simulator wave display indicates that y1 and y2 are uninitialised.

Here, because you assigned y1 and y2 to the output of an entity, then the initial value is ignored as the assignment takes place during elaboration and initial value is overriden. You will pretty much always get 'U' as the initial value from port maps.

0 Kudos
Explorer
Explorer
1,804 Views
Registered: ‎09-07-2011

Re: Suspected VHDL compiler/simulator bug

You can synthesis your example and have a look at the netlist..  or re-run the testbench on the netlist.

0 Kudos
Voyager
Voyager
1,704 Views
Registered: ‎06-20-2017

Re: Suspected VHDL compiler/simulator bug

This is certainly a bug.  If you run the following:

 

   -- need impure to access output
  impure function f1(x : signed(7 downto 0)) return signed is
    constant m    : natural            := 3;
    variable y    : signed(7 downto 0);
    variable sttr : line;
  begin
    write(sttr, "f1 n value is " & integer'image(n));
    writeline(output, sttr);  
    write(sttr, "f1 m value is " & integer'image(m));
    writeline(output, sttr);  
    if (n > m) then
        y := x + 1;
        write(sttr,string'("hello f1.1"));
        writeline(output, sttr);  -- never happens
    else
        y := x + 2;
        write(sttr,string'("hello f1.2"));
        writeline(output, sttr);  -- never happens      
    end if;
    write(sttr, "f1 x value is " & integer'image(to_integer(x)));
    writeline(output, sttr);  
    write(sttr, "f1 y value is " & integer'image(to_integer(y)));
    writeline(output, sttr);  
    return y;
  end function f1;

  impure function f2(x : signed(7 downto 0)) return signed is
    variable m    : natural            := 3;
    variable y    : signed(7 downto 0) ;--:= to_signed(6,8);
    variable sttr : line;
  begin
    write(sttr, "f2 n value is " & integer'image(n));
    writeline(output, sttr);  
    write(sttr, "f2 m value is " & integer'image(m));
    writeline(output, sttr);  

    if (n > m) then
        y := x + 1;
        write(sttr,string'("hello f2.1"));
        writeline(output, sttr);  
    else
        y := x + 2;
        write(sttr,string'("hello f2.2"));
        writeline(output, sttr);             
    end if;
    write(sttr, "f2 x value is " & integer'image(to_integer(x)));
    writeline(output, sttr);   
    write(sttr, "f2 y value is " & integer'image(to_integer(y)));
    writeline(output, sttr);  
    return y;
  end function f2; 

You will see the lines marked "-- never happens" never gets output to the console.

 

f1 n value is 3
f1 m value is 3
f1 x value is 3
f1 y value is 0
f2 n value is 3
f2 m value is 3
hello f2.2
f2 x value is 3
f2 y value is 5

Another workaround is:

  -- doesn't matter as far as I can tell if it is impure or pure 
  function f1new(x : signed(7 downto 0)) return signed is
    constant m    : natural := 3;
    variable y    : signed(7 downto 0); 
    variable tn   : natural;
  begin
    tn := n; -- this fixes the bug
    if (tn > m) then
        y := x + 1;
    else
        y := x + 2;
    end if;
    return y;
  end function f1new;  

But this is clearly a bug in that neither branch of the "if (n > m)" conditional in f1 is ever executed.  Looks like a bad optimizer in xsim.  Vivado synthesis seems to interpret the functions correctly, judging by the post synthesis schematic having the identical registers drive oY1 and oY2.

 

cap2.png

Calling @austin, this looks like a bug in vivado simulator to me.

Mike
Visitor cmhicks
Visitor
1,624 Views
Registered: ‎03-10-2011

Re: Suspected VHDL compiler/simulator bug

Thank you for your deep analysis of this. I ended up refactoring my code for other reasons and this specific problem became a non-issue. However, this is all part of evaluating vivado for for a new project (having previously used ISE some years ago) and to have discovered such a significant bug like this is concerning whichever way you look at it. It would be reassuring to have some feedback from Xilinx on this.

Thanks again,

CH
==

0 Kudos
Voyager
Voyager
1,029 Views
Registered: ‎06-20-2017

Re: Suspected VHDL compiler/simulator bug


@cmhicks wrote:

Thank you for your deep analysis of this. I ended up refactoring my code for other reasons and this specific problem became a non-issue. However, this is all part of evaluating vivado for for a new project (having previously used ISE some years ago) and to have discovered such a significant bug like this is concerning whichever way you look at it. It would be reassuring to have some feedback from Xilinx on this.

Thanks again,

CH
==


If it is confirmed and reproduced by Xilinx, I'm sure Xilinx will fix it.  But it is only significant if your coding style hits this condition.  My coding style does not.

 

If you're looking for a perfect piece of software at this level of complexity, it is going to cost a lot more than Vivado, or not do nearly as much, and it won't be perfect anyway.  I use VHDL functions all the time but I have not ever run into this bug until you provided this test case. 

 

The simulator is a pretty good simulator given the cost, and I've never run into such a bug before.  I'm not about to through the baby out with the bath water.  But I agree it would be nice to at least get a "we're investigating it".

 

Mike
0 Kudos
Scholar richardhead
Scholar
999 Views
Registered: ‎08-01-2012

Re: Suspected VHDL compiler/simulator bug

"The simulator is a pretty good simulator given the cost, and I've never run into such a bug before.  I'm not about to through the baby out with the bath water.  But I agree it would be nice to at least get a "we're investigating it".

 

If you're referring to "free", then personally, if you dont need XILINX IPs, you can get modelsim for free from Intel/Altera. It is a FAR superior simulator to the Vivado one, and has full 2008 features, System Verilog 2012 support, and is mixed language.

0 Kudos
Visitor cmhicks
Visitor
979 Views
Registered: ‎03-10-2011

Re: Suspected VHDL compiler/simulator bug

My situation is that I am evaluating Vivado/Zynq using the free version with a view to a possible purchase of a premium version to get proper support and enable us to target larger parts. To have found a bug like this in our first week of evaluation is not a good advert! I will have a look at modelsim.

CH
==

 

0 Kudos
Scholar austin
Scholar
965 Views
Registered: ‎02-27-2008

Re: Suspected VHDL compiler/simulator bug

cm,

 

All tools have bugs (a fact of life).  You get to know them, understand them, and use them, anyway.  Bugs get logged, and if serious enough (the most severe bugs get priority, so a simulator bug on assignment, which might be rarely, if ever used might not be viewed as a must fix right away ---), get fixed.

 

Entirely up to you to decide.  Buying supported 3rd party tools is obviously popular with many companies (it is how Cadence, Synopsys, Mentor, etc. do well in business).  It is why we promote their tools and support their use.

 

Luckily for you, the costs of designing ASIC/ASSP are so great, that FPGA CAD Tool business is now much more attractive than it used to be, so all the tools are better as a result (ours included).

 

 

Austin Lesea
Principal Engineer
Xilinx San Jose