We will often define a machine to include ``primitive'' operations that are
actually very complex. For example, in sections
and
we will treat Scheme's environment
manipulations as primitive. Such abstraction is valuable because it
allows us to ignore the details of parts of a machine so that we can
concentrate on other aspects of the design. The fact that we have
swept a lot of complexity under the rug, however, does not mean that a
machine design is unrealistic. We can always replace the complex
``primitives'' by simpler primitive operations.
Consider the GCD machine. The machine has an instruction that computes the remainder of the contents of registers a and b and assigns the result to register t. If we want to construct the GCD machine without using a primitive remainder operation, we must specify how to compute remainders in terms of simpler operations, such as subtraction. Indeed, we can write a Scheme procedure that finds remainders in this way:
(define (remainder n d)
(if (< n d)
n
(remainder (- n d) d)))
We can thus replace the remainder operation in the GCD machine's
data paths with a subtraction operation and a comparison test.
Figure
shows the data paths and controller
for the elaborated machine.
The instruction
(assign t (op rem) (reg a) (reg b))in the GCD controller definition is replaced by a sequence of instructions that contains a loop, as shown in figure
.
Exercise.
Design a machine to compute square roots using Newton's method, as
described in section
:
(define (sqrt x)
(define (good-enough? guess)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess)
(average guess (/ x guess)))
(define (sqrt-iter guess)
(if (good-enough? guess)
guess
(sqrt-iter (improve guess))))
(sqrt-iter 1.0))
Begin by assuming that good-enough? and improve operations
are available as primitives. Then show how to expand these in terms
of arithmetic operations. Describe each version of the sqrt
machine design by drawing a data-path diagram and writing a controller
definition in the register-machine language.