Почему умножение в VHDL иногда работает не так, как ожидалось, с целым числом?

#vhdl

#vhdl

Вопрос:

В VHDL со строгой типизацией при выполнении умножения я бы ожидал, что следующий оператор завершится 14-битным выводом:

 frame_addr  : out STD_LOGIC_VECTOR(13 downto 0);

...

signal  y_pos       : unsigned(4 downto 0);

...

frame_addr <= std_logic_vector(y_pos * 320);
  

Но в итоге я получаю ошибку:

expression has 10 elements, but must have 14 elements

Для меня это не имеет смысла… Поскольку 320 должно быть не менее 9 бит как беззнаковое, 10 как целое число, а при умножении на 5-битный сигнал y_pos я ожидал бы увидеть НЕ менее 14 бит…

У меня есть другой раздел кода, где это работает ОТЛИЧНО:

 ram_addr <= std_logic_vector(h_pos   (v_pos * 80))(14 downto 0);
  

Умножение на 80 работает просто отлично, без ошибок.

Итак, я перепробовал все, чтобы получить до 14 бит… и, конечно, кажется, что умножение просто НЕ происходит, когда в моей логике… Итак, я, наконец, сказал, хорошо, что, если я просто выполню умножение с ДВОИЧНЫМ кодом, сообщите ему именно то, что я хочу…

 frame_addr <= std_logic_vector(y_pos * "101000000");
  

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

Итак, почему существует это несоответствие? Оба они находятся в структуре архитектуры для релевантности, а не в процессах или чем-то подобном. Я просто не могу понять, почему существуют эти несоответствия… Оба используют одни и те же библиотеки:

 library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;
  

Так что же получается? Должен ли я использовать двоичный код везде, где мне нужно число для какой-либо согласованности кода?

Комментарии:

1. Из пакета numeric_std — function "*" (L: UNSIGNED; R: NATURAL) return UNSIGNED is begin return L * TO_UNSIGNED(R, L'LENGTH); end "*"; где два беззнаковых, умноженных вместе, имеют длину результата, которая является суммой длин операндов. Также обратите внимание, что для 320 требуется точность 9 бит, что привело бы к необходимости того, чтобы левый операнд был равен 9 битам, а результат равнялся 18 битам. Вам лучше преобразовать натуральное значение большей величины в беззнаковое с длиной, достаточной для хранения двоичного числового значения.

2. Ваш ПРЕКРАСНЫЙ пример не должен работать, чей инструмент (и версия)? Вы не можете вырезать выражение, префикс которого не является именем или вызовом функции (IEEE Std 1076-2008 8. Имена, 8.1 Общие сведения). Преобразование типа — это не вызов функции, это базовая операция (5. Типы, 5.1 Общие), и префикс должен соответствовать объекту одномерного массива (8.5 имен фрагментов). » Объект — это именованная сущность, которая содержит (имеет) значение определенного типа». (6.4 Объекты, 6.4.1).

Ответ №1:

Поскольку целое число не имеет побитовой длины, оно преобразуется в ту же длину, что и y_pos. Итак, в вашем первом примере Y_pos равен 5 битам. таким образом, 320 преобразуется в беззнаковое значение, также состоящее из 5 бит, что дает 10-битный результат. Это правило одинаково для всех арифметических операторов со знаком и без знака.

Целые числа в VHDL не имеют побитового определения, и поэтому их нужно как-то преобразовать. Компилятор не может выполнить интеллектуальную калибровку, поэтому полагается на то, что пользователь правильно ее определит. В вашем примере преобразование 320 в 5 бит явно усекает значение, и вы фактически получите «00000» и предупреждение о том, что это происходит во время моделирования.

Здесь нет никакой несогласованности, «101000000» и 320 — это совершенно разные и не связанные типы. Unsigned не является целым числом — это двоичное представление целого числа без знака.

Вероятно, вы захотите использовать функцию to_unsigned() для ваших целочисленных литералов, чтобы получить явный размер:

 frame_addr <= std_logic_vector(y_pos * to_unsigned(320, 9));
  

Комментарии:

1. Ваше первое утверждение («… оба операнда преобразуются в длину самого длинного операнда») неточно. Пакет numeric_std (-2008) function "*" (L, R : UNRESOLVED_UNSIGNED) return UNRESOLVED_UNSIGNED is variable RESULT : UNRESOLVED_UNSIGNED((L'length R'length-1) downto 0) := (others => '0'); Здесь длина результата равна сумме длин операндов, например. В спешке вы также допустили ошибку в арифметике.