void ngen_CC_Call(shil_opcode*op, void* function) { int regused = 0; int xmmused = 0; for (int i = CC_pars.size(); i-- > 0;) { verify(xmmused < 4 && regused < 4); shil_param& prm = *CC_pars[i].prm; switch (CC_pars[i].type) { //push the contents case CPT_u32: sh_to_reg(prm, mov, call_regs[regused++]); break; case CPT_f32: sh_to_reg_noimm(prm, movss, call_regsxmm[xmmused++]); break; //push the ptr itself case CPT_ptr: verify(prm.is_reg()); mov(call_regs64[regused++], (size_t)prm.reg_ptr()); //die("FAIL"); break; } } call(function); }
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) { mov(rax, (size_t)&cycle_counter); sub(dword[rax], block->guest_cycles); sub(rsp, 0x28); for (size_t i = 0; i < block->oplist.size(); i++) { shil_opcode& op = block->oplist[i]; switch (op.op) { case shop_ifb: if (op.rs1._imm) { mov(rax, (size_t)&next_pc); mov(dword[rax], op.rs2._imm); } mov(call_regs[0], op.rs3._imm); call(OpDesc[op.rs3._imm]->oph); break; case shop_jdyn: { mov(rax, (size_t)op.rs1.reg_ptr()); mov(ecx, dword[rax]); if (op.rs2.is_imm()) { add(ecx, op.rs2._imm); } mov(dword[rax], ecx); } break; case shop_mov32: { verify(op.rd.is_reg()); verify(op.rs1.is_reg() || op.rs1.is_imm()); sh_to_reg(op.rs1, mov, ecx); reg_to_sh(op.rd, ecx); } break; case shop_mov64: { verify(op.rd.is_reg()); verify(op.rs1.is_reg() || op.rs1.is_imm()); sh_to_reg(op.rs1, mov, rcx); reg_to_sh(op.rd, rcx); } break; case shop_readm: { sh_to_reg(op.rs1, mov, call_regs[0]); sh_to_reg(op.rs3, add, call_regs[0]); u32 size = op.flags & 0x7f; if (size == 1) { call(ReadMem8); movsx(rcx, al); } else if (size == 2) { call(ReadMem16); movsx(rcx, ax); } else if (size == 4) { call(ReadMem32); mov(rcx, rax); } else if (size == 8) { call(ReadMem64); mov(rcx, rax); } else { die("1..8 bytes"); } if (size != 8) reg_to_sh(op.rd, ecx); else reg_to_sh(op.rd, rcx); } break; case shop_writem: { u32 size = op.flags & 0x7f; sh_to_reg(op.rs1, mov, call_regs[0]); sh_to_reg(op.rs3, add, call_regs[0]); if (size != 8) sh_to_reg(op.rs2, mov, call_regs[1]); else sh_to_reg(op.rs2, mov, call_regs64[1]); if (size == 1) call(WriteMem8); else if (size == 2) call(WriteMem16); else if (size == 4) call(WriteMem32); else if (size == 8) call(WriteMem64); else { die("1..8 bytes"); } } break; default: shil_chf[op.op](&op); break; } } verify(block->BlockType == BET_DynamicJump); add(rsp, 0x28); ret(); ready(); block->code = (DynarecCodeEntryPtr)getCode(); emit_Skip(getSize()); }
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) { mov(rax, (size_t)&cycle_counter); sub(dword[rax], block->guest_cycles); sub(rsp, 0x28); for (size_t i = 0; i < block->oplist.size(); i++) { shil_opcode& op = block->oplist[i]; switch (op.op) { case shop_ifb: if (op.rs1._imm) { mov(rax, (size_t)&next_pc); mov(dword[rax], op.rs2._imm); } mov(call_regs[0], op.rs3._imm); call((void*)OpDesc[op.rs3._imm]->oph); break; case shop_jcond: case shop_jdyn: { mov(rax, (size_t)op.rs1.reg_ptr()); mov(ecx, dword[rax]); if (op.rs2.is_imm()) { add(ecx, op.rs2._imm); } mov(rdx, (size_t)op.rd.reg_ptr()); mov(dword[rdx], ecx); } break; case shop_mov32: { verify(op.rd.is_reg()); verify(op.rs1.is_reg() || op.rs1.is_imm()); sh_to_reg(op.rs1, mov, ecx); reg_to_sh(op.rd, ecx); } break; case shop_mov64: { verify(op.rd.is_reg()); verify(op.rs1.is_reg() || op.rs1.is_imm()); sh_to_reg(op.rs1, mov, rcx); reg_to_sh(op.rd, rcx); } break; case shop_readm: { sh_to_reg(op.rs1, mov, call_regs[0]); sh_to_reg(op.rs3, add, call_regs[0]); u32 size = op.flags & 0x7f; if (size == 1) { call((void*)ReadMem8); movsx(rcx, al); } else if (size == 2) { call((void*)ReadMem16); movsx(rcx, ax); } else if (size == 4) { call((void*)ReadMem32); mov(rcx, rax); } else if (size == 8) { call((void*)ReadMem64); mov(rcx, rax); } else { die("1..8 bytes"); } if (size != 8) reg_to_sh(op.rd, ecx); else reg_to_sh(op.rd, rcx); } break; case shop_writem: { u32 size = op.flags & 0x7f; sh_to_reg(op.rs1, mov, call_regs[0]); sh_to_reg(op.rs3, add, call_regs[0]); if (size != 8) sh_to_reg(op.rs2, mov, call_regs[1]); else sh_to_reg(op.rs2, mov, call_regs64[1]); if (size == 1) call((void*)WriteMem8); else if (size == 2) call((void*)WriteMem16); else if (size == 4) call((void*)WriteMem32); else if (size == 8) call((void*)WriteMem64); else { die("1..8 bytes"); } } break; default: shil_chf[op.op](&op); break; } } mov(rax, (size_t)&next_pc); switch (block->BlockType) { case BET_StaticJump: case BET_StaticCall: //next_pc = block->BranchBlock; mov(dword[rax], block->BranchBlock); break; case BET_Cond_0: case BET_Cond_1: { //next_pc = next_pc_value; //if (*jdyn == 0) //next_pc = branch_pc_value; mov(dword[rax], block->NextBlock); if (block->has_jcond) mov(rdx, (size_t)&Sh4cntx.jdyn); else mov(rdx, (size_t)&sr.T); cmp(dword[rdx], block->BlockType & 1); Xbyak::Label branch_not_taken; jne(branch_not_taken, T_SHORT); mov(dword[rax], block->BranchBlock); L(branch_not_taken); } break; case BET_DynamicJump: case BET_DynamicCall: case BET_DynamicRet: //next_pc = *jdyn; mov(rdx, (size_t)&Sh4cntx.jdyn); mov(edx, dword[rdx]); mov(dword[rax], edx); break; case BET_DynamicIntr: case BET_StaticIntr: if (block->BlockType == BET_DynamicIntr) { //next_pc = *jdyn; mov(rdx, (size_t)&Sh4cntx.jdyn); mov(edx, dword[rdx]); mov(dword[rax], edx); } else { //next_pc = next_pc_value; mov(dword[rax], block->NextBlock); } call((void*)UpdateINTC); break; default: die("Invalid block end type"); } add(rsp, 0x28); ret(); ready(); block->code = (DynarecCodeEntryPtr)getCode(); emit_Skip(getSize()); }