Как преобразовать большие целые числа в меньшие целые числа в vhdl?

У меня есть код VHDL, в котором я пытаюсь умножить значения пикселей. У меня есть следующая сущность:

entity xGradient is

port(
    clk : in std_logic;
    x11, x12, x13, x21, x22, x23, x31, x32, x33 : in integer range 0 to 255;
    gradientInX : out integer range 0 to 255
);

end xGradient;

Я делаю следующую операцию над ними:

gradientInX <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

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

-- declared signals
signal gradientMem: integer;

--beginning of my architecture
begin 

SobelOperator : process(gradientMem)

begin
    gradientMem <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem <= 255;
    elsif (gradientMem < 0) then
        gradientMem <= 0;
    end if;

end process SobelOperator;

затем присвоить градиентMem градиентуInX, но по какой-то причине это не работает. Любая помощь будет действительно оценена. Примечание. Я не включил весь код VHDL, так как думал, что он будет излишне длинным. Сообщение об ошибке, которое я получаю, заключается в том, что значение сигнала, полученное в результате операции, выходит за пределы диапазона (поскольку результирующее значение отрицательно, а выход имеет диапазон только от 0 до 255).

Мэтью


person Omnomnious    schedule 09.04.2017    source источник
comment
В вашем вопросе отсутствуют две важные части: 1) объявление gradientMen и 2) сообщение об ошибке. VHDL проверяет границы диапазона при назначении. Вы хотите создать арифметику насыщения. Поэтому определите gradientMem с большим диапазоном.   -  person Paebbels    schedule 09.04.2017
comment
Я только что отредактировал его, чтобы включить их. Я предполагаю, что моя главная проблема заключалась в том, что список чувствительности был неправильным. Мне также было интересно, есть ли в VHDL специфические операции с целыми числами, которые приводят результаты в определенный диапазон, но я предполагаю, что такой функции или операции не существует, поэтому мне просто нужно реализовать ее самостоятельно. В любом случае похоже, что моя проблема решена. Спасибо за ваш ответ и не стесняйтесь добавлять что-нибудь еще.   -  person Omnomnious    schedule 09.04.2017


Ответы (3)


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

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem := 255;
    elsif (gradientMem < 0) then
        gradientMem := 0;
    end if;
    gradientInX <= gradientMem;
end process SobelOperator;

Кстати, эта операция называется отсечение.

Если вы хотите обрезать, процесс должен быть написан так:

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    gradientInX <= gradientMem mod 256;
end process SobelOperator;
person JHBonarius    schedule 10.04.2017

Как предполагает @Paebbels в комментарии, скорее всего, диапазона градиентаMem недостаточно для обработки вывода операции.

Обратите внимание: в целочисленных операциях промежуточный диапазон (в основном) считается 32b со знаком, и диапазон проверяется в присваивании. Это дает довольно много предположений для инструмента синтеза и может привести к гораздо большему дизайну, чем оптимальный.

Чтобы преодолеть это, ieee.numeric_std.all используется для беззнаковых и подписанных типов и операций. Это дает абсолютный контроль над длинами промежуточных векторов. Это также заставляет вас понимать, что происходит в дополнение к вычитанию, умножению и т. д., что обычно помогает в дизайне RTL.

Однако следует отметить, что в векторной форме операции оцениваются парами, используя самую длинную из двух в качестве промежуточной длины вектора.

Например:

  process
    variable i1      : integer range 0 to 15 := 15;
    variable i2      : integer range 0 to 15 := 9;
    variable i3      : integer range 0 to 15 := 11;
    variable i4      : integer range 0 to 31 := 2;
    variable iSum    : integer range 0 to 63;
    variable u1      : unsigned(3 downto 0) := to_unsigned(15,4);
    variable u2      : unsigned(3 downto 0) := to_unsigned(9,4);
    variable u3      : unsigned(3 downto 0) := to_unsigned(11,4);
    variable u4      : unsigned(5 downto 0) := to_unsigned(2,6);
    variable uSum    : unsigned(5 downto 0);
  begin
    iSum := i1 + i2 + i3 + i4;
    uSum := u1 + u2 + u3 + u4;
    write(output, "int: " & to_string(iSum) & lf &
                  "us : " & to_string(to_integer(uSum)) & lf);
    wait;
  end process;

Дает:

# int: 37
# us : 5

Использование скобок решает проблему:

uSum := (u1 + (u2 + (u3 + u4)));
person FritzDC    schedule 10.04.2017

Ошибка в списке конфиденциальности вашего процесса SobelOperator : process(gradientMem). Здесь должны быть сигналы, которые влияют на результирующий сигнал(ы), другими словами, это список сигналов, к которым чувствителен процесс. Так что должны быть x11, x21, x31, x13, x23 и x33 как SobelOperator : process(x11, x21, x31, x13, x23, x33)

person Roman    schedule 09.04.2017
comment
Эй, спасибо за ваш ответ! Да, я действительно заметил это, когда писал свой вопрос. Я постараюсь исправить это и посмотреть, что произойдет. Я все еще хочу знать, есть ли в числовой библиотеке, например, функция, которая усекает целочисленный сигнал из одного диапазона в меньший. - person Omnomnious; 09.04.2017
comment
Для усечения вывода вы можете использовать тип std_logic_vector и взять из шины только бит, который вам нужен, а затем преобразовать его в целое число, если вам нужен вывод как тип integer - person Roman; 09.04.2017
comment
Да, список чувствительности неверен, но это не причина его проблем с дальностью... - person Paebbels; 09.04.2017
comment
@Paebbles Я не могу добавлять комментарии, потому что у меня недостаточно репутации, поэтому я разместил это как ответ. Или что мне делать? - person Roman; 09.04.2017
comment
Написать ответ можно, но недостаточно изменить только список конфиденциальности. Это не решает ошибку выхода за пределы. - person Paebbels; 10.04.2017