Is the A register for return values?
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
- jeffythedragonslayer
- Posts: 344
- Joined: Thu Dec 09, 2021 12:29 pm
Is the A register for return values?
Is it a bad idea to use the A register for .proc return values? Does it make sense for me to use the 65816 A register like the x86 eax register?
Re: Is the A register for return values?
I think it's safe as long as you add comments somewhere that explains "A register holds the return value"
You should come up with one standard way of handling this sort of thing and use it consistently, so there are no surprises.
You should come up with one standard way of handling this sort of thing and use it consistently, so there are no surprises.
nesdoug.com -- blog/tutorial on programming for the NES
- rainwarrior
- Posts: 8735
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Is the A register for return values?
A is the most common place for a return value, but in assembly you can use whatever is appropriate. It does not have to be consistent, as long as you can keep track of the usage.
For instance, if you know the value will be used as an index by the caller, return in X might be better.
The carry flag can be quite useful as a boolean return value (via sec/clc).
You could return in multiple registers or flags, you could use memory storage as well. A is just the most common "default".
C compilers have "calling conventions" where they tend to put return values in very specific places, but this is so the compiler can treat functions more generically. Writing in assembly directly we don't have the same requirements.
For instance, if you know the value will be used as an index by the caller, return in X might be better.
The carry flag can be quite useful as a boolean return value (via sec/clc).
You could return in multiple registers or flags, you could use memory storage as well. A is just the most common "default".
C compilers have "calling conventions" where they tend to put return values in very specific places, but this is so the compiler can treat functions more generically. Writing in assembly directly we don't have the same requirements.
- jeffythedragonslayer
- Posts: 344
- Joined: Thu Dec 09, 2021 12:29 pm
Re: Is the A register for return values?
Thanks; I haven't really come up with my own style yet but I'm sure I'll figure it out.
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: Is the A register for return values?
locking yourself to a style will only cause you lots of pain, and give you poor code. In Assembly you don't make a bunch of functions to get this or that, you write code to do what you do and then pull any common code you find into a "sub routine".
-
- Posts: 611
- Joined: Mon Jan 23, 2006 7:47 am
- Location: Germany
- Contact:
Re: Is the A register for return values?
Also a good tip for high-level languages.
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Re: Is the A register for return values?
Sure. Let's do the opposite of what I said. Consistency is for losers. /sOziphantom wrote: ↑Tue May 24, 2022 11:38 pm locking yourself to a style will only cause you lots of pain, and give you poor code. In Assembly you don't make a bunch of functions to get this or that, you write code to do what you do and then pull any common code you find into a "sub routine".
You can write functions however you want, but if you should at least write comments on each function about how arguments are passed back and forth. When you come back to the function a year later, it should be obvious the the return boolean is in the carry flag. Comments like "this function clobbers the A and X registers and returns A(16bit)=map address in VRAM"
nesdoug.com -- blog/tutorial on programming for the NES
Re: Is the A register for return values?
Here's an example of my comments for resizing an ArrayList.
Very easy to read. However, the X register returns untouched which I should probably mention in the comment. The "List" refers to the struct defining the array's size and location.
I have my own conventions but everything isn't too strict. If either A, X or Y are not mentioned as Entry, they're assumed free. However, for DB and DP, I assume they're going to be untouched on Return unless specified. I never return with different mx flags.
IMO, only using A for return is fine but I need my extra cycles in a lot of places.
This is the style I lock myself in.
Code: Select all
; Entry: X = List Pointer, Y = New size
; Return: X = List Pointer
I have my own conventions but everything isn't too strict. If either A, X or Y are not mentioned as Entry, they're assumed free. However, for DB and DP, I assume they're going to be untouched on Return unless specified. I never return with different mx flags.
IMO, only using A for return is fine but I need my extra cycles in a lot of places.
This is the style I lock myself in.
Re: Is the A register for return values?
No. It's not a bad idea. Returning values by registers has always been a thing. And like others have said, status flags can also be used. You can also use "pseudo regs" for return values. Since the processor is an accumulator based model, you can define DP or memory areas as pseudo regs (usually because they are access as address vectors), and use those for calling/return conventions (rather than a stack). It's really up to you and what makes sense for you. Returning by register is usually done for speed reasons, but sometimes it's not always the fastest method.jeffythedragonslayer wrote: ↑Fri May 20, 2022 1:24 pm Is it a bad idea to use the A register for .proc return values? Does it make sense for me to use the 65816 A register like the x86 eax register?
If it's your code, and only you work with it - then it really doesn't make a huge difference. You can mix and match. Though you should always have a block comment at the top of the function.. for your future self haha. If you're just trying to follow "good practice" or whatever, well then you're going to get a million and one opinions on that hahah.
Now, if you're writing a library for others to use, or writing ASM libs/code for use with a compiler.. then standardizing conventions matters.
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: Is the A register for return values?
When you only have 3~4 registers, yeah it's going to cause pain, as you will want to return things in A because that is your standard but then you really need the value in Y, and it could use X to leave A untouched so now you have todougeff wrote: ↑Wed May 25, 2022 6:19 amSure. Let's do the opposite of what I said. Consistency is for losers. /sOziphantom wrote: ↑Tue May 24, 2022 11:38 pm locking yourself to a style will only cause you lots of pain, and give you poor code. In Assembly you don't make a bunch of functions to get this or that, you write code to do what you do and then pull any common code you find into a "sub routine".
You can write functions however you want, but if you should at least write comments on each function about how arguments are passed back and forth. When you come back to the function a year later, it should be obvious the the return boolean is in the carry flag. Comments like "this function clobbers the A and X registers and returns A(16bit)=map address in VRAM"
Code: Select all
rep #$20
pha ; in case it trashes B as well
set up AXY size for the function
jsr myFunc
; make sure Y is the size you want it to be
tay
; make sure A is still 16bits
pla
; restore A to what you want
.. carry on with your code here
Code: Select all
jsr readPad
jsr updatePlayer
jsr updateEnemies
jsr doCollision
jsr updateHUD
jsr updateMusic
jmp waitVBlank
As for comments yes, each sub routine should be documented, I especially find "how I expect this to be used" to be very useful to me, as time goes on. A small working example has saved me a lot of trouble.
I have this format on a macro key, but here is an actual example.
Code: Select all
.comment DOC
### writeVDCRegP
This writes a 16 bit pointer to a register pair on the VDC
~~~~ {.Asm6502}
lda #<Value
ldy #>Value
ldx #LowerRegister
jsr writeVDCRegP
~~~~
Use the helper Macro _WRITE_POINTER_VDC_ to write from an address
~~~
#WRITE_POINTER_VDC Register Lo Hi
eg
#WRITE_POINTER_VDC #18 ZPPointer.lo ZPPointer.hi
~~~
_WRITE_16IMMEDIATE_VDC_ to write a immediate value
~~~
#WRITE_16IMMEDIATE_VDC Register 16BitValue
eg
#WRITE_16IMMEDIATE_VDC #18 $1f00
~~~
##### Param
------ -------------
__.A__ Lo Value
__.Y__ Hi Value
__.X__ Start Register
------ --------------
##### Returns
------ ------------------
__.A__ Preserved
__.Y__ Preserved
__.X__ Start Register + 1
------ ------------------
.endc
Here is how it looks in the "doc"
Re: Is the A register for return values?
Don't let people tell you that you can't decompose a task into subroutines just because you are writing assembly. Using subroutines to make a complex task easier to develop and read is just as valid in ASM as it is in C or Java. You are just more aware of the speed and space penalties when you are coding the bare metal.
It's a choice. Bloat the code a bit to make the development process easier, or write a single, 1000-line subroutine that's a nightmare to come back to a year later.
It's a choice. Bloat the code a bit to make the development process easier, or write a single, 1000-line subroutine that's a nightmare to come back to a year later.
-
- Posts: 611
- Joined: Mon Jan 23, 2006 7:47 am
- Location: Germany
- Contact:
Re: Is the A register for return values?
It depends on the problem. A 1000-line subroutine (which is easily achieved in e.g. a bytecode interpreter) with a clear structure can be made worse to understand by breaking it up into a rigid class hierarchy with several dozens of methods, all involving side effects.
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: Is the A register for return values?
if it needs 1000 lines then make the 1000s lines, get it working and then refactor the code into subroutines from the working code to make it easier and nicer to follow/reduce ROM size/extract parts that are useful for other things.