It is currently Mon Sep 16, 2019 7:50 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 19 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Mon Aug 12, 2019 6:31 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 97
Location: Finland
Oziphantom wrote:
SusiKette wrote:
Code:
ldx #$0110           ; Fixed point in stack
txs

that is a 16 bit load, not on a 6502 your not.. on a 65816, sure make as many stacks as you want around RAM for things. But then you also have ,s so...


Good point. I wrote those values with the absolute stack address in mind, not the stack pointer, and then forgot to change them before posting. They should be correct now.


Top
 Profile  
 
PostPosted: Tue Aug 13, 2019 3:29 pm 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 145
Location: Edmonton, Canada
I did try this approach, but eventually stripped it due for it being slow. I made a set of macroses to manage it. It will require you to use X to keep stack pointer, but when you need to use X, it gets messy. Anyway, below is the macro code and example for ca65, if you want to play with it.

There are 4 macroses:

1. stackalloc identifier, [size] - allocates size bytes on the stack
2. stackfree - deallocates all local variables
3. stackparam identifier - creates offsets for the parameters pushed on stack
4. stackcall identifier, param1, [param2...param6] - push up to 6 parameters on stack (in backwards order), call subroutine, clear up the stack after call.

Here is an example

Code:
.proc test
    stackalloc local1
    stackalloc local2
    stackparam param1
    stackparam param2
    tsx

    lda param1,x
    clc
    adc #5
    sta local1,x
    lda param2,x
    clc
    adc #5
    sta local2,x

    stackfree
    rts
.endproc

.proc main
    stackcall test, #1, #2
    jmp main


And lib code

Code:
.macro stackalloc ident, size
    .ifdef _stackParamPos
        .error "stackalloc must be called before stackparam"
    .endif
    .if .blank ({size})
        stackalloc {ident}, 1
        .exitmac
    .endif

    .ifdef _stackVarPos
        _stackVarPos .set _stackVarPos + size
        _stackVarCount .set _stackVarCount + size
    .else
        _stackVarPos .set $101
        _stackVarCount .set size
    .endif
    ident := _stackVarPos
    pha
.endmacro

.macro stackfree
    .ifndef _stackVarCount
        .error "stackalloc was not used"
    .endif
    .repeat _stackVarCount
        pla
    .endrepeat
.endmacro

.macro stackparam ident
    .ifdef _stackParamPos
        _stackParamPos .set (_stackParamPos) + 1
    .else
        .ifdef _stackVarPos
            _stackParamPos .set (_stackVarPos) + 3 ; to preserve return address
        .else
            _stackParamPos .set $103
        .endif
    .endif
    ident := _stackParamPos
.endmacro

.macro stackcall ident, p1, p2, p3, p4, p5, p6
    ; I don't know how to make .repeat with decreasing numbers
    .ifnblank p6
        lda p6
        pha
    .endif
    .ifnblank p5
        lda p5
        pha
    .endif
    .ifnblank p4
        lda p4
        pha
    .endif
    .ifnblank p3
        lda p3
        pha
    .endif
    .ifnblank p2
        lda p2
        pha
    .endif
    .ifnblank p1
        lda p1
        pha
    .endif
    jsr ident
    .ifnblank p6
        pla
    .endif
    .ifnblank p5
        pla
    .endif
    .ifnblank p4
        pla
    .endif
    .ifnblank p3
        pla
    .endif
    .ifnblank p2
        pla
    .endif
    .ifnblank p1
        pla
    .endif
.endmacro


Top
 Profile  
 
PostPosted: Wed Aug 14, 2019 11:31 am 
Offline
User avatar

Joined: Fri Nov 24, 2017 2:40 pm
Posts: 170
It was kind of touched on by some people, but even cc65 doesn't strictly use the standard C calling convention by default where everything needs to be pushed onto the stack. Normally it uses fastcall. The last argument is placed in the A register (or AX for 16 bit values), and return value is also passed by A. Extra arguments are pushed to the stack.

I like to write a mix of C and assembly, and basically use fastcall for all my assembly routines whether they are exposed to C or not. Most of those only take a single argument, and maybe half of the remainders pass arguments through global zero page variables. As a convention it works out nicely because I only need to document the calling convention for routines that don't use fastcall. Expect the last argument and the return value in A/X. Pass other values on the C stack, or document the globals they are expected in.

This isn't too different from amd64 ABIs today. The System V and MS ABIs both pass a half dozen arguments through registers, and a separate half dozen float arguments. Looking at my own code, it's pretty rare for arguments to spill onto the stack.


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 8:47 am 
Offline

Joined: Thu Apr 18, 2019 9:13 am
Posts: 161
slembcke wrote:
It was kind of touched on by some people, but even cc65 doesn't strictly use the standard C calling convention by default where everything needs to be pushed onto the stack. Normally it uses fastcall. The last argument is placed in the A register (or AX for 16 bit values), and return value is also passed by A. Extra arguments are pushed to the stack.


The compilers I've seen for compilers for platforms that would be even less capable of emulating a local-variable stack than the 6502 statically allocate local variables (automatic objects) based on a call graph; this requires that the compiler know all functions that may call others directly or indirectly, and disallows recursion. Functions can then simply use local variables for their parameters, with the slight caveat that if the calculation of more than one argument to a function call would require calling other functions, the results of all but one must be stored temporarily (either to compiler-temporary variables or the stack) and then copied to the appropriate arguments.

The linkers bundled with those compilers could automatically process the call graph information, but a tool to process such information into an ASM file for use with linkers that can't do that would be fairly simple. For every function, identify how many bytes of zero-page and non-zero-page RAM are used by the function plus the most demanding functions it calls. For leaf functions (those that don't call any other), this would simply be their own RAM usage. For each other function, find the maximum usage of functions that it calls and add its own RAM usage.

For many programs, using a small amount of zero-page for automatic variable storage could greatly improve performance compared with trying to use a (zp),y pseudo-stack.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page Previous  1, 2

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group