First attempt at splitting decoding and execution

This commit is contained in:
dingusdev
2024-09-14 22:12:07 -07:00
parent 02c8c8cde0
commit 0f6c32245b
7 changed files with 1038 additions and 1058 deletions

View File

@@ -37,13 +37,12 @@ static inline uint32_t power_rot_mask(unsigned rot_mb, unsigned rot_me) {
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_abs() {
uint32_t ppc_result_d;
ppc_grab_regsda(ppc_cur_instruction);
if (ppc_result_a == 0x80000000) {
ppc_result_d = ppc_result_a;
if (ppc_state.gpr[instr.arg1] == 0x80000000) {
ppc_result_d = ppc_state.gpr[instr.arg1];
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_result_d = (int32_t(ppc_result_a) < 0) ? -ppc_result_a : ppc_result_a;
ppc_result_d = (int32_t(ppc_state.gpr[instr.arg1]) < 0) ? -ppc_state.gpr[instr.arg1] : ppc_state.gpr[instr.arg1];
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
@@ -51,7 +50,7 @@ void dppc_interpreter::power_abs() {
if (rec)
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
}
template void dppc_interpreter::power_abs<RC0, OV0>();
@@ -60,36 +59,39 @@ template void dppc_interpreter::power_abs<RC1, OV0>();
template void dppc_interpreter::power_abs<RC1, OV1>();
void dppc_interpreter::power_clcs() {
uint32_t ppc_result_d;
ppc_grab_da(ppc_cur_instruction);
switch (reg_a) {
switch (ppc_state.gpr[instr.arg1]) {
case 12: //instruction cache line size
case 13: //data cache line size
case 14: //minimum line size
case 15: //maximum line size
default: ppc_result_d = is_601 ? 64 : 32; break;
default:
ppc_state.gpr[instr.arg0] = is_601 ? 64 : 32;
break;
case 7:
case 23: ppc_result_d = is_601 ? 64 : 0; break;
case 23:
ppc_state.gpr[instr.arg0] = is_601 ? 64 : 0;
break;
case 8:
case 9:
case 24:
case 25: ppc_result_d = is_601 ? 64 : 4; break;
case 25:
ppc_state.gpr[instr.arg0] = is_601 ? 64 : 4;
break;
case 10:
case 11:
case 26:
case 27: ppc_result_d = is_601 ? 64 : 0x4000; break;
case 27:
ppc_state.gpr[instr.arg0] = is_601 ? 64 : 0x4000;
break;
}
ppc_store_iresult_reg(reg_d, ppc_result_d);
}
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_div() {
uint32_t ppc_result_d;
ppc_grab_regsdab(ppc_cur_instruction);
int64_t dividend = (uint64_t(ppc_result_a) << 32) | ppc_state.spr[SPR::MQ];
int32_t divisor = ppc_result_b;
int64_t dividend = (uint64_t(ppc_state.gpr[instr.arg1]) << 32) | ppc_state.spr[SPR::MQ];
int32_t divisor = ppc_state.gpr[instr.arg2];
int64_t quotient;
int32_t remainder;
@@ -119,7 +121,7 @@ void dppc_interpreter::power_div() {
if (rec)
ppc_changecrf0(remainder);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
ppc_state.spr[SPR::MQ] = remainder;
}
@@ -132,28 +134,27 @@ template <field_rc rec, field_ov ov>
void dppc_interpreter::power_divs() {
uint32_t ppc_result_d;
int32_t remainder;
ppc_grab_regsdab(ppc_cur_instruction);
if (!ppc_result_b) { // handle the "anything / 0" case
if (!ppc_state.gpr[instr.arg2]) { // handle the "anything / 0" case
ppc_result_d = -1;
remainder = ppc_result_a;
remainder = ppc_state.gpr[instr.arg1];
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else if (ppc_result_a == 0x80000000U && ppc_result_b == 0xFFFFFFFFU) {
} else if (ppc_state.gpr[instr.arg1] == 0x80000000U && ppc_state.gpr[instr.arg2] == 0xFFFFFFFFU) {
ppc_result_d = 0x80000000U;
remainder = 0;
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else { // normal signed devision
ppc_result_d = int32_t(ppc_result_a) / int32_t(ppc_result_b);
remainder = (int32_t(ppc_result_a) % int32_t(ppc_result_b));
ppc_result_d = int32_t(ppc_state.gpr[instr.arg1]) / int32_t(ppc_state.gpr[instr.arg2]);
remainder = (int32_t(ppc_state.gpr[instr.arg1]) % int32_t(ppc_state.gpr[instr.arg2]));
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
if (rec)
ppc_changecrf0(remainder);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
ppc_state.spr[SPR::MQ] = remainder;
}
@@ -164,9 +165,8 @@ template void dppc_interpreter::power_divs<RC1, OV1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_doz() {
ppc_grab_regsdab(ppc_cur_instruction);
uint32_t ppc_result_d = (int32_t(ppc_result_a) < int32_t(ppc_result_b)) ?
ppc_result_b - ppc_result_a : 0;
uint32_t ppc_result_d = (int32_t(ppc_state.gpr[instr.arg1]) < int32_t(ppc_state.gpr[instr.arg2])) ?
ppc_state.gpr[instr.arg2] - ppc_state.gpr[instr.arg1] : 0;
if (ov) {
if (int32_t(ppc_result_d) < 0) {
@@ -178,7 +178,7 @@ void dppc_interpreter::power_doz() {
if (rec)
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
}
template void dppc_interpreter::power_doz<RC0, OV0>();
@@ -188,19 +188,17 @@ template void dppc_interpreter::power_doz<RC1, OV1>();
void dppc_interpreter::power_dozi() {
uint32_t ppc_result_d;
ppc_grab_regsdasimm(ppc_cur_instruction);
if (((int32_t)ppc_result_a) > simm) {
if (((int32_t)ppc_state.gpr[instr.arg1]) > instr.i_simm) {
ppc_result_d = 0;
} else {
ppc_result_d = simm - ppc_result_a;
ppc_result_d = instr.i_simm - ppc_state.gpr[instr.arg1];
}
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
}
template <field_rc rec>
void dppc_interpreter::power_lscbx() {
ppc_grab_regsdab(ppc_cur_instruction);
uint32_t ea = ppc_result_b + (reg_a ? ppc_result_a : 0);
uint32_t ea = ppc_state.gpr[instr.arg2] + (instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
uint32_t bytes_to_load = (ppc_state.spr[SPR::XER] & 0x7F);
uint32_t bytes_remaining = bytes_to_load;
@@ -216,9 +214,9 @@ void dppc_interpreter::power_lscbx() {
ppc_result_d |= return_value << shift_amount;
if (!shift_amount) {
if (reg_d != reg_a && reg_d != reg_b)
ppc_store_iresult_reg(reg_d, ppc_result_d);
reg_d = (reg_d + 1) & 0x1F;
if (instr.arg0 != instr.arg1 && instr.arg0 != instr.arg2)
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
instr.arg0 = (instr.arg0 + 1) & 0x1F;
ppc_result_d = 0;
shift_amount = 24;
} else {
@@ -235,8 +233,8 @@ void dppc_interpreter::power_lscbx() {
}
// store partially loaded register if any
if (shift_amount != 24 && reg_d != reg_a && reg_d != reg_b)
ppc_store_iresult_reg(reg_d, ppc_result_d);
if (shift_amount != 24 && instr.arg0 != instr.arg1 && instr.arg0 != instr.arg2)
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & ~0x7F) | (bytes_to_load - bytes_remaining);
@@ -253,9 +251,8 @@ template void dppc_interpreter::power_lscbx<RC1>();
template <field_rc rec>
void dppc_interpreter::power_maskg() {
ppc_grab_regssab(ppc_cur_instruction);
uint32_t mask_start = ppc_result_d & 0x1F;
uint32_t mask_end = ppc_result_b & 0x1F;
uint32_t mask_start = ppc_state.gpr[instr.arg0] & 0x1F;
uint32_t mask_end = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t insert_mask = 0;
if (mask_start < (mask_end + 1)) {
@@ -268,12 +265,12 @@ void dppc_interpreter::power_maskg() {
insert_mask = ~(power_rot_mask(mask_end + 1, mask_start - 1));
}
ppc_result_a = insert_mask;
ppc_state.gpr[instr.arg1] = insert_mask;
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_maskg<RC0>();
@@ -281,13 +278,11 @@ template void dppc_interpreter::power_maskg<RC1>();
template <field_rc rec>
void dppc_interpreter::power_maskir() {
ppc_grab_regssab(ppc_cur_instruction);
ppc_result_a = (ppc_result_a & ~ppc_result_b) | (ppc_result_d & ppc_result_b);
ppc_state.gpr[instr.arg1] = ((ppc_state.gpr[instr.arg1] & ~ppc_state.gpr[instr.arg2]) | \
(ppc_state.gpr[instr.arg0] & ppc_state.gpr[instr.arg2]));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_maskir<RC0>();
@@ -295,8 +290,7 @@ template void dppc_interpreter::power_maskir<RC1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_mul() {
ppc_grab_regsdab(ppc_cur_instruction);
int64_t product = int64_t(int32_t(ppc_result_a)) * int32_t(ppc_result_b);
int64_t product = int64_t(int32_t(ppc_state.gpr[instr.arg1])) * int32_t(ppc_state.gpr[instr.arg2]);
uint32_t ppc_result_d = uint32_t(uint64_t(product) >> 32);
ppc_state.spr[SPR::MQ] = uint32_t(product);
@@ -309,7 +303,7 @@ void dppc_interpreter::power_mul() {
}
if (rec)
ppc_changecrf0(uint32_t(product));
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
}
template void dppc_interpreter::power_mul<RC0, OV0>();
@@ -319,15 +313,14 @@ template void dppc_interpreter::power_mul<RC1, OV1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_nabs() {
ppc_grab_regsda(ppc_cur_instruction);
uint32_t ppc_result_d = (int32_t(ppc_result_a) < 0) ? ppc_result_a : -ppc_result_a;
uint32_t ppc_result_d = (int32_t(ppc_state.gpr[instr.arg1]) < 0) ? ppc_state.gpr[instr.arg1] : -ppc_state.gpr[instr.arg1];
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
if (rec)
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_store_iresult_reg(instr.arg0, ppc_result_d);
}
template void dppc_interpreter::power_nabs<RC0, OV0>();
@@ -336,37 +329,32 @@ template void dppc_interpreter::power_nabs<RC1, OV0>();
template void dppc_interpreter::power_nabs<RC1, OV1>();
void dppc_interpreter::power_rlmi() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_mb = (ppc_cur_instruction >> 6) & 0x1F;
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(rot_mb, rot_me);
uint32_t r =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(instr.arg3, instr.arg4);
ppc_result_a = ((r & mask) | (ppc_result_a & ~mask));
uint32_t ppc_result_a = ((r & mask) | (ppc_state.gpr[instr.arg1] & ~mask));
if ((ppc_cur_instruction & 0x01) == 1)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_result_a);
}
template <field_rc rec>
void dppc_interpreter::power_rrib() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
if (int32_t(ppc_result_d) < 0) {
ppc_result_a |= (0x80000000U >> rot_sh);
if (int32_t(ppc_state.gpr[instr.arg1]) < 0) {
ppc_state.gpr[instr.arg1] |= (0x80000000U >> rot_sh);
} else {
ppc_result_a &= ~(0x80000000U >> rot_sh);
ppc_state.gpr[instr.arg1] &= ~(0x80000000U >> rot_sh);
}
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_rrib<RC0>();
@@ -374,18 +362,18 @@ template void dppc_interpreter::power_rrib<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sle() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
ppc_result_a = ppc_result_d << rot_sh;
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] << rot_sh;
ppc_state.spr[SPR::MQ] =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_state.gpr[instr.arg1]);
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sle<RC0>();
@@ -393,18 +381,16 @@ template void dppc_interpreter::power_sle<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sleq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t r =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(0, 31 - rot_sh);
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = r;
ppc_state.gpr[instr.arg1] = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = r;
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sleq<RC0>();
@@ -412,15 +398,16 @@ template void dppc_interpreter::power_sleq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sliq() {
ppc_grab_regssash(ppc_cur_instruction);
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
ppc_result_a = ppc_result_d << rot_sh;
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] << rot_sh;
ppc_state.spr[SPR::MQ] =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sliq<RC0>();
@@ -428,17 +415,17 @@ template void dppc_interpreter::power_sliq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_slliq() {
ppc_grab_regssash(ppc_cur_instruction);
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t r =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(0, 31 - rot_sh);
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = r;
ppc_state.gpr[instr.arg1] = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = r;
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_slliq<RC0>();
@@ -446,19 +433,17 @@ template void dppc_interpreter::power_slliq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sllq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
if (ppc_result_b & 0x20) {
ppc_result_a = ppc_state.spr[SPR::MQ] & (-1U << rot_sh);
if (ppc_state.gpr[instr.arg2] & 0x20) {
ppc_state.gpr[instr.arg1] = ppc_state.spr[SPR::MQ] & (-1U << rot_sh);
} else {
ppc_result_a = ((ppc_result_d << rot_sh) | (ppc_state.spr[SPR::MQ] & ((1 << rot_sh) - 1)));
ppc_state.gpr[instr.arg1] =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.spr[SPR::MQ] & ((1 << rot_sh) - 1)));
}
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sllq<RC0>();
@@ -466,20 +451,19 @@ template void dppc_interpreter::power_sllq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_slq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
if (ppc_result_b & 0x20) {
ppc_result_a = 0;
if (ppc_state.gpr[instr.arg2] & 0x20) {
ppc_state.gpr[instr.arg1] = 0;
} else {
ppc_result_a = ppc_result_d << rot_sh;
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] << rot_sh;
}
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_state.spr[SPR::MQ] =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
}
template void dppc_interpreter::power_slq<RC0>();
@@ -487,12 +471,12 @@ template void dppc_interpreter::power_slq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sraiq() {
ppc_grab_regssash(ppc_cur_instruction);
uint32_t mask = (1 << rot_sh) - 1;
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
uint32_t mask = (1 << instr.arg2) - 1;
uint32_t ppc_result_a = (int32_t)ppc_state.gpr[instr.arg0] >> instr.arg2;
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> instr.arg2) |
(ppc_state.gpr[instr.arg0] << (32 - instr.arg2));
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
if ((int32_t(ppc_state.gpr[instr.arg1]) < 0) && (ppc_state.gpr[instr.arg1] & mask)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
@@ -501,7 +485,7 @@ void dppc_interpreter::power_sraiq() {
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_result_a);
}
template void dppc_interpreter::power_sraiq<RC0>();
@@ -509,24 +493,24 @@ template void dppc_interpreter::power_sraiq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sraq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t mask = (ppc_result_b & 0x20) ? -1 : (1 << rot_sh) - 1;
ppc_result_a = (int32_t)ppc_result_d >> ((ppc_result_b & 0x20) ? 31 : rot_sh);
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t mask = (ppc_state.gpr[instr.arg2] & 0x20) ? -1 : (1 << rot_sh) - 1;
ppc_state.gpr[instr.arg1] = (int32_t)ppc_state.gpr[instr.arg0] >>
((ppc_state.gpr[instr.arg2] & 0x20) ? 31 : rot_sh);
ppc_state.spr[SPR::MQ] =
((ppc_state.gpr[instr.arg0] << rot_sh) | (ppc_state.gpr[instr.arg0] >> (32 - rot_sh)));
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
if ((int32_t(ppc_state.gpr[instr.arg0]) < 0) && (ppc_state.gpr[instr.arg0] & mask)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
}
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> rot_sh) |
(ppc_state.gpr[instr.arg0] << (32 - rot_sh));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sraq<RC0>();
@@ -534,17 +518,14 @@ template void dppc_interpreter::power_sraq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sre() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] >> rot_sh;
unsigned rot_sh = ppc_result_b & 0x1F;
ppc_result_a = ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> rot_sh) |
(ppc_state.gpr[instr.arg0] << (32 - rot_sh));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sre<RC0>();
@@ -552,13 +533,12 @@ template void dppc_interpreter::power_sre<RC1>();
template <field_rc rec>
void dppc_interpreter::power_srea() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
uint32_t r = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t ppc_result_a = (int32_t)ppc_state.gpr[instr.arg0] >> rot_sh;
uint32_t r = ((ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh)));
uint32_t mask = -1U >> rot_sh;
if ((int32_t(ppc_result_d) < 0) && (r & ~mask)) {
if ((int32_t(ppc_state.gpr[instr.arg0]) < 0) && (r & ~mask)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
@@ -567,7 +547,7 @@ void dppc_interpreter::power_srea() {
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_result_a);
ppc_state.spr[SPR::MQ] = r;
}
@@ -576,17 +556,16 @@ template void dppc_interpreter::power_srea<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sreq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t mask = -1U >> rot_sh;
ppc_result_a = (ppc_result_d >> rot_sh) | (ppc_state.spr[SPR::MQ] & ~mask);
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
uint32_t ppc_result_a = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.spr[SPR::MQ] & ~mask);
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_store_iresult_reg(instr.arg1, ppc_result_a);
}
template void dppc_interpreter::power_sreq<RC0>();
@@ -594,14 +573,12 @@ template void dppc_interpreter::power_sreq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sriq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_result_a = ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
uint32_t rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_sriq<RC0>();
@@ -609,17 +586,15 @@ template void dppc_interpreter::power_sriq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_srliq() {
ppc_grab_regssash(ppc_cur_instruction);
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
unsigned mask = power_rot_mask(rot_sh, 31);
uint32_t rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t r = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh));
unsigned mask = power_rot_mask(ppc_state.gpr[instr.arg2], 31);
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.gpr[instr.arg1] = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = r;
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_srliq<RC0>();
@@ -627,21 +602,18 @@ template void dppc_interpreter::power_srliq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_srlq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
uint32_t r = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh));
unsigned mask = power_rot_mask(rot_sh, 31);
if (ppc_result_b & 0x20) {
ppc_result_a = (ppc_state.spr[SPR::MQ] & mask);
if (ppc_state.gpr[instr.arg2] & 0x20) {
ppc_state.gpr[instr.arg1] = (ppc_state.spr[SPR::MQ] & mask);
} else {
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.gpr[instr.arg1] = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
}
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_srlq<RC0>();
@@ -649,21 +621,18 @@ template void dppc_interpreter::power_srlq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_srq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
unsigned rot_sh = ppc_state.gpr[instr.arg2] & 0x1F;
if (ppc_result_b & 0x20) {
ppc_result_a = 0;
if (ppc_state.gpr[instr.arg2] & 0x20) {
ppc_state.gpr[instr.arg1] = 0;
} else {
ppc_result_a = ppc_result_d >> rot_sh;
ppc_state.gpr[instr.arg1] = ppc_state.gpr[instr.arg0] >> rot_sh;
}
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
ppc_state.spr[SPR::MQ] = (ppc_state.gpr[instr.arg0] >> rot_sh) | (ppc_state.gpr[instr.arg0] << (32 - rot_sh));
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_changecrf0(ppc_state.gpr[instr.arg1]);
}
template void dppc_interpreter::power_srq<RC0>();

View File

@@ -68,6 +68,23 @@ fpscr = FP Status and Condition Register
sr = Segment Register
**/
typedef struct struct_ppc_instr {
uint8_t arg0;
uint8_t arg1;
uint8_t arg2;
uint8_t arg3;
uint8_t arg4;
int32_t addr;
int32_t mask;
union {
int32_t i_simm;
uint32_t i_uimm;
};
} SetInstr;
SetInstr instr;
typedef struct struct_ppc_state {
FPR_storage fpr[32];
uint32_t pc; // Referred as the CIA in the PPC manual
@@ -81,7 +98,7 @@ typedef struct struct_ppc_state {
bool reserve; // reserve bit used for lwarx and stcwx
} SetPRS;
extern SetPRS ppc_state;
SetPRS ppc_state;
/** symbolic names for frequently used SPRs */
enum SPR : int {
@@ -406,14 +423,8 @@ void ppc_fpu_off();
void ppc_assert_int();
void ppc_release_int();
//void ppc_opcode4();
void ppc_opcode16();
void ppc_opcode18();
template <field_601 for601> void ppc_opcode19();
void ppc_opcode31();
void ppc_opcode59();
void ppc_opcode63();
void (*ref_instr)();
void decode_instr();
void initialize_ppc_opcode_tables(bool include_601);
extern double fp_return_double(uint32_t reg);
@@ -645,7 +656,6 @@ template <field_rc rec> extern void power_srq();
extern uint64_t get_virt_time_ns(void);
extern void ppc_main_opcode(void);
extern void ppc_exec(void);
extern void ppc_exec_single(void);
extern void ppc_exec_until(uint32_t goal_addr);

View File

@@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/timermanager.h>
#include <loguru.hpp>
#include "ppcemu.h"
#include "ppcmacros.h"
#include "ppcmmu.h"
#include "ppcdisasm.h"
@@ -60,8 +61,6 @@ bool is_601 = false;
bool power_on = false;
Po_Cause power_off_reason = po_enter_debugger;
SetPRS ppc_state;
uint32_t ppc_cur_instruction; // Current instruction for the PPC
uint32_t ppc_next_instruction_address; // Used for branching, setting up the NIA
@@ -229,12 +228,14 @@ void ppc_release_int() {
/** Opcode decoding functions. */
void ppc_opcode16() {
SubOpcode16Grabber[ppc_cur_instruction & 3]();
static void ppc_opcode16() {
ref_instr = SubOpcode16Grabber[ppc_cur_instruction & 3];
ppc_grab_branch(ppc_cur_instruction);
}
void ppc_opcode18() {
SubOpcode18Grabber[ppc_cur_instruction & 3]();
static void ppc_opcode18() {
ref_instr = SubOpcode18Grabber[ppc_cur_instruction & 3];
ppc_grab_branch(ppc_cur_instruction);
}
template<field_601 for601>
@@ -243,49 +244,62 @@ void ppc_opcode19() {
switch (subop_grab) {
case 0:
ppc_mcrf();
ref_instr = ppc_mcrf;
ppc_grab_regs_crf(ppc_cur_instruction);
break;
case 32:
ppc_bclr<LK0>();
ref_instr = ppc_bclr<LK0>;
ppc_grab_branch_cond(ppc_cur_instruction);
break;
case 33:
ppc_bclr<LK1>();
ref_instr = ppc_bclr<LK1>;
ppc_grab_branch_cond(ppc_cur_instruction);
break;
case 66:
ppc_crnor();
ref_instr = ppc_crnor;
ppc_grab_dab(ppc_cur_instruction);
break;
case 100:
ppc_rfi();
ref_instr = ppc_rfi;
break;
case 258:
ppc_crandc();
ref_instr = ppc_crandc;
ppc_grab_dab(ppc_cur_instruction);
break;
case 300:
ppc_isync();
ref_instr = ppc_isync;
break;
case 386:
ppc_crxor();
ref_instr = ppc_crxor;
ppc_grab_dab(ppc_cur_instruction);
break;
case 450:
ppc_crnand();
ref_instr = ppc_crnand;
ppc_grab_dab(ppc_cur_instruction);
break;
case 514:
ppc_crand();
ref_instr = ppc_crand;
ppc_grab_dab(ppc_cur_instruction);
break;
case 578:
ppc_creqv();
ref_instr = ppc_creqv;
ppc_grab_dab(ppc_cur_instruction);
break;
case 834:
ppc_crorc();
ref_instr = ppc_crorc;
ppc_grab_dab(ppc_cur_instruction);
break;
case 898:
ppc_cror();
ref_instr = ppc_cror;
ppc_grab_dab(ppc_cur_instruction);
break;
case 1056:
ppc_bcctr<LK0, for601>();
ref_instr = ppc_bcctr<LK0, for601>;
ppc_grab_branch_cond(ppc_cur_instruction);
break;
case 1057:
ppc_bcctr<LK1, for601>();
ref_instr = ppc_bcctr<LK1, for601>;
ppc_grab_branch_cond(ppc_cur_instruction);
break;
default:
ppc_illegalop();
@@ -295,31 +309,121 @@ void ppc_opcode19() {
template void ppc_opcode19<NOT601>();
template void ppc_opcode19<IS601>();
void ppc_opcode31() {
static void ppc_opcode31() {
uint16_t subop_grab = ppc_cur_instruction & 0x7FFUL;
SubOpcode31Grabber[subop_grab]();
ref_instr = SubOpcode59Grabber[subop_grab];
switch ((subop_grab >> 1)) {
case 0:
case 32:
ppc_grab_crfd_regsab(ppc_cur_instruction);
case 8:
ppc_grab_tw(ppc_cur_instruction);
break;
case 83:
ppc_grab_d(ppc_cur_instruction);
break;
case 210:
case 595:
ppc_grab_sr(ppc_cur_instruction);
break;
case 512:
ppc_grab_mcrxr(ppc_cur_instruction);
break;
default:
ppc_grab_regsdab(ppc_cur_instruction);
}
}
void ppc_opcode59() {
static void ppc_opcode59() {
uint16_t subop_grab = ppc_cur_instruction & 0x3FUL;
SubOpcode59Grabber[subop_grab]();
ref_instr = SubOpcode59Grabber[subop_grab];
ppc_grab_regsfpdabc(ppc_cur_instruction);
}
void ppc_opcode63() {
static void ppc_opcode63() {
uint16_t subop_grab = ppc_cur_instruction & 0x7FFUL;
SubOpcode63Grabber[subop_grab]();
ref_instr = SubOpcode59Grabber[subop_grab];
switch ((subop_grab >> 1)) {
case 0:
case 32:
ppc_grab_regsfpsab(ppc_cur_instruction);
break;
case 64:
ppc_grab_regs_crf(ppc_cur_instruction);
case 134:
default:
ppc_grab_regsfpdabc(ppc_cur_instruction);
}
}
/* Dispatch using main opcode */
void ppc_main_opcode()
{
#ifdef CPU_PROFILING
num_executed_instrs++;
#if defined(CPU_PROFILING_OPS)
num_opcodes[ppc_cur_instruction]++;
#endif
#endif
OpcodeGrabber[(ppc_cur_instruction >> 26) & 0x3F]();
static void ppc_main_opcode() {
uint32_t main_op = (ppc_cur_instruction >> 26) & 0x3F;
ref_instr = OpcodeGrabber[main_op];
switch (main_op) {
case 3:
ppc_grab_twi(ppc_cur_instruction);
break;
case 7: case 8: case 9:
case 12: case 13:
case 14: case 15:
ppc_grab_regs_dasimm(ppc_cur_instruction);
break;
case 20: case 21:
case 22: case 23:
ppc_grab_regs_sab_rot(ppc_cur_instruction);
case 24: case 25:
case 26: case 27:
case 28: case 29:
ppc_grab_regs_sauimm(ppc_cur_instruction);
case 32: case 33: case 34: case 35:
case 36: case 37: case 38: case 39:
case 40: case 31: case 42: case 43:
case 44: case 45: case 46: case 47:
case 48: case 49: case 50: case 51:
case 52: case 53: case 54: case 55:
ppc_grab_regs_da_addr(ppc_cur_instruction);
}
}
void decode_instr() {
uint32_t main_op = (ppc_cur_instruction >> 26) & 0x3F;
switch (main_op) {
case 16:
ppc_opcode16();
break;
case 18:
ppc_opcode18();
break;
case 19:
if (is_601)
ppc_opcode19<IS601>();
else
ppc_opcode19<NOT601>();
break;
case 31:
ppc_opcode31();
break;
case 59:
ppc_opcode59();
break;
case 63:
ppc_opcode63();
break;
default:
ppc_main_opcode();
}
#ifdef CPU_PROFILING
num_executed_instrs++;
#if defined(CPU_PROFILING_OPS)
num_opcodes[ppc_cur_instruction]++;
#endif
#endif
}
static long long cpu_now_ns() {
@@ -377,10 +481,11 @@ static void ppc_exec_inner()
exec_flags = 0;
pc_real = mmu_translate_imem(eb_start);
decode_instr();
// interpret execution block
while (power_on && ppc_state.pc < eb_end) {
ppc_main_opcode();
ref_instr();
if (g_icycles++ >= max_cycles || exec_timer) {
max_cycles = process_events();
}
@@ -391,10 +496,12 @@ static void ppc_exec_inner()
if (!(exec_flags & EXEF_RFI) && (eb_start & PPC_PAGE_MASK) == page_start) {
pc_real += (int)eb_start - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
decode_instr();
} else {
page_start = eb_start & PPC_PAGE_MASK;
eb_end = page_start + PPC_PAGE_SIZE - 1;
pc_real = mmu_translate_imem(eb_start);
eb_end = page_start + PPC_PAGE_SIZE - 1;
pc_real = mmu_translate_imem(eb_start);
decode_instr();
}
ppc_state.pc = eb_start;
exec_flags = 0;
@@ -402,6 +509,7 @@ static void ppc_exec_inner()
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
decode_instr();
}
}
}
@@ -433,7 +541,7 @@ void ppc_exec_single()
}
mmu_translate_imem(ppc_state.pc);
ppc_main_opcode();
ref_instr();
g_icycles++;
process_events();
@@ -464,11 +572,12 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
eb_end = page_start + PPC_PAGE_SIZE - 1;
exec_flags = 0;
pc_real = mmu_translate_imem(eb_start);
pc_real = mmu_translate_imem(eb_start);
decode_instr();
// interpret execution block
while (power_on && ppc_state.pc < eb_end) {
ppc_main_opcode();
ref_instr();
if (g_icycles++ >= max_cycles || exec_timer) {
max_cycles = process_events();
}
@@ -479,10 +588,12 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
if (!(exec_flags & EXEF_RFI) && (eb_start & PPC_PAGE_MASK) == page_start) {
pc_real += (int)eb_start - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
decode_instr();
} else {
page_start = eb_start & PPC_PAGE_MASK;
eb_end = page_start + PPC_PAGE_SIZE - 1;
pc_real = mmu_translate_imem(eb_start);
pc_real = mmu_translate_imem(eb_start);
decode_instr();
}
ppc_state.pc = eb_start;
exec_flags = 0;
@@ -490,6 +601,7 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
decode_instr();
}
if (ppc_state.pc == goal_addr)
@@ -531,12 +643,13 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
eb_end = page_start + PPC_PAGE_SIZE - 1;
exec_flags = 0;
pc_real = mmu_translate_imem(eb_start);
pc_real = mmu_translate_imem(eb_start);
decode_instr();
// interpret execution block
while (power_on && (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size)
&& (ppc_state.pc < eb_end)) {
ppc_main_opcode();
ref_instr();
if (g_icycles++ >= max_cycles || exec_timer) {
max_cycles = process_events();
}
@@ -547,10 +660,12 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
if (!(exec_flags & EXEF_RFI) && (eb_start & PPC_PAGE_MASK) == page_start) {
pc_real += (int)eb_start - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
decode_instr();
} else {
page_start = eb_start & PPC_PAGE_MASK;
eb_end = page_start + PPC_PAGE_SIZE - 1;
pc_real = mmu_translate_imem(eb_start);
pc_real = mmu_translate_imem(eb_start);
decode_instr();
}
ppc_state.pc = eb_start;
exec_flags = 0;
@@ -558,6 +673,7 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
decode_instr();
}
}
}

View File

@@ -154,13 +154,14 @@ static void ppc_update_fex() {
// Floating Point Arithmetic
template <field_rc rec>
void dppc_interpreter::ppc_fadd() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
max_double_check(val_reg_a, val_reg_b);
double ppc_dblresult64_d = val_reg_a + val_reg_b;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
ppc_update_fex();
@@ -173,13 +174,13 @@ template void dppc_interpreter::ppc_fadd<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fsub() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
double ppc_dblresult64_d = val_reg_a - val_reg_b;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -191,12 +192,13 @@ template void dppc_interpreter::ppc_fsub<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fdiv() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
double ppc_dblresult64_d = val_reg_a / val_reg_b;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -208,12 +210,13 @@ template void dppc_interpreter::ppc_fdiv<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmul() {
ppc_grab_regsfpdac(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_double_check(instr.arg1, instr.arg3);
double ppc_dblresult64_d = val_reg_a * val_reg_c;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -225,13 +228,15 @@ template void dppc_interpreter::ppc_fmul<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmadd() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -243,13 +248,15 @@ template void dppc_interpreter::ppc_fmadd<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmsub() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, -val_reg_b);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -261,13 +268,15 @@ template void dppc_interpreter::ppc_fmsub<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fnmadd() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, val_reg_b);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -279,13 +288,15 @@ template void dppc_interpreter::ppc_fnmadd<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fnmsub() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, -val_reg_b);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -297,12 +308,13 @@ template void dppc_interpreter::ppc_fnmsub<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fadds() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
double ppc_dblresult64_d = (float)(val_reg_a + val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
@@ -315,13 +327,13 @@ template void dppc_interpreter::ppc_fadds<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fsubs() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
double ppc_dblresult64_d = (float)(val_reg_a - val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -333,12 +345,13 @@ template void dppc_interpreter::ppc_fsubs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fdivs() {
ppc_grab_regsfpdab(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
snan_double_check(reg_a, reg_b);
snan_double_check(instr.arg1, instr.arg2);
double ppc_dblresult64_d = (float)(val_reg_a / val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -350,12 +363,13 @@ template void dppc_interpreter::ppc_fdivs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmuls() {
ppc_grab_regsfpdac(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_double_check(instr.arg1, instr.arg3);
double ppc_dblresult64_d = (float)(val_reg_a * val_reg_c);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -367,13 +381,15 @@ template void dppc_interpreter::ppc_fmuls<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmadds() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -385,13 +401,15 @@ template void dppc_interpreter::ppc_fmadds<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fmsubs() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -403,13 +421,15 @@ template void dppc_interpreter::ppc_fmsubs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fnmadds() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -421,13 +441,15 @@ template void dppc_interpreter::ppc_fnmadds<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fnmsubs() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
snan_double_check(reg_a, reg_c);
snan_single_check(reg_b);
snan_double_check(instr.arg1, instr.arg3);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
fpresult_update(ppc_dblresult64_d);
if (rec)
@@ -439,13 +461,11 @@ template void dppc_interpreter::ppc_fnmsubs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fabs() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double ppc_dblresult64_d = abs(GET_FPR(instr.arg2));
double ppc_dblresult64_d = abs(GET_FPR(reg_b));
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -456,14 +476,12 @@ template void dppc_interpreter::ppc_fabs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fnabs() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double ppc_dblresult64_d = abs(GET_FPR(reg_b));
double ppc_dblresult64_d = abs(GET_FPR(instr.arg2));
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -474,13 +492,11 @@ template void dppc_interpreter::ppc_fnabs<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fneg() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double ppc_dblresult64_d = -(GET_FPR(instr.arg2));
double ppc_dblresult64_d = -(GET_FPR(reg_b));
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -491,11 +507,13 @@ template void dppc_interpreter::ppc_fneg<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fsel() {
ppc_grab_regsfpdabc(ppc_cur_instruction);
double val_reg_a = GET_FPR(instr.arg1);
double val_reg_b = GET_FPR(instr.arg2);
double val_reg_c = GET_FPR(instr.arg3);
double ppc_dblresult64_d = (val_reg_a >= -0.0) ? val_reg_c : val_reg_b;
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -506,13 +524,11 @@ template void dppc_interpreter::ppc_fsel<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fsqrt() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double testd2 = (double)(GET_FPR(reg_b));
double testd2 = (double)(GET_FPR(instr.arg2));
double ppc_dblresult64_d = std::sqrt(testd2);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -523,13 +539,11 @@ template void dppc_interpreter::ppc_fsqrt<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fsqrts() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double testd2 = (double)(GET_FPR(reg_b));
double testd2 = (double)(GET_FPR(instr.arg2));
double ppc_dblresult64_d = (float)std::sqrt(testd2);
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -540,12 +554,11 @@ template void dppc_interpreter::ppc_fsqrts<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_frsqrte() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(reg_b);
snan_single_check(instr.arg2);
double testd2 = (double)(GET_FPR(reg_b));
double testd2 = (double)(GET_FPR(instr.arg2));
double ppc_dblresult64_d = 1.0 / sqrt(testd2);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -556,11 +569,10 @@ template void dppc_interpreter::ppc_frsqrte<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_frsp() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(reg_b);
snan_single_check(instr.arg2);
double ppc_dblresult64_d = (float)(GET_FPR(reg_b));
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
double ppc_dblresult64_d = (float)(GET_FPR(instr.arg2));
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (rec)
ppc_update_cr1();
@@ -571,13 +583,11 @@ template void dppc_interpreter::ppc_frsp<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_fres() {
ppc_grab_regsfpdb(ppc_cur_instruction);
snan_single_check(instr.arg2);
snan_single_check(reg_b);
double start_num = GET_FPR(reg_b);
double start_num = GET_FPR(instr.arg2);
double ppc_dblresult64_d = (float)(1.0 / start_num);
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
ppc_store_fpresult_flt(instr.arg0, ppc_dblresult64_d);
if (start_num == 0.0) {
ppc_state.fpscr |= FPSCR::ZX;
@@ -598,21 +608,20 @@ template void dppc_interpreter::ppc_fres<RC0>();
template void dppc_interpreter::ppc_fres<RC1>();
static void round_to_int(const uint8_t mode, field_rc rec) {
ppc_grab_regsfpdb(ppc_cur_instruction);
double val_reg_b = GET_FPR(reg_b);
double val_reg_b = GET_FPR(instr.arg2);
if (std::isnan(val_reg_b)) {
ppc_state.fpscr &= ~(FPSCR::FR | FPSCR::FI);
ppc_state.fpscr |= (FPSCR::VXCVI | FPSCR::VX);
if (check_snan(reg_b)) // issnan
if (check_snan(instr.arg2)) // issnan
ppc_state.fpscr |= FPSCR::VXSNAN;
if (ppc_state.fpscr & FPSCR::VE) {
ppc_state.fpscr |= FPSCR::FEX; // VX=1 and VE=1 cause FEX to be set
ppc_floating_point_exception();
} else {
ppc_state.fpr[reg_d].int64_r = 0xFFF8000080000000ULL;
ppc_state.fpr[instr.arg0].int64_r = 0xFFF8000080000000ULL;
}
} else if (val_reg_b > static_cast<double>(0x7fffffff) ||
val_reg_b < -static_cast<double>(0x80000000)) {
@@ -624,9 +633,9 @@ static void round_to_int(const uint8_t mode, field_rc rec) {
ppc_floating_point_exception();
} else {
if (val_reg_b >= 0.0f)
ppc_state.fpr[reg_d].int64_r = 0xFFF800007FFFFFFFULL;
ppc_state.fpr[instr.arg0].int64_r = 0xFFF800007FFFFFFFULL;
else
ppc_state.fpr[reg_d].int64_r = 0xFFF8000080000000ULL;
ppc_state.fpr[instr.arg0].int64_r = 0xFFF8000080000000ULL;
}
} else {
uint64_t ppc_result64_d;
@@ -647,7 +656,7 @@ static void round_to_int(const uint8_t mode, field_rc rec) {
ppc_result64_d |= 0xFFF8000000000000ULL;
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
ppc_store_fpresult_int(instr.arg0, ppc_result64_d);
}
if (rec)
@@ -673,173 +682,149 @@ template void dppc_interpreter::ppc_fctiwz<RC1>();
// Floating Point Store and Load
void dppc_interpreter::ppc_lfs() {
ppc_grab_regsfpdia(ppc_cur_instruction);
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += (reg_a) ? val_reg_a : 0;
uint32_t result = mmu_read_vmem<uint32_t>(ea);
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
instr.addr += ((instr.arg1) ? ppc_state.gpr[instr.arg1] : 0);
uint32_t result = mmu_read_vmem<uint32_t>(instr.addr);
ppc_state.fpr[instr.arg0].dbl64_r = *(float*)(&result);
}
void dppc_interpreter::ppc_lfsu() {
ppc_grab_regsfpdia(ppc_cur_instruction);
if (reg_a) {
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += (reg_a) ? val_reg_a : 0;
uint32_t result = mmu_read_vmem<uint32_t>(ea);
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
ppc_state.gpr[reg_a] = ea;
if (instr.arg1) {
instr.addr += ((instr.arg1) ? ppc_state.gpr[instr.arg1] : 0);
uint32_t result = mmu_read_vmem<uint32_t>(instr.addr);
ppc_state.fpr[instr.arg0].dbl64_r = *(float*)(&result);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_lfsx() {
ppc_grab_regsfpdiab(ppc_cur_instruction);
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
uint32_t result = mmu_read_vmem<uint32_t>(ea);
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
instr.addr = ppc_state.gpr[instr.arg2] + (instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
uint32_t result = mmu_read_vmem<uint32_t>(instr.addr);
ppc_state.fpr[instr.arg0].dbl64_r = *(float*)(&result);
}
void dppc_interpreter::ppc_lfsux() {
ppc_grab_regsfpdiab(ppc_cur_instruction);
if (reg_a) {
uint32_t ea = val_reg_a + val_reg_b;
uint32_t result = mmu_read_vmem<uint32_t>(ea);
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
ppc_state.gpr[reg_a] = ea;
if (ppc_state.gpr[instr.arg1]) {
instr.addr = ppc_state.gpr[instr.arg1] + ppc_state.gpr[instr.arg2];
uint32_t result = mmu_read_vmem<uint32_t>(instr.addr);
ppc_state.fpr[instr.arg0].dbl64_r = *(float*)(&result);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_lfd() {
ppc_grab_regsfpdia(ppc_cur_instruction);
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += (reg_a) ? val_reg_a : 0;
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea);
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
instr.addr += ((instr.arg1) ? ppc_state.gpr[instr.arg1] : 0);
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(instr.addr);
ppc_store_fpresult_int(instr.arg0, ppc_result64_d);
}
void dppc_interpreter::ppc_lfdu() {
ppc_grab_regsfpdia(ppc_cur_instruction);
if (reg_a != 0) {
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += val_reg_a;
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea);
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
ppc_state.gpr[reg_a] = ea;
if (instr.arg1 != 0) {
instr.addr += ppc_state.gpr[instr.arg1];
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(instr.addr);
ppc_store_fpresult_int(instr.arg0, ppc_result64_d);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_lfdx() {
ppc_grab_regsfpdiab(ppc_cur_instruction);
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea);
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
instr.addr = ppc_state.gpr[instr.arg2] + (instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(instr.addr);
ppc_store_fpresult_int(instr.arg0, ppc_result64_d);
}
void dppc_interpreter::ppc_lfdux() {
ppc_grab_regsfpdiab(ppc_cur_instruction);
if (reg_a) {
uint32_t ea = val_reg_a + val_reg_b;
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea);
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
ppc_state.gpr[reg_a] = ea;
if (instr.arg1) {
instr.addr = ppc_state.gpr[instr.arg1] + ppc_state.gpr[instr.arg2];
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(instr.addr);
ppc_store_fpresult_int(instr.arg0, ppc_result64_d);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_stfs() {
ppc_grab_regsfpsia(ppc_cur_instruction);
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += (reg_a) ? val_reg_a : 0;
float result = float(ppc_state.fpr[reg_s].dbl64_r);
mmu_write_vmem<uint32_t>(ea, *(uint32_t*)(&result));
instr.addr += ((instr.arg1) ? ppc_state.gpr[instr.arg1] : 0);
float result = float(ppc_state.fpr[instr.arg0].dbl64_r);
mmu_write_vmem<uint32_t>(instr.addr, *(uint32_t*)(&result));
}
void dppc_interpreter::ppc_stfsu() {
ppc_grab_regsfpsia(ppc_cur_instruction);
if (reg_a != 0) {
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += val_reg_a;
float result = float(ppc_state.fpr[reg_s].dbl64_r);
mmu_write_vmem<uint32_t>(ea, *(uint32_t*)(&result));
ppc_state.gpr[reg_a] = ea;
if (instr.arg1 != 0) {
instr.addr += ppc_state.gpr[instr.arg1];
float result = float(ppc_state.fpr[instr.arg0].dbl64_r);
mmu_write_vmem<uint32_t>(instr.addr, *(uint32_t*)(&result));
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_stfsx() {
ppc_grab_regsfpsiab(ppc_cur_instruction);
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
float result = float(ppc_state.fpr[reg_s].dbl64_r);
mmu_write_vmem<uint32_t>(ea, *(uint32_t*)(&result));
instr.addr = ppc_state.gpr[instr.arg2] +
(instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
float result = float(ppc_state.fpr[instr.arg0].dbl64_r);
mmu_write_vmem<uint32_t>(instr.addr, *(uint32_t*)(&result));
}
void dppc_interpreter::ppc_stfsux() {
ppc_grab_regsfpsiab(ppc_cur_instruction);
if (reg_a) {
uint32_t ea = val_reg_a + val_reg_b;
float result = float(ppc_state.fpr[reg_s].dbl64_r);
mmu_write_vmem<uint32_t>(ea, *(uint32_t*)(&result));
ppc_state.gpr[reg_a] = ea;
if (ppc_state.gpr[instr.arg1]) {
instr.addr = ppc_state.gpr[instr.arg1] + ppc_state.gpr[instr.arg2];
float result = float(ppc_state.fpr[instr.arg0].dbl64_r);
mmu_write_vmem<uint32_t>(instr.addr, *(uint32_t*)(&result));
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_stfd() {
ppc_grab_regsfpsia(ppc_cur_instruction);
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += reg_a ? val_reg_a : 0;
mmu_write_vmem<uint64_t>(ea, ppc_state.fpr[reg_s].int64_r);
instr.addr += ((instr.arg1) ? ppc_state.gpr[instr.arg1] : 0);
mmu_write_vmem<uint64_t>(instr.addr, ppc_state.fpr[instr.arg0].int64_r);
}
void dppc_interpreter::ppc_stfdu() {
ppc_grab_regsfpsia(ppc_cur_instruction);
if (reg_a != 0) {
uint32_t ea = int32_t(int16_t(ppc_cur_instruction));
ea += val_reg_a;
mmu_write_vmem<uint64_t>(ea, ppc_state.fpr[reg_s].int64_r);
ppc_state.gpr[reg_a] = ea;
if (instr.arg1 != 0) {
instr.addr += ppc_state.gpr[instr.arg1];
mmu_write_vmem<uint64_t>(instr.addr, ppc_state.fpr[instr.arg0].int64_r);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_stfdx() {
ppc_grab_regsfpsiab(ppc_cur_instruction);
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
mmu_write_vmem<uint64_t>(ea, ppc_state.fpr[reg_s].int64_r);
instr.addr = ppc_state.gpr[instr.arg2] + (instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
mmu_write_vmem<uint64_t>(instr.addr, ppc_state.fpr[instr.arg0].int64_r);
}
void dppc_interpreter::ppc_stfdux() {
ppc_grab_regsfpsiab(ppc_cur_instruction);
if (reg_a != 0) {
uint32_t ea = val_reg_a + val_reg_b;
mmu_write_vmem<uint64_t>(ea, ppc_state.fpr[reg_s].int64_r);
ppc_state.gpr[reg_a] = ea;
if (instr.arg1 != 0) {
instr.addr = ppc_state.gpr[instr.arg1] + ppc_state.gpr[instr.arg2];
mmu_write_vmem<uint64_t>(instr.addr, ppc_state.fpr[instr.arg0].int64_r);
ppc_state.gpr[instr.arg1] = instr.addr;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void dppc_interpreter::ppc_stfiwx() {
ppc_grab_regsfpsiab(ppc_cur_instruction);
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
mmu_write_vmem<uint32_t>(ea, uint32_t(ppc_state.fpr[reg_s].int64_r));
instr.addr = ppc_state.gpr[instr.arg2] + (instr.arg1 ? ppc_state.gpr[instr.arg1] : 0);
mmu_write_vmem<uint32_t>(instr.addr, uint32_t(ppc_state.fpr[instr.arg0].int64_r));
}
// Floating Point Register Transfer
template <field_rc rec>
void dppc_interpreter::ppc_fmr() {
ppc_grab_regsfpdb(ppc_cur_instruction);
ppc_state.fpr[reg_d].dbl64_r = ppc_state.fpr[reg_b].dbl64_r;
ppc_state.fpr[instr.arg0].dbl64_r = ppc_state.fpr[instr.arg2].dbl64_r;
if (rec)
ppc_update_cr1();
@@ -850,9 +835,7 @@ template void dppc_interpreter::ppc_fmr<RC1>();
template <field_601 for601, field_rc rec>
void dppc_interpreter::ppc_mffs() {
int reg_d = (ppc_cur_instruction >> 21) & 31;
ppc_state.fpr[reg_d].int64_r = uint64_t(ppc_state.fpscr) | (for601 ? 0xFFFFFFFF00000000ULL : 0xFFF8000000000000ULL);
ppc_state.fpr[instr.arg0].int64_r = uint64_t(ppc_state.fpscr) | (for601 ? 0xFFFFFFFF00000000ULL : 0xFFF8000000000000ULL);
if (rec)
ppc_update_cr1();
@@ -865,29 +848,34 @@ template void dppc_interpreter::ppc_mffs<IS601, RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_mtfsf() {
int reg_b = (ppc_cur_instruction >> 11) & 0x1F;
uint8_t fm = (ppc_cur_instruction >> 17) & 0xFF;
uint32_t cr_mask = 0;
if (fm == 0xFFU) // the fast case
if (instr.arg4 == 0xFFU) // the fast case
cr_mask = 0xFFFFFFFFUL;
else { // the slow case
if (fm & 0x80) cr_mask |= 0xF0000000UL;
if (fm & 0x40) cr_mask |= 0x0F000000UL;
if (fm & 0x20) cr_mask |= 0x00F00000UL;
if (fm & 0x10) cr_mask |= 0x000F0000UL;
if (fm & 0x08) cr_mask |= 0x0000F000UL;
if (fm & 0x04) cr_mask |= 0x00000F00UL;
if (fm & 0x02) cr_mask |= 0x000000F0UL;
if (fm & 0x01) cr_mask |= 0x0000000FUL;
if (instr.arg4 & 0x80)
cr_mask |= 0xF0000000UL;
if (instr.arg4 & 0x40)
cr_mask |= 0x0F000000UL;
if (instr.arg4 & 0x20)
cr_mask |= 0x00F00000UL;
if (instr.arg4 & 0x10)
cr_mask |= 0x000F0000UL;
if (instr.arg4 & 0x08)
cr_mask |= 0x0000F000UL;
if (instr.arg4 & 0x04)
cr_mask |= 0x00000F00UL;
if (instr.arg4 & 0x02)
cr_mask |= 0x000000F0UL;
if (instr.arg4 & 0x01)
cr_mask |= 0x0000000FUL;
}
// ensure neither FEX nor VX will be changed
cr_mask &= ~(FPSCR::FEX | FPSCR::VX);
// copy FPR[reg_b] to FPSCR under control of cr_mask
ppc_state.fpscr = (ppc_state.fpscr & ~cr_mask) | (ppc_state.fpr[reg_b].int64_r & cr_mask);
ppc_state.fpscr = (ppc_state.fpscr & ~cr_mask) | (ppc_state.fpr[instr.arg2].int64_r & cr_mask);
if (rec)
ppc_update_cr1();
@@ -898,14 +886,11 @@ template void dppc_interpreter::ppc_mtfsf<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_mtfsfi() {
int crf_d = (ppc_cur_instruction >> 21) & 0x1C;
uint32_t imm = (ppc_cur_instruction << 16) & 0xF0000000UL;
// prepare field mask and ensure that neither FEX nor VX will be changed
uint32_t mask = (0xF0000000UL >> crf_d) & ~(FPSCR::FEX | FPSCR::VX);
uint32_t mask = (0xF0000000UL >> instr.arg0) & ~(FPSCR::FEX | FPSCR::VX);
// copy imm to FPSCR[crf_d] under control of the field mask
ppc_state.fpscr = (ppc_state.fpscr & ~mask) | ((imm >> crf_d) & mask);
ppc_state.fpscr = (ppc_state.fpscr & ~mask) | ((instr.mask >> instr.arg0) & mask);
// Update FEX and VX according to the "usual rule"
ppc_update_vx();
@@ -966,17 +951,18 @@ void dppc_interpreter::ppc_mcrfs() {
// Floating Point Comparisons
void dppc_interpreter::ppc_fcmpo() {
ppc_grab_regsfpsab(ppc_cur_instruction);
double db_test_a = GET_FPR(instr.arg1);
double db_test_b = GET_FPR(instr.arg2);
uint32_t cmp_c = 0;
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= CRx_bit::CR_SO;
ppc_state.fpscr |= FX | VX;
if (check_snan(reg_a) || check_snan(reg_b)) {
if (check_snan(instr.arg1) || check_snan(instr.arg2)) {
ppc_state.fpscr |= VXSNAN;
}
if (!(ppc_state.fpscr & FEX) || check_qnan(reg_a) || check_qnan(reg_b)) {
if (!(ppc_state.fpscr & FEX) || check_qnan(instr.arg1) || check_qnan(instr.arg2)) {
ppc_state.fpscr |= VXVC;
}
}
@@ -992,18 +978,19 @@ void dppc_interpreter::ppc_fcmpo() {
ppc_state.fpscr &= ~VE; //kludge to pass tests
ppc_state.fpscr = (ppc_state.fpscr & ~FPSCR::FPCC_MASK) | (cmp_c >> 16); // update FPCC
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000 >> crf_d)) | (cmp_c >> crf_d));
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000 >> instr.arg0)) | (cmp_c >> instr.arg0));
}
void dppc_interpreter::ppc_fcmpu() {
ppc_grab_regsfpsab(ppc_cur_instruction);
double db_test_a = GET_FPR(instr.arg1);
double db_test_b = GET_FPR(instr.arg2);
uint32_t cmp_c = 0;
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= CRx_bit::CR_SO;
if (check_snan(reg_a) || check_snan(reg_b)) {
if (check_snan(instr.arg1) || check_snan(instr.arg2)) {
ppc_state.fpscr |= FX | VX | VXSNAN;
}
}
@@ -1019,6 +1006,6 @@ void dppc_interpreter::ppc_fcmpu() {
ppc_state.fpscr &= ~VE; //kludge to pass tests
ppc_state.fpscr = (ppc_state.fpscr & ~FPSCR::FPCC_MASK) | (cmp_c >> 16); // update FPCC
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000UL >> crf_d)) | (cmp_c >> crf_d));
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000UL >> instr.arg0)) | (cmp_c >> instr.arg0));
}

View File

@@ -23,194 +23,178 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define PPC_MACROS_H
#include <cinttypes>
#include "ppcemu.h"
#define ppc_grab_regsdasimm(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int32_t simm = int32_t(int16_t(opcode)); \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define reg_d(opcode) ((opcode >> 21) & 0x1F)
#define reg_a(opcode) ((opcode >> 16) & 0x1F)
#define reg_b(opcode) ((opcode >> 11) & 0x1F)
#define reg_c(opcode) ((opcode >> 6) & 0x1F)
#define reg_s(opcode) reg_d(opcode)
#define trap_to(opcode) reg_d(opcode)
#define simm(opcode) int32_t(int16_t(opcode))
#define uimm(opcode) uint16_t(opcode)
#define rot_sh(opcode) reg_b(opcode)
#define rot_mb(opcode) ((opcode >> 6) & 0x1F)
#define rot_me(opcode) ((opcode >> 1) & 0x1F)
#define crf_d(opcode) ((opcode >> 21) & 0x1C)
#define crf_s(opcode) ((opcode >> 16) & 0x1C)
#define crm(opcode) ((opcode >> 12) & 0xFFU)
#define fcrm(opcode) crm(opcode)
#define br_bo(opcode) reg_d(opcode)
#define br_bi(opcode) reg_a(opcode)
#define br_bd(opcode) int32_t(int16_t(opcode & ~3UL))
#define adr_li(opcode) int32_t((opcode & ~3UL) << 6) >> 6
#define adr_d(opcode) int32_t(int16_t(opcode))
#define segreg(opcode) ((opcode >> 16) & 0xF)
#define mtfsfi_mask(opcode) ((opcode << 16) & 0xF0000000UL)
#define ppc_grab_regsdauimm(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t uimm = uint16_t(opcode); \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_twi(opcode) \
instr.i_simm = simm(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg0 = trap_to(opcode);
#define ppc_grab_regsasimm(opcode) \
int reg_a = (opcode >> 16) & 31; \
int32_t simm = int32_t(int16_t(opcode)); \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_tw(opcode) \
instr.i_simm = simm(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg0 = trap_to(opcode);
#define ppc_grab_regssauimm(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t uimm = uint16_t(opcode); \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_mcrxr(opcode) \
instr.arg0 = crf_d(opcode);
#define ppc_grab_crfd_regsauimm(opcode) \
int crf_d = (opcode >> 21) & 0x1C; \
int reg_a = (opcode >> 16) & 31; \
uint32_t uimm = uint16_t(opcode); \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_sr(opcode) \
instr.arg0 = reg_d(opcode); \
instr.arg1 = segreg(opcode);
#define ppc_grab_da(opcode)\
int reg_d = (opcode >> 21) & 31;\
int reg_a = (opcode >> 16) & 31;\
#define ppc_grab_mtfsfi(opcode) \
instr.arg0 = reg_d(opcode); \
instr.mask = mtfsfi_mask(opcode);
#define ppc_grab_regs_dasimm(opcode) \
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.i_simm = simm(opcode); \
#define ppc_grab_regs_sauimm(opcode) \
instr.arg0 = reg_s(opcode); \
instr.arg1 = reg_a(opcode); \
instr.i_simm = simm(opcode); \
#define ppc_grab_regs_da_addr(opcode) \
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.addr = adr_d(opcode); \
#define ppc_grab_branch(opcode) \
instr.addr = adr_li(opcode);
#define ppc_grab_branch_cond(opcode) \
instr.arg0 = br_bo(opcode); \
instr.arg1 = br_bi(opcode);
#define ppc_grab_branch_cond(opcode) \
instr.arg0 = br_bo(opcode); \
instr.arg1 = br_bi(opcode);
#define ppc_grab_d(opcode) \
instr.arg0 = reg_d(opcode);
#define ppc_grab_dab(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31;
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regsasimm(opcode) \
instr.arg0 = reg_s(opcode); \
instr.arg1 = reg_a(opcode); \
instr.i_simm = simm(opcode); \
#define ppc_grab_regssauimm(opcode) \
instr.arg0 = reg_s(opcode); \
instr.arg1 = reg_a(opcode); \
instr.i_simm = simm(opcode); \
#define ppc_grab_crfd_regsauimm(opcode) \
instr.arg0 = crf_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.i_simm = simm(opcode); \
#define ppc_grab_crfd_regsab(opcode) \
instr.arg0 = crf_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode);
#define ppc_grab_s(opcode) \
int reg_s = (opcode >> 21) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s];
instr.arg0 = reg_s(opcode); \
#define ppc_grab_regs_crf(opcode) \
instr.arg0 = crf_d(opcode); \
instr.arg1 = crf_s(opcode); \
#define ppc_grab_regsdab(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a]; \
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regssab(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a]; \
uint32_t ppc_result_b = ppc_state.gpr[reg_b]; \
#define ppc_grab_regssab_stswx(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a]; \
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
#define ppc_grab_regsab(opcode) \
int reg_a = (opcode >> 16) & 31;\
int reg_b = (opcode >> 11) & 31;\
uint32_t ppc_result_a = ppc_state.gpr[reg_a];\
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
#define ppc_grab_regssa(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssa_stmw(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssash(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int rot_sh = (opcode >> 11) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssash_stswi(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int rot_sh = (opcode >> 11) & 31; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssb(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_b = ppc_state.gpr[reg_b]; \
#define ppc_grab_regsda(opcode) \
int reg_d = (opcode >> 21) & 31; \
uint32_t reg_a = (opcode >> 16) & 31; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regsdb(opcode) \
int reg_d = (opcode >> 21) & 31; \
uint32_t reg_b = (opcode >> 11) & 31; \
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
#define ppc_grab_regs_sab_rot(opcode) \
instr.arg0 = reg_s(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
instr.arg3 = rot_mb(opcode); \
instr.arg4 = rot_me(opcode); \
#define ppc_store_iresult_reg(reg, ppc_result)\
ppc_state.gpr[reg] = ppc_result;
#define ppc_store_sfpresult_int(reg, ppc_result64_d)\
ppc_state.fpr[(reg)].int64_r = ppc_result64_d;
#define ppc_store_sfpresult_flt(reg, ppc_dblresult64_d)\
ppc_state.fpr[(reg)].dbl64_r = ppc_dblresult64_d;
#define ppc_store_dfpresult_int(reg, ppc_result64_d)\
#define ppc_store_fpresult_int(reg, ppc_result64_d)\
ppc_state.fpr[(reg)].int64_r = ppc_result64_d;
#define ppc_store_dfpresult_flt(reg, ppc_dblresult64_d)\
#define ppc_store_fpresult_flt(reg, ppc_dblresult64_d)\
ppc_state.fpr[(reg)].dbl64_r = ppc_dblresult64_d;
#define ppc_grab_regsfpdb(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_b = (opcode >> 11) & 31;
instr.arg0 = reg_d(opcode); \
instr.arg2 = reg_b(opcode); \
#define GET_FPR(reg) \
#define GET_FPR(reg) \
ppc_state.fpr[(reg)].dbl64_r
#define ppc_grab_regsfpdiab(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t val_reg_a = ppc_state.gpr[reg_a]; \
uint32_t val_reg_b = ppc_state.gpr[reg_b];
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regsfpdia(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t val_reg_a = ppc_state.gpr[reg_a];
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
#define ppc_grab_regsfpsia(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
uint32_t val_reg_a = ppc_state.gpr[reg_a];
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
#define ppc_grab_regsfpsiab(opcode) \
int reg_s = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
uint32_t val_reg_a = ppc_state.gpr[reg_a]; \
uint32_t val_reg_b = ppc_state.gpr[reg_b];
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regsfpsab(opcode) \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
int crf_d = (opcode >> 21) & 0x1C; \
double db_test_a = GET_FPR(reg_a); \
double db_test_b = GET_FPR(reg_b);
instr.arg0 = crf_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regsfpdab(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
double val_reg_a = GET_FPR(reg_a); \
double val_reg_b = GET_FPR(reg_b);
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
#define ppc_grab_regsfpdac(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_c = (opcode >> 6) & 31; \
double val_reg_a = GET_FPR(reg_a); \
double val_reg_c = GET_FPR(reg_c);
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg3 = reg_c(opcode); \
#define ppc_grab_regsfpdabc(opcode) \
int reg_d = (opcode >> 21) & 31; \
int reg_a = (opcode >> 16) & 31; \
int reg_b = (opcode >> 11) & 31; \
int reg_c = (opcode >> 6) & 31; \
double val_reg_a = GET_FPR(reg_a); \
double val_reg_b = GET_FPR(reg_b); \
double val_reg_c = GET_FPR(reg_c);
instr.arg0 = reg_d(opcode); \
instr.arg1 = reg_a(opcode); \
instr.arg2 = reg_b(opcode); \
instr.arg3 = reg_c(opcode); \
#endif // PPC_MACROS_H

File diff suppressed because it is too large Load Diff

View File

@@ -42,12 +42,13 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
}
#endif
void xer_ov_test(string mnem, uint32_t opcode) {
static void xer_ov_test(string mnem, uint32_t opcode) {
ppc_state.gpr[3] = 2;
ppc_state.gpr[4] = 2;
ppc_state.spr[SPR::XER] = 0xFFFFFFFF;
ppc_cur_instruction = opcode;
ppc_main_opcode();
decode_instr();
ref_instr();
if (ppc_state.spr[SPR::XER] & 0x40000000UL) {
cout << "Invalid " << mnem << " emulation! XER[OV] should not be set." << endl;
nfailed++;
@@ -55,7 +56,7 @@ void xer_ov_test(string mnem, uint32_t opcode) {
ntested++;
}
void xer_update_test() {
static void xer_update_test() {
xer_ov_test("ADDCO", 0x7C632414);
xer_ov_test("ADDCO.", 0x7C632415);
xer_ov_test("ADDO", 0x7C632614);
@@ -153,7 +154,8 @@ static void read_test_data() {
ppc_cur_instruction = opcode;
ppc_main_opcode();
decode_instr();
ref_instr();
ntested++;
@@ -172,7 +174,7 @@ static void read_test_data() {
}
}
double double_from_string(string str) {
static double double_from_string(string str) {
if (str == "snan")
return std::numeric_limits<double>::signaling_NaN();
if (str == "qnan")
@@ -297,7 +299,8 @@ static void read_test_float_data() {
ppc_cur_instruction = opcode;
ppc_main_opcode();
decode_instr();
ref_instr();
ntested++;