Inaccurate timing in emulators

Talk about development tools here

Moderator: BigEvilCorporation

Post Reply
mic_
Very interested
Posts: 265
Joined: Tue Aug 12, 2008 12:26 pm
Location: Sweden
Contact:

Inaccurate timing in emulators

Post by mic_ » Wed Aug 20, 2008 8:25 am

I've been adding support for DAC playback in my VGM player and noticed that it behaves differently in different emulators, and on a real Megadrive.

On a real Megadrive the song plays slightly slower than I want, and seems to stutter a bit.

In Gens KMod 07c it behaves kind of like on a real Megadrive, but it's even slower.

In Fusion 3.51 it plays at the "right" speed (which of course is the wrong speed, since it differs from a real Megadrive).

I'm using timer A on the YM2612 to handle the delays specified in the VGM 0x8n commands. These delays are quite short (usually about 0.1-0.2 ms) and occur very often. I have not seen these inaccuracies in songs where the DAC isn't used and the delays are longer and fewer.

Here's a test ROM plus the source of the relevant parts. In case it isn't clear, I'm multiplying the delay count by 1.25 (10/8) at the beginning of delay_n_samples as an approximation of (1000000 / (44100 * 18)). 44100 being the VGM sample rate, and 18 being the timer A period in microseconds.

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Post by Eke » Wed Aug 20, 2008 10:12 am

Are you reading the FM status BUSY bit before writing stuff to the YM2612 ?
I don't think any emulator are emulating it so it might have some impact on timings too

mic_
Very interested
Posts: 265
Joined: Tue Aug 12, 2008 12:26 pm
Location: Sweden
Contact:

Post by mic_ » Wed Aug 20, 2008 10:16 am

No, I just insert two NOPs between the writes.

AamirM
Very interested
Posts: 472
Joined: Mon Feb 18, 2008 8:23 am
Contact:

Post by AamirM » Wed Aug 20, 2008 6:07 pm

Hi,

Timer implementation of each emulator is somewhat different from each other. Kega seems to play DAC a bit fast and runs Z80 a bit fast as well. I tried it on Regen and it also seems to run like Gens (but a bit fast).

stay safe,

AamirM

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Wed Aug 20, 2008 10:55 pm

On real HW, Z80 does have some access limitations when accessing ROM area, emulators give full access I think... that's the only thing I can think of. Timers are off in all emulators, real HW will always go ahead/leave behind when doing side by side comparsions.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Nemesis
Very interested
Posts: 791
Joined: Wed Nov 07, 2007 1:09 am
Location: Sydney, Australia

Post by Nemesis » Thu Aug 21, 2008 1:03 am

I think my emulator might get it closer. How does this sound?
http://www.mediafire.com/?zzze3vanpt8
That should (hopefully) match a PAL system.

Disclamer: The actual sound might be wrong. My YM2612 core is being changed constantly right now. I don't think I've got channel 1 self-feedback enabled currently for example. The timing of the notes should be correct though.

mic_
Very interested
Posts: 265
Joined: Tue Aug 12, 2008 12:26 pm
Location: Sweden
Contact:

Post by mic_ » Thu Aug 21, 2008 5:54 am

Here's a recording from my PAL Megadrive 2.

As for the Z80 having access limitations, that shouldn't matter since I'm not using the Z80.

Nemesis
Very interested
Posts: 791
Joined: Wed Nov 07, 2007 1:09 am
Location: Sydney, Australia

Post by Nemesis » Thu Aug 21, 2008 7:02 am

Hmm. Close, but not quite. Looks like I'm too slow by around 5.2%.

It's all down to timing. I overclocked the M68000 in my emulator by a factor of 10, and the thing ran at what sounded like full speed. Remember that an overflow could be triggered a fraction of a second after you test the YM2612 status register, but your code has to wait for another loop before it can test it again. In this way, your delay loop can never end too quickly, but it can run on too long. In reality, every loop will always be running on too long, even if only by a few microseconds. You'll need to try and adjust for this. This additional delay isn't a "percentage", it's simply a constant bias. When you have a very long delay, say, 0.1 seconds, you'll have the exact same error margin on your delay as one running for 0.1 microseconds. When you've got 1000 * 0.1 millisecond delays, you've got 1000 times the error margin of a single 0.1 second delay, even though the amount of time covered is the same. This is the reason this issue isn't obvious in songs with longer delays.

You'll need to adjust your delay subroutine to factor in the average delay, so that 50% of your loops end a little early, and 50% end a little late, meaning that averaged over time, your delays are correct. To do this, you'll just have to calculate the average error margin, and add it to each timer value. I'd pick a small number to add to each delay, test it on the hardware to figure out if it's too high or too low, then adjust it from there until you've got it as close as possible.

Oh, and you should change your delay multiplier to 1.2 as well. The system clock for a PAL Mega Drive is 53.203MHz, 53.6931MHz. M68000 clock is system clock/7. YM2612 Timer A is M68000 clock/144.
((53203000/7)/144)/44100=1.1968 - PAL
((53693100/7)/144)/44100=1.2079 - NTSC
Round to 1.2 and you've got a pretty good average.
Last edited by Nemesis on Thu Aug 21, 2008 8:34 am, edited 1 time in total.

mic_
Very interested
Posts: 265
Joined: Tue Aug 12, 2008 12:26 pm
Location: Sweden
Contact:

Post by mic_ » Thu Aug 21, 2008 7:45 am

The inner loop in delay_n_samples is pretty tight though. It shouldn't take more than 3-4 microseconds to do one iteration, unless there's some additional latency when reading from the YM2612 registers(?).

Nemesis
Very interested
Posts: 791
Joined: Wed Nov 07, 2007 1:09 am
Location: Sydney, Australia

Post by Nemesis » Thu Aug 21, 2008 8:32 am

Well, the YM2612 is on the Z80 bus. In order for the M68000 to access it, the request has to be forwarded onto the Z80 bus by the bus arbiter. This will result in slower access than simply accessing a device on the M68000 bus. I'm not sure how much slower, but at the very least it would be an extra couple of cycles.

Apart from that, there could potentially be some latency between when a timer is told to start, and when it actually starts. Likewise, there could be some latency between when a timer overflows, and when the overflow flag is actually set. I'd be surprised if there was any significant delay here, but if such a delay did exist, it could potentially be one or two timer cycles.

At any rate, wherever the delay is coming from, you should be able to adjust for it in the same way.

mic_
Very interested
Posts: 265
Joined: Tue Aug 12, 2008 12:26 pm
Location: Sweden
Contact:

Post by mic_ » Thu Aug 21, 2008 9:27 am

I switched to using a CPU based delay instead of a timer based delay for the DAC delays, and now it plays almost perfectly in Gens KMod. I haven't had the chance to try this version on my Megadrive yet.

Post Reply