Subroutine is a set of instructions within a large program that perform a specific task. Subroutine is coded such that it can be invoked repeatedly from anywhere in the program including other subroutines, and then returns and continues the execution at the next instruction after the invoke instruction. The sequence of execution involving subroutine is illustrated in Figure 1.
Instructions to call a subroutine are
bsr (branch subroutine) and jsr (jump subroutine). When bsr and jsr instructions are executed, the return address is saved in the stack and stack pointer (SP) is decremented by 2. Bothbsr and jsr, the operand is specified by using a label (relative addressing mode). The label specify the location of the subroutine in the program. In addition to relative addressing mode, operand of jsr instruction can be specified by using direct, extended, indexed and indexed indirect addressing modes. Program control returns to the main program by using rts. Return address is pop from the stack onto the PC and increment the SP by 2. Program execution continues at the address restored from the stack.There are issues that require consideration when implementing subroutines.
- Passing parameters
- Returning results
- Saving CPU registers
- Local variables
Parameter Passing and Results Returning
Subroutine might requires values from main program (caller) for its computation. Results of the computation might need to be returned to the main program. In fact, it is a common practice to write a subroutine with a specific purpose of computing one or more results whose values are determined by the parameters passed by the caller. Passing parameters may be implemented by using CPU registers, the stack or defining global memories. Parameters are pushed into the stack for example before the subroutine is called. Similar operation is performed when returning results to the main program. The results are placed in CPU registers before the subroutine complete its execution.
Saving CPU Registers
Subroutine may use CPU registers to hold values for its computation. However the values it the CPU registers may also be used by the caller. If the values are not preserved when a subroutine is called, the result computation of the caller will be incorrect. Therefore the CPU registers must be saved before a subroutine is executed. Either the caller or subroutine is responsible for saving the registers. Stack is used to save the registers.
Local Variables
Subroutine may require memory locations to hold temporary values for its computation. These memory locations are available and accessible by the subroutine thus it is called local variables. Allocating local variables are done by using
leas instruction. To allocate n local variables, the instruction is written asleas -n,SPSP is the base register which hold the base address and n is the offset. Before subroutine complete its execution, the local variables are deallocated.leas n,SPThe following program shows an example of program with a subroutine.
i equ 0
c equ 1
N equ 2
org $1510
arr1 dc.b $11,$22,$33,$44
org $1530
arr2 dc.b $55,$66,$77,$88,$99,$AA
org $2000
lds #$2000
ldx #arr1 ; parameter passing (index register X)
ldaa #4 ; parameter passing (accumulator B)
jsr tb7 ; call subroutine tb7
ldx #arr2
ldaa #6
jsr testb7
...
swi
; Subroutine begin
tb7 leas -3,sp ; allocate 3 local variables
clr c,sp ; init c
clr i,sp ; init i
staa N,sp ; init N/get value of N
loop ldab i,sp
cmpb N,sp
beq exit
ldaa b,x
bita #$80 ; test bit 7 for zero
bne skip ; tested bit 7 are not zero, don't count (skip)
inc c,sp
skip inc i,sp
bra loop
exit ldab c,sp ; result returning (accumulator B)
leas 3,sp ; deallocate local variables
rts; ; return to main program
; Subroutine end
end
Index register X and accumulator A are used for parameter passing while accumulator B is used to return the result to the caller. Three local variables are allocated by the subroutine.
