1613 lines
48 KiB
C
1613 lines
48 KiB
C
#define ppc_carry(a, b) (b < a) ? ppc_state.spr[SPR::XER] |= 0x20000000UL : ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL
|
|
#define ppc_carry_sub(a, b) (b >= a) ? ppc_state.spr[SPR::XER] |= 0x20000000UL : ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL
|
|
#define ppc_setsoov(a, b, d) ((a ^ b) & (a ^ d) & 0x80000000UL) ? ppc_state.spr[SPR::XER] |= 0xC0000000UL : ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL
|
|
|
|
GEN_OP(addi, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + code->simm;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(adde, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
uint32_t val_a = ppc_state.gpr[code->d2];
|
|
uint32_t val_b = ppc_state.gpr[code->d3];
|
|
|
|
uint32_t result = val_a + val_b + xer_ca;
|
|
if ((result < val_a) || (xer_ca && (result == val_a))) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_state.gpr[code->d1] = result;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(addze, {
|
|
uint32_t val_a = ppc_state.gpr[code->d2];
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
uint32_t result = val_a + xer_ca;
|
|
if (result < val_a) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_state.gpr[code->d1] = result;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(andidot, {
|
|
uint32_t result = ppc_state.gpr[code->d1] & code->uimm;
|
|
ppc_state.gpr[code->d2] = result;
|
|
ppc_changecrf0(result);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lwz, {
|
|
ppc_state.gpr[code->d1] = (mem_grab_dword((
|
|
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lwzu, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
ppc_state.gpr[code->d1] = mem_grab_dword(ea);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lbz, {
|
|
ppc_state.gpr[code->d1] = (mem_grab_byte((
|
|
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lhz, {
|
|
ppc_state.gpr[code->d1] = (mem_grab_word((
|
|
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(rlwinm, {
|
|
uint32_t val_s = ppc_state.gpr[code->d1];
|
|
uint32_t r = ((val_s << code->d3) | (val_s >> (32 - code->d3)));
|
|
uint32_t result = r & code->uimm;
|
|
ppc_state.gpr[code->d2] = result;
|
|
|
|
if (code->d4) {
|
|
ppc_changecrf0(result);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(srawidot, {
|
|
uint32_t val_s = ppc_state.gpr[code->d1];
|
|
uint32_t result = (int32_t)val_s >> code->d2;
|
|
if ((val_s & 0x80000000UL) && (val_s & code->uimm)) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_state.gpr[code->d2] = result;
|
|
ppc_changecrf0(result);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(bc, {
|
|
if (ppc_state.cr & code->uimm) {
|
|
#if defined(USE_DTC)
|
|
code += code->bt;
|
|
goto *(code->call_me);
|
|
#else
|
|
interp_tpc += code->bt;
|
|
#endif
|
|
} else {
|
|
NEXT;
|
|
}
|
|
})
|
|
|
|
GEN_OP(mtspr, {
|
|
ppc_state.spr[code->uimm] = ppc_state.gpr[code->d1];
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(mfspr, {
|
|
ppc_state.gpr[code->d1] = ppc_state.spr[code->uimm];
|
|
})
|
|
|
|
GEN_OP(bdnz, {
|
|
if (--ppc_state.spr[SPR::CTR]) {
|
|
#if defined(USE_DTC)
|
|
code += code->bt;
|
|
goto *(code->call_me);
|
|
#else
|
|
interp_tpc += code->bt;
|
|
#endif
|
|
} else {
|
|
NEXT;
|
|
}
|
|
})
|
|
|
|
GEN_OP(bdz, {
|
|
if (!(--ppc_state.spr[SPR::CTR])) {
|
|
#if defined(USE_DTC)
|
|
code += code->bt;
|
|
goto *(code->call_me);
|
|
#else
|
|
interp_tpc += code->bt;
|
|
#endif
|
|
} else {
|
|
NEXT;
|
|
}
|
|
})
|
|
|
|
GEN_OP(bclr, {
|
|
// PLACEHOLDER
|
|
})
|
|
|
|
GEN_OP(bexit, {
|
|
ppc_state.pc = code->uimm; // write source pc
|
|
#if defined(USE_DTC)
|
|
return;
|
|
#else
|
|
interp_running = false;
|
|
#endif
|
|
})
|
|
|
|
GEN_OP(twi, {
|
|
if ((((int32_t)ppc_state.gpr[code->d2] < code->simm) && (code->d1 & 0x10)) ||
|
|
(((int32_t)ppc_state.gpr[code->d2] > code->simm) && (code->d1 & 0x08)) ||
|
|
(((int32_t)ppc_state.gpr[code->d2] == code->simm) && (code->d1 & 0x04)) ||
|
|
((ppc_state.gpr[code->d2] < (uint32_t)code->simm) && (code->d1 & 0x02)) ||
|
|
((ppc_state.gpr[code->d2] > (uint32_t)code->simm) && (code->d1 & 0x01))) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(mulli, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] * (int64_t)(int32_t)code->simm;
|
|
ppc_state.gpr[code->d1] = (uint32_t)product;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(subfic, {
|
|
ppc_state.gpr[code->d1] = code->simm - ppc_state.gpr[code->d2];
|
|
|
|
if (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(cmpli, {
|
|
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (ppc_state.gpr[code->d2] == uimm)
|
|
? 0x20000000UL
|
|
: (ppc_state.gpr[code->d2] > uimm) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> code->d1)) | ((cmp_c + xercon) >> code->d1));
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(cmpi, {
|
|
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (code->d2 == code->simm)
|
|
? 0x20000000UL
|
|
: (ppc_state.gpr[code->d2] > uimm) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> code->d1)) | ((cmp_c + xercon) >> code->d1));
|
|
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(addic, {
|
|
ppc_state.gpr[code->d1] = (ppc_state.gpr[code->d2] + code->simm);
|
|
|
|
if (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(addicdot, {
|
|
ppc_state.gpr[code->d1] = (ppc_state.gpr[code->d2] + code->simm);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
|
|
if (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(addis, {
|
|
ppc_state.gpr[code->d1] = (code->d2 == 0) ? (code->simm << 16)
|
|
: ppc_state.gpr[code->d2] + code->simm;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(sc, { ppc_exception_handler(Except_Type::EXC_SYSCALL, 0x20000); })
|
|
|
|
GEN_OP(rlwimix, {
|
|
uint32_t val_s = ppc_state.gpr[code->d1];
|
|
uint32_t rotator = ((val_s << code->d3) | (val_s >> (32 - code->d3)));
|
|
ppc_state.gpr[code->d2] = (ppc_state.gpr[code->d2] & ~code->uimm) | (rotator & code->uimm);
|
|
if (code->d4) {
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
}
|
|
})
|
|
|
|
GEN_OP(rlwnmx, {
|
|
uint32_t val_s = ppc_state.gpr[code->d1];
|
|
uint32_t r = ((val_s << ppc_state.gpr[code->d3]) | (val_s >> (32 - ppc_state.gpr[code->d3])));
|
|
ppc_state.gpr[code->d2] = r & code->uimm;
|
|
if (code->d4) {
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
}
|
|
})
|
|
|
|
GEN_OP(ori, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | code->uimm;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(oris, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | (code->uimm << 16);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(xori, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] ^ code->uimm;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(xoris, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] ^ (code->uimm << 16);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(andisdot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] & (code->uimm << 16);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lbzu, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
ppc_state.gpr[code->d1] = mem_grab_byte(ea);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(stw, {
|
|
mem_write_dword((((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm),
|
|
ppc_state.gpr[code->d1]);
|
|
NEXT;
|
|
})
|
|
|
|
|
|
GEN_OP(stwu, {
|
|
if (reg_a != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_dword(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
|
|
GEN_OP(stb, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_byte(ea, ppc_state.gpr[code->d1]);
|
|
NEXT;
|
|
})
|
|
|
|
|
|
GEN_OP(stbu, {
|
|
if (reg_a != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_byte(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lhzu, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
ppc_state.gpr[code->d1] = mem_grab_word(ea);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lha, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
ppc_state.gpr[code->d1] = (int32_t)(int16_t)mem_grab_word(ea);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lhaux, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (int32_t)(int16_t)mem_grab_word(ea);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(sth, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_word(ea, ppc_state.gpr[code->d1]);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(sthu, {
|
|
if (reg_a != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_word(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lmw, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
do {
|
|
ppc_state.gpr[(code->d1)] = mem_grab_dword(ea);
|
|
ea += 4;
|
|
(code->d1)++;
|
|
} while (code->d1 < 32);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(stmw, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
|
|
|
|
if (ea & 3) {
|
|
ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000);
|
|
}
|
|
|
|
for (; code->d1 <= 31; code->d1++) {
|
|
mem_write_dword(ea, ppc_state.gpr[code->d1]);
|
|
ea += 4;
|
|
}
|
|
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lfs, {
|
|
uint64_t ppc_rep = (uint64_t)(
|
|
mem_grab_dword(((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
|
|
|
|
ppc_state.fpr[code->d1].int64_r = ppc_rep;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&ppc_rep;
|
|
NEXT;
|
|
})
|
|
|
|
|
|
GEN_OP(lfsu, {
|
|
if ((code->d2) == 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
uint64_t ppc_rep = (double)((uint64_t)mem_grab_dword(ea));
|
|
|
|
ppc_state.fpr[code->d1].int64_r = ppc_rep;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&ppc_rep;
|
|
ppc_state.gpr[code->d2] = ea;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lfd, {
|
|
uint64_t ppc_rep =
|
|
(double)(mem_grab_qword(((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
|
|
|
|
ppc_state.fpr[code->d1].int64_r = ppc_rep;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&ppc_rep;
|
|
|
|
NEXT;
|
|
})
|
|
|
|
|
|
GEN_OP(lfdu, {
|
|
if ((code->d2) == 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
uint64_t ppc_rep = (double)((uint64_t)mem_grab_qword(ea));
|
|
|
|
ppc_state.fpr[code->d1].int64_r = ppc_rep;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&ppc_rep;
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(stfs, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_dword(ea, uint32_t(ppc_state.fpr[code->d1].int64_r));
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(stfsu, {
|
|
if (code->d2 == 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_dword(ea, uint32_t(ppc_state.fpr[code->d1].int64_r));
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(stfd, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
|
|
})
|
|
|
|
GEN_OP(stfdu, {
|
|
ppc_grab_regsfpsia(true);
|
|
if (reg_a == 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(stfdx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_qword(ea, ppc_state.fpr[code->d1].int64_r);
|
|
})
|
|
|
|
// placeholders until I can figure out how to refactor these fully
|
|
GEN_OP(bcl, {})
|
|
GEN_OP(bca, {})
|
|
GEN_OP(bcla, {})
|
|
GEN_OP(b, {})
|
|
GEN_OP(bl, {})
|
|
GEN_OP(ba, {})
|
|
GEN_OP(bla, {})
|
|
GEN_OP(bclrl, {})
|
|
GEN_OP(rfi, {})
|
|
GEN_OP(isync, {})
|
|
|
|
GEN_OP(bcctr, {})
|
|
GEN_OP(bcctrl, {})
|
|
// back to real code!
|
|
|
|
GEN_OP(crnor, {
|
|
if (!((ppc_state.cr & (0x80000000UL >> code->d2)) || (ppc_state.cr & (0x80000000UL >> code->d3)))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(crandc, {
|
|
if ((ppc_state.cr & (0x80000000UL >> code->d2)) && !(ppc_state.cr & (0x80000000UL >> code->d3))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(crxor, {
|
|
if ((ppc_state.cr & (0x80000000UL >> code->d2)) ^ (ppc_state.cr & (0x80000000UL >> code->d3))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(crnand, {
|
|
if (!((ppc_state.cr & (0x80000000UL >> code->d2)) && (ppc_state.cr & (0x80000000UL >> code->d3)))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(crand, {
|
|
if ((ppc_state.cr & (0x80000000UL >> code->d2)) && (ppc_state.cr & (0x80000000UL >> code->d3))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(creqv, {
|
|
if (!((ppc_state.cr & (0x80000000UL >> code->d2)) ^ (ppc_state.cr & (0x80000000UL >> code->d3)))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(crorc, {
|
|
if ((ppc_state.cr & (0x80000000UL >> code->d2)) || !(ppc_state.cr & (0x80000000UL >> code->d3))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
GEN_OP(cror, {
|
|
if ((ppc_state.cr & (0x80000000UL >> code->d2)) || (ppc_state.cr & (0x80000000UL >> code->d3))) {
|
|
ppc_state.cr |= (0x80000000UL >> code->d1);
|
|
} else {
|
|
ppc_state.cr &= ~(0x80000000UL >> code->d1);
|
|
}
|
|
})
|
|
|
|
|
|
GEN_OP(cmp, {
|
|
uint32_t xer_in = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
uint32_t cmp_in = (((int32_t)ppc_state.gpr[code->d2]) == ((int32_t)ppc_state.gpr[code->d3]))
|
|
? 0x20000000UL
|
|
: (((int32_t)ppc_state.gpr[code->d2]) > ((int32_t)ppc_state.gpr[code->d3])) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.cr =
|
|
((ppc_state.cr & ~(0xf0000000UL >> (code->d1 & 0x1C))) |
|
|
((cmp_in + xer_in) >> (code->d1 & 0x1C)));
|
|
})
|
|
|
|
GEN_OP(tw, {
|
|
if ((((int32_t)ppc_state.gpr[code->d2] < (int32_t)ppc_state.gpr[code->d3]) && (code->d1 & 0x10)) ||
|
|
(((int32_t)ppc_state.gpr[code->d2] > (int32_t)ppc_state.gpr[code->d3]) && (code->d1 & 0x08)) ||
|
|
(((int32_t)ppc_state.gpr[code->d2] == (int32_t)ppc_state.gpr[code->d3]) && (code->d1 & 0x04)) ||
|
|
((ppc_state.gpr[code->d2] < ppc_state.gpr[code->d3]) && (code->d1 & 0x02)) ||
|
|
((ppc_state.gpr[code->d2] > ppc_state.gpr[code->d3]) && (code->d1 & 0x01))) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(subfc, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
ppc_carry_sub(ppc_state.gpr[code->d2], ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(subfcdot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
ppc_carry_sub(ppc_state.gpr[code->d2], ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(addc, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] + ppc_state.gpr[code->d2];
|
|
ppc_carry(ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(addcdot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] + ppc_state.gpr[code->d2];
|
|
ppc_carry(ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(mulhwu, {
|
|
uint64_t product = (uint64_t)ppc_state.gpr[code->d3] * (uint64_t)ppc_state.gpr[code->d2];
|
|
ppc_state.gpr[code->d1] = (uint32_t)(product >> 32);
|
|
})
|
|
|
|
GEN_OP(mulhwudot, {
|
|
uint64_t product = (uint64_t)ppc_state.gpr[code->d3] * (uint64_t)ppc_state.gpr[code->d2];
|
|
ppc_state.gpr[code->d1] = (uint32_t)(product >> 32);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(mfmsr, {
|
|
if (ppc_state.msr & 0x4000) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x00040000);
|
|
}
|
|
|
|
ppc_state.gpr[code->d1] = ppc_state.msr;
|
|
})
|
|
|
|
GEN_OP(dcbf, {})
|
|
|
|
GEN_OP(lbzx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = mem_grab_byte(ea);
|
|
})
|
|
|
|
GEN_OP(neg, {
|
|
ppc_state.gpr[code->d1] = ~(ppc_state.gpr[code->d2]) + 1;
|
|
})
|
|
|
|
GEN_OP(negdot, {
|
|
ppc_state.gpr[code->d1] = ~(ppc_state.gpr[code->d2]) + 1;
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(mul, {
|
|
uint64_t product = ((uint64_t)ppc_state.gpr[code->d2]) * ((uint64_t)ppc_state.gpr[code->d3]);
|
|
ppc_state.gpr[code->d1] = ((uint32_t)(product >> 32));
|
|
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
|
})
|
|
|
|
GEN_OP(muldot, {
|
|
uint64_t product = ((uint64_t)ppc_state.gpr[code->d2]) * ((uint64_t)ppc_state.gpr[code->d3]);
|
|
ppc_state.gpr[code->d1] = ((uint32_t)(product >> 32));
|
|
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(lbzux, {
|
|
if ((ppc_state.gpr[code->d2] != ppc_state.gpr[code->d3]) || ppc_state.gpr[code->d2] != 0) {
|
|
ppc_effective_address = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = mem_grab_byte(ppc_effective_address);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(nor, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] | ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(nordot, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] | ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(subfe, {
|
|
uint32_t grab_xer = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3] + grab_xer;
|
|
if (ppc_state.gpr[code->d3] < ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(subfedot, {
|
|
uint32_t grab_xer = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3] + grab_xer;
|
|
if (ppc_state.gpr[code->d3] < ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(addedot, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
uint32_t val_a = ppc_state.gpr[code->d2];
|
|
uint32_t val_b = ppc_state.gpr[code->d3];
|
|
|
|
uint32_t result = val_a + val_b + xer_ca;
|
|
if ((result < val_a) || (xer_ca && (result == val_a))) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_state.gpr[code->d1] = result;
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(mtcrf, {
|
|
crm = ((opcode >> 12) & 255);
|
|
// check this
|
|
uint32_t cr_mask = (crm & 128) ? 0xF0000000 : 0x00000000;
|
|
cr_mask += (crm & 64) ? 0x0F000000 : 0x00000000;
|
|
cr_mask += (crm & 32) ? 0x00F00000 : 0x00000000;
|
|
cr_mask += (crm & 16) ? 0x000F0000 : 0x00000000;
|
|
cr_mask += (crm & 8) ? 0x0000F000 : 0x00000000;
|
|
cr_mask += (crm & 4) ? 0x00000F00 : 0x00000000;
|
|
cr_mask += (crm & 2) ? 0x000000F0 : 0x00000000;
|
|
cr_mask += (crm & 1) ? 0x0000000F : 0x00000000;
|
|
ppc_state.cr = (ppc_result_d & cr_mask) | (ppc_state.cr & ~(cr_mask));
|
|
})
|
|
|
|
GEN_OP(mtmsr, {
|
|
if (ppc_state.msr & 0x4000) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x00040000);
|
|
}
|
|
|
|
ppc_state.msr = ppc_state.gpr[code->d1];
|
|
})
|
|
|
|
GEN_OP(stwcx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
if (ppc_state.reserve) {
|
|
mem_write_dword(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
|
|
ppc_state.reserve = false;
|
|
} else {
|
|
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x10000000 : 0;
|
|
}
|
|
})
|
|
|
|
GEN_OP(stwx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ppc_effective_address, ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(stwux, {
|
|
uint32_t ea = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
})
|
|
|
|
GEN_OP(mtsr, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1];
|
|
})
|
|
|
|
GEN_OP(nego, {
|
|
ppc_state.gpr[code->d1] = ~(ppc_state.gpr[code->d2]) + 1;
|
|
|
|
if (ppc_state.gpr[code->d2] == 0x80000000)
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
else
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFF;
|
|
})
|
|
|
|
GEN_OP(negodot, {
|
|
ppc_state.gpr[code->d1] = ~(ppc_state.gpr[code->d2]) + 1;
|
|
|
|
if (oe_flag) {
|
|
if (ppc_result_a == 0x80000000)
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
else
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFF;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(mfcr, {
|
|
ppc_state.gpr[code->d1] = ppc_state.cr;
|
|
})
|
|
|
|
GEN_OP(lwarx, {
|
|
ppc_state.reserve = true;
|
|
ppc_state.gpr[code->d1] =
|
|
(mem_grab_dword(((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3]));
|
|
})
|
|
|
|
GEN_OP(lwzx, {
|
|
ppc_state.gpr[code->d1] =
|
|
(mem_grab_dword(((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3]));
|
|
})
|
|
|
|
GEN_OP(slw, {
|
|
ppc_state.gpr[code->d2] =
|
|
((ppc_state.gpr[code->d3] > 0x1F) ? 0 : ppc_state.gpr[code->d1] << (ppc_state.gpr[code->d3] & 0x1F));
|
|
})
|
|
|
|
GEN_OP(slwdot, {
|
|
ppc_state.gpr[code->d2] =
|
|
((ppc_state.gpr[code->d3] > 0x1F) ? 0 : ppc_state.gpr[code->d1] << (ppc_state.gpr[code->d3] & 0x1F));
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(srw, {
|
|
ppc_state.gpr[code->d2] =
|
|
((ppc_state.gpr[code->d3] > 0x1F)
|
|
? 0
|
|
: ppc_state.gpr[code->d1] >> (ppc_state.gpr[code->d3] & 0x1F));
|
|
})
|
|
|
|
GEN_OP(srwdot, {
|
|
ppc_state.gpr[code->d2] =
|
|
((ppc_state.gpr[code->d3] > 0x1F)
|
|
? 0
|
|
: ppc_state.gpr[code->d1] >> (ppc_state.gpr[code->d3] & 0x1F));
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(cntlzw, {
|
|
uint32_t lead = 0;
|
|
uint32_t bit_check = ppc_state.gpr[code->d1];
|
|
|
|
#ifdef USE_GCC_BUILTINS
|
|
lead = __builtin_clz(bit_check);
|
|
#elif defined USE_VS_BUILTINS
|
|
lead = __lzcnt(bit_check);
|
|
#else
|
|
for (uint32_t mask = 0x80000000UL; mask; lead++, mask >>= 1) {
|
|
if (bit_check & mask)
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
ppc_state.gpr[code->d2] = lead;
|
|
})
|
|
|
|
GEN_OP(cntlzwdot, {
|
|
uint32_t lead = 0;
|
|
uint32_t bit_check = ppc_state.gpr[code->d1];
|
|
|
|
#ifdef USE_GCC_BUILTINS
|
|
lead = __builtin_clz(bit_check);
|
|
#elif defined USE_VS_BUILTINS
|
|
lead = __lzcnt(bit_check);
|
|
#else
|
|
for (uint32_t mask = 0x80000000UL; mask; lead++, mask >>= 1) {
|
|
if (bit_check & mask)
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
ppc_state.gpr[code->d2] = lead;
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(ppc_and, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] & ppc_state.gpr[code->d3];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(anddot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] & ppc_state.gpr[code->d3];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(orc, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | ~(ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(orcdot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | ~(ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(ppc_or, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | ppc_state.gpr[code->d3];
|
|
})
|
|
|
|
GEN_OP(ordot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] | ppc_state.gpr[code->d3];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(xor, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] ^ ppc_state.gpr[code->d3];
|
|
})
|
|
|
|
GEN_OP(xordot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] ^ ppc_state.gpr[code->d3];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(eqv, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] ^ ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(eqvdot, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] ^ ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(nand, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] & ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(nanddot, {
|
|
ppc_state.gpr[code->d2] = ~(ppc_state.gpr[code->d1] & ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(cmpl, {
|
|
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (ppc_state.gpr[code->d2] == ppc_state.gpr[code->d3])
|
|
? 0x20000000UL
|
|
: (ppc_state.gpr[code->d2] > ppc_state.gpr[code->d3]) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> code->d1)) | ((cmp_c + xercon) >> code->d1));
|
|
})
|
|
|
|
GEN_OP(subf, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
})
|
|
|
|
GEN_OP(subfdot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(dcbst, {
|
|
})
|
|
|
|
GEN_OP(lwzux, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
ppc_result_d = mem_grab_dword((ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3]));
|
|
ppc_result_a = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(andc, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] & ~(ppc_state.gpr[code->d3]);
|
|
})
|
|
|
|
GEN_OP(andcdot, {
|
|
ppc_state.gpr[code->d2] = ppc_state.gpr[code->d1] & ~(ppc_state.gpr[code->d3]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(mulhw, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] *
|
|
(int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = product >> 32;
|
|
})
|
|
|
|
GEN_OP(mulhwdot, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] *
|
|
(int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_result_d = product >> 32;
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(mullw, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] * (int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (uint32_t)product;
|
|
})
|
|
|
|
GEN_OP(mullwdot, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] * (int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (uint32_t)product;
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(mullwo, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] * (int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (uint32_t)product;
|
|
if (product != (int64_t)(int32_t)product) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(mullwodot, {
|
|
int64_t product = (int64_t)(int32_t)ppc_state.gpr[code->d2] * (int64_t)(int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (uint32_t)product;
|
|
if (product != (int64_t)(int32_t)product) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfco, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
|
|
if (ppc_state.gpr[code->d1] >= ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
if ((ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d3]) &
|
|
(ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d1]) & 0x80000000UL) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(subfcodot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
|
|
if (ppc_state.gpr[code->d1] >= ppc_state.gpr[code->d2]) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
if ((ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d3]) &
|
|
(ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d1]) & 0x80000000UL) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(lhbrx, {
|
|
uint32_t ea = ((code->d1 == 0) ? ppc_state.gpr[code->d3] : 0) + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = (uint32_t)(BYTESWAP_16(mem_grab_word(ppc_effective_address)));
|
|
})
|
|
|
|
GEN_OP(sraw, {
|
|
if (ppc_state.gpr[code->d3] & 0x20) {
|
|
ppc_state.gpr[code->d2] = (int32_t)ppc_state.gpr[code->d1] >> 31;
|
|
ppc_state.spr[SPR::XER] |= (ppc_state.gpr[code->d2] & 1) << 29;
|
|
} else {
|
|
uint32_t shift = ppc_state.gpr[code->d3] & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_state.gpr[code->d2] = (int32_t)ppc_state.gpr[code->d1] >> shift;
|
|
if ((ppc_state.gpr[code->d1] & 0x80000000UL) && (ppc_state.gpr[code->d1] & mask)) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
})
|
|
|
|
GEN_OP(srawdot, {
|
|
if (ppc_state.gpr[code->d3] & 0x20) {
|
|
ppc_state.gpr[code->d2] = (int32_t)ppc_state.gpr[code->d1] >> 31;
|
|
ppc_state.spr[SPR::XER] |= (ppc_state.gpr[code->d2] & 1) << 29;
|
|
} else {
|
|
uint32_t shift = ppc_state.gpr[code->d3] & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_state.gpr[code->d2] = (int32_t)ppc_state.gpr[code->d1] >> shift;
|
|
if ((ppc_state.gpr[code->d1] & 0x80000000UL) && (ppc_state.gpr[code->d1] & mask)) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(srawi, {
|
|
uint32_t val_s = ppc_state.gpr[code->d1];
|
|
uint32_t result = (int32_t)val_s >> code->d2;
|
|
if ((val_s & 0x80000000UL) && (val_s & code->uimm)) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_state.gpr[code->d2] = result;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(eieio, {})
|
|
|
|
GEN_OP(sthbrx, {
|
|
uint32_t ea = (code->d2 == 0) ? ppc_state.gpr[code->d3]
|
|
: (ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3]);
|
|
uint32_t val1 = (uint32_t)(BYTESWAP_16((uint16_t)ppc_state.gpr[code->d1]));
|
|
mem_write_word(ea, val1);
|
|
})
|
|
|
|
GEN_OP(extsb, {
|
|
ppc_state.gpr[code->d2] = (int32_t)(int8_t)ppc_state.gpr[code->d1];
|
|
})
|
|
|
|
GEN_OP(extsbdot, {
|
|
ppc_state.gpr[code->d2] = (int32_t)(int8_t)ppc_state.gpr[code->d1];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(extsh, {
|
|
ppc_state.gpr[code->d2] = (int32_t)(int16_t)ppc_state.gpr[code->d1];
|
|
})
|
|
|
|
GEN_OP(extshdot, {
|
|
ppc_state.gpr[code->d2] = (int32_t)(int16_t)ppc_state.gpr[code->d1];
|
|
ppc_changecrf0(ppc_state.gpr[code->d2]);
|
|
})
|
|
|
|
GEN_OP(divwu, {
|
|
if (!ppc_state.gpr[code->d3]) { /* division by zero */
|
|
ppc_state.gpr[code->d1] = 0;
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
} else {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] / ppc_state.gpr[code->d3];
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(divwudot, {
|
|
if (!ppc_state.gpr[code->d3]) { /* division by zero */
|
|
ppc_result_d = 0;
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
ppc_state.cr |= 0x20000000;
|
|
} else {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] / ppc_state.gpr[code->d3];
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
ppc_changecrf0(ppc_result_d);
|
|
}
|
|
})
|
|
|
|
GEN_OP(tlbld, {})
|
|
|
|
GEN_OP(icbi, {})
|
|
|
|
GEN_OP(stfiwx, {
|
|
uint32_t ea = (code->d2 == 0) ? ppc_state.gpr[code->d3]
|
|
: ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ea, (uint32_t)(ppc_state.fpr[code->d1].int64_r));
|
|
})
|
|
|
|
GEN_OP(divwo, {
|
|
if (!ppc_state.gpr[code->d3]) { /* handle the "anything / 0" case */
|
|
ppc_state.gpr[code->d1] = (ppc_state.gpr[code->d2] & 0x80000000) ? -1
|
|
: 0; /* UNDOCUMENTED! */
|
|
|
|
if (oe_flag)
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
|
|
} else if (ppc_state.gpr[code->d2] == 0x80000000UL && ppc_state.gpr[code->d3] == 0xFFFFFFFFUL) {
|
|
ppc_state.gpr[code->d1] = 0xFFFFFFFF;
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
|
|
} else { /* normal signed devision */
|
|
ppc_state.gpr[code->d1] = (int32_t)ppc_state.gpr[code->d2] / (int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(divwodot, {
|
|
if (!ppc_state.gpr[code->d3]) { /* handle the "anything / 0" case */
|
|
ppc_state.gpr[code->d1] = (ppc_state.gpr[code->d2] & 0x80000000) ? -1
|
|
: 0; /* UNDOCUMENTED! */
|
|
|
|
if (oe_flag)
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
|
|
} else if (ppc_state.gpr[code->d2] == 0x80000000UL && ppc_state.gpr[code->d3] == 0xFFFFFFFFUL) {
|
|
ppc_state.gpr[code->d1] = 0xFFFFFFFF;
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000;
|
|
|
|
} else { /* normal signed devision */
|
|
ppc_state.gpr[code->d1] = (int32_t)ppc_state.gpr[code->d2] / (int32_t)ppc_state.gpr[code->d3];
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(tlbli, {})
|
|
|
|
GEN_OP(dcbz, {
|
|
if (!(ppc_state.pc & 32) && (ppc_state.pc < 0xFFFFFFE0UL)) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_qword(ea, 0);
|
|
mem_write_qword((ea + 8), 0);
|
|
mem_write_qword((ea + 16), 0);
|
|
mem_write_qword((ea + 24), 0);
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(mcrxr, {
|
|
ppc_state.cr = (ppc_state.cr & ~(0xF0000000UL >> ppc_state.gpr[code->d1])) |
|
|
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> ppc_state.gpr[code->d1]);
|
|
ppc_state.spr[SPR::XER] &= 0x0FFFFFFF;
|
|
})
|
|
|
|
GEN_OP(subfze, {
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + (ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfzedot, {
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + (ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_result_d);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(mtsrin, {
|
|
if ((ppc_state.msr & 0x4000) == 0) {
|
|
uint32_t selection = ppc_state.gpr[code->d2] >> 28;
|
|
ppc_state.sr[selection] = code->d1;
|
|
}
|
|
})
|
|
|
|
GEN_OP(dcbtst, {})
|
|
|
|
GEN_OP(stbux, {
|
|
if (code->d2 != 0) {
|
|
uint32_t ea = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
mem_write_byte(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(add, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] + ppc_state.gpr[code->d2];
|
|
})
|
|
|
|
GEN_OP(adddot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] + ppc_state.gpr[code->d2];
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(dcbt, {})
|
|
|
|
GEN_OP(stfsx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ea, uint32_t(ppc_state.fpr[code->d1].int64_r));
|
|
})
|
|
|
|
GEN_OP(stfsux, {
|
|
if (code->d2 == 0) {
|
|
uint32_t ea = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ea, uint32_t(ppc_state.fpr[code->d1].int64_r));
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(lswx, {
|
|
if ((ppc_state.gpr[code->d1] == 0) && (ppc_state.gpr[code->d2] == 0)) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x100000);
|
|
}
|
|
if ((ppc_state.gpr[code->d1] == ppc_state.gpr[code->d2]) ||
|
|
(ppc_state.gpr[code->d2] == ppc_state.gpr[code->d3])) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x100000);
|
|
}
|
|
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
uint32_t words = ppc_state.spr[SPR::XER] & 0x7F;
|
|
uint32_t store_result = 0;
|
|
|
|
while (words > 0) {
|
|
switch (words) {
|
|
case 1:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
case 2:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
store_result += (mem_grab_byte(ea + 1)) << 16;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
case 3:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
store_result += (mem_grab_byte(ea + 1)) << 16;
|
|
store_result += (mem_grab_byte(ea + 2)) << 8;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
default:
|
|
ppc_state.gpr[code->d1] = mem_grab_dword(ea);
|
|
code->d1++;
|
|
ea += 4;
|
|
words -= 4;
|
|
}
|
|
}
|
|
})
|
|
|
|
GEN_OP(lswi, {
|
|
uint32_t ea = (code->d2) ? ppc_state.gpr[code->d2] : 0;
|
|
uint32_t words = (code->d3) ? code->d3 : 32;
|
|
uint32_t store_result = 0;
|
|
|
|
while (words > 0) {
|
|
switch (words) {
|
|
case 1:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
case 2:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
store_result += (mem_grab_byte(ea + 1)) << 16;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
case 3:
|
|
store_result = mem_grab_byte(ea) << 24;
|
|
store_result += (mem_grab_byte(ea + 1)) << 16;
|
|
store_result += (mem_grab_byte(ea + 2)) << 8;
|
|
ppc_state.gpr[code->d1] = store_result;
|
|
words = 0;
|
|
break;
|
|
default:
|
|
ppc_state.gpr[code->d1] = mem_grab_dword(ea);
|
|
code->d1++;
|
|
ea += 4;
|
|
words -= 4;
|
|
}
|
|
}
|
|
})
|
|
|
|
GEN_OP(stswx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
uint32_t words = ppc_state.spr[SPR::XER] & 0x7F;
|
|
while (words > 0) {
|
|
switch (words) {
|
|
case 1:
|
|
mem_write_byte(ea, (uint8_t)((ppc_state.gpr[code->d1]) >> 24));
|
|
words = 0;
|
|
break;
|
|
case 2:
|
|
mem_write_byte(ea, (uint8_t)((ppc_state.gpr[code->d1]) >> 24));
|
|
mem_write_byte((ea + 1), (uint8_t)((ppc_state.gpr[code->d1]) >> 16));
|
|
words = 0;
|
|
break;
|
|
case 3:
|
|
mem_write_byte(ea, (uint8_t)((ppc_state.gpr[code->d1]) >> 24));
|
|
mem_write_byte((ea + 1), (uint8_t)((ppc_state.gpr[code->d1]) >> 16));
|
|
mem_write_byte((ea + 2), (uint8_t)((ppc_state.gpr[code->d1]) >> 8));
|
|
words = 0;
|
|
break;
|
|
default:
|
|
mem_write_dword(ea, ((ppc_state.gpr[code->d1]) & 0xFF));
|
|
code->d1++;
|
|
ea += 4;
|
|
words -= 4;
|
|
}
|
|
}
|
|
})
|
|
|
|
GEN_OP(stswi, {
|
|
uint32_t ea = (code->d2) ? ppc_state.gpr[code->d2] : 0;
|
|
uint32_t words = (code->d3) ? code->d3 : 32;
|
|
while (words > 0) {
|
|
switch (words) {
|
|
case 1:
|
|
mem_write_byte(ea, (uint8_t)((ppc_state.gpr[code->d1]) >> 24));
|
|
words = 0;
|
|
break;
|
|
case 2:
|
|
mem_write_byte(ea, (((ppc_state.gpr[code->d1]) >> 24) & 0xFF));
|
|
mem_write_byte((ea + 1), (((ppc_state.gpr[code->d1]) >> 16) & 0xFF));
|
|
words = 0;
|
|
break;
|
|
case 3:
|
|
mem_write_byte(ea, (((ppc_state.gpr[code->d1]) >> 24) & 0xFF));
|
|
mem_write_byte((ea + 1), (((ppc_state.gpr[code->d1]) >> 16) & 0xFF));
|
|
mem_write_byte((ea + 2), (uint8_t)((ppc_state.gpr[code->d1]) >> 8));
|
|
words = 0;
|
|
break;
|
|
default:
|
|
mem_write_dword(ea, ((ppc_state.gpr[code->d1]) & 0xFF));
|
|
ea += 4;
|
|
words -= 4;
|
|
}
|
|
}
|
|
})
|
|
|
|
GEN_OP(tlbia, {})
|
|
|
|
GEN_OP(mftb, {
|
|
uint32_t ref_spr = (((opcode >> 11) & 31) << 5) | ((opcode >> 16) & 31);
|
|
code->d1 = (opcode >> 21) & 31;
|
|
switch (ref_spr) {
|
|
case 268:
|
|
ppc_state.gpr[code->d1] = timebase_counter & 0xFFFFFFFFUL;
|
|
break;
|
|
case 269:
|
|
ppc_state.gpr[code->d1] = (timebase_counter >> 32) & 0xFFFFFFFFUL;
|
|
break;
|
|
}
|
|
})
|
|
|
|
GEN_OP(stwbrx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_dword(ea, BYTESWAP_32(ppc_state.gpr[code->d1]));
|
|
})
|
|
|
|
GEN_OP(stfdux, {
|
|
if (code->d2 == 0) {
|
|
uint32_t ea = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
mem_write_qword(ea, ppc_state.fpr[code->d1].int64_r);
|
|
ppc_result_a = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(stbx, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_byte(ppc_effective_address, ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(subfme, {
|
|
uint32_t grab_xer = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + grab_xer - 1;
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfmedot, {
|
|
uint32_t grab_xer = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + grab_xer - 1;
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
ppc_setsoov(0xFFFFFFFF, ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfzeo, {
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + (ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_result_d);
|
|
ppc_setsoov(0, ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfzeodot, {
|
|
ppc_state.gpr[code->d1] = ~ppc_state.gpr[code->d2] + (ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_state.gpr[code->d2], ppc_result_d);
|
|
ppc_setsoov(0, ppc_state.gpr[code->d2], ppc_state.gpr[code->d1]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(addme, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + xer_ca - 1;
|
|
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_state.gpr[code->d2])) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(addmedot, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + xer_ca - 1;
|
|
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2])) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(addmeo, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + xer_ca - 1;
|
|
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2])) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
ppc_setsoov(ppc_state.gpr[code->d2], 0, ppc_result_d);
|
|
})
|
|
|
|
GEN_OP(addmeodot, {
|
|
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + xer_ca - 1;
|
|
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_state.gpr[code->d1] < ppc_state.gpr[code->d2])) {
|
|
ppc_state.spr[SPR::XER] |= 0x20000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
|
|
ppc_setsoov(ppc_state.gpr[code->d2], 0, ppc_state.gpr[code->d1]);
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(subfo, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
|
|
if ((ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d3]) &
|
|
(ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d1]) & 0x80000000UL) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
})
|
|
|
|
GEN_OP(subfodot, {
|
|
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d3] - ppc_state.gpr[code->d2];
|
|
|
|
if ((ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d3]) &
|
|
(ppc_state.gpr[code->d2] ^ ppc_state.gpr[code->d1]) & 0x80000000UL) {
|
|
ppc_state.spr[SPR::XER] |= 0xC0000000UL;
|
|
} else {
|
|
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_state.gpr[code->d1]);
|
|
})
|
|
|
|
GEN_OP(lhzx, {
|
|
ppc_effective_address = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = mem_grab_word(ppc_effective_address);
|
|
})
|
|
|
|
GEN_OP(lhzux, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
ppc_effective_address = ppc_state.gpr[code->d2] + ppc_state.gpr[code->d3];
|
|
ppc_state.gpr[code->d1] = mem_grab_word(ppc_effective_address);
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
|
|
|
|
GEN_OP(lhau, {
|
|
if ((code->d2 != code->d1) || code->d2 != 0) {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm;
|
|
uint16_t val = mem_grab_word(ea);
|
|
ppc_state.gpr[code->d1] = (int32_t)(int16_t)val;
|
|
ppc_state.gpr[code->d2] = ea;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lhax, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
uint16_t val = mem_grab_word(ea);
|
|
ppc_state.gpr[code->d1] = (int32_t)(int16_t)val;
|
|
})
|
|
|
|
GEN_OP(sthx, {
|
|
mem_write_word(((
|
|
(code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3]),
|
|
ppc_state.gpr[code->d1]);
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(sthux, {
|
|
uint32_t ea = ((code->d2) ? ppc_state.gpr[code->d2] : 0) + ppc_state.gpr[code->d3];
|
|
mem_write_word(ea, ppc_state.gpr[code->d1]);
|
|
ppc_state.gpr[code->d2] = ea;
|
|
NEXT;
|
|
})
|
|
|
|
GEN_OP(lfdx, {
|
|
uint32_t ea = (reg_a > 0) ? ppc_result_a + ppc_result_b : ppc_result_b;
|
|
uint64_t grab_flt = mem_grab_qword(ppc_effective_address);
|
|
ppc_state.fpr[code->d1].int64_r = grab_flt;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&grab_flt;
|
|
|
|
})
|
|
|
|
GEN_OP(lfdux, {
|
|
if (code->d2 == 0) {
|
|
uint32_t ea = code->d1 + ppc_state.gpr[code->d3];
|
|
uint64_t grab_flt = mem_grab_qword(ppc_effective_address);
|
|
ppc_state.fpr[code->d1].int64_r = grab_flt;
|
|
ppc_state.fpr[code->d1].dbl64_r = *(double*)&grab_flt;
|
|
ppc_state.gpr[code->d2] = ppc_effective_address;
|
|
} else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
})
|
|
|
|
GEN_OP(tlbie, {})
|
|
|
|
GEN_OP(lscbx, {})
|
|
|
|
GEN_OP(lscbxdot, {})
|
|
|
|
GEN_OP(dcbi, {})
|
|
|
|
GEN_OP(tlbsync, {})
|
|
|
|
GEN_OP(ppc_sync, {}) |