Generics and constants

R

Rob Misc

Hi,
I have a component which has a latency that needs to be known by
anything that instantiates it. The component sits in its own library
and so I've created a package with the latency in that is included by
anything that instantiates the component. Is that the good way of
doing things?

Now, I want to have two different versions of the component,
controlled by a generic. Unfortunately the latency of the component
will be different for each version. How can I go about providing the
latency as a constant now? As I understand it, you can't have generics
in a package.

I suppose an alternative is to create a integer port on the component
which outputs the latency, but that's really horrible. Is there any
better of doing what I've described?

Thanks,
Rob.
 
J

Jonathan Bromley

I have a component which has a latency that needs to be known by
anything that instantiates it. The component sits in its own library
and so I've created a package with the latency in that is included by
anything that instantiates the component. Is that the good way of
doing things?

Sounds OK to me. Keep related stuff together, as always. You could
put the component definition in the same package, if you don't mind
using indirect (component) instantiation.
Now, I want to have two different versions of the component,
controlled by a generic. Unfortunately the latency of the component
will be different for each version. How can I go about providing the
latency as a constant now? As I understand it, you can't have generics
in a package.

Fascinating. Almost exactly this was raised by someone else only
a couple of months ago, and it generated quite heated debate.

To set the record straight: VHDL does *not* provide any decent
way to propagate constant values UP the design hierarchy.
Generics, as I'm sure you've worked out for yourself, are
intended to propagate information DOWN the hierarchy, from
parent module to embedded instance.
Now, I want to have two different versions of the component,
controlled by a generic. Unfortunately the latency of the component
will be different for each version. How can I go about providing the
latency as a constant now?

When you say "controlled by a generic", do you mean that a
generic of the upper, instantiating module will control which
version is instantiated, using "if generate" or somesuch?
Or do you mean that you supply a generic to the component,
and as a consequence of that generic value its latency
can take one of two possible values? If it's the latter,
then I would have thought you could put a function into
your package that would return the latency as a function
of the generic (by table lookup or whatever). Or provide
a table of constants in the package, yielding latency as
a function of some enumeration type (which you could later
extend); you could then use the same enumeration type to
specify which version of the module you wish to instance.
As I understand it, you can't have generics in a package.

Correct, although VHDL-200x will offer package generics
which probably will do something like what you require.
You may need to beat on your tool vendor to get support
for package generics, though.
I suppose an alternative is to create a integer port on the component
which outputs the latency, but that's really horrible. Is there any
better of doing what I've described?

I'm not sure I understand what's so horrible about it.
Presumably the device must in some way inform the enclosing
module about its behaviour; why not by exposing some constant
value through a port? Synthesis should do The Right Thing (tm)
with it.

Otherwise, I'm afraid, it's a matter of finding *some* way
to drive the hierarchy from above, not from below.

Upwards propagation of generics (or parameters, or constants,
or whatever you like to call them) is a sure way to get nasty
problems with circular references at elaboration. For an
entertaining case in point, take a look at the way the Verilog
standard has had to be tweaked to avoid exactly these cyclic
parameter specification issues, since Verilog does indeed
offer arbitrary propagation of parameters up and down the
hierarchy using its "defparam" feature.
--
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.
 
K

KJ

Rob Misc said:
Hi,
I have a component which has a latency that needs to be known by
anything that instantiates it. The component sits in its own library
and so I've created a package with the latency in that is included by
anything that instantiates the component. Is that the good way of
doing things?

Now, I want to have two different versions of the component,
controlled by a generic. Unfortunately the latency of the component
will be different for each version. How can I go about providing the
latency as a constant now? As I understand it, you can't have generics
in a package.
One way is to create a function inside the package that returns the latency
as a function of the generic that is also used to control the component.
The downside to this is that there is nothing to prevent the higher level
stuff from calling the function and instantiating the entity using different
values for the generic. Well placed comments here in the instantiating code
can help.

Having said that though, the risk here is typically pretty low since
simulation should be validating that the overall function of the system is
correct and such oversights will end up in incorrect behaviour which should
cause your simulation testbench to catch the incorrect behaviour (but leave
it to you to debug down to the root cause being the discrepancy between how
the function was called and how the component was instantiated).
I suppose an alternative is to create a integer port on the component
which outputs the latency, but that's really horrible. Is there any
better of doing what I've described?
There is nothing particularly 'wrong' with having a component output that is
some constant that is computed as a function of some generic control. In
fact, such a solution avoids the above mentioned drawback about not really
being able to prevent the user of your component (the higher level stuff)
from thinking there should be one latency (as defined by the function) when
in fact there is a different one (as defined by the actual behaviour of the
component).

In either case, the higher level entity will be receiving something that is
a constant for a given instantiation and should synthesize to exactly the
same result (synthesizers love to optomize things they find to be
'constants').

The downside to this approach though is that this output can't then be used
to control other constants/generics of other components. So, for example,
you couldn't use this output signal as an input generic to some other
component (although it could be used as an input 'signal' to that other
component). Many times, you can pass in constants as signals with no
penalty in synthesis, but other times you can't. Whether that works for you
or not depends on precisely what you're trying to do.

Another way is for the component to output some form of 'valid data'
indicator and try to avoid having the higher level logic to have this need
to 'know' what the latency is in the first place. There isn't enough info
in your post to know whether or not your higher level logic really requires
this latency knowledge or if simply flagging the data is sufficient so
that's up to you to investigate.

KJ
 
K

KJ

<snip>
A fourth approach would be to change it around a bit and have the latency be
the generic that is specified instead. That way there is no need for the
higher level logic to 'know' what the latency of the component is, it
specifies the latency that it wants. Whether this is a good approach or not
depends on the usage within the component.

Using 'Latency' to select between using a 'bubble sort' or a 'quicksort'
algorithm would probably not be a good use of such a generic.

Using 'Latency' to control the number of pipeline stages you implement in
order to give the user of the component some control to tradeoff clock cycle
performance versus latency would be a good use.

If the latency generic is used you can also limit the range of that generic
to things that you know work and have tested. For example if latencies of 2
and 3 are the only acceptable values (for whatever reason) you could have
the generic specified as "Latency: in natural range 2 to 3;". If the only
acceptable values are 2 and 5 it would be a two step process; first define
the range as 2 to 5, then add asserts that check that the generic really is
only 2 or 5 and errors out if not. That way if the component is being used
in an unsupported manner, both simulation and synthesis will grind to a
halt.

I'm not sure if there is a way to embed the knowledge of only allowing 2 and
5 in the above example as the only valid values in the entity (it would be
nice), so I put such assertions in the architecture. The downside to this
on the simulation side is that it compiles just fine, because the assertion
doesn't occur until you start the simulation. If those asserts could be in
the entity I would think the compiler would catch it right up front before
you even try to simulate. Maybe Jonathon or Jim Lewis can chime in on this
point.

KJ
 
J

Jonathan Bromley

I'm not sure if there is a way to embed the knowledge of only allowing 2 and
5 in the above example as the only valid values in the entity (it would be
nice), so I put such assertions in the architecture.

In principle, entities can have a begin-end block with processes
(including assertions):

entity widget is
generic (M, N: integer);
port (....);
begin -- entity!!!
assert N = 2**M
report "Mismatched generics"
severity FATAL;
end;

Anything you thuswise put in an entity must be a "passive process",
i.e. it is not permitted to write to any signals.

I haven't yet found a synthesis tool that will buy this, so I
don't ever use it. Consequently I don't know at what stage a
simulator would check this assertion. I suspect it would
follow the same rules as for any other process: it'll start
to execute at time 0, when you begin to run the sim.

[speculation_mode = on]
So, how could you get an assertion to execute at elaboration
time? (No chance of running it at analysis time, of course).
Well... don't constant initialisers get evaluated at elab
time? So, suppose I add a declaration of a dummy constant,
initialise it from a function, and include an assertion in
that function?

package p is
function check(test:boolean) return boolean;
end;
package body p is
function check(test:boolean) return boolean is
begin
assert test report "check failed" severity failure;
return test;
end;
end;

use work.p.all;
entity mumble is
generic (M, N: integer);
begin
process
constant C: boolean := check(N = 2**M);
begin
wait;
end process;
end;

hmmm, no time to check this out right now. Something
for another day.
--
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.
 
R

Rob Misc

<snip>
A fourth approach would be to change it around a bit and have the latency be
the generic that is specified instead. That way there is no need for the
higher level logic to 'know' what the latency of the component is, it
specifies the latency that it wants. Whether this is a good approach or not
depends on the usage within the component.

Using 'Latency' to select between using a 'bubble sort' or a 'quicksort'
algorithm would probably not be a good use of such a generic.

Using 'Latency' to control the number of pipeline stages you implement in
order to give the user of the component some control to tradeoff clock cycle
performance versus latency would be a good use.

If the latency generic is used you can also limit the range of that generic
to things that you know work and have tested. For example if latencies of 2
and 3 are the only acceptable values (for whatever reason) you could have
the generic specified as "Latency: in natural range 2 to 3;". If the only
acceptable values are 2 and 5 it would be a two step process; first define
the range as 2 to 5, then add asserts that check that the generic really is
only 2 or 5 and errors out if not. That way if the component is being used
in an unsupported manner, both simulation and synthesis will grind to a
halt.

I'm not sure if there is a way to embed the knowledge of only allowing 2 and
5 in the above example as the only valid values in the entity (it would be
nice), so I put such assertions in the architecture. The downside to this
on the simulation side is that it compiles just fine, because the assertion
doesn't occur until you start the simulation. If those asserts could be in
the entity I would think the compiler would catch it right up front before
you even try to simulate. Maybe Jonathon or Jim Lewis can chime in on this
point.

KJ

Thanks Jonathan and KJ for your useful suggestions. In my case I think
I'll go down the route of a function in the package to return the
latency. It's not ideal as you point out because it relies on the
instantiating component being consistent in it's use of the generics,
but in my design that's fine.

Thinking about it, I suppose the output port method isn't "horrible",
but it probably isn't great for me: there are several components
controlled by the same generic and they all need to return their
appropriate latencies to higher levels and also components in the same
level. (The design is a pipeline with multiple branches). So in my
case, this would create lots of ports all over the place. Probably
workable, but the function method seems better.

Cheers,
Rob
 
T

Tricky

[speculation_mode = on]
So, how could you get an assertion to execute at elaboration
time? (No chance of running it at analysis time, of course).
Well... don't constant initialisers get evaluated at elab
time? So, suppose I add a declaration of a dummy constant,
initialise it from a function, and include an assertion in
that function?

package p is
function check(test:boolean) return boolean;
end;
package body p is
function check(test:boolean) return boolean is
begin
assert test report "check failed" severity failure;
return test;
end;
end;

use work.p.all;
entity mumble is
generic (M, N: integer);
begin
process
constant C: boolean := check(N = 2**M);
begin
wait;
end process;
end;

hmmm, no time to check this out right now. Something
for another day.


I can confirm this works, I have it in several parts of my VHDL (to
check generics are within limits, often to check that a generic is set
as an odd number).
Unfortunatly, this will cause Modelsim 6.1g to crash (both windows and
linux versions, confirmed by mentor as a bug) if the severity level is
failure (quite a critical failure! ;) ). This is true for both "assert
not fail report .." and "if fail then report....", all other levels
will work fine though . Works fine in 6.2+.
 
A

Amal

[speculation_mode = on]
So, how could you get an assertion to execute at elaboration
time? (No chance of running it at analysis time, of course).
Well... don't constant initialisers get evaluated at elab
time? So, suppose I add a declaration of a dummy constant,
initialise it from a function, and include an assertion in
that function?
package p is
function check(test:boolean) return boolean;
end;
package body p is
function check(test:boolean) return boolean is
begin
assert test report "check failed" severity failure;
return test;
end;
end;
use work.p.all;
entity mumble is
generic (M, N: integer);
begin
process
constant C: boolean := check(N = 2**M);
begin
wait;
end process;
end;
hmmm, no time to check this out right now. Something
for another day.

I can confirm this works, I have it in several parts of my VHDL (to
check generics are within limits, often to check that a generic is set
as an odd number).
Unfortunatly, this will cause Modelsim 6.1g to crash (both windows and
linux versions, confirmed by mentor as a bug) if the severity level is
failure (quite a critical failure! ;) ). This is true for both "assert
not fail report .." and "if fail then report....", all other levels
will work fine though . Works fine in 6.2+.

It bugs me that you cannot define a generic based on another generic.
Hopefully VHDL-200x has something for that and not using packages.

-- Amal
 
K

KJ

[speculation_mode = on]
So, how could you get an assertion to execute at elaboration
time? (No chance of running it at analysis time, of course).
Well... don't constant initialisers get evaluated at elab
time? So, suppose I add a declaration of a dummy constant,
initialise it from a function, and include an assertion in
that function?
package p is
function check(test:boolean) return boolean;
end;
package body p is
function check(test:boolean) return boolean is
begin
assert test report "check failed" severity failure;
return test;
end;
end;
use work.p.all;
entity mumble is
generic (M, N: integer);
begin
process
constant C: boolean := check(N = 2**M);
begin
wait;
end process;
end;
hmmm, no time to check this out right now. Something
for another day.
I can confirm this works, I have it in several parts of my VHDL (to
check generics are within limits, often to check that a generic is set
as an odd number).
Unfortunatly, this will cause Modelsim 6.1g to crash (both windows and
linux versions, confirmed by mentor as a bug) if the severity level is
failure (quite a critical failure! ;) ). This is true for both "assert
not fail report .." and "if fail then report....", all other levels
will work fine though . Works fine in 6.2+.

It bugs me that you cannot define a generic based on another generic.
Hopefully VHDL-200x has something for that and not using packages.

-- Amal- Hide quoted text -

For example??

A generic that is defined based on 'another' generic, doesn't sound
like a 'generic' in the VHDL sense. It sounds like a constant that is
computed (in the architecture most likely) based on the value of the
true generic.

Not sure what case you think is missing.

KJ
 
A

Amal

[speculation_mode = on]
So, how could you get an assertion to execute at elaboration
time? (No chance of running it at analysis time, of course).
Well... don't constant initialisers get evaluated at elab
time? So, suppose I add a declaration of a dummy constant,
initialise it from a function, and include an assertion in
that function?
package p is
function check(test:boolean) return boolean;
end;
package body p is
function check(test:boolean) return boolean is
begin
assert test report "check failed" severity failure;
return test;
end;
end;
use work.p.all;
entity mumble is
generic (M, N: integer);
begin
process
constant C: boolean := check(N = 2**M);
begin
wait;
end process;
end;
hmmm, no time to check this out right now. Something
for another day.
I can confirm this works, I have it in several parts of my VHDL (to
check generics are within limits, often to check that a generic is set
as an odd number).
Unfortunatly, this will cause Modelsim 6.1g to crash (both windows and
linux versions, confirmed by mentor as a bug) if the severity level is
failure (quite a critical failure! ;) ). This is true for both "assert
not fail report .." and "if fail then report....", all other levels
will work fine though . Works fine in 6.2+.
It bugs me that you cannot define a generic based on another generic.
Hopefully VHDL-200x has something for that and not using packages.
-- Amal- Hide quoted text -

For example??

A generic that is defined based on 'another' generic, doesn't sound
like a 'generic' in the VHDL sense. It sounds like a constant that is
computed (in the architecture most likely) based on the value of the
true generic.

Not sure what case you think is missing.

KJ

Not necessarily. I know it is a constant, but what if you need to
declare port sizes based on this new constant. You can define entity-
wide constants inside the entity declaration. But the fact that they
cannot be before port declarations, makes them unusable in this
sense. The following example shows this (log2_ceil is defined in a
package and returns ceil(logs(x))):

entity example is
generic (
WIDTH : positive := 8;
DEPTH : positive := 32;
-- Cannot reference another generic! :(
-- SIZE : positive := log2_ceil(DEPTH) + 1;
);
-- Cannot define constant here! :(
-- constant SIZE : positive := log2_ceil(DEPTH) + 1;
port (
a : in std_logic_vector(WIDTH-1 downto 0);
b : in std_logic_vector(DEPTH-1 downto 0);
c : out std_logic_vector(SIZE-1 downto 0)
);
-- Constant defined here cannot be used in the port list! :(
-- constant SIZE : positive := log2_ceil(DEPTH) + 1;
end entity example;

-- Amal
 
M

Mike Treseler

Amal said:
Not necessarily. I know it is a constant, but what if you need to
declare port sizes based on this new constant. You can define entity-
wide constants inside the entity declaration. But the fact that they
cannot be before port declarations, makes them unusable in this
sense. The following example shows this (log2_ceil is defined in a
package and returns ceil(logs(x))):


Your function and a subtype based on it,
could be declared in a package used by the entity.
I usually declare a package ahead of
each design entity, in the same file,
to cover this.

However, I still find generics useful for
testbench options on the command line.

-- Mike Treseler
 
K

KJ

It bugs me that you cannot define a generic based on another generic.
Not necessarily. I know it is a constant, but what if you need to
declare port sizes based on this new constant. You can define entity-
wide constants inside the entity declaration. But the fact that they
cannot be before port declarations, makes them unusable in this
sense. The following example shows this (log2_ceil is defined in a
package and returns ceil(logs(x))):

entity example is
generic (
WIDTH : positive := 8;
DEPTH : positive := 32;
-- Cannot reference another generic! :(
-- SIZE : positive := log2_ceil(DEPTH) + 1;
);
-- Cannot define constant here! :(
-- constant SIZE : positive := log2_ceil(DEPTH) + 1;
port (
a : in std_logic_vector(WIDTH-1 downto 0);
b : in std_logic_vector(DEPTH-1 downto 0);
c : out std_logic_vector(SIZE-1 downto 0)
);
-- Constant defined here cannot be used in the port list! :(
-- constant SIZE : positive := log2_ceil(DEPTH) + 1;
end entity example;

-- Amal- Hide quoted text -

- Show quoted text -

You can use functions though to define the port size thereby avoiding
needing to define an intermediate constant to use in the port size.
In your above example change the definition of port 'c' from

c : out std_logic_vector(SIZE-1 downto 0)

to this
c : out std_logic_vector((log2_ceil(DEPTH) + 1) - 1 downto 0)

or simply this
c : out std_logic_vector(log2_ceil(DEPTH) downto 0)

I've used this successfully (simulation with Modelsim; synthesis with
Quartus), other tools should handle this or have a service request
opened if they don't.

Kevin Jennings
 
A

Amal

You can use functions though to define the port size thereby avoiding
needing to define an intermediate constant to use in the port size.
In your above example change the definition of port 'c' from

c : out std_logic_vector(SIZE-1 downto 0)

to this
c : out std_logic_vector((log2_ceil(DEPTH) + 1) - 1 downto 0)

or simply this
c : out std_logic_vector(log2_ceil(DEPTH) downto 0)

I've used this successfully (simulation with Modelsim; synthesis with
Quartus), other tools should handle this or have a service request
opened if they don't.

Kevin Jennings

I guess I gave you a bad example. Yes it is true that in this case I
can use a function. And declaring constants and other functions in a
package does not make an entity a self contained object and ties it to
a package.

It would still be nice to refer to other generics, but declare these
constants somehow and not user programmable.
-- Amal
 
K

KJ

I guess I gave you a bad example. Yes it is true that in this case I
can use a function. And declaring constants and other functions in a
package does not make an entity a self contained object and ties it to
a package.

I agree that referring to other packages does not make an entity self
contained, but I guess I don't see the need for an entity to be self
contained either. Every entity that uses std_logic refers to and is
therefore tied to ieee.std_logic_1164 and would not be self contained
either. Based on that, I don't see that tying an entity to some
quirky function in some design specific package is necessarily a bad
thing to do. Many times that package and function might exist in the
same physical file if you put package/entity/architecture together
into a single file as I do.

For the particular case of the 'log2' function though, that is general
enough that I put it into a package of common and generally useful
functions/procedures that I tend to use multiple places but are not
design specific. In that case, that package exists in a separate file
so would not be quite so obvious to the casual observer simply
scanning the text. But since I would also usually try to call the
function as 'work.vhd_common.log2(...)' so that such an observer would
know that they need to hunt down the file that contains the package
'vhd_common'. They could also hunt for 'log2' obviously, it just
gives them two pieces of information for the search.
It would still be nice to refer to other generics, but declare these
constants somehow and not user programmable.
-- Amal- Hide quoted text -

I'm not disagreeing, just trying to understand the situation where
this might come up which was the reason I asked for an example. If
you can come up with one that can not be addressed by functions (or at
least not cleanly) I'm still interested.

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

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top