EquipDev
EquipDev

Reputation: 5931

How to get real type ratio between two time values?

Having two time values in VHDL, for example:

constant t_1 : time :=   1 us;
constant t_2 : time := 300 ms;

How do I calculate the ratio between the two time values represented in real type?

The ratio, represented with ":", should for example give:

The challenge is that VHDL division of two physical types, like doing t_1 / t_2, returns an (universal) integer, thus with a result of 0 for t_1 / t_2, and not the desired values between 0.0 and 1.0.

The solution should be generally applicable, and also work for simulators having minimum time of more than 1 fs.

Upvotes: 3

Views: 4878

Answers (2)

Kevin Thibedeau
Kevin Thibedeau

Reputation: 3421

Modelsim has a modelsim_lib.util package with a to_real() function in it and Aldec has the same in aldec.aldec_tools.

If you need a portable solution that can be used in synthesis for generating constants, I have a timing_ops package that contains a to_real() function along with a host of other time related utilities. The to_real() function makes an intermediate conversion to integer but intelligently handles large values of 64-bit time that exceed the range of the typical 32-bit integer by pre-scaling them. 64-bit integers are supported if available. The conversion function knows what the current time resolution is by using a modified version of the VHDL-2008 resolution_limit function. You will get the best accuracy in the integer conversion when the simulator resolution is as large as possible. At 1fs resolution you may lose some accuracy on large time values. It will preserve the maximum of 53-bits available in the IEEE 64-bit float significand when doing round trip conversion from time -> real -> time.

There are two versions of this package. The main one defines a physical type for frequency and works in Quartus and Vivado (and any simulator) but not XST. A stripped down timing_ops_xilinx removes the physical type to support XST. The logical package name remains timing_ops so your code can still be portable with only a change needed in library mapping.

Upvotes: 4

Paebbels
Paebbels

Reputation: 16221

I also tried to do such calculations but failed at some vendor tools ... My current solution is to use real constants for timings in ns or frequencies in MHz. If I need a concrete time I multiply the real constant with 1 ns which results in a time.

-- specify timing in microseconds
constant myTiming_us : real := 100.0;

-- scale timing and convert it to a time
constant myTime : time := 1 ns * myTiming_us * 1000.0;

Edit 1:

Yay! I found my old bug/error notes why I'm not using time types directly ...

All notes below were tested in 2011 with Xilinx XST version O.61xd - If I remember correctly this was ISE 13.2.

Here are my notes:

-- type TIME is not supported in Xilinx Synthese Tools (XST) - Version O.61xd 2011
--  declaration of constants with type TIME => ERROR
--  usage of type TIME in functions         => ERROR

function kHz2Time(Freq_kHz : POSITIVE) return TIME is
begin
    return 1.0 ms / real(Freq_kHz);
end;

-- has no static result in Xilinx Synthese Tools (XST) - Version O.61xd 2011
function kHz2Time(Freq_kHz : REAL) return TIME is
begin
    return 1.0 ms / Freq_kHz;
end;

-- has no static result in Xilinx Synthese Tools (XST) - Version O.61xd 2011
function kHz2Time(Freq_kHz : REAL) return TIME is
  constant result : TIME := 1.0 ms / Freq_kHz;
begin
    return result;
end;

All 3 variants are commented (here uncommented to use syntax highlighting) and are not working in XST 13.2. If I remember correct, iSim 13.2 has no problems with this code.

Edit 2:

I run my tests under ISE 14.7 again and as of now it seems to work correctly. So the 'has no static result' issue is solved. Constants of type TIME can also be used in synthesis.

Moreover it's possible to define new physical times:

-- not yet supported by Xilinx Synthese Tools (XST) - Version 13.2 (O.61xd 2011)
type FREQ is range 0 to INTEGER'high units
    Hz;
    kHz = 1000 Hz;
    MHz = 1000 kHz;
    GHz = 1000 MHz;
end units;

The frequency to time conversion is a bit tricky:

function to_time(Frequency : FREQ) return TIME is
    variable Result : TIME;
begin
    assert MY_VERBOSE report "to_time: Frequency = " & FREQ'image(Frequency) severity note;

    if (Frequency < 1.0 kHz) then
        Result := (1.0 / real(Frequency / 1.0  Hz)) * 1.0 sec;
    elsif (Frequency < 1.0 MHz) then
        Result := (1.0 / real(Frequency / 1.0 kHz)) * 1.0 ms;
    elsif (Frequency < 1.0 GHz) then
        Result := (1.0 / real(Frequency / 1.0 MHz)) * 1.0 us;
    else
        Result := (1.0 / real(Frequency / 1.0 GHz)) * 1.0 ns;
    end if;

    assert MY_VERBOSE report "  return " & TIME'image(Result) severity note;
    return Result;
end function;

XST 14.7 and iSim 14.7 have no complains about this code any more.

Upvotes: 2

Related Questions