ieee.numeric_std?

W

Weng Tianxiang

Guest
Hi,
There are many discussions on the liberaries used in VHDL.

The following are the key points I summirized from many useful
discussions and I would like to adopt in my coding:

-- 02/11/2006
-- 1. Use "use ieee.numeric_std.all", instead of two statements:
-- use ieee.std_logic_unsigned.all;
-- use ieee.std_logic_arith.all;
--
-- 2. All std_logic_vector() are converted to unsigned()
-- 3. When signed() is to be used, use type conversion function
to_integer()

The final remaining question is:
Is unsigend(...) acceptable in interface of entity?

Thank you.

Weng
 
On 11 Feb 2006 07:35:25 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi,
There are many discussions on the liberaries used in VHDL.

The following are the key points I summirized from many useful
discussions and I would like to adopt in my coding:

-- 02/11/2006
-- 1. Use "use ieee.numeric_std.all", instead of two statements:
-- use ieee.std_logic_unsigned.all;
-- use ieee.std_logic_arith.all;
--
-- 2. All std_logic_vector() are converted to unsigned()
-- 3. When signed() is to be used, use type conversion function
to_integer()

The final remaining question is:
Is unsigend(...) acceptable in interface of entity?
You might get a few differing opinions on this one...

My take is that you should use whatever data types make sense for
internal interfaces (e.g. use unsigned if it makes sense), but you
should not use anything other than std_logic or std_logic_vector for
top level ports (i.e. the pins of your chip).

Things gets a little complicated if you are into module reuse, and a
particular module can be compiled either as the whole chip or as a
module instantiated inside another module.
This leads to the use of a "top sheet" which maps your internal data
types to std_logic or std_logic_vector and is also a convenient place
to instantiate your clock buffers, etc.

Regards,
Allan
 
Allan Herriman wrote:

My take is that you should use whatever data types make sense for
internal interfaces (e.g. use unsigned if it makes sense), but you
should not use anything other than std_logic or std_logic_vector for
top level ports (i.e. the pins of your chip).
I mostly agree. For an internal entity,
I will match my variable types, whatever they are.
For the device pin entity I use std_logic_vector
for all vectors, std_logic for inout bits
and std_ulogic for all other bits.
Std_ulogic is 100% compatible with std_logic bits
in port maps and for any other use.
Integer and enumeration types generally cause
pin assignment confusion on the top entity.

Things gets a little complicated if you are into module reuse, and a
particular module can be compiled either as the whole chip or as a
module instantiated inside another module.
If I am making a module for another
designer who already owns the pin entity,
I will match his local bus types, whatever they are.

This leads to the use of a "top sheet" which maps your internal data
types to std_logic or std_logic_vector and is also a convenient place
to instantiate your clock buffers, etc.
Yes, a top wrapper sheet will work in any case.
Synthesis usually handles clock buffers
OK, but things like PLLs or purchased netlists
work well as unbound instances in the
top wrapper.

-- Mike Treseler
 
On Sat, 11 Feb 2006 11:21:25 -0800, Mike Treseler
<mike_treseler@comcast.net> wrote:

Allan Herriman wrote:

My take is that you should use whatever data types make sense for
internal interfaces (e.g. use unsigned if it makes sense), but you
should not use anything other than std_logic or std_logic_vector for
top level ports (i.e. the pins of your chip).

I mostly agree. For an internal entity,
I will match my variable types, whatever they are.
For the device pin entity I use std_logic_vector
for all vectors, std_logic for inout bits
and std_ulogic for all other bits.
Std_ulogic is 100% compatible with std_logic bits
in port maps and for any other use.
For the newbies: the perceived advantage of using std_ulogic instead
of std_logic is that the simulator will flag drivers shorted
together (i.e. multiple drivers on a non-resolved signal) as an error
at compile time.

Using std_logic (a resolved type) means that possibly buggy source
code will compiler ok, and you don't find the error until you simulate
your testbench.
If it gets past your testbench, it will cause the synthesiser to flag
an error, because the synthesiser will only allow multiple drivers on
a signal if the code driving the signal matches a particular template
(which you are rather unlikely to do by accident unless you like using
internal tristate buses).

I have never had a bug caused by accidentally shorted nets in VHDL
(using std_logic) or Verilog, so for me this is not really an
important issue.

Mike: do you have any stats on measured time savings (or losses)
caused by the use of std_ulogic vs std_logic on real world projects?


Integer and enumeration types generally cause
pin assignment confusion on the top entity.
In theory, one could independently synthesise each module using a
synthesiser from a different vendor, which could result in different
encodings for certain datatypes on internal ports.
At the EDIF level, one just has "bits".

Unsigned has a well defined representation, so it should be safe, but
we could argue that enumeration types, records, etc. aren't safe even
for internal ports, unless one also has control over the build scripts
(which is not always the case in a group project, or one being
maintained well after the original design has been completed).

That said, I have often used records for internal ports.

Regards,
Allan
 
Hi Allan,
I will accept your method through my new projects.

One thing you doesn't mention in your posts is why in the top level, we
must insist to use std_logic and std_logic_vector and why unsigined or
signed cannot be used in the top level.

Thank you.

Weng
 
Allan Herriman wrote:

I have never had a bug caused by accidentally shorted nets in VHDL
(using std_logic) or Verilog, so for me this is not really an
important issue.
No it isn't.
For me, it's more a non-conformist style signature
than an important design rule. Note that I don't
use std_ulogic_vector because it does not map cleanly.

Mike: do you have any stats on measured time savings (or losses)
caused by the use of std_ulogic vs std_logic on real world projects?
The only time I have "lost" to this problem was to
write myself an example to show that vcom could
in fact find shorted std_ulogic drivers.
I haven't seen it happen since.

I think that only the uninitiated wire process outputs together,
and not for very long. One of the advantages of a
single process internal entity is that there is no
second process to pick a fight with, so this problem cannot occur.

Integer and enumeration types generally cause
pin assignment confusion on the top entity.

In theory, one could independently synthesise each module using a
synthesiser from a different vendor, which could result in different
encodings for certain datatypes on internal ports.
At the EDIF level, one just has "bits".
Yes. I was assuming a full synthesis and one encoding setting.
It has been my experience that the first guy on the project
gets the top level and does all of the top synthesis during
development.

Unsigned has a well defined representation, so it should be safe,
I think it is.

but
we could argue that enumeration types, records, etc. aren't safe even
for internal ports, unless one also has control over the build scripts
(which is not always the case in a group project, or one being
maintained well after the original design has been completed).
I haven't tried it, but I can't imagine such a mismatch
occurring without at least a warning from synthesis.
In any case, these types are what makes well-written
vhdl code easier to read than some other HDLs.

That said, I have often used records for internal ports.
I think that is commendable.
Thanks for the posting.

-- Mike Treseler
 
On 11 Feb 2006 13:13:58 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi Allan,
I will accept your method through my new projects.

One thing you doesn't mention in your posts is why in the top level, we
must insist to use std_logic and std_logic_vector and why unsigined or
signed cannot be used in the top level.

You may wish to perform a gate level simulation at some stage. The
gate level representation comes from HDL that the back end tools spit
out.
Recall that EDIF (or its equivalent) doesn't keep the type information
- all ports are just "bits", consequently the gate level HDL just has
std_logic type for its ports. The tools are usually clever enough to
group like-named ports into std_logic_vectors where appropriate.

Now imagine plugging this into your testbench. It's not going to work
unless your testbench expects all ports to be std_logic or
std_logic_vector.


There were some other reasons, but I can't think of them right now.

Regards,
Allan
 
On Sat, 11 Feb 2006 13:49:48 -0800, Mike Treseler
<mike_treseler@comcast.net> wrote:

Allan Herriman wrote:

I have never had a bug caused by accidentally shorted nets in VHDL
(using std_logic) or Verilog, so for me this is not really an
important issue.

No it isn't.
For me, it's more a non-conformist style signature
than an important design rule.
You rebel!

:)

Allan
 
On 11 Feb 2006 13:13:58 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi Allan,
I will accept your method through my new projects.

One thing you doesn't mention in your posts is why in the top level, we
must insist to use std_logic and std_logic_vector and why unsigined or
signed cannot be used in the top level.

Thank you.
From the tools point of view, it can - synthesis and simulation of
"signed" and "unsigned" both work perfectly with some tools (Leonardo
Specrtum for synthesis, ModelSim for simulation). However I can't say
whether all tools - Xilinx ISE for example - also work perfectly.

The problem comes later, if you wish to simulate a gate-level version of
the component, (after synthesis, place&route, with the actual timings
back-annotated into the design). At this level, the tools give you an
architecture with all ports using std_logic_vector signals, whether you
like it or not.

This is no longer compatible with the behavioural model, UNLESS you used
std_logic_vector for the top level ports, so it cannot be dropped into
the same testbench to verify that it gives the same simulation results.

You could use a wrapper to convert port types, but it is less complex to
restrict the port types at the top level.

- Brian
 
On 11 Feb 2006 07:35:25 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi,
There are many discussions on the liberaries used in VHDL.

The following are the key points I summirized from many useful
discussions and I would like to adopt in my coding:

-- 02/11/2006
-- 1. Use "use ieee.numeric_std.all", instead of two statements:
-- use ieee.std_logic_unsigned.all;
-- use ieee.std_logic_arith.all;
--
-- 2. All std_logic_vector() are converted to unsigned()
-- 3. When signed() is to be used, use type conversion function
to_integer()
I would suggest a modification of rules 2 and 3 ...
firstly you suggest converting _all_ std_logic_vector to unsigned...
This makes sense for unsigned datapaths, but not for e.g. control signal
buses, and certainly not for signed datapaths!

I use all 3 types; "unsigned" typically forms the bulk in my case, for
unsigned datapaths, "signed" works equally well where the data is
signed, and "std_logic_vector" where the signal is genuinely neither;
e.g. for control signals (which could also be implemented as records)
but also for floating point data (for designs predates the new floation
point work).

This helps clarify the intent of the design.

- Brian
 
Hi,
I am not an expert in synthesis, but absolutely I am confused with all
discussions.

A very simple thing that exists over all CPU software systems become so
complex in the hardware system, unbelievable!

If doing the following ways, I don't think there would be any problems
with any type of signals whether they are on the top level or not.

1. All signal must use std_logic or std_logic_vector system;
2. If unsigned or signed are needed, just add type cast: unsigned() or
signed().

Is there any problem?

In C, you can freely use type cast to transfer what type you want for
the specified data: byte, word, double word, ...and over there there is
no any problem.

Weng
 
Weng Tianxiang wrote:


1. All signal must use std_logic or std_logic_vector system;
2. If unsigned or signed are needed, just add type cast: unsigned() or
signed().

Is there any problem?
If you have many conversions, you code may look not so nice. ;-)

A quick and dirty rule is: Use whatever type you want, but use
std_(U)logic(_vector) for your entities (or at least your top entity).

My way of coding is:
* std_ulogic(_vector) for normal signals (including I/O)
* std_logic(_vector) for tri-state signals (including I/O)
* unsigned / signed if I need arithmetics
* integer for special purposes
* float, time ... for testbenches

Ralf
 
Hi Brian,
The first post is my initial idea. Through many discussions of this
post, I found a new set of rules are much better than the first set and
I abandom the first set of rules.

New set of rules:
1. All signals are std_logic or std_logic_vector;
2. Use "use ieee.numeric_std.all", instead of two statements:
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.
4. If signed operations are heavily used, specify new signals with same
but signed data.

Here is an example:
signal A : std_logic_vector(3 downto 0);
signal B : std_logic_vector(3 downto 0);

if A, B are not very often used, for the following equations, we can
do:
if(to_integer(A) > to_integer(B)) then

It is a signed comparison.

If A, B are used heavily, do the following:
1. Add two signal names
signal Asigned : signed(3 downto 0);
signal Bsigned : signed(3 downto 0);

2. Add assignment equations to make them equal to original data without
adding to_integer() later.
Asigned <= to_integer(A);
Bsigned <= to_integer(B);

then where A and B are used as signed data, use Asigned and Bsigned.

By doing that way, one never has to pay attention to whether or not the
module is at the top level.

My practice told me that the simplest form of anythings works best.

Any comments?

Weng
 
On 12 Feb 2006 07:35:56 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi Brian,
The first post is my initial idea. Through many discussions of this
post, I found a new set of rules are much better than the first set and
I abandom the first set of rules.

New set of rules:
1. All signals are std_logic or std_logic_vector;
2. Use "use ieee.numeric_std.all", instead of two statements:
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.
4. If signed operations are heavily used, specify new signals with same
but signed data.

Here is an example:
signal A : std_logic_vector(3 downto 0);
signal B : std_logic_vector(3 downto 0);

if A, B are not very often used, for the following equations, we can
do:
if(to_integer(A) > to_integer(B)) then

It is a signed comparison.

If A, B are used heavily, do the following:
1. Add two signal names
signal Asigned : signed(3 downto 0);
signal Bsigned : signed(3 downto 0);

2. Add assignment equations to make them equal to original data without
adding to_integer() later.
Asigned <= to_integer(A);
Bsigned <= to_integer(B);

then where A and B are used as signed data, use Asigned and Bsigned.

By doing that way, one never has to pay attention to whether or not the
module is at the top level.
The vast majority of your modules *won't* be at the top level.
I recommend using either signed or unsigned types if you need to
perform arithmetic.

Regards,
Allan
 
Weng Tianxiang a écrit:
3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.
Here is an example:
signal A : std_logic_vector(3 downto 0);
signal B : std_logic_vector(3 downto 0);
if A, B are not very often used, for the following equations, we can
do:
if(to_integer(A) > to_integer(B)) then
No you can't. to_integer only accepts a signed or unsigned parameter,
not std_logic_vector.
I think you want to use a type cast (signed, if I understand your
point) instead.

Nicolas
 
On 12 Feb 2006 07:35:56 -0800, "Weng Tianxiang" <wtxwtx@gmail.com>
wrote:

Hi Brian,
The first post is my initial idea. Through many discussions of this
post, I found a new set of rules are much better than the first set and
I abandom the first set of rules.

New set of rules:
1. All signals are std_logic or std_logic_vector;
Allowing signed or unsigned where appropriate is better;
(it is not appropriate for top level ports as discussed elsewhere)

2. Use "use ieee.numeric_std.all", instead of two statements:
Definitely.

use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.
Not quite. "to_integer" on std_logic_vector would be ambiguous because
nothing tells it whether the std_logic_vector is signed or not; so it is
not permitted with the standard libraries.

"unsigned()" or "signed()" specifically gives you the right
interpretation of the data; if you really need a signed integer, then
"to(integer(signed())" will do it.

4. If signed operations are heavily used, specify new signals with same
but signed data.

Here is an example:
signal A : std_logic_vector(3 downto 0);
signal B : std_logic_vector(3 downto 0);

if A, B are not very often used, for the following equations, we can
do:
if(to_integer(A) > to_integer(B)) then

It is a signed comparison.
No, it won't work, because to_integer is ambiguous as above.

If A, B are used heavily, do the following:
1. Add two signal names
signal Asigned : signed(3 downto 0);
signal Bsigned : signed(3 downto 0);

2. Add assignment equations to make them equal to original data without
adding to_integer() later.
Asigned <= to_integer(A);
Bsigned <= to_integer(B);

then where A and B are used as signed data, use Asigned and Bsigned.
AAAH! I think I see the problem ... you are coming to VHDL from C, and
so it seems to you that "signed" and "unsigned" are varieties of integer
as they are in C.

Not so.

Think of them as subclasses of std_logic_vector, which inherit most of
the properties of std_logic_vector AND add _some_ properties inherited
from signed (or unsigned) integers. So you don't need the
std_logic_vector versions of these signals; signed or unsigned gives you
those properties too.

For example,

signal A,B : signed(37 downto 0);
A is very like a std_logic_vector 38 bits long, so it doesn't have
restrictions on word length like an integer would (in C or VHDL), and
you can still extract bits or ranges from it, perform logical operations
on it, etc. But if you assign it to a std_logic_vector (or an unsigned)
you have to cast it to the correct type.

if A(37) = '1' then -- A is negative
A(36 downto 0) <= (others => '0'); -- you can manipulate bits
end if;

But it also "inherits" arithmetic operations such as addition,
subtraction and multiplication. (Division is more difficult!)
Arithmetic is permitted between integer and signed, and between natural
and unsigned. The same applies to comparison operations.

signal S : signed(37 downto 0);
Signal U : unsigned(37 downto 0);
signal S_safe : signed(38 downto 0);
signal SLV : std_logic_vector(37 downto 0);

S <= A + B + 27; -- mix signed and integer
U <= unsigned(A + B); -- cast to unsigned
S_safe <= A(37) & A + B(37) & B; -- sign extend to prevent overflow
-- alternatively S_safe <= RESIZE(A,39) + RESIZE(B,39);
SLV <= std_logic_vector(S);

Inheritance is not strictly correct but it's a useful way of looking at
it.

For the full definition of operations permitted on std_logic_vector and
numeric_std, you can look at the ieee.std_logic_vector and
ieee.numeric_std packages.

By doing that way, one never has to pay attention to whether or not the
module is at the top level.
An alternative view: there is only one top level.
It is trivial to write a wrapper to perform the appropriate conversion
of port types ONCE at the top level and pass the signals on to an
identical module with the correct port types for internal use.

My practice told me that the simplest form of anythings works best.
Indeed ... and this is an area of VHDL worth understanding. You are
still trying to fight the type system, instead of letting it do the work
for you.

The simplest form makes the expressions simple and clear, instead of
peppered with type casts and conversions.

Using signed or unsigned, you don't need two versions of the data - you
get both sets of properties in the same type.

- Brian
 
Weng Tianxiang wrote:

3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.
Don't use integers at all except for constant values. For signed
arithmetic use the type "signed", that's what it is for. All arithmetic
operations are overloaded for "signed" in numeric_std.

Example:

Z <= A + B; -- A, B, Z are signed
Z <= std_logic_vector(signed(A) + signed(B)); -- A, B, Z are
std_logic_vector

The reason why not to use integer is that it is defined as a 32 bit
signed vector. If you happen to have operands that are wider than 32
bits, the use of integer fails. If your operands are shorter than 32,
there is the potential risk that the synthesis results are not optimal
because 32-bit operations are implemented instead of shorter ones.

Reto
 
Reto Zimmermann <reto@nospam.com> writes:

Weng Tianxiang wrote:

3. If signed operations are used not very often, add to_integer() to
change their types to meet operational requirements.

Don't use integers at all except for constant values. For signed
arithmetic use the type "signed", that's what it is for. All arithmetic
operations are overloaded for "signed" in numeric_std.
Reto is too modest to mention his paper on related issues, so I'll
do it for him:

http://www.synopsis.com/products/designware/dwtb/articles/coding_guidelines/coding_guidelines.html

Cheers,
Colin
 
Hi,
Reto paper is excellent.

Another question is unanswered:

Why unsigned/signed cannot be used in top layer? and why the signals in
the top layer must be std_logic and std_logic_vector?

Thank you.

Weng
 
Reto Zimmermann wrote:
The reason why not to use integer is that it is defined as a 32 bit
signed vector.
No, it isn't. It is defined as an integer with a range of at least
-2147483647 to +2147483647. The implementation could be anything with
suitable semantics. It could be stored as ten BCD digits and a sign bit.
It could be pseudo-ternary. It could be a list of prime numbers whose
sum is the value in question. The standard does NOT define how an
integer is stored or implemented.

Nor can you assume that a VHDL integer type can store ONLY 32-bit values.
It may be larger.

Nor can you assume that a VHDL integer type can store ALL 32-bit twos
complement integer values. It might not be able to store
-2147483648, which is a valid 32-bit twos complement value.

See section 3.1.2 of IEEE 1076-2000. (I don't have a copy of 1076-2002,
but I don't expect that the definition of the integer type is likely
to have changed significantly.)
 

Welcome to EDABoard.com

Sponsor

Back
Top