Whoa! I didn't expect such quick and numerous replies on a forum about vintage computers! You guys are much better than the rulebook nazis from Stack Overflow
True, maybe it isn't. But it's definitely a Good Thing To Have™. Therefore my usual approach is to try having it from the start, and only loosen this requirement where I need, or where keeping it would be too troublesome/inefficient. It's one of the requirements if you want your procedure to be a "black box", not affecting the user with some weird side effects.
Well, if the values in registers have to be retained, they surely must be stored somewhere, obviously :q
Yup, I know, that's what I was asking about in the last line of my original post. I know that there is such a technique, since I use it sometimes on x86, I just don't have much prior experience in how exactly do the same thing on 6502 where the register manipulation seems to be somewhat limited.
I suppose that I have to push A and X first, right? Because otherwise, TXS would damage at least X, and I can't push X directly, it has to go through A first.
So my guess is that I should start by first pushing the registers (first A, then X and Y through it), and only then I can copy S to X to manipulate it and peek through the stack with it to get the original values of the registers back?
Hmm... When I already have a copy of the original S in X for restoring it later, can I then use PLA for reloading the registers instead of LDA/LDX/LDY? (PLA would do that with one-byte instruction instead of three-byte). I mean, is it safe to do that? Because, since it moves the original S down the stack, I suspect there might be a risk of some interrupt overwriting the values above the stack pointer, am I right? If that's the case, I suppose it would be better to leave S where it is, and only peek the values below it through address arithmetics?
BINGO! That seems to be the thing I was looking for ? Directly addressing the data on the stack with respect to the original stack pointer (because I suppose it's better to leave it where it is, if interrupts might interfere).
Thank you for mentioning that. Definitely something worth keeping in mind.
Not a problem, as long as the previous value of X the user has passed is already sleeping nice & tight on the stack where I can reach it anytime with @drac030's technique
Why do you save A both in memory and on the stack?
Hahah so they realized their fault eventually and fixed it? :J This way it saves not only the registers, but also a lot of headache (and instruction bytes).
Well, one of the reasons might be that when a subroutine can mess up the values in X and Y, it cannot be used inside of a loop that already uses X and Y for the loop counters You then have to remember to save these registers yourself before every subroutine call and restore them later, and moreover, you have to repeat the saving/restoring code in every place of a call If you save/restore them inside the subroutine instead, the save/restore code is localized inside that subroutine and doesn't have to be repeated all over the program. With the "caller saves" approach, the caller cannot assume that the subroutine won't mess the registers, so the caller has to always save them before the call and restore afterwards if he wants to keep their values, even if the subroutine actually doesn't mess up those registers. In that case, all that work is wasted. On the other hand, if it's the job of the subroutine to save the registers it actually uses, it can avoid that overhead if it doesn't mess with the registers (and the subroutine knows best which registers it needs to mess with, so it should be its responsibility to save their values in that case).
Not to mention that there is a conceptual benefit from treating a subroutine as a "black box", so that the caller didn't have to know what does it do with the resisters inside, or produce any weird side effects.
Wow, threading on a machine with no hardware support for it? That's definitely something interesting that I'd like to try one day