diff --git a/CMakeLists.txt b/CMakeLists.txt index ddd3f56..8c104bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,4 +153,5 @@ if (PARALLEL_RSP_TESTS) rsp_add_test(cop0) rsp_add_test(cop2-basic) rsp_add_test(cop2-ls) + rsp_add_test(cop2-vector) endif() diff --git a/debug-toolchain/cop2-vector.s b/debug-toolchain/cop2-vector.s new file mode 100644 index 0000000..68792c8 --- /dev/null +++ b/debug-toolchain/cop2-vector.s @@ -0,0 +1,18 @@ +.data +buffer: +.hword 10, 20, 30, 40, 50, 60, 70, 80 +.hword 20, 30, 40, 50, 60, 70, 80, 90 + +.text +.set noreorder +.global main +main: + la $t0, buffer + # lqv 2, 0, 0(t0) + .word (0x32 << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (0 << 0) | (8 << 21) + # lqv 3, 0, 1(t0) + .word (0x32 << 26) | (4 << 11) | (3 << 16) | (0 << 7) | (1 << 0) | (8 << 21) + + .word (0x25 << 25) | (4 << 6) | (2 << 11) | (3 << 16) | (17 << 0) | (0 << 21) + # vsub v4, v2, v3, 0 + break diff --git a/rsp_jit.cpp b/rsp_jit.cpp index 6939f74..70e1110 100644 --- a/rsp_jit.cpp +++ b/rsp_jit.cpp @@ -727,6 +727,60 @@ void CPU::jit_instruction(jit_state_t *_jit, uint32_t pc, uint32_t instr, // VU if ((instr >> 25) == 0x25) { + // VU instruction. COP2, and high bit of opcode is set. + uint32_t op = instr & 63; + uint32_t vd = (instr >> 6) & 31; + uint32_t vs = (instr >> 11) & 31; + uint32_t vt = (instr >> 16) & 31; + uint32_t e = (instr >> 21) & 15; + + static const char *ops_str[64] = { + "VMULF", "VMULU", nullptr, nullptr, "VMUDL", "VMUDM", "VMUDN", "VMUDH", "VMACF", "VMACU", nullptr, + nullptr, "VMADL", "VMADM", "VMADN", "VMADH", "VADD", "VSUB", nullptr, "VABS", "VADDC", "VSUBC", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "VSAR", nullptr, nullptr, "VLT", + "VEQ", "VNE", "VGE", "VCL", "VCH", "VCR", "VMRG", "VAND", "VNAND", "VOR", "VNOR", + "VXOR", "VNXOR", nullptr, nullptr, "VRCP", "VRCPL", "VRCPH", "VMOV", "VRSQ", "VRSQL", "VRSQH", + "VNOP", + }; + + using VUOp = void (*)(RSP::CPUState *, unsigned vd, unsigned vs, unsigned vt, unsigned e); + + static const VUOp ops[64] = { + RSP_VMULF, RSP_VMULU, nullptr, nullptr, RSP_VMUDL, RSP_VMUDM, RSP_VMUDN, RSP_VMUDH, RSP_VMACF, RSP_VMACU, nullptr, + nullptr, RSP_VMADL, RSP_VMADM, RSP_VMADN, RSP_VMADH, RSP_VADD, RSP_VSUB, nullptr, RSP_VABS, RSP_VADDC, RSP_VSUBC, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RSP_VSAR, nullptr, nullptr, RSP_VLT, + RSP_VEQ, RSP_VNE, RSP_VGE, RSP_VCL, RSP_VCH, RSP_VCR, RSP_VMRG, RSP_VAND, RSP_VNAND, RSP_VOR, RSP_VNOR, + RSP_VXOR, RSP_VNXOR, nullptr, nullptr, RSP_VRCP, RSP_VRCPL, RSP_VRCPH, RSP_VMOV, RSP_VRSQ, RSP_VRSQL, RSP_VRSQH, + RSP_VNOP, + }; + + const char *op_str = ops_str[op]; + VUOp vuop; + if (op_str) + { + DISASM("%s v%u, v%u, v%u[%u]\n", op_str, vd, vs, vt, e); + vuop = ops[op]; + } + else + { + DISASM("cop2 %u reserved\n", op); + vuop = RSP_RESERVED; + } + + if (last_info.conditional) + jit_save_cond_branch_taken(_jit); + + jit_prepare(); + jit_pushargr(JIT_REGISTER_STATE); + jit_pushargi(vd); + jit_pushargi(vs); + jit_pushargi(vt); + jit_pushargi(e); + jit_finishi(reinterpret_cast(vuop)); + + if (last_info.conditional) + jit_restore_cond_branch_taken(_jit); + return; } @@ -1394,15 +1448,12 @@ void CPU::jit_instruction(jit_state_t *_jit, uint32_t pc, uint32_t instr, unsigned imm = (instr >> 7) & 15; static const char *lwc2_ops[32] = { - "LBV", "LSV", "LLV", "LDV", "LQV", "LRV", "LPV", "LUV", "LHV", nullptr, nullptr, - "LTV", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "LBV", "LSV", "LLV", "LDV", "LQV", "LRV", "LPV", "LUV", "LHV", nullptr, nullptr, "LTV", }; using LWC2Op = void (*)(RSP::CPUState *, unsigned rt, unsigned imm, int simm, unsigned rs); static const LWC2Op ops[32] = { - RSP_LBV, RSP_LSV, RSP_LLV, RSP_LDV, RSP_LQV, RSP_LRV, RSP_LPV, RSP_LUV, RSP_LHV, nullptr, nullptr, - RSP_LTV, + RSP_LBV, RSP_LSV, RSP_LLV, RSP_LDV, RSP_LQV, RSP_LRV, RSP_LPV, RSP_LUV, RSP_LHV, nullptr, nullptr, RSP_LTV, }; const char *op = lwc2_ops[rd]; @@ -1439,15 +1490,12 @@ void CPU::jit_instruction(jit_state_t *_jit, uint32_t pc, uint32_t instr, unsigned imm = (instr >> 7) & 15; static const char *swc2_ops[32] = { - "SBV", "SSV", "SLV", "SDV", "SQV", "SRV", "SPV", "SUV", "SHV", "SFV", nullptr, - "STV", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "SBV", "SSV", "SLV", "SDV", "SQV", "SRV", "SPV", "SUV", "SHV", "SFV", nullptr, "STV", }; using SWC2Op = void (*)(RSP::CPUState *, unsigned rt, unsigned imm, int simm, unsigned rs); static const SWC2Op ops[32] = { - RSP_SBV, RSP_SSV, RSP_SLV, RSP_SDV, RSP_SQV, RSP_SRV, RSP_SPV, RSP_SUV, RSP_SHV, RSP_SFV, nullptr, - RSP_STV, + RSP_SBV, RSP_SSV, RSP_SLV, RSP_SDV, RSP_SQV, RSP_SRV, RSP_SPV, RSP_SUV, RSP_SHV, RSP_SFV, nullptr, RSP_STV, }; const char *op = swc2_ops[rd];