Перейти к содержанию
    

Арифметика со знаком(сложение и вычитание)

Доброго всем времени суток!

Вопрос который прозвучит возможно покажется глупым (новичковым), но что-то я зашел в тупик. :cranky:

Вот собственно сам вопрос:

ПЛИС с АЦП получает 12 битные данные (только положительные числа от 0 до 4095) над которыми потом производится двоичная арифметика(сложение, вычитание и умножение). До некоторого момента арифметика производилась только над положительными числами все было прекрасно, а сейчас встал вопрос, что числа после вычитания могут быть как отрицательными так положительными и здесь проблема.

Нужно реализовать следующее выражение S = S + b - c

где b и с - данные с АЦП. Приведите плиз пример коректного описания.

PS что-то мне подсказывает что нужно задавать тип SIGNED и UNSIGNED (сейчас я для входных и выходных данных использую тип std_logic_vector(11 downto 0)), или как-то контролировать старший разряд, т.е. знак числа (тогда наверное вначале каким-то образом нужно преобразовывать входные данные).

:help: :help: :help:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если не хочется постигать signed/unsigned, то:

 

продолжайте использовать std_logic_vector.

используйте знаковый пакет USE IEEE.std_logic_unsigned.all;

к вашим входным данным добавьте (конкатенацией) слева нулевой битик (т.к. число всегда положительное).

типа

signal b_signed, c_signed, dif : std_logic_vector(12 downto 0);

...

b_signed <= '0' & b;

c_signed <= '0' & c;

dif <= b-c;

 

Вуаля. dif - значение разности ваших входов в знаковом виде. Ну а дальше с ним что хотите делайте, помня про расширение разрядности по необходимости.

Изменено пользователем alexadmin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если не хочется постигать signed/unsigned, то:

 

продолжайте использовать std_logic_vector.

используйте знаковый пакет USE IEEE.std_logic_unsigned.all;

к вашим входным данным добавьте (конкатенацией) слева нулевой битик (т.к. число всегда положительное).

типа

signal b_signed, c_signed, dif : std_logic_vector(12 downto 0);

...

b_signed <= '0' & b;

c_signed <= '0' & c;

dif <= b-c;

 

Вуаля. dif - значение разности ваших входов в знаковом виде. Ну а дальше с ним что хотите делайте, помня про расширение разрядности по необходимости.

 

Как-то сложно все. Если данные с АЦП приходят в дополнительном коде, то мудрить при сложениях/вычитаниях и умножениях вообще не надо. Если данные с АЦП в прямом коде, то я бы перевел их в дополнительный и не парился.

 

т.е. в случае дополнительного кода вот так можно:

 

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity qwerty is
port
    (
        a,b,c: in std_logic_vector(11 downto 0);
    Xout: out std_logic_vector(11 downto 0)
    );
    
end entity;


architecture qwerty of qwerty is

begin
    
    Xout <= a + b - c;
    
end architecture;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как-то сложно все. Если данные с АЦП приходят в дополнительном коде, то мудрить при сложениях/вычитаниях и умножениях вообще не надо. Если данные с АЦП в прямом коде, то я бы перевел их в дополнительный и не парился.

 

т.е. в случае дополнительного кода вот так можно:

 

Положительные числа что в прямом, что в дополнительном коде выглядят абсолютно одинаково, так что никуда их переводить не нужно. Ваш код не будет корректно работать потому что результат a + b - c может занимать на 2 разряда больше, чем операнды. Поэтому правильный код привел alexadmin, правда он описал только половину того, что нужно сделать.

 

:help: :help: :help:

 

Т.к. результат вычитания в общем случае может иметь диапазон от -4095 до +4095, то разрядность S, как минимум должна быть на 1 бит больше, чем разрядность a и b. Т.к., судя по выражению, вы собираетесь эту разницу накапливать, то разрядность S нужно еще увеличить. На сколько именно зависит от количества накоплений. Если брать общий случай, то если количество накоплений = 2^N, то разрядность S должна вырасти на N бит (если 2^(N-1) < разрядность S < 2^(N), то берем наибольшее т.е. N).

 

Что касается использования std_logic_vector, unsigned или signed, то для сложения/вычитания это безразлично - тем и хорош дополнительный код. Сумматор для любых чисел в дополнительном коде одинаковый (все синтезаторы генерят логику для дополнительного кода) Главное это разрядности правильно рассчитать.

 

Вот код

 

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity Accumulator is
 generic 
   (
     N : natural := 4     --по умолчанию 16 накоплений
   );
 port
   (
     CLK        : in std_logic;
     RESET      : in std_logic;

     A_i        : in std_logic_vector(11 downto 0);      -- i просто суффикс обозначающий направлений сигнла
     B_i        : in std_logic_vector(11 downto 0);      -- i просто суффикс обозначающий направлений сигнла

     ACCUM_ro   : out std_logic_vector (12+N downto 0)   -- ro просто суффикс обозначающий направлений сигнла
   );
end Accumulator;


architecture RTL of Accumulator is

 signal A     : std_logic_vector(ACCUM_ro'high downto 0);
 signal B     : std_logic_vector(ACCUM_ro'high downto 0);

 signal ACCUM : std_logic_vector(ACCUM_ro'high downto 0);

begin

A <= (A'high downto 12 => '0') & A_i;
B <= (B'high downto 12 => '0') & B_i;

process(CLK)
begin

 if(CLK'event and CLK = '1') then
--  {
     if RESET = '1' then
--      {
         ACCUM <= (others => '0');
--      }
     else
--      {
         ACCUM <= ACCUM + A - B;
--      }
     end  if;
--  }
 end if;

end process;

ACCUM_ro <= ACCUM;

end RTL;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Беру свои обратно. Плохо вник в проблему. Полностью согласен с Sefo.

Я бы еще вот эту строчку:

 

signal ACCUM : std_logic_vector(ACCUM_ro'high downto 0);

 

переписал бы вот так, чтобы симулировать было удобно:

 

signal ACCUM : std_logic_vector(ACCUM_ro'high downto 0):=(others=>'0');

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за подсказу и описание! Только я реализовал это ввиде FSM на 3 состояния (в псевдо коде ниже):

 

SIGNAL summ,  subb  : SIGNED (12 downto 0) := (others=>'0');
SIGNAL а, b  : SIGNED (12 downto 0) := (others=>'0');

when s0 => 
reg_strob <=0;
subb <= summ + a;
s_next <= s1;

when s1 => 
reg_strob <=0;
summ <= subb - b;
s_next <= s2;

when s2 => 
reg_strob <=1;
s_next <= s0;

 

Сигнал strob дает мне готовность данных

 

ЗЫ мне кажется если сразу написать summ = summ + a - b то выйдет более большая задержка и соответственно скоростные характеристики схемы будут более низкими

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ЗЫ мне кажется если сразу написать summ = summ + a - b то выйдет более большая задержка и соответственно скоростные характеристики схемы будут более низкими

 

Любопытно, о каких скоростных характеристиках идет речь?

 

Если частота выборки данных у АЦП является предельной для ПЛИС, то, разумеется, нужно конвееризировать вычисления, но ваш конвеер приведет к тому, что:

1)Если у Вас 2 АЦП то, вы будете обрабатывать только каждый третий отсчет, а если еще и не задержите b на такт, то будете копить разность отсчетов взятых в разные моменты времени.

2)Если АЦП один и a = x(t), а b = x(t+1) то, ваш конвеер будет пропускать каждый третий отсчет АЦП.

 

По-моему FSM для такой простой задачи слишком жирно :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Любопытно, о каких скоростных характеристиках идет речь?

 

Если частота выборки данных у АЦП является предельной для ПЛИС, то, разумеется, нужно конвееризировать вычисления, но ваш конвеер приведет к тому, что:

1)Если у Вас 2 АЦП то, вы будете обрабатывать только каждый третий отсчет, а если еще и не задержите b на такт, то будете копить разность отсчетов взятых в разные моменты времени.

2)Если АЦП один и a = x(t), а b = x(t+1) то, ваш конвеер будет пропускать каждый третий отсчет АЦП.

 

По-моему FSM для такой простой задачи слишком жирно :)

Извините, просто я не захотел описывать полностью задачу, чтобы не засорять форум.

Полная математика во вложении. АЦП работает на частоте 6 МГц. Частота работы ПЛИС 96 МГц. 96/6=16 тактов. И в эти 16 тактов нужно положить эту математику, чтобы к следующему приходу данных с АЦП был готов результат.

ЗЫ FSM пользуюсь, так как мне легче с помощью него распределить что и когда считается.

ЗЫ ЗЫ Вроде вчера задачу реализовал (во всяком случае в симуляторе она отрабатывается). Вроде - потому что еще не было проверки в "железе".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...