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
| 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 |
| 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 |
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