首页 > 解决方案 > VHDL:如何解决此语句:类型 foo 是范围 -(2**30) 到 2**30;?

问题描述

我在处理以下类型声明时遇到问题:

type foo is range -(2**30) to 2**30;

对于幂运算,有两种可能的解释需要考虑:

function "**"(universal_integer, integer) return universal_integer;

function "**"(integer, integer) return integer;

(有使用实数的解释,但我们可以很容易地拒绝那些,因为第一个参数是整数。)

由于求幂的第二个操作数必须是整数,因此使用任一替代方法都需要隐式转换。出于这个原因,我们不能以需要隐式转换为由取消任一选择的资格。

类型声明的边界必须是某种整数类型,但它们不必是相同的类型。如果没有任何进一步的限制,我拒绝这种类型声明是模棱两可的。

这似乎是求幂的一个怪癖。如果我改为:

type foo is range 0 to 2 * 30;

然后你有两个“*”的选择。然而:

function "*"(universal_integer,universal_integer) return universal_integer;

不需要隐式转换,因此我们可以使用它并拒绝另一个。

此外:

constant K: integer := 2 ** 30;

由于结果类型必须是整数的附加约束,也可以正常工作。

但是类型定义和求幂的结合使我们无法获得足够的信息来进行选择。

由于这种类型定义适用于其他实现,我错过了什么?

代表我的实施者.. Ken

标签: vhdlexponentiation

解决方案


为了

类型 foo 的范围是 -(2**30) 到 2**30;

有两个符合条件的“**”函数实现了幂运算符。

9.2.8 杂项运算符

为每个整数类型和每个浮点类型预定义了求幂运算符** 。在任何一种情况下,称为指数的右操作数都是预定义的整数类型。

表 9.2.8

用整数指数取幂相当于将左操作数与自身重复乘以指数的绝对值所指示的次数,从左到右;如果指数为负,则结果是指数绝对值的倒数。只有浮点类型的左操作数才允许使用负指数求幂。以零指数取幂得到值 1。浮点类型的值的取幂是近似的。

预定义类型的预定义运算符在包 STANDARD 中显示为注释。这里适用的两个:

16.3 封装标准

-- 函数 "**" (匿名:universal_integer;匿名:INTEGER)
-- 返回universal_integer;

-- 函数 "**" (匿名: INTEGER; 匿名: INTEGER) -- 返回 INTEGER;

请注意,正确的操作数类型是 INTEGER。右操作数受隐式类型转换的影响。

有两个的原因在 5.2.3 Integer types, 5.2.3.1 General 中找到:

在整数类型定义中使用的范围约束的每个边界应是某个整数类型的局部静态表达式,但两个边界不必具有相同的整数类型。(允许负边界。)

整数文字是匿名预定义类型的文字,在本标准中称为Universal_integer 。其他整数类型没有文字。然而,对于每个整数类型,都存在一个隐式转换,它将universal_integer类型的值转换为整数类型的相应值(如果有的话)(见9.3.6)。

边界必须是某种整数类型,并且可以包括Universal_integer

这两者中的哪一个由 重载决议的上下文基于在 9.3.6 类型转换中找到的语义:

在某些情况下,将执行隐式类型转换。将universal_integer类型的操作数隐式转换为另一种整数类型,或将universal_real类型的操作数隐式转换为另一种浮点类型,只有在操作数是数字文字或属性,或者操作数是由物理类型的值除以相同类型的值组成的表达式;这样的操作数称为可转换通用操作数。当且仅当最里面的完整上下文确定隐式转换的唯一(数字)目标类型时,才应用可转换通用操作数的隐式转换,并且没有此转换就没有此上下文的合法解释。

如果没有其他法律解释,您只能从universal_integer隐式转换为另一种整数类型。这是在重载解决方案的上下文中防止两种可能选择的机制。

对于 2 ** 30 是否必须隐式转换左操作数?不,您是否必须隐式转换正确的操作数?是的,这两种选择都要求类型为 INTEGER。此外,不要求结果是与整数类型定义(5.2.3.1)语义所要求的universal_integer 不同的整数类型。

查看 9.5 通用表达式,这里对整数类型的定义还有一个限制:

对于通用表达式的运算求值,适用以下规则。如果结果是universal_integer类型,则操作数和结果的值应在实现提供的最宽范围的整数类型范围内,不包括universal_integer类型本身。如果结果是universal_real类型,则操作数和结果的值应在实现提供的最大范围的浮点类型范围内,不包括universal_real类型本身。

您无法使用文字来描述值范围大于 INTEGER 类型的整数类型,这是唯一预定义的整数类型 (5.2.3.2)。

还有匿名类型universal_integer的整数文字的限制,其值范围是不可知的。

12.5 重载决议的上下文

在考虑对完整上下文的可能解释时,唯一考虑的规则是语法规则、范围和可见性规则,以及如下形式的规则:

a) ...
e) 解决重载子程序调用的规则;用于通用表达式的隐式转换;用于解释具有通用类型边界的离散范围;用于解释前缀表示子程序的扩展名称;并且对于在子程序实例化声明中命名的子程序来表示未实例化的子程序。
F) ...

我们可以看到 9.3.6 中发现的隐式转换的语义和 9.5 中发现的范围限制。

为了了解如何在提供运算符重载的两个候选函数之间进行选择,可以在 9.3.6 中找到键。

取幂运算符的两个操作数

constant K: integer := 2 ** 30;

可以隐式类型转换为另一种整数类型(INTEGER),而其他通用表达式 2 ** 30 不能隐式转换,不符合 9.3.6 的要求(操作数不是物理类型的值,运算符不是'不是乘法运算符/)。

包 STANDARD 中也提到了重载:

-- 函数 "**" (匿名: INTEGER; 匿名: INTEGER) -- 返回 INTEGER;

Chuck Swart(最后一位 ISAC 主席)在 Issue Report 2073 ( IR2073.txt ) 中将这种行为描述为强制将隐式类型转换为抽象语法树的叶子。用他的话来说,“这个子句意味着隐式转换在表达式树中尽可能向下发生。” 请注意,在重新编写 Accellera VHDL -2006 以符合 IEEE-SA 标准格式之前,9.3.6 是 7.3.5。

可以通过使用显式类型转换来强制将universal_integer转换为另一个整数类型:

constant K: integer := integer(2 ** 30);

注意 "**" 的右操作数,整数文字 30 仍将隐式类型转换为 INTEGER 类型,而左操作数和结果的类型为universal_integer


推荐阅读