Merge pull request #135 from mihaip/upstream-nofpu

Respect FP bit in MSR when running floating point instructions
This commit is contained in:
dingusdev 2025-01-21 06:53:14 -07:00 committed by GitHub
commit 7df166a99e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 88 additions and 32 deletions

View File

@ -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 */

View File

@ -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;

View File

@ -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") {

View File

@ -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