在 VHDL 中实现方程

Implement equation in VHDL

我正在尝试在 VHDL 中实现方程式,其中乘以某个常数和加法。等式如下,

  y<=-((x*x*x)*0.1666)+(2.5*(x*x))- (21.666*x) + 36.6653;   ----error

我收到错误消息

     HDLCompiler:1731 - found '0' definitions of operator "*",  
     can not determine exact overloaded matching definition for "*".

实体是

    entity eq1 is
        Port ( x : in  signed(15 downto 0);
               y : out signed (15 downto 0) );
    end eq1;

我尝试使用整数函数 RESIZE 和 x,但它给出了同样的错误。我应该使用另一种数据类型吗? x 具有纯整数值,如 2,4,6..etc.

found '0' definitions of operator “+” in VHDL, the VHDL compiler is unable to find the matching operator for your operation, which is e.g. multiplying x*x. You probably want to use numeric_std (see here 中所述) 以使 signed(和 unsigned)的运算符可用。

但请注意,VHDL 不是一种编程语言,而是一种硬件设计语言。也就是说,如果您的长期目标是将代码移动到 FPGA 或 CPLD,这些功能可能不再有效,因为它们不可综合。

我这么说是因为当你尝试乘以例如,你会遇​​到更多问题。 0.1666,因为 VHDL 通常不了解开箱即用的浮点数。

由于 xy 的数据类型为 signed,您可以将它们相乘。但是,没有符号与实数的乘法。即使有,结果也是真实的(无符号或整数)。

所以首先,你需要弄清楚你想要什么(语义)。然后你应该添加类型转换和转换函数。

y <= x*x; -- OK
y <= 0.5 * x; -- not OK
y <= to_signed(integer(0.5 * real(to_integer(x))),y'length); -- OK

这是另一种情况,在这种情况下,在合成之前进行模拟可能会很方便。例如,ghdl 会告诉您找到第一个错误的“*”运算符:

ghdl -a implement.vhdl
implement.vhdl:12:21: no function declarations for operator "*"

 y <= -((x*x*x) * 0.1666) + (2.5 * (x*x)) - (21.666 * x) + 36.6653;
 ---------------^  character position 21, line 12

乘以 x 的表达式的两个操作数的类型均为 signed

(稍后,我们还注意到信号分配操作右侧的复杂表达式最终将被解释为 signed 值,当分配给 [=18 时具有窄子类型约束=]).

VHDL判断文字的类型0.1666,是抽象文字,即十进制文字或浮点文字(IEEE Std 1076-2008 5.2.5 Floating-point types, 5.2.5.1 General , 第 5 段):

Floating-point literals are the literals of an anonymous predefined type that is called universal_real in this standard. Other floating-point types have no literals. However, for each floating-point type there exists an implicit conversion that converts a value of type universal_real into the corresponding value (if any) of the floating-point type (see 9.3.6).

VHDL中只有一种预定义的浮点类型,见5.2.5.2,universal_real类型的浮点字面量被隐式转换为REAL类型.

9.3.6 类型转换第 14 段告诉我们:

In certain cases, an implicit type conversion will be performed. An implicit conversion of an operand of type universal_integer to another integer type, or of an operand of type universal_real to another floating-point type, can only be applied if the operand is either a numeric literal or an attribute, or if the operand is an expression consisting of the division of a value of a physical type by a value of the same type; such an operand is called a convertible universal operand. An implicit conversion of a convertible universal operand is applied if and only if the innermost complete context determines a unique (numeric) target type for the implicit conversion, and there is no legal interpretation of this context without this conversion.

因为你没有包含一个包含另一种浮点类型的包,这让我们搜索一个 "*" 乘法运算符,其中一个操作数为 signed 类型,REAL 类型操作数为 return 类型的 signed (或另一个具有相反操作数类型参数的 "*" 运算符)并且 VHDL 找到了其中的 0 个。

没有

function "*" (l: signed; r: REAL) return REAL;

function "*" (l: signed; r: REAL) return signed;

在包 numeric_std 中找到。

Phillipe 建议通过将 signed x 转换为整数来解决这个问题。

历史上综合不包含 REAL 类型,在 2008 版 VHDL 标准之前,您可能具有任意精度,而 5.2.5 第 7 段现在告诉我们:

An implementation shall choose a representation for all floating-point types except for universal_real that conforms either to IEEE Std 754-1985 or to IEEE Std 854-1987; in either case, a minimum representation size of 64 bits is required for this chosen representation.

除非综合工具支持 REAL 的浮点类型并且符合 -2008 标准,否则这对我们没有帮助。

VHDL 在 2008 版本中引入了 float_generic_pkg 包,它执行符合合成条件的浮点运算,并通过与它的浮点类型相互转换来兼容 signed 类型的使用。

在我们建议像将所有这些计算作为 64 位浮点数执行所有这些计算并综合所有这些之前,让我们再次注意结果是 16 位 signed,它是 [=88 的数组类型=] 表示一个 16 位整数。

您可以将右侧的乘法建模为以浮点数或有符号形式执行的不同表达式 用于确定错误何时显着的表示。

因为您对 y 使用 16 位有符号值,显着意味着幅度上的差异大于 1。两种方法之间翻转的符号或意外的 0 可能会告诉您存在精度问题。

我写了一个小 C 程序来查看差异,它立即告诉我们 16 位不足以保存数学:

int16_t x, y, Y;
int16_t a,b,c,d;
double A,B,C,D;

a = x*x*x * 0.1666;
A = x*x*x * 0.1666;

b = 2.5 * x*x;
B = 2.5 * x*x;

c = 21.666 * x;
C = 21.666 * x;

d =     36;  
D = 36.6653;  

y = -( a + b - c + d);
Y = (int16_t) -(A + B - C + D);

并输出 x 最左边的值:

x = -32767, a =  11515, b =      0, c =  10967, y =   -584, Y =      0  
x = -32767, A = -178901765.158200, B = 2684190722.500000, C = -709929.822000
 x = -32767 , y =   -584 , Y=      0, double = -2505998923.829100 

输出的第一行是 16 位乘法,你可以看到所有三个带乘法的表达式都不正确。

第二行说 double 有足够的精度,但是 Y (-(A + B - C + D)) 不适合 16 位数字。除非输入大小保持不变,否则您无法通过增大结果大小来解决这个问题。然后,链接操作变成了选择最佳产品并跟踪规模的问题,这意味着您不妨使用浮点数。

如果合适,您当然可以进行夹紧。输出第三行的双精度值是非截断值。比 x'LOW.

更负面

您也可以在 16 位数学域中进行钳位,尽管所有这些都告诉您这个数学在硬件域中没有意义,除非它是在浮点数中完成的。

因此,如果您尝试在硬件中解决真正的数学问题,则需要浮点数,很可能使用包 float_generic_pkg 完成,并且不会有意义地适合 16 位结果。