📄 fpurt_lib.vhd
字号:
end if; elsif SIsInf(f1) then q1.v := Inf; elsif SIsZero(f1) then q1.v := Zero; end if; return(q1); end SToQuad; function DToQuad(f1: std_logic_vector) return Quad is variable q1 : Quad; begin q1.sign := f1(63); q1.exp := unsigned(ext(f1(62 downto 52),15)) + 16383 - 1023; q1.man := unsigned(ext(('1'& f1(51 downto 0) & "000"),113)); q1.v := Norm; if DIsNaN(f1) then if f1(51) = '1' then q1.v := QNaN; else q1.v := SNaN; end if; elsif DIsInf(f1) then q1.v := Inf; elsif DIsZero(f1) then q1.v := Zero; end if; return(q1); end DToQuad; procedure Normalize(q1 : inout quad) is variable i : integer := 0; begin if q1.v = norm then while (i < 113) and (q1.man(112 - i) = '0') loop i := i + 1; end loop; if (i < 57) then q1.man := shr(q1.man, conv_unsigned(57 - i,8)); else q1.man := shl(q1.man, conv_unsigned(i - 57 ,8)); end if; q1.exp := q1.exp + (57 - i); end if; end Normalize; procedure FPround(q : quad; res : inout std_logic_vector; SP : boolean) is variable i, intexp, iexp, isign, exprange, ig : integer; variable utmp : unsigned (14 downto 0); variable Pround : unsigned (112 downto 0) := (others => '0'); variable q1 : quad := q; variable lexp, lman : integer; variable RDL : std_logic_vector(1 downto 0); begin if q1.v = Inf then if SP then res(31 downto 0) := q1.sign & SPInf; else res(63 downto 0) := q1.sign & DPInf; end if; elsif q1.v = Zero then if SP then res(31 downto 0) := q1.sign & ext("0",31); else res(63 downto 0) := q1.sign & ext("0",63); end if; elsif q1.v <= SNan then if SP then res(31 downto 0) := SPNan; else res(63 downto 0) := DPNan; end if; else if SP then lexp := 8; lman := 23; else lexp := 11; lman := 52; end if; ig := 54 -lman; Pround(ig) := '1'; isign := lman + lexp; iexp := isign - 1; exprange := 2; for i in 2 to lexp loop exprange := exprange * 2; end loop; exprange := exprange; i := 0; -- First, we normalize to quad Normalize(q1); -- Round according to RD RDL := RD( 1 downto 0); if ((q1.man(ig downto 1)) /= unsigned(ext("0",ig-1))) or cexc(0) = '1' then cexc(0) := '1'; -- Inexact ieee flag case RDL(1 downto 0) is when "00" => -- round to nearest if ((q1.man(ig downto 0)) > unsigned('1' & ext("0",ig)) ) or (((q1.man(ig downto 0)) = unsigned('1' & ext("0",ig)) ) and (q1.man(ig+1) = '1') ) then q1.man := q1.man + Pround; Normalize(q1); end if; when "01" => -- round to zero (truncate) null; when "10" => -- round to +Inf if q1.sign = '0' then q1.man := q1.man + shl(Pround,"01"); end if; when "11" => -- round to -Inf if q1.sign = '1' then q1.man := q1.man + shl(Pround,"01"); end if; when others => null; end case; end if; res(isign) := q1.sign; utmp := q1.exp + (-16383 + (exprange / 2) -1); res(iexp downto lman) := std_logic_vector(utmp((lexp-1) downto 0)); res(lman-1 downto 0) := std_logic_vector(q1.man(54 downto (54 -lman +1))); -- Check ieee exceptions, improvements here are welcome intexp := conv_integer(q1.exp); if (intexp > ( 16383 + exprange/2 -1)) then cexc(3) := '1'; -- overflow case RDL(1 downto 0) is when "00" => -- round to nearest, return 1 res(iexp downto lman) := '0' & sxt("1",lexp - 1); res(lman-1 downto 0) := ext("0",lman); when "01" => -- round to zero, return largest norm res(iexp downto lman) := sxt("1",lexp - 1) & '0'; res(lman-1 downto 0) := sxt("1",lman); when "10" => -- round to +Inf if res(isign) = '1' then -- most negitive norm res(iexp downto lman) := sxt("1",lexp - 1) & '0'; res(lman-1 downto 0) := sxt("1",lman); else -- +Inf res(iexp downto lman) := sxt("1",lexp); res(lman-1 downto 0) := sxt("0",lman); end if; when "11" => -- round to -Inf if res(isign) = '0' then -- most positive norm res(iexp downto lman) := sxt("1",lexp - 1) & '0'; res(lman-1 downto 0) := sxt("1",lman); else -- -Inf res(iexp downto lman) := sxt("1",lexp); res(lman-1 downto 0) := sxt("0",lman); end if; when others => null; end case; elsif (intexp < (16383 - exprange/2 + 2)) then cexc(2) := '1'; -- underflow, return denorm i := 16383 - intexp + (exprange / 2) - 1; res(iexp downto lman) := ext("0",lexp); res(lman-1 downto 0) := std_logic_vector(shr(q1.man(55 downto 55 - lman +1),(conv_unsigned(i,8)))); end if; end if; if (SP) then res (63 downto 32) := res(31 downto 0); end if; end FPround; procedure fmul(rs1, rs2: Quad; res: out Quad) is variable q1: Quad; begin res.sign := rs1.sign xor rs2.sign; if (rs1.v = Zero) or (rs2.v = Zero) then res.v := Zero; elsif (rs1.v = Inf) or (rs2.v = Inf) then res.v := Inf; else res.v := Norm; res.exp := (rs1.exp - 16383) + rs2.exp - 55; res.man := '0' & (rs1.man(55 downto 0) * rs2.man(55 downto 0)); end if; end fmul; procedure fdiv(rs1, rs2: Quad; res: out Quad) is variable q1,q2: Quad; variable i : integer := 55; begin res.sign := rs1.sign xor rs2.sign; res.exp := (rs1.exp - rs2.exp) + 16383; res.man := unsigned(ext("0",113)); if (rs1.v = Zero) then res.v := Zero; elsif (rs2.v = Inf) then res.v := Zero; else res.v := Norm; q1.man := shl(rs1.man,"0111000"); q2.man := shl(rs2.man,"0111000"); while (i > 0) loop if q2.man <= q1.man then q1.man := q1.man - q2.man; res.man(i) := '1'; end if; i := i - 1; q2.man := shr(q2.man, "01"); end loop; if q1.man /= unsigned(ext("0",113)) then cexc(0) := '1'; -- Inexact end if; end if; end fdiv; procedure fcmp(q1, q2: quad; tfcc: out std_logic_vector) is variable s1, s2 : signed(127 downto 0); begin if ((q1.v = Inf) and (q2.v = Inf) and (q1.sign = q2.sign)) then tfcc := "11"; else s1 := signed(q1.sign & q1.exp & q1.man(111 downto 0)); s2 := signed(q2.sign & q2.exp & q2.man(111 downto 0)); if (s1 < s2) then tfcc := "01"; elsif (s1 > s2) then tfcc := "10"; else tfcc := "00"; end if; end if; end fcmp; procedure faddsub(rs1, rs2: quad; res: out quad; doadd : boolean) is variable s1, s2, exp1, exp2, man1, man2: quad; begin if (rs1.v = Inf) then res := rs1; if (rs2.v = Inf) then if ((doadd and (rs1.sign /= rs2.sign)) or (not doadd and (rs1.sign = rs2.sign))) then cexc(4) := '1'; res.v := QNan; res.sign := '0'; end if; end if; elsif (rs2.v = Inf) then res.v := Inf; if doadd then res.sign := rs2.sign; else res.sign := not rs2.sign; end if; elsif (rs1 = rs2) then res := rs1; if doadd then res.exp := rs1.exp + 1; else res.v := Zero; if RD = "11" then res.sign := '1'; else res.sign := '0'; end if; end if; elsif (rs1.v = Zero) then res := rs2; if (rs2.v = norm) and not doadd then res.sign := not rs2.sign; end if; elsif (rs2.v = Zero) then res := rs1; else if (rs1.exp < rs2.exp) then s1 := rs2; s2 := rs1; if not doadd then s1.sign := not s1.sign; end if; else s1 := rs1; s2 := rs2; if not doadd then s2.sign := not s2.sign; end if; end if; s2.man := shr(s2.man, s1.exp - s2.exp); if (s1.sign = '1') then s1.man := 0 - s1.man; end if; if (s2.sign = '1') then s2.man := 0 - s2.man; end if; s1.man := s1.man + s2.man; s1.sign := s1.man(112); if (s1.man(112) = '1') then s1.man := 0 - s1.man; end if; res := s1; if s1.man = unsigned(ext("0",113)) then res.v := Zero; end if; end if; end; procedure fsqrt(rs1 : quad; res: out quad; sp : boolean) is variable s1, s2, s3, s4, s5 : quad; variable accuracy : integer; begin -- Sqrt calculations according newton/rapson xn = (x2 +s1)/2x if (rs1.v = Norm) then s1 := rs1; s2 := rs1; if SP then accuracy := 16838 - 130; else accuracy := 16838 - 1026; end if; s2.exp := s2.exp - 1; -- s2 is seed, equal to s1/2 loop fmul(s2,s2,s3); Normalize(s3); faddsub(s3, s1, s4, false); Normalize(s4); s4.exp := s4.exp -1; fdiv(s4,s2,s3); Normalize(s3); faddsub(s2, s3, s5, false); Normalize(s5);-- s4 := s1;-- s4.exp := s4.exp -1;-- fdiv(s4,s2,s3);-- Normalize(s3);-- s4 := s2;-- s4.exp := s4.exp -1;-- faddsub(s3, s4, s5, true);-- Normalize(s5); if (s5.v /= norm) or (s3.v /= norm) or (s2 = s5) then exit; end if; s2 := s5; end loop;-- if s5.man(1 downto 0) = unsigned'("11") then-- s5.man := s5.man + 1;-- Normalize(s5);-- elsif s5.man(1 downto 0) = unsigned'("01") then-- s5.man(0) := '0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -