FPGAs are very useful when calculating plus or minus or dealing with large logic-vectors. Even multiplication is fine. But when it comes to dividing signals, FPGAs need support. Lothar Miller has a nice implemenation of a Radix-2-procedure to calculate the division of two fixed-point-numbers:

VHDL
-- Source: http://www.lothar-miller.de/s9y/categories/24-Rechnen

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity divider is
	generic (
		bit_width	:	natural range 4 to 48 := 32
	);
	port (
		clk			:	in   std_logic;
		start			:	in   std_logic;
		dividend		:	in   unsigned(bit_width - 1 downto 0);
		divisor		:	in   unsigned(bit_width - 1 downto 0);
		quotient		:	out  unsigned(bit_width - 1 downto 0);
		remainder	:	out  unsigned(bit_width - 1 downto 0);
		busy			:	out  std_logic
	);
end divider;

architecture Behave_Unsigned of divider is
	signal dd		:	unsigned(bit_width - 1 downto 0); -- dividend
	signal dr		:	unsigned(bit_width - 1 downto 0); -- divisor
	signal q			:	unsigned(bit_width - 1 downto 0); -- quotient
	signal r			:	unsigned(bit_width - 1 downto 0); -- remainder
	signal bits		:	integer range bit_width downto 0;
	type t_SM_state is (idle, prepare, shift, sub, done);
	signal s_SM_Main : t_SM_state;
begin

   process 
		variable diff : unsigned(bit_width - 1 downto 0);
   begin
      wait until rising_edge(clk);
      case s_SM_Main is 
         when idle => 
            if (start='1') then 
               s_SM_Main <= prepare; 
               busy <= '1';
            end if;
            dd <= dividend;
            dr <= divisor;

         when prepare =>
            q <= (others=>'0');
            r <= (others=>'0');
            s_SM_Main <= shift;            
            bits <= bit_width;
				
            -- Special case 1: Division by Zero
            if (dr = 0) then  
               q <= (others=>'1');
               r <= (others=>'1');
               s_SM_Main <= done;
					
            -- Special case 2: Divisor larger than Dividend
            elsif (dr > dd) then 
               r <= dd;
               s_SM_Main <= done;
					
            -- Special case 3: Divisor equals Dividend
            elsif (dr = dd) then
               q <= to_unsigned(1, bit_width);
               s_SM_Main <= done;
            end if;

         when shift =>
				-- first, move the two operands for the subtraction into place
            if ( (r(bit_width - 2 downto 0) & dd(bit_width - 1)) < dr) then
               bits <= bits - 1;
               r    <= r(bit_width - 2 downto 0) & dd(bit_width - 1);
               dd   <= dd(bit_width - 2 downto 0) & '0';
            else
               s_SM_Main <= sub;
            end if;

         when sub =>
            if (bits > 0) then
               r    <= r(bit_width - 2 downto 0) & dd(bit_width - 1);
               dd   <= dd(bit_width - 2 downto 0) & '0';
					
               -- remainder minus divisor
               diff := (r(bit_width - 2 downto 0) & dd(bit_width -1)) - dr;  
               if (diff(bit_width - 1)='0') then                 
                  -- if no underrun
                  --> divisor is fitting
                  --> MSB=0 --> 1 shift into result
                  q <= q(bit_width - 2 downto 0) & '1';
                  r <= diff;
               else
                  -- if underrund
                  --> shift 0, calculate with old value
                  q <= q(bit_width - 2 downto 0) & '0';
               end if;
               bits <= bits - 1;
            else
               s_SM_Main <= done;
            end if;
            
         when done =>
            busy <= '0';

				-- wait, until start signal is set to 0
            if (start = '0') then 
               s_SM_Main <= idle; 
            end if;
      end case;
   end process;
   
   quotient  <= q;
   remainder <= r;
end;

Leave a comment

Your email address will not be published. Required fields are marked *