Better Control Flow

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
johnnystarr
Posts: 22
Joined: Thu Dec 27, 2012 8:15 pm

Better Control Flow

Post by johnnystarr »

I am trying to understand control flow in 6502 assembly.

Say I have the following code:

Code: Select all

;  using asm6

ControlFlow:
   lda mem
   cmp #1
   bne @sub_one

   cmp #2
   bne @sub_two

   @sub_one:
     ; sub routine one goes here
     jmp @done ; <-------------- without this jmp, @sub_two will execute

   @sub_two:
    ; sub routine two goes here

   @done:

   rts
Personally, I would love a switch statement or some other control flow structure. The JMP above concerns me as well. It seems like there is a better way to handle multiple cases without this type of spaghetti code.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Re: Better Control Flow

Post by 3gengames »

I do that sometimes. But really, unless they're long, it's easiest to do that, or if you can, branch out of them. You can't avoid them. Now for some projects of mine that have 8 LONG functions where branching out of them don't work, I use a RTS to jump to them and them RTS from them out of the program which I find nice as you can adjust the routines as needed without worrying if you have enough space to jump out of them with.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Better Control Flow

Post by blargg »

When GOTO is your only tool, spaghetti is all you can make.

The JSR/RTS approach mentioned above applied to your code:

Code: Select all

   lda mem
   jsr sub_one_two
   ...
   rts

sub_one_two:
   cmp #1
   bne @sub_one
   cmp #2
   bne @sub_two

   @sub_one:
     ; sub routine one goes here
     rts

   @sub_two:
    ; sub routine two goes here
    rts
I've often made separate routines to improve code organization, even though they were only called once. Unless you can show that they cost too much in ROM space/speed, their organization benefit outweighs their slight cost.

There's discussion of an if macro for ca65 that hides the ugly jmp at the end of the controlled block.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Re: Better Control Flow

Post by 3gengames »

Actually I was talking about the LDA #SUBROUTINELocation-1 PHA, LDA #High, PHA, RTS to call it, and have the main routine jump back in to where it needs to, or RTS since the code ran at the end never changes.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Better Control Flow

Post by Dwedit »

But if you are using a language that doesn't support jump tables or switches, a binary tree of branches wins.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Better Control Flow

Post by thefox »

johnnystarr wrote:

Code: Select all

;  using asm6

ControlFlow:
   lda mem
   cmp #1
   bne @sub_one

   cmp #2
   bne @sub_two

   @sub_one:
     ; sub routine one goes here
     jmp @done ; <-------------- without this jmp, @sub_two will execute

   @sub_two:
    ; sub routine two goes here

   @done:

   rts
Personally, I would love a switch statement or some other control flow structure. The JMP above concerns me as well. It seems like there is a better way to handle multiple cases without this type of spaghetti code.
I understand the code was just an example, but I think the naming of labels is very confusing. One would expect sub_one to be executed when A is 1, and sub_two when A is 2, but that doesn't happen.

The closest you're going to get to switch statement with 6502 is jump tables. They're explained in the wiki: http://wiki.nesdev.com/w/index.php/Jump_Table

Anyway, personally I tend to use these kind of structures and indentation. It's just a different take:

Code: Select all

; For CA65.
.proc foo
  lda mem
  cmp #1
  bne not_sub_one
    ; sub1 stuff goes here.
    jmp out ; Could be RTS. Pros: Less code, faster. Cons: Less maintainable (in case clean up code gets added after the "out" label later).
  not_sub_one:
  cmp #2
  bne not_sub_two
    ; sub2 stuff goes here.
    ; Since it's the last condition, we don't need jmp, but let's use an assert to make sure
    ; we don't get in trouble if the code gets modified later.
    .assert * = out, error
  not_sub_two:
  out:
  rts
.endproc
Problem with this is that the code must fit within a page (because of the branches), or you'll have to start substituting the bne with beq+jmp for long branches.

P.S. How hard would it be to bolt a 6502 syntax hilighter in to phpBB? Maybe a different tag so it doesn't mess with other code. JavaScript hilighter such as SyntaxHilighter should be easy enough to add, and almost zero maintenance.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
Movax12
Posts: 529
Joined: Sun Jan 02, 2011 11:50 am

Re: Better Control Flow

Post by Movax12 »

johnnystarr wrote:

Code: Select all

;  using asm6

ControlFlow:
   lda mem
   cmp #1
   bne @sub_one

It's not directly relevant to the orginal question, but just though it should be pointed out that if mem = #1 it will not branch to @sub_one, you should be using beq.

But, you could code like this:

Code: Select all

ControlFlow:
   lda mem
   cmp #1
   bne @check_if_sub_two ; If not equal to #1, branch
   ; sub 1
   ; sub routine one goes here
   jmp @done ; <-------------- without this jmp, sub 2 will execute

   @check_if_sub_two
   cmp #2
   bne @done
   ; sub 2
   ; sub routine two goes here
   @done:

   rts
Edit: thefox is quick, this post is kind of pointless now, but I typed it all already....
User avatar
Movax12
Posts: 529
Joined: Sun Jan 02, 2011 11:50 am

Re: Better Control Flow

Post by Movax12 »

There's discussion of an if macro for ca65 that hides the ugly jmp at the end of the controlled block.
As much as I really would love everyone to use these macros, and they should, I would be a bit careful with these unless you are sure you understand how the flags are set, and how the branch instructions work. At least maybe stick to testing for flags only until you know how to use the extra flexibility the macros offer.
Post Reply