Skip to content

Commit fee7e75

Browse files
committed
Added the 'one-instruction' latency on interrupts.
1 parent d28a30a commit fee7e75

3 files changed

Lines changed: 103 additions & 32 deletions

File tree

include/MOS6502/MOS6502.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class MOS6502
5959
bool running = false;
6060

6161
std::array<bool, INTERRUPT::COUNT> signals = {};
62+
std::array<bool, INTERRUPT::COUNT> pending = {};
6263

6364
WORD PC = { .w = 0x0000 };
6465
WORD AB = { .w = 0x0000 };
@@ -84,10 +85,20 @@ class MOS6502
8485
const int8_t offset = static_cast<int8_t>(Fetch());
8586

8687
if (test) {
87-
Idle();
8888
const uint16_t target = static_cast<uint16_t>(PC.w + offset);
89-
if ((PC.w ^ target) & 0xFF00) { Load((PC.h << 8) | (target & 0xFF)); }
89+
if ((PC.w ^ target) & 0xFF00) {
90+
Idle();
91+
PollInterrupts();
92+
Load((PC.h << 8) | (target & 0xFF));
93+
} else {
94+
// Branch-taken quirk:
95+
// A non-page-crossing taken branch suppresses the interrupt poll entirely.
96+
// Any pending IRQ/NMI is therefore delayed by one additional instruction.
97+
Idle();
98+
}
9099
PC.w = target;
100+
} else {
101+
PollInterrupts();
91102
}
92103
}
93104

@@ -127,9 +138,23 @@ class MOS6502
127138
Push(PC.h);
128139
Push(PC.l);
129140
Push(P.value | 0x20);
141+
142+
// NMI hijack
143+
if (signals[INTERRUPT::NMI]) {
144+
signals[INTERRUPT::NMI] = false;
145+
pending[INTERRUPT::NMI] = false;
146+
vector = 0xFFFA;
147+
}
148+
149+
P.I = 1;
130150
PC.l = Load(vector);
151+
PollInterrupts();
131152
PC.h = Load(vector + 1);
132-
P.I = 1;
153+
}
154+
155+
inline void PollInterrupts() {
156+
if (signals[INTERRUPT::NMI]) { pending[INTERRUPT::NMI] = true; }
157+
pending[INTERRUPT::IRQ] = !P.I && signals[INTERRUPT::IRQ];
133158
}
134159

135160
[[nodiscard]] inline uint8_t Pull() {

0 commit comments

Comments
 (0)