From f4a6e585bea1176b2518bdd381e4bb44b30a23e7 Mon Sep 17 00:00:00 2001 From: anusko Date: Sat, 4 Sep 2010 01:04:37 +0000 Subject: [PATCH] Rollback on a DSI exception, for the instructions that need it. Not a good thing to say, but this isn't properly tested, since I don't know of any game that generates a DSI exception. I'll try to write some homebrew to test this, but I'm pretty confident it's ok. Anyway, please take a look at it and tell me if you find some mistake :-) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6172 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Interpreter/Interpreter_LoadStore.cpp | 173 +++++++++++++----- 1 file changed, 126 insertions(+), 47 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp index 831b2a399c..ba40da5369 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -195,39 +195,65 @@ void Interpreter::lhzu(UGeckoInstruction _inst) } } -// FIXME: lmw should do a total rollback if a DSI occurs void Interpreter::lmw(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA(_inst); - for (int iReg = _inst.RD; iReg <= 31; iReg++, uAddress += 4) + u32 EA = Helper_Get_EA(_inst); + int r = _inst.RD; + + const int rb_r = r; + static u32 rb_GPR[32]; + + while (r <= 31) { - u32 TempReg = Memory::Read_U32(uAddress); + u32 TempReg = Memory::Read_U32(EA); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PanicAlert("DSI exception in lmw"); NOTICE_LOG(POWERPC, "DSI exception in lmw"); + + while (r > rb_r) + { + m_GPR[r] = rb_GPR[r]; + r--; + } return; } - else - { - m_GPR[iReg] = TempReg; - } + rb_GPR[r] = m_GPR[r]; + m_GPR[r] = TempReg; + + r++; + EA += 4; } } -// FIXME: stmw should do a total rollback if a DSI occurs void Interpreter::stmw(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA(_inst); - for (int iReg = _inst.RS; iReg <= 31; iReg++, uAddress+=4) - { - Memory::Write_U32(m_GPR[iReg], uAddress); + u32 EA = Helper_Get_EA(_inst); + int r = _inst.RS; + + const int rb_r = r; + static u32 rb_mem[32]; + + while (r <= 31) + { + rb_mem[r] = Memory::ReadUnchecked_U32(EA); + Memory::Write_U32(m_GPR[r], EA); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PanicAlert("DSI exception in stmw"); NOTICE_LOG(POWERPC, "DSI exception in stmw"); + + while (r > rb_r) + { + Memory::WriteUnchecked_U32(rb_mem[r], EA); + r--; + EA -= 4; + } return; } + + r++; + EA += 4; } } @@ -523,7 +549,6 @@ void Interpreter::lhzx(UGeckoInstruction _inst) } // TODO: is this right? -// FIXME: Should rollback if a DSI occurs void Interpreter::lswx(UGeckoInstruction _inst) { u32 EA = Helper_Get_EA_X(_inst); @@ -531,8 +556,13 @@ void Interpreter::lswx(UGeckoInstruction _inst) int r = _inst.RD; int i = 0; + const u32 rb_EA = EA; + const int rb_r = r; + static u32 rb_GPR[32]; + if (n > 0) { + rb_GPR[r] = m_GPR[r]; m_GPR[r] = 0; do { @@ -541,6 +571,17 @@ void Interpreter::lswx(UGeckoInstruction _inst) { PanicAlert("DSI exception in lswx."); NOTICE_LOG(POWERPC, "DSI exception in lswx"); + + n = ((EA - rb_EA) / 4) + 1; + EA = rb_EA; + r = rb_r; + while (n > 0) + { + m_GPR[r] = rb_GPR[r]; + r = (r + 1) & 31; + EA += 4; + n--; + } return; } m_GPR[r] |= TempValue; @@ -552,6 +593,7 @@ void Interpreter::lswx(UGeckoInstruction _inst) { i = 0; r = (r + 1) & 31; + rb_GPR[r] = m_GPR[r]; m_GPR[r] = 0; } } while (n > 0); @@ -667,7 +709,6 @@ void Interpreter::sthx(UGeckoInstruction _inst) // __________________________________________________________________________________________________ // lswi - bizarro string instruction -// FIXME: Should rollback if a DSI occurs void Interpreter::lswi(UGeckoInstruction _inst) { u32 EA; @@ -682,38 +723,55 @@ void Interpreter::lswi(UGeckoInstruction _inst) else n = _inst.NB; - int r = _inst.RD - 1; + int r = _inst.RD; int i = 0; - while (n>0) + + const u32 rb_EA = EA; + const int rb_r = r; + static u32 rb_GPR[32]; + + if (n > 0) { - if (i==0) + rb_GPR[r] = m_GPR[r]; + m_GPR[r] = 0; + do { - r++; - r &= 31; - m_GPR[r] = 0; - } + u32 TempValue = Memory::Read_U8(EA) << (24 - i); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in lswi."); - u32 TempValue = Memory::Read_U8(EA) << (24 - i); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PanicAlert("DSI exception in lsw."); - return; - } + n = ((EA - rb_EA) / 4) + 1; + EA = rb_EA; + r = rb_r; + while (n > 0) + { + m_GPR[r] = rb_GPR[r]; + r = (r + 1) & 31; + EA += 4; + n--; + } + return; + } + m_GPR[r] |= TempValue; - m_GPR[r] |= TempValue; - - i += 8; - if (i == 32) - i = 0; - EA++; - n--; + EA++; + n--; + i += 8; + if (i == 32) + { + i = 0; + r = (r + 1) & 31; + rb_GPR[r] = m_GPR[r]; + m_GPR[r] = 0; + } + } while (n > 0); } } // todo : optimize ? // __________________________________________________________________________________________________ // stswi - bizarro string instruction -// FIXME: Should rollback if a DSI occurs void Interpreter::stswi(UGeckoInstruction _inst) { u32 EA; @@ -728,26 +786,47 @@ void Interpreter::stswi(UGeckoInstruction _inst) else n = _inst.NB; - int r = _inst.RS - 1; + int r = _inst.RS; int i = 0; - while (n > 0) - { - if (i == 0) - { - r++; - r &= 31; - } + + const u32 rb_EA = EA; + const int rb_r = r; + static u32 rb_mem[32]; + + while (n > 0) { + rb_mem[r] |= Memory::ReadUnchecked_U8(EA) << (24 - i); Memory::Write_U8((m_GPR[r] >> (24 - i)) & 0xFF, EA); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { + PanicAlert("DSI exception in stswi."); + + n = EA - rb_EA; + EA = rb_EA; + r = rb_r; + i = 0; + while (n > 0) + { + Memory::WriteUnchecked_U8((rb_mem[r] >> (24 - i)) & 0xFF, EA); + EA++; + i += 8; + if (i == 32) + { + i = 0; + r = (r + 1) & 31; + } + n--; + } return; } - i += 8; - if (i == 32) - i = 0; EA++; n--; + i += 8; + if (i == 32) + { + i = 0; + r = (r + 1) & 31; + } } }