LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
HWID : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
RAM_addr : OUT UNSIGNED(9 DOWNTO 0);
TYPE reg_type IS ARRAY (0 TO NUM_REGS-1) OF
STD_LOGIC_VECTOR(HWID'RANGE);
SIGNAL regs : reg_type;
SIGNAL data_in : STD_LOGIC_VECTOR(HWID'RANGE);
Line 156: RAM_addr <= UNSIGNED("00" & data_in);
and the error is:
Error (10327): VHDL error at xFace.vhd(156): can't determine
definition of operator ""&"" -- found 2 possible definitions
Error (10647): VHDL type inferencing error at xFace.vhd(156): type of
expression is ambiguous - "reg_type" or "std_logic_vector" are two
possible matches
Error (10411): VHDL Type Conversion error at xFace.vhd(156): can't
determine type of object or expression near text or symbol "UNSIGNED"
I have no idea why it thinks "reg_type" is a possible match. It seems
very clear that RAM_addr is unsigned, "00" is SLV, and data_in is
SLV. "&" can only have one possible meaning. I'm sure that I'm doing
something else wrong that you guys will point out in less than a
second! ;)
Shannon
> Line 156: RAM_addr <= UNSIGNED("00" & data_in);
> and the error is:
>
> Error (10327): VHDL error at xFace.vhd(156): can't determine
> definition of operator ""&"" -- found 2 possible definitions
> Error (10647): VHDL type inferencing error at xFace.vhd(156): type of
> expression is ambiguous - "reg_type" or "std_logic_vector" are two
> possible matches
> Error (10411): VHDL Type Conversion error at xFace.vhd(156): can't
> determine type of object or expression near text or symbol "UNSIGNED"
>
> I have no idea why it thinks "reg_type" is a possible match.
Make arrays of subtypes, not base types.
The problem is inside the parens.
"00" is an anonymous type that could be an reg_type *element*.
STD_LOGIC_VECTOR(HWID'RANGE) is an anonymous subtype.
The LRM does not require the compiler to think further.
That's just the way it is.
Simplest fix is to declare and use subtypes for the
various STD_LOGIC_VECTOR widths.
-- Mike Treseler
Thanks for the help Mike. I guess I still don't understand. I tried
googling for "anonymous subtype" but I didn't find any helpful
information.
I tried declaring a subtype by doing:
subtype hwid_type IS STD_LOGIC_VECTOR(7 DOWNTO 0);
and then:
TYPE reg_type IS ARRAY (0 TO NUM_REGS-1) OF hwid_type;
SIGNAL data_in : hwid_type;
That didn't change anything so I'm obviously not understanding the
term "anonymous subtype". Any hints?
Shannon
> That didn't change anything so I'm obviously not understanding the
> term "anonymous subtype". Any hints?
> Line 156: RAM_addr <= UNSIGNED("00" & data_in);
RAM_addr <= my_address_subtype'("00" & data_in);
I recently had a similar problem (though I was only using SLVs) and
fixed it by pulling the litteral constant out of the cast :
RAM_addr <= "00" & unsigned(data_in);
In this case the context is clear : "00" must be unsigned to make the
assignment valid.
I still don't understand why the context is unclear when concatenating a
litteral constant and a std_logic_vector.
Nicolas
Yes. Of course. That's the ticket.
> I still don't understand why the context is unclear when concatenating a
> literal constant and a std_logic_vector.
The parser is not saying that "00" won't '&' with data_in.
It's saying that it is possible that "00"
was *meant* to be an element of another type in scope.
Which would be a type error.
So it is a type error.
Hmmm.
-- Mike Treseler
RAM_addr is of type UNSIGNED not 'my_address_subtype'
So I tried:
RAM_addr <= UNSIGNED(my_address_subtype'("00" & data_in));
but then I'm back to the original errors again.
Nicolas's solution worked although I still don't understand why my
original line is wrong.
Thanks all!
Shannon
If "00" is a vague type in this case why can't I cast it to make the
error go away? For example:
RAM_addr <= UNSIGNED(STD_LOGIC_VECTOR'("00") & data_in);
Shannon
> If "00" is a vague type in this case why can't I cast it to make the
> error go away?
Declare it as a constant to give it a type.
That's good practice in any case.
I often declare zero constants for this:
RAM_addr <= my_adr_zero_c + data_in;
-- Mike Treseler
> If "00" is a vague type in this case why can't I cast it to make the
> error go away? For example:
>
> RAM_addr <= UNSIGNED(STD_LOGIC_VECTOR'("00") & data_in);
>
You should be able to, certainly I have in the past. Does it not work?
Cheers,
Martin
--
martin.j...@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.net/electronics.html
No, it doesn't work. It results in the same original errors. I'm
thinking it still doesn't work because in order to cast it as a SLV it
needs to know what it is casting it FROM. (i.e. it can't figure out
what "00" is in order to re-cast it.)
Shannon
> No, it doesn't work. It results in the same original errors. I'm
> thinking it still doesn't work because in order to cast it as a SLV it
> needs to know what it is casting it FROM. (i.e. it can't figure out
> what "00" is in order to re-cast it.)
I think that's about right.
Note that these fussy rules only apply
when I fail to declare my own constants
and subtypes.
-- Mike Treseler
What tool is this? It may be a bug. Here is why I think so, maybe
someone can straighten out my thoughts:
You are wrong and the tool is correct in that the type of the expression,
"00" & data_in, can be either std_logic_vector or reg_type (concatenation
is implicitly defined for all array types). For example, if NUM_REGS is
two, the following would be legal:
regs <= data_in & data_in ;
OTOH, the type conversion UNSIGNED can only convert arrays of std_logic
to type unsigned. Since the type reg_type is not an array of std_logic,
it should not be a potential match to the overload resolution.
Perhaps one of our resident compiler people could comment?
I would say report it as a bug.
The work around Nicolas gave you:
RAM_addr <= "00" & unsigned(data_in);
works because there is no other path the tool can consider for the &.
Cheers,
Jim
You don't have to convince me that it's a bug! hehehe But I always
want to understand WHY things are the way they are. The thing I
learned here was "scope". I had no idea it was using the concept of
scope to resolve ambiguous situations.
Personally I think type casting it as an SLV should have worked.
Shannon
Every array type comes with 4 implicit "&" operators:
"&"[array,array RETURN array]
"&"[array,elem RETURN array]
"&"[elem,array RETURN array]
"&"[elem,elem RETURN array]
VHDL uses only the base type when doing operator overloading
(figuring out which operator to use). This includes using
only the base type of the "elem" in the above.
--========================================================================
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
HWID : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
RAM_addr : OUT UNSIGNED(9 DOWNTO 0);
TYPE reg_type IS ARRAY (0 TO NUM_REGS-1) OF STD_LOGIC_VECTOR(HWID'RANGE);
SIGNAL regs : reg_type;
SIGNAL data_in : STD_LOGIC_VECTOR(HWID'RANGE);
Line 156: RAM_addr <= UNSIGNED("00" & data_in);
--========================================================================
Take the expression ("00" & data_in). Remember, we can't
use the enclosing type conversion target type UNSIGNED because
of the 7.3.5 rules. The type of data_in is clearly std_logic_vector.
Now we must figure out the type of "00" and which of these 8 to call:
In this testcase, 8 relevant "&" operators are visible.
1a) "&"[std_logic_vector,std_logic_vector RETURN std_logic_vector]
1b) "&"[std_logic_vector,std_ulogic RETURN std_logic_vector]
1c) "&"[std_ulogic,std_logic_vector RETURN std_logic_vector]
1d) "&"[std_ulogic,std_ulogic RETURN std_logic_vector]
2a) "&"[reg_type,reg_type RETURN reg_type]
2b) "&"[reg_type,std_logic_vector RETURN reg_type]
2c) "&"[std_logic_vector,reg_type RETURN reg_type]
2d) "&"[std_logic_vector,std_logic_vector RETURN reg_type]
In the items labeled with "2", the type "reg_type" really means
the anonymous base type of the constrained array subtype "reg_type".
From these 8 concatenation operators, we need to pick the 1 that
will work, else we have an ambiguity (error).
The right operand "data_in" type being std_logic_vector, there
remain 4 possible choices:
1a) "&"[std_logic_vector,std_logic_vector RETURN std_logic_vector]
1c) "&"[std_ulogic,std_logic_vector RETURN std_logic_vector]
2b) "&"[reg_type,std_logic_vector RETURN reg_type]
2d) "&"[std_logic_vector,std_logic_vector RETURN reg_type]
Looking at the left operand string literal "00" (which is necessarily
some 1-dim array type), we can further prune this down to 2 choices (and
know that "00" is std_logic_vector):
1a) "&"[std_logic_vector,std_logic_vector RETURN std_logic_vector]
2d) "&"[std_logic_vector,std_logic_vector RETURN reg_type]
We can't decide which one of these 2 "&" operators to call. Overloading
occurs on the base type, and we can't use the RETURN type at all
when we're in a type conversion expression. The number of elements
of the constrained array subtype "reg_type" is irrelevant, any
length error would occur separate and after the overload resolution
has occurred. Basically, we don't know if ("00" & data_in) means,
"make an even longer std_logic_vector value", or "make a 2-element array value
of type "reg_type" (which would be an error because every element
of such a value has to be the same length as the other, and has to be the
same length as the actual element subtype of the array); the 2-element
interpretation must be considered even if the "reg_type" doesn't
define exactly two elements, and regardless of the length of the
element subtype.
There are at least 2 ways to make this work:
This effectively tells the expression of the type conversion
to UNSIGNED that "you are of type std_logic_vector", eliminating
choice 2d from the list:
RAM_addr <= UNSIGNED(std_logic_vector'("00" & data_in));
This converts data_in to UNSIGNED, bringing into play the 4 "&"
operators for type UNSIGNED, changing the interpretation of "00"
so that it's of type UNSIGNED, and chosing the
"&"[unsigned,unsigned RETURN unsigned] concatenation operator:
RAM_addr <= "00" & UNSIGNED(data_in);
Hi Shannon,
This is not a bug. As others tried to explain to you, the expression ("00" & data_in) could mean an array of 10 elements of
std_logic, or it could mean an array of 2 elements of std_logic_vector. In the first case, the result type is 'std_logic_vector', in
the second case it can be type 'reg_type'.
The tool cannot know which one you mean because the expression is used as an operand to the type conversion (to type 'UNSIGNED'),
and LRM 7.3.5 states explicitly : "The type of the operand of a type conversion must be determinable independent of the context (in
particular, independent of the target type)."
So either type 'reg_type' or type 'std_logic_vector' could match here.
How to fix this ?
Work with EITHER 'std_logic_vector' OR with 'unsigned'. Convert between the two as little as you can. That will also make it clear
what the representation of the data is in the signals. If you have to convert, do it with a plain conversion (no expression in the
argument).
So, two solutions :
(1) Change 'data_in' to be an 'unsigned'. Then use normal assignment :
RAM_addr <= "00" & data_in;
(2) If you want to keep 'data_in' the same (type std_logic_vector), then concert it by itself :
RAM_addr <= "00" & UNSIGNED(data_in);
Either way should work (no ambiguity).
Rob
Unfortunately I agree with James' and Rob's analysis.
I don't like it, but there must be some reason for the
restriction.
Jim
OK, so I missed James' detailed message, which had the second paren
in the right place (ie two parens after data_in, not one after
"00")... sorry about that!
Cheers,
Martin
Great stuff! Thanks for the detailed explaination. This group is a
wonderful resource.
I think I followed James's explaination but I have one remaining
question.
If I (properly) used a subtype to declare my array:
subtype hwid_type IS STD_LOGIC_VECTOR(7 DOWNTO 0);
TYPE reg_type IS ARRAY (0 TO NUM_REGS-1) OF hwid_type;
SIGNAL data_in : hwid_type;
Then wouldn't "reg_type" resolve down to SLV and thereby remove the
ambiguity? To refer back to James's list we would have:
1a) "&"[std_logic_vector,std_logic_vector RETURN std_logic_vector]
2d) "&"[std_logic_vector,std_logic_vector RETURN reg_type]
but reg_type is really a subtype of SLV. So in fact 1a and 2d would
be equivalent.
(I know I'm wrong. I'm just looking for that last little bit of
understanding)
Shannon
Given that statement, how do I apply this when working with
constrained integers...
I have a function to perform a "shift" operation on an integer,
function sllint (x, sh : natural) return natural is
begin
return x*(2**sh);
end sllint;
I am using it with a constrained integer,
SIGNAL Addr : NibbInt;
where
subtype NibbInt is Integer range 0 to 2**4-1;
usage,
Addr <= sllint(Addr, CTPDATAWDTH) + to_nat(Scfg_Din);
where Scfg_Din is an SLV (1 downto 0) and CTPDATAWDTH is an integer
constant of 2.
I am not clear on what happens when I shift the value of Addr left by
2 and significant bits extend beyond the defined range. I thought
about defining an overloaded operator for shifting NibbInt which would
use the mod operator, but you say the subtype won't be used for
overloading. So it would just use the sllint operator defined for
integer anyway.
I don't want to have to pass into the function the range of the
parameter. The usage of the function just gets too messy. I guess I
could use an sllnib operator, but I would prefer not to have to pre-
select the function and the compiler select it as an overloaded
function.
How am I looking at this wrong? Shouldn't I be able to do this?
Rick
> function sllint (x, sh : natural) return natural is
> begin
> return x*(2**sh);
> end sllint;
> I am not clear on what happens when I shift the value of Addr left by
> 2 and significant bits extend beyond the defined range.
The function, as written, will return x*(2**sh)
up to the natural range. It knows nothing about
any other range unless you add a parameter
to to function.
I would use numeric_std.unsigned and the shift_left
function, and to_integer(my_uns, my_len) as needed.
-- Mike Treseler
function, and to_integer(my_uns) as needed.
>
> -- Mike Treseler
Declaring zero constants means declaring a constant for every possible
length (well, not actually every but still quite a lot)
I once had the idea of declaring a function for that (and I think it
worked quite well) :
function zero (n : natural) return std_logic_vector is
constant C_ZERO : std_logic_vector(n-1 downto 0) := (others => '0');
begin
return C_ZERO;
end function zero;
Nicolas
Hi Jim,
The restriction you talk about is probably the LRM 7.3.5 rule : "The type of the operand of a type conversion must be determinable
independent of the context (in
particular, independent of the target type)."
Why is this in there ?
I'm not entirely sure, but it does make sense from a wider point of view. Here is the type conversion in simplified syntax :
target_type( expression )
'expression' is 'cast' to type 'target_type'.
That means that 'target_type' is not the same as the expression type.
So how do we know which type 'expression' can or should be ? We don't !
That's why they put the rule in there that the type of the expression should be determinible without context info.
Later in 7.3.5, it is stated that the type conversion is only allowed if the target type is at least 'closely related' to the
expression type. 'closely related' is then defined as a certain dependency between expression type and target type. Other type
conversions are not allowed (except for some 'universal' implicit type conversions).
So it seems that they could have made the type-inference rule dependent on the 'closely related' semantics of the construct. Maybe
something like this :
"The type of the operand of a type conversion must be determinable independent of the context, but taken into consideration that the
type of the expression and the target type must be closely related."
This sentence is not entirely correct yet, since implicit (universal) type conversions would need to be included, but it would allow
for overloading to determine the expression type based on the target type in some form. This could be a headache for compiler
builders, since VHDL hardly ever has special-purpose type-conditions like this, and remember this was written before 1987, when
compiler technology was not yet so sophisticated as it is today. So I think that by making the type conversion rule simple, it would
be easier to bring out a full VHDL parser, and that's why the rules are a bit easier on the compiler.
Any way, that's my 2 cts on this issue.
Rob Dekker
Verific