Scanline counting

One method is to count how many scanlines there are, by watching how many values the scanline counter runs through between line 0 and the next line 0. You should get 262 on an NTSC (or Brazilian PAL/M) machine and 313 on a PAL machine.

Unfortunately, this is poorly emulated in many emulators and is not recommended.

Frame length counting

An alternative is to simply time (in software) how long a frame takes. A busy loop incrementing a counter can be used so long as the counter doesn't overflow in the time.

The code below is based on World Soccer, with minor modifications to make it generalised. It turns on frame interrupts and disables Z80 interrupts, so the VDP status flags can be used to detect VBlanks. An alternative (but more bulky) method is to use the scanline counter to detect line 0, but this is less reliably emulated.

; Returns a=0 for NTSC, a=1 for PAL
; uses a, hl, de
    di             ; disable interrupts
    ld a,%01100000 ; set VDP such that the screen is on
    out ($bf),a    ; with VBlank interrupts enabled
    ld a,$81
    out ($bf),a
    ld hl,$0000    ; init counter
-:  in a,($bf)     ; get VDP status
    or a           ; inspect
    jp p,-         ; loop until frame interrupt flag is set
-:  in a,($bf)     ; do the same again, in case we were unlucky and came in just
    or a           ;   before the start of the VBlank with the flag already set
    jp p,-
    ; the VDP must now be at the start of the VBlank
-:  inc hl         ; (6 cycles) increment counter until interrupt flag comes on again
    in a,($bf)     ; (11 cycles)
    or a           ; (4 cycles)
    jp p,-         ; (10 cycles)
    xor a          ; reset carry flag, also set a=0
    ld de,2048     ; see if hl is more or less than 2048
    sbc hl,de
    ret c          ; if less, return a=0
    ld a,1
    ret            ; if more or equal, return a=1

The main counter loop takes 31 clock cycles per iteration; it should therefore count up to approximately 3579545/60/31 = 1924 on NTSC machines and 3546893/50/31 = 2288 on PAL machines. 2048 is not exactly half-way between these but it probably doesn't matter much.

Return to top