2014-09-20 3 views
0

У меня есть код как таковой ниже, который предназначен для вычитания и сложения. В принципе, когда Binv установлен, он должен вычитать, а Binv равен 0, он должен добавить. К сожалению, кажется, что это добавление, когда Binv устанавливается иногда, и вычитание, когда оно не устанавливается иногда. Вот снимок моделирования:Модуль субтрактора VHDL генерирует неправильные значения

entity ADD_SUB is 
Port (A : in STD_LOGIC_VECTOR (31 downto 0); 
     B : in STD_LOGIC_VECTOR (31 downto 0); 
    Binv : in STD_LOGIC; 
    C_in: in STD_LOGIC; 
     S : out STD_LOGIC_VECTOR (31 downto 0); 
    TEST : out STD_LOGIC_VECTOR (31 downto 0); 
     C_out : out STD_LOGIC 
     ); 
end ADD_SUB; 

architecture ADD_SUB_ARCH of ADD_SUB is 
signal S_wider : std_logic_vector(32 downto 0); 
begin 

process (A,B,C_in,Binv) 
begin 

if Binv = '0' then 
    S_wider <= (A(31) & A) + (B(31) & B) + C_in; 
elsif Binv = '1' then 
    S_wider <= (A(31)& A) + ('1'& not B) + '1'; 
else 
    S_wider <= std_logic_vector(to_signed(0,32)); 
end if; 

S <= S_wider(31 downto 0); 
C_out <= S_wider(32); 

end process; 

enter image description here

Я получаю бессмысленные результаты, которые не имеют никакого смысла. В первом случае вы можете видеть, что я пытался сделать (50 - 30) (Binv равен 1). Я получаю 80, что неправильно. Однако вы можете видеть, что он работает (30-50), где я получаю -20. Вторая проблема в том, где я пытаюсь сделать (30 + (-50)), однако он показывает, как 20.

Результаты полностью выключен, и я не вижу, где я неправильно

+0

Можете ли вы попробовать без C_in (не уверен, что вы можете добавить C_in, который является std_logic для вектора)?. Кроме того, когда вы отрицаете B, should'nt это ((не B (31)) & (не B)) + "000000000000000000000000000000000001"? – neodelphi

ответ

1

Джим абсолютно прав.

Есть несколько моментов, которые могут стоить сделать.

Во-первых, + C_in или + not C_in подразумевает два 32-битных добавок, один из которых оптимизируется во время синтеза, оставляя только перенос в оставшееся дополнение.

Во-вторых, вы действительно управляете только B и C_in с использованием Binv. Вычитание эквивалентно добавлению дополнения двух, для B дополнение одного из них + X"00000001. Обратите внимание, что Jim инвертирует C_in с Binv, который позволяет использовать C_in для операций цепочки цепочек (например, 64-битное добавление или вычитание с 32-битным ALU).

Обе точки проиллюстрированы с помощью следующего кода, который также использует только numeric_std.unsigned и и нуждается только без знака numeric_std."+":

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity add_sub is 
    port ( 
     a:  in std_logic_vector (31 downto 0); 
     b:  in std_logic_vector (31 downto 0); 
     binv: in std_logic; 
     c_in: in std_logic; 
     s:  out std_logic_vector (31 downto 0); 
     test: out std_logic_vector (31 downto 0); 
     c_out: out std_logic 
    ); 
end entity; 

architecture foo of add_sub is 

begin 

UNLABELLED: 
    process (a,b,c_in,binv) 
     variable x,y,z: std_logic_vector (33 downto 0); 
    begin 
     x := a(31) & a & '1'; -- this '1' generates a true carry in to z(1) 
           -- z(0) is optimized away as unused it's carry 
           -- retained as carry in to the next MS bit. 
     if binv = '0' then 
      y := b(31) & b & c_in; 
     elsif binv = '1' then 
      y := not b(31) & not b & not c_in; 
     else 
      y := (others => 'X'); -- 'X' on binv is propagated from b onto y 
     end if; 

     z := std_logic_vector(unsigned(x) + unsigned(y)); -- only one add 

     c_out <= z(33); 
     s <= z(32 downto 1); 

    end process; 
end architecture; 

В указанном выше примере соединяет C_in немного более непосредственно на этапе сумматор с LS битами а и в, и дает:

tb_add_sub_nvc.png (изображение может быть нажата, чтобы открыть)

(программное обеспечение синтеза, как правило, достаточно умен, чтобы сделать Л.Л. это с использованием формы Джимы модифицирована либо добавить или вычесть на основе Binv и A и B продлен до 33 бит без какого-либо прямого бита или битовой манипуляции, имели наши инструменты синтеза более чем 25 лет, чтобы получить это право.)

сигнал был получен с помощью следующего испытательного стенда:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity tb_add_sub is 
end entity; 

architecture foo of tb_add_sub is 
    signal a:  std_logic_vector (31 downto 0) := (others =>'0'); 
    signal b:  std_logic_vector (31 downto 0) := (others =>'0'); 
    signal binv: std_logic := '0'; 
    signal c_in: std_logic := '0'; 
    signal s:  std_logic_vector (31 downto 0); 
    signal test: std_logic_vector (31 downto 0); 
    signal c_out: std_logic; 

begin 

DUT: 
    entity work.add_sub 
     port map ( 
      a => a, 
      b => b, 
      binv => binv, 
      c_in => c_in, 
      s => s, 
      test => test, 
      c_out => c_out 
     ); 

STIMULUS: 
    process 
    begin 
     wait for 100 ns; 
     a <= std_logic_vector(to_signed(50,a'length)); 
     b <= std_logic_vector(to_signed(30,b'length)); 
     wait for 100 ns; 
     binv <= '1'; 
     wait for 100 ns; 
     binv <= '0'; 
     a <= std_logic_vector(to_signed(30,a'length)); 
     b <= std_logic_vector(to_signed(-50,b'length)); 
     wait for 100 ns; 
     binv <= '1'; 
     b <= std_logic_vector(to_signed(50,b'length)); 
     wait for 600 ns; 
     wait; 
    end process; 
end architecture; 
+0

«this '1' генерирует истинное перенос в z (1)« Я не понимаю, почему вы не просто использовали 31 downto 0 – raaj

+0

О, я понял. Как вы даже думаете об этом методе?Я должен был записать его на бумаге, чтобы получить его – raaj

+1

Я подумал об этом, читая ваш вопрос и ответ Джима сегодня утром, и увидев второе дополнение, которое нужно занести. Я задавался вопросом, почему вы выражали сумматор/вычитатель без «- ». Похоже, вы визуализировали аппаратное обеспечение. Остальное выразилось в VHDL, поэтому оборудование показало еще немного. – user1155120

0

enter code here Ваш уравнение для вычитания неверно. Как @neodelphi предложил, он должен быть:

A - B = A + (not B) + 1 

Однако это не учитывает перенос в и что с ним делать. Если я правильно помню, то заимствуют вычитается:

A - B - C_in = A + (not B) + 1 - C_in = A + (not B) + (1 - C_in) 

Теперь обратите внимание, что:

(1 - C_in) = not C_in 

Теперь, чтобы преобразовать его в VHDL. Если я упускать из виду тот факт, что вы делаете подписанную математику с пакетом, std_logic_unsigned (гм), можно написать (по аналогии с @neodelphi):

S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in ; 

Примечание в пакете std_logic_unsigned, а также numeric_std с VHDL-2008 , нет проблем с добавлением с помощью std_ulogic.

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

Кроме того, использование соответствующего типа важно, так как математические пакеты позволяют добавлять два значения массива разных размеров. Если вы используете соответствующий тип, они выполняют соответствующий бит расширения для репликации расширения для подписанного или «0» заполнения для неподписанных.

Таким образом, если бы вы использовали тип подписи, то вы могли бы использовать первый аргумент (А) размера результата и были ленивы B и написано:

S_wider <= (A(31)& A) + not B + not C_in ; 

BTW, тестирование как для «0» и '1' никоим образом не помогает аппаратным средствам. Моя рекомендация состоит в том, чтобы либо быть ленивым (и безопасно) и написать:

if Binv = '0' then 
    S_wider <= (A(31) & A) + (B(31) & B) + C_in; 
else 
    S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in; 
end if; 

Поочередно быть параноиком и бдительными и сделать вывод «X», когда вход управления является «X». Однако не забудьте дважды проверить выражение «elsif» - сделайте это неправильно, когда оно более сложное, и может быть сложно найти ошибку (что означает, что вам лучше иметь тестовые примеры, которые охватывают все возможные входные значения элементов управления):

if Binv = '0' then 
    S_wider <= (A(31) & A) + (B(31) & B) + C_in; 
elsif Binv = '1' then 
    S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in; 
else 
    S_wider <= (others => 'X') ; -- X in propagates as X out can help debug 
end if; 
0

AddSub модуль имеет только один вход управления позволяет назвать его \ бар {добавить}/к югу. Это означает, что если add_sub равен нулю, выполните операцию добавления, если она выполняет вычитание.

Существует твердая связь между C_in и Binv. Если вы хотите добавить Binv и C_in равны нулю, если вы хотите вычесть, оба они равны единице.

Уравнение сумматор просто S := A + B + 0 для вычитающего может быть извлечено с помощью некоторых преобразований:

S := A - B       -- transform into an add operation 
S := A + (- B)      -- transform negative number using 2's complement 
S := A + (2's complement of B)  -- transform 2's complement into 1's complement 
S := A + ((1's complement of B) + 1) -- transform 1's complement into bit wise not operation 
S := A + ((bit wise not of B) + 1) 

Если объединить оба уравнения, вы получите:

S := A + (B xor vector(add_sub)) + add_sub 

Таким образом, в VHDL этой будет:

S_wider <= unsigned('0' & A) + unsigned('0' & (B xor (B'range => add_sub))) + unsigned((B'range => '0') & add_sub); 
S  <= S_wider(S'range); 
C_out <= S_wider(S_width'high); 

Синтез достаточно умен, чтобы плавать d a 3: 1 сумматор с переключаемым постоянным входом 3, являющимся блоком addub-macro. Если вы хотите выполнить подписанный add/sub, замените соответственно функции преобразования и расширения подписки.

Смежные вопросы