From: Sam Moore Date: Thu, 10 Apr 2014 11:23:53 +0000 (+0800) Subject: Initial Commit (steal code from https://github.com/jop-devel/jop) X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fvfpu.git;a=commitdiff_plain;h=0e33e3a609436a1fd615c12592ea78b5a21f0385 Initial Commit (steal code from https://github.com/jop-devel/jop) All code in the initial commit is as it was in the jop repo at the time. jop is under GPL 3.0 Note we are only taking the fpu from /vhdl/fpu - jop is a much larger project implementing the full JVM. From this point onwards all changes are by the commit author(s). --- 0e33e3a609436a1fd615c12592ea78b5a21f0385 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..365a631 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*~ +*.ipdf +*.test +*.out +*.err diff --git a/README b/README new file mode 100644 index 0000000..6204f1d --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +This is a virtual floating point unit (FPU) implemented in VHDL. + +It is (or was as of the initial commit) stolen from the Java Optimised Processor https://github.com/jop-devel/jop + +A test bench is used to compile a simulator executable for the FPU that reads from stdin and writes results to stdout. + +The VFPU namespace in the ipdf/code repository (git://git.ucc.asn.au/ipdf/code.git) can be used to send floating +point operations to this executable. This is in the files ipdf/code/src/vhdl.cpp and ipdf/code/src/vhdl.h + +In theory this will allow us to test different hardware representations of floating point numbers. +In practice it might be beyond the scope of our project to do much with this. + diff --git a/src/addsub_28.vhd b/src/addsub_28.vhd new file mode 100644 index 0000000..21d0fbe --- /dev/null +++ b/src/addsub_28.vhd @@ -0,0 +1,128 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: addition/subtraction entity for the addition/subtraction unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; +use IEEE.std_logic_arith.all; + +library work; +use work.fpupack.all; + +entity addsub_28 is + port( + clk_i : in std_logic; + fpu_op_i : in std_logic; + fracta_i : in std_logic_vector(FRAC_WIDTH+4 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + fractb_i : in std_logic_vector(FRAC_WIDTH+4 downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + fract_o : out std_logic_vector(FRAC_WIDTH+4 downto 0); + sign_o : out std_logic); +end addsub_28; + + +architecture rtl of addsub_28 is + +signal s_fracta_i, s_fractb_i : std_logic_vector(FRAC_WIDTH+4 downto 0); +signal s_fract_o : std_logic_vector(FRAC_WIDTH+4 downto 0); +signal s_signa_i, s_signb_i, s_sign_o : std_logic; +signal s_fpu_op_i : std_logic; + +signal fracta_lt_fractb : std_logic; +signal s_addop: std_logic; + +begin + +-- Input Register +--process(clk_i) +--begin +-- if rising_edge(clk_i) then + s_fracta_i <= fracta_i; + s_fractb_i <= fractb_i; + s_signa_i<= signa_i; + s_signb_i<= signb_i; + s_fpu_op_i <= fpu_op_i; +-- end if; +--end process; + +-- Output Register +process(clk_i) +begin + if rising_edge(clk_i) then + fract_o <= s_fract_o; + sign_o <= s_sign_o; + end if; +end process; + +fracta_lt_fractb <= '1' when s_fracta_i > s_fractb_i else '0'; + +-- check if its a subtraction or an addition operation +s_addop <= ((s_signa_i xor s_signb_i)and not (s_fpu_op_i)) or ((s_signa_i xnor s_signb_i)and (s_fpu_op_i)); + +-- sign of result +s_sign_o <= '0' when s_fract_o = conv_std_logic_vector(0,28) and (s_signa_i and s_signb_i)='0' else + ((not s_signa_i) and ((not fracta_lt_fractb) and (fpu_op_i xor s_signb_i))) or + ((s_signa_i) and (fracta_lt_fractb or (fpu_op_i xor s_signb_i))); + +-- add/substract +process(s_fracta_i, s_fractb_i, s_addop, fracta_lt_fractb) +begin + if s_addop='0' then + s_fract_o <= s_fracta_i + s_fractb_i; + else + if fracta_lt_fractb = '1' then + s_fract_o <= s_fracta_i - s_fractb_i; + else + s_fract_o <= s_fractb_i - s_fracta_i; + end if; + end if; +end process; + + + + +end rtl; + diff --git a/src/bug_report.txt b/src/bug_report.txt new file mode 100644 index 0000000..495a85d --- /dev/null +++ b/src/bug_report.txt @@ -0,0 +1,15 @@ +==fpu_v16== +1) Corrected an embarrassing sytax error in "tb_fpu.vhd": start_i <= 0 to start_i <= '0' +2) In "serial_div.vhd" and "sqrt.vhd": unused bits in some signals were initialized. +3)Not need line in "fpusim.bat" was removed. + +==fpu_v17== +1)Corrected bug related to adding two denormalized operands. + +==fpu_v18== +1)post_norm_addsub.vhd: Restructured and fixed a bug +2)fpu.vhd: Altered add/sub COUNT +3)tb_fpu.vhd: Added some boundary values. + +==fpu_v19== 26. April 2007 +1)A minor bug was found and corrected when the serial multiplier is used (thanks to Chris Basson!) diff --git a/src/comppack.vhd b/src/comppack.vhd new file mode 100644 index 0000000..e6da7c4 --- /dev/null +++ b/src/comppack.vhd @@ -0,0 +1,227 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: component package +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +library work; +use work.fpupack.all; + +package comppack is + + +--- Component Declartions --- + + --***Add/Substract units*** + + component pre_norm_addsub is + port(clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + opb_i : in std_logic_vector(31 downto 0); + fracta_28_o : out std_logic_vector(27 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + fractb_28_o : out std_logic_vector(27 downto 0); + exp_o : out std_logic_vector(7 downto 0)); + end component; + + component addsub_28 is + port(clk_i : in std_logic; + fpu_op_i : in std_logic; + fracta_i : in std_logic_vector(27 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + fractb_i : in std_logic_vector(27 downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + fract_o : out std_logic_vector(27 downto 0); + sign_o : out std_logic); + end component; + + component post_norm_addsub is + port(clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + opb_i : in std_logic_vector(31 downto 0); + fract_28_i : in std_logic_vector(27 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + exp_i : in std_logic_vector(7 downto 0); + sign_i : in std_logic; + fpu_op_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(31 downto 0); + ine_o : out std_logic + ); + end component; + + --***Multiplication units*** + + component pre_norm_mul is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + opb_i : in std_logic_vector(31 downto 0); + exp_10_o : out std_logic_vector(9 downto 0); + fracta_24_o : out std_logic_vector(23 downto 0); -- hidden(1) & fraction(23) + fractb_24_o : out std_logic_vector(23 downto 0) + ); + end component; + + component mul_24 is + port( + clk_i : in std_logic; + fracta_i : in std_logic_vector(23 downto 0); -- hidden(1) & fraction(23) + fractb_i : in std_logic_vector(23 downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + start_i : in std_logic; + fract_o : out std_logic_vector(47 downto 0); + sign_o : out std_logic; + ready_o : out std_logic + ); + end component; + + component serial_mul is + port( + clk_i : in std_logic; + fracta_i : in std_logic_vector(FRAC_WIDTH downto 0); -- hidden(1) & fraction(23) + fractb_i : in std_logic_vector(FRAC_WIDTH downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + start_i : in std_logic; + fract_o : out std_logic_vector(2*FRAC_WIDTH+1 downto 0); + sign_o : out std_logic; + ready_o : out std_logic + ); + end component; + + component post_norm_mul is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + opb_i : in std_logic_vector(31 downto 0); + exp_10_i : in std_logic_vector(9 downto 0); + fract_48_i : in std_logic_vector(47 downto 0); -- hidden(1) & fraction(23) + sign_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(31 downto 0); + ine_o : out std_logic + ); + end component; + + --***Division units*** + + component pre_norm_div is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + exp_10_o : out std_logic_vector(EXP_WIDTH+1 downto 0); + dvdnd_50_o : out std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); + dvsor_27_o : out std_logic_vector(FRAC_WIDTH+3 downto 0) + ); + end component; + + component serial_div is + port( + clk_i : in std_logic; + dvdnd_i : in std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); -- hidden(1) & fraction(23) + dvsor_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + sign_dvd_i : in std_logic; + sign_div_i : in std_logic; + start_i : in std_logic; + ready_o : out std_logic; + qutnt_o : out std_logic_vector(FRAC_WIDTH+3 downto 0); + rmndr_o : out std_logic_vector(FRAC_WIDTH+3 downto 0); + sign_o : out std_logic; + div_zero_o : out std_logic + ); + end component; + + component post_norm_div is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + qutnt_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + rmndr_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + exp_10_i : in std_logic_vector(EXP_WIDTH+1 downto 0); + sign_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + ine_o : out std_logic + ); + end component; + + + --***Square units*** + + component pre_norm_sqrt is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + fracta_52_o : out std_logic_vector(51 downto 0); + exp_o : out std_logic_vector(7 downto 0)); + end component; + + component sqrt is + generic (RD_WIDTH: integer; SQ_WIDTH: integer); -- SQ_WIDTH = RD_WIDTH/2 (+ 1 if odd) + port( + clk_i : in std_logic; + rad_i : in std_logic_vector(RD_WIDTH-1 downto 0); -- hidden(1) & fraction(23) + start_i : in std_logic; + ready_o : out std_logic; + sqr_o : out std_logic_vector(SQ_WIDTH-1 downto 0); + ine_o : out std_logic); + end component; + + + component post_norm_sqrt is + port( clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + fract_26_i : in std_logic_vector(25 downto 0); -- hidden(1) & fraction(11) + exp_i : in std_logic_vector(7 downto 0); + ine_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(31 downto 0); + ine_o : out std_logic); + end component; + + +end comppack; \ No newline at end of file diff --git a/src/fpu.vhd b/src/fpu.vhd new file mode 100644 index 0000000..71b88ab --- /dev/null +++ b/src/fpu.vhd @@ -0,0 +1,465 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: top entity +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_misc.all; + +library work; +use work.comppack.all; +use work.fpupack.all; + + +entity fpu is + port ( + clk_i : in std_logic; + + -- Input Operands A & B + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); -- Default: FP_WIDTH=32 + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + + -- fpu operations (fpu_op_i): + -- ======================== + -- 000 = add, + -- 001 = substract, + -- 010 = multiply, + -- 011 = divide, + -- 100 = square root + -- 101 = unused + -- 110 = unused + -- 111 = unused + fpu_op_i : in std_logic_vector(2 downto 0); + + -- Rounding Mode: + -- ============== + -- 00 = round to nearest even(default), + -- 01 = round to zero, + -- 10 = round up, + -- 11 = round down + rmode_i : in std_logic_vector(1 downto 0); + + -- Output port + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + + -- Control signals + start_i : in std_logic; -- is also restart signal + ready_o : out std_logic; + + -- Exceptions + ine_o : out std_logic; -- inexact + overflow_o : out std_logic; -- overflow + underflow_o : out std_logic; -- underflow + div_zero_o : out std_logic; -- divide by zero + inf_o : out std_logic; -- infinity + zero_o : out std_logic; -- zero + qnan_o : out std_logic; -- queit Not-a-Number + snan_o : out std_logic -- signaling Not-a-Number + ); +end fpu; + +architecture rtl of fpu is + + + constant MUL_SERIAL: integer range 0 to 1 := 1; -- 0 for parallel multiplier, 1 for serial + constant MUL_COUNT: integer:= 34; --11 for parallel multiplier, 34 for serial + + -- Input/output registers + signal s_opa_i, s_opb_i : std_logic_vector(FP_WIDTH-1 downto 0); + signal s_fpu_op_i : std_logic_vector(2 downto 0); + signal s_rmode_i : std_logic_vector(1 downto 0); + signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0); + signal s_ine_o, s_overflow_o, s_underflow_o, s_div_zero_o, s_inf_o, s_zero_o, s_qnan_o, s_snan_o : std_logic; + + type t_state is (waiting,busy); + signal s_state : t_state; + signal s_start_i : std_logic; + signal s_count : integer; + signal s_output1 : std_logic_vector(FP_WIDTH-1 downto 0); + signal s_infa, s_infb : std_logic; + + -- ***Add/Substract units signals*** + + signal prenorm_addsub_fracta_28_o, prenorm_addsub_fractb_28_o : std_logic_vector(27 downto 0); + signal prenorm_addsub_exp_o : std_logic_vector(7 downto 0); + + signal addsub_fract_o : std_logic_vector(27 downto 0); + signal addsub_sign_o : std_logic; + + signal postnorm_addsub_output_o : std_logic_vector(31 downto 0); + signal postnorm_addsub_ine_o : std_logic; + + -- ***Multiply units signals*** + + signal pre_norm_mul_exp_10 : std_logic_vector(9 downto 0); + signal pre_norm_mul_fracta_24 : std_logic_vector(23 downto 0); + signal pre_norm_mul_fractb_24 : std_logic_vector(23 downto 0); + + signal mul_24_fract_48 : std_logic_vector(47 downto 0); + signal mul_24_sign : std_logic; + signal serial_mul_fract_48 : std_logic_vector(47 downto 0); + signal serial_mul_sign : std_logic; + + signal mul_fract_48: std_logic_vector(47 downto 0); + signal mul_sign: std_logic; + + signal post_norm_mul_output : std_logic_vector(31 downto 0); + signal post_norm_mul_ine : std_logic; + + -- ***Division units signals*** + + signal pre_norm_div_dvdnd : std_logic_vector(49 downto 0); + signal pre_norm_div_dvsor : std_logic_vector(26 downto 0); + signal pre_norm_div_exp : std_logic_vector(EXP_WIDTH+1 downto 0); + + signal serial_div_qutnt : std_logic_vector(26 downto 0); + signal serial_div_rmndr : std_logic_vector(26 downto 0); + signal serial_div_sign : std_logic; + signal serial_div_div_zero : std_logic; + + signal post_norm_div_output : std_logic_vector(31 downto 0); + signal post_norm_div_ine : std_logic; + + -- ***Square units*** + + signal pre_norm_sqrt_fracta_o : std_logic_vector(51 downto 0); + signal pre_norm_sqrt_exp_o : std_logic_vector(7 downto 0); + + signal sqrt_sqr_o : std_logic_vector(25 downto 0); + signal sqrt_ine_o : std_logic; + + signal post_norm_sqrt_output : std_logic_vector(31 downto 0); + signal post_norm_sqrt_ine_o : std_logic; + + +begin + --***Add/Substract units*** + + i_prenorm_addsub: pre_norm_addsub + port map ( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + fracta_28_o => prenorm_addsub_fracta_28_o, + fractb_28_o => prenorm_addsub_fractb_28_o, + exp_o=> prenorm_addsub_exp_o); + + i_addsub: addsub_28 + port map( + clk_i => clk_i, + fpu_op_i => s_fpu_op_i(0), + fracta_i => prenorm_addsub_fracta_28_o, + fractb_i => prenorm_addsub_fractb_28_o, + signa_i => s_opa_i(31), + signb_i => s_opb_i(31), + fract_o => addsub_fract_o, + sign_o => addsub_sign_o); + + i_postnorm_addsub: post_norm_addsub + port map( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + fract_28_i => addsub_fract_o, + exp_i => prenorm_addsub_exp_o, + sign_i => addsub_sign_o, + fpu_op_i => s_fpu_op_i(0), + rmode_i => s_rmode_i, + output_o => postnorm_addsub_output_o, + ine_o => postnorm_addsub_ine_o + ); + + --***Multiply units*** + + i_pre_norm_mul: pre_norm_mul + port map( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + exp_10_o => pre_norm_mul_exp_10, + fracta_24_o => pre_norm_mul_fracta_24, + fractb_24_o => pre_norm_mul_fractb_24); + + i_mul_24 : mul_24 + port map( + clk_i => clk_i, + fracta_i => pre_norm_mul_fracta_24, + fractb_i => pre_norm_mul_fractb_24, + signa_i => s_opa_i(31), + signb_i => s_opb_i(31), + start_i => start_i, + fract_o => mul_24_fract_48, + sign_o => mul_24_sign, + ready_o => open); + + i_serial_mul : serial_mul + port map( + clk_i => clk_i, + fracta_i => pre_norm_mul_fracta_24, + fractb_i => pre_norm_mul_fractb_24, + signa_i => s_opa_i(31), + signb_i => s_opb_i(31), + start_i => s_start_i, + fract_o => serial_mul_fract_48, + sign_o => serial_mul_sign, + ready_o => open); + + -- serial or parallel multiplier will be choosed depending on constant MUL_SERIAL + mul_fract_48 <= mul_24_fract_48 when MUL_SERIAL=0 else serial_mul_fract_48; + mul_sign <= mul_24_sign when MUL_SERIAL=0 else serial_mul_sign; + + i_post_norm_mul : post_norm_mul + port map( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + exp_10_i => pre_norm_mul_exp_10, + fract_48_i => mul_fract_48, + sign_i => mul_sign, + rmode_i => s_rmode_i, + output_o => post_norm_mul_output, + ine_o => post_norm_mul_ine + ); + + --***Division units*** + + i_pre_norm_div : pre_norm_div + port map( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + exp_10_o => pre_norm_div_exp, + dvdnd_50_o => pre_norm_div_dvdnd, + dvsor_27_o => pre_norm_div_dvsor); + + i_serial_div : serial_div + port map( + clk_i=> clk_i, + dvdnd_i => pre_norm_div_dvdnd, + dvsor_i => pre_norm_div_dvsor, + sign_dvd_i => s_opa_i(31), + sign_div_i => s_opb_i(31), + start_i => s_start_i, + ready_o => open, + qutnt_o => serial_div_qutnt, + rmndr_o => serial_div_rmndr, + sign_o => serial_div_sign, + div_zero_o => serial_div_div_zero); + + i_post_norm_div : post_norm_div + port map( + clk_i => clk_i, + opa_i => s_opa_i, + opb_i => s_opb_i, + qutnt_i => serial_div_qutnt, + rmndr_i => serial_div_rmndr, + exp_10_i => pre_norm_div_exp, + sign_i => serial_div_sign, + rmode_i => s_rmode_i, + output_o => post_norm_div_output, + ine_o => post_norm_div_ine); + + + --***Square units*** + + i_pre_norm_sqrt : pre_norm_sqrt + port map( + clk_i => clk_i, + opa_i => s_opa_i, + fracta_52_o => pre_norm_sqrt_fracta_o, + exp_o => pre_norm_sqrt_exp_o); + + i_sqrt: sqrt + generic map(RD_WIDTH=>52, SQ_WIDTH=>26) + port map( + clk_i => clk_i, + rad_i => pre_norm_sqrt_fracta_o, + start_i => s_start_i, + ready_o => open, + sqr_o => sqrt_sqr_o, + ine_o => sqrt_ine_o); + + i_post_norm_sqrt : post_norm_sqrt + port map( + clk_i => clk_i, + opa_i => s_opa_i, + fract_26_i => sqrt_sqr_o, + exp_i => pre_norm_sqrt_exp_o, + ine_i => sqrt_ine_o, + rmode_i => s_rmode_i, + output_o => post_norm_sqrt_output, + ine_o => post_norm_sqrt_ine_o); + + + +----------------------------------------------------------------- + + -- Input Register + process(clk_i) + begin + if rising_edge(clk_i) then + s_opa_i <= opa_i; + s_opb_i <= opb_i; + s_fpu_op_i <= fpu_op_i; + s_rmode_i <= rmode_i; + s_start_i <= start_i; + end if; + end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + output_o <= s_output_o; + ine_o <= s_ine_o; + overflow_o <= s_overflow_o; + underflow_o <= s_underflow_o; + div_zero_o <= s_div_zero_o; + inf_o <= s_inf_o; + zero_o <= s_zero_o; + qnan_o <= s_qnan_o; + snan_o <= s_snan_o; + end if; + end process; + + + -- FSM + process(clk_i) + begin + if rising_edge(clk_i) then + if s_start_i ='1' then + s_state <= busy; + s_count <= 0; + elsif s_count=6 and ((fpu_op_i="000") or (fpu_op_i="001")) then + s_state <= waiting; + ready_o <= '1'; + s_count <=0; + elsif s_count=MUL_COUNT and fpu_op_i="010" then + s_state <= waiting; + ready_o <= '1'; + s_count <=0; + elsif s_count=33 and fpu_op_i="011" then + s_state <= waiting; + ready_o <= '1'; + s_count <=0; + elsif s_count=33 and fpu_op_i="100" then + s_state <= waiting; + ready_o <= '1'; + s_count <=0; + elsif s_state=busy then + s_count <= s_count + 1; + else + s_state <= waiting; + ready_o <= '0'; + end if; + end if; + end process; + + -- Output Multiplexer + process(clk_i) + begin + if rising_edge(clk_i) then + if fpu_op_i="000" or fpu_op_i="001" then + s_output1 <= postnorm_addsub_output_o; + s_ine_o <= postnorm_addsub_ine_o; + elsif fpu_op_i="010" then + s_output1 <= post_norm_mul_output; + s_ine_o <= post_norm_mul_ine; + elsif fpu_op_i="011" then + s_output1 <= post_norm_div_output; + s_ine_o <= post_norm_div_ine; +-- elsif fpu_op_i="100" then +-- s_output1 <= post_norm_sqrt_output; +-- s_ine_o <= post_norm_sqrt_ine_o; + else + s_output1 <= (others => '0'); + s_ine_o <= '0'; + end if; + end if; + end process; + + + s_infa <= '1' when s_opa_i(30 downto 23)="11111111" else '0'; + s_infb <= '1' when s_opb_i(30 downto 23)="11111111" else '0'; + + + --In round down: the subtraction of two equal numbers other than zero are always -0!!! + process(s_output1, s_rmode_i, s_div_zero_o, s_infa, s_infb, s_qnan_o, s_snan_o, s_zero_o, s_fpu_op_i, s_opa_i, s_opb_i ) + begin + if s_rmode_i="00" or (s_div_zero_o or (s_infa or s_infb) or s_qnan_o or s_snan_o)='1' then --round-to-nearest-even + s_output_o <= s_output1; + elsif s_rmode_i="01" and s_output1(30 downto 23)="11111111" then + --In round-to-zero: the sum of two non-infinity operands is never infinity,even if an overflow occures + s_output_o <= s_output1(31) & "1111111011111111111111111111111"; + elsif s_rmode_i="10" and s_output1(31 downto 23)="111111111" then + --In round-up: the sum of two non-infinity operands is never negative infinity,even if an overflow occures + s_output_o <= "11111111011111111111111111111111"; + elsif s_rmode_i="11" then + --In round-down: a-a= -0 + if (s_fpu_op_i="000" or s_fpu_op_i="001") and s_zero_o='1' and (s_opa_i(31) or (s_fpu_op_i(0) xor s_opb_i(31)))='1' then + s_output_o <= "1" & s_output1(30 downto 0); + --In round-down: the sum of two non-infinity operands is never postive infinity,even if an overflow occures + elsif s_output1(31 downto 23)="011111111" then + s_output_o <= "01111111011111111111111111111111"; + else + s_output_o <= s_output1; + end if; + else + s_output_o <= s_output1; + end if; + end process; + + + -- Generate Exceptions + s_underflow_o <= '1' when s_output1(30 downto 23)="00000000" and s_ine_o='1' else '0'; + s_overflow_o <= '1' when s_output1(30 downto 23)="11111111" and s_ine_o='1' else '0'; + s_div_zero_o <= serial_div_div_zero when fpu_op_i="011" else '0'; + s_inf_o <= '1' when s_output1(30 downto 23)="11111111" and (s_qnan_o or s_snan_o)='0' else '0'; + s_zero_o <= '1' when or_reduce(s_output1(30 downto 0))='0' else '0'; + s_qnan_o <= '1' when s_output1(30 downto 0)=QNAN else '0'; + s_snan_o <= '1' when s_opa_i(30 downto 0)=SNAN or s_opb_i(30 downto 0)=SNAN else '0'; + + +end rtl; diff --git a/src/fpupack.vhd b/src/fpupack.vhd new file mode 100644 index 0000000..58d210f --- /dev/null +++ b/src/fpupack.vhd @@ -0,0 +1,114 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: FPU package wich contains constants and functions needed in the FPU core +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +package fpupack is + + + -- Data width of floating-point number. Deafult: 32 + constant FP_WIDTH : integer := 32; + + -- Data width of fraction. Deafult: 23 + constant FRAC_WIDTH : integer := 23; + + -- Data width of exponent. Deafult: 8 + constant EXP_WIDTH : integer := 8; + + --Zero vector + constant ZERO_VECTOR: std_logic_vector(30 downto 0) := "0000000000000000000000000000000"; + + -- Infinty FP format + constant INF : std_logic_vector(30 downto 0) := "1111111100000000000000000000000"; + + -- QNaN (Quit Not a Number) FP format (without sign bit) + constant QNAN : std_logic_vector(30 downto 0) := "1111111110000000000000000000000"; + + -- SNaN (Signaling Not a Number) FP format (without sign bit) + constant SNAN : std_logic_vector(30 downto 0) := "1111111100000000000000000000001"; + + -- count the zeros starting from left + function count_l_zeros (signal s_vector: std_logic_vector) return std_logic_vector; + + -- count the zeros starting from right + function count_r_zeros (signal s_vector: std_logic_vector) return std_logic_vector; + +end fpupack; + +package body fpupack is + + -- count the zeros starting from left + function count_l_zeros (signal s_vector: std_logic_vector) return std_logic_vector is + variable v_count : std_logic_vector(5 downto 0); + begin + v_count := "000000"; + for i in s_vector'range loop + case s_vector(i) is + when '0' => v_count := v_count + "000001"; + when others => exit; + end case; + end loop; + return v_count; + end count_l_zeros; + + + -- count the zeros starting from right + function count_r_zeros (signal s_vector: std_logic_vector) return std_logic_vector is + variable v_count : std_logic_vector(5 downto 0); + begin + v_count := "000000"; + for i in 0 to s_vector'length-1 loop + case s_vector(i) is + when '0' => v_count := v_count + "000001"; + when others => exit; + end case; + end loop; + return v_count; + end count_r_zeros; + + + +end fpupack; \ No newline at end of file diff --git a/src/mul_24.vhd b/src/mul_24.vhd new file mode 100644 index 0000000..899a88b --- /dev/null +++ b/src/mul_24.vhd @@ -0,0 +1,230 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: multiplication entity for the multiplication unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +library work; +use work.fpupack.all; + +entity mul_24 is + port( + clk_i : in std_logic; + fracta_i : in std_logic_vector(FRAC_WIDTH downto 0); -- hidden(1) & fraction(23) + fractb_i : in std_logic_vector(FRAC_WIDTH downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + start_i : in std_logic; + fract_o : out std_logic_vector(2*FRAC_WIDTH+1 downto 0); + sign_o : out std_logic; + ready_o : out std_logic + ); +end mul_24; + +architecture rtl of mul_24 is + + + +signal s_fracta_i, s_fractb_i : std_logic_vector(FRAC_WIDTH downto 0); +signal s_signa_i, s_signb_i, s_sign_o : std_logic; +signal s_fract_o: std_logic_vector(2*FRAC_WIDTH+1 downto 0); +signal s_start_i, s_ready_o : std_logic; + +signal a_h, a_l, b_h, b_l : std_logic_vector(11 downto 0); +signal a_h_h, a_h_l, b_h_h, b_h_l, a_l_h, a_l_l, b_l_h, b_l_l : std_logic_vector(5 downto 0); + +type op_6 is array (7 downto 0) of std_logic_vector(5 downto 0); +type prod_6 is array (3 downto 0) of op_6; + +type prod_48 is array (4 downto 0) of std_logic_vector(47 downto 0); +type sum_24 is array (3 downto 0) of std_logic_vector(23 downto 0); + +type a is array (3 downto 0) of std_logic_vector(23 downto 0); +type prod_24 is array (3 downto 0) of a; + +signal prod : prod_6; +signal sum : sum_24; +signal prod_a_b : prod_48; + +signal count : integer range 0 to 4; + + +type t_state is (waiting,busy); +signal s_state : t_state; + +signal prod2 : prod_24; +begin + + +-- Input Register +process(clk_i) +begin + if rising_edge(clk_i) then + s_fracta_i <= fracta_i; + s_fractb_i <= fractb_i; + s_signa_i<= signa_i; + s_signb_i<= signb_i; + s_start_i<=start_i; + end if; +end process; + +-- Output Register +--process(clk_i) +--begin +-- if rising_edge(clk_i) then + fract_o <= s_fract_o; + sign_o <= s_sign_o; + ready_o<=s_ready_o; +-- end if; +--end process; + + +-- FSM +process(clk_i) +begin + if rising_edge(clk_i) then + if s_start_i ='1' then + s_state <= busy; + count <= 0; + elsif count=4 and s_state=busy then + s_state <= waiting; + s_ready_o <= '1'; + count <=0; + elsif s_state=busy then + count <= count + 1; + else + s_state <= waiting; + s_ready_o <= '0'; + end if; + end if; +end process; + +s_sign_o <= s_signa_i xor s_signb_i; + +--"000000000000" +-- A = A_h x 2^N + A_l , B = B_h x 2^N + B_l +-- A x B = A_hxB_hx2^2N + (A_h xB_l + A_lxB_h)2^N + A_lxB_l +a_h <= s_fracta_i(23 downto 12); +a_l <= s_fracta_i(11 downto 0); +b_h <= s_fractb_i(23 downto 12); +b_l <= s_fractb_i(11 downto 0); + + + +a_h_h <= a_h(11 downto 6); +a_h_l <= a_h(5 downto 0); +b_h_h <= b_h(11 downto 6); +b_h_l <= b_h(5 downto 0); + +a_l_h <= a_l(11 downto 6); +a_l_l <= a_l(5 downto 0); +b_l_h <= b_l(11 downto 6); +b_l_l <= b_l(5 downto 0); + + +prod(0)(0) <= a_h_h; prod(0)(1) <= b_h_h; +prod(0)(2) <= a_h_h; prod(0)(3) <= b_h_l; +prod(0)(4) <= a_h_l; prod(0)(5) <= b_h_h; +prod(0)(6) <= a_h_l; prod(0)(7) <= b_h_l; + + +prod(1)(0) <= a_h_h; prod(1)(1) <= b_l_h; +prod(1)(2) <= a_h_h; prod(1)(3) <= b_l_l; +prod(1)(4) <= a_h_l; prod(1)(5) <= b_l_h; +prod(1)(6) <= a_h_l; prod(1)(7) <= b_l_l; + +prod(2)(0) <= a_l_h; prod(2)(1) <= b_h_h; +prod(2)(2) <= a_l_h; prod(2)(3) <= b_h_l; +prod(2)(4) <= a_l_l; prod(2)(5) <= b_h_h; +prod(2)(6) <= a_l_l; prod(2)(7) <= b_h_l; + +prod(3)(0) <= a_l_h; prod(3)(1) <= b_l_h; +prod(3)(2) <= a_l_h; prod(3)(3) <= b_l_l; +prod(3)(4) <= a_l_l; prod(3)(5) <= b_l_h; +prod(3)(6) <= a_l_l; prod(3)(7) <= b_l_l; + + + +process(clk_i) +begin +if rising_edge(clk_i) then + if count < 4 then + prod2(count)(0) <= (prod(count)(0)*prod(count)(1))&"000000000000"; + prod2(count)(1) <= "000000"&(prod(count)(2)*prod(count)(3))&"000000"; + prod2(count)(2) <= "000000"&(prod(count)(4)*prod(count)(5))&"000000"; + prod2(count)(3) <= "000000000000"&(prod(count)(6)*prod(count)(7)); + end if; +end if; +end process; + + + +process(clk_i) +begin +if rising_edge(clk_i) then + if count > 0 and s_state=busy then + sum(count-1) <= prod2(count-1)(0) + prod2(count-1)(1) + prod2(count-1)(2) + prod2(count-1)(3); + end if; +end if; +end process; + + + +-- Last stage + + + prod_a_b(0) <= sum(0)&"000000000000000000000000"; + prod_a_b(1) <= "000000000000"&sum(1)&"000000000000"; + prod_a_b(2) <= "000000000000"&sum(2)&"000000000000"; + prod_a_b(3) <= "000000000000000000000000"&sum(3); + + prod_a_b(4) <= prod_a_b(0) + prod_a_b(1) + prod_a_b(2) + prod_a_b(3); + + s_fract_o <= prod_a_b(4); + + + +end rtl; + diff --git a/src/post_norm_addsub.vhd b/src/post_norm_addsub.vhd new file mode 100644 index 0000000..aaa336e --- /dev/null +++ b/src/post_norm_addsub.vhd @@ -0,0 +1,225 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: post-normalization entity for the addition/subtraction unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity post_norm_addsub is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + fract_28_i : in std_logic_vector(FRAC_WIDTH+4 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + exp_i : in std_logic_vector(EXP_WIDTH-1 downto 0); + sign_i : in std_logic; + fpu_op_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + ine_o : out std_logic + ); +end post_norm_addsub; + + +architecture rtl of post_norm_addsub is + + +signal s_opa_i, s_opb_i : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_fract_28_i : std_logic_vector(FRAC_WIDTH+4 downto 0); +signal s_exp_i : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_sign_i : std_logic; +signal s_fpu_op_i : std_logic; +signal s_rmode_i : std_logic_vector(1 downto 0); +signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_ine_o : std_logic; +signal s_overflow : std_logic; + +signal s_zeros, s_shr1, s_shl1 : std_logic_vector(5 downto 0); +signal s_shr2, s_carry : std_logic; + +signal s_exp10: std_logic_vector(9 downto 0); +signal s_expo9_1, s_expo9_2, s_expo9_3: std_logic_vector(EXP_WIDTH downto 0); + +signal s_fracto28_1, s_fracto28_2, s_fracto28_rnd : std_logic_vector(FRAC_WIDTH+4 downto 0); + +signal s_roundup : std_logic; +signal s_sticky : std_logic; + +signal s_zero_fract : std_logic; +signal s_lost : std_logic; +signal s_infa, s_infb : std_logic; +signal s_nan_in, s_nan_op, s_nan_a, s_nan_b, s_nan_sign : std_logic; + +begin + + -- Input Register + --process(clk_i) + --begin + -- if rising_edge(clk_i) then + s_opa_i <= opa_i; + s_opb_i <= opb_i; + s_fract_28_i <= fract_28_i; + s_exp_i <= exp_i; + s_sign_i <= sign_i; + s_fpu_op_i <= fpu_op_i; + s_rmode_i <= rmode_i; + -- end if; + --end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + output_o <= s_output_o; + ine_o <= s_ine_o; + end if; + end process; + + --*** Stage 1 **** + -- figure out the output exponent and howmuch the fraction has to be shiftd right/left + + s_carry <= s_fract_28_i(27); + + + s_zeros <= count_l_zeros(s_fract_28_i(26 downto 0)) when s_fract_28_i(27)='0' else "000000"; + + + s_exp10 <= ("00"&s_exp_i) + ("000000000"&s_carry) - ("0000"&s_zeros); -- negative flag & large flag & exp + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_exp10(9)='1' or s_exp10="0000000000" then + s_shr1 <= (others =>'0'); + if or_reduce(s_exp_i)/='0' then + s_shl1 <= s_exp_i(5 downto 0) - "000001"; + else + s_shl1 <= "000000"; + end if; + s_expo9_1 <= "000000001"; + elsif s_exp10(8)='1' then + s_shr1 <= (others =>'0'); + s_shl1 <= (others =>'0'); + s_expo9_1 <= "011111111"; + else + s_shr1 <= ("00000"&s_carry); + s_shl1 <= s_zeros; + s_expo9_1 <= s_exp10(8 downto 0); + end if; + end if; + end process; + +--- + -- *** Stage 2 *** + -- Shifting the fraction and rounding + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_shr1 /= "000000" then + s_fracto28_1 <= shr(s_fract_28_i, s_shr1); + else + s_fracto28_1 <= shl(s_fract_28_i, s_shl1); + end if; + end if; + end process; + + s_expo9_2 <= s_expo9_1 - "000000001" when s_fracto28_1(27 downto 26)="00" else s_expo9_1; + + -- round + s_sticky <='1' when s_fracto28_1(0)='1' or (s_fract_28_i(0) and s_fract_28_i(27))='1' else '0'; --check last bit, before and after right-shift + + s_roundup <= s_fracto28_1(2) and ((s_fracto28_1(1) or s_sticky)or s_fracto28_1(3)) when s_rmode_i="00" else -- round to nearset even + (s_fracto28_1(2) or s_fracto28_1(1) or s_sticky) and (not s_sign_i) when s_rmode_i="10" else -- round up + (s_fracto28_1(2) or s_fracto28_1(1) or s_sticky) and (s_sign_i) when s_rmode_i="11" else -- round down + '0'; -- round to zero(truncate = no rounding) + + s_fracto28_rnd <= s_fracto28_1 + "0000000000000000000000001000" when s_roundup='1' else s_fracto28_1; + + -- ***Stage 3*** + -- right-shift after rounding (if necessary) + s_shr2 <= s_fracto28_rnd(27); + + s_expo9_3 <= s_expo9_2 + "000000001" when s_shr2='1' and s_expo9_2 /= "011111111" else s_expo9_2; + s_fracto28_2 <= ("0"&s_fracto28_rnd(27 downto 1)) when s_shr2='1' else s_fracto28_rnd; +----- + + s_infa <= '1' when s_opa_i(30 downto 23)="11111111" else '0'; + s_infb <= '1' when s_opb_i(30 downto 23)="11111111" else '0'; + + s_nan_a <= '1' when (s_infa='1' and or_reduce (s_opa_i(22 downto 0))='1') else '0'; + s_nan_b <= '1' when (s_infb='1' and or_reduce (s_opb_i(22 downto 0))='1') else '0'; + s_nan_in <= '1' when s_nan_a='1' or s_nan_b='1' else '0'; + s_nan_op <= '1' when (s_infa and s_infb)='1' and (s_opa_i(31) xor (s_fpu_op_i xor s_opb_i(31)) )='1' else '0'; -- inf-inf=Nan + + s_nan_sign <= s_sign_i when (s_nan_a and s_nan_b)='1' else + s_opa_i(31) when s_nan_a='1' else + s_opb_i(31); + + -- check if result is inexact; + s_lost <= (s_shr1(0) and s_fract_28_i(0)) or (s_shr2 and s_fracto28_rnd(0)) or or_reduce(s_fracto28_2(2 downto 0)); + s_ine_o <= '1' when (s_lost or s_overflow)='1' and (s_infa or s_infb)='0' else '0'; + + s_overflow <='1' when s_expo9_3="011111111" and (s_infa or s_infb)='0' else '0'; + s_zero_fract <= '1' when s_zeros=27 and s_fract_28_i(27)='0' else '0'; -- '1' if fraction result is zero + + process(s_sign_i, s_expo9_3, s_fracto28_2, s_nan_in, s_nan_op, s_nan_sign, s_infa, s_infb, s_overflow, s_zero_fract) + begin + if (s_nan_in or s_nan_op)='1' then + s_output_o <= s_nan_sign & QNAN; + elsif (s_infa or s_infb)='1' or s_overflow='1' then + s_output_o <= s_sign_i & INF; + elsif s_zero_fract='1' then + s_output_o <= s_sign_i & ZERO_VECTOR; + else + s_output_o <= s_sign_i & s_expo9_3(7 downto 0) & s_fracto28_2(25 downto 3); + end if; + end process; + + +end rtl; diff --git a/src/post_norm_div.vhd b/src/post_norm_div.vhd new file mode 100644 index 0000000..7d300d4 --- /dev/null +++ b/src/post_norm_div.vhd @@ -0,0 +1,262 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: post-normalization entity for the division unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + + +entity post_norm_div is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + qutnt_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + rmndr_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + exp_10_i : in std_logic_vector(EXP_WIDTH+1 downto 0); + sign_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + ine_o : out std_logic + ); +end post_norm_div; + +architecture rtl of post_norm_div is + + +-- input&output register signals +signal s_opa_i, s_opb_i : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_expa, s_expb : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_qutnt_i, s_rmndr_i : std_logic_vector(FRAC_WIDTH+3 downto 0); +signal s_r_zeros : std_logic_vector(5 downto 0); +signal s_exp_10_i : std_logic_vector(EXP_WIDTH+1 downto 0); +signal s_sign_i : std_logic; +signal s_rmode_i : std_logic_vector(1 downto 0); +signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_ine_o, s_overflow : std_logic; + +signal s_opa_dn, s_opb_dn : std_logic; +signal s_qutdn : std_logic; + +signal s_exp_10b : std_logic_vector(9 downto 0); +signal s_shr1, s_shl1 : std_logic_vector(5 downto 0); +signal s_shr2 : std_logic; +signal s_expo1, s_expo2, s_expo3 : std_logic_vector(8 downto 0); +signal s_fraco1 : std_logic_vector(26 downto 0); +signal s_frac_rnd, s_fraco2 : std_logic_vector(24 downto 0); +signal s_guard, s_round, s_sticky, s_roundup : std_logic; +signal s_lost : std_logic; + +signal s_op_0, s_opab_0, s_opb_0 : std_logic; +signal s_infa, s_infb : std_logic; +signal s_nan_in, s_nan_op, s_nan_a, s_nan_b : std_logic; +signal s_inf_result: std_logic; + +begin + + -- Input Register + process(clk_i) + begin + if rising_edge(clk_i) then + s_opa_i <= opa_i; + s_opb_i <= opb_i; + s_expa <= opa_i(30 downto 23); + s_expb <= opb_i(30 downto 23); + s_qutnt_i <= qutnt_i; + s_rmndr_i <= rmndr_i; + s_exp_10_i <= exp_10_i; + s_sign_i <= sign_i; + s_rmode_i <= rmode_i; + end if; + end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + output_o <= s_output_o; + ine_o <= s_ine_o; + end if; + end process; + + -- qutnt_i + -- 26 25 3 + -- | | | + -- h fffffffffffffffffffffff grs + + --*** Stage 1 **** + -- figure out the exponent and howmuch the fraction has to be shiftd right/left + + s_opa_dn <= '1' when or_reduce(s_expa)='0' and or_reduce(opa_i(22 downto 0))='1' else '0'; + s_opb_dn <= '1' when or_reduce(s_expb)='0' and or_reduce(opb_i(22 downto 0))='1' else '0'; + + s_qutdn <= not s_qutnt_i(26); + + + s_exp_10b <= s_exp_10_i - ("000000000"&s_qutdn); + + + + process(clk_i) + variable v_shr, v_shl : std_logic_vector(9 downto 0); + begin + if rising_edge(clk_i) then + if s_exp_10b(9)='1' or s_exp_10b="0000000000" then + v_shr := ("0000000001" - s_exp_10b) - s_qutdn; + v_shl := (others =>'0'); + s_expo1 <= "000000001"; + elsif s_exp_10b(8)='1' then + v_shr := (others =>'0'); + v_shl := (others =>'0'); + s_expo1 <= s_exp_10b(8 downto 0); + else + v_shr := (others =>'0'); + v_shl := "000000000"& s_qutdn; + s_expo1 <= s_exp_10b(8 downto 0); + end if; + if v_shr(6)='1' then + s_shr1 <= "111111"; + else + s_shr1 <= v_shr(5 downto 0); + end if; + s_shl1 <= v_shl(5 downto 0); + end if; + end process; + + + -- *** Stage 2 *** + -- Shifting the fraction and rounding + + + -- shift the fraction + process(clk_i) + begin + if rising_edge(clk_i) then + if s_shr1 /= "000000" then + s_fraco1 <= shr(s_qutnt_i, s_shr1); + else + s_fraco1 <= shl(s_qutnt_i, s_shl1); + end if; + end if; + end process; + + s_expo2 <= s_expo1 - "000000001" when s_fraco1(26)='0' else s_expo1; + + + s_r_zeros <= count_r_zeros(s_qutnt_i); + + + s_lost <= '1' when (s_shr1+("00000"&s_shr2)) > s_r_zeros else '0'; + + -- ***Stage 3*** + -- Rounding + + s_guard <= s_fraco1(2); + s_round <= s_fraco1(1); + s_sticky <= s_fraco1(0) or or_reduce(s_rmndr_i); + + s_roundup <= s_guard and ((s_round or s_sticky)or s_fraco1(3)) when s_rmode_i="00" else -- round to nearset even + ( s_guard or s_round or s_sticky) and (not s_sign_i) when s_rmode_i="10" else -- round up + ( s_guard or s_round or s_sticky) and (s_sign_i) when s_rmode_i="11" else -- round down + '0'; -- round to zero(truncate = no rounding) + + + s_frac_rnd <= ("0"&s_fraco1(26 downto 3)) + '1' when s_roundup='1' else "0"&s_fraco1(26 downto 3); + s_shr2 <= s_frac_rnd(24); + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_shr2='1' then + s_expo3 <= s_expo2 + "1"; + s_fraco2 <= "0"&s_frac_rnd(24 downto 1); + else + s_expo3 <= s_expo2; + s_fraco2 <= s_frac_rnd; + end if; + end if; + end process; + + + --- + + ---***Stage 4**** + -- Output + + s_op_0 <= not ( or_reduce(s_opa_i(30 downto 0)) and or_reduce(s_opb_i(30 downto 0)) ); + s_opab_0 <= not ( or_reduce(s_opa_i(30 downto 0)) or or_reduce(s_opb_i(30 downto 0)) ); + s_opb_0 <= not or_reduce(s_opb_i(30 downto 0)); + + s_infa <= '1' when s_expa="11111111" else '0'; + s_infb <= '1' when s_expb="11111111" else '0'; + + s_nan_a <= '1' when (s_infa='1' and or_reduce (s_opa_i(22 downto 0))='1') else '0'; + s_nan_b <= '1' when (s_infb='1' and or_reduce (s_opb_i(22 downto 0))='1') else '0'; + s_nan_in <= '1' when s_nan_a='1' or s_nan_b='1' else '0'; + s_nan_op <= '1' when (s_infa and s_infb)='1' or s_opab_0='1' else '0';-- 0 / 0, inf / inf + + s_inf_result <= '1' when (and_reduce(s_expo3(7 downto 0)) or s_expo3(8))='1' or s_opb_0='1' else '0'; + + s_overflow <= '1' when s_inf_result='1' and (s_infa or s_infb)='0' and s_opb_0='0' else '0'; + + s_ine_o <= '1' when s_op_0='0' and (s_lost or or_reduce(s_fraco1(2 downto 0)) or s_overflow or or_reduce(s_rmndr_i))='1' else '0'; + + process(s_sign_i, s_expo3, s_fraco2, s_nan_in, s_nan_op, s_infa, s_infb, s_overflow, s_inf_result, s_op_0) + begin + if (s_nan_in or s_nan_op)='1' then + s_output_o <= '1' & QNAN; + elsif (s_infa or s_infb)='1' or s_overflow='1' or s_inf_result='1' then + s_output_o <= s_sign_i & INF; + elsif s_op_0='1' then + s_output_o <= s_sign_i & ZERO_VECTOR; + else + s_output_o <= s_sign_i & s_expo3(7 downto 0) & s_fraco2(22 downto 0); + end if; + end process; + +end rtl; \ No newline at end of file diff --git a/src/post_norm_mul.vhd b/src/post_norm_mul.vhd new file mode 100644 index 0000000..921388f --- /dev/null +++ b/src/post_norm_mul.vhd @@ -0,0 +1,269 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: post-normalization entity for the multiplication unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity post_norm_mul is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + exp_10_i : in std_logic_vector(EXP_WIDTH+1 downto 0); + fract_48_i : in std_logic_vector(2*FRAC_WIDTH+1 downto 0); -- hidden(1) & fraction(23) + sign_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + ine_o : out std_logic + ); +end post_norm_mul; + +architecture rtl of post_norm_mul is + +signal s_expa, s_expb : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_exp_10_i : std_logic_vector(EXP_WIDTH+1 downto 0); +signal s_fract_48_i : std_logic_vector(2*FRAC_WIDTH+1 downto 0); +signal s_sign_i : std_logic; +signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_ine_o, s_overflow : std_logic; +signal s_opa_i, s_opb_i : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_rmode_i : std_logic_vector(1 downto 0); + +signal s_zeros : std_logic_vector(5 downto 0); +signal s_carry : std_logic; +signal s_shr2, s_shl2 : std_logic_vector(5 downto 0); +signal s_expo1, s_expo2b : std_logic_vector(8 downto 0); +signal s_exp_10a, s_exp_10b : std_logic_vector(9 downto 0); +signal s_frac2a : std_logic_vector(47 downto 0); + +signal s_sticky, s_guard, s_round : std_logic; +signal s_roundup : std_logic; +signal s_frac_rnd, s_frac3 : std_logic_vector(24 downto 0); +signal s_shr3 : std_logic; +signal s_r_zeros : std_logic_vector(5 downto 0); +signal s_lost : std_logic; +signal s_op_0 : std_logic; +signal s_expo3 : std_logic_vector(8 downto 0); + +signal s_infa, s_infb : std_logic; +signal s_nan_in, s_nan_op, s_nan_a, s_nan_b : std_logic; + +begin + + -- Input Register + process(clk_i) + begin + if rising_edge(clk_i) then + s_opa_i <= opa_i; + s_opb_i <= opb_i; + s_expa <= opa_i(30 downto 23); + s_expb <= opb_i(30 downto 23); + s_exp_10_i <= exp_10_i; + s_fract_48_i <= fract_48_i; + s_sign_i <= sign_i; + s_rmode_i <= rmode_i; + end if; + end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + output_o <= s_output_o; + ine_o <= s_ine_o; + end if; + end process; + + --*** Stage 1 **** + -- figure out the exponent and howmuch the fraction has to be shiftd right/left + + s_carry <= s_fract_48_i(47); + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_fract_48_i(47)='0' then + s_zeros <= count_l_zeros(s_fract_48_i(46 downto 1)); + else + s_zeros <= "000000"; + end if; + s_r_zeros <= count_r_zeros(s_fract_48_i); + end if; + end process; + + s_exp_10a <= s_exp_10_i + ("000000000"&s_carry); + s_exp_10b <= s_exp_10a - ("0000"&s_zeros); + + process(clk_i) + variable v_shr1, v_shl1 : std_logic_vector(9 downto 0); + begin + if rising_edge(clk_i) then + if s_exp_10a(9)='1' or s_exp_10a="0000000000" then + v_shr1 := "0000000001" - s_exp_10a + ("000000000"&s_carry); + v_shl1 := (others =>'0'); + s_expo1 <= "000000001"; + else + if s_exp_10b(9)='1' or s_exp_10b="0000000000" then + v_shr1 := (others =>'0'); + v_shl1 := ("0000"&s_zeros) - s_exp_10a; + s_expo1 <= "000000001"; + elsif s_exp_10b(8)='1' then + v_shr1 := (others =>'0'); + v_shl1 := (others =>'0'); + s_expo1 <= "011111111"; + else + v_shr1 := ("000000000"&s_carry); + v_shl1 := ("0000"&s_zeros); + s_expo1 <= s_exp_10b(8 downto 0); + end if; + end if; + if v_shr1(6)='1' then --"110000" = 48; maximal shift-right postions + s_shr2 <= "111111"; + else + s_shr2 <= v_shr1(5 downto 0); + end if; + s_shl2 <= v_shl1(5 downto 0); + end if; + end process; + + + -- *** Stage 2 *** + -- Shifting the fraction and rounding + + + -- shift the fraction + process(clk_i) + begin + if rising_edge(clk_i) then + if s_shr2 /= "000000" then + s_frac2a <= shr(s_fract_48_i, s_shr2); + else + s_frac2a <= shl(s_fract_48_i, s_shl2); + end if; + end if; + end process; + + s_expo2b <= s_expo1 - "000000001" when s_frac2a(46)='0' else s_expo1; + + + + -- signals if precision was last during the right-shift above + s_lost <= '1' when (s_shr2+("00000"&s_shr3)) > s_r_zeros else '0'; + + + -- ***Stage 3*** + -- Rounding + + -- 23 + -- | + -- xx00000000000000000000000grsxxxxxxxxxxxxxxxxxxxx + -- guard bit: s_frac2a(23) (LSB of output) + -- round bit: s_frac2a(22) + s_guard <= s_frac2a(22); + s_round <= s_frac2a(21); + s_sticky <= or_reduce(s_frac2a(20 downto 0)) or s_lost; + + s_roundup <= s_guard and ((s_round or s_sticky)or s_frac2a(23)) when s_rmode_i="00" else -- round to nearset even + ( s_guard or s_round or s_sticky) and (not s_sign_i) when s_rmode_i="10" else -- round up + ( s_guard or s_round or s_sticky) and (s_sign_i) when s_rmode_i="11" else -- round down + '0'; -- round to zero(truncate = no rounding) + + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_roundup='1' then + s_frac_rnd <= (s_frac2a(47 downto 23)) + "1"; + else + s_frac_rnd <= (s_frac2a(47 downto 23)); + end if; + end if; + end process; + + s_shr3 <= s_frac_rnd(24); + + + + s_expo3 <= s_expo2b + '1' when s_shr3='1' and s_expo2b /= "011111111" else s_expo2b; + s_frac3 <= ("0"&s_frac_rnd(24 downto 1)) when s_shr3='1' and s_expo2b /= "011111111" else s_frac_rnd; + + + ---***Stage 4**** + -- Output + + s_op_0 <= not ( or_reduce(s_opa_i(30 downto 0)) and or_reduce(s_opb_i(30 downto 0)) ); + + s_infa <= '1' when s_expa="11111111" else '0'; + s_infb <= '1' when s_expb="11111111" else '0'; + + s_nan_a <= '1' when (s_infa='1' and or_reduce (s_opa_i(22 downto 0))='1') else '0'; + s_nan_b <= '1' when (s_infb='1' and or_reduce (s_opb_i(22 downto 0))='1') else '0'; + s_nan_in <= '1' when s_nan_a='1' or s_nan_b='1' else '0'; + s_nan_op <= '1' when (s_infa or s_infb)='1' and s_op_0='1' else '0';-- 0 * inf = nan + + + s_overflow <= '1' when s_expo3 = "011111111" and (s_infa or s_infb)='0' else '0'; + + s_ine_o <= '1' when s_op_0='0' and (s_lost or or_reduce(s_frac2a(22 downto 0)) or s_overflow)='1' else '0'; + + process(s_sign_i, s_expo3, s_frac3, s_nan_in, s_nan_op, s_infa, s_infb, s_overflow, s_r_zeros) + begin + if (s_nan_in or s_nan_op)='1' then + s_output_o <= s_sign_i & QNAN; + elsif (s_infa or s_infb)='1' or s_overflow='1' then + s_output_o <= s_sign_i & INF; + elsif s_r_zeros=48 then + s_output_o <= s_sign_i & ZERO_VECTOR; + else + s_output_o <= s_sign_i & s_expo3(7 downto 0) & s_frac3(22 downto 0); + + end if; + end process; + +end rtl; \ No newline at end of file diff --git a/src/post_norm_sqrt.vhd b/src/post_norm_sqrt.vhd new file mode 100644 index 0000000..95ede43 --- /dev/null +++ b/src/post_norm_sqrt.vhd @@ -0,0 +1,166 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: post-normalization entity for the square-root unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity post_norm_sqrt is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + fract_26_i : in std_logic_vector(FRAC_WIDTH+2 downto 0); -- hidden(1) & fraction(11) + exp_i : in std_logic_vector(EXP_WIDTH-1 downto 0); + ine_i : in std_logic; + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(FP_WIDTH-1 downto 0); + ine_o : out std_logic + ); +end post_norm_sqrt; + +architecture rtl of post_norm_sqrt is + +signal s_expa, s_exp_i : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_fract_26_i : std_logic_vector(FRAC_WIDTH+2 downto 0); +signal s_ine_i : std_logic; +signal s_rmode_i : std_logic_vector(1 downto 0); +signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_sign_i : std_logic; +signal s_opa_i : std_logic_vector(FP_WIDTH-1 downto 0); +signal s_ine_o : std_logic; + +signal s_expo : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_fraco1 : std_logic_vector(FRAC_WIDTH+2 downto 0); + +signal s_guard, s_round, s_sticky, s_roundup : std_logic; +signal s_frac_rnd : std_logic_vector(FRAC_WIDTH downto 0); + + +signal s_infa : std_logic; +signal s_nan_op, s_nan_a: std_logic; + +begin + + -- Input Register + process(clk_i) + begin + if rising_edge(clk_i) then + s_opa_i <= opa_i; + s_expa <= opa_i(30 downto 23); + s_sign_i <= opa_i(31); + s_fract_26_i <= fract_26_i; + s_ine_i <= ine_i; + s_exp_i <= exp_i; + s_rmode_i <= rmode_i; + end if; + end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + output_o <= s_output_o; + ine_o <= s_ine_o; + end if; + end process; + + + -- *** Stage 1 *** + + s_expo <= s_exp_i; + + s_fraco1 <= s_fract_26_i; + + + -- ***Stage 2*** + -- Rounding + + s_guard <= s_fraco1(1); + s_round <= s_fraco1(0); + s_sticky <= s_ine_i; + + s_roundup <= s_guard and ((s_round or s_sticky)or s_fraco1(3)) when s_rmode_i="00" else -- round to nearset even + ( s_guard or s_round or s_sticky) and (not s_sign_i) when s_rmode_i="10" else -- round up + ( s_guard or s_round or s_sticky) and (s_sign_i) when s_rmode_i="11" else -- round down + '0'; -- round to zero(truncate = no rounding) + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_roundup='1' then + s_frac_rnd <= s_fraco1(25 downto 2) + '1'; + else + s_frac_rnd <= s_fraco1(25 downto 2); + end if; + end if; + end process; + + + + -- ***Stage 3*** + -- Output + + s_infa <= '1' when s_expa="11111111" else '0'; + s_nan_a <= '1' when (s_infa='1' and or_reduce (s_opa_i(22 downto 0))='1') else '0'; + s_nan_op <= '1' when s_sign_i='1' and or_reduce(s_opa_i(30 downto 0))='1' else '0'; -- sqrt(-x) = NaN + + s_ine_o <= '1' when s_ine_i='1' and (s_infa or s_nan_a or s_nan_op)='0' else '0'; + + process( s_nan_a, s_nan_op, s_infa, s_sign_i, s_expo, s_frac_rnd) + begin + if (s_nan_a or s_nan_op)='1' then + s_output_o <= s_sign_i & QNAN; + elsif s_infa ='1' then + s_output_o <= s_sign_i & INF; + else + s_output_o <= s_sign_i & s_expo & s_frac_rnd(22 downto 0); + + end if; + end process; + +end rtl; \ No newline at end of file diff --git a/src/pre_norm_addsub.vhd b/src/pre_norm_addsub.vhd new file mode 100644 index 0000000..7237dbf --- /dev/null +++ b/src/pre_norm_addsub.vhd @@ -0,0 +1,168 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: pre-normalization entity for the addition/subtraction unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity pre_norm_addsub is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + fracta_28_o : out std_logic_vector(FRAC_WIDTH+4 downto 0); -- carry(1) & hidden(1) & fraction(23) & guard(1) & round(1) & sticky(1) + fractb_28_o : out std_logic_vector(FRAC_WIDTH+4 downto 0); + exp_o : out std_logic_vector(EXP_WIDTH-1 downto 0) + ); +end pre_norm_addsub; + + +architecture rtl of pre_norm_addsub is + + + signal s_exp_o : std_logic_vector(EXP_WIDTH-1 downto 0); + signal s_fracta_28_o, s_fractb_28_o : std_logic_vector(FRAC_WIDTH+4 downto 0); + signal s_expa, s_expb : std_logic_vector(EXP_WIDTH-1 downto 0); + signal s_fracta, s_fractb : std_logic_vector(FRAC_WIDTH-1 downto 0); + + signal s_fracta_28, s_fractb_28, s_fract_sm_28, s_fract_shr_28 : std_logic_vector(FRAC_WIDTH+4 downto 0); + + signal s_exp_diff : std_logic_vector(EXP_WIDTH-1 downto 0); + signal s_rzeros : std_logic_vector(5 downto 0); + + signal s_expa_eq_expb : std_logic; + signal s_expa_lt_expb : std_logic; + signal s_fracta_1 : std_logic; + signal s_fractb_1 : std_logic; + signal s_op_dn,s_opa_dn, s_opb_dn : std_logic; + signal s_mux_diff : std_logic_vector(1 downto 0); + signal s_mux_exp : std_logic; + signal s_sticky : std_logic; +begin + + -- Input Register + --process(clk_i) + --begin + -- if rising_edge(clk_i) then + s_expa <= opa_i(30 downto 23); + s_expb <= opb_i(30 downto 23); + s_fracta <= opa_i(22 downto 0); + s_fractb <= opb_i(22 downto 0); + -- end if; + --end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + exp_o <= s_exp_o; + fracta_28_o <= s_fracta_28_o; + fractb_28_o <= s_fractb_28_o; + end if; + end process; + + s_expa_eq_expb <= '1' when s_expa = s_expb else '0'; + s_expa_lt_expb <= '1' when s_expa > s_expb else '0'; + + -- '1' if fraction is not zero + s_fracta_1 <= or_reduce(s_fracta); + s_fractb_1 <= or_reduce(s_fractb); + + -- opa or Opb is denormalized + s_op_dn <= s_opa_dn or s_opb_dn; + s_opa_dn <= not or_reduce(s_expa); + s_opb_dn <= not or_reduce(s_expb); + + -- output the larger exponent + s_mux_exp <= s_expa_lt_expb; + process(clk_i) + begin + if rising_edge(clk_i) then + case s_mux_exp is + when '0' => s_exp_o <= s_expb; + when '1' => s_exp_o <= s_expa; + when others => s_exp_o <= "11111111"; + end case; + end if; + end process; + + -- convert to an easy to handle floating-point format + s_fracta_28 <= "01" & s_fracta & "000" when s_opa_dn='0' else "00" & s_fracta & "000"; + s_fractb_28 <= "01" & s_fractb & "000" when s_opb_dn='0' else "00" & s_fractb & "000"; + + + s_mux_diff <= s_expa_lt_expb & (s_opa_dn xor s_opb_dn); + process(clk_i) + begin + if rising_edge(clk_i) then + -- calculate howmany postions the fraction will be shifted + case s_mux_diff is + when "00"=> s_exp_diff <= s_expb - s_expa; + when "01"=> s_exp_diff <= s_expb - (s_expa+"00000001"); + when "10"=> s_exp_diff <= s_expa - s_expb; + when "11"=> s_exp_diff <= s_expa - (s_expb+"00000001"); + when others => s_exp_diff <= "11110000"; + end case; + end if; + end process; + + + s_fract_sm_28 <= s_fracta_28 when s_expa_lt_expb='0' else s_fractb_28; + + -- shift-right the fraction if necessary + s_fract_shr_28 <= shr(s_fract_sm_28, s_exp_diff); + + -- count the zeros from right to check if result is inexact + s_rzeros <= count_r_zeros(s_fract_sm_28); + s_sticky <= '1' when s_exp_diff > s_rzeros and or_reduce(s_fract_sm_28)='1' else '0'; + + s_fracta_28_o <= s_fracta_28 when s_expa_lt_expb='1' else s_fract_shr_28(27 downto 1) & (s_sticky or s_fract_shr_28(0)); + s_fractb_28_o <= s_fractb_28 when s_expa_lt_expb='0' else s_fract_shr_28(27 downto 1) & (s_sticky or s_fract_shr_28(0)); + + +end rtl; diff --git a/src/pre_norm_div.vhd b/src/pre_norm_div.vhd new file mode 100644 index 0000000..f8b137d --- /dev/null +++ b/src/pre_norm_div.vhd @@ -0,0 +1,125 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: pre-normalization entity for the division unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity pre_norm_div is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + exp_10_o : out std_logic_vector(EXP_WIDTH+1 downto 0); + dvdnd_50_o : out std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); + dvsor_27_o : out std_logic_vector(FRAC_WIDTH+3 downto 0) + ); +end pre_norm_div; + +architecture rtl of pre_norm_div is + + +signal s_expa, s_expb : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_fracta, s_fractb : std_logic_vector(FRAC_WIDTH-1 downto 0); +signal s_dvdnd_50_o : std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); +signal s_dvsor_27_o : std_logic_vector(FRAC_WIDTH+3 downto 0); +signal s_dvd_zeros, s_div_zeros: std_logic_vector(5 downto 0); +signal s_exp_10_o : std_logic_vector(EXP_WIDTH+1 downto 0); + +signal s_expa_in, s_expb_in : std_logic_vector(EXP_WIDTH+1 downto 0); +signal s_opa_dn, s_opb_dn : std_logic; +signal s_fracta_24, s_fractb_24 : std_logic_vector(FRAC_WIDTH downto 0); + +begin + + s_expa <= opa_i(30 downto 23); + s_expb <= opb_i(30 downto 23); + s_fracta <= opa_i(22 downto 0); + s_fractb <= opb_i(22 downto 0); + dvdnd_50_o <= s_dvdnd_50_o; + dvsor_27_o <= s_dvsor_27_o; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + exp_10_o <= s_exp_10_o; + end if; + end process; + + + s_opa_dn <= not or_reduce(s_expa); + s_opb_dn <= not or_reduce(s_expb); + + s_fracta_24 <= (not s_opa_dn) & s_fracta; + s_fractb_24 <= (not s_opb_dn) & s_fractb; + + -- count leading zeros + s_dvd_zeros <= count_l_zeros( s_fracta_24 ); + s_div_zeros <= count_l_zeros( s_fractb_24 ); + + -- left-shift the dividend and divisor + s_dvdnd_50_o <= shl(s_fracta_24, s_dvd_zeros) & "00000000000000000000000000"; + s_dvsor_27_o <= "000" & shl(s_fractb_24, s_div_zeros); + + + + process(clk_i) + begin + if rising_edge(clk_i) then + -- pre-calculate exponent + s_expa_in <= ("00"&s_expa) + ("000000000"&s_opa_dn); + s_expb_in <= ("00"&s_expb) + ("000000000"&s_opb_dn); + s_exp_10_o <= s_expa_in - s_expb_in + "0001111111" -("0000"&s_dvd_zeros) + ("0000"&s_div_zeros); + end if; + end process; + + + + +end rtl; diff --git a/src/pre_norm_mul.vhd b/src/pre_norm_mul.vhd new file mode 100644 index 0000000..3173abb --- /dev/null +++ b/src/pre_norm_mul.vhd @@ -0,0 +1,105 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: pre-normalization entity for the multiplication unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity pre_norm_mul is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + opb_i : in std_logic_vector(FP_WIDTH-1 downto 0); + exp_10_o : out std_logic_vector(EXP_WIDTH+1 downto 0); + fracta_24_o : out std_logic_vector(FRAC_WIDTH downto 0); -- hidden(1) & fraction(23) + fractb_24_o : out std_logic_vector(FRAC_WIDTH downto 0) + ); +end pre_norm_mul; + +architecture rtl of pre_norm_mul is + +signal s_expa, s_expb : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_fracta, s_fractb : std_logic_vector(FRAC_WIDTH-1 downto 0); +signal s_exp_10_o, s_expa_in, s_expb_in : std_logic_vector(EXP_WIDTH+1 downto 0); + +signal s_opa_dn, s_opb_dn : std_logic; + +begin + + + s_expa <= opa_i(30 downto 23); + s_expb <= opb_i(30 downto 23); + s_fracta <= opa_i(22 downto 0); + s_fractb <= opb_i(22 downto 0); + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + exp_10_o <= s_exp_10_o; + end if; + end process; + + -- opa or opb is denormalized + s_opa_dn <= not or_reduce(s_expa); + s_opb_dn <= not or_reduce(s_expb); + + + fracta_24_o <= not(s_opa_dn) & s_fracta; + fractb_24_o <= not(s_opb_dn) & s_fractb; + + s_expa_in <= ("00"&s_expa) + ("000000000"&s_opa_dn); + s_expb_in <= ("00"&s_expb) + ("000000000"&s_opb_dn); + + + + s_exp_10_o <= s_expa_in + s_expb_in - "0001111111"; + + + +end rtl; diff --git a/src/pre_norm_sqrt.vhd b/src/pre_norm_sqrt.vhd new file mode 100644 index 0000000..364260b --- /dev/null +++ b/src/pre_norm_sqrt.vhd @@ -0,0 +1,111 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: pre-normalization entity for the square-root unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + +entity pre_norm_sqrt is + port( + clk_i : in std_logic; + opa_i : in std_logic_vector(FP_WIDTH-1 downto 0); + fracta_52_o : out std_logic_vector(2*(FRAC_WIDTH+3)-1 downto 0); + exp_o : out std_logic_vector(EXP_WIDTH-1 downto 0) + ); +end pre_norm_sqrt; + +architecture rtl of pre_norm_sqrt is + +signal s_expa : std_logic_vector(EXP_WIDTH-1 downto 0); +signal s_exp_o, s_exp_tem : std_logic_vector(EXP_WIDTH downto 0); +signal s_fracta : std_logic_vector(FRAC_WIDTH-1 downto 0); +signal s_fracta_24 : std_logic_vector(FRAC_WIDTH downto 0); +signal s_fracta_52_o, s_fracta1_52_o, s_fracta2_52_o : std_logic_vector(2*(FRAC_WIDTH+3)-1 downto 0); +signal s_sqr_zeros_o : std_logic_vector(5 downto 0); + + +signal s_opa_dn : std_logic; + +begin + + s_expa <= opa_i(30 downto 23); + s_fracta <= opa_i(22 downto 0); + + + exp_o <= s_exp_o(7 downto 0); + fracta_52_o <= s_fracta_52_o; + + -- opa or opb is denormalized + s_opa_dn <= not or_reduce(s_expa); + + s_fracta_24 <= (not s_opa_dn) & s_fracta; + + -- count leading zeros + s_sqr_zeros_o <= count_l_zeros(s_fracta_24 ); + + -- adjust the exponent + s_exp_tem <= ("0"&s_expa)+"001111111" - ("000"&s_sqr_zeros_o); + + process(clk_i) + begin + if rising_edge(clk_i) then + if or_reduce(opa_i(30 downto 0))='1' then + s_exp_o <= ("0"&s_exp_tem(8 downto 1)); + else + s_exp_o <= "000000000"; + end if; + end if; + end process; + + -- left-shift the radicand + s_fracta1_52_o <= shl(s_fracta_24, s_sqr_zeros_o) & "0000000000000000000000000000"; + s_fracta2_52_o <= '0' & shl(s_fracta_24, s_sqr_zeros_o) & "000000000000000000000000000"; + + s_fracta_52_o <= s_fracta1_52_o when s_expa(0)='0' else s_fracta2_52_o; + +end rtl; diff --git a/src/readme.txt b/src/readme.txt new file mode 100644 index 0000000..c7b333e --- /dev/null +++ b/src/readme.txt @@ -0,0 +1,21 @@ +The Compilation order is: + +fpupack.vhd +pre_norm_addsub.vhd +addsub_28.vhd +post_norm_addsub.vhd +pre_norm_mul.vhd +mul_24.vhd +vcom serial_mul.vhd +post_norm_mul.vhd +pre_norm_div.vhd +serial_div.vhd +post_norm_div.vhd +pre_norm_sqrt.vhd +sqrt.vhd +post_norm_sqrt.vhd +comppack.vhd +fpu.vhd + +***For simulation **** +To run the simulation read readme.txt in folder test_bench. \ No newline at end of file diff --git a/src/serial_div.vhd b/src/serial_div.vhd new file mode 100644 index 0000000..fab5f2f --- /dev/null +++ b/src/serial_div.vhd @@ -0,0 +1,163 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: division entity for the division unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_misc.all; + +library work; +use work.fpupack.all; + + +entity serial_div is + port( + clk_i : in std_logic; + dvdnd_i : in std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); -- hidden(1) & fraction(23) + dvsor_i : in std_logic_vector(FRAC_WIDTH+3 downto 0); + sign_dvd_i : in std_logic; + sign_div_i : in std_logic; + start_i : in std_logic; + ready_o : out std_logic; + qutnt_o : out std_logic_vector(FRAC_WIDTH+3 downto 0); + rmndr_o : out std_logic_vector(FRAC_WIDTH+3 downto 0); + sign_o : out std_logic; + div_zero_o : out std_logic + ); +end serial_div; + +architecture rtl of serial_div is + +type t_state is (waiting,busy); + +signal s_qutnt_o, s_rmndr_o : std_logic_vector(FRAC_WIDTH+3 downto 0); + +signal s_dvdnd_i : std_logic_vector(2*(FRAC_WIDTH+2)-1 downto 0); +signal s_dvsor_i : std_logic_vector(FRAC_WIDTH+3 downto 0); +signal s_sign_dvd_i, s_sign_div_i, s_sign_o : std_logic; +signal s_div_zero_o : std_logic; +signal s_start_i, s_ready_o : std_logic; +signal s_state : t_state; +signal s_count : integer range 0 to FRAC_WIDTH+3; +signal s_dvd : std_logic_vector(FRAC_WIDTH+3 downto 0); + +begin + + +-- Input Register +process(clk_i) +begin + if rising_edge(clk_i) then + s_dvdnd_i <= dvdnd_i; + s_dvsor_i <= dvsor_i; + s_sign_dvd_i<= sign_dvd_i; + s_sign_div_i<= sign_div_i; + s_start_i <= start_i; + end if; +end process; + +-- Output Register +--process(clk_i) +--begin +-- if rising_edge(clk_i) then + qutnt_o <= s_qutnt_o; + rmndr_o <= s_rmndr_o; + sign_o <= s_sign_o; + ready_o <= s_ready_o; + div_zero_o <= s_div_zero_o; +-- end if; +--end process; + +s_sign_o <= sign_dvd_i xor sign_div_i; +s_div_zero_o <= '1' when or_reduce(s_dvsor_i)='0' and or_reduce(s_dvdnd_i)='1' else '0'; + +-- FSM +process(clk_i) +begin + if rising_edge(clk_i) then + if s_start_i ='1' then + s_state <= busy; + s_count <= 26; + elsif s_count=0 and s_state=busy then + s_state <= waiting; + s_ready_o <= '1'; + s_count <=26; + elsif s_state=busy then + s_count <= s_count - 1; + else + s_state <= waiting; + s_ready_o <= '0'; + end if; + end if; +end process; + + +process(clk_i) +variable v_div : std_logic_vector(26 downto 0); +begin + if rising_edge(clk_i) then + --Reset + if s_start_i ='1' then + s_qutnt_o <= (others =>'0'); + s_rmndr_o <= (others =>'0'); + elsif s_state=busy then + if s_count=26 then + v_div := "000" & s_dvdnd_i(49 downto 26); + else + v_div:= s_dvd; + end if; + if v_div < s_dvsor_i then + s_qutnt_o(s_count) <= '0'; + else + s_qutnt_o(s_count) <= '1'; + v_div:=v_div-s_dvsor_i; + end if; + s_rmndr_o <= v_div; + s_dvd <= v_div(25 downto 0)&'0'; + end if; + end if; +end process; + +end rtl; + diff --git a/src/serial_mul.vhd b/src/serial_mul.vhd new file mode 100644 index 0000000..3992ac8 --- /dev/null +++ b/src/serial_mul.vhd @@ -0,0 +1,146 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: Serial multiplication entity for the multiplication unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +library work; +use work.fpupack.all; + +entity serial_mul is + port( + clk_i : in std_logic; + fracta_i : in std_logic_vector(FRAC_WIDTH downto 0); -- hidden(1) & fraction(23) + fractb_i : in std_logic_vector(FRAC_WIDTH downto 0); + signa_i : in std_logic; + signb_i : in std_logic; + start_i : in std_logic; + fract_o : out std_logic_vector(2*FRAC_WIDTH+1 downto 0); + sign_o : out std_logic; + ready_o : out std_logic + ); +end serial_mul; + +architecture rtl of serial_mul is + +type t_state is (waiting,busy); + +signal s_fract_o: std_logic_vector(47 downto 0); + +signal s_fracta_i, s_fractb_i : std_logic_vector(23 downto 0); +signal s_signa_i, s_signb_i, s_sign_o : std_logic; +signal s_start_i, s_ready_o : std_logic; +signal s_state : t_state; +signal s_count : integer range 0 to 23; +signal s_tem_prod : std_logic_vector(23 downto 0); + +begin + +-- Input Register +process(clk_i) +begin + if rising_edge(clk_i) then + s_fracta_i <= fracta_i; + s_fractb_i <= fractb_i; + s_signa_i<= signa_i; + s_signb_i<= signb_i; + s_start_i <= start_i; + end if; +end process; + +-- Output Register +process(clk_i) +begin + if rising_edge(clk_i) then + fract_o <= s_fract_o; + sign_o <= s_sign_o; + ready_o <= s_ready_o; + end if; +end process; + +s_sign_o <= signa_i xor signb_i; + +-- FSM +process(clk_i) +begin + if rising_edge(clk_i) then + if s_start_i ='1' then + s_state <= busy; + s_count <= 0; + elsif s_count=23 then + s_state <= waiting; + s_ready_o <= '1'; + s_count <=0; + elsif s_state=busy then + s_count <= s_count + 1; + else + s_state <= waiting; + s_ready_o <= '0'; + end if; + end if; +end process; + +g1: for i in 0 to 23 generate + s_tem_prod(i) <= s_fracta_i(i) and s_fractb_i(s_count); +end generate; + +process(clk_i) +variable v_prod_shl : std_logic_vector(47 downto 0); +begin + if rising_edge(clk_i) then + if s_state=busy then + v_prod_shl := shl(conv_std_logic_vector(0,24)&s_tem_prod, conv_std_logic_vector(s_count,5)); + if s_count /= 0 then + s_fract_o <= v_prod_shl + s_fract_o; + else + s_fract_o <= v_prod_shl; + end if; + end if; + end if; +end process; + +end rtl; + diff --git a/src/sqrt.vhd b/src/sqrt.vhd new file mode 100644 index 0000000..f4cfefa --- /dev/null +++ b/src/sqrt.vhd @@ -0,0 +1,211 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: square-root entity for the square-root unit +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee ; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity sqrt is + generic (RD_WIDTH: integer:=52; SQ_WIDTH: integer:=26); -- SQ_WIDTH = RD_WIDTH/2 (+ 1 if odd) + port( + clk_i : in std_logic; + rad_i : in std_logic_vector(RD_WIDTH-1 downto 0); -- hidden(1) & fraction(23) + start_i : in std_logic; + ready_o : out std_logic; + sqr_o : out std_logic_vector(SQ_WIDTH-1 downto 0); + ine_o : out std_logic + ); +end sqrt; + +architecture rtl of sqrt is + +signal s_rad_i: std_logic_vector(RD_WIDTH-1 downto 0); +signal s_start_i, s_ready_o : std_logic; +signal s_sqr_o: std_logic_vector(RD_WIDTH-1 downto 0); +signal s_ine_o : std_logic; + +constant ITERATIONS : integer:= RD_WIDTH/2; -- iterations = N/2 +constant WIDTH_C : integer:= 5; -- log2(ITERATIONS) + --0000000000000000000000000000000000000000000000000000 +constant CONST_B : std_logic_vector(RD_WIDTH-1 downto 0) :="0000000000000000000000000010000000000000000000000000"; -- b = 2^(N/2 - 1) +constant CONST_B_2: std_logic_vector(RD_WIDTH-1 downto 0):="0100000000000000000000000000000000000000000000000000"; -- b^2 +constant CONST_C : std_logic_vector(WIDTH_C-1 downto 0):= "11010"; -- c = N/2 + + +signal s_count : integer range 0 to ITERATIONS; + +type t_state is (waiting,busy); +signal s_state : t_state; + +signal b, b_2, r0, r0_2, r1, r1_2 : std_logic_vector(RD_WIDTH-1 downto 0); +signal c : std_logic_vector(WIDTH_C-1 downto 0); + + signal s_op1, s_op2, s_sum1a, s_sum1b, s_sum2a, s_sum2b : std_logic_vector(RD_WIDTH-1 downto 0); + +begin + + + -- Input Register + process(clk_i) + begin + if rising_edge(clk_i) then + s_rad_i <= rad_i; + s_start_i <= start_i; + end if; + end process; + + -- Output Register + process(clk_i) + begin + if rising_edge(clk_i) then + sqr_o <= s_sqr_o(SQ_WIDTH-1 downto 0); + ine_o <= s_ine_o; + ready_o <= s_ready_o; + end if; + end process; + + + -- FSM + process(clk_i) + begin + if rising_edge(clk_i) then + if s_start_i ='1' then + s_state <= busy; + s_count <= ITERATIONS; + elsif s_count=0 and s_state=busy then + s_state <= waiting; + s_ready_o <= '1'; + s_count <=ITERATIONS; + elsif s_state=busy then + s_count <= s_count - 1; + else + s_state <= waiting; + s_ready_o <= '0'; + end if; + end if; + end process; + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_start_i='1' then + b <= CONST_B; + b_2 <= CONST_B_2; + c <= CONST_C; + else + b <= '0'&b(RD_WIDTH-1 downto 1); -- shr 1 + b_2 <= "00"&b_2(RD_WIDTH-1 downto 2);-- shr 2 + c <= c - '1'; + end if; + end if; + end process; + + + + s_op1 <= r0_2 + b_2; + s_op2 <= shl(r0, c); + s_sum1a <= "00000000000000000000000000"& (r0(25 downto 0) - b(25 downto 0)); + s_sum2a <= "00000000000000000000000000"& (r0(25 downto 0) + b(25 downto 0)); + s_sum1b <= s_op1 - s_op2; + s_sum2b <= s_op1 + s_op2; + + + + process(clk_i) + variable v_r1, v_r1_2 : std_logic_vector(RD_WIDTH-1 downto 0); + begin + if rising_edge(clk_i) then + if s_start_i='1' then + r0 <= (others =>'0'); + r0_2 <= (others =>'0'); + elsif s_state=busy then + if r0_2 > s_rad_i then + v_r1 := s_sum1a; + v_r1_2 := s_sum1b; + else + v_r1 := s_sum2a; + v_r1_2 := s_sum2b; + end if; + r0 <= v_r1; + r0_2 <= v_r1_2; + r1 <= v_r1; + r1_2 <= v_r1_2; + end if; + end if; + end process; + + process(clk_i) + begin + if rising_edge(clk_i) then + if s_start_i = '1' then + s_sqr_o <= (others =>'0'); + elsif s_count=0 then + if r1_2 > s_rad_i then + s_sqr_o <= r1 - '1'; + else + s_sqr_o <= r1; + end if; + end if; + end if; + end process; + + + -- check if result is inexact. In this way we saved 1 clk cycle! + process(clk_i) + variable v_r1_2 : std_logic_vector(RD_WIDTH-1 downto 0); + begin + if rising_edge(clk_i) then + v_r1_2 := r1_2 - (r1(RD_WIDTH-2 downto 0)&"0") + '1'; + if s_count=0 then + if r1_2 = s_rad_i or v_r1_2=s_rad_i then + s_ine_o <= '0'; + else + s_ine_o <= '1'; + end if; + end if; + + end if; + end process; + +end rtl; \ No newline at end of file diff --git a/src/test_bench/fpu_wave.do b/src/test_bench/fpu_wave.do new file mode 100644 index 0000000..51181b0 --- /dev/null +++ b/src/test_bench/fpu_wave.do @@ -0,0 +1,34 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb_fpu/clk_i +add wave -noupdate -format Literal /tb_fpu/opa_i +add wave -noupdate -format Literal /tb_fpu/opb_i +add wave -noupdate -format Literal /tb_fpu/fpu_op_i +add wave -noupdate -format Literal /tb_fpu/rmode_i +add wave -noupdate -format Literal /tb_fpu/output_o +add wave -noupdate -format Logic /tb_fpu/start_i +add wave -noupdate -format Logic /tb_fpu/ready_o +add wave -noupdate -format Logic /tb_fpu/ine_o +add wave -noupdate -format Logic /tb_fpu/overflow_o +add wave -noupdate -format Logic /tb_fpu/underflow_o +add wave -noupdate -format Logic /tb_fpu/div_zero_o +add wave -noupdate -format Logic /tb_fpu/inf_o +add wave -noupdate -format Logic /tb_fpu/zero_o +add wave -noupdate -format Logic /tb_fpu/qnan_o +add wave -noupdate -format Logic /tb_fpu/snan_o +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {16182 ns} 0} +configure wave -namecolwidth 255 +configure wave -valuecolwidth 317 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +update +WaveRestoreZoom {0 ns} {544 ns} diff --git a/src/test_bench/fpusim.bat b/src/test_bench/fpusim.bat new file mode 100644 index 0000000..f77b287 --- /dev/null +++ b/src/test_bench/fpusim.bat @@ -0,0 +1,29 @@ +set REL= ..\ + +vlib work + +vcom %REL%fpupack.vhd +vcom %REL%pre_norm_addsub.vhd +vcom %REL%addsub_28.vhd +vcom %REL%post_norm_addsub.vhd +vcom %REL%pre_norm_mul.vhd +vcom %REL%mul_24.vhd +vcom %REL%serial_mul.vhd +vcom %REL%post_norm_mul.vhd +vcom %REL%pre_norm_div.vhd +vcom %REL%serial_div.vhd +vcom %REL%post_norm_div.vhd +vcom %REL%pre_norm_sqrt.vhd +vcom %REL%sqrt.vhd +vcom %REL%post_norm_sqrt.vhd +vcom %REL%comppack.vhd +vcom %REL%fpu.vhd + +vcom txt_util.vhd +vcom tb_fpu.vhd + +pause Start simulation? + +vsim -do fpu_wave.do tb_fpu + + diff --git a/src/test_bench/maketest.bat b/src/test_bench/maketest.bat new file mode 100644 index 0000000..6500bb2 --- /dev/null +++ b/src/test_bench/maketest.bat @@ -0,0 +1,23 @@ +timesoftfloat -nearesteven float32_add > testcases.txt +timesoftfloat -nearesteven float32_sub >> testcases.txt +timesoftfloat -nearesteven float32_mul >> testcases.txt +timesoftfloat -nearesteven float32_div >> testcases.txt +timesoftfloat -nearesteven float32_sqrt >> testcases.txt + +timesoftfloat -tozero float32_add >> testcases.txt +timesoftfloat -tozero float32_sub >> testcases.txt +timesoftfloat -tozero float32_mul >> testcases.txt +timesoftfloat -tozero float32_div >> testcases.txt +timesoftfloat -tozero float32_sqrt >> testcases.txt + +timesoftfloat -up float32_add >> testcases.txt +timesoftfloat -up float32_sub >> testcases.txt +timesoftfloat -up float32_mul >> testcases.txt +timesoftfloat -up float32_div >> testcases.txt +timesoftfloat -up float32_sqrt >> testcases.txt + +timesoftfloat -down float32_add >> testcases.txt +timesoftfloat -down float32_sub >> testcases.txt +timesoftfloat -down float32_mul >> testcases.txt +timesoftfloat -down float32_div >> testcases.txt +timesoftfloat -down float32_sqrt >> testcases.txt \ No newline at end of file diff --git a/src/test_bench/readme.txt b/src/test_bench/readme.txt new file mode 100644 index 0000000..2511475 --- /dev/null +++ b/src/test_bench/readme.txt @@ -0,0 +1,9 @@ +To test the FPU core, do the following: + +1) Build timesoftfloat.exe for your specific platform(read instructions in folder SoftFloat for howto do that). + Before you do that, try the already included file. + +2) Create the testcases by running maketest.bat in folder test_bench. Default value is 100000 cases for each + arithmetic operation and for each rounding mode. This comes up to 2 million test cases. + +3) run fpusim.bat to simulate and test the FPU core using modelsim. \ No newline at end of file diff --git a/src/test_bench/tb_fpu.vhd b/src/test_bench/tb_fpu.vhd new file mode 100644 index 0000000..9a9f78f --- /dev/null +++ b/src/test_bench/tb_fpu.vhd @@ -0,0 +1,259 @@ +------------------------------------------------------------------------------- +-- +-- Project: +-- +-- Description: test bench for the FPU core +------------------------------------------------------------------------------- +-- +-- 100101011010011100100 +-- 110000111011100100000 +-- 100000111011000101101 +-- 100010111100101111001 +-- 110000111011101101001 +-- 010000001011101001010 +-- 110100111001001100001 +-- 110111010000001100111 +-- 110110111110001011101 +-- 101110110010111101000 +-- 100000010111000000000 +-- +-- Author: Jidan Al-eryani +-- E-mail: jidan@gmx.net +-- +-- Copyright (C) 2006 +-- +-- This source file may be used and distributed without +-- restriction provided that this copyright statement is not +-- removed from the file and that any derivative work contains +-- the original copyright notice and the associated disclaimer. +-- +-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY +-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR +-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +-- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_misc.all; +use std.textio.all; +use work.txt_util.all; + + -- fpu operations (fpu_op_i): + -- ======================== + -- 000 = add, + -- 001 = substract, + -- 010 = multiply, + -- 011 = divide, + -- 100 = square root + -- 101 = unused + -- 110 = unused + -- 111 = unused + + -- Rounding Mode: + -- ============== + -- 00 = round to nearest even(default), + -- 01 = round to zero, + -- 10 = round up, + -- 11 = round down + + +entity tb_fpu is +end tb_fpu; + +architecture rtl of tb_fpu is + +component fpu + port ( + clk_i : in std_logic; + opa_i : in std_logic_vector(31 downto 0); + opb_i : in std_logic_vector(31 downto 0); + fpu_op_i : in std_logic_vector(2 downto 0); + rmode_i : in std_logic_vector(1 downto 0); + output_o : out std_logic_vector(31 downto 0); + ine_o : out std_logic; + overflow_o : out std_logic; + underflow_o : out std_logic; + div_zero_o : out std_logic; + inf_o : out std_logic; + zero_o : out std_logic; + qnan_o : out std_logic; + snan_o : out std_logic; + start_i : in std_logic; + ready_o : out std_logic + ); +end component; + + +signal clk_i : std_logic:= '1'; +signal opa_i, opb_i : std_logic_vector(31 downto 0); +signal fpu_op_i : std_logic_vector(2 downto 0); +signal rmode_i : std_logic_vector(1 downto 0); +signal output_o : std_logic_vector(31 downto 0); +signal start_i, ready_o : std_logic ; +signal ine_o, overflow_o, underflow_o, div_zero_o, inf_o, zero_o, qnan_o, snan_o: std_logic; + + + +signal slv_out : std_logic_vector(31 downto 0); + +constant CLK_PERIOD :time := 10 ns; -- period of clk period + + +begin + + -- instantiate fpu + i_fpu: fpu port map ( + clk_i => clk_i, + opa_i => opa_i, + opb_i => opb_i, + fpu_op_i => fpu_op_i, + rmode_i => rmode_i, + output_o => output_o, + ine_o => ine_o, + overflow_o => overflow_o, + underflow_o => underflow_o, + div_zero_o => div_zero_o, + inf_o => inf_o, + zero_o => zero_o, + qnan_o => qnan_o, + snan_o => snan_o, + start_i => start_i, + ready_o => ready_o); + + + --------------------------------------------------------------------------- + -- toggle clock + --------------------------------------------------------------------------- + clk_i <= not(clk_i) after 5 ns; + + + verify : process + --The operands and results are in Hex format. The test vectors must be placed in a strict order for the verfication to work. + file testcases_file: TEXT open read_mode is "testcases.txt"; --Name of the file containing the test cases. + + variable file_line: line; + variable str_in: string(8 downto 1); + variable str_fpu_op: string(3 downto 1); + variable str_rmode: string(2 downto 1); + begin + + + --------------------------------------------------------------------------------------------------------------------------------------------------- + ---------------------------------------------------SoftFloat test vectors (10000 test cases for each operation) -------------------------------------------------------------------- + start_i <= '0'; + while not endfile(testcases_file) loop + + wait for CLK_PERIOD; start_i <= '1'; + + str_read(testcases_file,str_in); + opa_i <= strhex_to_slv(str_in); + + str_read(testcases_file,str_in); + opb_i <= strhex_to_slv(str_in); + + str_read(testcases_file,str_fpu_op); + fpu_op_i <= to_std_logic_vector(str_fpu_op); + + str_read(testcases_file,str_rmode); + rmode_i <= to_std_logic_vector(str_rmode); + + str_read(testcases_file,str_in); + slv_out <= strhex_to_slv(str_in); + + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + + assert output_o = slv_out + report "Error!!!" + severity failure; + str_read(testcases_file,str_in); + + end loop; + + -------- Boundary values----- + + start_i <= '0'; + -- seeeeeeeefffffffffffffffffffffff + --infinity + wait for CLK_PERIOD; start_i <= '1'; + opa_i <= "01111111011111111111111111111111"; + opb_i <= "01111111011111111111111111111111"; + fpu_op_i <= "000"; + rmode_i <= "00"; + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + assert output_o="01111111100000000000000000000000" + report "Error!!!" + severity failure; + + -- seeeeeeeefffffffffffffffffffffff + -- 1 x1.001 - 1x1.000 = 0x0.001 + wait for CLK_PERIOD; start_i <= '1'; + opa_i <= "00000000100100000000000000000000"; + opb_i <= "10000000100000000000000000000000"; + fpu_op_i <= "000"; + rmode_i <= "00"; + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + assert output_o="00000000000100000000000000000000" + report "Error!!!" + severity failure; + + -- seeeeeeeefffffffffffffffffffffff + -- 10 x 1.0001 - 10 x 1.0000 = + wait for CLK_PERIOD; start_i <= '1'; + opa_i <= "00000001000010000000000000000000"; + opb_i <= "10000001000000000000000000000000"; + fpu_op_i <= "000"; + rmode_i <= "00"; + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + assert output_o="00000000000100000000000000000000" + report "Error!!!" + severity failure; + + + -- seeeeeeeefffffffffffffffffffffff + -- -0 -0 = -0 + wait for CLK_PERIOD; start_i <= '1'; + opa_i <= "10000000000000000000000000000000"; + opb_i <= "10000000000000000000000000000000"; + fpu_op_i <= "000"; + rmode_i <= "00"; + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + assert output_o="10000000000000000000000000000000" + report "Error!!!" + severity failure; + + -- seeeeeeeefffffffffffffffffffffff + -- 0 + x = x + wait for CLK_PERIOD; start_i <= '1'; + opa_i <= "00000000000000000000000000000000"; + opb_i <= "01000010001000001000000000100000"; + fpu_op_i <= "000"; + rmode_i <= "00"; + wait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1'; + assert output_o="01000010001000001000000000100000" + report "Error!!!" + severity failure; + + + ---------------------------------------------------------------------------------------------------------------------------------------------------- + assert false + report "Success!!!.......Yahoooooooooooooo" + severity failure; + + wait; + + end process verify; + +end rtl; \ No newline at end of file diff --git a/src/test_bench/timesoftfloat.exe b/src/test_bench/timesoftfloat.exe new file mode 100644 index 0000000..1f747bf Binary files /dev/null and b/src/test_bench/timesoftfloat.exe differ diff --git a/src/test_bench/txt_util.vhd b/src/test_bench/txt_util.vhd new file mode 100644 index 0000000..3ccc65d --- /dev/null +++ b/src/test_bench/txt_util.vhd @@ -0,0 +1,614 @@ +library ieee; +use ieee.std_logic_1164.all; +use std.textio.all; + + +package txt_util is + + -- prints a message to the screen + procedure print(text: string); + + -- prints the message when active + -- useful for debug switches + procedure print(active: boolean; text: string); + + -- converts std_logic into a character + function chr(sl: std_logic) return character; + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string; + + -- converts std_logic_vector into a string (binary base) + function str(slv: std_logic_vector) return string; + + -- converts boolean into a string + function str(b: boolean) return string; + + -- converts an integer into a single character + -- (can also be used for hex conversion and other bases) + function chr(int: integer) return character; + + -- converts integer into string using specified base + function str(int: integer; base: integer) return string; + + -- converts integer to string, using base 10 + function str(int: integer) return string; + + -- convert std_logic_vector into a string in hex format + function hstr(slv: std_logic_vector) return string; + + + -- functions to manipulate strings + ----------------------------------- + + -- convert a character to upper case + function to_upper(c: character) return character; + + -- convert a character to lower case + function to_lower(c: character) return character; + + -- convert a string to upper case + function to_upper(s: string) return string; + + -- convert a string to lower case + function to_lower(s: string) return string; + + + + -- functions to convert strings into other formats + -------------------------------------------------- + + -- converts a character into std_logic + function to_std_logic(c: character) return std_logic; + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector; + + -- convert Hex string to 32-bit into std_logic_vector + function strhex_to_slv(s : string) return std_logic_vector; + + + + -- file I/O + ----------- + + -- read variable length string from input file + procedure str_read(file in_file: TEXT; + res_string: out string); + + -- print string to a file and start new line + procedure print(file out_file: TEXT; + new_string: in string); + + -- print character to a file and start new line + procedure print(file out_file: TEXT; + char: in character); + +end txt_util; + + + + +package body txt_util is + + + + + -- prints text to the screen + + procedure print(text: string) is + variable msg_line: line; + begin + write(msg_line, text); + writeline(output, msg_line); + end print; + + + + + -- prints text to the screen when active + + procedure print(active: boolean; text: string) is + begin + if active then + print(text); + end if; + end print; + + + -- converts std_logic into a character + + function chr(sl: std_logic) return character is + variable c: character; + begin + case sl is + when 'U' => c:= 'U'; + when 'X' => c:= 'X'; + when '0' => c:= '0'; + when '1' => c:= '1'; + when 'Z' => c:= 'Z'; + when 'W' => c:= 'W'; + when 'L' => c:= 'L'; + when 'H' => c:= 'H'; + when '-' => c:= '-'; + end case; + return c; + end chr; + + + + -- converts std_logic into a string (1 to 1) + + function str(sl: std_logic) return string is + variable s: string(1 to 1); + begin + s(1) := chr(sl); + return s; + end str; + + + + -- converts std_logic_vector into a string (binary base) + -- (this also takes care of the fact that the range of + -- a string is natural while a std_logic_vector may + -- have an integer range) + + function str(slv: std_logic_vector) return string is + variable result : string (1 to slv'length); + variable r : integer; + begin + r := 1; + for i in slv'range loop + result(r) := chr(slv(i)); + r := r + 1; + end loop; + return result; + end str; + + + function str(b: boolean) return string is + + begin + if b then + return "true"; + else + return "false"; + end if; + end str; + + + -- converts an integer into a character + -- for 0 to 9 the obvious mapping is used, higher + -- values are mapped to the characters A-Z + -- (this is usefull for systems with base > 10) + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function chr(int: integer) return character is + variable c: character; + begin + case int is + when 0 => c := '0'; + when 1 => c := '1'; + when 2 => c := '2'; + when 3 => c := '3'; + when 4 => c := '4'; + when 5 => c := '5'; + when 6 => c := '6'; + when 7 => c := '7'; + when 8 => c := '8'; + when 9 => c := '9'; + when 10 => c := 'A'; + when 11 => c := 'B'; + when 12 => c := 'C'; + when 13 => c := 'D'; + when 14 => c := 'E'; + when 15 => c := 'F'; + when 16 => c := 'G'; + when 17 => c := 'H'; + when 18 => c := 'I'; + when 19 => c := 'J'; + when 20 => c := 'K'; + when 21 => c := 'L'; + when 22 => c := 'M'; + when 23 => c := 'N'; + when 24 => c := 'O'; + when 25 => c := 'P'; + when 26 => c := 'Q'; + when 27 => c := 'R'; + when 28 => c := 'S'; + when 29 => c := 'T'; + when 30 => c := 'U'; + when 31 => c := 'V'; + when 32 => c := 'W'; + when 33 => c := 'X'; + when 34 => c := 'Y'; + when 35 => c := 'Z'; + when others => c := '?'; + end case; + return c; + end chr; + + + + -- convert integer to string using specified base + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function str(int: integer; base: integer) return string is + + variable temp: string(1 to 10); + variable num: integer; + variable abs_int: integer; + variable len: integer := 1; + variable power: integer := 1; + + begin + + -- bug fix for negative numbers + abs_int := abs(int); + + num := abs_int; + + while num >= base loop -- Determine how many + len := len + 1; -- characters required + num := num / base; -- to represent the + end loop ; -- number. + + for i in len downto 1 loop -- Convert the number to + temp(i) := chr(abs_int/power mod base); -- a string starting + power := power * base; -- with the right hand + end loop ; -- side. + + -- return result and add sign if required + if int < 0 then + return '-'& temp(1 to len); + else + return temp(1 to len); + end if; + + end str; + + + -- convert integer to string, using base 10 + function str(int: integer) return string is + + begin + + return str(int, 10) ; + + end str; + + + + -- converts a std_logic_vector into a hex string. + function hstr(slv: std_logic_vector) return string is + variable hexlen: integer; + variable longslv : std_logic_vector(67 downto 0) := (others => '0'); + variable hex : string(1 to 16); + variable fourbit : std_logic_vector(3 downto 0); + begin + hexlen := (slv'left+1)/4; + if (slv'left+1) mod 4 /= 0 then + hexlen := hexlen + 1; + end if; + longslv(slv'left downto 0) := slv; + for i in (hexlen -1) downto 0 loop + fourbit := longslv(((i*4)+3) downto (i*4)); + case fourbit is + when "0000" => hex(hexlen -I) := '0'; + when "0001" => hex(hexlen -I) := '1'; + when "0010" => hex(hexlen -I) := '2'; + when "0011" => hex(hexlen -I) := '3'; + when "0100" => hex(hexlen -I) := '4'; + when "0101" => hex(hexlen -I) := '5'; + when "0110" => hex(hexlen -I) := '6'; + when "0111" => hex(hexlen -I) := '7'; + when "1000" => hex(hexlen -I) := '8'; + when "1001" => hex(hexlen -I) := '9'; + when "1010" => hex(hexlen -I) := 'A'; + when "1011" => hex(hexlen -I) := 'B'; + when "1100" => hex(hexlen -I) := 'C'; + when "1101" => hex(hexlen -I) := 'D'; + when "1110" => hex(hexlen -I) := 'E'; + when "1111" => hex(hexlen -I) := 'F'; + when "ZZZZ" => hex(hexlen -I) := 'z'; + when "UUUU" => hex(hexlen -I) := 'u'; + when "XXXX" => hex(hexlen -I) := 'x'; + when others => hex(hexlen -I) := '?'; + end case; + end loop; + return hex(1 to hexlen); + end hstr; + + + + -- functions to manipulate strings + ----------------------------------- + + + -- convert a character to upper case + + function to_upper(c: character) return character is + + variable u: character; + + begin + + case c is + when 'a' => u := 'A'; + when 'b' => u := 'B'; + when 'c' => u := 'C'; + when 'd' => u := 'D'; + when 'e' => u := 'E'; + when 'f' => u := 'F'; + when 'g' => u := 'G'; + when 'h' => u := 'H'; + when 'i' => u := 'I'; + when 'j' => u := 'J'; + when 'k' => u := 'K'; + when 'l' => u := 'L'; + when 'm' => u := 'M'; + when 'n' => u := 'N'; + when 'o' => u := 'O'; + when 'p' => u := 'P'; + when 'q' => u := 'Q'; + when 'r' => u := 'R'; + when 's' => u := 'S'; + when 't' => u := 'T'; + when 'u' => u := 'U'; + when 'v' => u := 'V'; + when 'w' => u := 'W'; + when 'x' => u := 'X'; + when 'y' => u := 'Y'; + when 'z' => u := 'Z'; + when others => u := c; + end case; + + return u; + + end to_upper; + + + -- convert a character to lower case + + function to_lower(c: character) return character is + + variable l: character; + + begin + + case c is + when 'A' => l := 'a'; + when 'B' => l := 'b'; + when 'C' => l := 'c'; + when 'D' => l := 'd'; + when 'E' => l := 'e'; + when 'F' => l := 'f'; + when 'G' => l := 'g'; + when 'H' => l := 'h'; + when 'I' => l := 'i'; + when 'J' => l := 'j'; + when 'K' => l := 'k'; + when 'L' => l := 'l'; + when 'M' => l := 'm'; + when 'N' => l := 'n'; + when 'O' => l := 'o'; + when 'P' => l := 'p'; + when 'Q' => l := 'q'; + when 'R' => l := 'r'; + when 'S' => l := 's'; + when 'T' => l := 't'; + when 'U' => l := 'u'; + when 'V' => l := 'v'; + when 'W' => l := 'w'; + when 'X' => l := 'x'; + when 'Y' => l := 'y'; + when 'Z' => l := 'z'; + when others => l := c; + end case; + + return l; + + end to_lower; + + + + -- convert a string to upper case + + function to_upper(s: string) return string is + + variable uppercase: string (s'range); + + begin + + for i in s'range loop + uppercase(i):= to_upper(s(i)); + end loop; + return uppercase; + + end to_upper; + + + + -- convert a string to lower case + + function to_lower(s: string) return string is + + variable lowercase: string (s'range); + + begin + + for i in s'range loop + lowercase(i):= to_lower(s(i)); + end loop; + return lowercase; + + end to_lower; + + + +-- functions to convert strings into other types + + +-- converts a character into a std_logic + +function to_std_logic(c: character) return std_logic is + variable sl: std_logic; + begin + case c is + when 'U' => + sl := 'U'; + when 'X' => + sl := 'X'; + when '0' => + sl := '0'; + when '1' => + sl := '1'; + when 'Z' => + sl := 'Z'; + when 'W' => + sl := 'W'; + when 'L' => + sl := 'L'; + when 'H' => + sl := 'H'; + when '-' => + sl := '-'; + when others => + sl := 'X'; + end case; + return sl; + end to_std_logic; + + +-- converts a string into std_logic_vector + +function to_std_logic_vector(s: string) return std_logic_vector is + variable slv: std_logic_vector(s'high-s'low downto 0); + variable k: integer; +begin + k := s'high-s'low; + for i in s'range loop + slv(k) := to_std_logic(s(i)); + k := k - 1; + end loop; + return slv; +end to_std_logic_vector; + + +-- convert Hex string to 32-bit SLV + function strhex_to_slv(s : string) return std_logic_vector is + variable int : string(1 to s'length) := s; + variable ptr : integer range 0 to 32 := 0; + variable slv: std_logic_vector(31 downto 0) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => slv(ptr+3 downto ptr) := "0000"; ptr := ptr+4; + when '1' => slv(ptr+3 downto ptr) := "0001"; ptr := ptr+4; + when '2' => slv(ptr+3 downto ptr) := "0010"; ptr := ptr+4; + when '3' => slv(ptr+3 downto ptr) := "0011"; ptr := ptr+4; + when '4' => slv(ptr+3 downto ptr) := "0100"; ptr := ptr+4; + when '5' => slv(ptr+3 downto ptr) := "0101"; ptr := ptr+4; + when '6' => slv(ptr+3 downto ptr) := "0110"; ptr := ptr+4; + when '7' => slv(ptr+3 downto ptr) := "0111"; ptr := ptr+4; + when '8' => slv(ptr+3 downto ptr) := "1000"; ptr := ptr+4; + when '9' => slv(ptr+3 downto ptr) := "1001"; ptr := ptr+4; + when 'a'|'A' => slv(ptr+3 downto ptr) := "1010"; ptr := ptr+4; + when 'b'|'B' => slv(ptr+3 downto ptr) := "1011"; ptr := ptr+4; + when 'c'|'C' => slv(ptr+3 downto ptr) := "1100"; ptr := ptr+4; + when 'd'|'D' => slv(ptr+3 downto ptr) := "1101"; ptr := ptr+4; + when 'e'|'E' => slv(ptr+3 downto ptr) := "1110"; ptr := ptr+4; + when 'f'|'F' => slv(ptr+3 downto ptr) := "1111"; ptr := ptr+4; + when others => null; + end case; + end loop; + return slv; + end strhex_to_slv; +---------------- +-- file I/O -- +---------------- + + + +-- read variable length string from input file + +procedure str_read(file in_file: TEXT; + res_string: out string) is + + variable l: line; + variable c: character; + variable is_string: boolean; + + begin + + readline(in_file, l); + -- clear the contents of the result string + for i in res_string'range loop + res_string(i) := ' '; + end loop; + -- read all characters of the line, up to the length + -- of the results string + for i in res_string'range loop + read(l, c, is_string); + res_string(i) := c; + if not is_string then -- found end of line + exit; + end if; + end loop; + +end str_read; + + +-- print string to a file +procedure print(file out_file: TEXT; + new_string: in string) is + + variable l: line; + + begin + + write(l, new_string); + writeline(out_file, l); + +end print; + + +-- print character to a file and start new line +procedure print(file out_file: TEXT; + char: in character) is + + variable l: line; + + begin + + write(l, char); + writeline(out_file, l); + +end print; + + + +-- appends contents of a string to a file until line feed occurs +-- (LF is considered to be the end of the string) + +procedure str_write(file out_file: TEXT; + new_string: in string) is + begin + + for i in new_string'range loop + print(out_file, new_string(i)); + if new_string(i) = LF then -- end of string + exit; + end if; + end loop; + +end str_write; + + + + +end txt_util; + + + +