Subroutines

  • Subroutines make use of the stack to keep track of the program counter value upon returning from a subroutine.
  • Whenever a program uses subroutine(s), we must first initialize the stack pointer.
initstack:                                ;  r16   SP
           ldi  r16, HIGH(RAMEND-0x20)    ; 0x08  ----
           out  SPH, r16                  ; 0x08  08--
           ldi  r16, LOW(RAMEND-0x20)     ; 0x3f  08--
           out  SPL, r16                  ; 0x3f  083f
  • We jump to a subroutine using either RCALL or CALL (relative or not).
  • We return from a subroutine using RET.

Example Program

The following program shows an example of calling a delay subroutine. Can you walk through the code and keep track of the registers R16-R18, the program counter, the stack and the stack pointer?

.cseg
.org 0x0
         rjmp initStack

.org 0x2a
initStack:
           ldi   r16, HIGH(RAMEND-0x20)
           out   SPH, r16
           ldi   r16, LOW(RAMEND-0x20)
           out   SPL, r16

start:
           ldi   r16, 0
           rcall delay
           dec   r16
           rjmp  start

delay:
           push  r16
           push  r17
           push  r18
           ldi   r16, 20
loop1:
           ldi   r17, 255
loop2:
           ldi   r18, 255
loop3:
           dec   r18
           brne  loop3
           dec   r17
           brne  loop2
           dec   r16
           brne  loop1
           pop   r18
           pop   r17
           pop   r16
           ret
  • Your subroutine should begin by pushing all of the register values that your subroutine uses onto the stack.
  • Your subroutine should end with popping all of the saved register values off of the stack and into the appropriate registers.
  • If you don't do this, your subroutine may corrupt the value of a register that the code calling the subroutine relied on.

General Stack Usage Rules

  • The stack is used by:
    • PUSH and POP
    • CALL, RCALL and RET
    • Interrupts (more on these later this quarter)
  • If using any of the above, you must initialize the stack pointer.
  • For every PUSH there must be a POP.
  • A RET is needed at the end of every subroutine.
  • Never jump or branch (RJMP, BRNE, etc) into a subroutine.
  • Never jump or branch out of a subroutine.
ce2800/subroutines.txt · Last modified: 2010/03/09 20:55 (external edit)
 

This website is not owned or managed by the Milwaukee School of Engineering.

© 2003-2010 Dr. Christopher C. Taylor, et. al. • Office: L-343 • Phone: 277-7339 • npǝ˙ǝosɯ@ɹolʎɐʇ • -> RSS <-