Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Generics vs Constants - what criteria do you use to choose between these?

13 views
Skip to first unread message

Andrew FPGA

unread,
Oct 4, 2006, 5:03:17 PM10/4/06
to
Hi all,
I often find myself implementing a piece of functionality whose
behaviour I want to control using either a Generic or a constant. But
sometimes I'm not sure if a generic or a constant is the best approach.
By "best" approach I mean the style which gives the best tradeoff in
flexibility of design, ease of understanding the design, and ease of
use by grouping these "build functionality modifiers". What criteria
do others use when choosing between the use of a generic or a constant
in their design?

Quick example: Say I have some debug code (say a PRBS generator) that I
only want included in the design for debug builds. For the production
release I don't want the functionality there. I would use a generate
statement around the PRBS generator. Then I could
a) have a Generic on the module in which this PRBS generator exists
called "INCLUDE_PRBS_GENERATOR : boolean" . Whenever this module is
instantiated I can choose to build with or without the PRBS generator.
b) I could have a constant INCLUDE_PRBS_GENERATOR. That constant can be
set to true/false within the module or could be put into a package
collecting together all build options in one place.

Advantages of the generic approach:
1) Each instantiation of the module can be customised differently to
the others.
2) ?

Advantages of the constant approach:
1) All build options can be packaged up in one place, not scattered
throughout the design hierarchy.
2) Less typing, don't need to remember to include the generic on every
instantiation.
3)?

Regards
Andrew

Mike Treseler

unread,
Oct 4, 2006, 6:13:45 PM10/4/06
to
Andrew FPGA wrote:

> Quick example: Say I have some debug code (say a PRBS generator) that I
> only want included in the design for debug builds. For the production
> release I don't want the functionality there.

I would put the generator in the testbench
if it were not a hardware option.

For hardware options, I use input port bits
to set mode options and I let synthesis
work out the details of generating
the exact hardware needed for static or dynamic modes.

I comment out debug assertions in uut code
once a problem is solved.
Or I might replace the debug code with
an explanation of the bug and the fix.

> Advantages of the generic approach:

I use generics on a testbench for
controlling tests from the command line
using vsim -G.

A complex design entity usually needs
a package to share types and constants
common to the uut and testbench, but
sometimes I like to set basic port dimensions
with a generic default on the uut and let the testbench
ignore it or override the default with
a generic map.

> Advantages of the constant approach:

Packaged types and constants can be shared.

The downside is, I have to open
another file to remember the actual
lengths, enumerations etc.

-- Mike Treseler


KJ

unread,
Oct 5, 2006, 7:06:50 AM10/5/06
to

"Andrew FPGA" <andrew.n...@gmail.com> wrote in message
news:1159995797.6...@i3g2000cwc.googlegroups.com...

> Hi all,
> I often find myself implementing a piece of functionality whose
> behaviour I want to control using either a Generic or a constant. But
> sometimes I'm not sure if a generic or a constant is the best approach.
> By "best" approach I mean the style which gives the best tradeoff in
> flexibility of design, ease of understanding the design, and ease of
> use by grouping these "build functionality modifiers". What criteria
> do others use when choosing between the use of a generic or a constant
> in their design?
The basic question that I ask is "If I were to reuse this code in some
fashion, what things can I pull out and make generics so that I don't have
to look at the details of the code in order to know how to use it in a
different application?" Anything not meeting that criteria would be coded
as a constant, the ones that do I would make generics on the entity.

> Quick example: Say I have some debug code (say a PRBS generator) that I
> only want included in the design for debug builds. For the production
> release I don't want the functionality there. I would use a generate
> statement around the PRBS generator. Then I could
> a) have a Generic on the module in which this PRBS generator exists
> called "INCLUDE_PRBS_GENERATOR : boolean" . Whenever this module is
> instantiated I can choose to build with or without the PRBS generator.
> b) I could have a constant INCLUDE_PRBS_GENERATOR. That constant can be
> set to true/false within the module or could be put into a package
> collecting together all build options in one place.
>
> Advantages of the generic approach:
> 1) Each instantiation of the module can be customised differently to
> the others.
> 2) ?

2. Design reuse. Since you'll have the RTL anyway you don't give up the
ability to look at the code again when you're reusing it and suspect
something isn't working but do you really want to have to get intimately
involved with every line of code that you (or someone) wrote a while back
just because you want to reuse it? I don't, I just want to use it, if it
doesn't work then I'll debug and improve it but jsut right out of the shoot
I don't care to require myself to know how it works as long as I have some
confidence that it was designed using sound design practices (which is tough
to know on anything other than stuff you write yourself).
3. Productivity. Because of #2, you'll be more productive (i.e. system
functions implemented per hour) if you can properly parameterize your code.
If you do a poor job I suppose you're no better off than having not done it
at all, don't see how it would be worse.

> Advantages of the constant approach:
> 1) All build options can be packaged up in one place, not scattered
> throughout the design hierarchy.

Don't need to be scattered. Typically when I create an entity with a
generic parameter, in many cases that generic will percolate it's way up to
the top level because at any level I mentally ask the question "If I were to
reuse this code..." and decide whether the generic of some lower level
entity should be brought up a level. Given that most percolate to the top
level of the design anyway, then this implies that all of the constants are
in one place, the top level design file where I then set them as constants
in that architecture.

> 2) Less typing, don't need to remember to include the generic on every
> instantiation.

Which is handy if you don't think the code will ever need to be modified.
But ideally you don't really write too much of that 'use it only once' code.
If you frequently do then maybe you should take a step back and see if there
really isn't a bigger picture to see.

One example that I use frequently in FPGA designs are for those things that
need to generate signals for specific times (for example a timer, or a
control signal that needs to have a certain pulse width, etc.) I'll have a
parameter of type time called Clock_Period. This parameter always
percolates all the way up to the top level since it's only there that you
can say what the clock period really is....and sometimes you don't know what
that period is until after you get a feel for what speed your code will run
at so having a simple constant to change in one file that gets passed down
as a generic is a big thing. My typical usage of Clock_Period would be
something like

entity Foo is generic(Clock_Period: time)
....
architecture RTL of Foo is
constant T1: 1 us; -- Assuming that T1 itself shouldn't be brought out as a
generic
constant T1_Counter: natural range 0 to T1 / Clock_Period;
begin
...
Define the usual code for a counter for signal T1_Counter that counts from 0
to T1 / Clock_Period - 1
end RTL;

At that top level where the generics are ultimately defined as constants I
find that there is frequently a bit of interaction between these constants
(i.e. one is derived from the other in some fashion). That
interrelationship should 'make sense', when it doesn't it means that you
probably have some conflicting ideas floating around that you need to get
resolved. If those constants were buried down in the code you wouldn't be
as likely to have noticed the conflict in the first place and wouldn't catch
it until you couldn't get the simulation (or your board) to work correctly.

By the way, I also don't limit myself to simple scalar type generics like
'Clock_Period' or integers for defining signal bus widths or booleans for
including/excluding sections of code. Arrays of some type, record types,
arrays of record types are very handy at times to use as signals and
generics....it all depends on how you choose to parameterize the design.
The better you get at parameterizing your code the more you'll find using
more than just scalar type generics is a 'good' thing.

KJ


Andy

unread,
Oct 9, 2006, 3:58:29 PM10/9/06
to
I've found a very interesting hybrid approach to managing constant
design parameters, but let me summarize some pro's and con's of
constants vs generics.

Constants can be defined in a global package for the project, and one
can simply be added anytime a new parameter in some lower level module
is needed. Constants, so long as they are not deferred, are locally
static values, and can be used virtually anywhere. But modifying
constants requires changing source code in a difficult-to-manage way.
Different sets of constants (say for build vs verification) must be
managed with separate files that define the same package, and are
selectively used based on the application (there are no named package
bodies that can be chosen via configurations, etc., and even if there
were, it would require deferred constants, which then loses the locally
static advantage).

Generics are not locally static, and must be passed down through the
hierarchy if they are to be centrally managed. However, they can be
managed within the abilities of vhdl, without resorting to file naming
slight-of-hand, by instantiation, configuration, and tool command line
options.

While there is nothing that can be done to address the non-locally
static problem of generics, managing their passing through the
hierarchy can be made easier. By defining a record type in a global
package which contains elements for each constant required, we can have
a flexible "handle" by which to pass all the parameters to every level
with a single generic map association. Whenever a new parameter is
needed, the record type is changed to add it, the value is set at the
top (entity, instance, configuration, or tool) and only the lower level
entity/architecture that needs it is modified to extract it from the
record.

The default values for the top level generic can be defined in the
generic declaration, or by referencing a constant defined in the same
global package that defined the record type. Either way, the default
assignments can be overridden by the testbench that instantiates the
top level entity, by one or more configuration declarations (requiring
a wrapper around the otherwise top level entity), or by tool command
line options.

BTW, I almost always use a ns_per_clk : positive generic to pass clock
period info for timers, etc. Synopsis used to not be able to specify
non-integer generics from the command line. I don't know if they can
today. To get around such a problem with records, the top leve entity
can have all the separate integer generics declared, and then assemble
them into a record in the top level architecture, for passing down
through the hierarchy.

No matter which method is used (constants or generics), I strongly
recommend subtyping them to constrain the values to practical limits.
If a parameter must, say, be a integral power of two, then a concurrent
assertion statement should verify that at the point of use.

Comments?

Andy

Paul Uiterlinden

unread,
Oct 9, 2006, 4:35:18 PM10/9/06
to
Andy wrote:

> While there is nothing that can be done to address the non-locally
> static problem of generics, managing their passing through the
> hierarchy can be made easier. By defining a record type in a global
> package which contains elements for each constant required, we can
> have a flexible "handle" by which to pass all the parameters to
> every level with a single generic map association. Whenever a new
> parameter is needed, the record type is changed to add it, the value
> is set at the top (entity, instance, configuration, or tool) and
> only the lower level entity/architecture that needs it is modified
> to extract it from the record.

[snip]
> Comments?

Just one clarification needed.

Correct me if I'm wrong: I suppose you also declare a signal in the
package. The type of the signal is the record type. And with a
concurrent signal assignment in the toplevel architecture you assign
the toplevel generic to that signal. It is that signal that you use
(read) at the lower levels. The signal is made visable by a use
clause at those levels.

> No matter which method is used (constants or generics), I strongly
> recommend subtyping them to constrain the values to practical
> limits. If a parameter must, say, be a integral power of two, then a
> concurrent assertion statement should verify that at the point of
> use.

Couldn't agree more. Although I would use the exponent as generic and
do the exponentiation (2**generic) where I need it (via a constant so
it is only compted once).

--
Paul.

Mike Treseler

unread,
Oct 9, 2006, 5:15:10 PM10/9/06
to
Andy wrote:

> Generics are not locally static, and must be passed down through the
> hierarchy if they are to be centrally managed. However, they can be
> managed within the abilities of vhdl, without resorting to file naming
> slight-of-hand, by instantiation, configuration, and tool command line
> options.

Yes, for a related example, see seed_c below:

generic (tb_char_g : natural := 8; -- generic length

--...
constant msb : natural := tb_char_g -1;
-- generic

subtype char_t is unsigned(msb downto 0);
-- generic type, usually 8 bits

constant zero_c : char_t := (others => '0');
-- generic type, usually 8 bits

constant seed_c : char_t := "100001" + zero_c;
-- follows wider generic widths

> Whenever a new parameter is
> needed, the record type is changed to add it, the value is set at the
> top (entity, instance, configuration, or tool) and only the lower level
> entity/architecture that needs it is modified to extract it from the
> record.

Very clever.
Thanks for the posting.

> Comments?

Could we trouble you for a simple example?

-- Mike Treseler

Andy

unread,
Oct 9, 2006, 6:30:48 PM10/9/06
to

While generics are not locally static, at least they are static.
Signals, even when driven from constants/generics, cannot drive range
constraints, generate statements, etc.

You are correct about the exponent example, but i've run into cases
where it was not as simple as that, and I could not adequately
constrain a generic to ensure compliance with the limitations of the
design. You also bring up a good point about related parameters:
whenever possible, they should be specified as one value, and the other
values calculated from them (a good example might be a bitwidth and a
corresponding numerical range, calculated via exponentiation).
Whenever one cannot be calculated from the others, but must meet some
relational requirement (i.e. a must be less than b) then an assertion
at the point of use is a good thing to use to verify it. Some
simulators will evaluate concurrent assertion statements with static
expressions during elaboration, before simulation even starts.

Andy

Andy

unread,
Oct 9, 2006, 6:37:14 PM10/9/06
to
Here is an example of a package and top level entity/architecture that
uses a record for the generic at the lower levels, but breaks it out at
the top level to make it easier to deal with setting generic values by
tool command line options.

Andy

library ieee;
use ieee.std_logic_1164.all;

package parameters is
-- define parameter record structure
type param_t is
record
ns_per_clk : positive; -- clock period in ns
num_channels : positive; -- number of input channels
channel_width : positive; -- width of each channel
end record;

-- (optional) define a set of default values for the parameters
constant default_param : param_t := (
ns_per_clk => 10,
num_channels => 16,
channel_width => 8
);

subtype slv is std_logic_vector; -- abbreviation

end package parameters;

library ieee;
use ieee.std_logic_1164.all;
use work.parameters.all;

entity top is
-- To maintain compatibility with compilers that do not
-- allow cmd line specification of non-scalar generic values,
-- we can separately define the individual generics here
-- then combine them into a record in the top level architecture.

generic ( -- individual scalar generics for tool compatibility
ns_per_clk : positive := default_param.ns_per_clk;
num_channels : positive := default_param.num_channels;
channel_width : positive := default_param.channel_width
);
port (
clk, we : in std_logic;
input : in slv(channel_width - 1 downto 0);
addr : in natural range 0 to num_channels - 1;
output : out slv(channel_width - 1 downto 0)
);

end entity top;

architecture rtl of top is
-- define parameter record contents for lower level generic
constant p : param_t := (
ns_per_clk => ns_per_clk,
num_channels => num_channels,
channel_width => channel_width
);

begin
u1: entity work.lower_level(rtl)
generic map ( -- pass just one parameter record
p => p
)
port map (
clk => clk,
we => we,
addr => addr,
input => input,
output => output
);
end architecture rtl;

Martin Thompson

unread,
Oct 10, 2006, 6:35:52 AM10/10/06
to
Hi Andy,

Good summary - thanks!

"Andy" <jone...@comcast.net> writes:
> BTW, I almost always use a ns_per_clk : positive generic to pass clock
> period info for timers, etc.

One question:

Do you find ns to be sufficiently precise? Or are you lucky int hat
all your clocks come out as a round number of ns?

> If a parameter must, say, be a integral power of two, then a concurrent
> assertion statement should verify that at the point of use.
>

Absolutely!

Cheers,
Martin

--
martin.j...@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.net/electronics.html


KJ

unread,
Oct 10, 2006, 6:40:36 AM10/10/06
to

"Andy" <jone...@comcast.net> wrote in message
news:1160423909....@i42g2000cwa.googlegroups.com...

> I've found a very interesting hybrid approach to managing constant
> design parameters, but let me summarize some pro's and con's of
> constants vs generics.
>
> While there is nothing that can be done to address the non-locally
> static problem of generics, managing their passing through the
> hierarchy can be made easier.
I guess I haven't found the managing of generic passing to be difficult...no
different than a signal.

> By defining a record type in a global
> package which contains elements for each constant required, we can have
> a flexible "handle" by which to pass all the parameters to every level
> with a single generic map association. Whenever a new parameter is
> needed, the record type is changed to add it, the value is set at the
> top (entity, instance, configuration, or tool) and only the lower level
> entity/architecture that needs it is modified to extract it from the
> record.

Perhaps we're seeing things a bit differently but when I pass my generics
through the hierarchy, the list-o-generics is generally quite a bit smaller
than the list-o-signals so having mapping for each of the generics is not
that tedious.

The other big problem is that the idea doesn't scale well. Within the
individual entity/architecture that will actually use the generic you now
have basically a global naming problem (i.e. entity foo uses G.some_integer
to control something). But then sometime later you create a new entity H
which needs some integer value so you think to use the 'some_integer' entry
to pass that value down.....still later you want to use both G and H in some
design and they are now both coded to use 'some_integer' but need them set
differently. The only way around that problem is to have that record type
continuously growing with each new parameter of each entity that you ever
write so that they are all totally independent. This gets to be an ugly
looking thing when...
- You go to assign values and have to assign all sorts of constants that
have nothing to do with today's design but they are in the record type
because they are used in entities A, B, C, D...etc. that were written years
ago.
- The individual record type names will also grow ugly because you will need
something like 'some_integer_for_entity_G' and 'some_integer_for_entity_H'
and the actual naming of generics will depend on the generics for every
other design that you've ever written up to that point.
- Then you'll try to integrate that with code that somebody else wrote
(using this same method) and have real ugliness because your record
definition will be completely different than theirs. So now you'll either
have to integrate their record type into yours and maintain the 'single'
generic approach or break your approach and pass in two generics, one of
'my_type' of one 'their_type'....which now makes all of those entities that
use two generics off in their own little space of all of the IP that you've
written.
- There will be no common standard for this generic. Instead the record
definition will be sort of a trail or history showing the various designs
that engineer 'X' has ever written in their career.
- As you get more sophisticated with the types of things you want to pass in
as generics you'll bust through and want to pass custom record types and
arrays and such (in case you're thinking that this is too esoteric, it's
not, I do this) which will mean that you'll need to include those custom
record types for the entire history of your career in every new design which
you probably do not want to do either.
- At some point the record type will get too unwieldy (becuase of the above
mentioned scaling issues) and you'll say to heck with it and chop it at some
point and create a second scaled down record type for 'simple'
generics....and repeat the same basic cycle.

Passing things that won't change from design to design (like the need for a
'clock period' generic) won't typically have this problem but I've found
this to be only a small fraction of the generics; most of them are specific
to the entity.

>
> BTW, I almost always use a ns_per_clk : positive generic to pass clock
> period info for timers, etc. Synopsis used to not be able to specify
> non-integer generics from the command line. I don't know if they can
> today. To get around such a problem with records, the top leve entity
> can have all the separate integer generics declared, and then assemble
> them into a record in the top level architecture, for passing down
> through the hierarchy.

Use of an integer like 'ns_per_clk' instead of simply using 'time' is
usually a band-aid because some tool (translated: synthesis tool) doesn't
support type 'time'. Synplify supports time types now because of a bug
report I submitted a couple years back...and they should support it
correctly soon because of yet another bug report I recently submitted.
Quartus supports 'time' and a couple other tools I've tried do as well
(forget exactly which ones I've tried it on, but I know I haven't tried it
on ISE yet).

In any case, use of integers is less descriptive than time. 'ns_per_clk'
becomes a bit of an issue when (if?) you at some point in the future find
yourself describing something near a GHz. Round off errors (i.e. using 7 or
8 instead of 7.8) for the clock period becomes a problem. Depending on how
that number ultimately gets used rounding down might not be appropriate in
some cases, rounding up in others....don't have that issue with 'time'.
Also the 'units' are more easily carried along and handled automatically.
I'd much rather see 25.4 us than 25400 and have to mentally remember the
units are 'ns_per_clk'....or did we switch to 'ps_per_clk' and the number
should be 25400000 (let me check, did I get the right number of '0's?)


>
> No matter which method is used (constants or generics), I strongly
> recommend subtyping them to constrain the values to practical limits.

I would say limit them to ranges that you've at least somewhat tested.

> If a parameter must, say, be a integral power of two, then a concurrent
> assertion statement should verify that at the point of use.

Yep, assertion check your generics so they don't get misused.

KJ


Andy

unread,
Oct 10, 2006, 10:06:51 AM10/10/06
to
KJ,

Thanks for the comments, you raise some really good points...

I've had FPGA designs with dozens of centralized parameters; assuming
you want those managed from one place, there are two reasonable
possibilities, a global package of constants, or generic records.

With generics, the parameters must be passed through every level, from
the top down to where they are needed. In a large, complex design,
managing what goes where is a lot tougher than managing a record
typedef, and passing everything everywhere. The record typedef becomes
the conduit, and you can pull as many wires through it as you want
(unlike a real conduit!), only having to worry about the endpoints, not
all the interfaces along the way.

BTW, I've used records for signal interfaces too, but they get uglier
with in/out/inout modes. They're supposed to be working on that (mode
definitions for multi-mode record ports). Since generics are always
like "mode in", records work extremely well for generics.

If naming collisions between record elements get to be a problem, you
could break up the record into subrecords for different sets of related
parameters, or even mimic the hierarchy of the design in the record
itself. The latter may or may not work so well when the same parameter
is used in different leaves of the hierarchy, since referencing it in
one leaf requires knowledge of the location of the other leaf where it
is set in the record.

You can also define functions along with the record type that override
a given element in the record, while passing the others intact, so you
do not have to manually break out the record elements and assign them
individually when you need to override an individual record element
before passing it on down. This would be helpful if an architecture
modifies a port width (muxing or demuxing it), or DCM's the clock
before handing it to a lower level entity.

Naming collisions between record elements and local objects do not
exist, since the elements are always prefixed with the record whose
type resolves the reference. You'll notice the top level individual
generics in the example have the same names as the record elements, and
that compiles ok.

I don't really see any difference, WRT the history of a designer's
designs, between a global package opf constants and using generics to
centrally manage design parameters. You'd have to prune the package or
the record to keep the parameters pared to those needed in the current
design. Using a record simplifies the generic pruning (compared to
separate generics), since it need only be done in one place (or two, if
you break them out individually at the top level)

It sounds like your argument is more specifically against centralized
parameter management, preferring to manage the parameters at the point
of use (at which point they cease being a parameter), or slightly above
it. That's another approach that has both strengths and weaknesses. I
like having a single 'parameter set' that controls the whole design,
and multiple ways to control that (defaults, instance generic map,
configurations, and tool options), but it does have its costs in
maintenance, etc. Centralized management also is really nice when two
distant entities need the same parameter. Managing them locally to each
entity invites problems with keeping them in sync.

Using a subtype of time for the clock period is a superior solution, so
long as your toolset, including simulation, formal analysis, synthesis,
etc. supports it universally. Some tools even support setting record
type generics on the command line, but unless they also support named
association (and not just a parenthesized list of values), that would
get really ugly, and it would probably be better to break them out into
individual generics at the top level if you intend to manage them
through the tool. If instead you only want to manage them through the
language (instance generic maps, configuration declarations, etc.) then
there is no need to break them out at the top level.

> I would say limit them [generic subtypes] to ranges that you've at least somewhat tested.

Thanks, that's a better way to define "practical".

Andy

Ben Jones

unread,
Oct 10, 2006, 10:14:58 AM10/10/06
to

"KJ" <kkjen...@sbcglobal.net> wrote in message
news:EMKWg.4918$NE6....@newssvr11.news.prodigy.com...

> The other big problem is that the idea doesn't scale well. Within the
> individual entity/architecture that will actually use the generic you now
> have basically a global naming problem (i.e. entity foo uses
> G.some_integer to control something). But then sometime later you create
> a new entity H which needs some integer value so you think to use the
> 'some_integer' entry to pass that value down.....still later you want to
> use both G and H in some design and they are now both coded to use
> 'some_integer' but need them set differently. The only way around that
> problem is to have that record type continuously growing with each new
> parameter of each entity that you ever write so that they are all totally

> independent. <snip>

Sounds like a "slippery slope" argument to me. :) No-one said you had to
have "just one" of these record types in your design...

I find that grouping signals and generics into record types early on in the
design phase is very useful. It massively reduces the amount of typing that
is needed to connect some signals from one block to another, and
simultaneously makes the code clearer because the reader doesn't have to sit
and compare two port lists to see that every signal in a group is connected
between A and B. And as previously pointed out, if you suddenly discover
that you need an extra signal or an extra generic in one of these bundles -
like I did this morning, in fact - you only need to add it in the definition
and the points of use; no need to go hunting through dozens of files adding
signals to entity declarations and port maps.

With generics, you definitely want to do this on a project-by-project basis.
I didn't experience the "explosion of fields in one monolithic record type"
problem; I think that would be a bit of an extreme situation. Rather, I tend
to have some high-level, design-specific information - such as which
features are supported, what latencies and relative latencies my
sub-components should have, and various derivative information - and keep
the local/ephemeral stuff local.

This approach also allows you to do some concentrated parameter checking by
writing a function to validate your record of generics (e.g. checking for
contradictory parameters). This, in addition to as many local assertions
etc. as necessary, seems be quite a robust way to manage your design
configuration.

Cheers,

-Ben-


KJ

unread,
Oct 10, 2006, 12:25:35 PM10/10/06
to

Andy wrote:
> KJ,
>
> Thanks for the comments, you raise some really good points...
>
> I've had FPGA designs with dozens of centralized parameters; assuming
> you want those managed from one place, there are two reasonable
> possibilities, a global package of constants, or generic records.
I prefer to put the constants in the top level of the design itself.
If there are multiple designs that need to access the same constant
then it would go into a package. By 'top level of the design' I mean
that if for example, I have three FPGAs and one CPLD on a board then
each of those parts will have some 'top level' source file and that's
the place I would put all but the shared constants.

I realize I could pull those constants out and make them generics as
well and bring them up higher but then you can run into the problem of
you're simulating one way for building actual parts another. By
stopping the generics at the top level of a physical design and making
them constants at that level, there is no chance of that happening. In
simulating real board designs with multiple parts I find that one less
headache is a good thing but others might like to bring those constants
out to be tweaked by the simulation testbench model itself and then
manually manage that synthesis builds use the correct parameter values.

> With generics, the parameters must be passed through every level, from
> the top down to where they are needed. In a large, complex design,
> managing what goes where is a lot tougher than managing a record
> typedef, and passing everything everywhere. The record typedef becomes
> the conduit, and you can pull as many wires through it as you want
> (unlike a real conduit!), only having to worry about the endpoints, not
> all the interfaces along the way.

I agree it is easier to manage things through the single generic record
type IF the entity is in flux and subject to change. I just haven't
hit the "threshold of pain" yet where this management hurts. Now maybe
the only reason for that is because of editor macros and the way I go
about instantiating an entity the first time. Plopping down an entity
to use it somewhere generally takes me mere moments regardless of how
many signals and generics there are.

Now if the entity itself is in flux and the signals or generics are
frequently changing then the record approach will pay for itself in
time....but so would nailing down the entity in the first place.

>
> BTW, I've used records for signal interfaces too, but they get uglier
> with in/out/inout modes. They're supposed to be working on that (mode
> definitions for multi-mode record ports). Since generics are always
> like "mode in", records work extremely well for generics.

I tried records for signal interfaces also and didn't like the way
Modelsim handled it in the 'Dataflow' window which I use while
debugging. I came to the conclusion that while it did sort of look
tidy to have all of the 'gazintas' in a single record, (and gazoutas
and bi-directs) in practice I didn't like to use it.

>
> If naming collisions between record elements get to be a problem, you
> could break up the record into subrecords for different sets of related
> parameters, or even mimic the hierarchy of the design in the record
> itself. The latter may or may not work so well when the same parameter
> is used in different leaves of the hierarchy, since referencing it in
> one leaf requires knowledge of the location of the other leaf where it
> is set in the record.

Getting messy ;)

>
> You can also define functions along with the record type that override
> a given element in the record, while passing the others intact, so you
> do not have to manually break out the record elements and assign them
> individually when you need to override an individual record element
> before passing it on down. This would be helpful if an architecture
> modifies a port width (muxing or demuxing it), or DCM's the clock
> before handing it to a lower level entity.

Functions are great that way.

> I don't really see any difference, WRT the history of a designer's
> designs, between a global package opf constants and using generics to
> centrally manage design parameters.

I don't either. I'll just point out that the "edit all of the design
parameters in a single file" can also be accomplished by simply putting
them as constants in whatever the 'top level' is.

We already agree that there are advantages to the record approach.
Where I was going with the "history of a designer's designs" was from
the standpoint of design reuse. In order to reuse the code without
modification you would need to not change the name of that record type.
This would lead one to choose a name for that record "KJ_Generics" and
always use that. That way any code that I write could safely get at
any record elements. Now you've done the same thing but I'm guessing
that yours might be called "Andys_Generics" or something...but
certainly not "KJ_Generics". Integrating our code will cause a bit of
headaches on those generics.

Using a record name that is somehow associated with the project
"ProjectX_Generics" doesn't solve the problem when you try to reuse
code on "Project Y".

If you don't reuse code much then this is not an issue....but since you
probably do I think it will.

> You'd have to prune the package or
> the record to keep the parameters pared to those needed in the current
> design. Using a record simplifies the generic pruning (compared to
> separate generics), since it need only be done in one place (or two, if
> you break them out individually at the top level)

And that pruning will be a reason to make sure you don't do the design
specific sort of path name thing that I think you were alluding to
either. You wouldn't want any parameter to be down a path since it
will probably be down a different path when reused in a different
design.

>
> It sounds like your argument is more specifically against centralized
> parameter management, preferring to manage the parameters at the point
> of use (at which point they cease being a parameter), or slightly above
> it.

No I manage it at the top level of each physical design as I mentioned
earlier which is just as centralized, definitely not point of use.
Must've been confusing in my wording.

> That's another approach that has both strengths and weaknesses. I
> like having a single 'parameter set' that controls the whole design,
> and multiple ways to control that (defaults, instance generic map,
> configurations, and tool options), but it does have its costs in
> maintenance, etc. Centralized management also is really nice when two
> distant entities need the same parameter. Managing them locally to each
> entity invites problems with keeping them in sync.

I agree but like I said I don't like to ever be caught in the situation
when there is a problem on a real board that needs debugging and I'm
simulating something that is different because of a difference in
parameter settings. Putting the constants at the top level of each
physical design (but putting constants that are shared between designs
into a package) is the best way I've found to avoid getting into that
situation.

> Using a subtype of time for the clock period is a superior solution, so
> long as your toolset, including simulation, formal analysis, synthesis,
> etc. supports it universally.

And complain to the tool vendor when they don't, that's the best way to
improve the tool (although not guaranteed to work). Synplify responded
on my beef with 'time'. It doesn't get you past the immediate problem
if the tool chokes but like I said that's when you can band-aid it with
a type that the tool is happy with.

> Some tools even support setting record
> type generics on the command line, but unless they also support named
> association (and not just a parenthesized list of values), that would
> get really ugly, and it would probably be better to break them out into
> individual generics at the top level if you intend to manage them
> through the tool. If instead you only want to manage them through the
> language (instance generic maps, configuration declarations, etc.) then
> there is no need to break them out at the top level.

Another good reason for leaving them as constants where I do...less
tool specific issues.

> > I would say limit them [generic subtypes] to ranges that you've at least somewhat tested.
>
> Thanks, that's a better way to define "practical".
>

Good discussion. The idea of a single generic as a record type is
certainly a 'neat and tidy' solution that has a lot of merit. Whether
people find it productive or not I think would depend on how fluid
those entity definitions are and the design reuse perspective....and
both of those will probably a function of the particular engineer and
the company they work for, etc.

KJ

KJ

unread,
Oct 10, 2006, 12:41:17 PM10/10/06
to

Ben Jones wrote:
> "KJ" <kkjen...@sbcglobal.net> wrote in message
> news:EMKWg.4918$NE6....@newssvr11.news.prodigy.com...
>
> > The other big problem is that the idea doesn't scale well. Within the
> > individual entity/architecture that will actually use the generic you now
> > have basically a global naming problem (i.e. entity foo uses
> > G.some_integer to control something). But then sometime later you create
> > a new entity H which needs some integer value so you think to use the
> > 'some_integer' entry to pass that value down.....still later you want to
> > use both G and H in some design and they are now both coded to use
> > 'some_integer' but need them set differently. The only way around that
> > problem is to have that record type continuously growing with each new
> > parameter of each entity that you ever write so that they are all totally
> > independent. <snip>
>
> Sounds like a "slippery slope" argument to me. :) No-one said you had to
> have "just one" of these record types in your design...
That was implicit I thought...

>
> I find that grouping signals and generics into record types early on in the
> design phase is very useful. It massively reduces the amount of typing that
> is needed to connect some signals from one block to another, and
> simultaneously makes the code clearer because the reader doesn't have to sit
> and compare two port lists to see that every signal in a group is connected
> between A and B.

I use copy/paste and an editor macro to weed out these problems....it
works when you first instantiate the component so if the entity does
not need to change I'm fine...but...read on...


> And as previously pointed out, if you suddenly discover
> that you need an extra signal or an extra generic in one of these bundles -
> like I did this morning, in fact - you only need to add it in the definition
> and the points of use; no need to go hunting through dozens of files adding
> signals to entity declarations and port maps.

And I agree, if the entity definition is in flux and signals get
added/removed then having things collected into a record definitely
simplifies the maintenance. If the entity is solid then there is no
benefit if you instantiate the entity one time; if it's more than that
(and that instantiatin is not in a generate statement) then again the
record approach would result in less typing.

Although this is somewhat off the beaten path of the topic of this
thread, what I've found is when you standardize on a logical interface
for all entities that the entity definition itself firms up quickly and
you don't have the situation as often where you need to bring in a
signal. The standardization doesn't cause much/any actual logic
resource overhead. I think this basic approach be better as a general
principle but I'm not going that far, just my hunch. What I can say is
that since doing this I've been doing very little (if any) futzing with
the entity to fix any problem, it's always in the architecture.


>
> With generics, you definitely want to do this on a project-by-project basis.
> I didn't experience the "explosion of fields in one monolithic record type"
> problem; I think that would be a bit of an extreme situation. Rather, I tend
> to have some high-level, design-specific information - such as which
> features are supported, what latencies and relative latencies my
> sub-components should have, and various derivative information - and keep
> the local/ephemeral stuff local.

Like I mentioned in my post back to Andy, you may have to be careful
when trying to reuse designs between projects. Depending on your
situation though this may not apply even when you do reuse code, just
something to keep in mind.

>
> This approach also allows you to do some concentrated parameter checking by
> writing a function to validate your record of generics (e.g. checking for
> contradictory parameters). This, in addition to as many local assertions
> etc. as necessary, seems be quite a robust way to manage your design
> configuration.

Right, and I'll concentrate my parameter checking in the architecture.
Either way I think is roughly equivalent amount of work just different
ways of doing things.

KJ

Jim Lewis

unread,
Oct 10, 2006, 12:58:10 PM10/10/06
to
Andy,

> BTW, I've used records for signal interfaces too, but they get uglier
> with in/out/inout modes. They're supposed to be working on that (mode
> definitions for multi-mode record ports). Since generics are always
> like "mode in", records work extremely well for generics.

I am one of the people in the standards group who is looking at
this. Can you send me some examples (directly) of how you are
currently using this and perhaps some of the things you would
like to be able to do.

Standards groups are becomming more and more user driven.
As a result, we need more user participation and more user
examples/feature requests to support implementing a feature.

Do you want to use it for RTL? If so how? Do you want to
use it for testbenches? If so how?

Thanks,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:J...@SynthWorks.com
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

Expert VHDL Training for Hardware Design and Verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Andy

unread,
Oct 10, 2006, 3:34:52 PM10/10/06
to
KJ,

OK, I think I had the wrong impression of how you were managing
parameters. So, if I understand you correctly, you define constants at
the top (fpga) level architecture, and then pass those down as
individual generics through the hierarchy to their individual point(s)
of use? And you generally only use a handful of those top level
constants/lower level generics.

If so, there is very little coding difference between a constant
declaration and a generic declaration with a default value at the top
level. And the overhead in handling the relatively few generics is not
worth the extra effort of creating the record. That certainly works, so
long as the number of parameters being managaed from the top is
relatively small, and/or is fairly well set in concrete. Neither of
those tends to be true in my work...

On the subject of design reuse, say I'm reusing a module in an upgrade
to an existing FPGA. I now have to patch the new generics for that
module all the way through the hierarchy up to the top (granted,
depending on the interfaces, the ports may have to be plumbed up to the
top too). If that module used a package xy for its generic record
typedef jk, then all I'd have to do is create/modify an xy package
where I declared subtype jk is ab, where ab is my main design's generic
typedef from my main package. Then add the elements the module needs to
my main typedef ab. Hook the module up to my existing generic, and I'm
done. There's no need to have a common name for the package or the
generic record type, just the name of the element.

If I run into a naming collision on the element name, I could also
handle that with a type conversion function on the instance generic map
of the lower level module. Say the module needs an element called 'a',
but there's already an 'a' defined in the ab record for something else.
Put the data into the ab record under a different name, then at the
module's instance generic map, use a type conversion function to rename
the new element name back to 'a'. That type conversion could even be
used in a configuration.

There are many reasons to have different configurations for simulation
and build, but you're right, at some point you need to simulate the
as-built configuration. Having named vhdl configurations for these
helps in keeping track of what you are simulating or building. Keeping
track of them with differently named top level architectures works too,
but there is a lot of extra baggage that has to be maintained (like the
interconnects and insances of all the lower level modules!) in each of
those. I use simulation-only configurations to omit unused parts of the
circuit when I'm testing something else, so it greatly speeds up the
simulation. I may also test the design with a slower clock in order to
simulate fewer clock cycles for a given simulated time interval (for
rtl only). These kinds of simulations run much faster to rat out most
of the bugs, then the final, full-up simulation makes sure the bugs
stay gone. The faster the simulations run, the more corner cases I can
verify, and the more bugs I get out. The slower, as-built simulation is
run relatively few times, since most of the bugs are found and fixed
before that. The same process works for gate level vs rtl level
simulations.

BTW, in my designs, the as-built configuration (unless there are
multiple as-built configurations) is always represented by the default
generic assignments at the top level entity (or if they are mapped to a
named constant, then the default values are defined in the top level
package. The bottom line is, the as-built configuration always works
with no generic map, no tool overrides, and no vhdl configurations.

You're right, this is a good discussion.

Andy

Andrew FPGA

unread,
Oct 10, 2006, 3:57:10 PM10/10/06
to
Andy wrote:
> I've found a very interesting hybrid approach to managing constant
> design parameters, but let me summarize some pro's and con's of
> constants vs generics.
>
> Comments?

A single record generic is an interesting idea but the main issue I
have with it is that it makes it harder to look at an entity and see
straight away what has been paramatised for this entity. With a
complete generic parameter list at the top of the entity its
immediately obvious what aspects of the entity can be configured.

I'm also worried about global namespace issue, its sort of like the
reverse of encapsulation, all the parameters are spread to all
entities/modules.

Generics vs constants:
I'm starting to form the opinion that most all paramaters that
statically configure an entity should be in the generic list (or the
port list in the case of Mike Treselers method). I can only think of a
few exceptions:
1) static configuration that affects almost all entities/modules across
the project and that must take on the same value for all
entities/modules. Even the clks_per_tic doesn't meet that requirement,
although its a design goal to minimise the number of clks, its hardly
ever 1.
2) static configuration that affects a group of entities that can be
put into a package that only that group of entities include. E.g.
parameters for an optical link, like frame length, frame sync word etc
where the optical link is implemented with several entities(say a
receive framer, transmit framer etc).

PS: I quite like Mike Treseler's method of using just normal port
signals instead of generics. One advantage I can see if in the future
you want to dynamically control the behaviour, just wire the port
signal up to a cpu register bit, no change to the entity required. If
you want it static just hold the control constant and synthesis
optimises the control logic away.

Paul Uiterlinden

unread,
Oct 10, 2006, 5:50:00 PM10/10/06
to
Andy wrote:

> While generics are not locally static, at least they are static.
> Signals, even when driven from constants/generics, cannot drive
> range constraints, generate statements, etc.

You're right. I suppose I got carried away a bit. Still, you can use a
global signal in that way to convey some sorts of generics. I have
done that at some occasion. Don't ask me whether it was
synthesizable, it was behavioral code.

> You are correct about the exponent example, but i've run into cases
> where it was not as simple as that, and I could not adequately
> constrain a generic to ensure compliance with the limitations of the
> design. You also bring up a good point about related parameters:
> whenever possible, they should be specified as one value, and the
> other values calculated from them (a good example might be a
> bitwidth and a corresponding numerical range, calculated via
> exponentiation). Whenever one cannot be calculated from the others,
> but must meet some relational requirement (i.e. a must be less than
> b) then an assertion at the point of use is a good thing to use to
> verify it. Some simulators will evaluate concurrent assertion
> statements with static expressions during elaboration, before
> simulation even starts.

That's neat. And it follows a healthy principle: crash early.

--
Paul.

Andy

unread,
Oct 10, 2006, 6:19:13 PM10/10/06
to
Jim,

I just want to be able to declare a record type, and then be able to
declare one or more named modes for that type that indicate the
individual modes on each element of the record for use in a port
declaration. Note that for a record of records, you would also have a
"mode of modes".

For example, say I wanted to define a processor bus, and hook it up
between a cpu and a peripheral. Both cpu and periph attach to the same
signal (of type bus) but the cpu and peripheral drive/read different
signals within that bus.

Here is an idea of what I would like to be able to do, both for
synthesis and testbenches :

library ieee;
use ieee.std_logic_1164.all;

package bus_types is

-- abbreviations
subtype slv is std_logic_vector;
subtype sl is std_logic;

-- typedefs
type bus_t is
record
addr : slv(0 to 35);
as_n : sl;
aack_n: sl;
data : slv(0 to 63);
ds_n : sl;
dack_n: sl;
ts : slv(0 to 2);
tt : slv(0 to 3);
end record bus_t;

-- mode defs
mode master of bus_t is -- new keyword "mode"???
addr : out; -- only the name of the element need be repeated, not
its type
as_n : out; -- so changes in element types do not ripple to mode
definitions
aack_n : in;
data : inout;
ds_n : out;
dack_n: in;
ts : out;
tt : out;
end mode master;

mode slave of bus_t is
addr : in;
as_n : in;
aack_n : out;
data : inout;
ds_n : in;
dack_n : out;
ts : in;
tt : in;
end mode slave;

end package bus_types;

use work.bus_types.all;
entity periph is
port (pbus: slave bus_t); -- compiler selects & verifies mode slave
exists for type bus_t
end entity periph;

use work.bus_types.all;
entity cpu is
port (pbus: master bus_t);
end entity cpu;

Then in some architecture, I could:

architecture some of thing is

signal mybus: bus_t;

begin

u1: entity work.cpu(rtl)
port map (pbus => mybus);

u2: entity work.periph(rtl)
port map (pbus => mybus);

end architecture rtl;

In more complex examples, this could be used to quickly and easily
plumb complex ports up/down through multiple levels of the hierarchy,
in a "virtual" way such that the type and mode definitions can be
changed, but the entities/architectures along the way remain unchanged.
Think of a record/mode combination as a handle by which to abstract
the interface.

I could also use it in procedure calls in a testbench, such as write(),
read(), or respond();

Andy

Jim Lewis

unread,
Oct 10, 2006, 10:20:31 PM10/10/06
to
Andy,
That is about what I have gravitated toward.
Since SystemVerilog has a similar capability with interfaces
it confuses the issue some (as SV interfaces do much more).

Should the record and mode be OO extensible?

Cheers,
Jim

0 new messages