Revision 6ea83fed target-mips/translate.c
b/target-mips/translate.c | ||
---|---|---|
2 | 2 |
* MIPS32 emulation for qemu: main translation routines. |
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2004-2005 Jocelyn Mayer |
5 |
* Copyright (c) 2006 Marius Groeger (FPU operations) |
|
5 | 6 |
* |
6 | 7 |
* This library is free software; you can redistribute it and/or |
7 | 8 |
* modify it under the terms of the GNU Lesser General Public |
... | ... | |
217 | 218 |
OPC_WAIT = 0x20 | EXT_CP0, |
218 | 219 |
}; |
219 | 220 |
|
221 |
#ifdef MIPS_USES_FPU |
|
222 |
enum { |
|
223 |
/* Coprocessor 1 (FPU) */ |
|
224 |
OPC_MFC1 = 0x00 | EXT_CP1, |
|
225 |
OPC_MTC1 = 0x04 | EXT_CP1, |
|
226 |
OPC_CFC1 = 0x02 | EXT_CP1, |
|
227 |
OPC_CTC1 = 0x06 | EXT_CP1, |
|
228 |
}; |
|
229 |
#endif |
|
230 |
|
|
220 | 231 |
const unsigned char *regnames[] = |
221 | 232 |
{ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
222 | 233 |
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
... | ... | |
248 | 259 |
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); |
249 | 260 |
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); |
250 | 261 |
|
262 |
#ifdef MIPS_USES_FPU |
|
263 |
const unsigned char *fregnames[] = |
|
264 |
{ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
|
265 |
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
|
266 |
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
|
267 |
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; |
|
268 |
|
|
269 |
# define SFGEN32(func, NAME) \ |
|
270 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
271 |
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ |
|
272 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ |
|
273 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ |
|
274 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ |
|
275 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ |
|
276 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ |
|
277 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ |
|
278 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ |
|
279 |
}; \ |
|
280 |
static inline void func(int n) \ |
|
281 |
{ \ |
|
282 |
NAME ## _table[n](); \ |
|
283 |
} |
|
284 |
|
|
285 |
# define DFGEN32(func, NAME) \ |
|
286 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
287 |
NAME ## 0, 0, NAME ## 2, 0, \ |
|
288 |
NAME ## 4, 0, NAME ## 6, 0, \ |
|
289 |
NAME ## 8, 0, NAME ## 10, 0, \ |
|
290 |
NAME ## 12, 0, NAME ## 14, 0, \ |
|
291 |
NAME ## 16, 0, NAME ## 18, 0, \ |
|
292 |
NAME ## 20, 0, NAME ## 22, 0, \ |
|
293 |
NAME ## 24, 0, NAME ## 26, 0, \ |
|
294 |
NAME ## 28, 0, NAME ## 30, 0, \ |
|
295 |
}; \ |
|
296 |
static inline void func(int n) \ |
|
297 |
{ \ |
|
298 |
NAME ## _table[n](); \ |
|
299 |
} |
|
300 |
|
|
301 |
SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); |
|
302 |
SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); |
|
303 |
|
|
304 |
SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); |
|
305 |
SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); |
|
306 |
|
|
307 |
SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); |
|
308 |
SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); |
|
309 |
|
|
310 |
DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); |
|
311 |
DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); |
|
312 |
|
|
313 |
DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); |
|
314 |
DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); |
|
315 |
|
|
316 |
DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); |
|
317 |
DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); |
|
318 |
|
|
319 |
#define FOP_CONDS(fmt) \ |
|
320 |
static GenOpFunc * cond_ ## fmt ## _table[16] = { \ |
|
321 |
gen_op_cmp_ ## fmt ## _f, \ |
|
322 |
gen_op_cmp_ ## fmt ## _un, \ |
|
323 |
gen_op_cmp_ ## fmt ## _eq, \ |
|
324 |
gen_op_cmp_ ## fmt ## _ueq, \ |
|
325 |
gen_op_cmp_ ## fmt ## _olt, \ |
|
326 |
gen_op_cmp_ ## fmt ## _ult, \ |
|
327 |
gen_op_cmp_ ## fmt ## _ole, \ |
|
328 |
gen_op_cmp_ ## fmt ## _ule, \ |
|
329 |
gen_op_cmp_ ## fmt ## _sf, \ |
|
330 |
gen_op_cmp_ ## fmt ## _ngle, \ |
|
331 |
gen_op_cmp_ ## fmt ## _seq, \ |
|
332 |
gen_op_cmp_ ## fmt ## _ngl, \ |
|
333 |
gen_op_cmp_ ## fmt ## _lt, \ |
|
334 |
gen_op_cmp_ ## fmt ## _nge, \ |
|
335 |
gen_op_cmp_ ## fmt ## _le, \ |
|
336 |
gen_op_cmp_ ## fmt ## _ngt, \ |
|
337 |
}; \ |
|
338 |
static inline void gen_cmp_ ## fmt(int n) \ |
|
339 |
{ \ |
|
340 |
cond_ ## fmt ## _table[n](); \ |
|
341 |
} |
|
342 |
|
|
343 |
FOP_CONDS(d) |
|
344 |
FOP_CONDS(s) |
|
345 |
|
|
346 |
#endif |
|
347 |
|
|
251 | 348 |
typedef struct DisasContext { |
252 | 349 |
struct TranslationBlock *tb; |
253 | 350 |
target_ulong pc, saved_pc; |
... | ... | |
312 | 409 |
} \ |
313 | 410 |
} while (0) |
314 | 411 |
|
412 |
#ifdef MIPS_USES_FPU |
|
413 |
|
|
414 |
# define GEN_LOAD_FREG_FTN(FTn, Fn) \ |
|
415 |
do { \ |
|
416 |
glue(gen_op_load_fpr_, FTn)(Fn); \ |
|
417 |
} while (0) |
|
418 |
|
|
419 |
#define GEN_STORE_FTN_FREG(Fn, FTn) \ |
|
420 |
do { \ |
|
421 |
glue(gen_op_store_fpr_, FTn)(Fn); \ |
|
422 |
} while (0) |
|
423 |
|
|
424 |
#endif |
|
425 |
|
|
315 | 426 |
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) |
316 | 427 |
{ |
317 | 428 |
#if defined MIPS_DEBUG_DISAS |
... | ... | |
397 | 508 |
OP_ST_TABLE(b); |
398 | 509 |
OP_LD_TABLE(l); |
399 | 510 |
OP_ST_TABLE(c); |
511 |
#ifdef MIPS_USES_FPU |
|
512 |
OP_LD_TABLE(wc1); |
|
513 |
OP_ST_TABLE(wc1); |
|
514 |
OP_LD_TABLE(dc1); |
|
515 |
OP_ST_TABLE(dc1); |
|
516 |
#endif |
|
400 | 517 |
|
401 | 518 |
/* Load and store */ |
402 | 519 |
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, |
... | ... | |
551 | 668 |
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); |
552 | 669 |
} |
553 | 670 |
|
671 |
#ifdef MIPS_USES_FPU |
|
672 |
|
|
673 |
/* Load and store */ |
|
674 |
static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, |
|
675 |
int base, int16_t offset) |
|
676 |
{ |
|
677 |
const unsigned char *opn = "unk"; |
|
678 |
|
|
679 |
if (base == 0) { |
|
680 |
GEN_LOAD_IMM_TN(T0, offset); |
|
681 |
} else if (offset == 0) { |
|
682 |
gen_op_load_gpr_T0(base); |
|
683 |
} else { |
|
684 |
gen_op_load_gpr_T0(base); |
|
685 |
gen_op_set_T1(offset); |
|
686 |
gen_op_add(); |
|
687 |
} |
|
688 |
/* Don't do NOP if destination is zero: we must perform the actual |
|
689 |
* memory access |
|
690 |
*/ |
|
691 |
switch (opc) { |
|
692 |
case OPC_LWC1: |
|
693 |
op_ldst(lwc1); |
|
694 |
GEN_STORE_FTN_FREG(ft, WT0); |
|
695 |
opn = "lwc1"; |
|
696 |
break; |
|
697 |
case OPC_SWC1: |
|
698 |
GEN_LOAD_FREG_FTN(WT0, ft); |
|
699 |
op_ldst(swc1); |
|
700 |
opn = "swc1"; |
|
701 |
break; |
|
702 |
case OPC_LDC1: |
|
703 |
op_ldst(ldc1); |
|
704 |
GEN_STORE_FTN_FREG(ft, DT0); |
|
705 |
opn = "ldc1"; |
|
706 |
break; |
|
707 |
case OPC_SDC1: |
|
708 |
GEN_LOAD_FREG_FTN(DT0, ft); |
|
709 |
op_ldst(sdc1); |
|
710 |
opn = "sdc1"; |
|
711 |
break; |
|
712 |
default: |
|
713 |
MIPS_INVAL("float load/store"); |
|
714 |
generate_exception(ctx, EXCP_CpU); |
|
715 |
return; |
|
716 |
} |
|
717 |
MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); |
|
718 |
} |
|
719 |
#endif |
|
720 |
|
|
554 | 721 |
/* Arithmetic with immediate operand */ |
555 | 722 |
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, |
556 | 723 |
int rs, int16_t imm) |
... | ... | |
1265 | 1432 |
MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); |
1266 | 1433 |
} |
1267 | 1434 |
|
1435 |
#ifdef MIPS_USES_FPU |
|
1436 |
/* CP1 Branches (before delay slot) */ |
|
1437 |
static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, |
|
1438 |
int32_t offset) |
|
1439 |
{ |
|
1440 |
target_ulong btarget; |
|
1441 |
|
|
1442 |
btarget = ctx->pc + 4 + offset; |
|
1443 |
|
|
1444 |
switch (cond) { |
|
1445 |
case 0x0000: /* bc1f */ |
|
1446 |
gen_op_bc1f(); |
|
1447 |
MIPS_DEBUG("bc1f %08x", btarget); |
|
1448 |
goto not_likely; |
|
1449 |
case 0x0002: /* bc1fl */ |
|
1450 |
gen_op_bc1f(); |
|
1451 |
MIPS_DEBUG("bc1fl %08x", btarget); |
|
1452 |
goto likely; |
|
1453 |
case 0x0001: /* bc1t */ |
|
1454 |
gen_op_bc1t(); |
|
1455 |
MIPS_DEBUG("bc1t %08x", btarget); |
|
1456 |
not_likely: |
|
1457 |
ctx->hflags |= MIPS_HFLAG_BC; |
|
1458 |
break; |
|
1459 |
case 0x0003: /* bc1tl */ |
|
1460 |
gen_op_bc1t(); |
|
1461 |
MIPS_DEBUG("bc1tl %08x", btarget); |
|
1462 |
likely: |
|
1463 |
ctx->hflags |= MIPS_HFLAG_BL; |
|
1464 |
break; |
|
1465 |
default: |
|
1466 |
MIPS_INVAL("cp1 branch/jump"); |
|
1467 |
generate_exception(ctx, EXCP_RI); |
|
1468 |
return; |
|
1469 |
} |
|
1470 |
gen_op_set_bcond(); |
|
1471 |
|
|
1472 |
MIPS_DEBUG("enter ds: cond %02x target %08x", |
|
1473 |
ctx->hflags, btarget); |
|
1474 |
ctx->btarget = btarget; |
|
1475 |
|
|
1476 |
return; |
|
1477 |
} |
|
1478 |
|
|
1268 | 1479 |
/* Coprocessor 1 (FPU) */ |
1480 |
static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) |
|
1481 |
{ |
|
1482 |
const unsigned char *opn = "unk"; |
|
1483 |
|
|
1484 |
switch (opc) { |
|
1485 |
case OPC_MFC1: |
|
1486 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1487 |
gen_op_mfc1(); |
|
1488 |
GEN_STORE_TN_REG(rt, T0); |
|
1489 |
opn = "mfc1"; |
|
1490 |
break; |
|
1491 |
case OPC_MTC1: |
|
1492 |
GEN_LOAD_REG_TN(T0, rt); |
|
1493 |
gen_op_mtc1(); |
|
1494 |
GEN_STORE_FTN_FREG(fs, WT0); |
|
1495 |
opn = "mtc1"; |
|
1496 |
break; |
|
1497 |
case OPC_CFC1: |
|
1498 |
if (fs != 0 && fs != 31) { |
|
1499 |
MIPS_INVAL("cfc1 freg"); |
|
1500 |
generate_exception(ctx, EXCP_RI); |
|
1501 |
return; |
|
1502 |
} |
|
1503 |
GEN_LOAD_IMM_TN(T1, fs); |
|
1504 |
gen_op_cfc1(); |
|
1505 |
GEN_STORE_TN_REG(rt, T0); |
|
1506 |
opn = "cfc1"; |
|
1507 |
break; |
|
1508 |
case OPC_CTC1: |
|
1509 |
if (fs != 0 && fs != 31) { |
|
1510 |
MIPS_INVAL("ctc1 freg"); |
|
1511 |
generate_exception(ctx, EXCP_RI); |
|
1512 |
return; |
|
1513 |
} |
|
1514 |
GEN_LOAD_IMM_TN(T1, fs); |
|
1515 |
GEN_LOAD_REG_TN(T0, rt); |
|
1516 |
gen_op_ctc1(); |
|
1517 |
opn = "ctc1"; |
|
1518 |
break; |
|
1519 |
default: |
|
1520 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
|
1521 |
fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", |
|
1522 |
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, |
|
1523 |
((ctx->opcode >> 16) & 0x1F)); |
|
1524 |
} |
|
1525 |
generate_exception(ctx, EXCP_RI); |
|
1526 |
return; |
|
1527 |
} |
|
1528 |
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); |
|
1529 |
} |
|
1530 |
|
|
1531 |
/* verify if floating point register is valid; an operation is not defined |
|
1532 |
* if bit 0 of any register specification is set and the FR bit in the |
|
1533 |
* Status register equals zero, since the register numbers specify an |
|
1534 |
* even-odd pair of adjacent coprocessor general registers. When the FR bit |
|
1535 |
* in the Status register equals one, both even and odd register numbers |
|
1536 |
* are valid. |
|
1537 |
* |
|
1538 |
* Multiple float registers can be checked by calling |
|
1539 |
* CHECK_FR(ctx, freg1 | freg2 | ... | fregN); |
|
1540 |
*/ |
|
1541 |
#define CHECK_FR(ctx, freg) do { \ |
|
1542 |
if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \ |
|
1543 |
generate_exception(ctx, EXCP_RI); \ |
|
1544 |
return; \ |
|
1545 |
} \ |
|
1546 |
} while(0) |
|
1547 |
|
|
1548 |
#define FOP(func, fmt) (((fmt) << 21) | (func)) |
|
1549 |
|
|
1550 |
static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func) |
|
1551 |
{ |
|
1552 |
const unsigned char *opn = "unk"; |
|
1553 |
const char *condnames[] = { |
|
1554 |
"c.f", |
|
1555 |
"c.un", |
|
1556 |
"c.eq", |
|
1557 |
"c.ueq", |
|
1558 |
"c.olt", |
|
1559 |
"c.ult", |
|
1560 |
"c.ole", |
|
1561 |
"c.ule", |
|
1562 |
"c.sf", |
|
1563 |
"c.ngle", |
|
1564 |
"c.seq", |
|
1565 |
"c.ngl", |
|
1566 |
"c.lt", |
|
1567 |
"c.nge", |
|
1568 |
"c.le", |
|
1569 |
"c.ngt", |
|
1570 |
}; |
|
1571 |
int binary = 0; |
|
1572 |
|
|
1573 |
switch (ctx->opcode & FOP(0x3f, 0x1f)) { |
|
1574 |
case FOP(0, 17): |
|
1575 |
CHECK_FR(ctx, fs | ft | fd); |
|
1576 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1577 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1578 |
gen_op_float_add_d(); |
|
1579 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1580 |
opn = "add.d"; |
|
1581 |
binary = 1; |
|
1582 |
break; |
|
1583 |
case FOP(1, 17): |
|
1584 |
CHECK_FR(ctx, fs | ft | fd); |
|
1585 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1586 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1587 |
gen_op_float_sub_d(); |
|
1588 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1589 |
opn = "sub.d"; |
|
1590 |
binary = 1; |
|
1591 |
break; |
|
1592 |
case FOP(2, 17): |
|
1593 |
CHECK_FR(ctx, fs | ft | fd); |
|
1594 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1595 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1596 |
gen_op_float_mul_d(); |
|
1597 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1598 |
opn = "mul.d"; |
|
1599 |
binary = 1; |
|
1600 |
break; |
|
1601 |
case FOP(3, 17): |
|
1602 |
CHECK_FR(ctx, fs | ft | fd); |
|
1603 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1604 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1605 |
gen_op_float_div_d(); |
|
1606 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1607 |
opn = "div.d"; |
|
1608 |
binary = 1; |
|
1609 |
break; |
|
1610 |
case FOP(4, 17): |
|
1611 |
CHECK_FR(ctx, fs | fd); |
|
1612 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1613 |
gen_op_float_sqrt_d(); |
|
1614 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1615 |
opn = "sqrt.d"; |
|
1616 |
break; |
|
1617 |
case FOP(5, 17): |
|
1618 |
CHECK_FR(ctx, fs | fd); |
|
1619 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1620 |
gen_op_float_abs_d(); |
|
1621 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1622 |
opn = "abs.d"; |
|
1623 |
break; |
|
1624 |
case FOP(6, 17): |
|
1625 |
CHECK_FR(ctx, fs | fd); |
|
1626 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1627 |
gen_op_float_mov_d(); |
|
1628 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1629 |
opn = "mov.d"; |
|
1630 |
break; |
|
1631 |
case FOP(7, 17): |
|
1632 |
CHECK_FR(ctx, fs | fd); |
|
1633 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1634 |
gen_op_float_chs_d(); |
|
1635 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1636 |
opn = "neg.d"; |
|
1637 |
break; |
|
1638 |
/* 8 - round.l */ |
|
1639 |
/* 9 - trunc.l */ |
|
1640 |
/* 10 - ceil.l */ |
|
1641 |
/* 11 - floor.l */ |
|
1642 |
case FOP(12, 17): |
|
1643 |
CHECK_FR(ctx, fs | fd); |
|
1644 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1645 |
gen_op_float_roundw_d(); |
|
1646 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1647 |
opn = "round.w.d"; |
|
1648 |
break; |
|
1649 |
case FOP(13, 17): |
|
1650 |
CHECK_FR(ctx, fs | fd); |
|
1651 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1652 |
gen_op_float_truncw_d(); |
|
1653 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1654 |
opn = "trunc.w.d"; |
|
1655 |
break; |
|
1656 |
case FOP(14, 17): |
|
1657 |
CHECK_FR(ctx, fs | fd); |
|
1658 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1659 |
gen_op_float_ceilw_d(); |
|
1660 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1661 |
opn = "ceil.w.d"; |
|
1662 |
break; |
|
1663 |
case FOP(15, 17): |
|
1664 |
CHECK_FR(ctx, fs | fd); |
|
1665 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1666 |
gen_op_float_floorw_d(); |
|
1667 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1668 |
opn = "ceil.w.d"; |
|
1669 |
break; |
|
1670 |
case FOP(33, 20): /* cvt.d.w */ |
|
1671 |
CHECK_FR(ctx, fs | fd); |
|
1672 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1673 |
gen_op_float_cvtd_w(); |
|
1674 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1675 |
opn = "cvt.d.w"; |
|
1676 |
break; |
|
1677 |
case FOP(48, 17): |
|
1678 |
case FOP(49, 17): |
|
1679 |
case FOP(50, 17): |
|
1680 |
case FOP(51, 17): |
|
1681 |
case FOP(52, 17): |
|
1682 |
case FOP(53, 17): |
|
1683 |
case FOP(54, 17): |
|
1684 |
case FOP(55, 17): |
|
1685 |
case FOP(56, 17): |
|
1686 |
case FOP(57, 17): |
|
1687 |
case FOP(58, 17): |
|
1688 |
case FOP(59, 17): |
|
1689 |
case FOP(60, 17): |
|
1690 |
case FOP(61, 17): |
|
1691 |
case FOP(62, 17): |
|
1692 |
case FOP(63, 17): |
|
1693 |
CHECK_FR(ctx, fs | ft); |
|
1694 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1695 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1696 |
gen_cmp_d(func-48); |
|
1697 |
opn = condnames[func-48]; |
|
1698 |
break; |
|
1699 |
case FOP(0, 16): |
|
1700 |
CHECK_FR(ctx, fs | ft | fd); |
|
1701 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1702 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1703 |
gen_op_float_add_s(); |
|
1704 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1705 |
opn = "add.s"; |
|
1706 |
binary = 1; |
|
1707 |
break; |
|
1708 |
case FOP(1, 16): |
|
1709 |
CHECK_FR(ctx, fs | ft | fd); |
|
1710 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1711 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1712 |
gen_op_float_sub_s(); |
|
1713 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1714 |
opn = "sub.s"; |
|
1715 |
binary = 1; |
|
1716 |
break; |
|
1717 |
case FOP(2, 16): |
|
1718 |
CHECK_FR(ctx, fs | ft | fd); |
|
1719 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1720 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1721 |
gen_op_float_mul_s(); |
|
1722 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1723 |
opn = "mul.s"; |
|
1724 |
binary = 1; |
|
1725 |
break; |
|
1726 |
case FOP(3, 16): |
|
1727 |
CHECK_FR(ctx, fs | ft | fd); |
|
1728 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1729 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1730 |
gen_op_float_div_s(); |
|
1731 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1732 |
opn = "div.s"; |
|
1733 |
binary = 1; |
|
1734 |
break; |
|
1735 |
case FOP(4, 16): |
|
1736 |
CHECK_FR(ctx, fs | fd); |
|
1737 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1738 |
gen_op_float_sqrt_s(); |
|
1739 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1740 |
opn = "sqrt.s"; |
|
1741 |
break; |
|
1742 |
case FOP(5, 16): |
|
1743 |
CHECK_FR(ctx, fs | fd); |
|
1744 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1745 |
gen_op_float_abs_s(); |
|
1746 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1747 |
opn = "abs.s"; |
|
1748 |
break; |
|
1749 |
case FOP(6, 16): |
|
1750 |
CHECK_FR(ctx, fs | fd); |
|
1751 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1752 |
gen_op_float_mov_s(); |
|
1753 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1754 |
opn = "mov.s"; |
|
1755 |
break; |
|
1756 |
case FOP(7, 16): |
|
1757 |
CHECK_FR(ctx, fs | fd); |
|
1758 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1759 |
gen_op_float_chs_s(); |
|
1760 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1761 |
opn = "neg.s"; |
|
1762 |
break; |
|
1763 |
case FOP(12, 16): |
|
1764 |
CHECK_FR(ctx, fs | fd); |
|
1765 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1766 |
gen_op_float_roundw_s(); |
|
1767 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1768 |
opn = "round.w.s"; |
|
1769 |
break; |
|
1770 |
case FOP(13, 16): |
|
1771 |
CHECK_FR(ctx, fs | fd); |
|
1772 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1773 |
gen_op_float_truncw_s(); |
|
1774 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1775 |
opn = "trunc.w.s"; |
|
1776 |
break; |
|
1777 |
case FOP(32, 20): /* cvt.s.w */ |
|
1778 |
CHECK_FR(ctx, fs | fd); |
|
1779 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1780 |
gen_op_float_cvts_w(); |
|
1781 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1782 |
opn = "cvt.s.w"; |
|
1783 |
break; |
|
1784 |
case FOP(36, 16): /* cvt.w.s */ |
|
1785 |
CHECK_FR(ctx, fs | fd); |
|
1786 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1787 |
gen_op_float_cvtw_s(); |
|
1788 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1789 |
opn = "cvt.w.s"; |
|
1790 |
break; |
|
1791 |
case FOP(36, 17): /* cvt.w.d */ |
|
1792 |
CHECK_FR(ctx, fs | fd); |
|
1793 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1794 |
gen_op_float_cvtw_d(); |
|
1795 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1796 |
opn = "cvt.w.d"; |
|
1797 |
break; |
|
1798 |
case FOP(48, 16): |
|
1799 |
case FOP(49, 16): |
|
1800 |
case FOP(50, 16): |
|
1801 |
case FOP(51, 16): |
|
1802 |
case FOP(52, 16): |
|
1803 |
case FOP(53, 16): |
|
1804 |
case FOP(54, 16): |
|
1805 |
case FOP(55, 16): |
|
1806 |
case FOP(56, 16): |
|
1807 |
case FOP(57, 16): |
|
1808 |
case FOP(58, 16): |
|
1809 |
case FOP(59, 16): |
|
1810 |
case FOP(60, 16): |
|
1811 |
case FOP(61, 16): |
|
1812 |
case FOP(62, 16): |
|
1813 |
case FOP(63, 16): |
|
1814 |
CHECK_FR(ctx, fs | ft); |
|
1815 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1816 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1817 |
gen_cmp_s(func-48); |
|
1818 |
opn = condnames[func-48]; |
|
1819 |
break; |
|
1820 |
default: |
|
1821 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
|
1822 |
fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n", |
|
1823 |
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, |
|
1824 |
((ctx->opcode >> 16) & 0x1F)); |
|
1825 |
} |
|
1826 |
generate_exception(ctx, EXCP_RI); |
|
1827 |
return; |
|
1828 |
} |
|
1829 |
if (binary) |
|
1830 |
MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]); |
|
1831 |
else |
|
1832 |
MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); |
|
1833 |
} |
|
1834 |
#endif |
|
1269 | 1835 |
|
1270 | 1836 |
/* ISA extensions */ |
1271 | 1837 |
/* MIPS16 extension to MIPS32 */ |
... | ... | |
1495 | 2061 |
case 0x35: /* LDC1 */ |
1496 | 2062 |
case 0x39: /* SWC1 */ |
1497 | 2063 |
case 0x3D: /* SDC1 */ |
2064 |
#if defined(MIPS_USES_FPU) |
|
2065 |
gen_op_cp1_enabled(); |
|
2066 |
gen_flt_ldst(ctx, op, rt, rs, imm); |
|
2067 |
#else |
|
2068 |
generate_exception_err(ctx, EXCP_CpU, 1); |
|
2069 |
#endif |
|
2070 |
break; |
|
2071 |
|
|
1498 | 2072 |
case 0x11: /* CP1 opcode */ |
1499 | 2073 |
#if defined(MIPS_USES_FPU) |
1500 |
/* XXX: not correct */ |
|
2074 |
gen_op_cp1_enabled(); |
|
2075 |
op1 = ((ctx->opcode >> 21) & 0x1F); |
|
2076 |
switch (op1) { |
|
2077 |
case 0x00: /* mfc1 */ |
|
2078 |
case 0x02: /* cfc1 */ |
|
2079 |
case 0x04: /* mtc1 */ |
|
2080 |
case 0x06: /* ctc1 */ |
|
2081 |
gen_cp1(ctx, op1 | EXT_CP1, rt, rd); |
|
2082 |
break; |
|
2083 |
case 0x08: /* bc */ |
|
2084 |
gen_compute_branch1(ctx, rt, imm << 2); |
|
2085 |
return; |
|
2086 |
case 0x10: /* 16: fmt=single fp */ |
|
2087 |
case 0x11: /* 17: fmt=double fp */ |
|
2088 |
case 0x14: /* 20: fmt=32bit fixed */ |
|
2089 |
case 0x15: /* 21: fmt=64bit fixed */ |
|
2090 |
gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f); |
|
2091 |
break; |
|
2092 |
default: |
|
2093 |
generate_exception_err(ctx, EXCP_RI, 1); |
|
2094 |
break; |
|
2095 |
} |
|
2096 |
break; |
|
1501 | 2097 |
#else |
1502 | 2098 |
generate_exception_err(ctx, EXCP_CpU, 1); |
1503 | 2099 |
#endif |
... | ... | |
1586 | 2182 |
int j, lj = -1; |
1587 | 2183 |
|
1588 | 2184 |
if (search_pc && loglevel) |
1589 |
fprintf (logfile, "search pc %d\n", search_pc);
|
|
2185 |
fprintf (logfile, "search pc %d\n", search_pc);
|
|
1590 | 2186 |
|
1591 | 2187 |
pc_start = tb->pc; |
1592 | 2188 |
gen_opc_ptr = gen_opc_buf; |
... | ... | |
1696 | 2292 |
#endif |
1697 | 2293 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
1698 | 2294 |
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); |
1699 |
target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
|
|
2295 |
target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
|
|
1700 | 2296 |
fprintf(logfile, "\n"); |
1701 | 2297 |
} |
1702 | 2298 |
if (loglevel & CPU_LOG_TB_OP) { |
... | ... | |
1722 | 2318 |
return gen_intermediate_code_internal(env, tb, 1); |
1723 | 2319 |
} |
1724 | 2320 |
|
2321 |
#ifdef MIPS_USES_FPU |
|
2322 |
void fpu_dump_state(CPUState *env, FILE *f, |
|
2323 |
int (*fpu_fprintf)(FILE *f, const char *fmt, ...), |
|
2324 |
int flags) |
|
2325 |
{ |
|
2326 |
int i; |
|
2327 |
|
|
2328 |
# define printfpr(fp) do { \ |
|
2329 |
fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \ |
|
2330 |
(fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \ |
|
2331 |
} while(0) |
|
2332 |
|
|
2333 |
fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", |
|
2334 |
env->fcr0, env->fcr31, |
|
2335 |
(env->CP0_Status & (1<<CP0St_FR)) != 0); |
|
2336 |
fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); |
|
2337 |
fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); |
|
2338 |
fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); |
|
2339 |
for(i=0; i < 32; i+=2) { |
|
2340 |
fpu_fprintf(f, "f%02d: ", i); |
|
2341 |
printfpr(FPR(env, i)); |
|
2342 |
} |
|
2343 |
|
|
2344 |
#undef printfpr |
|
2345 |
} |
|
2346 |
|
|
2347 |
void dump_fpu(CPUState *env) |
|
2348 |
{ |
|
2349 |
if (loglevel) { |
|
2350 |
fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", |
|
2351 |
env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); |
|
2352 |
fpu_dump_state(env, logfile, fprintf, 0); |
|
2353 |
} |
|
2354 |
} |
|
2355 |
#endif /* MIPS_USES_FPU */ |
|
2356 |
|
|
1725 | 2357 |
void cpu_dump_state (CPUState *env, FILE *f, |
1726 | 2358 |
int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
1727 | 2359 |
int flags) |
... | ... | |
1751 | 2383 |
c0_status, env->CP0_Cause, env->CP0_EPC); |
1752 | 2384 |
cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", |
1753 | 2385 |
env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); |
2386 |
#ifdef MIPS_USES_FPU |
|
2387 |
fpu_dump_state(env, f, cpu_fprintf, flags); |
|
2388 |
#endif |
|
1754 | 2389 |
} |
1755 | 2390 |
|
1756 | 2391 |
CPUMIPSState *cpu_mips_init (void) |
... | ... | |
1788 | 2423 |
#if defined(CONFIG_USER_ONLY) |
1789 | 2424 |
env->hflags |= MIPS_HFLAG_UM; |
1790 | 2425 |
#endif |
2426 |
#ifdef MIPS_USES_FPU |
|
2427 |
env->fcr0 = MIPS_FCR0; |
|
2428 |
#endif |
|
1791 | 2429 |
return env; |
1792 | 2430 |
} |
Also available in: Unified diff