Just wondering if this is the generally accepted approach to detecting if you are in a PAL or an NTSC system.
- In the NMI handler clear a counter and set a flag variable and RTI
- In the reset handler infinite loop, if the flag is set increment a counter over and over (probably needs to be 16 bit)
- When the next NMI handler fires, un-set the flag (or change states in the state machine), and determine what mode we are in based on that counter. I can look at the values in a debugger and so I can see which value I get on PAL and which on NTSC, and base my mode on those values.
Is this how you guys do it? I want to make sure I approach this correctly.
Thanks,
Al
A simpler way would be to start a two notes on the APU with lengths 1 and 2, poll $4015 until the first one stops, then poll $4015 until the second one stops and count the number of iterations. The count will tell whether it's NTSC or PAL. When I get a spare moment I'll try implementing this and testing it on both types of NES.
If you write to $4017 to reset the frame sequencer immediately before running the test, then you'll only need one note (of length 1) to determine the timing. This method is probably the simplest since it does not depend on interrupt code timing (which can vary as you extend the capabilities of your NMI handler). However, it might not work well in emulators that don't properly implement APU timing (especially for PAL). Using NMI timing is likely to be more emulation-safe.
Hey, I'm getting a bit outtopic, but I also trough of this method once, when brainstorming about how a MMC5 cart could detect if it has it's sound hardware implemented or not. Just start a note with a run time-lenght, and poll $5015 for a while. If it's set forever (or clear forever), then the MMC5 doesn't have sound. Unfortunately, carts without sound still have it implemented. This could still detect bad emulators or simplified MMC5s faked by other circuits.
I like the method you mentioned blargg (and dvdmuth) since it means a much smaller change, particularly to my NMI and state machine.
I have a question about how you test though. Are you able to run a PAL NES (with a proper power converter) on an NTSC TV.
Al
Now that I look at Years Behind, it seems I actually used the buggy polling of $2002 to wait for the next frame when doing the PAL/NTSC detection. This should mean that with enough resets, you could in theory get the cart to run on NTSC with a lucky shot. The demo would crash later on though.
Gotta try this sometime. :)
I got it working. I reset the frame counter, emit a sound, and poll 4015 until the sounds completes. However I dont really know why the sound that I chose works. As far as I can tell, its a zero length sound. Is the reason it worked because I disabled the length counter, or because a sound cannot have a length of zero.
Anyways here's the code.
Code:
; Reset the audio frame counter
LDA #$40 ; same as #%01000000
STA $4017
; Make a sound on rect1
LDA #$00
STA $4000
STA $4001
STA $4002
STA $4003
; Poll 4015 (lowest bit is rect1) until the sound goes away
TEST_REGION:
INC REGION_CHECK_LOW
BNE :+
INC REGION_CHECK_HIGH
:
LDA $4015
AND #$01
BNE TEST_REGION
Even though it works, am I actually doing this right?
(edit- make the code readable)
BTW: REGION_CHECK_LOW and REGION_CHECK_HIGH are variables on zero page.
I found that in FCEU the high gets a value of 0x22 on NTSC and 0x26 on PAL (so I just say its PAL if the value exceeds 0x24) Seems to work find in Nintendulator as well (although I'm having troubles viewing the memory). Real hardware (NTSC) is also fine.
Al
OK, you've persuaded me to write some code and run it on my NTSC and PAL NES motherboards. As for zero length, remember that the value you write to $4003 in the upper 5 bits is an index into the length table, not the length itself. As I remember, $00 gives a length of $0A. If you used $18 (corrected), you'd get a length of $02, the shortest available. Same goes for writing zero to $4000; this doesn't give zero volume, but rather a quick envelope. The reason you get a silent square is because you used a period of 0 ($4002 and $4003).
EDIT: made correction, should have been length index $18, not $08.
Thanks Blargg. That makes more sense to me now.
Al
Here's some code tested on NTSC and PAL NES boards. The routine doesn't modify X or Y and doesn't need any zero-page locations. I put the decision point mid-way between NTSC and PAL, so an emulator with slightly different timing should still work. To use, run the routine then examine the Z flag or see if A is zero or not:
Code:
jsr is_pal_nes
sta is_pal_flag
bne is_pal
is_ntsc:
...
is_pal:
...
; Deteremines whether code is running on an NTSC or PAL NES
; For NTSC, A = 0. For PAL, A != 0. Z flag also set.
; Chanes APU frame sequencer mode and $4015 enables.
; Takes about 1/60 second to complete.
; Preserved: X, Y
is_pal_nes:
; Start tone
lda #$40 ; reset frame sequencer, IRQ off
sta $4017
lda #$01 ; enable square 0
sta $4015
lda #$00 ; pitch = 0 (silent)
sta $4002
lda #$18 ; load length with $02
sta $4003
; Count time until tone stops
lda #5 ; makes NTSC and PAL be equal
sec ; distances from $80 after loop
is_pal_nes_loop:
adc #0 ; iter counter
pha
lda #$D0 ; internal delay loop
is_pal_nes_delay:
adc #1
bne is_pal_nes_delay
lda $4015 ; C set if tone is running
lsr a
pla ; doesn't modify C, but does set N flag
bcs is_pal_nes_loop
; A=$79 for NTSC
; A=$86 for PAL
bmi is_pal ; PAL if count >= $80
lda #0 ; clear to 0 if NTSC
is_pal:
rts
On real hardware (front loading NES) this code seems to work the first time but not after the reset button is pressed. Runs fine in emulators I have checked, but they will likely do something different at reset. According to microbug is_pal_nes_loop is never exited. Using microbug shouldn't be a problem because it is waiting for the audio to not be playing? Any ideas?
LJ65 (formerly Tetramino) currently has separate builds for NTSC and PAL. I lock out users of the wrong build because they have different delays in them, and I don't want people cheating by claiming scores from the NTSC version run on a PAL machine. LJ65's init code just counts cycles between two NMIs.
Famicom, NTSC NES, PAL/M NES, PlayChoice: 262*341/3 ~= 29780 c
PAL NES: 312*341/3.2 ~= 33247 c
Dendy is thought to use PAL scanline count but an NTSC compatible divider, which would give 312*341/3 ~= 35464 c. But does anyone on this board have access to a Dendy unit and a devcart to run tests?
Why exactly did you change the title? Legal trouble?
This is for a physical cart so separate builds is just a hassle. And its some previously unknown info about the NES state
NES - stuck in loop after 1st reset
RetroDuo - game doesnt run, stuck in loop first time?
NEX - no problems
FC Twin - no problems
FC Mobile - no reset button, game runs fine
How about just waiting a few frames, make sure DMC is disabled, and between two NMIs, see whether 29780 (NTSC), or 33247 (PAL) cycles pass?
Maybe give or take 50. That will also make it more emulator friendly.
Yes there are other ways to do it, but they don't answer the question of why that fails after reset on real hardware. $4015 unreliable? Does the APU need some kind of resetting? Is there something else it needs?
Brian, have you tried clearing $4000 and $4001 using your routine.
I dont know if it will change anything, but if it does it might imply an unknown state of those registers during reset.
Al
Al Bailey may be my hero
I wrote #$00 to both $4000 and $4001 and it at least exits the loop now. Used PowerPak so I will have to build a real board to test on RetroDuo.