我有这个定义:
subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);
现在在代码中,我想将信号设置为sample_t的最大值除以2:
signal max_sample : sample_t;
max_sample <= to_signed(max_sample'<some attribute>/2,max_sample'LENGTH);
我已经查看了sample_t'HIGH和sample_t'RIGHT属性,但这些属性似乎返回数组的最高下标。
从此列表中:https://www.csee.umbc.edu/portal/help/VHDL/attribute.html
T'HIGH is the highest value of type T.
A'HIGH is the highest subscript of array A or constrained array type.
如何在sample_t上使用第一个定义?
评论者建议之一:
max_sample <= (max_sample'LEFT => '0', others => '1');
有效。但这:
max_sample <= (max_sample'LEFT => '0', others => '1')/2;
失败,显示“ OTHERS是不受约束目标的非法聚合选择”。
为什么会出现此错误?
答案 0 :(得分:1)
在VHDL中,std::sample
是数组类型,而不是整数。核心语言仅知道它是signed
对象的集合。仅按惯例,由numeric_std库函数引入的数字解释为数字,该函数定义std_logic
的运算符和类型强制转换。因此,整数特定的属性将不适用于数组类型。
您最后一次除法尝试失败的原因是,由于signed
,形成股息的汇总表达式尚未完全确定范围。聚合仍然只是一个中间临时数据,无法从others
中提取其长度。这会阻止除法运算符进行编译。
如果使用完全受限制的范围,它将进行编译:
max_sample
或者,如果您使用限定表达式:
max_sample <= (max_sample'high => '0', max_sample'high-1 downto max_sample'low => '1') / 2;
另一种解决方案是仅对max_sample <= sample_t'(max_sample'high => '0', others => '1') / 2;
进行子类型化,而不使用integer
。然后,您可以以更整数的方式使用它:
signed
如果constant SAMPLE_T_MAX : integer := 2**(SAMPLE_WIDTH-1)-1;
subtype sample_t is integer range -SAMPLE_T_MAX-1 to SAMPLE_T_MAX;
max_sample <= sample_t'high; -- Assuming that the "divide by 2" was just to avoid the sign bit
超出了您的工具支持的最大整数大小,该大小通常仍为32位(包括符号),则此方法将无效。另外,出于实际原因,最好不要对合成后将在顶级端口上显示的信号使用整数类型。
否则,您必须在对数字使用数组类型的限制内进行工作。您的选择是如上所述使用位旋转或类似于整数子类型直接计算最大值:
sample_t_max
答案 1 :(得分:1)
凯文·西伯多(Kevin Thibedeau)接受的答案无法与实际问题(为什么会出现这个错误?)相吻合。答案可以用VHDL标准来解释。
首先可以为问题构建Minimum, Complete, and Verifiable example:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity foo is
end entity;
architecture fum of foo is
constant SAMPLE_WIDTH: natural := 42; -- pick a number
subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);
signal max_sample : sample_t;
begin
-- max_sample <= (max_sample'LEFT => '0', others => '1'); -- analyzes
max_sample <= (max_sample'LEFT => '0', others => '1')/2; -- Doesn't analyze
end architecture;
因为在分析(编译)过程中我们要处理语义规则,所以该示例除了复制错误外无需执行任何操作。错误消息未在VHDL中标准化,并且会因实现方式而异。
在聚合中使用其他选项的语义:
IEEE Std 1076-2008 9.3聚合,9.3.3数组聚合,第7段(部分):
具有其他选择的数组集合的索引范围应从上下文中确定。也就是说,具有其他选择的数组集合仅应出现在以下情况之一中: ...
e)作为赋值语句中的值表达式,其中目标是声明的对象(或其成员),并且目标的子类型是完全约束的数组子类型,或者目标是切片名称
这就是第一个示例(注释掉)进行分析的原因。 sample_t是完全受约束的子类型,请参见5。类型,5.1常规完全受约束的的定义,第6段(部分):
如果满足以下条件,则称复合子类型完全受约束:
-它是具有索引约束的数组子类型,而元素子类型不是复合子类型,也不是完全约束的复合类型,或者
...
其中sample_t元素的基本类型为std_ulogic,而子类型具有索引约束。
回到第二个示例。
我们不满足规则e),聚合不是赋值语句的值表达式,而是IEEE软件包numeric_std中用于重载的“ /”函数定义的除法运算符的操作数:
-- Id: A.25
function "/" (L : UNRESOLVED_SIGNED; R : INTEGER) return UNRESOLVED_SIGNED;
-- Result subtype: UNRESOLVED_SIGNED(L'LENGTH-1 downto 0)
-- Result: Divides an UNRESOLVED_SIGNED vector, L, by an INTEGER, R.
-- If NO_OF_BITS(R) > L'LENGTH, result is truncated to L'LENGTH.
(对于numeric_std的早期版本,将对参数和结果类型进行SIGNED而不是UNRESOLVED_SIGNED,-2008正式定义了如何定义复合类型驱动程序的解析函数。)
因为9.3.3第7条的规则是包容性的,而不是排他性的, 需要找到一条允许我们使用聚合的规则,并且很容易找到一个规则:
i)作为限定表达式的操作数,其类型标记表示完全受约束的数组子类型
我们可以使用限定表达式:
max_sample <= sample_t'(max_sample'LEFT => '0', others => '1')/2;
这将成功分析(编译)。
要弄清楚分配给max_sample的值表达式是除以2的结果,该结果使用运算符重载,并且谁的函数没有返回约束子类型。 (不受限制的是UNRESOLVED_SIGNED或SIGNED)。
之所以具有包容性规则,是为了允许在分析时(编译时)确定将值与聚合元素相关联的代码。通过检查VHDL标准的先前版本,您会发现包含规则的列表已得到扩展。
关于第二个示例的问题的答案:
max_sample <= (max_sample'LEFT => '0', others => '1')/2;
是在不从上下文中知道子类型的情况下,无法标识聚合的元素。
如果要查看解析器的输出,该解析器会生成用于语义分析的抽象语法树,则可以在分配语句中的右侧表达可以按层次表示。 (11.6并发信号分配语句,波形由一个或多个波形元素组成,请参见10.5.2简单信号分配,10.5.2.1。一般,波形元素可以包含值表达式,请参见10.5.2.2执行简单的分配语句, 9.表达式,9.1通用BNF。)
使用包含性规则可以减轻在分析过程中遍历表达式层次结构和计算聚合(操作数)子类型的需要,并且需要标准不要求的语义“ /”功能。您还可以构建在分析时无法通过表征轻易确定亚型的情况。结果是在9.3.3数组汇总第7段中找到的规则。
限定表达式直接提供子类型。