It is currently Wed Dec 13, 2017 5:44 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sun Jul 24, 2005 9:35 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
Blargg's APU doc mentions that the square programmable timer clocks the duty cycle every OTHER clock (effectively dividing the frequency by 2). And that the duty cycle takes 8 steps rather than 16.

This reminds me of BT's section on the noise channel. It have higher frequency values for the noise lookup table but said that the RNG unit is updated every OTHER clock.

Anyway -- I've since been thinking about it... and does this make ANY difference at all when emulating? I mean it's good to know the exact hardware behavior... but doing a 16-step duty cycle would have the exact same effect as a divided by 2 8-step duty cycle, wouldn't it?

As brought up in that savestate thread you said we should save the duty cycle as 0-7 -- but then wouldn't we have to save ANOTHER byte (or just a bit) to signal whether this is the first or second clock in the 2-step divider? Couldn't we just say that the low bit of the duty cycle counter is the step of the divider?

I don't know how much sense I'm making (it's pretty late and I'm tired) -- but my question is simple: Does emulating a 16-bit duty cycle have ANY effect on the generated wave? Or does it yeild the exact same result as emulating a divided-by-2 8-step duty cycle. Because I can't see how it would be different (and it sure is loads simpler to do 16-steps).


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 11:04 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
As I understand, the main difference is that updating the period while the channel is playing will result in slightly different behaviour between the two methods.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 2:20 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Maybe I'll get an award for the most rewrites of this post.

My APU reference is incorrect regarding the timer with divde-by-two on the output. I was thinking of the Wiki where it has been corrected. Apologies for that and any other remaining errors.

Yes, a 16-step duty sequence is equivalent to using an 8-step duty sequence with a divide-by-two on its input. And yes, it would be a mess to try to explicitly code the divide-by-two and save this state. I thought the question was whether the divide-by-two was before or after the timer, which does make a difference. If before, the timer is only reloaded 8 times per wave, otherwise it's reloaded 16 times per wave.

I've written several tests to verify that the divide-by-two is before the timer (link to test ROM below). That should be just as simple to implement as having it after (reload timer with raw * 2 + 2, use 8-step duty sequence).

In the simplest test, I ran the square with $4002 = 8 (i.e. highest pitch). Then I executed

Code:
lda #255
sta $4002
pha       ; 21 delay
pla
pha
pla
pha
pla
lda #8
sta $4002


which would cause the timer to be reloaded one time with whatever 255 gives. Looking in a sound editor, the flat section in the middle of the high pitch was 512 clocks (divider before timer) rather than 256 clocks (divider after timer).

In a more complex test I run a cycle-timed loop that changes $4003 momentarily (for 4 clocks) every fourth timer reload. This produces two different results depending on where the divider is. I verified both by putting the divider before and after in an emulator. The NES matches with the divider before. Here's the NES ROM, main asm code, and recordings for before and after:

square_timer_div2.zip


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 9:48 am 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3076
Location: Brazil
Well, I didn't get the idea... >_< but the result in my emulator was the sound played in "correct.wav". However, there are "clicks" during the playback; minor, but audible. I use 8 steps - if I switch to 16 steps, then I hear "after.wav".

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 11:58 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Quote:
Well, I didn't get the idea


Same here :). I rewrote the loop last night (almost three hours on this topic, ugh) and put some diagrams in the asm source, but they still don't make it completely clear.

Your emulator probably works right. Changing the timer to the other way and verifying the test failed was a good idea to do.

The test plays three tones. The first one's pitch depends on how the timer is implemented, the second with the pitch it should be, and the third the pitch it would be if the divider is put after the timer. There will probably sometimes be a slight click between the tones (I actually wanted to re-run it on a NES until it did click, so I didn't make it seem as if it should be seamless).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 12:03 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3076
Location: Brazil
Nice test, blargg. I forgot to say this... ^_^;;

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 12:42 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19342
Location: NE Indiana, USA (NTSC)
blargg wrote:
The test plays three tones. [...] There will probably sometimes be a slight click between the tones (I actually wanted to re-run it on a NES until it did click, so I didn't make it seem as if it should be seamless).

Or you could insert clicks manually with CPU$4011. Do you plan on making an updated version of the test case?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 3:13 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
As a reminder, the square duty handling isn't something that is detectable from the 6502 CPU, so instead of having a nice pass/fail result code printed on screen, the test has to cause a large audible difference when there is a problem. Every test of this sort requires a unique strategy for magnifying differences in behavior, and the pass/fail result will of course be different. I need to better document what is relevant to the test result, and what can be ignored.

I'm working on a set of kick-ass validation ROMs to verify both the documented operation of the APU and emulator implementations of it. The few tests I've released are just a preview of what's to come. I'm thrilled to be working on these because they are so useful for validating an emulator, especially when you make big changes to it. I hope to get around to writing tests for the CPU, memory, and PPU subtleties too. I love being able to shine a spotlight into obscure corners of software so it can be improved.

Disch's recent distinction between APU behavior that affects long-term emulation accuracy (things that code running on the CPU can detect) and that which only affects audio output was useful in helping me focus on finishing the ROMs that validate CPU-detectable APU errors. It's been very difficult figuring out a strategy of what to test, how to test it, how to package the tests, etc.

I'm sure everyone will enjoy implementing the new complex APU frame counter behavior once I get it documented and finish the test ROMs (not!). I haven't even implemented it yet.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: Gilbert and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group