OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [divu32_s2.vhd] - Rev 159

Go to most recent revision | Compare with Previous | Blame | View Log

--===========================================================================--
--                                                                           --
--                  Synthesizable unsigned 32 bit integer divider            --
--                                                                           --
--===========================================================================--
--
--  File name      : divu32.vhd
--
--  Entity name    : udiv32
--
--  Purpose        : Implements a 32 bit unsigned integer divider 
--                  
--  Dependencies   : ieee.std_logic_1164
--                   ieee.numeric_std
--                   ieee.std_logic_unsigned
--
--  Author         : John E. Kent
--
--  Email          : dilbert57@opencores.org      
--
--  Web            : http://opencores.org/project,system09
--
--  Registers      :
--  0 Dividend  1st Byte MSB
--  1           2nd Byte
--  2           3rd Byte 
--  3           4th Byte LSB
--  4 Divisor   1st Byte MSB
--  5           2nd Byte
--  6           3rd Byte
--  7           4th Byte LSB
--  8 Result    1st Byte MSB
--  9           2nd Byte
-- 10           3rd Byte
-- 11           4th byte LSB
-- 12 Remainder 1st Byte MSB
-- 13           2nd Byte
-- 14           3rd Byte
-- 15           4th byte LSB
--
--  32 bit unsigned binary division.
--
--  Write the most significant byte of the dividend at the 0th register first 
--  down to the least significant byte of the divisor in the 7th register.
--  Writing the least significant byte of the divisor will start the division.
--
--  The 32 bit division will take 32 clock cycles.
--  There is no status register so the CPU must execute a software delay
--  to wait 32 clock cycles after the least significant byte of the divisor 
--  is written before reading the result of the division or the remainder.
--
--  The dividend and divisor input registers are read/writable
--  The result and remainder output registers are read only.
--  The result register holds the integer part of the result of the division.
--  The remainder register holds the dividend modulo the divisor.
--
--  Copyright (C) 2012 - 2014 John Kent
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation, either version 3 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
--===========================================================================--
--                                                                           --
--                              Revision  History                            --
--                                                                           --
--===========================================================================--
--
-- Version Author        Date         Changes
--
-- 0.1     John Kent     2012-04-06    Initial version
-- 0.2     John Kent     2014-05-07    Replaced Status register with 4 byte remainder
-- 0.3     John Kent     2016-02-04    Shortend result_temp to 33 bits so subtraction is faster.
--                                     Add hold output to pause CPU until result is valid.
 
library ieee;
  use ieee.std_logic_1164.all;
  use ieee.numeric_std.all;
  use ieee.std_logic_unsigned.all;
--library unisim;
--  use unisim.vcomponents.all;
 
entity udiv32 is
  port (
    --
    -- CPU Interface signals
    --
    clk      : in  std_logic;                     -- CPU Clock
    rst      : in  std_logic;                     -- Reset input (active high)
    cs       : in  std_logic;                     -- Chip Select
    addr     : in  std_logic_vector(3 downto 0);  -- Register Select
    rw       : in  std_logic;                     -- Read / Not Write
    data_in  : in  std_logic_vector(7 downto 0);  -- Data Bus In 
    data_out : out std_logic_vector(7 downto 0);  -- Data Bus Out
	 hold     : out std_logic                      -- Result access hold
    );
end udiv32;  
--================== End of entity ==============================--
 
-------------------------------------------------------------------
-- Architecture for unsigned 32 bit integer divider interface
-------------------------------------------------------------------
 
architecture rtl of udiv32 is
 
signal dividend      : std_logic_vector(31 downto 0) := (others => '0');
signal divisor       : std_logic_vector(31 downto 0) := (others => '0');
signal result        : std_logic_vector(31 downto 0) := (others => '0');
signal remainder     : std_logic_vector(63 downto 0) := (others => '0');
signal count         : std_logic_vector( 4 downto 0) := (others => '0');
signal req_flag      : std_logic := '0';  -- Request Division
signal act_flag      : std_logic := '0';  -- Division Active
 
begin
 
--
-- Write registers
--
udiv32_write : process( clk, rst, cs, rw, addr, data_in, act_flag, req_flag )
begin
  if rst = '1' then
      dividend    <= (others=> '0');   -- reset the dividend to zero
      divisor     <= (others=> '0');   -- reset the divisor to zero
      req_flag    <= '0';				   -- the default state is stopped
  elsif falling_edge( clk ) then
      --
      -- write to registers
      --
      if (cs = '1') and (rw = '0') then
        case addr is
        when "0000" =>
          dividend(31 downto 24) <= data_in;
        when "0001" =>
          dividend(23 downto 16) <= data_in;
        when "0010" =>
          dividend(15 downto  8) <= data_in;
        when "0011" =>
          dividend( 7 downto  0) <= data_in;
        when "0100" =>
          divisor(31 downto 24)  <= data_in;
        when "0101" =>
          divisor(23 downto 16)  <= data_in;
        when "0110" =>
          divisor(15 downto  8)  <= data_in;
        when "0111" =>
          divisor( 7 downto  0)  <= data_in;
          --
          -- writing the last byte of the divisor 
			 -- should pulse the request flag high for one cycle 
			 -- starting the division,
          -- provided the previous division has finished
          --
			 if (act_flag = '0') and (req_flag = '0') then
				req_flag <= '1';
			 end if;
        when others =>
           null;
        end case;
      end if;
  end if; -- rst/clk
  if( act_flag = '1') and (req_flag = '1') then
    req_flag <= '0';
  end if;
  hold <= cs and rw and addr(3) and act_flag;
end process;
 
--
-- Read registers
--
udiv32_read : process( addr, dividend, divisor, result, remainder )
begin
  case addr is
  when "0000" =>
    data_out <= dividend(31 downto 24);
  when "0001" =>
    data_out <= dividend(23 downto 16);
  when "0010" =>
    data_out <= dividend(15 downto  8);
  when "0011" =>
    data_out <= dividend( 7 downto  0);
  when "0100" =>
    data_out <= divisor(31 downto 24);
  when "0101" =>
    data_out <= divisor(23 downto 16);
  when "0110" =>
    data_out <= divisor(15 downto  8);
  when "0111" =>
    data_out <= divisor( 7 downto  0);
  when "1000" =>
    data_out <= result(31 downto 24);
  when "1001" =>
    data_out <= result(23 downto 16);
  when "1010" =>
    data_out <= result(15 downto  8);
  when "1011" =>
    data_out <= result( 7 downto  0);
  when "1100" =>
    data_out <= remainder(63 downto 56);
  when "1101" =>
    data_out <= remainder(55 downto 48);
  when "1110" =>
    data_out <= remainder(47 downto 40);
  when "1111" =>
    data_out <= remainder(39 downto 32);
  when others =>
    null;
  end case;
end process;
 
--
-- When the finish flag is high and the start flag goes high, 
-- start the division by clearing the finish flag
-- When the finish flag is low and the count reaches 31 
udiv32_divide : process( rst, clk, req_flag, act_flag )
variable remainder_temp    : std_logic_vector(32 downto 0);
begin
    if (rst = '1') then
      remainder      <= (others=>'0');
      remainder_temp := (others=>'0');
      result         <= (others=>'0');
      count          <= (others=>'0');
      act_flag       <= '0';             -- default state is inactive
    elsif falling_edge( clk ) then
      --
      -- activate the division if the last division was complete
		-- i.e. the active flag was clear
      -- and the last byte of the divisor was just written
      -- i.e. the request flag was pulsed high for one clock cycle
		--
      if (req_flag = '1') and (act_flag = '0') then
        remainder(63 downto 32) <= (others => '0');            -- Clear Most Significant Word of remainder
        remainder(31 downto  0) <= dividend(31 downto 0);      -- Dividend in the Least Significant Word of remainder
        remainder_temp          := (others => '0');            -- Clear the remainder temp variable
        count                   <= (others => '0');            -- Clear the bit counter
        act_flag                <= '1';                        -- Flag division in progress
 
      elsif (req_flag = '0') and (act_flag = '1') then                              -- If active flag is set the division must be in progress
 
        remainder_temp := (remainder(63 downto 31)) - ("0" & divisor);   -- subtract the divisor from the remainder
 
        if remainder_temp(32) = '0' then                           -- if the remainder temp carry is clear
          remainder(63 downto 32) <= remainder_temp(31 downto 0);  -- update the remainder variable with remainder temp
        else
          remainder(63 downto 32) <= remainder(62 downto 31);      -- shift remainder up one bit
		  end if;
        remainder(31 downto  1) <= remainder(30 downto 0);         -- shift remainder up one bit
		  remainder(0) <= '0';
 
        --
        -- shift the result up one bit
        -- The LSBit is the inverted remainder carry
        --
        result(31 downto 1) <= result(30 downto 0);
        result(0)           <= not remainder_temp(32);
        --
        -- 32 bit division should take 32 clock cycles
        --
        count               <= count + "00001";
        --
		  -- When the count reaches the 31st cycle of the division 
        -- flag that the division is complete by clrearing the active flag.
        -- 
        if count = "11111" then
          act_flag <= '0';  -- flag division complete
        end if;
 
      end if; -- start/finish
    end if; -- rst/clk
end process;
 
end rtl; -- end of architecture

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.