FPU: Implement fcmpu and fcmpo

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/245/head
Paul Mackerras 4 years ago
parent 4cd9301da6
commit 49f3d1e77a

@ -436,6 +436,8 @@ architecture behaviour of decode1 is
constant decode_op_63l_array : op_63_subop_array_0_t := (
-- unit internal in1 in2 in3 out CR CR inv inv cry cry ldst BR sgn upd rsrv 32b sgn rc lk sgl
-- op in out A out in out len ext pipe
2#000000000# => (FPU, OP_FPOP, FRA, FRB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- 0/0=fcmpu
2#000000001# => (FPU, OP_FPOP, FRA, FRB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- 1/0=fcmpo
2#000000010# => (FPU, OP_FPOP, NONE, NONE, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- 2/0=mcrfs
2#011000001# => (FPU, OP_FPOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 1/6=mtfsb1
2#011000010# => (FPU, OP_FPOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- 2/6=mtfsb0

@ -37,7 +37,7 @@ architecture behaviour of fpu is

type state_t is (IDLE,
DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF,
DO_FMR, DO_FMRG,
DO_FMR, DO_FMRG, DO_FCMP,
DO_FCFID, DO_FCTI,
DO_FRSP, DO_FRI,
DO_FADD, DO_FMUL, DO_FDIV,
@ -45,6 +45,7 @@ architecture behaviour of fpu is
DO_FSEL,
FRI_1,
ADD_SHIFT, ADD_2, ADD_3,
CMP_1, CMP_2,
MULT_1,
LOOKUP,
DIV_2, DIV_3, DIV_4, DIV_5, DIV_6,
@ -603,7 +604,11 @@ begin
if e_in.valid = '1' then
case e_in.insn(5 downto 1) is
when "00000" =>
v.state := DO_MCRFS;
if e_in.insn(7) = '1' then
v.state := DO_MCRFS;
else
v.state := DO_FCMP;
end if;
when "00110" =>
if e_in.insn(10) = '0' then
if e_in.insn(8) = '0' then
@ -669,6 +674,62 @@ begin
v.instr_done := '1';
v.state := IDLE;

when DO_FCMP =>
-- fcmp[uo]
v.instr_done := '1';
v.state := IDLE;
update_fx := '1';
opsel_a <= AIN_B;
opsel_r <= RES_SUM;
v.result_exp := r.b.exponent;
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
(r.b.class = NAN and r.b.mantissa(53) = '0') then
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
if r.insn(6) = '1' and r.fpscr(FPSCR_VE) = '0' then
v.fpscr(FPSCR_VXVC) := '1';
end if;
invalid := '1';
v.cr_result := "0001"; -- unordered
elsif r.a.class = NAN or r.b.class = NAN then
if r.insn(6) = '1' then
-- fcmpo
v.fpscr(FPSCR_VXVC) := '1';
invalid := '1';
end if;
v.cr_result := "0001"; -- unordered
elsif r.a.class = ZERO and r.b.class = ZERO then
v.cr_result := "0010"; -- equal
elsif r.a.negative /= r.b.negative then
v.cr_result := r.a.negative & r.b.negative & "00";
elsif r.a.class = ZERO then
-- A and B are the same sign from here down
v.cr_result := not r.b.negative & r.b.negative & "00";
elsif r.a.class = INFINITY then
if r.b.class = INFINITY then
v.cr_result := "0010";
else
v.cr_result := r.a.negative & not r.a.negative & "00";
end if;
elsif r.b.class = ZERO then
-- A is finite from here down
v.cr_result := r.a.negative & not r.a.negative & "00";
elsif r.b.class = INFINITY then
v.cr_result := not r.b.negative & r.b.negative & "00";
elsif r.exp_cmp = '1' then
-- A and B are both finite from here down
v.cr_result := r.a.negative & not r.a.negative & "00";
elsif r.a.exponent /= r.b.exponent then
-- A exponent is smaller than B
v.cr_result := not r.a.negative & r.a.negative & "00";
else
-- Prepare to subtract mantissas, put B in R
v.cr_result := "0000";
v.instr_done := '0';
v.state := CMP_1;
end if;
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;

when DO_MTFSB =>
-- mtfsb{0,1}
j := to_integer(unsigned(insn_bt(r.insn)));
@ -1193,6 +1254,26 @@ begin
v.state := NORMALIZE;
end if;

when CMP_1 =>
opsel_a <= AIN_A;
opsel_b <= BIN_R;
opsel_binv <= '1';
carry_in <= '1';
v.state := CMP_2;

when CMP_2 =>
if r.r(63) = '1' then
-- A is smaller in magnitude
v.cr_result := not r.a.negative & r.a.negative & "00";
elsif (r_hi_nz or r_lo_nz) = '0' then
v.cr_result := "0010";
else
v.cr_result := r.a.negative & not r.a.negative & "00";
end if;
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
v.instr_done := '1';
v.state := IDLE;

when MULT_1 =>
f_to_multiply.valid <= r.first;
opsel_r <= RES_MULT;

Loading…
Cancel
Save