Strategy for managing register values

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

User avatar
Posts: 4214
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Strategy for managing register values

Post by koitsu » Sun Oct 14, 2018 7:28 pm

Myask wrote:Well, yes, phy/ply/phx/plx are 65c02 on up…
Gack, sorry, another case of my whole 65c02 -> 6502 -> 65816 transition throughout my years. I swear, once you get used to the additional opcodes, you kinda forget which ones are limited to which architecture. (Eyes/Lichty's 65816 book has a wonderful chart outlining which are available on each of the 3 architectures)

Cycle and byte wise, here's the breakdown of methodologies (assuming 8-bit mode on 65816):

pha/phx/phy = 65c02 and 65816 only (i.e. not NES). Cycles: 9 total (3+3+3). Bytes: 3 total (1+1+1)
ply/plx/pla = 65c02 and 65816 only (i.e. not NES). Cycles: 12 total (4+4+4). Bytes: 3 total (1+1+1)

pha/txa/pha/tya/pha = all archs. Cycles: 13 total (3+2+3+2+3). Bytes: 5 total (1+1+1+1+1)
pla/tay/pla/tax/pla = all archs. Cycles: 16 total (4+2+4+2+4). Bytes: 5 total (1+1+1+1+1)

sta zp/stx zp/sty zp = all archs. Cycles: 9 total (3+3+3). Bytes: 6 total (2+2+2), plus 3 bytes of ZP usage
ldy zp/ldx zp/lda zp = all archs. Cycles: 9 total (3+3+3). Bytes: 6 total (2+2+2), plus 3 bytes of ZP usage

The latter methodology is certainly the most efficient on 6502. If you switch zp for someplace else in RAM, the cycle and byte counts increase, so using ZP is best.

And don't forget php/plp if you care about flags -- all archs, 7 cycles (3+4), 2 bytes (1+1).

User avatar
Posts: 7642
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada

Re: Strategy for managing register values

Post by rainwarrior » Sun Oct 14, 2018 7:43 pm

koitsu wrote:The latter methodology is certainly the most efficient on 6502. If you switch zp for someplace else in RAM, the cycle and byte counts increase, so using ZP is best.
If the problem you're trying to solve with using the stack is side effects on your temporaries, ZP is worst, though. That's just more temporaries to manage. (Obviously: can't use the same ZP variables in each function.)

It's the fastest way to save and restore them, but requires exclusive access for the duration of that subroutine.

Posts: 769
Joined: Tue Feb 07, 2017 2:03 am

Re: Strategy for managing register values

Post by Oziphantom » Sun Oct 14, 2018 9:03 pm

Some things missing from the other answers.

Step1. Don't use Macros. From your other posts here I'm assuming you are very new to 6502. In the "One must crawl before they can walk", macros are "Running with scissors". I call them Mermaids, you need to be able to look at a macro and see through it, be able to write the code that it writes for you. I know they are lovely and make the code faster and neater and oh so handy... they will eat you alive! Every time you use a Macro you must give it a long hard stare and say "will this bite me", and the way you learn this is by writing the code behind them each time again and again and again and again and again.. then in say 1.5 years from now you will be able to start using them, because by then you will have written all the code pieces so many times, you will be able to do it by rote and when you slap down a nice macro you will be able to read the code in the macro as you scan your code. However even then you will still made the odd stupid mistake with them..

Code: Select all

.macro somemacro
  .local @endofmacro:
  .local @macrovar1
  .local @macrovar2

  ; code in here doesn't really matter
  sta @macrovar1
  lda some_global
  adc #28
  sta some_global
  lda @macrovar1

  ; end of main macro code

  jmp @endofmacro
  ; start of macro local variables
  @macrovar1: .byte #$00
  @macrovar2: .byte #$00

Macros are not standard, each assembler does it in its own way. So this may make a unique instance of each macrovar per use of the macro. Which may or may not eat RAM like no tomorrow and force you in to a massive rework at some point, even on a C64 where you have an insane 64K of contiguous RAM. You may also use it so much that the assembler runs out of the 2K on the NES and enters into mapping them in the RAM Mirror trashing other memory locations ;)
Your assembler may only make one instance of the vars due to how it instances and sorts it macro code so all instances of the macro only use 1 set. Sounds great, what could possibly go wrong...

Code: Select all

..normal code
..more normal code

..ISR code
...more ISR code
Can we spot the horrible bug waiting to happen??? What if the interrupt just so happens to fire during somewhere in the middle of #myMacro, then the #myMacro in the ISR happens, TRASHES some var inside the macro and boy do you have a fun bug to trace...
They are mermaids, don't swim with them until you really really know what you are doing.

When I program on my C128 then using Macros really helps, as I can store them on a file in the disk and so they don't eat up my RAM, they make it slow to assemble but not slower than making 3 files to assemble at once. They also let me fit a LOT more code on my 25 line high screen. And Ctrl+C and Ctrl+V wasn't invented yet, although my editors do have copy and paste its clunky, I don't have a mouse and I don't have "search as I type" meaning, typing a Macro makes it so much easier for me. On a modern day pc with mouse, Ctrl+C, V and oh 1GB of RAM and Code folding. No need, that can assemble a whole 512K cart in 2 seconds, not a huge issue. My point is you don't need Macros yet, you can copy paste, use snippets and other modern tools to get the quality of life, without getting bitten.

However How do you stop functions from trashing things..

You can't welcome to Assembly.

Naming conventions may help as you form your "style", for example if you have a function that trashes x,y you may wish to name it such
myFunc_t123 ; trashes temp 1,2,3
Overtime however you will generate a coding style and you will learn to stick to it, where you will form your own conventions and this will mostly be shaped buy how many times and by what you get bitten by.

User avatar
Posts: 536
Joined: Thu Mar 31, 2016 11:15 am

Re: Strategy for managing register values

Post by pubby » Sun Oct 14, 2018 9:50 pm

I don't really agree. Macros are about as complex as subroutines, and have the same pitfalls when it comes to clobbering. It's silly to disdain one and not the other.

Posts: 769
Joined: Tue Feb 07, 2017 2:03 am

Re: Strategy for managing register values

Post by Oziphantom » Sun Oct 14, 2018 10:50 pm

Functions are usually large, and encapsulate an entire thing. So yes they clobber and do things, but you are not usually relying upon the opcode before and above to be preserved in some way. Macros are very atomic in nature and are inlined in code, where trashing something is critical to the flow of the code they are within. While functions you do have "special case" where so say all entity update functions must keep EntNum in X, but the majority of functions don't have special rules. You would also have a lot less function instances than macros in a code base.

Posts: 148
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California

Re: Strategy for managing register values

Post by Garth » Mon Oct 15, 2018 1:39 am

I've never had the problem mentioned in the head post, knock on wood. In fact, for me, macros have prevented loads of bugs and saved me a lot of time. I sense that in many cases others make very poor use of macros though. I'd have to see a lot of examples in order to identify a pattern of what's happening, and then I'd like to put something helpful about it on my website to get people "over the hump"—whatever that "hump" proves to be.

In good usage, macros will usually (but not always of course) have parameters. A nice side effect of the parameters is that it's extra clear what variables (or sometimes even what processor registers) the macro might affect. Regarding the hypothetical situation given where some macro code is interrupted and the ISR uses the same macro, that shouldn't be any problem as long as you keep in mind what interrupts are and how to service them without messing up the background program. It's the same care taken with or without macros. I was just looking at a big work project from four years ago, where I had 28 macro invocations in a very complex ISR. (These were largely conditional, so only a small portion of the ISR got executed any given time, and the conditions dictated which portions.) I never had any trouble with it. The same macros were used all over the background code too.

If the assembled code will go into RAM, then rather than doing the variables local to the macro, how about using self-modifying code instead, where the variable is the actual operand of an instruction. Then your lda @macrovar1 for example becomes LDA #__. The assembler will need an operand, so just make it 0 (or whatever you like), but the STA above it will store useful variable data to the LDA#'s operand address. (Did you ever think there's be a practical use for STA#__? :lol:) The prospect of self-modifying code's debugging can scare some people; but once the macro is debugged (which shouldn't be hard), it will work every time, and you don't have to keep looking at the ugly internal details.

I have used variable pseudonyms a few times to reduce confusion in situations where the different bytes of a scratch variable needed more-descriptive names for a particular routine (like for a 32-bit divide routine), but diagrammed it at the beginning of the routine, in the comments, so there's no risk of it going unnoticed. If you really do need to save something, there are ways to do it with stacks. (Yes, stacks, plural. You're not limited to the page-1 hardware stack). Or, instead of saving it, operate on a local variable that is essentially inaccessible to other parts of the program. You can even make it recursive. Section 14 of my 6502 stacks treatise is on local environments and variables. Section 15 is on recursion. (And there's no reason you can't do this in macros too.) lots of 6502 resources

Post Reply