I use this code in a testbench, which works as expected:
std_logic_vector(to_unsigned(integer(0.603205*(2**16)),16))
i want to replace it with a function defined in the same file:
function convert_mult(mult : real) return std_logic_vector is
begin
return std_logic_vector(to_unsigned(integer(mult*(2**16)),16));
end function;
and call it like this:
convert_mult(0.603205)
the function fails compilation with "Cannot find the "*" operator with operands denoted with the "[REAL, UNIVERSAL_INTEGER]" signature."
I can't work out whats wrong with this, i thought real * integer was supported? should i be using another type?
TL;DR
You can mix real and integer literals like in 0.603205*(2**16) but not non-literal reals and integer literals like in mult*(2**16). As noted by Matthew, real and integer are closely related types, so converting is easy. Use:
return std_logic_vector(to_unsigned(integer(mult*real(2**16)),16));
And, incidentally, you write I thought real * integer was supported. Well, you were wrong. It is not supported. You must use an explicit conversion... except with literals.
Details
Why does it work with literals but not with non-literals? According the VHDL 2008 Language Reference Manual (IEEE Std 1076-2008) universal_integer and universal_real are, respectively, the types of integer and floating point literals.
0.603205 is a universal_real.
2**16 is a bit more complex because it is an expression involving integer literals (universal_integers). Section 9.3.6 Type conversions of the LRM explains that universal_integer can be automatically converted to another integer type when needed by the context. I do not know exactly what automatic conversions take place because the LRM is not very easy to follow on this, but I suspect that the 16 is automatically converted to an integer according rules of section 9.3.6, which allows the use of the universal_integer ** integer operand of package STANDARD that returns a universal_integer (see section 16.3 Package STANDARD where all these operators are defined in their functional form).
Finally, section 9.5 Universal expressions explicitly states that the * operator is defined on universal_integer * universal_real and universal_real * universal_integer. Both return a universal_real.
Note: there is also a universal_real / universal_integer returning universal_real but no universal_integer / universal_real.
Related
I get this error message:
testbench.vhd:16:22: no function declarations for operator "+"
at this line:
Z <= unsigned(X) + resize(unsigned(Y),X'length);
with this code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MCVE is
end entity MCVE;
architecture MCVE of MCVE is
signal X, Z : std_logic_vector(15 downto 0);
signal Y : std_logic_vector(7 downto 0);
begin
process
begin
Z <= unsigned(X) + resize(unsigned(Y),X'length);
end process;
end architecture MCVE;
https://www.edaplayground.com/x/2LBg
I don't understand why.
The error message is pretty clear. There is no function declarations for operator "+" which can add two unsigneds together and return a std_logic_vector. In the package numeric_std, there is however an opertor "+" which can add two unsigneds together and return an unsigned.
So, if you add another type conversion to convert the result of the addition back to a std_logic_vector the compiler can choose the version of the "+" operator that returns an unsigned.
Z <= std_logic_vector(unsigned(X) + unsigned(Y));
Overloading only works if there is exactly one fit for function, procedure or operator. If there is less than one, then there is no version for the compiler to choose; if there is more than one, the compiler doesn't know which one to choose and there is an ambiguity which needs to be sorted out.
Actually, you don't need to resize Y: the "+" operator is happy as long as one of the operands is the same width as the result.
https://www.edaplayground.com/x/4VJE
While Giwrgos Rizeakos original question was on resizing, there's a long history of questions and answers on operator and function overload visibility (there no function declaration visible here for operator "+").
After a search through those questions and answers this answer attempts to provide a question and answer pair that can be used to eliminated future duplicate questions based on providing authoritative references in an explanatory flow.
The problem starts with visibility:
12.3 Visibility
The meaning of the occurrence of an identifier at a given place in the text is defined by the visibility rules and also, in the case of overloaded declarations, by the overloading rules. The identifiers considered in this subclause include any identifier other than a reserved word or an attribute designator that denotes a predefined attribute. The places considered in this subclause are those where a lexical element (such as an identifier) occurs. The overloaded declarations considered in this subclause are those for subprograms and enumeration literals.
For each identifier and at each place in the text, the visibility rules determine a set of declarations (with this identifier) that define the possible meanings of an occurrence of the identifier. A declaration is said to be visible at a given place in the text when, according to the visibility rules, the declaration defines a possible meaning of this occurrence. The following two cases arise in determining the meaning of such a declaration:
— The visibility rules determine at most one possible meaning. In such a case, the visibility rules are sufficient to determine the declaration defining the meaning of the occurrence of the identifier, or in the absence of such a declaration, to determine that the occurrence is not legal at the given point.
— The visibility rules determine more than one possible meaning. In such a case, the occurrence of the identifier is legal at this point if and only if exactly one visible declaration is acceptable for the overloading rules in the given context or all visible declarations denote the same named entity.
It involves overloaded subprograms:
4.5.2 Operator overloading
The declaration of a function whose designator is an operator symbol is used to overload an operator. The sequence of characters of the operator symbol shall be one of the operators in the operator classes defined in 9.2.
The subprogram specification of a unary operator shall have a single parameter, unless the subprogram specification is a method (see 5.6.2) of a protected type. In this latter case, the subprogram specification shall have no parameters. The subprogram specification of a binary operator shall have two parameters, unless the subprogram specification is a method of a protected type, in which case, the subprogram specification shall have a single parameter. If the subprogram specification of a binary operator has two parameters, for each use of this operator, the first parameter is associated with the left operand, and the second parameter is associated with the right operand.
Operator overloads are defined as subprograms and use subprogram overloading rules:
4.5 Subprogram overloading
4.5.1 General
Two formal parameter lists are said to have the same parameter type profile if and only if they have the same number of parameters, and if at each parameter position the corresponding parameters have the same base type. Two subprograms are said to have the same parameter and result type profile if and only if both have the same parameter type profile, and if either both are functions with the same result base type or neither of the two is a function.
As a segue subprograms can be described in terms of signatures as a shorthand:
4.5.3 Signatures
A signature distinguishes between overloaded subprograms and overloaded enumeration literals based on their parameter and result type profiles. A signature can be used in a subprogram instantiation declaration, attribute name, entity designator, or alias declaration.
signature ::= [ [ type_mark { , type_mark } ] [ return type_mark ] ]
(Note that the initial and terminal brackets are part of the syntax of signatures and do not indicate that the entire right-hand side of the production is optional.) A signature is said to match the parameter and the result type profile of a given subprogram if, and only if, all of the following conditions hold:
— The number of type marks prior to the reserved word return, if any, matches the number of formal parameters of the subprogram.
— At each parameter position, the base type denoted by the type mark of the signature is the same as the base type of the corresponding formal parameter of the subprogram.
— If the reserved word return is present, the subprogram is a function and the base type of the type mark following the reserved word in the signature is the same as the base type of the return type of the function, or the reserved word return is absent and the subprogram is a procedure.
And here the example:
Z <= unsigned(X) + resize(unsigned(Y),X'length);
can be described in terms of a signature.
Z is declared as type std_logic_vector. The left operand to "+" is X which is subject type conversion to unsigned (rules given in 9.3.6, both array types, same element type). The right operand is the result of resize with a signature of [unsigned, natural, return unsigned] found in package numeric_std by overload resolution:
12.5 The context of overload resolution
Overloading is defined for names, subprograms, and enumeration literals.
...
When considering possible interpretations of a complete context, the only rules considered are the syntax rules, the scope and visibility rules, and the rules of the form as follows:
a) Any rule that requires a name or expression to have a certain type or to have the same type as another name or expression.
b) Any rule that requires the type of a name or expression to be a type of a certain class; similarly, any rule that requires a certain type to be a discrete, integer, floating-point, physical, universal, or character type.
...
e) The rules given for the resolution of overloaded subprogram calls; for the implicit conversions of universal expressions; for the interpretation of discrete ranges with bounds having a universal type; for the interpretation of an expanded name whose prefix denotes a subprogram; and for a subprogram named in a subprogram instantiation declaration to denote an uninstantiated subprogram.
...
And the function made visible through the use of use clause making the declarations in numeric_std visible:
12.4 Use clauses
A use clause achieves direct visibility of declarations that are visible by selection.
The same overload resolution is performed on the example where no function declaration is found. No function declaration is found for "+" [unsigned, unsigned return std_logic_vector] where the return value must match type std_logic_vector (the a) rule above).
And as Matthew Taylor points out you can alter the assignment right hand expression by type conversion to std_logic_vector:
Z <= std_logic_vector(unsigned(X) + resize(unsigned(Y),X'length));
And why the resize function call is not needed can authoritatively be shown by referencing the function declaration for "+" `[unsigned, unsigned return unsigned] found in IEEE package numeric_std, (found in numeric_std-body.vhdl, in the 1076-2008 downloads.zip which is part of the -2008 standard):
-- Id: A.3R
function "+" (L : UNRESOLVED_UNSIGNED; R : STD_ULOGIC)
return UNRESOLVED_UNSIGNED
is
variable XR : UNRESOLVED_UNSIGNED(L'length-1 downto 0) := (others => '0');
begin
XR(0) := R;
return (L + XR);
end function "+";
Interpreting that authoritatively requires the the declaration for unsigned in numeric_std.vhdl (also found in the same above zip file):
type UNRESOLVED_UNSIGNED is array (NATURAL range <>) of STD_ULOGIC;
subtype UNSIGNED is (resolved) UNRESOLVED_UNSIGNED;
which is a subtype of unresolved_unsigned providing an element resolution function name. Resolution functions are explained in the standard:
4.6 resolution functions
A resolution function is a function that defines how the values of multiple sources of a given signal are to be resolved into a single value for that signal. Resolution functions are associated with signals that require resolution by including the name of the resolution function in the declaration of the signal or in the declaration of the subtype of the signal. A signal with an associated resolution function is called a resolved signal (see 6.4.2.3).
and the subtype declaration syntax can require a resolution function be found:
6.3 Subtype declarations
subtype_declaration ::=
subtype identifier is subtype_indication ;
subtype_indication ::=
[ resolution_indication ] type_mark [ constraint ]
resolution_indication ::=
resolution_function_name | ( element_resolution )
element_resolution ::= array_element_resolution | record_resolution
and function resolved is found in the the std_logic_1164 package declaration (in the same above zip file, provided as part of the standard).
Resolution is a matter for simulation, see 14.7 Execution of a model, particularly 14.7.3 Propagation of signal values and it's sub-clauses where resolution is applied to signals.
(And about here you see why there can be a lot of incomplete answers that don't preclude future questions. Finding answers in the standard requires subject matter understanding and it's primary audiences are tool implementors and advanced users where VHDL syntax and semantics are defined concisely allowing it's use as a formal notation.)
In 2013 there was a question on converting a big working code from double to quadruple precision: "Converting a working code from double-precision to quadruple-precision: How to read quadruple-precision numbers in FORTRAN from an input file", and the consensus was to declare variables using an adjustable parameter "WP" that specifies the "working precision", instead of having a separate version of the program with variables declared using D+01, and another version using Q+01. This way we can easily switch back and forth by defining WP=real128 or WP=real64 at the top, and the rest doesn't need to change.
But how do we do this?
I tried the suggestion in the answer to that question, by making a simple code TEST.F90:
PROGRAM TEST
use ISO_FORTRAN_ENV
WP= real128
IMPLICIT NONE
real (WP) :: X
X= 5.4857990945E-4_WP
END PROGRAM TEST
compiled with:
~/gcc-4.6/bin/gfortran -o tst.x TEST.F90
But it gives:
IMPLICIT NONE
1
Error: Unexpected IMPLICIT NONE statement at (1)
QLEVEL16.F90:5.12:
real (WP) :: MEL
1
Error: Parameter 'wp' at (1) has not been declared or is a variable, which does not reduce to a constant expression
QLEVEL16.F90:6.29:
MEL= 5.4857990945E-4_WP
1
Error: Missing kind-parameter at (1)
The kind specifier must be an integer parameter - and you do not declare it appropriately. Furthermore, implicit none must go before any declaration.
Here is a working version addressing both issues:
PROGRAM TEST
use ISO_FORTRAN_ENV
IMPLICIT NONE
integer, parameter :: WP= real128
real (WP) :: X
X= 5.4857990945E-4_WP
END PROGRAM TEST
Actually many code using this WP approach. Many with select_*_kind intrinsic function. But I think there is a 'easier' way. It's to use default precision without specifying any kind keyword andusing compiler's flag to choose what the default precision is.
Pro is this method is easier if you don't need a precise control of precision on each variable. Con is that will heavily depend on compiler flags, which varies for each compiler or even might not available.
For gfortran, there is more flags -freal4-real8 or -freal4-real16 to promote each explicitly specified lower precision variable to higher precision.
Type Inference is a powerful attribute of Swift. It means the compiler can infer the literal's type from its value provided by the programmer, the explicit type specification is not needed.
For example var IntNum = 3; the compiler can infer that the variable IntNum is of type Int. In Xcode, If user hits the key and clicks on the variable name, here IntNum, then Xcode tells you what the type it is.
However, if I did that on the literal value 3, Xcode provides nothing. I guess, the literal value I put on the screen simply has no type at all, only the object variable and constant has the type property.
I just guess so, can someone explain that to me?
Cheers
SL
That's right.
From the documentation
Type Safety and Type Inference
Type inference is particularly useful when you declare a constant or
variable with an initial value. This is often done by assigning a
literal value (or literal) to the constant or variable at the point
that you declare it. (A literal value is a value that appears directly
in your source code)
...
If you combine integer and floating-point literals in an expression, a
type of Double will be inferred from the context:
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
The literal value of 3 has no explicit type in and of itself, and so
an appropriate output type of Double is inferred from the presence of
a floating-point literal as part of the addition.
Well, I try to understand limitations in Const expressions in VBScript. I was not able to use anything except literals. What the docs say is:
Literal or other constant, or any combination that includes all
arithmetic or logical operators except Is.
So, if "that includes all arithmetic or logical operators" then logically I expect I can do something like this:
Const X = (1 + 2)
But that brings the error "Expected literal constant". I found an interesting answer here that allows one to cheat, at some level, so the above can be done with:
Execute "Const X = " & (1 + 2)
But my question is about standard constant declaration. If by chance the docs said something like "expression could be ONLY literal", then I would never ask.
So what Else I can use (besides literal)?
Script56.chm says the following in the Remarks section:
Constants are public by default. Within procedures, constants are always private; their visibility can't be changed. Within a script, the default visibility of a script-level constant can be changed using the Private keyword.
To combine several constant declarations on the same line, separate each constant assignment with a comma. When constant declarations are combined in this way, the Public or Private keyword, if used, applies to all of them.
You can't use variables, user-defined functions, or intrinsic VBScript functions (such as Chr) in constant declarations. By definition, they can't be constants. You also can't create a constant from any expression that involves an operator, that is, only simple constants are allowed. Constants declared in a Sub or Function procedure are local to that procedure. A constant declared outside a procedure is defined throughout the script in which it is declared. You can use constants anywhere you can use an expression.
The bit in italics above makes a nonsense of the "or any combination that includes all arithmetic or logical operators except Is" claim.
Ruby is strongly typed language. Thus it performs type conversion rather than type casting. Now there is two types of conversions - implicit and explicit.
Based on what rules ruby determines which kind of conversion to be applied on what context?
Ruby is "duck typed", neither strong or weak typed, which means the behavior of a variable/object does not necessarily depend on the class it belongs to, but rather very "blind" and do method call at runtime without type check. If it cannot do that, it raises error.
Ruby does implicit conversion for Integer, String and some other internal classes. Whether to perform a conversion depends on the left operand. For example,
1 + "2"
The left operand is an integer, so ruby tries to do a math operation +. But the right operand is a string, so ruby will try to do a conversion (coersion) from string to integer. (Although it still failed. To make it work, one need to redefine the method + for Integer or we call monkey patch to do an explicit conversion using String#to_i)