ref: a0c3c62fcd25dd62d5c69353a604d3f6afbaa75b
dir: /vl.asm/
; ID_VL.ASM IDEAL MODEL MEDIUM,C INCLUDE 'ID_VL.EQU' SCREENSEG = 0a000h DATASEG EXTRN TimeCount:WORD ; incremented every 70th of a second EXTRN linewidth:WORD starttime dw ? CODESEG ;=========================================================================== ;============== ; ; VL_WaitVBL ******** NEW ********* ; ; Wait for the vertical retrace (returns before the actual vertical sync) ; ;============== PROC VL_WaitVBL num:WORD PUBLIC VL_WaitVBL @@wait: mov dx,STATUS_REGISTER_1 mov cx,[num] ; ; wait for a display signal to make sure the raster isn't in the middle ; of a sync ; @@waitnosync: in al,dx test al,8 jnz @@waitnosync @@waitsync: in al,dx test al,8 jz @@waitsync loop @@waitnosync ret ENDP ;=========================================================================== ;============== ; ; VL_SetCRTC ; ;============== PROC VL_SetCRTC crtc:WORD PUBLIC VL_SetCRTC ; ; wait for a display signal to make sure the raster isn't in the middle ; of a sync ; cli mov dx,STATUS_REGISTER_1 @@waitdisplay: in al,dx test al,1 ;1 = display is disabled (HBL / VBL) jnz @@waitdisplay ; ; set CRTC start ; ; for some reason, my XT's EGA card doesn't like word outs to the CRTC ; index... ; mov cx,[crtc] mov dx,CRTC_INDEX mov al,0ch ;start address high register out dx,al inc dx mov al,ch out dx,al dec dx mov al,0dh ;start address low register out dx,al mov al,cl inc dx out dx,al sti ret ENDP ;=========================================================================== ;============== ; ; VL_SetScreen ; ;============== PROC VL_SetScreen crtc:WORD, pel:WORD PUBLIC VL_SetScreen mov cx,[timecount] ; if timecount goes up by two, the retrace add cx,2 ; period was missed (an interrupt covered it) mov dx,STATUS_REGISTER_1 ; ; wait for a display signal to make sure the raster isn't in the middle ; of a sync ; @@waitdisplay: in al,dx test al,1 ;1 = display is disabled (HBL / VBL) jnz @@waitdisplay @@loop: sti jmp $+2 cli cmp [timecount],cx ; will only happen if an interrupt is jae @@setcrtc ; straddling the entire retrace period ; ; when several succesive display not enableds occur, ; the bottom of the screen has been hit ; in al,dx test al,8 jnz @@waitdisplay test al,1 jz @@loop in al,dx test al,8 jnz @@waitdisplay test al,1 jz @@loop in al,dx test al,8 jnz @@waitdisplay test al,1 jz @@loop in al,dx test al,8 jnz @@waitdisplay test al,1 jz @@loop in al,dx test al,8 jnz @@waitdisplay test al,1 jz @@loop @@setcrtc: ; ; set CRTC start ; ; for some reason, my XT's EGA card doesn't like word outs to the CRTC ; index... ; mov cx,[crtc] mov dx,CRTC_INDEX mov al,0ch ;start address high register out dx,al inc dx mov al,ch out dx,al dec dx mov al,0dh ;start address low register out dx,al mov al,cl inc dx out dx,al ; ; set horizontal panning ; mov dx,ATR_INDEX mov al,ATR_PELPAN or 20h out dx,al jmp $+2 mov al,[BYTE pel] ;pel pan value out dx,al sti ret ENDP ;=========================================================================== ;============================================================================ ; ; VL_ScreenToScreen ; ; Basic block copy routine. Copies one block of screen memory to another, ; using write mode 1 (sets it and returns with write mode 0). bufferofs is ; NOT accounted for. ; ;============================================================================ PROC VL_ScreenToScreen source:WORD, dest:WORD, wide:WORD, height:WORD PUBLIC VL_ScreenToScreen USES SI,DI pushf cli mov dx,SC_INDEX mov ax,SC_MAPMASK+15*256 out dx,ax mov dx,GC_INDEX mov al,GC_MODE out dx,al inc dx in al,dx and al,NOT 3 or al,1 out dx,al popf mov bx,[linewidth] sub bx,[wide] mov ax,SCREENSEG mov es,ax mov ds,ax mov si,[source] mov di,[dest] ;start at same place in all planes mov dx,[height] ;scan lines to draw mov ax,[wide] @@lineloop: mov cx,ax rep movsb add si,bx add di,bx dec dx jnz @@lineloop mov dx,GC_INDEX+1 in al,dx and al,NOT 3 out dx,al mov ax,ss mov ds,ax ;restore turbo's data segment ret ENDP ;=========================================================================== MASM ;��������������������������������������������������������� ; ; Name: VL_VideoID ; ; Function: Detects the presence of various video subsystems ; ; int VideoID; ; ; Subsystem ID values: ; 0 = (none) ; 1 = MDA ; 2 = CGA ; 3 = EGA ; 4 = MCGA ; 5 = VGA ; 80h = HGC ; 81h = HGC+ ; 82h = Hercules InColor ; ;��������������������������������������������������������� ;��������������������������������������������������������� ; ; Equates ; ;��������������������������������������������������������� VIDstruct STRUC ; corresponds to C data structure Video0Type DB ? ; first subsystem type Display0Type DB ? ; display attached to first subsystem Video1Type DB ? ; second subsystem type Display1Type DB ? ; display attached to second subsystem VIDstruct ENDS Device0 EQU word ptr Video0Type[di] Device1 EQU word ptr Video1Type[di] MDA EQU 1 ; subsystem types CGA EQU 2 EGA EQU 3 MCGA EQU 4 VGA EQU 5 HGC EQU 80h HGCPlus EQU 81h InColor EQU 82h MDADisplay EQU 1 ; display types CGADisplay EQU 2 EGAColorDisplay EQU 3 PS2MonoDisplay EQU 4 PS2ColorDisplay EQU 5 TRUE EQU 1 FALSE EQU 0 ;��������������������������������������������������������� ; ; Program ; ;��������������������������������������������������������� Results VIDstruct <> ;results go here! EGADisplays DB CGADisplay ; 0000b, 0001b (EGA switch values) DB EGAColorDisplay ; 0010b, 0011b DB MDADisplay ; 0100b, 0101b DB CGADisplay ; 0110b, 0111b DB EGAColorDisplay ; 1000b, 1001b DB MDADisplay ; 1010b, 1011b DCCtable DB 0,0 ; translate table for INT 10h func 1Ah DB MDA,MDADisplay DB CGA,CGADisplay DB 0,0 DB EGA,EGAColorDisplay DB EGA,MDADisplay DB 0,0 DB VGA,PS2MonoDisplay DB VGA,PS2ColorDisplay DB 0,0 DB MCGA,EGAColorDisplay DB MCGA,PS2MonoDisplay DB MCGA,PS2ColorDisplay TestSequence DB TRUE ; this list of flags and addresses DW FindPS2 ; determines the order in which this ; program looks for the various EGAflag DB ? ; subsystems DW FindEGA CGAflag DB ? DW FindCGA Monoflag DB ? DW FindMono NumberOfTests EQU ($-TestSequence)/3 PUBLIC VL_VideoID VL_VideoID PROC push bp ; preserve caller registers mov bp,sp push ds push si push di push cs pop ds ASSUME DS:@Code ; initialize the data structure that will contain the results lea di,Results ; DS:DI -> start of data structure mov Device0,0 ; zero these variables mov Device1,0 ; look for the various subsystems using the subroutines whose addresses are ; tabulated in TestSequence; each subroutine sets flags in TestSequence ; to indicate whether subsequent subroutines need to be called mov byte ptr CGAflag,TRUE mov byte ptr EGAflag,TRUE mov byte ptr Monoflag,TRUE mov cx,NumberOfTests mov si,offset TestSequence @@L01: lodsb ; AL := flag test al,al lodsw ; AX := subroutine address jz @@L02 ; skip subroutine if flag is false push si push cx call ax ; call subroutine to detect subsystem pop cx pop si @@L02: loop @@L01 ; determine which subsystem is active call FindActive mov al,Results.Video0Type mov ah,0 ; was: Results.Display0Type pop di ; restore caller registers and return pop si pop ds mov sp,bp pop bp ret VL_VideoID ENDP ; ; FindPS2 ; ; This subroutine uses INT 10H function 1Ah to determine the video BIOS ; Display Combination Code (DCC) for each video subsystem present. ; FindPS2 PROC near mov ax,1A00h int 10h ; call video BIOS for info cmp al,1Ah jne @@L13 ; exit if function not supported (i.e., ; no MCGA or VGA in system) ; convert BIOS DCCs into specific subsystems & displays mov cx,bx xor bh,bh ; BX := DCC for active subsystem or ch,ch jz @@L11 ; jump if only one subsystem present mov bl,ch ; BX := inactive DCC add bx,bx mov ax,[bx+offset DCCtable] mov Device1,ax mov bl,cl xor bh,bh ; BX := active DCC @@L11: add bx,bx mov ax,[bx+offset DCCtable] mov Device0,ax ; reset flags for subsystems that have been ruled out mov byte ptr CGAflag,FALSE mov byte ptr EGAflag,FALSE mov byte ptr Monoflag,FALSE lea bx,Video0Type[di] ; if the BIOS reported an MDA ... cmp byte ptr [bx],MDA je @@L12 lea bx,Video1Type[di] cmp byte ptr [bx],MDA jne @@L13 @@L12: mov word ptr [bx],0 ; ... Hercules can't be ruled out mov byte ptr Monoflag,TRUE @@L13: ret FindPS2 ENDP ; ; FindEGA ; ; Look for an EGA. This is done by making a call to an EGA BIOS function ; which doesn't exist in the default (MDA, CGA) BIOS. FindEGA PROC near ; Caller: AH = flags ; Returns: AH = flags ; Video0Type and ; Display0Type updated mov bl,10h ; BL := 10h (return EGA info) mov ah,12h ; AH := INT 10H function number int 10h ; call EGA BIOS for info ; if EGA BIOS is present, ; BL <> 10H ; CL = switch setting cmp bl,10h je @@L22 ; jump if EGA BIOS not present mov al,cl shr al,1 ; AL := switches/2 mov bx,offset EGADisplays xlat ; determine display type from switches mov ah,al ; AH := display type mov al,EGA ; AL := subystem type call FoundDevice cmp ah,MDADisplay je @@L21 ; jump if EGA has a monochrome display mov CGAflag,FALSE ; no CGA if EGA has color display jmp short @@L22 @@L21: mov Monoflag,FALSE ; EGA has a mono display, so MDA and ; Hercules are ruled out @@L22: ret FindEGA ENDP ; ; FindCGA ; ; This is done by looking for the CGA's 6845 CRTC at I/O port 3D4H. ; FindCGA PROC near ; Returns: VIDstruct updated mov dx,3D4h ; DX := CRTC address port call Find6845 jc @@L31 ; jump if not present mov al,CGA mov ah,CGADisplay call FoundDevice @@L31: ret FindCGA ENDP ; ; FindMono ; ; This is done by looking for the MDA's 6845 CRTC at I/O port 3B4H. If ; a 6845 is found, the subroutine distinguishes between an MDA ; and a Hercules adapter by monitoring bit 7 of the CRT Status byte. ; This bit changes on Hercules adapters but does not change on an MDA. ; ; The various Hercules adapters are identified by bits 4 through 6 of ; the CRT Status value: ; ; 000b = HGC ; 001b = HGC+ ; 101b = InColor card ; FindMono PROC near ; Returns: VIDstruct updated mov dx,3B4h ; DX := CRTC address port call Find6845 jc @@L44 ; jump if not present mov dl,0BAh ; DX := 3BAh (status port) in al,dx and al,80h mov ah,al ; AH := bit 7 (vertical sync on HGC) mov cx,8000h ; do this 32768 times @@L41: in al,dx and al,80h ; isolate bit 7 cmp ah,al loope @@L41 ; wait for bit 7 to change jne @@L42 ; if bit 7 changed, it's a Hercules mov al,MDA ; if bit 7 didn't change, it's an MDA mov ah,MDADisplay call FoundDevice jmp short @@L44 @@L42: in al,dx mov dl,al ; DL := value from status port and dl,01110000b ; mask bits 4 thru 6 mov ah,MDADisplay ; assume it's a monochrome display mov al,HGCPlus ; look for an HGC+ cmp dl,00010000b je @@L43 ; jump if it's an HGC+ mov al,HGC ; look for an InColor card or HGC cmp dl,01010000b jne @@L43 ; jump if it's not an InColor card mov al,InColor ; it's an InColor card mov ah,EGAColorDisplay @@L43: call FoundDevice @@L44: ret FindMono ENDP ; ; Find6845 ; ; This routine detects the presence of the CRTC on a MDA, CGA or HGC. ; The technique is to write and read register 0Fh of the chip (cursor ; low). If the same value is read as written, assume the chip is ; present at the specified port addr. ; Find6845 PROC near ; Caller: DX = port addr ; Returns: cf set if not present mov al,0Fh out dx,al ; select 6845 reg 0Fh (Cursor Low) inc dx in al,dx ; AL := current Cursor Low value mov ah,al ; preserve in AH mov al,66h ; AL := arbitrary value out dx,al ; try to write to 6845 mov cx,100h @@L51: loop @@L51 ; wait for 6845 to respond in al,dx xchg ah,al ; AH := returned value ; AL := original value out dx,al ; restore original value cmp ah,66h ; test whether 6845 responded je @@L52 ; jump if it did (cf is reset) stc ; set carry flag if no 6845 present @@L52: ret Find6845 ENDP ; ; FindActive ; ; This subroutine stores the currently active device as Device0. The ; current video mode determines which subsystem is active. ; FindActive PROC near cmp word ptr Device1,0 je @@L63 ; exit if only one subsystem cmp Video0Type[di],4 ; exit if MCGA or VGA present jge @@L63 ; (INT 10H function 1AH cmp Video1Type[di],4 ; already did the work) jge @@L63 mov ah,0Fh int 10h ; AL := current BIOS video mode and al,7 cmp al,7 ; jump if monochrome je @@L61 ; (mode 7 or 0Fh) cmp Display0Type[di],MDADisplay jne @@L63 ; exit if Display0 is color jmp short @@L62 @@L61: cmp Display0Type[di],MDADisplay je @@L63 ; exit if Display0 is monochrome @@L62: mov ax,Device0 ; make Device0 currently active xchg ax,Device1 mov Device0,ax @@L63: ret FindActive ENDP ; ; FoundDevice ; ; This routine updates the list of subsystems. ; FoundDevice PROC near ; Caller: AH = display # ; AL = subsystem # ; Destroys: BX lea bx,Video0Type[di] cmp byte ptr [bx],0 je @@L71 ; jump if 1st subsystem lea bx,Video1Type[di] ; must be 2nd subsystem @@L71: mov [bx],ax ; update list entry ret FoundDevice ENDP IDEAL END