2

I am trying to implement the equation in VHDL which has multiplication by some constant and addition. The equation is as below,

  y<=-((x*x*x)*0.1666)+(2.5*(x*x))- (21.666*x) + 36.6653;   ----error

I got the error

     HDLCompiler:1731 - found '0' definitions of operator "*",  
     can not determine exact overloaded matching definition for "*".

entity is

    entity eq1 is
        Port ( x : in  signed(15 downto 0);
               y : out signed (15 downto 0) );
    end eq1;

I tried using the function RESIZE and x in integer but it gives same error. Should i have to use another data type? x is having pure integer values like 2,4,6..etc.

Raj
  • 195
  • 4
  • 12
  • *Where* does the error occur? – Sebastian Jan 21 '15 at 09:41
  • y<=-((x*x*x)*0.1666)+(2.5*(x*x))- (21.666*x) + 36.6653; – Raj Jan 21 '15 at 09:42
  • This is related to [found '0' definitions of operator “+” in VHDL](http://stackoverflow.com/questions/26598471/found-0-definitions-of-operator-in-vhdl) – Sebastian Jan 21 '15 at 09:45
  • The questions might be related, but it might not be clear to all readers *why* they're related (i.e. for this case, that there is no built-in operator to multiply a `signed` with a `real`, and VHDL's strong typing prevents it from "assuming" anything about the operation). – fru1tbat Jan 21 '15 at 13:15

3 Answers3

3

Since x and y are of datatype signed, you can multiply them. However, there is no multiplication of signed with real. Even if there was, the result would be real (not signed or integer).

So first, you need to figure out what you want (the semantics). Then you should add type casts and conversion functions.

y <= x*x; -- OK
y <= 0.5 * x; -- not OK
y <= to_signed(integer(0.5 * real(to_integer(x))),y'length); -- OK
Philippe
  • 3,700
  • 1
  • 21
  • 34
  • During Synthesis the real is not synthesizable. – Raj Jan 21 '15 at 16:09
  • 1
    Your question did not specifically say you were doing synthesis. You will need to represent your `real` values as vectors, either by using the built-in `fixed_pkg`, if your tools support it, or use `signed` and do the fraction point bookkeeping yourself. – fru1tbat Jan 21 '15 at 16:35
3

This is another case where simulating before synthesis might be handy. ghdl for instances tells you which "*" operator it finds the first error for:

ghdl -a implement.vhdl
implement.vhdl:12:21: no function declarations for operator "*"

 y <= -((x*x*x) * 0.1666) + (2.5 * (x*x)) - (21.666 * x) + 36.6653;
 ---------------^  character position 21, line 12

The expressions with x multiplied have both operands with a type of signed.

(And for later, we also note that the complex expression on the right hand side of the signal assignment operation will eventually be interpreted as a signed value with a narrow subtype constraint when assigned to y).

VHDL determines the type of the literal 0.1666, it's an abstract literal, that is decimal literal or floating-point literal (IEEE Std 1076-2008 5.2.5 Floating-point types, 5.2.5.1 General, paragraph 5):

Floating-point literals are the literals of an anonymous predefined type that is called universal_real in this standard. Other floating-point types have no literals. However, for each floating-point type there exists an implicit conversion that converts a value of type universal_real into the corresponding value (if any) of the floating-point type (see 9.3.6).

There's only one predefined floating-point type in VHDL, see 5.2.5.2, and the floating-point literal of type universal_real is implicitly converted to type REAL.

9.3.6 Type conversions paragraph 14 tells us:

In certain cases, an implicit type conversion will be performed. An implicit conversion of an operand of type universal_integer to another integer type, or of an operand of type universal_real to another floating-point type, can only be applied if the operand is either a numeric literal or an attribute, or if the operand is an expression consisting of the division of a value of a physical type by a value of the same type; such an operand is called a convertible universal operand. An implicit conversion of a convertible universal operand is applied if and only if the innermost complete context determines a unique (numeric) target type for the implicit conversion, and there is no legal interpretation of this context without this conversion.

Because you haven't included a package containing another floating-point type that leaves us searching for a "*" multiplying operator with one operand of type signed and one of type REAL with a return type of signed (or another "*" operator with the opposite operand type arguments) and VHDL found 0 of those.

There is no

function "*" (l: signed; r: REAL) return REAL;

or

function "*" (l: signed; r: REAL) return signed;

found in package numeric_std.

Phillipe suggests one way to overcome this by converting signed x to integer.

Historically synthesis doesn't encompass type REAL, prior to the 2008 version of the VHDL standard you were likely to have arbitrary precision, while 5.2.5 paragraph 7 now tells us:

An implementation shall choose a representation for all floating-point types except for universal_real that conforms either to IEEE Std 754-1985 or to IEEE Std 854-1987; in either case, a minimum representation size of 64 bits is required for this chosen representation.

And that doesn't help us unless the synthesis tool supports floating-point types of REAL and is -2008 compliant.

VHDL has the float_generic_pkg package introduced in the 2008 version, which performs synthesis eligible floating point operations and is compatible with the used of signed types by converting to and from it's float type.

Before we suggest something so drastic as performing all these calculations as 64 bit floating point numbers and synthesize all that let's again note that the result is a 16 bit signed which is an array type of std_ulogic and represents a 16 bit integer.

You can model the multiplications on the right hand side as distinct expressions executed in both floating point or signed representation to determine when the error is significant.

Because you are using a 16 bit signed value for y, significant would mean a difference greater than 1 in magnitude. Flipped signs or unexpected 0s between the two methods will likely tell you there's a precision issue.

I wrote a little C program to look at the differences and right off the bat it tells us 16 bits isn't enough to hold the math:

int16_t x, y, Y;
int16_t a,b,c,d;
double A,B,C,D;

a = x*x*x * 0.1666;
A = x*x*x * 0.1666;

b = 2.5 * x*x;
B = 2.5 * x*x;

c = 21.666 * x;
C = 21.666 * x;

d =     36;  
D = 36.6653;  

y = -( a + b - c + d);
Y = (int16_t) -(A + B - C + D);

And outputs for the left most value of x:

x = -32767, a =  11515, b =      0, c =  10967, y =   -584, Y =      0  
x = -32767, A = -178901765.158200, B = 2684190722.500000, C = -709929.822000
 x = -32767 , y =   -584 , Y=      0, double = -2505998923.829100 

The first line of output is for 16 bit multiplies and you can see all three expressions with multiplies are incorrect.

The second line says double has enough precision, yet Y (-(A + B - C + D)) doesn't fit in a 16 bit number. And you can't cure that by making the result size larger unless the input size remains the same. Chaining operations then becomes a matter of picking best product and keeping track of the scale, meaning you might as well use floating point.

You could of course do clamping if it were appropriate. The double value on the third line of output is the non truncated value. It's more negative than x'LOW.

You could also do clamping in the 16 bit math domain, though all this tells you this math has no meaning in the hardware domain unless it's done in floating point.

So if you were trying to solve a real math problem in hardware it would require floating point, likely accomplished using package float_generic_pkg, and wouldn't fit meaningfully in a 16 bit result.

2

As stated in found '0' definitions of operator “+” in VHDL, the VHDL compiler is unable to find the matching operator for your operation, which is e.g. multiplying x*x. You probably want to use numeric_std (see here) in order to make operators for signed (and unsigned) available.

But note, that VHDL is not a programming language but a hardware design language. That is, if your long-term goal is to move the code to an FPGA or CPLD, these functions might not work any longer, because they are not synthesizable.

I'm stating this, because you will become more problems when you try to multiply with e.g. 0.1666, because VHDL usually has no knowledge about floating point numbers out of the box.

Community
  • 1
  • 1
Sebastian
  • 8,046
  • 2
  • 34
  • 58
  • I used that package also signed and unsigned packages. Can we make it synthesizable by taking some approximation in the constatn value? – Raj Jan 21 '15 at 10:18
  • Don't get me wrong on this, it is possible to do floating point value calculations, but it surely introduces overhead and you have to think very carefully how to do this. Another option would be to use fixed point arithmetics. – Sebastian Jan 21 '15 at 10:25
  • ok. But the " * " is creating error. I used Numeric_std with signed and unsigned packages. – Raj Jan 21 '15 at 10:50
  • Well, it depends to which `*` the compiler refers. If it is the one with the floating point value, then this is not defined. I'd suggest to build the equation up step by step. – Sebastian Jan 21 '15 at 10:53
  • Step by step means i did not get it. yes i have to multiply integer with floating point value that's why its giving error. – Raj Jan 21 '15 at 10:56
  • Yeah, then you'll have to find a way how to multiply `signed` with `float` in VHDL or turn your floating point numbers into fixed point. – Sebastian Jan 21 '15 at 10:59
  • @Sebastian Multiplying integers (and signed and unsigned) is perfectly synthesizable. VHDL does know floating points out of the box: it has been in the first version of the language standard. One issue is that current synthesizers will not synthesize floating point operations. The OP's problem however has to do with type conversions in the first place. Synthesis is a whole separate problem. – Philippe Jan 21 '15 at 11:40
  • @Philippe I did not state the opposite. – Sebastian Jan 21 '15 at 11:42
  • If i use both x and y as integer in the entity and write the equation as........y <= integer(-(0.1666 * real((x*x*x)))+(2.5 * real(x*x))- (21.666*real(x))+36.6653); .......i got the result what i want. But during synthesize it gives an error : "Real operand is not supported in this context." – Raj Jan 21 '15 at 16:02
  • @Raj this is exactly what I meant before. – Sebastian Jan 21 '15 at 16:03
  • So any other way to implement this and which is synthesizable. – Raj Jan 21 '15 at 16:10
  • @Raj IMO nothing without any additional effort. E.g. if you are on Xilinx, you can probably use an IPCore. Or try to make it happen with fixed point integer arithmetic. – Sebastian Jan 21 '15 at 16:15
  • y : out signed(40 downto 0)) ---------------------- signal a : signed(19 downto 0) := "00000010101010100110"; signal b : signed(19 downto 0) := "00000010101010100110";------------- multiplying a and b y<=a*b; The size of y for signed multiplication should be 20+20+1 =41. however during simulation it gives an error. " Target Size 41 and source size 40 for array dimension 0 does not match. " I used fixed point for a,b=0.1666. – Raj Jan 22 '15 at 06:13
  • @Raj probably open a new question on this. – Sebastian Jan 22 '15 at 06:14