8

我想知道是否在 VHDL 中定义了整数溢出。我无法在 2002 规范中找到任何内容。

作为一个例子(注意,这可能无法编译,它只是一个通用的例子......)

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;

很明显,x它将从 0 变为 1,然后变为 2。它是否定义了下一个增量会发生什么?那是未定义的行为吗?

4

3 回答 3

6

对于 ghdl 中 foo 的 rtl 的测试台:

ghdl -r foo_tb --wave=foo_tb.ghw
./foo_tb:error: foo_tb.vhdl:15 的边界检查失败
./foo_tb:error: 模拟失败

我在 Bill 的 foo 实体和架构中添加了一个上下文子句:

library ieee;
use ieee.std_logic_1164.all;

entity foo is port (

第 15 行是对 x 的信号分配:

            x <= x + 1;

这是一个模拟错误(发生在运行时)。

来自 IEEE 1076-1993:

7.2.4 添加运算符

加法运算符 + 和 - 是为任何数字类型预定义的,并具有其传统的数学含义。

这意味着“+”运算符的结果可以在 x 的子类型约束之外。请注意,声明为“+”提供重载的函数不允许指定结果子类型。(返回值可以是声明了子类型指示的对象,可以定义取值范围或数组长度)。

和 12.6.2 信号值的传播

为了在给定的仿真周期内更新信号,内核进程首先确定该信号的驱动值和有效值。然后内核进程用新确定的有效值更新包含信号当前值的变量,如下所示:

a) 如果 S 是某种非数组类型的信号,则 S 的有效值用于更新 S 的当前值。检查 S 的有效值是否属于 S 的子类型。如果此子类型检查失败,则会发生错误。最后,将 S 的有效值赋给代表信号当前值的变量。

如果添加的结果与目标 x 的子类型约束不匹配,则会产生错误。该子类型约束由 object x 声明提供,该声明为整数(范围)提供子类型指示。

对于符合 LRM 的实现,运行时错误会导致仿真终止。

如果没有用于错误报告的标准化格式,ghdl 不提供当前模拟时间。可以通过检查生成的波形找到:

foo_tb.png

波形在 20 ns 后完全更新。下一个预定活动:

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;

将是 25 ns 处 clk 的上升沿。

所以这告诉我们一个受约束的整数是如何产生溢出错误的。

没有子类型约束的整数怎么样:

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;

我们将 x 定义为一个不受约束的整数集,它是我们期望 x 溢出的默认值。

包标准明确声明 INTEGER "+":

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

如果我们看到“+”具有普通的数学含义,则预期结果超出 INTEGER 的范围。

但是,从包标准中的实现依赖声明:

type integer is range -2147483648 to 2147483647;

和模拟:

foo_tb_wrap_around.png

我们看到 x 的值环绕。

“+”运算符结果的赋值没有违反约束:

3 种类型:

给定类型的对象的可能值集合可以受到称为约束的条件(也包括约束不施加限制的情况);如果一个值满足相应的条件,则称该值满足约束。子类型是带有约束的类型。如果一个值属于该类型并满足约束,则称该值属于给定类型的子类型;给定类型称为子类型的基本类型。类型是其自身的子类型;这样的子类型被称为不受约束的(它对应于不施加限制的条件)。类型的基类型是类型本身。

在我们的第二个架构中,没有任何约束,但在声明的 INTEGER 类型范围之外没有可能的值。相反,该值会翻转。

VHDL 的语义已构建为不需要在此处检测,这与表示二进制位(硬件)的元素的一维数组上的数学运算相匹配。

于 2012-11-20T23:06:51.523 回答
3

任何体面的模拟器都会停在那里,并显示一条错误消息,该错误消息正好指向溢出的加法。(如果您记得打开检查,Xilinx Isim 只是一个不错的模拟器,我上次查看时)

如果这些年来你做了太多的 C 编程,那就太可怕了!

合成将做任何节省硬件的事情,(在这种情况下,没有输出,优化 X 和过程完全消失!)所以最好在模拟中捕获这种错误。

于 2012-11-19T08:53:33.910 回答
2

整数上溢(和下溢)是 VHDL 中实现定义的行为。我目前无法引用规范,但如果您仔细阅读,您会发现几乎所有关于整数范围的内容都是实现定义的,超出了最小支持范围(-2**31to 2**31)。

32 位机器上的大多数 VHDL 实现实际上表现得好像它们是 32 位 2 的补全整数(例如机器整数在这些平台上的行为),而 64 位实现通常具有 64 位整数,但你不能指望这个.

对于您的具体示例,如果您使用具有范围的整数子类型,如果您尝试分配该范围之外的值,则会出现错误,并将在运行时生成断言。(另一方面,合成器会做他们想做的任何奇怪的事情——通常它们会溢出,就好像它是一个 2 的补码整数一样)。

于 2012-11-19T04:51:29.100 回答