Does 6502 instruction fetching count as a memory read?

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Does 6502 instruction fetching count as a memory read?

Post by Petruza »

I'm using the same function memory_read() to resolve addressing modes, but also to fetch the opcode at PC, and depending on the instruction length, fetching 1 or 2 more bytes starting at PC+1.
The question that arises is if this reads into memory count as regular memory reads, in the sense that, for example, suppose that for some reason the PC is pointing to one byte before a memory-mapped register, then fetching the opcode will be fine, but fetching its operand, if any, will have a side effect of reading the register.
Or it may even happen, I don't know if any game uses this technique, but suppose that the PC at some point has the address of a memory-mapped register, would the opcode fetch read the register?
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Yes. They're all the same.

Any fetch will count as a 'read' for registers.

Even DMA from things like the DMC or $4014.


EDIT:

also note that some addressing modes have "dummy" reads/writes that can affect some registers.
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza »

Disch wrote:also note that some addressing modes have "dummy" reads/writes that can affect some registers.
Oh please give some example
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

LDA $1234,X will fetch both $1234 and $1234+X I think. Not 100% sure on this, but I think that's one of them that does a dummy read.
The read-write-modify instructions (INC, ASL, etc) do dummy writes, and the MMC1 chip only sees the dummy write, and not the final write. Bill & Ted's excellent adventure and a few other games rely on this.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Bill & Ted's Excellent Video Game Adventure does this:

Code: Select all

INC $FFFF ; where $FFFF = $FF
You might think it would read $FF, then write $00

But it actually has a dummy write, so it will read $FF, write $FF, then write $00 (this impacts an MMC1 register)

Ironsword does this:

Code: Select all

STA $4000,X  ; where X = $15
which READS $4015 (acknowledging the frame IRQ) before writing to $4015. Failure to do the dummy read may be why this game was so often broken in emulators.


Read this doc for outlines on what reads/writes are performed when and where (there's charts at the bottom)

http://nesdev.com/6502_cpu.txt (edit2: specifically, read the "6510 Instruction Timing" section. Ctrl+F the file to get to it)


EDIT: doh, I'm too slow.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Dwedit wrote:LDA $1234,X will fetch both $1234 and $1234+X I think.
It actually fetches three bytes of the instruction, then $1200 + <($34+X) (with the bytes added without carry), then $1234+X if it differs.
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza »

tepples wrote:
Dwedit wrote:LDA $1234,X will fetch both $1234 and $1234+X I think.
It actually fetches three bytes of the instruction, then $1200 + <($34+X) (with the bytes added without carry), then $1234+X if it differs.
Tepples, what was the <() notation? I think I knew it but I forgot. Is it a bitshift?

Disch: thanks for the link!
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Post by thefox »

Petruza wrote:
tepples wrote:
Dwedit wrote:LDA $1234,X will fetch both $1234 and $1234+X I think.
It actually fetches three bytes of the instruction, then $1200 + <($34+X) (with the bytes added without carry), then $1234+X if it differs.
Tepples, what was the <() notation? I think I knew it but I forgot. Is it a bitshift?
Low byte. E.g. <$6789 is $89 whereas >$6789 is $67.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza »

tepples wrote:
Dwedit wrote:LDA $1234,X will fetch both $1234 and $1234+X I think.
It actually fetches three bytes of the instruction, then $1200 + <($34+X) (with the bytes added without carry), then $1234+X if it differs.
Oh, so this is what happens always on absolute indexed addressing? the indexing occurs first on the low byte only?

Damn, my cpu interpreter will take longer than I thought.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Petruza wrote:
tepples wrote:
Dwedit wrote:LDA $1234,X will fetch both $1234 and $1234+X I think.
It actually fetches three bytes of the instruction, then $1200 + <($34+X) (with the bytes added without carry), then $1234+X if it differs.
Oh, so this is what happens always on absolute indexed addressing? the indexing occurs first on the low byte only?
Yes. The 6502 has one 8-bit ALU and one 16-bit upcounter (for PC). To calculate a,x or a,y absolute indexed addressing in an instruction other than sta, stx, or sty, it uses the 8-bit ALU to first calculate the low byte while it fetches the high byte. If there's a carry out, it goes "oops", applies the carry using the ALU, and repeats the read at the correct address. Store instructions always have this "oops" cycle: the CPU first reads from the partially added address and then writes to the correct address. The same thing happens on (d),y indirect addressing.

As for (d,x) indirect addressing, I don't know how many cycles that takes. As a programmer, I've never had a chance to use it in a loop. The only time I've ever used a table of addresses on zero page was in a music engine, where x had the possibility of being 0, 4, 8, or 12.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Atari 2600 games love zeropage indexed addressing mode.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

All ($xx,X) instructions takes 6 cycles according to this. : http://www.6502.org/tutorials/6502opcodes.html
However this page contains at least 1 error : and $xx is 3 cycles and not 2.

For the 6 cycles it should be like that :
1) Read opcode
2) Read argument
3) Read $xx+X
4) Read $xx+X+1
5) Read [$xx+X]

So there is one more dummy read in the process too.
As for (d,x) indirect addressing, I don't know how many cycles that takes. As a programmer, I've never had a chance to use it in a loop. The only time I've ever used a table of addresses on zero page was in a music engine, where x had the possibility of being 0, 4, 8, or 12.
It's fun, because I also only used the lda ($xx,X) instruction only one time for my music engine. Sounds like it's a common way to do it.

Also maybe I used this instruction with X = 00 in all cases, if Y was busy with something else, I'm not sure exactly, but it doesn't really count.
Useless, lumbering half-wits don't scare us.
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Close @ the reads. It is 6 cycles like you said, but you only listed 5 of them.

The doc I linked to before lays it out: http://nesdev.com/6502_cpu.txt


1) Read PC (opcode)
2) Read PC+1 (argument)
3) Read $xx (dummy read, gives time to add X to $xx)
4) Read $xx+X (low byte)
5) Read $xx+X+1 (high byte)
6) Read ($xx+X) (final data)
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

There are some dummy read test ROMs available.
Post Reply