Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

Arithmetic using numeric std

Dr DC Hendry

March 1, 2006

1 Operators in VHDL
1. VHDL takes a very similar approach to the definition of operators as other
modern programming languages. If we assume that the variables x, y and
z are of type integer, then the expression:

z := x + y;

2. is interpreted by the compiler as a call to a function, specifically:

z := +(x, y);

3. The same mechanism applies to operators such as *, - and so on.

A second feature of modern programming languages is the use of function over-


loading. This allows a number of functions to be defined with the same name.
Which function is referred to in a call to such functions is determined by the
number of arguments and the type of the arguments. Assume that we have de-
fined two functions:

function +(integer, integer) returns integer;


function +(real, integer) returns real;

then an expression such as 3 + 4 is interpreted as a call to the first function, and


an expression such as 3.0 + 4 is interpreted as a call to the second function.
numeric std

2 Types Signed and Unsigned

If we looked at the various functions supplied by a VHDL system we would find


that functions such as that above are available. There is however no function
named + that takes arguments of type bit vector or of type std logic vector.
Thus if we have defined a, b and c as of type std logic vector, the expression:

c <= a + b;

is undefined and would give rise to a compile time error.

It would seem that we should be able to write a function which does define
the function + with arguments of type std logic vector. While this could
be done, the approach taken with VHDL is to define two alternative forms of
std logic vector called signed and unsigned. Definitions of the operators
+, -, * and so on are then given for arguments of these two types. The
definitions of the types signed and unsigned are simply:

type signed is array(natural range <>) of std_logic;


type unsigned is array(natural range <>) of std_logic;

Both of which are of course identical to the definition of type std logic vector.
The crucial point is that we can now define functions such as +(unsigned,
unsigned) and +(signed, signed). As you might expect the type signed
defines the various arithmetic functions assuming that the bit pattern represents
a 2s complement signed number, whereas type unsigned assumes a bit pattern
for unsigned binary numbers.

These definitions are included in the package numeric std, which is to be found
in the library ieee.

2.1 Type Conversions

Since VHDL is a strongly typed language, there are next to no built in type
conversions. All such conversions must be explicitly called for by the designer.
Even although types std logic vector, signed and unsigned are identically
defined they are nevertheless considered as different types. Given that each
however is an array of the same basic element type (that is each is an array
of std logic), VHDL permits the type conversions to be specified by simply
giving the name of the required type. This is shown in the following code for

Revision : 1.2 Page 2 of 8 Dr DC Hendry


numeric std

an adder design:

library ieee;
use ieee.std logic 1164.all;
use ieee.numeric std.all;

entity adder is
generic(N : integer);
port(a, b : in std logic vector(N 1 downto 0);
y : out std logic vector(N 1 downto 0));
end entity adder;

architecture rtl of adder is


signal as, bs, ys : signed(N 1 downto 0);
begin
as <= signed(a);
bs <= signed(b);
ys <= as + bs;
y <= std logic vector(ys);
end architecture rtl;

The statement as <= signed(a); converts the signal a from type std logic value
to type signed, similarly for the statement bs <= signed(b);. Note that at
synthesis time both of these statements imply no hardware, they simply ensure
that the VHDL code meets the requirements of the typing rules.

The statement ys <= as + bs; carries out the addition assuming that both bit
patterns represent signed numbers. Finally, the statement y <= std logic vector(ys);
converts the result (again no actual processing is involved) to type std logic vector.

One might ask, why not make the arguments of the adder design of type signed
rather than of type std logic vector. The answer is that as yet, not all of
the additional tools available with synthesis systems support all types on design
ports. This situation may change with time.

3 Conversion to/from Integers

It is often useful to convert from any of the vectors of std logic, that is,
types signed, unsigned or std logic vector to type integer. This is useful

Revision : 1.2 Page 3 of 8 Dr DC Hendry


3.1 Conversion to Integer numeric std

in a variety of situations. In testbenches data may be read from control files


in integer format and then converted to a std logic vector bit pattern for
application to the device under test. In a synthesisable design the use of integers
derived from a vector of std logic as indices into a data array can provide
highly readable designs that specify the required behaviour rather than the
means of implementation.

3.1 Conversion to Integer

Before a conversion to integer can take place, the encoding of the source bit
pattern is needed. This is specified by indicating that the source is of type
signed for 2s complement numbers, or unsigned for the natural numbers.

Consider the following skeleton code:

signal sgnd : signed(15 downto 0);


signal usgnd : unsigned(15 downto 0);
signal slvtr : std_logic_vector(15 downto 0);
signal intgr : integer;
.
.
intgr <= to_integer(sgnd); -- OK
intgr <= to_integer(usgnd); -- OK
intgr <= to_integer(slvtr); -- FAILS
intgr <= to_integer(signed(slvtr)); -- OK, treats as signed.
intgr <= to_integer(unsigned(slvtr)); -- OK, treats as unsigned.

3.2 Conversion from Integer

In converting from integer to a vector of std logic it is necessary to specify the


number of bits required in the conversion. Again a direct conversion from type
integer to type std logic vector is not possible, again an intermediate type,
either signed or unsigned must be used to specify the format of the conversion.
Here is example code:

signal sgnd : signed(15 downto 0);


signal usgnd : unsigned(15 downto 0);
signal slvtr : std_logic_vector(15 downto 0);
signal intgr : integer;
.
.

Revision : 1.2 Page 4 of 8 Dr DC Hendry


numeric std

sgnd <= to_signed(intgr, 16); -- 16 bit conversion.


usgnd <= to_unsigned(intgr, usgndlength); -- better coding
slvtr <= std_logic_vector(to_signed(intgr, sgndlength)); -- OK!
slvtr <= std_logic_vector(to_unsigned(intgr, usgndlength)); -- OK

4 The resize function

Consider again the basic adder statement:

signal a, b, c : signed(15 downto 0);


.
.
c <= a + b;

When two 16 bit numbers, such as a and b above, are added the resulting
number could require 17 bits to represent it. In the vast majority of designs
however two 16 bit numbers are added to give a 16 bit result, with overflow
being regarded as a run time error. The numeric std package returns a result
of the same length as the longest of the two operands.

Situations can arise however where the designer wishes to take closer control over
the number of bits in a representation, or it is necessary to add for example an
8-bit number to a 16-bit number. The function resize is then useful. The resize
functions are used to truncate or extend values of type signed or unsigned.
The function takes two arguments, the first is the signal or variable to resize, and
the second is the size to resize it to. This should be a constant for synthesisable
code. There are actually two versions of resize, one for signed signals or
variables, and the second for unsigned signals or variables. The usual function
overloading mechanism chooses between the two.

There are essentially four situations:

1. Extend a signed number.


2. Extend an unsigned number.

3. Truncate a signed number.


4. Truncate an unsigned number.

Revision : 1.2 Page 5 of 8 Dr DC Hendry


4.1 Extending a Signed Number numeric std

4.1 Extending a Signed Number

With 2s complement format the leftmost bit, the most significant bit, is the
sign bit. When extending the number it is necessary to copy this bit to all bits
left of the original position, here is the code for this, and a diagram of the bit
movements:

signal a : signed(7 downto 0);


signal x : signed(15 downto 0);
.
.
x <= resize(a, xlength);

msb lsb
1 1 0 0 1 0 1 0
sign bit

1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0

4.2 Extending an Unsigned Number

With unsigned numbers the additional bits should all be set to zero, again code
and diagram of the bit movements:

signal a : unsigned(7 downto 0);


signal x : unsighed(15 downto 0);
.
.
x <= resize(a, xlength);

msb lsb
1 0 1 1 1 1 0 0
0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0

4.3 Truncating a Signed Number

When truncating number we cannot be certain that the truncated number will
have the same value as the original number, unless we know that the high bits to

Revision : 1.2 Page 6 of 8 Dr DC Hendry


4.4 Truncating an Unsigned Number numeric std

be discarded are all 0s for a positive number, and 1s for a negative number.
Presumably the designer knows this to be case on some other grounds. To
preserve the sign of the number the sign bit is copied from the high bit of the
longer number to the sign bit of the shorter number.

signal a : signed(7 downto 0);


signal x : signed(15 downto 0);
.
.
a <= resize(x, alength);

msb discarded lsb

1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1

sign
bit
1 0 1 0 0 0 1 1

4.4 Truncating an Unsigned Number

Again we need to know that the high bits to be discarded are all zeros.

signal a : unsigned(7 downto 0);


signal x : unsigned(15 downto 0);
.
.
a <= resize(x, alength);

msb
discarded lsb

0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 1

1 0 1 1 0 1 1 1

5 Other Arithmetic Packages

In addition to the package numeric std, IEEE also provide the package numeric bit.
Prior to standardisation of the numeric std pack various synthesis tool ven-
dors developed their own packages to provide the functionality now provided

Revision : 1.2 Page 7 of 8 Dr DC Hendry


5.1 numeric bit numeric std

by numeric std. In some companies these vendor specific packages have been
adopted over numeric std, and you will very likely come across code using the
package std logic arith.

5.1 numeric bit

The package numeric bit provides much the same facilities as package numeric std
but uses vectors in which each element is of type bit. Unlike numeric std, the
designer cannot specify dont cares or high impedance, and so tristate buses
cannot be synthesised.

5.2 std logic arith

This package is not standardised. The original std logic arith package was
written by Synopsys Corporation for use with their synthesis tools. The facil-
ities provided by the package are very similar to those in numeric std, types
unsigned and signed are declared and then used to provide (usually synthe-
sisable) descriptions of various operators. The package is also supplied by a
variety of other vendors, including Cadence in slightly different forms. This
does complicate use of the package when working with CAD tools for a variety
of vendors (for example, simulation from Cadence, synthesis from Synopsys).

Conversion between vector types is identical, but conversion to/from integers is


handled differently.

Revision : 1.2 Page 8 of 8 Dr DC Hendry

You might also like