SC_INDEX        equ     3c4h    ;Sequence Controller Index register
GC_INDEX        equ     3ceh    ;Graphics Controller Index register
CRTC_INDEX      equ     3d4h    ;CRT Controller Index register
MEMORY_MODE     equ     4       ;Memory Mode register index in SC
UNDERLINE       equ     14h     ;Underline Location reg index in CRTC
MODE_CONTROL    equ     17h     ;Mode Control register index in CRTC
GRAPHICS_MODE   equ     5       ;Graphics Mode register index in GC
MISCELLANEOUS   equ     6       ;Miscellaneous register index in GC

hseq1 LABEL WORD ;0=start
	dw	479	;display enable end
	dw	485	;start vertical blank
	dw	490	;start vertical retrace
	dw	500	;end vertical retrace
	dw	505	;end vertical blank
	dw	510	;vertical total
	dw	480+1	;200/350/400/480=lines/monitor, +1=double scanning
	
hseq2 LABEL WORD ;0=start
	dw	349	;display enable end
	dw	354	;start vertical blank
	dw	360+50	;start vertical retrace
	dw	375+100	;end vertical retrace
	dw	395+100	;end vertical blank
	dw	399+100	;vertical total
	
tweak320x200 PROC NEAR
;
; First, go to normal 320x200 256-color mode, which is really a
; 320x400 256-color mode with each line scanned twice.
;
	mov     ax,0013h  ;AH = 0 means mode set, AL = 13h selects
			; 256-color graphics mode
	int     10h     ;BIOS video interrupt
	mov	dx,3c8h
	mov	al,0
	out	dx,al
	inc	dx
	mov	cx,768
reclr:	out	dx,al
	loop	reclr
;
; Change CPU addressing of video memory to linear (not odd/even,
; chain, or chain 4), to allow us to access all 256K of display
; memory. When this is done, VGA memory will look just like memory
; in modes 10h and 12h, except that each byte of display memory will
; control one 256-color pixel, with 4 adjacent pixels at any given
; address, one pixel per plane.
;
	mov     dx,SC_INDEX
	mov     al,MEMORY_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 08h      ;turn off chain 4
	or      al,04h          ;turn off odd/even
	out     dx,al
	mov     dx,GC_INDEX
	mov     al,GRAPHICS_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 10h      ;turn off odd/even
	out     dx,al
	dec     dx
	mov     al,MISCELLANEOUS
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 02h      ;turn off chain
	out     dx,al

;
; Tweak the mode to 320x200 256-color mode by scanning each
; line twice.
;
	mov     dx,CRTC_INDEX
	mov     al,9
;	out     dx,al
	inc     dx
;	in      al,dx
	and     al,not 5fh      ;set maximum scan line = 0
	OR      AL,1
;	out     dx,al
	dec     dx
;
; Change CRTC scanning from doubleword mode to byte mode, allowing
; the CRTC to scan more than 64K of video data.
;
	mov     al,UNDERLINE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 40h      ;turn off doubleword
	out     dx,al
	dec     dx
	mov     al,MODE_CONTROL
	out     dx,al
	inc     dx
	in      al,dx
	or      al,40h  ;turn on the byte mode bit, so memory is
			; scanned for video data in a purely
			; linear way, just as in modes 10h and 12h
	out     dx,al
	
	ret
	
;
; First, go to normal 320x200 256-color mode, which is really a
; 320x400 256-color mode with each line scanned twice.
;
	mov     ax,0013h  ;AH = 0 means mode set, AL = 13h selects
			; 256-color graphics mode
	int     10h     ;BIOS video interrupt
;
; Change CPU addressing of video memory to linear (not odd/even,
; chain, or chain 4), to allow us to access all 256K of display
; memory. When this is done, VGA memory will look just like memory
; in modes 10h and 12h, except that each byte of display memory will
; control one 256-color pixel, with 4 adjacent pixels at any given
; address, one pixel per plane.
;
	mov     dx,SC_INDEX
	mov     al,MEMORY_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 08h      ;turn off chain 4
	or      al,04h          ;turn off odd/even
	out     dx,al
	mov     dx,GC_INDEX
	mov     al,GRAPHICS_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 10h      ;turn off odd/even
	out     dx,al
	dec     dx
	mov     al,MISCELLANEOUS
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 02h      ;turn off chain
	out     dx,al

	mov     dx,SC_INDEX
	mov     ax,00f02h       ;CLEAR ALL PLANES
	out     dx,ax
	;mov     ax,cs:vram
	;mov     es,ax
	;mov     cx,32768
	;xor     ax,ax
	;rep     stosw
;
; Tweak the mode to 320x200 256-color mode by scanning each
; line twice.
;
	mov     dx,CRTC_INDEX
	mov     al,9
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 5fh      ;set maximum scan line = 0
	OR      AL,1
	out     dx,al
	dec     dx
;
; Change CRTC scanning from doubleword mode to byte mode, allowing
; the CRTC to scan more than 64K of video data.
;
	mov     al,UNDERLINE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 40h      ;turn off doubleword
	out     dx,al
	dec     dx
	mov     al,MODE_CONTROL
	out     dx,al
	inc     dx
	in      al,dx
	or      al,40h  ;turn on the byte mode bit, so memory is
			; scanned for video data in a purely
			; linear way, just as in modes 10h and 12h
	out     dx,al
	
	mov	dx,CRTC_INDEX
	mov	ax,2813h
	out	dx,ax ;width>=320
	
	ret
tweak320x200 ENDP

sethseq PROC NEAR ;ds:si=hseq
	mov	bl,1fh 	;overflow
	mov	bh,40h	;maximum scan line
	test	word ptr ds:[si+12],1
	jz	sss9
	or	bh,80h
sss9:
	mov	ax,ds:[si+0]
	test	ax,256
	jz	sss3
	or	bl,2
sss3:	test	ax,512
	jz	sss4
	or	bl,64
sss4:	mov	ah,al
	mov	dx,3d4h
	mov	al,12h
	out	dx,ax
	
	mov	ax,ds:[si+2]
	test	ax,256
	jz	sss1
	or	bl,8
sss1:	test	ax,512
	jz	sss2
	or	bh,32
sss2:	mov	ah,al
	mov	dx,3d4h
	mov	al,15h
	out	dx,ax
	
	mov	ax,ds:[si+4]
	test	ax,256
	jz	sss7
	or	bl,4
sss7:	test	ax,512
	jz	sss8
	or	bl,128
sss8:	mov	ah,al
	mov	dx,3d4h
	mov	al,10h
	out	dx,ax
	
	mov	ax,ds:[si+6]
	mov	ah,al
	and	ah,15
	or	ah,20h ;disable vertical int
	mov	dx,3d4h
	mov	al,11h
	out	dx,ax
	
	mov	ax,ds:[si+8]
	mov	ah,al
	mov	dx,3d4h
	mov	al,16h
	out	dx,ax
	
	mov	ax,ds:[si+10]
	test	ax,256
	jz	sss5
	or	bl,1
sss5:	test	ax,512
	jz	sss6
	or	bl,32
sss6:	mov	ah,al
	mov	dx,3d4h
	mov	al,6h
	out	dx,ax
	
	mov	dx,3d4h
	mov	al,7h
	mov	ah,bl
	out	dx,ax
	
	mov	dx,3d4h
	mov	al,9h
	mov	ah,bh
	out	dx,ax

	mov	ax,ds:[si+12]
	and	ax,not 1
	mov	bh,0
	cmp	ax,350
	jne	sss10
	mov	bh,1*64
sss10:	cmp	ax,400
	jne	sss11
	mov	bh,2*64
sss11:	cmp	ax,480
	jne	sss12
	mov	bh,3*64
sss12:	mov	dx,3cch
	in	al,dx
	and	al,3fh
	or	al,bh
	mov	dx,3c2h
	out	dx,al
	ret
sethseq ENDP

vptbl	dw	06a00h	; horz total 
	dw	05901h	; horz displayed
	dw	05a02h	; start horz blanking
	dw	08d03h	; end horz blanking
	dw	05e04h	; start h sync
	dw	08a05h	; end h sync
	dw	08b06h ;0d06h	; vertical total
	dw	01f07h ;03e07h	; overflow
	dw	04009h	; cell height
	dw	06810h	; v sync start
	dw	02a11h	; v sync end and protect cr0-cr7
	dw	05d12h	; vertical displayed
	dw	02e13h	; offset 92
	dw	00014h	; turn off dword mode
	dw	05d15h	; v blank start
	dw	00016h	; v blank end
	dw	0e317h	; turn on byte mode
vpend	label	word

mode13x	proc
	push	ds
	mov	ax,cs
	mov	ds,ax

	mov	ax,13h		; start with standard mode 13h
	int	10h		; let the bios set the mode

	mov	dx,3c4h		; alter sequencer registers
	mov	ax,0604h	; disable chain 4
	out	dx,ax

	mov	ax,0f02h	; set write plane mask to all bit planes
	out	dx,ax
	push	di
	xor	di,di
	mov	ax,0a000h	; screen starts at segment A000
	mov	es,ax
	mov	cx,21600	; ((XSIZE*YSIZE)/(4 planes))/(2 bytes per word)
	xor	ax,ax
	cld
	rep	stosw		; clear the whole of the screen
	pop	di

	mov	ax,0100h	; synchronous reset
	out	dx,ax		; asserted
	mov	dx,3c2h		; misc output
	mov	al,0a7h		; use 28 mHz dot clock ;a7
	out	dx,al		; select it
	mov	dx,3c4h		; sequencer again
	mov	ax,0300h	; restart sequencer
	out	dx,ax		; running again

	mov	dx,3d4h		; alter crtc registers

	mov	al,11h		; cr11
	out	dx,al		; current value
	inc	dx		; point to data
	in	al,dx		; get cr11 value
	and	al,7fh		; remove cr0 -> cr7
	out	dx,al		;    write protect
	dec	dx		; point to index
	cld
	mov	si,offset vptbl
	mov	cx,((offset vpend)-(offset vptbl)) shr 1
outlp:	lodsw
	out	dx,ax
	loop	outlp

	mov	ax,cs
	mov	ds,ax
	mov	si,OFFSET hseq2
	call	sethseq

;	mov	dx,3dah
;	in	al,dx
;	mov	dx,3c0h
;	mov	al,11h+32
;	out	dx,al
;	mov	al,8
;	out	dx,al

	pop	ds
	ret
mode13x	endp

tweak640x400 PROC NEAR
;
; First, go to normal 320x200 256-color mode, which is really a
; 320x400 256-color mode with each line scanned twice.
;
	mov     ax,002fh
	int     10h     ;BIOS video interrupt
;
; Change CPU addressing of video memory to linear (not odd/even,
; chain, or chain 4), to allow us to access all 256K of display
; memory. When this is done, VGA memory will look just like memory
; in modes 10h and 12h, except that each byte of display memory will
; control one 256-color pixel, with 4 adjacent pixels at any given
; address, one pixel per plane.
;
	mov     dx,SC_INDEX
	mov     al,MEMORY_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 08h      ;turn off chain 4
	or      al,04h          ;turn off odd/even
	out     dx,al
	mov     dx,GC_INDEX
	mov     al,GRAPHICS_MODE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 10h      ;turn off odd/even
	out     dx,al
	dec     dx
	mov     al,MISCELLANEOUS
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 02h      ;turn off chain
	out     dx,al
	ret
;
; Change CRTC scanning from doubleword mode to byte mode, allowing
; the CRTC to scan more than 64K of video data.
;
	mov     al,UNDERLINE
	out     dx,al
	inc     dx
	in      al,dx
	and     al,not 40h      ;turn off doubleword
	out     dx,al
	dec     dx
	mov     al,MODE_CONTROL
	out     dx,al
	inc     dx
	in      al,dx
	or      al,40h  ;turn on the byte mode bit, so memory is
			; scanned for video data in a purely
			; linear way, just as in modes 10h and 12h
	out     dx,al
	
	ret
tweak640x400 ENDP

hseq3 LABEL WORD ;0=start
	dw	349	;display enable end
	dw	355	;start vertical blank
	dw	395	;start vertical retrace
	dw	405	;end vertical retrace
	dw	445	;end vertical blank
	dw	455	;vertical total
	dw	350	;200/350/400/480=lines/monitor, +1=double scanning

tweak360x350	proc
	push	ds
	mov	ax,cs
	mov	ds,ax

	mov	ax,13h		; start with standard mode 13h
	int	10h		; let the bios set the mode

	mov	dx,3c4h		; alter sequencer registers
	mov	ax,0604h	; disable chain 4
	out	dx,ax

	mov	ax,0f02h	; set write plane mask to all bit planes
	out	dx,ax
	push	di
	xor	di,di
	mov	ax,0a000h	; screen starts at segment A000
	mov	es,ax
	mov	cx,21600	; ((XSIZE*YSIZE)/(4 planes))/(2 bytes per word)
	xor	ax,ax
	cld
	rep	stosw		; clear the whole of the screen
	pop	di

	mov	ax,0100h	; synchronous reset
	out	dx,ax		; asserted
	mov	dx,3c2h		; misc output
	mov	al,0a7h		; use 28 mHz dot clock
	out	dx,al		; select it
	mov	dx,3c4h		; sequencer again
	mov	ax,0300h	; restart sequencer
	out	dx,ax		; running again

	mov	dx,3d4h		; alter crtc registers

	mov	al,11h		; cr11
	out	dx,al		; current value
	inc	dx		; point to data
	in	al,dx		; get cr11 value
	and	al,7fh		; remove cr0 -> cr7
	out	dx,al		;    write protect
	dec	dx		; point to index
	cld
	mov	si,offset vptbl
	mov	cx,((offset vpend)-(offset vptbl)) shr 1
outlpn:	lodsw
	out	dx,ax
	loop	outlpn

	mov	ax,cs
	mov	ds,ax
	mov	si,OFFSET hseq3
	call	sethseq

	pop	ds
	ret
tweak360x350 endp

hseq4 LABEL WORD ;0=start
	dw	349	;display enable end
	dw	355	;start vertical blank
	dw	395	;start vertical retrace
	dw	405	;end vertical retrace
	dw	450	;end vertical blank
	dw	455	;vertical total
	dw	350	;200/350/400/480=lines/monitor, +1=double scanning

tweak320x350	proc
	call	tweak360x350
	ret
tweak320x350 endp
