📄 cp1.c
字号:
fp_madd(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, unsigned64 op3, FP_formats fmt){ return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 0, fmt);}unsigned64fp_msub(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, unsigned64 op3, FP_formats fmt){ return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 0, fmt);}unsigned64fp_nmadd(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, unsigned64 op3, FP_formats fmt){ return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 1, fmt);}unsigned64fp_nmsub(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, unsigned64 op3, FP_formats fmt){ return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 1, fmt);}/* MIPS-3D ASE operations. *//* Variant of fp_binary for *r.ps MIPS-3D operations. */static unsigned64fp_binary_r(sim_cpu *cpu, address_word cia, int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *), unsigned64 op1, unsigned64 op2) { sim_fpu wop1; sim_fpu wop2; sim_fpu ans; sim_fpu_round round = rounding_mode (GETRM ()); sim_fpu_denorm denorm = denorm_mode (cpu); sim_fpu_status status_u, status_l; unsigned64 result; unsigned32 res_u, res_l; /* The format must be fmt_ps. */ status_u = 0; sim_fpu_32to (&wop1, FP_PS_upper (op1)); sim_fpu_32to (&wop2, FP_PS_lower (op1)); status_u |= (*sim_fpu_op) (&ans, &wop1, &wop2); status_u |= sim_fpu_round_32 (&ans, round, denorm); sim_fpu_to32 (&res_u, &ans); status_l = 0; sim_fpu_32to (&wop1, FP_PS_upper (op2)); sim_fpu_32to (&wop2, FP_PS_lower (op2)); status_l |= (*sim_fpu_op) (&ans, &wop1, &wop2); status_l |= sim_fpu_round_32 (&ans, round, denorm); sim_fpu_to32 (&res_l, &ans); result = FP_PS_cat (res_u, res_l); update_fcsr (cpu, cia, status_u | status_l); return result;}unsigned64fp_add_r(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, FP_formats fmt){ return fp_binary_r (cpu, cia, &sim_fpu_add, op1, op2);}unsigned64fp_mul_r(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, FP_formats fmt){ return fp_binary_r (cpu, cia, &sim_fpu_mul, op1, op2);}#define NR_FRAC_GUARD (60)#define IMPLICIT_1 LSBIT64 (NR_FRAC_GUARD)static intfpu_inv1(sim_fpu *f, const sim_fpu *l){ static const sim_fpu sim_fpu_one = { sim_fpu_class_number, 0, IMPLICIT_1, 0 }; int status = 0; sim_fpu t; if (sim_fpu_is_zero (l)) { *f = sim_fpu_maxfp; f->sign = l->sign; return sim_fpu_status_invalid_div0; } if (sim_fpu_is_infinity (l)) { *f = sim_fpu_zero; f->sign = l->sign; return status; } status |= sim_fpu_div (f, &sim_fpu_one, l); return status;}static intfpu_inv1_32(sim_fpu *f, const sim_fpu *l){ if (sim_fpu_is_zero (l)) { *f = sim_fpu_max32; f->sign = l->sign; return sim_fpu_status_invalid_div0; } return fpu_inv1 (f, l);}static intfpu_inv1_64(sim_fpu *f, const sim_fpu *l){ if (sim_fpu_is_zero (l)) { *f = sim_fpu_max64; f->sign = l->sign; return sim_fpu_status_invalid_div0; } return fpu_inv1 (f, l);}unsigned64fp_recip1(sim_cpu *cpu, address_word cia, unsigned64 op, FP_formats fmt){ switch (fmt) { case fmt_single: case fmt_ps: return fp_unary (cpu, cia, &fpu_inv1_32, op, fmt); case fmt_double: return fp_unary (cpu, cia, &fpu_inv1_64, op, fmt); } return 0;}unsigned64fp_recip2(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, FP_formats fmt){ static const unsigned64 one_single = UNSIGNED64 (0x3F800000); static const unsigned64 one_double = UNSIGNED64 (0x3FF0000000000000); static const unsigned64 one_ps = (UNSIGNED64 (0x3F800000) << 32 | UNSIGNED64 (0x3F800000)); unsigned64 one; /* Implemented as nmsub fd, 1, fs, ft. */ switch (fmt) { case fmt_single: one = one_single; break; case fmt_double: one = one_double; break; case fmt_ps: one = one_ps; break; default: one = 0; abort (); } return fp_mac (cpu, cia, &sim_fpu_sub, op1, op2, one, 0, 1, fmt);}static intfpu_inv_sqrt1(sim_fpu *f, const sim_fpu *l){ static const sim_fpu sim_fpu_one = { sim_fpu_class_number, 0, IMPLICIT_1, 0 }; int status = 0; sim_fpu t; if (sim_fpu_is_zero (l)) { *f = sim_fpu_maxfp; f->sign = l->sign; return sim_fpu_status_invalid_div0; } if (sim_fpu_is_infinity (l)) { if (!l->sign) { f->class = sim_fpu_class_zero; f->sign = 0; } else { *f = sim_fpu_qnan; status = sim_fpu_status_invalid_sqrt; } return status; } status |= sim_fpu_sqrt (&t, l); status |= sim_fpu_div (f, &sim_fpu_one, &t); return status;}static intfpu_inv_sqrt1_32(sim_fpu *f, const sim_fpu *l){ if (sim_fpu_is_zero (l)) { *f = sim_fpu_max32; f->sign = l->sign; return sim_fpu_status_invalid_div0; } return fpu_inv_sqrt1 (f, l);}static intfpu_inv_sqrt1_64(sim_fpu *f, const sim_fpu *l){ if (sim_fpu_is_zero (l)) { *f = sim_fpu_max64; f->sign = l->sign; return sim_fpu_status_invalid_div0; } return fpu_inv_sqrt1 (f, l);}unsigned64fp_rsqrt1(sim_cpu *cpu, address_word cia, unsigned64 op, FP_formats fmt){ switch (fmt) { case fmt_single: case fmt_ps: return fp_unary (cpu, cia, &fpu_inv_sqrt1_32, op, fmt); case fmt_double: return fp_unary (cpu, cia, &fpu_inv_sqrt1_64, op, fmt); } return 0;}unsigned64fp_rsqrt2(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, FP_formats fmt){ static const unsigned64 half_single = UNSIGNED64 (0x3F000000); static const unsigned64 half_double = UNSIGNED64 (0x3FE0000000000000); static const unsigned64 half_ps = (UNSIGNED64 (0x3F000000) << 32 | UNSIGNED64 (0x3F000000)); unsigned64 half; /* Implemented as (nmsub fd, 0.5, fs, ft)/2, where the divide is done by scaling the exponent during multiply. */ switch (fmt) { case fmt_single: half = half_single; break; case fmt_double: half = half_double; break; case fmt_ps: half = half_ps; break; default: half = 0; abort (); } return fp_mac (cpu, cia, &sim_fpu_sub, op1, op2, half, -1, 1, fmt);}/* Conversion operations. */uword64convert (sim_cpu *cpu, address_word cia, int rm, uword64 op, FP_formats from, FP_formats to){ sim_fpu wop; sim_fpu_round round = rounding_mode (rm); sim_fpu_denorm denorm = denorm_mode (cpu); unsigned32 result32; unsigned64 result64; sim_fpu_status status = 0; /* Convert the input to sim_fpu internal format */ switch (from) { case fmt_double: sim_fpu_64to (&wop, op); break; case fmt_single: sim_fpu_32to (&wop, op); break; case fmt_word: status = sim_fpu_i32to (&wop, op, round); break; case fmt_long: status = sim_fpu_i64to (&wop, op, round); break; default: sim_io_eprintf (SD, "Bad switch\n"); abort (); } /* Convert sim_fpu format into the output */ /* The value WOP is converted to the destination format, rounding using mode RM. When the destination is a fixed-point format, then a source value of Infinity, NaN or one which would round to an integer outside the fixed point range then an IEEE Invalid Operation condition is raised. Not used if destination format is PS. */ switch (to) { case fmt_single: status |= sim_fpu_round_32 (&wop, round, denorm); /* For a NaN, normalize mantissa bits (cvt.s.d can't preserve them) */ if (sim_fpu_is_qnan (&wop)) wop = sim_fpu_qnan; sim_fpu_to32 (&result32, &wop); result64 = result32; break; case fmt_double: status |= sim_fpu_round_64 (&wop, round, denorm); /* For a NaN, normalize mantissa bits (make cvt.d.s consistent) */ if (sim_fpu_is_qnan (&wop)) wop = sim_fpu_qnan; sim_fpu_to64 (&result64, &wop); break; case fmt_word: status |= sim_fpu_to32i (&result32, &wop, round); result64 = result32; break; case fmt_long: status |= sim_fpu_to64i (&result64, &wop, round); break; default: result64 = 0; sim_io_eprintf (SD, "Bad switch\n"); abort (); } update_fcsr (cpu, cia, status); return result64;}unsigned64ps_lower(sim_cpu *cpu, address_word cia, unsigned64 op){ return FP_PS_lower (op);}unsigned64ps_upper(sim_cpu *cpu, address_word cia, unsigned64 op){ return FP_PS_upper(op);}unsigned64pack_ps(sim_cpu *cpu, address_word cia, unsigned64 op1, unsigned64 op2, FP_formats fmt){ unsigned64 result = 0; /* The registers must specify FPRs valid for operands of type "fmt". If they are not valid, the result is undefined. */ /* The format type should already have been checked: */ switch (fmt) { case fmt_single: { sim_fpu wop; unsigned32 res_u, res_l; sim_fpu_32to (&wop, op1); sim_fpu_to32 (&res_u, &wop); sim_fpu_32to (&wop, op2); sim_fpu_to32 (&res_l, &wop); result = FP_PS_cat(res_u, res_l); break; } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); } return result;}unsigned64convert_ps (sim_cpu *cpu, address_word cia, int rm, unsigned64 op, FP_formats from, FP_formats to){ sim_fpu wop_u, wop_l; sim_fpu_round round = rounding_mode (rm); sim_fpu_denorm denorm = denorm_mode (cpu); unsigned32 res_u, res_l; unsigned64 result; sim_fpu_status status_u = 0, status_l = 0; /* As convert, but used only for paired values (formats PS, PW) */ /* Convert the input to sim_fpu internal format */ switch (from) { case fmt_word: /* fmt_pw */ sim_fpu_i32to (&wop_u, (op >> 32) & (unsigned)0xFFFFFFFF, round); sim_fpu_i32to (&wop_l, op & (unsigned)0xFFFFFFFF, round); break; case fmt_ps: sim_fpu_32to (&wop_u, FP_PS_upper(op)); sim_fpu_32to (&wop_l, FP_PS_lower(op)); break; default: sim_io_eprintf (SD, "Bad switch\n"); abort (); } /* Convert sim_fpu format into the output */ switch (to) { case fmt_word: /* fmt_pw */ status_u |= sim_fpu_to32i (&res_u, &wop_u, round); status_l |= sim_fpu_to32i (&res_l, &wop_l, round); result = (((unsigned64)res_u) << 32) | (unsigned64)res_l; break; case fmt_ps: status_u |= sim_fpu_round_32 (&wop_u, 0, round); status_l |= sim_fpu_round_32 (&wop_l, 0, round); sim_fpu_to32 (&res_u, &wop_u); sim_fpu_to32 (&res_l, &wop_l); result = FP_PS_cat(res_u, res_l); break; default: result = 0; sim_io_eprintf (SD, "Bad switch\n"); abort (); } update_fcsr (cpu, cia, status_u | status_l); return result;}static const char *fpu_format_name (FP_formats fmt){ switch (fmt) { case fmt_single: return "single"; case fmt_double: return "double"; case fmt_word: return "word"; case fmt_long: return "long"; case fmt_ps: return "ps"; case fmt_unknown: return "<unknown>"; case fmt_uninterpreted: return "<uninterpreted>"; case fmt_uninterpreted_32: return "<uninterpreted_32>"; case fmt_uninterpreted_64: return "<uninterpreted_64>"; default: return "<format error>"; }}#ifdef DEBUGstatic const char *fpu_rounding_mode_name (int rm){ switch (rm) { case FP_RM_NEAREST: return "Round"; case FP_RM_TOZERO: return "Trunc"; case FP_RM_TOPINF: return "Ceil"; case FP_RM_TOMINF: return "Floor"; default: return "<rounding mode error>"; }}#endif /* DEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -