|
2 | 2 | // copyright-holders:Aaron Giles
|
3 | 3 | /***************************************************************************
|
4 | 4 |
|
5 |
| - ppcdrc.c |
| 5 | + ppcdrc.cpp |
6 | 6 |
|
7 | 7 | Universal machine language-based PowerPC emulator.
|
8 | 8 |
|
@@ -1746,12 +1746,12 @@ void ppc_device::generate_sequence_instruction(drcuml_block &block, compiler_sta
|
1746 | 1746 | UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0
|
1747 | 1747 | }
|
1748 | 1748 |
|
1749 |
| - /* validate our TLB entry at this PC; if we fail, we need to handle it */ |
1750 |
| - if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION)) |
| 1749 | + // validate our TLB entry at this PC; if we fail, we need to handle it |
| 1750 | + // TODO: this code is highly sus based on the PPC architecture manual, but I'll only disable for 601 for now |
| 1751 | + if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION) && !(m_cap & PPCCAP_601BAT)) |
1751 | 1752 | {
|
1752 | 1753 | const vtlb_entry *tlbtable = vtlb_table();
|
1753 | 1754 |
|
1754 |
| - /* if we currently have a valid TLB read entry, we just verify */ |
1755 | 1755 | if (tlbtable[desc->pc >> 12] != 0)
|
1756 | 1756 | {
|
1757 | 1757 | if (PRINTF_MMU)
|
@@ -2024,6 +2024,23 @@ bool ppc_device::generate_opcode(drcuml_block &block, compiler_state *compiler,
|
2024 | 2024 | // muls rd,rd,ra,simm
|
2025 | 2025 | return true;
|
2026 | 2026 |
|
| 2027 | + case 0x9: /* DOZI (POWER) */ |
| 2028 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2029 | + |
| 2030 | + UML_AND(block, I0, op, 0xffff); |
| 2031 | + UML_CMP(block, R32(G_RA(op)), I0); // cmp ra, I0 |
| 2032 | + UML_JMPc(block, COND_B, compiler->labelnum); // bae 0: |
| 2033 | + |
| 2034 | + UML_XOR(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RD(op))); // xor rd, rd, rd (rd = 0) |
| 2035 | + UML_JMP(block, compiler->labelnum + 1); // jmp 1: |
| 2036 | + |
| 2037 | + UML_LABEL(block, compiler->labelnum++); // 0: |
| 2038 | + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), I0); |
| 2039 | + UML_ADD(block, R32(G_RD(op)), R32(G_RD(op)), 0x1); |
| 2040 | + |
| 2041 | + UML_LABEL(block, compiler->labelnum++); // 1: |
| 2042 | + return true; |
| 2043 | + |
2027 | 2044 | case 0x0e: /* ADDI */
|
2028 | 2045 | UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), (int16_t)G_SIMM(op)); // add rd,ra,simm
|
2029 | 2046 | return true;
|
@@ -2687,6 +2704,13 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co
|
2687 | 2704 | generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), false);// <update flags>
|
2688 | 2705 | return true;
|
2689 | 2706 |
|
| 2707 | + case 0x6b: /* MUL (POWER) */ |
| 2708 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2709 | + |
| 2710 | + UML_MULU(block, SPR32(SPR601_MQ), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // mulu mq, rd, ra, rb |
| 2711 | + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV | XER_SO : 0), false); // <update flags> |
| 2712 | + return true; |
| 2713 | + |
2690 | 2714 | case 0x1cb: /* DIVWUx */
|
2691 | 2715 | case 0x3cb: /* DIVWUOx */
|
2692 | 2716 | UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0
|
@@ -2714,6 +2738,63 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co
|
2714 | 2738 | UML_LABEL(block, compiler->labelnum++); // 1:
|
2715 | 2739 | return true;
|
2716 | 2740 |
|
| 2741 | + case 0x14b: /* DIV (POWER) */ |
| 2742 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2743 | + |
| 2744 | + UML_SHL(block, I0, R32(G_RB(op)), 32); // I0 = RA << 32 |
| 2745 | + UML_OR(block, I0, I0, SPR32(SPR601_MQ)); // I0 |= MQ |
| 2746 | + UML_CMP(block, I0, 0x0); // cmp I0, #0 |
| 2747 | + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: |
| 2748 | + |
| 2749 | + UML_MOV(block, R32(G_RD(op)), 0x0); // mov rd, #0 |
| 2750 | + if (op & M_OE) |
| 2751 | + { |
| 2752 | + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 |
| 2753 | + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 |
| 2754 | + } |
| 2755 | + if (op & M_RC) |
| 2756 | + { |
| 2757 | + UML_MOV(block, CR32(0), 0x2); // CR = EQ |
| 2758 | + UML_AND(block, CR32(0), CR32(0), ~0x1); |
| 2759 | + UML_OR(block, CR32(0), CR32(0), XERSO32); |
| 2760 | + } |
| 2761 | + |
| 2762 | + UML_JMP(block, compiler->labelnum + 1); // jmp 1: |
| 2763 | + |
| 2764 | + UML_LABEL(block, compiler->labelnum++); // 0: |
| 2765 | + UML_DIVS(block, R32(G_RD(op)), SPR32(SPR601_MQ), I0, R32(G_RB(op))); // divs rd,mq,I0,rb |
| 2766 | + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV | XER_SO : 0), false); // <update flags> |
| 2767 | + UML_LABEL(block, compiler->labelnum++); // 1: |
| 2768 | + return true; |
| 2769 | + |
| 2770 | + case 0x16b: /* DIVS (POWER) */ |
| 2771 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2772 | + |
| 2773 | + UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 |
| 2774 | + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: |
| 2775 | + |
| 2776 | + UML_MOV(block, R32(G_RD(op)), 0x0); // mov rd, #0 |
| 2777 | + if (op & M_OE) |
| 2778 | + { |
| 2779 | + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 |
| 2780 | + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 |
| 2781 | + } |
| 2782 | + if (op & M_RC) |
| 2783 | + { |
| 2784 | + UML_MOV(block, CR32(0), 0x2); // CR = EQ |
| 2785 | + UML_AND(block, CR32(0), CR32(0), ~0x1); |
| 2786 | + UML_OR(block, CR32(0), CR32(0), XERSO32); |
| 2787 | + } |
| 2788 | + |
| 2789 | + UML_JMP(block, compiler->labelnum + 1); // jmp 1: |
| 2790 | + |
| 2791 | + UML_LABEL(block, compiler->labelnum++); // 0: |
| 2792 | + UML_DIVS(block, R32(G_RD(op)), SPR32(SPR601_MQ), R32(G_RA(op)), R32(G_RB(op))); // divs rd,mq,ra,rb |
| 2793 | + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), false); // <update flags> |
| 2794 | + |
| 2795 | + UML_LABEL(block, compiler->labelnum++); // 1: |
| 2796 | + return true; |
| 2797 | + |
2717 | 2798 | case 0x1eb: /* DIVWx */
|
2718 | 2799 | case 0x3eb: /* DIVWOx */
|
2719 | 2800 | UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0
|
@@ -2767,6 +2848,78 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co
|
2767 | 2848 | UML_LABEL(block, compiler->labelnum++); // 3:
|
2768 | 2849 | return true;
|
2769 | 2850 |
|
| 2851 | + case 0x108: /* DOZ (POWER) */ |
| 2852 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2853 | + |
| 2854 | + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra, rb |
| 2855 | + UML_JMPc(block, COND_B, compiler->labelnum); // bae 0: |
| 2856 | + |
| 2857 | + UML_XOR(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RD(op))); // xor rd, rd, rd (rd = 0) |
| 2858 | + UML_JMP(block, compiler->labelnum+1); // jmp 1: |
| 2859 | + |
| 2860 | + UML_LABEL(block, compiler->labelnum++); // 0: |
| 2861 | + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); |
| 2862 | + UML_ADD(block, R32(G_RD(op)), R32(G_RD(op)), 0x1); |
| 2863 | + |
| 2864 | + UML_LABEL(block, compiler->labelnum++); // 1: |
| 2865 | + if (op & M_OE) |
| 2866 | + { |
| 2867 | + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 |
| 2868 | + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 |
| 2869 | + } |
| 2870 | + if (op & M_RC) |
| 2871 | + { |
| 2872 | + UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 |
| 2873 | + generate_compute_flags(block, desc, op & M_RC, 0, false); // <update flags> |
| 2874 | + } |
| 2875 | + return true; |
| 2876 | + |
| 2877 | + case 0x168: /* ABS (POWER) */ |
| 2878 | + case 0x1e8: /* NABS (POWER) */ |
| 2879 | + assert(m_cap & PPCCAP_LEGACY_POWER); |
| 2880 | + |
| 2881 | + // is rA already the correct sign (positive for ABS, negative for NABS)? |
| 2882 | + UML_CMP(block, R32(G_RA(op)), 0); |
| 2883 | + if (op & 0x080) |
| 2884 | + { |
| 2885 | + UML_JMPc(block, COND_L, compiler->labelnum); // bl 0: |
| 2886 | + } |
| 2887 | + else |
| 2888 | + { |
| 2889 | + UML_JMPc(block, COND_GE, compiler->labelnum); // bge 0: |
| 2890 | + } |
| 2891 | + |
| 2892 | + UML_SUB(block, I0, 0, R32(G_RA(op))); // sub 0, ra (make positive) |
| 2893 | + UML_JMP(block, compiler->labelnum + 1); // jmp 1: |
| 2894 | + |
| 2895 | + UML_LABEL(block, compiler->labelnum++); // 0: |
| 2896 | + UML_MOV(block, I0, R32(G_RA(op))); |
| 2897 | + |
| 2898 | + UML_LABEL(block, compiler->labelnum++); // 1: |
| 2899 | + UML_MOV(block, R32(G_RD(op)), I0); // mov rd, I0 |
| 2900 | + if (op & M_RC) |
| 2901 | + { |
| 2902 | + UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs |
| 2903 | + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_DWORD, SCALE_x4); // load i0,cmp_cr_table,i0,dword |
| 2904 | + } |
| 2905 | + if (op & M_OE) |
| 2906 | + { |
| 2907 | + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 2908 | + } |
| 2909 | + return true; |
| 2910 | + |
| 2911 | + case 0x21d: /* MASKIR (POWER) */ |
| 2912 | + UML_AND(block, I0, R32(G_RS(op)), R32(G_RB(op))); // and i0, rs, rb |
| 2913 | + UML_XOR(block, I1, R32(G_RB(op)), 0xffffffff); // xor i1, rb, 0xffffffff |
| 2914 | + UML_AND(block, I1, I1, R32(G_RA(op))); // and i1, i1, ra |
| 2915 | + UML_OR(block, R32(G_RA(op)), I0, I1); // or ra, i0, i1 |
| 2916 | + if (op & M_RC) |
| 2917 | + { |
| 2918 | + UML_GETFLGS(block, R32(G_RA(op)), FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs |
| 2919 | + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_DWORD, SCALE_x4); // load i0,cmp_cr_table,i0,dword |
| 2920 | + } |
| 2921 | + return true; |
| 2922 | + |
2770 | 2923 | case 0x01c: /* ANDx */
|
2771 | 2924 | UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // and ra,rs,rb
|
2772 | 2925 | generate_compute_flags(block, desc, op & M_RC, 0, false); // <update flags>
|
|
0 commit comments