diff options
Diffstat (limited to 'sim/mips')
-rw-r--r-- | sim/mips/ChangeLog | 18 | ||||
-rw-r--r-- | sim/mips/cp1.c | 209 | ||||
-rw-r--r-- | sim/mips/mips.igen | 138 | ||||
-rw-r--r-- | sim/mips/sim-main.h | 10 |
4 files changed, 362 insertions, 13 deletions
diff --git a/sim/mips/ChangeLog b/sim/mips/ChangeLog index 336eda5..2756249 100644 --- a/sim/mips/ChangeLog +++ b/sim/mips/ChangeLog @@ -1,3 +1,21 @@ +2002-06-13 Chris Demetriou <cgd@broadcom.com> + + * cp1.c (FP_PS_upper, FP_PS_lower, FP_PS_cat, FPQNaN_PS): New macros. + (value_fpr, store_fpr, fp_cmp, fp_unary, fp_binary, fp_mac) + (fp_inv_sqrt, fpu_format_name): Add paired-single support. + (convert): Note that this function is not used for paired-single + format conversions. + (ps_lower, ps_upper, pack_ps, convert_ps): New functions. + * mips.igen (FMT, MOVtf.fmt): Add paired-single support. + (check_fmt_p): Enable paired-single support. + (ALNV.PS, CVT.PS.S, CVT.S.PL, CVT.S.PU, PLL.PS, PLU.PS, PUL.PS) + (PUU.PS): New instructions. + (CVT.S.fmt): Don't use this instruction for paired-single format + destinations. + * sim-main.h (FP_formats): New value 'fmt_ps.' + (ps_lower, ps_upper, pack_ps, convert_ps): New prototypes. + (PSLower, PSUpper, PackPS, ConvertPS): New macros. + 2002-06-12 Chris Demetriou <cgd@broadcom.com> * mips.igen: Fix formatting of function calls in diff --git a/sim/mips/cp1.c b/sim/mips/cp1.c index 66e7c58..24c0a21 100644 --- a/sim/mips/cp1.c +++ b/sim/mips/cp1.c @@ -71,13 +71,28 @@ with this program; if not, write to the Free Software Foundation, Inc., siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii s = 1bit = sign i = 63bits = integer + + PAIRED SINGLE precision floating: + seeeeeeeefffffffffffffffffffffffseeeeeeeefffffffffffffffffffffff + | upper || lower | + s = 1bit = sign + e = 8bits = exponent + f = 23bits = fraction + Note: upper = [63..32], lower = [31..0] */ +/* Extract packed single values: */ +#define FP_PS_upper(v) (((v) >> 32) & (unsigned)0xFFFFFFFF) +#define FP_PS_lower(v) ((v) & (unsigned)0xFFFFFFFF) +#define FP_PS_cat(u,l) (((unsigned64)((u) & (unsigned)0xFFFFFFFF) << 32) \ + | (unsigned64)((l) & 0xFFFFFFFF)) + /* Explicit QNaN values. */ #define FPQNaN_SINGLE (0x7FBFFFFF) #define FPQNaN_WORD (0x7FFFFFFF) #define FPQNaN_DOUBLE (UNSIGNED64 (0x7FF7FFFFFFFFFFFF)) #define FPQNaN_LONG (UNSIGNED64 (0x7FFFFFFFFFFFFFFF)) +#define FPQNaN_PS (FP_PS_cat (FPQNaN_SINGLE, FPQNaN_SINGLE)) static const char *fpu_format_name (FP_formats fmt); #ifdef DEBUG @@ -131,6 +146,7 @@ value_fpr (sim_cpu *cpu, case fmt_double: value = FPQNaN_DOUBLE; break; case fmt_word: value = FPQNaN_WORD; break; case fmt_long: value = FPQNaN_LONG; break; + case fmt_ps: value = FPQNaN_PS; break; default: err = -1; break; } } @@ -146,6 +162,7 @@ value_fpr (sim_cpu *cpu, case fmt_uninterpreted: case fmt_double: case fmt_long: + case fmt_ps: value = FGR[fpr]; break; @@ -183,6 +200,10 @@ value_fpr (sim_cpu *cpu, } break; + case fmt_ps: + SignalException (ReservedInstruction, 0); + break; + default: err = -1; break; @@ -237,6 +258,7 @@ store_fpr (sim_cpu *cpu, case fmt_uninterpreted: case fmt_double: case fmt_long: + case fmt_ps: FGR[fpr] = value; FPR_STATE[fpr] = fmt; break; @@ -280,6 +302,11 @@ store_fpr (sim_cpu *cpu, } break; + case fmt_ps: + FPR_STATE[fpr] = fmt_unknown; + SignalException (ReservedInstruction, 0); + break; + default: FPR_STATE[fpr] = fmt_unknown; err = -1; @@ -567,6 +594,18 @@ fp_cmp(sim_cpu *cpu, SETFCC (cc, result); break; } + case fmt_ps: + { + int result0, result1; + status = fp_test(FP_PS_lower (op1), FP_PS_lower (op2), fmt_single, + abs, cond, &result0); + status |= fp_test(FP_PS_upper (op1), FP_PS_upper (op2), fmt_single, + abs, cond, &result1); + update_fcsr (cpu, cia, status); + SETFCC (cc, result0); + SETFCC (cc+1, result1); + break; + } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); @@ -613,6 +652,20 @@ fp_unary(sim_cpu *cpu, result = res; break; } + case fmt_ps: + { + int status_u = 0, status_l = 0; + unsigned32 res_u, res_l; + sim_fpu_32to (&wop, FP_PS_upper(op)); + status_u |= (*sim_fpu_op) (&ans, &wop); + sim_fpu_to32 (&res_u, &ans); + sim_fpu_32to (&wop, FP_PS_lower(op)); + status_l |= (*sim_fpu_op) (&ans, &wop); + sim_fpu_to32 (&res_l, &ans); + result = FP_PS_cat(res_u, res_l); + status = status_u | status_l; + break; + } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); @@ -663,6 +716,22 @@ fp_binary(sim_cpu *cpu, result = res; break; } + case fmt_ps: + { + int status_u = 0, status_l = 0; + unsigned32 res_u, res_l; + sim_fpu_32to (&wop1, FP_PS_upper(op1)); + sim_fpu_32to (&wop2, FP_PS_upper(op2)); + status_u |= (*sim_fpu_op) (&ans, &wop1, &wop2); + sim_fpu_to32 (&res_u, &ans); + sim_fpu_32to (&wop1, FP_PS_lower(op1)); + sim_fpu_32to (&wop2, FP_PS_lower(op2)); + status_l |= (*sim_fpu_op) (&ans, &wop1, &wop2); + sim_fpu_to32 (&res_l, &ans); + result = FP_PS_cat(res_u, res_l); + status = status_u | status_l; + break; + } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); @@ -784,6 +853,20 @@ fp_mac(sim_cpu *cpu, status = inner_mac(sim_fpu_op, op1, op2, op3, scale, negate, fmt, round, denorm, &result); break; + case fmt_ps: + { + int status_u, status_l; + unsigned64 result_u, result_l; + status_u = inner_mac(sim_fpu_op, FP_PS_upper(op1), FP_PS_upper(op2), + FP_PS_upper(op3), scale, negate, fmt_single, + round, denorm, &result_u); + status_l = inner_mac(sim_fpu_op, FP_PS_lower(op1), FP_PS_lower(op2), + FP_PS_lower(op3), scale, negate, fmt_single, + round, denorm, &result_l); + result = FP_PS_cat(result_u, result_l); + status = status_u | status_l; + break; + } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); @@ -863,6 +946,18 @@ fp_inv_sqrt(sim_cpu *cpu, case fmt_double: status = inner_rsqrt (op1, fmt, round, denorm, &result); break; + case fmt_ps: + { + int status_u, status_l; + unsigned64 result_u, result_l; + status_u = inner_rsqrt (FP_PS_upper(op1), fmt_single, round, denorm, + &result_u); + status_l = inner_rsqrt (FP_PS_lower(op1), fmt_single, round, denorm, + &result_l); + result = FP_PS_cat(result_u, result_l); + status = status_u | status_l; + break; + } default: sim_io_eprintf (SD, "Bad switch\n"); abort (); @@ -1044,8 +1139,8 @@ convert (sim_cpu *cpu, /* 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. */ + 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: @@ -1080,6 +1175,114 @@ convert (sim_cpu *cpu, return result64; } +unsigned64 +ps_lower(sim_cpu *cpu, + address_word cia, + unsigned64 op) +{ + return FP_PS_lower (op); +} + +unsigned64 +ps_upper(sim_cpu *cpu, + address_word cia, + unsigned64 op) +{ + return FP_PS_upper(op); +} + +unsigned64 +pack_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; +} + +unsigned64 +convert_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) { @@ -1093,6 +1296,8 @@ fpu_format_name (FP_formats fmt) return "word"; case fmt_long: return "long"; + case fmt_ps: + return "ps"; case fmt_unknown: return "<unknown>"; case fmt_uninterpreted: diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen index 4e895a1..a264365 100644 --- a/sim/mips/mips.igen +++ b/sim/mips/mips.igen @@ -3522,6 +3522,7 @@ case fmt_double: return "d"; case fmt_word: return "w"; case fmt_long: return "l"; + case fmt_ps: return "ps"; default: return "?"; } } @@ -3610,13 +3611,9 @@ *mipsV: *mips64: { -#if 0 /* XXX FIXME: FP code doesn't yet support paired single ops. */ if ((fmt != fmt_single) && (fmt != fmt_double) && (fmt != fmt_ps || (UserMode && (SR & (status_UX|status_PX)) == 0))) SignalException (ReservedInstruction, insn); -#else - check_fmt (SD_, fmt, insn); -#endif } @@ -3684,6 +3681,32 @@ } +010011,5.RS,5.FT,5.FS,5.FD,011,110:COP1X:64,f::ALNV.PS +"alnv.ps f<FD>, f<FS>, f<FT>, r<RS>" +*mipsV: +*mips64: +{ + unsigned64 fs; + unsigned64 ft; + unsigned64 fd; + check_fpu (SD_); + check_u64 (SD_, instruction_0); + fs = ValueFPR (FS, fmt_ps); + if ((GPR[RS] & 0x3) != 0) + Unpredictable (); + if ((GPR[RS] & 0x4) == 0) + fd = fs; + else + { + ft = ValueFPR (FT, fmt_ps); + if (BigEndianCPU) + fd = PackPS (PSLower (fs), PSUpper (ft)); + else + fd = PackPS (PSLower (ft), PSUpper (fs)); + } + StoreFPR (FD, fmt_ps, fd); +} + // BC1F // BC1FL @@ -3946,10 +3969,22 @@ } +010001,10,000,5.FT,5.FS,5.FD,100110:COP1:64,f::CVT.PS.S +"cvt.ps.s f<FD>, f<FS>, f<FT>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_ps, PackPS (ValueFPR (FS, fmt_single), + ValueFPR (FT, fmt_single))); +} + + // // FIXME: Does not correctly differentiate between mips* // -010001,10,3.FMT,00000,5.FS,5.FD,100000:COP1:32,f::CVT.S.fmt +010001,10,3.FMT!6,00000,5.FS,5.FD,100000:COP1:32,f::CVT.S.fmt "cvt.s.%s<FMT> f<FD>, f<FS>" *mipsI: *mipsII: @@ -3971,6 +4006,28 @@ } +010001,10,110,00000,5.FS,5.FD,101000:COP1:64,f::CVT.S.PL +"cvt.s.pl f<FD>, f<FS>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_single, PSLower (ValueFPR (FS, fmt_ps))); +} + + +010001,10,110,00000,5.FS,5.FD,100000:COP1:64,f::CVT.S.PU +"cvt.s.pu f<FD>, f<FS>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_single, PSUpper (ValueFPR (FS, fmt_ps))); +} + + 010001,10,3.FMT,00000,5.FS,5.FD,100100:COP1:32,f::CVT.W.fmt "cvt.w.%s<FMT> f<FD>, f<FS>" *mipsI: @@ -4284,12 +4341,22 @@ { int fmt = FMT; check_fpu (SD_); - { - if (GETFCC(CC) == TF) - StoreFPR (FD, fmt, ValueFPR (FS, fmt)); - else - StoreFPR (FD, fmt, ValueFPR (FD, fmt)); - } + if (fmt != fmt_ps) + { + if (GETFCC(CC) == TF) + StoreFPR (FD, fmt, ValueFPR (FS, fmt)); + else + StoreFPR (FD, fmt, ValueFPR (FD, fmt)); /* set fmt */ + } + else + { + unsigned64 fd; + fd = PackPS (PSUpper (ValueFPR ((GETFCC (CC+1) == TF) ? FS : FD, + fmt_ps)), + PSLower (ValueFPR ((GETFCC (CC+0) == TF) ? FS : FD, + fmt_ps))); + StoreFPR (FD, fmt_ps, fd); + } } @@ -4449,6 +4516,30 @@ } +010001,10,110,5.FT,5.FS,5.FD,101100:COP1:64,f::PLL.PS +"pll.ps f<FD>, f<FS>, f<FT>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_ps, PackPS (PSLower (ValueFPR (FS, fmt_ps)), + PSLower (ValueFPR (FT, fmt_ps)))); +} + + +010001,10,110,5.FT,5.FS,5.FD,101101:COP1:64,f::PLU.PS +"plu.ps f<FD>, f<FS>, f<FT>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_ps, PackPS (PSLower (ValueFPR (FS, fmt_ps)), + PSUpper (ValueFPR (FT, fmt_ps)))); +} + + 010011,5.BASE,5.INDEX,5.HINT,00000,001111:COP1X:64::PREFX "prefx <HINT>, r<INDEX>(r<BASE>)" *mipsIV: @@ -4467,6 +4558,31 @@ } } + +010001,10,110,5.FT,5.FS,5.FD,101110:COP1:64,f::PUL.PS +"pul.ps f<FD>, f<FS>, f<FT>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_ps, PackPS (PSUpper (ValueFPR (FS, fmt_ps)), + PSLower (ValueFPR (FT, fmt_ps)))); +} + + +010001,10,110,5.FT,5.FS,5.FD,101111:COP1:64,f::PUU.PS +"puu.ps f<FD>, f<FS>, f<FT>" +*mipsV: +*mips64: +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + StoreFPR (FD, fmt_ps, PackPS (PSUpper (ValueFPR (FS, fmt_ps)), + PSUpper (ValueFPR (FT, fmt_ps)))); +} + + 010001,10,3.FMT,00000,5.FS,5.FD,010101:COP1:32,f::RECIP.fmt "recip.%s<FMT> f<FD>, f<FS>" *mipsIV: diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h index 25f8a0d..833fd5f 100644 --- a/sim/mips/sim-main.h +++ b/sim/mips/sim-main.h @@ -73,6 +73,7 @@ typedef enum { fmt_double = 1, fmt_word = 4, fmt_long = 5, + fmt_ps = 6, /* The following are well outside the normal acceptable format range, and are used in the register status vector. */ fmt_unknown = 0x10000000, @@ -674,6 +675,12 @@ unsigned64 value_fpr (SIM_STATE, int fpr, FP_formats); #define ValueFPR(FPR,FMT) value_fpr (SIM_ARGS, (FPR), (FMT)) void store_fpr (SIM_STATE, int fpr, FP_formats fmt, unsigned64 value); #define StoreFPR(FPR,FMT,VALUE) store_fpr (SIM_ARGS, (FPR), (FMT), (VALUE)) +unsigned64 ps_lower (SIM_STATE, unsigned64 op); +#define PSLower(op) ps_lower (SIM_ARGS, op) +unsigned64 ps_upper (SIM_STATE, unsigned64 op); +#define PSUpper(op) ps_upper (SIM_ARGS, op) +unsigned64 pack_ps (SIM_STATE, unsigned64 op1, unsigned64 op2, FP_formats from); +#define PackPS(op1,op2) pack_ps (SIM_ARGS, op1, op2, fmt_single) /* FCR access. */ @@ -720,6 +727,9 @@ unsigned64 fp_nmsub (SIM_STATE, unsigned64 op1, unsigned64 op2, #define NegMultiplySub(op1,op2,op3,fmt) fp_nmsub(SIM_ARGS, op1, op2, op3, fmt) unsigned64 convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to); #define Convert(rm,op,from,to) convert (SIM_ARGS, rm, op, from, to) +unsigned64 convert_ps (SIM_STATE, int rm, unsigned64 op, FP_formats from, + FP_formats to); +#define ConvertPS(rm,op,from,to) convert_ps (SIM_ARGS, rm, op, from, to) /* MDMX access. */ |