Это еще один случай, когда симуляция перед синтезом может быть удобной. ghdl для случаев указывает, какой "*" оператор находит первое сообщение об ошибке для:
ghdl -a implement.vhdl
implement.vhdl: 12: 21: нет функции объявления для оператора "*"
y <= -((x*x*x) * 0.1666) + (2.5 * (x*x)) - (21.666 * x) + 36.6653;
---------------^ character position 21, line 12
выражения с x
умножаются оба операнда с типом signed
.
(И далее мы также отметим, что комплексное выражение в правой части операции назначения сигнала в конечном итоге будет интерпретировано как значение signed
с узким ограничением подтипа при назначении y
).
VHDL определяет тип литерала 0.1666
, это абстрактный литерал, то есть десятичный литерал или литерал с плавающей точкой (IEEE Std 1076-2008 5.2.5 Типы с плавающей точкой, 5.2.5.1 Общие, пункт 5):
с плавающей точкой литералы являются литералы анонимного предопределенного типа, который называется в универсальный-настоящему стандарту. Другие типы с плавающей точкой не имеют литералов. Однако для каждого типа с плавающей точкой существует неявное преобразование, которое преобразует значение типа universal_real в соответствующее значение (если оно имеется) типа с плавающей запятой (см. 9.3.6).
Там только один предопределенный тип с плавающей точкой в VHDL, см 5.2.5.2, и с плавающей точкой литерал типа универсальный-неявно преобразуется в тип REAL.
9.3.6 Преобразование типа пункт 14 говорит нам:
В некоторых случаях, неявное преобразование типа будет выполняться. Неявное преобразование операнда типа universal_integer другому целочисленному типу или операнду типа universal_real другому типу с плавающей запятой может применяться только в том случае, если операндом является либо числовой литерал, либо атрибут, либо если операнд - это выражение, состоящее из деления значения физического типа на значение того же типа; такой операнд называется конвертируемым универсальным операндом. Неявное преобразование конвертируемого универсального операнда применяется тогда и только тогда, когда самый внутренний полный контекст определяет уникальный (числовой) тип цели для неявного преобразования, и нет никакой юридической интерпретации этого контекста без этого преобразования.
Потому что вы не включили в пакет, содержащий другой тип с плавающей точкой, которая оставляет нас на поиск оператора в "*"
умножения с одним операндом типа signed
и одного типа REAL, с типом возвращаемого signed
(или другого "*"
оператор с аргументами противоположного операнда), а VHDL обнаружил 0 из них.
Там нет
function "*" (l: signed; r: REAL) return REAL;
или
function "*" (l: signed; r: REAL) return signed;
найден в пакете numeric_std.
Phillipe предлагает один из способов преодолеть это путем преобразования signed
x
в целое число.
Исторически синтез не охватывает реальный тип, до версии стандарта VHDL вы, вероятно, иметь произвольную точность 2008 года, а в пункте 7 5.2.5 теперь рассказывает нам:
Реализация должна выбрать представление для всех типов с плавающей точкой, за исключением universal_real, которое соответствует либо IEEE Std 754-1985, либо IEEE Std 854-1987; в любом случае для этого выбранного представления требуется минимальный размер представления 64 бит.
И это не поможет нам, если инструмент синтеза не поддерживает типы REAL с плавающей точкой и совместим с -2008.
VHDL имеет пакет float_generic_pkg, представленный в версии 2008 года, который выполняет операции с плавающей запятой, соответствующие синтезу, и совместим с используемыми типами signed
путем преобразования в его тип float и из него.
Прежде чем мы предложим нечто столь радикальное, как выполнение всех этих вычислений, как 64-битные числа с плавающей запятой и синтезируем все, что давайте еще раз отметим, что результатом является 16 бит signed
, который является типом массива std_ulogic и представляет собой 16-битное целое число.
Вы можете моделировать умножения с правой стороны в виде отдельных выражений, выполняемых как в плавающей запятой, так и в подписанном представлении , чтобы определить, когда ошибка является значительной.
Поскольку вы используете 16-значное знаковое значение для y
, существенное значение будет означать разницу, превышающую 1. Перевернутые знаки или неожиданные 0s между этими двумя методами, скорее всего, скажут вам, что существует проблема с высокой точностью.
Я написал небольшую программу на С, чтобы посмотреть на различия и сразу же он говорит нам 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-битовому результату.
* Где * возникает ошибка? –
y <= - ((x * x * x) * 0.1666) + (2.5 * (x * x)) - (21.666 * x) + 36.6653; – Raj
Это связано с [найденными «0» определениями оператора «+» в VHDL] (http://stackoverflow.com/questions/26598471/found-0-definitions-of-operator-in-vhdl) –