summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/powerpc/ppcdrc.cpp
diff options
context:
space:
mode:
author 987123879113 <63495610+987123879113@users.noreply.github.com>2023-08-28 02:54:20 +0900
committer GitHub <noreply@github.com>2023-08-28 03:54:20 +1000
commitbced77dec95faea0a2adaa3de09dd1cb48b5ae92 (patch)
tree3eb67c6d92715036192174bd2f647f7fed4243ad /src/devices/cpu/powerpc/ppcdrc.cpp
parent59e8aef15e24d1e960ae2b4fbeb4974cfa87b52b (diff)
-cpu/powerpc: Don't overwrite RA in lmw instruction. (#11512)
* For 4xx series and 601, skip over the register update. * For any other flavor, raise an illegal instruction exception. -konami/stingnet: Added ATA CS1 to address map, and removed comment about crash which has been fixed.
Diffstat (limited to 'src/devices/cpu/powerpc/ppcdrc.cpp')
-rw-r--r--src/devices/cpu/powerpc/ppcdrc.cpp25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/devices/cpu/powerpc/ppcdrc.cpp b/src/devices/cpu/powerpc/ppcdrc.cpp
index b1f2a2a2568..1905e1eb1d6 100644
--- a/src/devices/cpu/powerpc/ppcdrc.cpp
+++ b/src/devices/cpu/powerpc/ppcdrc.cpp
@@ -2256,12 +2256,27 @@ bool ppc_device::generate_opcode(drcuml_block &block, compiler_state *compiler,
case 0x2e: /* LMW */
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra
- for (int regnum = G_RD(op); regnum < 32; regnum++)
+
+ if (G_RD(op) <= G_RA(op) && !(m_cap & PPCCAP_4XX) && m_flavor != PPC_MODEL_601)
+ {
+ // RA being in the range is an invalid form
+ // 403 and 405 manual allows writes where regnum != RA || regnum == 31, regnum == RA is skipped
+ // 601 user manual lists no special rules for R31 being valid but regnum == RA is skipped
+ // 603 and above just says it's an invalid form
+ // tropchnc (403GA) is known to use this behavior
+ UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000
+ }
+ else
{
- UML_ADD(block, I0, mem(&m_core->tempaddr), (int16_t)G_SIMM(op) + 4 * (regnum - G_RD(op)));
- // add i0,[tempaddr],simm + 4*(regnum-rd)
- UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align
- UML_MOV(block, R32(regnum), I0); // mov regnum,i0
+ for (int regnum = G_RD(op); regnum < 32; regnum++)
+ {
+ UML_ADD(block, I0, mem(&m_core->tempaddr), (int16_t)G_SIMM(op) + 4 * (regnum - G_RD(op)));
+ // add i0,[tempaddr],simm + 4*(regnum-rd)
+ UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align
+
+ if (regnum != G_RA(op) || ((m_cap & PPCCAP_4XX) && regnum == 31))
+ UML_MOV(block, R32(regnum), I0); // mov regnum,i0
+ }
}
generate_update_cycles(block, compiler, desc->pc + 4, true); // <update cycles>
return true;