Reputation: 11
I am trying to make a binary divider to be part of a calculator using VHDL, I have written the code that I think should work but have been stuck for hours, can someone please help me.
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;
Upvotes: 1
Views: 21855
Reputation: 551
To prevent mistakes, it is advisable to use explicitly the type unsigned or signed when implementing arithmetic circuits. The numeric_std package contains the following arithmetic operators for these types: +, -, *, /, abs, rem, mod.
Below is a suggested code (for unsigned division). Note that some lines in the arch can be eliminated, but were used to make the code more "didactic".
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
Upvotes: 2
Reputation: 15924
In the iteration part of the divide process, when Ain > Bin
, the assign
Atemp <= (Ain - Bin)
is always performed, even if the iteration should be
completed. Process that assign to a signal also in the sensitivity list, is
hard to get right.
The code may be updated with Atemp as a variable instead, some other
simplifications with removal of unrequired code, and adding value for remainder
when Ain = Bin
, resulting in architecture as:
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;
The inner process statements may actually be reduced to:
cnt := "0000";
Atemp := Ain;
while (Atemp >= Bin) loop
Atemp := (Atemp - Bin);
cnt := cnt + "0001";
end loop;
Q <= cnt;
R <= Atemp;
Whether this will synthesize to the required frequency with the unrolled
while
is another question, that depends on the target frequency and
technology.
An alternative solution, given the short Ain
and Bin
, is to implement the
divider using a constant lookup table, with address as Ain & Bin
and output
of Q & R
. This will evaluate in fixed time, and synthesis is very likely to
reduce considerably if made as combinatorial logic.
Last comment is that you may also want to handle division by zero, when Bin
is zero.
Upvotes: 3