What instructions can affect registers?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

What instructions can affect registers?

Post by SusiKette »

While it is common to use instructions like STA, STX and STY to modify registers, are there other instructions that can affect them? For instance, does DEC and INC have any effect on registers and do they behave as expected?
Avatar is pixel art of Noah Prime from Astral Chain
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: What instructions can affect registers?

Post by lidnariq »

Memory-mapped registers (to distinguish from CPU registers) could be modified by some Read-Modify-Write instruction like INC or LSR, but it's rare that there's already a useful value at that address to be loaded by the CPU and then written to the register.

The only wide-spread exception that I know of is with mapper registers (instead of 2A03/2C02 registers), where several games tickle the MMC1's reset functionality with a INC $FFFF.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What instructions can affect registers?

Post by koitsu »

Are you talking about MMIO registers (ex. $2002) or CPU registers (ex. A/X/Y)?

If the latter: sta/stx/sty don't modify CPU registers.

If the former: any opcode that does a write operation to an absolute address, directly or indirectly, can affect an MMIO register. A proper opcode list should contain a list of all of its addressing modes. Thusly, as an example, inc/dec can indeed be used to write to an MMIO register.

HOWEVER, it's very important you understand how these opcodes work under the hood (at the silicon/transistor level), on a per-cycle level. These are often called T-states (timing states). A good reference is here, though it contains some instructions for the 6510 CPU and I think some unofficial opcodes (blah, screw those). Scroll down to around line 891 for what I'm talking about.

inc/dec are what's called RMW instructions ("read-modify-write"), which means they behave in a way that is not immediately intuitive: they actually read from the destination address first, followed by writing the value read back to the same address (yes really!), followed by writing the new value desired to the address.

Why this is important: the read operation can cause oddities depending on if the MMIO register does something uniquely on a read, and the same goes for the fact that the MMIO register is written to twice. If there's a latch that increments or triggers based on read or write operation, you may find that the end result you desire is not quite what you get.

Here's an example: inc $2000. The CPU would issue a read from $2000 (it's a write-only register so I'm not sure what value you'd get back here, maybe open bus? Others can verify), followed by writing the value it got to $2000, followed by writing the incremented value to $2000.

An even scarier example would be inc $2007.

The rule of thumb is: if you aren't completely sure what the behaviour of the MMIO register is, don't use RMW instructions on them, stick with instructions which issue a single write and do not involve a read or issue two writes.
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: What instructions can affect registers?

Post by SusiKette »

yaros wrote:...affect A (DEC A,...
Wait. DEC has Accumulator addressing mode? All references I looked at only listed Zero Page, Absolute and their X variants
Avatar is pixel art of Noah Prime from Astral Chain
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: What instructions can affect registers?

Post by lidnariq »

(No. DEC A is only present in later variations of the 6502, not the one inside the NES)
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: What instructions can affect registers?

Post by rainwarrior »

I believe reading from $2000 I think will read back from the PPU read buffer thing, so it depends on what the last values on that bus was before you use the instruction. (Basically: it's complicated and there's no reason to try and rely on this.)

Something you should avoid, though, is that using indexed / indirect / RMW instructions may do an extra read or write. On many MMIO registers it doesn't matter if you write the same value twice, for example, but if you try to STA (zp), Y to $2007 you'll end up skipping every second byte with an extra read in the instruction.

There's a cycle by cycle breakdown of instructions by addressing type here: http://nesdev.com/6502_cpu.txt

Summary:

Just use plain STA, STX, STY for most cases. STA abs, X is okay for APU (@ $4000), and might be okay for some mapper registers, if you're careful, but that question is already becoming complicated. Anything beyond this is advanced, and/or unreliable.

If you want to figure out the advanced stuff, refer to that document I linked above to see what an instruction does in terms of reads and writes. For RMW instructions like INC, ROR, etc. the value read is important, and that in itself can be complicated to determine for some things (e.g. PPU @ $2000), or other open bus behaviour. As always, mapper registers are a case by case basis, and you will need to look up the specific mapper you're using to see where they're mirrored and how they respond to individual reads and writes.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: What instructions can affect registers?

Post by rainwarrior »

MOS Technology is the one who should be sorry about that. ;)
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: What instructions can affect registers?

Post by dougeff »

Not to go on a tangent, but aren't there some games that set / trigger mapper specific addresses with inc/dec or rol/ror?

And I mean normally ROM addresses where it wouldn't normally make sense.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: What instructions can affect registers?

Post by rainwarrior »

dougeff wrote:Not to go on a tangent, but aren't there some games that set / trigger mapper specific addresses with inc/dec or rol/ror?
Lidnariq covered the only example I know of:
lidnariq wrote:The only wide-spread exception that I know of is with mapper registers (instead of 2A03/2C02 registers), where several games tickle the MMC1's reset functionality with a INC $FFFF.
This occurs in Bill & Ted's Excellent Adventure. There's a note about it on the wiki.

In this case it uses INC on a ROM location that holds an $FF to send that $FF to the MMC1's register to reset it. It's weird, but I guess it's smaller than LDA imm / STA abs, though not actually any faster than that. Note that the final write of the INC is actually a $00, but this instruction does an extra write of $FF before it gets incremented... and this should screw things up but apparently the MMC1 can't receive writes that fast and ignores the real (second) write, so it only gets the $FF. This is really annoying to emulate properly, and a lot of emulators will fail that game.

So... it's a dumb trick for saving 2 bytes of a 5 byte reset operation.

In cases where you need to write a constant to an MMIO that's mirrored across some range of ROM, you could INC on a ROM byte that's one less than what you need, and it will send two writes to that address (the value, then the incremented value). Again saving 2 bytes out of 5 for that operation, but with an extra write. On some mappers it'd probably be less stupid than relying on the MMC1 to ignore the second write. :P This critically depends on how the chosen mapper handles two writes in a row.


Don't know which games do this, though there are probably some. The MMC1 case is more noteworthy because it requires extra mapper emulation to compensate for the ignored write.

All the RMW instructions do a double write like this (INC, ROR, etc.), again check that document I linked above if you want reference for it. In this case look for the "Absolute addressing" section and see its Read-Modify-Write subsection.
Post Reply