Jump to content
IGNORED

bne jmp bpl


Recommended Posts

bne means Branch if Not Equal (to zero).

 

If a computation produces a result other than zero, then the Z flag is not set, and the bne instruction will cause a jump to a new location in the program (otherwise, the next instruction in the program is executed).

 

bpl means Branch if Plus.

 

Often programmers use the topmost bit as a negative sign bit.

If a computation produces a result where bit 7 is not set, then the N flag is also not set, and the bpl instruction will cause a jump to a new location in the program (otherwise, the next instruction in the program is executed).

 

jmp means Jump.

 

A jmp instruction is always taken.

 

-Bry

Link to comment
Share on other sites

That's why I never see "if then else" in Andrew Davie's sessions or even

(if xxxxx == 33){

 

}

 

 

 

 

lda xxxxx

cmp #33

bne elsenot33 ; take branch only if xxxx is NOT = 33

 

; this stuff done when xxxx IS = 33

jmp finished ; now unconditionally jump past the 'else' code

 

elsenot33

 

; this stuff done when xxxxx not = 33

 

finished

 

; we've just done an 'if-then-else' in assembler

Link to comment
Share on other sites

Substituting branching instructions for jumps is also a good way of reducing the number of bytes or cycles in a routine when hacking games (you need to watch your cycle times when the display is being constructed tho). Branches use 1 less byte and 1 less cycle than a JMP. The downside is that they can only direct a program to go 128 bytes forward or back. Branch descriptions:

 

BCC - branch on carry clear. This is most commonly used to check values that are less than what you are comparing it to...

LDA $DF ;get value of a ram location

CMP #$0A ;check if it's a value of 10

BCC $50 ;if $DF is less than that, take the branch

 

You can also use it to check for rollovers during arithmatic. You should use CLC or SEC instructions just prior to using ADC or SBC (respecively) if there is a possibility of the byte rolling over $FF or under $00. The status of that carry can also be used in adding or subtracting values that are larger than $FF...

LDA $A8 ;load the low byte of our "score"

CLC ;clear the carry flag

ADC #$01 ;add 1 point **

STA $A8 ;...and save it

LDA $A9 ;load the high byte of our "score"

ADC #$00 ;if the carry flag was set by **, it will be adding 1 here

STA $A9 ;...and then save it

 

BCS - branch on carry set. This is the opposite from above, the branch is taken if the result is greater than the value you are checking for.

 

BEQ - branch on zero. This one checks if they are equal. If our example $DF is equal to $0A...there will be no remainder when comparing it against a value of $0A - branch on zero. You can also use it just to see if the contents of a memory location are equal to zero...

LDA $DF ;load the ram location

BEQ $50 ;if it's zero, take the branch

 

BNE - branch if not zero. The opposite from the above...the program will take the branch if the result is anything BUT zero (i.e. not equal to).

 

BMI - branch on minus. The branch is taken if the high bit is set ($80 to $FF are considered to be negative)

 

BPL - branch on plus. The opposite from the above, the branch is taken if the result is between $00 and $7F. Really handy to use in loops that count down. You'll see it used often in display kernals where a specific amount of time needs to be wasted...

LDX #$10 ;start with a value of 16 decimal

DEX ;subtract 1 (doing nothing for 2 cycles)

BPL $FD ;also using 2 cycles, branch back up until X rolls over to $FF.

 

BVC - branch on overflow clear. This is similar to BPL...you are just looking at one bit in the value to see if it's not set (the second-highest bit...which has a value of $40)

 

BVS - chanch on overflow set. The opposite from the above. The branch will be taken if that bit is on. Since the 2600 is seriously limited for ram space, variables are often shared in a single ram location. No need to waste a full byte if all you want to do is toggle something on or off :) The code...

LDA $F0 ;load a ram location

AND #$40 ;keep only the second-highest bit

BEQ $E0 ;branch if that bit is off

 

...can be shortened to...

LDA $F0 ;load a ram location

BVC $E0 ;branch if bit 6 is off

 

...and if you don't want your accumulator's value to be overwritten, you could even do this...

BIT $F0 ;check a ram location

BVC $E0 ;branch if bit 6 is off

 

...but I won't go into that :D

 

 

That covers branches...but JMP also has a couple of formats. You probably already know JMP $location...always jump to the address unconditionally, but there is another one that is used when you want to have a choice of jumping to one of many locations from within the program. It's indirect jumping...that is to say that the program looks up 2 ram locations and jumps to the address that THEY contain. Although all of the 2600's ram is located only on single-byte zero page locations, the instruction still uses 3...so the high byte is usually zero...

Example:

JMP ($00D0)

This instruction is looking at the contents of $D0 and $D1 for the address to jump to. If $D0=$05 and $D1=$F1, the jump will go to $F105. Often, these values are located in a table located someplace in Rom...and the program puts the one it needs (depending on what is currently happening) into the ram locations just prior to using the indirect JMP.

 

And as stated above, JSR acts as Basic's GOSUB. It jumps to a new location, and saves the return address for when an RTS instruction is met. You still need to watch out for how many "nests" you can perform at one time tho. So the program might overwrite some of the ram locations used for variables if you use too many JSR's at the same time. JSR's are also the biggest wasters of cycle time...6 cycles to jump there and 6 cycles to return - that's 12 cycles and you didn't even do anything there!

Link to comment
Share on other sites

Substituting branching instructions for jumps is also a good way of reducing the number of bytes or cycles in a routine when hacking games (you need to watch your cycle times when the display is being constructed tho).  Branches use 1 less byte and 1 less cycle than a JMP.  The downside is that they can only direct a program to go 128 bytes forward or back.  Branch descriptions:

 

 

Thanks for that. I think we'll probably have to have a tutorial on branching. The above seems mostly OK, but there are a few more tricks/gotchas. For example, BCC is a branch less than only if the numbers you are dealing with are considered unsigned. For signed comparisons, BPL and BMI are used instead of BCC and BCS. To be honest, I almost never do signed comparisons... but something to be aware of.

 

On a slightly different subject, I'm playing around with a '2600 programming Wiki. See http://twiki.org/cgi-bin/view/Sandbox/AtariVCS2600 for an idea of what it might be like. Feel free, of course, to make changes -- that's what a wiki is all about. Takes a while to get used to, but looks VERY useful and powerful once you do. Highly recommended.

Link to comment
Share on other sites

Assembly can be fun.

 

As was already said: Forget what you know about high-level languages.

 

True, true.

 

Once you do, and start thinking in Hex & Binary, it makes a lot of sense and is quite easy to work with.

 

Heck, I've never even used a real assembler. I used my C-128's built-in ML monitor to do all my programming. And it was still fun & easy. :)

 

Not to mention FAST. I needed to swap out a specific byte-pair in a graphic image. I wrote a program in Assembly & Basic 7 to do it. The basic program was 2k, took 23 minutes. The assembly program was like 300 something bytes and took 1.5 seconds. 8)

Link to comment
Share on other sites

I forgot to mention that the BIT instruction can be used to perform very small "jumps" forward...skipping only 1 or 2 bytes. If you have a routine that looks like this:

LDA $80,X ;check our group of ram values

CMP #$30 ;compare to a value of $30

BCC Load2 ;if it's lower, branch ahead

LDA #0 ;...otherwise load a zero

BEQ Save ;...and skip ahead to save it

Load2: LDA #$20 ;use $20 for the ones that were lower than $30

Save: STA $90,Y ;save it to the other group of ram values

 

...you have all 3 registers in use. X is being used for the offset in the first table, Y is being used as the offset in the second table, and the accumulator is occupied holding the value we want to save. Since all BEQ Save is doing is skipping ahead 2 bytes, we can use BIT $absolute instead...

LDA $80,X ;check our group of ram values

CMP #$30 ;compare to a value of $30

BCC Load2 ;if it's lower, branch ahead

LDA #0 ;...otherwise load a zero

.byte $2C ;...and skip ahead to save it

Load2: LDA #$20 ;use $20 for the ones that were lower than $30

Save: STA $90,Y ;save it to the other group of ram values

 

$2C is the value of the BIT $absolute instruction. So the computer will read this as the following when it's loading the zero...

LDA #0

BIT $20A9

STA $90,Y

 

Where did that $20A9 come from? The BIT instruction read the next instruction (LDA #$20) as a two-byte address...and is "fooled" into jumping two bytes ahead. So what is at $20A9? Who cares...the important thing is that we skipped over it. That replaced the BEQ instruction (2 bytes) with just 1. BIT $zeropage can be used to skip just 1-byte instructions ahead...one like an INX instruction.

Link to comment
Share on other sites

Thanks everybody

I also downloaded the Stella programmer's guide. It might help me to make my own 2600 games.

Have you written much in other languages? If you're not used to programming in general the atari is a very tough place to start.

 

You also might want to read through my own 2600 101, a kind of quickstart guide to programming the atari. It's built up around building a basic working program as quickly as possible, and then learning how to do more and more. (Also, my upcoming 2600 Cookbook, might already be useful on the few additional topics it covers)

Link to comment
Share on other sites

Have you written much in other languages?  If you're not used to programming in general the atari is a very tough place to start.

 

I know Basic, Qbasic, Klik & Play, AGI and SCI0.

 

Somebody told me programming c64 (assembler) is easier than 2600 but

I didn't check it at the moment.

 

I just finished my 3 playfields for my 3 levels at the moment. Now I have to deal with sprites by following the tutorials.

 

 

Serguei2

post-1196-1081965982_thumb.jpg

Link to comment
Share on other sites

LDA $F0 ;load a ram location

BVC $E0 ;branch if bit 6 is off

 

Actually, that doesn't work. LDA doesn't affect the overflow flag. I've gotten burned by that a couple times, in fact.

 

BIT $F0 ;check a ram location

BVC $E0 ;branch if bit 6 is off

 

This does work; BIT *does* set or clear the V flag as appropriate.

 

According to my 6502 reference, the *only* computational instructions that affect the V flag are ADC and BIT. (PLP and RTI also do, by pulling it from stack, and of course CLV clears it.)

 

Instructions that don't affect the overflow flag, but you might think they do, are LDA/LDX/LDY, CMP/CPX/CPY, SBC, all the IN_ and DE_ ops, and all the T__ transfer ops.

 

 

Here's how to remember how the sign and carry flags work with the compare instructions. CMP does the same thing as SEC+SBC without changing the accumulator. So suppose A holds the number 55, and we do CMP #30. The result of the 55 - 30 would be 25, binary %00011001. The topmost bit of the result is clear, so the sign flag is; and the result of the subtraction did not go below 0 so the carry stays set.

 

Suppose A held 30, and we did CMP #55. The result of the subtraction would be -25, or in binary %11100111. The topmost bit is set, so the sign bit is set (meaning negative). And the result of the subtraction went below 0, so the carry gets cleared.

 

CPX and CPY behave the same as CMP, of course.

 

Maybe Andrew can work that into a more coherent form for the tutorial lesson on branching. :)

Link to comment
Share on other sites

According to my 6502 reference, the *only* computational instructions that affect the V flag are ADC and BIT.  (PLP and RTI also do, by pulling it from stack, and of course CLV clears it.)

 

Instructions that don't affect the overflow flag, but you might think they do, are LDA/LDX/LDY, CMP/CPX/CPY, SBC, all the IN_ and DE_ ops, and all the T__ transfer ops.

 

Wrong, SBC does too. (See http://www.6502.org/tutorials/6502opcodes.htm for a good 6502 opcode list.)

 

ADC, BIT, CLV, PLP, RTI and SBC all update the oVerflow flag.

CLV clears it, BIT grabs bit 6 from the memory location, and PLP and RTI pull the entire Processor Status (aka Flags) Register from the stack.

 

See http://www.6502.org/tutorials/vflag.html for more on the oVerflow flag.

 

On a related note, IN_ and DE_ also do not change the Carry bit.

Link to comment
Share on other sites

I don't think the compare instructions affect V.

 

-Bry

 

Wrong  (See http://www.6502.org/tutorials/6502opcodes.htm for a good 6502 opcode list.)

 

ADC, BIT, CLV, CMP, CPX, CPY, PLP, RTI and SBC all update the oVerflow flag.

CLV clears it, BIT grabs bit 6 from the memory location, and PLP and RTI pull the entire Processor Status (aka Flags) Register from the stack.

 

See http://www.6502.org/tutorials/vflag.html for more on the oVerflow flag.

 

On a related note, IN_ and DE_ also do not change the Carry bit.

post-3606-1082433268_thumb.jpg

Link to comment
Share on other sites

Wrong  (See http://www.6502.org/tutorials/6502opcodes.htm for a good 6502 opcode list.)

 

ADC, BIT, CLV, CMP, CPX, CPY, PLP, RTI and SBC all update the oVerflow flag.

CLV clears it, BIT grabs bit 6 from the memory location, and PLP and RTI pull the entire Processor Status (aka Flags) Register from the stack.

 

 

Actually, the link that you give agrees with me that the compare instructions don't affect the V flag. "Affects Flags: S Z C".

 

And I listed all the other instructions you mention, except for SBC. Looks like my reference was wrong on that, but the point stands... the only opcodes that do something computational to the overflow flag are ADC, BIT, and SBC. CLV, PLP, and RTI do obvious things to it and are just about never used in 2600 programming anyway.

 

 

To Nukey Shay: LDA definitely doesn't update the overflow flag, so LDA/BVC definitely doesn't work. BIT/BVC certainly does, so that's probably what you've been using...?

Link to comment
Share on other sites

Hi there!

 

Then just write a simple program and test it on real hardware (or trust the emulators).

 

Ok, here's the code handling CMP in in Z26:

;*
;* flag setting macros
;*



useztest macro	op1	; use to test Z

mov	[RZTest],op1

endm



usentest macro	op1	; use to test N   

mov	[RNTest],op1

endm



usetest macro	op1	; use to test both N and Z (normal)

useztest op1

usentest op1

endm


;*
;* compare macros
;*



CompDH macro  ; compare dh and dl

sub	dh,dl

usetest	dh

setnc	ah

endm



_CMP macro  ; compare al and dl

mov	dh,al

CompDH

endm

 

usetest handles Z and N

setnc handles C.

 

No V code in sight :)

 

Greetings,

Manuel

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...