Branch instructions result in infinite loop?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Branch instructions result in infinite loop?
by on (#195657)
The first instructions in the rom for Donkey Kong are the following:

SEI
CLD
LDA 10
STA $2000
LDX ff
TXS
LDA $2002
AND 80, imm
BEQ f9, imm

Since BEQ branches if the zero flag is set, and $2002 is 0 initially, LDA sets the zero flag when it executes. BEQ then branches 7 bytes back to the LDA command, and it loops forever like this. Am I doing something wrong, or is the CPU waiting for some signal from the PPU here? (I know that $2000-$2007 are PPU registers, and since $2002 is being read, the CPU could be waiting for something?)
Re: Branch instructions result in infinite loop?
by on (#195658)
PolarBITS wrote:
is the CPU waiting for some signal from the PPU here?

Yes, it's waiting for the PPU to signal that vblank has started.

Since you're apparently coding an NES emulator, it might be a good idea to familiarize yourself with the basic architecture of the system, otherwise you'll run into all sorts of little surprises like this.

Quote:
(I know that $2000-$2007 are PPU registers, and since $2002 is being read, the CPU could be waiting for something?)

When in doubt, look at the PPU's documentation to see what bits of which register are being used/watched, and you should get a better idea of what the code is trying to do.
Re: Branch instructions result in infinite loop?
by on (#195667)
I'm looking at the PPU documentation and I'm a bit confused. STA writes 0x10 (16 in decimal and 00010000 in binary) to address $2000. The byte that controls vblank is the first one, byte 7, yet it seems to be set to 0. What am I missing?
Re: Branch instructions result in infinite loop?
by on (#195668)
PolarBITS wrote:
The byte

You mean bit. Anyway, that bit controls whether the PPU generates an NMI every time vblank starts, not whether vblanks happen. Even if NMIs are turned off, vblanks will still happen, and their occurrence will be signaled in bit 7 of register $2002.
Re: Branch instructions result in infinite loop?
by on (#195669)
Right. Nothing seems to be writing anything to bit 7 of $2002 though.
Re: Branch instructions result in infinite loop?
by on (#195670)
Hold on nevermind it's usually set at powerup. I'm dumb lol
Re: Branch instructions result in infinite loop?
by on (#195671)
$2002 is a read-only register. Games read it to get information about what the PPU is doing, they aren't supposed to write to $2002.
Re: Branch instructions result in infinite loop?
by on (#195672)
One thing that's important to note it's that memory-mapped registers are NOT memory. They are "ports" that allow the CPU to communicate with other parts of the hardware, such as the PPU and the APU. The CPU writes to these ports to send messages, but the written values are not stored in actual memory locations that can be read back. The CPU can also read from certain registers to receive messages from other parts of the system, and this is different from a memory read, because what you get is a dynamic value supplied by the hardware being pooled, not a static byte that was previously stored in a memory location.
Re: Branch instructions result in infinite loop?
by on (#195696)
After the BEQ I have the following instructions:

LDY 07, imm
STY 01, zp
LDY 00, imm
STY 00, zp
LDA 00, imm
STA 00, indY
DEY
BNE fb, imm
DEC 01, zp
BPL f7, imm

This still results in an infinite loop for me. If I'm getting it right, the following happens:

7 is stored in Y
Y is stored in $0001 (value of $0001 is now 7)
0 is stored in Y
Y is stored in $0000 (value of $0000 is now 0)
0 is stored in A
A is stored in the value at $0000 plus Y (therefore A is stored in $0000, same effect as above)
Y is decremented (Y is now -1 and the Negative flag is set)
The program branches back to (STA 00), because the negative flag is set.

This causes another infinite loop. What's the problem here?
Re: Branch instructions result in infinite loop?
by on (#195700)
PolarBITS wrote:
Y is decremented (Y is now -1 and the Negative flag is set)
The program branches back to (STA 00), because the negative flag is set.

This causes another infinite loop. What's the problem here?

BNE does not branch on negative, BNE branches on not-zero. It is the opposite of BEQ. (BNE = branch not equal, BEQ = branch equal. Would have been nicer if they were named BZC and BZS maybe?)

BMI branches on negative (branch minus), and BPL branches on positive (branch plus). (Again, BNS and BNC would have been clearer, IMO.)

DEY will eventally set the zero flag when Y reaches zero. (On the first test it will be $FF = -1, on the 256th test it will be back down to 0.)

DEC $01 will eventually set the negative flag when ($01) rolls over to $FF.
Re: Branch instructions result in infinite loop?
by on (#195703)
Quote:
A is stored in the value at $0000 plus Y (therefore A is stored in $0000, same effect as above)

wrong. Instruction "sta ($00), y" is post indexed indirect, That mean register A is stored in
address "at where" is pointing address $0000 plus y, not address $00 plus y.

address $0000 = 00
address $0001 = 07
register y = 0
sta ($00),y = $0700 + y = $0700

for what I can see this code fill with 0's entirely the main RAM.
Re: Branch instructions result in infinite loop?
by on (#195704)
Ah, yeah I figured it was a "clear RAM" loop (PolarBITS seems to be working through a startup sequence), but I had neglected to notice that this loop overwrites its own counters, i.e. $01 is expected to be overwritten with 0 at some point. Interesting that this loop will leave with ($01)=$FF after that last DEC, and it has to write the $00XX page last.

If "indY" meant "indexed Y" it would overwrite $01 right away and the BPL would trigger on the first test, but yeah obviously it is "indirect Y".
Re: Branch instructions result in infinite loop?
by on (#195706)
This non standard notation threw me off too, I also assumed that was "indexed Y".
Re: Branch instructions result in infinite loop?
by on (#195707)
rainwarrior wrote:
(On the first test it will be $FF = -1, on the 256th test it will be back down to 0.)
[/quote]

So you're saying that all numbers in RAM are unsigned bytes? I completely forgot about that lol.
Re: Branch instructions result in infinite loop?
by on (#195708)
Everything on a 6502 is unsigned, with the exception of the V flag in ADC, CMP, and SBC. N just means bit 7.
Re: Branch instructions result in infinite loop?
by on (#195710)
Signed or unsigned is the same when represented in binary. The program gets to choose whether to interpret them as signed or unsigned.
Re: Branch instructions result in infinite loop?
by on (#195729)
PolarBITS wrote:
rainwarrior wrote:
(On the first test it will be $FF = -1, on the 256th test it will be back down to 0.)

So you're saying that all numbers in RAM are unsigned bytes? I completely forgot about that lol.

Well, I was really saying that $FF and -1 are equivalent names for binary %11111111. It's a standard two's complement binary representation of numbers.

Aside from the indexed address modes where X or Y is always interpreted as unsigned, or the immediate branch argument which is always signed, it's generally up to how you use it. Usually "unsigned" usage is simpler/faster, so it's sort of the default case for 6502.

For instance: an unsigned less-than comparison is just CMP followed by BCC or BCS. The equivalent signed less-than comparison involves a few more steps, though if the numbers involved are small enough not to cause an overflow, CMP followed by BMI or BPL can be sufficient as a limited "signed" comparison. BMI might also be useful for testing an unsigned byte for >= 128, so it's not necessarily a "signed" instruction.

Anyhow, it may be helpful when learning to think of it as unsigned by default?