One thing we haven't really discussed yet is how to call functions and pass parameters, and what registers / cog memory locations have special uses. This kind of thing is called an Application Binary Interface (ABI) and is usually standardized for a processor so that different languages can interoperate.
The first thing we should probably nail down is what register/location is used for the stack pointer, what direction the stack grows in, and what alignment is required for the stack. For example, an obvious proposal is: PTRB is the stack pointer, it grows up (push increments the stack pointer, pop decrements it), and should always be long aligned. The choices are somewhat arbitrary, but if we don't have a standard languages won't be able to call each other. C compilers typically specify that the stack grows down (from high addresses towards low) and the malloc heap grows up (from low towards high) but it's not required, and we can change this to match whatever Spin does.
I suspect that for efficiency we will need to have two standard forms of functions -- bytecode (stack based) and compiled (cog memory based). Fastspin already does this, calling them "stackcall" and "fastcall". Pushing parameters onto the stack makes things easier for interpreters, but it's not very efficient. Consider a function to add two variables:
PUB sum(a, b)
If we compile this to PASM with a stack based calling convention we get something like:
rdlong x0, --ptrb ' pop b
rdlong x1, --ptrb ' pop a
add x0, x1
wrlong x0, ptrb++ ' push sum
With a register based convention we get:
mov result1, arg1
add result1, arg2
where "result1", "arg1", and "arg2" are some predefined COG memory locations.
Fastspin uses fastcall (the register based convention) by default, but if it sees that a function does something tricky like taking the address of a parameter it switches over to stackcall so that the stack layout will match Spin's. Of course this is for Spin1 compatibility, so we can change it for Spin2.