When a
computer must decide between two courses of action, it needs to either continue
running code where it is or change the location of memory where it will start
running the code at the new instruction pointer (IP) address. This was given the term branching. There are
many branching commands that the 6502 contains so it makes sense to have a
special handing function for dealing with it. First, we need to know if the
branch is going to be taken, this is the check which is simply the result of
checking to see if the flag used for determining if we should branch is in the
appropriate state for taking the branch. The offset parameter is simply the
amount to adjust the instruction pointer.
fun processBranch(check:Boolean, offset:Int) {
if (check) {
++state.tick
val adjOff = if (offset > 127)
-( (offset xor 255)+1) else offset
val target = state.ipNext + adjOff
pageBoundsCheck(state.ipNext,
target)
state.ipNext = target
}
}
The zero
flag happens to be handy to use for looping if you are counting down as it is
set when you hit zero. It is also handy if you are incrementing a multiple byte
number as you know when the byte has wrapped so you know it is time to
increment the next byte. BNE takes the branch whenever the last zero-flag
modifying command has a non-zero result while BEQ branches when the last result
set the zero flag. Counting forward will also work if you are using a compare
instruction which sets the zero flag if the comparison matches but the compare
instructions won’t be implemented for a while yet.
The high
order bit (128) is the negative bit and is used when you are dealing with
signed numbers. We will be covering signed numbers next time when we get into
the mathematical operations of the 6502 (adding and subtracting). If you are
dealing with signed numbers or numbers less than 128 then this is handy as you
know that if the negative flag is set then the result of the last action
resulted in a value less than zero while if it is not set then the result is
greater than or equal to zero. This is commonly used in conjunction with the
zero flag checks to give you less than, equal, or greater than.
; operation being checked for here
BMI lessThan
BEQ equals
; code for greater than here
BMI is used
to see if the negative bit is set, while BPL is used to see if the negative bit
is clear.
BEQ – Branch if EQual to zero
Address Mode
|
Decimal OPCode
|
Hexadecimal OpCode
|
Size
|
Cycles
|
Relative
|
240
|
$F0
|
2
|
2-4
|
Flags affected: None
Cycle Notes: If branching will take an additional cycle
(3). If branch crosses page boundaries then an additional cycle will be added
on top of the cycle for branching (4).
Usage: Used to see if the last operation resulted in
a zero result which is a very common test in things such as while loops.
Test Code:
; BEQ test
LDY #1
LDX #1
BEQ done
INY ;
Make y 2 if reached which should be
DEX
BEQ done
DEY ;
Make y 1 (or 0) if reached which fails test!
done: BRK
; expect y = 2
Implementation:
processBranch(state.flags
and ZERO_FLAG == ZERO_FLAG, mem.read(state.ip+1) )
BNE – Branch if Not Equal to zero
Address Mode
|
Decimal OPCode
|
Hexadecimal OpCode
|
Size
|
Cycles
|
Relative
|
208
|
$D0
|
2
|
2-4
|
Flags affected: None
Cycle Notes: If branching will take an additional cycle
(3). If branch crosses page boundaries then an additional cycle will be added
on top of the cycle for branching (4).
Usage: Used to see if last result was not zero. Often
used for looping as by going from high value down to low value you can get the
zero flag set for free saving a comparison instruction and the time and memory
used for that instruction.
Test Code:
; BNE test 5 + 5 using iny and looping
LDX
#5
LDY
#5
add: INY
DEX
BNE
add
BRK
;
expect y=10
Implementation:
processBranch(state.flags
and ZERO_FLAG != ZERO_FLAG, mem.read(state.ip+1) )
BMI – Branch on Minus (negative) result
Address Mode
|
Decimal OPCode
|
Hexadecimal OpCode
|
Size
|
Cycles
|
Relative
|
48
|
$30
|
2
|
2-4
|
Flags affected: None
Cycle Notes: If branching will take an additional cycle
(3). If branch crosses page boundaries then an additional cycle will be added
on top of the cycle for branching (4).
Usage: Check to see if a number is negative (high
order bit set). Useful for comparison operations as this gives you the
equivalent of a register being less than a number (or alternatively if the
number compared is greater than the register)
Test Code:
; BMI -> ABS(-16) the hard way
LDX
#$F0 ; two's complement value for -16
LDY
#0
add: INY
INX
BMI
add ; repeat while X is negative
BRK
;
expect y=16
Implementation:
processBranch(state.flags
and NEGATIVE_FLAG == NEGATIVE_FLAG, mem.read(state.ip+1) )
BPL
Branch on Result Plus
BPL – Branch on result PLus (positive)
Address Mode
|
Decimal OPCode
|
Hexadecimal OpCode
|
Size
|
Cycles
|
Relative
|
16
|
$10
|
2
|
2-4
|
Flags affected: None
Cycle Notes: If branching will take an additional cycle
(3). If branch crosses page boundaries then an additional cycle will be added
on top of the cycle for branching (4).
Usage: Checking to see if a number is 0 or positive
(high order bit not set). Useful for comparison operations as this gives you
the equivalent of the register being greater than or equal to the tested value
(or the tested value being less than or equal to the register)
Test Code:
; BPL - Count to 28 the hard way
LDX
#100
LDY
#0
count: INY
INX
BPL
count ; will count from 100 to 127, quit
when 128 hit
BRK
;
exect y=28
Implementation:
processBranch(state.flags
and NEGATIVE_FLAG != NEGATIVE_FLAG, mem.read(state.ip+1) )