Section
06 Part 02 – The CMP, TST & BTST Instructions |
“What
lies behind you and what lies in front of you, pales in comparison to what
lies inside of you.” ~Ralph Waldo Emerson |
Introduction
These
instructions test the destination operand for certain conditions, and set the CCR flags accordingly. The destination operand in these cases remains unchanged though.
The CMP
Instruction
CMP - CoMPare
The source operand is subtracted from the destination operand to get the CCR
conditions. The destination operand is not changed however.
Examples
You’ve
seen CMP used before in the previous part:
cmpi.w #$0F20,d0 |
We’ll
pretend that d0 contains FF940F21. Since the instruction is .w for word, only
the 0F21 is compared with. The way the CMP instruction gets its results
is by subtracting the source from the destination, but without saving the result.
So 0F21 – 0F20 = 0001.
Now,
it sets the flags:
After
this instruction d0 will still contain FF940F21, but now the CCR flags are
set, and can be used.
Once
again, you’ll notice in the example the CMP instruction had “i” for immediate, ensure you use “i”
for immediate values (though once again, your assembler make take care of
this for you).
You
can compare using byte, word or long-word sizes. The CMP instruction is capable of comparing
between; data registers, address registers, memory addresses, memory using
address registers, just to list the most common here. It should be noted that address registers can
not be compared using byte.
The TST
Instruction
TST – TeST
an operand
The destination operand is compared with zero to get
the CCR conditions. The destination operand remains unchanged.
Examples
Here’s
the instruction:
tst.w d0 |
Now
this here is pretty much the same as:
cmpi.w #$0000,d0 |
The
same flags are changed for the same reasons.
Except obviously, the V and C flags will always end up being cleared
here.
This
instruction is smaller and quicker than using the CMP instruction, so in cases
where you need to check for zero. It is
recommended to use the TST instruction for optimal reasons.
The BTST
Instruction
BTST – TeST
a Bit
This
instruction will test the bit number in the destination operand decided by the source operand. The result is saved
to the Z flag.
Examples
If
you remember back in Section 03 Part 05 we looked at BSET, BCLR and BCHG.
This instruction works in the
same way, the source
operand and destination operand are restricted in the same
way (i.e. the source can only be an immediate
value or a data register, data registers are long-word operated while other
modes are byte operated, etc).
The
difference here is the bit number is not changed, instead it is simply tested
to see if it is set (1) or clear (0):
btst.l #$03,d0 |
In
this example, bit 03 in data register d0 is checked. We’ll pretend that d0 contains 7FF290F5, in binary that’s:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
1F |
1E |
1D |
1C |
1B |
1A |
19 |
18 |
17 |
16 |
15 |
14 |
13 |
12 |
11 |
10 |
0F |
0E |
0D |
0C |
0B |
0A |
09 |
08 |
07 |
06 |
05 |
04 |
03 |
02 |
01 |
00 |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
As
you can see, bit 03 is clear (0), and since it’s zero, the Z flag of the CCR is set.
Here’s
another:
btst.l #$11,d0 |
Again,
d0 contains 7FF290F5:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
1F |
1E |
1D |
1C |
1B |
1A |
19 |
18 |
17 |
16 |
15 |
14 |
13 |
12 |
11 |
10 |
0F |
0E |
0D |
0C |
0B |
0A |
09 |
08 |
07 |
06 |
05 |
04 |
03 |
02 |
01 |
00 |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
Here,
bit 11 is set (1), and since it is not zero, the Z flag of the CCR is cleared.
Summary
These
instructions are used to set the CCR flags when needed; you’ll often be using
them with a condition
branch instruction
(e.g. the BEQ instruction). Though it is
important to note that the 68k is quite a unique architecture, being orthogonal,
many instructions will set, clear, or change the CCR flags anyway. For example:
add.b d1,d0 tst.b d0 beq.s ValueIsZero |
In
this case, a byte of d1
is added to a byte of d0. d0 is then checked to see if it
is zero. The BEQ instruction will then
branch to the lable ValueIsZero if the result is zero, if it
is not, it’ll continue.
The
thing is, the ADD instruction sets the CCR Z flag anyway. So you could remove that TST instruction and
leave only the ADD and the BEQ:
add.b d1,d0 beq.s ValueIsZero |
And
it’ll function just the same, except now you’re using
less instructions, it’s smaller, and slightly faster.