Преобразования типов на VHDL Печать
Добавил(а) microsin   

Любой дизайн VHDL FPGA может иметь в коде несколько используемых типов VHDL. Большинство используемых типов в синтезируемом коде VHDL это std_logic, std_logic_vector, signed, unsigned и integer. Поскольку VHDL это язык со строгим контролем типов, очень часто отличающиеся типы не могут использоваться в одном выражении. Кроме того, когда Вы можете прямо комбинировать два типа в одном выражении, то на самом деле оставляете на волю компилятора или инструмента синтеза определить, как должно себя вести это выражение, что довольно опасная вещь.

В этой статье (перевод [1]) обсуждаются следующие темы:

1. Преобразование типов (type cast) и функции преобразования.
2. В чем важность использования подходящего типа.
3. Обычное использование преобразований типов и примеры.

[Преобразование типов (type cast) и функции преобразования на VHDL]

На картинке ниже показано, как преобразовать большинство типов VHDL.

VHDL type conversions

Преобразование типов используется для перехода от типа std_logic_vector к типам signed и unsigned.

-- Определения сигналов:
signal slv : std_logic_vector(7 downto 0);
signal s : signed(7 downto 0);
signal us : unsigned(7 downto 0);
 
-- Преобразование из std_logic_vector в signed/unsigned:
sgn <= signed(slv);
usgn <= unsigned(slv);
 
-- Преобразование из signed/unsigned в std_logic_vector:
svl <= std_logic_vector(sgn);
svl <= std_logic_vector(usgn);

Для перехода между типами signed/unsigned и integer используют функции преобразования.

-- Определения сигналов:
signal i : integer;
signal sgn : signed(7 downto 0);
signal usgn : unsigned(7 downto 0);
 
-- Преобразование из integer в signed/unsigned:
sgn <= to_signed(i,8);
usgn <= to_unsigned(i,8);
 
-- Преобразование из signed/unsigned в integer:
i <= to_integer(sgn);
i <= to_integer(usgn);

Простой способ запомнить, когда надо использовать функцию, а когда type cast, состоит в том, что оба типа std_logic_vector и signed/unsigned определяются со специфичной шириной в битах, в то время как числа integer не определяют разрядность.

Type cast между std_logic_vector и signed/unsigned может быть использовано, пока источник и место назначения сигнала имеют одинаковую разрядность. Числа integer не имеют установленную разрядность, по этой причине функция преобразования от integer к signed/unsigned включает спецификацию нужной разрядности.

Дополнительное замечание по integer: следует обратить внимание, что нет прямого пути преобразования между типом std_logic_vector и типом integer. Типы integer не имеют установленной ширины в битах, в отличие от типов signed, unsigned и std_logic_vector. Чтобы преобразовать значения между типами integer и std_logic_vector, Вы должны сначала сделать преобразование значения в signed или unsigned.

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

[Использование корректного типа на VHDL]

Хотя можно выполнить множество математических функций с использованием типа std_logic_vector, поступать таким образом означает добавлять ненужную сложность при проектировании цифровой обработки сигналов (DSP). Используйте типы signed и unsigned, чтобы отслеживать точность и тип знака. В конце концов, почему Вы применяете VHDL, если не собираетесь использовать его силу строгого контроля типов?

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

[Общее использование, примеры]

Обычны ситуации, когда нужно применить type cast или преобразование в математических выражениях. Другой обычный случай, когда Вы хотите использовать значение счетчика в качестве индекса в массиве. Может быть множество других применений конверсии, но рассмотрим только эти два.

Вот что происходит, когда вычитаются друг из друга два числа unsigned:

signal sum_u : unsigned(11 downto 0);
signal sum_s : signed(11 downto 0);
constant a : unsigned(3 downto 0) := X"A";
 
sum_u <= counter_fr + (X"00" & a);
sum_s <= signed(counter_fr) + signed(X"00" & a);

В зависимости от того, как определен результат операции, signed или unsigned, результаты получатся абсолютно разные. Когда счетчик counter_fr содержит двоичное значение 1000 (binary), sum_u=18 и sum_s=2. Причина в том, что двоичное значение 1000 это десятичное 8, и -8 это число со знаком, представленное в стандартном формате дополнения до 2 (two’s complement signed).

Другое обычное использование - преобразование типа std_logic_vector или unsigned в тип integer таким образом, чтобы integer можно было использовать в качестве индекса массива. К содержимому массива можно получить доступ только через индексы, которые имеют тип integer. Не спрашивайте меня, почему.

constant vec : std_logic_vector(15 downto 0);
signal count : std_logic_vector(3 downto 0);
signal element : std_logic_vector(0 downto 0);
 
...
element <= vec(to_integer(unsigned(count),4));

[Ссылки]

1. VHDL Type Conversion site:bitweenie.com.
2. VHDL Shift Register site:bitweenie.com.
3. VHDL Counter site:bitweenie.com.
4. Verilog vs. VHDL site:bitweenie.com.