URL
https://opencores.org/ocsvn/System09/System09/trunk
Subversion Repositories System09
[/] [System09/] [trunk/] [rtl/] [VHDL/] [divs32_s2.vhd] - Rev 171
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