Я хочу сделать код, который накапливает входной сигнал. Это означает, что входной сигнал добавляется к предыдущему значению. Тогда это выход
library IEEE;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_1164.all
entity adder is
port(clock : in std_logic;
ADD_value : in signed(k-1 downto 0));
Result: out signed(k-1 downto 0));
end adder;
architecture behavioral of adder is
begin
variable acc_value : signed(k-1 downto 0);
process(clock)
begin
if rising_edge(clock) then
acc_value := acc_value + Add_value;
Result<=acc_value ;
end if;
end process;
end behavioral;
Проблема в том, что обе переменные подписаны. Если происходит переполнение, то переполнение переходит из позиции k-1 в позицию k-1, что означает уничтожение знака. Например, если у меня есть 01111 с первым «0» в качестве знака, и я добавляю «10», он переходит к «10001», что побитово правильно, но неправильно со знаком, потому что это отрицательное значение
Я пробовал такие вещи, как acc_value := resize(acc_value + Result_var,k); или acc_value := to_signed(acc_value + Result_var,k);, но у меня была та же проблема.
В результате я хочу сохранить длину данных k и в случае переполнения. Если происходит переполнение, результат должен быть установлен на максимально возможное значение по отношению к знаку. Это означает, что мне все равно, есть ли переполнение, мне нужно только максимальное/минимальное значение
Максимум (минимум в случае отрицательного значения) как разновидность насыщения. Можно снова уйти от максимума, так как допускаются и отрицательные значения.
С acc_value и result_var одинаковой длины, у вас всегда будет эта проблема. Сложение двух чисел требует дополнительного бита для захвата переполнения. Вы, вероятно, хотите, чтобы временное значение выполняло обнаружение переполнения.
«вещи, которые вы пробовали», не будут работать с кодом, как опубликовано, потому что 1. acc_value не является переменной, и вы использовали присвоение переменной, и 2. нет объявления объекта k.
В опубликованном вами коде, помимо отсутствующего объявления объекта k, вам также не хватает пункта использования для use ieee.std_logic_1164.all, чтобы сделать тип std_logic видимым.
Спасибо за подсказку. Это означает, что вы должны записать его в новую переменную, а затем изменить размер переменной до нужной длины?
Да. И тогда у вас есть лишний бит, позволяющий вам проверять переполнение или недополнение.
Изменение размера значений со знаком подразумевает либо отсечение значащих битов, либо удлинение знака до большей длины и не устраняет потерю информации. Аккумулятор в первую очередь хочет быть достаточно большим. Используйте отдельные дженерики для спецификаторов длины или свяжите аккумулятор с количеством раз, которое он может накапливать, прежде чем он будет отброшен/сброшен/загружен (здесь отсутствует). Обратите внимание, что общее предложение или предложение использования, делающее k непосредственно видимым, отсутствует. Не используйте входной режим, выходные порты режима -2008 имеют ту же семантику, что и буфер режима, и могут быть оценены.
"Как избежать переполнения" слишком расплывчато: укажите желаемое поведение. Это факт, что переполнение происходит, когда значение максимальное, и вы увеличиваете его на единицу. Что происходит после этого, так это бизнес-логика: т.е. специфичная для ваших требований.
Спасибо. Я уточнил название, вопрос, свои требования. Я тоже исправил код. Мои требования заключаются в том, что в случае переполнения я хочу установить максимальное значение по отношению к знаку. Это означает максимум/минимум. Я не хочу менять длину бита.
Нет смысла накапливать вечно. Должен существовать барьер, который вы могли бы проверить (и, возможно, сигнализировать о переполнении, если барьер превышен). Ваш сигнал acc_value должен иметь ширину max_bit_width, которая представляет этот барьер (учтите, что сигнал sum_temp имеет на 1 бит больше, см. ниже). Result_var может иметь еще ширину k. Затем вы можете закодировать (я изменил acc_value с «out» на «buffer», чтобы иметь возможность его прочитать, возможно, вам следует ввести промежуточный сигнал и оставить acc_value как «out» или использовать VHDL2008, как было предложено):
acc_value : buffer signed(maximum_bit_width-1 downto 0);
…
process(clock)
variable sum_temp : signed(maximum_bit_width downto 0);
begin
if rising_edge(clock) then
sum_temp := acc_value(maximum_bit_width-1)&acc_value + Result_var;
if sum_temp(maximum_bit_width)=sum_temp(maximum_bit_width-1) then
acc_value <= sum_temp(maximum_bit_width-1 downto 0);
else
if sum_temp(maximum_bit_width)=‘0‘ then
acc_value <= (‘0‘, others => ‘1‘);
else
acc_value <= (‘1‘, others => ‘0‘);
end if;
end if;
end if;
end process;
Вместо того, чтобы вручную расширять acc_value, вы можете использовать функцию resize, так как это подпишет расширение за вас. sum_temp :=resize(acc_value, sum_temp'length) + Result_var; Я бы также рекомендовал никогда не использовать режим buffer, так как это может усложнить подключение портов при создании экземпляров.
Спасибо за ответ. Меня код не устраивает. Во-первых, я не вижу объявления «переполнения». Если это сигнал, мне пришлось добавить дополнительный порт, чего я не хочу. Мои требования заключаются в том, что в случае переполнения я хочу установить максимальное значение по отношению к знаку. Это означает максимум/минимум. Я не хочу менять длину бита.
К «Нет смысла накапливать вечно»: Есть случаи, в которых есть смысл. См. максимум (минимум в случае отрицательного значения) как своего рода насыщение. Также можно снова отойти от максимума, так как допускаются и отрицательные значения.
@hajo: я отредактировал ответ в соответствии с вашими идеями.
Большое спасибо за ваше решение! Так рад, что есть решение для этого. 2 маленькие подсказки на моем сайте: 1. acc_value <= ('1', (другие => '0')); выдает мне ошибку, что на нужном сайте он видит только один элемент вместо элементов max_bit_width-1. 2. работа с max_bit_width-1 и max_bit_width была для меня довольно запутанной, я думаю, что с написанием «высокий» или «длина» это лучше понятно. Большое спасибо!
@hajo: я исправил вашу точку зрения 1. отредактировав ответ, я ввел слишком много скобок.
Большое спасибо ! Я очень благодарен за ваши усилия и ваш ответ!
Пожалуйста, возможно вам это тоже пригодится: hdl_fsm_editor
Спасибо, посмотрю!
Почему acc_value это inout? VHDL 2008 позволяет читать out порты. inout обычно требуется только для буферов с тремя состояниями.