3

I'm learning Assembly through the "Easy 6502 by skilldrick" website. I have one question. I'm in the part about branching. I wrote the following code:

  LDA #$FA
  ADC #$01
  BCS OverflowOccurred
  LDA #$AA

OverflowOccurred:
  LDA #$99

From what I understood the BCS tell to go to the label OverflowOccurred if the carry flag is set. So in this case A will be $FA + $01 = $FB so the carry flag is not set. So it doesn't go to the label OverflowOccurred and will load the value of $AA into the A register. If I don't put the BRK after the instruction LDA #$AA when I click run the final result of A is $99.

Instead if I put this, the final value is correctly set to $AA:

  LDA #$FA
  ADC #$01
  BCS OverflowOccurred
  LDA #$AA
  BRK
OverflowOccurred:
  LDA #$99

Can someone explain me why? Is a must the BRK? If I don't put it, it executes the label instruction even if BCS doesn't isn't true?

6
  • 3
    Yes, labels in assembly are just markers for address locations, they don't wrap something like a block in a higher level language. You usually need a jump before a label to avoid running into it. Commented Oct 22 at 10:04
  • 2
    In normal code, you would not normally use BRK, but rather another jump to skip the following LDA. Basically, as most instructions execute one after another, BCS skips over the "else" code path; but the "else" code path at its end typically has to skip over the "then" code path. Commented Oct 22 at 10:22
  • 1
    Near-duplicates: What if there is no return statement in a CALLed block of code in assembly programs / Code executes condition wrong? - those are for x86, but they explain labels, and that execution continuing to the next machine-code address unless it executes a branch / jump. That works the same way across all ISAs I'm familiar with. Commented Oct 22 at 10:32
  • Very important: always set (SEC) or clear (CLC) the carry to the desired value before ADC or SBC, or you might get the wrong result. Commented Nov 3 at 15:05
  • @PeterCordes: The only (partial) alternative I can think of is ISAs like early ARM CPUs where nearly every instruction was conditional. Ideal for simple if/then cases like this. It was fun in the 90's. Commented Nov 9 at 2:43

2 Answers 2

6

Labels are a convenience for the programmer so they don't have to calculate the offset for the branch or the absolute address for a jmp. They do not form part of the final assembled program.

Your code is identical to:

  LDA #$FA
  ADC #$01
  BCS 2
  LDA #$AA
  LDA #$99

2 is the offset added to the program counter if the carry flag is set (when the BCS is executed, the program counter already points at the next instruction).

So you can see that after executing LDA #$AA the CPU will then go on to execute LDA #$99. If you insert a BRK your program is equivalent to:

  LDA #$FA
  ADC #$01
  BCS 3
  LDA #$AA
  BRK
  LDA #$99

The offset is now 3 because you now need to jump over the BRK and the LDA.

BRK forces a transfer of control through the interrupt vector. As long as the code there doesn't execute an RTI it will never come back to do the last LDA. In fact, BRK doesn't return to the location following the BRK but skips it. But we can ignore that nuance for now.

Anything that causes the CPU to miss out the LDA #$99 will work, so you might just do this:

  LDA #$FA
  ADC #$01
  BCS OverflowOccurred
  LDA #$AA
  JMP carryOn:

OverflowOccurred:
  LDA #$99

carryOn:
; Rest of your code

This is the assembler version of a high level if ... else ... statement. It's equivalent to the following pseudo code

if not(carry is set)
    a = $aa
else
    a = $99

Other options include setting a "default" value in advance

  LDA #$FA
  ADC #$01
  LDA #$99
  BCS OverflowOccurred
  LDA #$AA
OverflowOccurred:
; Rest of your code

This saves 3 bytes and one of two branches/jumps

Be careful with that one. It works for carry, but if you want to test for negative or non zero, the N and Z flags are affected by LDA.

Or you can save one byte by using a branch instead of a jump

  LDA #$FA
  ADC #$01
  BCS OverflowOccurred
  LDA #$AA
  BNE carryOn:

OverflowOccurred:
  LDA #$99

carryOn:
; Rest of your code

This takes advantage of the fact that you know $AA is not zero.

Sign up to request clarification or add additional context in comments.

3 Comments

Can I say one thing? Even if it is very old it amaze how all works.
Thank you very much for the time you took in order to reply. Really appreciate it. Can't wait to learn more.
Nice edit; I kept it compact since it wasn't my answer, but expanding it and adding 6502-specific details (I forgot about load-immediate setting flags in some ISA!) makes it more readable and much better.
2

High level languages have constructs like if-then, if-then-else, while-do, do-while, and even functions definition, function calling.

Assembly language does not have any of these high level forms directly but they can all be had with an equivalent pattern using assembly's if-goto-label form.

Also in assembly language, labels do not execute or change the flow of control.  Only branch instructions can change the flow of control, so otherwise just sequential execution.  Normal sequential control flow will automatically go right through a label since they don't actually exist in the machine code.

Note that in high level languages, we also have sequential execution, here though of language statements not assembly instructions.

For example, the if-then-else statement may be in a larger context like:

if ( condition ) { <then-part...> } else { <else-part...> }
<some following statement...>

And here no matter whether the then-part or the else-part executes, upon completion of the if-statement we expect the following statement to execute next.


We expect the same from an if-then-else in assembly, that (1) only one of the then-part or else-part executes, and (2) that after the whole if statement is done (whether by running the then-part or the else-part) the next sequential statement after is whats run after.

The pattern for if-then-else such as this:

if ( <condition...> ) {
    <then-part...>
}
else {
    <else-part...>
}

Translated to if-goto-label looks like this:

    if <condition...> is not true goto elsePart;
    <then-part...>
    goto endOfIf; // this skips around the else part to go on to the next 
                  // statement at the same level of and sequentially after the if
elsePart:
    <else-part...>
endOfIf:

Yes, this pattern ends with a label!  But that label is more logically part of the if-then-else translation into if-goto-label, rather than having to do with the code following the if statement.

Let's also note that in this translation pattern, whereas the then-part does need to finish with a goto endOfIf; (because when the then-part executes we must preclude the else-part), yet the else-part does not, since it will fall through the label by sequential execution, and that's where we expect the code for the next sequential statement to be located.  (When the else-part executes, the then-part has already been skipped by the condition's branching.  Thus, only either the then-part or else the else-part will execute.)

For each separate if-statement we have, we need to use its own unique labels for its translation to if-goto-label form.  (Some assembly languages have some features to reduce the number of new labels needed by these patterns.)  However, given that these patterns both nest and follow logically.


There are many possible variation, though the above is common.  We can reverse the order of then and else parts, if we also reverse the condition test (test for true instead of not true).

We can move the then part and the else part far away from each other, and then you might need the goto endOfIf after both the then part and the elsePart (or could eliminate one or the other).

Such is the flexibility of assembly that high level languages don't have (thankfully!).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.