Skip to content

Commit ccc07b1

Browse files
bfirshclaude
andcommitted
Improve CPU accuracy for indexed addressing modes
- Add dummy reads on page boundary crossing for Absolute,X, Absolute,Y, and (Indirect),Y addressing modes. When indexing crosses a page boundary, the 6502 first reads from the "wrong" address (before carry is applied to high byte), then reads from the correct address. - Add dummy read for STA with indexed addressing modes (Absolute,X, Absolute,Y, (Indirect),Y) even without page crossing, matching real 6502 behavior where write instructions always perform a read cycle. - Clean up (Indirect,X) addressing mode - remove incorrect page crossing check since zero-page indexing wraps within the zero page. Fixes dummy read cycle errors in AccuracyCoin. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4c4af69 commit ccc07b1

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

src/cpu.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ CPU.prototype = {
215215
// indexed, but with the high byte.
216216
addr = this.load16bit(opaddr + 2);
217217
if ((addr & 0xff00) !== ((addr + this.REG_X) & 0xff00)) {
218+
// Page boundary crossed - dummy read from wrong address first
219+
this.load((addr & 0xff00) | ((addr + this.REG_X) & 0xff));
218220
cycleAdd = 1;
219221
}
220222
addr += this.REG_X;
@@ -225,6 +227,8 @@ CPU.prototype = {
225227
// indexed, but with the high byte.
226228
addr = this.load16bit(opaddr + 2);
227229
if ((addr & 0xff00) !== ((addr + this.REG_Y) & 0xff00)) {
230+
// Page boundary crossed - dummy read from wrong address first
231+
this.load((addr & 0xff00) | ((addr + this.REG_Y) & 0xff));
228232
cycleAdd = 1;
229233
}
230234
addr += this.REG_Y;
@@ -234,13 +238,9 @@ CPU.prototype = {
234238
// Pre-indexed Indirect mode. Find the 16-bit address
235239
// starting at the given location plus
236240
// the current X register. The value is the contents of that
237-
// address.
241+
// address. No page crossing or dummy read - wraps within zero page.
238242
addr = this.load(opaddr + 2);
239-
if ((addr & 0xff00) !== ((addr + this.REG_X) & 0xff00)) {
240-
cycleAdd = 1;
241-
}
242-
addr += this.REG_X;
243-
addr &= 0xff;
243+
addr = (addr + this.REG_X) & 0xff;
244244
addr = this.load16bit(addr);
245245
break;
246246
}
@@ -252,6 +252,8 @@ CPU.prototype = {
252252
// stored at that adress.
253253
addr = this.load16bit(this.load(opaddr + 2));
254254
if ((addr & 0xff00) !== ((addr + this.REG_Y) & 0xff00)) {
255+
// Page boundary crossed - dummy read from wrong address first
256+
this.load((addr & 0xff00) | ((addr + this.REG_Y) & 0xff));
255257
cycleAdd = 1;
256258
}
257259
addr += this.REG_Y;
@@ -936,6 +938,14 @@ CPU.prototype = {
936938
// *******
937939

938940
// Store accumulator in memory
941+
// For indexed addressing modes, STA always does a dummy read.
942+
// Page-crossing case is handled in address mode; handle non-crossing here.
943+
if (
944+
cycleAdd === 0 &&
945+
(addrMode === 8 || addrMode === 9 || addrMode === 11)
946+
) {
947+
this.load(addr);
948+
}
939949
this.write(addr, this.REG_ACC);
940950
break;
941951
}

0 commit comments

Comments
 (0)