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 = 4This 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 hanoiNow 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 |