Frequency to Time Conversion

Discussion in 'VHDL' started by alivingstone, Oct 17, 2007.

1. alivingstoneGuest

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.
alivingstone, Oct 17, 2007

2. Laurent PinchartGuest

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
Laurent Pinchart, Oct 17, 2007

3. Ralf HildebrandtGuest

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
Ralf Hildebrandt, Oct 17, 2007
4. Jeff CunninghamGuest

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
Jeff Cunningham, Oct 17, 2007
5. Jonathan BromleyGuest

On Wed, 17 Oct 2007 06:36:07 -0700, alivingstone
<> 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.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
Jonathan Bromley, Oct 17, 2007
6. alivingstoneGuest

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.
alivingstone, Oct 17, 2007
7. AmalGuest

On Oct 17, 11:23 am, alivingstone <> 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
Amal, Oct 17, 2007
8. KJGuest

"Amal" <> wrote in message
news:...
> On Oct 17, 11:23 am, alivingstone <> 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
KJ, Oct 18, 2007
9. AmalGuest

On Oct 17, 8:04 pm, "KJ" <> wrote:
> "Amal" <> wrote in message
>
> news:...> On Oct 17, 11:23 am, alivingstone <> 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
Amal, Oct 18, 2007
10. Guest

On Oct 18, 9:30 am, Amal <> wrote:
> On Oct 17, 8:04 pm, "KJ" <> wrote:
>
>
>
> > "Amal" <> wrote in message

>
> >news:...> On Oct 17, 11:23 am, alivingstone <> 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
, Oct 18, 2007
11. KJGuest

On Oct 18, 9:30 am, Amal <> wrote:
> On Oct 17, 8:04 pm, "KJ" <> wrote:
>
>
>
>
>
> > "Amal" <> wrote in message

>
> >news:...> On Oct 17, 11:23 am, alivingstone <> 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.
>

Whenever I've needed to put time in the denominator of a calculation,
the work around I've used is to first convert the numbers to reals by
dividing both the numerator and denominator by a 'small' time unit.
So if I need to compute A / B where A and B are both of type time,
then I'd compute it as
real(A / 1 ps) / real (B / 1 ps)

This will return a number of type real. In your case of trying to
convert to frequency units, A would be '1 sec' and B would be your
input clock period. The problem comes up if the small time unit '1
ps' in the denominator is smaller than the simulator resolution in
which case it compiles fine but when you go to start simulating you
get a floating point exception because of a divide by 0.

If you try to use the smallest available time unit that VHDL defines
(1 fs) and simulate with fs time resolution I'm guessing that there
might be some simulation performance hit. Since the simulator is
event driven, it *shouldn't* really matter if signal event times are
now accurate to the fs level but I haven't tested this enough to say
for sure. If it doesn't really affect the time it takes to simulate
then simply using 'fs' in the above calculation and for simulation
time resolution would be a robust approach to the problem, but like I
said I haven't explored it enough to know.

If you do divisions of time types in this fashion, you've created a
dependency now between the VHDL code and the simulation environment
used to run that code as well as a dependency between the VHDL code
and the synthesis environment (if the division of time types is part
of synthesizable code).

While such dependencies aren't usually a good thing, it's typically
not necessarily a bad thing either since most projects of any size
will have build scripts or macros or something where the minimum time
unit can be specified (if necessary).

> 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.
>

I think the basic point was that for physical types (i.e. one with a
'units' definition, type 'time' being the classic example) that these
are defining minimum 'quanta' steps. Since the types can be defined
with whatever units one wants and you do have control over the
simulation environment, I don't think what is there now is unable to
define real world standard units 'as is' but I suppose we may be
getting near the limits if devices get even faster and 'ps' time
resolution is no longer accurate enough.

KJ
KJ, Oct 18, 2007
12. KJGuest

<> wrote in message
news:...
>
> 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.

It's not a language issue. The reason small time increments 'change' to 0
is because the simulator was not told to use the proper simulation time
step.

> This is handy for rough 'n' ready engineering use but makes it awkward
> to use for meaninfgul algebraic manipulation.
>

But can be mostly overcome with a little bit of thought once the basic
understanding of the issue is there.

> (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.

'Time' is already a type....making a 'new' one wouldn't help. What you're
trading off here is the use of VHDL 'units' on a new type.

>
> 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.
>

And that problem will always exist in any finite precision mathematics based
system.

> 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.
>

I wouldn't approach that problem with a simulator that used finite precision
mathematics if I wanted an 'exact' answer. Having a time step of 'fs'
though would likely be accurate enough for the length of the simulation run
if I did need to run in a logic simulation environment.

KJ
KJ, Oct 18, 2007