Search code examples
assemblystack8051

Adjust stack pointer for pushing arguements for functions


Normally when I write assembly for a 8051 chip. I use the registers R0-R7 for arguement before I call functions.

mov r6, #6
mov r7, #2
lcall setpos

I was interested in doing this with using the stack (ignoring the fact that this may be less efficient). Searching on the internet I found an awnser in this link

I was missing something in the answer. In the answer he does the following

push #0
push #5
call function
pop  r7 ; return value -> r7
...
function:
   pop r7
   pop r6 ; store return address
   pop b ; 5 -> b
   pop a ; 0 -> a
   add a, b
   push a  ; store result in a and push it
   push r6
   push r7
   ret

I thought that every register was modify-able including the stack pointer so it is possible to do

push #4
push #8
call function
pop r7 ; result -> r7
...
function:
    dec SP ; leave return address untouched
    dec SP
    pop r4 ; 8 -> A
    pop r5 ; 4 -> B
    add A, B
    inc SP
    push A; push result
    ret

instead? And am I doing it correctly?


Solution

  • Your idea is not that bad since it does not need registers to buffer the return address, uses less clock cycles, and uses less code space.

    There is only one issue to be aware of: Because the return address keeps its place in the stack also all space for the arguments is in use. At the calling site you have to POP <any> or DEC SP the same amount as was pushed before the call.

    So your example should be:

    push #4
    push #8
    call function
    pop r7 ; result -> r7
    dec sp
    

    The called function must not change the SP before returning:

    function:
        dec SP ; leave return address untouched
        dec SP
        pop r4 ; 8 -> A
        pop r5 ; 4 -> B
        add A, B
        inc SP
        push A; push result
        inc SP
        inc SP
        ret
    

    Additional note: PUSH and POP only take an address of the internal RAM (00H to 7FH) and special function registers (80H to 0FFH) as parameter. There are no variants for immediate values. Even if you write PUSH R2 the absolute address of R2 in the current register set is used.