;---------------------------------------------------------------------- ; factRecursive.s --- Recursive computation of the factorial function. ; ; This program illustrates parameter passing via registers. ; ; This program modifies memory --- you'll need to use the map.ini file ; to allow this. ;---------------------------------------------------------------------- ; The following startup code sets the initial stack and frame ; pointers and then calls main(), which is expected to return. ; This illustrates some of the work an operating system has to ; perform before passing control to a program. ; ; For your programs it's not necessary to be so elaborate. ; Your main program can initialize sp and fp, and the last ; instruction in your main program can be the unconditional ; branch to itself. area prog, code, readwrite entry mov r0, #-1 ; For identification purposes, put known mov r1, #-2 ; values into all the registers. mov r2, #-3 mov r3, #-4 mov r4, #-5 mov r5, #-6 mov r6, #-7 mov r7, #-8 mov r8, #-9 mov r9, #-0xA mov r10, #-0xB mov r11, #-0xC mov r12, #-0xD mov r13, #-0xE mov r14, #-0xF ldr sp, =bos ; Modifies r13 --- sp. mov fp, sp ; Modifies r11 --- fp. bl main ; SET A BREAKPOINT HERE. fin b fin ;---------------------------------------------------------------------- ; void main(void) ; ; Use r0 through r3 for passing parameters and for scratch storage. ; Return results through r0. Use r4 through r10 for local variables. ; ; The caller will not expect scratch values in r0--r3 to be preserved ; across calls. ; ; The caller will expect that local variable values in r4--r10 to be ; preserved across calls. If you modify any of these registers, you ; must save them into your activation frame upon entry and restore them ; from your activation frame upon exit. ; ; The frame pointer (fp) and link register (lr) are _always_ saved ; and restored. ; ; The first three instructions create the activation frame ; for this function. ; ;---------------------------------------------------------------------- main str fp, [sp, #-4]! ; Save the old fp by pushing it onto the ; stack. ; Remember, the word pointed to by sp is ; "occupied," so I use the '#-4' to point ; to the word preceding the word pointed ; to by sp. The '!' updates the value ; in sp by adding the offset value of -4. ; The addressing mode of '[sp, #-4]!' ; is analogous to pre-decrementing sp, ; written as --sp in C. mov fp, sp ; Establish the new fp. ; This function uses r4 and r5. Save them first by pushing ; them onto the stack. The '!' following sp means that sp ; will be updated. In this case, because we're pushing three ; registers, sp will be decremented by 3 words (12 bytes). ; 'stmfd' stands for "store multiple, full descending." stmfd sp!, {r4-r5, lr} ; The function's "real" code begins here. mov r0, #6 ; SET A BREAKPOINT HERE. bl fact mov r4, r0 ; Return value should be 720, 0x2D0. mov r0, #10 bl fact mov r5, r0 ; Return value should be 3,628,800, 0x375F00. ; The following three instructions restore all saved registers ; and destroy the activation frame. ldmfd is the inverse of ; stmfd. Since we pushed r4, r5, and lr last, we pop them first. ldmfd sp!, {r4-r5, lr} ; Set a break point here, so that I can ; check r4 and r5 before they're restored. ; sp is pointing to the saved fp. Restore fp and pop it by post- ; incrementing sp by one word. Post-incrementing is analogous to ; sp++ in C. ldr fp, [sp], #4 bx lr ;---------------------------------------------------------------------- ; int fact(int n) ; ; n is in r0. ; ; Note the similarities here between the activation frame creation/ ; destruction code. All that differs is the set of local variable ; registers saved/restored. ;---------------------------------------------------------------------- fact str fp, [sp, #-4]! mov fp, sp stmfd sp!, {r4, lr} cmp r0, #0 ; SET A BREAKPOINT HERE. movlt r0, #-1 blt efact cmp r0, #2 movlt r0, #1 blt efact mov r4, r0 ; Save n's value. sub r0, r0, #1 ; Prepare to call fact(n-1). bl fact mul r0, r4, r0 ; Calculate n * fact(n-1). efact ldmfd sp!, {r4, lr} ldr fp, [sp], #4 bx lr ;---------------------------------------------------------------------- ; The following creates a 1KB = 256 words activation frame stack. ; ; bos = Base Of Stack. ; ; Remember: the stack grows towards address 0. ;---------------------------------------------------------------------- area progdata, data, readwrite space 1024 bos dcd 0x0 end