MATH_REAL log2 function - vhdl

Log2 function of MATH_REAL is not working.
Here is the code:
Num: integer:=64;
num: integer:=2;
...
out: out STD_LOGIC_VECTOR(natural(log2(Num/(2**(num*2-1)))) downto 0)
...
The error I am having is: "found '0' definitions of operator "/", cannot determine exact overloaded matching definition for "/""
Thanks!

Cast as real before you apply log2 (or before you divide, if you don't want integer division).
Incidentally, you can't use "Num" and "num" for two different identifiers - VHDL is not case-sensitive.
std_logic_vector(natural(log2(real(num1) / real(2**(num2*2-1)))) downto 0);

Log2 has the following signature (see: here) :
function LOG2 (X : in REAL ) return REAL;
you are giving it
Num/(2**(num*2-1))
which is probably of type integer, ie not the real type expected, assuming you are using standard division for integers. My suggestion is you look into how to divide reals (e.g. through casting, though this may cause synthesis issues), or overload the division operator yourself.

Related

vhdl signed and unsigned type endianess

I am writing a code in vhdl quite full of algebraic operations and I declared some signed variables (I know that there are better types, but I needed to reduce the bits used). I was wondering if it is better to declare them as
variable foo1 := signed (7 downto 0);
or
variable foo2 := signed (0 to 7);
I know it is related to endianess, but I am fairly confused. For example, if I declare
variable foo3 := signed (0 to 7) := "01100100";
Will it be interpreted as 100 or 38 in decimal? And if I have a condition on foo3 as
if (foo3(1) = '1') then
-- whatever you want
endif;
Will foo3(1) = '1' be true or false?
For consistency across VHDL's math packages, it is better to use downto.
variable foo1 : signed (7 downto 0);
This has nothing to do with numeric_std package. As with the numeric_std package, the leftmost element is always the most significant element, independent of whether you use downto or to. Also interesting with numeric_std, the value is in no way dependent on the indices - so (15 downto 8) works the same as (7 downto 0).
On the other hand, with VHDL-2008's fixed point and floating point packages, the only direction supported is downto. The actual range has meaning. With fixed point, the indices have weight. Negative indices are the fractional part.
variable foo4 : sfixed(7 downto -2) ; -- 8 bits of integer, 2 bits of fraction
variable foo5 : sfixed(7 downto 1) ; -- even numbers only.
For more on fixed and floating point, see:
https://synthworks.com/papers/vhdl_fixedfloat_lewis_bishop_date_2007.pdf
For more on unsigned / signed, see:
https://synthworks.com/papers/vhdl_math_tricks_mapld_2003.pdf
In IEEE Standard VHDL Synthesis Packages:
The type UNSIGNED represents an unsigned binary integer with the most
significant bit on the left, while the type SIGNED represents a
two’s-complement binary integer with the most significant bit on the
left. In particular, a one-element SIGNED vector represents the
integer values –1 and 0.
So the number will be interpreted as 100, regardless the range direction. However, accessing or assigning a single element will match with the to range, i.e. foo3(1) = '1'.

How to set VHDL vector size based on the log of a constant

I would like to know what is corresponding VHDL code for $clog2(DATA_WIDTH) , for example in this line:
parameter DATA_OUT_WIDTH = $clog2(DATA_WIDTH)
and also for this sign " -: " in this example
if ( Pattern == In[i_count-:PATTERN_WIDTH] )
I will appreciate if anyone can help me.
You can do something like this
constant DATA_OUT_WIDTH : positive := positive(ceil(log2(real(DATA_WIDTH))));
or define a clog2 function encapsulating that expression. ceil and log2 can be found in math_real
use ieee.math_real.all;
In VHDL you can just specify the full range, for example
foo(i_count to i_count + 7)
foo(i_count downto i_count - 7)
Don't use In as an identifier though, it's a reserved word in VHDL.
In addition to Lars example you can easily write a function for finding the ceiling log 2 to determine the number of element address 'bits' necessary for some bus width. Some vendors or verification support libraries provide one already.
The reason there isn't a predefined function in an IEEE library already is expressed in Lars answer, you tend not to use it much, you can assign the value to a constant and an expression can be cobbled together from existing functions.
An example clog2 function
A borrowed and converted log2 routine from IEEE package float_generic:
function clog2 (A : NATURAL) return INTEGER is
variable Y : REAL;
variable N : INTEGER := 0;
begin
if A = 1 or A = 0 then -- trivial rejection and acceptance
return A;
end if;
Y := real(A);
while Y >= 2.0 loop
Y := Y / 2.0;
N := N + 1;
end loop;
if Y > 0.0 then
N := N + 1; -- round up to the nearest log2
end if;
return N;
end function clog2;
The argument A type NATURAL prevents passing negative integer values. Rounding is strict, any remainder below 2.0 causes rounding up.
Note that because this uses REAL and uses division it's only suitable for use during analysis and elaboration. It's a pure function.
You could note Lars example:
constant DATA_OUT_WIDTH : positive := positive(ceil(log2(real(DATA_WIDTH))));
has the same constraints on use for analysis (locally static) and elaboration (globally static). REAL types are generally not supported for synthesis and floating point operations can consume lots of real estate.
The if condition
if ( Pattern == In[i_count-:PATTERN_WIDTH] )
Is a base index (an lsb or msb depending on ascending or descending declared bit order) and a width.
See IEEE Std 1800-2012 (SystemVerilog), 11.5.1 Vector bit-select and part-select addressing.
An indexed part-select is given with the following syntax:
logic [15:0] down_vect;
logic [0:15] up_vect;
down_vect[lsb_base_expr +: width_expr]
up_vect[msb_base_expr +: width_expr]
down_vect[msb_base_expr -: width_expr]
up_vect[lsb_base_expr -: width_expr]
The msb_base_expr and lsb_base_expr shall be integer expressions, and the width_expr shall be a positive constant integer expression. Each of these expressions shall be evaluated in a self-determined context. The lsb_base_expr and msb_base_expr can vary at run time. The first two examples select bits starting at the base and ascending the bit range. The number of bits selected is equal to the width expression. The second two examples select bits starting at the base and descending the bit range.
In VHDL terms this would be a slice with bounds determined from the high index and a width by subtraction.
PATTERN_WIDTH can be globally static (as in a generic constant) as well as locally static (a non-deferred constant). i_count can be variable.
Depending on the declared range of In for example:
constant DATAWIDTH: natural := 8;
signal In_in: std_logic_vector (31 downto 0);
The equivalent expression would be
if Pattern = In_in(i_count downto i_count - DATAWIDTH - 1) then
Note that if the slice length or i_count is less than DATAWIDTH - 1 you'll get a run time error. The - 1 is because In_in'RIGHT = 0.
Without providing the declarations for In (or Pattern) and DATAWIDTH a better answer can't be provided. It really wants to be re-written as VHDL friendly.
Note as Lars indicated in is reserved word (VHDL is not case sensitive here) and the name was changed.

Implement equation in VHDL

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.
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
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.
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.

VHDL code to convert 5 bit vector to integer

I am stuck in the following problem-
I need to write a VHDL function that converts 5 bit vector to integer where integer value of binary number a4a3a2a1a0 can be computed as (((0 + a4)* + a3)* + a2 )* +a1)* +a0.
This is not any homework. But I am preparing for my exams.
Thanks!
If your binary number a4a3a2a1a0 is an std_logic_vector, you can use standard conversion functions:
use IEEE.NUMERIC_STD.ALL;
.
integer_result <= to_integer(unsigned(input_vector));
The NUMERIC_STD library must have been used for this to work.
In many cases it may be possible to use 'unsigned' as the type of the input vector, removing one conversion stage.

How do I create numeric_std signed value greater than 2³¹-1?

In the following type and constant declaration, the last value in the array will not actually be 2**35-1, since integers greater than 2**31-1 are not standard VHDL (2002)
library ieee;
use ieee.numeric_std.all;
-- Boilerplate elided...
constant X_SIZE : natural := 40; -- Really, anything greater than 32
type x_array is array(natural range <>) of signed;
constant XS : x_array := (
to_signed(0, X_SIZE),
to_signed(1, X_SIZE),
to_signed(2**35 - 1, X_SIZE) -- Not possible!
);
I can't do to_signed(2, X_SIZE)**35 - 1 because exponentiation is not defined on signed. I'm loathe to type out the full array because it seems clunky and X_SIZE might change in the future. So how do I create the value I want here? Is there a better way than literally typing out 40 0s and 1s?
Depending on the value, there are a few ways to do it.
Using a hexadecimal literal is good for arbitrary numbers and will save a bit of space: x"1FFFFFFFF"
Aggregate assignment gives a way to specify a pattern (eg. for any size, one zero followed by all ones): (X_SIZE-1 downto 35 => '0', others => '1') — be warned though, if you try to combine this with other operators or functions, the compiler will not be able to infer the required size of the vector. You'll need to do something like: (X_SIZE-1 downto 35 => '1', 35 downto 0 => '0'). At this point you might not be saving much space, but depending on what you're doing, it might make your intent much clearer than a literal.
You can also construct a unit in the desired type, and shift it around: shift_left(to_unsigned(1, X_SIZE), 35) - 1.

Resources