Welcome

Tuesday, January 28, 2020

Branching and Comparisons

Branching and comparison operations


Branching is one of those topics which seems to confuse most people when it comes to very low level programming, which is probably because it is based on the condition of the status register rather than what you are wanting to compare.

The status register is an 8bit register and sets bits on or off according the result of the running commands.

For branch comparison we need only look at 4 of these:

C - Carry flag set if the result of an arithmetic operation exceeds 8bit
Z - Zero flag set if the result of an operation  is zero
V - Over flow set if an overflow condition is set
N - Negative set if a value result in a negative value, I'll go more into how numbers can be negative later.

The flag registers are set when the CPU runs an instruction and, depending on the instruction and the result, the appropriate flag or flags are set. I'm not going to go into which instructions set which flag, many other people have already produced tables of these operations and the one I use on a daily basis is http://www.obelisk.me.uk/6502/reference.html#SBC

Branch instructions test the status of these flags and act accordingly and can be thought of in pairs. The first instruct will test if the flag is set, the other will check if its clear.


  • Carry flag
    • BCS - Branch if carry set
    • BCC - Branch if carry clear
  • Zero flag
    • BEQ - Branch if zero is set
    • BNE - Branch if zero is clear
  • Negative flag
    • BMI - Branch if minus is set 
    • BPL - Branch if minus clear
  • Overflow flag
    • BVS - Branch if overflow is set
    • BVC - Branch if overflow is clear
     

The most common use of branching instructions is after a comparison operation, your basic IF THEN type of construct.

for example

IF a = 5 THEN GOTO LABLE

There are comparison functions for the A, X and Y registers but for these examples I'll stick to using A Conf consistency.

lda #5 // set the value in A
cmp #5 // compare a to 5
beq someLable // branch

This looks pretty straight forward, we load a value into the A register, compare it to 5 and if they are equal we branch.

However, that's not actually what is being done here.

5 is loaded into the A register.

The compare instruction then subtracts its value from the accumulate, in this example 5 - 5  = 0, so the compare instruct sets to zero bit in the status register.

The branch instruct then looks at the status register, checks the status is the zero flag and then if the zero flag is set it performs the branch.

At no point does the branch instruction have any knowledge of what the value in A is, its just looking at the zero flag.

In the above example we can test if A is not equal to 5 by replacing the beq instruction with the bne.

Using the code above the following flags are set


  • IF A >= value 
    • Carry flag is set
  • IF A < value
    • Negative flag is set
  • If A = value
    • Zero flag is set

You will see that there is no single condition for <= but this can still tested it just need to be done in two stages by testing the negative flag then the  zero flag.

lda #5
cmp #10.     
bmi lessThanOrEqual.                       // if the negative flag set its <
beq lessThanOrEqual                        // it the zero flag is set it =

Its not only the CMP instructions that can set the flags though, when a value is loaded into a register the zero and negative flags will be set accordingly.

lda #0
beq label

The above will branch because the lda #0 instruction will set the zero flag, again its because the instruction sets the flag that we can branch, not because of the content of the A register. I know I'm really pushing the point here but it’s important to get into that mindset when working with assembler code.

Other instructions that will set flag are the INX/DEX instructions which will set the negative and zero flags when appropriate, this is useful if you have a loop that counts down for example you don't need to CPX:



ldx #10
loop:
// some code
dex
bne loop

Here to loop counter X is decreased and the code loops until X is zero, we don't need to perform a CPX #0 because the zero flag is set by the DEX instruction. This is why its important to think in terms of flags.







2 comments:

  1. Here is a single condition that test for <=
    If it ain't Greater Than, must be Less Than Or Equal

    lda #83 ; load a heart in Accumulator
    sta 1024 ; print heart to screen memory location 1

    ldx #200
    cpx #73 ; <---- 72 or lower no longer works!
    bpl LESEQUAL ; Branch if plus

    GRTR
    lda #0 ; load black
    sta 55296 ; set color of screen mem 1
    rts

    LESEQUAL
    lda #1 ; load white
    sta 55296 ; set color of screen mem 1
    rts

    ReplyDelete
  2. Whoops sorry, got the labels backwards. I was doing some tweeking to the code to experiment. But you get the idea. Observe however that BPL no longer works correctly if the difference between the two values is greater than 128

    ReplyDelete

Setting up Mega65 Connect for LAN

The latest Mega65 Core (0.96) now supports remote access from the  M65Connect using Jtag and now ethernet. This guide will explain how to se...