Implementing Stack-based Call and Return

Here are two routines that can be used to implement stack-based subroutines. One register will be needed to point to the call routine, and another to the ret routine. Register RF is used by both routines for temporary storage. Both routines assume R[2] is pointing to a stack.

Due to the short branches in each routine, each routine must not cross page boundaries.

    1 0000:             ; *****************************************************
    2 0000:             ; *** Function to implement a stack based call      ***
    3 0000:             ; ***    R5 is assumed to be the main PC            ***
    4 0000:             ; ***    R2 is assumed to be the stack pointer      ***
    5 0000:             ; ***    RF is consumed                             ***
    6 0000:             ; ***    usage is:    sep R4                        ***
    7 0000:             ; ***                 dw  call_addr                 ***
    8 0000:             ; *** Routine saves R5 values onto the stack        ***
    9 0000:             ; *** and and sets it to the call address           ***
   10 0000:             ; *****************************************************
   11 0000: d5                   sep     r5       ; jump to called routine
   12 0001: bf          call:    phi     rf       ; save D
   13 0002: e2                   sex     r2       ; set x to stack segment
   14 0003: 45                   lda     r5       ; get high byte
   15 0004: af                   plo     rf       ; save it
   16 0005: 15                   inc     r5       ; move past low address
   17 0006: 85                   glo     r5       ; get low of return address
   18 0007: 73                   stxd             ; store onto stack
   19 0008: 95                   ghi     r5       ; get high of return address
   20 0009: 73                   stxd             ; and place onto stack
   21 000a: 25                   dec     r5       ; point to low byte
   22 000b: 05                   ldn     r5       ; get low byte
   23 000c: a5                   plo     r5       ; place into low byte of PC
   24 000d: 8f                   glo     rf       ; recover high byte
   25 000e: b5                   phi     r5       ; put into high of PC
   26 000f: 9f                   ghi     rf       ; recover D
   27 0010: 30 00                br      call-1   ; transfer control
   28 0012:             
   29 0012: d5                   sep     r5       ; transfer control back
   30 0013: bf          ret:     phi     rf       ; save return value
   31 0014: 12                   inc     r2       ; high byte of return address
   32 0015: 42                   lda     r2       ; get high byte
   33 0016: b5                   phi     r5       ; put into register 5
   34 0017: 02                   ldn     r2       ; get low byte
   35 0018: a5                   plo     r5       ; put into low
   36 0019: 9f                   ghi     rf       ; recall return value
   37 001a: 30 12                br      ret-1    ; and return to caller

The Call function:

Lines Description
11 This transfers control back to R5, leaving the Call Register again pointing to the beginning of the call routine
12 This saves the value in D so that it can be used as a passed parameter to subroutines
13 X is set so that we can use the STXD commands to save the return address on the stack
14-16 This block moves the original PC (R5) past the call address, we pick up the high byte of the call address and store it in RF.0 on our way past
17-20 This block takes the new position of R5 and stores it on the stack
21-23 This block of code moves back to the low byte of the call address, retreives it and places it into R5.0
24-25 Now we retrieve the strored high address value and place it into R5.1. R5 is now pointing at the subroutine to be called
26-27 Retreive the stored value of D and jump to line 11 in order to transfer control to the called subroutine

The Ret function:

Lines Description
29 This transfers control back to R5, leaving the Ret Register again pointing to the beginning of the ret routine
30 Save the value of D so that it can be used as a return value
31-35 Retreive the return address from the stack and place into R5
36 Recover D
37 Jump to line 29 in order to transfer control back to the original

Sample Code:

This sample assumes that R4 has been previously set to point to the Call routine, R7 has been set to point to the Ret routine, and R2 is pointing at suitable memory for a stack.

       ldi   0beh      ; byte to display
       sep   r4        ; transfer control to call routine
       dw    disp      ; address of subroutine to call

       ...

disp:  str   r2        ; write value in D to the stack
       sex   r2        ; point the X register at stored value
       out   4         ; write value to the hex displays
       dec   r2        ; put stack pointer back where it was
       sep   r7        ; transfer control to the ret routine