assembly68hc12

Proper convention for handling the stack when managing parameters and the return address


What is the best way to handle having the return address of a calling function on top of any parameters that have been placed in the stack when you need to access parameters 'below' it in the stack? I am using the S12 Motorola/Freescale processor. (The S12 has: D register with 16 bits consisting of A and B registers each of which has 8 bits. X and Y index registers each 16 bits, a program counter and a stack pointer) A sample of the code is:

MAIN ORG    $1500        ;Set the start of the program 
     LDD    #SomeValue   ;Load the D register with a value
     PSHD                ;Push D onto the stack
     JSR    ROUTINE      ;Go to the subroutine - pushes the PC to the SP
END_MAIN    END

ROUTINE     
     PULD                ;Pull the top of the stack into the D register
                         ;D now holds the address for returning to the 
                         ;main function. 
     PSHD                ;Push the return address back onto the stack
END_ROUTINE RTS          ;Return to Main routine

The problem is that the top of the stack holds the address for the next instruction which makes it difficult to maneuver around. For example, if I needed a parameter that is underneath the the address, I would have to either manually adjust the SP (which seems rather hacky) or I will have to pull the top of the stack off and store it in a register which takes up space. A twist on the last approach is to store the return address in a variable, unfortunately, the variables declared here are global in scope, which does not feel ideal.

ReturnAddress EQU $2000        ;Declare variable at address $2000
STD           ReturnAddress    ;Store the D register's contents in variable

Is there another option which I am not seeing here?


Solution

  • Thanks to some input from Jester, it is fairly simple to be able to observe what is happening in the stack and to use parameters contained therein. I wrote a simple program that demonstrates passing parameters by value and reference.

    QUOTIENT    EQU     $1000       ;Variable to hold our QUOTIENT
    REMAINDER   EQU     $1002       ;Variable to hold our REMAINDER
    
    MAIN        ORG     $2000       ;Set the start of the program
                LDD     #!50        ;Load the D register with a value (16 bits)
                PSHD                ;Push D onto the stack (16 bits)
                LDD     #!10        ;Load the D register with a value (16 bits)
                PSHD                ;Push D onto the stack (16 bits)
                LDD     #QUOTIENT   ;Load the D register with an address (16 bits)
                PSHD                ;Push D onto the stack (16 bits)
                LDD     #REMAINDER  ;Load the D register with an address (16 bits)
                PSHD                ;Push D onto the stack (16 bits)
                JSR     DIVIDE      ;Push the PC onto the stack (16 bits).
                LEAS $0A, SP         ;Instead of PULD 5x, thanks Jester
    END_MAIN    END
    
    
    ;******************************************************************************;
    ;DIVIDE - This routine expects the following parameters to be on the stack:
    ; STACK
    ;( 0 ) - (16 bits for return address)
    ;( 2 ) - (16 bits of address to store the REMAINDER (ANSWER var reference))
    ;( 4 ) - (16 bits of address to store the QUOTIENT (ANSWER var reference))
    ;( 6 ) - (16 bits for divisor)
    ;( 8 ) - (16 bits for dividend)
    ;******************************************************************************;
    DIVIDE      LDD     8,SP       ;Loads the dividend (50)
                LDX     6,SP       ;Loads the divisor (10)
                IDIV               ;Divide
                LDY     4,SP       ;Get the address of the Quotient
                STX     0,Y        ;Store at that address
                LDY     2,SP       ;Get the address of the remainder
                STD     0,Y        ;Store at that address
    END_DIVIDE  RTS