【问题标题】:no function declarations for operator运算符没有函数声明
【发布时间】:2018-06-14 16:07:44
【问题描述】:

我收到此错误消息:

testbench.vhd:16:22: 运算符“+”没有函数声明

在这一行:

    Z <= unsigned(X) + resize(unsigned(Y),X'length);

使用此代码:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity MCVE is
end entity MCVE;

architecture MCVE of MCVE is
  signal X, Z : std_logic_vector(15 downto 0);
  signal Y    : std_logic_vector(7 downto 0);
begin

  process    
  begin
    Z <= unsigned(X) + resize(unsigned(Y),X'length);
  end process;

end architecture MCVE;

https://www.edaplayground.com/x/2LBg

我不明白为什么。

【问题讨论】:

  • 不知何故我之前的评论被删除了。所以我会重复一遍:我不明白这一点。您似乎在“伪造”一个问题以发布答案。对我来说,这似乎不是 SO 的用途。 SO 文档因某种原因被关闭。
  • @JHBonarius 还有一个问题说得太糟糕了,以至于需要几个 cmets 才能确定实际问的是什么。一旦确定了这一点,而不是回答电子邮件跟踪,我认为最好重述问题。实际上,提问和回答问题是完全合法的做法:甚至还有一个按钮。

标签: vhdl


【解决方案1】:

错误信息很清楚。运算符“+”没有函数声明,它可以将两个unsigneds 相加并返回一个std_logic_vector。然而,在包numeric_std 中,有一个运算符“+”可以将两个unsigneds 相加并返回一个unsigned

因此,如果您添加另一个类型转换以将加法的结果转换回std_logic_vector,编译器可以选择返回unsigned 的“+”运算符版本。

Z <= std_logic_vector(unsigned(X) + unsigned(Y));

重载只有在恰好有一个适合函数、过程或运算符的情况下才有效。如果少于一个,则编译器没有版本可供选择;如果有多个,编译器不知道选择哪一个,并且有歧义需要解决。

实际上,您不需要调整Y 的大小:只要其中一个操作数与结果的宽度相同,“+”运算符就很高兴。

https://www.edaplayground.com/x/4VJE

【讨论】:

    【解决方案2】:

    虽然 Giwrgos Rizeakos 的原始 question 正在调整大小,但关于运算符和函数重载可见性的问题和答案由来已久(这里没有针对运算符“+”的函数声明)。

    在对这些问题和答案进行搜索后,此答案会尝试提供一个问答对,基于在解释流程中提供权威参考,可用于消除未来重复的问题。

    问题从可见性开始:

    12.3 可见性

    在文本中给定位置出现的标识符的含义由可见性规则定义,在重载声明的情况下,由重载规则定义。本条中考虑的标识符包括除保留字或表示预定义属性的属性指示符之外的任何标识符。本小节中考虑的地方是出现词汇元素(例如标识符)的地方。本小节中考虑的重载声明是用于子程序和枚举字面量的声明。

    对于每个标识符和文本中的每个位置,可见性规则确定一组声明(带有此标识符),这些声明定义了标识符出现的可能含义。当根据可见性规则,声明定义了此事件的可能含义时,则称声明在文本中的给定位置可见。在确定此类声明的含义时会出现以下两种情况:

    ——可见性规则最多确定一个可能的含义。在这种情况下,可见性规则足以确定定义标识符出现的含义的声明,或者在没有这样的声明的情况下,确定该出现在给定点是不合法的。
    — 可见性规则决定了不止一种可能的含义。在这种情况下,当且仅当恰好一个可见声明对于给定上下文中的重载规则是可接受的,或者所有可见声明都表示相同的命名实体时,此时标识符的出现是合法的。

    涉及重载子程序:

    4.5.2 运算符重载

    其指示符是运算符符号的函数的声明用于重载运算符。运算符符号的字符序列应是 9.2 中定义的运算符类别中的运算符之一。

    一元运算符的子程序规范应该有一个参数,除非子程序规范是受保护类型的方法(见 5.6.2)。在后一种情况下,子程序规范不应有参数。二元运算符的子程序规范应具有两个参数,除非子程序规范是受保护类型的方法,在这种情况下,子程序规范应具有单个参数。如果二元运算符的子程序规范有两个参数,则每次使用该运算符时,第一个参数与左操作数相关联,第二个参数与右操作数相关联。

    运算符重载被定义为子程序并使用子程序重载规则:

    4.5 子程序重载

    4.5.1 常规

    当且仅当它们具有相同数量的参数并且在每个参数位置对应的参数具有相同的基本类型时,才称两个形参列表具有相同的参数类型配置文件。当且仅当两个子程序具有相同的参数类型配置文件,并且如果两者都是具有相同结果基类型的函数或两者都不是函数,则称两个子程序具有相同的参数和结果类型配置文件。

    作为一个segue,子程序可以用签名作为简写来描述:

    4.5.3 签名

    签名根据参数和结果类型配置文件区分重载子程序和重载枚举字面量。签名可用于子程序实例化声明、属性名称、实体指示符或别名声明。

    签名 ::= [ [ type_mark { , type_mark } ] [ return type_mark ] ]

    (请注意,初始括号和终止括号是签名语法的一部分,并不表示产生式的整个右侧都是可选的。)据说签名匹配参数和结果类型配置文件当且仅当满足以下所有条件时,给定子程序:

    ——保留字返回之前的类型标记的数量,如果有的话,与子程序的形式参数的数量相匹配。
    — 在每个参数位置,签名的类型标记所表示的基类型与子程序对应的形参的基类型相同。
    — 如果存在保留字return,则子程序是一个函数,并且签名中保留字后面的类型标记的基类型与函数的返回类型的基类型相同,或者保留字return是缺席,子程序是一个过程。

    这里是例子:

    Z <= unsigned(X) + resize(unsigned(Y),X'length);
    

    可以用签名来描述。

    Z 被声明为 std_logic_vector 类型。 “+”的左操作数是 X,它是主题类型转换为无符号的(9.3.6 中给出的规则,两种数组类型,相同的元素类型)。右操作数是通过重载解析在 numeric_std 包中找到签名为 [unsigned, natural, return unsigned] 的调整大小的结果:

    12.5 重载解析的上下文

    为名称、子程序和枚举字面量定义了重载。

    ...

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

    a) 要求名称或表达式具有特定类型或与另一个名称或表达式具有相同类型的任何规则。
    b) 任何要求名称或表达式的类型为某个类的类型的规则;同样,任何要求特定类型为离散、整数、浮点、物理、通用或字符类型的规则。
    ...
    e) 为解决重载子程序调用而给出的规则;用于通用表达式的隐式转换;用于解释具有通用类型边界的离散范围;用于解释前缀表示子程序的扩展名称;对于在子程序实例化声明中命名的子程序来表示未实例化的子程序。
    ...

    并且该函数通过使用 use 子句使 numeric_std 中的声明可见:

    12.4 使用子句

    use 子句实现了通过选择可见的声明的直接可见性。

    在没有找到函数声明的示例上执行相同的重载决议。未找到“+”[unsigned, unsigned return std_logic_vector] 的函数声明,其中返回值必须匹配类型 std_logic_vector(上述 a)规则。

    正如 Matthew Taylor 指出的那样,您可以通过将类型转换为 std_logic_vector 来更改赋值右手 表达式

    Z <= std_logic_vector(unsigned(X) + resize(unsigned(Y),X'length));
    

    为什么不需要 resize 函数调用可以通过引用 IEEE 包 numeric_std 中“+” `[unsigned, unsigned return unsigned] 的函数声明来权威地显示,(在numeric_std-body.vhdl中找到,在@987654323 @这是-2008标准的一部分):

      -- Id: A.3R
      function "+" (L : UNRESOLVED_UNSIGNED; R : STD_ULOGIC)
        return UNRESOLVED_UNSIGNED
      is
        variable XR : UNRESOLVED_UNSIGNED(L'length-1 downto 0) := (others => '0');
      begin
        XR(0) := R;
        return (L + XR);
      end function "+";
    

    权威解释需要在 numeric_std.vhdl 中声明 unsigned (也可以在上述相同的 zip 文件中找到):

       type UNRESOLVED_UNSIGNED is array (NATURAL range <>) of STD_ULOGIC;
    
    
        subtype UNSIGNED is (resolved) UNRESOLVED_UNSIGNED;
    

    它是 unresolved_unsigned 的子类型,提供元素解析函数名称。解析函数在标准中有解释:

    4.6 分辨率函数

    解析函数是定义如何将给定信号的多个源的值解析为该信号的单个值的函数。解析函数与需要解析的信号相关联,方法是在信号声明或信号子类型声明中包含解析函数的名称。具有相关解析函数的信号称为解析信号(参见 6.4.2.3)。

    并且子类型声明语法可能需要找到解析函数:

    6.3 子类型声明

    子类型声明 ::=
    子类型标识符是 subtype_indication ;

    subtype_indication ::=
    [分辨率指示]类型标记[约束]

    分辨率指示 ::=
    分辨率_函数名 | (元素分辨率)

    元素分辨率 ::= 数组元素分辨率 |记录分辨率

    在 std_logic_1164 包声明中找到函数已解析(在上述相同的 zip 文件中,作为标准的一部分提供)。

    分辨率是模拟的问题,请参阅 14.7 模型的执行,特别是 14.7.3 信号值的传播及其将分辨率应用于信号的子条款。

    (关于这里,您会看到为什么会有很多不排除未来问题的不完整答案。在标准中寻找答案需要理解主题,它的主要受众是工具实现者和高级用户,其中 VHDL 语法和语义被简洁地定义允许它用作正式符号。)

    【讨论】:

    • (马修接受他自己的答案并不排除使用这个答案来阻止未来的问题。区别在于相同的问题主题(注意这个标题)和一个可以应用的答案所有它的变体。)
    • 我认为更大的问题是大多数人(/gals)不是 RTFM,因此遇到了同样的问题。他们只想要一些可以复制粘贴的模板/示例。 (我在大学经常遇到这种行为。我们真的必须对评分的家庭作业进行抄袭搜索。)所以对他们来说,这个信息是 TL;DR。
    • 评估 VHDL 课程或书籍的有效性可能比寻找包含过载解决方案要糟糕得多。 VHDL 是strongly-typed,同时包括对用户定义类型的支持和重载解析是强类型的基础;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多