Section 06
Part 01 – The CCR (Conditional Code Register) |
“Never make friends with people who are above or below you in
status. Such friendships will never give you any happiness.” ~Chanakya |
Introduction
Most
(If not all) processors have some form of CCR (Conditional Code Register) to
keep track of conditions. These
conditions may help determine things like; “Was the byte changed to 00?”, “Is
the word now signed negative?”, “Is this byte higher or lower than another
byte?”.
The
purpose of the CCR is to allow you to get the CPU to perform a different action
under certain conditions.
Brief
Example
We’ll
have a brief example here using two new instructions, just so you better
understand the purpose:
cmp.b #$20,d0 beq.s ValueIs20 move.b d0,d1 ValueIs20: |
The
two instructions here are CMP
and BEQ. CMP
is CoMPare, which in this example will compare the byte 20 with the byte that is in d0.
The
next instruction BEQ is Branch on Equal, if the result of our CMP is
Zero (Equal), then the 68k will branch to the lable “ValueIs20:” and will continue from
there. If the result of out CMP is
Non-Zero (Not Equal), then the 68k will simply continue to the next instruction
“move.b d0,d1”, it will not branch.
These
new instructions will be explained more thoroughly in due time. The point is, you understand how the 68k can
branch off and read other instructions if a byte, word or long-word does not
meet the right conditions.
The flags
The
CCR itself is a byte big, in binary that gives you:
CCR – In binary |
|||||||
|
|||||||
- |
- |
- |
X |
N |
Z |
V |
C |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
As
you can see, the 68k has 5 conditional flags:
Most
instructions of the 68k might set (1), clear (0), reversed, or leave these
flags untouched. Depending
on the result.
Carry
Let’s
say for example, we add a byte to a register:
addi.b #$04,d0 |
Now,
we’ll pretend that d0 contains 000000FE for this example. So you should know by now, FE + 04 = 102, you
should also know that only the 02 is saved into d0, making d0 00000002. The 1 on the end of 102 (in binary 0001) is saved into the carry
flag, because it cannot fit into the byte, it is therefore “carried over”. The carry flag is set.
If d0
contained 00000090 instead, 90 + 04 = 94, d0 now contains 00000094, and the
“carried over” value is 0 (0000). The carry flag is cleared.
The
same applies to using instructions such as LSR, for shifting right. Any bit that gets shifted out of the
register/memory space, is carried over into the carry
flag.
Overflow
Imagine
for a moment that d0 contains 0000007D:
addi.b #$04,d0 |
After
this d0 will contain 00000081, now, if you treat the byte as signed, 7D is positive, while 81 is negative.
This change from positive to negative will set the overflow.
The
idea is, 7D + 04 = 0081, Positive + Positive =
Positive.
But
since only a byte of 0081
is saved, that means the answer is 81, it
is not negative, which makes no sense from a mathematical point of view. You can’t have Positive + Positive =
Negative. So, the overflow flag is set.
The
same will apply if Negative + Negative = Positive.
Zero
This
is the simplest of them all, we’ll pretend that d0
contains 0024000C:
subi.b #$0C,d0 |
After
this d0 will contain 00240000,
0C – 0C = 00. Because the byte is zero, the Zero flag is
set. If the byte were not zero, then the
Zero flag would be cleared.
Negative
This
one is quite simple too, we’ll imagine that d0
contains 00049044:
addi.w #$0100,d0 |
9044 + 0100 = 9144.
The
word in d0 is negative, so the Negative flag is set. If the result were positive, the Negative
flag would be cleared.
Extended
This
is the same as the carry flag; it will be set or cleared depending on the value
that is “carried over”.
However,
not all instructions that change the carry flag will change the extended
flag. The idea is that you can have an
instruction that will change the conditions of both C and X, and then later
have an instruction that will change the condition of the C flag, but leaving
the X flag alone un-tampered with.
Debriefing
Here’s
another set of instructions including the BEQ instruction:
addi.b #$20,d0 beq.s ValueIsNull move.b d0,d1 ValueIsNull: |
Now,
we’ll pretend that d0 contains 0048F0F0.
The ADD instruction adds byte 20 to d0, so 20 + F0 = 110. Of course, only the 10 is saved, so now d0
contains 0048F010.
Now,
the CCR is dealt with, so first the C and X flags. They are both set here because 110 is too big to fit into a byte, so the 1 on the end (in
binary 0001) is saved into the C and X.
Next,
the Z flag, since the resulting byte is 10, that is
not zero, therefore the Z flag is cleared.
Next,
the V flag, since the equation is positive + negative = positive (20 + F0 = 10),
it is perfectly valid, therefore the V flag is
cleared.
Finally,
the N flag, since the resulting byte is 10,
which is a positive byte, the N flag is cleared for not being negative.
CCR – In binary |
|||||||
|
|||||||
- |
- |
- |
X |
N |
Z |
V |
C |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
So
that’s the CCR sorted. The next
instruction “beq.s ValueIsNull” Branch on Equal, this will
check the Z flag. Is the Z flag
set? No, so the result is non-zero (Not
equal). And so, the 68k will not branch,
and instead will continue to the “move.b d0,d1” instruction.
Reference
Since
all instructions set/clear/change different flags for different reasons, you
must NOT rely on the above
debriefing as an example for all situations.
I strongly suggest picking up a 68k quick reference manual from
somewhere (you can find them easily online).
It will tell you which instructions will set/clear which CCR flags.