A reliable PAL/NTSC check! "Where am I from?" - this quite philosophic question is not uninteresting for C64 programmers. Even those without a SuperCPU may learn something here. by Wolfram Sang (Ninja/The Dreams - www.the-dreams.de) ======================================================= Our beloved Commodores exist in PAL- and NTSC versions, what means they have differences in their cycle clock and picture generation. Let us check the facts: === System VIC-Type-No. Cycles per Raster lines Screen- Clock cycle rasterline per screen refreshrate --------------------------------------------------------------------------- NTSC 6567 65 263 ~60Hz 1022727 Hz PAL 6569 63 312 ~50Hz 985248 Hz --------------------------------------------------------------------------- === A program which relies on this must know on which kind of system it is currently running. The kernal offers the memory location $02A6 for that (0 = NTSC, 1 = PAL), which is accepted as reliable enough by many programmers. Unfortunately, this method has two major disadvantages: First it can lead to wrong results, since this location is only set in the Reset routine ($ff5b - $ff6a). Afterwards the value can be modified (by mistake or intentionally), for example with a simple POKE command. Second, this value will always indicate an NTSC machine when a SuperCPU is running and has been in 20 MHz mode during Reset. To explain that, let's take a further look at the system detection method of the kernal routine. A good idea... As you can see from the above table, a PAL-C64 generates more rasterlines than an NTSC one, exactly 312 instead of 263. To check this, just write a number of a rasterline only existent on PAL into the latch $D011/12 (for example $137 = dec. 311). In the Interrupt Request Register (IRR) at $D019 bit 0 we can see whether there have been the same values in the latch and in the real current rasterline. We just wait until one entire screen has been built up and then look if the rasterline $137 was displayed. Remember: This is only possible on PAL systems! So we have an absolutely sure decision criterium. ... badly realized Why this so sure method now fails with a SuperCPU? Well, this is the fault of Commodore. The responsible kernal routine doesn't wait until a full screen has been built up, it performs some other tasks meanwhile (clear screen etc.). On a standard C64 it is absolutely sure that these tasks take more time than one screen build-up. Unfortunately, the developers at Commodore couldn't know that a 20 MHz turbo board, introduced 15 years later, would be too fast to ever reach rasterline $137. The following routine solves the problem. It delivers a 100% sure identification of the system, even with a SuperCPU in turbo mode. However, only 6510 opcodes were used, so that this routine will also work on an unexpanded C64. The improved version Let's look at our new routine step by step. First we disable the interrupts and set the NMI vector to an RTI - we need silence for the detection of the video mode, any interrupt could lead to a wrong result. Now we wait until $d012 equals zero, meaning that we are either in rasterline 0 or 256. Which one doesn't matter, this check only prevents that the routine is called when the rasterline is close to $137, which could lead to an error under certain circumstances. Now we write the number of our test-line into the latch register. Afterwards we reset the bit 0 in the IRR to remove a maybe existing old request. With the following waiting loop we make sure that an entire screen was really built up. Since we check the rasterline itself for this, this routine will probably still work in 15 years with the 200 MHz ultra turbocard. Now the only thing we need to do is mask out the crucial bit in the IRR, reset $D019 and leave the routine. The value in the accu now represents PAL or NTSC, just like in $02A6, but much more reliable. Finished! As you can see, this check is neither long nor complicated. I urgently recommend to use this one instead of $02A6. Because who likes an X to be treated as a U? === souce code ; Reliable PAL/NTSC-Detector by Ninja/The Dreams/TempesT ; for Go64!/CW issue 06/2000 (detailed description there) ; This routine can't be fooled like $02a6 and works also with a SCPU include standard.c64 nmivec = $0318 ; NMI-vector org $0801 adr $080b, 64 byt $9e,"2061",0,0,0 ; Basic-line jmp_in: lda #lo(text) ldy #hi(text) jsr $ab1e ; print startup-message jsr palntsc ; perform check sta $02a6 ; update KERNAL-variable beq ntsc ; if accu=0, then go to NTSC lda #lo(pal_text) ldy #hi(pal_text) ; otherwise print PAL-text jmp $ab1e ; and go back. ntsc: lda #lo(ntsc_text) ldy #hi(ntsc_text) ; print NTSC-text jmp $ab1e ; and go back. palntsc: sei ; disable interrupts ldx nmivec ldy nmivec+1 ; remember old NMI-vector lda #lo(rti) sta nmivec lda #hi(rti) ; let NMI-vector point to sta nmivec+1 ; a RTI wait: lda $d012 bne wait ; wait for rasterline 0 or 256 lda #$37 sta $d012 lda #$9b ; write testline $137 to the sta $d011 ; latch-register lda #$01 sta $d019 ; clear IMR-Bit 0 wait1: lda $d011 ; Is rasterbeam in the area bpl wait1 ; 0-255? if yes, wait wait2: lda $d011 ; Is rasterbeam in the area bmi wait2 ; 256 to end? if yes, wait lda $d019 ; read IMR and #$01 ; mask Bit 0 sta $d019 ; clear IMR-Bit 0 stx nmivec sty nmivec+1 ; restore old NMI-vector cli ; enable interrupts rts ; return rti: rti ; go immediately back after ; a NMI cascii text: byt $93,$05,$0e,$0d byt "Reliable PAL/NTSC-Detector",$0d byt "by Ninja/The Dreams in 2000",$0d byt "for GO64!/CW-Magazine.",$0d,$0d byt $9b,"You have a ",0 pal_text: byt "PAL-machine.",$0d,$05,0 ntsc_text: byt "NTSC-machine.",$0d,$05,0 end $0801 === uuencoded binary begin 666 palntsc-detector.prg M`0@+"$``GC(P-C$```"I:J`((!ZK("H(C:8"\`>IRJ`(3!ZKJ=F@"$P>JWBN M&`.L&0.I:8T8`ZD(C1D#K1+0T/NI-XT2T*F;C1'0J0&-&="M$=`0^ZT1T##[ MK1G0*0&-&=".&`.,&0-88$"3!0X-