Another Rusty Topic -- Locally Static

M

M. Norton

Hello again. I'm running into something I think ought to work, and as
far as I can tell from Ashenden, it ought to work, but it all is based
around values being locally static.

I have a record type to aggregate information about my memory map.
Something like:

type MEMORY_STRUCT is record
source_device_id : std_logic;
source_channel : unsigned(3 downto 0);
mem_bank : std_logic;
mem_base_addr : unsigned(15 downto 0);
end record;

Then using this I defined constants:

constant C_MYCHANNEL : MEMORY_STRUCT := ('1', X"2", '0', X"8000");

This is declared IN THE ARCHITECTURE BODY, which appears to be an
important point. The only discussion of doing this sort of thing I
found in Ashenden was handling deferred constants that were declared
but not defined in a package. As far as I can tell for this
architecture, the constant ought to be static and known at the time of
analysis.

Then later I'm getting errors are a case choice:

case current_channel is
when C_MYCHANNEL.source_channel =>

And the compiler declares C_MYCHANNEL.source_channel to not be locally
static. However it's constant, declared local to the architecture
body, fully defined in the architecture body... what am I missing
here? Is it the fact that I'm referencing a record subvalue? Still,
the value of that is constant as far as I can tell and additionally
declared and defined locally, so I'm not entirely certain what isn't
locally static.

Fortunately it's not a major issue, there are only 15 choices and I
can just go in and declare string constants, but I'd prefer to
abstract that out if possible. It just seems to make more sense that
way.

Anyhow, if anyone knows why the constant isn't static, I'm all ears.
Thanks!

Best regards,
Mark Norton
 
A

Andy

Just a guess, but is the record type, as well as the constant,
declared in the same architecture as contains the case statement?
Maybe it is having a problem withe the ".source_channel" part?

Andy
 
M

M. Norton

Just a guess, but is the record type, as well as the constant,
declared in the same architecture as contains the case statement?
Maybe it is having a problem withe the ".source_channel" part?

Well I figure it must be the record type. If I had declared something
like:

constant C_MYCHANNEL_SRC_CHAN : unsigned(3 downto 0) := X"2";

I'm absolutely sure that I could use that value as the expression
value in the /when/ portion of a sequential case statement. It's a
little disappointing though as it seemed quite nice to bundle this
information together in a single location. Creating another ancillary
group of constants just to support the one value in the record that I
want to select against seems inelegant. I was stymied because I
thought I couldn't make the value any more local or static than what I
did (obviously not static enough). In the interests of getting it
done, I've simply gone back and used string constants for my /when/
expressions, but I grumbled while I did it ;-).
 
M

M. Norton

Just a guess, but is the record type, as well as the constant,
declared in the same architecture as contains the case statement?
Maybe it is having a problem withe the ".source_channel" part?

I realized I misread what you were asking. The answer is yes. The
type/record statement is in the architecture definition along with the
constants. I should have been more explicit with my psuedo-code
earlier. Something like this more fully illustrates the scopes
involved.

architecture rtl of foobar_driver is

type MEMORY_STRUCT is record
source_device_id : std_logic;
source_channel : unsigned(3 downto 0);
mem_bank : std_logic;
mem_base_addr : unsigned(15 downto 0);
end record;

constant MY_CONSTANT : MEMORY_STRUCT := ('1', X"2", '0',
X"8000");

begin

SOME_PROCESS : process (clk, rst)
begin
...
case my_signal is
when MY_CONSTANT.source_channel => -- !!!!! Flagged as
not locally static.
...
end process;

end architecture rtl;

So, it's not even that. It must be a fundamental condition of "non-
static" for record objects for any identifier whether signal,
variable, or constant.

Mark
 
J

Jonathan Bromley

Hello again. I'm running into something I think ought to work, and as
far as I can tell from Ashenden, it ought to work, but it all is based
around values being locally static.

So, we all knew that VHDL has an obsessive-compulsive streak,
and here it is on public display, as obvious as a train-spotter
with a nervous tic.
I have a record type to aggregate information about my memory map.
Something like:

type MEMORY_STRUCT is record
source_device_id : std_logic;
source_channel : unsigned(3 downto 0);
mem_bank : std_logic;
mem_base_addr : unsigned(15 downto 0);
end record;

Then using this I defined constants:

constant C_MYCHANNEL : MEMORY_STRUCT := ('1', X"2", '0', X"8000");

And then you found that the constant couldn't be used as a case
statement choice, because it isn't locally static. Grrrr.
This is declared IN THE ARCHITECTURE BODY, which appears to be an
important point.

It isn't especially important. The important thing is that
a record aggregate expression is not on the rather short list
of things that count as locally static expressions (section
7.4.1 in the 2002 LRM; I don't have the 2008 LRM to hand).
So, in its turn the record constant is not locally static,
and therefore neither is an element selected from it.

So your simulator is obsessively telling the truth as per LRM.

No, I didn't know that either until I looked it up. And
I agree with you that it is way, way irritating.

I *think* that VHDL-2008 has considerably relaxed the rules
about static-ness of things appearing in a case statement.
Check with Jim Lewis's excellent "Just the new bits" book.
However, the easy (but slightly ugly) workaround is to
re-cast your case statement as an if...elsif... instead.

For a maximally synthesis-friendly version you could
consider building an array of such constants, and
scanning a for-loop over that array, comparing the input
value with each in turn. I have used this approach
successfully in the past to build address decoders and
suchlike that are driven from a table of constants.
The only discussion of doing this sort of thing I
found in Ashenden [...]

I know this sounds a bit schoolmaster-ish, but I've
generally found that there is no substitute for having
the LRM to hand when it comes to gnarly stuff like this.
The VHDL LRM is not exactly something you'd read over
the morning toast and marmalade, but it is rather precisely
written and generally rewards the diligent by serving up
the right answers to troublesome questions. Whether those
answers are the ones you wanted to hear is quite another
matter.
Fortunately it's not a major issue, there are only 15
choices and I can just go in and declare string constants,

No, don't do that. Structured constants are one of the
really good things about VHDL. Find another way to use
them that doesn't offend the compiler's more delicate
sensibilities.

cheers
 
K

Kenn Heinrich

Jonathan Bromley said:
So, we all knew that VHDL has an obsessive-compulsive streak,
and here it is on public display, as obvious as a train-spotter
with a nervous tic.

It isn't especially important. The important thing is that
a record aggregate expression is not on the rather short list
of things that count as locally static expressions (section
7.4.1 in the 2002 LRM; I don't have the 2008 LRM to hand).
So, in its turn the record constant is not locally static,
and therefore neither is an element selected from it.

I scanned the LRM and came to the same conclusion as Jonathan. I
wasn't entirely convinced that my interpretation was right, because I
couldn't create an example to convince myself that there was a benefit
in restricting the "locally static" concept that severely.

The LRM can be concise in places, but it can also be irritatingly
obscure and force you to search in a dozens of places to infer
non-existence, rather than just tell you something right out.

For a maximally synthesis-friendly version you could
consider building an array of such constants, and
scanning a for-loop over that array, comparing the input
value with each in turn. I have used this approach
successfully in the past to build address decoders and
suchlike that are driven from a table of constants.

As a tangent, in a past project, I found one synthesizer that accepted
the original record constant construct. I didn't realize it was a gray
area until I ported the code to another synthesizer, where it
bombed. At which point I found myself very annoyed with both vendors
*and* the LRM.

- Kenn
 
M

M. Norton

So your simulator is obsessively telling the truth as per LRM.

No, I didn't know that either until I looked it up.  And
I agree with you that it is way, way irritating.

Well frustrating because there seems to be perfect semantically
appropriate way to describe the behavior desired and it's stifled by
the language. I don't run into that too often, there's usually a good
and design aesthetically pleasing way to do most things in VHDL in my
experience.
I *think* that VHDL-2008 has considerably relaxed the rules
about static-ness of things appearing in a case statement.
Check with Jim Lewis's excellent "Just the new bits" book.
However, the easy (but slightly ugly) workaround is to
re-cast your case statement as an if...elsif... instead.

For a maximally synthesis-friendly version you could
consider building an array of such constants, and
scanning a for-loop over that array, comparing the input
value with each in turn.  I have used this approach
successfully in the past to build address decoders and
suchlike that are driven from a table of constants.

I have to admit, I try to be a progressively modern digital VHDL
designer who doesn't get worried over using variables and all that,
but for-loops in RTL code still (possibly irrationally) make me a
little phobic. The guy I was working with yesterday had a shift
register construct he'd gotten out of a textbook that used a for-loop
and I was a little shocked THAT wasn't the part of the code that was
having trouble. Apparently the synthesizer was just peachy with it.

I have used the array method for testbenches before and agree that it
can be very handy. I've just never attempted it for RTL. I may punt
and go with your if-elsif structure for the moment until I have time
to experiment with the for loop construct. I will have to create an
ARINC-429 interface soon too, and the table of addresses and labels
that need to be supported for ARINC also lend themselves to this
constant record array method and that might be a good way to
experiment and fold it into getting things done at the same time.
The only discussion of doing this sort of thing I
found in Ashenden [...]

I know this sounds a bit schoolmaster-ish, but I've
generally found that there is no substitute for having
the LRM to hand when it comes to gnarly stuff like this.
The VHDL LRM is not exactly something you'd read over
the morning toast and marmalade, but it is rather precisely
written and generally rewards the diligent by serving up
the right answers to troublesome questions.  Whether those
answers are the ones you wanted to hear is quite another
matter.

I believe you are quite likely right with this. Ashenden is so
comprehensive that it's easy to forget it's not DEFINITIVE in the same
way the language reference manual is.

Thanks for the commentary, I really appreciate it.

Best regards,
Mark Norton
 
A

Andy

I have to admit, I try to be a progressively modern digital VHDL
designer who doesn't get worried over using variables and all that,
but for-loops in RTL code still (possibly irrationally) make me a
little phobic. The guy I was working with yesterday had a shift
register construct he'd gotten out of a textbook that used a for-loop
and I was a little shocked THAT wasn't the part of the code that was
having trouble. Apparently the synthesizer was just peachy with it.

It helps to think about RTL for-loops the way the synthesis tool does:
it just unrolls them. This is why most synthesizable for-loops must
have "static" bounds (from an RTL POV, not necessarily an LRM POV).

Also keep in mind that, once the loop is unrolled, then the index
value is just another static value for each iteration of the loop. So
it can be used where, for instance you need a static power of two, or
you need to bound an inner loop using the current outer index value.

The reverse is also helpful. If a case statement contains (or can be
written to contain) sequentially indexed when => statements and
assignments/expressions, it can often be re-written into a series of
if-then statements. Then that series can be rolled up into a loop.

Rolling up an if-then-else series into a loop usually involves the use
of an exit statement.

For example:

if input(0) = '1' then
...
elsif input(1) = '1' then
...
elsif input(2) = '1' then
...
end if;

Can be re-written as:

for i in input'reverse_range loop
if input(i) = '1' then
...
exit; -- exit the loop
end if;
end loop;

Happy Looping,

Andy
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top