Is integer overflow defined in VHDL?

Bill Lynch picture Bill Lynch · Nov 19, 2012 · Viewed 12k times · Source

I was wondering if integer overflow is defined in VHDL. I wasn't able to find anything in the 2002 Specification.

As an example (Note, this might not compile, it's just a generic example...):

entity foo is port (
    clk : std_logic
);
end entity;

architecture rtl of foo is
    signal x : integer range 0 to 2 := 0;
begin
    process (clk)
    begin
        if rising_edge(clk) then
            x <= x + 1;
        end if;
    end process;
end architecture;

It's clear that x will go from 0 to 1, and then to 2. Is it defined what will happen on the next increment? Is that undefined behavior?

Answer

user1155120 picture user1155120 · Nov 21, 2012

for a test bench for rtl of foo in ghdl:

ghdl -r foo_tb --wave=foo_tb.ghw
./foo_tb:error: bound check failure at foo_tb.vhdl:15
./foo_tb:error: simulation failed

I added a context clause to Bill's foo entity and architecture:

library ieee;
use ieee.std_logic_1164.all;

entity foo is port (

Line 15 is the signal assignment to x:

            x <= x + 1;

This is a simulation error (occurs at runtime).

From IEEE 1076-1993:

7.2.4 Adding operators

The adding operators + and - are predefined for any numeric type and have their conventional mathematical meaning.

This means the result of the "+" operator can be outside the subtype constraint of x. Note that a function declared to provide an overload for the "+" is not allowed to specify the result subtype. (The returned value may be an object declared with a subtype indication, which can define the value range or an array length).

and 12.6.2 Propagation of signal values

In order to update a signal during a given simulation cycle, the kernel process first determines the driving and effective values of that signal. The kernel process then updates the variable containing the current value of the signal with the newly determined effective value, as follows:

a) If S is a signal of some type that is not an array type, the effective value of S is used to update the current value of S. A check is made that the effective value of S belongs to the subtype of S. An error occurs if this subtype check fails. Finally, the effective value of S is assigned to the variable representing the current value of the signal.

If the result of the addition doesn't match the subtype constraint of the target x it will generate an error. That subtype constraint is provided by the object x declaration which provides a subtype indication for an integer (the range).

A run-time error causes the simulation to terminate for an LRM compliant implementation.

Without a standardized format for error reporting ghdl does not provide the current simulation time. That can be found be examining the produced waveform:

foo_tb.png

The waveform quite being updated after 20 ns. The next scheduled event:

library ieee;
use ieee.std_logic_1164.all;

entity foo_tb is
end entity;

architecture foo of foo_tb is
    signal clk: std_logic := '0';
begin
DUT:
    entity work.foo
        port map (
            clk => clk
        );
        
CLOCK:
    process
    begin
        wait for 5 ns;
        clk <= not clk;
        if now > 30 ns then
            wait;
        end if;
    end process;
    
end architecture;

would have been the rising edge of clk at 25 ns.

So this tells us how a constrained integer produces an overflow error.

What about an integer without a subtype constraint:

architecture fum of foo is
    signal x : integer := INTEGER'HIGH - 2;
begin
    process (clk)
    begin
        if rising_edge(clk) then
            x <= x + 1;
        end if;
    end process;
end architecture;

We define x as an unconstrained integer set it's default value where we expect x to overflow.

Package standard explicity declares INTEGER "+":

--  function "+"      (anonymous, anonymous: INTEGER) return INTEGER;

The expected result is outside the range of INTEGER if as we see "+" has it's ordinary mathematical meaning.

However, from the implementation dependent declaration in package standard:

type integer is range -2147483648 to 2147483647;

and simulation:

foo_tb_wrap_around.png

We see the value of x wrap around.

The assignment of the "+" operator result violated no constraint:

3 Types:

The set of possible values for an object of a given type can be subjected to a condition that is called a constraint (the case where the constraint imposes no restriction is also included); a value is said to satisfy a constraint if it satisfies the corresponding condition. A subtype is a type together with a constraint. A value is said to belong to a subtype of a given type if it belongs to the type and satisfies the constraint; the given type is called the base type of the subtype. A type is a subtype of itself; such a subtype is said to be unconstrained (it corresponds to a condition that imposes no restriction). The base type of a type is the type itself.

In our second architecture and there is no constraint but there are no possible values outside the declared range for type INTEGER. The value instead rolls over.

The semantics for VHDL have been constructed to not require detection here and this matches mathematical operations on single dimensional arrays of elements representing binary bits (hardware).