program while;
var x, y : integer;
begin
x := 0;
while x < 5 do
x := (x + 1);
y := 0
end.
b) Let's first hand trace this Pascal program;
note that it just increments
x in a while loop,
and stores the final value
in y; it does not
output anything.
We only have to keep track
of 2 memory
locations: x &
y, but I will also keep track
of the Boolean test, and
I will add a "comment"
column:
x | y | x<5? | comments |
---|---|---|---|
0 | x is initialized to 0 (x := 0) | ||
true | the test is tested; since it's true,
we enter the body of the while loop; |
||
1 | x is incremented (x := x+1) | ||
true | we loop back to the test
it's still true, so we're still in the loop |
||
2 | x := x+1 | ||
true | |||
3 | |||
true | |||
4 | |||
true | |||
5 | |||
false | this time, x is not < 5, so the
test is false, we exit the loop, and go to the next instruction |
||
5 | the final value of x is stored
in y (y := x) |
c) Here's the P88 assembly-language version of
the program created by compiling
the Pascal
program for our P88 simulated
computer:
line label
instruction
=== =====
=========
0
COPY AX, #C0
1
COPY X, AX
2
L0 COPY AX,
X
3
CMP AX, #C1
4
JNB L1
5
COPY AX, X
6
ADD AX, #C2
7
COPY _E0, AX
8
COPY AX, _E0
9
COPY X, AX
10
JMP L0
11
L1 NO-OP
12
COPY AX, X
13
COPY Y, AX
14
#C0 0
15
#C1 5
16
#C2 1
17
_E0 0
18
X 0
19
Y 0
20
#L1 2
21
#L2 11
OK: Take a deep breath, and let's hand-trace this:
We need to keep track of 2 CPU registers: AX & CF,
& we need to keep track of several Memory registers,
some of which will never change their values.
To make it a bit easier (I hope) to follow, I won't
record the registers whose values don't change;
they are #C0, #C1, #C2, #L1, #L2. (Notice, for what
it's worth, that they are all and only the registers
whose names begin with "#"!)
AX | CF | _E0 | X | Y | comments |
---|---|---|---|---|---|
0 | NB | 0 | 0 | 0 | these are the initial values
stored in these registers |
0 | #C0 is copied into AX in
order to make sure that the 0 that is to be stored in X is placed in AX |
||||
0 | the 0 in AX is stored in X;
thus, the first 2 lines of the P88 program correspond to "x := 0" |
||||
0 | we need to compare X to 5,
so we need to put X in AX |
||||
B | we compare AX to the 5
that is stored in #C1; since the 0 in AX < the 5 in #C1, the CMP instruction puts "B" in the CF register |
||||
next, the JNB L1 command
is fetched, but it is not executed, since CF <> NB, so the instruction on the next line, line 5, is fetched |
|||||
this means that we enter
the body of the loop |
|||||
0 | X is stored in AX again,
because we are getting ready to execute the body of the loop, which first requires us to add x+1 |
||||
1 | #C2 (i.e., 1) is added to
the 1 in the AX (which of course just came from X), so we've just done "x+1" |
||||
1 | the sum of x+1 is stored in _E0
temporarily |
||||
1 | the sum, now stored in _E0,
is copied into AX (remember: x := x+1, so after adding 1 to X, we store the new value back into X) |
||||
1 | we store it in X | ||||
we unconditionally jump back to L0;
thus, we begin the loop again. Note that to get to L0, we look up the memory register whose name is "L0", find that it contains 2, put 2 in the IP, and so that becomes the next instruction |
|||||
So as not to bore you
or confuse you I will not trace the rest of the loop. Instead, let's assume that we have just gone through the repetition in which we finally incremented X to be 5. So the next line shows the current content of X: |
|||||
5 | Next, we jump back to L0 | ||||
5 | We copy X into AX | ||||
NB | This time, x is not < 5,
so the CF is set to "NB" |
||||
We next jump on NB to L1
which is instruction 11 |
|||||
It's a "no-op";
i.e., no operation is performed |
|||||
5 | X is copied into AX
to get it ready for storage in Y |
||||
5 | It is stored in Y;
end of program |
e.g.) I/P: 2, 4, 6, -1
These
are converted to: 6, 12, 18
(the -1 is ignored; it's just there to tell
the program when the input is finished)
Then they are added up: 6+12+18=36
In Pascal, this would be:
sum
:= 0;
readln(x);
while x >= 0 do
begin {while x >= 0}
sum := sum + (3 * x);
readln(x)
end; {while x >= 0}
writeln(sum)
You should either type this into Unix, compile it, and
run it, or else handtrace it, to make sure that you
understand how it works and that it does the job.
Here's a P88 version (using the "jump to label start"
technique that I mentioned in lecture), with
comments:
JUMP
START
SUM 0
; this is data
START IN AX
; get the 1st integer
LOOP CMP AX, 0 ; loop
& maintain sum
; (if AX < 0, then CF = B
;
else CF = NB)
JB END ; jump to "end"
if a negative
; integer is input
MUL AX, 3
ADD AX, SUM
COPY SUM, AX
IN AX
; get the next integer
JMP LOOP ; go back to beginning
of
; while loop
END COPY AX, SUM
OUT AX
; print sum
HALT
You should handtrace this to make sure you
understand it!
I/P: 2 integers, call them "small" and "large"
O/P: small+1, small+2, ..., large-1
e.g.) I/P = 3, 7
O/P = 4, 5,
6
e.g.) I/P = 1, 100
O/P = 2, 3,
4, ..., 97, 98, 99
In Pascal:
readln(small);
readln(large);
small := small + 1;
while small < large do
begin {while small < large}
writeln(small);
small := small + 1
end {while small < large}
Strategy (in almost-flowchart form):
input
"small"
|
v
input "large"
|
v
add 1 to small <----------\
|
|
v
|
result < large?--true--> output result
|
| (false)
v
halt
But: the 2nd time through, we don't want to add 1 to
"small"; rather, we want
to add 1 to the current
sum.
Solution: Keep a running total in AX
& use "add 1 to AX":
input
"small"
|
v
input "large"
|
v
AX := small
|
v
AX := AX + 1 <-------------\
|
|
v
|
AX < large? -- true --> output AX
|
| (false)
v
halt
In P88 code:
IN AX
COPY SMALL, AX
IN AX
COPY LARGE, AX
COPY AX, SMALL
increment ADD AX, 1
CMP AX, LARGE
JNB print
JMP end
print OUT AX
JMP increment
end
HALT
Again, make sure you understand this, by handtracing
it. I suggest you try input 3, 7 as above for one
example, and maybe 1,10 as another example.