3

I'm currently writing a test to check whether the type time is synthesized / simulated properly in various FPGA vendor tools. One corner case is the usage of real literals as the abstract literal for time values, e.g.: 1.001 us.

The IEEE Std. 1076-2008, Section 5.2.4.1 or IEEE Std. 1076-1993, Section 3.1.3, Para 8 states:

There is a position number corresponding to each value of a physical type. The position number of the value corresponding to a unit name is the number of primary units represented by that unit name. The position number of the value corresponding to a physical literal with an abstract literal part is the largest integer that is not greater than the product of the value of the abstract literal and the position number of the accompanying unit name.

As per definition of TIME (see Section 16.2 or 14.2), the primary unit is femto seconds, so that, the position number of 1 us is 1,000,000,000. Thus, the position number of 1.001 us should be 1,001,000,000 which is also the position number of 1001 ns. Thus, both values should be equal.

But, I get different results when I try to synthesize or simulate the following stripped down unit. I have checked, that the minimum time resolution is either 1 fs or 1 ps.

entity physical_test is
    generic (
        C1 : time := 1001 ns;
        C2 : time := 1.001 us;
        C3 : time := TIME'val(integer(real(TIME'pos(1 us)) * 1.001))
    );
    port (
        y : out bit);
end entity physical_test;

architecture rtl of physical_test is
    function f return boolean is
    begin
        report "C1 = " & TIME'image(C1) severity note;
        report "C2 = " & TIME'image(C2) severity note;
        report "C3 = " & TIME'image(C3) severity note;
        return false;
    end f;

    constant C : boolean := f;
begin  -- architecture rtl
    y <= '0';
end architecture rtl;

QuestaSim (ModelSim) was the only tool which reported the expected result:

# ** Note: C1 = 1001000000 fs
# ** Note: C2 = 1001000000 fs
# ** Note: C3 = 1001000000 fs

But, the actual result when synthesizing with Quartus 15.0 or ISE 14.7 is:

Note: "C1 = 1001000000 fs"
Note: "C2 = 1000999999 fs"
Note: "C3 = 1001000000 fs"

Thus, the value of C2 is not as expected. If I write down the cited text as an equation, then I get the expected result in the constant C3. When I use the integrated simulators of ISE 14.7 or Vivado 2015.4, I get a similar result:

Note: "C1 = 1001000 ps"
Note: "C2 = 1000999 ps"
Note: "C3 = 1001000 ps"

So, should be the behaviour of Quartus / ISE / Vivado considered as a bug? Or is it allowed by the VHDL standard that 1.001 us is not equal to 1001 ns?

EDIT: The bug happens also when I compare 1.001 ps to 1001 fs as well as when I compare 1.001 ns to 1001 ps. As also the manual computation with C3 was correct, it should not be a problem with the accuracy of real.

Just to note, the synthesizer of Vivado reports weird results:

Parameter C1 bound to: 32'b00111011101010100000110001000000    -- 1001000000
Parameter C2 bound to: 32'b10010011011101001011110001101010    -- 2473901162
Parameter C3 bound to: 32'sb00000000000000000000000000000001   -- 1
Martin Zabel
  • 3,589
  • 3
  • 19
  • 34
  • You can add ghdl (0.33) to the list of tools that gets the answer you expect. –  Jan 11 '16 at 23:31

1 Answers1

2

This is an issue with floating point numbers and has very little to do VHDL. Integer decimal numbers can be converted to binary and back to decimals without loosing information (unless the numbers are too big or too small). This is not the case for decimal fractions. The decimal number 1.001 converted to binary is irrational. When converting back from binary to decimal, there will be rounding errors.

Quartus and ISE show expected behaviour.

In the Vivado case something happened with the MSB of C2. It appears that some conversion between signed and unsigned integers took place, where it should not have. And C3 was apparently rounded of.

Your examples could be used to support the rule that using the primary unit is the best choice.

bogl
  • 1,864
  • 1
  • 15
  • 32
  • The bug happens also when I compare `1.001 ps` to `1001 fs` as well as when I compare `1.001 ns` to `1001 ps`. Also the manual computation with `C3` was correct. Thus, it should not be a problem with the accuracy of real. – Martin Zabel Jan 11 '16 at 18:53
  • Are you refering to Vivado now? It probably is not even a bug, just a limitation.. ;) – bogl Jan 11 '16 at 19:08
  • Seriously, I never used Vivado. Maybe there are some hints in the documentation. Your C3 example is a bit artificial, but the problem with C2=1.001 could be submitted as a bug report. Xilinx is usually quite responsive. – bogl Jan 11 '16 at 19:18
  • Mind you, `1.001 us` or `1.001 ps` makes no difference in this matter. In most computer languages 0.1+0.2 does not equal 0.3. See http://stackoverflow.com/questions/588004/is-floating-point-math-broken – bogl Jan 11 '16 at 19:22
  • Yes, you are right. The problem is the number 1.001, when it is stored as an IEEE-754 double, it actually represents the number 1.0009999... I know the limitations of floating-point arithmetic, but didn't expect a problem with this number. My C test program now proves me wrong. So what's left is the difference to C3. By the way, I'm still refering to ISE / Quartus as well. – Martin Zabel Jan 11 '16 at 20:53
  • You wouldn't expect a synthesiser to understand either reals or times, so Vivado's synthesis reports for `C2` and `C3` couldn't be considered to be a "bug". `C2` looks pretty random to me. It might be interesting to try some reals without the time stuff to see if/how it handles them. – EML Jan 12 '16 at 11:16