File tree Expand file tree Collapse file tree 2 files changed +13
-4
lines changed Expand file tree Collapse file tree 2 files changed +13
-4
lines changed Original file line number Diff line number Diff line change @@ -140,6 +140,8 @@ struct ARM7TDMI {
140
140
bool is_banked = id >= 8 && id != 15 ;
141
141
142
142
if (unlikely (ldm_usermode_conflict && is_banked)) {
143
+ // This array holds the current user/sys bank value only if the CPU wasn't in user or system mode all along during the user mode LDM instruction.
144
+ // We take care in the LDM implementation that this branch is only taken if that was the case.
143
145
result |= state.bank [BANK_NONE][id - 8 ];
144
146
}
145
147
@@ -154,6 +156,8 @@ struct ARM7TDMI {
154
156
bool is_banked = id >= 8 && id != 15 ;
155
157
156
158
if (unlikely (ldm_usermode_conflict && is_banked)) {
159
+ // This array holds the current user/sys bank value only if the CPU wasn't in user or system mode all along during the user mode LDM instruction.
160
+ // We take care in the LDM implementation that this branch is only taken if that was the case.
157
161
state.bank [BANK_NONE][id - 8 ] = value;
158
162
}
159
163
Original file line number Diff line number Diff line change @@ -544,7 +544,7 @@ void ARM_BlockDataTransfer(u32 instruction) {
544
544
int base = (instruction >> 16 ) & 0xF ;
545
545
int list = instruction & 0xFFFF ;
546
546
547
- Mode mode;
547
+ Mode mode = state. cpsr . f . mode ;
548
548
bool transfer_pc = list & (1 << 15 );
549
549
int first = 0 ;
550
550
int bytes = 0 ;
@@ -571,10 +571,15 @@ void ARM_BlockDataTransfer(u32 instruction) {
571
571
bytes = 64 ;
572
572
}
573
573
574
- bool switch_mode = user_mode && (!load || !transfer_pc);
574
+ /* *
575
+ * Whether the instruction is a LDM^ instruction and we need to switch to user mode.
576
+ * Note that we only switch to user mode if we aren't in user or system mode already.
577
+ * This is important for emulation of the LDM user mode register bus conflict,
578
+ * since the implementation of this quirk in GetReg() and SetReg() only works if the CPU isn't in user or system mode anymore.
579
+ */
580
+ const bool switch_mode = user_mode && (!load || !transfer_pc) && mode != MODE_USR && mode != MODE_SYS;
575
581
576
582
if (switch_mode) {
577
- mode = state.cpsr .f .mode ;
578
583
SwitchMode (MODE_USR);
579
584
}
580
585
@@ -633,7 +638,7 @@ void ARM_BlockDataTransfer(u32 instruction) {
633
638
bus.Idle ();
634
639
635
640
if (switch_mode) {
636
- /* During the following two cycles of a usermode LDM,
641
+ /* During the following two cycles of a user mode LDM,
637
642
* register accesses will go to both the user bank and original bank.
638
643
*/
639
644
ldm_usermode_conflict = true ;
You can’t perform that action at this time.
0 commit comments