FPU: Implement the frsp instruction

This brings in the invalid exception for the case of frsp with a
signalling NaN as input, and the need to be able to convert a
signalling NaN to a quiet NaN.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/245/head
Paul Mackerras 4 years ago
parent 9e8fb293ed
commit 34b5d4a7b5

@ -441,6 +441,7 @@ architecture behaviour of decode1 is
2#100000010# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 2/8=fmr 2#100000010# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 2/8=fmr
2#100000100# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 4/8=fnabs 2#100000100# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 4/8=fnabs
2#100001000# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 8/8=fabs 2#100001000# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 8/8=fabs
2#110000000# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- 0/12=frsp
2#111011010# => (FPU, OP_FPOP_I, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 26/14=fcfid 2#111011010# => (FPU, OP_FPOP_I, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 26/14=fcfid
2#111011110# => (FPU, OP_FPOP_I, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 30/14=fcfidu 2#111011110# => (FPU, OP_FPOP_I, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 30/14=fcfidu
others => illegal_inst others => illegal_inst

@ -39,6 +39,7 @@ architecture behaviour of fpu is
DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF, DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF,
DO_FMR, DO_FMR,
DO_FCFID, DO_FCFID,
DO_FRSP,
FINISH, NORMALIZE, FINISH, NORMALIZE,
ROUND_UFLOW, ROUND_OFLOW, ROUND_UFLOW, ROUND_OFLOW,
ROUNDING, ROUNDING_2, ROUNDING_3, ROUNDING, ROUNDING_2, ROUNDING_3,
@ -71,6 +72,7 @@ architecture behaviour of fpu is
cr_mask : std_ulogic_vector(7 downto 0); cr_mask : std_ulogic_vector(7 downto 0);
old_exc : std_ulogic_vector(4 downto 0); old_exc : std_ulogic_vector(4 downto 0);
update_fprf : std_ulogic; update_fprf : std_ulogic;
quieten_nan : std_ulogic;
tiny : std_ulogic; tiny : std_ulogic;
denorm : std_ulogic; denorm : std_ulogic;
round_mode : std_ulogic_vector(2 downto 0); round_mode : std_ulogic_vector(2 downto 0);
@ -217,7 +219,7 @@ architecture behaviour of fpu is


-- Construct a DP floating-point result from components -- Construct a DP floating-point result from components
function pack_dp(sign: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS-1 downto 0); function pack_dp(sign: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS-1 downto 0);
mantissa: std_ulogic_vector; single_prec: std_ulogic) mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic)
return std_ulogic_vector is return std_ulogic_vector is
variable result : std_ulogic_vector(63 downto 0); variable result : std_ulogic_vector(63 downto 0);
begin begin
@ -238,7 +240,8 @@ architecture behaviour of fpu is
result(62 downto 52) := "11111111111"; result(62 downto 52) := "11111111111";
when NAN => when NAN =>
result(62 downto 52) := "11111111111"; result(62 downto 52) := "11111111111";
result(51 downto 29) := mantissa(53 downto 31); result(51) := quieten_nan or mantissa(53);
result(50 downto 29) := mantissa(52 downto 31);
if single_prec = '0' then if single_prec = '0' then
result(28 downto 0) := mantissa(30 downto 2); result(28 downto 0) := mantissa(30 downto 2);
end if; end if;
@ -348,6 +351,7 @@ begin
variable round : std_ulogic_vector(1 downto 0); variable round : std_ulogic_vector(1 downto 0);
variable update_fx : std_ulogic; variable update_fx : std_ulogic;
variable arith_done : std_ulogic; variable arith_done : std_ulogic;
variable invalid : std_ulogic;
variable mant_nz : std_ulogic; variable mant_nz : std_ulogic;
variable min_exp : signed(EXP_BITS-1 downto 0); variable min_exp : signed(EXP_BITS-1 downto 0);
variable max_exp : signed(EXP_BITS-1 downto 0); variable max_exp : signed(EXP_BITS-1 downto 0);
@ -384,6 +388,7 @@ begin
if e_in.op = OP_FPOP_I then if e_in.op = OP_FPOP_I then
int_input := '1'; int_input := '1';
end if; end if;
v.quieten_nan := '1';
v.tiny := '0'; v.tiny := '0';
v.denorm := '0'; v.denorm := '0';
v.round_mode := '0' & r.fpscr(FPSCR_RN+1 downto FPSCR_RN); v.round_mode := '0' & r.fpscr(FPSCR_RN+1 downto FPSCR_RN);
@ -429,6 +434,7 @@ begin
fpscr_mask := (others => '1'); fpscr_mask := (others => '1');
update_fx := '0'; update_fx := '0';
arith_done := '0'; arith_done := '0';
invalid := '0';
renormalize := '0'; renormalize := '0';
set_x := '0'; set_x := '0';


@ -452,6 +458,8 @@ begin
end if; end if;
when "01000" => when "01000" =>
v.state := DO_FMR; v.state := DO_FMR;
when "01100" =>
v.state := DO_FRSP;
when "01110" => when "01110" =>
-- fcfid[u][s] -- fcfid[u][s]
v.state := DO_FCFID; v.state := DO_FCFID;
@ -552,6 +560,7 @@ begin
opsel_a <= AIN_B; 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';
if r.insn(9) = '1' then if r.insn(9) = '1' then
v.result_sign := '0'; -- fabs v.result_sign := '0'; -- fabs
elsif r.insn(8) = '1' then elsif r.insn(8) = '1' then
@ -567,6 +576,33 @@ begin
v.instr_done := '1'; v.instr_done := '1';
v.state := IDLE; v.state := IDLE;


when DO_FRSP =>
opsel_a <= AIN_B;
v.result_class := r.b.class;
v.result_sign := r.b.negative;
v.result_exp := r.b.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.b.class = NAN and r.b.mantissa(53) = '0' then
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
set_x := '1';
if r.b.class = FINITE then
if r.b.exponent < to_signed(-126, EXP_BITS) then
v.shift := r.b.exponent - to_signed(-126, EXP_BITS);
v.state := ROUND_UFLOW;
elsif r.b.exponent > to_signed(127, EXP_BITS) then
v.state := ROUND_OFLOW;
else
v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
else
arith_done := '1';
end if;

when DO_FCFID => when DO_FCFID =>
v.result_sign := '0'; v.result_sign := '0';
opsel_a <= AIN_B; opsel_a <= AIN_B;
@ -735,8 +771,11 @@ begin
end case; end case;


if arith_done = '1' then if arith_done = '1' then
v.writing_back := '1'; -- Enabled invalid exception doesn't write result or FPRF
v.update_fprf := '1'; if (invalid and r.fpscr(FPSCR_VE)) = '0' then
v.writing_back := '1';
v.update_fprf := '1';
end if;
v.instr_done := '1'; v.instr_done := '1';
v.state := IDLE; v.state := IDLE;
update_fx := '1'; update_fx := '1';
@ -827,7 +866,7 @@ begin
fp_result <= r.r; fp_result <= r.r;
else else
fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r, fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r,
r.single_prec); r.single_prec, r.quieten_nan);
end if; end if;
if r.update_fprf = '1' then if r.update_fprf = '1' then
v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.result_sign, r.result_class, v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.result_sign, r.result_class,

Loading…
Cancel
Save