Detecting VDP version
Here’s a routine to help you detect the VDP version. It takes about a frame to complete, so it is recommended to do it once at the start of the program.
;
; Detect VDP version
;
; a <- 0: TMS9918A, 1: V9938, 2: V9958, x: VDP ID
; f <- z: TMS9918A, nz: other
;
VDP_GetVersion:
call VDP_IsTMS9918A ; use a different way to detect TMS9918A
ret z
ld a,1 ; select s#1
di
out (99H),a
ld a,15 + 128
out (99H),a
in a,(99H) ; read s#1
and 00111110B ; get VDP ID
rrca
ex af,af'
xor a ; select s#0 as required by BIOS
out (99H),a
ld a,15 + 128
ei
out (99H),a
ex af,af'
ret nz ; return VDP ID for V9958 or higher
inc a ; return 1 for V9938
ret
;
; Test if the VDP is a TMS9918A.
;
; The VDP ID number was only introduced in the V9938, so we have to use a
; different method to detect the TMS9918A. We wait for the vertical blanking
; interrupt flag, and then quickly read status register 2 and expect bit 6
; (VR, vertical retrace flag) to be set as well. The TMS9918A has only one
; status register, so bit 6 (5S, 5th sprite flag) will return 0 in stead.
;
; f <- z: TMS9918A, nz: V99X8
;
VDP_IsTMS9918A:
in a,(99H) ; read s#0, make sure interrupt flag (F) is reset
di
VDP_IsTMS9918A_Wait:
in a,(99H) ; read s#0
and a ; wait until interrupt flag (F) is set
jp p,VDP_IsTMS9918A_Wait
ld a,2 ; select s#2 on V9938
out (99H),a
ld a,15 + 128 ; (this mirrors to r#7 on TMS9918 VDPs)
out (99H),a
in a,(99H) ; read s#2 / s#0
ex af,af'
xor a ; select s#0 as required by BIOS
out (99H),a
ld a,15 + 128
out (99H),a
ld a,(0F3E6H) ; RG7SAV
out (99H),a ; restore r#7 if it mirrored (small flash visible)
ld a,7 + 128
ei
out (99H),a
ex af,af'
and 01000000B ; check if bit 6 was 0 (s#0 5S) or 1 (s#2 VR)
ret
Note: As you may know, the MSX VDPs have a race condition in the design of the F, FH and FL interrupt flags, which makes polling unreliable since the flag can be missed occasionally. If that situation occurs the detection will take a frame longer to complete, but still provide the correct result.
Grauw