Customization with CONSTANTS and/or GENERICs

S

Sean Durkin

Hi *,

I've come across something I don't quite understand and thought I'd ask
the experts here. I've prepared a simple test case and put it here:
http://www.wiggy.de/testcase.html

Basically, what I'm doing is this:

I have two different entities with differing port lengths, and want to
instantiate one or the other depending on the value of a constant
defined in a package. So, in pseudo-code, what I have is this:

if (CONSTANT=value1) generate
instantiate_entity_1;
end generate;

if (CONSTANT=value2) generate
instantiate_entity_2;
end generate;

The entities connect to top-level ports, whose lengths are defined by
the same constant in the package.

Now, this works fine in ModelSim, but when I'm trying to synthesize in
Xilinx' XST, it throws an error about not-matching port lengths between
the top-level ports and the ports of the entity in the "wrong" generate
block. It seems that what's inside the generate blocks is ALWAYS
evaluated even if the if-condition is not met, or maybe it is evaluated
BEFORE the if-condition.

If I do the whole thing using a GENERIC, it works in both XST and
ModelSim, but in my eyes it shouldn't really make a difference.
Sometimes I prefer to do stuff like that with constants instead of
GENERICs so I don't have to drag a GENERIC through the entire hierarchy
and can just edit one central configuration package.

Now, is this a bug in XST or in ModelSim, or am I trying something
"illegal" here? What in general is the preferable way to do something
like this?

Looking at what XST does I would think that using a GENERIC, things are
thrown out or configured right at compile time, whereas when I use a
constant, stuff would not be thrown out until later in the optimization
stage.

Are there any differences in the end result in current tools? From a
pure language standpoint, there should be no difference, right?

cu,
Sean
 
K

KJ

Hi *,

I've come across something I don't quite understand and thought I'd ask
the experts here. I've prepared a simple test case and put it here:http://www.wiggy.de/testcase.html

Thanks...posting full working code demonstrating the problem makes
things easier for all who want to respond.
Basically, what I'm doing is this:

I have two different entities with differing port lengths, and want to
instantiate one or the other depending on the value of a constant
defined in a package. So, in pseudo-code, what I have is this:

if (CONSTANT=value1) generate
  instantiate_entity_1;
end generate;

if (CONSTANT=value2) generate
  instantiate_entity_2;
end generate;

The entities connect to top-level ports, whose lengths are defined by
the same constant in the package.

Looks good.
Now, this works fine in ModelSim, but when I'm trying to synthesize in
Xilinx' XST, it throws an error about not-matching port lengths between
the top-level ports and the ports of the entity in the "wrong" generate
block. It seems that what's inside the generate blocks is ALWAYS
evaluated even if the if-condition is not met, or maybe it is evaluated
BEFORE the if-condition.

XST has a bug.
If I do the whole thing using a GENERIC, it works in both XST and
ModelSim, but in my eyes it shouldn't really make a difference.

You are correct, it shouldn't.
Sometimes I prefer to do stuff like that with constants instead of
GENERICs so I don't have to drag a GENERIC through the entire hierarchy
and can just edit one central configuration package.

Depending on the situation, constants in a package can be easier to
manage. It all depends on just how 'constant' those things are. I
find that repurposing some chunk of code or design can end up causing
yesterday's package constant to be today's generic parameter...but
this is all just a tangent...
Now, is this a bug in XST or in ModelSim, or am I trying something
"illegal" here?

Today, Modelsim and Quartus are what I consider to be the 'gold
standard' as far as correctly interpreting the language. That's not
to say that they don't have their bugs and can also be incorrect, but
at present they seem to be the closest to correct.

Your code synthesizes just fine with Quartus 9.0 (try it yourself with
the Web edition...those free downloads are useful even if you're not
intending to use those tools for design right now). Since you say it
compiles just fine in Modelsim than it is highly probable that the bug
is in XST. What you should do is:

- Open a bug report with Xilinx against XST, mentioning that "it
compiles just fine with both Modelsim and Quartus. If this bug is not
corrected in a timely manner, I may have to consider switching to
devices that are supported by tools that do not have this bug".
Whether or not you're paid up on support or a freeloader, you're
providing useful feedback on a product deficiency that the product
owner is likely motivated to correct.
- Develop a work around, whether that means using generics where you'd
like to use a constant so that you can continue to use XST or consider
using other tools and devices as mentioned in the first bullet. In
general, the code work around is usually the path taken, but one
should always consider all the options.
What in general is the preferable way to do something
like this?

I assume "like this" is referring to using package constants versus
generics.

If so, then it depends mostly on just how 'constant' those things in
the package really are as I mentioned earlier. But it's also not that
big of a deal if something needs to change from a package constant to
a design parameter generic. The process is
- Comment out the constant definition in the package
- Edit all the places you find the constant being used and
parameterize it wherever is the appropriate place in the design for it
to be a parameter. Compile all.
- Fix up the places that you missed above and recompile...repeat until
you've got it right.
Looking at what XST does I would think that using a GENERIC, things are
thrown out or configured right at compile time, whereas when I use a
constant, stuff would not be thrown out until later in the optimization
stage.

You're thinking too hard about a design you probably no nothing about
(i.e XST). Just how exactly XST, Quartus, Synplify, etc. translate a
set of text files containing VHDL code into a bitstream is anybody's
guess. Once you've exhausted your review of your design (which in
many cases IS the source of the error, not the tool) and the only
thing left to suspect is the tool, then usually the best course of
action is to try a different tool.

You've already taken the step of reducing it down to a simple test
case, so submit it to Xilinx and when the bug gets fixed you've done
your part to improve XST not only for yourself but for all. Unless
this is something that Xilinx is already aware of, their fix won't
likely be available for you on your current project so step #2 is
always to come up with how you're going to work around the problem.
Even if Xilinx chooses not to fix the problem (or not in a timely
manner), they are just hurting themselves by ignoring valid customer
feedback.

Don't hold your breath waiting for a fix unless this is absolutely
critical and you're too far down the road to change tools and
devices...in those situations, you'll need to engage the local FAE to
try to have the issue escalated. In your situation though, since
there does seem to be a work around it likely wouldn't be considered
'critical'.

Also, don't interpret any of this as trying to disparage Xilinx. Bugs
happen with all tools, your post was simply questioning brand X tools.

Good luck.

Kevin Jennings
 
S

Sean Durkin

Hi KJ,

thank you for responding.
XST has a bug.

OK, that's what I thought. I just wasn't sure if maybe I was missing
something. I'll file a bug report with Xilinx.

By now I've tried it with Precision Synthesis, works there as well. I'll
try Synplify and ActiveHDL when I get back to the office next week, just
to have some more ammo. :)
Depending on the situation, constants in a package can be easier to
manage. It all depends on just how 'constant' those things are. I
find that repurposing some chunk of code or design can end up causing
yesterday's package constant to be today's generic parameter...but
this is all just a tangent...

OK, so there's no "golden" standard to do this. :)

Currently, I use a mixture of both, which makes me a little unhappy. As
you said, it always depends...

When I design a more or less isolated functional module that someone
else might put into their design, I prefer GENERICs, since I don't want
to have to burden them with adding another package to their design,
dragging around yet another file... Plus for testbenches I prefer
GENERICs, since I can just override them when starting the simulation
and can then easily e.g. select which test to run via command-line
parameters to my simulation script. And GENERICs are more handy if it's
just a couple of parameters...

But when it's some bigger design made up of a lot of files and levels of
hierarchy, and potentially a dozen or more GENERICs clogging up my
entity declarations, I prefer constants. That way I don't have to drag a
GENERIC through a dozen files until I finally reach the only file it
really pertains to.
Plus, I hate having a dozen ports like "din: in
std_logic_vector(BITWIDTH-1 downto 0);) in every entity, I'd rather
declare a subtype or a record in a central types package or something.

In this specific test case, as a quick workaround, I might just do both:
Add a GENERIC to the entity that is initialized with the constant value
from the package, and use the GENERIC in the module. That way, the
changes neccessary are minimal and don't affect any other parts and
files of the design. This works in XST as well.
You're thinking too hard about a design you probably no nothing about
(i.e XST). Just how exactly XST, Quartus, Synplify, etc. translate a
set of text files containing VHDL code into a bitstream is anybody's
guess. Once you've exhausted your review of your design (which in
many cases IS the source of the error, not the tool) and the only
thing left to suspect is the tool, then usually the best course of
action is to try a different tool.
You're right, I know nothing about the inner workings of synthesis
tools. That's why I thought I'd ask here, maybe somone knows.

It would be interesting to know if maybe there actually are differences
in the way synthesis tools handle GENERICs and constants like in my
case; and if so, why. If it were really like I guessed in my original
post, I'd suspect that there would be differences in the runtime of the
synthesis process, and possibly even differences in the end result.

But, well, just a thought experiment. This is not an issue that can't
easily be worked around or has any major implications.

cu,
Sean
 
M

Mike Treseler

Sean said:
When I design a more or less isolated functional module that someone
else might put into their design, I prefer GENERICs, since I don't want
to have to burden them with adding another package to their design,
dragging around yet another file...

Sometimes I put a package at the top of the file containing
the design entity. That way the testbench, or anything using the design
file gets access to the package as well.

-- Mike Treseler
 
A

Andy

Hi KJ,

thank you for responding.


OK, that's what I thought. I just wasn't sure if maybe I was missing
something. I'll file a bug report with Xilinx.

By now I've tried it with Precision Synthesis, works there as well. I'll
try Synplify and ActiveHDL when I get back to the office next week, just
to have some more ammo. :)


OK, so there's no "golden" standard to do this. :)

Currently, I use a mixture of both, which makes me a little unhappy. As
you said, it always depends...

When I design a more or less isolated functional module that someone
else might put into their design, I prefer GENERICs, since I don't want
to have to burden them with adding another package to their design,
dragging around yet another file... Plus for testbenches I prefer
GENERICs, since I can just override them when starting the simulation
and can then easily e.g. select which test to run via command-line
parameters to my simulation script. And GENERICs are more handy if it's
just a couple of parameters...

But when it's some bigger design made up of a lot of files and levels of
hierarchy, and potentially a dozen or more GENERICs clogging up my
entity declarations, I prefer constants. That way I don't have to drag a
GENERIC through a dozen files until I finally reach the only file it
really pertains to.
Plus, I hate having a dozen ports like "din: in
std_logic_vector(BITWIDTH-1 downto 0);) in every entity, I'd rather
declare a subtype or a record in a central types package or something.

In this specific test case, as a quick workaround, I might just do both:
Add a GENERIC to the entity that is initialized with the constant value
from the package, and use the GENERIC in the module. That way, the
changes neccessary are minimal and don't affect any other parts and
files of the design. This works in XST as well.



You're right, I know nothing about the inner workings of synthesis
tools. That's why I thought I'd ask here, maybe somone knows.

It would be interesting to know if maybe there actually are differences
in the way synthesis tools handle GENERICs and constants like in my
case; and if so, why. If it were really like I guessed in my original
post, I'd suspect that there would be differences in the runtime of the
synthesis process, and possibly even differences in the end result.

But, well, just a thought experiment. This is not an issue that can't
easily be worked around or has any major implications.

cu,
Sean

A couple of suggestions:

If you have enough generics to cause a headache (especially plumbing
them through multiple levels of hierarchy) then create a record in a
package that contains fields for all of your generics. That way, when
you need to add a top level generic for a lower level entity that
needs it, you just add it to the record, define it at the top, and
extract it at the entity that needs it. Of course the record has to be
defined in a package that must be referenced by every entity that uses
or passes it.

Use unconstrained ports.

Andy
 
S

Sean Durkin

Hi,

in case anyone's interested:
I opened a web case with Xilinx. They admit that it's a bug, but they
won't fix it... They wrote a new HDL parser for the Virtex-6 and
Spartan-6 architectures which doesn't have this bug anymore. For older
architectures, the old parser will still be used.

Since all the development time will now go into the new architectures,
the parser will not be fixed for the "obsolete" architectures like the
Virtex-5 I am using at the moment.

Yeah, well...

cu,
Sean
 
S

Sean Durkin

Andy said:
A couple of suggestions:

If you have enough generics to cause a headache (especially plumbing
them through multiple levels of hierarchy) then create a record in a
package that contains fields for all of your generics. That way, when
you need to add a top level generic for a lower level entity that
needs it, you just add it to the record, define it at the top, and
extract it at the entity that needs it. Of course the record has to be
defined in a package that must be referenced by every entity that uses
or passes it.
That's the kind of case where I usually use a constant in a package.
Doesn't really make much of a difference if I change a top-level generic
or a constant in a central configuration package, plus I don't have to
drag any generics around at all, be it one record containing all I need
or a dozen single generics. But you're right, that would be a "unified"
way of doing this... all generics, with minimal entity declaration
clutter... hmm...
Use unconstrained ports.
You're right, that would be the most "elegant" solution for the test
case I posted, and I use that technique on occasion.

But in the actual design I'm working on at the moment, the two
selectable entities are two different CoreGen-cores, so it didn't quite
work there.

cu,
Sean
 
K

KJ

You're right, that would be the most "elegant" solution for the test
case I posted, and I use that technique on occasion.

Actually, unconstrained ports on entities are generally not
appropriate because one or both of the following apply:
- The size of two or more vectors on the entity are related in some
fashion, they are not independent.
- The direction of the vectors matter because internal to the entity
implicit assumptions were made about vector directions (i.e. 'to' or
'downto').

In your test case, point #1 applies because 'din' and 'dout' must be
the same length. Sluffing off making this requirement explicit (by
defining the lengths via a generic as you did in your test case) and
instead hiding the requirement (by using unconstrained vectors) isn't
in any way 'elegant'. Yes, it is more typing...that extra typing is
also known as 'live, executable documentation'. Some user down the
road that inherits your code will appreciate it.

Kevin Jennings
 
A

Andy

Actually, unconstrained ports on entities are generally not
appropriate because one or both of the following apply:
- The size of two or more vectors on the entity are related in some
fashion, they are not independent.
- The direction of the vectors matter because internal to the entity
implicit assumptions were made about vector directions (i.e. 'to' or
'downto').

In your test case, point #1 applies because 'din' and 'dout' must be
the same length.  Sluffing off making this requirement explicit (by
defining the lengths via a generic as you did in your test case) and
instead hiding the requirement (by using unconstrained vectors) isn't
in any way 'elegant'.  Yes, it is more typing...that extra typing is
also known as 'live, executable documentation'.  Some user down the
road that inherits your code will appreciate it.

Kevin Jennings

Assertion statements that can verify relationships between port sizes
can be put in the entity itself, so they are just as self-documenting
as defining the port widths explicitly from generics in the port map.
And those assertion statements can handle more complex relationships
too.

They may or may not be less typing... but I tend to agree that less
typing is not always a good thing. I think of some of the verbosity of
VHDL is really just compiler-enforced comments.

Andy
 
A

Andy

That's the kind of case where I usually use a constant in a package.
Doesn't really make much of a difference if I change a top-level generic
or a constant in a central configuration package, plus I don't have to
drag any generics around at all, be it one record containing all I need
or a dozen single generics. But you're right, that would be a "unified"
way of doing this... all generics, with minimal entity declaration
clutter... hmm...


You're right, that would be the most "elegant" solution for the test
case I posted, and I use that technique on occasion.

But in the actual design I'm working on at the moment, the two
selectable entities are two different CoreGen-cores, so it didn't quite
work there.

cu,
Sean

The advantage of plumbing generics all the way to the top is that
their value can be set via command line arguments in the tool, and
thus no re-compilation is required, which would be required if they
were constants in a package. I define the "default" values for the
record elements in the same package that defines the record itself, so
you can use it both ways if you want.

Depending on the tool's ability to allow a record type generic value
to be specified via the command line, you may have to break out the
record's elements into individual generics at the top level. The tools
that do allow you to define a record type generic value on the command
line are going to require you to define the entire record, whereas
individual generic values can be defined on the command line for only
those generics for which you do not want to use the default value.

I have not looked at generics on packages yet, but I'll bet there's an
easier way to handle "system-wide" generics using them (once the tools
establish support for the feature), especially if the package can
define several different constants that are related to a single
package generic.

Andy
 
K

KJ

Assertion statements that can verify relationships between port sizes
can be put in the entity itself,

Last I checked, the definition of the widths of interface signal for
an entity is in the entity also...so your point is...???
so they are just as self-documenting
as defining the port widths explicitly from generics in the port map.

We'll just have to disagree on that one then. Refer to example 1
which defines the port widths explicitly and generically versus
example 2 which uses unconstrained ports and assertions. I'm guessing
not too many people would agree with you that example 2 is "just as
self-documenting" as example 1, even if you were to spruce up example
2. Example 2 is too wordy and forces the intended user of the entity
to look in the port map and the assertions just to divine the data
type and the data width. With example 1, both pieces of information
are on a single standardized line.

Example 2 can only be considered "just as self-documenting" in the
sense that the same information is supplied as in example 1...from the
standpoint of someone trying to extract that information, I suspect
that most people think that example 2 would lose out on the "just as"

Using assertions to validate entity bus widths so you can use
unconstrained vectors is the hard way to do something simple.

What nobody has come forth with is why using unconstrained vectors in
Sean's example is in any way a benefit to anyone other than a few
keystrokes by the designer. Those few keystrokes comes at the expense
of everyone who ever has to look at it later until that code
disappears into the dustbin of history.
And those assertion statements can handle more complex relationships
too.

We're talking about calculating bus widths of entity interface
signals...any 'complex relationship' that can be asserted can also be
put into the port map definition of the entity with better clarity.

Putting entity interface vector ranges into assertions allows the
designer to come up with all kinds of creative ways to constrain the
range; when you define the signals in the port map the format is
completely defined by the language standard and will not vary.

Using unconstrained vectors on any interface where there are
relationships between different elements of that interface that must
be observed is a misuse of unconstrained vectors...using them in that
fashion just shows that anything that has a useful purpose can also be
misused.
They may or may not be less typing...

It's hard to see how example 2 could ever be even remotely close to
example 1 in terms of typing. On a more important measure of how well
the interface is documented by live executable code, example 2 again
seems to be a distant second even in the contrived case of Sean's two
signal entity interface.

Kevin Jennings


**** Example 1 ****
-- Explicitly defining the vector width in the entity port map...
entity test_width8 is
generic(BUS_WIDTH_BYTES: natural range 1 to 2);
port (
din : in std_logic_vector(8*BUS_WIDTH_BYTES - 1 downto 0);
dout : out std_logic_vector(8*BUS_WIDTH_BYTES - 1 downto 0)
);
end test_width8;

**** Example 2 ****
-- Asserting the vector width outside the entity port map just so you
-- can use an unconstrained vector...
entity test_width8 is
port (
din : in std_logic_vector;
dout : out std_logic_vector
);
begin
-- Note: Trying to minimize typing here...you could also do more
-- typing and check for 'left to be equal to 7 or 15
assert ((din'left mod 8) = 7)
and (din'right = 0)
and ((din'length / 8) < 2)
report "OOPS! I guess you didn't manage to figure out the
proper range for din"
severity FAILURE;
assert (din'left = dout'left)
and (din'right = dout'right)
report "OOPS! I guess you didn't discover that din and dout
must have the same range"
severity FAILURE;
end test_width8;
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top