timing 2 ^_^;;

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
timing 2 ^_^;;
by on (#3985)
Because of APU test issues, I rebuild my CPU core to handle cycles in a lower level - it means:

* By taking STA $HHLL, it does 1 clock cycle to read the opcode, 2 cycles to fetch the address HHLL, instead of clocking 4 cycles at end of STA. That's an example.

It caused the timing to be better for a few games/demos, but very bad for others (mapper #7). Battletoads&Double Dragon does not hang when a PCM sound is played. While it was playing nicely, it stopped on level 5 beginning. >_<. I suspect I would have to rewrite my PPU core too.

Detail (NTSC only): for each CPU cycle, the PPU does 3 clock cycles, APU does 1 clock cycle. I gave a look in other emus and (except for Nintendulator?), they use a cycle table. Is the PPU/APU clocked before or after an instruction? Any help?
Re: timing 2 ^_^;;
by on (#3986)
Fx3 wrote:
I gave a look in other emus and (except for Nintendulator?), they use a cycle table


That's because Nintendulator already uses the "high precision timing" method you just implemented.

by on (#3989)
Fx3 wrote:
Is the PPU/APU clocked before or after an instruction?


Good question. The APU is likely clocked at the same time as the CPU (well, technically the CPU has a two-phase clock). This brings up the question, if the CPU performs a read on a given clock, does it get data generated by the APU on that clock, or from the previous clock? Answering this probably requires hooking a scope up to the NES bus.

Fortunately what really matters is the behavior you get by running code, which can be determined by running test code and observing the results. Thus it becomes irrelevant as to when the units are clocked. What one needs to know (both for programming the NES and writing an emulator) is, if this read occurs at such-and-such time relative to a previous write (or NMI etc.), what value do I get?

Regarding instruction timing, can't you just use a "regular" CPU core and pass a timestamp adjustment along with memory reads/writes? So for STA $xxxx, instead of WRITE( addr, a ) you do WRITE( addr, a, 3 ) since the write is on the fourth clock.

I doubt that it really matters to be precise with regard to opcode reads, since it's unlikely anything is going to try to execute from I/O space. In my CPU core I even avoid the usual memory access function for opcode reads, instead going directly through the memory mapping table without any function calls. And hopefully you optimize zero-page and stack accesses to avoid function calls, since those can never cause any side-effects (as far as I know).

by on (#3990)
blargg wrote:
And hopefully you optimize zero-page and stack accesses to avoid function calls, since those can never cause any side-effects (as far as I know).

Is the CPU address bus visible on the cart edge during internal RAM accesses?

by on (#3996)
blargg wrote:
In my CPU core I even avoid the usual memory access function for opcode reads, instead going directly through the memory mapping table without any function calls.


How does that work for games like Zelda which move code to cartridge RAM and jump to it? or does your emu not support that?

edit:
Or do you mean you do like an if/else range check for opcode reads?

by on (#4004)
I started a new thread for reading directly without calling the emulated read function. Both questions are answered there.