460 likes | 775 Views
Stacks and Subroutines. Some example stacks. Stacks and subroutine usage. The stack is a special area of the random access memory in the overall memory system The stack is used for General data storage (limited) Temporary data storage (true)
E N D
Stacks and subroutine usage • The stack is a special area of the random access memory in the overall memory system • The stack is used for • General data storage (limited) • Temporary data storage (true) • Parameter and control information storage for subroutines (yes!)
Stack • Last-in, first-out (LIFO) structure • All access is at the top of the stack • Operations • Push • Places an item onto the stack • Pull • Removes an item from the stack • Some (most!) people use the term “pop” • Bottom of the stack is at highest memory address, and top of the stack is at the lowest address • Stack grows from high to low address Cont..
Stack • For EVBU, stack is usually placed at $01FF • Stack Pointer (SP) • Register that points to the memory location immediately preceding the top of the stack • In other words, the SP normally contains the address for a new data item to be pushed Cont..
PUSH Instructions • Push instructions • PSHA, PSHB, PSHX, PSHY • Stores data in memory at address pointed to by SP • Decrements SP • For 16-bit values, low-order byte is pushed first, followed by high-order byte • How can we push CCR?
PUSH Instructions • Pull instructions • PULA, PULB, PULX, PULY • Increments SP • Loads data from memory address pointed to by SP
Other Stack Operations • Other stack operations • Can modify or read the SP LDS Load the SP STS Store the SP INS Increment SP DES Decrement SP TSX Transfer SP+1 to IX TSY Transfer SP+1 to IY TXS Transfer IX-1 to SP TYS Transfer IY-1 to SP
Stacks • Stacks • Remember to initialize SP at beginning of • program • Important to pull data in reverse order that you pushed it • Note that SP points to empty memory location (= location where next value will be stored)
Using the Stacks • Using the stack • Passing parameters to subroutines (more on this later) • Temporary storage • 68HC11 has limited number of registers • Use stack to preserve register values • Example: Multiply ACCA and ACCB, round to 8 bits PSHB ; save value in ACCB MUL ; ACCD = ACCA*ACCB ADCA #$00 ; round to 8 bits PULB ; restore ACCB Cont..
Using the Stacks • Using the stack • You can also use the stack to save intermediate • values • Example: (Listing 3.1 in text) This calculates x squared plus y squared. x and y are 8-bit numbers stored in addresses $1031 and $1032. The 8-bit result is put in ACCA. ORG $E000 BEGIN: LDS #$FF ; initialize SP LDAA $1031 ; get x value TAB ; square it Cont..
Using the Stacks MUL ADCA #$00 ; round to 8 bits PSHA ; save it LDAA $1032 ; get y value TAB ; square it MUL ADCA #$00 ; round to 8 bits PULB ; retrieve first result ABA ; add them
Dangers Using the Stacks • Dangers in using the stack • Overflow • Too many pushes Stack grows so large that it overwrites portions of memory that are being used for other purposes • Example: ORG $E0 FOO RMB 2 ORG $E000 LDS #$FF ; initialize SP LDAB #$FF ; initialize loop count LOOP: Cont..
Dangers Using the Stacks PSHA ; push value on stack DECB ; decrement count BNE LOOP ; and repeat • Underflow • Too many pulls • SP points to address higher than the intended bottom of the stack • The HC11 does not protect you from overflow or underflow! • Only way to recover is to reset the system • Be aware of the stack size that your program needs. Cont..
Dangers Using the Stacks • Typical memory layout for EVBU: • 512 bytes of RAM ($00-$1FF) • $00 - $FF used by Buffalo monitor • Don’t use these locations in your programs • User variables should start at $100 ($100-?) • Stack starts at $1FF (? - $1FF) • More variables = less stack space
Subroutine • Why use them? • Provides modularity to reduce program complexity • Creates many smaller, but more easily developed and tested program units • May save on memory space (to store program) • Can be reused in different parts of a program • Can be placed in a library for use by many programs and applications • Subroutines should . . . • Be small, to ease writing, testing, and modifying • Have a well defined purpose • Have a well defined interface Cont..
Subroutine • Be well documented (like the rest of the program!) • Describe input parameters • Registers, memory locations, values on the stack, etc. • Describe output parameters • Registers, memory locations, stack, condition codes • Describe any side effects • Registers that are changed, condition codes, etc.
Example of proper Documentation Format • Example of proper documentation format: ;****************************** ; Function: ToUpper ; This function replaces all lower-case ; characters in a string with upper-case. ; The end of the string is marked with ; $00. ; Input: IX = starting address of string ; Output: none ; Registers affected: ACCA, CCR ;*******************************
Calling Subroutines • Calling a subroutine JSR sbr BSR sbr • Address of next instruction (return address) is pushed onto the stack • This is the current value of PC • PC is loaded with the starting address of the subroutine • Next instruction fetched will be from the subroutine
Returning Subroutine • Returning from a subroutine • RTS instruction • Must be the last instruction in subroutine • Pops return address off the stack, loads it into PC • Next instruction fetch will be the instruction following the JSR/BSR • If your subroutine manipulates the stack, be aware of where the return address is stored. • It must be at the top of the stack when you execute the RTS
Subroutine Parameter Passing • Subroutine parameter passing -- how are the parameters / arguments for the subroutine passed to it? • Registers • Parameters are placed in predetermined register locations • Simple and fast • Number of parameters is limited by the number of "free" registers • Code is not reentrant • Dedicated memory • A series of (predetermined) memory locations are used to hold the parameters Cont..
Subroutine Parameter Passing • Simple, but added overhead due to memory operations • Possible to pass many parameters • Code is not reentrant • Pointer to memory • Pass the subroutine a register value containing the address of the parameters in memory • More complex, extra overhead for use of the pointer • Code is reentrant • Use the stack • Parameters, in addition to the return address, are pushed onto the stack -- the combination is called the stack frame • You must push the parameters before the JSR/BSR Cont..
Subroutine Parameter Passing • Requires care in manipulating the parameters • Don’t forget about the return address! • Many parameters can be passed • Separate parameter stack can be created and used in addition to the system stack • Code is reentrant
Example • Example: • Timing delay • Write a subroutine that will delay for a specified number of milliseconds. The delay time is passed as a parameter in ACCB. • The subroutine should also preserve the contents of all registers as well as the condition codes • Main program: LDAB #$0A ; delay for 10 ms JSR DELAY
Example • Example: • Write a subroutine to find the maximum of two signed 8-bit numbers. The two numbers are passed to the subroutine on the stack, and the maximum is returned to the calling routine on the stack. • Main program: LDAA #$73 ; load the 2 values LDAB #$A8 PSHA ; push them on the stack PSHB JSR MAX ; find the max PULA ; pull max off stack
Example • Example: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Subroutine - MAX ; This subroutine returns the maximum of 2 ; signed 8-bit numbers. ; Input - The 2 numbers are passed on the stack ; Output - The maximum is returned on the stack ; Registers used - ACCA, ACCB, IY, CCR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MAX: PULY ; save return address PULB ; get the 2 numbers Cont..
Example PULA CBA ; compare them BGT A_IS_MAX ; branch if ACCA > ACCB B_IS_MAX: PSHB ; return the value in ACCB BRA MAX_EXIT A_IS_MAX: PSHA ; return the value in ACCA MAX_EXIT: PSHY ; put return address back on stack RTS ; and return
Example • Example: • Convert an 8-bit hex number into 2 ASCII characters • For example, convert $3F into ‘3’ and ‘F’ • The hex number is passed to the subroutine on the stack, and the 2 ASCII characters are returned on the stack, with the high-order character on top. • Main program: LDAA #$3F ; get hex number PSHA JSR HEX_TO_ASCII ; convert it PULB ; ACCB = ‘3’ = $33 PULA ; ACCA = ‘F’ = $46
Example • Example • Converting hex digit to 2 ASCII characters • Pseudo code: Get hex digit from stack Convert lower nibble to ASCII Push char on stack Convert upper nibble to ASCII Push char on stack Return • We’ll use a second subroutine to convert a nibble to ASCII • Note that the ASCII codes for 0-9 are $30-$39, and the codes for A-F are $41-$46 Cont..
Example • Pseudo code: Add #$30 to nibble If (result > $39) Add #$07 Return
Example • Example: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Subroutine - CONVERT_NIBBLE ; This subroutine converts a nibble (4-bit value) ; to ASCII. ; Input: ACCB contains the nibble ; Output: ACCB contains the ASCII code ; Registers affected: None ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONVERT_NIBBLE: PSHA ; save ACCA Cont..
Example TPA ; save CCR PSHA ADDB #$30 ; convert to ASCII CMPB #$39 ; is nibble > 9? BLS CN_EXIT ; branch if not ADDB #$07 ; for A-F CN_EXIT: PULA ; restore CCR TAP PULA ; restore ACCA RTS ; return
Example • Example: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Subroutine - HEX_TO_ASCII ; This subroutine converts an 8-bit hex number ; to two ASCII digits. ; Input: Hex number is passed on the stack ; Output: ASCII characters are returned on the ; stack, with the high-order nibble on top. ; Registers affected: ACCA, ACCB, IY, CCR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HEX_TO_ASCII: PULY ; save return address Cont..
Example PULA ; get hex number TAB ; copy it to ACCB ANDB #$0F ; get lower nibble JSR CONVERT_NIBBLE PSHB ; save ASCII on stack TAB ; get hex number again LSRB ; get upper nibble LSRB LSRB LSRB JSR CONVERT_NIBBLE Cont..
Example PSHB ; save ASCII on stack PSHY ; push return address RTS ; and return
Summary • Summary • Stack • Be sure to initialize the stack pointer at the beginning of your program LDS #$1FF • Don’t do this if you’re calling your program from Buffalo • Buffalo initializes SP for you • Push and Pull operations • Remember SP points to next empty location
Summary • Summary • Subroutines • Break your program into subroutines • Well-defined (and documented!) function • Well-defined (and documented!) interface • Passing parameters • Use registers if possible • Else, use stack if needed • Don’t forget about the return address