Velocity Reviews > VHDL > Frequency to Time Conversion

# Frequency to Time Conversion

alivingstone
Guest
Posts: n/a

 10-17-2007
I'm trying to make a frequency to time conversion in VHDL to help make
my testbenches more readable and I think I'm running into a language
limitation. Anyone done anything like this:

I want to have a function that takes an integer input (frequency in
hertz) and outputs the half-period of the wave so that I can use it to
generate my testbench clock. For instance:

constant F_CLK : positive := 1_544_000; --Hz
constant T_CLK : time := (1 / F_CLK / 2) * (1 sec);
...
clk <= not clk after T_CLK;

However, the above generates a T_CLK of 0ps. My assumption was that
time is stored as an integer, so result of the 1/F_CLK division (<1)
was being rounded to zero. So I tried scaling the initial division:

constant T_CLK : time := (10**9 / F_CLK / 2) * (1 ns);

The above works great, generating the correct half-period of 323ns.
The problem is that the above restricts T_CLK to an integer in
nanoseconds, leaving me with an error of ~0.8ns per half-period
(~1.6ns per clock cycle). I tried to get more resolution by changing
the division prescaler:

constant T_CLK : time := (10**12 / F_CLK / 2) * (1 ps);

but the 10**12 causes an overflow at compile time and the calculation
fails. So doing it by this method leaves me with only nanosecond
resolution --- unacceptable for most frequencies.

Has anyone successfully done this? Maybe someone more clever than
myself can anyone think of a way to do the scaling without overflowing
the language constructs.

Many thanks.

Laurent Pinchart
Guest
Posts: n/a

 10-17-2007
alivingstone wrote:

> I'm trying to make a frequency to time conversion in VHDL to help make
> my testbenches more readable and I think I'm running into a language
> limitation. Anyone done anything like this:
>
> I want to have a function that takes an integer input (frequency in
> hertz) and outputs the half-period of the wave so that I can use it to
> generate my testbench clock. For instance:
>
> constant F_CLK : positive := 1_544_000; --Hz
> constant T_CLK : time := (1 / F_CLK / 2) * (1 sec);
> ...
> clk <= not clk after T_CLK;
>
> However, the above generates a T_CLK of 0ps. My assumption was that
> time is stored as an integer, so result of the 1/F_CLK division (<1)
> was being rounded to zero. So I tried scaling the initial division:
>
> constant T_CLK : time := (10**9 / F_CLK / 2) * (1 ns);
>
> The above works great, generating the correct half-period of 323ns.
> The problem is that the above restricts T_CLK to an integer in
> nanoseconds, leaving me with an error of ~0.8ns per half-period
> (~1.6ns per clock cycle). I tried to get more resolution by changing
> the division prescaler:
>
> constant T_CLK : time := (10**12 / F_CLK / 2) * (1 ps);
>
> but the 10**12 causes an overflow at compile time and the calculation
> fails. So doing it by this method leaves me with only nanosecond
> resolution --- unacceptable for most frequencies.
>
>
> Has anyone successfully done this? Maybe someone more clever than
> myself can anyone think of a way to do the scaling without overflowing
> the language constructs.

Try to use a floating point (real) type for F_CLK.

Laurent Pinchart

Ralf Hildebrandt
Guest
Posts: n/a

 10-17-2007
alivingstone schrieb:
> I'm trying to make a frequency to time conversion in VHDL to help make
> my testbenches more readable and I think I'm running into a language
> limitation. Anyone done anything like this:
>
> I want to have a function that takes an integer input (frequency in
> hertz) and outputs the half-period of the wave so that I can use it to
> generate my testbench clock. For instance:
>
> constant F_CLK : positive := 1_544_000; --Hz
> constant T_CLK : time := (1 / F_CLK / 2) * (1 sec);
> ...
> clk <= not clk after T_CLK;

Let's see how time is defined:

type TIME is range \$- to \$+
units
fs; -- femtosecond
ps = 1000 fs; -- picosecond
ns = 1000 ps; -- nanosecond
us = 1000 ns; -- microsecond
ms = 1000 us; -- millisecond
sec = 1000 ms; -- second
min = 60 sec; -- minute
hr = 60 min; -- hour;
end units;

(See <http://www.csee.umbc.edu/help/VHDL/standard.vhdl>)

This makes "1 sec" quite a huge number. Therefore you problem should be
solved using (not tested):

constant T_CLK : time := 1 sec / F_CLK / 2;

Ralf

Jeff Cunningham
Guest
Posts: n/a

 10-17-2007
alivingstone wrote:

> constant T_CLK : time := (1 / F_CLK / 2) * (1 sec);

try "keeping it real" like this:

constant T_CLK : time := (1.0 / F_CLK / 2.0) * (1 sec);

-Jeff

Jonathan Bromley
Guest
Posts: n/a

 10-17-2007
On Wed, 17 Oct 2007 06:36:07 -0700, alivingstone
<(E-Mail Removed)> wrote:

>I want to have a function that takes an integer input (frequency in
>hertz) and outputs the half-period of the wave so that I can use it to
>generate my testbench clock.

[...]

You can also use REAL numbers to do arithmetic on TIME,
so you can do something like this:

function half_period ( freq_Hz: integer ) return time is
begin
return 0.5 sec / real(freq_Hz);
end;

Now, thanks to the REAL arithmetic, you'll get the period
to the best possible resolution - probably determined by
some command-line setting on your simulator.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.

alivingstone
Guest
Posts: n/a

 10-17-2007
Thanks everyone for the responses.

Ralf,
I tested your suggestion and it works great. I used:

constant T_CLK : time := 1 sec / F_CLK / 2;

***

Jeff,
You were on the right path, you just need to either define F_CLK as a
real or convert it to a real since division of an integer into a real
isn't defined by VHDL. So if I extend Jonathan's suggestion, the
following will work:

constant T_CLK : time := (1.0 / real(F_CLK) / 2.0) * (1 sec);

Thanks again all.

Amal
Guest
Posts: n/a

 10-17-2007
On Oct 17, 11:23 am, alivingstone <(E-Mail Removed)> wrote:
> Thanks everyone for the responses.
>
> Ralf,
> I tested your suggestion and it works great. I used:
>
> constant T_CLK : time := 1 sec / F_CLK / 2;
>
> ***
>
> Jeff,
> You were on the right path, you just need to either define F_CLK as a
> real or convert it to a real since division of an integer into a real
> isn't defined by VHDL. So if I extend Jonathan's suggestion, the
> following will work:
>
> constant T_CLK : time := (1.0 / real(F_CLK) / 2.0) * (1 sec);
>
> Thanks again all.

Would have been nice to have a FREQUENCY type and units defined in a
standard package as well.

Take a look at the following example code. The to_time function works
fine regardless of the simulator resolution, but to_frequency would
choke depending on what the simulator resolution is. Probably after
the ENV package from the IEEE_PROPOSED is implemented in different
simulators, it is possible to fix the to_frequency function somehow to
work properly. Also integer range is way too small for higher
frequencies.

library IEEE;
use IEEE.std_logic_1164.all;
library STD;
use STD.textio.all;

entity test is
end entity test;

architecture behavioral of test is

-- frequency type (easier/readable clock settings)
type FREQUENCY is range 0 to integer'high
units Hz; -- Hertz
KHz = 1000 Hz; -- Kilo Hertz
MHz = 1000 KHz; -- Mega Hertz
GHz = 1000 MHz; -- Giga Hertz
THz = 1000 GHz; -- Tera Hertz
end units;

function to_time( f : frequency ) return time is
begin
return( 1 Sec / (f/Hz) );
end function to_time;

-- function to_frequency( t : time ) return frequency is
-- begin
-- return( 1 Hz * (t/Sec) );
-- end function to_frequency;

constant CLOCK_FREQUENCY : frequency := 1.0 MHz;
-- Convert to time (check to_time function)
constant CLOCK_PERIOD : time :=
to_time(CLOCK_FREQUENCY);
-- -- Convert back to frequency (check to_frequency function)
-- constant CLOCK_FREQUENCY_NEW : frequency :=
to_frequency(CLOCK_PERIOD);

signal clock : std_logic;

begin

p_Clock_Gen: process
begin
clock <= '0', '1' after CLOCK_PERIOD/2;
wait for CLOCK_PERIOD;
end process p_Clock_Gen;

end architecture behavioral;

-- Amal

KJ
Guest
Posts: n/a

 10-18-2007

"Amal" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> On Oct 17, 11:23 am, alivingstone <(E-Mail Removed)> wrote:
>> Thanks everyone for the responses.
>>

<snip>
> Would have been nice to have a FREQUENCY type and units defined in a
> standard package as well.
>
> Take a look at the following example code. The to_time function works
> fine regardless of the simulator resolution,

No it doesn't. Try your code with a frequency of 10 GHz and a simulator
time resolution of 1 ns (Modelsim's default). You'll get a clock period of
0 ns; Change the simulator resolution to 'ps' and you'll get the correct
clock period.

Good demonstration of the use of VHDL 'units' in defining your frequency
type though. It can make for clearer more understandable code but read on
for a 'gotcha'.

> but to_frequency would
> choke depending on what the simulator resolution is.

Converting from type 'time' to type 'frequency' is problematic because the
only time you can have type 'time' in the denominator of a calculation is
when there is also type 'time' in the numerator and the calculation gets
performed in the same manner as dividing two integers (i.e. 3 sec / 2 sec
3.0 sec / 2.0 sec = 1 sec...but it 'should' be 1.5 sec). I haven't found a
clean way around that one, but again it has nothing to do with the simulator
time resolution.

This behaviour during division I'm pretty sure is also true of any type
where VHDL 'units' are defined since I *think* a physical type definition
(i.e. something with 'units') must be in integer increments. If that is the
case, then it kind of presents a bit of a hinderance to using VHDL 'units'
elsewhere (like, 'foot', 'inch', 'meters', 'lbs', 'kg', etc.) because at
some point you'll want to put one of those things of that type in the
denominator of some equation and run into the same problem in translating
'time' to 'frequency'.

KJ

Amal
Guest
Posts: n/a

 10-18-2007
On Oct 17, 8:04 pm, "KJ" <(E-Mail Removed)> wrote:
> "Amal" <(E-Mail Removed)> wrote in message
>
> news:(E-Mail Removed) oups.com...> On Oct 17, 11:23 am, alivingstone <(E-Mail Removed)> wrote:
> >> Thanks everyone for the responses.

>
> <snip>
> > Would have been nice to have a FREQUENCY type and units defined in a
> > standard package as well.

>
> > Take a look at the following example code. The to_time function works
> > fine regardless of the simulator resolution,

>
> No it doesn't. Try your code with a frequency of 10 GHz and a simulator
> time resolution of 1 ns (Modelsim's default). You'll get a clock period of
> 0 ns; Change the simulator resolution to 'ps' and you'll get the correct
> clock period.
>
> Good demonstration of the use of VHDL 'units' in defining your frequency
> type though. It can make for clearer more understandable code but read on
> for a 'gotcha'.
>
> > but to_frequency would
> > choke depending on what the simulator resolution is.

>
> Converting from type 'time' to type 'frequency' is problematic because the
> only time you can have type 'time' in the denominator of a calculation is
> when there is also type 'time' in the numerator and the calculation gets
> performed in the same manner as dividing two integers (i.e. 3 sec / 2 sec
> 3.0 sec / 2.0 sec = 1 sec...but it 'should' be 1.5 sec). I haven't found a
> clean way around that one, but again it has nothing to do with the simulator
> time resolution.
>
> This behaviour during division I'm pretty sure is also true of any type
> where VHDL 'units' are defined since I *think* a physical type definition
> (i.e. something with 'units') must be in integer increments. If that is the
> case, then it kind of presents a bit of a hinderance to using VHDL 'units'
> elsewhere (like, 'foot', 'inch', 'meters', 'lbs', 'kg', etc.) because at
> some point you'll want to put one of those things of that type in the
> denominator of some equation and run into the same problem in translating
> 'time' to 'frequency'.
>
> KJ

I understand the point you're making KJ. Division of two time units
yields integer. But the case for the to_frequency function somehow
returns to the simulator resolution I think and it makes time units
smaller than the simulator resolution zero and that causes a division
by zero in ( t/sec ). For example if simulator resolution is ns and t
is specified as 10 fs, then t is evaluated as 0.

Then maybe time should have been defined using real? I guess that
would have caused made vhdl simulators more like AMS and not discrete
time! How does VHDL-AMS deal with this? What's the point of units if
one cannot use it to define real world standard units.

-- Amal

kennheinrich@sympatico.ca
Guest
Posts: n/a

 10-18-2007
On Oct 18, 9:30 am, Amal <(E-Mail Removed)> wrote:
> On Oct 17, 8:04 pm, "KJ" <(E-Mail Removed)> wrote:
>
>
>
> > "Amal" <(E-Mail Removed)> wrote in message

>
> >news:(E-Mail Removed) roups.com...> On Oct 17, 11:23 am, alivingstone <(E-Mail Removed)> wrote:
> > >> Thanks everyone for the responses.

>
> > <snip>
> > > Would have been nice to have a FREQUENCY type and units defined in a
> > > standard package as well.

>
> > > Take a look at the following example code. The to_time function works
> > > fine regardless of the simulator resolution,

>
> > No it doesn't. Try your code with a frequency of 10 GHz and a simulator
> > time resolution of 1 ns (Modelsim's default). You'll get a clock period of
> > 0 ns; Change the simulator resolution to 'ps' and you'll get the correct
> > clock period.

>
> > Good demonstration of the use of VHDL 'units' in defining your frequency
> > type though. It can make for clearer more understandable code but read on
> > for a 'gotcha'.

>
> > > but to_frequency would
> > > choke depending on what the simulator resolution is.

>
> > Converting from type 'time' to type 'frequency' is problematic because the
> > only time you can have type 'time' in the denominator of a calculation is
> > when there is also type 'time' in the numerator and the calculation gets
> > performed in the same manner as dividing two integers (i.e. 3 sec / 2 sec
> > 3.0 sec / 2.0 sec = 1 sec...but it 'should' be 1.5 sec). I haven't found a
> > clean way around that one, but again it has nothing to do with the simulator
> > time resolution.

>
> > This behaviour during division I'm pretty sure is also true of any type
> > where VHDL 'units' are defined since I *think* a physical type definition
> > (i.e. something with 'units') must be in integer increments. If that is the
> > case, then it kind of presents a bit of a hinderance to using VHDL 'units'
> > elsewhere (like, 'foot', 'inch', 'meters', 'lbs', 'kg', etc.) because at
> > some point you'll want to put one of those things of that type in the
> > denominator of some equation and run into the same problem in translating
> > 'time' to 'frequency'.

>
> > KJ

>
> I understand the point you're making KJ. Division of two time units
> yields integer. But the case for the to_frequency function somehow
> returns to the simulator resolution I think and it makes time units
> smaller than the simulator resolution zero and that causes a division
> by zero in ( t/sec ). For example if simulator resolution is ns and t
> is specified as 10 fs, then t is evaluated as 0.
>
> Then maybe time should have been defined using real? I guess that
> would have caused made vhdl simulators more like AMS and not discrete
> time! How does VHDL-AMS deal with this? What's the point of units if
> one cannot use it to define real world standard units.
>
> -- Amal

In this thread, we're fighting two distinct issues:

(1) standard type 'time' has special properties (from the language
definition) that make it silently change small time values to zero.
This is handy for rough 'n' ready engineering use but makes it awkward
to use for meaninfgul algebraic manipulation.

(2) value of physical types are always discrete (i.e. based on an
integer range, not a real (or floating point) range)

Problem (1) you could work around in limited form by defining your own
type, but then you'd just have to convert it back to standard 'time'
to be legal in all the places you want it to be (like following an
'after' keyword). Overloading would let you hide some, but not all, of
the mess.

Problem (2) has been addressed above by using various forms of type
casting to get the integer value of the time value into the reals
where you can do better arithmetic. But these still suffer from more
fundamental problem that you can't always assume that expressions
written as integers, reals, and rationals are equally expressive and
will preserve relationships. What I mean by this, is that if you have
two integer frequency constants as integers that are in the *exact*
ratio 3:4, it may not be true that the real times your function
computes are still in the *exact* ratio of 4:3. I don't think the
proposed FREQUENCY type mentioned earlier would help this.

Consider that if you wanted to simulate two locked clocks of 100 MHz
and 133.333... MHz MHz, locked to each other, that there is no simple
way of writing two independent loops of the form "clock <= not clock
after delta_T" that will keep the two clocks in phase and locked over
unbounded simulation time. For the general case you have to approach
the problem differently and do a bit more work.

- Kenn