On this page:
5.5.1 Factorial machine
5.5.2 Fibonacci machine

5.5 Exercise 5.5

5.5.1 Factorial machine
(controller
   (assign continue (label fact-done))
 fact-loop
   (test (op =) (reg n) (const 1))
   (branch (label base-case))
   (save continue)
   (save n)
   (assign n (op -) (reg n) (const 1))
   (assign continue (label after-fact))
   (goto (label fact-loop))
 after-fact
   (restore n)
   (restore continue)
   (assign val (op *) (reg n) (reg val))
   (goto (reg continue))
 base-case
   (assign val (const 1))
   (goto (reg continue))
 fact-done)

After each instruction, if any register values have changed, they all will be shown in a table, like this:

Register

     

Value

n

     

2

The stack will also be shown when it is updated, like this:

Stack value

<end>

(assign continue (label fact-done))

Register

     

Value

n

     

2

continue

     

(label fact-done)

(test (op =) (reg n) (const 1))
(branch (label base-case))

This evaluates to false, so we don’t branch.

(save continue)
(save n)

This adds two values to the stack:

Stack value

2

(label fact-done)

<end>

(assign n (op -) (reg n) (const 1))
(assign continue (label after-fact))
(goto (label fact-loop))

This updates the values of n and continue for the next recursive call, and jumps to the beginning of the loop.

Register

     

Value

n

     

1

continue

     

(label after-fact)

(test (op =) (reg n) (const 1))
(branch (label base-case))

In this case, we do take this branch, moving to the base-case label.

(assign val (const 1))
(goto (reg continue))

Register

     

Value

n

     

1

continue

     

(label after-fact)

val

     

1

At this point, we have first assigned to the val register where the final result will be stored, and will jump to the instruction currently pointed at by the continue register – that is, the after-fact label.

(restore n)
(restore continue)

Register

     

Value

n

     

2

continue

     

(label fact-done)

val

     

1

Stack value

<end>

(assign val (op *) (reg n) (reg val))
(goto (reg continue))

We assign the final val and will presently jump to fact-done, ending the procedure.

Register

     

Value

n

     

2

continue

     

(label fact-done)

val

     

2

5.5.2 Fibonacci machine
(controller
   (assign continue (label fib-done))
 fib-loop
   (test (op <) (reg n) (const 2))
   (branch (label immediate-answer))
   (save continue)
   (assign continue (label afterfib-n-1))
   (save n)
   (assign n (op -) (reg n) (const 1))
   (goto (label fib-loop))
 afterfib-n-1
   (restore n)
   (restore continue)
   (assign n (op -) (reg n) (const 2))
   (save continue)
   (assign continue (label afterfib-n-2))
   (save val)
   (goto (label fib-loop))
 afterfib-n-2
   (assign n (reg val))
   (restore val)
   (restore continue)
   (assign val
           (op +) (reg val) (reg n))
   (goto (reg continue))
 immediate-answer
   (assign val (reg n))
   (goto (reg continue))
 fib-done)

Our register values will start out like this:

Register

     

Value

n

     

3

And our stack is empty:

Stack value

<end>

(assign continue (label fib-done))

Register

     

Value

n

     

3

continue

     

(label fact-done)

(test (op <) (reg n) (const 2))
(branch (label immediate-answer))

This is false, so we don’t branch.

(save continue)

Stack value

(label fib-done)

<end>

(assign continue (label afterfib-n-1))

Register

     

Value

n

     

3

continue

     

(label afterfib-n-1)

(save n)

Stack value

3

(label fib-done)

<end>

(assign n (op -) (reg n) (const 1))
(goto (label fib-loop))

We decrement n and move on to the next loop.

Register

     

Value

n

     

2

continue

     

(label afterfib-n-1)

(test (op <) (reg n) (const 2))
(branch (label immediate-answer))

This is false, so we don’t branch.

(save continue)

Stack value

(label afterfib-n-1)

3

(label fib-done)

<end>

(assign continue (label afterfib-n-1))

This happens to do nothing.

Register

     

Value

n

     

2

continue

     

(label afterfib-n-1)

(save n)

Stack value

2

(label afterfib-n-1)

3

(label fib-done)

<end>

(assign n (op -) (reg n) (const 1))
(goto (label fib-loop))

We decrement n and move on to the next loop.

Register

     

Value

n

     

1

continue

     

(label afterfib-n-1)

(test (op <) (reg n) (const 2))
(branch (label immediate-answer))

This is now true, so we will branch.

(assign val (reg n))
(goto (reg continue))

We write the base case value into the val register and will presently jump to afterfib-n-1.

Register

     

Value

n

     

1

continue

     

(label afterfib-n-1)

val

     

1

(restore n)
(restore continue)

Register

     

Value

n

     

2

continue

     

(label afterfib-n-1)

val

     

1

Stack value

3

(label fib-done)

<end>

(assign n (op -) (reg n) (const 2))

Register

     

Value

n

     

0

continue

     

(label afterfib-n-1)

val

     

1

(save continue)

Stack value

(label afterfib-n-1)

3

(label fib-done)

<end>

(assign continue (label afterfib-n-2))

We prepare to jump into the other recursive branch for the first time.

Register

     

Value

n

     

0

continue

     

(label afterfib-n-2)

val

     

1

(save val)
(goto (label fib-loop))

We also save the value of Fib(1) – we’re going to need it later.

Stack value

1

(label afterfib-n-1)

3

(label fib-done)

<end>

After this, we will begin looping again.

(test (op <) (reg n) (const 2))
(branch (label immediate-answer))

This is true, so we branch.

(assign val (reg n))
(goto (reg continue))

We write the base case value into the val register (overwriting the value that we saved to the stack earlier) and will presently jump to afterfib-n-1.

Register

     

Value

n

     

0

continue

     

(label afterfib-n-2)

val

     

0

(assign n (reg val))

This happens to do nothing.

Register

     

Value

n

     

0

continue

     

(label afterfib-n-2)

val

     

0

(restore val)
(restore continue)

Register

     

Value

n

     

0

continue

     

(label afterfib-n-1)

val

     

1

Stack value

3

(label fib-done)

<end>

(assign val (op +) (reg val) (reg n))
(goto (reg continue))

This also happens to do nothing. After this, we will jump to afterfib-n-1 for another recursive go-around.

Register

     

Value

n

     

0

continue

     

(label afterfib-n-1)

val

     

1

(restore n)
(restore continue)

Register

     

Value

n

     

3

continue

     

(label fib-done)

val

     

1

Stack value

<end>

(assign n (op -) (reg n) (const 2))

Register

     

Value

n

     

1

continue

     

(label fib-done)

val

     

1

(save continue)

Notice how we have popped this label off of the stack and immediately put it back.

Stack value

(label fact-done)

<end>

(assign continue (label afterfib-n-2))

Register

     

Value

n

     

1

continue

     

(label afterfib-n-2)

val

     

1

(save val)
(goto (label fib-loop))

Stack value

1

(label fact-done)

<end>

(test (op <) (reg n) (const 2))
(branch (label immediate-answer))

This is true, so we will branch.

(assign val (reg n))
(goto (reg continue))

This happens to do nothing.

Register

     

Value

n

     

1

continue

     

(label afterfib-n-2)

val

     

1

(assign n (reg val))

This happens to do nothing.

Register

     

Value

n

     

1

continue

     

(label afterfib-n-2)

val

     

1

(restore val)
(restore continue)

Register

     

Value

n

     

1

continue

     

(label fact-done)

val

     

1

Stack value

<end>

(assign val (op +) (reg val) (reg n))
(goto (reg continue))

With this final addition, we reach our final answer and exit the procedure.

Register

     

Value

n

     

1

continue

     

(label fact-done)

val

     

2