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

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [divs32_s2.vhd] - Rev 206

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

--===========================================================================--
--                                                                           --
--                  Synthesizable unsigned 32 bit integer divider            --
--                                                                           --
--===========================================================================--
--
--  File name      : divs32.vhd
--
--  Entity name    : sdiv32
--
--  Purpose        : Implements a 32 bit signed 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 quotient    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 quotient of the division or the remainder.
--
--  The dividend and divisor input registers are read/writable
--  The quotient and remainder output registers are read only.
--  The quotient 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.
-- 0.4     John Kent     2018-03-21    Changed unsigned udiv32 to signed sdiv32
--
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 sdiv32 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 sdiv32;  
--================== End of entity ==============================--
 
-------------------------------------------------------------------
-- Architecture for unsigned 32 bit integer divider interface
-------------------------------------------------------------------
 
architecture rtl of sdiv32 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(63 downto 0) := (others => '0');
signal quotient      : std_logic_vector(31 downto 0) := (others => '0');
signal remainder     : std_logic_vector(31 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
--
sdiv32_write : process( clk, rst, cs, rw, addr, data_in, req_flag, act_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 (req_flag = '0') and (act_flag = '0') then
				req_flag <= '1';
			 end if;
        when others =>
           null;
        end case;
      end if;
  end if; -- rst/clk
  if (req_flag = '1') and (act_flag = '1') then
    req_flag <= '0';
  end if;
  hold <= cs and rw and addr(3) and act_flag;
end process;
 
--
-- Read registers
--
sdiv32_read : process( addr, dividend, divisor, quotient, 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 <= quotient(31 downto 24);
  when "1001" =>
    data_out <= quotient(23 downto 16);
  when "1010" =>
    data_out <= quotient(15 downto  8);
  when "1011" =>
    data_out <= quotient( 7 downto  0);
  when "1100" =>
    data_out <= remainder(31 downto 24);
  when "1101" =>
    data_out <= remainder(23 downto 16);
  when "1110" =>
    data_out <= remainder(15 downto 8);
  when "1111" =>
    data_out <= remainder(7 downto 0);
  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 
sdiv32_divide : process( rst, clk, dividend, divisor, remainder, req_flag, act_flag, count )
variable result_temp  : std_logic_vector(32 downto 0);
begin
    if (rst = '1') then
	   result          <= (others=>'0');
		result_temp     := (others=>'0');
      remainder       <= (others=>'0');
      quotient        <= (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  
		  --
		  -- put dividend in result and make positive
		  --
        result(63 downto 32) <= (others => '0');
		  if dividend(31) = '0' then
          result(31 downto  0) <= dividend;                 -- Dividend in the Least Significant Word of remainder
		  else
		    result(31 downto  0) <= "00000000000000000000000000000000" - dividend;
		  end if;
		  --
		  -- Initialize temp variables
		  --
        result_temp        := (others => '0');            -- Clear the remainder temp variable
		  --
		  -- reset bit counter and activate division
		  --
        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
		  --
		  -- if dividend positive, subrtact divisor
		  -- if dividend negative, add divisor
		  --
        if (divisor(31)) = '0' then 
          result_temp := result(63 downto 31) - (divisor(31) & divisor);   -- subtract the divisor from the remainder if positive
        else
          result_temp := result(63 downto 31) + (divisor(31) & divisor);   -- add the divisor to the remainder if negative
        end if;
 
		  --
		  -- if carry clear from add or subract
		  -- update the remainder
		  --
        if result_temp(32) = '0' then                          -- if the remainder temp carry is clear
          result(63 downto 32) <= result_temp(31 downto 0);    -- update the result with remainder
        else
          result(63 downto 32) <= result(62 downto 31);        -- otherwise shift remainder up one bit
		  end if;
 
        --
        -- shift the quotient up one bit
        -- The LSBit is the inverted remainder carry
        --
        result(31 downto  1) <= result(30 downto 0);        -- shift lower remainder up one bit
		  result(0) <= not result_temp(32);                   -- shift quotient in bottom of remainder
 
        --
        -- 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
 
		--
		-- negating the result will take another clock cycle.
		-- If the cpu is held on a read access of the
		-- quotient or remainder it may get the wrong result.
		--
 
		--
		-- quotient has sign of dividend exclusive or divisor
		--
      if( (dividend(31) xor divisor(31)) = '0') then
        quotient <= result(31 downto 0);
      else
        quotient <= "00000000000000000000000000000000" - result(31 downto 0);
      end if;
 
		--
		-- remainder has sign of dividend
		--
		if dividend(31) = '0' then
		  remainder <= result(63 downto 32);
		else
		  remainder <= "00000000000000000000000000000000" - result(63 downto 32);
		end if;
 
    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.