14 Jumps, Branches, and Loops

All the assembler programs in the previous section have been executed instruction by instruction following the sequence specified by the order of the instructions in memory. The jump and branch instructions enable' the flow of control to be altered, making it possible to implement loops.

14.1 Jumps

The JMP instruction is followed by the address of the instruction to be executed next.

JMP Jump 

14.2 Labels

Before using the JMP instruction we need to be able to indicate to the assembler where we want to jump to, and to do this conveniently 'labels' are needed. In the assembler labels are variables of the form AA to ZZ followed by a number (0, 1, 2 ... etc). If you are already familiar with ATOM BASIC you will recognise these as the arrays.

First the labels to be used in an assembler program must be declared in the DIM statement. Note that we still need to declare P(-1) as before, and this must be the last thing declared. For example, to provide space for four labels LL0, LL1, LL2, and LL3 we would declare:

DIM LL(3), P(-1)

Labels used in a program are prefixed by a colon ':' character. For example, enter the following assembler program:

10 DIM LL(3),P(-1)
20 W=#FFF4
30[
40:LL0 LDA @#2A
50:LL1 JSR W
60 JMP LL0
70]
80 END

To execute the program the procedure is slightly different from the previous examples, because space has now been assigned at TOP for the labels. When using labels in an assembler program you should place a label at the start of the program, as with LLO in this example, and LINK to that label. So, in this example, execute the program with:

LINK LL0

The program will output an asterisk, and then jump back to the previous instruction. The program has become stuck in an endless loop! If you know BASIC, compare this program with the BASIC program in section 4.6 that has the same effect.
A flowchart for this program is as follows:

Try pressing ESCAPE. ESCAPE will not work; it only works in BASIC programs, and here we are executing machine code instructions so ESCAPE is no longer checked for. Fortunately there is one means of salvation: press BREAK, and then type OLD to retrieve the original program.

14.3 Flags

The carry flag has already been introduced; it is set or cleared as the result of an ADC instruction. The CPU contains several other flags, which are set or cleared depending on the outcome of certain instructions; this section will introduce another one.

14.3.1 Zero Flag

The zero flag, called Z, is set if the result of the previous operation gave zero, and is cleared otherwise. So, for example:

LDA #80

would set the zero flag if the contents of #80 were zero.

14.4 Conditional Branches

The conditional branches enable the program to act on the outcome of an operation. The branch instructions look at a specified flag, and then either carry on execution if the test was false, or cause a branch to a different address if the test was true. There are 8 different branch instructions, four of which will be introduced here:

BEQ Branch if equal to zero (i.e. Z=1)
BNE Branch if not equal to zero (i.e. Z=0)
BCC Branch if carry-flag clear (i.e. C=0) BCS Branch if carry-flag set (i.e. C=1)

The difference between a 'branch' and a 'jump' is that the jump instruction is three bytes long (op-code and two-byte address) whereas the branch instructions are only two bytes long (op-code and one-byte offset). The difference is automatically looked after by the assembler.

The following simple program will print an exclamation mark if #80 contains zero, and a star if it does not contain zero; the comments in lower-case can be omitted when you enter the program:

10 DIM BB(3),P(-1)
20 W=#FFF4
30[
40:BBO LDA #80
50 BEQ BB1	if zero go to BB1
60 LDA @#2A star
70 JSR W print it
BO RTS	return
90:BB1 LDA @#21 exclamation mark 100 JSR W print it
110 RTS return
120]
130 END

A flowchart for this program is as follows:

  START  
  Look at
location #80
 
     
no is it zero? yes
Print '*'   Print '!’
END   END

Now assemble the program with RUN as usual. You will almost certainly get the message:

OUT OF RANGE:

before the line containing the instruction BEQ BB1, and the offset in the branch instruction will have been set to zero. The message is produced because the label BB1 has not yet been met when the branch instruction referring to it is being assembled; in other words, the assembler program contains a forward reference. Therefore you should assemble the program a second time by typing RUN again. This time the message will not be produced and the correct offset will be calculated for the branch instruction.

Note that whenever a program contains forward references it should be assembled twice before executing the machine code.

Now execute the program by typing:

LINK BB0

for different values in #80, and verify that the behaviour is as specified above.

14.5 X and Y registers

The CPU contains two registers in addition to the accumulator, and these are called the X and Y registers. As with the accumulator, there are instructions to load and store the X and Y registers:

LDX Load X register from memory	X=M
LDY Load Y register from memory	Y=M
STX Store X register to memory	M=X
STY Store Y register to memory	M=Y

However the X and Y registers cannot be used as one of the operands in arithmetic or logical instructions like the accumulator; they have their own special uses, including loop control and indexed addressing.

14.6 Loops in Machine Code

The X and Y registers are particularly useful as the control variables in iterative loops, because of four special instructions which will either increment (add 1 to) or decrement (subtract 1 from) their values:

INX Increment X register	X=X+1
INY Increment Y register	Y=Y+1
DEX Decrement X register	X=X-1
DEY Decrement Y register	Y=Y-1

Note that these instructions do not affect the carry flag, so incrementing #FF will give #00 without changing the carry bit. The zero flag is, however, affected by these instructions, and the following program tests the zero flag to detect when X reaches zero.

14.6.1 Iterative Loop

The iterative loop enables the same set of instructions to be executed a fixed number of times. For example, enter the following program:

10 DIM LL(4),P(-1)
20 W=#FFF4
30[
40:LL0 LDX @8 initialise X
50:LL1 LDA @#2A code for star
60:LL2 JSR W output it
70 DEX	count it
80 BNE LL2 all done?
90 RTS
100 ]
110 END

A flowchart for the program is as follows:

START
X = 8
Print "*"
Subtract 1 from X
no
X = 0?
yes
END

Assemble the program by typing RUN. This program prints out a star, decrements the X register, and then branches back if the result after decrementing the X register is not zero. Consider what value X will have on successive times around the loop and predict how many stars will be printed out; then execute the program with LINK LLO and see if your prediction was correct. If you were wrong, try thinking about the case where X was initially set to 1 instead of 8 in line 40.

How many stars are printed if you change the instruction on line 40 to LDX @0 ?

14.7 Compare

In the previous example the condition X=0 was used to terminate the loop. Sometimes we might want to count up from 0 and terminate on some specified value other than zero. The compare instruction can be used to compare the contents of a register with a value in memory; if the two are the same, the zero flag will be set. If they are not the same, the zero flag will be cleared. The compare instruction also affects the carry flag.

CMP Compare accumulator with memory	A-M
CPX Compare X register with memory	X-M
CPY Compare Y register with memory	Y-M

Note that the compare instruction does not affect its two operands; it just changes the flags as a result of the comparison.

The next example again prints 8 stars, but this time it uses X as a counter to count upwards from 0 to 8:

10 DIM LL(2),P(-1)
20 W=#FFF4
30[
40:LL0 LDX @0 start at zero
50:LL1 LDA @#2A code for star
60 JSR W	output it
70 INX	next X
80 CPX @8	all done?
90 BNE LL1
100 RTS return
110]
120 END

In this program X takes the values 0, 1, 2, 3, 4, 5, 6, and 7. The last time around the loop X is incremented to 8, and the loop terminates. Try drawing a flowchart for this program.

14.8 Using the Control Variable

In the previous two examples X was simply used as a counter, and so it made no difference whether we counted up or down. However, it is often useful to use the value of the control variable in the program. For example, we could print out the character in the X register each time around the loop. We therefore need a way of transferring the value in the X register to the accumulator so that it can be printed out by the OSWRCH routine. One way would be to execute:

STX #82 LDA #82

where #82 is not being used for any other purpose. There is a more convenient way, using one of four new instructions:

TAX Transfer accumulator to X register	X=A
TAY Transfer accumulator to Y register	Y=A
TXA Transfer X register to accumulator	A=X
TYA Transfer Y register to accumulator	A=Y

Note that the transfer instructions only affect the register being transferred to.
The following example prints out the alphabet by making X cover the range #41, the code for A, to #5A, the code for Z.

10 DIM LL(2),P(-1)
20 W=#FFF4
30[
40:LL0 LDX @#41 start at A
50:LL1 TXA	put it in A
60 JSR W	print it
70 INX	next one
80 CPX @#5B done Z?
90 BNE LL1 if so – continue
100 RTS	else – return
110]
120 END

Modify the program to print the alphabet in reverse order, Z to A.

All these examples could have used Y as the control variable instead of X in exactly the same way.

Next chapter