Frequency to Time Conversion

A

alivingstone

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

Laurent Pinchart

alivingstone said:
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
 
R

Ralf Hildebrandt

alivingstone said:
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
 
J

Jeff Cunningham

alivingstone said:
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
 
J

Jonathan Bromley

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
(e-mail address 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.
 
A

alivingstone

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

Amal

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
 
K

KJ

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
 
A

Amal

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


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
 
K

kennheinrich

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
 
K

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
 
K

KJ

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top