NCL 103: Changing the Path
So far, every program we've written has followed the same path.
The NCS/e starts at the first instruction, executes it, moves to the next instruction, and continues downward until there are no more instructions.
For example:
MOVE r0 5
INC r0
MUL r0 r0 2
D.TXT r0
D.BLT
You can follow this program simply by reading from top to bottom.
But what if we want the computer to do something more than once?
Doing something repeatedly
Suppose we want the NCS/e to count down from 5.
We already know enough NCL to do that:
MOVE r0 5
D.TXT r0
D.TXT " "
DEC r0
D.TXT r0
D.TXT " "
DEC r0
D.TXT r0
D.TXT " "
DEC r0
D.TXT r0
D.TXT " "
DEC r0
D.TXT r0
D.BLT
This works.
The program displays:
5 4 3 2 1
Follow what happens to r0.
It begins at 5.
We display it, subtract 1, display the new value, subtract 1 again, and continue until we reach 1.
But this is rather tedious.
We're doing the same things over and over:
D.TXT r0
D.TXT " "
DEC r0
If we wanted to count down from 100, we could keep copying those instructions.
We could.
Let's not.
Going back
Instead of writing the same instructions repeatedly, we can tell the CPU to execute the same instructions repeatedly.
MOVE r0 5
D.TXT r0
D.TXT " "
DEC r0
BGT 2 r0 0
D.BLT
This program displays the same countdown:
5 4 3 2 1
Most of the program should already be familiar.
The first instruction:
MOVE r0 5
puts 5 into r0.
Then:
D.TXT r0
D.TXT " "
writes the value in r0, followed by a space, to the display buffer.
Next:
DEC r0
subtracts 1 from r0.
The only new instruction is:
BGT 2 r0 0
BGT means branch if greater than.
It compares two values. If the first value is greater than the second, execution continues from the specified location instead of continuing to the next instruction.
Here:
BGT 2 r0 0
means:
If the value in
r0is greater than0, continue execution from line 2.
If r0 is not greater than 0, the branch does not happen. The CPU simply continues with the next instruction as usual.
Following the program
Let's walk through the entire program one instruction at a time.
We begin with:
MOVE r0 5
r0 now contains 5.
Next:
D.TXT r0
writes 5 to the display buffer.
Then:
D.TXT " "
writes a space after it.
Next:
DEC r0
subtracts 1, so r0 now contains 4.
Then we reach:
BGT 2 r0 0
Is 4 greater than 0?
Yes.
Instead of continuing downward to D.BLT, the CPU goes back to line 2.
Line 2 is:
D.TXT r0
This time, r0 contains 4, so 4 is written to the display buffer.
Then a space is written after it.
DEC subtracts 1 again, so r0 now contains 3.
The CPU reaches:
BGT 2 r0 0
again.
Is 3 greater than 0?
Yes.
The CPU goes back to line 2 again.
The same thing happens as r0 changes from 3, to 2, to 1.
Eventually, r0 contains 1.
It is written to the display buffer, followed by a space.
Then:
DEC r0
changes r0 from 1 to 0.
The CPU reaches the branch again:
BGT 2 r0 0
Is 0 greater than 0?
No.
This time, the branch does not happen.
The CPU continues to the next instruction:
D.BLT
which makes everything we've written to the display buffer visible.
There are no more instructions after D.BLT, so the program ends.
Loops
Our program executed some of its instructions more than once.
It started at line 2, worked downward to BGT, and then went back to line 2 as long as r0 was greater than 0.
This repeated part of a program is called a loop.
Notice that not every instruction is inside the loop.
MOVE r0 5
executes only once, before the loop begins.
That's important. If it were inside the loop, it would keep putting 5 back into r0, and our countdown would never finish.
Likewise:
D.BLT
is outside the loop.
The program builds the entire countdown in the display buffer, then makes it visible once the loop has finished.
Try changing it
Change:
MOVE r0 5
to:
MOVE r0 10
Before you run the program, predict what it will display.
Then try changing:
BGT 2 r0 0
to:
BGT 2 r0 5
Walk through the program one instruction at a time.
Each time you reach BGT, ask yourself:
What is in
r0right now?
Then:
Is that value greater than
5?
When will the branch stop happening?
What do you expect the program to display?
Run it and see if you were right.
A problem with line numbers
Our original branch says:
BGT 2 r0 0
This works because line 2 is the beginning of the part we want to repeat.
Suppose we decide to add a heading to our countdown:
MOVE r0 5
D.TXT "Counting: "
D.TXT r0
D.TXT " "
DEC r0
BGT 2 r0 0
D.BLT
The beginning of our loop has moved.
Line 2 is now:
D.TXT "Counting: "
But our branch still goes to line 2.
The program now displays:
Counting: 5 Counting: 4 Counting: 3 Counting: 2 Counting: 1
We can fix it:
BGT 3 r0 0
Now the branch goes to line 3, and the program displays:
Counting: 5 4 3 2 1
But we've discovered a problem.
If we add or remove instructions above the beginning of our loop, its line number can change. Every branch that uses that line number may need to change with it.
There is a better way.
Labels
Instead of referring to a location by its line number, NCL lets us give that location a name.
MOVE r0 5
D.TXT "Counting: "
$again
D.TXT r0
D.TXT " "
DEC r0
BGT $again r0 0
D.BLT
Here:
$again
is a label.
A label gives a location in the program a name. It does not perform an action by itself.
When the CPU reaches $again, execution simply continues with the instruction after it.
We can use that name as the destination of our branch:
BGT $again r0 0
This means:
If the value in
r0is greater than0, continue execution from$again.
Now we no longer need to know which line number contains the beginning of the loop.
We can add instructions above $again without changing the branch:
MOVE r0 5
D.TXT "Counting down: "
D.TXT "Starting at five. "
$again
D.TXT r0
D.TXT " "
DEC r0
BGT $again r0 0
D.BLT
The location of the loop has moved, but:
BGT $again r0 0
does not need to change.
$again still identifies the beginning of the part we want to repeat.
Try it
Start with the labelled version:
MOVE r0 5
D.TXT "Counting: "
$again
D.TXT r0
D.TXT " "
DEC r0
BGT $again r0 0
D.BLT
Change the starting value and predict the result before running it.
Try changing the value used by BGT and follow the program one instruction at a time.
Pay particular attention each time the CPU reaches:
BGT $again r0 0
Ask yourself:
What is in
r0right now?
Then:
Is that value greater than
0?
If it is, go back to $again as you follow the program.
If it isn't, continue downward.
In the next lesson, NCL 104: Choosing a Path, we'll build on branches and loops to make programs follow different paths.