vesa2.asm
bazz1tv_mac-zsnes-1_36/src/dos/vesa2.asm
;Copyright (C) 1997-2001 ZSNES Team ( zsknight@zsnes.com / _demo_@zsnes.com )
;
;This program is free software; you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;as published by the Free Software Foundation; either
;version 2 of the License, or (at your option) any later
;version.
;
;This program is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY; without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License
;along with this program; if not, write to the Free Software
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

%include "macros.mac"

EXTSYM printnum
EXTSYM DosExit,ZSNESBase,Change_Dir,PrintStr,newengen
EXTSYM HalfTransB,HalfTransC
EXTSYM InitDrive,gotoroot,InitDir,fulladdtab
;        EXTSYM printhex
;        EXTSYM printhex
EXTSYM UnusedBit,HalfTrans,UnusedBitXor,ngrposng,nggposng,ngbposng
;        EXTSYM printhex

EXTSYM Init_2xSaIMMX

NEWSYM Vesa2AsmStart


SECTION .data

; add 0214h video mode
anticrash times 10 db 0


ALIGN32
NEWSYM vesa2_usbit,     dd 0            ; Unused bit in proper bit location
NEWSYM vesa2_clbit,     dd 0            ; clear all bit 0's if AND is used
NEWSYM vesa2_clbitng,   dd 0            ; clear all bit 0's if AND is used
NEWSYM vesa2_clbitng2,  dd 0,0          ; clear all bit 0's if AND is used
NEWSYM vesa2_clbitng3,  dd 0            ; clear all bit 0's if AND is used
NEWSYM vesa2_x,         dd 320          ; Desired screen width
NEWSYM vesa2_y,         dd 240          ; Height
NEWSYM vesa2selec,      dd 0            ; VESA2 Selector Location
NEWSYM vesa2_bits,      dd 8            ; Bits per pixel
NEWSYM vesa2_rpos,      dd 0            ; Red bit position
NEWSYM vesa2_gpos,      dd 0            ; Green bit position
NEWSYM vesa2_bpos,      dd 0            ; Blue bit position
NEWSYM vesa2_rposng,    dd 0            ; Red bit position
NEWSYM vesa2_gposng,    dd 0            ; Green bit position
NEWSYM vesa2_bposng,    dd 0            ; Blue bit position

NEWSYM vesa2_rtrcl,     dd 0            ; red transparency clear     (bit+4)
NEWSYM vesa2_rtrcla,    dd 0            ; red transparency (AND) clear (not(bit+4))
NEWSYM vesa2_rfull,     dd 0            ; red max (or bit*1Fh)
NEWSYM vesa2_gtrcl,     dd 0            ; red transparency clear     (bit+4)
NEWSYM vesa2_gtrcla,    dd 0            ; red transparency (AND) clear (not(bit+4))
NEWSYM vesa2_gfull,     dd 0            ; red max (or bit*1Fh)
NEWSYM vesa2_btrcl,     dd 0            ; red transparency clear     (bit+4)
NEWSYM vesa2_btrcla,    dd 0            ; red transparency (AND) clear (not(bit+4))
NEWSYM vesa2_bfull,     dd 0            ; red max (or bit*1Fh)
NEWSYM vesa2red10,      dd 0            ; red position at bit 10
NEWSYM videotroub,      dd 0            ; red position at bit 10
NEWSYM vesa3en,         dd 0
NEWSYM VESAAddr,        dd 0
NEWSYM ExitFromGUI,     db 0
NEWSYM ErrorPointer,    dd 0
NEWSYM TripBufAvail,    db 0


;NEWSYM dcolortab, times 256 dd 0


SECTION .bss

NEWSYM dcolortab, times 256 resd 1


SECTION .text

NEWSYM genfulladdtab
        ; Write to buffer
        cmp byte[newengen],1
        jne .notneweng
        cmp byte[vesa2red10],0
        jne near genfulladdtabred
.notneweng
        xor ecx,ecx
.loopers
        mov ax,cx
        test [vesa2_rtrcl],cx
        jz .nor
        and ax,[vesa2_rtrcla]
        or ax,[vesa2_rfull]
.nor
        test [vesa2_gtrcl],cx
        jz .nog
        and ax,[vesa2_gtrcla]
        or ax,[vesa2_gfull]
.nog
        test [vesa2_btrcl],cx
        jz .nob
        and ax,[vesa2_btrcla]
        or ax,[vesa2_bfull]
.nob
        shl ax,1
        mov [fulladdtab+ecx*2],ax
        dec cx
        jnz .loopers
        ret

NEWSYM genfulladdtabred
NEWSYM genfulladdtabng
        ; Write to buffer
        xor ecx,ecx
.loopers
        mov ax,cx
        test cx,0100000000000000b
        jz .nor
        and ax,1011111111111111b
        or ax, 0011110000000000b
.nor
        test cx,0000001000000000b
        jz .nog
        and ax,1111110111111111b
        or ax, 0000000111100000b
.nog
        test cx,0000000000010000b
        jz .nob
        and ax,1111111111101111b
        or ax, 0000000000001111b
.nob
        shl ax,1
        mov [fulladdtab+ecx*2],ax
        dec cx
        jnz .loopers
        ret

NEWSYM VESA2EXITTODOS
        mov byte[videotroub],1
        cmp byte[ExitFromGUI],0
        je .nogui
        mov [ErrorPointer],edx
        ret
.nogui
        mov ax,0003h
        int 10h
        push edx
        mov edx,.exitfromvesa2
        call PrintStr
        pop edx
        call PrintStr
        mov edx,.return
        call PrintStr

        mov dl,[InitDrive]
        mov ebx,InitDir
        call Change_Dir
        jmp DosExit

.exitfromvesa2 db 'Unable to Initialize VESA2 : ',0
.return db 10,13,0

;*******************************************************
;	Set up Vesa 2
;*******************************************************

NEWSYM InitVesa2
	   ;-------------------------------------------------;
	    ; First - allocate some bytes in DOS memory for ;
	    ; communication with VBE			    ;
	   ;-------------------------------------------------;

	mov eax,0100h
	mov ebx,512/16			; 512 bytes
	int 31h				; Function 31h,100h - Allocate
					; DOS memory (512 bytes)
	jnc .gotmem
	    mov edx,.nomemmessage
            jmp VESA2EXITTODOS
	    .nomemmessage
            db 'Unable to locate DOS memory.',0

	.gotmem
	mov fs,dx			; FS now points to the DOS
					; buffer


	   ;--------------------------------------------------;
	    ; Now, get information about the video card into ;
	    ; a data structure				     ;
	   ;--------------------------------------------------;

	mov edi,RMREGS
        mov dword[fs:0],'VBE2'          ; Request VBE 2.0 info
	mov dword[RMREGS.eax],4f00h
	mov word[RMREGS.es],ax		; Real mode segment of DOS 
					; buffer
	mov dword[RMREGS.edi],0

	push es
        push ds
	pop es
	mov eax,300h
	mov ebx,10h
	xor ecx,ecx
	int 31h				; Simulate real mode interrupt
	pop es

	jnc .int1ok
	    mov edx,.noint1message
            jmp VESA2EXITTODOS
	    .noint1message
            db 'Simulated real mode interrupt failed.',0

	.int1ok			; Real mode int successful!!!
	mov eax,[RMREGS.eax]
	cmp al,4fh		; Check vbe interrupt went OK
	jz .vbedetected
	    mov edx,.novbemessage
            jmp VESA2EXITTODOS
	    .novbemessage
            db 'VBE not detected!!',0

	.vbedetected
	cmp dword[fs:0000],'VESA'
	jz .vesadetected	; Check for presence of vesa
	    mov edx,.novesamessage
            jmp VESA2EXITTODOS
	    .novesamessage
            db 'VESA not detected!',0

	.vesadetected
	cmp word[fs:0004],200h
	jae .vesa2detected	; Check we've got VESA 2.0 or greater
	    mov edx,.novesa2message
            jmp VESA2EXITTODOS
	    .novesa2message
            db 'VESA 2.0 or greater required!',0


		;-----------------------------------------------------;
		 ; OK - vesa 2.0 or greater has been detected. Copy  ;
		 ; mode information into VESAmodelist		     ;
		;-----------------------------------------------------;

	.vesa2detected
        mov dword[vesa3en],0
        cmp word[fs:004],300h
        jb .notvbe3
        mov dword[vesa3en],1
        .notvbe3
	mov ax,[fs:12h]			; Get no. of 64k blocks
	mov [noblocks],ax
	mov ax, 2
	mov bx,[fs:10h]
	int 31h

	jnc .wegottheselector
	    mov edx, .oopsnoselector
            jmp VESA2EXITTODOS
	    .oopsnoselector
                db 'Failed to allocate vesa display selector!',0

	.wegottheselector

	mov gs,ax
	xor eax,eax
	mov ebp,VESAmodelist
	mov ecx,512
	mov ax,[fs:0eh]

	.loopcopymodes
	    mov bx,[gs:eax]
	    mov [ebp],bx
	    cmp bx,0ffffh
	    jz .copiedmodes
	    add ebp,2
	    add eax,2
	    dec ecx
	    jz .outofmodelistspace
	    jmp .loopcopymodes

		.outofmodelistspace
		mov edx,.outofmodelistspacemessage
                jmp VESA2EXITTODOS
		.outofmodelistspacemessage
                db 'Out of VESA2 mode list space!',0

		   ;----------------------------------------------;
		    ; OK - Scan the mode list to find a matching ;
		    ; mode for vesa2_x, vesa2_y and vesa2_depth	 ;
		   ;----------------------------------------------;

    .copiedmodes

	mov ebp,VESAmodelist
	xor ecx,ecx

    .loopcheckmodes
	mov cx, [ebp]
	cmp cx, 0ffffh
	jnz .notendoflist

	    mov edx,.endoflist
            jmp VESA2EXITTODOS

            .endoflist db 'This VESA2 mode does not work on your video card / driver.',0
            .whichwin db 0

    .notendoflist

        mov edi, RMREGS
        mov dword[RMREGS.eax],4f01h
        mov dword[RMREGS.ebx],0
        mov dword[RMREGS.ecx],ecx
        mov dword[RMREGS.edi],0

	push es
        push ds
	pop es
	mov eax,300h
	mov ebx,10h
	xor ecx,ecx
	int 31h				; Simulate real mode interrupt
	pop es
	jnc .modecheckok
	    mov edx,.modecheckfail
            jmp VESA2EXITTODOS
	    .modecheckfail
            db 'Real mode interrupt failure while checking vesa mode',0

	.modecheckok
	add ebp,2

        test word[fs:0000h],1b
            jz near .loopcheckmodes     ; If mode is not available

;
;        xor eax,eax
;        mov ax,[fs:12h]
;        call printnum
;        mov ah,02h
;        mov dl,'x'
;        int 21h
;        mov ax,[fs:14h]
;        call printnum
;        mov ah,02h
;        mov dl,'x'
;        int 21h
;        xor ah,ah
;        mov al,[fs:19h]
;        call printnum
;        mov ah,02h
;        mov dl,13
;        int 21h
;        mov dl,10
;        int 21h

	mov eax,[vesa2_x]
	cmp [fs:12h],ax			; Check that the height matches
	    jnz near .loopcheckmodes
	mov eax,[vesa2_y]
	cmp [fs:14h],ax			; Check that the width matches
	    jnz near .loopcheckmodes
	mov al,[vesa2_bits]
	cmp [fs:19h],al			; Check bits/pixel for match
	    jnz near .loopcheckmodes

;        mov ax,3
;        int 10h
;        xor eax,eax
;        mov ax,[fs:0h]
;        call printnum
;        jmp DosExit

        mov byte[TripBufAvail],1
        test word[fs:0000h],400h
        jz .notbuf
        mov byte[TripBufAvail],1
.notbuf

;        jz .notvesa3
;        xor eax,eax
;        mov ax,[fs:0000h]
;        call printhex
;        jmp DosExit
.notvesa3

;        mov ah,07h
;        int 21h

;        D0 = Window supported
;                0 = Window is not supported
;                1 = Window is supported
;        D1 = Window readable
;                0 = Window is not readable
;                1 = Window is readable
;        D2 = Window writeable
;                0 = Window is not writeable
;                1 = Window is writeable
;        D3-D7 = Reserved

        mov byte[.whichwin],0
	mov al,[fs:2]			; Get window A attributes
        and al,0100b
        cmp al,0100b
        je .foundwin    ; Mode supported
        mov al,[fs:3]                   ; Get window B attributes
        and al,0100b
        cmp al,0100b
        jne .foundwin    ; Mode not supported
        mov byte[.whichwin],1
.foundwin

		; Success - a match has been found!!

	sub ebp,2
	mov ax,[ebp]
	mov [vesamode],ax		; Store vesa 2 mode number

;        call printhex
;        jmp DosExit

        mov ax,[fs:10h]
        mov byte[vesa2red10],0
        mov byte[vesa2_rposng],11
        mov byte[vesa2_gposng],6
        mov byte[vesa2_bposng],0
        mov dword[vesa2_clbitng],1111011111011110b
        mov dword[vesa2_clbitng2],11110111110111101111011111011110b
        mov dword[vesa2_clbitng2+4],11110111110111101111011111011110b
        mov dword[vesa2_clbitng3],0111101111101111b
	mov [bytesperscanline],ax	; Store bytes per scan line
        cmp byte[fs:20h],10
        jne near .nored10
        mov byte[fs:20h],11
        mov byte[vesa2red10],1
        mov byte[vesa2_rposng],10
        mov byte[vesa2_gposng],5
        mov dword[vesa2_clbitng],0111101111011110b
        mov dword[vesa2_clbitng2],01111011110111100111101111011110b
        mov dword[vesa2_clbitng2+4],01111011110111100111101111011110b
        mov dword[vesa2_clbitng3],0011110111101111b

        mov dword[UnusedBit],     10000000000000001000000000000000b
        mov dword[HalfTrans],     01111011110111100111101111011110b
        mov dword[UnusedBitXor],  01111111111111110111111111111111b
        mov dword[UnusedBit+4],   10000000000000001000000000000000b
        mov dword[HalfTrans+4],   01111011110111100111101111011110b
        mov dword[UnusedBitXor+4],01111111111111110111111111111111b
        mov dword[HalfTransB],    00000100001000010000010000100001b
        mov dword[HalfTransB+4],  00000100001000010000010000100001b
        mov dword[HalfTransC],    01111011110111100111101111011110b
        mov dword[HalfTransC+4],  01111011110111100111101111011110b
        mov dword[ngrposng],10
        mov dword[nggposng],5
        mov dword[ngbposng],0

.nored10
        ; fix up bit lengths
        mov al,16
        sub al,[fs:20h]
        mov ah,[fs:22h]
        sub ah,[fs:20h]
        mov bl,[fs:24h]
        sub bl,[fs:20h]
        mov bh,al
        cmp bh,ah
        jb .scheck1
        mov bh,ah
      .scheck1
        cmp bh,bl
        jb .scheck2
        mov bh,bl
      .scheck2
        mov byte[fs:19h],5

        mov al,16
        sub al,[fs:22h]
        mov ah,[fs:20h]
        sub ah,[fs:22h]
        mov bl,[fs:24h]
        sub bl,[fs:22h]
        mov bh,al
        cmp bh,ah
        jb .scheck1b
        mov bh,ah
      .scheck1b
        cmp bh,bl
        jb .scheck2b
        mov bh,bl
      .scheck2b
        mov [fs:21h],bh

        mov al,16
        sub al,[fs:24h]
        mov ah,[fs:20h]
        sub ah,[fs:24h]
        mov bl,[fs:22h]
        sub bl,[fs:24h]
        mov bh,al
        cmp bh,ah
        jb .scheck1c
        mov bh,ah
      .scheck1c
        cmp bh,bl
        jb .scheck2c
        mov bh,bl
      .scheck2c
        mov [fs:23h],bh

        mov word[vesa2_clbit],0

        cmp byte[fs:20h],10
        jne .nottopbit
        mov word[vesa2_usbit],8000h
.nottopbit

        ; Process Red Stuff
        mov al,[fs:20h]         ; bit sizes = [fs:19h,21h,23h]
        mov cl,al
        mov bx,1
        shl bx,cl
        cmp byte[fs:19h],6
        jne .no6bit
        mov [vesa2_usbit],bx
        inc al
.no6bit
        or [vesa2_clbit],bx
        mov [vesa2_rpos],al
        dec al
        mov cl,al
        mov bx,001Fh
        cmp cl,0FFh
        je .shrr
        shl bx,cl
        jmp .shlr
.shrr
        shr bx,1
.shlr
        mov word[vesa2_rfull],bx
        add al,5
        mov bx,1
        mov cl,al
        shl bx,cl
        mov word[vesa2_rtrcl],bx
        xor bx,0FFFFh
        mov word[vesa2_rtrcla],bx

;        mov ax,03h
;        int 10h
;        mov ax,[vesa2_rfull]
;        call printhex
;        jmp DosExit

        ; Process Green Stuff
        mov al,[fs:22h]
        mov cl,al
        mov bx,1
        shl bx,cl
        cmp byte[fs:21h],6
        jne .no6bitb
        mov [vesa2_usbit],bx
        inc al
.no6bitb
        or [vesa2_clbit],bx
        mov [vesa2_gpos],al
        dec al
        mov cl,al
        mov bx,001Fh
        cmp cl,0FFh
        je .shrg
        shl bx,cl
        jmp .shlg
.shrg
        shr bx,1
.shlg
        mov word[vesa2_gfull],bx
        add al,5
        mov bx,1
        mov cl,al
        shl bx,cl
        mov word[vesa2_gtrcl],bx
        xor bx,0FFFFh
        mov word[vesa2_gtrcla],bx

        ; Process Blue Stuff
        mov al,[fs:24h]
        mov cl,al
        mov bx,1
        shl bx,cl
        cmp byte[fs:23h],6
        jne .no6bitc
        mov [vesa2_usbit],bx
        inc al
.no6bitc
        or [vesa2_clbit],bx
        mov [vesa2_bpos],al
        dec al
        mov cl,al
        mov bx,001Fh
        cmp cl,0FFh
        je .shrb
        shl bx,cl
        jmp .shlb
.shrb
        shr bx,1
.shlb
        mov word[vesa2_bfull],bx
        add al,5
        mov bx,1
        mov cl,al
        shl bx,cl
        mov word[vesa2_btrcl],bx
        xor bx,0FFFFh
        mov word[vesa2_btrcla],bx

        xor word[vesa2_clbit],0FFFFh

;vesa2_rtrcl     dw 0            ; red transparency clear     (bit+4)
;vesa2_rtrcla    dw 0            ; red transparency (AND) clear (not(bit+4))
;vesa2_rfull     dw 0            ; red max (or (bit-1)*1Fh)

        call genfulladdtab

	test word[fs:0h],10000000b	; Check if linear available
	jnz .linearavailable
            mov edx,.nolframebuffer
            jmp VESA2EXITTODOS               ; None available
        .nolframebuffer db 'Linear Frame Buffer not Detected.',0

		;---------------------------------------------;
		 ; OK - now set the vesa 2 mode based on the ;
		 ; information gleaned...		     ;
		;---------------------------------------------;

	.linearavailable
	or word[vesamode],4000h		; Convert mode to its LFB
					; equivalent
	mov ebx,[fs:28h]		; Read in physical base ptr

	mov cx,bx
	shr ebx,16
	mov si,[noblocks]
	xor edi,edi			; Since noblocks = number of
					; 64k blocks, these lines leave
					; si:di holding byte size
	mov eax,800h
	int 31h
	jnc .mappedphysicalarea
            mov edx,.unablemap
            jmp VESA2EXITTODOS               ; Failure!!!
        .unablemap db 'Unable to map physical area.',0

	.mappedphysicalarea
	shl ebx,16
	mov bx,cx
	mov [LFBpointer],ebx
        mov eax,ebx
        sub eax,[ZSNESBase]
        mov [VESAAddr],eax

	xor eax,eax
	xor ebx,ebx
	xor ecx,ecx
	xor edx,edx
	mov ax,4f02h
	mov bx,[vesamode]
	int 10h				; Set the vesa mode
	cmp ax,004fh
	jz .modesetok
            mov edx,.unableset
            jmp VESA2EXITTODOS               ; Failure!!!
        .unableset db 'Unable to initialize video mode.',0

	.modesetok
;******************************* EXTRA BIT ****************************

;        cmp byte[.whichwin],1           ; Check if Write is at Window B
;        jne .nowinB
;
;        mov ax,4F05h
;        mov bx,1
;        mov dx,0
;        int 10h
;
;.nowinB

        ; Check logical scanline length
        mov eax,4f06h
        mov ebx,1
        int 10h
        cmp cx,[vesa2_x]
        je .correctwidth

	mov eax,4f06h			; VBE Set/Get logical scan line
					; length
	mov ebx,0			; Set scan line length in
					; pixels
        mov ecx, [vesa2_x]                ; Desired screen width
	int 10h
	cmp ax,04fh
	jz .correctwidth
            mov edx, .unablescan
	    jmp VESA2EXITTODOS		; Failure!!!
        .unablescan db 'Unable to set scan line length.',0

	.correctwidth

;*************************** END OF EXTRA BIT *************************

	xor eax,eax
	mov ecx,1
	int 31h				; Allocate a descriptor

	mov bx,ax			; Move our selector into bx

	mov ecx,[LFBpointer]
	mov dx,cx
	shr ecx,16
	mov eax,7
	int 31h				; Set our selector to LFB
	jnc .selectornowset
                mov edx,.unablelfb
                jmp VESA2EXITTODOS           ; Failure!!!
        .unablelfb db 'Unable to set selector to LFB.',0

	.selectornowset

	xor ecx,ecx
	mov cx,[noblocks]
	shl ecx,6			; Multiply by 64
	shl ecx,10			; And again by 1024
	sub ecx,1			; Necessary!!!
	mov dx,cx
	shr ecx,16			; CX:DX size of screen
	mov eax,8
	int 31h				; Set size of selector
	jnc .ok
                mov edx,.unablesets
                jmp VESA2EXITTODOS           ; Failure!!!
        .unablesets db 'Unable to set size of selector.',0

	.ok
	lar ecx,ebx
	shr ecx,8
	and cl,60h
	or cl,93h
	and ch,0c0h			; Keep granularity bit
	mov ax,9
	int 31h				; Set selector access rights
	jnc .accessrightsset
                mov edx,.unablesetar
                jmp VESA2EXITTODOS
        .unablesetar db 'Unable to set selector access rights.',0

	.accessrightsset
        mov [vesa2selec],bx

        cmp byte[vesa2red10],1
        je .red10
        mov eax,565
        jmp .red11
.red10
        mov eax,555
.red11
        push eax
        call Init_2xSaIMMX
        pop eax
        ret


SECTION .data

NEWSYM LFBpointer
	dd 0
NEWSYM noblocks
	dw 0
NEWSYM bytesperscanline
	dw 0
NEWSYM vesamode
	dw 0
;----------------------------------------------------------------------
;NEWSYM VESAmodelist
;   times 512 dw 0
;----------------------------------------------------------------------


SECTION .bss

NEWSYM VESAmodelist, times 512 resw 1


;NEWSYM RMREGS
;.edi  dd 0
;.esi  dd 0
;.ebp  dd 0
;.esp  dd 0
;.ebx  dd 0
;.edx  dd 0
;.ecx  dd 0
;.eax  dd 0
;
;.flags   dw 0
;.es   dw 0
;.ds   dw 0 
;.fs   dw 0
;.gs   dw 0
;.ip   dw 0
;.cs   dw 0
;.sp   dw 0
;.ss   dw 0
;.spare   times 20 dd 0

NEWSYM RMREGS
.edi  resd 1
.esi  resd 1
.ebp  resd 1
.esp  resd 1
.ebx  resd 1
.edx  resd 1
.ecx  resd 1
.eax  resd 1

.flags   resw 1
.es   resw 1
.ds   resw 1 
.fs   resw 1
.gs   resw 1
.ip   resw 1
.cs   resw 1
.sp   resw 1
.ss   resw 1
.spare   times 20 resd 1
;----------------------------------------------------------------------
NEWSYM Vesa2AsmEnd
