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