4-битный двоичный делитель VHDL

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

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;


    entity Div is
    Port ( Ain   : in  STD_LOGIC_VECTOR (3 downto 0);
       Bin   : in  STD_LOGIC_VECTOR (3 downto 0);
       Q   : out  STD_LOGIC_VECTOR (3 downto 0);
       R   : out  STD_LOGIC_VECTOR (3 downto 0));
    end Div;

architecture Behavioral of Div is
Signal Atemp : Std_Logic_Vector (3 downto 0);
begin


Proc1: Process (Ain,Bin, Atemp)
variable cnt : STD_LOGIC_Vector(3 downto 0);
begin


if (Ain < Bin) then
        cnt := "0000";
        Atemp <= Ain;
elsif (Ain = Bin) then
        cnt := "0001";
elsif (Ain > Bin) then
        cnt := "0001";
        Atemp <= (Ain - Bin);
        while (Atemp >= Bin) loop
            if(Atemp >=Bin) then
                Atemp <= (Atemp - Bin);
                cnt := cnt + "0001";
            end if;
        end loop;
end if;
Q <= cnt;
R <= Atemp;
end process Proc1;
end Behavioral;

person user3034001    schedule 25.11.2013    source источник
comment
На чем ты застрял? У вас есть ошибки компиляции? Вы имитируете свой дизайн? Нам нужно больше подробностей от вас о вашей конкретной проблеме.   -  person Russell    schedule 26.11.2013
comment
@peter я получаю предупреждения ПРЕДУПРЕЖДЕНИЕ: Xst: 1710 - FF/Latch ‹0› (без значения инициализации) имеет постоянное значение 0 в блоке ‹2›(‹3›‹div›). Этот FF/Latch будет обрезан в процессе оптимизации. и ПРЕДУПРЕЖДЕНИЕ:Xst:737 - Обнаружена 4-битная защелка для сигнала ‹cnt› (и Atemp). Защелки могут быть сгенерированы из неполных операторов case или if. Мы не рекомендуем использовать защелки в конструкциях FPGA/CPLD, так как они могут привести к проблемам с синхронизацией.   -  person user3034001    schedule 26.11.2013


Ответы (2)


В итерационной части процесса деления, когда Ain > Bin, всегда выполняется назначение Atemp <= (Ain - Bin), даже если итерация должна быть завершена. Процесс, который присваивается сигналу также в списке чувствительности, трудно сделать правильно.

Вместо этого код может быть обновлен с помощью Atemp в качестве переменной, некоторых других упрощений с удалением ненужного кода и добавлением значения для остатка при Ain = Bin, что приводит к следующей архитектуре:

architecture Behavioral of Div is
begin

  Proc1 : process (Ain, Bin) is
    variable cnt   : std_logic_vector(3 downto 0);
    variable Atemp : std_logic_vector(3 downto 0);
  begin
    if (Ain < Bin) then
      cnt   := "0000";
      Atemp := Ain;
    elsif (Ain = Bin) then
      cnt := "0001";
      Atemp := (others => '0');  -- Added to give correct remainder
    elsif (Ain > Bin) then
      cnt   := "0001";
      Atemp := (Ain - Bin);
      while (Atemp >= Bin) loop
        -- Removed trivial true if statement, since condition identical to condition in while
        Atemp := (Atemp - Bin);
        cnt   := cnt + "0001";
      end loop;
    end if;
    Q <= cnt;
    R <= Atemp;
  end process Proc1;

end Behavioral;

Внутренние операторы процесса могут быть сокращены до:

cnt   := "0000";
Atemp := Ain;
while (Atemp >= Bin) loop
  Atemp := (Atemp - Bin);
  cnt   := cnt + "0001";
end loop;
Q <= cnt;
R <= Atemp;

Будет ли это синтезироваться на требуемую частоту с развернутой while — это другой вопрос, который зависит от целевой частоты и технологии.

Альтернативное решение, учитывая короткие Ain и Bin, состоит в том, чтобы реализовать делитель с использованием постоянной таблицы поиска с адресом Ain & Bin и выводом Q & R. Это будет оцениваться за фиксированное время, и синтез, скорее всего, значительно сократится, если он будет выполнен как комбинаторная логика.

Последний комментарий заключается в том, что вы также можете захотеть обработать деление на ноль, когда Bin равно нулю.

person Morten Zilmer    schedule 25.11.2013
comment
Спасибо @MortenZdk, это сработало нормально, все, что мне нужно было сделать, это добавить AND (cnt ‹ 1111) к циклу while, чтобы компилятор признал, что он не бесконечен. - person user3034001; 26.11.2013
comment
@user3034001 user3034001, если это решение сработало для вас, нажмите на галочку рядом с ответом, чтобы вопрос был помечен как отвеченный. - person Russell; 26.11.2013

Во избежание ошибок при реализации арифметических схем рекомендуется явно использовать беззнаковый или знаковый тип. Пакет numeric_std содержит следующие арифметические операторы для этих типов: +, -, *, /, abs, rem, mod.

Ниже приведен рекомендуемый код (для беззнакового деления). Обратите внимание, что некоторые строки в арке могут быть удалены, но они были использованы для того, чтобы сделать код более «поучительным».

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

entity divider is
  generic (size: natural := 4);
  port ( 
    A: in std_logic_vector(size-1 downto 0);
    B: in std_logic_vector(size-1 downto 0);
    Q: out std_logic_vector(size-1 downto 0);
    R: out std_logic_vector(size-1 downto 0));
end entity;

architecture direct of divider is 
  signal Auns, Buns, Quns, Runs: unsigned(size-1 downto 0);
begin 

  --Convert inputs to unsigned:
  Auns <= unsigned(A);
  Buns <= unsigned(B);

  --Do the division:
  Quns <= Auns/Buns;
  Runs <= Auns rem Buns; --Or: Runs <= Auns - resize(Quns*Buns, size);

  --Covert results to std_logic_vector:
  Q <= std_logic_vector(Quns);
  R <= std_logic_vector(Runs);  

end architecture
person VAP    schedule 26.11.2013