Nesasm(?) error
Page 1 of 1

Author:  H3xaCod3 [ Thu Jul 03, 2008 11:50 am ]
Post subject:  Nesasm(?) error

My code is getting a little big, and it appeared today:

I:\NesProgramming\sprites>NESASM3 sprites.asm
NES Assembler (v3.00)

pass 1
pass 2
#[2]   Controller.asm
   14  00:C16C              BEQ ReadAllDone
       Branch address out of range!
# 1 error(s)


What I do? :(


Author:  tokumaru [ Thu Jul 03, 2008 12:04 pm ]
Post subject: 

Instead of branching to the location, branch around a JMP to the location. Say you have the following:
   bne FarAway

Which doesn't assemble because "FarAway" is too far. Just do the following:
   beq DontJump
   jmp FarAway

That's it. Use the branch to check for the inverse condition and skip the JMP instruction.

EDIT: Just to make it clear, it's not a NESASM error, it's a limitation of the 6502. Branches use relative addressing, which means that the displacement is calculated based on the difference between the current location and the destination location. It uses a byte to hold that difference, and if it's too large (the destination is too far away), it will not fit in just 8-bits, so the assembler throws an error. Jumps on the other hand use absolute addresses, so it's possible to jump anywere in the program (bankswitching aside). The solution is to combine both instructions, a branch and a jump.

Author:  H3xaCod3 [ Thu Jul 03, 2008 12:27 pm ]
Post subject: 

Thank you, now it worked!! :D :D
Now I understand what happens, thank you for explaining. Sometimes we do things without knowing why we do .. tks :D

Author:  sdm [ Mon Nov 21, 2016 6:12 am ]
Post subject:  Re: Nesasm(?) error

Is this method also works with other branches? As BEQ, BMI, BPL, etc.?
Or maybe there are some limitations and can not always be used?

Author:  tokumaru [ Mon Nov 21, 2016 9:04 am ]
Post subject:  Re: Nesasm(?) error

It works for any branch instruction, but you always have to use the opposite branch condition to skip over the JMP. Say you want to BCC somewhere, but the distance is to large, so instead you BCS over a JMP to the desired target location.

Author:  koitsu [ Mon Nov 21, 2016 4:50 pm ]
Post subject:  Re: Nesasm(?) error

sdm wrote:
Is this method also works with other branches? As BEQ, BMI, BPL, etc.?
Or maybe there are some limitations and can not always be used?

The "method" isn't magical or mystical in some manner -- no CPU should be "magical". This is a computer, it has definitive behaviour. Your question implies that you don't understand branches (vs. jumps), so let's put that to rest:

Branch instructions on the 6502 are opcodes bpl, bmi, bvc, bvs, bcc (blt), bcs (bge), bne, beq. These instructions consist of 2 bytes: 1 byte for the opcode, and 1 byte for the operand. The operand being 1 byte in size is the key to understanding branches. The operand represents an "offset" from the active PC (the address of the operand, not the opcode!) -- this is also known as a "relative address" or "PC relative".

The operand is therefore a signed 8-bit number (more precisely: its twos complement), which means that the range it's limited to is +127 bytes (up to 127 bytes "forward", i.e. values $01 to $7F) and -128 (up to 128 bytes "backwards", i.e. value $80 to $FF) from the address of the operand. Thus, the branch range "from the branch opcode itself" is effectively +129 and -126. A little-mentioned quirk/feature is how an operand value of $00 on a branch instruction just continues on with the next instruction regardless of the conditional results (think of it as a 2-byte nop with a variable cycle count dependant on the result of the conditional).

The reason branch instructions are 2 bytes (rather than 3 (see below)) is to save space/memory.

In contrast, jump instructions on the 6502 are opcode jmp, jsr. This instruction consists of 3 bytes: 1 byte for the opcode, and 2 bytes for the location to jump to -- this is known as an "absolute address" (the same type of addressing used in something like sta $2100). The operand specifies a literal value from $0000 to $FFFF, which the CPU loads directly into PC. I won't explain the difference between jmp and jsr here -- it's not relevant to what is being discussed (relative vs. absolute addressing). And as should be obvious, jump instructions are unconditional.

The way people work around the relative addressing range on the 65xx is by doing exactly what tokumaru described -- the most common being to reverse the branch logic and use a jmp.

Edit: clarification on branches with an operand of $00.

Author:  tokumaru [ Mon Nov 21, 2016 5:12 pm ]
Post subject:  Re: Nesasm(?) error

Koitsu is right, this is not some mystical voodoo stuff, it's just a very logical way to get around a limitation of the CPU. If you didn't yet understand why this works, please tell us what is confusing you so we can explain it better.

In a nutshell, you have to replace a branch, that has limited range, by a jump, that can reach the whole program. Problem is, a jump is unconditional, so in order to guarantee that it will only happen when a certain condition is met, you need to avoid the jump (i.e. branch over it) when the opposite condition is met.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group