Created
July 31, 2014 13:58
-
-
Save zeptometer/74bf3496cbf1d85cc6ab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| library ieee; | |
| use ieee.std_logic_1164.all; | |
| use ieee.numeric_std.all; | |
| library work; | |
| use work.utility.all; | |
| entity fadd is | |
| port ( clk : in std_logic; | |
| i1 : in unsigned(31 downto 0); | |
| i2 : in unsigned(31 downto 0); | |
| o : out unsigned(31 downto 0)); | |
| end fadd; | |
| architecture implementation of fadd is | |
| constant ieee_plus_zero : unsigned(31 downto 0) := "00000000000000000000000000000000"; | |
| constant ieee_mins_zero : unsigned(31 downto 0) := "10000000000000000000000000000000"; | |
| constant ieee_nan : unsigned(31 downto 0) := "01111111100000000000000000000001"; | |
| constant ieee_plus_inf : unsigned(31 downto 0) := "01111111100000000000000000000000"; | |
| constant ieee_minus_inf : unsigned(31 downto 0) := "11111111100000000000000000000000"; | |
| constant ieee_inf : unsigned(30 downto 0) := "1111111100000000000000000000000"; | |
| constant ieee_zero : unsigned(30 downto 0) := "0000000000000000000000000000000"; | |
| constant zero : unsigned(31 downto 0) := "00000000000000000000000000000000"; | |
| function fadd_formal(r : unsigned(31 downto 0); | |
| q : unsigned(31 downto 0)) | |
| return unsigned is | |
| function fadd_formal_frac(same_sign: std_logic; | |
| offset: unsigned(31 downto 0); | |
| lfrac : unsigned(31 downto 0); | |
| rfrac : unsigned(31 downto 0)) | |
| return unsigned is | |
| variable l : unsigned(31 downto 0); | |
| variable r : unsigned(31 downto 0); | |
| variable sticky : unsigned(31 downto 0); | |
| begin | |
| l := shift_left(lfrac, 3) or "00000100000000000000000000000000"; | |
| r := shift_left(rfrac, 3) or "00000100000000000000000000000000"; | |
| if (offset < 32) then | |
| sticky := some(shift_left(r, 32-to_integer(offset))); | |
| r := shift_right(r, to_integer(offset)) or sticky; | |
| else | |
| r := some(r); | |
| end if; | |
| if (same_sign = '1') then | |
| return l+r; | |
| else | |
| return l-r; | |
| end if; | |
| end fadd_formal_frac; | |
| function formalize(sign : unsigned(31 downto 0); | |
| expt : unsigned(31 downto 0); | |
| frac : unsigned(31 downto 0)) | |
| return unsigned is | |
| variable i : integer := 31; | |
| variable diff : integer; | |
| variable tmp : unsigned(31 downto 0); | |
| variable sticky : std_logic; | |
| variable ffrac : unsigned(31 downto 0); | |
| variable fexpt : unsigned(31 downto 0); | |
| begin | |
| while (frac(i) = '0') loop | |
| i := i-1; | |
| end loop; | |
| diff := i-26; | |
| if (diff > 0) then | |
| tmp := shift_right(frac, diff); | |
| sticky := some(shift_left(frac, 32-diff))(0); | |
| else | |
| tmp := shift_left(frac, -diff); | |
| sticky := '0'; | |
| end if; | |
| ffrac := shift_right(tmp, 3); | |
| if (tmp(4) = '1' and (tmp(8) = '1' or tmp(2) = '1' or sticky = '1')) then | |
| ffrac := ffrac + 1; | |
| end if; | |
| if (diff >= 0) then | |
| fexpt := expt + to_unsigned(diff, 32); | |
| elsif (fexpt <= to_unsigned(-diff, 32)) then | |
| fexpt := zero; | |
| else | |
| fexpt := fexpt - to_unsigned(-diff, 32); | |
| end if; | |
| if (ffrac(24) = '1') then | |
| ffrac := shift_right(ffrac, 1); | |
| fexpt := fexpt + 1; | |
| end if; | |
| if (fexpt >= to_unsigned(255, 32)) then | |
| return sign(0 downto 0) & ieee_inf; | |
| elsif (fexpt = to_unsigned(0, 32)) then | |
| return sign(0 downto 0) & ieee_zero; | |
| else | |
| return sign(0 downto 0) & fexpt(7 downto 0) & ffrac(22 downto 0); | |
| end if; | |
| end formalize; | |
| variable rs : unsigned(31 downto 0); | |
| variable qs : unsigned(31 downto 0); | |
| variable re : unsigned(31 downto 0); | |
| variable qe : unsigned(31 downto 0); | |
| variable rf : unsigned(31 downto 0); | |
| variable qf : unsigned(31 downto 0); | |
| variable same_sign : std_logic; | |
| variable sign : unsigned(31 downto 0); | |
| variable expt : unsigned(31 downto 0); | |
| variable frac : unsigned(31 downto 0); | |
| begin | |
| rs := resize(r(31 downto 31), 32); | |
| re := resize(r(30 downto 23), 32); | |
| rf := resize(r(22 downto 0), 32); | |
| qs := resize(q(31 downto 31), 32); | |
| qe := resize(q(30 downto 23), 32); | |
| qf := resize(q(22 downto 0), 32); | |
| if (rs = qs) then | |
| same_sign := '1'; | |
| else | |
| same_sign := '0'; | |
| end if; | |
| if (same_sign = '0' and re = qe and rf = qf) then | |
| return ieee_plus_zero; | |
| end if; | |
| if (re > qe or (re = qe and rf > qf)) then | |
| sign := rs; | |
| expt := re; | |
| frac := fadd_formal_frac(same_sign, re-qe, rf, qf); | |
| else | |
| sign := qs; | |
| expt := qe; | |
| frac := fadd_formal_frac(same_sign, qe-re, qf, rf); | |
| end if; | |
| return formalize(sign, expt, frac); | |
| end fadd_formal; | |
| type ftype is (plus_zero, minus_zero, formal, informal, plus_inf, minus_inf, nan); | |
| function get_ftype(r : unsigned(31 downto 0)) | |
| return ftype is | |
| variable s : unsigned(0 downto 0); | |
| variable e : unsigned(7 downto 0); | |
| variable f : unsigned(22 downto 0); | |
| begin | |
| s := r(31 downto 31); | |
| e := r(30 downto 23); | |
| f := r(22 downto 0); | |
| if (s = "0" and e = "00000000" and f = "00000000000000000000000") then | |
| return plus_zero; | |
| elsif (s = "1" and e = "00000000" and f = "00000000000000000000000") then | |
| return minus_zero; | |
| elsif (e = "00000000" and f /= "00000000000000000000000") then | |
| return informal; | |
| elsif (s = "0" and e = "11111111" and f = "00000000000000000000000") then | |
| return plus_inf; | |
| elsif (s = "1" and e = "11111111" and f = "00000000000000000000000") then | |
| return minus_inf; | |
| elsif (e = "11111111" and f /= "00000000000000000000000") then | |
| return nan; | |
| else | |
| return formal; | |
| end if; | |
| end get_ftype; | |
| begin | |
| process(clk) | |
| variable t1 : ftype; | |
| variable t2 : ftype; | |
| variable ans : unsigned(31 downto 0); | |
| begin | |
| if (rising_edge(clk)) then | |
| t1 := get_ftype(i1); | |
| t2 := get_ftype(i1); | |
| if (t1 = nan or t2 = nan | |
| or (t1 = plus_inf and t2 = minus_inf) | |
| or (t1 = minus_inf and t2 = plus_inf)) then | |
| ans := ieee_nan; | |
| elsif (t1 = plus_inf or t2 = plus_inf) then | |
| ans := ieee_plus_inf; | |
| elsif (t1 = minus_inf or t2 = minus_inf) then | |
| ans := ieee_minus_inf; | |
| elsif (t1 = minus_zero) then | |
| ans := i2; | |
| elsif (t2 = minus_zero) then | |
| ans := i1; | |
| elsif (t1 = plus_zero) then | |
| ans := i2; | |
| elsif (t2 = plus_zero) then | |
| ans := i1; | |
| elsif (t1 = informal) then | |
| ans := i2; | |
| elsif (t2 = informal) then | |
| ans := i1; | |
| else | |
| ans := fadd_formal(i1, i2); | |
| end if; | |
| o <= ans; | |
| end if; | |
| end process; | |
| end implementation; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment