It is currently Mon Oct 23, 2017 9:11 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Feb 07, 2015 1:34 pm 
Offline

Joined: Mon Sep 27, 2004 2:57 pm
Posts: 1248
In one of my projects, I needed NTSC/PAL detection so I could clean up screen-split scanlines. I didn't want to use the cycle counting method on the wiki because I preferred not adding one-time-use code to the NMI, so I came up with this alternative method instead, which runs as part of the reset routine, where you need to poll $2002 for vblanks for PPU stabilization anyway.

It works by having a cycle-timed loop that causes a forced blanking period long enough to skip past the first few scanlines on NTSC machines, while short enough to expire while still in vblank on PAL machines. A sprite 0 hit is set up during the portion of the frame that gets blanked on NTSC, so the passing/failing of the sprite 0 hit flag determines whether the machine is NTSC or PAL.

I'm putting it here just in case anyone's interested.

This code assumes CHR-RAM, but it could easily be modified for CHR-ROM; FCEUX indicates that rendering gets enabled on scanline 17 (about double than what's needed), so just removing the tile upload won't disturb the timing. It also runs after a RAM-clearing routine, so all RAM is zeroed when this runs.

Code:
 ldy #$03      ; Wait for 3 vblanks, for the PPU to ready itself
ppu_stabilize
 bit $2002
 bpl ppu_stabilize
 dey
 bne ppu_stabilize

 ; Detect NTSC/PAL
 ; At this point, we're right at the beginning of vblank. Upload a known tile.
 ; Y is 0 right now
 sty $2006
 sty $2006
 dey
 sty $2007
 sty $2007
 sty $2007
 sty $2007
 iny
 ; Put tile 0 at the beginning of the first nametable
 lda #$20
 sta $2006
 sty $2006
 sty $2007
 ; Set sprite 0 to 0,0 on screen. All-zeroed ram will already have this.
 sty $4014
 ; Set scrolling such that the first byte of the first nametable is at 0,0 on screen,
 ; that and we're using page 0 for both bg and sprites
 sty $2000
 sty $2005
 sty $2005
 ; Wait for a bit
wait_loop1
 inc $FF
 dec $FF
 dey
 bne wait_loop1
 ; On NTSC, this wait will be several scanlines longer than vblank
 lda #$1E
 sta $2001
 ; Enable rendering, on NTSC, rendering will start past sprite 0, so the sprite 0
 ; hit will fail.
wait_loop2
 inc $FF
 dec $FF
 inc $FF
 dec $FF
 dey
 bne wait_loop2
 ; If this is PAL, we should be in the visible portion of the frame by now, which means
 ; sprite 0 would've been detected.
 lda $2002
 asl
 asl
 rol palFlag
 tya
 sta $2001
 ; I defined my reset routine to exit with A = X = Y = 0, so TYA/STA instead of STY.


A Dendy would be detected as NTSC. Considering the purpose of this code is to determine whether to use NTSC or PAL screen timings, and the Dendy was designed to be compatible with NTSC timings, this is appropriate.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 2:48 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5736
Location: Canada
Interesting alternative.


I don't consider tepples' NTSC/PAL detection on the wiki an addition to my NMI routine though. All of that code is outside the NMI, it just requires that your NMI handler:
1. Increments a frame counter variable.
2. Can finish in under 1500 cycles (doesn't have to always, just requires that it can).

Every NMI handler I've written has needed to meet these requirements whether or not I wanted to use the detection code, so there's never been any loss/complexity in the handler to support tepples' detector.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 4:35 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
True, one can just set flags that tell the NMI handler that there is nothing to draw, no music to play, etc. But a "run the entire game engine in NMI" style engine (e.g. SMB1) or a "constant timed NMI to do some raster effect at the top" engine (is this Battletoads?) might have trouble with this. Putting in a variable to disable this behavior might count as "adding one-time-use code to the NMI".

Anyway, as you point out, Dendy doesn't need adjustments to raster effects or music pitch, unlike PAL NES. But how are you adjusting game speed or music speed? In those respects, Dendy needs to be handled like a PAL NES.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 5:10 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5736
Location: Canada
I suppose if you had no use for a frame counter or NMI lockout variable, the lightest you could make it is a 5 cycle indirect JMP at the head of your NMI routine, also taking up 2 permanent RAM bytes. (You would need a temporary frame counter during detection, but you can reuse it after startup.) Or if you want to avoid using any extra RAM you could BIT, BMI with your PAL/NTSC detect variable initialized to $80 in 6 cycles (7 if not ZP).

5 cycles isn't much (you can barely store a byte to the PPU in this time), and it's certainly not an impediment to timed code.

Still, if you don't need it, you don't need it. It's good to have other options, like Drag's.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 5:38 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
Relying on sprites and rendering sounds like overkill to me... I do my region detection right after the mandatory waits for VBlank in the initialization code (i.e. it doesn't involve the NMI at all), when the CPU is reasonably aligned with the PPU:

Code:
   ;wait for the PPU to become stable
   bit PPUSTATUS
-   bit PPUSTATUS
   bpl -
-   bit PPUSTATUS
   bpl -

;----------------------------------------------------------------
; console detection - start
;----------------------------------------------------------------

   ;wait for the next NTSC vertical blank (PAL and Dendy would take longer)
   ldx #$70
-   ldy #$35
--   dey
   bne --
   dex
   bne -

   ;detect whether the frame rate is 60Hz or 50Hz
   lda PPUSTATUS
   sta FrameRateIs60

   ;wait enough time to reach the PAL vertical blank (Dendy would take longer)
   ldx #$70
-   ldy #$05
--   dey
   bne --
   dex
   bne -

   ;detect whether vertical blanks are long or short
   lda PPUSTATUS
   sta VBlankIsLong

;----------------------------------------------------------------
; console detection - end
;----------------------------------------------------------------

I use separate flags for the frame rare (60Hz = NTSC; 50Hz = PAL/Dendy) and for the VBlank length (long = PAL; short = NTSC/Dendy) because the Dendy is a mix of PAL and NTSC, so I'd rather make decisions based on these two aspects separately than check for a specific type of console.

If you didn't care about telling PAL and Dendy apart, just the first part would be enough to detect NTSC vs. PAL/Dendy, and I think it's a pretty simple way to do it. You know you're in VBlank, so just wait enough cycles to be in VBlank again, if you're not, the console is not NTSC. Can't get any simpler.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 8:11 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6303
Location: Seattle
Here's the detection code I added for the the NROM port of Driar:
Code:
;;; the "nice" thing is that I'm using the PPU power-on wait to detect the video system-
        ;; A,X,Y are all 0 at entry
@vwait1:
        bit $2002
        bpl @vwait1  ; at this point, about 27384 cycles have passed
@vwait2:
        inx
        bne @noincy
        iny
@noincy:
        bit $2002
        bpl @vwait2  ; at this point, about 57165 cycles have passed

;;; BUT because of a hardware oversight, we might have missed a vblank flag.
;;;  so we need to both check for 1Vbl and 2Vbl
;;; NTSC NES: 29780 cycles / 12.005 -> $9B0 or $1361 (Y:X)
;;; PAL NES:  33247 cycles / 12.005 -> $AD1 or $15A2
;;; Dendy:    35464 cycles / 12.005 -> $B8A or $1714

        tya
        cmp #16
        bcc @nodiv2
        lsr
@nodiv2:
        clc
        adc #<-9
        cmp #3
        bcc @noclip3
        lda #3
@noclip3:
;;; Right now, A contains 0,1,2,3 for NTSC,PAL,Dendy,Bad
Modifying Driar's NMI was out of scope, so (like you) I wanted a NMI-less solution.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 8:26 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
lidnariq wrote:
BUT because of a hardware oversight, we might have missed a vblank flag.

This is why I think it's a better idea to wait the number of cycles that are supposed to pass and check the VBlank flag than wait for the VBlank flag and check how many cycles have passed. The hardware oversight becomes irrelevant.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 8:49 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6303
Location: Seattle
tokumaru wrote:
This is why I think it's a better idea to wait the number of cycles that are supposed to pass and check the VBlank flag than wait for the VBlank flag and check how many cycles have passed. The hardware oversight becomes irrelevant.
I'm not clear why it matters if we lose one or two vblanks? And being able to detect Dendy is handy, even though you gave good reasons to not care.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:07 pm 
Offline

Joined: Mon Sep 27, 2004 2:57 pm
Posts: 1248
tokumaru wrote:
I use separate flags for the frame rare (60Hz = NTSC; 50Hz = PAL/Dendy) and for the VBlank length (long = PAL; short = NTSC/Dendy) because the Dendy is a mix of PAL and NTSC, so I'd rather make decisions based on these two aspects separately than check for a specific type of console.

Wow, I really like your technique. Do you mind if I use it?


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:17 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
Drag wrote:
Wow, I really like your technique. Do you mind if I use it?

Not at all... if I did I wouldn't have posted it! :wink:


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:23 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
The 0=NTSC, 1=PAL NES, 2=Dendy scheme admits the following rules:
  • If non-zero, correct speeds.
  • If bit 0 is true, correct pitches and raster effects.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:36 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
lidnariq wrote:
I'm not clear why it matters if we lose one or two vblanks?

Well, you did solve the problem by dividing the cycle count by 2 if it's too big, but I normally prefer the solution that doesn't need workarounds.

Quote:
And being able to detect Dendy is handy, even though you gave good reasons to not care.

I don't know if I'd go out of my way to support the Dendy, but as long as it's just "do like on PAL" or "do like on NTSC", I'll probably try to keep my programs working properly on that console as well.

tepples wrote:
The 0=NTSC, 1=PAL NES, 2=Dendy scheme admits the following rules:
  • If non-zero, correct speeds.
  • If bit 0 is true, correct pitches and raster effects.

Yeah, it's true that if I were to completely separate all aspects I'd need more flags, but like you said, 2 bits are enough. I probably should find better names for my variables, but the reason I have them in separate bytes is that I can just use BIT to test them, while keeping them in the same byte would require the accumulator for testing.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:41 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
It only takes a "bit" of code to map those values to $00=NTSC, $C0=PAL NES, $80=Dendy. This way N means correct speeds, and V means correct raster effects and pitches.


Top
 Profile  
 
PostPosted: Sat Feb 07, 2015 9:58 pm 
Offline

Joined: Mon Sep 27, 2004 2:57 pm
Posts: 1248
Thanks a bunch!

By the way, yes, I'm doing something like Battletoads where I'm using forced blanking to upload more stuff to the PPU per frame, making it necessary to know what timing is being used for the screen.

And yeah, I know I can make accomodations in my NMI, but I still preferred a way to do it without needing the IRQs. It's nice to see everyone's approach to the solution, and that there indeed was something simpler than what I was doing. :P

I was using the flag I generated as an array index too, instead of just a boolean, so having each bit separated is going to be beneficial in some cases.


Top
 Profile  
 
PostPosted: Sun Feb 08, 2015 1:59 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6303
Location: Seattle
The real problem, as I can see it, is that Dendy = NTSC DPCM, NTSC prerender time, NTSC raster effects, PAL NMI speed (affecting both music engine and game play), PAL master palette, PAL color emphasis bits. So "just treating it as PAL" is ok if you do no raster effects nor use DPCM, and "just treating it as NTSC" is ok if you're ok with the game slowing down and don't use the color emphasis bits.

I was going to say something about the DPCM rates, but I realized that I don't actually know what they are. Are the DPCM / noise channel periods the same from the 2C02 to the UA6527P?

edits in green


Last edited by lidnariq on Sun Feb 08, 2015 1:26 pm, edited 1 time in total.

Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users 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