Understanding 6502 assembly on the Commodore 64 - (18) Status flags NV-BDIZC

     The execution of Instructions in the 6502 is only half of the story.  The 6502 and its machine code is a running example of cause and effect.  We think of machine code as being at such low level that nothing is done without explicitly instructing it, however, the processor is much more dynamic than is initially apparent on the surface.








     This is our Segway into processor status flags.   In the last chapter, we ended just before discussing the status flags. It would have been an injustice to make this a sub topic, as this demands our full attention.  Its a lot easier at first to believe that our instructions are as straight forward as they appear.


LDA #$55  ;LOAD HEX 55 into the Accumulator


     While its true, this instruction did in fact load $55 into A, that's not all it did.  Different OPCODES have different affects on status flags.   Some may have no affect, some may affect just one, some two or more.

     The good news is there is no secret as to which flags are affected.  As a matter of fact, it is well documented.  Furthermore, it is no accident as to why particular flags are affected by the OPCODES. Reading on the internet for information about 6502 can be difficult on the eyes.  While I prefer books, I don't always reach for one to check up on my work.   One site that is particularly well laid out is:

https://sites.google.com/site/6502asembly/6502-instruction-set

     The content, I find, to be well formatted and easy to read.   Generally, for the purpose of displaying affected status flags we will see the following conventions used:

LDA      NV-BIZC
                     + - - - - + -
or 

LDA      N,Z

     Basically stated, LDA has a direct effect on flags N and Z


Good,   now that the notation is established, what do these flags mean?????   Lets start with the easiest!!!!


FLAG - (BIT 5)  :  Nope, this isn't a flag, and doesn't do anything of any great use on the 6502 you will generally find it ON (1) and is of no great consequence. Moving on.......

Too Easy!!!!!!   7 to go!!!  The next 4 flags we will discuss are ZCN and V




FLAG Z (BIT 1) :  

     DEFINITION: Should the last operation you conducted, produce a ZERO as a result of that operation, then the ZERO flag becomes set (1).  Inversely, should the last operation you conducted not produce a ZERO, the flag is unset (0).   Yes, I realize the non zero value is zero and the zero value is 1, but were talking about the ZERO flag and not its flag value

Lets display the operation, in context:

LDA #$55   ;Doesn't produce a ZERO, ZERO flag is not set (0)
LDX #$08   ;Doesn't produce a ZERO, ZERO flag is not set (0)
LDY #$00   ;Does produce a ZERO, ZERO flag is set (1)

Ok, that seems rather obvious... watch further, in this next example...

LDX #$01   ;Doesn't produce a ZERO, ZERO flag is not set (0)
DEX        ;Does produce a ZERO, ZERO flag is set (1)
INX        ;Doesn't produce a ZERO, ZERO flag is not set (0)

Or maybe a overflow...

LDX #$FF   ;Doesn't produce a ZERO, ZERO flag is not set (0)
INX        ;Does produce a ZERO, ZERO flag is set (1)
DEX        ;Doesn't produce a ZERO, ZERO flag is not set (0)


     Incidentally, If you checked the listing and search for opcodes LDA, LDX, LDY, INX, DEX, INY, DEY, they all list as affecting the Z flag, amongst other things.  As a matter of fact, any manipulative operation that changes the value stored in A,X and Y, are going to effect the Z flag.   This is a very busy and quite useful flag.  We have relied upon it quite heavily in the last 17 chapters, though the reason, not so obvious until now.

Try this example........

LDA #$07   ;Doesn't produce a ZERO, ZERO flag is not set (0)
CMP #$07   ;Does produce a ZERO, ZERO flag is set (1)
LDA #$33   ;Doesn't produce a ZERO, ZERO flag is not set (0)
CMP #$07   ;Doesn't produce a ZERO, ZERO flag is not set (0)

     Wait. What????  What does compare have to do with ZERO?  The better question would be what does the processor do to compare two numbers?  Well, if you subtract the $07 in A with the $07 in CMP and you get zero as the value, then they must be EQUAL.  If you get any other number, then they must be NOT EQUAL.


Suppose I would like to test a number and branch if it is equal.......

START:
LDA #$07       ;Doesn't produce a ZERO, ZERO flag is not set (0)
CMP #$07       ;Does produce a ZERO, ZERO flag is set (1)
BEQ LALALAND   ;If the Z flag is set to 1 Branch to LALALAND
JMP START

LALALAND:
rts

     BEQ could care less about whats in A, or the value in CMP, it only cares about the ZERO flag, produced by our comparison CMP.

     Suppose for a minute we simply wanted to test the "ZERONESS" or "NON ZERONESS" of A, we could forgo a comparison altogether because LDA set the flag to 1 of zero and 0 if not zero for us.........

START:
LDA #$07      ;Doesn't produce a ZERO, ZERO flag is not set (0)
BEQ LALALAND  ;If the Z flag is set to 1 Branch to LALALAND
JMP START

LALALAND:
rts

No trips to LALALAND here....... because A did not produce a zero flag. How about:

START:
LDA #$00       ;Does produce a ZERO, ZERO flag is set (1)
BEQ LALALAND   ;If the Z flag is set to 1 Branch to LALALAND
JMP START

LALALAND:
rts

As you can see, testing for ZERONESS and NON-ZERONESS saves us processor cycles as well as a few bytes of memory.  Consider BNE will do the same thing for us inversely.

START:
LDA #$00       ;Does produce a ZERO, ZERO flag is set (1)
BNE LALALAND   ;If the Z flag is set to 0 Branch to LALALAND
JMP START

LALALAND:
rts

     BNE and BEQ as you can see, rely upon the Z flag to conduct their business.  They evaluate whether to branch or not based on the status of Z.  What they don't do is manipulate any data, just control flow.  That being said, BNE and BEQ do not affect any FLAGS themselves, they are benign.





FLAG N (BIT 7) :  

     DEFINITION: Should the last operation you did, produce a 1 (ONE) in the 7th bit (the High BIT) as a result of that operation then the N (NEGATIVE) flag becomes set (1).  Inversely, should the last operation you did not produce a 1 (ONE), the flag is unset (0).


     Once again, at the surface, very easy to understand.  Looking at out last execution of code we can see the predictable outcome of this flag.


LDA #$55   ;01010101, NEGATIVE flag is not set (0)
LDX #$08   ;00001000, NEGATIVE flag is not set (0)
LDX #$E8   ;11101000, NEGATIVE flag is set (1)


Or Perhaps:

LDX #$7F   ;01111111, NEGATIVE flag is not set (0)
INX        ;10000000, NEGATIVE flag is set (1)
DEX        ;01111111, NEGATIVE flag is not set (0)


Or maybe an overflow:

LDX #$FF   ;11111111, NEGATIVE flag is set (1)
INX        ;00000000, NEGATIVE flag is not set (0)
DEX        ;11111111, NEGATIVE flag is set (1)



Just like our ZERO flag, which can also be evaluated and acted upon with BNE and BEQ, the NEGATIVE flag is acted upon with BMI (BRANCH MINUS) and BPL (BRANCH PLUS)


START:
LDA #$00       ;00000000, NEGATIVE flag is not set (0)
BMI LALALAND   ;If the N flag is set to 1 Branch to LALALAND
JMP START

LALALAND:
rts


Nope, In this scenario, our branch not was executed, having the flag set to 0.  Though it could have been using BPL

START:
LDA #$00       ;00000000, NEGATIVE flag is not set (0)
BPL LALALAND   ;If the N flag is set to 0 Branch to LALALAND
JMP START

LALALAND:
rts 

Here we will branch off because the branch condition is 0. Inversely:

START:
LDA #$80       ;10000000, NEGATIVE flag is set (1)
BPL LALALAND   ;If the N flag is set to 0 Branch to LALALAND
JMP START

LALALAND:
rts 

Having been set to 1 there will be no branch.  


     The value in this feature has not been explained yet.  We haven't done any code which takes advantage of this flag nor its branching conditions.  It has been avoided thus far and its use will be explained later.  You must only understand what the flag is and how it gets set and unset for the time being.  Also look at the explanation of the BIT opcode further down in this chapter.




FLAG C (BIT 0) :  

     The C flag, unlike Z and N is affected by a more specific set of operations, it is more of a math centric flag than the aforementioned data manipulation flags.  Its function though, as with the others can be clearly defined.

DEFINITION: In an arithmetic operation, should the operation show that the value was comparatively greater than or equal to the value compared. then the C (CARRY) flag becomes set (1).  Inversely, should the last operation you did be less than the value compared, the flag becomes unset (0).

     The C flag is also different in that it has two dedicated OPCODES to turn the flag ON and OFF

SEC - SEt Carry     : Turns the flag on (1)
CLC - CLear Carry: Turns the flag off (0)



SEC        ; We turned on the Carry flag set (1)
CLC        ; We turned off the Carry flag set (0)
LDA #$55   ; Does not affect the C flag
CMP #$08   ; $55 is greater than $08 Carry flag (1)
CMP #$54   ; $55 is greater than $54 Carry flag (1)
CMP #$55   ; $55 equal to or greater than $55 Carry flag (1)
CMP $E0    ; $55 less than $E0 Carry flag (0)


A bit more comprehensive:

CLC        ; We turned off the Carry flag set (0)
LDX #$55   ; Does not affect the C flag
CPX #$56   ; $55 is less than $56, Carry flag (0)
INX        ; X=X+1 Does not affect the C flag
CPX #$56   ; $56 is Equal to $56, Carry flag set (1)


 Like our other functions, the Carry flag has its own branching instructions

BCS - Branch if Carry Set
BCC - Branch if Carry Clear


In this example we would not be branching off, because the Carry flag is set to 0

START:
CLC            ; We turned off the Carry flag set (0)
LDA #$55       LDA #$55   ; Does not affect the C flag
CMP #$56       ; $55 is less than $56, Carry flag (0)
BCS LALALAND   ;If the C flag is set to 1 Branch to LALALAND
JMP START

LALALAND:
rts


In this example we would be branching off, because the Carry flag is set to 0

START:
CLC            ; We turned off the Carry flag set (0)
LDA #$55       LDA #$55   ; Does not affect the C flag
CMP #$56       ; $55 is less than $56, Carry flag (0)
BCC LALALAND   ;If the C flag is set to 0 Branch to LALALAND
JMP START

LALALAND:
rts


     There are more math and compare functions that benefit from this flag, and they will be discussed in future chapters, notably addition and subtraction. While we have used this briefly in previous code we have not discussed its purposes.  It has been avoided thus far and its use will be explained later.  You must only understand what the flag is and how it gets set and unset for the time being.




FLAG V (BIT 6) :  


     The V (OVERFLOW) flag, like the C flag is affected by a more specific set of operations, it is more of a math centric flag Affected by Adding and Subtracting signed numbers.  It is one of the lesser used flags. Its function though, as with the others can also be clearly defined.  We will see that the definition of the V flag is almost exactly the same as N, with one great exception


    DEFINITION: Should the last operation you did with ADC, SBC, or BIT, produce a 1 (ONE) in the 6th bit (the 2nd Highest BIT) as a result of that operation then the V (OVERFLOW) flag becomes set (1).  Inversely, should the operation you did with ADC, SBC, BIT not produce a 1 (ONE), the flag is unset (0).

     The V flag, like the C flag, has two dedicated OPCODES to turn the flag ON and OFF

BVS - Branch oVerflow Set      : Turns the flag on (1)
CLV - Clear oVerflow               : Turns the flag off (0)

We can see that this is highly specialized, disregarding the OPCODES that turn it on and off there are only 3 OPCODES that affect its function.  ADC, SBC, BIT.  I can't get into ADC, and SBC right now. This would open up a whole can of worms that we do not yet want to deal with.  I can however discuss BIT without getting us into any trouble.

BIT - BIt Test:   BIT only works on the value in memory.  The value will have a direct affect on both the N and V flags.  BIT is a highly specialized function, but makes a great example.


LDA #$55   ;01010101
STA $0400 
BIT $0400  ; Sets N to 0 and V to 1
LDA #$00   ;00000000
STA $0400
BIT $0400  ; Sets N to 0 and V to 0
LDA #$E8   ;11101000
STA $0400
BIT $0400  ; Sets N to 1 and V to 1


This is about as far as we can go into V without getting into all sorts of math related topics. Our last remaining status flags I,B, and D fall into a different category and can be very easily explained.



FLAG I (BIT 2) :

  
   The I (Interrupt Disable) flag is directly set and unset with two OPCODES, SEI and CLI.  BRK can also cause the Interrupt to bet set (1).


DEFINITION: Should the interrupt request (IRQ) be disabled the flag will be set (1).  Should the interrupt request not be disabled, the flag will be unset (0)


The I flag. like the C and V flag, has two dedicated OPCODES to turn the flag ON and OFF

SEI - SEt Interrupt disable                     : Turns the flag on (1)
CLI - CLear Interrupt disable                : Turns the flag off (0)


     Interrupts are their own separate topic, you should only know that the Value if V shows weather interrupt requests are enabled or disabled.  Note that BRK sets the interrupt flag (1), our next logical choice for discussion is the B flag.




FLAG B (BIT 4) :

     The B flag is the easiest to define and the easiest to explain........

DEFINITION: Should an interrupt occur, was it caused by BRK execution.  If the Interrupt is caused by a BRK then the B flag is set  (1).  If the interrupt flag was not caused by BRK, then B is unset (0).

     You will not see B in the list of FLAGS effected by OPCODES when looking at lists of the 6502 instruction set.  No OPCODE sets or unsets B.  Only the circumstances of an Interrupt.  Note that if an interrupt, or subsequent interrupt occurs, and it was not caused by BRK, the value will be unset (0)


And now, onto our last flag........  The weird one in the bunch.....




FLAG D (BIT 3) :

     In the world of 6502 weirdness comes flag D.  This flag, in and of itself is almost a perversion of the art that is processing numerical values within a computer.  With this flag set we can process numbers as decimals instead of hexadecimal.


DEFINITION: Should D be set,  Addition and subtraction of numbers will be treated as Decimal and not Hexadecimal. 


The D flag. like the C, I and V flag, has two dedicated OPCODES to turn the flag ON and OFF

SED - SEt Decimal                     : Turns the flag on (1)
CLD- CLear Decimal                 : Turns the flag off (0)


     No I can't make this stuff up.  I said we weren't getting into math today, but I can't resist this one. We will employ ADC and SBC, Add with carry, and Subtract with carry to illustrate this.



CLD        ; Decimal mode off
LDA #$07   ; A = $07
ADC #$05   ; Add $05 to it, A is now 0C


Lets start again.......... Decimal Mode!!!!!!!

SED        ; Decimal mode on
LDA #$07   ; A = $07
ADC #$05   ; Add $05 to it, A is now 12



Or perhaps........

CLD        ; Decimal mode off
LDA #$20   ; A = $20
SBC #$05   ; Subtract $05 from it, A is now 1A



And then, perhaps in Decimal Mode!!!!!!!

SED        ; Decimal mode on
LDA #$20   ; A = $20
SBC #$05   ; Subtract $05 from it, A is now 15



     I would not recommend people new to 6502 to use this flag while learning basic maths.  This will only lead to utter confusion.  While this does have its rightful place, perhaps a small incrementing counter to the screen without requiring conversion, it is not necessary for those learning.  You have been warned.




NEXT----->
Understanding 6502 assembly on the Commodore 64 - (19) The Truth of the matter




Table of contents








No comments:

Post a Comment