@ -44,7 +44,7 @@ architecture behaviour of fpu is
DO_FRE, DO_FRSQRTE,
DO_FRE, DO_FRSQRTE,
DO_FSEL,
DO_FSEL,
FRI_1,
FRI_1,
ADD_SHIFT, ADD_2, ADD_3,
ADD_1, ADD_SHIFT, ADD_2, ADD_3,
CMP_1, CMP_2,
CMP_1, CMP_2,
MULT_1,
MULT_1,
FMADD_1, FMADD_2, FMADD_3,
FMADD_1, FMADD_2, FMADD_3,
@ -65,7 +65,8 @@ architecture behaviour of fpu is
DENORM,
DENORM,
RENORM_A, RENORM_A2,
RENORM_A, RENORM_A2,
RENORM_B, RENORM_B2,
RENORM_B, RENORM_B2,
RENORM_C, RENORM_C2);
RENORM_C, RENORM_C2,
NAN_RESULT, EXC_RESULT);
type reg_type is record
type reg_type is record
state : state_t;
state : state_t;
@ -111,6 +112,12 @@ architecture behaviour of fpu is
first : std_ulogic;
first : std_ulogic;
count : unsigned(1 downto 0);
count : unsigned(1 downto 0);
doing_ftdiv : std_ulogic_vector(1 downto 0);
doing_ftdiv : std_ulogic_vector(1 downto 0);
opsel_a : std_ulogic_vector(1 downto 0);
use_a : std_ulogic;
use_b : std_ulogic;
use_c : std_ulogic;
invalid : std_ulogic;
negate : std_ulogic;
end record;
end record;
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
@ -118,7 +125,6 @@ architecture behaviour of fpu is
signal r, rin : reg_type;
signal r, rin : reg_type;
signal fp_result : std_ulogic_vector(63 downto 0);
signal fp_result : std_ulogic_vector(63 downto 0);
signal opsel_a : std_ulogic_vector(1 downto 0);
signal opsel_b : std_ulogic_vector(1 downto 0);
signal opsel_b : std_ulogic_vector(1 downto 0);
signal opsel_r : std_ulogic_vector(1 downto 0);
signal opsel_r : std_ulogic_vector(1 downto 0);
signal opsel_s : std_ulogic_vector(1 downto 0);
signal opsel_s : std_ulogic_vector(1 downto 0);
@ -724,7 +730,7 @@ begin
v.update_fprf := '0';
v.update_fprf := '0';
v.shift := to_signed(0, EXP_BITS);
v.shift := to_signed(0, EXP_BITS);
v.first := '0';
v.first := '0';
opsel_a <= AIN_R;
v.opsel_a := AIN_R;
opsel_ainv <= '0';
opsel_ainv <= '0';
opsel_amask <= '0';
opsel_amask <= '0';
opsel_b <= BIN_ZERO;
opsel_b <= BIN_ZERO;
@ -758,6 +764,11 @@ begin
shiftin := '0';
shiftin := '0';
case r.state is
case r.state is
when IDLE =>
when IDLE =>
v.use_a := '0';
v.use_b := '0';
v.use_c := '0';
v.invalid := '0';
v.negate := '0';
if e_in.valid = '1' then
if e_in.valid = '1' then
case e_in.insn(5 downto 1) is
case e_in.insn(5 downto 1) is
when "00000" =>
when "00000" =>
@ -770,6 +781,7 @@ begin
elsif e_in.insn(7) = '1' then
elsif e_in.insn(7) = '1' then
v.state := DO_MCRFS;
v.state := DO_MCRFS;
else
else
v.opsel_a := AIN_B;
v.state := DO_FCMP;
v.state := DO_FCMP;
end if;
end if;
when "00110" =>
when "00110" =>
@ -789,14 +801,17 @@ begin
v.state := DO_MTFSF;
v.state := DO_MTFSF;
end if;
end if;
when "01000" =>
when "01000" =>
v.opsel_a := AIN_B;
if e_in.insn(9 downto 8) /= "11" then
if e_in.insn(9 downto 8) /= "11" then
v.state := DO_FMR;
v.state := DO_FMR;
else
else
v.state := DO_FRI;
v.state := DO_FRI;
end if;
end if;
when "01100" =>
when "01100" =>
v.opsel_a := AIN_B;
v.state := DO_FRSP;
v.state := DO_FRSP;
when "01110" =>
when "01110" =>
v.opsel_a := AIN_B;
if int_input = '1' then
if int_input = '1' then
-- fcfid[u][s]
-- fcfid[u][s]
v.state := DO_FCFID;
v.state := DO_FCFID;
@ -805,25 +820,45 @@ begin
end if;
end if;
when "01111" =>
when "01111" =>
v.round_mode := "001";
v.round_mode := "001";
v.opsel_a := AIN_B;
v.state := DO_FCTI;
v.state := DO_FCTI;
when "10010" =>
when "10010" =>
v.opsel_a := AIN_A;
if v.b.mantissa(54) = '0' and v.a.mantissa(54) = '1' then
v.opsel_a := AIN_B;
end if;
v.state := DO_FDIV;
v.state := DO_FDIV;
when "10100" | "10101" =>
when "10100" | "10101" =>
v.opsel_a := AIN_A;
v.state := DO_FADD;
v.state := DO_FADD;
when "10110" =>
when "10110" =>
v.is_sqrt := '1';
v.is_sqrt := '1';
v.opsel_a := AIN_B;
v.state := DO_FSQRT;
v.state := DO_FSQRT;
when "10111" =>
when "10111" =>
v.state := DO_FSEL;
v.state := DO_FSEL;
when "11000" =>
when "11000" =>
v.opsel_a := AIN_B;
v.state := DO_FRE;
v.state := DO_FRE;
when "11001" =>
when "11001" =>
v.is_multiply := '1';
v.is_multiply := '1';
v.opsel_a := AIN_A;
if v.c.mantissa(54) = '0' and v.a.mantissa(54) = '1' then
v.opsel_a := AIN_C;
end if;
v.state := DO_FMUL;
v.state := DO_FMUL;
when "11010" =>
when "11010" =>
v.is_sqrt := '1';
v.is_sqrt := '1';
v.opsel_a := AIN_B;
v.state := DO_FRSQRTE;
v.state := DO_FRSQRTE;
when "11100" | "11101" | "11110" | "11111" =>
when "11100" | "11101" | "11110" | "11111" =>
if v.a.mantissa(54) = '0' then
v.opsel_a := AIN_A;
elsif v.c.mantissa(54) = '0' then
v.opsel_a := AIN_C;
else
v.opsel_a := AIN_B;
end if;
v.state := DO_FMADD;
v.state := DO_FMADD;
when others =>
when others =>
illegal := '1';
illegal := '1';
@ -880,11 +915,10 @@ begin
when DO_FCMP =>
when DO_FCMP =>
-- fcmp[uo]
-- fcmp[uo]
-- r.opsel_a = AIN_B
v.instr_done := '1';
v.instr_done := '1';
v.state := IDLE;
v.state := IDLE;
update_fx := '1';
update_fx := '1';
opsel_a <= AIN_B;
opsel_r <= RES_SUM;
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
(r.b.class = NAN and r.b.mantissa(53) = '0') then
(r.b.class = NAN and r.b.mantissa(53) = '0') then
@ -930,6 +964,7 @@ begin
-- Prepare to subtract mantissas, put B in R
-- Prepare to subtract mantissas, put B in R
v.cr_result := "0000";
v.cr_result := "0000";
v.instr_done := '0';
v.instr_done := '0';
v.opsel_a := AIN_A;
v.state := CMP_1;
v.state := CMP_1;
end if;
end if;
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
@ -1017,7 +1052,7 @@ begin
v.state := IDLE;
v.state := IDLE;
when DO_FMR =>
when DO_FMR =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
v.quieten_nan := '0';
v.quieten_nan := '0';
@ -1037,7 +1072,7 @@ begin
v.state := IDLE;
v.state := IDLE;
when DO_FRI => -- fri[nzpm]
when DO_FRI => -- fri[nzpm]
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
@ -1062,7 +1097,7 @@ begin
end if;
end if;
when DO_FRSP =>
when DO_FRSP =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B, r.shift = 0
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
@ -1092,7 +1127,7 @@ begin
-- instr bit 9: 1=dword 0=word
-- instr bit 9: 1=dword 0=word
-- instr bit 8: 1=unsigned 0=signed
-- instr bit 8: 1=unsigned 0=signed
-- instr bit 1: 1=round to zero 0=use fpscr[RN]
-- instr bit 1: 1=round to zero 0=use fpscr[RN]
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
@ -1130,8 +1165,8 @@ begin
end case;
end case;
when DO_FCFID =>
when DO_FCFID =>
-- r.opsel_a = AIN_B
v.result_sign := '0';
v.result_sign := '0';
opsel_a <= AIN_B;
if r.insn(8) = '0' and r.b.negative = '1' then
if r.insn(8) = '0' and r.b.negative = '1' then
-- fcfid[s] with negative operand, set R = -B
-- fcfid[s] with negative operand, set R = -B
opsel_ainv <= '1';
opsel_ainv <= '1';
@ -1150,16 +1185,19 @@ begin
when DO_FADD =>
when DO_FADD =>
-- fadd[s] and fsub[s]
-- fadd[s] and fsub[s]
opsel_a <= AIN_A;
-- r.opsel_a = AIN_A
v.result_sign := r.a.negative;
v.result_sign := r.a.negative;
v.result_class := r.a.class;
v.result_class := r.a.class;
v.result_exp := r.a.exponent;
v.result_exp := r.a.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
v.use_a := '1';
v.use_b := '1';
is_add := r.a.negative xor r.b.negative xor r.insn(1);
is_add := r.a.negative xor r.b.negative xor r.insn(1);
if r.a.class = FINITE and r.b.class = FINITE then
if r.a.class = FINITE and r.b.class = FINITE then
v.is_subtract := not is_add;
v.is_subtract := not is_add;
v.add_bsmall := r.exp_cmp;
v.add_bsmall := r.exp_cmp;
v.opsel_a := AIN_B;
if r.exp_cmp = '0' then
if r.exp_cmp = '0' then
v.shift := r.a.exponent - r.b.exponent;
v.shift := r.a.exponent - r.b.exponent;
v.result_sign := r.b.negative xnor r.insn(1);
v.result_sign := r.b.negative xnor r.insn(1);
@ -1169,77 +1207,55 @@ begin
v.state := ADD_SHIFT;
v.state := ADD_SHIFT;
end if;
end if;
else
else
opsel_a <= AIN_B;
v.state := ADD_1;
v.shift := r.b.exponent - r.a.exponent;
v.result_exp := r.b.exponent;
v.state := ADD_SHIFT;
end if;
end if;
else
else
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
if r.a.class = NAN or r.b.class = NAN then
(r.b.class = NAN and r.b.mantissa(53) = '0') then
v.state := NAN_RESULT;
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.a.class = NAN then
-- nothing to do, result is A
elsif r.b.class = NAN then
v.result_class := NAN;
v.result_sign := r.b.negative;
opsel_a <= AIN_B;
elsif r.a.class = INFINITY and r.b.class = INFINITY and is_add = '0' then
elsif r.a.class = INFINITY and r.b.class = INFINITY and is_add = '0' then
-- invalid operation, construct QNaN
-- invalid operation, construct QNaN
v.fpscr(FPSCR_VXISI) := '1';
v.fpscr(FPSCR_VXISI) := '1';
qnan_result := '1';
qnan_result := '1';
arith_done := '1';
elsif r.a.class = ZERO and r.b.class = ZERO and is_add = '0' then
elsif r.a.class = ZERO and r.b.class = ZERO and is_add = '0' then
-- return -0 for rounding to -infinity
-- return -0 for rounding to -infinity
v.result_sign := r.round_mode(1) and r.round_mode(0);
v.result_sign := r.round_mode(1) and r.round_mode(0);
arith_done := '1';
elsif r.a.class = INFINITY or r.b.class = ZERO then
elsif r.a.class = INFINITY or r.b.class = ZERO then
-- nothing to do, result is A
-- result is A
v.opsel_a := AIN_A;
v.state := EXC_RESULT;
else
else
-- result is +/- B
-- result is +/- B
v.result_sign := r.b.negative xnor r.insn(1);
v.opsel_a := AIN_B;
v.result_class := r.b.class;
v.negate := not r.insn(1);
v.result_exp := r.b.exponent;
v.state := EXC_RESULT;
opsel_a <= AIN_B;
end if;
end if;
arith_done := '1';
end if;
end if;
when DO_FMUL =>
when DO_FMUL =>
-- fmul[s]
-- fmul[s]
opsel_a <= AIN_A;
-- r.opsel_a = AIN_A unless C is denorm and A isn't
v.result_sign := r.a.negative;
v.result_sign := r.a.negative xor r.c.negative;
v.result_class := r.a.class;
v.result_class := r.a.class;
v.result_exp := r.a.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
v.use_a := '1';
v.use_c := '1';
if r.a.class = FINITE and r.c.class = FINITE then
if r.a.class = FINITE and r.c.class = FINITE then
v.result_sign := r.a.negative xor r.c.negative;
v.result_exp := r.a.exponent + r.c.exponent;
v.result_exp := r.a.exponent + r.c.exponent;
-- Renormalize denorm operands
-- Renormalize denorm operands
if r.a.mantissa(54) = '0' then
if r.a.mantissa(54) = '0' then
v.state := RENORM_A;
v.state := RENORM_A;
elsif r.c.mantissa(54) = '0' then
elsif r.c.mantissa(54) = '0' then
opsel_a <= AIN_C;
v.state := RENORM_C;
v.state := RENORM_C;
else
else
f_to_multiply.valid <= '1';
f_to_multiply.valid <= '1';
v.state := MULT_1;
v.state := MULT_1;
end if;
end if;
else
else
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
if r.a.class = NAN or r.c.class = NAN then
(r.c.class = NAN and r.c.mantissa(53) = '0') then
v.state := NAN_RESULT;
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.a.class = NAN then
-- result is A
elsif r.c.class = NAN then
v.result_class := NAN;
v.result_sign := r.c.negative;
opsel_a <= AIN_C;
elsif (r.a.class = INFINITY and r.c.class = ZERO) or
elsif (r.a.class = INFINITY and r.c.class = ZERO) or
(r.a.class = ZERO and r.c.class = INFINITY) then
(r.a.class = ZERO and r.c.class = INFINITY) then
-- invalid operation, construct QNaN
-- invalid operation, construct QNaN
@ -1247,22 +1263,22 @@ begin
qnan_result := '1';
qnan_result := '1';
elsif r.a.class = ZERO or r.a.class = INFINITY then
elsif r.a.class = ZERO or r.a.class = INFINITY then
-- result is +/- A
-- result is +/- A
v.result_sign := r.a.negative xor r.c.negative;
arith_done := '1';
else
else
-- r.c.class is ZERO or INFINITY
-- r.c.class is ZERO or INFINITY
v.result_class := r.c.class;
v.opsel_a := AIN_C;
v.result_sign := r.a.negative xor r.c.negative;
v.negate := r.a.negative;
v.state := EXC_RESULT;
end if;
end if;
arith_done := '1';
end if;
end if;
when DO_FDIV =>
when DO_FDIV =>
opsel_a <= AIN_A;
-- r.opsel_a = AIN_A unless B is denorm and A isn't
v.result_sign := r.a.negative;
v.result_class := r.a.class;
v.result_class := r.a.class;
v.result_exp := r.a.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
v.use_a := '1';
v.use_b := '1';
v.result_sign := r.a.negative xor r.b.negative;
v.result_sign := r.a.negative xor r.b.negative;
v.result_exp := r.a.exponent - r.b.exponent;
v.result_exp := r.a.exponent - r.b.exponent;
v.count := "00";
v.count := "00";
@ -1271,26 +1287,14 @@ begin
if r.a.mantissa(54) = '0' then
if r.a.mantissa(54) = '0' then
v.state := RENORM_A;
v.state := RENORM_A;
elsif r.b.mantissa(54) = '0' then
elsif r.b.mantissa(54) = '0' then
opsel_a <= AIN_B;
v.state := RENORM_B;
v.state := RENORM_B;
else
else
v.first := '1';
v.first := '1';
v.state := DIV_2;
v.state := DIV_2;
end if;
end if;
else
else
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
if r.a.class = NAN or r.b.class = NAN then
(r.b.class = NAN and r.b.mantissa(53) = '0') then
v.state := NAN_RESULT;
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.a.class = NAN then
-- result is A
v.result_sign := r.a.negative;
elsif r.b.class = NAN then
v.result_class := NAN;
v.result_sign := r.b.negative;
opsel_a <= AIN_B;
elsif r.b.class = INFINITY then
elsif r.b.class = INFINITY then
if r.a.class = INFINITY then
if r.a.class = INFINITY then
v.fpscr(FPSCR_VXIDI) := '1';
v.fpscr(FPSCR_VXIDI) := '1';
@ -1298,6 +1302,7 @@ begin
else
else
v.result_class := ZERO;
v.result_class := ZERO;
end if;
end if;
arith_done := '1';
elsif r.b.class = ZERO then
elsif r.b.class = ZERO then
if r.a.class = ZERO then
if r.a.class = ZERO then
v.fpscr(FPSCR_VXZDZ) := '1';
v.fpscr(FPSCR_VXZDZ) := '1';
@ -1308,46 +1313,36 @@ begin
end if;
end if;
v.result_class := INFINITY;
v.result_class := INFINITY;
end if;
end if;
-- else r.b.class = FINITE, result_class = r.a.class
arith_done := '1';
end if;
else -- r.b.class = FINITE, result_class = r.a.class
arith_done := '1';
arith_done := '1';
end if;
end if;
end if;
when DO_FSEL =>
when DO_FSEL =>
opsel_a <= AIN_A;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
v.result_sign := r.c.negative;
v.opsel_a := AIN_C;
v.result_exp := r.c.exponent;
v.result_class := r.c.class;
opsel_a <= AIN_C;
else
else
v.result_sign := r.b.negative;
v.opsel_a := AIN_B;
v.result_exp := r.b.exponent;
v.result_class := r.b.class;
opsel_a <= AIN_B;
end if;
end if;
v.quieten_nan := '0';
v.quieten_nan := '0';
arith_done := '1';
v.state := EXC_RESULT;
when DO_FSQRT =>
when DO_FSQRT =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.b.class = NAN and r.b.mantissa(53) = '0' then
v.use_b := '1';
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
case r.b.class is
case r.b.class is
when FINITE =>
when FINITE =>
v.result_exp := r.b.exponent;
v.result_exp := r.b.exponent;
if r.b.negative = '1' then
if r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1';
v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1';
qnan_result := '1';
arith_done := '1';
elsif r.b.mantissa(54) = '0' then
elsif r.b.mantissa(54) = '0' then
v.state := RENORM_B;
v.state := RENORM_B;
elsif r.b.exponent(0) = '0' then
elsif r.b.exponent(0) = '0' then
@ -1356,7 +1351,9 @@ begin
v.shift := to_signed(1, EXP_BITS);
v.shift := to_signed(1, EXP_BITS);
v.state := RENORM_B2;
v.state := RENORM_B2;
end if;
end if;
when NAN | ZERO =>
when NAN =>
v.state := NAN_RESULT;
when ZERO =>
-- result is B
-- result is B
arith_done := '1';
arith_done := '1';
when INFINITY =>
when INFINITY =>
@ -1369,15 +1366,12 @@ begin
end case;
end case;
when DO_FRE =>
when DO_FRE =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.b.class = NAN and r.b.mantissa(53) = '0' then
v.use_b := '1';
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
case r.b.class is
case r.b.class is
when FINITE =>
when FINITE =>
v.result_exp := - r.b.exponent;
v.result_exp := - r.b.exponent;
@ -1387,8 +1381,7 @@ begin
v.state := FRE_1;
v.state := FRE_1;
end if;
end if;
when NAN =>
when NAN =>
-- result is B
v.state := NAN_RESULT;
arith_done := '1';
when INFINITY =>
when INFINITY =>
v.result_class := ZERO;
v.result_class := ZERO;
arith_done := '1';
arith_done := '1';
@ -1399,15 +1392,12 @@ begin
end case;
end case;
when DO_FRSQRTE =>
when DO_FRSQRTE =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
v.result_class := r.b.class;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_sign := r.b.negative;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.b.class = NAN and r.b.mantissa(53) = '0' then
v.use_b := '1';
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
v.shift := to_signed(1, EXP_BITS);
v.shift := to_signed(1, EXP_BITS);
case r.b.class is
case r.b.class is
when FINITE =>
when FINITE =>
@ -1415,7 +1405,6 @@ begin
if r.b.negative = '1' then
if r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1';
v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1';
qnan_result := '1';
arith_done := '1';
elsif r.b.mantissa(54) = '0' then
elsif r.b.mantissa(54) = '0' then
v.state := RENORM_B;
v.state := RENORM_B;
elsif r.b.exponent(0) = '0' then
elsif r.b.exponent(0) = '0' then
@ -1424,8 +1413,7 @@ begin
v.state := RENORM_B2;
v.state := RENORM_B2;
end if;
end if;
when NAN =>
when NAN =>
-- result is B
v.state := NAN_RESULT;
arith_done := '1';
when INFINITY =>
when INFINITY =>
if r.b.negative = '1' then
if r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1';
v.fpscr(FPSCR_VXSQRT) := '1';
@ -1442,25 +1430,26 @@ begin
when DO_FMADD =>
when DO_FMADD =>
-- fmadd, fmsub, fnmadd, fnmsub
-- fmadd, fmsub, fnmadd, fnmsub
opsel_a <= AIN_A;
-- r.opsel_a = AIN_A if A is denorm, else AIN_C if C is denorm,
-- else AIN_B
v.result_sign := r.a.negative;
v.result_sign := r.a.negative;
v.result_class := r.a.class;
v.result_class := r.a.class;
v.result_exp := r.a.exponent;
v.result_exp := r.a.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
v.use_a := '1';
v.use_b := '1';
v.use_c := '1';
is_add := r.a.negative xor r.c.negative xor r.b.negative xor r.insn(1);
is_add := r.a.negative xor r.c.negative xor r.b.negative xor r.insn(1);
if r.a.class = FINITE and r.c.class = FINITE and
if r.a.class = FINITE and r.c.class = FINITE and
(r.b.class = FINITE or r.b.class = ZERO) then
(r.b.class = FINITE or r.b.class = ZERO) then
v.is_subtract := not is_add;
v.is_subtract := not is_add;
mulexp := r.a.exponent + r.c.exponent;
mulexp := r.a.exponent + r.c.exponent;
v.result_exp := mulexp;
v.result_exp := mulexp;
opsel_a <= AIN_B;
-- Make sure A and C are normalized
-- Make sure A and C are normalized
if r.a.mantissa(54) = '0' then
if r.a.mantissa(54) = '0' then
opsel_a <= AIN_A;
v.state := RENORM_A;
v.state := RENORM_A;
elsif r.c.mantissa(54) = '0' then
elsif r.c.mantissa(54) = '0' then
opsel_a <= AIN_C;
v.state := RENORM_C;
v.state := RENORM_C;
elsif r.b.class = ZERO then
elsif r.b.class = ZERO then
-- no addend, degenerates to multiply
-- no addend, degenerates to multiply
@ -1483,25 +1472,8 @@ begin
v.state := FMADD_2;
v.state := FMADD_2;
end if;
end if;
else
else
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
if r.a.class = NAN or r.b.class = NAN or r.c.class = NAN then
(r.b.class = NAN and r.b.mantissa(53) = '0') or
v.state := NAN_RESULT;
(r.c.class = NAN and r.c.mantissa(53) = '0') then
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.a.class = NAN then
-- nothing to do, result is A
elsif r.b.class = NAN then
-- result is B
v.result_class := NAN;
v.result_sign := r.b.negative;
opsel_a <= AIN_B;
elsif r.c.class = NAN then
-- result is C
v.result_class := NAN;
v.result_sign := r.c.negative;
opsel_a <= AIN_C;
elsif (r.a.class = ZERO and r.c.class = INFINITY) or
elsif (r.a.class = ZERO and r.c.class = INFINITY) or
(r.a.class = INFINITY and r.c.class = ZERO) then
(r.a.class = INFINITY and r.c.class = ZERO) then
-- invalid operation, construct QNaN
-- invalid operation, construct QNaN
@ -1516,32 +1488,36 @@ begin
-- result is infinity
-- result is infinity
v.result_class := INFINITY;
v.result_class := INFINITY;
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
arith_done := '1';
end if;
end if;
else
else
-- Here A is zero, C is zero, or B is infinity
-- Here A is zero, C is zero, or B is infinity
-- Result is +/-B in all of those cases
-- Result is +/-B in all of those cases
v.result_class := r.b.class;
v.opsel_a := AIN_B;
v.result_exp := r.b.exponent;
if r.b.class /= ZERO or is_add = '1' then
if v.result_class /= ZERO or is_add = '1' then
v.negate := not (r.insn(1) xor r.insn(2));
v.result_sign := not (r.b.negative xor r.insn(1) xor r.insn(2));
else
else
-- have to be careful about rule for 0 - 0 result sign
-- have to be careful about rule for 0 - 0 result sign
v.result_sign := (r.round_mode(1) and r.round_mode(0)) xor r.insn(2);
v.negate := r.b.negative xor (r.round_mode(1) and r.round_mode(0)) xor r.insn(2);
end if;
end if;
opsel_a <= AIN_B;
v.state := EXC_RESULT;
end if;
end if;
arith_done := '1';
end if;
end if;
when RENORM_A =>
when RENORM_A =>
renormalize := '1';
renormalize := '1';
v.state := RENORM_A2;
v.state := RENORM_A2;
if r.insn(4) = '1' then
v.opsel_a := AIN_C;
else
v.opsel_a := AIN_B;
end if;
when RENORM_A2 =>
when RENORM_A2 =>
-- r.opsel_a = AIN_C for fmul/fmadd, AIN_B for fdiv
set_a := '1';
set_a := '1';
v.result_exp := new_exp;
v.result_exp := new_exp;
if r.insn(4) = '1' then
if r.insn(4) = '1' then
opsel_a <= AIN_C;
if r.c.mantissa(54) = '1' then
if r.c.mantissa(54) = '1' then
if r.insn(3) = '0' or r.b.class = ZERO then
if r.insn(3) = '0' or r.b.class = ZERO then
v.first := '1';
v.first := '1';
@ -1551,13 +1527,13 @@ begin
if new_exp + 1 >= r.b.exponent then
if new_exp + 1 >= r.b.exponent then
v.madd_cmp := '1';
v.madd_cmp := '1';
end if;
end if;
v.opsel_a := AIN_B;
v.state := DO_FMADD;
v.state := DO_FMADD;
end if;
end if;
else
else
v.state := RENORM_C;
v.state := RENORM_C;
end if;
end if;
else
else
opsel_a <= AIN_B;
if r.b.mantissa(54) = '1' then
if r.b.mantissa(54) = '1' then
v.first := '1';
v.first := '1';
v.state := DIV_2;
v.state := DIV_2;
@ -1578,6 +1554,7 @@ begin
else
else
v.result_exp := new_exp;
v.result_exp := new_exp;
end if;
end if;
v.opsel_a := AIN_B;
v.state := LOOKUP;
v.state := LOOKUP;
when RENORM_C =>
when RENORM_C =>
@ -1595,23 +1572,31 @@ begin
if new_exp + 1 >= r.b.exponent then
if new_exp + 1 >= r.b.exponent then
v.madd_cmp := '1';
v.madd_cmp := '1';
end if;
end if;
v.opsel_a := AIN_B;
v.state := DO_FMADD;
v.state := DO_FMADD;
end if;
end if;
when ADD_1 =>
-- transferring B to R
v.shift := r.b.exponent - r.a.exponent;
v.result_exp := r.b.exponent;
v.state := ADD_SHIFT;
when ADD_SHIFT =>
when ADD_SHIFT =>
-- r.shift = - exponent difference
-- r.shift = - exponent difference
opsel_r <= RES_SHIFT;
opsel_r <= RES_SHIFT;
v.x := s_nz;
v.x := s_nz;
set_x := '1';
set_x := '1';
longmask := '0';
longmask := '0';
v.state := ADD_2;
when ADD_2 =>
if r.add_bsmall = '1' then
if r.add_bsmall = '1' then
opsel_a <= AIN_A;
v.opsel_a := AIN_A;
else
else
opsel_a <= AIN_B;
v.opsel_a := AIN_B;
end if;
end if;
v.state := ADD_2;
when ADD_2 =>
-- r.opsel_a = AIN_A if r.add_bsmall = 1 else AIN_B
opsel_b <= BIN_R;
opsel_b <= BIN_R;
opsel_binv <= r.is_subtract;
opsel_binv <= r.is_subtract;
carry_in <= r.is_subtract and not r.x;
carry_in <= r.is_subtract and not r.x;
@ -1655,7 +1640,7 @@ begin
end if;
end if;
when CMP_1 =>
when CMP_1 =>
opsel_a <= AIN_A;
-- r.opsel_a = AIN_A
opsel_b <= BIN_R;
opsel_b <= BIN_R;
opsel_binv <= '1';
opsel_binv <= '1';
carry_in <= '1';
carry_in <= '1';
@ -1696,7 +1681,7 @@ begin
when FMADD_2 =>
when FMADD_2 =>
-- Product is potentially bigger here
-- Product is potentially bigger here
-- r.shift = addend exp - product exp + 64
-- r.shift = addend exp - product exp + 64, r.r = r.b.mantissa
set_s := '1';
set_s := '1';
opsel_s <= S_SHIFT;
opsel_s <= S_SHIFT;
v.shift := r.shift - to_signed(64, EXP_BITS);
v.shift := r.shift - to_signed(64, EXP_BITS);
@ -1757,7 +1742,7 @@ begin
end if;
end if;
when LOOKUP =>
when LOOKUP =>
opsel_a <= AIN_B;
-- r.opsel_a = AIN_B
-- wait one cycle for inverse_table[B] lookup
-- wait one cycle for inverse_table[B] lookup
v.first := '1';
v.first := '1';
if r.insn(4) = '0' then
if r.insn(4) = '0' then
@ -2260,6 +2245,41 @@ begin
opsel_r <= RES_SHIFT;
opsel_r <= RES_SHIFT;
arith_done := '1';
arith_done := '1';
when NAN_RESULT =>
if (r.use_a = '1' and r.a.class = NAN and r.a.mantissa(53) = '0') or
(r.use_b = '1' and r.b.class = NAN and r.b.mantissa(53) = '0') or
(r.use_c = '1' and r.c.class = NAN and r.c.mantissa(53) = '0') then
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.use_a = '1' and r.a.class = NAN then
v.opsel_a := AIN_A;
elsif r.use_b = '1' and r.b.class = NAN then
v.opsel_a := AIN_B;
elsif r.use_c = '1' and r.c.class = NAN then
v.opsel_a := AIN_C;
end if;
v.state := EXC_RESULT;
when EXC_RESULT =>
-- r.opsel_a = AIN_A, AIN_B or AIN_C according to which input is the result
case r.opsel_a is
when AIN_B =>
v.result_sign := r.b.negative xor r.negate;
v.result_exp := r.b.exponent;
v.result_class := r.b.class;
when AIN_C =>
v.result_sign := r.c.negative xor r.negate;
v.result_exp := r.c.exponent;
v.result_class := r.c.class;
when others =>
v.result_sign := r.a.negative xor r.negate;
v.result_exp := r.a.exponent;
v.result_class := r.a.class;
end case;
arith_done := '1';
end case;
end case;
if zero_divide = '1' then
if zero_divide = '1' then
@ -2271,11 +2291,15 @@ begin
v.result_sign := '0';
v.result_sign := '0';
misc_sel <= "0001";
misc_sel <= "0001";
opsel_r <= RES_MISC;
opsel_r <= RES_MISC;
arith_done := '1';
end if;
if invalid = '1' then
v.invalid := '1';
end if;
end if;
if arith_done = '1' then
if arith_done = '1' then
-- Enabled invalid exception doesn't write result or FPRF
-- Enabled invalid exception doesn't write result or FPRF
-- Neither does enabled zero-divide exception
-- Neither does enabled zero-divide exception
if (invalid and r.fpscr(FPSCR_VE)) = '0' and
if (v.invalid and r.fpscr(FPSCR_VE)) = '0' and
(zero_divide and r.fpscr(FPSCR_ZE)) = '0' then
(zero_divide and r.fpscr(FPSCR_ZE)) = '0' then
v.writing_back := '1';
v.writing_back := '1';
v.update_fprf := '1';
v.update_fprf := '1';
@ -2355,7 +2379,7 @@ begin
else
else
mask := right_mask(unsigned(mshift(5 downto 0)));
mask := right_mask(unsigned(mshift(5 downto 0)));
end if;
end if;
case opsel_a is
case r.opsel_a is
when AIN_R =>
when AIN_R =>
in_a0 := r.r;
in_a0 := r.r;
when AIN_A =>
when AIN_A =>