locally static expression

R

rickman

I looked this up once in the VHDL spec, but I don't recall the details.
I seem to remember that the definition of a locally static expression
is rather complex with a lot of little details. But a tool is flagging
warnings on some code which seems to be due to the use of conversion
from SLV to integer.

constant SWAP : IRSLV := to_slv(FIXOP + 16#00#, 8); -- E0 (1110 0000)

type INSTDSPLY is (RST, IACK, LTR, JMP, JUMZ, JUMC, JUMO, CALA, CALR,
SWP, OVR, RUP, DUP, SHFL, SHFC, ZFLG, RFTC,
RDRP, RTN, FTCH, FCHB, RFRM, RSB, RCM, FCHP, FHPB, RARS,
DDRP, TOR, CPNC, CPC, ADNC, ADC, SBNC, SBC,
BFL, RTI, STOR, STRB, BLAN, RADT, BLOR, STRP, STPB, BLXR);

when TO_INTEGER(UNSIGNED(SWAP)) => return SWP;

The warning comes from lines like this last one, allegedly from the
value returned by the TO_INTEGER conversion. "Choice TO_INTEGER is not
a locally static expression."

I do this in a lot of places in some existing code. My MO is to avoid
warning messages, so I can't believe that I would have done this and
lived with the dozens of warnings I am getting. But then the older
tool may not have been as true to the spec as it could have been.

Rather than make me go dig up my copy of the VHDL spec and read all
those cross-referenced paragraphs to re-learn what this really means,
can anyone give me the 25 cent explanation and an easy cure?
 
R

rickman

Well, no one took pity on me so I had to figure it out for myself. It
has been awhile since I have done any HDL coding so I had forgotten
about this. Just in case anyone else wants to know what this is about,
I'll explain what I found.

The function calls that convert the SLV SWAP to an integer are not
allowed where I am trying to use it in the CASE statement. This
function call is not invoked until later in the compilation process, so
the value is unknown at this time. The solution is to either declare
integer values for the opcodes with slightly different names (so I
don't have to call a conversion routine), or to use IF statements which
don't have the same limitations as the CASE statement.

Even though I don't like this, it seems perfectly logical to me.
 
J

Jim Lewis

Rickman,
To further this, there are some changes that were
made in the Accellera 3.0 draft of VHDL to what can
be locally static. First, it allows arrays such as
std_logic_vector, signed, unsigned to be a locally
static type. Furthermore, functions defined in any of
the following standard packages will also be locally
static, std_logic_1164, numeric_std, and numeric_std_unsigned.

So if you use the to_slv from numeric_std_unsigned,
I think your code will be ok - when the vendors implement
the standard. Accellera 3.0 draft of VHDL became a
standard at DAC 2006.

Note functions from std_logic_arith or std_logic_unsigned
will not be locally static since they are not standard
packages - may they RIP.

Of course, we need to make sure both simulator
and synthesis vendors are up to speed on these
changes. I recommend that you start making your
requests today.

Cheers,
Jim


I looked this up once in the VHDL spec, but I don't recall the details.
I seem to remember that the definition of a locally static expression
is rather complex with a lot of little details. But a tool is flagging
warnings on some code which seems to be due to the use of conversion
from SLV to integer.

constant SWAP : IRSLV := to_slv(FIXOP + 16#00#, 8); -- E0 (1110 0000)

type INSTDSPLY is (RST, IACK, LTR, JMP, JUMZ, JUMC, JUMO, CALA, CALR,
SWP, OVR, RUP, DUP, SHFL, SHFC, ZFLG, RFTC,
RDRP, RTN, FTCH, FCHB, RFRM, RSB, RCM, FCHP, FHPB, RARS,
DDRP, TOR, CPNC, CPC, ADNC, ADC, SBNC, SBC,
BFL, RTI, STOR, STRB, BLAN, RADT, BLOR, STRP, STPB, BLXR);

when TO_INTEGER(UNSIGNED(SWAP)) => return SWP;

The warning comes from lines like this last one, allegedly from the
value returned by the TO_INTEGER conversion. "Choice TO_INTEGER is not
a locally static expression."

I do this in a lot of places in some existing code. My MO is to avoid
warning messages, so I can't believe that I would have done this and
lived with the dozens of warnings I am getting. But then the older
tool may not have been as true to the spec as it could have been.

Rather than make me go dig up my copy of the VHDL spec and read all
those cross-referenced paragraphs to re-learn what this really means,
can anyone give me the 25 cent explanation and an easy cure?


--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:[email protected]
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

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

Brian Drummond

The function calls that convert the SLV SWAP to an integer are not
allowed where I am trying to use it in the CASE statement. This
function call is not invoked until later in the compilation process, so
the value is unknown at this time. The solution is to either declare
integer values for the opcodes with slightly different names (so I
don't have to call a conversion routine), or to use IF statements which
don't have the same limitations as the CASE statement.

I don't know the full context, so this may be off base, but...

if the intent is a one to one mapping between opcodes and INSTDSPLY
elements, is there a way to use positional attributes or 'image
attributes to accomplish what you want?
Perhaps deriving the SWAP opcode in terms of integer'image(SWP)?

Then things are a lot closer to self-maintaining in the event that you
extend or modify INSTDSPLY.

- Brian
 
A

Andy

Yep, functions declared in packages not part of 1076 are not locally
static. They're moving std_logic_1164, numeric_std, and numeric_bit
packages into the 1076 standard for this reason, among others.

Try declaring an integer constant (and an slv vector from that if
necessary), then using the integer constant in the case statement.

Andy
 
K

KJ

rickman said:
constant SWAP : IRSLV := to_slv(FIXOP + 16#00#, 8); -- E0 (1110 0000)
Could 'SWAP' be an integer instead?
i.e. constant SWAP: integer range 0 to ?? : FIXOP + 16#00#;
type INSTDSPLY is (RST, IACK, LTR, JMP, JUMZ, JUMC, JUMO, CALA, CALR,
SWP, OVR, RUP, DUP, SHFL, SHFC, ZFLG, RFTC,
RDRP, RTN, FTCH, FCHB, RFRM, RSB, RCM, FCHP, FHPB, RARS,
DDRP, TOR, CPNC, CPC, ADNC, ADC, SBNC, SBC,
BFL, RTI, STOR, STRB, BLAN, RADT, BLOR, STRP, STPB, BLXR);

when TO_INTEGER(UNSIGNED(SWAP)) => return SWP;
If 'SWAP' was an integer then the above line would simply be
when SWAP => return SWP;

Alternatively, if 'SWAP' really needs to be a standard logic vector
then you could use the following lines of code in the appropriate
places...
constant SWAP_integer: integer range 0 to ?? : FIXOP + 16#00#;
constant SWAP : IRSLV := to_slv(SWAP_integer); -- E0 (1110 0000)
when SWAP_integer => return SWP;

As yet another alternative, if the point of the case statements is to
translate between integers and 'INSTDSPLY' elements, the whole case
statement might be replaced by

variable An_Instruction: INSTDSPLY :=
INSTDSPLY'pos(An_Instruction_Index);

The reverse translation from INSTDSPLY to an index would be...

variable An_Instruction_Index: integer range 0 to ??:
INSTDSPLY'val(An_Instruction);

The ?? on the upper end of the integer range in the above is something
that equates to...

INSTDSPLY'pos(BLXR) - INSTDSPLY'pos(RST)

There is a cleaner way to get this upper end of the integer range but I
forget what it is and whenever I do something like this I have to go
back and relook it up. What you need to get is the position of the
rightmost element of INSTDSPLY (so that you don't have to make the
assumption that 'BLXR' is the rightmost one). I'm pretty sure that
"INSTDSPLY'pos(RST)" will return 0...but again, the brain is foggy on
whether the leftmost element of an enumerated type is position '0' or
'1'. Once again though the idea is to get the index of the leftmost
element. And now that I recall a bit more, to really be clean about
it, the lower bound on the index should be INSTDSPLY'pos(the leftmost
element) and not necessarily 0.

That may help somewhat.

KJ
 
R

rickman

KJ said:
Could 'SWAP' be an integer instead?
i.e. constant SWAP: integer range 0 to ?? : FIXOP + 16#00#;

No, SWAP is the SLV corresponding to the instruction as used in the
synthesized code. I don't want to clutter that up with conversions.
So it needs to be SLV.

Everything else is just for displaying a coherent value in the
simulator. Rather than having to look at the hex for an instruction, I
can view the enumerated value that is returned from this conversion
routine since the simulator will display the ASCII name of the
enumerated value.
If 'SWAP' was an integer then the above line would simply be
when SWAP => return SWP;

Alternatively, if 'SWAP' really needs to be a standard logic vector
then you could use the following lines of code in the appropriate
places...
constant SWAP_integer: integer range 0 to ?? : FIXOP + 16#00#;
constant SWAP : IRSLV := to_slv(SWAP_integer); -- E0 (1110 0000)
when SWAP_integer => return SWP;

Yes, that is what I will have to do, add an integer constant for every
one of the 36 opcodes. So each opcode will have an SLV value, an
integer value and an enumerated value. Not such a big deal really.

As yet another alternative, if the point of the case statements is to
translate between integers and 'INSTDSPLY' elements, the whole case
statement might be replaced by

variable An_Instruction: INSTDSPLY :=
INSTDSPLY'pos(An_Instruction_Index);

I believe this converts to an enumerated value. If you check, I think
you will find that the required conversion is from SLV to the
enumerated value.
The reverse translation from INSTDSPLY to an index would be...

variable An_Instruction_Index: integer range 0 to ??:
INSTDSPLY'val(An_Instruction);

The ?? on the upper end of the integer range in the above is something
that equates to...

INSTDSPLY'pos(BLXR) - INSTDSPLY'pos(RST)

There is a cleaner way to get this upper end of the integer range but I
forget what it is and whenever I do something like this I have to go
back and relook it up. What you need to get is the position of the
rightmost element of INSTDSPLY (so that you don't have to make the
assumption that 'BLXR' is the rightmost one). I'm pretty sure that
"INSTDSPLY'pos(RST)" will return 0...but again, the brain is foggy on
whether the leftmost element of an enumerated type is position '0' or
'1'. Once again though the idea is to get the index of the leftmost
element. And now that I recall a bit more, to really be clean about
it, the lower bound on the index should be INSTDSPLY'pos(the leftmost
element) and not necessarily 0.

That may help somewhat.

Thanks for the ideas. This may all be academic. This is a CPU that I
built a while back for an Altera ACEX part since Altera does not
support their NIOS for that family. After spending a fair amount of
time on the architecture, I did the minimum of actual coding and design
to get it running. If memory serves me, it clocked in at 55 MHz max
and it was run at 40 MHz. Currently I wanted to look at how fast it
might run if I redid it for a current FPGA architecture using
synchronous memories. I compiled it for a Spartan 3 and got a speed up
to 77 MHz using less than 10% of an XC3S400 (about 310 slices I
believe). I am not impressed with the speed. I expected a much larger
increase and had hoped for operation at over 100 MHz. Although it may
approach 100 MHz with careful floorplanning, I don't think this is
worth the effort.

Instead I think it will take a look at the third party MicroBlaze core
and see if that is as small and fast and memory efficient. There is
little reason to knock myself out when so many have done this before me.
 
A

Andy

Another alternative is to do the conversion in the case expression, not
the when expression(s).

The compiler only needs to know the type of the return of the
conversion function, which is locally static information, since it is
defined in the package declaration, not the package body.

The when target expression VALUES (not just type) must be locally
static so that the compiler can verify that every possible value of the
case expression (bound by the type of the expression) is covered
exactly once in the targets.

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top