int fib(int n)
{
if (n = 0)
return 1;
else if (n == 1)
return 1;
else
{
return fib(n-1) + fib(n-2);
}
}
|
int n, result; result = fib(n); |
|
Therefore, the main program must pass the parameter n to Fibonacci by pushing n onto the system stack:
move.l n, -(a7)
|
This instruction will create the following stack structure:
+---------------------+ <------------ Stack pointer (A7) | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... | |
bsr fib
|
This will push the return address on the stack and create the following stack structure:
+---------------------+ <------------ Stack pointer (A7) | return address | +---------------------+ | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... | |
int fib(int n)
{
if (n = 0)
return 1;
else if (n == 1)
return 1;
else
{
return fib(n-1) + fib(n-2);
}
}
|
You will notice that there are two (recursive) calls to Fibonacci.
|
|
Conclussion:
|
Where is a safe place in recursive programming:
|
Therefore:
|
********************************* PRELUDE
move.l a6, -(a7) ; Save caller's frame pointer
move.l a7, a6 ; Setup my own frame pointer
suba.l #4, a7 ; Allocate space for local variable for fib(n-1)
*********************************
|
I will explain what each one does below. Make sure that you realise that the structure of the stack frame is like this when the prelude is always executed:
+---------------------+ <------------ Stack pointer (A7) | return address | +---------------------+ | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... |
This will save the frame pointer on the stack, creating this partial stack frame structure:
+---------------------+ <------------ Stack pointer (A7) | saved a6 | +---------------------+ | return address | +---------------------+ | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... |
This will make the frame pointer A6 points to the stack frame that is now being built:
+---------------------+ <---- Frame pointer A6 & Stack pointer (A7) | saved a6 | point to the same location.... +---------------------+ | return address | +---------------------+ | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... |
This will push the stack pointer A7 4 bytes up, allocating 1 integer variables -- used to save the return value of fib(n-1).
+---------------------+ <---- Stack pointer (A7) | help (local var)| +---------------------+ <---- Frame pointer (A6) | saved a6 | +---------------------+ | return address | +---------------------+ | parameter n | +---------------------+ | ....... | | rest of the stack | | ....... |
|
|
|
|
Make sure you pop the parameter from the stack after Fibonacci returns - because the parameter has not been cleaned up.
The following is the program fragment where Fibonacci calls fib(n-1):
move.l 8(a6), d0 ; retrieve parameter n into register d0
sub.l #1, d0 ; d0 = n - 1
*
* ----------------------------- ; fib is calling fib now !!!!
*
move.l d0, -(a7) ; Push (n-1) as parameter
bsr fib ; Call fib(n-1)
adda.l #4,a7 ; Clean up parameter from stack
move.l d0, -4(a6) ; help = return value of fib(n-1) in register D0
|
Fibonacci will call itself a second time with value n-2. The following is the program fragment where Fibonacci calls fib(n-2):
move.l 8(a6), d0 ; retrieve parameter n into register d0
sub.l #2, d0 ; d0 = n - 2
*
* ----------------------------- ; fib is calling fib again....
*
move.l d0, -(a7) ; Push (n-2) as parameter
bsr fib ; Call fib(n-2)
adda.l #4,a7 ; Clean up parameter from stack
add.l -4(a6),d0 ; Compute the value: fib(n-1)+fib(n-2)
|
I have highlighted the difference between the first call and the second. The second call uses a different parameter value and stores the return value in a different local variable !
* ===============================================
* main: result = fib(n)
* ===============================================
Start:
movea.l #12345,a6 ; Store something in a6 to make it dramatic
move.l n,-(a7) ; Call fib(n)
bsr fib
adda.l #4,a7 ; pop parameter off the stack
move.l d0,result ; result = return value
Stop: nop
n: dc.l 5 ; variable n (input)
result: ds.l 1 ; variable result (output)
* ========================================================= Fib
* int fib(int n)
* {
* if (n = 0)
* return 1;
* else if (n == 1)
* return 1;
* else
* {
* return fib(n-1) + fib(n-2);
* }
* }
*
* ----------------------------------------------------
* Input: n on stack
* Output: fib(n) in register d0
fib:
********************************* PRELUDE
move.l a6,-(a7) ; Save caller's frame pointer
move.l a7,a6 ; Setup my own frame pointer
suba.l #4,a7 ; Allocate space for local var. "help"
*********************************
* Start of function....
move.l 8(a6),d0 ; n
cmp.l #0,d0 ; n == 0 ?
bne else1
move.l #1,d0 ; return(1)
********************************* POSTLUDE
move.l a6,a7 ; Deallocate local variable(s)
move.l (a7)+,a6 ; restore caller's frame pointer
*********************************
rts
else1: move.l 8(a6),d0 ; n
cmp.l #1,d0 ; n == 1 ?
bne else2
move.l #1,d0 ; return(1)
********************************* POSTLUDE
move.l a6,a7 ; Deallocate local variable(s)
move.l (a7)+,a6 ; restore caller's frame pointer
*********************************
rts
else2:
********************************* fib(n-1)
move.l 8(a6),d0 ; n
sub.l #1,d0 ; n - 1
move.l d0,-(a7) ; Push (n-1)
bsr fib ; call fib(n-1) - will return to next instruction
adda.l #4,a7 ; Clean up: Pop parameter (n-1) from stack
move.l d0,-4(a6) ; Save return value (fib(n-1)) in local var !!
********************************* compute fib(n-2)
move.l 8(a6),d0 ; n
sub.l #2,d0 ; n - 2
move.l d0,-(a7) ; Push (n-2)
bsr fib ; call fib(n-2) - will return to next instruction
adda.l #4,a7 ; Clean up: Pop parameter (n-2) from stack
**********
add.l -4(a6),d0 ; Compute the return value: fib(n-1)+fib(n-2)
********************************* POSTLUDE
move.l a6,a7 ; Deallocate local variable(s)
move.l (a7)+,a6 ; restore caller's frame pointer
*********************************
rts
End:
end
|
How to run the program:
|