Skip to content

Commit fc2b510

Browse files
committed
Fixed a bug in some illegal opcodes.
1 parent fee7e75 commit fc2b510

3 files changed

Lines changed: 67 additions & 3 deletions

File tree

build-and-run.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
3+
cmake --preset default # Configure (output in build/)
4+
cmake --build --preset default # Build
5+
cmake --build --preset run # Build and run the NES example against the test ROM

src/MOS6502.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// by Naomi Peori (naomi@peori.ca)
44
//
55

6+
#include <functional>
67
#include "MOS6502/MOS6502.h"
78

89
void MOS6502::Run() {

src/MOS6502_illegal.cpp

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// by Naomi Peori (naomi@peori.ca)
44
//
55

6+
#include <functional>
67
#include "MOS6502/MOS6502.h"
78

89
//
@@ -62,47 +63,104 @@ void MOS6502::RunIllegal(BYTE opcode) {
6263

6364
// ---------------------------------------------------------------
6465
// SHY — Store Y & (addr_high + 1), Absolute, X
66+
// On page-cross the effective address's high byte is corrupted to v.
6567
// ---------------------------------------------------------------
6668

6769
case 0x9C: {
6870
AB.l = Fetch();
6971
AB.h = Fetch();
70-
BYTE v = Y & (AB.h + 1);
72+
BYTE argHigh = AB.h;
73+
BYTE v = Y & (argHigh + 1);
7174
AB = IdleOnPageAlways(AB, X);
7275
PollInterrupts();
76+
if (AB.h != argHigh) { AB.h = v; }
7377
Store(AB.w, v);
7478
break;
7579
}
7680

7781
// ---------------------------------------------------------------
7882
// SHX — Store X & (addr_high + 1), Absolute, Y
83+
// On page-cross the effective address's high byte is corrupted to v.
7984
// ---------------------------------------------------------------
8085

8186
case 0x9E: {
8287
AB.l = Fetch();
8388
AB.h = Fetch();
84-
BYTE v = X & (AB.h + 1);
89+
BYTE argHigh = AB.h;
90+
BYTE v = X & (argHigh + 1);
8591
AB = IdleOnPageAlways(AB, Y);
8692
PollInterrupts();
93+
if (AB.h != argHigh) { AB.h = v; }
8794
Store(AB.w, v);
8895
break;
8996
}
9097

9198
// ---------------------------------------------------------------
9299
// TAS — S = A & X; store S & (addr_high + 1), Absolute, Y
100+
// On page-cross the effective address's high byte is corrupted to v.
93101
// ---------------------------------------------------------------
94102

95103
case 0x9B: {
96104
AB.l = Fetch();
97105
AB.h = Fetch();
106+
BYTE argHigh = AB.h;
98107
S = A & X;
99-
BYTE v = S & (AB.h + 1);
108+
BYTE v = S & (argHigh + 1);
100109
AB = IdleOnPageAlways(AB, Y);
101110
PollInterrupts();
111+
if (AB.h != argHigh) { AB.h = v; }
102112
Store(AB.w, v);
103113
break;
104114
}
105115

116+
// ---------------------------------------------------------------
117+
// SHA — Store A & X & (addr_high + 1)
118+
// On page-cross the effective address's high byte is corrupted to v.
119+
// ---------------------------------------------------------------
120+
121+
case 0x9F: { // Absolute, Y
122+
AB.l = Fetch();
123+
AB.h = Fetch();
124+
BYTE argHigh = AB.h;
125+
BYTE v = A & X & (argHigh + 1);
126+
AB = IdleOnPageAlways(AB, Y);
127+
PollInterrupts();
128+
if (AB.h != argHigh) { AB.h = v; }
129+
Store(AB.w, v);
130+
break;
131+
}
132+
133+
case 0x93: { // Indirect, Y
134+
TB.w = Fetch();
135+
AB.l = Load(TB.w);
136+
TB.l += 1;
137+
AB.h = Load(TB.w);
138+
BYTE argHigh = AB.h;
139+
BYTE v = A & X & (argHigh + 1);
140+
AB = IdleOnPageAlways(AB, Y);
141+
PollInterrupts();
142+
if (AB.h != argHigh) { AB.h = v; }
143+
Store(AB.w, v);
144+
break;
145+
}
146+
147+
// ---------------------------------------------------------------
148+
// ANE / XAA — A = (A | magic) & X & #imm (unstable on hardware)
149+
// LXA — A = X = (A | magic) & #imm (unstable on hardware)
150+
// The "magic" constant varies by die/temperature; 0xEE is the value
151+
// Blargg's test ROMs assume.
152+
// ---------------------------------------------------------------
153+
154+
case 0x8B:
155+
PollInterrupts();
156+
A = Flags((A | 0xEE) & X & Fetch());
157+
break;
158+
159+
case 0xAB:
160+
PollInterrupts();
161+
A = X = Flags((A | 0xEE) & Fetch());
162+
break;
163+
106164
// ---------------------------------------------------------------
107165
// DCP — DEC, then CMP
108166
// ---------------------------------------------------------------

0 commit comments

Comments
 (0)