Page 1 of 1

Calling Convention

Posted: Thu Mar 10, 2016 7:53 pm
by ashterix
6502/816 is still something new to me so I'm still figuring out how to organise my code best. For subroutines I've been doing this strange form of calling convention, if you can call it that, where I use the first sixteen bytes of RAM for arguments and return data by using a pointer in X. I don't really like this much, and it makes recursion basically impossible. Is there a better way to do this? For NES and SNES programming, how do you prefer to do your function calling conventions?

Re: Calling Convention

Posted: Thu Mar 10, 2016 8:05 pm
by rainwarrior
You can store anything you need for recursion using the stack (see: PHA/PLA/TXS/TSX). Use TSX and you can use indexed loads/stores to access your function-local stuff.

I rarely need recursion, though. Usually I just specify the use of ZP temporaries and registers in the function documentation (i.e. where is the return value, which are paramters, which get clobbered, etc.) and where functions call eachother I try not to overlap. In the cases where I can't avoid overlap (e.g. later code changes), I use the stack as an escape route.

Re: Calling Convention

Posted: Thu Mar 10, 2016 8:08 pm
by tepples
ashterix wrote:For subroutines I've been doing this strange form of calling convention, if you can call it that, where I use the first sixteen bytes of RAM for arguments
As do I, incidentally. Because subroutines call other subroutines, I document which bytes in $0000-$000F are overwritten by any particular subroutine.
and return data by using a pointer in X.
Could you give an example?
I don't really like this much, and it makes recursion basically impossible.
What recursion are you trying to accomplish in 27,000 cycles? The only thing I can anticipate needing recursion for would be a flood fill in a game like Rampart or Bombliss or Magical Drop or Bust-A-Move or Puzzle League, and that can be done as easily with a circular buffer of next things to check.

Re: Calling Convention

Posted: Sat Mar 12, 2016 12:10 am
by zzo38
It may be useful to use different calling conventions for different subroutines (if you are programming in pure assembly language rather than in C). What memory locations, registers, and/or flags affect and are affected by the subroutine can vary by each one. And in some cases you can use macros instead of subroutine calls. You could also see if something you are doing that is using recursion, does not necessarily need it; if it does you could use a different calling convention in such a case.

Re: Calling Convention

Posted: Sat Dec 17, 2016 7:13 pm
by Garth
In my 6502 stacks treatise, chapter 14 is on local variables and environments at http://wilsonminesco.com/stacks/loc_vars.html, and, following naturally, is chapter 15 on recursion at http://wilsonminesco.com/stacks/recurse.html . You can do it!

Re: Calling Convention

Posted: Fri Jan 06, 2017 11:01 am
by JRoatch
I have been trying out many different ways to implement the data stack idea since my canceled game in 2014. I believe I now have a parameter convention that works for my entire code base and fixes the many gripes I had about wasting space and cycles on load and store instructions.

The Y register for the first low byte; the A register for the second high byte which can be ignored for subroutines that don't need it; and the X register for the pointer to the data stack of 16-bit numbers in little endian order. Y and A together form the 16-bit number for the top of stack. 32-bit numbers are also entirely little endian where the high word gets pushed first contrary to the convention of 6502 forth.

Using the Y register as the low byte was counter intuitive for me, but works better for data addressing using (Indirect),Y for Incrementing TOS, and for pushing an address to the return stack, and other things. Representing all numbers as little endian in memory helps reduce the size of 32-bit addition and subtraction subroutines, and removes the need to use swap for UM/MOD.