type op_19_subop_array_t is array(0 to 7) of decode_rom_t;
type op_30_subop_array_t is array(0 to 15) of decode_rom_t;
type op_31_subop_array_t is array(0 to 1023) of decode_rom_t;
+ type op_59_subop_array_t is array(0 to 31) of decode_rom_t;
type minor_rom_array_2_t is array(0 to 3) of decode_rom_t;
type op_63_subop_array_0_t is array(0 to 511) of decode_rom_t;
others => decode_rom_init
);
+ constant decode_op_59_array : op_59_subop_array_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#01110# => (FPU, OP_FPOP_I, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fcfid[u]s
+ others => illegal_inst
+ );
+
constant decode_op_62_array : minor_rom_array_2_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#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#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#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
others => illegal_inst
);
when 58 =>
v.decode := decode_op_58_array(to_integer(unsigned(f_in.insn(1 downto 0))));
+ when 59 =>
+ if HAS_FPU then
+ -- floating point operations, mostly single-precision
+ v.decode := decode_op_59_array(to_integer(unsigned(f_in.insn(5 downto 1))));
+ if f_in.insn(5) = '0' and not std_match(f_in.insn(10 downto 1), "11-1001110") then
+ vi.override := '1';
+ end if;
+ end if;
+
when 62 =>
v.decode := decode_op_62_array(to_integer(unsigned(f_in.insn(1 downto 0))));
type state_t is (IDLE,
DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF,
- DO_FMR);
+ DO_FMR,
+ DO_FCFID,
+ FINISH, NORMALIZE,
+ ROUND_UFLOW, ROUND_OFLOW,
+ ROUNDING, ROUNDING_2, ROUNDING_3,
+ DENORM);
type reg_type is record
state : state_t;
fpscr : std_ulogic_vector(31 downto 0);
a : fpu_reg_type;
b : fpu_reg_type;
- r : std_ulogic_vector(63 downto 0);
+ r : std_ulogic_vector(63 downto 0); -- 10.54 format
+ x : std_ulogic;
result_sign : std_ulogic;
result_class : fp_number_class;
result_exp : signed(EXP_BITS-1 downto 0);
+ shift : signed(EXP_BITS-1 downto 0);
writing_back : std_ulogic;
int_result : std_ulogic;
cr_result : std_ulogic_vector(3 downto 0);
cr_mask : std_ulogic_vector(7 downto 0);
+ old_exc : std_ulogic_vector(4 downto 0);
+ update_fprf : std_ulogic;
+ tiny : std_ulogic;
+ denorm : std_ulogic;
+ round_mode : std_ulogic_vector(2 downto 0);
end record;
signal r, rin : reg_type;
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_r : std_ulogic_vector(1 downto 0);
+ signal opsel_ainv : std_ulogic;
+ signal opsel_amask : std_ulogic;
+ signal in_a : std_ulogic_vector(63 downto 0);
+ signal in_b : std_ulogic_vector(63 downto 0);
signal result : std_ulogic_vector(63 downto 0);
+ signal carry_in : std_ulogic;
+ signal lost_bits : std_ulogic;
+ signal r_hi_nz : std_ulogic;
+ signal r_lo_nz : std_ulogic;
+ signal misc_sel : std_ulogic_vector(3 downto 0);
+
+ -- opsel values
+ constant AIN_R : std_ulogic_vector(1 downto 0) := "00";
+ constant AIN_A : std_ulogic_vector(1 downto 0) := "01";
+ constant AIN_B : std_ulogic_vector(1 downto 0) := "10";
+
+ constant BIN_ZERO : std_ulogic_vector(1 downto 0) := "00";
+ constant BIN_R : std_ulogic_vector(1 downto 0) := "01";
+ constant BIN_MASK : std_ulogic_vector(1 downto 0) := "10";
+
+ constant RES_SUM : std_ulogic_vector(1 downto 0) := "00";
+ constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01";
+ constant RES_MISC : std_ulogic_vector(1 downto 0) := "11";
+
+ -- Left and right shifter with 120 bit input and 64 bit output.
+ -- Shifts inp left by shift bits and returns the upper 64 bits of
+ -- the result. The shift parameter is interpreted as a signed
+ -- number in the range -64..63, with negative values indicating
+ -- right shifts.
+ function shifter_64(inp: std_ulogic_vector(119 downto 0);
+ shift: std_ulogic_vector(6 downto 0))
+ return std_ulogic_vector is
+ variable s1 : std_ulogic_vector(94 downto 0);
+ variable s2 : std_ulogic_vector(70 downto 0);
+ variable result : std_ulogic_vector(63 downto 0);
+ begin
+ case shift(6 downto 5) is
+ when "00" =>
+ s1 := inp(119 downto 25);
+ when "01" =>
+ s1 := inp(87 downto 0) & "0000000";
+ when "10" =>
+ s1 := x"0000000000000000" & inp(119 downto 89);
+ when others =>
+ s1 := x"00000000" & inp(119 downto 57);
+ end case;
+ case shift(4 downto 3) is
+ when "00" =>
+ s2 := s1(94 downto 24);
+ when "01" =>
+ s2 := s1(86 downto 16);
+ when "10" =>
+ s2 := s1(78 downto 8);
+ when others =>
+ s2 := s1(70 downto 0);
+ end case;
+ case shift(2 downto 0) is
+ when "000" =>
+ result := s2(70 downto 7);
+ when "001" =>
+ result := s2(69 downto 6);
+ when "010" =>
+ result := s2(68 downto 5);
+ when "011" =>
+ result := s2(67 downto 4);
+ when "100" =>
+ result := s2(66 downto 3);
+ when "101" =>
+ result := s2(65 downto 2);
+ when "110" =>
+ result := s2(64 downto 1);
+ when others =>
+ result := s2(63 downto 0);
+ end case;
+ return result;
+ end;
+
+ -- Generate a mask with 0-bits on the left and 1-bits on the right which
+ -- selects the bits will be lost in doing a right shift. The shift
+ -- parameter is the bottom 6 bits of a negative shift count,
+ -- indicating a right shift.
+ function right_mask(shift: unsigned(5 downto 0)) return std_ulogic_vector is
+ variable result: std_ulogic_vector(63 downto 0);
+ begin
+ result := (others => '0');
+ for i in 0 to 63 loop
+ if i >= shift then
+ result(63 - i) := '1';
+ end if;
+ end loop;
+ return result;
+ end;
-- Split a DP floating-point number into components and work out its class.
-- If is_int = 1, the input is considered an integer
-- 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);
- mantissa: std_ulogic_vector) return std_ulogic_vector is
+ mantissa: std_ulogic_vector; single_prec: std_ulogic)
+ return std_ulogic_vector is
variable result : std_ulogic_vector(63 downto 0);
begin
result := (others => '0');
-- normalized number
result(62 downto 52) := std_ulogic_vector(resize(exp, 11) + 1023);
end if;
- result(51 downto 0) := mantissa(53 downto 2);
+ result(51 downto 29) := mantissa(53 downto 31);
+ if single_prec = '0' then
+ result(28 downto 0) := mantissa(30 downto 2);
+ end if;
when INFINITY =>
result(62 downto 52) := "11111111111";
when NAN =>
result(62 downto 52) := "11111111111";
- result(51 downto 0) := mantissa(53 downto 2);
+ result(51 downto 29) := mantissa(53 downto 31);
+ if single_prec = '0' then
+ result(28 downto 0) := mantissa(30 downto 2);
+ end if;
end case;
return result;
end;
+ -- Determine whether to increment when rounding
+ -- Returns rounding_inc & inexact
+ -- Assumes x includes the bottom 29 bits of the mantissa already
+ -- if single_prec = 1 (usually arranged by setting set_x = 1 earlier).
+ function fp_rounding(mantissa: std_ulogic_vector(63 downto 0); x: std_ulogic;
+ single_prec: std_ulogic; rn: std_ulogic_vector(2 downto 0);
+ sign: std_ulogic)
+ return std_ulogic_vector is
+ variable grx : std_ulogic_vector(2 downto 0);
+ variable ret : std_ulogic_vector(1 downto 0);
+ variable lsb : std_ulogic;
+ begin
+ if single_prec = '0' then
+ grx := mantissa(1 downto 0) & x;
+ lsb := mantissa(2);
+ else
+ grx := mantissa(30 downto 29) & x;
+ lsb := mantissa(31);
+ end if;
+ ret(1) := '0';
+ ret(0) := or (grx);
+ case rn(1 downto 0) is
+ when "00" => -- round to nearest
+ if grx = "100" and rn(2) = '0' then
+ ret(1) := lsb; -- tie, round to even
+ else
+ ret(1) := grx(2);
+ end if;
+ when "01" => -- round towards zero
+ when others => -- round towards +/- inf
+ if rn(0) = sign then
+ -- round towards greater magnitude
+ ret(1) := ret(0);
+ end if;
+ end case;
+ return ret;
+ end;
+
+ -- Determine result flags to write into the FPSCR
+ function result_flags(sign: std_ulogic; class: fp_number_class; unitbit: std_ulogic)
+ return std_ulogic_vector is
+ begin
+ case class is
+ when ZERO =>
+ return sign & "0010";
+ when FINITE =>
+ return (not unitbit) & sign & (not sign) & "00";
+ when INFINITY =>
+ return '0' & sign & (not sign) & "01";
+ when NAN =>
+ return "10001";
+ end case;
+ end;
+
begin
fpu_0: process(clk)
begin
variable j, k : integer;
variable flm : std_ulogic_vector(7 downto 0);
variable int_input : std_ulogic;
+ variable mask : std_ulogic_vector(63 downto 0);
+ variable in_a0 : std_ulogic_vector(63 downto 0);
+ variable in_b0 : std_ulogic_vector(63 downto 0);
+ variable misc : std_ulogic_vector(63 downto 0);
+ variable shift_res : std_ulogic_vector(63 downto 0);
+ variable round : std_ulogic_vector(1 downto 0);
+ variable update_fx : std_ulogic;
+ variable arith_done : std_ulogic;
+ variable mant_nz : std_ulogic;
+ variable min_exp : signed(EXP_BITS-1 downto 0);
+ variable max_exp : signed(EXP_BITS-1 downto 0);
+ variable bias_exp : signed(EXP_BITS-1 downto 0);
+ variable new_exp : signed(EXP_BITS-1 downto 0);
+ variable exp_tiny : std_ulogic;
+ variable exp_huge : std_ulogic;
+ variable renormalize : std_ulogic;
+ variable clz : std_ulogic_vector(5 downto 0);
+ variable set_x : std_ulogic;
+ variable mshift : signed(EXP_BITS-1 downto 0);
begin
v := r;
illegal := '0';
if e_in.op = OP_FPOP_I then
int_input := '1';
end if;
+ v.tiny := '0';
+ v.denorm := '0';
+ v.round_mode := '0' & r.fpscr(FPSCR_RN+1 downto FPSCR_RN);
adec := decode_dp(e_in.fra, int_input);
bdec := decode_dp(e_in.frb, int_input);
v.a := adec;
v.b := bdec;
end if;
+ r_hi_nz <= or (r.r(55 downto 31));
+ r_lo_nz <= or (r.r(30 downto 2));
+
+ if r.single_prec = '0' then
+ max_exp := to_signed(1023, EXP_BITS);
+ min_exp := to_signed(-1022, EXP_BITS);
+ bias_exp := to_signed(1536, EXP_BITS);
+ else
+ max_exp := to_signed(127, EXP_BITS);
+ min_exp := to_signed(-126, EXP_BITS);
+ bias_exp := to_signed(192, EXP_BITS);
+ end if;
+ new_exp := r.result_exp - r.shift;
+ exp_tiny := '0';
+ exp_huge := '0';
+ if new_exp < min_exp then
+ exp_tiny := '1';
+ end if;
+ if new_exp > max_exp then
+ exp_huge := '1';
+ end if;
+
v.writing_back := '0';
v.instr_done := '0';
- opsel_r <= "00";
+ v.update_fprf := '0';
+ v.shift := to_signed(0, EXP_BITS);
+ opsel_a <= AIN_R;
+ opsel_ainv <= '0';
+ opsel_amask <= '0';
+ opsel_b <= BIN_ZERO;
+ opsel_r <= RES_SUM;
+ carry_in <= '0';
+ misc_sel <= "0000";
fpscr_mask := (others => '1');
+ update_fx := '0';
+ arith_done := '0';
+ renormalize := '0';
+ set_x := '0';
case r.state is
when IDLE =>
end if;
when "01000" =>
v.state := DO_FMR;
+ when "01110" =>
+ -- fcfid[u][s]
+ v.state := DO_FCFID;
when others =>
illegal := '1';
end case;
end if;
+ v.x := '0';
+ v.old_exc := r.fpscr(FPSCR_VX downto FPSCR_XX);
when DO_MCRFS =>
j := to_integer(unsigned(insn_bfa(r.insn)));
when DO_MFFS =>
v.int_result := '1';
v.writing_back := '1';
- opsel_r <= "10";
+ opsel_r <= RES_MISC;
case r.insn(20 downto 16) is
when "00000" =>
-- mffs
v.state := IDLE;
when DO_FMR =>
+ opsel_a <= AIN_B;
v.result_class := r.b.class;
v.result_exp := r.b.exponent;
if r.insn(9) = '1' then
v.instr_done := '1';
v.state := IDLE;
+ when DO_FCFID =>
+ v.result_sign := '0';
+ opsel_a <= AIN_B;
+ if r.insn(8) = '0' and r.b.negative = '1' then
+ -- fcfid[s] with negative operand, set R = -B
+ opsel_ainv <= '1';
+ carry_in <= '1';
+ v.result_sign := '1';
+ end if;
+ v.result_class := r.b.class;
+ v.result_exp := to_signed(54, EXP_BITS);
+ v.fpscr(FPSCR_FR) := '0';
+ v.fpscr(FPSCR_FI) := '0';
+ if r.b.class = ZERO then
+ arith_done := '1';
+ else
+ v.state := FINISH;
+ end if;
+
+ when FINISH =>
+ if r.r(63 downto 54) /= "0000000001" then
+ renormalize := '1';
+ v.state := NORMALIZE;
+ else
+ set_x := '1';
+ if exp_tiny = '1' then
+ v.shift := new_exp - min_exp;
+ v.state := ROUND_UFLOW;
+ elsif exp_huge = '1' then
+ v.state := ROUND_OFLOW;
+ else
+ v.shift := to_signed(-2, EXP_BITS);
+ v.state := ROUNDING;
+ end if;
+ end if;
+
+ when NORMALIZE =>
+ -- Shift so we have 9 leading zeroes (we know R is non-zero)
+ opsel_r <= RES_SHIFT;
+ set_x := '1';
+ if exp_tiny = '1' then
+ v.shift := new_exp - min_exp;
+ v.state := ROUND_UFLOW;
+ elsif exp_huge = '1' then
+ v.state := ROUND_OFLOW;
+ else
+ v.shift := to_signed(-2, EXP_BITS);
+ v.state := ROUNDING;
+ end if;
+
+ when ROUND_UFLOW =>
+ v.tiny := '1';
+ if r.fpscr(FPSCR_UE) = '0' then
+ -- disabled underflow exception case
+ -- have to denormalize before rounding
+ opsel_r <= RES_SHIFT;
+ set_x := '1';
+ v.shift := to_signed(-2, EXP_BITS);
+ v.state := ROUNDING;
+ else
+ -- enabled underflow exception case
+ -- if denormalized, have to normalize before rounding
+ v.fpscr(FPSCR_UX) := '1';
+ v.result_exp := r.result_exp + bias_exp;
+ if r.r(54) = '0' then
+ renormalize := '1';
+ v.state := NORMALIZE;
+ else
+ v.shift := to_signed(-2, EXP_BITS);
+ v.state := ROUNDING;
+ end if;
+ end if;
+
+ when ROUND_OFLOW =>
+ v.fpscr(FPSCR_OX) := '1';
+ if r.fpscr(FPSCR_OE) = '0' then
+ -- disabled overflow exception
+ -- result depends on rounding mode
+ v.fpscr(FPSCR_XX) := '1';
+ v.fpscr(FPSCR_FI) := '1';
+ if r.round_mode(1 downto 0) = "00" or
+ (r.round_mode(1) = '1' and r.round_mode(0) = r.result_sign) then
+ v.result_class := INFINITY;
+ v.fpscr(FPSCR_FR) := '1';
+ else
+ v.fpscr(FPSCR_FR) := '0';
+ end if;
+ -- construct largest representable number
+ v.result_exp := max_exp;
+ opsel_r <= RES_MISC;
+ misc_sel <= "001" & r.single_prec;
+ arith_done := '1';
+ else
+ -- enabled overflow exception
+ v.result_exp := r.result_exp - bias_exp;
+ v.shift := to_signed(-2, EXP_BITS);
+ v.state := ROUNDING;
+ end if;
+
+ when ROUNDING =>
+ opsel_amask <= '1';
+ round := fp_rounding(r.r, r.x, r.single_prec, r.round_mode, r.result_sign);
+ v.fpscr(FPSCR_FR downto FPSCR_FI) := round;
+ if round(1) = '1' then
+ -- set mask to increment the LSB for the precision
+ opsel_b <= BIN_MASK;
+ carry_in <= '1';
+ v.shift := to_signed(-1, EXP_BITS);
+ v.state := ROUNDING_2;
+ else
+ if r.r(54) = '0' then
+ -- result after masking could be zero, or could be a
+ -- denormalized result that needs to be renormalized
+ renormalize := '1';
+ v.state := ROUNDING_3;
+ else
+ arith_done := '1';
+ end if;
+ end if;
+ if round(0) = '1' then
+ v.fpscr(FPSCR_XX) := '1';
+ if r.tiny = '1' then
+ v.fpscr(FPSCR_UX) := '1';
+ end if;
+ end if;
+
+ when ROUNDING_2 =>
+ -- Check for overflow during rounding
+ v.x := '0';
+ if r.r(55) = '1' then
+ opsel_r <= RES_SHIFT;
+ if exp_huge = '1' then
+ v.state := ROUND_OFLOW;
+ else
+ arith_done := '1';
+ end if;
+ elsif r.r(54) = '0' then
+ -- Do CLZ so we can renormalize the result
+ renormalize := '1';
+ v.state := ROUNDING_3;
+ else
+ arith_done := '1';
+ end if;
+
+ when ROUNDING_3 =>
+ mant_nz := r_hi_nz or (r_lo_nz and not r.single_prec);
+ if mant_nz = '0' then
+ v.result_class := ZERO;
+ arith_done := '1';
+ else
+ -- Renormalize result after rounding
+ opsel_r <= RES_SHIFT;
+ v.denorm := exp_tiny;
+ v.shift := new_exp - to_signed(-1022, EXP_BITS);
+ if new_exp < to_signed(-1022, EXP_BITS) then
+ v.state := DENORM;
+ else
+ arith_done := '1';
+ end if;
+ end if;
+
+ when DENORM =>
+ opsel_r <= RES_SHIFT;
+ arith_done := '1';
+
end case;
+ if arith_done = '1' then
+ v.writing_back := '1';
+ v.update_fprf := '1';
+ v.instr_done := '1';
+ v.state := IDLE;
+ update_fx := '1';
+ end if;
+
-- Data path.
+ -- This has A and B input multiplexers, an adder, a shifter,
+ -- count-leading-zeroes logic, and a result mux.
+ if r.single_prec = '1' then
+ mshift := r.shift + to_signed(-29, EXP_BITS);
+ else
+ mshift := r.shift;
+ end if;
+ if mshift < to_signed(-64, EXP_BITS) then
+ mask := (others => '1');
+ elsif mshift >= to_signed(0, EXP_BITS) then
+ mask := (others => '0');
+ else
+ mask := right_mask(unsigned(mshift(5 downto 0)));
+ end if;
+ case opsel_a is
+ when AIN_R =>
+ in_a0 := r.r;
+ when AIN_A =>
+ in_a0 := r.a.mantissa;
+ when others =>
+ in_a0 := r.b.mantissa;
+ end case;
+ if (or (mask and in_a0)) = '1' and set_x = '1' then
+ v.x := '1';
+ end if;
+ if opsel_ainv = '1' then
+ in_a0 := not in_a0;
+ end if;
+ if opsel_amask = '1' then
+ in_a0 := in_a0 and not mask;
+ end if;
+ in_a <= in_a0;
+ case opsel_b is
+ when BIN_ZERO =>
+ in_b0 := (others => '0');
+ when BIN_R =>
+ in_b0 := r.r;
+ when BIN_MASK =>
+ in_b0 := mask;
+ when others =>
+ in_b0 := (others => '0');
+ end case;
+ in_b <= in_b0;
+ if r.shift >= to_signed(-64, EXP_BITS) and r.shift <= to_signed(63, EXP_BITS) then
+ shift_res := shifter_64(r.r & x"00000000000000",
+ std_ulogic_vector(r.shift(6 downto 0)));
+ else
+ shift_res := (others => '0');
+ end if;
case opsel_r is
- when "00" =>
- result <= r.b.mantissa;
- when "10" =>
- result <= x"00000000" & (r.fpscr and fpscr_mask);
+ when RES_SUM =>
+ result <= std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);
+ when RES_SHIFT =>
+ result <= shift_res;
when others =>
- result <= (others => '0');
+ case misc_sel is
+ when "0000" =>
+ misc := x"00000000" & (r.fpscr and fpscr_mask);
+ when "0010" =>
+ -- mantissa of max representable DP number
+ misc := x"007ffffffffffffc";
+ when "0011" =>
+ -- mantissa of max representable SP number
+ misc := x"007fffff80000000";
+ when others =>
+ misc := x"0000000000000000";
+ end case;
+ result <= misc;
end case;
v.r := result;
+ if opsel_r = RES_SHIFT then
+ v.result_exp := new_exp;
+ end if;
+
+ if renormalize = '1' then
+ clz := count_left_zeroes(r.r);
+ v.shift := resize(signed('0' & clz) - 9, EXP_BITS);
+ end if;
+
if r.int_result = '1' then
fp_result <= r.r;
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);
+ end if;
+ if r.update_fprf = '1' then
+ v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.result_sign, r.result_class,
+ r.r(54) and not r.denorm);
end if;
v.fpscr(FPSCR_VX) := (or (v.fpscr(FPSCR_VXSNAN downto FPSCR_VXVC))) or
(or (v.fpscr(FPSCR_VXSOFT downto FPSCR_VXCVI)));
v.fpscr(FPSCR_FEX) := or (v.fpscr(FPSCR_VX downto FPSCR_XX) and
v.fpscr(FPSCR_VE downto FPSCR_XE));
+ if update_fx = '1' and
+ (v.fpscr(FPSCR_VX downto FPSCR_XX) and not r.old_exc) /= "00000" then
+ v.fpscr(FPSCR_FX) := '1';
+ end if;
if r.rc = '1' then
v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
end if;
putchar(*str);
}
-void print_hex(unsigned long val, int ndigits)
+void print_hex(unsigned long val, int ndigits, const char *str)
{
int i, x;
else
putchar(x + '0');
}
+ print_string(str);
}
// i < 100
asm("lfs 20,0(%0); stfd 20,0(%1)"
: : "b" (&sp_dp_equiv[arg].sp), "b" (&dp) : "memory");
if (dp != sp_dp_equiv[arg].dp) {
- print_hex(sp_dp_equiv[arg].sp, 8);
- print_string(" ");
- print_hex(dp, 16);
- print_string(" ");
- print_hex(sp_dp_equiv[arg].dp, 16);
- print_string(" ");
+ print_hex(sp_dp_equiv[arg].sp, 8, " ");
+ print_hex(dp, 16, " ");
+ print_hex(sp_dp_equiv[arg].dp, 16, " ");
}
return dp != sp_dp_equiv[arg].dp;
}
return 0;
}
+struct int_fp_equiv {
+ long ival;
+ unsigned long fp;
+ unsigned long fp_u;
+ unsigned long fp_s;
+ unsigned long fp_us;
+} intvals[] = {
+ { 0, 0, 0, 0, 0 },
+ { 1, 0x3ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000 },
+ { -1, 0xbff0000000000000, 0x43f0000000000000, 0xbff0000000000000, 0x43f0000000000000 },
+ { 2, 0x4000000000000000, 0x4000000000000000, 0x4000000000000000, 0x4000000000000000 },
+ { -2, 0xc000000000000000, 0x43f0000000000000, 0xc000000000000000, 0x43f0000000000000 },
+ { 0x12345678, 0x41b2345678000000, 0x41b2345678000000, 0x41b2345680000000, 0x41b2345680000000 },
+ { 0x0008000000000000, 0x4320000000000000, 0x4320000000000000, 0x4320000000000000, 0x4320000000000000 },
+ { 0x0010000000000000, 0x4330000000000000, 0x4330000000000000, 0x4330000000000000, 0x4330000000000000 },
+ { 0x0020000000000000, 0x4340000000000000, 0x4340000000000000, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000000000001, 0x4340000000000000, 0x4340000000000000, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000000000002, 0x4340000000000001, 0x4340000000000001, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000000000003, 0x4340000000000002, 0x4340000000000002, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000010000000, 0x4340000008000000, 0x4340000008000000, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000020000000, 0x4340000010000000, 0x4340000010000000, 0x4340000000000000, 0x4340000000000000 },
+ { 0x0020000030000000, 0x4340000018000000, 0x4340000018000000, 0x4340000020000000, 0x4340000020000000 },
+ { 0x0020000040000000, 0x4340000020000000, 0x4340000020000000, 0x4340000020000000, 0x4340000020000000 },
+ { 0x0020000080000000, 0x4340000040000000, 0x4340000040000000, 0x4340000040000000, 0x4340000040000000 },
+ { 0x0040000000000000, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000001, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000002, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000003, 0x4350000000000001, 0x4350000000000001, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000004, 0x4350000000000001, 0x4350000000000001, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000005, 0x4350000000000001, 0x4350000000000001, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000006, 0x4350000000000002, 0x4350000000000002, 0x4350000000000000, 0x4350000000000000 },
+ { 0x0040000000000007, 0x4350000000000002, 0x4350000000000002, 0x4350000000000000, 0x4350000000000000 },
+};
+
+int test7(long arg)
+{
+ long i;
+ unsigned long results[4];
+
+ for (i = 0; i < sizeof(intvals) / sizeof(intvals[0]); ++i) {
+ asm("lfd%U0%X0 3,%0; fcfid 6,3; fcfidu 7,3; stfd 6,0(%1); stfd 7,8(%1)"
+ : : "m" (intvals[i].ival), "b" (results) : "memory");
+ asm("fcfids 9,3; stfd 9,16(%0); fcfidus 10,3; stfd 10,24(%0)"
+ : : "b" (results) : "memory");
+ if (results[0] != intvals[i].fp ||
+ results[1] != intvals[i].fp_u ||
+ results[2] != intvals[i].fp_s ||
+ results[3] != intvals[i].fp_us) {
+ print_string("\r\n");
+ print_hex(results[0], 16, " ");
+ print_hex(results[1], 16, " ");
+ print_hex(results[2], 16, " ");
+ print_hex(results[3], 16, " ");
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
int fpu_test_6(void)
{
enable_fp();
return trapit(0, test6);
}
+int fpu_test_7(void)
+{
+ enable_fp();
+ return trapit(0, test7);
+}
+
int fail = 0;
void do_test(int num, int (*test)(void))
} else {
fail = 1;
print_string("FAIL ");
- print_hex(ret, 5);
- print_string(" SRR0=");
- print_hex(mfspr(SRR0), 16);
- print_string(" SRR1=");
- print_hex(mfspr(SRR1), 16);
- print_string("\r\n");
+ print_hex(ret, 5, " SRR0=");
+ print_hex(mfspr(SRR0), 16, " SRR1=");
+ print_hex(mfspr(SRR1), 16, "\r\n");
}
}
do_test(4, fpu_test_4);
do_test(5, fpu_test_5);
do_test(6, fpu_test_6);
+ do_test(7, fpu_test_7);
return fail;
}