Is the A register for return values?

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
User avatar
jeffythedragonslayer
Posts: 344
Joined: Thu Dec 09, 2021 12:29 pm

Is the A register for return values?

Post by jeffythedragonslayer »

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?
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Is the A register for return values?

Post by dougeff »

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.
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: Is the A register for return values?

Post by rainwarrior »

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.
User avatar
jeffythedragonslayer
Posts: 344
Joined: Thu Dec 09, 2021 12:29 pm

Re: Is the A register for return values?

Post by jeffythedragonslayer »

Thanks; I haven't really come up with my own style yet but I'm sure I'll figure it out.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Is the A register for return values?

Post by Oziphantom »

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".
creaothceann
Posts: 611
Joined: Mon Jan 23, 2006 7:47 am
Location: Germany
Contact:

Re: Is the A register for return values?

Post by creaothceann »

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
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Is the A register for return values?

Post by dougeff »

Oziphantom 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".
Sure. Let's do the opposite of what I said. Consistency is for losers. /s

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
Myself086
Posts: 158
Joined: Sat Nov 10, 2018 2:49 pm

Re: Is the A register for return values?

Post by Myself086 »

Here's an example of my comments for resizing an ArrayList.

Code: Select all

	; Entry: X = List Pointer, Y = New size
	; Return: X = List Pointer
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.
turboxray
Posts: 348
Joined: Thu Oct 31, 2019 12:56 am

Re: Is the A register for return values?

Post by turboxray »

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?
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.

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.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Is the A register for return values?

Post by Oziphantom »

dougeff wrote: Wed May 25, 2022 6:19 am
Oziphantom 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".
Sure. Let's do the opposite of what I said. Consistency is for losers. /s

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"
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 to

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
while in this case the routine could just use X and Y and return in Y avoid all the pain. Multiply this pain by every function and yeah. If you have a standard but then you start to bend it here and their to avoid the pain, you are now making it worse for yourself as you expect "P" but randomly get "Q" sometimes adding to your misery. Sticking to a standard will not really work for you and you should build the code inline and then pull it out into sub routines as you go along. I.e make it work, even if you copy paste a bit, as you think it might be shared, you don't know yet. Then once working evaluate what you have and decide what should be pulled out in to a subroutine, or what other routines you need to write of a similar nature will require now that you have the experience of getting this one to work. Will probably keep a junior programmer in better stead. I feel that in 6502/65816 and most other assemblies subroutine is more of an optimization step, just a readability one and you shouldn't do it prematurely. The high level functions are fine as your structure as they tend to have no parameters. i.e.

Code: Select all

jsr readPad
jsr updatePlayer
jsr updateEnemies
jsr doCollision
jsr updateHUD
jsr updateMusic
jmp waitVBlank
The code should do what it needs to do, how it is needed to be done, rather than "things must be returned in A and passed in via X", if that works for the sub routine, great, if it doesn't, then don't do it.

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
I then have a program that goes through the source code looking for .comment DOC which it then extracts them all throws it through pandoc with an IBM DOS manual style formatting to make a HTML page with the docs, so I don't have to keep scrolling through a large pile of code and files every time I need to call some routine I have made 6 months ago.
Here is how it looks in the "doc"
docExample.png
User avatar
qbradq
Posts: 972
Joined: Wed Oct 15, 2008 11:50 am

Re: Is the A register for return values?

Post by qbradq »

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.
turboxray
Posts: 348
Joined: Thu Oct 31, 2019 12:56 am

Re: Is the A register for return values?

Post by turboxray »

qbradq wrote: Thu May 26, 2022 10:26 am 1000-line subroutine
Gross. Hahaha. I seriously cringe when I come across code like this (in ANY language), especially if I have been tasked with maintaining/updating/fixing it (which I have recently).
creaothceann
Posts: 611
Joined: Mon Jan 23, 2006 7:47 am
Location: Germany
Contact:

Re: Is the A register for return values?

Post by creaothceann »

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
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: Is the A register for return values?

Post by 93143 »

qbradq wrote: Thu May 26, 2022 10:26 amIt'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.
Macros?
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Is the A register for return values?

Post by Oziphantom »

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.
Post Reply