2

Could someone please explain me how VHDL's to_unsigned works or confirm that my understanding is correct? For example:

C(30 DOWNTO 0) <= std_logic_vector (to_unsigned(-30, 31))

Here is my understanding:

  • -30 is a signed value, represented in bits as 1111111111100010
  • all bits should be inverted and to it '1' added to build the value of C
  • 0000000000011101+0000000000000001 == 0000000000011111
Paebbels
  • 15,573
  • 13
  • 70
  • 139
Sasa Stamenkovic
  • 85
  • 1
  • 2
  • 9

2 Answers2

5

In IEEE package numeric_std, the declaration for TO_UNSIGNED:

  -- Id: D.3
  function TO_UNSIGNED (ARG, SIZE: NATURAL) return UNSIGNED;
  -- Result subtype: UNSIGNED(SIZE-1 downto 0)
  -- Result: Converts a non-negative INTEGER to an UNSIGNED vector with
  --         the specified SIZE.

You won't find a declared function to_unsigned with an argument or size that are declared as type integer. What is the consequence?

Let's put that in a Minimal, Complete, and Verifiable example:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity what_to_unsigned is
end entity;

architecture does of what_to_unsigned is
    signal C:   std_logic_vector (31 downto 0);
begin

    C(30 DOWNTO 0) <= std_logic_vector (to_unsigned(-30, 31));

end architecture;

A VHDL analyzer will give us an error:

ghdl -a what_to_unsigned.vhdl
what_to_unsigned.vhdl:12:53: static constant violates bounds
ghdl: compilation error

And tell us -30 (line 12:character 53) has a bounds violation. Meaning in this case the numerical literal converted to universal_integer doesn't convert to type natural in the function to_unsigned.

A different tool might tell us a bit more graphically:

nvc -a what_to_unsigned.vhdl  
** Error: value -30 out of bounds 0 to 2147483647 for parameter ARG  
  File what_to_unsigned.vhdl, Line 12  
        C(30 DOWNTO 0) <= std_logic_vector (to_unsigned(-30, 31));  
                                                        ^^^

And actually tells us where in the source code the error is found.

It's safe to say what you think to_unsigned does is not what the analyzer thinks it does.

VHDL is a strongly typed language, you tried to provide a value to place where that value is out of range for the argument ARG in function TO_UNSIGNED declared in IEEE package numeric_std.

The type NATURAL is declared in package standard and is made visible by an inferred declaration library std; use std.standard.all; in the context clause. (See IEEE Std 1076-2008, 13.2 Design libraries):

Every design unit except a context declaration and package STANDARD is assumed to contain the following implicit context items as part of its context clause:

library STD, WORK; use STD.STANDARD.all;

The declaration of natural found in 16.3 Package STANDARD:

subtype NATURAL is INTEGER range 0 to INTEGER'HIGH;

A value declared as a NATURAL is a subtype of INTEGER that has a constrained range excluding negative numbers.

And about here you can see you have the ability to answer this question with access to a VHDL standard compliant tool and referencing the IEEE Std 1076-2008, IEEE Standard VHDL Language Reference Manual.

The TL:DR; detail
You could note that 9.4 Static expressions, 9.4.1 General gives permission to evaluate locally static expressions during analysis:

Certain expressions are said to be static. Similarly, certain discrete ranges are said to be static, and the type marks of certain subtypes are said to denote static subtypes.

There are two categories of static expression. Certain forms of expression can be evaluated during the analysis of the design unit in which they appear; such an expression is said to be locally static. Certain forms of expression can be evaluated as soon as the design hierarchy in which they appear is elaborated; such an expression is said to be globally static.

There may be some standard compliant tools that do not evaluate locally static expressions during analysis. "can be" is permissive not mandatory. The two VHDL tools demonstrated on the above code example take advantage of that permission. In both tools the command line argument -a tells the tool to analyze the provided file which is if successful, inserted into the current working library (WORK by default, see 13.5 Order of analysis, 13.2 Design libraries).

Tools that evaluate bounds checking at elaboration for locally static expressions are typically purely interpretive and even that can be overcome with a separate analysis pass.

The VHDL language can be used for formal specification of a design model used in formal proofs within the bounds specified by Annex D Potentially nonportable constructs and when relying on pure functions only (See 4.Subprograms and packages, 4.1 General).

VHDL compliant tools are guaranteed to give the same results, although there is no standardization of error messages nor limitations placed on tool implementation methodology.

Community
  • 1
  • 1
4

to_unsigned is for converting between different types:

signal i : integer := 2;
signal u : unsigned(3 downto 0);

...

u <= i;  -- Error, incompatible types
u <= to_unsigned(i, 4); -- OK, conversion function does the right thing

If you try to convert a negative integer, this is an error.

u <= to_unsigned(-2, 4); -- Error, does not work with negative numbers

If you simply want to invert an integer, i.e. 2 becomes -2, 5 becomes -5, just use the - operator:

u <= to_unsigned(-i, 4);  -- OK as long as `i` was negative or zero

If you want the absolute value, a function for this is provided by the numeric_std library.

u <= to_unsigned(abs(i), 4);
scary_jeff
  • 4,314
  • 13
  • 27