Latch timing

Strictly for discussing ZSNES development and for submitting code. You can also join us on IRC at irc.libera.chat in #zsnes.
Please, no requests here.

Moderator: ZSNES Mods

Post Reply
Reznor007
Lurker
Posts: 118
Joined: Fri Jul 30, 2004 8:11 am
Contact:

Post by Reznor007 »

anomie wrote:Or is the converter just skipping or stuttering frames to bring it very close to 60/1.001 Hz?
It doesn't skip frames, the TV appears to sync up perfectly. Come to think of it, certain model TV's won't work with the MK games because of the odd refresh(mainly certain Sony Wega TV's), so I believe the TV adjusts its own sync rate.

EDIT- http://www.jrok.com/hardware/RGB.html That's the actual converter I have.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

More APU timing results: the 64KHz timer ticks every 16 SPC700 cycles, and no 'refresh' or anything was detected. But is it really 64 KHz?

The problem so far: in a normal frame, the SPC700 should execute on average (1365*262-2)/(1.89e9/88)*1024000 ~= 17051.1 cycles. OTOH, we can only account for 1314.5*12 = 15774 cycles. So what happens to those other 1277.1 cycles? We get similar numbers for interlace frames, too.
byuu

Post by byuu »

I ran some more timing tests yesterday, and found out some neat things.

First off, a method for getting perfect accuracy with dot timings: I noticed that if there is no variable code at the start of a test ROM, then latching $2137 always results in the same value. In other words, initializing the SNES, then using - lda $4212 : bpl -, - lda $4212 : bmi -, lda $2137 will always latch the same value, no matter how many times you reset. To time an NOP instruction, insert the NOP between the bmi - and the lda $2137, and you'll see the x dot position increase by exactly 3 (assuming FastROM speed).

I used this test to time Interlaced/Non-Interlaced modes. My results are as follows:
The SNES always starts on an even frame, but reading $2137 immediately at startup returns random values. Therefore, a vblank wait should always be used before timing things.
In interlace mode, each scanline is always 1364 master cycles. Even frames have 263 scanlines, and odd frames have 262 scanlines.
In non-interlace mode, all scanlines are 1364 master cycles long, and both even and odd frames have 262 scanlines. It skips right over scanline 263 (262 with 0-262), so there are in fact 524 scanlines for two frames in non-interlace mode. The only anomaly is that on odd frames, scanline 241 is 4 master cycles (1 dot) short.
This is exactly what TRAC/various NES scene people have described, except that it occurs on scanline 241 ($f1), and not 240.
Here are my timing results to verify this:

Code: Select all

Format: (opcode) x (number of times executed) { ($213c) : ($213d) }
nop = 12 master cycles, or 3 dots.
If each scanline is 341 dots, then nop * 341 should run exactly 3 scanlines.
The nearest evenly divisble number of nop's that will push to the next frame is 264 scanlines, or: 264 scanlines -> ((1324*264)/12) -> 29128

/* interlace test */

odd frame:
  nop x     0 { 000e : 0000 }
  nop x 29128 { 000e : 0002 }
even frame:
  nop x     0 { 0008 : 0000 }
  nop x 29128 { 0008 : 0001 }

/* non-interlace test */

odd frame:
+ nop x     0 { 0009 : 0000 }
+ nop x 26480 { 0009 : 00f0 }
  nop x 26481 { 000c : 00f0 }
  nop x 26500 { 0045 : 00f0 }
  nop x 26520 { 0081 : 00f0 }
  nop x 26521 { 0084 : 00f0 }
  nop x 26522 { 0091 : 00f0 } (87+0a)
  nop x 26530 { 00a9 : 00f0 }
  nop x 26697 { 0153 : 00f1 } >
  nop x 26698 { 0002 : 00f2 } <
  nop x 26701 { 000b : 00f2 }
+ nop x 26811 { 000a : 00f3 }
  nop x 26591 { 000c : 00f1 }
+ nop x 29128 { 000a : 0002 }
even frame:
  nop x     0 { 000f : 0000 }
  nop x 29128 { 000f : 0002 }
I don't know when the DRAM refresh signal is raised, but the latest dot position that can be latched is $86.

Code: Select all

dram refresh timing:
  nop x 26521 { 0084 : 00f0 }
  nop x 26522 { 0091 : 00f0 } (87+0a)
  nop x 26301 { 0086 : 00ee }
DRAM Refresh is, without a doubt, exactly 40 master cycles (10 dots) long. It occurs on every scanline at the same position regardless of interlace/frame #.

I need to run more tests, but I believe that when you latch $2137, it does not latch the position until -after- the current instruction has completed. Thus, lda $37 will latch a lower value than lda $2137. I don't know if the counters are latched mid-opcode, or at the end, though.

Lastly, I need to see what happens when you toggle interlace mid-frame. Right now, I ignore interlace changes until the start of the next frame, but I have a feeling this is incorrect. Much like overscan, it can probably be changed wherever it wants to. I also have no info on certain dots being longer/shorter than others, but from my tests above, I didn't experience them personally. I also wasn't trying to.
Lord Nightmare
Rookie
Posts: 14
Joined: Fri Nov 26, 2004 7:50 pm
Location: PA, USA
Contact:

Post by Lord Nightmare »

Reznor007 Wrote:
Email Guru and ask if he can measure a SNES. He has tons of equipment for hardware analysis and ROM dumping.
Guru doesn't have an email, he doesn't like spam. I did talk to him on IRC about this, here are some log excerpts:

<Lord_Nightmare> you around? do you have an snes and an o
scilloscope? http://board.zsnes.com/phpBB2/viewtopic.php?t=1700
<Guru> just woke up
<Guru> i have a scope, but not a snes
<Lord_Nightmare> d'oh! oh well. ...

So if anyone wants to send an SNES to Guru for testing....

Lord Nightmare
"When life gives you zombies... *CHA-CHIK* ...you make zombie-ade!"
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:DRAM Refresh is, without a doubt, exactly 40 master cycles (10 dots) long. It occurs on every scanline at the same position regardless of interlace/frame #.
How do you figure this? I can't think of any dot-latching test results that would work with 40 master cycles and 1364 master cycles per scanline but wouldn't work with 41 master cycles, dot $87 being 5 master cycles long, and the whole scanline being 1365 master cycles long. We already see weirdness with dots $143 and $147, so why not one more?

That's one of the reasons I've been trying to make sense of the SPC700 sync, being completely independant that could test the refresh length...
I need to run more tests, but I believe that when you latch $2137, it does not latch the position until -after- the current instruction has completed. Thus, lda $37 will latch a lower value than lda $2137. I don't know if the counters are latched mid-opcode, or at the end, though.
lda $37 versus lda $2137 is obvious anyway just from the timings in the datasheet. The latch must begin during the 6 master cycles $2137 is being read (although whether it goes during the first cycle, the last cycle, or even delays a few cycles we don't know).
Lastly, I need to see what happens when you toggle interlace mid-frame. Right now, I ignore interlace changes until the start of the next frame, but I have a feeling this is incorrect.
It is incorrect, at least as far as the display goes. I've used HDMA to toggle interlace for only the middle portion of a frame and that middle portion was rendered 'interlaced'. I'm not sure if it's really interlacing or just flickering the BG like OBJ does with $2133=2. I can't say what happens with the frame timing at all.

When you say 'even' and 'odd', does this have anything to do with $213f bit 7? Are 'even' frames always 263 scanlines in interlace mode, no matter if you first enable interlace on an even or an odd frame? And ditto for disabling interlace and the parity of the 262*1324-2 frame?

BTW, very nice work.
byuu

Post by byuu »

How do you figure this? I can't think of any dot-latching test results that would work with 40 master cycles and 1364 master cycles per scanline but wouldn't work with 41 master cycles, dot $87 being 5 master cycles long, and the whole scanline being 1365 master cycles long. We already see weirdness with dots $143 and $147, so why not one more?
This is certainly a possibility. The way I did my test was to run over an entire frame. If the refresh was more than 40 master cycles, then it would have thrown off my overall result of executing 264 scanlines worth of nop's.
The way I'm thinking about it, the SNES actually gives the program code as many cycles as I've mentioned, exactly that many, there may be more that are hidden somewhere. If refresh is longer, and/or one of the dots is actually longer, then it is faking the dot counter position. It just seems like that's too complex. There's no reason to fake the dot counter position like that, and then allow something like the scanline 241 exception. Also, if one dot position is longer than the others, then it -has- to even back out somewhere on that exact line, otherwise my tests would be incorrect.
I haven't really tested for what dot positions are longer/shorter, nor am I sure how I'm going to go about that, given we can't get within more than 2 master cycles accuracy (nop fastrom = 12, slowrom = 14).
That's one of the reasons I've been trying to make sense of the SPC700 sync, being completely independant that could test the refresh length...
I'm still working on my spc700 core. Once I get that done, I'll start trying to time the SNES CPU against the APU. I think it'll be a real pain, but doable.
It is incorrect, at least as far as the display goes. I've used HDMA to toggle interlace for only the middle portion of a frame and that middle portion was rendered 'interlaced'. I'm not sure if it's really interlacing or just flickering the BG like OBJ does with $2133=2. I can't say what happens with the frame timing at all.
I've tried that before as well, actually. I noticed some oddities in what the PPU draws when you do that, but I'll focus on that once I get the timing figured out without messing with interlace mid-frame.
When you say 'even' and 'odd', does this have anything to do with $213f bit 7? Are 'even' frames always 263 scanlines in interlace mode, no matter if you first enable interlace on an even or an odd frame? And ditto for disabling interlace and the parity of the 262*1324-2 frame?
The SNES starts on an even frame. An even frame is scanlines 0, 2, 4, 6, ... 524. Odd would be 1, 3, 5, ..., 523. In non-interlace, it probably draws to the even scanlines twice, and ignores the last line, but $213f bit 7 does change each frame, either way.
So you can see why in interlace, the even frame has 263 scanlines.
I don't know what happens when you toggle interlace mid-frame. For my test, I enabled interlace on the even frame (right when the SNES started), then I waited until the start of the next frame, odd, by waiting for 4212 bit 7 to be set, then cleared. To get to an even frame, I waited on 4212 to be set and cleared twice.
BTW, very nice work.
Thanks, you too. Your efforts have saved me hundreds of hours of reverse-engineering strange quirks of the SNES and PPU.
Reznor007
Lurker
Posts: 118
Joined: Fri Jul 30, 2004 8:11 am
Contact:

Post by Reznor007 »

Lord Nightmare wrote:Reznor007 Wrote:
Email Guru and ask if he can measure a SNES. He has tons of equipment for hardware analysis and ROM dumping.
Guru doesn't have an email, he doesn't like spam. I did talk to him on IRC about this, here are some log excerpts:

<Lord_Nightmare> you around? do you have an snes and an o
scilloscope? http://board.zsnes.com/phpBB2/viewtopic.php?t=1700
<Guru> just woke up
<Guru> i have a scope, but not a snes
<Lord_Nightmare> d'oh! oh well. ...

So if anyone wants to send an SNES to Guru for testing....

Lord Nightmare
Hmm...him not having email must be new. I used to email him a few months back. I sent him a few Sega Model 1 arcade PCB's for emulation purposes.
byuu

Post by byuu »

Ok, I'm going to be running some more tests (hopefully) today.
The first will be to determine the lengths of each dot, with extra emphasis on $143/$147. To do this, I'm going to use - lda $4212 : bpl - : - lda $4212 : bmi - : lda $37, and get the latch value. Then do the same with nop (SlowROM) : lda $37. Let's say the first value was $09. If the second value is $0c, then we know we are at cycle $0c*4+2, if the second value is $0d, then we know we are at $0d*4+0. I'll then add just enough cycles to get to scanline 1 dot 0 cycle 0. I can then use a combination of opcodes to determine the lengths of every dot within 2 cycles of accuracy. I'll run the test on a couple of scanlines until I'm satisfied that they're all the same, and make special note of scanline 241 non-interlace odd frame. My current theory is that $143/$147 is 6 master cycles long, and the scanline has dots 0-339, and that scanline 241 non-interlace odd frame has $143/$147 as regular 4 cycle dots, and is still 0-339, but we shall see ;)

My next test I'm going to need help on. My goal is to find out how many frames per second the SNES runs at. The idea is to make a ROM that prints a message, like 'press start'. The user will run this on a copier/flash cart, and press start, and immediately start a stopwatch/clock. When a message appears that the test is done, the user will stop the timer.
The test will just be a sequence of 'wait till next frame' commands.
We know that if the SNES runs at NTSC speed, it will be 59.97fps, if it runs at its own clock speed (NTSC color subcarrier * 6), it will be 60.0855fps, or maybe it's just 60fps.
If we wait for 3600 full frames to occur, the test should take either 59.97 minutes, 60.0 minutes, or 60.0855 minutes. Too close to call, so if we make it wait for 36,000 full frames, then it will take 599.7 minutes, 600 minutes, or 600.855 minutes. We could increase it longer, too.
What I need is as many people as possible to run this test to make sure we're all getting the same results, and someone to help verify that there's no errors in my calculations.
I'll wait for some opinions from you guys, then make the ROM and post it here for review.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

More SPC700 results: i finally found a way to get the numbers to add up to match the results observed on my real SNES! But it's a rather interesting change: i have to simulate the SPC700 at ~1026900 Hz rather than 1024000 Hz (or decrease the 5A22 master clock to give the same ratio (or both)). Any thoughts on this?
byuusan wrote:My goal is to find out how many frames per second the SNES runs at. The idea is to make a ROM that prints a message, like 'press start'. The user will run this on a copier/flash cart, and press start, and immediately start a stopwatch/clock. When a message appears that the test is done, the user will stop the timer.
I'm going to try to run some tests like this tomorrow. Hopefully I can get sufficient stopwatch accuracy by hand. Otherwise, I suppose i could have my SNES play some tones to start and end the test and have my computer automatically start and stop the timer based on the microphone input ;)
byuu

Post by byuu »

i have to simulate the SPC700 at ~1026900 Hz rather than 1024000 Hz (or decrease the 5A22 master clock to give the same ratio (or both)). Any thoughts on this?
Sadly, no. Haven't done much with the SPC700 yet.
I'm going to try to run some tests like this tomorrow. Hopefully I can get sufficient stopwatch accuracy by hand. Otherwise, I suppose i could have my SNES play some tones to start and end the test and have my computer automatically start and stop the timer based on the microphone input ;)
If you make the frame count big enough, you won't even need the stopwatch ;)

Sorry I still don't have any of my tests done, I've been kind of taking it easy, as I'm a tad bit worn out at the moment. Also been job hunting all week >_<
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:If you make the frame count big enough, you won't even need the stopwatch ;)
But i'd rather not spend all day running just one test ;) 35 minutes is long enough.

Results: Non-interlace mode takes ~2129.981788 seconds to run 128000 frames. Interlace takes ~2133.850515. That's ~60.09 and ~59.98 fps.

More results on the scanline timing as well. I forgot to mention it earlier, but that 1026900 figure for the SPC700 only works with 1364 cycles per scanline. And now this latest test again gives 1364 cycles per scanline at a master clock rate of 1.89e9/88 Hz to make the numbers work. I think we have it, finally! :D
byuu

Post by byuu »

Awesome, so now all we need to do is figure out all the dot anomalies, what happens when you change $2133 bit 0 mid-frame, and I'll run the FPS timing again, just to add verification to your results, and we should be good!
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:Awesome, so now all we need to do is figure out all the dot anomalies
I've found that non-interlace dots $143 and $147 are 6 master cycles instead of 4. You've found that line 241 is short every other frame, so i'm sure that those two dots become normal then. That's it.

Oh, and i've yet to get a clear answer on whether $213f bit 7 corresponds to the long/short frames or not.

IOW, is this chart (or a similar one) correct, or is there no such chart?

Code: Select all

   |      $2137 bit 1
   |     0      |    1
---+------------+-----------
 I | 1364*263   | 1364*262
---+------------+-----------
NI | 1364*262-4 | 1364*262
what happens when you change $2133 bit 0 mid-frame
Well, if you change it and then change it back mid-frame, i suspect the frame lengths are as if you had never changed it (but that portion is still 'drawn' as if in the other mode). But just where is the cutoff point is, i don't know. It's even possible that there's two cutoff points (end of scanline 241 (and then what if you change it between dots $143 and $147...?) and end of scanline 262?), so you could get a frame 1364*263-4 somehow. Whee.
byuu

Post by byuu »

The chart is incorrect. $213f bit 7 = 0 is for even frames, $213f bit 7 = 1 is for odd frames. The odd frame lacks 1 dot on scanline 241.
Therefore, the correct table should be:

Code: Select all

$213f |          |
bit 7 |     0    |     1
------+----------+------------
   I  | 1364*263 | 1364*262
------+----------+------------
  NI  | 1364*262 | 1364*262-4
The SNES starts with $213f bit 7 = 0, $2137 bit 0 = 0
byuu

Post by byuu »

Ok, my cycle to dot test thing is done.
http://setsuna.the2d.com/files/cycle_test.zip

It won't work in any emulators that don't emulate the reset vector properly.
Basically, the first time you start it, it checks a magic value at $7ffffc, if it's there, then it knows it's not the first time running it, and it runs test code located at $7f0000, and then grabs the latch values.
Now, regardless of whether or not its the first time starting it, it will give you a menu where you can tell it how many opcodes to generate for the test. There are four opcodes: nop, lda.dp, lda.addr ($2100), and lda.addr ($0000), which take 14, 24, 30, and 32 master cycles, respectively.
You can tell it to execute each opcode anywhere from 0-4095 times.
When you're ready, press start to generate the code at $7f0000+, and lock the input.
Now, reset the SNES, and it will tell you the x/y positions of $213c/$213d.

Here's how to get perfect timing results: First, start the game on your copier and immediately press start. Reset the SNES, and write down the x position. Let's say it is 47. Now set nop to 1, and the rest to 0. Press start and reset. If the new number is 51, then you were at dot 47 cycle 2 (47*4+2), if the new number is 50, then you were at dot 47 cycle 0 (47*4).
From here, it should be possible to come up with combinations that will touch every dot on every possible position (0 or 2), although you may have to span over a few scanlines to do it.
This is because the smallest increment is 2 cycles, and the last two opcodes have that precision. All 4 opcodes are there to make coming up with counts to reach certain dots easier.
If you need to go to the next frame or toggle interlace, you'll need to do that yourself by modifying the included source code.
I'm going to run this for a while and try and come up with some results that I'll post here. Just wanted to post this here for peer review. Maybe you can play around with it a bit too, anomie?
byuu

Post by byuu »

Ok, finished. It took me 3 1/2 hours to do this, here are my results:
http://setsuna.the2d.com/files/dot_timings.txt

I couldn't do this automatically as I needed to manually reset the SNES each test to guarantee the dot positions always latched at the same time.

My test started on scanline 0 on an odd frame with interlace disabled. It spanned 7 scanlines using SlowROM nop's to latch every possible cycle/dot position (there are 1324/2, or 662 possible positions per scanline).
You'll notice that in the count column, the values range from 0-661.
Count position 662 is identical to count position 0, only 7 scanlines lower.

Basically, my findings are as follows:
You're essentially correct that two dots are 6 cycles long instead of 4, but these two dots are dots 323 and 326 ($143 and $146), not 323 and 327 ($143 and $147). Not a big deal either way, probably just a margin of error in your tests. I checked and verified all of these results twice (two runs through all the results), and dots 320-330 about four times, just to be safe.
Every other dot is exactly 4 cycles long. Thusly, with 1364 cycles/scanline, the effective range for $213c is 0-339.

Code: Select all

Format: (cycle count:$213c dot position:nop opcode count)

1288:322: 78
1290:322:551

1292:323:362
1294:323:173
1296:323:646

1298:324:457
1300:324:268
1302:325: 79
1304:325:552

1306:326:363
1308:326:174
1310:326:647

1312:327:458
1314:327:269
I also beat the hell out of the dram refresh stuff again while I was at it.
Now then, I am absolutely positive that DRAM refresh starts at cycle 536 (dot 134/$86), and is exactly 40 cycles (10 dots) long. Or at the very least, the very last value that can be latched is cycle 534, or dot 133.5

Code: Select all

 528:132:594
 530:132:405
 532:133:216
 534:133: 27
 576:144:500 *DRAM refresh +40
 578:144:311 *DRAM refresh +40
The above numbers can be used with my test program posted above to verify my results.

We also know the interlace/non-interlace even/odd frame timings (TRAC and myself), and the true SNES clock speed (myself) and refresh rates (anomie).
This leaves us with the following tests that need to be run to complete the core system timing:
I) Find out what happens when $2133 bit 0 is toggled mid-frame, around scanline 241, around scanline 261, on scanline 262 on even frames, etc.
II) Find out if dots 323 and 326 exhibit the same effects on all scanlines, especially on scanline 241 non-interlace odd frames. What happens if we enable interlacing on this line? Are the two dots stretched back to 6 cycles each?
III) Does I or II affect the SPC700 timing at all?

I'll start running these tests tomorrow, specifically I and II. I'll have to leave III up to you (anomie), as I am unable to test this myself. Once I'm finished, then we should be done! Perfect SNES timing at last!!
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:

Code: Select all

Format: (cycle count:$213c dot position:nop opcode count)
[...]
1310:326:647
Hmmm... my SNES gives dot 327 here, not dot 326. What are your 5c77 and 5c78 version numbers?
I also beat the hell out of the dram refresh stuff again while I was at it.
Now then, I am absolutely positive that DRAM refresh starts at cycle 536 (dot 134/$86), and is exactly 40 cycles (10 dots) long. Or at the very least, the very last value that can be latched is cycle 534, or dot 133.5
I'm starting to doubt my old assertion that the WRAM refresh waits until the current instruction completes. Would it give the same results to make it pause hard at cycle 536? Hrm... a test: do LDA $37 (with D=2100) and LDA $002137 both have a last-value of 534? Or does one have 526 and the other 542?
and the true SNES clock speed (myself)
I seem to have forgotten this...
III) Does I or II affect the SPC700 timing at all?
I'm fairly certain the SPC700 timing is completely independant. According to the schematics we have floating around, there's nothing besides Address Bus B and /RESET connecting both subsystems. So it should only affect the timing as far as it affects our sampling loops...
byuu

Post by byuu »

Hmmm... my SNES gives dot 327 here, not dot 326. What are your 5c77 and 5c78 version numbers?
Wow, my test ROM does? Interesting...
I have a first-generation style Japanese SNES. I'll read the chip versions later on tonight.
I guess this really doesn't matter too much, huh? Although checking for this would make a great regional lockout, I'm completely certain that emulating the correct dot based on system isn't neccesary.
For the record, though. What versions are your 5c77/5c78? Which region/style SNES?
I'll probably add a toggle, like with $21c2/$21c3. By the way, I tried the SNES Test Program on my copier, and it loops on initializing the scroll registers on that one tests forever there, too. So that's another SNES-model specific difference.
I'm starting to doubt my old assertion that the WRAM refresh waits until the current instruction completes. Would it give the same results to make it pause hard at cycle 536? Hrm... a test: do LDA $37 (with D=2100) and LDA $002137 both have a last-value of 534? Or does one have 526 and the other 542?
Hmm, you're right. My test wouldn't really assert that sort of thing. Let me play around with the other three opcodes on my test program and see what all I can latch.
I seem to have forgotten this...
For NTSC, it is (315/88)*6mhz. With that speed, you end up with ~60.1fps for non-interlace, and ~50.98fps for interlace.
Formula for non-interlace: (((315/88)*6*1000000)/(1364*262+1364*261+1360))*2 = ~60.0988fps
Formula for interlace: (((315/88)*6*1000000)/(1364*525))*2 = ~59.98fps

This means the clock rate is six times the NTSC color subcarrier. I believe this is the case because having an even multiple of the color subcarrier would allow the SNES to better sync with an NTSC TV. Also, the clock chips are probably extremely common in multiples of NTSC, due to how popular televions are. So I wouldn't put this past a cost savings thing for Nintendo.

Keeping in mind that's the refresh rate for each individual frame. There would only be ~29.9920 full frames per second in interlace-mode.
These match the timing results you got yesterday.
Results: Non-interlace mode takes ~2129.981788 seconds to run 128000 frames. Interlace takes ~2133.850515. That's ~60.09 and ~59.98 fps.
Neither speeds match NTSC interlace mode, so the only thing we have to be careful of is if the APU ever gets out of sync with the CPU (e.g. there's a pause) between the end of one frame and the start of the next, or the same with scanlines. This seems unlikely, and I honestly suspect the SNES refresh rate is just slightly higher than NTSC, and TVs still work ok with it. But do we have proof either way, yet?

---

The next thing I would like to take care of is initial latch values, if possible. On my emulator, I always seem to end up latching a value that is ~8 dots higher than a real SNES, when I latch with:
- lda $4212 : bpl - : -lda $4212 : bmi - : lda $2137
This little anomaly makes direct cycle-to-cycle count comparison tests in my emulator vs. the snes impossible. Since the value is a constant every reset, it should be possible to end up with the same start position in emulators.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:I guess this really doesn't matter too much, huh? Although checking for this would make a great regional lockout, I'm completely certain that emulating the correct dot based on system isn't neccesary.
For the record, though. What versions are your 5c77/5c78? Which region/style SNES?
1 and 3 (and 2 for the 5A22, BTW). Normal top-loading US style.
I'll probably add a toggle, like with $21c2/$21c3. By the way, I tried the SNES Test Program on my copier, and it loops on initializing the scroll registers on that one tests forever there, too. So that's another SNES-model specific difference.
Interestingly, my SNES doesn't have trouble with that test. I should probably re-test those for open bus.
Hmm, you're right. My test wouldn't really assert that sort of thing. Let me play around with the other three opcodes on my test program and see what all I can latch.
The important part is the actual latching instruction. If the refresh pause is soft, a longer instruction (LDA $002137) would let us latch a later dot position than a shorter one (LDA $37) since the latch-read comes during the final 6 cycles of the instruction.
For NTSC, it is (315/88)*6mhz. With that speed, you end up with ~60.1fps for non-interlace, and ~50.98fps for interlace.
TRAC told me that number (1.89e9/88 Hz) a long time ago, but I never knew where he got it.
Neither speeds match NTSC interlace mode, so the only thing we have to be careful of is if the APU ever gets out of sync with the CPU (e.g. there's a pause) between the end of one frame and the start of the next, or the same with scanlines. This seems unlikely, and I honestly suspect the SNES refresh rate is just slightly higher than NTSC, and TVs still work ok with it. But do we have proof either way, yet?
Only that it hasn't been found yet, in any of the places I've thought to look for it.


Once we have this timing down, we can try to figure out the timing of NMI, IRQ, and the various bits in $4210, $4211, and $4212.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

The important part is the actual latching instruction. If the refresh pause is soft, a longer instruction (LDA $002137) would let us latch a later dot position than a shorter one (LDA $37) since the latch-read comes during the final 6 cycles of the instruction.
Well, a test of mine gives the same results for LDA $37 and LDA $002137.

OTOH, i get latching on dot $86 in either test... And in your test, if I set {0,0,2,10}=536 (that's 0 NOPs, 0 LDA $00s, 2 LDA $2100s, and 10 LDA $0000s, total 536 cycles) it latches dot 134 line 0! {0,0,1,11}=538 latches [144,0] though. {0,1,26,28}=523 still latches [133,1], but {0,1,25,29}=534 latches [143,1]. {0,2,46,50}=536 latches [134,2] again. {0,4,66,71}=534 latches [143,3] again. {0,5,86,93}=536 is [134,4]. {0,6,109,112}=534 is [143,5]. {0,100,2201,2011}=536 is [134,100]. {0,101,2225,2029}=534 is [143,101]. {39,3880,4071,4067}=536 latches [134,261]. {39,3881,4094,4086}=534 latches [143,0] on the next frame. So... WRAM refresh alternates between starting on cycle 534 and cycle 538?

BTW: you have a bug in your prog, it doesn't do LDA $00 right (it jumps back too far, i just changed the $d8 to a $ee and it works). And it would be helpful to make L and R adjust by 100 ;)
byuu

Post by byuu »

Well, a test of mine gives the same results for LDA $37 and LDA $002137.
My tests indicate that lda $002137 results in a higher value than lda $37.
I'll try it again, though, to be sure.
So... WRAM refresh alternates between starting on cycle 534 and cycle 538?
Seems very possible. My test log actually spanned 7 lines to hit every half-dot (2 cycles) possible, so I didn't think this was the case. With all 4 opcodes, you can reach any half-dot position on any line, which seems to be what you've done in your tests.
We'll need to see what happens with interlace enabled/disabled, and on scanline 241 odd-frame non-interlace, as well then.
As for interlace, I'm curious if the start position will always be 538 for even lines, and 534 for odd, or if the extra scanline will invert that every other frame.
{0,101,2225,2029}=534 is [143,101]
Sorry, that must've taken an eternity to reach >_<

Code: Select all

  rep #$20 : lda !op1_count : tax : sep #$20
.loop_op1 {
    cpx #$0000 : beq .endl1
    lda #$a5 : sta $2180
    lda #$00 : sta $2180
    dex : bra .loop_op0 ;*
  }
.endl1
* - oops. Sorry about that. I copy/pasted the code for that, must've overlooked it... I'll fix this and add the L/R thing to this when I get a chance.

I apologize for going so slowly. I got your e-mail and I'll run your test program next time I get my copier out, as well as get those PPU/CPU version numbers for you. Just have a lot of real life stuff going on at the moment.

---

This is all starting to get kind of complex in the number of small quirks we are finding, so I think I'll start documenting this all very soon, and we can keep revising it until we're as close as we can get. Making some test ROMs that always pass on a real SNES that rely on these quirks would be good, so that emulator authors can verify implementing these things properly.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:My tests indicate that lda $002137 results in a higher value than lda $37.
I'll try it again, though, to be sure.
Send me your test too, so i can check on my SNES.
As for interlace, I'm curious if the start position will always be 538 for even lines, and 534 for odd, or if the extra scanline will invert that every other frame.
It already inverts: {39,3881,4094,4086}=534 latched [143,0]. I suspect it changed around the line-241 thing. To really figure that one out, we'd need to test around line 241 for several frames (can you add a "wait until next frame" 'opcode' to your test to run before the other 4?)
I apologize for going so slowly. I got your e-mail and I'll run your test program next time I get my copier out, as well as get those PPU/CPU version numbers for you. Just have a lot of real life stuff going on at the moment.
No problem.


Hrm... perhaps i should post this before i forget about it. I ran a test recently what set up an IRQ for mid-refresh ($8a, IIRC), fastrom, SEI, and WAI for it, then immediately LDA $37 and look at the H dot position. It ended up latching in a very regular pattern: $98, $98, $97, $98, $97, $99. 0x10000 $98s, 0x5555 $99s, and 0xAAAA $97s. Remember WAI is supposed to take 12 master cycles to 'wake up', but OTOH we don't know whether it starts immediately on the IRQ or whether it tests every 6 master cycles or something...
byuu

Post by byuu »

can you add a "wait until next frame" 'opcode' to your test to run before the other 4?
Yes, but it will break the perfect timing. There's no way to tell where a 'wait until next frame' loop ends.
You'd do something like wai/$4212 bit 7/nmi, but regardless, all 3 methods will result in different latches every time.
So, say wait = 0, x = 39.0, y = 0; wait = 1, x = 41.5, y = 0; wait = 2, x = 38.5, y = 0 (the .5 just meaning it's halfway through the dot)
If you still want that functionality even with that considered, it should be relatively easy to add. An interlace toggle would probably be a good idea as well.
anomie
Lurker
Posts: 151
Joined: Tue Dec 07, 2004 1:40 am

Post by anomie »

byuusan wrote:There's no way to tell where a 'wait until next frame' loop ends.
Use the same loop you use to wait for the start of the first frame: - lda $4212 : bpl - : - lda $4212 : bmi -. If it's reliable to go to the start of the odd frame, shouldn't it be reliable enough to skip to the next even frame too? As long as for each value of 'wait' x is constant each time the thing is run. We'd just have to do the same test with NOPS you did figuring out where wait=0 dropped us.
byuu

Post by byuu »

Ok, the new version is up (v1.01), here:
http://setsuna.the2d.com/files/cycle_test.zip

First, this invalidates our old numbers, because I had to change initialization. Sorry about that, hopefully we won't have to do this again.

Next, I fixed the bug with lda $00 opcodes, thanks for pointing that out. I also added L/R +/- 100 as you suggested. It doesn't check for overflows, so if you press L (-100) when the counter is at 0, the result is ((0 - 100) & 4095). I also added the frame count that you wanted. The program starts by skipping two frames to place it at the start of an even frame. Therefore, if the frame skip counter is an even number, you're on an even frame ($213f bit 7 = 0), if it's odd, then you're on an odd frame ($213f bit 7 = 1).

I also added an interlace toggle, press select to toggle it. The interlace effect has to be enabled before the frame skip code is executed, because weird things happen when your test ends on interlace line 262 and you reset with interlace disabled. I actually ended up getting a counter that ran to x:339, y:0, then reset to x:0, y:0... We'll work on that later.
For now, just keep in mind that if you toggle interlace, the four opcode values/frame skip value will always result in different x/y positions.
We're going to need hand-crafted test ROMs to figure out what happens when you toggle interlace mid-(scanline/frame).

I'm going to go time scanline 241 odd-frame non-interlace/interlace, and I'll post my results here.

Note: About resetting the SNES... I made the program initialize $7f0000 with one rtl now, so if you start the program and immediately reset, it won't crash. Basically what happens when you press start, is the code at $7f0000+ is generated, based on the counters. If you reset without pressing this button, the counters stay updated to their new values, but the old code is still at $7f0000+, so you get the same x/y results. The same applies to the frame skip #.
If you reset the SNES while the code is being generated, it will most likely cause the SNES to die, or return bad results in the x/y counters. A power cycle is needed to correct this.
The toggle interlace doesn't need code in $7f0000+, so it will take effect without pressing start, but I recommend you don't run tests that swap between interlace and non-interlace only, anyway.
Post Reply