Skip to content

Instantly share code, notes, and snippets.

@zeptometer
Created July 31, 2014 13:58
Show Gist options
  • Select an option

  • Save zeptometer/74bf3496cbf1d85cc6ab to your computer and use it in GitHub Desktop.

Select an option

Save zeptometer/74bf3496cbf1d85cc6ab to your computer and use it in GitHub Desktop.
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