I have the following VHDL case structure:
signal numa : unsigned(2 downto 0);
constant cA : unsigned(2 downto 0) := "000";
constant cB : unsigned(2 downto 0) := "001";
constant cC : unsigned(2 downto 0) := "100";
process(rstn, clk)
begin
if rstn='0' then
numa <= "000";
elsif rising_edge(clk) then
...
case to_integer(numa) is
when to_integer(cA) => ...
when to_integer(cB) to to_integer(cC) => ...
when others => ...
end case;
end if;
end process;
When trying to insert a (Lattice) Reveal core I get the following
error message:
"ERROR: case choice must be a locally static expression (VHDL-1438)"
How can I make use of the discrete range choice without violating the
static expression rule ?
Thank you for your opinion.
Cheers,
hssig
>signal numa : unsigned(2 downto 0);
>
>constant cA : unsigned(2 downto 0) := "000";
>constant cB : unsigned(2 downto 0) := "001";
>constant cC : unsigned(2 downto 0) := "100";
>
>process(rstn, clk)
>begin
> if rstn='0' then
> numa <= "000";
>
> elsif rising_edge(clk) then
> ...
>
> case to_integer(numa) is
> when to_integer(cA) => ...
> when to_integer(cB) to to_integer(cC) => ...
> when others => ...
> end case;
>
> end if;
>
>end process;
>"ERROR: case choice must be a locally static expression (VHDL-1438)"
>
>How can I make use of the discrete range choice without violating the
>static expression rule ?
"Locally static" in VHDL is a very aggressive restriction and
there's not much you can do about it. Function call in the
case choice is a no-no, sorry.
I suggest you re-cast your code so that the original constants
are integers:
--- Useful bits and pieces
subtype u3 is unsigned(2 downto 0);
subtype i3 is integer range 0 to (2**u3'length - 1);
function to_u3(n: i3) return u3 is begin
return to_unsigned(n, u3'length);
end;
--- Your constants as proper integers
constant nA : i3 := 0;
constant nB : i3 := 1;
constant nC : i3 := 4;
--- Your unsigned signals and constants,
--- derived from the original integers
signal numa: u3;
constant cA: u3 := to_u3(nA);
constant cB: u3 := to_u3(nB);
constant cC: u3 := to_u3(nC);
--- Now the case statement should be OK,
--- as well as being easier to read:
case to_integer(numa) is
when nA => ...
when nB to nC => ...
when others => ...
end case;
Hope this helps
--
Jonathan Bromley
>Hi,
>
>I have the following VHDL case structure:
>
>signal numa : unsigned(2 downto 0);
>constant cA : unsigned(2 downto 0) := "000";
>constant cB : unsigned(2 downto 0) := "001";
>constant cC : unsigned(2 downto 0) := "100";
>
...
> case to_integer(numa) is
> when to_integer(cA) => ...
> when to_integer(cB) to to_integer(cC) => ...
> when others => ...
> end case;
>"ERROR: case choice must be a locally static expression (VHDL-1438)"
>
>How can I make use of the discrete range choice without violating the
>static expression rule ?
The number of type conversions here suggest you are fighting the type system
instead of using it... that's often a hint that the design can be improved.
Assuming you need to write the constant values in binary for clarity, one way is
to keep them in integer form, and write
subtype numaRange is
constant cA : natural range 0 to 7 := 2#000#;
subtype BtoC is natural range 2#
and
case to_integer(numa) is
when cA => ...
when BtoC => ...
Much less clutter. And it avoids functions in the case arm branches, which is
the likely cause of the error...
The meaning of "to_integer" is not locally defined; since it is a function
declared somewhere else, it may not even have been written yet!
Thinking hardware, a case statement typically generates a multiplexer.
So while a function call in the case variable is allowed (you can select a
different multiplexer input depending on external conditions), a function call
in a case arm would change the shape of the hardware implementation if the
function evaluated differently ... it's not surprising that isn't allowed.
The fact that it is a standard function from a standard library is known to you,
but not to me, or the compiler. From the code you posted (no use clauses) I
can't tell if you are using the "real" unsigned, (from numeric_std), or an
impostor (from the Synopsis libraries) or even your own implementation.
VHDL doesn't cheat and impose special case meanings on your code - even at the
level of assuming '1' = true and '0' = false. That decision is (IMO, correctly)
kept outside the language, in the libraries. So you could implement negative
logic systems simply by replacing std_logic_1164 and numeric_std with their
negative logit equivalents. (If ECL ever comes back into fashion, this could be
a big win for VHDL over that other language, but I'm not holding my breath!)
You do have to be explicit about what you mean - in your case, simply using
integer ranges will do. IMO the result is cleaner - and easier for the next guy
to read and understand..
- Brian
IINM, the reason for the locally static restriction on choice
expressions is because the case statement choices must be evaluated at
analysis time (before elaboration) to determine that they are complete
and mutually exclusive. Non-locally static function calls cannot be
evaluated at analysis time, and therefore the set of choices cannot be
evaluated for completeness and mutual exclusivity.
Andy
thank you for your answers.
@Brian:
I use "std_logic_arith" and "numeric_std".
The constant definition "constant cA : natural range 0 to 7 :=
2#000#;"
is clear to me. But how do you use the proposed subtypes
subtype numaRange is
subtype BtoC is natural range 2#
? What is their purpose ?
Cheers,
hssig
Cheers,
hssig
Sorry, the subtype got garbled in editing; I was doing something else but
decided to shorten the post.
Jonathan answered it better anyway, but to borrow from his post:
subtype u3 is unsigned(2 downto 0); -- was "numaRange" in my post
constant cB: u3 := to_u3(nB);
constant cC: u3 := to_u3(nC);
case to_integer(numa) is
when nA => ...
when nB to nC => ...
"nB to nC" here is a range; this is essentially a subtype.
So it ought to be possible to write:
subtype BtoC is natural range cB to cC;
case to_integer(numa) is
when nA => ...
when BtoC => ...
In this example it doesn't add clarity.
But if "numa" stands for "Non-Uniform Memory Architecture", then (with suitable
constant and subtype names) you can write
case (numa_address) is
when local => ...
when close => ...
when distant => ...
when others => -- garbled address
and make the intent clear.
And when you extend the design, hopefully you only need to change the subtype
and maybe constant declarations:
subtype u3 is unsigned(4 downto 0);
-- oops! hence in my opinion: name it after its purpose, not its size!
subtype numaRange is unsigned(4 downto 0);
and the work is done.
Or only 99% of it; there's usually one explicit "std_logic(2 downto 0)" on a top
level port that slipped through somehow...
- Brian
> How can I make use of the discrete range choice without violating the
> static expression rule ?
I like to use cases of enumerated types, but ...
If I couldn't change your declarations, I would use
if, elsif, elsif, ..., else
You will get no such errors,
the conditions can be whatever you like,
and it won't cost any gates unless you really need them.
-- Mike Treseler
>And when you extend the design, hopefully you only need to change the subtype
>and maybe constant declarations:
> subtype u3 is unsigned(4 downto 0);
> -- oops! hence in my opinion: name it after its purpose, not its size!
> subtype numaRange is unsigned(4 downto 0);
Yes, of course Brian is completely right about this -
unless, as occasionally happens, the size is an essential
part of the nature of the thing. Apologies for the
illiterate programming. [*]
[*] If Brian can use Knuth as a stick to beat me with,
there's no reason why I shouldn't do so myself :-)
--
Jonathan Bromley
Cheers,
hssig
Does lattice have a language switch for VHDL-2008? If not submit the
issue as a bug since it is supported in the current revision of the
language - approved by IEEE in September 2008 and approved by
Accellera as a trial standard in July 2006, so vendors really don't
have an excuse for not having implemented it at this point.
Best,
Jim
SynthWorks
Unfortunately the excuse they gave me is that not many users are asking for it!
I find this very frustrating since there are some very basic language
enhancements which can make your code a lot cleaner, examples are:
1) Reading output ports
2) Case statement with don't care support
3) Expressions in port maps
4) Process(all)
5) Generic on packages
So have a look at the new language features and then send an email to your
vendor, it shouldn't take long!
Hans
www.ht-lab.com
>
> Best,
> Jim
> SynthWorks
when compiling such case description including the "to_integer"
function in the when-tree(s)
"when to_integer(cA) => ..."
Modelsim PE 6.5d (Compile Options 2008) also shows the warning: "Case
choice must be a locally static expression."
So if Mentor did implement the VHDL-2008 feature correctly there would
be no warning ?
Cheers,
hssig
> So if Mentor did implement the VHDL-2008 feature correctly there would
> be no warning ?
I don't know, and it doesn't really matter in this moment.
If we put the function in the case clause, like this:
case to_integer(unsigned(in_vec)) is
everything just works.
-- Mike
____________________________________________________
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity case_of_function is
port (
in_vec : in std_logic_vector(7 downto 0) := x"06");
end case_of_function;
architecture sim of case_of_function is
begin
case_test : process is
constant vec_len_c : natural := in_vec'length;
begin
case to_integer(unsigned(in_vec)) is
when 5|6 => report "it's a 5 or 6";
when 7 => report "it's a 7";
when others => report "it's not 5-7";
end case;
wait;
end process case_test;
end sim;
-- _______________________________
-- Sample run:
-- vsim -c case_of_function
-- VSIM 1> run
-- ** Note: it's a 5 or 6
-- Time: 0 ns Iteration: 0 Instance: /case_of_function
Yes, it does matter because I am trying to find out whether it is
allowed to put the function "to_integer"
in the when trees of a case statement.
Cheers,
hssig
> Yes, it does matter because I am trying to find out whether it is
> allowed to put the function "to_integer"
> in the when trees of a case statement.
All I can tell you is that both Modelsim and Quartus disapprove.
This makes the reason irrelevant to me.
Besides, cases of integers or enums are easier for me to read.
So reread this thread.
Others have spent time given you rational reasons for the restriction.
Good luck.
-- Mike Treseler
Nope. You can't have a non static computed value in a choice. The
compiler would have no means to determine if the case statement covers
each choice once and only once (think that the body of the function
might be not compiled yet).
You can use if/elsif instead.
--
jr
Particulier non cumulable
Yes, I agree. But at this point we are trying to find out if these
restrictions are still applicable for VHDL-2008 and whether M, X, A, L
or whatever vendors are implementing functions in case statements
the way the new standard is telling them.
>All I can tell you is that both Modelsim and Quartus disapprove.
>This makes the reason irrelevant to me.
But that does not prove that they are implementing it correctly (or at
all), doesn't it ?
Cheers,
hssig
Modelsim's VHDL2008 support is very limited, just look under
help->technotes->vhdl2008 to see what is currently supported (in 6.6),
Hans
www.ht-lab.com
>
> Cheers,
> hssig
>
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity function_in_case is
port( Clk : in std_logic;
Ad : in std_logic_vector(7 downto 0);
Sig : out std_logic_vector(1 downto 0)
);
end function_in_case;
architecture beh of function_in_case is
constant A : unsigned(7 downto 0) := x"00";
constant B : unsigned(7 downto 0) := x"01";
constant C : unsigned(7 downto 0) := x"EE";
signal addr : unsigned(7 downto 0);
begin
addr <= unsigned(Ad);
process(Clk)
begin
if rising_edge(Clk) then
case to_integer(addr) is
when to_integer(A) =>
Sig <= "00";
when to_integer(B) to to_integer(C) =>
Sig <= "01";
when others =>
Sig <= "11";
end case;
end if;
end process;
end beh;
Cheers,
hssig