Suggestions to follow branch instructions

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
dougeff
Posts: 2741
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Suggestions to follow branch instructions

Post by dougeff » Sat Nov 16, 2019 3:55 pm

rom memory in position 2000h or 8194d
I'm talking about $2002, which is hardwired directly to the PPU, a second chip on the motherboard.

Also, usually the ROM is "mapped" to the $8000-ffff region of memory. There will never be ROM mapped below $4020.

I suggest, spend some time reading the wiki.
http://wiki.nesdev.com/w/index.php/Nesdev_Wiki
Last edited by dougeff on Sat Nov 16, 2019 10:44 pm, edited 1 time in total.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
Quietust
Posts: 1606
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Suggestions to follow branch instructions

Post by Quietust » Sat Nov 16, 2019 5:01 pm

I have a feeling that there might be a language barrier here, and some machine translator is distorting not only the original question but our replies as well. Is English your native language?
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
Zepper
Formerly Fx3
Posts: 3220
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Suggestions to follow branch instructions

Post by Zepper » Sat Nov 16, 2019 7:16 pm

Quietust wrote:I have a feeling that there might be a language barrier here, and some machine translator is distorting not only the original question but our replies as well. Is English your native language?
That... or a bot. If human, yes, english isn't his mother-language, as far as I can tell ya.

colt
Posts: 13
Joined: Sat Nov 02, 2019 2:53 pm

Re: Suggestions to follow branch instructions

Post by colt » Mon Nov 18, 2019 5:02 pm

rainwarrior wrote:It might be a little easier to discuss if you provided more context. It's really hard to offer any helpful insight with such a tiny view of what you're looking at.

What ROM is this?

Or if you don't want to disclose that, at least show the LDA / BPL instruction you're talking about (i.e. what are the 5 bytes of code in this loop, and where are they loaded in memory). What mapper?
Here the first two lines:

Image

colt
Posts: 13
Joined: Sat Nov 02, 2019 2:53 pm

Re: Suggestions to follow branch instructions

Post by colt » Wed Nov 27, 2019 4:10 pm

Unfortunately, I am still stuck with this issue. My program currently is trapped between an infinite loop between a absolute load instruction "AD" instruction and a BPL. This happens because: The LDA instruction loads a value from position 2002. This value happens to be 27, which means its seventh bit of the A register will be 0. Hence the seventh bit of the status register won't be changed. Since it already was zero, it will continue to be so. Then the BPL instruction starts to execute. It will check the seventh bit of the status register and see that its value is zero. Hence it will move backward three bytes, back to the LDA instruction. Then will do the same thing once again and forever, entering into an infinite "ping pong" between both instructions.

I was thinking into possible causes

1)I am loading the wrong value from memory, possibly because I am loading from the wrong position

2)There is some kind of logical error.

3)There is something else to be done that I do not have knowledge of.

So my questions are. How I can find out the reason behind of this?

lidnariq
Posts: 9690
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Suggestions to follow branch instructions

Post by lidnariq » Wed Nov 27, 2019 4:16 pm

colt wrote:
Wed Nov 27, 2019 4:10 pm
The LDA instruction loads a value from position 2002. This value happens to be 27, which means its seventh bit of the A register will be 0.
No it is not. LDA $2002 means instruct the NES's CPU to ask something to put a value on the data bus when the CPU puts $2002 on the address bus.

But that's not ROM.

Instead, the NES uses what's referred to as Memory-mapped I/O to interact with other devices beyond its own RAM and ROM.

In the NES, $2002 means "ask the PPU what's up".

User avatar
tokumaru
Posts: 11864
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Suggestions to follow branch instructions

Post by tokumaru » Wed Nov 27, 2019 7:30 pm

Your branching code appears to be working fine, games are supposed to get "stuck" reading $2002 when they're initializing. The problem here is that you're treating $2002 as a static memory location, but like dougeff told you in the previous page, this address is RAM or ROM, it's actually a communication port with the PPU. PPUSTATUS is a register that contains some information about what the PPU is doing - bit 7 in particular indicates whether the vertical blank (period between video frames) has started. Before vblank starts, bit 7 reads back as 0, so the BPL instruction will branch while this is the case, but as soon as vblank starts, bit 7 will become 1, and the CPU will get out of that loop.

If you're writing an emulator, now might be the time to start implementing a PPU, and have it signal the start of vblank via register $2002.

colt
Posts: 13
Joined: Sat Nov 02, 2019 2:53 pm

Re: Suggestions to follow branch instructions

Post by colt » Thu Dec 05, 2019 4:41 pm

Okay, so when v-blank is activated, the seventh bit of the ppu status register is changed to one, leading to the end of this loop. But what causes it? I found this:
The VBlank flag of the PPU is set at tick 1 (the second tick) of scanline 241, where the VBlank NMI also occurs. The PPU makes no memory accesses during these scanlines, so PPU memory can be freely accessed by the program.
So during the second "tick" (clock pulse?) of the scanline 241 the seventh bit of the PPU status register becomes one.

So I will have to:

1)Start to count ticks, both from the PPU and from the CPU
2)Start to count scanlines

Since there is about 113 cpu clocks per scanline, does that mean that at only 241*113.667 = a lot of clock cycles will the loop stops? I shall start the counting of the cpu cycles from the cpu's first instruction read? and the ppu?

ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm
Contact:

Re: Suggestions to follow branch instructions

Post by ReaperSMS » Fri Dec 06, 2019 10:00 am

Short answers: Yes, yes, and yes.

Technically you count from either RESET or power on, and there's the question of counting CPU clocks, master clocks, or PPU dots, but where you come down on that depends on how accurate you are trying to be.

More or less every game is going to start with two of those vb: LDA $2002 / BPL vb busy waits before they start executing the rest -- Big N said you had to, and the PPU needs some warmup time to get everything in order, and ignores anything you send before it is ready. Two vblanks guarantees it is ready.

colt
Posts: 13
Joined: Sat Nov 02, 2019 2:53 pm

Re: Suggestions to follow branch instructions

Post by colt » Mon Dec 09, 2019 5:51 pm

ReaperSMS wrote:
Fri Dec 06, 2019 10:00 am
Short answers: Yes, yes, and yes.

Technically you count from either RESET or power on, and there's the question of counting CPU clocks, master clocks, or PPU dots, but where you come down on that depends on how accurate you are trying to be.

More or less every game is going to start with two of those vb: LDA $2002 / BPL vb busy waits before they start executing the rest -- Big N said you had to, and the PPU needs some warmup time to get everything in order, and ignores anything you send before it is ready. Two vblanks guarantees it is ready.
I read the documentation and came to these conclusions:
1) I can only think of counting clock cycles from the first instruction. As I increment the clocks cycles when reading an instruction, I would just keep switching between the bpl and the lda instruction until the cpu clock cycle where the seventh bit of the ppu status register changes to one.
2)I mentioned before here 241*113.667 cpu clock cycles. Honestly I do not remember from where I took these numbers, nonetheless, this link: http://wiki.nesdev.com/w/index.php/PPU_frame_timing mentions 341*262/3 = 29780 2/3. It says
If the CPU checks the VBL flag in a loop every 29781 clocks, the read will occur one PPU tick later relative to the start of the frame each frame, until at some point the CPU "catches up" to the location where the flag gets set. At this point, the CPU and PPU synchronization is known down the PPU tick.
Does this have some immediate impact to what I intend to achieve (leave the bpl-lda loop and resume the execution of the other instructions) ? If not, will cause trouble in the future, to the point I will have to change this checking?

ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm
Contact:

Re: Suggestions to follow branch instructions

Post by ReaperSMS » Tue Dec 10, 2019 10:36 am

There are a variety of ways to handle the clock counting and synchronization. Generally they come down to what granularity you ping-pong to PPU or APU emulation. From simplest and least accurate to most accurate, things usually go:

Run an entire frame of CPU cycles, then render a full frame of the PPU. Terrible for accuraccy, most status bars won't work, etc etc.
Run a scanline of the CPU, render a scanline of the PPU. Generally workable, and will handle most titles. MMC3 will have some quirks.
Run an instruction on the CPU, render that many dots on the PPU. Straightforward, but can be a perf hog. May still have some subtle PPU issues regarding timing.
Run a cycle at a time on the CPU, and getting the reads/writes exactly on the right cycles, render 3 dots on the PPU. Generally the most accurate worth trying to do.
Run a PPU dot at a time, with a CPU cycle every three. Likely the most accurate, but the cases where it will differ from the above are few and far between.

As for the implementation details there, there are several examples running around the wiki and the internet at this point. A common approach is to keep a timestamped buffer of writes from the CPU to the other units (PPU/APU), and only switch over to catch them up when the CPU reads data back from them, and when they need to trigger an NMI or IRQ.

Regarding the CPU/PPU tick synchronization, getting that to just the right CPU cycle is good enough for most things. Where it will cause trouble later is passing blargg's PPU timing tests, some MMC3 edge cases, and Battletoads.

Internally, the PPU counts dots in X and Y, and sets/clears flags, and fetches data in a set pattern.

Post Reply