NCL 105: Keeping Track of More
So far, our programs have used r0 whenever they needed to remember a number.
For example, this loop counts from 1 to 5:
MOVE r0 1
$again
D.TXT r0
D.TXT " "
INC r0
BLE $again r0 5
D.BLT
Throughout the program, r0 has one job: it keeps track of the current number.
But a program often needs to keep track of more than one thing at a time.
Adding the numbers together
Suppose we want to add the numbers from 1 through 5.
The calculation we want is:
1 + 2 + 3 + 4 + 5 = 15
We already know how to make r0 count from 1 through 5.
But we also need somewhere to keep the total as it grows.
If we use r0 for the total, we lose the number we're counting with.
Fortunately, r0 is not the only register available.
We can use another one:
r1
Just like r0, r1 can remember an integer while the program is running.
This lets us give the two registers different jobs:
| Register | Job |
|---|---|
r0 |
Current number |
r1 |
Running total |
We'll begin the current number at 1:
MOVE r0 1
The total starts at 0:
MOVE r1 0
Now we can add the current number to the total:
ADD r1 r1 r0
Remember that the first value after ADD is where the result goes.
If r0 contains 1 and r1 contains 0, this instruction adds:
0 + 1
and stores the result back in r1.
Afterward:
r0 = 1
r1 = 1
Most importantly, r0 has not changed.
We can still use it to control our loop.
Putting it in a loop
Let's combine that with the loop from the previous lesson:
MOVE r0 1
MOVE r1 0
$again
ADD r1 r1 r0
INC r0
BLE $again r0 5
D.TXT r1
D.BLT
There are now two values changing as the program runs.
To understand what the program is doing, we need to keep track of both.
Let's follow it.
The first two instructions give us:
r0 = 1
r1 = 0
Then we reach $again.
The first instruction in the loop:
ADD r1 r1 r0
adds the current number to the running total.
On the first trip through the loop, that means:
0 + 1 = 1
So r1 becomes 1.
Then:
INC r0
changes r0 from 1 to 2.
Finally:
BLE $again r0 5
asks whether 2 is less than or equal to 5.
It is, so the CPU goes back to $again.
This time, ADD adds:
1 + 2 = 3
The total in r1 is now 3, while the current number in r0 is still 2.
The two registers are doing different jobs, and each changes independently.
Tracing more than one register
When a program uses several registers, it can become difficult to keep all of their values in your head.
Instead, we can write down the value of each register after every instruction that changes one.
For our loop:
| Instruction | r0 |
r1 |
|---|---|---|
MOVE r0 1 |
1 | |
MOVE r1 0 |
1 | 0 |
ADD r1 r1 r0 |
1 | 1 |
INC r0 |
2 | 1 |
ADD r1 r1 r0 |
2 | 3 |
INC r0 |
3 | 3 |
ADD r1 r1 r0 |
3 | 6 |
INC r0 |
4 | 6 |
ADD r1 r1 r0 |
4 | 10 |
INC r0 |
5 | 10 |
ADD r1 r1 r0 |
5 | 15 |
INC r0 |
6 | 15 |
After the final INC, r0 contains 6.
The branch:
BLE $again r0 5
asks whether 6 is less than or equal to 5.
It isn't, so the loop ends.
Then:
D.TXT r1
D.BLT
displays:
15
A table like this is a useful way to trace a program when it becomes difficult to follow all of its changing values in your head.
You don't need to remember everything at once. Follow one instruction at a time and update whichever value that instruction changes.
Try changing it
Change the loop so it adds the numbers from 1 through 10.
You only need to change one instruction.
Before running it, follow the first few trips through the loop.
What is in r0?
What is in r1?
When will the loop stop?
You don't need to trace the entire calculation if you already understand the pattern.
Then run the program and see what it displays.
Another register
We can also put the end of the count into a register.
Instead of:
BLE $again r0 10
we could store 10 in another register:
MOVE r2 10
and compare against r2:
BLE $again r0 r2
Our program becomes:
MOVE r0 1
MOVE r1 0
MOVE r2 10
$again
ADD r1 r1 r0
INC r0
BLE $again r0 r2
D.TXT r1
D.BLT
Now the program is keeping track of three different values:
| Register | Job |
|---|---|
r0 |
Current number |
r1 |
Running total |
r2 |
Ending number |
r2 does not change during the loop, but keeping the value there means the program can use it wherever it needs the ending number.
It also shows us something important about the branch:
BLE $again r0 r2
The values being compared do not have to be numbers written directly into the instruction.
Here, the CPU compares the value stored in r0 with the value stored in r2.
Try changing:
MOVE r2 10
to another value.
The rest of the loop does not need to change.
Keeping track of the registers
Our program is still fairly small, but there is a new problem.
Look at this instruction:
ADD r1 r1 r0
If you haven't looked at the program for a while, do you remember what r1 is for?
What about r0?
Or r2?
We can keep reminding ourselves:
| Register | Job |
|---|---|
r0 |
Current number |
r1 |
Running total |
r2 |
Ending number |
But as programs get larger and use more registers, remembering what every numbered register is supposed to contain quickly becomes inconvenient.
We'll solve that problem next.
In NCL 106: Naming Registers, we'll give registers names that describe what they're being used for.