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.