From cf4ce01ddd611e5fd657be4c19d17fb783ba92d1 Mon Sep 17 00:00:00 2001 From: joevt Date: Sat, 16 Dec 2023 05:34:43 -0800 Subject: [PATCH] ppcopcodes: set DSISR for alignment exception. --- cpu/ppc/ppcemu.h | 1 + cpu/ppc/ppcexceptions.cpp | 112 ++++++++++++++++++++++++++++++++++++++ cpu/ppc/ppcmmu.cpp | 51 ++++++++--------- cpu/ppc/ppcopcodes.cpp | 6 +- 4 files changed, 139 insertions(+), 31 deletions(-) diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 7d2056b..2f751a0 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -394,6 +394,7 @@ void update_fpscr(uint32_t new_fpscr); void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits); [[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits); void ppc_floating_point_exception(); +void ppc_alignment_exception(uint32_t ea); // MEMORY DECLARATIONS extern MemCtrlBase* mem_ctrl_instance; diff --git a/cpu/ppc/ppcexceptions.cpp b/cpu/ppc/ppcexceptions.cpp index d421bf4..5e7a588 100644 --- a/cpu/ppc/ppcexceptions.cpp +++ b/cpu/ppc/ppcexceptions.cpp @@ -200,3 +200,115 @@ void ppc_floating_point_exception() { ppc_state.pc, ppc_cur_instruction); // mmu_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::FPU_EXCEPTION); } + +void ppc_alignment_exception(uint32_t ea) +{ + uint32_t dsisr; + + switch (ppc_cur_instruction & 0xfc000000) { + case 0x80000000: // lwz + case 0x90000000: // stw + case 0xa0000000: // lhz + case 0xa8000000: // lha + case 0xb0000000: // sth + case 0xb8000000: // lmw + case 0xc0000000: // lfs + case 0xc8000000: // lfd + case 0xd0000000: // stfs + case 0xd8000000: // stfd + case 0x84000000: // lwzu + case 0x94000000: // stwu + case 0xa4000000: // lhzu + case 0xac000000: // lhau + case 0xb4000000: // sthu + case 0xbc000000: // stmw + case 0xc4000000: // lfsu + case 0xcc000000: // lfdu + case 0xd4000000: // stfsu + case 0xdc000000: // stfdu +indirect_with_immediate_index: + dsisr = ((ppc_cur_instruction >> 12) & 0x00004000) // bit 17 — Set to bit 5 of the instruction. + | ((ppc_cur_instruction >> 17) & 0x00003c00); // bits 18–21 - set to bits 1–4 of the instruction. + break; + case 0x7c000000: + switch (ppc_cur_instruction & 0xfc0007ff) { + case 0x7c000028: // lwarx (invalid form - bits 15-21 of DSISR are identical to those of lwz) + case 0x7c0002aa: // lwax (64-bit only) + case 0x7c00042a: // lswx + case 0x7c0004aa: // lswi + case 0x7c00052a: // stswx + case 0x7c0005aa: // stswi + case 0x7c0002ea: // lwaux (64 bit only) + case 0x7c00012c: // stwcx + case 0x7c00042c: // lwbrx + case 0x7c00052c: // stwbrx + case 0x7c00062c: // lhbrx + case 0x7c00072c: // sthbrx + case 0x7c00026c: // eciwx // MPC7451 + case 0x7c00036c: // ecowx // MPC7451 + case 0x7c00002e: // lwzx + case 0x7c00012e: // stwx + case 0x7c00022e: // lhzx + case 0x7c0002ae: // lhax + case 0x7c00032e: // sthx + case 0x7c00042e: // lfsx + case 0x7c0004ae: // lfdx + case 0x7c00052e: // stfsx + case 0x7c0005ae: // stfdx + case 0x7c00006e: // lwzux + case 0x7c00016e: // stwux + case 0x7c00026e: // lhzux + case 0x7c0002ee: // lhaux + case 0x7c00036e: // sthux + case 0x7c00046e: // lfsux + case 0x7c0004ee: // lfdux + case 0x7c00056e: // stfsux + case 0x7c0005ee: // stfdux +indirect_with_index: + dsisr = ((ppc_cur_instruction << 14) & 0x00018000) // bits 15–16 - set to bits 29–30 of the instruction. + | ((ppc_cur_instruction << 8) & 0x00004000) // bit 17 - set to bit 25 of the instruction. + | ((ppc_cur_instruction << 3) & 0x00003c00); // bits 18–21 - set to bits 21–24 of the instruction. + break; + case 0x7c0007ec: + if ((ppc_cur_instruction & 0xffe007ff) == 0x7c0007ec) // dcbz + goto indirect_with_index; + /* fallthrough */ + default: + goto unexpected_instruction; + } + break; + default: +unexpected_instruction: + dsisr = 0; + LOG_F(ERROR, "Alignment exception from unexpected instruction 0x%08x", + ppc_cur_instruction); + } + + // bits 22–26 - Set to bits 6–10 (source or destination) of the instruction. + // Undefined for dcbz. + dsisr |= ((ppc_cur_instruction >> 16) & 0x000003e0); + + if ((ppc_cur_instruction & 0xfc000000) == 0xb8000000) { // lmw + LOG_F(ERROR, "Alignment exception from instruction 0x%08x (lmw). " + "What to set DSISR bits 27-31?", ppc_cur_instruction); + // dsisr |= ((ppc_cur_instruction >> ?) & 0x0000001f); // bits 27–31 + } + else if ((ppc_cur_instruction & 0xfc0007ff) == 0x7c0004aa) { // lswi + LOG_F(ERROR, "Alignment exception from instruction 0x%08x (lswi). " + "What to set DSISR bits 27-31?", ppc_cur_instruction); + // dsisr |= ((ppc_cur_instruction >> ?) & 0x0000001f); // bits 27–31 + } + else if ((ppc_cur_instruction & 0xfc0007ff) == 0x7c00042a) { // lswx + LOG_F(ERROR, "Alignment exception from instruction 0x%08x (lswx). " + "What to set DSISR bits 27-31?", ppc_cur_instruction); + // dsisr |= ((ppc_cur_instruction >> ?) & 0x0000001f); // bits 27–31 + } + else { + // bits 27–31 - Set to bits 11–15 of the instruction (rA) + dsisr |= ((ppc_cur_instruction >> 16) & 0x0000001f); + } + + ppc_state.spr[SPR::DSISR] = dsisr; + ppc_state.spr[SPR::DAR] = ea; + ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); +} diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 7fc04af..488cf90 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -1075,19 +1075,17 @@ inline T mmu_read_vmem(uint32_t guest_va) iomem_reads_total++; #endif if (sizeof(T) == 8) { - if (guest_va & 3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); - } - { - return ( - ((T)tlb2_entry->rgn_desc->devobj->read(tlb2_entry->rgn_desc->start, - guest_va - tlb2_entry->dev_base_va, - 4) << 32) | - tlb2_entry->rgn_desc->devobj->read(tlb2_entry->rgn_desc->start, - guest_va + 4 - tlb2_entry->dev_base_va, - 4) - ); - } + if (guest_va & 3) + ppc_alignment_exception(guest_va); + + return ( + ((T)tlb2_entry->rgn_desc->devobj->read(tlb2_entry->rgn_desc->start, + guest_va - tlb2_entry->dev_base_va, + 4) << 32) | + tlb2_entry->rgn_desc->devobj->read(tlb2_entry->rgn_desc->start, + guest_va + 4 - tlb2_entry->dev_base_va, + 4) + ); } else { return ( @@ -1199,19 +1197,16 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) iomem_writes_total++; #endif if (sizeof(T) == 8) { - if (guest_va & 3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); - } - { - tlb2_entry->rgn_desc->devobj->write(tlb2_entry->rgn_desc->start, - guest_va - tlb2_entry->dev_base_va, - value >> 32, 4); - tlb2_entry->rgn_desc->devobj->write(tlb2_entry->rgn_desc->start, - guest_va + 4 - tlb2_entry->dev_base_va, - (uint32_t)value, 4); - } - } - else { + if (guest_va & 3) + ppc_alignment_exception(guest_va); + + tlb2_entry->rgn_desc->devobj->write(tlb2_entry->rgn_desc->start, + guest_va - tlb2_entry->dev_base_va, + value >> 32, 4); + tlb2_entry->rgn_desc->devobj->write(tlb2_entry->rgn_desc->start, + guest_va + 4 - tlb2_entry->dev_base_va, + (uint32_t)value, 4); + } else { tlb2_entry->rgn_desc->devobj->write(tlb2_entry->rgn_desc->start, guest_va - tlb2_entry->dev_base_va, value, sizeof(T)); @@ -1282,7 +1277,7 @@ static T read_unaligned(uint32_t guest_va, uint8_t *host_va) return READ_DWORD_BE_U(host_va); case 8: if (guest_va & 3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + ppc_alignment_exception(guest_va); } return READ_QWORD_BE_U(host_va); } @@ -1328,7 +1323,7 @@ static void write_unaligned(uint32_t guest_va, uint8_t *host_va, T value) break; case 8: if (guest_va & 3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + ppc_alignment_exception(guest_va); } WRITE_QWORD_BE_U(host_va, value); break; diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index 1b99a70..fa26960 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -1776,7 +1776,7 @@ void dppc_interpreter::ppc_stmw() { /* what should we do if EA is unaligned? */ if (ppc_effective_address & 3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000); + ppc_alignment_exception(ppc_effective_address); } for (; reg_s <= 31; reg_s++) { @@ -2236,7 +2236,7 @@ void dppc_interpreter::ppc_eciwx() { ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b); if (ppc_effective_address & 0x3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + ppc_alignment_exception(ppc_effective_address); } ppc_result_d = mmu_read_vmem(ppc_effective_address); @@ -2256,7 +2256,7 @@ void dppc_interpreter::ppc_ecowx() { ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b); if (ppc_effective_address & 0x3) { - ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + ppc_alignment_exception(ppc_effective_address); } mmu_write_vmem(ppc_effective_address, ppc_result_d);