From 0e33e3a609436a1fd615c12592ea78b5a21f0385 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Thu, 10 Apr 2014 19:23:53 +0800 Subject: [PATCH] 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). --- .gitignore | 7 + README | 12 + src/addsub_28.vhd | 128 +++++++ src/bug_report.txt | 15 + src/comppack.vhd | 227 ++++++++++++ src/fpu.vhd | 465 +++++++++++++++++++++++ src/fpupack.vhd | 114 ++++++ src/mul_24.vhd | 230 ++++++++++++ src/post_norm_addsub.vhd | 225 +++++++++++ src/post_norm_div.vhd | 262 +++++++++++++ src/post_norm_mul.vhd | 269 ++++++++++++++ src/post_norm_sqrt.vhd | 166 +++++++++ src/pre_norm_addsub.vhd | 168 +++++++++ src/pre_norm_div.vhd | 125 +++++++ src/pre_norm_mul.vhd | 105 ++++++ src/pre_norm_sqrt.vhd | 111 ++++++ src/readme.txt | 21 ++ src/serial_div.vhd | 163 ++++++++ src/serial_mul.vhd | 146 ++++++++ src/sqrt.vhd | 211 +++++++++++ src/test_bench/fpu_wave.do | 34 ++ src/test_bench/fpusim.bat | 29 ++ src/test_bench/maketest.bat | 23 ++ src/test_bench/readme.txt | 9 + src/test_bench/tb_fpu.vhd | 259 +++++++++++++ src/test_bench/timesoftfloat.exe | Bin 0 -> 44226 bytes src/test_bench/txt_util.vhd | 614 +++++++++++++++++++++++++++++++ 27 files changed, 4138 insertions(+) create mode 100644 .gitignore create mode 100644 README create mode 100644 src/addsub_28.vhd create mode 100644 src/bug_report.txt create mode 100644 src/comppack.vhd create mode 100644 src/fpu.vhd create mode 100644 src/fpupack.vhd create mode 100644 src/mul_24.vhd create mode 100644 src/post_norm_addsub.vhd create mode 100644 src/post_norm_div.vhd create mode 100644 src/post_norm_mul.vhd create mode 100644 src/post_norm_sqrt.vhd create mode 100644 src/pre_norm_addsub.vhd create mode 100644 src/pre_norm_div.vhd create mode 100644 src/pre_norm_mul.vhd create mode 100644 src/pre_norm_sqrt.vhd create mode 100644 src/readme.txt create mode 100644 src/serial_div.vhd create mode 100644 src/serial_mul.vhd create mode 100644 src/sqrt.vhd create mode 100644 src/test_bench/fpu_wave.do create mode 100644 src/test_bench/fpusim.bat create mode 100644 src/test_bench/maketest.bat create mode 100644 src/test_bench/readme.txt create mode 100644 src/test_bench/tb_fpu.vhd create mode 100644 src/test_bench/timesoftfloat.exe create mode 100644 src/test_bench/txt_util.vhd 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 0000000000000000000000000000000000000000..1f747bf9730a69e8db17f8b4a8fa9136343f3aac GIT binary patch literal 44226 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 Q7q-_bGGOG~ 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; + + + + -- 2.20.1