2015-11-20 2 views
0

Привет, я пытаюсь создать 32-разрядный сумматор с несколькими кодами операций, и у меня это работает достаточно хорошо, за исключением двух случаев, и я не могу найти, что их вызывает. Возможно ты можешь помочь мне?Реализация ALU с ADDER

Сбой при вычитании по какой-либо причине по ошибке и по ошибке ADDC не может вычислить правильный вывод, когда он должен использовать бит переноса в c_reg, который был создан операцией ADDS.

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 
USE ieee.numeric_std.ALL; 

ENTITY ALU IS 
    GENERIC(WIDTH : NATURAL := 32); 
    PORT(Clk : IN STD_LOGIC := '0'; 
     Reset : IN STD_LOGIC := '0'; 
     A  : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0'); 
     B  : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0'); 
     Op  : IN STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0'); 
     Outs : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0)); 
END ALU; 

ARCHITECTURE arch_ALU OF ALU IS 

    COMPONENT adder 
    PORT(OpA : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0); 
     OpB : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0); 
     Cin : IN STD_LOGIC; 
     Cout : OUT STD_LOGIC; 
     Result : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0)); 
END COMPONENT; 

    SIGNAL adder_output : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0'); 
    SIGNAL B_neg  : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0'); 
    SIGNAL c_flag : STD_LOGIC := '0'; 
    SIGNAL c_reg : STD_LOGIC := '0'; 
    SIGNAL cin  : STD_LOGIC := '0'; 

BEGIN 

adder_comp : adder 
    PORT MAP(OpA => A, 
      OpB => B_neg, 
      Cin => cin, 
      Result => adder_output, 
      Cout => c_flag);   

    WITH Op SELECT 
     B_neg <= NOT(B) WHEN "1000", 
        B WHEN OTHERS; 

    WITH Op SELECT 
     cin <= '1'  WHEN "1000", -- SUB 
       c_reg WHEN "0111", -- ADDC 
       '0'  WHEN OTHERS; -- ADD/ADDS  

    ALU_Process: 
    PROCESS(Clk) 
    BEGIN 
     IF Reset = '0' THEN 
      Outs <= (OTHERS => '0'); 
     ELSIF rising_edge(Clk) THEN 
      CASE Op IS 
       WHEN "0001" => Outs <= A AND B; 
       WHEN "0010" => Outs <= A OR B; 
       WHEN "0011" => Outs <= A NOR B; 
       WHEN "0100" => Outs <= A XOR B; 
       WHEN "0101" => Outs <= adder_output; -- ADD 
       WHEN "0110" => Outs <= adder_output; -- ADDS 
        c_reg <= c_flag;  
       WHEN "0111" => Outs <= adder_output; -- ADDC 
       WHEN "1000" => Outs <= adder_output; -- SUB 
       WHEN "1001" => Outs <= STD_LOGIC_VECTOR(UNSIGNED(A) SLL to_integer(UNSIGNED(B(4 DOWNTO 0)))); 
       WHEN "1010" => Outs <= STD_LOGIC_VECTOR(unsigned(A) SRL to_integer(UNSIGNED(B(4 DOWNTO 0)))); 
       WHEN "1011" => Outs <= STD_LOGIC_VECTOR(shift_right(SIGNED(A),to_integer(UNSIGNED(B(4 DOWNTO 0))))); 
       WHEN OTHERS => Outs <= (OTHERS => '0'); 
      END CASE; 
     END IF; 
    END PROCESS; 
END arch_ALU; 

Только операция добавляет должна написать это вынос в c_reg и эксплуатацию ADDC следует принимать c_reg во внимание при расчете на его выход Сумматор протестирован и работают правильно, так что проблема не в конструкции сумматора ,

Прежде всего, я хотел бы узнать проблему вычитания, потому что это делает вычитание, но результат немного откусил .. Например:

A: h'E6A4960F B: h'7B494E34 Op: d'1000 Ушли: h'6B5B47DA в то время как он должен быть h'6B5B47DB

A: h'EFDE31A3 B: h'0BCAB8FA Op: d'1000 Out: h'E41378BB в то время как должен быть h'E41378A9

Можете ли вы рассказать о своей ошибке? Потому что я, конечно, не могу ..

ответ

1

В то время как вы не предоставили Minimal, Complete, and Verifiable example читателя может по крайней мере испытать вычитаем части дизайна, которые присутствуют:

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

entity alu is 
    generic (width: natural := 32); 
    port (
     clk:  in std_logic := '0'; 
     reset: in std_logic := '0'; 
     a:  in std_logic_vector(width - 1 downto 0) := (others => '0'); 
     b:  in std_logic_vector(width - 1 downto 0) := (others => '0'); 
     op:  in std_logic_vector(3 downto 0) := (others => '0'); 
     outs: out std_logic_vector(width - 1 downto 0) 
    ); 
end alu; 

architecture arch_alu of alu is 

--  component adder 
--  port (
--   opa:  in std_logic_vector(width - 1 downto 0); 
--   opb:  in std_logic_vector(width - 1 downto 0); 
--   cin:  in std_logic; 
--   cout: out std_logic; 
--   result: out std_logic_vector(width - 1 downto 0) 
-- ); 
-- end component; 

    procedure adder (
     signal opa:  in std_logic_vector(width - 1 downto 0); 
     signal opb:  in std_logic_vector(width - 1 downto 0); 
     signal cin:  in std_logic; 
     signal cout: out std_logic; 
     signal result: out std_logic_vector(width - 1 downto 0) 
    ) is 
     variable sum: unsigned (width downto 0); 
    begin 
     sum := unsigned('0' & opa) + unsigned(opb) + unsigned'(""& cin); 
     result <= std_logic_vector(sum (width - 1 downto 0)); 
     cout <= sum(width); 
    end procedure; 

    signal adder_output: std_logic_vector(width - 1 downto 0) := (others => '0'); 
    signal b_neg:   std_logic_vector(width - 1 downto 0) := (others => '0'); 
    signal c_flag:  std_logic := '0'; 
    signal c_reg:   std_logic := '0'; 
    signal cin:   std_logic := '0'; 

begin 

adder_comp: 
    adder 
     -- port map (
     (
      opa => a, 
      opb => b_neg, 
      cin => cin, 
      result => adder_output, 
      cout => c_flag 
     );   

    with op select 
     b_neg <= not b when "1000", 
        b when others; 

    with op select 
     cin <= '1'  when "1000", -- sub 
       c_reg when "0111", -- addc 
       '0'  when others; -- add/adds  

alu_process: 
    process(clk) 
    begin 
     if reset = '0' then 
      outs <= (others => '0'); 
     elsif rising_edge(clk) then 
      case op is 
       when "0001" => outs <= a and b; 
       when "0010" => outs <= a or b; 
       when "0011" => outs <= a nor b; 
       when "0100" => outs <= a xor b; 
       when "0101" => outs <= adder_output; -- add 
       when "0110" => outs <= adder_output; -- adds 
           c_reg <= c_flag;  
       when "0111" => outs <= adder_output; -- addc 
       when "1000" => outs <= adder_output; -- sub 
       when "1001" => outs <= std_logic_vector (
        unsigned(a) sll to_integer(unsigned(b(4 downto 0))) 
       ); 
       when "1010" => outs <= std_logic_vector (
        unsigned(a) srl to_integer(unsigned(b(4 downto 0))) 
       ); 
       when "1011" => outs <= std_logic_vector ( 
        shift_right(signed(a),to_integer(unsigned(b(4 downto 0)))) 
       ); 
       when others => outs <= (others => '0'); 
      end case; 
     end if; 
    end process; 
end arch_alu; 

library ieee; 
use ieee.std_logic_1164.all; 

entity alu_tb is 
end entity; 

architecture foo of alu_tb is 
    constant width: integer := 32; 
    signal clk:  std_logic := '0'; 
    signal reset: std_logic := '0'; 
    signal a:  std_logic_vector(width - 1 downto 0) := (others => '0'); 
    signal b:  std_logic_vector(width - 1 downto 0) := (others => '0'); 
    signal op:  std_logic_vector(3 downto 0) := (others => '0'); 
    signal outs: std_logic_vector(width - 1 downto 0); 
begin 
CLOCK: 
    process 
    begin 
     wait for 10 ns; 
     clk <= not clk; 
     if Now > 90 ns then 
      wait; 
     end if; 
    end process; 
DUT: 
    entity work.alu 
     port map (
      clk => clk, 
      reset => reset, 
      a => a, 
      b => b, 
      op => op, 
      outs => outs 
     ); 

STIMULUS: 
    process 
    begin 
     wait for 20 ns; 
     reset <= '1'; 
     a <= x"E6A4960F"; 
     b <= x"7B494E34"; 
     op <= "1000"; 
     wait for 20 ns; 
     a <= x"EFDE31A3"; 
     b <= x"0BCAB8FA"; 
     wait for 20 ns; 
     wait; 
    end process; 
end architecture; 

Я написал быстрый и грязный процедуры сумматор. Это устраняет сущность/архитектуру сумматора и декларацию компонента.

Я добавил простой тестовый стенд для двух вычитаний, что исключает ваш стенд или процедуру тестирования.

И это дает:

alu_tb.png

И как вы можете видеть результаты, что вы утверждаете, как правильно.

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

Итак, что мы получаем от этого, так это то, что вы не представили достаточно информации, чтобы определить, где ошибка.

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

+0

Да, спасибо за отличный ответ, мне дали сумматор, и это сказал, что он проверен и проверен. Я просто испытал один и тот же дизайн с моим дизайном переноса пульсаций, и он работал безупречно. Думаю, мне придется отлаживать сумку тогда :) – Pethead

0

Чтобы вычесть B из A, вам не нужно использовать уравнение A + (not B), но A + (not B) + 1. Добавив это значение 1, вы вернетесь к двум предыдущим вычислениям (вы можете использовать ввод переноса для добавления 1 без вычисления).

В case вы назначаете c_reg только тогда, когда это опкод 0110, но делает это так, вы никогда не сбросить значение c_reg. Вы должны назначить его также во всех остальных случаях 0, чтобы у вас было правильное значение, когда код операции 0110.

Еще одна деталь: добавьте Reset сигнал в список чувствительности с помощью Clk, чтобы вы создали триггер.

Это то, что я вижу. Но если вы добавите пример неправильного выполнения с операциями ADDS, более легко понять, где проблема.

+0

Да, я знаю, как сделать вычитание, и это именно то, что я пытаюсь сделать. В первом выборе я устанавливаю B_neg <= NOT (B), а во втором select я устанавливаю cin <= '1', но расчет по-прежнему неверен. :/ – Pethead

+0

Должен ли я перезагрузить c_reg в других случаях? Поскольку это должна быть только операция ADDS, которая записывает c_reg, и ADDC следует читать из нее при выполнении добавления. Один пример, когда операция ADDC при создании неправильного результата после ADDS на A = h'978A8254 и B = h'E3E0A965, и это устанавливает c_Reg = '1'. Затем я запускаю коды операций «0100», «1011», «0101» и, наконец, «0111», а результат ошибочный, конечный результат неверен:/ – Pethead

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