Revision 460f00c4
b/target-mips/translate.c | ||
---|---|---|
1452 | 1452 |
int rd, int rs, int rt) |
1453 | 1453 |
{ |
1454 | 1454 |
const char *opn = "arith"; |
1455 |
TCGv t0 = tcg_temp_local_new(); |
|
1456 |
TCGv t1 = tcg_temp_local_new(); |
|
1457 | 1455 |
|
1458 | 1456 |
if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB |
1459 | 1457 |
&& opc != OPC_DADD && opc != OPC_DSUB) { |
1460 | 1458 |
/* If no destination, treat it as a NOP. |
1461 | 1459 |
For add & sub, we must generate the overflow exception when needed. */ |
1462 | 1460 |
MIPS_DEBUG("NOP"); |
1463 |
goto out; |
|
1464 |
} |
|
1465 |
gen_load_gpr(t0, rs); |
|
1466 |
/* Specialcase the conventional move operation. */ |
|
1467 |
if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU |
|
1468 |
|| opc == OPC_SUBU || opc == OPC_DSUBU)) { |
|
1469 |
gen_store_gpr(t0, rd); |
|
1470 |
goto out; |
|
1461 |
return; |
|
1471 | 1462 |
} |
1472 |
gen_load_gpr(t1, rt); |
|
1463 |
|
|
1473 | 1464 |
switch (opc) { |
1474 | 1465 |
case OPC_ADD: |
1475 | 1466 |
{ |
1476 |
TCGv r_tmp1 = tcg_temp_new(); |
|
1477 |
TCGv r_tmp2 = tcg_temp_new(); |
|
1467 |
TCGv t0 = tcg_temp_local_new(); |
|
1468 |
TCGv t1 = tcg_temp_new(); |
|
1469 |
TCGv t2 = tcg_temp_new(); |
|
1478 | 1470 |
int l1 = gen_new_label(); |
1479 | 1471 |
|
1480 |
save_cpu_state(ctx, 1);
|
|
1481 |
tcg_gen_ext32s_tl(r_tmp1, t0);
|
|
1482 |
tcg_gen_ext32s_tl(r_tmp2, t1);
|
|
1483 |
tcg_gen_add_tl(t0, r_tmp1, r_tmp2);
|
|
1484 |
|
|
1485 |
tcg_gen_xor_tl(r_tmp1, r_tmp1, t1);
|
|
1486 |
tcg_gen_xori_tl(r_tmp1, r_tmp1, -1);
|
|
1487 |
tcg_gen_xor_tl(r_tmp2, t0, t1);
|
|
1488 |
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
|
1489 |
tcg_temp_free(r_tmp2);
|
|
1490 |
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
|
1472 |
gen_load_gpr(t1, rs);
|
|
1473 |
gen_load_gpr(t2, rt);
|
|
1474 |
tcg_gen_add_tl(t0, t1, t2);
|
|
1475 |
tcg_gen_ext32s_tl(t0, t0);
|
|
1476 |
tcg_gen_xor_tl(t1, t1, t2); |
|
1477 |
tcg_gen_not_tl(t1, t1);
|
|
1478 |
tcg_gen_xor_tl(t2, t0, t2);
|
|
1479 |
tcg_gen_and_tl(t1, t1, t2);
|
|
1480 |
tcg_temp_free(t2);
|
|
1481 |
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
|
1482 |
tcg_temp_free(t1);
|
|
1491 | 1483 |
/* operands of same sign, result different sign */ |
1492 | 1484 |
generate_exception(ctx, EXCP_OVERFLOW); |
1493 | 1485 |
gen_set_label(l1); |
1494 |
tcg_temp_free(r_tmp1); |
|
1495 |
|
|
1496 |
tcg_gen_ext32s_tl(t0, t0); |
|
1486 |
gen_store_gpr(t0, rd); |
|
1487 |
tcg_temp_free(t0); |
|
1497 | 1488 |
} |
1498 | 1489 |
opn = "add"; |
1499 | 1490 |
break; |
1500 | 1491 |
case OPC_ADDU: |
1501 |
tcg_gen_add_tl(t0, t0, t1); |
|
1502 |
tcg_gen_ext32s_tl(t0, t0); |
|
1492 |
if (rs != 0 && rt != 0) { |
|
1493 |
tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1494 |
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); |
|
1495 |
} else if (rs == 0 && rt != 0) { |
|
1496 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1497 |
} else if (rs != 0 && rt == 0) { |
|
1498 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1499 |
} else { |
|
1500 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1501 |
} |
|
1503 | 1502 |
opn = "addu"; |
1504 | 1503 |
break; |
1505 | 1504 |
case OPC_SUB: |
1506 | 1505 |
{ |
1507 |
TCGv r_tmp1 = tcg_temp_new(); |
|
1508 |
TCGv r_tmp2 = tcg_temp_new(); |
|
1506 |
TCGv t0 = tcg_temp_local_new(); |
|
1507 |
TCGv t1 = tcg_temp_new(); |
|
1508 |
TCGv t2 = tcg_temp_new(); |
|
1509 | 1509 |
int l1 = gen_new_label(); |
1510 | 1510 |
|
1511 |
save_cpu_state(ctx, 1);
|
|
1512 |
tcg_gen_ext32s_tl(r_tmp1, t0);
|
|
1513 |
tcg_gen_ext32s_tl(r_tmp2, t1);
|
|
1514 |
tcg_gen_sub_tl(t0, r_tmp1, r_tmp2);
|
|
1515 |
|
|
1516 |
tcg_gen_xor_tl(r_tmp2, r_tmp1, t1);
|
|
1517 |
tcg_gen_xor_tl(r_tmp1, r_tmp1, t0);
|
|
1518 |
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
|
1519 |
tcg_temp_free(r_tmp2);
|
|
1520 |
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
|
1521 |
/* operands of different sign, first operand and result different sign */
|
|
1511 |
gen_load_gpr(t1, rs);
|
|
1512 |
gen_load_gpr(t2, rt);
|
|
1513 |
tcg_gen_sub_tl(t0, t1, t2);
|
|
1514 |
tcg_gen_ext32s_tl(t0, t0);
|
|
1515 |
tcg_gen_xor_tl(t2, t1, t2); |
|
1516 |
tcg_gen_xor_tl(t1, t0, t1);
|
|
1517 |
tcg_gen_and_tl(t1, t1, t2);
|
|
1518 |
tcg_temp_free(t2);
|
|
1519 |
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
|
1520 |
tcg_temp_free(t1);
|
|
1521 |
/* operands of same sign, result different sign */
|
|
1522 | 1522 |
generate_exception(ctx, EXCP_OVERFLOW); |
1523 | 1523 |
gen_set_label(l1); |
1524 |
tcg_temp_free(r_tmp1); |
|
1525 |
|
|
1526 |
tcg_gen_ext32s_tl(t0, t0); |
|
1524 |
gen_store_gpr(t0, rd); |
|
1525 |
tcg_temp_free(t0); |
|
1527 | 1526 |
} |
1528 | 1527 |
opn = "sub"; |
1529 | 1528 |
break; |
1530 | 1529 |
case OPC_SUBU: |
1531 |
tcg_gen_sub_tl(t0, t0, t1); |
|
1532 |
tcg_gen_ext32s_tl(t0, t0); |
|
1530 |
if (rs != 0 && rt != 0) { |
|
1531 |
tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1532 |
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); |
|
1533 |
} else if (rs == 0 && rt != 0) { |
|
1534 |
tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1535 |
} else if (rs != 0 && rt == 0) { |
|
1536 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1537 |
} else { |
|
1538 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1539 |
} |
|
1533 | 1540 |
opn = "subu"; |
1534 | 1541 |
break; |
1535 | 1542 |
#if defined(TARGET_MIPS64) |
1536 | 1543 |
case OPC_DADD: |
1537 | 1544 |
{ |
1538 |
TCGv r_tmp1 = tcg_temp_new(); |
|
1539 |
TCGv r_tmp2 = tcg_temp_new(); |
|
1545 |
TCGv t0 = tcg_temp_local_new(); |
|
1546 |
TCGv t1 = tcg_temp_new(); |
|
1547 |
TCGv t2 = tcg_temp_new(); |
|
1540 | 1548 |
int l1 = gen_new_label(); |
1541 | 1549 |
|
1542 |
save_cpu_state(ctx, 1);
|
|
1543 |
tcg_gen_mov_tl(r_tmp1, t0);
|
|
1544 |
tcg_gen_add_tl(t0, t0, t1);
|
|
1545 |
|
|
1546 |
tcg_gen_xor_tl(r_tmp1, r_tmp1, t1);
|
|
1547 |
tcg_gen_xori_tl(r_tmp1, r_tmp1, -1);
|
|
1548 |
tcg_gen_xor_tl(r_tmp2, t0, t1);
|
|
1549 |
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
|
1550 |
tcg_temp_free(r_tmp2);
|
|
1551 |
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
|
1550 |
gen_load_gpr(t1, rs);
|
|
1551 |
gen_load_gpr(t2, rt);
|
|
1552 |
tcg_gen_add_tl(t0, t1, t2);
|
|
1553 |
tcg_gen_xor_tl(t1, t1, t2); |
|
1554 |
tcg_gen_not_tl(t1, t1);
|
|
1555 |
tcg_gen_xor_tl(t2, t0, t2);
|
|
1556 |
tcg_gen_and_tl(t1, t1, t2);
|
|
1557 |
tcg_temp_free(t2);
|
|
1558 |
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
|
1559 |
tcg_temp_free(t1);
|
|
1552 | 1560 |
/* operands of same sign, result different sign */ |
1553 | 1561 |
generate_exception(ctx, EXCP_OVERFLOW); |
1554 | 1562 |
gen_set_label(l1); |
1555 |
tcg_temp_free(r_tmp1); |
|
1563 |
gen_store_gpr(t0, rd); |
|
1564 |
tcg_temp_free(t0); |
|
1556 | 1565 |
} |
1557 | 1566 |
opn = "dadd"; |
1558 | 1567 |
break; |
1559 | 1568 |
case OPC_DADDU: |
1560 |
tcg_gen_add_tl(t0, t0, t1); |
|
1569 |
if (rs != 0 && rt != 0) { |
|
1570 |
tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1571 |
} else if (rs == 0 && rt != 0) { |
|
1572 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1573 |
} else if (rs != 0 && rt == 0) { |
|
1574 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1575 |
} else { |
|
1576 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1577 |
} |
|
1561 | 1578 |
opn = "daddu"; |
1562 | 1579 |
break; |
1563 | 1580 |
case OPC_DSUB: |
1564 | 1581 |
{ |
1565 |
TCGv r_tmp1 = tcg_temp_new(); |
|
1566 |
TCGv r_tmp2 = tcg_temp_new(); |
|
1582 |
TCGv t0 = tcg_temp_local_new(); |
|
1583 |
TCGv t1 = tcg_temp_new(); |
|
1584 |
TCGv t2 = tcg_temp_new(); |
|
1567 | 1585 |
int l1 = gen_new_label(); |
1568 | 1586 |
|
1569 |
save_cpu_state(ctx, 1);
|
|
1570 |
tcg_gen_mov_tl(r_tmp1, t0);
|
|
1571 |
tcg_gen_sub_tl(t0, t0, t1);
|
|
1572 |
|
|
1573 |
tcg_gen_xor_tl(r_tmp2, r_tmp1, t1);
|
|
1574 |
tcg_gen_xor_tl(r_tmp1, r_tmp1, t0);
|
|
1575 |
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
|
1576 |
tcg_temp_free(r_tmp2);
|
|
1577 |
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
|
1578 |
/* operands of different sign, first operand and result different sign */
|
|
1587 |
gen_load_gpr(t1, rs);
|
|
1588 |
gen_load_gpr(t2, rt);
|
|
1589 |
tcg_gen_sub_tl(t0, t1, t2);
|
|
1590 |
tcg_gen_xor_tl(t2, t1, t2); |
|
1591 |
tcg_gen_xor_tl(t1, t0, t1);
|
|
1592 |
tcg_gen_and_tl(t1, t1, t2);
|
|
1593 |
tcg_temp_free(t2);
|
|
1594 |
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
|
1595 |
tcg_temp_free(t1);
|
|
1596 |
/* operands of same sign, result different sign */
|
|
1579 | 1597 |
generate_exception(ctx, EXCP_OVERFLOW); |
1580 | 1598 |
gen_set_label(l1); |
1581 |
tcg_temp_free(r_tmp1); |
|
1599 |
gen_store_gpr(t0, rd); |
|
1600 |
tcg_temp_free(t0); |
|
1582 | 1601 |
} |
1583 | 1602 |
opn = "dsub"; |
1584 | 1603 |
break; |
1585 | 1604 |
case OPC_DSUBU: |
1586 |
tcg_gen_sub_tl(t0, t0, t1); |
|
1605 |
if (rs != 0 && rt != 0) { |
|
1606 |
tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1607 |
} else if (rs == 0 && rt != 0) { |
|
1608 |
tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1609 |
} else if (rs != 0 && rt == 0) { |
|
1610 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1611 |
} else { |
|
1612 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1613 |
} |
|
1587 | 1614 |
opn = "dsubu"; |
1588 | 1615 |
break; |
1589 | 1616 |
#endif |
1590 |
case OPC_SLT: |
|
1591 |
gen_op_lt(t0, t0, t1); |
|
1592 |
opn = "slt"; |
|
1617 |
case OPC_MUL: |
|
1618 |
if (likely(rs != 0 && rt != 0)) { |
|
1619 |
tcg_gen_mul_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1620 |
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); |
|
1621 |
} else { |
|
1622 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1623 |
} |
|
1624 |
opn = "mul"; |
|
1593 | 1625 |
break; |
1594 |
case OPC_SLTU: |
|
1595 |
gen_op_ltu(t0, t0, t1); |
|
1596 |
opn = "sltu"; |
|
1626 |
} |
|
1627 |
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); |
|
1628 |
} |
|
1629 |
|
|
1630 |
/* Conditional move */ |
|
1631 |
static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt) |
|
1632 |
{ |
|
1633 |
const char *opn = "cond move"; |
|
1634 |
int l1; |
|
1635 |
|
|
1636 |
if (rd == 0) { |
|
1637 |
/* If no destination, treat it as a NOP. |
|
1638 |
For add & sub, we must generate the overflow exception when needed. */ |
|
1639 |
MIPS_DEBUG("NOP"); |
|
1640 |
return; |
|
1641 |
} |
|
1642 |
|
|
1643 |
l1 = gen_new_label(); |
|
1644 |
switch (opc) { |
|
1645 |
case OPC_MOVN: |
|
1646 |
if (likely(rt != 0)) |
|
1647 |
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rt], 0, l1); |
|
1648 |
else |
|
1649 |
tcg_gen_br(l1); |
|
1650 |
opn = "movn"; |
|
1651 |
break; |
|
1652 |
case OPC_MOVZ: |
|
1653 |
if (likely(rt != 0)) |
|
1654 |
tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rt], 0, l1); |
|
1655 |
opn = "movz"; |
|
1597 | 1656 |
break; |
1657 |
} |
|
1658 |
if (rs != 0) |
|
1659 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1660 |
else |
|
1661 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1662 |
gen_set_label(l1); |
|
1663 |
|
|
1664 |
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); |
|
1665 |
} |
|
1666 |
|
|
1667 |
/* Logic */ |
|
1668 |
static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt) |
|
1669 |
{ |
|
1670 |
const char *opn = "logic"; |
|
1671 |
|
|
1672 |
if (rd == 0) { |
|
1673 |
/* If no destination, treat it as a NOP. */ |
|
1674 |
MIPS_DEBUG("NOP"); |
|
1675 |
return; |
|
1676 |
} |
|
1677 |
|
|
1678 |
switch (opc) { |
|
1598 | 1679 |
case OPC_AND: |
1599 |
tcg_gen_and_tl(t0, t0, t1); |
|
1680 |
if (likely(rs != 0 && rt != 0)) { |
|
1681 |
tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1682 |
} else { |
|
1683 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1684 |
} |
|
1600 | 1685 |
opn = "and"; |
1601 | 1686 |
break; |
1602 | 1687 |
case OPC_NOR: |
1603 |
tcg_gen_nor_tl(t0, t0, t1); |
|
1688 |
if (rs != 0 && rt != 0) { |
|
1689 |
tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1690 |
} else if (rs == 0 && rt != 0) { |
|
1691 |
tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1692 |
} else if (rs != 0 && rt == 0) { |
|
1693 |
tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1694 |
} else { |
|
1695 |
tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); |
|
1696 |
} |
|
1604 | 1697 |
opn = "nor"; |
1605 | 1698 |
break; |
1606 | 1699 |
case OPC_OR: |
1607 |
tcg_gen_or_tl(t0, t0, t1); |
|
1700 |
if (likely(rs != 0 && rt != 0)) { |
|
1701 |
tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1702 |
} else if (rs == 0 && rt != 0) { |
|
1703 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1704 |
} else if (rs != 0 && rt == 0) { |
|
1705 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1706 |
} else { |
|
1707 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1708 |
} |
|
1608 | 1709 |
opn = "or"; |
1609 | 1710 |
break; |
1610 | 1711 |
case OPC_XOR: |
1611 |
tcg_gen_xor_tl(t0, t0, t1); |
|
1712 |
if (likely(rs != 0 && rt != 0)) { |
|
1713 |
tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); |
|
1714 |
} else if (rs == 0 && rt != 0) { |
|
1715 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); |
|
1716 |
} else if (rs != 0 && rt == 0) { |
|
1717 |
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); |
|
1718 |
} else { |
|
1719 |
tcg_gen_movi_tl(cpu_gpr[rd], 0); |
|
1720 |
} |
|
1612 | 1721 |
opn = "xor"; |
1613 | 1722 |
break; |
1614 |
case OPC_MUL: |
|
1615 |
tcg_gen_mul_tl(t0, t0, t1); |
|
1616 |
tcg_gen_ext32s_tl(t0, t0); |
|
1617 |
opn = "mul"; |
|
1723 |
} |
|
1724 |
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); |
|
1725 |
} |
|
1726 |
|
|
1727 |
/* Set on lower than */ |
|
1728 |
static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt) |
|
1729 |
{ |
|
1730 |
const char *opn = "slt"; |
|
1731 |
TCGv t0, t1; |
|
1732 |
|
|
1733 |
if (rd == 0) { |
|
1734 |
/* If no destination, treat it as a NOP. */ |
|
1735 |
MIPS_DEBUG("NOP"); |
|
1736 |
return; |
|
1737 |
} |
|
1738 |
|
|
1739 |
t0 = tcg_temp_new(); |
|
1740 |
t1 = tcg_temp_new(); |
|
1741 |
gen_load_gpr(t0, rs); |
|
1742 |
gen_load_gpr(t1, rt); |
|
1743 |
switch (opc) { |
|
1744 |
case OPC_SLT: |
|
1745 |
gen_op_lt(cpu_gpr[rd], t0, t1); |
|
1746 |
opn = "slt"; |
|
1618 | 1747 |
break; |
1619 |
case OPC_MOVN: |
|
1620 |
{ |
|
1621 |
int l1 = gen_new_label(); |
|
1748 |
case OPC_SLTU: |
|
1749 |
gen_op_ltu(cpu_gpr[rd], t0, t1); |
|
1750 |
opn = "sltu"; |
|
1751 |
break; |
|
1752 |
} |
|
1753 |
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); |
|
1754 |
tcg_temp_free(t0); |
|
1755 |
tcg_temp_free(t1); |
|
1756 |
} |
|
1622 | 1757 |
|
1623 |
tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); |
|
1624 |
gen_store_gpr(t0, rd); |
|
1625 |
gen_set_label(l1); |
|
1626 |
} |
|
1627 |
opn = "movn"; |
|
1628 |
goto print; |
|
1629 |
case OPC_MOVZ: |
|
1630 |
{ |
|
1631 |
int l1 = gen_new_label(); |
|
1758 |
/* Shifts */ |
|
1759 |
static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc, |
|
1760 |
int rd, int rs, int rt) |
|
1761 |
{ |
|
1762 |
const char *opn = "shifts"; |
|
1763 |
TCGv t0, t1; |
|
1632 | 1764 |
|
1633 |
tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); |
|
1634 |
gen_store_gpr(t0, rd); |
|
1635 |
gen_set_label(l1); |
|
1636 |
} |
|
1637 |
opn = "movz"; |
|
1638 |
goto print; |
|
1765 |
if (rd == 0) { |
|
1766 |
/* If no destination, treat it as a NOP. |
|
1767 |
For add & sub, we must generate the overflow exception when needed. */ |
|
1768 |
MIPS_DEBUG("NOP"); |
|
1769 |
return; |
|
1770 |
} |
|
1771 |
|
|
1772 |
t0 = tcg_temp_new(); |
|
1773 |
t1 = tcg_temp_new(); |
|
1774 |
gen_load_gpr(t0, rs); |
|
1775 |
gen_load_gpr(t1, rt); |
|
1776 |
switch (opc) { |
|
1639 | 1777 |
case OPC_SLLV: |
1640 | 1778 |
tcg_gen_andi_tl(t0, t0, 0x1f); |
1641 | 1779 |
tcg_gen_shl_tl(t0, t1, t0); |
1642 |
tcg_gen_ext32s_tl(t0, t0);
|
|
1780 |
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
|
1643 | 1781 |
opn = "sllv"; |
1644 | 1782 |
break; |
1645 | 1783 |
case OPC_SRAV: |
1646 | 1784 |
tcg_gen_ext32s_tl(t1, t1); |
1647 | 1785 |
tcg_gen_andi_tl(t0, t0, 0x1f); |
1648 |
tcg_gen_sar_tl(t0, t1, t0);
|
|
1786 |
tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
|
|
1649 | 1787 |
opn = "srav"; |
1650 | 1788 |
break; |
1651 | 1789 |
case OPC_SRLV: |
... | ... | |
1654 | 1792 |
tcg_gen_ext32u_tl(t1, t1); |
1655 | 1793 |
tcg_gen_andi_tl(t0, t0, 0x1f); |
1656 | 1794 |
tcg_gen_shr_tl(t0, t1, t0); |
1657 |
tcg_gen_ext32s_tl(t0, t0);
|
|
1795 |
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
|
1658 | 1796 |
opn = "srlv"; |
1659 | 1797 |
break; |
1660 | 1798 |
case 1: |
1661 | 1799 |
/* rotrv is decoded as srlv on non-R2 CPUs */ |
1662 | 1800 |
if (env->insn_flags & ISA_MIPS32R2) { |
1663 |
int l1 = gen_new_label(); |
|
1664 |
int l2 = gen_new_label(); |
|
1665 |
|
|
1666 |
tcg_gen_andi_tl(t0, t0, 0x1f); |
|
1667 |
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); |
|
1668 |
{ |
|
1669 |
TCGv_i32 r_tmp1 = tcg_temp_new_i32(); |
|
1670 |
TCGv_i32 r_tmp2 = tcg_temp_new_i32(); |
|
1671 |
|
|
1672 |
tcg_gen_trunc_tl_i32(r_tmp1, t0); |
|
1673 |
tcg_gen_trunc_tl_i32(r_tmp2, t1); |
|
1674 |
tcg_gen_rotr_i32(r_tmp1, r_tmp1, r_tmp2); |
|
1675 |
tcg_temp_free_i32(r_tmp1); |
|
1676 |
tcg_temp_free_i32(r_tmp2); |
|
1677 |
tcg_gen_br(l2); |
|
1678 |
} |
|
1679 |
gen_set_label(l1); |
|
1680 |
tcg_gen_mov_tl(t0, t1); |
|
1681 |
gen_set_label(l2); |
|
1801 |
TCGv_i32 t2 = tcg_temp_new_i32(); |
|
1802 |
TCGv_i32 t3 = tcg_temp_new_i32(); |
|
1803 |
|
|
1804 |
tcg_gen_trunc_tl_i32(t2, t0); |
|
1805 |
tcg_gen_trunc_tl_i32(t3, t1); |
|
1806 |
tcg_gen_andi_i32(t2, t2, 0x1f); |
|
1807 |
tcg_gen_rotr_i32(t2, t3, t2); |
|
1808 |
tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); |
|
1809 |
tcg_temp_free_i32(t2); |
|
1810 |
tcg_temp_free_i32(t3); |
|
1682 | 1811 |
opn = "rotrv"; |
1683 | 1812 |
} else { |
1684 | 1813 |
tcg_gen_ext32u_tl(t1, t1); |
1685 | 1814 |
tcg_gen_andi_tl(t0, t0, 0x1f); |
1686 | 1815 |
tcg_gen_shr_tl(t0, t1, t0); |
1687 |
tcg_gen_ext32s_tl(t0, t0);
|
|
1816 |
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
|
1688 | 1817 |
opn = "srlv"; |
1689 | 1818 |
} |
1690 | 1819 |
break; |
... | ... | |
1697 | 1826 |
#if defined(TARGET_MIPS64) |
1698 | 1827 |
case OPC_DSLLV: |
1699 | 1828 |
tcg_gen_andi_tl(t0, t0, 0x3f); |
1700 |
tcg_gen_shl_tl(t0, t1, t0);
|
|
1829 |
tcg_gen_shl_tl(cpu_gpr[rd], t1, t0);
|
|
1701 | 1830 |
opn = "dsllv"; |
1702 | 1831 |
break; |
1703 | 1832 |
case OPC_DSRAV: |
1704 | 1833 |
tcg_gen_andi_tl(t0, t0, 0x3f); |
1705 |
tcg_gen_sar_tl(t0, t1, t0);
|
|
1834 |
tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
|
|
1706 | 1835 |
opn = "dsrav"; |
1707 | 1836 |
break; |
1708 | 1837 |
case OPC_DSRLV: |
1709 | 1838 |
switch ((ctx->opcode >> 6) & 0x1f) { |
1710 | 1839 |
case 0: |
1711 | 1840 |
tcg_gen_andi_tl(t0, t0, 0x3f); |
1712 |
tcg_gen_shr_tl(t0, t1, t0);
|
|
1841 |
tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
|
|
1713 | 1842 |
opn = "dsrlv"; |
1714 | 1843 |
break; |
1715 | 1844 |
case 1: |
1716 | 1845 |
/* drotrv is decoded as dsrlv on non-R2 CPUs */ |
1717 | 1846 |
if (env->insn_flags & ISA_MIPS32R2) { |
1718 |
int l1 = gen_new_label(); |
|
1719 |
int l2 = gen_new_label(); |
|
1720 |
|
|
1721 | 1847 |
tcg_gen_andi_tl(t0, t0, 0x3f); |
1722 |
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); |
|
1723 |
{ |
|
1724 |
tcg_gen_rotr_tl(t0, t1, t0); |
|
1725 |
tcg_gen_br(l2); |
|
1726 |
} |
|
1727 |
gen_set_label(l1); |
|
1728 |
tcg_gen_mov_tl(t0, t1); |
|
1729 |
gen_set_label(l2); |
|
1848 |
tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); |
|
1730 | 1849 |
opn = "drotrv"; |
1731 | 1850 |
} else { |
1732 | 1851 |
tcg_gen_andi_tl(t0, t0, 0x3f); |
... | ... | |
1741 | 1860 |
} |
1742 | 1861 |
break; |
1743 | 1862 |
#endif |
1744 |
default: |
|
1745 |
MIPS_INVAL(opn); |
|
1746 |
generate_exception(ctx, EXCP_RI); |
|
1747 |
goto out; |
|
1748 | 1863 |
} |
1749 |
gen_store_gpr(t0, rd); |
|
1750 |
print: |
|
1751 | 1864 |
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); |
1752 |
out: |
|
1753 | 1865 |
tcg_temp_free(t0); |
1754 | 1866 |
tcg_temp_free(t1); |
1755 | 1867 |
} |
... | ... | |
7465 | 7577 |
case OPC_SRL ... OPC_SRA: |
7466 | 7578 |
gen_arith_imm(env, ctx, op1, rd, rt, sa); |
7467 | 7579 |
break; |
7468 |
case OPC_MOVZ ... OPC_MOVN: |
|
7580 |
case OPC_MOVN: /* Conditional move */ |
|
7581 |
case OPC_MOVZ: |
|
7469 | 7582 |
check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); |
7470 |
case OPC_SLLV: /* Arithmetic */ |
|
7471 |
case OPC_SRLV ... OPC_SRAV: |
|
7472 |
case OPC_ADD ... OPC_NOR: |
|
7473 |
case OPC_SLT ... OPC_SLTU: |
|
7583 |
gen_cond_move(env, op1, rd, rs, rt); |
|
7584 |
break; |
|
7585 |
case OPC_ADD ... OPC_SUBU: |
|
7474 | 7586 |
gen_arith(env, ctx, op1, rd, rs, rt); |
7475 | 7587 |
break; |
7588 |
case OPC_SLLV: /* Shifts */ |
|
7589 |
case OPC_SRLV: |
|
7590 |
case OPC_SRAV: |
|
7591 |
gen_shift(env, ctx, op1, rd, rs, rt); |
|
7592 |
break; |
|
7593 |
case OPC_SLT: /* Set on less than */ |
|
7594 |
case OPC_SLTU: |
|
7595 |
gen_slt(env, op1, rd, rs, rt); |
|
7596 |
break; |
|
7597 |
case OPC_AND: /* Logic*/ |
|
7598 |
case OPC_OR: |
|
7599 |
case OPC_NOR: |
|
7600 |
case OPC_XOR: |
|
7601 |
gen_logic(env, op1, rd, rs, rt); |
|
7602 |
break; |
|
7476 | 7603 |
case OPC_MULT ... OPC_DIVU: |
7477 | 7604 |
if (sa) { |
7478 | 7605 |
check_insn(env, ctx, INSN_VR54XX); |
... | ... | |
7545 | 7672 |
check_mips_64(ctx); |
7546 | 7673 |
gen_arith_imm(env, ctx, op1, rd, rt, sa); |
7547 | 7674 |
break; |
7548 |
case OPC_DSLLV: |
|
7549 |
case OPC_DSRLV ... OPC_DSRAV: |
|
7550 | 7675 |
case OPC_DADD ... OPC_DSUBU: |
7551 | 7676 |
check_insn(env, ctx, ISA_MIPS3); |
7552 | 7677 |
check_mips_64(ctx); |
7553 | 7678 |
gen_arith(env, ctx, op1, rd, rs, rt); |
7554 | 7679 |
break; |
7680 |
case OPC_DSLLV: |
|
7681 |
case OPC_DSRAV: |
|
7682 |
case OPC_DSRLV: |
|
7683 |
check_insn(env, ctx, ISA_MIPS3); |
|
7684 |
check_mips_64(ctx); |
|
7685 |
gen_shift(env, ctx, op1, rd, rs, rt); |
|
7686 |
break; |
|
7555 | 7687 |
case OPC_DMULT ... OPC_DDIVU: |
7556 | 7688 |
check_insn(env, ctx, ISA_MIPS3); |
7557 | 7689 |
check_mips_64(ctx); |
Also available in: Unified diff