diff --git a/decode1.vhdl b/decode1.vhdl index 09aaf91..ba9964e 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -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 diff --git a/fpu.vhdl b/fpu.vhdl index 59e6f5d..c726be3 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -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;