VHDL: Как разрешается этот оператор: тип foo - это диапазон - (от 2 ** 30) до 2 ** 30 ;? - PullRequest
1 голос
/ 05 марта 2020

У меня проблема с обработкой следующего объявления типа:

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;

также отлично работает из-за дополнительного ограничения, что тип результата должен быть целым числом.

Но комбинация определения типа и возведения в степень лишает нас достаточного количества информации, чтобы сделать выбор.

Поскольку это определение типа работает в других реализациях, что мне не хватает?

От имени моего разработчика. Кен

1 Ответ

2 голосов
/ 09 марта 2020

Для

тип foo имеет диапазон - (от 2 ** 30) до 2 ** 30;

Существует две допустимые функции "**", реализующие оператор возведения в степень.

9.2.8 Разные операторы

Возражающий оператор ** предопределен для каждого целочисленного типа и для каждого типа с плавающей запятой. В любом случае правый операнд, называемый показателем степени, имеет предопределенный тип INTEGER.

table 9.2.8

Вычисление с целым показателем эквивалентно повторному умножению левый операнд сам по себе несколько раз указывается абсолютным значением показателя степени и слева направо; если показатель отрицателен, то результат является обратным результату, полученному с абсолютным значением показателя. Возведение в степень с отрицательным показателем допускается только для левого операнда типа с плавающей точкой. Возведение в степень с нулевым показателем приводит к значению один. Возведение в степень значения типа с плавающей точкой является приблизительным.

Предопределенные операторы для предопределенных типов отображаются в виде комментариев в пакете STANDARD. Здесь применимо два:

16.3 Пакет STANDARD

- функция "**" (анонимный: universal_integer; анонимный: INTEGER)
- вернуть universal_integer;

- функция "**" (анонимный: INTEGER; анонимный: INTEGER) - вернуть INTEGER;

Обратите внимание, что правильный тип операнда - INTEGER. Правый операнд подлежит неявному преобразованию типов.

Причина, по которой их два, содержится в 5.2.3 Целочисленные типы, 5.2.3.1 Общие сведения:

Каждая граница ограничения диапазона то, что используется в определении целочисленного типа, должно быть локально выражением c некоторого целочисленного типа, но эти две границы не обязательно должны иметь одинаковый целочисленный тип. (Допускаются отрицательные границы.)

Целочисленные литералы - это литералы анонимного предопределенного типа, который в этом стандарте называется universal_integer . Другие целочисленные типы не имеют литералов. Однако для каждого целочисленного типа существует неявное преобразование, которое преобразует значение типа universal_integer в соответствующее значение (если оно есть) целочисленного типа (см. 9.3.6).

Границы должны быть целого типа, который может включать universal_integer .

Какие из этих двух выбираются контекстом разрешения перегрузки основано по семантике, найденной в 9.3.6 Преобразования типов:

В некоторых случаях будет выполняться неявное преобразование типов. Неявное преобразование операнда типа universal_integer в другой целочисленный тип или операнда типа universal_real в другой тип с плавающей запятой может применяться, только если операнд является цифра c литерал или атрибут, или если операнд является выражением, состоящим из деления значения физического типа на значение того же типа; такой операнд называется конвертируемым универсальным операндом. Неявное преобразование конвертируемого универсального операнда применяется тогда и только тогда, когда самый внутренний полный контекст определяет уникальный (цифра c) целевой тип для неявного преобразования, и без этого преобразования нет юридической интерпретации этого контекста.

Вы неявно конвертируете из universal_integer в другой целочисленный тип, если нет другой юридической интерпретации. Это механизм предотвращения двух возможных вариантов здесь в контексте разрешения перегрузки.

Для 2 ** 30 нужно ли вам неявно преобразовывать левый операнд? Нет. Нужно ли неявно преобразовывать правильный операнд? Да, оба варианта требуют, чтобы тип был INTEGER. Кроме того, не требуется, чтобы результат представлял собой целочисленный тип, отличный от универсального_интегратора, требуемый семантикой определения целочисленного типа (5.2.3.1).

Если посмотреть на 9.5 универсальных выражений, есть одно дополнительное ограничение на определение целочисленного типа здесь:

Для оценки операции универсального выражения применяются следующие правила. Если результат имеет тип universal_integer , то значения операндов и результата должны l ie в пределах диапазона целочисленного типа с самым широким диапазоном, предоставленным реализацией, исключая тип universal_integer сама. Если результат имеет тип universal_real , то значения операндов и результат должны составлять l ie в пределах диапазона типа с плавающей запятой с самым широким диапазоном, предоставленным реализацией, исключая тип universal_real .

Невозможно использовать литералы для описания целочисленного типа с диапазоном значений, превышающим диапазон типа INTEGER, единственного предопределенного целочисленного типа (5.2.3.2).

Существует также ограничение целочисленных литералов анонимного типа universal_integer , диапазон значений которого неизвестен.

12.5 Контекст разрешения перегрузки

Когда Принимая во внимание возможные интерпретации полного контекста, рассматриваются только правила синтаксиса, правила области видимости и видимости, а также правила вида:

a) ...
e ) Правила для разрешения перегруженных вызовов подпрограмм; для неявных преобразований универсальных выражений; для интерпретации дискретных диапазонов с границами, имеющими универсальный тип; для интерпретации расширенного имени, префикс которого обозначает подпрограмму; и для подпрограммы, названной в объявлении экземпляра подпрограммы, чтобы обозначить необоснованную подпрограмму.
f) ...

Где мы можем видеть обе семантики неявного преобразования, найденные в 9.3. 6, и ограничения по диапазону, найденные в 9.5, приняты.

Чтобы узнать, как выбирать между двумя возможными функциями, обеспечивающими перегрузку оператора, ключ находится в 9.3.6.

Оба операнда of оператора возведения в степень в

constant K: integer := 2 ** 30;

может быть неявно преобразован тип в другой целочисленный тип (INTEGER), в то время как универсальное выражение 2 ** 30 в противном случае не может быть неявно преобразовано, не отвечая требованиям 9.3. 6 (операнды не являются значениями физического типа, а оператор не является оператором умножения / ).

Перегрузка для этого также упоминается в пакете STANDARD:

- функция "**" (анонимно: INTEGER; анонимно: INTEGER) - вернуть INTEGER;

Чак Сварт ( последний ISA C стул) описал это поведение в Отчете о проблемах 2073 ( IR2073.txt ) как принудительное неявное преобразование типов в листья абстрактного синтаксического дерева. По его словам, «этот пункт подразумевает, что неявные преобразования происходят как можно глубже в дереве выражений». Обратите внимание, что 9.3.6 было 7.3.5 до того, как Accellera VHDL-2006 была переписана для соответствия стандарту IEEE-SA для стандарта.

universal_integer в другое целочисленное преобразование типов может быть принудительно удален от листьев с помощью явного преобразования типов:

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

Принимая во внимание правый операнд «**», целочисленный литерал 30 все равно будет неявно преобразован в тип INTEGER, тогда как левый операнд и результат имеет тип universal_integer .

...