Revision 5a5012ec target-mips/translate.c
b/target-mips/translate.c | ||
---|---|---|
333 | 333 |
OPC_MFC1 = (0x00 << 21) | OPC_CP1, |
334 | 334 |
OPC_DMFC1 = (0x01 << 21) | OPC_CP1, |
335 | 335 |
OPC_CFC1 = (0x02 << 21) | OPC_CP1, |
336 |
OPC_MFHCI = (0x03 << 21) | OPC_CP1,
|
|
336 |
OPC_MFHC1 = (0x03 << 21) | OPC_CP1,
|
|
337 | 337 |
OPC_MTC1 = (0x04 << 21) | OPC_CP1, |
338 | 338 |
OPC_DMTC1 = (0x05 << 21) | OPC_CP1, |
339 | 339 |
OPC_CTC1 = (0x06 << 21) | OPC_CP1, |
340 |
OPC_MTHCI = (0x07 << 21) | OPC_CP1,
|
|
340 |
OPC_MTHC1 = (0x07 << 21) | OPC_CP1,
|
|
341 | 341 |
OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ |
342 |
OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, |
|
343 |
OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, |
|
342 | 344 |
OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ |
343 | 345 |
OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ |
344 | 346 |
OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ |
345 | 347 |
OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ |
346 | 348 |
OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ |
347 | 349 |
OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ |
350 |
OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */ |
|
348 | 351 |
}; |
349 | 352 |
|
353 |
#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) |
|
354 |
#define MASK_BC1(op) MASK_CP1(op) | (op & (0x3 << 16)) |
|
355 |
|
|
350 | 356 |
enum { |
351 | 357 |
OPC_BC1F = (0x00 << 16) | OPC_BC1, |
352 | 358 |
OPC_BC1T = (0x01 << 16) | OPC_BC1, |
... | ... | |
354 | 360 |
OPC_BC1TL = (0x03 << 16) | OPC_BC1, |
355 | 361 |
}; |
356 | 362 |
|
357 |
#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16)) |
|
358 |
#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) |
|
363 |
enum { |
|
364 |
OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2, |
|
365 |
OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2, |
|
366 |
}; |
|
367 |
|
|
368 |
enum { |
|
369 |
OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4, |
|
370 |
OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4, |
|
371 |
}; |
|
359 | 372 |
|
360 | 373 |
#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
361 | 374 |
|
... | ... | |
404 | 417 |
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; |
405 | 418 |
|
406 | 419 |
/* Warning: no function for r0 register (hard wired to zero) */ |
407 |
#define GEN32(func, NAME) \ |
|
408 |
static GenOpFunc *NAME ## _table [32] = { \
|
|
409 |
NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
|
|
410 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
|
|
411 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
|
|
412 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
|
|
413 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
|
|
414 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
|
|
415 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
|
|
416 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
|
|
417 |
}; \
|
|
418 |
static inline void func(int n) \
|
|
419 |
{ \
|
|
420 |
NAME ## _table[n](); \
|
|
420 |
#define GEN32(func, NAME) \
|
|
421 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
422 |
NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ |
|
423 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ |
|
424 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ |
|
425 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ |
|
426 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ |
|
427 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ |
|
428 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ |
|
429 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ |
|
430 |
}; \ |
|
431 |
static inline void func(int n) \ |
|
432 |
{ \ |
|
433 |
NAME ## _table[n](); \ |
|
421 | 434 |
} |
422 | 435 |
|
423 | 436 |
/* General purpose registers moves */ |
... | ... | |
434 | 447 |
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
435 | 448 |
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; |
436 | 449 |
|
437 |
# define SFGEN32(func, NAME) \
|
|
438 |
static GenOpFunc *NAME ## _table [32] = { \
|
|
439 |
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
|
|
440 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
|
|
441 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
|
|
442 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
|
|
443 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
|
|
444 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
|
|
445 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
|
|
446 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
|
|
447 |
}; \
|
|
448 |
static inline void func(int n) \
|
|
449 |
{ \
|
|
450 |
NAME ## _table[n](); \
|
|
450 |
#define FGEN32(func, NAME) \
|
|
451 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
452 |
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ |
|
453 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ |
|
454 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ |
|
455 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ |
|
456 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ |
|
457 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ |
|
458 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ |
|
459 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ |
|
460 |
}; \ |
|
461 |
static inline void func(int n) \ |
|
462 |
{ \ |
|
463 |
NAME ## _table[n](); \ |
|
451 | 464 |
} |
452 | 465 |
|
453 |
# define DFGEN32(func, NAME) \ |
|
454 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
455 |
NAME ## 0, 0, NAME ## 2, 0, \ |
|
456 |
NAME ## 4, 0, NAME ## 6, 0, \ |
|
457 |
NAME ## 8, 0, NAME ## 10, 0, \ |
|
458 |
NAME ## 12, 0, NAME ## 14, 0, \ |
|
459 |
NAME ## 16, 0, NAME ## 18, 0, \ |
|
460 |
NAME ## 20, 0, NAME ## 22, 0, \ |
|
461 |
NAME ## 24, 0, NAME ## 26, 0, \ |
|
462 |
NAME ## 28, 0, NAME ## 30, 0, \ |
|
463 |
}; \ |
|
464 |
static inline void func(int n) \ |
|
465 |
{ \ |
|
466 |
NAME ## _table[n](); \ |
|
467 |
} |
|
466 |
FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); |
|
467 |
FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); |
|
468 |
|
|
469 |
FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); |
|
470 |
FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); |
|
468 | 471 |
|
469 |
SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
|
|
470 |
SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
|
|
472 |
FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
|
|
473 |
FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
|
|
471 | 474 |
|
472 |
SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
|
|
473 |
SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
|
|
475 |
FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
|
|
476 |
FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
|
|
474 | 477 |
|
475 |
SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
|
|
476 |
SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
|
|
478 |
FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
|
|
479 |
FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
|
|
477 | 480 |
|
478 |
DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
|
|
479 |
DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
|
|
481 |
FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
|
|
482 |
FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
|
|
480 | 483 |
|
481 |
DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
|
|
482 |
DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
|
|
484 |
FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr);
|
|
485 |
FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr);
|
|
483 | 486 |
|
484 |
DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); |
|
485 |
DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); |
|
487 |
FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr); |
|
488 |
FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); |
|
489 |
|
|
490 |
FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); |
|
491 |
FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); |
|
486 | 492 |
|
487 | 493 |
#define FOP_CONDS(fmt) \ |
488 |
static GenOpFunc * cond_ ## fmt ## _table[16] = { \
|
|
494 |
static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \
|
|
489 | 495 |
gen_op_cmp_ ## fmt ## _f, \ |
490 | 496 |
gen_op_cmp_ ## fmt ## _un, \ |
491 | 497 |
gen_op_cmp_ ## fmt ## _eq, \ |
... | ... | |
503 | 509 |
gen_op_cmp_ ## fmt ## _le, \ |
504 | 510 |
gen_op_cmp_ ## fmt ## _ngt, \ |
505 | 511 |
}; \ |
506 |
static inline void gen_cmp_ ## fmt(int n) \
|
|
512 |
static inline void gen_cmp_ ## fmt(int n, long cc) \
|
|
507 | 513 |
{ \ |
508 |
cond_ ## fmt ## _table[n](); \
|
|
514 |
cond_ ## fmt ## _table[n](cc); \
|
|
509 | 515 |
} |
510 | 516 |
|
511 | 517 |
FOP_CONDS(d) |
512 | 518 |
FOP_CONDS(s) |
519 |
FOP_CONDS(ps) |
|
513 | 520 |
|
514 | 521 |
typedef struct DisasContext { |
515 | 522 |
struct TranslationBlock *tb; |
516 | 523 |
target_ulong pc, saved_pc; |
517 | 524 |
uint32_t opcode; |
525 |
uint32_t fp_status, saved_fp_status; |
|
518 | 526 |
/* Routine used to access memory */ |
519 | 527 |
int mem_idx; |
520 | 528 |
uint32_t hflags, saved_hflags; |
... | ... | |
600 | 608 |
if (ctx->hflags != ctx->saved_hflags) { |
601 | 609 |
gen_op_save_state(ctx->hflags); |
602 | 610 |
ctx->saved_hflags = ctx->hflags; |
603 |
if (ctx->hflags & MIPS_HFLAG_BR) { |
|
611 |
switch (ctx->hflags & MIPS_HFLAG_BMASK) { |
|
612 |
case MIPS_HFLAG_BR: |
|
604 | 613 |
gen_op_save_breg_target(); |
605 |
} else if (ctx->hflags & MIPS_HFLAG_B) { |
|
606 |
gen_op_save_btarget(ctx->btarget); |
|
607 |
} else if (ctx->hflags & MIPS_HFLAG_BMASK) { |
|
614 |
break; |
|
615 |
case MIPS_HFLAG_BC: |
|
608 | 616 |
gen_op_save_bcond(); |
617 |
/* fall through */ |
|
618 |
case MIPS_HFLAG_BL: |
|
619 |
/* bcond was already saved by the BL insn */ |
|
620 |
/* fall through */ |
|
621 |
case MIPS_HFLAG_B: |
|
609 | 622 |
gen_op_save_btarget(ctx->btarget); |
623 |
break; |
|
610 | 624 |
} |
611 | 625 |
} |
612 | 626 |
} |
613 | 627 |
|
628 |
static inline void save_fpu_state (DisasContext *ctx) |
|
629 |
{ |
|
630 |
if (ctx->fp_status != ctx->saved_fp_status) { |
|
631 |
gen_op_save_fp_status(ctx->fp_status); |
|
632 |
ctx->saved_fp_status = ctx->fp_status; |
|
633 |
} |
|
634 |
} |
|
635 |
|
|
614 | 636 |
static inline void generate_exception_err (DisasContext *ctx, int excp, int err) |
615 | 637 |
{ |
616 | 638 |
#if defined MIPS_DEBUG_DISAS |
... | ... | |
677 | 699 |
OP_ST_TABLE(wc1); |
678 | 700 |
OP_LD_TABLE(dc1); |
679 | 701 |
OP_ST_TABLE(dc1); |
702 |
OP_LD_TABLE(wxc1); |
|
703 |
OP_ST_TABLE(wxc1); |
|
704 |
OP_LD_TABLE(dxc1); |
|
705 |
OP_ST_TABLE(dxc1); |
|
706 |
OP_LD_TABLE(uxc1); |
|
707 |
OP_ST_TABLE(uxc1); |
|
680 | 708 |
|
681 | 709 |
/* Load and store */ |
682 | 710 |
static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, |
... | ... | |
1472 | 1500 |
if (ctx->hflags & MIPS_HFLAG_BMASK) { |
1473 | 1501 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
1474 | 1502 |
fprintf(logfile, |
1475 |
"undefined branch in delay slot at PC " TARGET_FMT_lx "\n",
|
|
1503 |
"Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
|
|
1476 | 1504 |
ctx->pc); |
1477 | 1505 |
} |
1478 | 1506 |
MIPS_INVAL("branch/jump in bdelay slot"); |
... | ... | |
1672 | 1700 |
MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); |
1673 | 1701 |
not_likely: |
1674 | 1702 |
ctx->hflags |= MIPS_HFLAG_BC; |
1703 |
gen_op_set_bcond(); |
|
1675 | 1704 |
break; |
1676 | 1705 |
case OPC_BLTZALL: |
1677 | 1706 |
gen_op_ltz(); |
... | ... | |
1679 | 1708 |
MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); |
1680 | 1709 |
likely: |
1681 | 1710 |
ctx->hflags |= MIPS_HFLAG_BL; |
1711 |
gen_op_set_bcond(); |
|
1712 |
gen_op_save_bcond(); |
|
1682 | 1713 |
break; |
1683 | 1714 |
default: |
1684 | 1715 |
MIPS_INVAL("conditional branch/jump"); |
1685 | 1716 |
generate_exception(ctx, EXCP_RI); |
1686 | 1717 |
return; |
1687 | 1718 |
} |
1688 |
gen_op_set_bcond(); |
|
1689 | 1719 |
} |
1690 | 1720 |
MIPS_DEBUG("enter ds: link %d cond %02x target %08x", |
1691 | 1721 |
blink, ctx->hflags, btarget); |
... | ... | |
4220 | 4250 |
|
4221 | 4251 |
/* CP1 Branches (before delay slot) */ |
4222 | 4252 |
static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, |
4223 |
int32_t offset) |
|
4253 |
int32_t cc, int32_t offset)
|
|
4224 | 4254 |
{ |
4225 | 4255 |
target_ulong btarget; |
4226 | 4256 |
|
... | ... | |
4228 | 4258 |
|
4229 | 4259 |
switch (op) { |
4230 | 4260 |
case OPC_BC1F: |
4231 |
gen_op_bc1f(); |
|
4261 |
gen_op_bc1f(cc);
|
|
4232 | 4262 |
MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); |
4233 | 4263 |
goto not_likely; |
4234 | 4264 |
case OPC_BC1FL: |
4235 |
gen_op_bc1f(); |
|
4265 |
gen_op_bc1f(cc);
|
|
4236 | 4266 |
MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); |
4237 | 4267 |
goto likely; |
4238 | 4268 |
case OPC_BC1T: |
4239 |
gen_op_bc1t(); |
|
4269 |
gen_op_bc1t(cc);
|
|
4240 | 4270 |
MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); |
4241 |
not_likely: |
|
4242 |
ctx->hflags |= MIPS_HFLAG_BC; |
|
4243 |
break; |
|
4271 |
goto not_likely; |
|
4244 | 4272 |
case OPC_BC1TL: |
4245 |
gen_op_bc1t(); |
|
4273 |
gen_op_bc1t(cc);
|
|
4246 | 4274 |
MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); |
4247 | 4275 |
likely: |
4248 | 4276 |
ctx->hflags |= MIPS_HFLAG_BL; |
4277 |
gen_op_set_bcond(); |
|
4278 |
gen_op_save_bcond(); |
|
4249 | 4279 |
break; |
4250 |
default: |
|
4251 |
MIPS_INVAL("cp1 branch/jump"); |
|
4280 |
case OPC_BC1FANY2: |
|
4281 |
gen_op_bc1fany2(cc); |
|
4282 |
MIPS_DEBUG("bc1fany2 " TARGET_FMT_lx, btarget); |
|
4283 |
goto not_likely; |
|
4284 |
case OPC_BC1TANY2: |
|
4285 |
gen_op_bc1tany2(cc); |
|
4286 |
MIPS_DEBUG("bc1tany2 " TARGET_FMT_lx, btarget); |
|
4287 |
goto not_likely; |
|
4288 |
case OPC_BC1FANY4: |
|
4289 |
gen_op_bc1fany4(cc); |
|
4290 |
MIPS_DEBUG("bc1fany4 " TARGET_FMT_lx, btarget); |
|
4291 |
goto not_likely; |
|
4292 |
case OPC_BC1TANY4: |
|
4293 |
gen_op_bc1tany4(cc); |
|
4294 |
MIPS_DEBUG("bc1tany4 " TARGET_FMT_lx, btarget); |
|
4295 |
not_likely: |
|
4296 |
ctx->hflags |= MIPS_HFLAG_BC; |
|
4297 |
gen_op_set_bcond(); |
|
4298 |
break; |
|
4299 |
default: |
|
4300 |
MIPS_INVAL("cp1 branch"); |
|
4252 | 4301 |
generate_exception (ctx, EXCP_RI); |
4253 | 4302 |
return; |
4254 | 4303 |
} |
4255 |
gen_op_set_bcond(); |
|
4256 | 4304 |
|
4257 | 4305 |
MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, |
4258 | 4306 |
ctx->hflags, btarget); |
... | ... | |
4262 | 4310 |
} |
4263 | 4311 |
|
4264 | 4312 |
/* Coprocessor 1 (FPU) */ |
4313 |
|
|
4314 |
/* verify if floating point register is valid; an operation is not defined |
|
4315 |
* if bit 0 of any register specification is set and the FR bit in the |
|
4316 |
* Status register equals zero, since the register numbers specify an |
|
4317 |
* even-odd pair of adjacent coprocessor general registers. When the FR bit |
|
4318 |
* in the Status register equals one, both even and odd register numbers |
|
4319 |
* are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. |
|
4320 |
* |
|
4321 |
* Multiple 64 bit wide registers can be checked by calling |
|
4322 |
* CHECK_FR(ctx, freg1 | freg2 | ... | fregN); |
|
4323 |
* |
|
4324 |
* FIXME: This is broken for R2, it needs to be checked at runtime, not |
|
4325 |
* at translation time. |
|
4326 |
*/ |
|
4327 |
#define CHECK_FR(ctx, freg) do { \ |
|
4328 |
if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ |
|
4329 |
generate_exception (ctx, EXCP_RI); \ |
|
4330 |
return; \ |
|
4331 |
} \ |
|
4332 |
} while(0) |
|
4333 |
|
|
4334 |
#define FOP(func, fmt) (((fmt) << 21) | (func)) |
|
4335 |
|
|
4265 | 4336 |
static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) |
4266 | 4337 |
{ |
4267 | 4338 |
const char *opn = "unk"; |
... | ... | |
4280 | 4351 |
opn = "mtc1"; |
4281 | 4352 |
break; |
4282 | 4353 |
case OPC_CFC1: |
4283 |
if (fs != 0 && fs != 31) { |
|
4284 |
MIPS_INVAL("cfc1 freg"); |
|
4285 |
generate_exception (ctx, EXCP_RI); |
|
4286 |
return; |
|
4287 |
} |
|
4288 | 4354 |
GEN_LOAD_IMM_TN(T1, fs); |
4289 | 4355 |
gen_op_cfc1(); |
4290 | 4356 |
GEN_STORE_TN_REG(rt, T0); |
4291 | 4357 |
opn = "cfc1"; |
4292 | 4358 |
break; |
4293 | 4359 |
case OPC_CTC1: |
4294 |
if (fs != 0 && fs != 31) { |
|
4295 |
MIPS_INVAL("ctc1 freg"); |
|
4296 |
generate_exception (ctx, EXCP_RI); |
|
4297 |
return; |
|
4298 |
} |
|
4299 | 4360 |
GEN_LOAD_IMM_TN(T1, fs); |
4300 | 4361 |
GEN_LOAD_REG_TN(T0, rt); |
4301 | 4362 |
gen_op_ctc1(); |
4302 | 4363 |
opn = "ctc1"; |
4303 | 4364 |
break; |
4304 | 4365 |
case OPC_DMFC1: |
4366 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4367 |
gen_op_dmfc1(); |
|
4368 |
GEN_STORE_TN_REG(rt, T0); |
|
4369 |
opn = "dmfc1"; |
|
4370 |
break; |
|
4305 | 4371 |
case OPC_DMTC1: |
4306 |
/* Not implemented, fallthrough. */ |
|
4372 |
GEN_LOAD_REG_TN(T0, rt); |
|
4373 |
gen_op_dmtc1(); |
|
4374 |
GEN_STORE_FTN_FREG(fs, DT0); |
|
4375 |
opn = "dmtc1"; |
|
4376 |
break; |
|
4377 |
case OPC_MFHC1: |
|
4378 |
CHECK_FR(ctx, fs); |
|
4379 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4380 |
gen_op_mfhc1(); |
|
4381 |
GEN_STORE_TN_REG(rt, T0); |
|
4382 |
opn = "mfhc1"; |
|
4383 |
break; |
|
4384 |
case OPC_MTHC1: |
|
4385 |
CHECK_FR(ctx, fs); |
|
4386 |
GEN_LOAD_REG_TN(T0, rt); |
|
4387 |
gen_op_mthc1(); |
|
4388 |
GEN_STORE_FTN_FREG(fs, WTH0); |
|
4389 |
opn = "mthc1"; |
|
4390 |
break; |
|
4307 | 4391 |
default: |
4308 | 4392 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
4309 | 4393 |
fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", |
... | ... | |
4316 | 4400 |
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); |
4317 | 4401 |
} |
4318 | 4402 |
|
4319 |
/* verify if floating point register is valid; an operation is not defined |
|
4320 |
* if bit 0 of any register specification is set and the FR bit in the |
|
4321 |
* Status register equals zero, since the register numbers specify an |
|
4322 |
* even-odd pair of adjacent coprocessor general registers. When the FR bit |
|
4323 |
* in the Status register equals one, both even and odd register numbers |
|
4324 |
* are valid. This limitation exists only for 64 bit wide (d,l) registers. |
|
4325 |
* |
|
4326 |
* Multiple 64 bit wide registers can be checked by calling |
|
4327 |
* CHECK_FR(ctx, freg1 | freg2 | ... | fregN); |
|
4328 |
*/ |
|
4329 |
#define CHECK_FR(ctx, freg) do { \ |
|
4330 |
if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \ |
|
4331 |
generate_exception (ctx, EXCP_RI); \ |
|
4332 |
return; \ |
|
4333 |
} \ |
|
4334 |
} while(0) |
|
4403 |
static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) |
|
4404 |
{ |
|
4405 |
uint32_t ccbit; |
|
4335 | 4406 |
|
4336 |
#define FOP(func, fmt) (((fmt) << 21) | (func)) |
|
4407 |
GEN_LOAD_REG_TN(T0, rd); |
|
4408 |
GEN_LOAD_REG_TN(T1, rs); |
|
4409 |
if (cc) |
|
4410 |
ccbit = 1 << (24 + cc); |
|
4411 |
else |
|
4412 |
ccbit = 1 << 23; |
|
4413 |
if (!tf) |
|
4414 |
gen_op_movf(ccbit); |
|
4415 |
else |
|
4416 |
gen_op_movt(ccbit); |
|
4417 |
GEN_STORE_TN_REG(rd, T0); |
|
4418 |
} |
|
4419 |
|
|
4420 |
#define GEN_MOVCF(fmt) \ |
|
4421 |
static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \ |
|
4422 |
{ \ |
|
4423 |
uint32_t ccbit; \ |
|
4424 |
\ |
|
4425 |
if (cc) \ |
|
4426 |
ccbit = 1 << (24 + cc); \ |
|
4427 |
else \ |
|
4428 |
ccbit = 1 << 23; \ |
|
4429 |
if (!tf) \ |
|
4430 |
glue(gen_op_float_movf_, fmt)(ccbit); \ |
|
4431 |
else \ |
|
4432 |
glue(gen_op_float_movt_, fmt)(ccbit); \ |
|
4433 |
} |
|
4434 |
GEN_MOVCF(d); |
|
4435 |
GEN_MOVCF(s); |
|
4436 |
GEN_MOVCF(ps); |
|
4437 |
#undef GEN_MOVCF |
|
4337 | 4438 |
|
4338 |
static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) |
|
4439 |
static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, |
|
4440 |
int fs, int fd, int cc) |
|
4339 | 4441 |
{ |
4340 | 4442 |
const char *opn = "unk"; |
4341 | 4443 |
const char *condnames[] = { |
... | ... | |
4360 | 4462 |
uint32_t func = ctx->opcode & 0x3f; |
4361 | 4463 |
|
4362 | 4464 |
switch (ctx->opcode & FOP(0x3f, 0x1f)) { |
4465 |
case FOP(0, 16): |
|
4466 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4467 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4468 |
gen_op_float_add_s(); |
|
4469 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4470 |
opn = "add.s"; |
|
4471 |
binary = 1; |
|
4472 |
break; |
|
4473 |
case FOP(1, 16): |
|
4474 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4475 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4476 |
gen_op_float_sub_s(); |
|
4477 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4478 |
opn = "sub.s"; |
|
4479 |
binary = 1; |
|
4480 |
break; |
|
4481 |
case FOP(2, 16): |
|
4482 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4483 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4484 |
gen_op_float_mul_s(); |
|
4485 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4486 |
opn = "mul.s"; |
|
4487 |
binary = 1; |
|
4488 |
break; |
|
4489 |
case FOP(3, 16): |
|
4490 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4491 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4492 |
gen_op_float_div_s(); |
|
4493 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4494 |
opn = "div.s"; |
|
4495 |
binary = 1; |
|
4496 |
break; |
|
4497 |
case FOP(4, 16): |
|
4498 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4499 |
gen_op_float_sqrt_s(); |
|
4500 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4501 |
opn = "sqrt.s"; |
|
4502 |
break; |
|
4503 |
case FOP(5, 16): |
|
4504 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4505 |
gen_op_float_abs_s(); |
|
4506 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4507 |
opn = "abs.s"; |
|
4508 |
break; |
|
4509 |
case FOP(6, 16): |
|
4510 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4511 |
gen_op_float_mov_s(); |
|
4512 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4513 |
opn = "mov.s"; |
|
4514 |
break; |
|
4515 |
case FOP(7, 16): |
|
4516 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4517 |
gen_op_float_chs_s(); |
|
4518 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4519 |
opn = "neg.s"; |
|
4520 |
break; |
|
4521 |
case FOP(8, 16): |
|
4522 |
CHECK_FR(ctx, fs); |
|
4523 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4524 |
gen_op_float_roundl_s(); |
|
4525 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4526 |
opn = "round.l.s"; |
|
4527 |
break; |
|
4528 |
case FOP(9, 16): |
|
4529 |
CHECK_FR(ctx, fs); |
|
4530 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4531 |
gen_op_float_truncl_s(); |
|
4532 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4533 |
opn = "trunc.l.s"; |
|
4534 |
break; |
|
4535 |
case FOP(10, 16): |
|
4536 |
CHECK_FR(ctx, fs); |
|
4537 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4538 |
gen_op_float_ceill_s(); |
|
4539 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4540 |
opn = "ceil.l.s"; |
|
4541 |
break; |
|
4542 |
case FOP(11, 16): |
|
4543 |
CHECK_FR(ctx, fs); |
|
4544 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4545 |
gen_op_float_floorl_s(); |
|
4546 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4547 |
opn = "floor.l.s"; |
|
4548 |
break; |
|
4549 |
case FOP(12, 16): |
|
4550 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4551 |
gen_op_float_roundw_s(); |
|
4552 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4553 |
opn = "round.w.s"; |
|
4554 |
break; |
|
4555 |
case FOP(13, 16): |
|
4556 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4557 |
gen_op_float_truncw_s(); |
|
4558 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4559 |
opn = "trunc.w.s"; |
|
4560 |
break; |
|
4561 |
case FOP(14, 16): |
|
4562 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4563 |
gen_op_float_ceilw_s(); |
|
4564 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4565 |
opn = "ceil.w.s"; |
|
4566 |
break; |
|
4567 |
case FOP(15, 16): |
|
4568 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4569 |
gen_op_float_floorw_s(); |
|
4570 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4571 |
opn = "floor.w.s"; |
|
4572 |
break; |
|
4573 |
case FOP(17, 16): |
|
4574 |
GEN_LOAD_REG_TN(T0, ft); |
|
4575 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4576 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4577 |
gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); |
|
4578 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4579 |
opn = "movcf.s"; |
|
4580 |
break; |
|
4581 |
case FOP(18, 16): |
|
4582 |
GEN_LOAD_REG_TN(T0, ft); |
|
4583 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4584 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4585 |
gen_op_float_movz_s(); |
|
4586 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4587 |
opn = "movz.s"; |
|
4588 |
break; |
|
4589 |
case FOP(19, 16): |
|
4590 |
GEN_LOAD_REG_TN(T0, ft); |
|
4591 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4592 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4593 |
gen_op_float_movn_s(); |
|
4594 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4595 |
opn = "movn.s"; |
|
4596 |
break; |
|
4597 |
case FOP(33, 16): |
|
4598 |
CHECK_FR(ctx, fd); |
|
4599 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4600 |
gen_op_float_cvtd_s(); |
|
4601 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4602 |
opn = "cvt.d.s"; |
|
4603 |
break; |
|
4604 |
case FOP(36, 16): |
|
4605 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4606 |
gen_op_float_cvtw_s(); |
|
4607 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4608 |
opn = "cvt.w.s"; |
|
4609 |
break; |
|
4610 |
case FOP(37, 16): |
|
4611 |
CHECK_FR(ctx, fs | fd); |
|
4612 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4613 |
gen_op_float_cvtl_s(); |
|
4614 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4615 |
opn = "cvt.l.s"; |
|
4616 |
break; |
|
4617 |
case FOP(38, 16): |
|
4618 |
CHECK_FR(ctx, fs | ft | fd); |
|
4619 |
GEN_LOAD_FREG_FTN(WT1, fs); |
|
4620 |
GEN_LOAD_FREG_FTN(WT0, ft); |
|
4621 |
gen_op_float_cvtps_s(); |
|
4622 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4623 |
opn = "cvt.ps.s"; |
|
4624 |
break; |
|
4625 |
case FOP(48, 16): |
|
4626 |
case FOP(49, 16): |
|
4627 |
case FOP(50, 16): |
|
4628 |
case FOP(51, 16): |
|
4629 |
case FOP(52, 16): |
|
4630 |
case FOP(53, 16): |
|
4631 |
case FOP(54, 16): |
|
4632 |
case FOP(55, 16): |
|
4633 |
case FOP(56, 16): |
|
4634 |
case FOP(57, 16): |
|
4635 |
case FOP(58, 16): |
|
4636 |
case FOP(59, 16): |
|
4637 |
case FOP(60, 16): |
|
4638 |
case FOP(61, 16): |
|
4639 |
case FOP(62, 16): |
|
4640 |
case FOP(63, 16): |
|
4641 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4642 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4643 |
gen_cmp_s(func-48, cc); |
|
4644 |
opn = condnames[func-48]; |
|
4645 |
break; |
|
4363 | 4646 |
case FOP(0, 17): |
4364 | 4647 |
CHECK_FR(ctx, fs | ft | fd); |
4365 | 4648 |
GEN_LOAD_FREG_FTN(DT0, fs); |
... | ... | |
4424 | 4707 |
GEN_STORE_FTN_FREG(fd, DT2); |
4425 | 4708 |
opn = "neg.d"; |
4426 | 4709 |
break; |
4427 |
/* 8 - round.l */ |
|
4428 |
/* 9 - trunc.l */ |
|
4429 |
/* 10 - ceil.l */ |
|
4430 |
/* 11 - floor.l */ |
|
4710 |
case FOP(8, 17): |
|
4711 |
CHECK_FR(ctx, fs); |
|
4712 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4713 |
gen_op_float_roundl_d(); |
|
4714 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4715 |
opn = "round.l.d"; |
|
4716 |
break; |
|
4717 |
case FOP(9, 17): |
|
4718 |
CHECK_FR(ctx, fs); |
|
4719 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4720 |
gen_op_float_truncl_d(); |
|
4721 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4722 |
opn = "trunc.l.d"; |
|
4723 |
break; |
|
4724 |
case FOP(10, 17): |
|
4725 |
CHECK_FR(ctx, fs); |
|
4726 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4727 |
gen_op_float_ceill_d(); |
|
4728 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4729 |
opn = "ceil.l.d"; |
|
4730 |
break; |
|
4731 |
case FOP(11, 17): |
|
4732 |
CHECK_FR(ctx, fs); |
|
4733 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4734 |
gen_op_float_floorl_d(); |
|
4735 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4736 |
opn = "floor.l.d"; |
|
4737 |
break; |
|
4431 | 4738 |
case FOP(12, 17): |
4432 | 4739 |
CHECK_FR(ctx, fs); |
4433 | 4740 |
GEN_LOAD_FREG_FTN(DT0, fs); |
... | ... | |
4456 | 4763 |
GEN_STORE_FTN_FREG(fd, WT2); |
4457 | 4764 |
opn = "floor.w.d"; |
4458 | 4765 |
break; |
4459 |
case FOP(33, 16): |
|
4460 |
CHECK_FR(ctx, fd); |
|
4461 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4462 |
gen_op_float_cvtd_s(); |
|
4766 |
case FOP(17, 17): |
|
4767 |
GEN_LOAD_REG_TN(T0, ft); |
|
4768 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4769 |
GEN_LOAD_FREG_FTN(DT2, fd); |
|
4770 |
gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); |
|
4463 | 4771 |
GEN_STORE_FTN_FREG(fd, DT2); |
4464 |
opn = "cvt.d.s";
|
|
4772 |
opn = "movcf.d";
|
|
4465 | 4773 |
break; |
4466 |
case FOP(33, 20): |
|
4467 |
CHECK_FR(ctx, fd); |
|
4468 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4469 |
gen_op_float_cvtd_w(); |
|
4774 |
case FOP(18, 17): |
|
4775 |
GEN_LOAD_REG_TN(T0, ft); |
|
4776 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4777 |
GEN_LOAD_FREG_FTN(DT2, fd); |
|
4778 |
gen_op_float_movz_d(); |
|
4470 | 4779 |
GEN_STORE_FTN_FREG(fd, DT2); |
4471 |
opn = "cvt.d.w"; |
|
4780 |
opn = "movz.d"; |
|
4781 |
break; |
|
4782 |
case FOP(19, 17): |
|
4783 |
GEN_LOAD_REG_TN(T0, ft); |
|
4784 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4785 |
GEN_LOAD_FREG_FTN(DT2, fd); |
|
4786 |
gen_op_float_movn_d(); |
|
4787 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4788 |
opn = "movn.d"; |
|
4472 | 4789 |
break; |
4473 | 4790 |
case FOP(48, 17): |
4474 | 4791 |
case FOP(49, 17): |
... | ... | |
4489 | 4806 |
CHECK_FR(ctx, fs | ft); |
4490 | 4807 |
GEN_LOAD_FREG_FTN(DT0, fs); |
4491 | 4808 |
GEN_LOAD_FREG_FTN(DT1, ft); |
4492 |
gen_cmp_d(func-48); |
|
4809 |
gen_cmp_d(func-48, cc);
|
|
4493 | 4810 |
opn = condnames[func-48]; |
4494 | 4811 |
break; |
4495 |
case FOP(0, 16): |
|
4812 |
case FOP(32, 17): |
|
4813 |
CHECK_FR(ctx, fs); |
|
4814 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4815 |
gen_op_float_cvts_d(); |
|
4816 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4817 |
opn = "cvt.s.d"; |
|
4818 |
break; |
|
4819 |
case FOP(36, 17): |
|
4820 |
CHECK_FR(ctx, fs); |
|
4821 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4822 |
gen_op_float_cvtw_d(); |
|
4823 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4824 |
opn = "cvt.w.d"; |
|
4825 |
break; |
|
4826 |
case FOP(37, 17): |
|
4827 |
CHECK_FR(ctx, fs | fd); |
|
4828 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4829 |
gen_op_float_cvtl_d(); |
|
4830 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4831 |
opn = "cvt.l.d"; |
|
4832 |
break; |
|
4833 |
case FOP(32, 20): |
|
4496 | 4834 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4497 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4498 |
gen_op_float_add_s(); |
|
4835 |
gen_op_float_cvts_w(); |
|
4499 | 4836 |
GEN_STORE_FTN_FREG(fd, WT2); |
4500 |
opn = "add.s"; |
|
4501 |
binary = 1; |
|
4837 |
opn = "cvt.s.w"; |
|
4502 | 4838 |
break; |
4503 |
case FOP(1, 16): |
|
4839 |
case FOP(33, 20): |
|
4840 |
CHECK_FR(ctx, fd); |
|
4504 | 4841 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4842 |
gen_op_float_cvtd_w(); |
|
4843 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4844 |
opn = "cvt.d.w"; |
|
4845 |
break; |
|
4846 |
case FOP(32, 21): |
|
4847 |
CHECK_FR(ctx, fs); |
|
4848 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4849 |
gen_op_float_cvts_l(); |
|
4850 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4851 |
opn = "cvt.s.l"; |
|
4852 |
break; |
|
4853 |
case FOP(33, 21): |
|
4854 |
CHECK_FR(ctx, fs | fd); |
|
4855 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4856 |
gen_op_float_cvtd_l(); |
|
4857 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4858 |
opn = "cvt.d.l"; |
|
4859 |
break; |
|
4860 |
case FOP(38, 20): |
|
4861 |
case FOP(38, 21): |
|
4862 |
CHECK_FR(ctx, fs | fd); |
|
4863 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4864 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4865 |
gen_op_float_cvtps_pw(); |
|
4866 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4867 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4868 |
opn = "cvt.ps.pw"; |
|
4869 |
break; |
|
4870 |
case FOP(0, 22): |
|
4871 |
CHECK_FR(ctx, fs | ft | fd); |
|
4872 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4873 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4505 | 4874 |
GEN_LOAD_FREG_FTN(WT1, ft); |
4506 |
gen_op_float_sub_s(); |
|
4875 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
4876 |
gen_op_float_add_ps(); |
|
4507 | 4877 |
GEN_STORE_FTN_FREG(fd, WT2); |
4508 |
opn = "sub.s";
|
|
4509 |
binary = 1;
|
|
4878 |
GEN_STORE_FTN_FREG(fd, WTH2);
|
|
4879 |
opn = "add.ps";
|
|
4510 | 4880 |
break; |
4511 |
case FOP(2, 16): |
|
4881 |
case FOP(1, 22): |
|
4882 |
CHECK_FR(ctx, fs | ft | fd); |
|
4512 | 4883 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4884 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4513 | 4885 |
GEN_LOAD_FREG_FTN(WT1, ft); |
4514 |
gen_op_float_mul_s(); |
|
4886 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
4887 |
gen_op_float_sub_ps(); |
|
4515 | 4888 |
GEN_STORE_FTN_FREG(fd, WT2); |
4516 |
opn = "mul.s";
|
|
4517 |
binary = 1;
|
|
4889 |
GEN_STORE_FTN_FREG(fd, WTH2);
|
|
4890 |
opn = "sub.ps";
|
|
4518 | 4891 |
break; |
4519 |
case FOP(3, 16): |
|
4892 |
case FOP(2, 22): |
|
4893 |
CHECK_FR(ctx, fs | ft | fd); |
|
4520 | 4894 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4895 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4521 | 4896 |
GEN_LOAD_FREG_FTN(WT1, ft); |
4522 |
gen_op_float_div_s(); |
|
4897 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
4898 |
gen_op_float_mul_ps(); |
|
4523 | 4899 |
GEN_STORE_FTN_FREG(fd, WT2); |
4524 |
opn = "div.s";
|
|
4525 |
binary = 1;
|
|
4900 |
GEN_STORE_FTN_FREG(fd, WTH2);
|
|
4901 |
opn = "mul.ps";
|
|
4526 | 4902 |
break; |
4527 |
case FOP(4, 16): |
|
4903 |
case FOP(5, 22): |
|
4904 |
CHECK_FR(ctx, fs | fd); |
|
4528 | 4905 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4529 |
gen_op_float_sqrt_s(); |
|
4906 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4907 |
gen_op_float_abs_ps(); |
|
4530 | 4908 |
GEN_STORE_FTN_FREG(fd, WT2); |
4531 |
opn = "sqrt.s"; |
|
4909 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4910 |
opn = "abs.ps"; |
|
4532 | 4911 |
break; |
4533 |
case FOP(5, 16): |
|
4912 |
case FOP(6, 22): |
|
4913 |
CHECK_FR(ctx, fs | fd); |
|
4534 | 4914 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4535 |
gen_op_float_abs_s(); |
|
4915 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4916 |
gen_op_float_mov_ps(); |
|
4536 | 4917 |
GEN_STORE_FTN_FREG(fd, WT2); |
4537 |
opn = "abs.s"; |
|
4918 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4919 |
opn = "mov.ps"; |
|
4538 | 4920 |
break; |
4539 |
case FOP(6, 16): |
|
4921 |
case FOP(7, 22): |
|
4922 |
CHECK_FR(ctx, fs | fd); |
|
4540 | 4923 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4541 |
gen_op_float_mov_s(); |
|
4924 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4925 |
gen_op_float_chs_ps(); |
|
4542 | 4926 |
GEN_STORE_FTN_FREG(fd, WT2); |
4543 |
opn = "mov.s"; |
|
4927 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4928 |
opn = "neg.ps"; |
|
4544 | 4929 |
break; |
4545 |
case FOP(7, 16): |
|
4930 |
case FOP(17, 22): |
|
4931 |
GEN_LOAD_REG_TN(T0, ft); |
|
4546 | 4932 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4547 |
gen_op_float_chs_s(); |
|
4933 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4934 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4935 |
GEN_LOAD_FREG_FTN(WTH2, fd); |
|
4936 |
gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1); |
|
4548 | 4937 |
GEN_STORE_FTN_FREG(fd, WT2); |
4549 |
opn = "neg.s"; |
|
4938 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4939 |
opn = "movcf.ps"; |
|
4550 | 4940 |
break; |
4551 |
case FOP(12, 16): |
|
4941 |
case FOP(18, 22): |
|
4942 |
GEN_LOAD_REG_TN(T0, ft); |
|
4552 | 4943 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4553 |
gen_op_float_roundw_s(); |
|
4944 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4945 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4946 |
GEN_LOAD_FREG_FTN(WTH2, fd); |
|
4947 |
gen_op_float_movz_ps(); |
|
4554 | 4948 |
GEN_STORE_FTN_FREG(fd, WT2); |
4555 |
opn = "round.w.s"; |
|
4949 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4950 |
opn = "movz.ps"; |
|
4556 | 4951 |
break; |
4557 |
case FOP(13, 16): |
|
4952 |
case FOP(19, 22): |
|
4953 |
GEN_LOAD_REG_TN(T0, ft); |
|
4558 | 4954 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4559 |
gen_op_float_truncw_s(); |
|
4955 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4956 |
GEN_LOAD_FREG_FTN(WT2, fd); |
|
4957 |
GEN_LOAD_FREG_FTN(WTH2, fd); |
|
4958 |
gen_op_float_movn_ps(); |
|
4560 | 4959 |
GEN_STORE_FTN_FREG(fd, WT2); |
4561 |
opn = "trunc.w.s"; |
|
4960 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4961 |
opn = "movn.ps"; |
|
4562 | 4962 |
break; |
4563 |
case FOP(32, 17):
|
|
4963 |
case FOP(32, 22):
|
|
4564 | 4964 |
CHECK_FR(ctx, fs); |
4565 |
GEN_LOAD_FREG_FTN(DT0, fs);
|
|
4566 |
gen_op_float_cvts_d();
|
|
4965 |
GEN_LOAD_FREG_FTN(WTH0, fs);
|
|
4966 |
gen_op_float_cvts_pu();
|
|
4567 | 4967 |
GEN_STORE_FTN_FREG(fd, WT2); |
4568 |
opn = "cvt.s.d";
|
|
4968 |
opn = "cvt.s.pu";
|
|
4569 | 4969 |
break; |
4570 |
case FOP(32, 20): |
|
4970 |
case FOP(36, 22): |
|
4971 |
CHECK_FR(ctx, fs | fd); |
|
4571 | 4972 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4572 |
gen_op_float_cvts_w(); |
|
4973 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4974 |
gen_op_float_cvtpw_ps(); |
|
4573 | 4975 |
GEN_STORE_FTN_FREG(fd, WT2); |
4574 |
opn = "cvt.s.w"; |
|
4976 |
GEN_STORE_FTN_FREG(fd, WTH2); |
|
4977 |
opn = "cvt.pw.ps"; |
|
4575 | 4978 |
break; |
4576 |
case FOP(36, 16): |
|
4979 |
case FOP(40, 22): |
|
4980 |
CHECK_FR(ctx, fs); |
|
4577 | 4981 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4578 |
gen_op_float_cvtw_s();
|
|
4982 |
gen_op_float_cvts_pl();
|
|
4579 | 4983 |
GEN_STORE_FTN_FREG(fd, WT2); |
4580 |
opn = "cvt.w.s";
|
|
4984 |
opn = "cvt.s.pl";
|
|
4581 | 4985 |
break; |
4582 |
case FOP(36, 17): |
|
4583 |
CHECK_FR(ctx, fs); |
|
4584 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
4585 |
gen_op_float_cvtw_d(); |
|
4586 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
4587 |
opn = "cvt.w.d"; |
|
4986 |
case FOP(44, 22): |
|
4987 |
CHECK_FR(ctx, fs | ft | fd); |
|
4988 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
4989 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
4990 |
gen_op_float_pll_ps(); |
|
4991 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
4992 |
opn = "pll.ps"; |
|
4588 | 4993 |
break; |
4589 |
case FOP(48, 16): |
|
4590 |
case FOP(49, 16): |
|
4591 |
case FOP(50, 16): |
|
4592 |
case FOP(51, 16): |
|
4593 |
case FOP(52, 16): |
|
4594 |
case FOP(53, 16): |
|
4595 |
case FOP(54, 16): |
|
4596 |
case FOP(55, 16): |
|
4597 |
case FOP(56, 16): |
|
4598 |
case FOP(57, 16): |
|
4599 |
case FOP(58, 16): |
|
4600 |
case FOP(59, 16): |
|
4601 |
case FOP(60, 16): |
|
4602 |
case FOP(61, 16): |
|
4603 |
case FOP(62, 16): |
|
4604 |
case FOP(63, 16): |
|
4994 |
case FOP(45, 22): |
|
4995 |
CHECK_FR(ctx, fs | ft | fd); |
|
4605 | 4996 |
GEN_LOAD_FREG_FTN(WT0, fs); |
4997 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
4998 |
gen_op_float_plu_ps(); |
|
4999 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
5000 |
opn = "plu.ps"; |
|
5001 |
break; |
|
5002 |
case FOP(46, 22): |
|
5003 |
CHECK_FR(ctx, fs | ft | fd); |
|
5004 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
4606 | 5005 |
GEN_LOAD_FREG_FTN(WT1, ft); |
4607 |
gen_cmp_s(func-48); |
|
5006 |
gen_op_float_pul_ps(); |
|
5007 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
5008 |
opn = "pul.ps"; |
|
5009 |
break; |
|
5010 |
case FOP(47, 22): |
|
5011 |
CHECK_FR(ctx, fs | ft | fd); |
|
5012 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
5013 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
5014 |
gen_op_float_puu_ps(); |
|
5015 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
5016 |
opn = "puu.ps"; |
|
5017 |
break; |
|
5018 |
case FOP(48, 22): |
|
5019 |
case FOP(49, 22): |
|
5020 |
case FOP(50, 22): |
|
5021 |
case FOP(51, 22): |
|
5022 |
case FOP(52, 22): |
|
5023 |
case FOP(53, 22): |
|
5024 |
case FOP(54, 22): |
|
5025 |
case FOP(55, 22): |
|
5026 |
case FOP(56, 22): |
|
5027 |
case FOP(57, 22): |
|
5028 |
case FOP(58, 22): |
|
5029 |
case FOP(59, 22): |
|
5030 |
case FOP(60, 22): |
|
5031 |
case FOP(61, 22): |
|
5032 |
case FOP(62, 22): |
|
5033 |
case FOP(63, 22): |
|
5034 |
CHECK_FR(ctx, fs | ft); |
|
5035 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
5036 |
GEN_LOAD_FREG_FTN(WTH0, fs); |
|
5037 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
5038 |
GEN_LOAD_FREG_FTN(WTH1, ft); |
|
5039 |
gen_cmp_ps(func-48, cc); |
|
4608 | 5040 |
opn = condnames[func-48]; |
4609 | 5041 |
break; |
4610 |
default:
|
|
5042 |
default: |
|
4611 | 5043 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
4612 | 5044 |
fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", |
4613 | 5045 |
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, |
... | ... | |
4622 | 5054 |
MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); |
4623 | 5055 |
} |
4624 | 5056 |
|
4625 |
static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) |
|
5057 |
/* Coprocessor 3 (FPU) */ |
|
5058 |
static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, |
|
5059 |
int base, int index) |
|
4626 | 5060 |
{ |
4627 |
uint32_t ccbit;
|
|
5061 |
const char *opn = "unk";
|
|
4628 | 5062 |
|
4629 |
if (cc) |
|
4630 |
ccbit = 1 << (24 + cc); |
|
4631 |
else |
|
4632 |
ccbit = 1 << 23; |
|
4633 |
if (!tf) |
|
4634 |
gen_op_movf(ccbit, rd, rs); |
|
4635 |
else |
|
4636 |
gen_op_movt(ccbit, rd, rs); |
|
5063 |
GEN_LOAD_REG_TN(T0, base); |
|
5064 |
GEN_LOAD_REG_TN(T1, index); |
|
5065 |
/* Don't do NOP if destination is zero: we must perform the actual |
|
5066 |
* memory access |
|
5067 |
*/ |
|
5068 |
switch (opc) { |
|
5069 |
case OPC_LWXC1: |
|
5070 |
op_ldst(lwxc1); |
|
5071 |
GEN_STORE_FTN_FREG(fd, WT0); |
|
5072 |
opn = "lwxc1"; |
|
5073 |
break; |
|
5074 |
case OPC_LDXC1: |
|
5075 |
op_ldst(ldxc1); |
|
5076 |
GEN_STORE_FTN_FREG(fd, DT0); |
|
5077 |
opn = "ldxc1"; |
|
5078 |
break; |
|
5079 |
case OPC_LUXC1: |
|
5080 |
op_ldst(luxc1); |
|
5081 |
GEN_STORE_FTN_FREG(fd, DT0); |
|
5082 |
opn = "luxc1"; |
|
5083 |
break; |
|
5084 |
case OPC_SWXC1: |
|
5085 |
GEN_LOAD_FREG_FTN(WT0, fd); |
|
5086 |
op_ldst(swxc1); |
|
5087 |
opn = "swxc1"; |
|
5088 |
break; |
|
5089 |
case OPC_SDXC1: |
|
5090 |
GEN_LOAD_FREG_FTN(DT0, fd); |
|
5091 |
op_ldst(sdxc1); |
|
5092 |
opn = "sdxc1"; |
|
5093 |
break; |
|
5094 |
case OPC_SUXC1: |
|
5095 |
GEN_LOAD_FREG_FTN(DT0, fd); |
|
5096 |
op_ldst(suxc1); |
|
5097 |
opn = "suxc1"; |
|
5098 |
break; |
|
5099 |
default: |
|
5100 |
MIPS_INVAL("extended float load/store"); |
|
5101 |
generate_exception(ctx, EXCP_RI); |
|
5102 |
return; |
|
5103 |
} |
|
5104 |
MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]); |
|
5105 |
} |
|
5106 |
|
|
5107 |
static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, |
|
5108 |
int fr, int fs, int ft) |
|
5109 |
{ |
|
5110 |
const char *opn = "unk"; |
|
5111 |
|
|
5112 |
/* All of those work only on 64bit FPUs. */ |
|
5113 |
CHECK_FR(ctx, fd | fr | fs | ft); |
|
5114 |
switch (opc) { |
|
5115 |
case OPC_ALNV_PS: |
|
5116 |
GEN_LOAD_REG_TN(T0, fr); |
|
5117 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
5118 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
5119 |
gen_op_float_alnv_ps(); |
|
5120 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
5121 |
opn = "alnv.ps"; |
|
5122 |
break; |
|
5123 |
case OPC_MADD_S: |
|
5124 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
5125 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
5126 |
GEN_LOAD_FREG_FTN(WT2, fr); |
|
5127 |
gen_op_float_muladd_s(); |
|
5128 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
5129 |
opn = "madd.s"; |
|
5130 |
break; |
|
5131 |
case OPC_MADD_D: |
|
5132 |
generate_exception (ctx, EXCP_RI); |
|
5133 |
opn = "madd.d"; |
|
5134 |
break; |
|
5135 |
case OPC_MADD_PS: |
|
5136 |
generate_exception (ctx, EXCP_RI); |
|
5137 |
opn = "madd.ps"; |
|
5138 |
break; |
|
5139 |
case OPC_MSUB_S: |
|
5140 |
generate_exception (ctx, EXCP_RI); |
|
5141 |
opn = "msub.s"; |
|
5142 |
break; |
|
5143 |
case OPC_MSUB_D: |
|
5144 |
generate_exception (ctx, EXCP_RI); |
|
5145 |
opn = "msub.d"; |
|
5146 |
break; |
|
5147 |
case OPC_MSUB_PS: |
|
5148 |
generate_exception (ctx, EXCP_RI); |
|
5149 |
opn = "msub.ps"; |
|
5150 |
break; |
|
5151 |
case OPC_NMADD_S: |
|
5152 |
generate_exception (ctx, EXCP_RI); |
|
5153 |
opn = "nmadd.s"; |
|
5154 |
break; |
|
5155 |
case OPC_NMADD_D: |
|
5156 |
generate_exception (ctx, EXCP_RI); |
|
5157 |
opn = "nmadd.d"; |
|
5158 |
break; |
|
5159 |
case OPC_NMADD_PS: |
|
5160 |
generate_exception (ctx, EXCP_RI); |
|
5161 |
opn = "nmadd.ps"; |
|
5162 |
break; |
|
5163 |
case OPC_NMSUB_S: |
|
5164 |
generate_exception (ctx, EXCP_RI); |
|
5165 |
opn = "nmsub.s"; |
|
5166 |
break; |
|
5167 |
case OPC_NMSUB_D: |
|
5168 |
generate_exception (ctx, EXCP_RI); |
|
5169 |
opn = "nmsub.d"; |
|
5170 |
break; |
|
5171 |
case OPC_NMSUB_PS: |
|
5172 |
generate_exception (ctx, EXCP_RI); |
|
5173 |
opn = "nmsub.ps"; |
|
5174 |
break; |
|
5175 |
default: |
|
5176 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
|
5177 |
fprintf(logfile, "Invalid extended FP arith function: %08x %03x %03x\n", |
|
5178 |
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F); |
|
5179 |
} |
|
5180 |
generate_exception (ctx, EXCP_RI); |
|
5181 |
return; |
|
5182 |
} |
|
5183 |
MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr], |
|
5184 |
fregnames[fs], fregnames[ft]); |
|
4637 | 5185 |
} |
4638 | 5186 |
|
4639 | 5187 |
/* ISA extensions (ASEs) */ |
... | ... | |
4641 | 5189 |
/* SmartMIPS extension to MIPS32 */ |
4642 | 5190 |
|
4643 | 5191 |
#ifdef TARGET_MIPS64 |
4644 |
/* Coprocessor 3 (FPU) */ |
|
4645 | 5192 |
|
4646 | 5193 |
/* MDMX extension to MIPS64 */ |
4647 | 5194 |
/* MIPS-3D extension to MIPS64 */ |
4648 | 5195 |
|
4649 | 5196 |
#endif |
4650 | 5197 |
|
4651 |
static void gen_blikely(DisasContext *ctx) |
|
4652 |
{ |
|
4653 |
int l1; |
|
4654 |
l1 = gen_new_label(); |
|
4655 |
gen_op_jnz_T2(l1); |
|
4656 |
gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); |
|
4657 |
gen_goto_tb(ctx, 1, ctx->pc + 4); |
|
4658 |
gen_set_label(l1); |
|
4659 |
} |
|
4660 |
|
|
4661 | 5198 |
static void decode_opc (CPUState *env, DisasContext *ctx) |
4662 | 5199 |
{ |
4663 | 5200 |
int32_t offset; |
... | ... | |
4673 | 5210 |
} |
4674 | 5211 |
|
4675 | 5212 |
if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { |
5213 |
int l1; |
|
4676 | 5214 |
/* Handle blikely not taken case */ |
4677 | 5215 |
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); |
4678 |
gen_blikely(ctx); |
|
5216 |
l1 = gen_new_label(); |
|
5217 |
gen_op_jnz_T2(l1); |
|
5218 |
gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); |
|
5219 |
gen_goto_tb(ctx, 1, ctx->pc + 4); |
|
5220 |
gen_set_label(l1); |
|
4679 | 5221 |
} |
4680 | 5222 |
op = MASK_OP_MAJOR(ctx->opcode); |
4681 | 5223 |
rs = (ctx->opcode >> 21) & 0x1f; |
... | ... | |
5024 | 5566 |
case OPC_DMFC1: |
5025 | 5567 |
case OPC_DMTC1: |
5026 | 5568 |
#endif |
5569 |
case OPC_MFHC1: |
|
5570 |
case OPC_MTHC1: |
|
5027 | 5571 |
gen_cp1(ctx, op1, rt, rd); |
5028 | 5572 |
break; |
5029 | 5573 |
case OPC_BC1: |
5030 |
gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); |
|
5574 |
gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), |
|
5575 |
(rt >> 2) & 0x7, imm << 2); |
|
5031 | 5576 |
return; |
5032 | 5577 |
case OPC_S_FMT: |
5033 | 5578 |
case OPC_D_FMT: |
5034 | 5579 |
case OPC_W_FMT: |
5035 | 5580 |
case OPC_L_FMT: |
5036 |
gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); |
|
5581 |
case OPC_PS_FMT: |
|
5582 |
gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa, |
|
5583 |
(imm >> 8) & 0x7); |
|
5037 | 5584 |
break; |
5038 | 5585 |
default: |
5039 | 5586 |
generate_exception (ctx, EXCP_RI); |
... | ... | |
5060 | 5607 |
gen_op_cp1_enabled(); |
5061 | 5608 |
op1 = MASK_CP3(ctx->opcode); |
5062 | 5609 |
switch (op1) { |
5610 |
case OPC_LWXC1: |
|
5611 |
case OPC_LDXC1: |
|
5612 |
case OPC_LUXC1: |
|
5613 |
case OPC_SWXC1: |
|
5614 |
case OPC_SDXC1: |
|
5615 |
case OPC_SUXC1: |
|
5616 |
gen_flt3_ldst(ctx, op1, sa, rs, rt); |
|
5617 |
break; |
|
5063 | 5618 |
case OPC_PREFX: |
5064 | 5619 |
/* treat as noop */ |
5065 | 5620 |
break; |
5066 |
/* Not implemented */ |
|
5621 |
case OPC_ALNV_PS: |
|
5622 |
case OPC_MADD_S: |
|
5623 |
case OPC_MADD_D: |
|
5624 |
case OPC_MADD_PS: |
|
5625 |
case OPC_MSUB_S: |
|
5626 |
case OPC_MSUB_D: |
|
5627 |
case OPC_MSUB_PS: |
|
5628 |
case OPC_NMADD_S: |
|
5629 |
case OPC_NMADD_D: |
|
5630 |
case OPC_NMADD_PS: |
|
5631 |
case OPC_NMSUB_S: |
|
5632 |
case OPC_NMSUB_D: |
|
5633 |
case OPC_NMSUB_PS: |
|
5634 |
gen_flt3_arith(ctx, op1, sa, rs, rd, rt); |
|
5635 |
break; |
|
5067 | 5636 |
default: |
5068 | 5637 |
generate_exception (ctx, EXCP_RI); |
5069 | 5638 |
break; |
... | ... | |
5107 | 5676 |
ctx->hflags &= ~MIPS_HFLAG_BMASK; |
5108 | 5677 |
ctx->bstate = BS_BRANCH; |
5109 | 5678 |
save_cpu_state(ctx, 0); |
5110 |
switch (hflags & MIPS_HFLAG_BMASK) {
|
|
5679 |
switch (hflags) { |
|
5111 | 5680 |
case MIPS_HFLAG_B: |
5112 | 5681 |
/* unconditional branch */ |
5113 | 5682 |
MIPS_DEBUG("unconditional branch"); |
... | ... | |
5134 | 5703 |
/* unconditional branch to register */ |
5135 | 5704 |
MIPS_DEBUG("branch to register"); |
5136 | 5705 |
gen_op_breg(); |
5706 |
gen_op_reset_T0(); |
|
5707 |
gen_op_exit_tb(); |
|
5137 | 5708 |
break; |
5138 | 5709 |
default: |
5139 | 5710 |
MIPS_DEBUG("unknown branch"); |
... | ... | |
5166 | 5737 |
/* Restore delay slot state from the tb context. */ |
5167 | 5738 |
ctx.hflags = tb->flags; |
5168 | 5739 |
ctx.saved_hflags = ctx.hflags; |
5169 |
if (ctx.hflags & MIPS_HFLAG_BR) { |
|
5740 |
switch (ctx.hflags & MIPS_HFLAG_BMASK) { |
|
5741 |
case MIPS_HFLAG_BR: |
|
5170 | 5742 |
gen_op_restore_breg_target(); |
5171 |
} else if (ctx.hflags & MIPS_HFLAG_B) { |
|
5743 |
break; |
|
5744 |
case MIPS_HFLAG_B: |
|
5172 | 5745 |
ctx.btarget = env->btarget; |
5173 |
} else if (ctx.hflags & MIPS_HFLAG_BMASK) { |
|
5174 |
/* If we are in the delay slot of a conditional branch, |
|
5175 |
* restore the branch condition from env->bcond to T2 |
|
5176 |
*/ |
|
5746 |
break; |
|
5747 |
case MIPS_HFLAG_BC: |
|
5748 |
case MIPS_HFLAG_BL: |
|
5177 | 5749 |
ctx.btarget = env->btarget; |
5178 | 5750 |
gen_op_restore_bcond(); |
5751 |
break; |
|
5179 | 5752 |
} |
5180 | 5753 |
#if defined(CONFIG_USER_ONLY) |
5181 | 5754 |
ctx.mem_idx = 0; |
... | ... | |
5237 | 5810 |
gen_op_debug(); |
5238 | 5811 |
} else { |
5239 | 5812 |
switch (ctx.bstate) { |
5240 |
case BS_EXCP: |
|
5241 |
gen_op_interrupt_restart(); |
|
5242 |
gen_op_reset_T0(); |
|
5243 |
/* Generate the return instruction. */ |
|
5244 |
gen_op_exit_tb(); |
|
5245 |
break; |
|
5246 | 5813 |
case BS_STOP: |
5247 | 5814 |
gen_op_interrupt_restart(); |
5248 | 5815 |
/* Fall through. */ |
... | ... | |
5250 | 5817 |
save_cpu_state(ctxp, 0); |
5251 | 5818 |
gen_goto_tb(&ctx, 0, ctx.pc); |
5252 | 5819 |
break; |
5253 |
case BS_BRANCH:
|
|
5254 |
default:
|
|
5820 |
case BS_EXCP:
|
|
5821 |
gen_op_interrupt_restart();
|
|
5255 | 5822 |
gen_op_reset_T0(); |
5256 |
/* Generate the return instruction. */ |
|
5257 | 5823 |
gen_op_exit_tb(); |
5258 | 5824 |
break; |
5825 |
case BS_BRANCH: |
|
5826 |
default: |
|
5827 |
break; |
|
5259 | 5828 |
} |
5260 | 5829 |
} |
5261 | 5830 |
done_generating: |
... | ... | |
5307 | 5876 |
int flags) |
5308 | 5877 |
{ |
5309 | 5878 |
int i; |
5310 |
|
|
5311 |
# define printfpr(fp) do { \ |
|
5312 |
fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \ |
|
5313 |
(fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \ |
|
5879 |
int is_fpu64 = !!(env->CP0_Status & (1 << CP0St_FR)); |
|
5880 |
|
|
5881 |
#define printfpr(fp) \ |
|
5882 |
do { \ |
|
5883 |
if (is_fpu64) \ |
|
5884 |
fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \ |
|
5885 |
(fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \ |
|
5886 |
(fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \ |
|
5887 |
else { \ |
|
5888 |
fpr_t tmp; \ |
|
5889 |
tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ |
|
5890 |
tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ |
|
5891 |
fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \ |
|
5892 |
tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \ |
|
5893 |
tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \ |
|
5894 |
} \ |
|
5314 | 5895 |
} while(0) |
5315 | 5896 |
|
5316 |
fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", |
|
5317 |
env->fcr0, env->fcr31,
|
|
5318 |
(env->CP0_Status & (1 << CP0St_FR)) != 0);
|
|
5897 |
|
|
5898 |
fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n",
|
|
5899 |
env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status));
|
|
5319 | 5900 |
fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); |
5320 | 5901 |
fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); |
5321 | 5902 |
fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); |
5322 |
for(i = 0; i < 32; i += 2) {
|
|
5323 |
fpu_fprintf(f, "%s: ", fregnames[i]); |
|
5324 |
printfpr(FPR(env, i));
|
|
5903 |
for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
|
|
5904 |
fpu_fprintf(f, "%3s: ", fregnames[i]);
|
|
5905 |
printfpr(&env->fpr[i]);
|
|
5325 | 5906 |
} |
5326 | 5907 |
|
5327 | 5908 |
#undef printfpr |
Also available in: Unified diff