Subroutine calls in machine language are characterized by the form of passing parameters and the form of returning to the caller. The PALM processor has no instructions for subroutine mechanisms, so the programmer has to prove his creativity. Subroutine calls and passing parameters are independent from each other so they are described in two separate paragraphs.
A subroutine call consists of storing the current program counter and jumping
to another location. At the end of the subroutine a jump back to the origin
is performed by jumping to the location indicated by the stored program
counter.
A jump instruction is any instruction that modifies register R0. Normally
ADD/SUB R0,#xx is used for relative jumps, LWI R0,#xxxx for
absolute jumps and MOVE R0,xx resp. MOVE R0,(Rx) for
indirect jumps.
The return address is always passed in a register, most commonly in R2. Of
course you can calculate another address or point to a different location
in the program if it is desired to return somewhere else. But normally
a return to the instruction following the subroutine call is desired, so
the INC2 instruction is used.
This will look like this:
Address Opcode Mnemonic ----------------------------------------------------------- 2000 0203 INC2 R2, R0 ; R2 <- $2004 2002 A00B ADD R0, #12 ; R0 <- $2010 2004 0000 HALT ... 2010 A500 ADD R5, #1 2012 0024 MOVE R0, R2 ; R0 <- $2004
The disadvantage of passing the return address in a register is obvious when
nested or recursive calls are needed because only a limited set of registers
may be available. If all registers are used by the program only one single
call can be made. Therefore it is advised to create a stack, e.g. with R15
as stack pointer, that will store all return addresses (and other stuff
if desired).
Example:
Address Opcode Mnemonic ----------------------------------------------------------- 2000 D401 ABCD LWI R4, #$ABCD 2004 0203 D021 7654 CALL $7654, R2 ;(INC2 R2, R0; LWI R0, #$7654) 200A 0000 HALT ... 7654 52F1 MOVE (R15)+, R2 ; push R2 onto stack 7656 D301 0014 LWI R3, #20 7658 0203 0044 CALL (R4), R2 ; jump to $ABCD 765C FF01 SUB R15, #2 ; decrement SP by two 765E D0F8 MOVE R0, (R15) ; return to caller
The most common forms of passing parameters are register values, common memory area or a stack (e.g. with R15 as SP, see above). Implementing these forms is an easy task. Another form that is often found in PALM programs is a parameter list following the call instruction. This is realized in the following manner:
Address Opcode Mnemonic ----------------------------------------------------------- 2000 0203 D021 3000 CALL $3000, R2 2006 0200 0400 0040 dw $0200, $0400, ' ' 200C 0000 HALT ... 3000 D321 MOVE R3, (R2)+ ; R3 <- $0200 3002 D421 MOVE R4, (R2)+ ; R4 <- $0400 3004 D521 MOVE R5, (R2)+ ; R5 <- ' ' 3006 014C MHL R1, R4 3008 0146 OR R1, R4 300A C10B SNZ R1 ; test if R4 is $0000 300C 0024 RET R2 ; MOVE R0, R2 300E F400 SUB R4, #1 3010 7530 MOVB (R3)+, R5 3012 F00D BRA $3006
The subroutine fills a memory area with a certain value. This example fills the area from $0200 and a length of $0400 with blanks, so the screen will be cleared. The parameters build a kind of mini-stack that lies directly after the subroutine call. The return address is the "stack pointer" after all parameters have been popped.