Here is my CS170 webpage that explain the important of pre-conditioning in the Tower of Hanoi problem: click here
void hanoi(int ndisks, int fromPeg, int toPeg)
{
int helpPeg;
if (ndisks == 1) then
WriteLn "move disk from peg " + fromPeg + " to " + " + toPeg
else
{
helpPeg := 6 - fromPeg - toPeg;
hanoi(ndisks-1, fromPeg, helpPeg);
WriteLn "move disk from peg " + fromPeg + " to " + " + toPeg
hanoi(ndisks-1, helpPeg, toPeg);
}
}
hanoi(n, 1, 3);to move n disks from peg 1 to peg 3.
+---------------------+ <------------ Stack pointer (SP) | use for helpPeg | +---------------------+ <------------ Frame Pointer (FP) | old Frame Pointer | +---------------------+ | Return Address | +---------------------+ | use for ndisks | +---------------------+ | use for fromPeg | +---------------------+ | use for toPeg | +---------------------+ |
/* -------------------------------------------------------
Call Hanoi(4, 1, 3): move 4 disk from peg 1 to peg 3
------------------------------------------------------- */
mov r0, #3
push {r0} // Pass peg2 = 3
mov r0, #1
push {r0} // Pass peg1 = 1
mov r0, #4
push {r0} // Pass ndisks = 4
/* ----------------------------------------
Call Hanoi(4, 1, 3)
---------------------------------------- */
bl Hanoi
add sp, sp, #12 // Pop parameters
|
/* ==========================================================
Stack frame:
SP ----> +------------+
| helpPeg | FP - 4
FP ----> +------------+
| old FP |
+------------+
| return addr|
+------------+
| ndisks | FP + 8
+------------+
| fromPeg | FP + 12
+------------+
| toPeg | FP + 16
+------------+
========================================================== */
Hanoi:
// Prelude
push {lr} // Save return address
push {fp} // Save frame pointer
mov fp, sp // Make base pointer
sub sp, sp, #4 // Local var helpPeg
// if (ndisk == 1 )
ldr r0, [fp, #8] // r0 = ndisks
cmp r0, #1 // Check (ndisks == 1)
bne else
// printf("Move disk from peg %d to peg %d\n", fromPeg, toPeg)
movw r0, #:lower16:Str
movt r0, #:upper16:Str
ldr r1, [fp, #12] // r1 = fromPeg
ldr r2, [fp, #16] // r2 = toPeg
bl printf
b ifEnd
else:
// helpPeg = 6 - fromPeg - toPeg
ldr r0, [fp, #12] // r0 = fromPeg
rsb r0, r0, #6 // r0 = 6 - fromPeg
ldr r1, [fp, #16] // r1 = toPeg
sub r0, r0, r1 // r0 = 6 - fromPeg - toPeg
str r0, [fp, #-4] // helpPeg = 6 - fromPeg - toPeg
// Hanoi(ndisk-1, fromPeg, helpPeg)
ldr r0, [fp, #-4]
push {r0} // Pass helpPeg
ldr r0, [fp, #12]
push {r0} // Pass fromPeg
ldr r0, [fp, #8]
sub r0, r0, #1
push {r0} // Pass ndisk-1
/* ----------------------------------------
Call Hanoi(ndisk-1, fromPeg, helpPeg)
---------------------------------------- */
bl Hanoi
add sp, sp, #12 // Pop parameters
// printf("Move disk from peg %d to peg %d\n", fromPeg, toPeg)
movw r0, #:lower16:Str
movt r0, #:upper16:Str
ldr r1, [fp, #12] // r1 = fromPeg
ldr r2, [fp, #16] // r2 = toPeg
bl printf
// Hanoi(ndisk-1, helpPeg, toPeg)
ldr r0, [fp, #16]
push {r0} // Pass toPeg
ldr r0, [fp, #-4]
push {r0} // Pass helpPeg
ldr r0, [fp, #8]
sub r0, r0, #1
push {r0} // Pass ndisk-1
/* ----------------------------------------
Call Hanoi(ndisk-1, fromPeg, helpPeg)
---------------------------------------- */
bl Hanoi
add sp, sp, #12 // Pop parameters
ifEnd:
// Return
mov sp, fp
pop {fp}
pop {pc}
// ************************ Starting variable definition *****************
.data
// ***********************************************************************
Str: .asciz "Move a disk from peg %d to peg %d\n"
|
The main program passes the parameter n to hanoi by pushing 4, 1, and 3 in the reverse order onto the system stack with the following instructions:
mov r0, #3
push {r0} // Pass peg2 = 3
mov r0, #1
push {r0} // Pass peg1 = 1
mov r0, #4
push {r0} // Pass ndisks = 4
This will create the following stack structure:
+---------------------+ <------------ Stack pointer (SP) | ndisk = 4 | +---------------------+ | fromPeg = 1 | +---------------------+ | toPeg = 3 | +---------------------+
The main program calls the hanoi function with a bl instruction:
pass parameters (see above)
bl hanoi
Now the Hanoi function will
begin execution.
Let's take a look at the Hanoi function
The prelude of the hanoi function consists of these instructions:
********************************* PRELUDE
push {lr} // Save return address
push {fp} // Save frame pointer
mov fp, sp // Make base pointer
sub sp, sp, #4 // Local var helpPeg
*********************************
I will explain what each one does below.
Make sure that you realise that the structure of the stack frame is
always
like this when the prelude is executed:
+---------------------+ <------------ Stack pointer (SP) | parameter N | +---------------------+ | parameter 1 | +---------------------+ | parameter 3 | +---------------------+
This will save the return address on the stack, creating this partial stack frame structure:
+---------------------+ <------------ Stack pointer (SP) | return address | +---------------------+ | parameter N | +---------------------+ | parameter 1 | +---------------------+ | parameter 3 | +---------------------+
This will save the frame pointer on the stack, creating this partial stack frame structure:
+---------------------+ <------------ Stack pointer (FP) | saved FP | +---------------------+ | return address | +---------------------+ | parameter N | +---------------------+ | parameter 1 | +---------------------+ | parameter 3 | +---------------------+
This will make the frame pointer FP points to the stack frame that is now being built:
+---------------------+ <---- Frame pointer FP & Stack pointer (SP) | saved FP | point to the same location.... +---------------------+ | return address | +---------------------+ | parameter N | +---------------------+ | parameter 1 | +---------------------+ | parameter 3 | +---------------------+
This will push the stack pointer SP 4 bytes up, allocating 1 integer local variable
This variable will be used is for helpPeg.
+---------------------+ <---- Stack pointer (SP) | helpPeg | +---------------------+ <---- Frame pointer (FP) | saved FP | +---------------------+ | return address | +---------------------+ | parameter N | +---------------------+ | parameter 1 | +---------------------+ | parameter 3 | +---------------------+
+---------------------+ <---- Stack pointer (SP)
FP - 4 | helpPeg |
+---------------------+ <---- Frame pointer (FP)
| saved a6 |
+---------------------+
| return address |
+---------------------+
FP + 8 | param ndisks |
+---------------------+
FP + 12 | param fromPeg |
+---------------------+
FP + 16 | param toPeg |
+---------------------+
|
So the address mode that will let you get to this variable is [fp, #8]
So the address mode that will let you get to this variable is [fp, #12]
So the address mode that will let you get to this variable is [fp, #16]
So the address mode that will let you get to this variable is [fp, #-4]
It is no different from how the main program calls the Hanoi function. Simply push the parameter in the proper order on the stack, and call Hanoi.
But make sure you pop the parameter from the stack after Hanoi returns - because the parameter has not been cleaned up.
The following is the program fragment where Hanoi calls hanoi(ndisks-1, fromPeg, helpPeg):
// Hanoi(ndisk-1, fromPeg, helpPeg)
ldr r0, [fp, #-4]
push {r0} // Pass helpPeg
ldr r0, [fp, #12]
push {r0} // Pass fromPeg
ldr r0, [fp, #8]
sub r0, r0, #1
push {r0} // Pass ndisk-1
Hanoi will call itself a second time with hanoi(ndisks-1, thirdPeg, toPeg); The following is the program fragment where Hanoi calls hanoi(ndisks-1, thirdPeg, toPeg):
// Hanoi(ndisk-1, helpPeg, toPeg)
ldr r0, [fp, #16]
push {r0} // Pass toPeg
ldr r0, [fp, #-4]
push {r0} // Pass helpPeg
ldr r0, [fp, #8]
sub r0, r0, #1
push {r0} // Pass ndisk-1
/* ----------------------------------------
Call Hanoi(ndisk-1, fromPeg, helpPeg)
---------------------------------------- */
bl Hanoi
add sp, sp, #12 // Pop parameters
WriteLn "move disk from peg " + fromPeg + " to " + " + toPeg
The parameters of printf( ) are:
|
// printf("Move disk from peg %d to peg %d\n", fromPeg, toPeg)
movw r0, #:lower16:Str
movt r0, #:upper16:Str
ldr r1, [fp, #12] // r1 = fromPeg
ldr r2, [fp, #16] // r2 = toPeg
bl printf
|
How to run the program:
|
Sample output: (4 disks)
Move a disk from peg 1 to peg 2 Move a disk from peg 1 to peg 3 Move a disk from peg 2 to peg 3 Move a disk from peg 1 to peg 2 Move a disk from peg 3 to peg 1 Move a disk from peg 3 to peg 2 Move a disk from peg 1 to peg 2 Move a disk from peg 1 to peg 3 Move a disk from peg 2 to peg 3 Move a disk from peg 2 to peg 1 Move a disk from peg 3 to peg 1 Move a disk from peg 2 to peg 3 Move a disk from peg 1 to peg 2 Move a disk from peg 1 to peg 3 Move a disk from peg 2 to peg 3 |