mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-02-10 14:30:59 +00:00
Respect FP bit in MSR when running floating point instructions
Rather than running them normally, they should trigger a "no FPU" exception. This appears to be required to allow correct graphical rendering under Mac OS X - the FP bit cleared via mtmsr and rfi instructions and something else appears to be relying on the exception to be thrown. Implemented by maintaining a parallel version of the OpcodeGrabber table (OpcodeGrabberNoFPU) which contains alternate implementations for all the floating point instructions. We switch the table whenever the MSR value changes. This should minimize the overhead of doing these checks.
This commit is contained in:
parent
38c4f1e4cc
commit
acc6e77ec5
@ -646,6 +646,8 @@ extern void ppc_exec_single(void);
|
||||
extern void ppc_exec_until(uint32_t goal_addr);
|
||||
extern void ppc_exec_dbg(uint32_t start_addr, uint32_t size);
|
||||
|
||||
extern void ppc_msr_did_change();
|
||||
|
||||
/* debugging support API */
|
||||
void print_fprs(void); /* print content of the floating-point registers */
|
||||
uint64_t get_reg(std::string reg_name); /* get content of the register reg_name */
|
||||
|
@ -117,6 +117,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
|
||||
ppc_state.msr &= 0xFFFB1041;
|
||||
/* copy MSR[ILE] to MSR[LE] */
|
||||
ppc_state.msr = (ppc_state.msr & ~MSR::LE) | !!(ppc_state.msr & MSR::ILE);
|
||||
ppc_msr_did_change();
|
||||
|
||||
if (ppc_state.msr & MSR::IP) {
|
||||
ppc_next_instruction_address |= 0xFFF00000;
|
||||
|
@ -184,12 +184,27 @@ public:
|
||||
primary opcode (bits 0...5) and modifier (bits 21...31). */
|
||||
static PPCOpcode OpcodeGrabber[64 * 2048];
|
||||
|
||||
/** Alternate lookup table when floating point instructions are disabled.
|
||||
Floating point instructions are mapped to ppc_fpu_off,
|
||||
everything else is the same.*/
|
||||
static PPCOpcode OpcodeGrabberNoFPU[64 * 2048];
|
||||
|
||||
static PPCOpcode* curOpcodeGrabber = OpcodeGrabberNoFPU;
|
||||
|
||||
void ppc_msr_did_change() {
|
||||
curOpcodeGrabber = ppc_state.msr & MSR::FP ? OpcodeGrabber : OpcodeGrabberNoFPU;
|
||||
}
|
||||
|
||||
/** Exception helpers. */
|
||||
|
||||
void ppc_illegalop(uint32_t opcode) {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||
}
|
||||
|
||||
void ppc_fpu_off(uint32_t opcode) {
|
||||
ppc_exception_handler(Except_Type::EXC_NO_FPU, Exc_Cause::FPU_OFF);
|
||||
}
|
||||
|
||||
void ppc_assert_int() {
|
||||
int_pin = true;
|
||||
if (ppc_state.msr & MSR::EE) {
|
||||
@ -215,7 +230,7 @@ void ppc_main_opcode(uint32_t opcode)
|
||||
num_opcodes[opcode]++;
|
||||
#endif
|
||||
#endif
|
||||
OpcodeGrabber[(opcode >> 15 & 0x1F800) | (opcode & 0x7FF)](opcode);
|
||||
curOpcodeGrabber[(opcode >> 15 & 0x1F800) | (opcode & 0x7FF)](opcode);
|
||||
}
|
||||
|
||||
static long long cpu_now_ns() {
|
||||
@ -414,17 +429,39 @@ for (uint32_t mod = 0; mod < 2048; mod++) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OP_fp(opcode, fn) \
|
||||
do { \
|
||||
for (uint32_t mod = 0; mod < 2048; mod++) { \
|
||||
OpcodeGrabber[((opcode) << 11) | mod] = fn; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | mod] = ppc_fpu_off; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OPX(opcode, subopcode, fn) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1)] = fn; \
|
||||
} while (0)
|
||||
|
||||
#define OPX_fp(opcode, subopcode, fn) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1)] = fn; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | ((subopcode)<<1)] = ppc_fpu_off; \
|
||||
} while (0)
|
||||
|
||||
#define OPXd(opcode, subopcode, fn) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x000] = fn<RC0>; \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x001] = fn<RC1>; \
|
||||
} while (0)
|
||||
|
||||
#define OPXd_fp(opcode, subopcode, fn) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x000] = fn<RC0>; \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x001] = fn<RC1>; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | ((subopcode)<<1) | 0x000] = ppc_fpu_off; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | ((subopcode)<<1) | 0x001] = ppc_fpu_off; \
|
||||
} while (0)
|
||||
|
||||
#define OPXod(opcode, subopcode, fn) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x000] = fn<RC0, OV0>; \
|
||||
@ -439,6 +476,14 @@ do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x001] = fn<carry, RC1>; \
|
||||
} while (0)
|
||||
|
||||
#define OPXdc_fp(opcode, subopcode, fn, carry) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x000] = fn<carry, RC0>; \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x001] = fn<carry, RC1>; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | ((subopcode)<<1) | 0x000] = ppc_fpu_off; \
|
||||
OpcodeGrabberNoFPU[((opcode) << 11) | ((subopcode)<<1) | 0x001] = ppc_fpu_off; \
|
||||
} while (0)
|
||||
|
||||
#define OPXcod(opcode, subopcode, fn, carry) \
|
||||
do { \
|
||||
OpcodeGrabber[((opcode) << 11) | ((subopcode)<<1) | 0x000] = fn<carry, RC0, OV0>; \
|
||||
@ -460,36 +505,33 @@ do { \
|
||||
} while (0)
|
||||
|
||||
#define OP31(subopcode, fn) OPX(31, subopcode, fn)
|
||||
#define OP31_fp(subopcode, fn) OPX_fp(31, subopcode, fn)
|
||||
#define OP31d(subopcode, fn) OPXd(31, subopcode, fn)
|
||||
#define OP31od(subopcode, fn) OPXod(31, subopcode, fn)
|
||||
#define OP31dc(subopcode, fn, carry) OPXdc(31, subopcode, fn, carry)
|
||||
#define OP31cod(subopcode, fn, carry) OPXcod(31, subopcode, fn, carry)
|
||||
|
||||
#define OP63(subopcode, fn) OPX(63, subopcode, fn)
|
||||
#define OP63d(subopcode, fn) OPXd(63, subopcode, fn)
|
||||
#define OP63dc(subopcode, fn, carry) OPXdc(63, subopcode, fn, carry)
|
||||
#define OP63(subopcode, fn) OPX_fp(63, subopcode, fn)
|
||||
#define OP63d(subopcode, fn) OPXd_fp(63, subopcode, fn)
|
||||
#define OP63dc(subopcode, fn, carry) OPXdc_fp(63, subopcode, fn, carry)
|
||||
|
||||
#define OP59d(subopcode, fn) \
|
||||
do { \
|
||||
OPXd(59, (subopcode), fn); \
|
||||
OPXd_fp(59, (subopcode), fn); \
|
||||
} while (0)
|
||||
|
||||
#define OP59cd(subopcode, fn) \
|
||||
do { \
|
||||
for (uint32_t ccccc = 0; ccccc < 32; ccccc++) { \
|
||||
OPXd(59, (ccccc << 5) | (subopcode), fn); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OP4_ccccc10xxxx(subopcode, fn) \
|
||||
do { \
|
||||
for (uint32_t ccccc = 0; ccccc < 32; ccccc++) { \
|
||||
OPr(4, (ccccc << 6) | (subopcode), fn); \
|
||||
OPXd_fp(59, (ccccc << 5) | (subopcode), fn); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void initialize_ppc_opcode_table() {
|
||||
std::fill_n(OpcodeGrabber, 64 * 2048, ppc_illegalop);
|
||||
auto opcodeGrabberSize = sizeof(OpcodeGrabber) / sizeof(OpcodeGrabber[0]);
|
||||
std::fill_n(OpcodeGrabber, opcodeGrabberSize, ppc_illegalop);
|
||||
std::fill_n(OpcodeGrabberNoFPU, opcodeGrabberSize, ppc_illegalop);
|
||||
|
||||
OP(3, ppc_twi);
|
||||
//OP(4, ppc_opcode4); - Altivec instructions not emulated yet. Uncomment once they're implemented.
|
||||
OP(7, ppc_mulli);
|
||||
@ -528,14 +570,14 @@ void initialize_ppc_opcode_table() {
|
||||
OP(45, ppc_stu<uint16_t>);
|
||||
OP(46, ppc_lmw);
|
||||
OP(47, ppc_stmw);
|
||||
OP(48, ppc_lfs);
|
||||
OP(49, ppc_lfsu);
|
||||
OP(50, ppc_lfd);
|
||||
OP(51, ppc_lfdu);
|
||||
OP(52, ppc_stfs);
|
||||
OP(53, ppc_stfsu);
|
||||
OP(54, ppc_stfd);
|
||||
OP(55, ppc_stfdu);
|
||||
OP_fp(48, ppc_lfs);
|
||||
OP_fp(49, ppc_lfsu);
|
||||
OP_fp(50, ppc_lfd);
|
||||
OP_fp(51, ppc_lfdu);
|
||||
OP_fp(52, ppc_stfs);
|
||||
OP_fp(53, ppc_stfsu);
|
||||
OP_fp(54, ppc_stfd);
|
||||
OP_fp(55, ppc_stfdu);
|
||||
|
||||
OPla(16, 0x0, (dppc_interpreter::ppc_bc<LK0, AA0>)); // bc
|
||||
OPla(16, 0x1, (dppc_interpreter::ppc_bc<LK1, AA0>)); // bcl
|
||||
@ -597,11 +639,11 @@ void initialize_ppc_opcode_table() {
|
||||
OP31(375, ppc_lhaux);
|
||||
OP31(533, ppc_lswx);
|
||||
OP31(534, ppc_lwbrx);
|
||||
OP31(535, ppc_lfsx);
|
||||
OP31(567, ppc_lfsux);
|
||||
OP31_fp(535, ppc_lfsx);
|
||||
OP31_fp(567, ppc_lfsux);
|
||||
OP31(597, ppc_lswi);
|
||||
OP31(599, ppc_lfdx);
|
||||
OP31(631, ppc_lfdux);
|
||||
OP31_fp(599, ppc_lfdx);
|
||||
OP31_fp(631, ppc_lfdux);
|
||||
OP31(790, ppc_lhbrx);
|
||||
|
||||
OPr(31, (150<<1) | 1, ppc_stwcx); // No Rc=0 variant.
|
||||
@ -613,13 +655,13 @@ void initialize_ppc_opcode_table() {
|
||||
OP31(439, ppc_stux<uint16_t>);
|
||||
OP31(661, ppc_stswx);
|
||||
OP31(662, ppc_stwbrx);
|
||||
OP31(663, ppc_stfsx);
|
||||
OP31(695, ppc_stfsux);
|
||||
OP31_fp(663, ppc_stfsx);
|
||||
OP31_fp(695, ppc_stfsux);
|
||||
OP31(725, ppc_stswi);
|
||||
OP31(727, ppc_stfdx);
|
||||
OP31(759, ppc_stfdux);
|
||||
OP31_fp(727, ppc_stfdx);
|
||||
OP31_fp(759, ppc_stfdux);
|
||||
OP31(918, ppc_sthbrx);
|
||||
if (!is_601) OP31(983, ppc_stfiwx);
|
||||
if (!is_601) OP31_fp(983, ppc_stfiwx);
|
||||
|
||||
OP31(310, ppc_eciwx);
|
||||
OP31(438, ppc_ecowx);
|
||||
@ -739,6 +781,12 @@ void initialize_ppc_opcode_table() {
|
||||
OP63d(i + 30, ppc_fnmsub);
|
||||
OP63d(i + 31, ppc_fnmadd);
|
||||
}
|
||||
|
||||
for (auto i = 0; i < opcodeGrabberSize; i++) {
|
||||
if (OpcodeGrabberNoFPU[i] != ppc_fpu_off) {
|
||||
OpcodeGrabberNoFPU[i] = OpcodeGrabber[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool do_include_601, uint64_t tb_freq)
|
||||
@ -788,6 +836,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool do_include_6
|
||||
}
|
||||
|
||||
ppc_mmu_init();
|
||||
ppc_msr_did_change();
|
||||
|
||||
/* redirect code execution to reset vector */
|
||||
ppc_state.pc = 0xFFF00100;
|
||||
@ -845,8 +894,10 @@ static uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
|
||||
return ppc_state.pc;
|
||||
}
|
||||
if (reg_name_u == "MSR") {
|
||||
if (is_write)
|
||||
if (is_write) {
|
||||
ppc_state.msr = (uint32_t)val;
|
||||
ppc_msr_did_change();
|
||||
}
|
||||
return ppc_state.msr;
|
||||
}
|
||||
if (reg_name_u == "CR") {
|
||||
|
@ -802,6 +802,7 @@ void dppc_interpreter::ppc_mtmsr(uint32_t opcode) {
|
||||
}
|
||||
uint32_t reg_s = (opcode >> 21) & 0x1F;
|
||||
ppc_state.msr = ppc_state.gpr[reg_s];
|
||||
ppc_msr_did_change();
|
||||
|
||||
// generate External Interrupt Exception
|
||||
// if CPU interrupt line is asserted
|
||||
@ -1379,6 +1380,7 @@ void dppc_interpreter::ppc_rfi(uint32_t opcode) {
|
||||
uint32_t new_srr1_val = (ppc_state.spr[SPR::SRR1] & 0x87C0FF73UL);
|
||||
uint32_t new_msr_val = (ppc_state.msr & ~0x87C0FF73UL);
|
||||
ppc_state.msr = (new_msr_val | new_srr1_val) & 0xFFFBFFFFUL;
|
||||
ppc_msr_did_change();
|
||||
|
||||
// generate External Interrupt Exception
|
||||
// if CPU interrupt line is still asserted
|
||||
|
Loading…
x
Reference in New Issue
Block a user