;	Generic assembler routines having to do with video adapter
;
; ---- Video Routines
;
;	setvideomode()
;	setvideotext()
;	getcolor()
;	putcolor()
;	out_line()
;	drawbox()
;	home()
;	movecursor()
;	keycursor()
;	putstring()
;	setattr()
;	scrollup()
;	scrolldown()
;	putstr()
;	loaddac()
;	spindac()
;	adapter_init
;	adapter_detect
;	setnullvideo
;
; ---- Help (Video) Support
;
;	setfortext()
;	setforgraphics()
;	setclear()
;	findfont()
;

;			 required for compatibility if Turbo ASM
IFDEF ??version
	MASM51
	QUIRKS
ENDIF

	.MODEL	medium,c

	.8086

	; these must NOT be in any segment!!
	; this get's rid of TURBO-C fixup errors

	extrn	startvideo:far		; start your-own-video routine
	extrn	readvideo:far		; read	your-own-video routine
	extrn	writevideo:far		; write your-own-video routine
	extrn	endvideo:far		; end	your-own-video routine
	extrn	readvideopalette:far	; read-your-own-palette routine
	extrn	writevideopalette:far	; write-your-own-palette routine

	extrn	startdisk:far		; start disk-video routine
	extrn	readdisk:far		; read	disk-video routine
	extrn	writedisk:far		; write disk-video routine
	extrn	enddisk:far		; end	disk-video routine

	extrn	buzzer:far		; nyaah, nyaah message

	extrn	getakey:far		; for keycursor routine
	extrn	keypressed:far		;  ...

; TARGA 28 May 80 - j mclain
	extrn	StartTGA  :far		; start TARGA
	extrn	ReadTGA   :far		; read	TARGA
	extrn	WriteTGA  :far		; write TARGA
	extrn	EndTGA	  :far		; end	TARGA
	extrn	ReopenTGA :far		; restart TARGA

; TARGA+ Mark Peterson 2-12-91
	extrn	MatchTPlusMode:far
	extrn	CheckForTPlus:far
	extrn	WriteTPlusBankedPixel:far
	extrn	ReadTPlusBankedPixel:far
	extrn	TPlusLUT:far

; 8514/A routines		; changed 8514/A routines to near JCO 4/11/92
	extrn	open8514  :near	    ; start 8514a
	extrn	reopen8514:near	    ; restart 8514a
	extrn	close8514 :near	    ; stop 8514a
	extrn	fr85wdot  :near	    ; 8514a write dot
	extrn	fr85wbox  :near	    ; 8514a write box
	extrn	fr85rdot  :near	    ; 8514a read dot
	extrn	fr85rbox  :near	    ; 8514a read box
	extrn	w8514pal  :near	    ; 8514a pallete update

; HW Compatible 8514/A routines    ; AW, made near JCO 4/11/92
	extrn	open8514hw  :near      ; start 8514a
	extrn	reopen8514hw:near      ; restart 8514a
	extrn	close8514hw :near      ; stop 8514a
	extrn	fr85hwwdot  :near      ; 8514a write dot
	extrn	fr85hwwbox  :near      ; 8514a write box
	extrn	fr85hwrdot  :near      ; 8514a read dot
	extrn	fr85hwrbox  :near      ; 8514a read box
	extrn	w8514hwpal  :near      ; 8514a pallete update

; Hercules Routines
	extrn	inithgc   :far	    ; Initialize Hercules card graphics mode
	extrn	termhgc   :far	    ; Terminate Hercules card graphics mode
	extrn	writehgc  :far	    ; Hercules write dot
	extrn	readhgc   :far	    ; Hercules read dot

; setforgraphics/setfortext textsafe=save
	extrn	savegraphics	:far
	extrn	restoregraphics :far

.DATA

; ************************ External variables *****************************

	extrn	oktoprint: word 	; flag: == 1 if printf() will work
	extrn	videoentry:byte 	; video table entry flag
	extrn	dotmode: word		; video mode (see the comments
					; in front of the internal video
					; table for legal dot modes)
	extrn	textsafe2: word 	; textsafe over-ride from videotable

	extrn	sxdots:word,sydots:word ; physical screen number of dots
	extrn	sxoffs:word,syoffs:word ; logical screen top left
	extrn	colors:word		; colors
	extrn	cyclelimit:word 	; limiting factor for DAC-cycler
	extrn	debugflag:word		; for debugging purposes only

	extrn	boxcount:word		; (previous) box pt counter: 0 if none.
	extrn	boxx:word, boxy:word	; zoom-box save-value locations
	extrn	boxvalues:byte		; zoom-box save-pixel locations

	extrn	xorTARGA:word		; TARGA 3 June 89 j mclain
					; flag says xor pixels for box

	extrn	cpu:word		; CPU type (86, 186, 286, or 386)
	extrn	extraseg:word		; location of the EXTRA segment

	extrn	suffix:word		; (safe place during video-mode switches)

	extrn	swaplength:word 	; savegraphics/restoregraphics stuff
	extrn	swapoffset:dword	; ...
	extrn	swapvidbuf:dword	; ...
	extrn	swaptotlen:dword	; ...

	extrn	rotate_lo:word, rotate_hi:word

	extrn	bios_palette:word
	extrn	paldata:byte

	extrn	xdots:word
	extrn	ydots:word
	extrn	colors:word
	extrn	NonInterlaced:word
	extrn	PixelZoom:word
	extrn	MaxColorRes:word
	extrn	TPlusFlag:WORD		; TARGA+ Mark Peterson 2-12-91
	extrn	ai_8514:byte		;flag for 8514a afi JCO 4/11/92

; ************************ Public variables *****************************

public		andcolor		; used by 'calcmand'
public		videotable
public		loadPalette		; flag for loading VGA/TARGA palette from disk
public		dacbox			; GIF saves use this
public		daclearn, daccount	; Rotate may want to use this
public		rowcount		; row-counter for decoder and out_line
public		gotrealdac		; loaddac worked, really got a dac
public		reallyega		; "really an EGA" (faking a VGA) flag
public		diskflag		; disk video active flag
public		video_type		; video adapter type
public		svga_type		; SuperVGA video adapter type
public		mode7text		; for egamono and hgc
public		textaddr		; text segment
public		textsafe		; setfortext/setforgraphics logic
public		boxcolor		; zoom box color
public		goodmode		; video mode ok?
public		text_type		; current mode's type of text
public		textrow 		; current row in text mode
public		textcol 		; current column in text mode
public		textrbase		; textrow is relative to this
public		textcbase		; textcol is relative to this

public		color_dark		; darkest color in palette
public		color_bright		; brightest color in palette
public		color_medium		; nearest to medbright grey in palette

public		swapsetup		; for savegraphics/restoregraphics

public		TPlusInstalled

public		vesa_detect		; set to 0 to disable VESA-detection

public          vxdots                  ; virtual scan line length
;		arrays declared here, used elsewhere
;		arrays not used simultaneously are deliberately overlapped

; ************************ Internal variables *****************************

vxdots		dw	0		; virtual scan line length (bytes)

goodmode	dw	0		; if non-zero, OK to read/write pixels
dotwrite	dw	0		; write-a-dot routine:	mode-specific
dotread 	dw	0		; read-a-dot routine:	mode-specific
linewrite	dw	0		; write-a-line routine: mode-specific
lineread	dw	0		; read-a-line routine: mode-specific
swapsetup	dd	0		; setfortext/graphics setup routine
andcolor	dw	0		; "and" value used for color selection
color		db	0		; the color to set a pixel
videoflag	db	0		; special "your-own-video" flag
tgaflag 	db	0		; TARGA 28 May 89 - j mclain
loadPalette	db	0		; TARGA/VGA load palette from disk

f85flag 	db	0		;flag for 8514a

HGCflag 	db	0		;flag for Hercules Graphics Adapter

TPlusInstalled	dw	0

xga_pos_base	dw	0		; MCA Pos Base value
xga_cardid	dw	0		; MCA Card ID value
xga_reg_base	dw	-1		; XGA IO Reg Base (-1 means dunno yet)
xga_1mb 	dd	0		; XGA 1MB aperture address
xga_4mb 	dd	0		; XGA 4MB aperture address
xga_result	dw	0		; XGA_detect result code
xga_isinmode	dw	0		; XGA is in this mode right now
xga_iscolors	dw	0		; XGA using this many colors (0=64K)
xga_clearvideo	db	0		; set to 80h to prevent video-clearing
xga_loaddac	db	0		; set to 1 to load 'dacbox' on modesw
xga_xdots	dw	0		; pixels per scan line

		align	2
tmpbufptr	dd	0
color_dark	dw	0		; darkest color in palette
color_bright	dw	0		; brightest color in palette
color_medium	dw	0		; nearest to medbright grey in palette
;					; Zoom-Box values (2K x 2K screens max)
boxcolor	dw	0		; Zoom-Box color
reallyega	dw	0		; 1 if its an EGA posing as a VGA
gotrealdac	dw	0		; 1 if loaddac has a dacbox
diskflag	dw	0		; special "disk-video" flag
palettega	db	17 dup(0)	; EGA palette registers go here
daclearn	db	0		; 0 if "learning" DAC speed
dacnorm 	db	0		; 0 if "normal" DAC update
daccount	dw	0		; DAC registers to update in 1 pass
dacbox		db	773 dup(0)	; DAC goes here
;;saved_dacreg	dw	0ffffh,0,0,0	; saved DAC register goes here

orvideo 	db	0		; "or" value for setvideo
		align	2
rowcount	dw	0		; row-counter for decoder and out_line

videomem	dw	0a000h		; VGA videomemory
videoax 	dw	0		; graphics mode values: ax
videobx 	dw	0		; graphics mode values: bx
videocx 	dw	0		; graphics mode values: cx
videodx 	dw	0		; graphics mode values: dx

video_type	dw	0		; actual video adapter type:
					;   0  = type not yet determined
					;   1  = Hercules
					;   2  = CGA (assumed if nothing else)
					;   3  = EGA
					;   4  = MCGA
					;   5  = VGA
					;   6  = VESA (not yet checked)
					;  11  = 8514/A (not yet checked)
					;  12  = TIGA	(not yet checked)
					;  13  = TARGA	(not yet checked)
svga_type	dw	0		;  (forced) SVGA type
					;   1 = ahead "A" type
					;   2 = ATI
					;   3 = C&T
					;   4 = Everex
					;   5 = Genoa
					;   6 = Ncr
					;   7 = Oak-Tech
					;   8 = Paradise
					;   9 = Trident
					;  10 = Tseng 3000
					;  11 = Tseng 4000
					;  12 = Video-7
					;  13 = ahead "B" type
					;  14 = "null" type (for testing only)
mode7text	dw	0		; nonzero for egamono and hgc
textaddr	dw	0b800h		; b800 for mode 3, b000 for mode 7
textsafe	dw	0		; 0 = default, runup chgs to 1
					; 1 = yes
					; 2 = no, use 640x200
					; 3 = bios, yes plus use int 10h-1Ch
					; 4 = save, save entire image
text_type	dw	0		; current mode's type of text:
					;   0  = real text, mode 3 (or 7)
					;   1  = 640x200x2, mode 6
					;   2  = some other mode, graphics
video_entries	dw	0		; offset into video_entries table
video_bankadr	dw	0		; offset  of  video_banking routine
video_bankseg	dw	0		; segment of  video_banking routine

textrow 	dw	0		; for putstring(-1,...)
textcol 	dw	0		; for putstring(..,-1,...)
textrbase	dw	0		; textrow is relative to this
textcbase	dw	0		; textcol is relative to this
cursortyp	dw	0

tandyseg	dw	?		;Tandy 1000 video segment address
tandyofs	dw	?		;Tandy 1000 Offset into video buffer
tandyscan	dw	?		;Tandy 1000 scan line address pointer


; ******************* "Tweaked" VGA mode variables ************************

						; 704 x 528 mode
x704y528	db	704/8			; number of screen columns
		db	528/16			; number of screen rows
		db	 68h, 57h, 58h, 8Bh	; CRTC Registers
		db	 59h, 86h, 3EH,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 3Dh
		db	 19h, 8Bh, 0Fh, 2Ch
		db	  0h, 18h, 38h,0E3h
		db	0FFh
						; 720 x 540 mode
x720y540	db	720/8			; number of screen columns
		db	540/16			; number of screen rows
		db	 6Ah, 59h, 5Ah, 8Dh	; CRTC Registers
		db	 5Eh, 8Bh, 4AH,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 49h
		db	 24h, 86h, 1Bh, 2Dh
		db	  0h, 24h, 44h,0E3h
		db	0FFh
						; 736 x 552 mode
x736y552	db	736/8			; number of screen columns
		db	552/16			; number of screen rows
		db	 6Ch, 5Bh, 5Ch, 8Fh	; CRTC Registers
		db	 5Fh, 8Ch, 56H,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 55h
		db	 2Bh, 8Dh, 27h, 2Eh
		db	  0h, 30h, 50h,0E3h
		db	0FFh
						; 752 x 564 mode
x752y564	db	752/8			; number of screen columns
		db	564/16			; number of screen rows
		db	 6Eh, 5Dh, 5Eh, 91h	; CRTC Registers
		db	 62h, 8Fh, 62H,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 61h
		db	 37h, 89h, 33h, 2Fh
		db	  0h, 3Ch, 5Ch,0E3h
		db	0FFh
						; 768 x 576 mode
x768y576	db	768/8			; number of screen columns
		db	576/16			; number of screen rows
		db	 70h, 5Fh, 60h, 93h	; CRTC Registers
		db	 66h, 93h, 6EH,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 6Dh
		db	 43h, 85h, 3Fh, 30h
		db	  0h, 48h, 68h,0E3h
		db	0FFh
						; 784 x 588 mode
x784y588	db	784/8			; number of screen columns
		db	588/16			; number of screen rows
		db	 72h, 61h, 62h, 95h	; CRTC Registers
		db	 69h, 96h, 7AH,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 79h
		db	 4Fh, 81h, 4Bh, 31h
		db	  0h, 54h, 74h,0E3h
		db	0FFh
						; 800 x 600 mode
x800y600	db	800/8			; number of screen columns
		db	600/16			; number of screen rows
		db	 74h, 63h, 64h, 97h	; CRTC Registers
		db	 68h, 95h, 86H,0F0h
		db	  0h, 60h,  0h,  0h
		db	  0h,  0h,  2h, 85h
		db	 5Bh, 8Dh, 57h, 32h
		db	  0h, 60h, 80h,0E3h
		db	0FFh

x360y480	db	360/8			; number of screen columns
		db	480/16			; number of screen rows
		db	 6bh, 59h, 5ah, 8eh	; CRTC Registers
		db	 5eh, 8ah, 0DH,03Eh
		db	  0h, 40h, 00h,  0h
		db	  0h,  0h,  0h, 31h
		db	0EAh, 0ACh, 0DFh, 2Dh
		db	  0h,0E7h, 06h,0E3h
		db	0FFh

x320y480	db	320/8			; number of screen columns
		db	480/16			; number of screen rows
		db	 5fh, 4fh, 50h, 82h	; CRTC Registers
		db	 54h, 80h, 0DH,03Eh
		db	  0h, 40h, 00h,  0h
		db	  0h,  0h,  0h,  0h
		db	0EAh, 0AEh, 0DFh, 28h
		db	  0h,0E7h, 006h,0E3h
		db	0FFh

; mode x from Michael Abrash
x320y240	db	320/8			; number of screen columns
		db	240/16			; number of screen rows
		db	05fh, 04fh, 050h, 082h
		db	054h, 080h, 0dh, 03eh
		db	00h, 041h, 00h, 00h
		db	00h, 00h, 00h, 00h
		db	0eah, 0ach, 0dfh, 028h
		db	00h, 0e7h, 06h, 0e3h
		db	 0ffh

x320y400	db	320/8			; number of screen columns
		db	400/16			; number of screen rows
		db	 5fh, 4fh, 50h, 82h	; CRTC Registers
		db	 54h, 80h,0bfh, 1fh
		db	 00h, 40h, 00h, 00h
		db	 00h, 00h, 00h, 00h
		db	 9ch, 8eh, 8fh, 28h
		db	 00h, 96h,0b9h,0E3h
		db	0FFh

x640y400	db	640/8			; number of screen columns
		db	400/16			; number of screen rows
		db	 5eh, 4fh, 50h, 01h	; CRTC Registers
		db	 54h, 9fh,0c0h, 1fh
		db	 00h, 40h, 00h, 00h
		db	 00h, 00h, 00h, 00h
		db	 9ch,08eh, 8fh, 28h
		db	 00h, 95h,0bch,0c3h
		db	 0ffh
;for VGA
x400y600	db	400/8
		db	600/16
		db	74h,63h,64h,97h
		db	68h,95h,86h,0F0h
		db	00h,60h,00h,00h
		db	00h,00h,00h,31h
		db	5Bh,8Dh,57h,32h
		db	0h,60h,80h,0E3h
		db	0FFh
;for VGA
x376y564	db	376/8
		db	564/16
		db	6eh,5dh,5eh,91h
		db	62h,8fh,62h,0F0h
		db	00h,60h,00h,00h
		db	00h,00h,00h,31h
		db	37h,89h,33h,2fh
		db	0h,3ch,5ch,0E3h
		db	0FFh
;for VGA
x400y564	db	400/8
		db	564/16
		db	74h,63h,64h,97h
		db	68h,95h,62h,0F0h
		db	00h,60h,00h,00h
		db	00h,00h,00h,31h
		db	37h,89h,33h,32h
		db	0h,3ch,5ch,0E3h
		db	0FFh

testati 	db	832/8
		db	612/16
		db	7dh,65h,68h,9fh
		db	69h,92h,44h,1Fh
		db	00h,00h,00h,00h
		db	00h,00h,00h,00h
		db	34h,86h,37h,34h
		db	0fh,34h,40h,0E7h
		db	0FFh

		align	2

tweaks		dw	offset x704y528 	; tweak table
		dw	offset x704y528
		dw	offset x720y540
		dw	offset x736y552
		dw	offset x752y564
		dw	offset x768y576
		dw	offset x784y588
		dw	offset x800y600
		dw	offset x360y480
		dw	offset x320y400
		dw	offset x640y400 	; Tseng Super VGA
		dw	offset x400y600 	; new tweak (VGA)
		dw	offset x376y564 	; new tweak (VGA)
		dw	offset x400y564 	; new tweak (VGA)
		dw	offset x720y540 	; ATI Tweak
		dw	offset x736y552 	; ATI Tweak
		dw	offset x752y564 	; ATI Tweak
		dw	offset testati		; ATI 832x816 (works!)
		dw	offset x320y480
		dw	offset x320y240

tweakflag	dw	0			; tweak mode active flag
tweaktype	dw	0			; 8 or 9 (320x400 or 360x480)

bios_vidsave	dw	0			; for setfortext/graphics

.CODE

FRAME	MACRO regs
	push	bp
	mov	bp, sp
	IRP	reg, <regs>
	  push	reg
	  ENDM
	ENDM

UNFRAME MACRO regs
	IRP	reg, <regs>
	  pop reg
	  ENDM
	pop bp
	ENDM


;			Video Table Entries
;
;	The Video Table has been moved to a FARDATA segment to relieve
;	some of the pressure on the poor little overloaded 64K DATA segment.

.code

video_requirements	dw	0		; minimal video_type req'd
	dw	1, 3, 4, 5, 5, 5, 5, 5, 1, 1	; dotmodes  1 - 10
	dw	1, 5, 2, 1, 5, 5, 5, 5, 1, 5	; dotmodes 11 - 20
	dw	5, 5, 5, 5, 5, 5, 5, 5, 5, 5	; dotmodes 21 - 30

videotable	label	byte	; video table actually starts on the NEXT byte

;	Feel free to add your favorite video adapter to FRACTINT.CFG.
;	The entries hard coded here are repeated from fractint.cfg in case
;	it gets lost/destroyed, so a user can still have some modes.

;	Currently available Video Modes are (use the BIOS as a last resort)
;		1) use the BIOS (INT 10H, AH=12/13, AL=color) ((SLOW))
;		2) pretend it's a (perhaps super-res) EGA/VGA
;		3) pretend it's an MCGA
;		4) SuperVGA 256-Color mode using the Tseng Labs Chipset
;		5) SuperVGA 256-Color mode using the Paradise Chipset
;		6) SuperVGA 256-Color mode using the Video-7 Chipset
;		7) Non-Standard IBM VGA 360 x 480 x 256-Color mode
;		8) SuperVGA 1024x768x16 mode for the Everex Chipset
;		9) TARGA video modes
;		10) HERCULES video mode
;		11) Non-Video [disk or RAM] "video"
;		12) 8514/A video modes
;		13) CGA 320x200x4-color and 640x200x2-color modes
;		14) Tandy 1000 video modes
;		15) SuperVGA 256-Color mode using the Trident Chipset
;		16) SuperVGA 256-Color mode using the Chips & Tech Chipset
;		17) SuperVGA 256-Color mode using the ATI VGA Wonder Chipset
;		18) SuperVGA 256-Color mode using the Everex Chipset
;		19) Roll-Your-Own video, as defined in YOURVID.C
;		20) SuperVGA 1024x768x16 mode for the ATI VGA Wonder Chipset
;		21) SuperVGA 1024x768x16 mode for the Tseng Labs Chipset
;		22) SuperVGA 1024x768x16 mode for the Trident Chipset
;		23) SuperVGA 1024x768x16 mode for the Video 7 Chipset
;		24) SuperVGA 1024x768x16 mode for the Paradise Chipset
;		25) SuperVGA 1024x768x16 mode for the Chips & Tech Chipset
;		26) SuperVGA 1024x768x16 mode for the Everex Chipset
;		27) SuperVGA Auto-Detect mode
;		28) VESA modes
;		29) True Color Auto-Detect

;	(Several entries have been commented out - they should/did work,
;	but are handled by alternative entries.  Where multiple SuperVGA
;	entries are covered by a single SuperVGA Autodetect mode, the
;	individual modes have been commented out.  Where a SuperVGA
;	Autodetect mode covers only one brand of adapter, the Autodetect
;	mode has been commented out to avoid confusion.)

;		|--Adapter/Mode-Name------|-------Comments-----------|

;		|------INT 10H------|Dot-|--Resolution---|
;	    |key|--AX---BX---CX---DX|Mode|--X-|--Y-|Color|

	db	"IBM 16-Color EGA         ",0,"Standard EGA hi-res mode ",0
	dw 1060,  10h,	 0,   0,   0,	2, 640, 350,  16
	db	"IBM 256-Color VGA/MCGA   ",0,"Quick and LOTS of colors ",0
	dw 1061,  13h,	 0,   0,   0,	3, 320, 200, 256
	db	"IBM 16-Color VGA         ",0,"Nice high resolution     ",0
	dw 1062,  12h,	 0,   0,   0,	2, 640, 480,  16
	db	"IBM 4-Color CGA          ",0,"(Ugh - Yuck - Bleah)     ",0
	dw 1063,   4h,	 0,   0,   0,  13, 320, 200,   4
	db	"IBM Hi-Rez B&W CGA       ",0,"('Hi-Rez' Ugh - Yuck)    ",0
	dw 1064,   6h,	 0,   0,   0,  13, 640, 200,   2
	db	"IBM B&W EGA              ",0,"(Monochrome EGA)         ",0
	dw 1065,  0fh,	 0,   0,   0,	2, 640, 350,   2
	db	"IBM B&W VGA              ",0,"(Monochrome VGA)         ",0
	dw 1066,  11h,	 0,   0,   0,	2, 640, 480,   2
	db	"IBM Low-Rez EGA          ",0,"Quick but chunky         ",0
	dw 1067,  0dh,	 0,   0,   0,	2, 320, 200,  16
	db	"IBM VGA (non-std)        ",0,"Register Compatibles ONLY",0
	dw 1068,   0h,	 0,   0,   9,	7, 320, 400, 256
	db	"IBM VGA (non-std)        ",0,"Register Compatibles ONLY",0
	dw 1084,   0h,	 0,   0,   8,	7, 360, 480, 256
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1085,    0,	 0,   0,   0,  27, 800, 600,  16
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1086,    0,	 0,   0,   0,  27,1024, 768,  16
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1087,    0,	 0,   0,   0,  27, 640, 400, 256
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1088,    0,	 0,   0,   0,  27, 640, 480, 256
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1089,    0,	 0,   0,   0,  27, 800, 600, 256
	db	"SuperVGA/VESA Autodetect ",0,"Works with most SuperVGA ",0
	dw 1090,    0,	 0,   0,   0,  27,1024, 768, 256
	db	"VESA Standard interface  ",0,"OK: Andy Fu - Chips&Tech ",0
	dw 1091,4f02h,106h,   0,   0,  28,1280,1024,  16
	db	"VESA Standard interface  ",0,"OK: Andy Fu - Chips&Tech ",0
        dw 1092,4f02h,107h,   0,   0,  28,1280,1024, 256
        db      "8514/A Low  Res          ",0,"HW/AI (AI Reqs HDILOAD)  ",0
        dw 1093,   3h,   0,   0,   1,  12, 640, 480, 256
        db      "8514/A High Res          ",0,"HW/AI (AI Reqs HDILOAD)  ",0
        dw 1094,   3h,   0,   0,   1,  12,1024, 768, 256
        db      "8514/A Low  W/Border     ",0,"HW/AI (AI Reqs HDILOAD)  ",0
        dw 1095,   3h,   0,   0,   1,  12, 632, 474, 256
        db      "8514/A High W/Border     ",0,"HW/AI (AI Reqs HDILOAD)  ",0
        dw 1096,   3h,   0,   0,   1,  12,1016, 762, 256
        db      "IBM Med-Rez EGA          ",0,"(Silly but it's there!)  ",0
        dw 1097,  0eh,   0,   0,   0,   2, 640, 200,  16
        db      "IBM VGA (non-std)        ",0,"Register Compatibles ONLY",0
        dw 1098,   0h,   0,   0,  18,   7, 320, 480, 256
        db      "Hercules Graphics        ",0,"OK: Timothy Wegner       ",0
        dw 1099,   8h,   0,   0,   0,  10, 720, 348,   2
        db      "Tandy 1000               ",0,"OK: Joseph Albrecht      ",0
        dw 1100,   9h,   0,   0,   0,  14, 320, 200,  16
        db      "Pdise/AST/COMPAQ VGA     ",0,"OK: Phil Wilson          ",0
        dw 1101,  59h,   0,   0,   0,   1, 800, 600,   2
        db      140     dup(0)  ; 2 unused slots here default table
        db      "Disk/RAM 'Video'         ",0,"Full-Page L-Jet @  75DPI ",0
	dw 1104,   3h,	 0,   0,   0,  11, 800, 600,   2
	db	"Disk/RAM 'Video'         ",0,"Full-Page L-Jet @ 150DPI ",0
	dw 1105,   3h,	 0,   0,   0,  11,1600,1200,   2
	db	"Disk/RAM 'Video'         ",0,"Full-Page Epson @ 120DPI ",0
	dw 1106,   3h,	 0,   0,   0,  11, 768, 960,   2
	db	"Disk/RAM 'Video'         ",0,"Full-Page Paintjet 90DPI ",0
	dw 1107,   3h,	 0,   0,   0,  11, 960, 720, 256
	db	"Disk/RAM 'Video'         ",0,"For Background Fractals  ",0
	dw 1108,   3h,	 0,   0,   0,  11, 800, 600, 256
	db	"Disk/RAM 'Video'         ",0,"For Background Fractals  ",0
	dw 1109,   3h,	 0,   0,   0,  11,2048,2048, 256
	db	280	dup(0)	; 4 unused slots here default table
	db	 70	dup(0)	; 1 slot reserved for unassigned current mode


bios_savebuf db 256 dup(0)  ; enough for 4 blocks (64 bytes/block)

.code

;		XGA Graphics mode setup values
;		(the first two entries in each line
;		indicate where the table values are to be stored)
;
;		1024x768x256 vvv
;		1024x768x16  -----vvvv
;		640x480x256  -----------vvvv
;		640x480x65536 ----------------vvvv
;		800x600x16   -----------------------vvvv
;		800x600x256  -----------------------------vvvv
;		800x600x65536 ----------------------------------vvvv

xga_twidth dw	9					; width of these tables

xga_requir dw	   0,	 0,  0dh,  05h,  01h,  09h,  01h,  01h,  09h	; adapter requirements
xga_colors dw	   0,	 0,  256,   16,  256,	 0,   16,  256,    0	; 0 means 64K colors
xga_swidth dw	   0,	 0, 1024,  512,  640, 1280,  400,  800, 1600	; bytes / scan line

xga_val db	004h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; interrupt enable
	db	005h, 000h, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh	; interrupt status
	db	000h, 000h, 004h, 004h, 004h, 004h, 004h, 004h, 004h	; operating mode
	db	00ah, 064h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; palette mask
	db	001h, 000h, 001h, 001h, 001h, 001h, 001h, 001h, 001h	; vid mem aper cntl
	db	008h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; vid mem aper indx
	db	006h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; virt mem ctl
	db	009h, 000h, 003h, 002h, 003h, 004h, 002h, 003h, 004h	; mem access mode
	db	00ah, 050h, 001h, 001h, 001h, 001h, 001h, 001h, 001h	; disp mode 1
	db	00ah, 050h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; disp mode 1
	db	00ah, 010h, 09dh, 09dh, 063h, 063h, 088h, 088h, 088h	; horiz tot lo.
	db	00ah, 011h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; horiz tot hi.
	db	00ah, 012h, 07fh, 07fh, 04fh, 04fh, 063h, 063h, 063h	; hor disp end lo
	db	00ah, 013h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; hor disp end hi
	db	00ah, 014h, 080h, 080h, 050h, 050h, 064h, 064h, 064h	; hor blank start lo
	db	00ah, 015h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; hor blank start hi
	db	00ah, 016h, 09ch, 09ch, 062h, 062h, 087h, 087h, 087h	; hor blank end lo
	db	00ah, 017h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; hor blank end hi
	db	00ah, 018h, 087h, 087h, 055h, 055h, 06ah, 06ah, 06ah	; hor sync start lo
	db	00ah, 019h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; hor sync start hi
	db	00ah, 01ah, 09ch, 09ch, 061h, 061h, 084h, 084h, 084h	; hor sync end lo
	db	00ah, 01bh, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; hor sync end hi
	db	00ah, 01ch, 040h, 040h, 000h, 000h, 000h, 000h, 000h	; hor sync pos
	db	00ah, 01eh, 004h, 004h, 000h, 000h, 000h, 000h, 000h	; hor sync pos
	db	00ah, 020h, 030h, 030h, 00ch, 00ch, 086h, 086h, 086h	; vert tot lo
	db	00ah, 021h, 003h, 003h, 002h, 002h, 002h, 002h, 002h	; vert tot hi
	db	00ah, 022h, 0ffh, 0ffh, 0dfh, 0dfh, 057h, 057h, 057h	; vert disp end lo
	db	00ah, 023h, 002h, 002h, 001h, 001h, 002h, 002h, 002h	; vert disp end hi
	db	00ah, 024h, 000h, 000h, 0e0h, 0e0h, 058h, 058h, 058h	; vert blank start lo
	db	00ah, 025h, 003h, 003h, 001h, 001h, 002h, 002h, 002h	; vert blank start hi
	db	00ah, 026h, 02fh, 02fh, 00bh, 00bh, 085h, 085h, 085h	; vert blank end lo
	db	00ah, 027h, 003h, 003h, 002h, 002h, 002h, 002h, 002h	; vert blank end hi
	db	00ah, 028h, 000h, 000h, 0eah, 0eah, 058h, 058h, 058h	; vert sync start lo
	db	00ah, 029h, 003h, 003h, 001h, 001h, 002h, 002h, 002h	; vert sync start hi
	db	00ah, 02ah, 008h, 008h, 0ech, 0ech, 06eh, 06eh, 06eh	; vert sync end
	db	00ah, 02ch, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh	; vert line comp lo
	db	00ah, 02dh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh	; vert line comp hi
	db	00ah, 036h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; sprite cntl
	db	00ah, 040h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; start addr lo
	db	00ah, 041h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; start addr me
	db	00ah, 042h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; start addr hi
	db	00ah, 043h, 080h, 040h, 050h, 0a0h, 032h, 064h, 0c8h	; pixel map width lo
	db	00ah, 044h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; pixel map width hi
	db	00ah, 054h, 00dh, 00dh, 000h, 000h, 001h, 001h, 001h	; clock sel
	db	00ah, 051h, 003h, 002h, 003h, 004h, 002h, 003h, 004h	; display mode 2
	db	00ah, 070h, 000h, 000h, 000h, 000h, 080h, 080h, 080h	; ext clock sel
	db	00ah, 050h, 00fh, 00fh, 0c7h, 0c7h, 007h, 007h, 007h	; display mode 1
	db	00ah, 055h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; Border Color
	db	00ah, 060h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; Sprite Pal Lo
	db	00ah, 061h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; Sprite Pal hi
	db	00ah, 062h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; Sprite Pre Lo
	db	00ah, 063h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; Sprite Pre hi
	db	00ah, 064h, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh	; Palette Mask
	db	0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh	; end of the list


xga_newbank	proc			; XGA-specific bank-switching routine
	cmp	xga_isinmode,2		; are we in an XGA-specific mode?
	jl	return			;  nope.  bail out.
	mov	curbk,ax		; save the new current bank value
	mov	dx,xga_reg_base 	; Select Page
	add	dx,08h
	out	dx,al			; assumes bank number is in al
return: ret
xga_newbank	endp

xga_16linewrite proc	near		; 16-color Line Write
	mov	bx,ax			; calculate the # of columns
	sub	bx,cx
	mov	ax,xga_xdots		; this many dots / line
	mul	dx			; times this many lines - ans in dx:ax
	push	cx			; save the X-value for a tad
	shr	cx,1			; and adjust for two bits per pixel
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; answer in dx:ax - dl=bank, ax=offset
	mov	di,ax			; save offset in DI
	pop	cx			; restore the X-value
	mov	ax,dx			; xga_newbank expects bank in al
new_bank:
	call	far ptr xga_newbank
same_bank:
	mov	ah,es:[di]		; grab the old byte value
	mov	al,[si] 		; and the new color value
	and	al,0fh			; isolate the bits we want
	test	cx,1			; odd pixel address?
	jnz	xga_sk1 		;  yup
	and	ah,0f0h 		; isolate the low-order
	jmp	short	xga_sk2
xga_sk1:and	ah,0fh			; isolate the high-order
	shl	al,1
	shl	al,1
	shl	al,1
	shl	al,1
xga_sk2:or	al,ah			; combine the two nibbles
	mov	es:[di],al		; write the dot
	inc	si			; increment the source addr
	dec	bx			; more to go?
	jz	done			; nope
	inc	cx			; next pixel
	test	cx,1			; odd pixel?
	jnz	same_bank		;  yup
	inc	di			; increment the destination
	cmp	di,0			; segment wrap?
	jnz	same_bank		;  nope
	mov	ax,curbk		; update the bank cvalue
	inc	ax
	jmp	new_bank
done:	ret
xga_16linewrite 	endp

xga_super16addr proc near		; can be put in-line but shared by
					; read and write routines
	clc				; clear carry flag
	push	ax			; save this for a tad
	mov	ax,xga_xdots		; this many dots / line
	mul	dx			; times this many lines - ans in dx:ax
	push	cx			; save the X-value for a tad
	shr	cx,1			; and adjust for two bits per pixel
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; answer in dx:ax - dl=bank, ax=offset
	pop	cx			; restore the X-value
	mov	bx,ax			; save this in BX
	cmp	dx,curbk		; see if bank changed
	je	same_bank		; jump if old bank ok
	mov	ax,dx			; xga_newbank expects bank in al
	call	far ptr xga_newbank
same_bank:
	pop	ax			; restore AX
	ret
xga_super16addr endp

xga_16write	proc near		; XGA 256 colors write-a-dot
	call	xga_super16addr 	; calculate address and switch banks
	mov	ah,es:[bx]		; grab the old byte value
	and	al,0fh			; isolate the bits we want
	test	cx,1			; odd pixel address?
	jnz	xga_sk1 		;  yup
	and	ah,0f0h 		; isolate the low-order
	jmp	short	xga_sk2
xga_sk1:and	ah,0fh			; isolate the high-order
	shl	al,1
	shl	al,1
	shl	al,1
	shl	al,1
xga_sk2:or	al,ah			; combine the two nibbles
	mov	es:[bx],al		; write the dot
	ret				; we done.
xga_16write	endp

xga_16read	proc near		; XGA 256 colors read-a-dot
	call	xga_super16addr 	; calculate address and switch banks
	mov	al,es:[bx]		; read the dot
	test	cx,1			; odd number of pixels?
	jz	xga_sk1 		;  nope
	shr	ax,1			; adjust for odd pixel count
	shr	ax,1
	shr	ax,1
	shr	ax,1
xga_sk1:and	ax,0fh			; isolate the byte value
	ret				; we done.
xga_16read	endp

xga_clear	proc	uses es si di	; clear the XGA memory
	cmp	xga_clearvideo,0	; should we really do this?
	jne	return			;  nope.  skip it.
	mov	bx,xga_result		; find out how much memory we have
	and	bx,08h			;  in 64K pages
	add	bx,08h
	mov	ax,0a000h		; set up to clear 0a0000-0affff
	push	ax
	pop	es
xloop:	mov	ax,bx			; initialize the bank addr
	call	xga_newbank
	mov	ax,0
	mov	cx,16384		; clear out 32K
	mov	di,0
	rep	stosw
	mov	cx,16384		; clear out 32K
	rep	stosw
	dec	bx			; another page?
	cmp	bx,0
	jge	xloop
return: ret
xga_clear	endp

xga_setpalette	proc	uses es si di, palette:word	; set the XGA palette
	cmp	xga_isinmode,2		; are we in an XGA graphics mode?
	jl	return			;  nope

	mov	dx,xga_reg_base 	; wait for a retrace
	add	dx,5
	mov	al,1			; clear the start-of-blanking
	out	dx,al
bloop:	in	al,dx
	test	al,01h			; blanking started?
	jz	bloop			;  nope - try again

	mov	dx,xga_reg_base 	; set up for a palette load
	add	dx,0ah
	mov	ax,0064h		; make invisible
	out	dx,ax
	mov	ax,0055h		; border color
	out	dx,ax
	mov	ax,0066h		; palette mode
	out	dx,ax
	mov	ax,0060h		; start at palette 0
	out	dx,ax
	mov	ax,0061h
	out	dx,ax

	mov	si,palette
	mov	cx,768
	mov	ax,065h 		; palette update
	out	dx,al
	inc	dx			; palette data
.186
	rep	outsb
.8086
	dec	dx

	mov	ax,0ff64h		; make visible
	out	dx,ax

return: ret
xga_setpalette	endp

xga_detect	proc	uses es di si

	cmp	xga_reg_base,-2 	; has the XGA detector already failed?
	jne	xga_sk1 		; ne = not yet
	jmp	xga_notfound		; e = yes, fail again
xga_sk1:cmp	xga_reg_base,-1 	; have we already found the XGA?
	je	xga_loc 		; e = no
	jmp	xga_found		; yes, process it

xga_loc:push	bp			; save around int 10H calls
	mov	ax,1f00h		; XGA-2 detect:
	int	10h			;  get DMQS length
	pop	bp			; restore BP
	cmp	al,1fh			; did this work?
	jne	xga_man			;  nope - try the older, manual approach
	cmp	bx,768			; room for the results?
	ja	xga_man			;  no?!?  try the older approach
	mov	ax,1f01h		; get DMQS info
	push	ds			;  into here
	pop	es			;  ...
	mov	di, offset dacbox	;  ...
	int	10h			;  ...
	cmp	al,1fh			; safety first
	jne	xga_man			; ?? try the older approach
	mov	bx, word ptr dacbox+09h	; get the register base
	mov	xga_reg_base,bx		; save the results
	mov	xga_result,1		; say we found an adapter
	cmp	byte ptr dacbox+15h,4	; do we have 1MB of adapter RAM?
	jb	@F			;  nope
	or	xga_result,8h		;  yup - say so.
@@:	mov	bx, word ptr dacbox+13h	; get the composite monitor ID
	and	bx,0f00h		; high-rez-monitor?
	cmp	bx,0f00h		;  ..
	je	@F			;  nope
	or	xga_result,4		;  yup
@@:	jmp	xga_found		; say we found the adapter

xga_man:mov	ah,35h			; DOS get interrupt vector
	mov	al,15h			; Int 15h
	int	21h			; returns vector in es:bx
	mov	ax,es			; segment part
	or	ax,ax			; undefined vector?
	jnz	xga_sk2 		; nz = no, OK so far
	jmp	xga_notfound		; z = yes - not an MCA machine
xga_sk2:mov	dx,-1			; start with an invalid POS address
	mov	ax,0c400h		; look for POS base address
	int	15h			;  (Microchannel machines only)
	jnc	xga_sk3 		; nc = success
	jmp	xga_notfound		; error - not an MC machine
xga_sk3:mov	xga_pos_base,dx 	; save pos_base_address
	xor	cx,cx			; check all MCA slots & motherboard
	cmp	dx,-1			; do we have a good POS?
	jne	xga_lp1 		; ne = yes, proceed with MCA checks
	jmp	xga_notfound		; no, fail
xga_lp1:cli				; no interrupts, please
	cmp	cx,0			; treat the motherboard differently?
	jne	xga_sk4 		; ne = yes
	mov	al,0dfh 		; enable the motherboard for setup
	mov	dx,94h
	out	dx,al
	jmp	short xga_sk5
xga_sk4:mov	ax,0c401h		; enable an MCA slot for setup
	mov	bx,cx			;  this slot
	int	15h
xga_sk5:mov	dx,xga_pos_base 	; get pos record for the slot ID
	in	ax,dx
	mov	xga_cardid,ax
	add	dx,2			; compute IO Res Base
	in	al,dx			;  get POS data byte1
	mov	byte ptr xga_1mb,al	;   save it temporarily
	inc	dx			; switch to byte 2
	in	al,dx			;  get POS data
	mov	byte ptr xga_1mb+1,al	;   save it temporarily
	inc	dx			; switch to byte 3
	in	al,dx			;  get POS data
	mov	byte ptr xga_1mb+2,al	;   save it temporarily
	inc	dx			; switch to byte 4
	in	al,dx			;  get POS data
	mov	byte ptr xga_1mb+3,al	;   save it temporarily
	cmp	cx,0			; treat the motherboard differently
	jne	xga_sk6 		; ne = yes
	mov	al,0ffh 		; enable the motherboard for normal
	out	094h,al
	jmp	short xga_sk7
xga_sk6:mov	ax,0c402h		; enable the MCA slot for normal
	mov	bx,cx			;  this slot
	int	15h
xga_sk7:sti				; interrupts on again

	mov	ax,xga_cardid		; is an XGA adapter on this slot?
	cmp	ax,08fd8h
	jae	xga_sk8 		; ae = yes
	jmp	xga_lp2 		; try another slot
xga_sk8:cmp	ax,08fdbh		; still within range?
	jbe	xga_sk9 		; be = yes
	jmp	xga_lp2 		; no, try another slot

xga_sk9:mov	al,byte ptr xga_1mb	;  restore POS data byte 1
	and	ax,0eh			;  muck about with it to get reg base
	shl	ax,1
	shl	ax,1
	shl	ax,1
	add	ax,2100h
	mov	xga_reg_base,ax
	mov	dx,xga_reg_base 	; is there a monitor on this slot?
	add	dx,0ah
	mov	al,052h
	out	dx,al
	mov	dx,xga_reg_base
	add	dx,0bh
	in	al,dx
	and	al,0fh
	cmp	al,00h			; illegal value, returned under Win 3.0
	je	xga_lp2
	cmp	al,0fh
	jne	xga_isthere		; ne = yes

xga_lp2:inc	cx			; try another adapter?
	cmp	cx,9			; done all slots?
	ja	xga_ska 		; a = yes
	jmp	xga_lp1 		; no, try another slot

xga_ska:jmp	xga_notfound		; forget it - no XGA here

xga_isthere:
	and	ax,06h			; strip off the low & high bit
	xor	ax,05h			; reverse the 3rd & low bits
	mov	xga_result,ax		; save the result flag

	mov	dx,xga_reg_base 	; is this XGA in VGA mode?
	in	al,dx
	test	al,1
	jnz	xga_skb 		; nz = yes - single-monitor setup
	or	xga_result,10h		;  dual-monitor setup
xga_skb:

	mov	ah,byte ptr xga_1mb+2	; retrieve POS data byte 3
	and	ax,0fe00h		; eliminate the low-order bits
	mov	bl,byte ptr xga_1mb	; retrieve POS data byte 1
	and	bx,0eh			; strip it down to the IODA
	mov	cx,5			; shift it up 5 bits
	shl	bx,cl
	or	ax,bx			; compute the 4MB aperture value
	mov	word ptr xga_4mb+2,ax	; save the result

	mov	al, byte ptr xga_1mb+3	; retrieve POS data byte 4
	and	ax,0fh			; select the 1MB aperture bits
	mov	cx,4			; shift it up 4 bits
	shl	ax,cl
	mov	word ptr xga_1mb+2,ax	; save the result
	mov	ax,0
	mov	word ptr xga_1mb,ax

	mov	dx,xga_reg_base 	; Interrupt Disable
	add	dx,4
	xor	al,al
	out	dx,al

	mov	dx,xga_reg_base 	; Switch to Extended Mode
;;	add	dx,00h
	mov	al,4
	out	dx,al

	mov	dx,xga_reg_base 	; Aperture Control
	add	dx,01h
	mov	al,1
	out	dx,al

	mov	dx,xga_reg_base 	; disable Palette Mask
	add	dx,0ah
	mov	ax,0064h
	out	dx,ax

	mov	xga_isinmode,2		; pretend we're already in graphics
	mov	al,12			; select page 12
	call	xga_newbank

	push	es			; see if this page has any memory
	mov	ax,0a000h
	push	ax
	pop	es
	mov	ah,000a5h
	mov	es:0,al
	mov	es:1,ah
	cmp	es:0,al
	jne	xga_512
	add	xga_result,8		; 1MB RAM found
xga_512:pop	es

	mov	al,0			; select page 0
	call	xga_newbank
	mov	xga_isinmode,0		; replace the "in-graphics" flag

	mov	dx,xga_reg_base 	; Palette Mask
	add	dx,0ah
	mov	ax,0ff64h
	out	dx,ax

	test	xga_result,10h		; dual monitor setup?
	jnz	xga_found		;  yup - don't restore as a VGA

	mov	dx,xga_reg_base 	; Switch to VGA Mode
;;	add	dx,00h
	mov	al,1
	out	dx,al

	mov	dx,03c3h		; Enable VGA Address Code
	mov	al,1
	out	dx,al

	jmp	short	xga_found

xga_notfound:
	mov	xga_reg_base,-2 	; set failure flag
xga_found:
	mov	ax,xga_result		; return the result
	ret

xga_detect	endp

xga_mode	proc	uses es di si, mode:word

	mov	curbk,-1		; preload impossible bank number

	call	xga_detect		; is an XGA adapter present?
	cmp	ax,0
	jne	whichmode
	jmp	nope			;  nope
whichmode:
	mov	bx,mode
	cmp	bx,xga_twidth		; mode number out of range?
	jb	whichmode0
	jmp	nope			;  yup - fail right now.
whichmode0:
	cmp	mode,0			; 80-col VGA text mode?
	jne	whichmode1
	jmp	mode_0			;  yup
whichmode1:
	cmp	mode,1			; 132-col VGA text mode?
	jne	whichmode2
	jmp	nope			;  Fractint doesn't use this routine
whichmode2:
	mov	bx,mode 		; locate the table entries
	add	bx,mode
	mov	dx,xga_requir[bx]	; does our setup support this mode?
	and	al,dl
	cmp	al,dl
	je	whichmode3
	jmp	nope			;  nope
whichmode3:

	mov	ax,13h			; switch to 320x200x256 mode
	call	maybeor 		; maybe or AL or (for Video-7s) BL
	int	10h
	push	ds			; reset ES==DS
	pop	es
	mov	ax,1017h		; get the DAC values
	mov	bx,0
	mov	cx,256
	mov	dx,offset paldata	; a safe place when switching XGA modes
	int	10h
	cmp	xga_loaddac,0		; save the palette?
	je	paskip			;  (yes, if we want to fake 'loaddac')
	mov	si, offset paldata
	mov	di, offset dacbox
	mov	cx,768/2
	rep	movsw
	mov	xga_loaddac,0		; reset the toggle for next time
paskip:
	mov	bx,769			; adjust the palette
paloop:	dec	bx
	mov	ah,paldata[bx]

	shl	ah,1
	shl	ah,1
	mov	paldata[bx],ah
	cmp	bx,0
	jne	paloop

	mov	dx,xga_reg_base 	; Palette Mask
	add	dx,0ah
	mov	ax,00064h		; (Disable the XGA palette)
	out	dx,ax

	mov	dx,xga_swidth[bx]	; collect and save the scan-line length
	mov	xga_xdots,dx
	mov	dx,xga_colors[bx]	; how many colors do we have?
	mov	xga_iscolors,dx 	; save this

mode_3: mov	dx,03c3h		; Enable VGA Address Code
	mov	al,1
	out	dx,al

	mov	si,offset xga_val	; point to start of values table
	mov	bx,mode 		; use mode as an offset
model1: mov	dx,xga_reg_base 	; get the base pointer
	mov	ah,0			; get the increment
	mov	al,cs:0[si]
	cmp	al,0ffh 		; end of the table?
	je	model2			;  yup
	add	dx,ax
	cmp	al,0ah			; check for access type
	je	modsk2
	mov	al,cs:0[si+bx]		; get the value and OUT it
	out	dx,al
	jmp	short modsk3
modsk2: mov	al,cs:1[si]		; get the value and OUT it
	mov	ah,cs:0[si+bx]
	out	dx,ax
modsk3: add	si,xga_twidth		; try another table entry
	jmp	short model1
model2:

	mov	xga_isinmode,2		; pretend we're already in graphics
	call	xga_clear		; clear out the memory
	mov	curbk,-1		; reset the bank counter

	mov	dx,xga_reg_base 	; set up for final loads
	add	dx,0ah
	mov	bx,mode 		; how many colors do we have?
	add	bx,mode
	cmp	xga_colors[bx],0	; "true color" mode?
	jne	modsk4			; nope - skip the funny palette load

	mov	ax,0064h		; make invisible
	out	dx,ax
	mov	ax,8055h		; border color
	out	dx,ax
	mov	ax,0066h		; palette mode
	out	dx,ax
	mov	ax,0060h		; start at palette 0
	out	dx,ax
	mov	ax,0061h		; ""
	out	dx,ax

	mov	cx,0			; ready to update the palette
	mov	al,065h 		; palette update
	out	dx,al
	inc	dx			; palette data
model3: mov	al,0			; zero out the...
	out	dx,al			;  red value
	out	dx,al			;  and the green value
	mov	al,cl			; klooge up the blue value
	and	al,1fh			; convert to 1,2,...1f
	shl	al,1			; convert to 2,4,...3e
	shl	al,1			; convert to 4,8,...7c
	shl	al,1			; convert to 8,16,..fd
	out	dx,al			; blue value
	inc	cx			; another palette value to go?
	cmp	cx,128
	jb	model3
	dec	dx			; back to normal

	mov	ax,0ff64h		; make the palette visible
	out	dx,ax
	jmp	ok

modsk4:	mov	bx, offset paldata	; reset the palette
	push	bx
	mov	xga_isinmode,2
	call	xga_setpalette
	pop	bx
	jmp	ok

mode_0: 				; Set 80 column mode
	mov	dx,xga_reg_base 	; Aperture Control
	add	dx,01h
	xor	al,al			; (disable the XGA 64K aperture)
	out	dx,al

	mov	dx,xga_reg_base 	; Interrupt Disable
	add	dx,4
	xor	al,al
	out	dx,al

	mov	dx,xga_reg_base 	; Clear Interrupts
	add	dx,5
	mov	al,0ffh
	out	dx,al

	test	xga_result,10h		; dual monitor setup?
	jz	mode_0a
	jmp	nope			;  yup - don't restore as a VGA
mode_0a:

	mov	dx,xga_reg_base 	; Palette Mask
	add	dx,0ah
	mov	ax,0ff64h		; (Enable the XGA palette)
	out	dx,ax

	mov	dx,xga_reg_base 	; Enable VFB, Prepare for Reset
	add	dx,0ah
	mov	ax,1550h
	out	dx,ax

	mov	dx,xga_reg_base 	; Enable VFB, reset CRTC
	add	dx,0ah
	mov	ax,1450h
	out	dx,ax

	mov	dx,xga_reg_base 	; Normal Scale Factors
	add	dx,0ah
	mov	ax,0051h
	out	dx,ax

	mov	dx,xga_reg_base 	; Select VGA Oscillator
	add	dx,0ah
	mov	ax,0454h
	out	dx,ax

	mov	dx,xga_reg_base 	; Ext Oscillator (VGA)
	add	dx,0ah
	mov	ax,7f70h
	out	dx,ax

	mov	dx,xga_reg_base 	; Ensure no Vsynch Interrupts
	add	dx,0ah
	mov	ax,202ah
	out	dx,ax

	mov	dx,xga_reg_base 	; Switch to VGA Mode
;;	add	dx,00h
	mov	al,1
	out	dx,al

	mov	dx,03c3h		; Enable VGA Address Code
	mov	al,1
	out	dx,al

	mov	ax,1202h		; select 400 scan lines
	mov	bl,30h
	int	10h

	mov	ax,0+3			; set video mode 3
	or	al,xga_clearvideo	; (might supress video-clearing)
	cmp	xga_clearvideo,0	; clear the video option set?
	je	mode_0b
	mov	ax,08eh 		; ugly klooge: VGA graphics, no clear
mode_0b:
	int	10h

	jmp	ok			; we're done

nope:
	mov	xga_isinmode,0
	mov	ax,0			; return failure
	ret
ok:
	mov	ax,mode 		; remember the mode we're in
	mov	xga_isinmode,ax
	mov	ax,1			; return OK
	ret
xga_mode	endp


; **************** internal Read/Write-a-dot routines ***********************
;
;	These Routines all assume the following register values:
;
;		AL = The Color (returned on reads, sent on writes)
;		CX = The X-Location of the Pixel
;		DX = The Y-Location of the Pixel

nullwrite	proc	near		; "do-nothing" write
	ret
nullwrite	endp

nullread	proc	near		; "do-nothing" read
	mov	ax,0			; "return" black pixels
	ret
nullread	endp

normalwrite	proc	near		; generic write-a-dot routine
	mov	ah,12			; write the dot (al == color)
	mov	bx,0			; this page
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret				; we done.
normalwrite	endp

normalread	proc	near		; generic read-a-dot routine
	mov	ah,13			; read the dot (al == color)
	mov	bx,0			; this page
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret				; we done.
normalread	endp

mcgawrite	proc	near		; MCGA 320*200, 246 colors
	xchg	dh,dl			; bx := 256*y
	mov	bx,cx			; bx := x
	add	bx,dx			; bx := 256*y + x
	shr	dx,1
	shr	dx,1			; dx := 64*y
	add	bx,dx			; bx := 320*y + x
	mov	es:[bx],al		; write the dot
	ret				; we done.
mcgawrite	endp

mcgaread	proc	near		; MCGA 320*200, 246 colors
	xchg	dh,dl			; dx := 256*y
	mov	bx,cx			; bx := x
	add	bx,dx			; bx := 256*y + x
	shr	dx,1
	shr	dx,1			; dx := 64*y
	add	bx,dx			; bx := 320*y + x
	mov	al,es:[bx]		; retrieve the previous value
	ret				; we done.
mcgaread	endp

;	These routines are for bit-plane 16 color modes, including bank
;	switched superVGA varieties such as the Tseng 1024x768x16 mode.
;		Tim Wegner
;
vgawrite	proc	near		; bank-switched EGA/VGA write mode 0
	mov	bh,al			; save the color value for a bit
	mov	ax,vxdots		; this many dots / line
	mul	dx			; times this many lines
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; DX:AX now holds the pixel count
	mov	cx,ax			; save this for the bit mask
	and	cx,7			; bit-mask shift calculation
	xor	cl,7			;  ...
	mov	si,ax			; set up for the address shift
	shr	dx,1			; (ugly) 32-bit shift-by-3 logic
	rcr	si,1			;  ((works on ANY 80x6 processor))
	shr	dx,1			;  ...
	rcr	si,1			;  ...
	shr	dx,1			;  ...
	rcr	si,1			;  ...

	cmp	dx,curbk		; see if bank changed
	je	vgasame_bank		; jump if old bank ok
	mov	ax,dx			; newbank expects bank in al
	call	far ptr newbank 	; switch banks
vgasame_bank:

	mov	dx,03ceh		; graphics controller address
	mov	ax,0108h		; set up controller bit mask register
	shl	ah,cl			;  ...
	out	dx,ax			;  ...
	mov	ah,bh			; set set/reset registers
	mov	al,0			;  ...
	out	dx,ax			;  ...
	mov	ax,0f01h		; enable set/reset registers
	out	dx,ax			;  ...
	or	es:[si],al		; update all bit planes
	ret				; we done.
vgawrite	endp

vgaread proc	near		; bank-switched EGA/VGA read mode 0
	mov	ax,vxdots		; this many dots / line
	mul	dx			; times this many lines
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; DX:AX now holds the pixel count
	mov	cx,ax			; save this for the bit mask
	and	cx,7			; bit-mask shift calculation
	xor	cl,7			;  ...
	mov	si,ax			; set up for the address shift
	shr	dx,1			; (ugly) 32-bit shift-by-3 logic
	rcr	si,1			;  ((works on ANY 80x6 processor))
	shr	dx,1			;  ...
	rcr	si,1			;  ...
	shr	dx,1			;  ...
	rcr	si,1			;  ...

	cmp	dx,curbk		; see if bank changed
	je	vgasame_bank		; jump if old bank ok
	mov	ax,dx			; newbank expects bank in al
	call	far ptr newbank 	; switch banks
vgasame_bank:

	mov	ch,01h			; bit mask to shift
	shl	ch,cl			;  ...
	mov	bx,0			; initialize bits-read value (none)
	mov	dx,03ceh		; graphics controller address
	mov	ax,0304h		; set up controller address register
vgareadloop:
	out	dx,ax			; do it
	mov	bh,es:[si]		; retrieve the old value
	and	bh,ch			; mask one bit
	neg	bh			; set bit 7 correctly
	rol	bx,1			; rotate the bit into bl
	dec	ah			; go for another bit?
	jge	vgareadloop		;  sure, why not.
	mov	al,bl			; returned pixel value
	ret				; we done.
vgaread endp

outax8bit	proc	near		; convert OUT DX,AX to
	push	ax			; several OUT DX,ALs
	out	dx,al			; (leaving registers intact)
	inc	dx
	mov	al,ah
	out	dx,al
	dec	dx
	pop	ax
	ret
outax8bit	endp


; --------------------------------------------------------------------------

; new Tandy and CGA code from Joseph Albrecht

		align	2
;Scan line address table for 16K video memory
scan16k 	dw	0000h,2000h,0050h,2050h,00A0h,20A0h,00F0h,20F0h
		dw	0140h,2140h,0190h,2190h,01E0h,21E0h,0230h,2230h
		dw	0280h,2280h,02D0h,22D0h,0320h,2320h,0370h,2370h
		dw	03C0h,23C0h,0410h,2410h,0460h,2460h,04B0h,24B0h
		dw	0500h,2500h,0550h,2550h,05A0h,25A0h,05F0h,25F0h
		dw	0640h,2640h,0690h,2690h,06E0h,26E0h,0730h,2730h
		dw	0780h,2780h,07D0h,27D0h,0820h,2820h,0870h,2870h
		dw	08C0h,28C0h,0910h,2910h,0960h,2960h,09B0h,29B0h
		dw	0A00h,2A00h,0A50h,2A50h,0AA0h,2AA0h,0AF0h,2AF0h
		dw	0B40h,2B40h,0B90h,2B90h,0BE0h,2BE0h,0C30h,2C30h
		dw	0C80h,2C80h,0CD0h,2CD0h,0D20h,2D20h,0D70h,2D70h
		dw	0DC0h,2DC0h,0E10h,2E10h,0E60h,2E60h,0EB0h,2EB0h
		dw	0F00h,2F00h,0F50h,2F50h,0FA0h,2FA0h,0FF0h,2FF0h
		dw	1040h,3040h,1090h,3090h,10E0h,30E0h,1130h,3130h
		dw	1180h,3180h,11D0h,31D0h,1220h,3220h,1270h,3270h
		dw	12C0h,32C0h,1310h,3310h,1360h,3360h,13B0h,33B0h
		dw	1400h,3400h,1450h,3450h,14A0h,34A0h,14F0h,34F0h
		dw	1540h,3540h,1590h,3590h,15E0h,35E0h,1630h,3630h
		dw	1680h,3680h,16D0h,36D0h,1720h,3720h,1770h,3770h
		dw	17C0h,37C0h,1810h,3810h,1860h,3860h,18B0h,38B0h
		dw	1900h,3900h,1950h,3950h,19A0h,39A0h,19F0h,39F0h
		dw	1A40h,3A40h,1A90h,3A90h,1AE0h,3AE0h,1B30h,3B30h
		dw	1B80h,3B80h,1BD0h,3BD0h,1C20h,3C20h,1C70h,3C70h
		dw	1CC0h,3CC0h,1D10h,3D10h,1D60h,3D60h,1DB0h,3DB0h
		dw	1E00h,3E00h,1E50h,3E50h,1EA0h,3EA0h,1EF0h,3EF0h

;Scan line address table for 32K video memory
scan32k 	dw	0000h,2000h,4000h,6000h,00a0h,20a0h,40a0h,60a0h
		dw	0140h,2140h,4140h,6140h,01e0h,21e0h,41e0h,61e0h
		dw	0280h,2280h,4280h,6280h,0320h,2320h,4320h,6320h
		dw	03c0h,23c0h,43c0h,63c0h,0460h,2460h,4460h,6460h
		dw	0500h,2500h,4500h,6500h,05a0h,25a0h,45a0h,65a0h
		dw	0640h,2640h,4640h,6640h,06e0h,26e0h,46e0h,66e0h
		dw	0780h,2780h,4780h,6780h,0820h,2820h,4820h,6820h
		dw	08c0h,28c0h,48c0h,68c0h,0960h,2960h,4960h,6960h
		dw	0a00h,2a00h,4a00h,6a00h,0aa0h,2aa0h,4aa0h,6aa0h
		dw	0b40h,2b40h,4b40h,6b40h,0be0h,2be0h,4be0h,6be0h
		dw	0c80h,2c80h,4c80h,6c80h,0d20h,2d20h,4d20h,6d20h
		dw	0dc0h,2dc0h,4dc0h,6dc0h,0e60h,2e60h,4e60h,6e60h
		dw	0f00h,2f00h,4f00h,6f00h,0fa0h,2fa0h,4fa0h,6fa0h
		dw	1040h,3040h,5040h,7040h,10e0h,30e0h,50e0h,70e0h
		dw	1180h,3180h,5180h,7180h,1220h,3220h,5220h,7220h
		dw	12c0h,32c0h,52c0h,72c0h,1360h,3360h,5360h,7360h
		dw	1400h,3400h,5400h,7400h,14a0h,34a0h,54a0h,74a0h
		dw	1540h,3540h,5540h,7540h,15e0h,35e0h,55e0h,75e0h
		dw	1680h,3680h,5680h,7680h,1720h,3720h,5720h,7720h
		dw	17c0h,37c0h,57c0h,77c0h,1860h,3860h,5860h,7860h
		dw	1900h,3900h,5900h,7900h,19a0h,39a0h,59a0h,79a0h
		dw	1a40h,3a40h,5a40h,7a40h,1ae0h,3ae0h,5ae0h,7ae0h
		dw	1b80h,3b80h,5b80h,7b80h,1c20h,3c20h,5c20h,7c20h
		dw	1cc0h,3cc0h,5cc0h,7cc0h,1d60h,3d60h,5d60h,7d60h
		dw	1e00h,3e00h,5e00h,7e00h,1ea0h,3ea0h,5ea0h,7ea0h

;Scan line address table for 64K video memory
scan64k 	dw	00000h,00140h,00280h,003c0h,00500h,00640h,00780h,008c0h
		dw	00a00h,00b40h,00c80h,00dc0h,00f00h,01040h,01180h,012c0h
		dw	01400h,01540h,01680h,017c0h,01900h,01a40h,01b80h,01cc0h
		dw	01e00h,01f40h,02080h,021c0h,02300h,02440h,02580h,026c0h
		dw	02800h,02940h,02a80h,02bc0h,02d00h,02e40h,02f80h,030c0h
		dw	03200h,03340h,03480h,035c0h,03700h,03840h,03980h,03ac0h
		dw	03c00h,03d40h,03e80h,03fc0h,04100h,04240h,04380h,044c0h
		dw	04600h,04740h,04880h,049c0h,04b00h,04c40h,04d80h,04ec0h
		dw	05000h,05140h,05280h,053c0h,05500h,05640h,05780h,058c0h
		dw	05a00h,05b40h,05c80h,05dc0h,05f00h,06040h,06180h,062c0h
		dw	06400h,06540h,06680h,067c0h,06900h,06a40h,06b80h,06cc0h
		dw	06e00h,06f40h,07080h,071c0h,07300h,07440h,07580h,076c0h
		dw	07800h,07940h,07a80h,07bc0h,07d00h,07e40h,07f80h,080c0h
		dw	08200h,08340h,08480h,085c0h,08700h,08840h,08980h,08ac0h
		dw	08c00h,08d40h,08e80h,08fc0h,09100h,09240h,09380h,094c0h
		dw	09600h,09740h,09880h,099c0h,09b00h,09c40h,09d80h,09ec0h
		dw	0a000h,0a140h,0a280h,0a3c0h,0a500h,0a640h,0a780h,0a8c0h
		dw	0aa00h,0ab40h,0ac80h,0adc0h,0af00h,0b040h,0b180h,0b2c0h
		dw	0b400h,0b540h,0b680h,0b7c0h,0b900h,0ba40h,0bb80h,0bcc0h
		dw	0be00h,0bf40h,0c080h,0c1c0h,0c300h,0c440h,0c580h,0c6c0h
		dw	0c800h,0c940h,0ca80h,0cbc0h,0cd00h,0ce40h,0cf80h,0d0c0h
		dw	0d200h,0d340h,0d480h,0d5c0h,0d700h,0d840h,0d980h,0dac0h
		dw	0dc00h,0dd40h,0de80h,0dfc0h,0e100h,0e240h,0e380h,0e4c0h
		dw	0e600h,0e740h,0e880h,0e9c0h,0eb00h,0ec40h,0ed80h,0eec0h
		dw	0f000h,0f140h,0f280h,0f3c0h,0f500h,0f640h,0f780h,0f8c0h

;
; ***** CGA Video Routines *****
;

;plot a point on 320x200x4 color graphics screen
plotcga4	proc	near

	mov	bx,0b800h		;point es at video buffer
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan16k[bx]	; ..
	mov	ah,cl			;save low byte of column
	shr	cx,1			;get column offset
	shr	cx,1			; ..
	add	bx,cx			;add column offset to address
	not	ah			;get shift count
	and	ah,3			; ..
	shl	ah,1			; ..
	mov	cl,ah			; ..
	and	al,3			;mask off unwanted bits
	rol	al,cl			;get or mask
	mov	ah,0fch 		;get and mask
	rol	ah,cl			; ..
	mov	cl,es:[bx]		;plot the point
	and	cl,ah			; ..
	or	cl,al			; ..
	mov	es:[bx],cl		; ..
	ret

plotcga4	endp

;return a point from 320x200x4 color graphics screen
getcga4 	proc	near

	mov	bx,0b800h		;point es at video buffer
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan16k[bx]	; ..
	mov	ax,cx			;save column
	shr	ax,1			;get column offset
	shr	ax,1			; ..
	add	bx,ax			;add column offset to address
	not	cl			;get shift count
	and	cl,3			; ..
	shl	cl,1			; ..
	mov	al,es:[bx]		;return the point
	ror	al,cl			; ..
	and	ax,3			; ..
	ret

getcga4 	endp

;plot a point on 640x200x2 color graphics screen
plotcga2	proc	near

	mov	bx,0b800h		;point es at video buffer
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan16k[bx]	; ..
	mov	ah,cl			;save low order byte of column
	shr	cx,1			;get column offset
	shr	cx,1			; ..
	shr	cx,1			; ..
	add	bx,cx			;add column offset to address
	not	ah			;get shift count
	and	ah,7			; ..
	mov	cl,ah			; ..
	and	al,1			;mask off unwanted bits
	rol	al,cl			;get or mask
	mov	ah,0feh 		;get and mask
	rol	ah,cl			; ..
	mov	cl,es:[bx]		;plot the point
	and	cl,ah			; ..
	or	cl,al			; ..
	mov	es:[bx],cl		; ..
	ret

plotcga2	endp

;return a point from 640x200x2 color graphics screen
getcga2 	proc	near

	mov	bx,0b800h		;point es at video buffer
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan16k[bx]	; ..
	mov	ax,cx			;save column
	shr	ax,1			;get column offset
	shr	ax,1			; ..
	shr	ax,1			; ..
	add	bx,ax			;add column offset to address
	not	cl			;get shift count
	and	cl,7			; ..
	mov	al,es:[bx]		;return the point
	ror	al,cl			; ..
	and	ax,1			; ..
	ret

getcga2 	endp

;
; ***** Tandy 1000 Video Routines *****
;

;plot a point on tandy 1000 640x200x4 color graphics screen
plottandy4	proc	near

	mov	bx,0b800h		;point es at video segment
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan32k[bx]	; ..
	mov	dx,cx			;save column
	shr	dx,1			;get column offset
	shr	dx,1			; ..
	and	dl,0feh 		; ..
	add	bx,dx			;add column offset to address
	not	cl			;get shift count
	and	cl,7			; ..
	mov	ah,al			;get or mask
	shr	ah,1			; ..
	and	ax,101h 		; ..
	rol	ax,cl			; ..
	mov	dx,0fefeh		;get and mask
	rol	dx,cl			; ..
	mov	cx,es:[bx]		;plot the point
	and	cx,dx			; ..
	or	cx,ax			; ..
	mov	es:[bx],cx		; ..
	ret

plottandy4	endp

;return a point from tandy 1000 640x200x4 color graphics screen
gettandy4	proc	near

	mov	bx,0b800h		;point es at video segment
	mov	es,bx			; ..
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	mov	bx,cs:scan32k[bx]	; ..
	mov	ax,cx			;save column
	shr	ax,1			;get column offset
	shr	ax,1			; ..
	and	al,0feh 		; ..
	add	bx,ax			;add column offset to address
	not	cl			;get shift count
	and	cl,7			; ..
	mov	ax,es:[bx]		;return the point
	ror	ax,cl			; ..
	and	ax,101h 		; ..
	rol	ah,1			; ..
	or	al,ah			; ..
	and	ax,3			; ..
	ret

gettandy4	endp

;plot a point on tandy 1000 16 color graphics screen
plottandy16	proc	near

	mov	es,tandyseg		;point es at video buffer
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	add	bx,tandyscan		; ..
	mov	bx,cs:[bx]		; ..
	mov	ah,0f0h 		;set mask for odd pixel
	mov	dx,cx			;save x
	shr	dx,1			;get column offset
	jc	plottandy16a		;check for odd/even pixel
	not	ah			;set mask for even pixel
	mov	cl,4			;move color to proper pobxtion
	shl	al,cl			; ..
plottandy16a:
	add	bx,dx			;add column offset to address
	mov	dl,es:[bx]		;plot the point
	and	dl,ah			; ..
	or	dl,al			; ..
	mov	es:[bx],dl		; ..
	ret

plottandy16	endp

;return a point from tandy 1000 16 color graphics mode
gettandy16	proc	near

	mov	es,tandyseg		;point es at video buffer
	mov	bx,dx			;get scan line address
	shl	bx,1			; ..
	add	bx,tandyscan		; ..
	mov	bx,cs:[bx]		; ..
	mov	dx,cx			;save x
	shr	cx,1			;add column offset to address
	add	bx,cx			; ..
	mov	al,es:[bx]		;get pixel
	test	dl,1			;check for odd/even pixel
	jnz	gettandy16a		; ..
	mov	cl,4			;move color to proper position
	shr	al,cl			; ..
gettandy16a:
	and	ax,0fh			;mask off unwanted bits
	ret

gettandy16	endp

;setup tandy 1000 640x200x16 color mode
tandysetup	proc	near
	mov	dx,03d4h		; write to this address
	mov	ax,07100h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,05001h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,05a02h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,00e03h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,0ff04h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,00605h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,0c806h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,0e207h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,00009h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,0000ch		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,01810h		; write to this register and value
	call	tandyport		;  do it.
	mov	ax,04612h		; write to this register and value
	call	tandyport		;  do it.
	mov	dx,03d8h		; new port
	mov	al,01bh 		;  and value
	out	dx,al			;  do it.
	mov	dx,03d9h		; new port
	mov	al,000h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03ddh		; new port
	mov	al,000h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dfh		; new port
	mov	al,024h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dah		; new port
	mov	al,001h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03deh		; new port
	mov	al,00fh 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dah		; new port
	mov	al,002h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03deh		; new port
	mov	al,000h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dah		; new port
	mov	al,003h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03deh		; new port
	mov	al,010h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dah		; new port
	mov	al,005h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03deh		; new port
	mov	al,001h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03dah		; new port
	mov	al,008h 		;  and value
	out	dx,al			;  do it.
	mov	dx,03deh		; new port
	mov	al,002h 		;  and value
	out	dx,al			;  do it.

;set color palette registers to default state
	mov	cx,16			;reset colors 0-15 to default state
	xor	bh,bh			;set initial color
	xor	bl,bl			;set initial paletter register
	mov	di,2			;reset border color
	call	settandypal		; ..
tandysetup1:
	mov	di,16			;port offset for palette registers
	call	settandypal		;set palette register
	inc	bl			;bump up to next palette register
	inc	bh			;bump up to next color
	loop	tandysetup1		;do remaining palette registers

	cmp	orvideo,0		; are we supposed to clear RAM?
	jne	tandysetup2		;  (nope)
	push	es			; save ES for a tad
	mov	ax,0a000h		; clear the memory
	mov	es,ax			;  ...
	cld				; string ops forward
	mov	cx,07d00h		; this many words
	mov	di,0			; starting here
	mov	ax,0			; clear out to zero
	rep	stosw			; do it.
	pop	es			; restore ES
tandysetup2:
	mov	oktoprint,0		; no printing in this mode
	ret

tandysetup	endp

;write data to 6845 registers
tandyport	proc	near

	out	dx,al			;write 6845 reg number to port 3d4
	mov	al,ah			;write 6845 reg data to port 3d5
	inc	dx			; ..
	out	dx,al			; ..
	dec	dx			;point back to port 3d4
	ret

tandyport	endp

;subroutine to set a Tandy 1000 palette register
settandypal	proc	near
	mov	dx,3dah 		;address & status register
	cli				;disable interrupts
settandypal2:
	in	al,dx			;get status register
	and	al,8			;look for bit 3
	jz	settandypal2		;wait for vertical retrace
	mov	al,bl			;get palette number
	cbw				; ..
	add	ax,di			;add offset for palette register
	out	dx,al			;set palette
	mov	al,bh			;get color to store
	mov	dx,3deh 		;palette data register
	out	dx,al			;set palette color
	mov	dx,3dah 		;address & status register
	xor	ax,ax			;al = 0 to reset address register
	out	dx,al			;reset it
	sti				;re-enable interrupts
	ret

settandypal	endp

; -----------------------------------------------------------------------------


;	The 360x480 mode draws heavily on Michael Abrash's article in
;	the January/February 1989 "Programmer's Journal" and files uploaded
;	to Compuserv's PICS forum by Dr. Lawrence Gozum - integrated here
;	by Timothy Wegner

; Michael Abrash equates. Not all used, but I'll leave for reference.

VGA_SEGMENT	  EQU	0A000h
SC_INDEX	  EQU	3C4h	 ;Sequence Controller Index register
GC_INDEX	  EQU	3CEh	 ;Graphics Controller Index register
CRTC_INDEX	  EQU	3D4h	 ;CRT Controller Index register
MAP_MASK	  EQU	2	 ;Map Mask register index in SC
MEMORY_MODE	  EQU	4	 ;Memory Mode register in SC
MAX_SCAN_LINE	  EQU	9	 ;Maximum Scan Line reg index in CRTC
				 ;Use 9 for 2 pages of 320x400
;MAX_SCAN_LINE	  EQU	1	 ;Use 1 for 4 pages of 320x200
START_ADD_HIGH	  EQU	0Ch	 ;Start Address High reg index in CRTC
UNDERLINE	  EQU	14h	 ;Underline Location reg index in CRTC
MODE_CONTROL	  EQU	17h	 ;Mode Control reg index in CRTC
READ_MAP	  EQU	4	 ;Read Mask register index in SC
GRAPHICS_MODE	  EQU	5	 ;Graphics Mode register index in SC
MISC		  EQU	6	 ;Miscellaneous register index in SC
WORD_OUTS_OK	  EQU	1	 ;set to 0 to assemble for computers
				 ;that can't handle word outs to indexed
				 ;VGA registers
;
;Macro to output a word value to a port
;
OUT_WORD MACRO
IF WORD_OUTS_OK
	 OUT	  DX,AX
ELSE
	 OUT	  DX,AL
	 INC	  DX
	 XCHG	  AH,AL
	 OUT	  DX,AL
	 DEC	  DX
	 XCHG	  AH,AL
ENDIF
	 ENDM

;Macro to ouput a constant value to an indexed VGA register
CONSTANT_TO_INDEXED_REGISTER	 MACRO	ADDRESS,INDEX,VALUE
	 MOV	  DX,ADDRESS
	 MOV	  AX,(VALUE SHL 8)+INDEX
	 OUT_WORD
	 ENDM

tweak256read	proc near uses si	; Tweaked-VGA ...x256 color mode

  mov	  ax,vxdots
;;  shr   ax,1
;;  shr   ax,1			 ; now ax = vxdots/4
  mul	  dx			 ;Point to start of desired row
  push	  cx			 ;Save X coordinate for later
  shr	  cx,1			 ;There are 4 pixels at each address
  shr	  cx,1			 ;so divide X by 4
  add	  ax,cx 		 ;Point to pixels address
  mov	  si,ax
  pop	  ax			 ;Retrieve X coordinate
  and	  al,3			 ;Get the plane number of the pixel
  mov	  ah,al
  mov	  al,READ_MAP
  mov	  dx,GC_INDEX
  OUT_WORD			 ;Set to write to the proper plane for the
				 ;pixel
  xor	  ax,ax
  lods	  byte ptr es:[si]	 ;Read the pixel
  ret

tweak256read	endp

tweak256write	proc near uses di	; Tweaked-VGA ...x256 color mode
  mov	  bl,al 		; color
  mov	  ax,vxdots
;;  shr   ax, 1
;;  shr   ax, 1 		 ; now ax = vxdots/4
  mul	  dx			;Point to start of desired row
  push	  cx			;Save X coordinate for later
  shr	  cx,1			;There are 4 pixels at each address
  shr	  cx,1			;so divide X by 4
  add	  ax,cx 		;Point to pixels address
  mov	  di,ax
  pop	  cx			;Retrieve X coordinate
  and	  cl,3			;Get the plane number of the pixel
  mov	  ah,1
  shl	  ah,cl 		;Set the bit corresponding to the plane
				;the pixel is in
  mov	  al,MAP_MASK
  mov	  dx,SC_INDEX
  OUT_WORD			 ;Set to write to the proper plane for the
				 ;pixel
  mov	  es:[di],bl		 ;Draw the pixel

  ret
tweak256write	endp

;	The following ATI 1024x768x16 mode is courtesy of Mark Peterson

ati1024read	proc near		; ATI 1024x768x16 read
	call	ati1024addr		; calculate the address
	mov	al,es:[bx]		; get the byte the pixel is in

	cmp	xga_isinmode,0		; say, is this really XGA-style I/O?
	je	notxga			;  nope
	test	cl,1			; is X odd?
	jnz	atireadhigh		;  Yup.  Use the high bits
	jmp	short atireadlow	;  else use the low bits
notxga:

	test	cl,1			; is X odd?
	jz	atireadhigh		;  Nope.  Use the high bits
atireadlow:
	and	ax,0fh			; zero out the high-order bits
	ret
atireadhigh:
	and	ax,0f0h 		; zero out the low-order bits
	mov	cl,4			; shift the results
	shr	al,cl			;  ...
	ret
ati1024read	endp

ati1024write	proc near		; ATI 1024x768x16 write
	call	ati1024addr		; calculate the address
	mov	dl,es:[bx]		; get the byte the pixel is in
	and	al,00fh 		; zero out the high-order color bits

	cmp	xga_isinmode,0		; say, is this really XGA-style I/O?
	je	notxga			;  nope
	test	cl,1			; is X odd?
	jnz	atiwritehigh		;  Yup.  Use the high bits
	jmp	short atiwritelow	;  else use the low bits
notxga:

	test	cl,1			; is X odd?
	jz	atiwritehigh		;  Nope.  Use the high bits
atiwritelow:
	and	dl,0f0h 		; zero out the low-order video bits
	or	dl,al			; add the two together
	mov	es:[bx],dl		; and write the results
	ret
atiwritehigh:
	mov	cl,4			; shift the color bits
	shl	al,cl			;  ...
	and	dl,0fh			; zero out the high-order video bits
	or	dl,al			; add the two together
	mov	es:[bx],dl		; and write the results
	ret
ati1024write	endp

ati1024addr	proc	near		; modification of TIW's Super256addr
	clc				; clear carry flag
	push	ax			; save this for a tad
	mov	ax,vxdots		; this many dots / line
	mul	dx			; times this many lines - ans in dx:ax
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; answer in dx:ax
	shr	dx,1			; shift the answer right one bit
	rcr	ax,1			;  .. in the 32-bit DX:AX combo
	mov	bx,ax			; save this in BX
	cmp	dx,curbk		; see if bank changed
	je	atisame_bank		; jump if old bank ok
	mov	ax,dx			; newbank expects bank in al
	call	far ptr newbank
atisame_bank:
	pop	ax			; restore AX
	ret
ati1024addr	endp

;
;	The following 'Super256' code is courtesy of Timothy Wegner.
;

super256write	proc near		; super-VGA ...x256 colors write-a-dot
	call	super256addr		; calculate address and switch banks
	mov	es:[bx],al		; write the dot
	ret				; we done.
super256write	endp

super256read	proc near		; super-VGA ...x256 colors read-a-dot
	call	super256addr		; calculate address and switch banks
	mov	al,es:[bx]		; read the dot
	ret				; we done.
super256read	endp

super256addr	proc near		; can be put in-line but shared by
					; read and write routines
	clc				; clear carry flag
	push	ax			; save this for a tad
	mov	ax,vxdots		; this many dots / line
	mul	dx			; times this many lines - ans in dx:ax
	add	ax,cx			; plus this many x-dots
	adc	dx,0			; answer in dx:ax - dl=bank, ax=offset
	mov	bx,ax			; save this in BX
	cmp	dx,curbk		; see if bank changed
	je	same_bank		; jump if old bank ok
	mov	ax,dx			; newbank expects bank in al
	call	far ptr newbank
same_bank:
	pop	ax			; restore AX
	ret
super256addr	endp

;
;	BANKS.ASM was used verbatim except:
;	   1) removed ".model small"
;	   2) deleted "end"
;	Integrated by Tim Wegner 8/15/89
;	(switched to John's 9/7/89 version on 9/10/89 - Bert)
;	(switched to John's 1/5/90 version on 1/9/90  - Bert)
;	(switched to John's version 3 on 4/27/90  - Bert)
;	(added logic for various resolution on 9/10/90 - Bert)
;	(upgraded to John's version 3.5 on 5/14/91 - Bert)
;

;	.MODEL medium,c

;
;	Copyright 1988,89,90,91 John Bridges
;	Free for use in commercial, shareware or freeware applications
;
;	SVGAMODE.ASM
;
.data

OSEG	equ	SS:			;segment override for variable access

bankadr dw	offset $nobank
if @CodeSize
bankseg dw	seg $nobank
endif

vesa_bankswitch 	dd	$vesa_nullbank ; initially, do-nothing
vesa_mapper		dd	$nobank
vesa_detect		dw	1	; set to 0 to disable VESA-detection
vesa_gran_offset	dw	0
vesa_low_window 	dw	0
vesa_high_window	dw	1
vesa_granularity	db	0	; BDT VESA Granularity value

	public	curbk

		align	2
curbk	dw	0

vga512	dw	0
vga1024 dw	0


	public	supervga_list	; pointer to head of the SuperVGA list

supervga_list	db	"aheada"
aheada	dw	0
	db	"ati   "
ativga	dw	0
	db	"chi   "
chipstech dw	0
	db	"eve   "
everex	dw	0
	db	"gen   "
genoa	dw	0
	db	"ncr   "
ncr	dw	0
	db	"oak   "
oaktech dw	0
	db	"par   "
paradise dw	0
	db	"tri   "
trident dw	0
	db	"tseng3"
tseng	dw	0
	db	"tseng4"
tseng4	dw	0
	db	"vid   "
video7	dw	0
	db	"aheadb"
aheadb	dw	0
	db	"vesa  "
vesa	dw	0
	db	"cirrus"
cirrus	dw	0
	db	"t8900 "
t8900	dw	0
	db	"compaq"
compaq	dw	0
	db	"xga   "
xga	dw	0
	db	"      "	; end-of-the-list
	dw	0

done_detect dw	0		;flag to call adapter_detect & whichvga once

		; this part is new - Bert
.code

vesa_entries	dw	0
	dw	 640, 400,256, 4f02h,100h
	dw	 640, 480,256, 4f02h,101h
	dw	 800, 600, 16, 4f02h,102h
	dw	 800, 600,256, 4f02h,103h
	dw	1024, 768, 16, 4f02h,104h
	dw	1024, 768,256, 4f02h,105h
	dw	1280,1024, 16, 4f02h,106h
	dw	1280,1024,256, 4f02h,107h
ahead_entries	dw	0
	dw	 800, 600, 16, 06ah,0
	dw	 800, 600, 16, 071h,0
	dw	1024, 768, 16, 074h,0
	dw	 640, 400,256, 060h,0
	dw	 640, 480,256, 061h,0
	dw	 800, 600,256, 062h,0
	dw	1024, 768,256, 063h,0
ati_entries	dw	0
	dw	 800, 600, 16, 054h,0
	dw	1024, 768, 16, 065h,0ffh	; (non-standard mode flag)
;	dw	1024, 768, 16, 055h,0
	dw	 640, 400,256, 061h,0
	dw	 640, 480,256, 062h,0
	dw	 800, 600,256, 063h,0
	dw	1024, 768,256, 064h,0
chips_entries	dw	0
	dw	 800, 600, 16, 070h,0
	dw	1024, 768, 16, 072h,0
	dw	 640, 400,256, 078h,0
	dw	 640, 480,256, 079h,0
	dw	 800, 600,256, 07bh,0
compaq_entries	dw	0
	dw	 640, 480,256, 02eh,0fdh	; (non-standard mode flag)
everex_entries	dw	0
	dw	 752, 410, 16, 070h,01h
	dw	 800, 600, 16, 070h,02h
	dw	1280, 350,  4, 070h,11h
	dw	1280, 600,  4, 070h,12h
	dw	 640, 350,256, 070h,13h
	dw	 640, 400,256, 070h,14h
	dw	 512, 480,256, 070h,15h
	dw	1024, 768, 16, 070h,20h
	dw	 640, 480,256, 070h,30h
	dw	 800, 600,256, 070h,31h
	dw	1024, 768,256, 070h,32h
genoa_entries	dw	0
	dw	1024, 768,  4, 07fh,0
	dw	 720, 512, 16, 059h,0
	dw	 800, 600, 16, 079h,0
	dw	1024, 768, 16, 05fh,0
	dw	 640, 350,256, 05bh,0
	dw	 640, 400,256, 07eh,0
	dw	 640, 480,256, 05ch,0
	dw	 720, 512,256, 05dh,0
	dw	 800, 600,256, 05eh,0
ncr_entries	 dw	0
	dw	1024, 768,  2, 5ah,0
	dw	 800, 600, 16, 58h,0
	dw	1024, 768, 16, 5dh,0
	dw	 640, 400,256, 5eh,0
	dw	 640, 480,256, 5fh,0
	dw	 800, 600,256, 5ch,0
;	dw	0	; this appears to be extra! JCO
oaktech_entries dw	0
	dw	 800, 600, 16, 52h,0
	dw	 640, 480,256, 53h,0
	dw	 800, 600,256, 54h,0
	dw	1024, 768, 16, 56h,0
	dw	1024, 768,256, 59h,0
	dw	1280,1024, 16, 58h,0
;	dw	0
paradise_entries	dw	0
	dw	 800, 600,  2, 059h,0
	dw	 800, 600, 16, 058h,0
	dw	 640, 400,256, 05eh,0
	dw	 640, 480,256, 05fh,0
	dw	1024, 768, 16, 05dh,0
	dw	 800, 600,256, 05ch,0	; Chuck Ebbert, 910524
trident_entries dw     0
	dw	1024, 768,  4, 060h,0
	dw	 800, 600, 16, 05bh,0
	dw	1024, 768, 16, 05fh,0
	dw	 640, 400,256, 05ch,0
	dw	 640, 480,256, 05dh,0
	dw	 800, 600,256, 05eh,0
	dw	1024, 768,256, 062h,0
tseng_entries	dw	0
	dw	 800, 600, 16, 029h,0
	dw	1024, 768, 16, 037h,0
	dw	 640, 350,256, 02dh,0
	dw	 640, 400,256, 0,0feh	; (non-standard mode flag)
	dw	 640, 480,256, 02eh,0
	dw	 720, 512,256, 02fh,0
	dw	 800, 600,256, 030h,0
	dw	1024, 768,256, 038h,0
tseng4_entries	dw	0
	dw	 800, 600, 16, 29h,0
	dw	1024, 768, 16, 37h,0
	dw	 640, 350,256, 2dh,0
	dw	 640, 400,256, 2fh,0
	dw	 640, 480,256, 2eh,0
	dw	 800, 600,256, 30h,0
	dw	1024, 768,256, 38h,0
video7_entries	dw	0
	dw	 752, 410, 16, 6f05h,60h
	dw	 720, 540, 16, 6f05h,61h
	dw	 800, 600, 16, 6f05h,62h
	dw	1024, 768,  2, 6f05h,63h
	dw	1024, 768,  4, 6f05h,64h
	dw	1024, 768, 16, 6f05h,65h
	dw	 640, 400,256, 6f05h,66h
	dw	 640, 480,256, 6f05h,67h
	dw	 720, 540,256, 6f05h,68h
	dw	 800, 600,256, 6f05h,69h
	dw	1024, 768,256, 6f05h,6ah
xga_entries	dw	0
	dw	1024, 768,256,0ffffh,02h
	dw	1024, 768, 16,0ffffh,03h
	dw	 640, 400,256,0ffffh,04h
	dw	 640, 480,256,0ffffh,04h
	dw	 800, 600, 16,0ffffh,06h
	dw	 800, 600,256,0ffffh,07h
no_entries	dw	0
	dw	 320, 200,256, 13h,0
	dw	 640, 480, 16, 12h,0
	dw	0

.code

newbank proc			;bank number is in AX
	cli
	mov	OSEG[curbk],ax
if @CodeSize
	call	dword ptr OSEG[bankadr]
else
	call	word ptr OSEG[bankadr]
endif
	ret
newbank endp

$tseng	proc		;Tseng
	push	ax
	push	dx
	and	al,7
	mov	ah,al
	shl	al,1
	shl	al,1
	shl	al,1
	or	al,ah
	or	al,01000000b
	mov	dx,3cdh
	out	dx,al
	sti
	pop	dx
	pop	ax
	ret
$tseng	endp

$tseng4 proc		;Tseng 4000 series
	push	ax
	push	dx
	mov	ah,al
	mov	dx,3bfh 		;Enable access to extended registers
	mov	al,3
	out	dx,al
	mov	dl,0d8h
	mov	al,0a0h
	out	dx,al
	and	ah,15
	mov	al,ah
	shl	al,1
	shl	al,1
	shl	al,1
	shl	al,1
	or	al,ah
	mov	dl,0cdh
	out	dx,al
	sti
	pop	dx
	pop	ax
	ret
$tseng4 endp

$trident proc		;Trident
	push	ax
	push	dx
	mov	dx,3ceh 	;set page size to 64k
	mov	al,6
	out	dx,al
	inc	dl
	in	al,dx
	dec	dl
	or	al,4
	mov	ah,al
	mov	al,6
	out	dx,ax

	mov	dl,0c4h 	;switch to BPS mode
	mov	al,0bh
	out	dx,al
	inc	dl
	in	al,dx
	dec	dl

	mov	ah,byte ptr OSEG[curbk]
	xor	ah,2
	mov	dx,3c4h
	mov	al,0eh
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$trident endp

$video7 proc		;Video 7
	push	ax
	push	dx
	push	cx
; Video-7 1024x768x16 mode patch (thanks to Frank Lozier 11/8/89).
	cmp	colors,16
	jne	video7xx
	shl	ax,1
	shl	ax,1
video7xx:
	and	ax,15
	mov	ch,al
	mov	dx,3c4h
	mov	ax,0ea06h
	out	dx,ax
	mov	ah,ch
	and	ah,1
	mov	al,0f9h
	out	dx,ax
	mov	al,ch
	and	al,1100b
	mov	ah,al
	shr	ah,1
	shr	ah,1
	or	ah,al
	mov	al,0f6h
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	and	al,not 1111b
	or	ah,al
	mov	al,0f6h
	out	dx,ax
	mov	ah,ch
	mov	cl,4
	shl	ah,cl
	and	ah,100000b
	mov	dl,0cch
	in	al,dx
	mov	dl,0c2h
	and	al,not 100000b
	or	al,ah
	out	dx,al
	sti
	pop	cx
	pop	dx
	pop	ax
	ret
$video7 endp

$paradise proc		;Paradise
	push	ax
	push	dx
	mov	dx,3ceh
	mov	ax,50fh 	;turn off write protect on VGA registers
	out	dx,ax
	mov	ah,byte ptr OSEG[curbk]
	shl	ah,1
	shl	ah,1
	shl	ah,1
	shl	ah,1
	mov	al,9
	out	dx,ax
	mov	ax,000Fh	;reprotect registers, 910512
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$paradise endp

$chipstech proc 	;Chips & Tech
	push	ax
	push	dx
	mov	dx,46e8h	;place chip in setup mode
	mov	ax,1eh
	out	dx,ax
	mov	dx,103h 	;enable extended registers
	mov	ax,0080h	; (patched per JB's msg - Bert)
	out	dx,ax
	mov	dx,46e8h	;bring chip out of setup mode
	mov	ax,0eh
	out	dx,ax
	mov	ah,byte ptr OSEG[curbk]
	shl	ah,1		;change 64k bank number into 16k bank number
	shl	ah,1
	mov	al,10h
	mov	dx,3d6h
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$chipstech endp

$ativga proc		;ATI VGA Wonder
	push	ax
	push	dx
	mov	ah,al
	mov	dx,1ceh
	mov	al,0b2h
	out	dx,al
	inc	dl
	in	al,dx
	shl	ah,1
	and	al,0e1h
	or	ah,al
	mov	al,0b2h
	dec	dl
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$ativga endp

$everex proc		;Everex
	push	ax
	push	dx
	push	cx
	mov	cl,al
	mov	dx,3c4h
	mov	al,8
	out	dx,al
	inc	dl
	in	al,dx
	dec	dl
	shl	al,1
	shr	cl,1
	rcr	al,1
	mov	ah,al
	mov	al,8
	out	dx,ax
	mov	dl,0cch
	in	al,dx
	mov	dl,0c2h
	and	al,0dfh
	shr	cl,1
	jc	nob2
	or	al,20h
nob2:	out	dx,al
	sti
	pop	cx
	pop	dx
	pop	ax
	ret
$everex endp

$aheada proc
	push	ax
	push	dx
	push	cx
	mov	ch,al
	mov	dx,3ceh 	;Enable extended registers
	mov	ax,200fh
	out	dx,ax
	mov	dl,0cch 	;bit 0
	in	al,dx
	mov	dl,0c2h
	and	al,11011111b
	shr	ch,1
	jnc	temp_1
	or	al,00100000b
temp_1: out	dx,al
	mov	dl,0cfh 	;bits 1,2,3
	mov	al,0
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	and	al,11111000b
	or	al,ch
	mov	ah,al
	mov	al,0
	out	dx,ax
	sti
	pop	cx
	pop	dx
	pop	ax
	ret
$aheada endp

$aheadb proc
	push	ax
	push	dx
	push	cx
	mov	ch,al
	mov	dx,3ceh 	;Enable extended registers
	mov	ax,200fh
	out	dx,ax
	mov	ah,ch
	mov	cl,4
	shl	ah,cl
	or	ah,ch
	mov	al,0dh
	out	dx,ax
	sti
	pop	cx
	pop	dx
	pop	ax
	ret
$aheadb endp

$oaktech proc		;Oak Technology Inc OTI-067
	push	ax
	push	dx
	and	al,15
	mov	ah,al
	shl	al,1
	shl	al,1
	shl	al,1
	shl	al,1
	or	ah,al
	mov	al,11h
	mov	dx,3deh
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$oaktech endp

$genoa	proc			;GENOA GVGA
	push	ax
	push	dx
	mov	ah,al
	shl	al,1
	shl	al,1
	shl	al,1
	or	ah,al
	mov	al,6
	or	ah,40h
	mov	dx,3c4h
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$genoa	endp

$ncr	proc				;NCR 77C22E
	push	ax
	push	dx
	shl	al,1		;change 64k bank number into 16k bank number
	shl	al,1
	mov	ah,al
	mov	al,18h
	mov	dx,3c4h
	out	dx,ax
	mov	ax,19h
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$ncr	endp

$compaq proc			;Compaq
	push	ax
	push	dx
	mov	dx,3ceh
	mov	ax,50fh 	;unlock extended registers
	out	dx,ax
	mov	ah,byte ptr OSEG[curbk]
	shl	ah,1		;change 64k bank number into 4k bank number
	shl	ah,1
	shl	ah,1
	shl	ah,1
	mov	al,45h
	out	dx,ax
	sti
	pop	dx
	pop	ax
	ret
$compaq endp

;
;  Read/Write 64K pages
;
$vesa1	proc				; VESA bank switching
	push	ax
	push	bx
	push	dx
	mul	vesa_granularity	; Adjust for the granularity factor
	mov	dx,ax			; Select window position
	mov	bx,0			; select window (bank) sub-command
	call	dword ptr vesa_bankswitch  ; do it!
	pop	dx
	pop	bx
	pop	ax
	sti
	ret
$vesa1	endp
;
;  Read-only/Write-only 64K pages
;
$vesa2	proc				; VESA bank switching
	push	ax
	push	bx
	push	dx
	mul	vesa_granularity	; Adjust for the granularity factor
	mov	dx,ax			; Select window position
	push	dx
	mov	bx,0			; select window (bank) sub-command
	call	dword ptr vesa_bankswitch  ; do it!
	pop	dx
	inc	bx
	call	dword ptr vesa_bankswitch
	pop	dx
	pop	bx
	pop	ax
	sti
	ret
$vesa2	endp
;
;  Read/Write 32K pages
;
$vesa3	proc				; VESA bank switching
	push	ax
	push	bx
	push	dx
	mul	vesa_granularity	; Adjust for the granularity factor
	mov	dx,ax			; Select window position
	push	dx
	mov	bx,vesa_low_window	; select window (bank) sub-command
	call	dword ptr vesa_bankswitch  ; do it!
	pop	dx
	add	dx,vesa_gran_offset	; 2nd window is at 32K offset from 1st
	mov	bx,vesa_high_window
	call	dword ptr vesa_bankswitch
	pop	dx
	pop	bx
	pop	ax
	sti
	ret
$vesa3	endp

$vesa_nullbank proc ; null routine for vesa_bankswitch when unknown
	ret
$vesa_nullbank endp

$nobank proc
	sti
	ret
$nobank endp

bkadr	macro	flag,func,entries		; Bert
	mov	video_entries, offset entries	; Bert
	mov	[flag],1
	mov	[bankadr],offset func
if @CodeSize
	mov	[bankseg],seg func
endif
	endm

nojmp	macro
	local	lbl
	jmp	lbl
lbl:
	endm

whichvga proc	near
	push	bp			; save it around all the int 10s

	cmp	svga_type,0		; was a SuperVGA adapter forced?
	jne	type1_forced		;  yup - wade through the options
	jmp	not_forced		;  nope - skip this section
type1_forced:
	cmp	svga_type,1
	jne	type2_forced
	bkadr	aheada,$aheada,ahead_entries
type2_forced:
	cmp	svga_type,2
	jne	type3_forced
	bkadr	ativga,$ativga,ati_entries
type3_forced:
	cmp	svga_type,3
	jne	type4_forced
	bkadr	chipstech,$chipstech,chips_entries
type4_forced:
	cmp	svga_type,4
	jne	type5_forced
	bkadr	everex,$everex,everex_entries
type5_forced:
	cmp	svga_type,5
	jne	type6_forced
	bkadr	genoa,$genoa,genoa_entries
type6_forced:
	cmp	svga_type,6
	jne	type7_forced
	bkadr	ncr,$ncr,ncr_entries
type7_forced:
	cmp	svga_type,7
	jne	type8_forced
	bkadr	oaktech,$oaktech,oaktech_entries
type8_forced:
	cmp	svga_type,8
	jne	type9_forced
	bkadr	paradise,$paradise,paradise_entries
type9_forced:
	cmp	svga_type,9
	jne	type10_forced
	bkadr	trident,$trident,trident_entries
type10_forced:
	cmp	svga_type,10
	jne	type11_forced
	bkadr	tseng,$tseng,tseng_entries
type11_forced:
	cmp	svga_type,11
	jne	type12_forced
	bkadr	tseng4,$tseng4,tseng4_entries
type12_forced:
	cmp	svga_type,12
	jne	type13_forced
	bkadr	video7,$video7,video7_entries
type13_forced:
	cmp	svga_type,13
	jne	type14_forced
	bkadr	aheadb,$aheadb,ahead_entries
type14_forced:
	jmp	fini
not_forced:

	cmp	vesa_detect,0		; is VESA-detection disabled?
	je	notvesa 		;  yup - skip this
	mov	ax,4f00h		; check for VESA adapter
	push	ds			; set ES == DS
	pop	es			;  ...
	mov	di, offset dacbox	; answer goes here (a safe place)
	int	10h			; do it.
	cmp	ax,004fh		; successful response?
	jne	notvesa 		; nope.  Not a VESA adapter

	cmp	byte ptr 0[di],'V'      ; string == 'VESA'?
	jne	notvesa 		; nope.  Not a VESA adapter
	cmp	byte ptr 1[di],'E'      ; string == 'VESA'?
	jne	notvesa 		; nope.  Not a VESA adapter
	cmp	byte ptr 2[di],'S'      ; string == 'VESA'?
	jne	notvesa 		; nope.  Not a VESA adapter
	cmp	byte ptr 3[di],'A'      ; string == 'VESA'?
	jne	notvesa 		; nope.  Not a VESA adapter
	bkadr	vesa,$vesa_nullbank, vesa_entries
	jmp	fini
notvesa:

	call	xga_detect		; XGA Adapter?
	cmp	ax,0
	je	notxga			; nope
	bkadr	xga,xga_newbank, xga_entries
	jmp	fini
notxga:

	mov	si,1
	mov	ax,0c000h
	mov	es,ax
	cmp	word ptr es:[40h],'13'
	jnz	noati
	bkadr	ativga,$ativga,ati_entries		; Bert
	mov	dx,es:[10h]		; Get value of ATI extended register
	mov	bl,es:[43h]		; Get value of ATI chip version
	cmp	bl,'3'
	jae	v6up			; Use different method to determine
	mov	al,0bbh 		; memory size of chip version is 3 or higher
	cli
	out	dx,al
	inc	dx
	in	al,dx			; Get ramsize byte for chip versions 1 & 2
	sti
	test	al,20h
	jz	no512
	mov	[vga512],1
	jmp	short no512

v6up:	mov	al,0b0h			; Method used for newer ATI chip versions
	cli
	out	dx,al
	inc	dx
	in	al,dx			; Get ramsize byte for versions 3-5
	sti
	test	al,10h			; Check if ramsize byte indicates 256K or 512K bytes
	jz	v7up
	mov	[vga512],1
v7up:	cmp	bl,'4'			; Check for ramsize for ATI chip versions 4 & 5
	jb	no512
	test	al,8			; Check if version 5 ATI chip has 1024K
	jz	no512
	mov	[vga1024],1
no512:	jmp	fini

noati:	mov	ax,7000h		;Test for Everex
	xor	bx,bx
	cld
	int	10h
	cmp	al,70h
	jnz	noev
	bkadr	everex,$everex, everex_entries		; Bert
	and	ch,11000000b
	jz	temp_2
	mov	[vga512],1
temp_2: and	dx,0fff0h
	cmp	dx,6780h
	jz	yeste
	cmp	dx,2360h
	jnz	note
yeste:	bkadr	trident,$trident, everex_entries	; Bert
	mov	everex,0
note:	jmp	fini

noev:
	mov	ax,0bf03h		;Test for Compaq
	xor	bx,bx
	mov	cx,bx
	int	10h
	cmp	ax,0bf03h
	jnz	nocp
	test	cl,40h			;is 640x480x256 available? ;(??)
	jz	nocp
	bkadr	compaq,$compaq,compaq_entries		; Bert
	mov	[vga512],1
	jmp	fini

nocp:	mov	dx,3c4h 		;Test for NCR 77C22E
	mov	ax,0ff05h
	call	$isport2
	jnz	noncr
	mov	ax,5			;Disable extended registers
	out	dx,ax
	mov	ax,0ff10h		;Try to write to extended register 10
	call	$isport2		;If it writes then not NCR
	jz	noncr
	mov	ax,105h 		;Enable extended registers
	out	dx,ax
	mov	ax,0ff10h
	call	$isport2
	jnz	noncr			;If it does NOT write then not NCR
	bkadr	ncr,$ncr,ncr_entries		; Bert
	mov	[vga512],1
	jmp	fini

noncr:	mov	dx,3c4h 		;Test for Trident
	mov	al,0bh
	out	dx,al
	inc	dl
	in	al,dx
	and	al,0fh
	cmp	al,06h
	ja	notri
	cmp	al,2
	jb	notri
	bkadr	trident,$trident, trident_entries	; Bert
	cmp	al,3
	jb	no89
	mov	[t8900],1
	mov	dx,3d4h		; (was 3d5h in version 17.2)
	mov	al,1fh
	out	dx,al
	inc	dx
	in	al,dx
	and	al,3
	cmp	al,1
	jb	notmem
	mov	[vga512],1
	je	notmem
	mov	[vga1024],1
notmem: jmp	fini

no89:	mov	[vga512],1
	jmp	fini

notri:	mov	ax,6f00h		;Test for Video 7
	xor	bx,bx
	cld
	int	10h
	cmp	bx,'V7'
	jnz	nov7
	bkadr	video7,$video7, video7_entries		; Bert
	mov	ax,6f07h
	cld
	int	10h
	and	ah,7fh
	cmp	ah,1
	jbe	temp_3
	mov	[vga512],1
temp_3:	cmp	ah,3
	jbe	temp_4
	mov	[vga1024],1
temp_4:	jmp	fini

nov7:	mov	dx,3d4h 		;Test for GENOA GVGA
	mov	al,2eh			;check for Herchi Register top 6 bits
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	test	al,11111100b		;top 6 bits should be zero
	jnz	nogn
	mov	ax,032eh		;check for Herchi Register
	call	$isport2
	jnz	nogn
	mov	dx,3c4h
	mov	al,7
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	test	al,10001000b
	jnz	nogn
	mov	al,10h
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	and	al,00110000b
	cmp	al,00100000b
	jnz	nogn
	mov	dx,3ceh
	mov	ax,0ff0bh
	call	$isport2
	jnz	nogn
	mov	dx,3c4h 		;check for memory segment register
	mov	ax,3f06h
	call	$isport2
	jnz	nogn
	mov	dx,3ceh
	mov	ax,0ff0ah
	call	$isport2
	jnz	nogn
	bkadr	genoa,$genoa, genoa_entries		; Bert
	mov	[vga512],1
	jmp	fini

nogn:	call	$cirrus 		;Test for Cirrus
	cmp	[cirrus],0
	je	noci
	jmp	fini

noci:	mov	dx,3ceh 		;Test for Paradise
	mov	al,9			;check Bank switch register
	out	dx,al
	inc	dx
	in	al,dx
	dec	dx
	or	al,al
	jnz	nopd

	mov	ax,50fh 		;turn off write protect on VGA registers
	out	dx,ax
	mov	dx,offset $pdrsub
	mov	cx,1
	call	$chkbk
	jc	nopd			;if bank 0 and 1 same not paradise
	bkadr	paradise,$paradise, paradise_entries	; Bert
	mov	dx,3ceh
	mov	al,0bh			;512k detect from Bob Berry
	out	dx,al
	inc	dx
	in	al,dx
	test	al,80h			;if top bit set then 512k
	jz	nop512
	test	al,40h
	jz	nop1024
	mov	[vga1024],1
	jmp	fini
nop1024:
	mov	[vga512],1
nop512: jmp	fini

nopd:	mov	ax,5f00h		;Test for Chips & Tech
	xor	bx,bx
	cld
	int	10h
	cmp	al,5fh
	jnz	noct
	bkadr	chipstech,$chipstech, chips_entries	; Bert
	cmp	bh,1
	jb	temp_5
	mov	[vga512],1
temp_5:
	jmp	fini

noct:	mov	ch,0
	mov	dx,3dah			;Test for Tseng 4000 & 3000
	in	al,dx			;bit 8 is opposite of bit 4
	mov	ah,al			;(vertical retrace bit)
	shr	ah,1
	shr	ah,1
	shr	ah,1
	shr	ah,1
	xor	al,ah
	test	al,00001000b
;	jz	nots
	jnz	@F
	jmp	nots
@@:
	mov	dx,3d4h 		;check for Tseng 4000 series
	mov	ax,0f33h
	call	$isport2
	jnz	not4
	mov	ax,0ff33h		;top 4 bits should not be there
	call	$isport2
;	jz	nots
	jnz	@F
	jmp	nots
@@:
	mov	ch,1

not4:	mov	dx,3bfh 		;Enable access to extended registers
	mov	al,3
	out	dx,al
	mov	dx,3d8h
	mov	al,0a0h
	out	dx,al
	cmp	ch,0
	jnz	yes4

	mov	dx,3d4h 		;Test for Tseng 3000 or 4000
	mov	ax,1f25h		;is the Overflow High register there?
	call	$isport2
	jnz	nots
	mov	al,03fh 		;bottom six bits only
	jmp	short yes3
yes4:	mov	al,0ffh
yes3:	mov	dx,3cdh 		;test bank switch register
	call	$isport1
	jnz	nots
	bkadr	tseng,$tseng, tseng_entries		; Bert
	cmp	ch,0
	jnz	t4mem
;	mov	[vga512],1
	call	$t3memchk
	jmp	fini

t4mem:	mov	dx,3d4h 		;Tseng 4000 memory detect 1meg
	mov	al,37h
	out	dx,al
	inc	dx
	in	al,dx
	test	al,1000b		;if using 64kx4 RAMs then no more than 256k
	jz	nomem
	and	al,3
	cmp	al,1			;if 8 bit wide bus then only two 256kx4 RAMs
	jbe	nomem
	mov	[vga512],1
	cmp	al,2			;if 16 bit wide bus then four 256kx4 RAMs
	je	nomem
	mov	[vga1024],1		;full meg with eight 256kx4 RAMs
nomem:	bkadr	tseng4,$tseng4, tseng4_entries		; Bert
	jmp	fini

nots:
	mov	dx,3ceh 	;Test for Above A or B chipsets
	mov	ax,0ff0fh		;register should not be fully available
	call	$isport2
	jz	noab
	mov	ax,200fh
	out	dx,ax
	inc	dx
	nojmp
	in	al,dx
	cmp	al,21h
	jz	verb
	cmp	al,20h
	jnz	noab
	bkadr	aheada,$aheada, ahead_entries		; Bert
	mov	[vga512],1
	jmp	short fini

verb:	bkadr	aheadb,$aheadb, ahead_entries		; Bert
	mov	[vga512],1
	jmp	short fini

noab:	mov	dx,3deh 		;Test for Oak Technology
	mov	ax,0ff11h		;look for bank switch register
	call	$isport2
	jnz	nooak
	bkadr	oaktech,$oaktech, oaktech_entries		; Bert
	mov	al,0dh
	out	dx,al
	inc	dx
	nojmp
	in	al,dx
	test	al,11000000b
	jz	no4ram
	mov	[vga512],1
	test	al,01000000b
	jz	no4ram
	mov	[vga1024],1
no4ram: jmp	short fini

nooak:	mov	si,0

fini:	mov	ax,si
	pop	bp
	ret
whichvga endp


;Segment to access video buffer (based on GR[6])
buftbl	dw	0A000h,0A000h,0B000h,0B800h

$t3memchk proc near			;[Charles Marslett -- ET3000 memory ck]
	mov	dx,3dah
	in	al,dx			;Reset the attribute flop (read 0x3DA)
	mov	dx,03c0h
	mov	al,36h
	out	dx,al
	inc	dx
	in	al,dx			;Save contents of ATTR[0x16]
	push	ax
	or	al,10h
	dec	dx
	out	dx,al
	mov	dx,3ceh			;Find the RAM buffer...
	mov	al,6
	out	dx,al
	inc	dx
	in	al,dx
	and	ax,000Ch
	shr	ax,1

	mov	bx,ax
	push	es
	mov	es,cs:buftbl[bx]
	mov	ax,09C65h
	mov	bx,1
	mov	es:[bx],ax
	mov	es:[bx+2],ax
	inc	bx
	mov	ax,es:[bx]
	pop	es
	cmp	ax,0659Ch
	jne	et3k_256
	mov	[vga512],1
et3k_256:
	mov	dx,3c0h
	mov	al,36h
	out	dx,al
	pop	ax
	out	dx,al			;Restore ATTR[16h]
	ret
$t3memchk endp


$cirrus proc	near
	mov	dx,3d4h 	; assume 3dx addressing
	mov	al,0ch		; screen a start address hi
	out	dx,al		; select index
	inc	dx		; point to data
	mov	ah,al		; save index in ah
	in	al,dx		; get screen a start address hi
	xchg	ah,al		; swap index and data
	push	ax		; save old value
	push	dx		; save crtc address
	xor	al,al		; clear crc
	out	dx,al		; and out to the crtc

	mov	al,1fh		; Eagle ID register
	dec	dx		; back to index
	out	dx,al		; select index
	inc	dx		; point to data
	in	al,dx		; read the id register
	mov	bh,al		; and save it in bh

	mov	cl,4		; nibble swap rotate count
	mov	dx,3c4h 	; sequencer/extensions
	mov	bl,6		; extensions enable register

	ror	bh,cl		; compute extensions disable value
	mov	ax,bx		; extensions disable
	out	dx,ax		; disable extensions
	inc	dx		; point to data
	in	al,dx		; read enable flag
	or	al,al		; disabled ?
	jnz	exit		; nope, not an cirrus

	ror	bh,cl		; compute extensions enable value
	dec	dx		; point to index
	mov	ax,bx		; extensions enable
	out	dx,ax		; enable extensions
	inc	dx		; point to data
	in	al,dx		; read enable flag
	cmp	al,1		; enabled ?
	jne	exit		; nope, not an cirrus
	mov	[cirrus],1
	mov	video_entries, offset no_entries	; Bert
	mov	[bankadr],offset $nobank
if @CodeSize
	mov	[bankseg],seg $nobank
endif
exit:	pop	dx		; restore crtc address
	dec	dx		; point to index
	pop	ax		; recover crc index and data
	out	dx,ax		; restore crc value
	ret
$cirrus endp

$chkbk	proc	near		;paradise bank switch check
	mov	di,0b800h
	mov	es,di
	xor	di,di
	mov	bx,1234h
	call	$gochk
	jnz	nopd
	mov	bx,4321h
	call	$gochk
	jnz	nopd
	clc
	ret
nopd:	stc
	ret
$chkbk	endp

$gochk	proc	near
	push	si
	mov	si,bx

	mov	al,cl
	call	dx
	xchg	bl,es:[di]
	mov	al,ch
	call	dx
	xchg	bh,es:[di]

	xchg	si,bx

	mov	al,cl
	call	dx
	xor	bl,es:[di]
	mov	al,ch
	call	dx
	xor	bh,es:[di]

	xchg	si,bx

	mov	al,ch
	call	dx
	mov	es:[di],bh
	mov	al,cl
	call	dx
	mov	es:[di],bl

	mov	al,0
	call	dx
	or	si,si
	pop	si
	ret
$gochk	endp


$pdrsub proc	near		;Paradise
	push	dx
	mov	ah,al
	mov	dx,3ceh
	mov	al,9
	out	dx,ax
	pop	dx
	ret
$pdrsub endp

$isport2 proc	near
	push	bx
	mov	bx,ax
	out	dx,al
	mov	ah,al
	inc	dx
	in	al,dx
	dec	dx
	xchg	al,ah
	push	ax
	mov	ax,bx
	out	dx,ax
	out	dx,al
	mov	ah,al
	inc	dx
	in	al,dx
	dec	dx
	and	al,bh
	cmp	al,bh
	jnz	noport
	mov	al,ah
	mov	ah,0
	out	dx,ax
	out	dx,al
	mov	ah,al
	inc	dx
	in	al,dx
	dec	dx
	and	al,bh
	cmp	al,0
noport: pop	ax
	out	dx,ax
	pop	bx
	ret
$isport2 endp

$isport1 proc	near
	mov	ah,al
	in	al,dx
	push	ax
	mov	al,ah
	out	dx,al
	in	al,dx
	and	al,ah
	cmp	al,ah
	jnz	noport
	mov	al,0
	out	dx,al
	in	al,dx
	and	al,ah
	cmp	al,0
noport: pop	ax
	out	dx,al
	ret
$isport1 endp

videowrite	proc	near		; your-own-video write routine
	mov	ah,0			; clear the high-order color byte
	push	ax			; colors parameter
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr writevideo	; let the external routine do it
	add	sp,6			; pop the parameters
	ret				; we done.
videowrite	endp

videoread	proc	near		; your-own-video read routine
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr readvideo	; let the external routine do it
	add	sp,4			; pop the parameters
	ret				; we done.
videoread	endp

diskwrite	proc	near		; disk-video write routine
	push	ax			; colors parameter
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr writedisk	; let the external routine do it
	add	sp,6			; pop the parameters
	ret				; we done.
diskwrite	endp

diskread	proc	near		; disk-video read routine
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr readdisk	; let the external routine do it
	add	sp,4			; pop the parameters
	ret				; we done.
diskread	endp


; ***********************************************************************
;
; TARGA MODIFIED 1 JUNE 89 - j mclain
;
tgawrite	proc	near
	push	ax			; colors parameter
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr WriteTGA	; writeTGA( x, y, color )
	add	sp,6			; pop the parameters
	ret
tgawrite	endp

tgaread 	proc	near
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr ReadTGA 	; readTGA( x, y )
	add	sp,4			; pop the parameters
	ret
tgaread endp


; TARGA+ Code 2-11-91, Mark Peterson

TPlusWrite	PROC	NEAR
	push	ax
	push	dx
	push	cx
	call	FAR PTR WriteTPlusBankedPixel
	add	sp, 6
	ret
TPlusWrite     ENDP

TPlusRead      PROC    NEAR
	push	dx
	push	cx
	call	FAR PTR ReadTPlusBankedPixel
	add	sp, 4
	ret
TPlusRead      ENDP

; 8514/a afi routines JCO, not needed, 4/11/92
;f85start    proc    near
;	call   far ptr open8514
;	ret
;f85start    endp

;f85end	proc	near
;	call   far ptr close8514
;	ret
;f85end	endp

;f85write    proc    near
;	call   far ptr fr85wdot
;	ret
;f85write    endp

;f85read proc	near
;	call   far ptr fr85rdot
;	ret
;f85read endp

hgcwrite proc near
	mov	ah,0			; clear the high-order color byte
	push	ax			; colors parameter
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr writehgc	; let the Herc. Write dot routine do it
	add	sp,6			; pop the parameters
	ret
hgcwrite endp

hgcread proc near
	push	dx			; 'y' parameter
	push	cx			; 'x' parameter
	call	far ptr readhgc 	; call the Hercules Read dot routine
	add	sp,4			; pop the parameters
	ret
hgcread endp

hgcstart	proc	near		; hercules start routine
	call	far ptr inithgc 	; let the external routine do it
	ret				; we done.
hgcstart	endp

hgcend		proc	near		; hercules end routine
	call	far ptr termhgc 	; let the external routine do it
	ret				; we done.
hgcend		endp

; **************** video adapter initialization *******************
;
; adapter_init:
;	called from general.asm once per run

adapter_init	proc	far		; initialize the video adapter (to VGA)
	mov	ax,[bankadr]		; Initialize the bank-switching
	mov	video_bankadr,ax	;  logic to the do-nothing routine
	mov	ax,[bankseg]		;  ...
	mov	video_bankseg,ax	;  ...
	mov	bx,0			; clear out all of the 256-mode flags
	mov	tseng,bx		;  ...
	mov	trident,bx		;  ...
	mov	video7,bx		;  ...
	mov	paradise,bx		;  ...
	mov	chipstech,bx	;  ...
	mov	ativga,bx		;  ...
	mov	everex,bx		;  ...
	mov	cirrus,bx		;  ...
	mov	aheada,bx		;  ...
	mov	aheadb,bx		;  ...
	mov	tseng4,bx		;  ...
	mov	oaktech,bx		;  ...
	mov	[bankadr],offset $nobank
	mov	[bankseg],seg $nobank
	mov	video_entries, offset no_entries	; ...
	ret
adapter_init	endp

; adapter_detect:
;	This routine performs a few quick checks on the type of
;	video adapter installed.
;	It sets variables video_type and textsafe,
;	and fills in a few bank-switching routines.

adapter_detect	proc	uses di si es
	push	bp			; some bios's don't save during int 10h
	cmp	done_detect,0		; been called already?
	je	adapter_detect2 	;  nope
	jmp	adapter_ret		; yup, do nothing
adapter_detect2:
	inc	done_detect		; don't get called again

	cmp	video_type,0		; video_type preset by command line arg?
	jne	go_adapter_set		;  yup, use what we're told

	cmp	TPlusFlag, 0
	je	NotTPlus
	call	far ptr CheckForTPlus
	or	ax, ax
	jz	NotTPlus
	mov	TPlusInstalled, 1	; flag it and check for primary adapter

NotTPlus:
	mov	ax,1a00h		; start by trying int 10 func 1A
	int	10h			;  ...
	cmp	al,1ah			; was AL modified?
	je	adapter_detect_4	;  yup. go decode what we got
	mov	ax,1200h		; try this vga-only function
	mov	bl,34h			;  enable cursor emulation
	int	10h			;  ...
	cmp	al,12h			; did it work?
	je	adapter_detect_vga	;  yup, vga
	mov	ah,12h			; look for an EGA
	mov	bl,10h			;  by using an EGA-specific call
	int	10h			;  ...
	cmp	bl,10h			; was BL modified?
	je	adapter_detect_notega	;  nope, < EGA
	mov	video_type,3		; set the video type: EGA
	cmp	bh,1			; monochrome monitor?
	jne	go_adapter_set		;  nope
	mov	mode7text,1		; yup, use mode 7 for text
	jmp	short go_adapter_set	; We done.
adapter_detect_4:
	cmp	bl,1			; =1?
	jne	adapter_detect_4a	;  nope
	jmp	adapter_detect_hgc	; MDA, assume HGC (nothing else works)
adapter_detect_4a:
	mov	video_type,2		; set the video type: CGA
	cmp	bl,3			; <=2?
	jb	go_adapter_set		;  exit with type CGA
	mov	video_type,3		; set the video type: EGA
	cmp	bl,5			; =5?
	jne	adapter_detect_5	;  nope
	mov	mode7text,1		; yup, monochrome monitor, mode 7 text
go_adapter_set:
	jmp	adapter_set
adapter_detect_5:
	cmp	bl,6			; <=5?
	jb	go_adapter_set		;  exit with type EGA
	cmp	bl,10			; <=9?
	jb	adapter_detect_vga	;  vga, go check which kind
	mov	video_type,4		; set the video type: MCGA
	cmp	bl,13			; <=12?
	jb	go_adapter_set		;  exit with type MCGA
adapter_detect_vga:
	mov	video_type,5		; set the video type: VGA
	call	whichvga		; autodetect which VGA is there
	mov	ax,[bankadr]		; save the results
	mov	video_bankadr,ax	;  ...
	mov	ax,[bankseg]		;  ...
	mov	video_bankseg,ax	;  ...
	jmp	adapter_set
adapter_detect_notega:
	mov	video_type,2		; set the video type: CGA
	; HGC detect code from book by Richard Wilton follows
	mov	dx,3B4h 		; check for MDA, use MDA CRTC address
	mov	al,0Fh			; select 6845 reg 0Fh (Cursor Low)
	out	dx,al
	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,200h
mdalp:	loop	mdalp			; wait for 6845 to respond
	in	al,dx			; read cursor low again
	xchg	ah,al
	out	dx,al			; restore original value
	cmp	ah,66h			; test whether 6845 responded
	jne	adapter_set		;  nope, exit with type CGA
	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
mdalp2: in	al,dx
	and	al,80h			; isolate bit 7
	cmp	ah,al
	loope	mdalp2			; wait for bit 7 to change
	je	adapter_set		;  didn't change, exit with type CGA
;;	in	al,dx
;;	and	al,01100000b		; mask off bits 5 and 6
;; Next line probably backwards but doesn't matter, the test in this area
;; distinguishes HGC/HGC+/InColor, which we don't care about anyway.
;;	jnz	adapter_set		; not hgc/hgc+, exit with type CGA
adapter_detect_hgc:
	mov	video_type,1		; HGC
	mov	mode7text,1		; use mode 7 for text

adapter_set:
	; ensure a nice safe standard state
	mov	ax,3			; set 80x25x16 text mode, clear screen
	cmp	mode7text,0		; use mode 7 for text?
	je	adapter_set2		;  nope
	mov	ax,7			; set mono text mode, clear screen
adapter_set2:
	int	10h			; set text mode
	mov	ax,0500h		; select display page zero
	int	10h			;  ...

	; now the color text stuff
	cmp	textsafe,2		; command line textsafe=no?
	je	adapter_go_ret		;  yup, believe the user
	cmp	video_type,3		; >= ega?
	jae	adapter_setup		;  yup
	mov	textsafe,2		; textsafe=no
adapter_go_ret: 			; a label for some short jumps
	jmp	adapter_ret		;  to the exit

adapter_setup:
	; more standard state, ega and up stuff
	mov	ax,1003h		; top attribute bit means blink
	mov	bl,01h			;  ...
	int	10h			;  ...
	mov	ax,1103h		; font block 0, 256 chars (not 512)
	mov	bl,00h			;  ...
	int	10h			;  ...
	mov	ax,1202h		; 400 scan lines in text mode (vga)
	mov	bl,30h			;  ...
	int	10h			;  ...
	mov	ax,1200h		; cga cursor emulation (vga)
	mov	bl,34h			;  ...
	int	10h			;  ...
	mov	ax,1200h		; enable default palette loading
	mov	bl,31h			;  ...
	int	10h			;  ...
	cmp	textsafe,0		; were we told textsafe=yes|bios|save?
	jne	adapter_ret		;  yup
	mov	textsafe,1		; set textsafe=yes
adapter_ret:
	cld				; some MSC 6.0 libraries assume this!
	pop	bp
	ret
adapter_detect	endp


; select_vga_plane:
;	Call this routine with cx = plane number.
;	It works for vga and for ega.  (I hope.)
;	It uses no local variables, caller may have ds register modified.
;	On return from this routine, the requested vid mem plane is mapped
;	to A0000;  this means that the sequencer and graphics controller
;	states are not very useful for further real work - before any further
;	screen painting, better reset video mode.

select_vga_plane proc near		; cl = plane number
	; some callers may have ds modified, use no variables in here!
	mov	dx,SC_INDEX		; sequencer controller
	mov	ax,0102h		; select plane
	shl	ah,cl			;  bit for desired plane
	out	dx,ax			;  ...
	mov	ax,0604h		; no chaining
	out	dx,ax			;  ...
	mov	dx,GC_INDEX		; graphics controller
	mov	ax,0001h		; use processor data
	out	dx,ax			;  ...
	mov	al,  04h		; select read plane
	mov	ah,cl			;  desired plane
	out	dx,ax			;  ...
	mov	ax,0005h		; no even/odd, write mode 0
	out	dx,ax			;  ...
	mov	ax,0106h		; map to a000, no chain, graphics
	out	dx,ax			;  ...
	mov	ax,0ff08h		; enable 8 bits per write
	out	dx,ax			;  ...
	ret				; all done
select_vga_plane endp


; **************** internal Read/Write-a-line routines *********************
;
;	These routines are called by out_line(), put_line() and get_line().
;	They assume the following register values:
;
;		si = offset of array of colors for a row (write routines)
;		di = offset of array of colors for a row (read routines)
;
;		ax = stopping column
;		bx =
;		cx = starting column
;		dx = row
;
; Note: so far have converted only normaline, normalineread, mcgaline,
;	mcgareadline, super256line, super256readline -- Tim

normaline	proc	near		; Normal Line
normal_line1:
	push	ax			; save stop col
	mov	al,[si] 		; retrieve the color
	xor	ah,ah			; MCP 6-7-91
	push	cx			; save the counter around the call
	push	dx			; save column around the call
	push	si			; save the pointer around the call also
	call	dotwrite		; write the dot via the approved method
	pop	si			; restore the pointer
	pop	dx			; restore the column
	pop	cx			; restore the counter
	inc	si			; bump it up
	inc	cx			; bump it up
	pop	ax			; retrieve number of dots
	cmp	cx,ax			; more to go?
	jle	normal_line1		; yup.	do it.
	ret
normaline	endp

normalineread	proc	near		; Normal Line
	mov	bx,videomem
	mov	es,bx
normal_lineread1:
	push	ax			; save stop col
	push	cx			; save the counter around the call
	push	dx			; save column around the call
	push	di			; save the pointer around the call also
	call	dotread 		; read the dot via the approved method
	pop	di			; restore the pointer
	pop	dx			; restore the column
	pop	cx			; restore the counter
	mov	bx,di			; locate the actual pixel color
	mov	[bx],al 		; retrieve the color
	inc	di			; bump it up
	inc	cx			; bump it up
	pop	ax			; retrieve number of dots
	cmp	cx,ax			; more to go?
	jle	normal_lineread1	; yup.	do it.
	ret
normalineread	endp

mcgaline	proc	near		; MCGA 320*200, 246 colors
	sub	ax,cx			; last col - first col
	inc	ax			;   + 1

	xchg	dh,dl			; bx := 256*y
	mov	bx,cx			; bx := x
	add	bx,dx			; bx := 256*y + x
	shr	dx,1
	shr	dx,1			; dx := 64*y
	add	bx,dx			; bx := 320*y + x
	mov	di,bx			; di = offset of row in video memory

	mov	cx,ax			; move this many bytes
	rep	movsb			; zap line into memory
	ret
mcgaline	endp

mcgareadline	proc	near		; MCGA 320*200, 246 colors

	sub	ax,cx			; last col - first col
	inc	ax			;   + 1

	xchg	dh,dl			; bx := 256*y
	mov	bx,cx			; bx := x
	add	bx,dx			; bx := 256*y + x
	shr	dx,1
	shr	dx,1			; dx := 64*y
	add	bx,dx			; bx := 320*y + x
	mov	si,bx			; di = offset of row in video memory

	mov	cx,ax			; move this many bytes
	mov	ax,ds			; copy data segment to ...
	mov	es,ax			;  ... es
	mov	ax,videomem		; copy video segment to ...
	mov	ds,ax			;  ... ds
	rep	movsb			; zap line into memory
	mov	ax,es
	mov	ds,ax			; restore data segement to ds
	ret
mcgareadline	endp

vgaline proc	near		; Bank Switch EGA/VGA line write
	push	cx			; save a few registers
	push	ax			;  ...
	push	dx			;  ...

	mov	bx,dx			; save the rowcount
	mov	ax,vxdots		; compute # of dots / pass
	shr	ax,1			;  (given 8 passes)
	shr	ax,1			;  ...
	shr	ax,1			;  ...
	mov	di,ax
	neg	di			; temp: to see if line will overflow
	mul	bx			; now calc first video addr
	cmp	dx,curbk		; see if bank changed
	jne	bank_is_changing	; if bank change call normaline
	cmp	ax,di
	ja	bank_is_changing	; if bank WILL change, call normaline

	mov	di,cx			; compute the starting destination
	shr	di,1			; divide by 8
	shr	di,1			;  ...
	shr	di,1			;  ...
	add	di,ax			; add the first pixel offset

	mov	dx,03ceh		; set up graphics cntrlr addr
	mov	ax,8008h		; set up for the bit mask
	and	cx,7			; adjust for the first pixel offset
	ror	ah,cl			;  ...

	pop	bx			; flush old DX value
	pop	bx			; flush old AX value
	pop	cx			; flush old CX value
	sub	bx,cx			; convert to a length value
	add	bx,si			; locate the last source locn

	mov	cx,ax			; save the bit mask

vgaline1:
	out	dx,ax			; set the graphics bit mask
	push	ax			; save registers for a tad
	push	si			;  ...
	push	di			;  ...
vgaline2:
	mov	ah,ds:[si]		; get the color
	mov	al,0			; set set/reset registers
	out	dx,ax			;  do it.
	mov	ax,0f01h		; enable set/reset registers
	out	dx,ax			;  do it.
	or	es:[di],al		; update all bit planes
	inc	di			; set up the next video addr
	add	si,8			;  and the next source addr
	cmp	si,bx			; are we beyond the end?
	jbe	vgaline2		; loop if more dots this pass
	pop	di			; restore the saved registers
	pop	si			;  ...
	pop	ax			;  ...
	inc	si			; offset the source 1 byte
	cmp	si,bx			; are we beyond the end?
	ja	vgaline4		; stop if no more dots this pass
	ror	ah,1			; alter bit mask value
	cmp	ah,80h			; time to update DI:
	jne	vgaline3		;  nope
	inc	di			;  yup
vgaline3:
	cmp	ah,ch			; already done all 8 of them?
	jne	vgaline1		;  nope.  do another one.
vgaline4:
;;;	call	videocleanup		; else cleanup time.
	ret				;  and we done.

bank_is_changing:
	pop	dx			; restore the registers
	pop	ax			;  ...
	pop	cx			;  ...
	call	normaline		; just calling newbank didn't quite
	ret				;  work. This depends on no bank
vgaline endp				;  change mid line (ok for 1024 wide)

vgareadline	proc	near		; Bank Switch EGA/VGA line read
	push	cx			; save a few registers
	push	ax			;  ...
	push	dx			;  ...

	mov	bx,dx			; save the rowcount
	mov	ax,vxdots		; compute # of dots / pass
	shr	ax,1			;  (given 8 passes)
	shr	ax,1			;  ...
	shr	ax,1			;  ...
	mul	bx			; now calc first video addr
	cmp	dx,curbk		; see if bank changed
	jne	bank_is_changing	; if bank change call normaline

	mov	si,cx			; compute the starting destination
	shr	si,1			; divide by 8
	shr	si,1			;  ...
	shr	si,1			;  ...
	add	si,ax			; add the first pixel offset

	and	cx,7			; adjust for the first pixel offset
	mov	ch,cl			; save the original offset value

	pop	bx			; flush old DX value
	pop	bx			; flush old AX value
	pop	ax			; flush old CX value
	sub	bx,ax			; convert to a length value
	add	bx,di			; locate the last dest locn

	mov	ax,0a000h		; EGA/VGA screen starts here
	mov	es,ax			;  ...

	mov	dx,03ceh		; set up graphics cntrlr addr

vgaline1:
	push	bx			; save BX for a tad
	mov	ch,80h			; bit mask to shift
	shr	ch,cl			;  ...
	mov	bx,0			; initialize bits-read value (none)
	mov	ax,0304h		; set up controller address register
vgareadloop:
	out	dx,ax			; do it
	mov	bh,es:[si]		; retrieve the old value
	and	bh,ch			; mask one bit
	neg	bh			; set bit 7 correctly
	rol	bx,1			; rotate the bit into bl
	dec	ah			; go for another bit?
	jge	vgareadloop		;  sure, why not.
	mov	ds:[di],bl		; returned pixel value
	pop	bx			; restore BX
	inc	di			; set up the next dest addr
	cmp	di,bx			; are we beyond the end?
	ja	vgaline3		;  yup.  We done.
	inc	cl			; alter bit mask value
	cmp	cl,8			; time to update SI:
	jne	vgaline2		;  nope
	inc	si			;  yup
	mov	cl,0			;  ...
vgaline2:
	jmp	short vgaline1		;  do another one.

vgaline3:
;;;	call	videocleanup		; else cleanup time.
	ret				;  and we done.

bank_is_changing:
	pop	dx			; restore the registers
	pop	ax			;  ...
	pop	cx			;  ...
	call	normalineread		; just calling newbank didn't quite
	ret				;  work. This depends on no bank
vgareadline	endp			;  change mid line (ok for 1024 wide)

super256lineaddr    proc    near		; super VGA 256 colors
	mov	ax,vxdots	 ; this many dots / line
	mov	bx,dx		 ; rowcount
	mul	bx		 ; times this many lines
	push	ax		 ; save pixel address for later
	cmp	dx,curbk	 ; bank ok?
	push	dx		 ; save bank
	je	bank_is_ok	 ; jump if bank ok
	mov	al,dl		 ; newbank needs bank in al
	call	far ptr newbank
bank_is_ok:
	inc	bx		 ; next row
	mov	ax,vxdots	 ; this many dots / line
	mul	bx		 ; times this many lines
	sub	ax,1		 ; back up some to the last pixel of the
	sbb	dx,0		 ; previous line
	pop	bx		 ; bank at start of row
	pop	ax		 ; ax = offset of row in video memory
	ret
super256lineaddr endp

super256line	proc	near		; super VGA 256 colors
	push	ax			; stop col
	push	dx			; row
	call super256lineaddr		; ax=video,dl=newbank,bl=oldbank
	mov	di,ax			; video offset
	cmp	dl,bl			; did bank change?
	pop	dx			; row
	pop	ax			; stop col
	jne	bank_did_chg
	add	di,cx			; add start col to video address
	sub	ax,cx			; ax = stop - start
	mov	cx,ax			;  + start column
	inc	cx			; number of bytes to move
	rep	movsb			; zap line into memory
	jmp	short linedone
bank_did_chg:
	call	normaline		; normaline can handle bank change
linedone:
	ret
super256line	endp

super256readline    proc    near     ; super VGA 256 colors
	push	ax			; stop col
	push	dx			; row
	call super256lineaddr		; ax=video,dl=newbank,bl=oldbank
	mov	si,ax			; video offset
	cmp	dl,bl			; did bank change?
	pop	dx			; row
	pop	ax			; stop col
	jne	bank_did_chg

	add	si,cx			; add start col to video address
	sub	ax,cx			; ax = stop - start
	mov	cx,ax			;  + start column
	inc	cx			; number of bytes to move
	mov	ax,ds			; save data segment to es
	mov	es,ax
	mov	ax,videomem		; video segment to es
	mov	ds,ax
	rep	movsb			; zap line into memory
	mov	ax,es			; restore data segment to ds
	mov	ds,ax
	jmp	short linedone
bank_did_chg:
	call	normalineread		; normaline can handle bank change
linedone:
	ret
super256readline    endp

tweak256line	proc	near		; Normal Line:	no assumptions
  local plane:byte
	mov	bx,ax			; bx = stop col
	sub	bx,cx			; bx = stop-start
	inc	bx			; bx = how many pixels to write
	cmp	bx,3			; less than four points?
	jg	nottoosmall		; algorithm won't work as written
	call	normaline		;  - give up and call normaline
	ret				; we done
nottoosmall:				; at least four points - go for it!
	push	bx			; save number of pixels
	and	bx,3			;  pixels modulo 4 = no of extra pts
	mov	ax,vxdots		; width of video row
;;	shr	ax, 1
;;	shr	ax, 1			; now ax = vxdots/4
	mul	dx			; ax points to start of desired row
	push	cx			; Save starting column for later
	shr	cx,1			; There are 4 pixels at each address
	shr	cx,1			;   so divide X by 4
	add	ax,cx			; Point to pixel's address
	mov	di,ax			; video offset of first point
	pop	cx			; Retrieve starting column
	and	cl,3			; Get the plane number of the pixel
	mov	ah,1
	shl	ah,cl			; Set the bit corresponding to the plane
					;  the pixel is in
	mov	plane,ah		; Save starting plane for ending test
	mov	al,MAP_MASK		;
	mov	dx,SC_INDEX
	pop	cx			; number of pixels to write
	shr	cx,1
	shr	cx,1			; cx = number of pixels/4
	cmp	bx,0			; extra pixels?
	je	tweak256line1		; nope - don't add one
	inc	cx			; yup - add one more pixel
tweak256line1:
	OUT	 DX,AX			; set up VGA registers for plane
	push	cx			; save registers changed by movsb
	push	si			;  ...
	push	di			;  ...
tweak256line2:
	movsb				; move the next pixel
	add	si,3			; adjust the source addr (+4, not +1)
	loop	tweak256line2		; loop if more dots this pass
	pop	di			; restore the saved registers
	pop	si			;  ...
	pop	cx			;  ...
	dec	bx			; one less extra pixel
	cmp	bx,0			; out of extra pixels?
	jne	noextra
	dec	cx			; yup - next time one fewer to write
noextra:
	inc	si			; offset the source 1 byte
	shl	ah,1			; set up for the next video plane
	cmp	ah,16			; at last plane?
	jne	notlastplane
	mov	ah,1			; start over with plane 0
	inc	di			; bump up video memory
notlastplane:
	cmp	ah,plane		; back to first plane?
	jne	tweak256line1		;  nope.  perform another loop.
	ret
tweak256line	endp

tweak256readline	proc	near		; Normal Line:	no assumptions
  local plane:byte
	mov	bx,ax			; bx = stop col
	sub	bx,cx			; bx = stop-start
	inc	bx			; bx = how many pixels to write
	cmp	bx,3			; less than four points?
	jg	nottoosmall		; algorithm won't work as written
	call	normalineread		;  - give up and call normalineread
	ret				; we done
nottoosmall:				; at least four points - go for it!
	push	bx			; save number of pixels
	and	bx,3			;  pixels modulo 4 = no of extra pts
	mov	ax,vxdots		; width of video row
;;	shr	ax, 1
;;	shr	ax, 1			; now ax = vxdots/4
	mul	dx			; ax points to start of desired row
	push	cx			; Save starting column for later
	shr	cx,1			; There are 4 pixels at each address
	shr	cx,1			;   so divide X by 4
	add	ax,cx			; Point to pixel's address
	mov	si,ax
	pop	cx			; Retrieve starting column
	and	cl,3			; Get the plane number of the pixel
	mov	ah,cl
	mov	plane,ah		; Save starting plane
	mov	al,READ_MAP
	mov	dx,GC_INDEX
	pop	cx			; number of pixels to write
	shr	cx,1
	shr	cx,1			; cx = number of pixels/4
	cmp	bx,0			; extra pixels?
	je	tweak256line1		; nope - don't add one
	inc	cx			; yup - add one more pixel
tweak256line1:
	out	dx,ax
	push	ax			; save registers
	push	cx			;  ...
	push	di			;  ...
	push	si			;  ...
	mov	ax,ds			; copy data segment to es
	mov	es,ax			;  ...
	mov	ax,videomem		; copy video segment to ds
	mov	ds,ax			;  ...
tweak256line2:
	movsb				; move the next pixel
	add	di,3			; adjust the source addr (+4, not +1)
	loop	tweak256line2		; loop if more dots this pass
	mov	ax,es
	mov	ds,ax			; restore data segement to ds
	pop	si			; restore the saved registers
	pop	di			;  ...
	pop	cx			;  ...
	pop	ax			;  ...
	dec	bx			; one less extra pixel
	cmp	bx,0			; out of extra pixels?
	jne	noextra
	dec	cx			; yup - next time one fewer to write
noextra:
	inc	di			; offset the source 1 byte
	inc	ah			; set up for the next video plane
	and	ah,3
	cmp	ah,0			; at last plane?
	jne	notlastplane
	inc	si			; bump up video memory
notlastplane:
	cmp	ah,plane		; back to first plane?
	jne	tweak256line1		;  nope.  perform another loop.
	ret
tweak256readline	endp


;f85line proc	near
;	call	fr85wbox	;put out the box
;	ret
;f85line endp

;f85readline proc    near
;	call	fr85rbox	;read the box
;	ret
;f85readline endp

; ******************** Function videocleanup() **************************

;	Called at the end of any assembler video read/writes to make
;	the world safe for 'printf()'s.
;	Currently, only ega/vga needs cleanup work, but who knows?
;

;;videocleanup	  proc	  near
;;	  mov	  ax,dotwrite		  ; check: were we in EGA/VGA mode?
;;	  cmp	  ax,offset vgawrite	  ;  ...
;;	  jne	  short videocleanupdone  ; nope.  no adjustments
;;	  mov	  dx,03ceh		  ; graphics controller address
;;	  mov	  ax,0ff08h		  ; restore the default bit mask
;;	  out	  dx,ax 		  ; ...
;;	  mov	  ax,0003h		  ; restore the function select
;;	  out	  dx,ax 		  ;  ...
;;	  mov	  ax,0001h		  ; restore the enable set/reset
;;	  out	  dx,ax 		  ;  ...
;;videocleanupdone:
;;	  ret
;;videocleanup	  endp


; ******************** Zoombox functions **************************

clearbox proc	 uses di si es
	mov	xorTARGA,1		; faster to flag xorTARGA rather
					; than check if TARGA is runnin

	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine

	mov	bx,boxcount		; load up a counter: # points to clear
	dec	bx			; switch to an offset value
eraseoldbox:
	shl	bx,1			; switch to a word pointer
	mov	cx,boxx[bx]		; get the (previous) point location
	mov	dx,boxy[bx]		;  ...
	shr	bx,1			; switch back to character pointer
	mov	al,boxvalues[bx]	; get the (previous) color
	push	bx			; save the counter
	call	dotwrite		; adjust the dot.
	pop	bx			; restore the counter
	dec	bx			; are we done yet?
	jns	eraseoldbox		;  nope.  try again.
	mov	xorTARGA,0		; in case of TARGA, no more xor
;;;	call	videocleanup		; perform any video cleanup required
	ret				; we done.
clearbox endp

dispbox proc	uses di si es
	mov	xorTARGA,1		; faster to flag xorTARGA rather
					; than check if TARGA is runnin

	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine

	mov	bx,boxcount		; load up a counter: # points to draw
	dec	bx			; switch to an offset
readnewbox:
	shl	bx,1			; switch to word counter
	mov	cx,boxx[bx]		; get the (new) point location
	mov	dx,boxy[bx]		;  ...
	shr	bx,1			; switch back to character counter
	push	bx			; save the counter
	call	dotread 		; read the (previous) dot value
	pop	bx			; restore the counter
	mov	boxvalues[bx],al	; get the (previous) color
	dec	bx			; are we done yet?
	jns	readnewbox		;  nope.  try again.
	mov	bx,boxcount		; load up a counter: # points to draw
	dec	bx			; switch to an offset
drawnewbox:
	shl	bx,1			; switch to word counter
	mov	cx,boxx[bx]		; get the (new) point location
	mov	dx,boxy[bx]		;  ...
	shr	bx,1			; switch back to character counter
	mov	ax,colors		; set the (new) box color
	dec	ax
	and	ax,boxcolor
	cmp	colors,2		; uhh, is this a B&W screen?
	jne	drawnewnotbw		;  nope.  proceed
	mov	al,1			; XOR the old color
	sub	al,boxvalues[bx]	;  for visibility
drawnewnotbw:
	push	bx			; save the counter
	call	dotwrite		; adjust the dot.
	pop	bx			; restore the counter
	dec	bx			; are we done yet?
	jns	drawnewbox		;  nope.  try again.
	mov	xorTARGA,0		; in case of TARGA, no more xor
;;;	call	videocleanup		; perform any video cleanup required
	ret				; we done.

dispbox endp


; ********************** Function setvideotext() ************************

;	Sets video to text mode, using setvideomode to do the work.

setvideotext	proc
	sub	ax,ax
	mov	dotmode,ax		; make this zero to avoid trouble
	push	ax
	push	ax
	push	ax
	mov	ax,3
	push	ax
	call	far ptr setvideomode	; (3,0,0,0)
	add	sp,8
	ret
setvideotext	endp


; **************** Function setvideomode(ax, bx, cx, dx) ****************

;	This function sets the (alphanumeric or graphic) video mode
;	of the monitor.   Called with the proper values of AX thru DX.
;	No returned values, as there is no particular standard to
;	adhere to in this case.

;	(SPECIAL "TWEAKED" VGA VALUES:  if AX==BX==CX==0, assume we have a
;	genuine VGA or register compatable adapter and program the registers
;	directly using the coded value in DX)

setvideomode	proc	uses di si es,argax:word,argbx:word,argcx:word,argdx:word

	mov	ax,sxdots		; initially, set the virtual line
	mov	vxdots,ax		; to be the scan line length

	cmp	dotmode, 29
	jne	NotTrueColorMode
	jmp	TrueColorAuto
NotTrueColorMode:
	cmp	diskflag,1		; is disk video active?
	jne	nodiskvideo		;  nope.
	call	far ptr enddisk 	; yup, external disk-video end routine
nodiskvideo:
	cmp	videoflag,1		; say, was the last video your-own?
	jne	novideovideo		;  nope.
	call	far ptr endvideo	; yup, external your-own end routine
	mov	videoflag,0		; set flag: no your-own-video
	jmp	short notarga
novideovideo:
	cmp	tgaflag,1		; TARGA MODIFIED 2 June 89 j mclain
	jne	notarga
	call	far ptr EndTGA		; endTGA( void )
	mov	tgaflag,0		; set flag: targa cleaned up
notarga:

	cmp	xga_isinmode,0		; XGA in graphics mode?
	je	noxga			; nope
	mov	ax,0			; pull it out of graphics mode
	push	ax
	mov	xga_clearvideo,al
	call	far ptr xga_mode
	pop	ax
noxga:

	cmp	f85flag, 1		; was the last video 8514?
	jne	no8514			; nope.
	cmp	ai_8514, 0		;check afi flag, JCO 4/11/92
	jne	f85endafi
	call	close8514hw		;use registers, JCO 4/11/92
	jmp	f85enddone
f85endafi:
	call	close8514		;use near afi, JCO 4/11/92
;	call	f85end		;use afi
f85enddone:
	mov	f85flag, 0
no8514:
	cmp	HGCflag, 1		; was last video Hercules
	jne	noHGC			; nope
	call	hgcend
	mov	HGCflag, 0
noHGC:
	mov	oktoprint,1		; say it's OK to use printf()
	mov	goodmode,1		; assume a good video mode
	mov	xga_loaddac,1		; tell the XGA to fake a 'loaddac'
	mov	ax,video_bankadr	; restore the results of 'whichvga()'
	mov	[bankadr],ax		;  ...
	mov	ax,video_bankseg	;  ...
	mov	[bankseg],ax		;  ...

	mov	ax,argax		; load up for the interrupt call
	mov	bx,argbx		;  ...
	mov	cx,argcx		;  ...
	mov	dx,argdx		;  ...

	mov	videoax,ax		; save the values for future use
	mov	videobx,bx		;  ...
	mov	videocx,cx		;  ...
	mov	videodx,dx		;  ...

	call	setvideo		; call the internal routine first

	cmp	goodmode,0		; is it still a good video mode?
	jne	videomodeisgood 	; yup.
	mov	ax,offset nullwrite	; set up null write-a-dot routine
	mov	bx,offset mcgaread	; set up null read-a-dot  routine
	mov	cx,offset normaline	; set up normal linewrite routine
	mov	dx,offset mcgareadline	; set up normal linewrite routine
	mov	si,offset swapnormread	; set up the normal swap routine
	jmp	videomode		; return to common code

videomodeisgood:
	mov	bx,dotmode		; set up for a video table jump
	cmp	bx,30			; are we within the range of dotmodes?
	jbe	videomodesetup		; yup.	all is OK
	mov	bx,0			; nope.  use dullnormalmode
videomodesetup:
	shl	bx,1			; switch to a word offset
	mov	bx,cs:videomodetable[bx]	; get the next step
	jmp	bx			; and go there
videomodetable	dw	offset dullnormalmode	; mode 0
	dw	offset dullnormalmode	; mode 1
	dw	offset vgamode		; mode 2
	dw	offset mcgamode 	; mode 3
	dw	offset tseng256mode	; mode 4
	dw	offset paradise256mode	; mode 5
	dw	offset video7256mode	; mode 6
	dw	offset tweak256mode	; mode 7
	dw	offset everex16mode	; mode 8
	dw	offset targaMode	; mode 9
	dw	offset hgcmode		; mode 10
	dw	offset diskmode 	; mode 11
	dw	offset f8514mode	; mode 12
	dw	offset cgamode		; mode 13
	dw	offset tandymode	; mode 14
	dw	offset trident256mode	; mode 15
	dw	offset chipstech256mode ; mode 16
	dw	offset ati256mode	; mode 17
	dw	offset everex256mode	; mode 18
	dw	offset yourownmode	; mode 19
	dw	offset ati1024mode	; mode 20
	dw	offset tseng16mode	; mode 21
	dw	offset trident16mode	; mode 22
	dw	offset video716mode	; mode 23
	dw	offset paradise16mode	; mode 24
	dw	offset chipstech16mode	; mode 25
	dw	offset everex16mode	; mode 26
	dw	offset VGAautomode	; mode 27
	dw	offset VESAmode 	; mode 28
	dw	offset TrueColorAuto	; mode 29
	dw	offset dullnormalmode	; mode 30
	dw	offset dullnormalmode	; mode 31

tandymode:	; from Joseph Albrecht
	mov	tandyseg,0b800h 	; set video segment address
	mov	tandyofs,0		; set video offset address
	mov	ax,offset plottandy16	; set up write-a-dot
	mov	bx,offset gettandy16	; set up read-a-dot
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	cmp	videoax,8		; check for 160x200x16 color mode
	je	tandy16low		; ..
	cmp	videoax,9		; check for 320x200x16 color mode
	je	tandy16med		; ..
	cmp	videoax,0ah		; check for 640x200x4 color mode
	je	tandy4high		; ..
	cmp	videoax,0bh		; check for 640x200x16 color mode
	je	tandy16high		; ..
tandy16low:
	mov	tandyscan,offset scan16k; set scan line address table
	jmp	videomode		; return to common code
tandy16med:
	mov	tandyscan,offset scan32k; set scan line address table
	jmp	videomode		; return to common code
tandy4high:
	mov	ax,offset plottandy4	; set up write-a-dot
	mov	bx,offset gettandy4	; set up read-a-dot
	jmp	videomode		; return to common code
tandy16high:
	mov	tandyseg,0a000h 	; set video segment address
	mov	tandyofs,8000h		; set video offset address
	mov	tandyscan,offset scan64k; set scan line address table
	jmp	videomode		; return to common code
dullnormalmode:
	mov	ax,offset normalwrite	; set up the BIOS write-a-dot routine
	mov	bx,offset normalread	; set up the BIOS read-a-dot  routine
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	jmp	videomode		; return to common code
mcgamode:
	mov	ax,offset mcgawrite	; set up MCGA write-a-dot routine
	mov	bx,offset mcgaread	; set up MCGA read-a-dot  routine
	mov	cx,offset mcgaline	; set up the MCGA linewrite routine
	mov	dx,offset mcgareadline	; set up the MCGA lineread  routine
	mov	si,offset swap256	; set up the MCGA swap routine
	jmp	videomode		; return to common code
tseng16mode:
	mov	tseng,1 		; set chipset flag
	mov	[bankadr],offset $tseng
	mov	[bankseg],seg $tseng
	jmp	vgamode 	; set ega/vga functions
trident16mode:
	mov	trident,1		; set chipset flag
	mov	[bankadr],offset $trident
	mov	[bankseg],seg $trident
	jmp	vgamode
video716mode:
	mov	video7,1		; set chipset flag
	mov	[bankadr],offset $video7
	mov	[bankseg],seg $video7
	jmp	vgamode
paradise16mode:
	mov	paradise,1		; set chipset flag
	mov	[bankadr],offset $paradise
	mov	[bankseg],seg $paradise
	jmp	vgamode
chipstech16mode:
	mov	chipstech,1		; set chipset flag
	mov	[bankadr],offset $chipstech
	mov	[bankseg],seg $chipstech
	jmp	vgamode
everex16mode:
	mov	everex,1		; set chipset flag
	mov	[bankadr],offset $everex
	mov	[bankseg],seg $everex
	jmp	vgamode
VESAmode:				; set VESA 16-color mode
	mov	ax,word ptr vesa_mapper
	mov	[bankadr],ax
	mov	ax,word ptr vesa_mapper+2
	mov	[bankseg],ax
VGAautomode:				; set VGA auto-detect mode
	cmp	colors,256		; 256 colors?
	je	VGAauto256mode		; just like SuperVGA
	cmp	xga_isinmode,0		; in an XGA mode?
	jne	xgamode
	cmp	colors,16		; 16 colors?
	je	vgamode 		; just like a VGA
	jmp	dullnormalmode		; otherwise, use the BIOS

xgamode:
	mov	ax,offset xga_16write	   ; set up XGA write-a-dot routine
	mov	bx,offset xga_16read	   ; set up XGA read-a-dot  routine
	mov	cx,offset xga_16linewrite  ; set up the XGA linewrite routine
	mov	dx,offset normalineread    ; set up the XGA lineread  routine
	mov	si,offset swap256	   ; set up the swap routine
	jmp	videomode		   ; return to common code

VGAauto256mode:
	jmp	super256mode		; just like a SuperVGA
egamode:
vgamode:
;;;	shr	vxdots,1		; scan line increment is in bytes...
;;;	shr	vxdots,1
;;;	shr	vxdots,1
	mov	ax,offset vgawrite	; set up EGA/VGA write-a-dot routine.
	mov	bx,offset vgaread	; set up EGA/VGA read-a-dot  routine
	mov	cx,offset vgaline	; set up the EGA/VGA linewrite routine
	mov	dx,offset vgareadline	; set up the EGA/VGA lineread  routine
	mov	si,offset swapvga	; set up the EGA/VGA swap routine
	jmp	videomode		; return to common code
tseng256mode:
	mov	tseng,1 		; set chipset flag
	mov	[bankadr],offset $tseng
	mov	[bankseg],seg $tseng
	jmp	super256mode		; set super VGA linear memory functions
paradise256mode:
	mov	paradise,1		; set chipset flag
	mov	[bankadr],offset $paradise
	mov	[bankseg],seg $paradise
	jmp	super256mode		; set super VGA linear memory functions
video7256mode:
	mov	video7, 1		; set chipset flag
	mov	[bankadr],offset $video7
	mov	[bankseg],seg $video7
	jmp	super256mode		; set super VGA linear memory functions
trident256mode:
	mov	trident,1		; set chipset flag
	mov	[bankadr],offset $trident
	mov	[bankseg],seg $trident
	jmp	super256mode		; set super VGA linear memory functions
chipstech256mode:
	mov	chipstech,1		; set chipset flag
	mov	[bankadr],offset $chipstech
	mov	[bankseg],seg $chipstech
	jmp	super256mode		; set super VGA linear memory functions
ati256mode:
	mov	ativga,1		; set chipset flag
	mov	[bankadr],offset $ativga
	mov	[bankseg],seg $ativga
	jmp	super256mode		; set super VGA linear memory functions
everex256mode:
	mov	everex,1		; set chipset flag
	mov	[bankadr],offset $everex
	mov	[bankseg],seg $everex
	jmp	super256mode		; set super VGA linear memory functions
VGA256automode: 			; Auto-detect SuperVGA
	jmp	super256mode		; set super VGA linear memory functions
VESA256mode:				; set VESA 256-color mode
	mov	ax,word ptr vesa_mapper
	mov	[bankadr],ax
	mov	ax,word ptr vesa_mapper+2
	mov	[bankseg],ax
	jmp	super256mode		; set super VGA linear memory functions
super256mode:
	mov	ax,offset super256write ; set up superVGA write-a-dot routine
	mov	bx,offset super256read	; set up superVGA read-a-dot  routine
	mov	cx,offset super256line	; set up the  linewrite routine
	mov	dx,offset super256readline ; set up the normal lineread  routine
	mov	si,offset swap256	; set up the swap routine
	jmp	videomode		; return to common code
tweak256mode:
	shr	vxdots,1		; scan line increment is in bytes...
	shr	vxdots,1
	mov	oktoprint,0		; NOT OK to printf() in this mode
	mov	ax,offset tweak256write ; set up tweaked-256 write-a-dot
	mov	bx,offset tweak256read	; set up tweaked-256 read-a-dot
	mov	cx,offset tweak256line	; set up tweaked-256 read-a-line
	mov	dx,offset tweak256readline ; set up the normal lineread  routine
	mov	si,offset swapvga	; set up the swap routine
	jmp	videomode		; return to common code
cgamode:
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	cmp	videoax,4		; check for 320x200x4 color mode
	je	cga4med 		; ..
	cmp	videoax,5		; ..
	je	cga4med 		; ..
	cmp	videoax,6		; check for 640x200x2 color mode
	je	cga2high		; ..
cga4med:
	mov	ax,offset plotcga4	; set up CGA write-a-dot
	mov	bx,offset getcga4	; set up CGA read-a-dot
	jmp	videomode		; return to common code
cga2high:
	mov	ax,offset plotcga2	; set up CGA write-a-dot
	mov	bx,offset getcga2	; set up CGA read-a-dot
	jmp	videomode		; return to common code
ati1024mode:
	mov	ativga,1		; set ATI flag.
	mov	ax,offset ati1024write	; set up ATI1024 write-a-dot
	mov	bx,offset ati1024read	; set up ATI1024 read-a-dot
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swap256	; set up the swap routine
	jmp	videomode		; return to common code
diskmode:
	call	far ptr startdisk	; external disk-video start routine
	mov	ax,offset diskwrite	; set up disk-vid write-a-dot routine
	mov	bx,offset diskread	; set up disk-vid read-a-dot routine
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	jmp	videomode		; return to common code
yourownmode:
	call	far ptr startvideo	; external your-own start routine
	mov	ax,offset videowrite	; set up ur-own-vid write-a-dot routine
	mov	bx,offset videoread	; set up ur-own-vid read-a-dot routine
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	mov	videoflag,1		; flag "your-own-end" needed.
	jmp	videomode		; return to common code
targaMode:				; TARGA MODIFIED 2 June 89 - j mclain
	call	far ptr StartTGA
	mov	ax,offset tgawrite	;
	mov	bx,offset tgaread	;
	mov	cx,offset normaline	; set up the normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	mov	tgaflag,1		;
	jmp	videomode		; return to common code
f8514mode:				; 8514 modes
	cmp	ai_8514, 0		; check if afi flag is set, JCO 4/11/92
	jne	f85afi		; yes, try afi
	call	open8514hw		; start the 8514a, try registers first JCO
	jnc	f85ok
	mov	ai_8514, 1		; set afi flag
f85afi:
	call	open8514		; start the 8514a, try afi
	jnc	f85ok
	mov	ai_8514, 0		; clear afi flag, JCO 4/11/92
	mov	goodmode,0		; oops - problems.
	mov	dotmode, 0		; if problem starting use normal mode
	jmp	dullnormalmode
hgcmode:
	mov	oktoprint,0		; NOT OK to printf() in this mode
	call	hgcstart		; Initialize the HGC card
	mov	ax,offset hgcwrite	; set up HGC write-a-dot routine
	mov	bx,offset hgcread	; set up HGC read-a-dot  routine
	mov	cx,offset normaline	; set up normal linewrite routine
	mov	dx,offset normalineread ; set up the normal lineread  routine
	mov	si,offset swapnormread	; set up the normal swap routine
	mov	HGCflag,1		; flag "HGC-end" needed.
	jmp	videomode		; return to common code
f85ok:
	cmp	ai_8514, 0
	jne	f85okafi			; afi flag is set JCO 4/11/92
	mov	ax,offset fr85hwwdot	;use register routines
	mov	bx,offset fr85hwrdot	;changed to near calls
	mov	cx,offset fr85hwwbox	;
	mov	dx,offset fr85hwrbox	;
	mov	si,offset swapnormread	; set up the normal swap routine
	mov	f85flag,1		;
	mov	oktoprint,0		; NOT OK to printf() in this mode
	jmp	videomode		; return to common code
f85okafi:
	mov	ax,offset fr85wdot	;use afi routines, JCO 4/11/92
	mov	bx,offset fr85rdot	;changed to near calls
	mov	cx,offset fr85wbox	;
	mov	dx,offset fr85rbox	;
	mov	si,offset swapnormread	; set up the normal swap routine
	mov	f85flag,1		;
	mov	oktoprint,0		; NOT OK to printf() in this mode
	jmp	videomode		; return to common code
TrueColorAuto:
	cmp	TPlusInstalled, 1
	jne	NoTPlus
	push	NonInterlaced
	push	PixelZoom
	push	MaxColorRes
	push	ydots
	push	xdots
	call	far ptr MatchTPlusMode
	add	sp, 10
	or	ax, ax
	jz	NoTrueColorCard

	cmp	ax, 1			  ; Are we limited to 256 colors or less?
	jne	SetTPlusRoutines	  ; All right! True color mode!

	mov	cx, MaxColorRes 	  ; Aw well, give'm what they want.
	shl	ax, cl
	mov	colors, ax

SetTPlusRoutines:
	mov	goodmode, 1
	mov	oktoprint, 1
	mov	ax, offset TPlusWrite
	mov	bx, offset TPlusRead
	mov	cx, offset normaline
	mov	dx, offset normalineread
	mov	si, offset swapnormread
	jmp	videomode

NoTPlus:
NoTrueColorCard:
	mov	goodmode, 0
	jmp	videomode

videomode:
	mov	dotwrite,ax		; save the results
	mov	dotread,bx		;  ...
	mov	linewrite,cx		;  ...
	mov	lineread,dx		;  ...
	mov	word ptr swapsetup,si	;  ...
	mov	ax,cs			;  ...
	mov	word ptr swapsetup+2,ax ;  ...

	mov	ax,colors		; calculate the "and" value
	dec	ax			; to use for eventual color
	mov	andcolor,ax		; selection

	mov	boxcount,0		; clear the zoom-box counter

	mov	daclearn,0		; set the DAC rotates to learn mode
	mov	daccount,6		; initialize the DAC counter
	cmp	cpu,88			; say, are we on a 186/286/386?
	jbe	setvideoslow		;  boo!  hiss!
	mov	daclearn,1		; yup.	bypass learn mode
	mov	ax,cyclelimit		;  and go as fast as he wants
	mov	daccount,ax		;  ...
setvideoslow:
	call	far ptr loaddac 	; load the video dac, if we can
	ret
setvideomode	endp

set_vesa_mapping_func proc near
	mov	cx, word ptr suffix+2
	and	cx,0707h
	cmp	cx,0305h
	je	use_vesa2
	cmp	cx,0503h
	je	use_vesa2
	test	ch,01h
	jz	use_vesa1
	cmp	word ptr suffix+6,32	; None of the above -- 2 32K R/W?
	jne	use_vesa1		;    if not, use original 1 64K R/W!
	mov	word ptr vesa_mapper,offset $vesa3
	mov	ax,32
	div	byte ptr suffix+4	; Get number of pages in 32K
	mov	vesa_gran_offset,ax	; Save it for mapping function
	xor	dx,dx
	mov	al,1
	test	word ptr suffix+8, 00800h
	jz	low_high_seq
	xchg	ax,dx
low_high_seq:
	mov	vesa_low_window,dx	; Window number at A000-A7FF
	mov	vesa_high_window,ax	; Window number at A800-AFFF
	jmp	short vesamapselected
use_vesa2:
	mov	word ptr vesa_mapper,offset $vesa2
	jmp	short vesamapselected
use_vesa1:
	mov	word ptr vesa_mapper,offset $vesa1
vesamapselected:
	mov	word ptr vesa_mapper+2,seg $vesa1
	ret
set_vesa_mapping_func endp


setnullvideo proc
	mov	ax,offset nullwrite	; set up null write-a-dot routine
	mov	dotwrite,ax		;  ...
	mov	ax,offset nullread	; set up null read-a-dot routine
	mov	dotread,ax		;  ...
	ret
setnullvideo endp

setvideo	proc	near		; local set-video more

	cmp	xga_isinmode,0		; XGA in graphics mode?
	je	noxga			; nope
	push	ax
	push	bx
	push	cx
	push	dx
	mov	ax,0			; pull it out of graphics mode
	push	ax
	mov	xga_clearvideo,al
	call	far ptr xga_mode
	pop	ax
	pop	dx
	pop	cx
	pop	bx
	pop	ax
noxga:

	push	bp			; save it around all the int 10s
	mov	text_type,2		; set to this for most exit paths
	mov	si,offset $vesa_nullbank ; set to do nothing if mode not vesa
	mov	word ptr vesa_bankswitch,si
	mov	si,seg $vesa_nullbank
	mov	word ptr vesa_bankswitch+2,si
	mov	word ptr vesa_mapper,offset $nobank
	mov	word ptr vesa_mapper+2,seg $nobank
	mov	tweakflag,0

	cmp	ax,0			; TWEAK?:  look for AX==BX==CX==0
	jne	short setvideobios	;  ...
	cmp	bx,0			;  ...
	jne	short setvideobios	;  ...
	cmp	cx,0			;  ...
	jne	short setvideobios	;  ...

	cmp	dotmode, 27		; check for auto-detect modes
	je	setvideoauto1
	cmp	dotmode, 20		; check for auto-detect modes
	je	setvideoauto1
	cmp	dotmode, 4		; check for auto-detect modes
	je	setvideoauto1
	cmp	dotmode, 28		; check for auto-detect modes
	je	setvideoauto1

	jmp	setvideoregs		; anything else - assume register tweak

setvideoauto1:
	jmp	setvideoauto		; stupid short 'je' instruction!!

setvideobios:
	mov	text_type,0		; if next branch taken this is true
	cmp	ax,3			; text mode?
	jne	setvideobios2		;  nope
	mov	textaddr,0b800h
	cmp	mode7text,0		; egamono/hgc?
	je	setvideobios_doit	;  nope.  Just do it.
	mov	textaddr,0b000h
	mov	ax,7			; use mode 7
	call	maybeor 		; maybe or AL or (for Video-7s) BL
	push	bp			; weird but necessary, set mode twice
	int	10h			;  get colors right on vga systems
	pop	bp			;  ..
	mov	ax,7			; for the 2nd hit
	jmp	short setvideobios_doit
setvideobios2:
	mov	text_type,1		; if next branch taken this is true
	cmp	ax,6			; 640x200x2 mode?
	je	setvideobios_doit	;  yup.  Just do it.
	mov	text_type,2		; not mode 3 nor 6, so this is true
	mov	si,dotmode		; compare the dotmode against
	mov	di,video_type		; the video type
	add	si,si			; (convert to a word pointer)
	cmp	cs:video_requirements[si],di
	jbe	setvideobios_doit	; ok
	jmp	setvideoerror		;  Error.
setvideobios_doit:
	cmp	dotmode,14		; check for Tandy 1000 mode
	jne	setvideobios_doit2	; ..
	cmp	ax,0ah			; check for Tandy 640x200x4 color mode
	jne	setvideobios_doit1	; ..
	push	bp			; setup Tandy 640x200x4 color mode
	int	10h			; ..
	pop	bp			; ..
	mov	di,16			;port offset for palette registers
	mov	bx,0b01h		; remap colors for better display on
	call	settandypal		; .. Tandy 640x200x4 color mode
	mov	di,16			;port offset for palette registers
	mov	bx,0d02h		; ..
	call	settandypal		; ..
	mov	di,16			;port offset for palette registers
	mov	bx,0f03h		; ..
	call	settandypal		; ..
	jmp	setvideobios_worked
setvideobios_doit1:
	cmp	ax,0bh			; check for Tandy 640x200x16 color mode
	jne	setvideobios_doit2	; ..
	call	tandysetup		; setup Tandy 640x200x16 color mode
	jmp	setvideobios_worked
setvideobios_doit2:
	call	maybeor 		; maybe or AL or (for Video-7s) BL
	push	bp			; some BIOS's don't save this
	int	10h			; do it via the BIOS.
	pop	bp			; restore the saved register
	cmp	dotmode,28		; VESA mode?
	jne	setvideobios_worked	;  Nope. Return.
	cmp	ah,0			; did it work?
	jne	setvideoerror		;  Nope. Failed.
	mov	vesa_granularity,1	; say use 64K granules
	push	es			; set ES == DS
	mov	ax,ds			;  ...
	mov	es,ax			;  ...
	mov	ax,4f01h		; ask about this video mode
	mov	cx,bx			;  this mode
	and	cx,07fffh		; (oops - correct for the high-bit)
	mov	di, offset suffix	; (a safe spot for 256 bytes)
	int	10h			; do it
	cmp	ax,004fh		; did the call work?
	jne	nogoodvesamode		;  nope
	mov	cx, word ptr suffix	; get the attributes
	test	cx,1			; available video mode?
	jz	nogoodvesamode		; nope.  skip some code
	call	set_vesa_mapping_func
	mov	cx, word ptr suffix+12	; get the Bank-switching routine
	mov	word ptr vesa_bankswitch, cx  ;  ...
	mov	cx, word ptr suffix+14	;   ...
	mov	word ptr vesa_bankswitch+2, cx	;  ...
	mov	cx, word ptr suffix+16	; get the bytes / scan line
	cmp	cx,0			; is this entry filled in?
	je	skipvesafix		;  nope
;;;	cmp	colors,256		; 256-color mode?
;;;	jne	skipvesafix		;  nope
	cmp	byte ptr suffix+24,1
	jbe	store_vesa_bytes
	shl	cx,1			; if a planar mode, bits are pixels
	shl	cx,1			; so we multiply bytes by 8
	shl	cx,1
store_vesa_bytes:
	mov	vxdots,cx		; adjust the screen width accordingly XXX
;       cmp     cx,sxdots               ; 8/93 JRS textsafe=save fix
;       je      skipvesafix
;       mov     ax,offset swapnormread  ; use the slow swap routine
;       mov     word ptr swapsetup,ax   ;  ...
skipvesafix:
	mov	cx, word ptr suffix+4	; get the granularity
	cmp	cl,1			; ensure the divide won't blow out
	jb	nogoodvesamode		;  granularity == 0???
	mov	ax,64			;  ...
	div	cl			; divide 64K by granularity
	mov	vesa_granularity,al	; multiply the bank number by this
nogoodvesamode:
	pop	es			; restore ES
	mov	ax,4f02h		; restore the original call
setvideobios_worked:
	jmp	setvideoreturn		;  Return.

setvideoerror:				; oops.  No match found.
	mov	goodmode,0		; note that the video mode is bad
	mov	ax,3			; switch to text mode
	jmp	setvideobios_doit

setvideoauto:
	mov	si, video_entries	; look for the correct resolution
	sub	si,8			; get a running start
setvideoloop:
	add	si,10			; get next entry
	mov	ax,cs:0[si]		; check X-res
	cmp	ax,0			; anything there?
	je	setvideoerror		; nope.  No match
	cmp	ax,sxdots
	jne	setvideoloop
	mov	ax,cs:2[si]		; check Y-res
	cmp	ax,sydots
	jne	setvideoloop
	mov	ax,cs:4[si]		; check Colors
	cmp	ax,colors
	jne	setvideoloop
	mov	ax,cs:6[si]		; got one!  Load AX
	mov	bx,cs:8[si]		;	    Load BX

	cmp	ax,0ffffh		; XGA special?
	jne	notxgamode
	mov	al,orvideo
	mov	xga_clearvideo,al
	cmp	al,0			; clearing the video?
	jne	xgask1			;  yup
	mov	ax,03h			; switch to text mode (briefly)
	int	10h
xgask1:
	push	bx
	call	far ptr xga_mode
	pop	bx
	cmp	ax,0
	je	setvideoloop
	jmp	setvideoreturn
notxgamode:

	cmp	bx,0ffh 		; ATI 1024x768x16 special?
	jne	notatimode
	mov	dotmode,20		; Convert to ATI specs
	mov	al,65h
	mov	bx,0
	jmp	setvideobios
notatimode:
	cmp	bx,0feh 		; Tseng 640x400x256 special?
	jne	nottsengmode
	mov	ax,0			; convert to Tseng specs
	mov	bx,0
	mov	cx,0
	mov	dx,10
	mov	dotmode,4
	jmp	setvideoregs
nottsengmode:
	cmp	bx,0fdh 		; Compaq 640x480x256 special?
	jne	notcompaqmode
	mov	vxdots,1024		; (compaq uses 1024-byte scanlines)
	mov	bx,offset swapnormread	; use the slow swap routine
	mov	word ptr swapsetup,bx	;  ...
	mov	bx,0
	jmp	setvideobios
notcompaqmode:
	cmp	ax,4f02h		; VESA mode?
	jne	notvesamode
	mov	dotmode,28		; convert to VESA specs
notvesamode:
	jmp	setvideobios

setvideoregs:				; assume genuine VGA and program regs
	mov	si, dotmode		; compare the dotmode against
	mov	di,video_type		; the video type
	add	si,si			; (convert to a word pointer)
	cmp	cs:video_requirements[si],di
	jbe	setvideoregs_doit	;  good value.	Do it.
	jmp	setvideoerror		;  bad value.  Error.
setvideoregs_doit:
	mov	si,dx			; get the video table offset
	shl	si,1			;  ...
	mov	si,word ptr tweaks[si]	;  ...

	mov	tweaktype, dx		; save tweaktype
	cmp	dx,8			; 360x480 tweak256mode?
	je	isatweaktype		; yup
	cmp	dx,9			; 320x400 tweak256mode?
	je	isatweaktype		; yup
	cmp	dx,18			; 320x480 tweak256mode?
	je	isatweaktype		; yup
	cmp	dx,19			; 320x240 tweak256mode?
	je	isatweaktype		; yup
	cmp	dx,10			; Tseng tweak?
	je	tsengtweak		; yup
;Patch - Michael D. Burkey (5/22/90)
	cmp	dx,14			; ATI Mode Support
	je	ATItweak
	cmp	dx,15
	je	ATItweak
	cmp	dx,16
	je	ATItweak
	cmp	dx,17
	je	ATItweak2		; ATI 832x616 mode
	cmp	dx,11			; tweak256mode? (11 & up)
	jae	isatweaktype		; yup
;End Patch
	jmp	not256			; nope none of the above
tsengtweak:
	mov	ax,46			; start with S-VGA mode 2eh
	call	maybeor 		; maybe don't clear the video memory
	int	10h			; let the bios clear the video memory
	mov	dx,3c2h 		; misc output
	mov	al,063h 		; dot clock
	out	dx,al			; select it
	mov	dx,3c4h 		; sequencer again
	mov	ax,0300h		; restart sequencer
	out	dx,ax			; running again
	jmp	is256;
ATItweak:
	mov	ax,62h
;; pb, why no maybeor call here?
	int	10h
	mov	dx,3c2h
	mov	al,0e3h
	out	dx,al
	mov	dx,3c4h
	mov	ax,0300h
	out	dx,ax
	jmp	is256

ATItweak2:
	mov	ax,63h
;; pb, why no maybeor call here?
	int	10h
	mov	dx,3c4h
	mov	ax,0300h
	out	dx,ax
	jmp	is256

isatweaktype:
	mov	tweakflag,1
	mov	ax,0013h		; invoke video mode 13h
	call	maybeor 		; maybe or AL or (for Video-7s) BL
	int	10h			; do it

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

	cmp	orvideo,0		; are we supposed to clear RAM?
	jne	noclear256		;  (nope)

	mov	dx,03c4h		; alter sequencer registers
	mov	ax,0f02h		; enable writes to all planes
	OUT_WORD

	push	es			; save ES for a tad
	mov	ax,VGA_SEGMENT		; clear out all 256K of
	mov	es,ax			;  video memory
	sub	di,di			;  (64K at a time, but with
	mov	ax,di			;  all planes enabled)
	mov	cx,8000h		;# of words in 64K
	cld
	rep stosw			;clear all of display memory
	pop	es			; restore ES

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

	jmp	short is256		; forget the ROM characters

not256:

	mov	ax,0012h		; invoke video mode 12h
	call	maybeor 		; maybe or AL or (for Video-7s) BL
	int	10h			; do it.

is256:	push	es			; save ES for a tad
	mov	ax,40h			; Video BIOS DATA area
	mov	es,ax			;  ...

	mov	dx,word ptr es:[63h]	; say, where's the 6845?
	add	dx,6			; locate the status register
vrdly1: in	al,dx			; loop until vertical retrace is off
	test	al,8			;   ...
	jnz	vrdly1			;   ...
vrdly2: in	al,dx			; now loop until it's on!
	test	al,8			;   ...
	jz	vrdly2			;   ...

	cli				; turn off all interrupts
	mov	dx,tweaktype
	cmp	dx,9			; 320x400 mode?
	je	not256mode		; yup - skip this stuff
	cmp	dx,10			; Tseng tweak mode?
	je	not256mode		; yup - skip this stuff
;patch #2 (M. Burkey 5/22/90)
	cmp	dx,17			; for 832x616 ATI Mode
	je	not256mode
;patch end
	mov	cl,0E7h 		; value for misc output reg
	cmp	dx,18			; 320x480 mode?
	je	setmisc320		;  nope, use above value
	cmp	dx,19			; 320x240 mode?
	jne	setmiscoreg		;  nope, use above value
setmisc320:
	mov	cl,0E3h 		; value for misc output reg
setmiscoreg:
	mov	dx,03c4h		; Sequencer Synchronous reset
	mov	ax,0100h		; set sequencer reset
	out	dx,ax
	mov	dx,03c2h		; Update Misc Output Reg
	mov	al,cl
	out	dx,al
	mov	dx,03c4h		; Sequencer Synchronous reset
	mov	ax,0300h		; clear sequencer reset
	out	dx,ax
not256mode:
	mov	dx,word ptr es:[63h]	; say, where's the 6845?
	add	si,2			; point SI to the CRTC registers table
	mov	al,11h			; deprotect registers 0-7
	mov	ah,byte ptr [si+11h]
	and	ah,7fh
	out	dx,ax

	mov	cx,18h			; update this many registers
	mov	bx,00			; starting with this one.
crtcloop:
	mov	al,bl			; update this register
	mov	ah,byte ptr [bx+si]	; to this
	out	dx,ax
	inc	bx			; ready for the next register
	loop	crtcloop		; (if there is a next register)
	sti				; restore interrupts

	pop	es			; restore ES

setvideoreturn:
	mov	curbk,0ffffh		; stuff impossible value into cur-bank
	mov	orvideo,0		; reset the video to clobber memory
	pop	bp
	ret
setvideo	endp

maybeor proc	near			; or AL or BL for mon-destr switch
	cmp	ah,4fh			; VESA special mode?
	je	maybeor2		;  yup.  Do this one different
	cmp	ah,6fh			; video-7 special mode?
	je	maybeor1		;  yup.  do this one different
	or	al,orvideo		; normal non-destructive switch
	jmp	short maybeor99 	; we done.
maybeor1:
	or	bl,orvideo		; video-7 switch
	jmp	short maybeor99
maybeor2:
	or	bh,orvideo		; VESA switch
maybeor99:
	ret				; we done.
maybeor endp


; ********* Functions setfortext() and setforgraphics() ************

;	setfortext() resets the video for text mode and saves graphics data
;	setforgraphics() restores the graphics mode and data
;	setclear() clears the screen after setfortext()

monocolors db  0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

setfortext	proc	uses es si di
	push	bp			; save it around the int 10s
	cmp	dotmode, 12		;check for 8514
	jne	tnot8514
	cmp	f85flag, 0		;check 8514 active flag
	je	go_dosettext
	cmp	ai_8514, 0		;using registers? JCO 4/11/92
	jne	not85reg
	call	close8514hw		;close adapter if not, with registers
	jmp	done85close
not85reg:
	call	close8514		;close adapter if not, with afi
done85close:
	mov	f85flag, 0
go_dosettext:
	jmp	dosettext		; safe to go to mode 3
tnot8514:
	cmp	dotmode,9		; Targa?
	je	go_dosettext		;  yup, leave it open & go to text

	cmp	xga_isinmode,0		; XGA in graphics mode?
	je	noxga			;  nope
	mov	ax,xga_isinmode 	; remember if we were in XGA mode
	mov	xga_clearvideo,80h	; don't clear the video!
	mov	ax,0			; switch to VGA (graphics) mode
	push	ax
	call	far ptr xga_mode
	pop	ax			; proceed on like nothing happened
	mov	xga_clearvideo,0	; reset the clear-video flag
noxga:

	cmp	dotmode,14		; (klooge for Tandy 640x200x16)
	je	setfortextcga
	cmp	videoax,0		; check for CGA modes
	je	go_setfortextnocga	;  not this one
	cmp	dotmode,10		; Hercules?
	je	setfortextcga		;  yup
	cmp	videoax,7		; <= vid mode 7?
	jbe	setfortextcga		;  yup
go_setfortextnocga:
	jmp	setfortextnocga 	;  not this one
setfortextcga:	; from mode ensures we can go to mode 3, so do it
	mov	ax,extraseg		; set ES == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	es,ax			;  ...
	mov	di,4000h		; save the video data here
	mov	ax,0b800h		; video data starts here <XXX>
	mov	si,0			;  ...
	cmp	videoax,3		; from mode 3?
	jne	setfortextcga2		;  nope
	cmp	mode7text,0		; egamono/hgc?
	je	setfortextcga2		;  nope
	mov	ax,0b000h		; video data starts here
setfortextcga2:
	mov	cx,2000h		; save this many words
	cmp	dotmode,10		; Hercules?
	jne	setfortextcganoherc	;  nope
	mov	di,0			; (save 32K)
	mov	ax,0b000h		; (from here)
	mov	cx,4000h		; (save this many words)
setfortextcganoherc:
	cmp	dotmode,14		; check for Tandy 1000 specific modes
	jne	setfortextnotandy	; ..
	mov	ax,tandyseg		; video data starts here
	mov	si,tandyofs		; save video data here
	mov	di,0			; save the video data here
	mov	cx,4000h		; save this many words
setfortextnotandy:
	push	ds			; save DS for a tad
	mov	ds,ax			;  reset DS
	cld				; clear the direction flag
	rep	movsw			;  save them.
	pop	ds			; restore DS
	cmp	dotmode,10		; Hercules?
	jne	dosettext		;  nope
	cmp	HGCflag, 0		; check HGC active flag
	je	dosettext
	call	hgcend			; close adapter
	mov	HGCflag, 0
dosettext:
	mov	ax,3			; set up the text call
	mov	bx,0			;  ...
	mov	cx,0			;  ...
	mov	dx,0			;  ...
	call	setvideo		; set the video
	jmp	setfortextreturn
setfortextnocga:
	mov	bios_vidsave,0		; default, not using bios for state save
	mov	ax,textsafe2		; videotable override?
	cmp	ax,0			;  ...
	jne	setfortextsafe		;  yup
	mov	ax,textsafe		; nope, use general setting
setfortextsafe:
	cmp	ax,2			; textsafe=no?
	jne	setforcolortext 	;  nope
	jmp	setfordummytext 	;  yup, use 640x200x2
setforcolortext:
	; must be ega, mcga, or vga, else we'd have set textsafe=no in runup
	cmp	ax,4			; textsafe=save?
	jne	setforcolortext2	;  nope
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	call	far ptr savegraphics	; C rtn which uses swapsetup
	call	swapvga_reset		; some cleanup for swapvga case
	mov	orvideo,80h		; preserve memory, just for speed
	cmp	videoax,0fh		; ega 640x350x2?
	jne	dosettext		;  nope, go call bios for mode 3
	mov	ax,83h			; I know this is silly! have to set
	int	10h			; mode twice when coming from mode 0fh
	jmp	dosettext		; on some machines to get right colors
setforcolortext2:
	cmp	ax,3			; textsafe=bios?
	jne	setforcolortext3	;  nope
	cmp	video_type,5		; vga?
	jl	setforcolortext3	;  nope
	mov	ax,1c00h		; check size of reqd save area
	mov	cx,3			;  for hardware + bios states
	int	10h			;  ask...
	cmp	al,1ch			; function recognized?
	jne	setforcolortext3	;  nope
	cmp	bx,4			; buffer big enough? (3 seems usual)
	ja	setforcolortext3	;  nope
	mov	bios_vidsave,1		; using bios to save vid state
	mov	ax,cs			; ptr to save buffer
	mov	es,ax			;  ...
	mov	bx,offset bios_savebuf	;  ...
	mov	ax,1c01h		;  save state
	mov	cx,3			;  hardware + bios
	int	10h			;  ...
setforcolortext3:
	push	ds			; save ds
	mov	ax,extraseg		; set ES == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	es,ax			;  ...
	cld
	mov	ax,0a000h		; video mem address
	cmp	video_type,4		; mcga?
	jne	setfortextegavga	;  nope
	mov	ds,ax			; set ds to video mem
	xor	di,di			; from vid offset 0
	xor	si,si			; to save offset 0
	mov	cx,1000h		; save 4k words
	rep movsw			; font info
	mov	si,8000h		; from vid offset 8000h
	mov	cx,0800h		; save 2k words
	rep movsw			; characters and attributes
	pop	ds			; restore ds
	mov	orvideo,80h		; set the video to preserve memory
	jmp	dosettext		; (else more than we saved gets cleared)
setfortextegavga:
	sub	ax,ax			; set bank just in case
	call far ptr newbank
	mov	ax,8eh			; switch to a mode with known mapping
	cmp	videoax,0fh		; coming from ega 640x350x2?
	jne	sftknownmode		;  nope
	mov	ax,8fh			; yup, stay in it but do the set mode
sftknownmode:
	int	10h			; set the safe mode
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	mov	ax,0a000h		; video mem address
	mov	ds,ax			; set ds to video mem
	xor	di,di			; to offset 0 in save area
;;	mov	cx,0			; set to plane 0
;;	call	select_vga_plane	;  ...
;;	mov	cx,0800h		; save 2k words
;;	xor	si,si			; from offset 0 in vid mem
;;	rep movsw			; save plane 0 2k bytes (char values)
	mov	cx,2			; set to plane 2
	call	select_vga_plane	;  ...
	mov	cx,1000h		; save 4k words
	xor	si,si			; from offset 0 in vid mem
	rep movsw			; save plane 2 8k bytes (font)
;;	mov	cx,1			; set to plane 1
;;	call	select_vga_plane	;  ...
;;	mov	cx,0800h		; save 2k words
;;	xor	si,si			; from offset 0 in vid mem
;;	rep movsw			; save plane 1 2k bytes (attributes)
;;	push	ds			; now zap attributes to zero to
;;	pop	es			;  avoid flicker in the next stages
;;	xor	di,di			;  ...
;;	xor	ax,ax			;  ...
;;	mov	cx,0400h		;  ...
;;	rep stosw			;  ...
	pop	ds			; restore ds
	mov	orvideo,80h		; set the video to preserve memory
	mov	ax,3			; set up the text call
	mov	bx,0			;  ...
	mov	cx,0			;  ...
	mov	dx,0			;  ...
	call	setvideo		; set the video
	push	ds			; save ds
	mov	ax,extraseg		; set ES == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	es,ax			;  ...
	mov	ax,textaddr
	mov	ds,ax
	cld
	xor	si,si
	mov	di,2000h		; past the saved font info
	mov	cx,0800h		; 2k words (text & attrs)
	rep	movsw			; save them
	pop	ds
	jmp	setfortextreturn
setfordummytext:			; use 640x200x2 simulated text mode
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	mov	orvideo,80h		; set the video to preserve memory
	mov	ax,6			; set up the text call
	mov	bx,0			;  ...
	mov	cx,0			;  ...
	mov	dx,0			;  ...
	call	setvideo		; set the video
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	cld				; clear the direction flag
	mov	ax,extraseg		; set ES == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	es,ax			;  ...
	mov	di,4000h		; save the video data here
	mov	ax,0b800h		; video data starts here
	push	ds			; save DS for a tad
	mov	ds,ax			;  reset DS
	mov	si,0			;  ...
	mov	cx,4000 		; save this many words
	rep	movsw			;  save them.
	mov	si,2000h		;  ...
	mov	cx,4000 		; save this many words
	rep	movsw			;  save them.
	pop	ds			; restore DS
	mov	ax,0b800h		; clear the video buffer
	mov	es,ax			;  ...
	mov	di,0			;  ...
	mov	ax,0			; to blanks
	mov	cx,4000 		; this many blanks
	rep	stosw			; do it.
	mov	di,2000h		;  ...
	mov	cx,4000 		; this many blanks
	rep	stosw			; do it.
	mov	ax,20h			; enable the video (I think)
	call	disablevideo		;  ...
	mov	bx,23			; set mode 6 fgrd to grey
	mov	cx,2a2ah		; register 23, rgb white
	mov	dh,2ah			;  ...
	mov	ax,1010h		; int 10 10-10 affects mcga,vga
	int	10h			;  ...
	mov	ax,cs			; do it again, another way
	mov	es,ax			;  ...
	mov	dx,offset monocolors	;  ...
	mov	ax,1002h		; int 10 10-02 handles pcjr,ega,vga
	int	10h			;  ...

setfortextreturn:
	call	far ptr setclear	; clear and home the cursor
	pop	bp
	ret
setfortext	endp

setforgraphics	proc	uses es si di
	push	bp			; save it around the int 10s
	cmp	dotmode, 12		;check for 8514
	jne	gnot8514
	cmp	f85flag, 0
	jne	go_graphicsreturn
	cmp	ai_8514, 0		;check afi flag JCO 4/11/92
	jne	reopenafi
	call	reopen8514hw	;use registers
	jmp	reopen85done
reopenafi:
	call	reopen8514		;use afi
reopen85done:
	mov	f85flag, 1
go_graphicsreturn:
	jmp	setforgraphicsreturn
gnot8514:
	cmp	dotmode,9		; Targa?
	jne	gnottarga		;  nope
	call	far ptr ReopenTGA
	jmp	short go_graphicsreturn
gnottarga:

	cmp	dotmode,14		; check for Tandy 1000 specific modes
	je	setforgraphicscga	;  yup
	cmp	videoax,0		; check for CGA modes
	je	setforgraphicsnocga_x	;  not this one
	cmp	dotmode,10		; Hercules?
	je	setforgraphicscga	;  yup
	cmp	videoax,7		; vid mode <=7?
	jbe	setforgraphicscga	;  CGA mode
setforgraphicsnocga_x:
	jmp	setforgraphicsnocga
setforgraphicscga:
	cmp	dotmode,10		; Hercules?
	jne	tnotHGC2		;  (nope.  dull-normal stuff)
	call	hgcstart		; Initialize the HGC card
	mov	HGCflag,1		; flag "HGC-end" needed.
	jmp	short twasHGC2		; bypass the normal setvideo call
tnotHGC2:
	cmp	dotmode,14		; Tandy?
	jne	tnottandy1		;  nope
	mov	orvideo,80h		; set the video to preserve memory
tnottandy1:
	mov	ax,videoax		; set up the video call
	mov	bx,videobx		;  ...
	mov	cx,videocx		;  ...
	mov	dx,videodx		;  ...
	call	setvideo		; do it.
twasHGC2:
	mov	bx,extraseg		; restore is from Extraseg
	add	bx,1000h		; (plus 64K)
	mov	si,4000h		; video data is saved here
	mov	ax,0b800h		; restore the video area
	mov	di,0			;  ...
	cmp	videoax,3		; from mode 3?
	jne	setforgraphicscga2	;  nope
	cmp	mode7text,0		; egamono/hgc?
	je	setforgraphicscga2	;  nope
	mov	ax,0b000h		; video data starts here
setforgraphicscga2:
	mov	cx,2000h		; restore this many words
	cmp	dotmode,10		; Hercules?
	jne	setforgraphicscganoherc ;  nope
	mov	si,0			; (restore 32K)
	mov	ax,0b000h		; (to here)
	mov	cx,4000h		; (restore this many words)
setforgraphicscganoherc:
	cmp	dotmode,14		; check for Tandy 1000 specific modes
	jne	tnottandy2		; ..
	mov	ax,tandyseg		; video data starts here
	mov	di,tandyofs		; save video data here
	mov	si,0			; video data is saved here
	mov	cx,4000h		; save this many words
tnottandy2:
	push	ds			; save DX for a tad
	mov	es,ax			; load the dest seg into ES
	mov	ds,bx			; restore it from the source seg
	cld				; clear the direction flag
	rep	movsw			; restore them.
	pop	ds			; restore DS
	jmp	setforgraphicsreturn
setforgraphicsnocga:
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	cld				; clear the direction flag
	mov	ax,textsafe2		; videotable override?
	cmp	ax,0			;  ...
	jne	setforgraphicssafe	;  yup
	mov	ax,textsafe		; nope, use general setting
setforgraphicssafe:
	cmp	ax,2			; textsafe=no?
	jne	setforgraphicsnocga2
	jmp	setfordummygraphics	;  yup, 640x200x2
setforgraphicsnocga2:
	; must be ega, mcga, or vga, else we'd have set textsafe=no in runup
	cmp	ax,4			; textsafe=save?
	jne	setforgraphicsnocga3	;  nope
;; pb, always clear video here:
;;  need if for ega/vga with < 16 colors to clear unused planes
;;  and, some bios's don't implement ah or'd with 80h?!?, dodge their bugs
;;	cmp	dotmode,2		; ega/vga, <=16 colors?
;;	jne	setfgncfast		;  nope
;;	cmp	colors,16		; < 16 colors?
;;	jae	setfgncfast		;  nope
;;	jmp	short setfgncsetvid	; special, need unused planes clear
;;setfgncfast:
;;	mov	orvideo,80h		; preserve memory (just to be fast)
;;setfgncsetvid:
        mov     orvideo,00h   ; JRS          ; preserve memory (just to be fast)
	mov	ax,videoax		; set up the video call
	mov	bx,videobx		;  ...
	mov	cx,videocx		;  ...
	mov	dx,videodx		;  ...
	call	setvideo		; do it.
	sub	ax,ax			; disable the video (I think)
	call	disablevideo		;  ...
	call	far ptr restoregraphics ; C rtn which uses swapsetup
	call	swapvga_reset		; some cleanup for swapvga case
	mov	ax,20h			; enable the video (I think)
	call	disablevideo		;  ...
	jmp	setforgraphicsreturn
setforgraphicsnocga3:
	push	ds			; save ds
	mov	ax,0a000h		; set es to video mem
	mov	es,ax			;  ...
	cmp	video_type,4		; mcga?
	jne	setforgraphicsegavga	;  nope
	mov	ax,extraseg		; set DS == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	ds,ax			;  ...
	xor	si,si			; from save offset 0
	xor	di,di			; to vid offset 0
	mov	cx,1000h		; restore 4k words
	rep movsw			; font info
	mov	di,8000h		; to vid offset 8000h
	mov	cx,0800h		; restore 2k words
	rep movsw			; characters and attributes
	jmp	short setforgraphicsdoit
setforgraphicsegavga:
;;	mov	cx,0			; set to plane 0
;;	call	select_vga_plane	;  ...
;;	mov	ax,extraseg		; set DS == Extra Segment
;;	add	ax,1000h		; (plus 64K)
;;	mov	ds,ax			;  ...
;;	mov	cx,0800h		; restore 2k words
;;	xor	si,si			; from offset 0 in save area
;;	xor	di,di			; to offset 0 in vid mem
;;	rep movsw			; restore plane 0 2k bytes (char values)
	mov	ax,textaddr
	mov	es,ax
	mov	ax,extraseg		; set DS == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	ds,ax			;  ...
	cld
	xor	di,di
	mov	si,2000h		; past the saved font info
	mov	cx,0800h		; 2k words (text & attrs)
	rep	movsw			; restore them
	pop	ds
	mov	ax,8eh			; switch to a mode with known mapping
	cmp	videoax,0fh		; returning to ega 640x350x2?
	jne	sfgnotega		;  nope
	mov	ax,8fh			; yup, go directly to it
sfgnotega:
	int	10h			; set the safe mode
	mov	ax,0			; disable the video (I think)
	call	disablevideo		;  ...
	mov	cx,2			; set to plane 2
	call	select_vga_plane	;  ...
	push	ds
	mov	ax,0a000h		; set es to video mem
	mov	es,ax			;  ...
	mov	ax,extraseg		; set DS == Extra Segment
	add	ax,1000h		; (plus 64K)
	mov	ds,ax			;  ...
	mov	cx,1000h		; restore 4k words
	xor	di,di			; to offset 0 in vid mem
	xor	si,si			; from offset 0 in extraseg
	rep movsw			; restore plane 2 8k bytes (font)
;;	mov	cx,1			; set to plane 1
;;	call	select_vga_plane	;  ...
;;	mov	cx,0800h		; restore 2k words
;;	xor	di,di			; to offset 0 in vid mem
;;	rep movsw			; restore plane 1 2k bytes (attributes)
	jmp	short setforgraphicsdoit
setfordummygraphics:
	push	ds			; save ds
	mov	ax,0b800h		; restore the video area
	mov	es,ax			; ES == video addr
	mov	di,0			;  ...
	mov	ax,extraseg		;  ...
	add	ax,1000h		; (plus 64K)
	mov	ds,ax			;  ...
	mov	si,4000h		; video data is saved here
	mov	cx,4000 		; restore this many words
	rep	movsw			; restore them.
	mov	di,2000h
	mov	cx,4000 		; restore this many words
	rep	movsw			; restore them.
setforgraphicsdoit:
	pop	ds			; restore DS
	cmp	bios_vidsave,0		; did setfortext use bios state save?
	je	setforgraphicssetvid	;  nope
	mov	ax,cs			; ptr to save buffer
	mov	es,ax			;  ...
	mov	bx,offset bios_savebuf	;  ...
	mov	ax,1c02h		;  restore state
	mov	cx,3			;  hardware + bios
	int	10h			;  ...
	jmp	short setforgraphicsreturn
setforgraphicssetvid:
	mov	orvideo,80h		; set the video to preserve memory
	mov	ax,videoax		; set up the video call
	mov	bx,videobx		;  ...
	mov	cx,videocx		;  ...
	mov	dx,videodx		;  ...
	call	setvideo		; do it.
	mov	ax,20h			; enable the video (I think)
	call	disablevideo		;  ...
setforgraphicsreturn:
	mov	curbk,0ffffh		; stuff impossible value into cur-bank
	mov	ax,1			; set up call to spindac(0,1)
	push	ax			;  ...
	mov	ax,0			;  ...
	push	ax			;  ...
	call	far ptr spindac 	; do it.
	pop	ax			; restore the registers
	pop	ax			;  ...
	pop	bp
	ret
setforgraphics	endp

; swapxxx routines: indirect call via swapsetup, used by savegraphics
;		    and restoregraphics

swap256 	proc uses es si di	; simple linear banks version
	mov	ax,word ptr swapoffset+2; high word of offset is bank
	call	far ptr newbank 	; map in the bank
	mov	ax,0a000h		; high word of vid addr
	mov	word ptr swapvidbuf+2,ax; store it
	mov	ax,word ptr swapoffset	; offset in bank
	mov	word ptr swapvidbuf,ax	; store as low word of vid addr
	neg	ax			; 65536-offset
	jz	swap256ret		; offset 0
	cmp	ax,swaplength		; rest of bank smaller than req length?
	jae	swap256ret		;  nope
	mov	swaplength,ax		; yup, reduce length to what's available
swap256ret:
	ret
swap256 	endp

swapvga 	proc uses es si di	; 4 (or less) planes version
	xor	si,si			; this will be plane number
	mov	ax,word ptr swaptotlen	; dx,ax = total length
	mov	dx,word ptr swaptotlen+2
	mov	cx,word ptr swapoffset	; bx,cx = offset
	mov	bx,word ptr swapoffset+2
	cmp	colors,4		; 4 or 2 color mode?
	jle	swapvga_2		;  yup, no plane 2/3
	shr	dx,1			; 1/2 of total
	rcr	ax,1			;  ...
	cmp	dx,bx			; 1/2 total <= offset?
	jb	swapvga_1		;  yup
	ja	swapvga_2		;  nope
	cmp	ax,cx			; ...
	ja	swapvga_2		;  nope
swapvga_1:
	mov	si,2			; plane 2
	sub	cx,ax			; subtract 1/2 total from offset
	sbb	bx,dx			;  ...
swapvga_2:
	cmp	colors,2		; 2 color mode?
	jle	swapvga_4		;  yup, just plane 0
	shr	dx,1			; 1/4 of total (or 1/2 if 4 colors)
	rcr	ax,1			;  ...
	cmp	dx,bx			; 1/4 total <= remaining offset?
	jb	swapvga_3		;  yup
	ja	swapvga_4		;  nope
	cmp	ax,cx			; ...
	ja	swapvga_4		;  nope
swapvga_3:
	inc	si			; plane 1 or 3
	sub	cx,ax			; subtract 1/4 total from offset
	sbb	bx,dx			;  ...
swapvga_4:
	mov	di,0			; bank size (65536 actually)
	cmp	bx,dx			; in last bank?
	jne	swapvga_5		;  nope
	mov	di,ax			; yup, note its size
swapvga_5:
	mov	ax,0a000h		; high word of vid addr
	mov	word ptr swapvidbuf+2,ax; store it
	mov	word ptr swapvidbuf,cx	; low word of vid addr (offset in bank)
	sub	di,cx			; bank size - offset
	je	swapvga_6		; 0 implies bank = 65536
	cmp	di,swaplength		; rest of bank smaller than req length?
	jae	swapvga_6		;  nope
	mov	swaplength,di		; yup, reduce length to what's available
swapvga_6:
	push	si			; remember plane
	mov	ax,bx			; top word of offset is bank
	call	far ptr newbank 	; map in the bank
	mov	dx,03ceh		; graphics controller address
	pop	cx			; plane
	mov	ah,cl			;  ...
	mov	al,04h			; set up controller address register
	out	dx,ax			; map the plane into memory for reads
	mov	ax,0001h		; set/reset enable - all bits processor
	out	dx,ax			;  ...
	mov	ax,0ff08h		; bit mask - all bits processor
	out	dx,ax			;  ...
	mov	dx,03c4h		; sequencer address
	mov	ah,1			; 1 << plane number
	shl	ah,cl			;  ...
	mov	al,02h			; sequencer plane write enable register
	out	dx,ax			; enable just this plane for writing
	ret
swapvga 	endp

swapvga_reset	proc near
	cmp	word ptr swapsetup,offset swapvga; swapvga being used?
	jne	swapvga_reset_ret
	mov	ax,0f02h		; write enable register, all planes
	mov	dx,03c4h		; sequencer address
	out	dx,ax
swapvga_reset_ret:
	ret
swapvga_reset	endp

swapnormread	proc uses es si di	; the SLOW version
	local	xdot:word,ydot:word,bytesleft:word,bits:word,bitctr:word
	local	savebyte:byte
	mov	ax,swaplength		; bytes to save
	mov	bytesleft,ax		;  ...
	mov	bits,8			; bits/pixel
	mov	bx,word ptr swapoffset	; pixel offset to save
	mov	cx,word ptr swapoffset+2
	mov	ax,colors		; colors
swapnorm_bits:
	cmp	ax,256			; accounted for 8 bits yet?
	jae	swapnorm_gotbits	;  yup
	shr	bits,1			; nope, halve the bits/pixel
	shl	bx,1			; double the pixel offset
	rcl	cx,1			;  ...
	mul	ax			; square colors accounted for
	jmp	short swapnorm_bits	; check if enough yet
swapnorm_gotbits:
	mov	ax,bx			; pixel offset now in dx:ax
	mov	dx,cx			;  ...
	div	sxdots			; translate pixel offset to row/col
	mov	ydot,ax 		;  ...
	mov	xdot,dx 		;  ...
	mov	ax,extraseg		; Extra Segment
	add	ax,1000h		;  plus 64K
	mov	word ptr swapvidbuf+2,ax; temp buffer to return to caller
	mov	word ptr swapvidbuf,0	;  ...
	mov	word ptr tmpbufptr+2,ax ; running ptr for building buffer
	mov	word ptr tmpbufptr,0	;  ...
	mov	bitctr,0
swapnorm_loop:
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			;  for dotread
	mov	cx,xdot 		; load up the registers
	mov	dx,ydot 		;  for the video routine
	call	dotread 		; read the dot via the approved method
	mov	cx,bits 		; bits per pixel
	cmp	cx,8			; 1 byte per pixel?
	je	swapnorm_store		;  yup, go store a byte
	add	bitctr,cx		; nope, add how many we're storing
	mov	bl,savebyte		; load the byte being built
swapnorm_shift:
	shr	al,1			; shift pixel into byte
	rcr	bl,1			;  ...
	loop	swapnorm_shift		; for number of bits/pixel
	mov	savebyte,bl		; save byte we're building
	cmp	bitctr,8		; filled a byte yet?
	jb	swapnorm_nxt		;  nope
	mov	al,bl			; yup, set up to store
	mov	bitctr,0		; clear counter for next time
swapnorm_store:
	les	di,tmpbufptr		; buffer pointer
	stosb				; store byte
	dec	bytesleft		; finished?
	jz	swapnorm_ret		;  yup
	mov	word ptr tmpbufptr,di	; store incremented buffer pointer
swapnorm_nxt:
	inc	xdot			; for next dotread call
	mov	ax,xdot 		; past row length?
	cmp	ax,sxdots		;  ...
	jb	swapnorm_loop		;  nope, go for next pixel
	inc	ydot			; yup, increment row
	mov	xdot,0			; and reset column
	jmp	short swapnorm_loop	; go for next pixel
swapnorm_ret:
	ret
swapnormread	endp

swapnormwrite	proc uses es si di	; the SLOW way
	local	xdot:word,ydot:word,bytesleft:word,bits:word,bitctr:word
	local	savebyte:byte
	mov	ax,swaplength		; bytes to restore
	inc	ax			; +1
	mov	bytesleft,ax		; save it
	mov	bits,8			; bits/pixel
	mov	bx,word ptr swapoffset	; pixel offset to restore
	mov	cx,word ptr swapoffset+2;  ...
	mov	ax,colors		; colors
swapnormw_bits:
	cmp	ax,256			; accounted for 8 bits yet?
	jae	swapnormw_gotbits	;  yup
	shr	bits,1			; nope, halve the bits/pixel
	shl	bx,1			; double the pixel offset
	rcl	cx,1			;  ...
	mul	ax			; square colors accounted for
	jmp	short swapnormw_bits	; check if enough yet
swapnormw_gotbits:
	mov	ax,bx			; pixel offset now in dx:ax
	mov	dx,cx			;  ...
	div	sxdots			; translate pixel offset to row/col
	mov	ydot,ax 		;  ...
	mov	xdot,dx 		;  ...
	mov	dx,word ptr swapvidbuf+2; temp buffer from caller
	mov	ax,word ptr swapvidbuf	;  ...
	mov	word ptr tmpbufptr+2,dx ; running ptr in buffer
	mov	word ptr tmpbufptr,ax	;  ...
	mov	bitctr,0
swapnormw_loop:
	mov	cx,bits 		; bits per pixel
	sub	bitctr,cx		; subtract a pixel from counter
	jg	swapnormw_extract	;  got some left in savebyte
	dec	bytesleft		; all done?
	jz	swapnormw_ret		;  yup
	les	si,tmpbufptr		; buffer pointer
	mov	dl,es:[si]		; next byte
	inc	word ptr tmpbufptr	; incr buffer pointer for next time
	mov	bitctr,8		; reset unused bit count
	cmp	cx,8			; 1 byte/pixel?
	je	swapnormw_store 	;  yup, go the fast way
	mov	bl,dl			; byte to extract from
	jmp	short swapnormw_extract2
swapnormw_extract:
	mov	bl,savebyte		; byte with bits left to use
	mov	dl,bl			; current pixel in bottom n bits
swapnormw_extract2:
	shr	bl,1			; for next time
	loop	swapnormw_extract2	; for bits per pixel
	mov	savebyte,bl		; save remaining bits
swapnormw_store:
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			;  for dotread
	mov	al,dl			; color to write
	and	ax,andcolor		;  ...
	mov	cx,xdot 		; load up the registers
	mov	dx,ydot 		;  for the video routine
	call	dotwrite		; write the dot via the approved method
	inc	xdot			; for next dotread call
	mov	ax,xdot 		; past row length?
	cmp	ax,sxdots		;  ...
	jb	swapnormw_loop		;  nope, go for next pixel
	inc	ydot			; yup, increment row
	mov	xdot,0			; and reset column
	jmp	short swapnormw_loop	; go for next pixel
swapnormw_ret:
	ret
swapnormwrite	endp

; far move routine for savegraphics/restoregraphics

movewords proc	uses es di si, len:word, fromptr:dword, toptr:dword
	push	ds			; save DS
	mov	cx,len			; words to move
	les	di,toptr		; destination buffer
	lds	si,fromptr		; source buffer
	cld				; direction=forward
	rep	movsw			; do it.
	pop	ds			; restore DS
	ret				; we done.
movewords endp

; clear text screen

setclear	proc	uses es si di	; clear the screen after setfortext
	call	far ptr home		; home the cursor
	mov	ax,textaddr
	mov	es,ax
	xor	di,di
	cmp	text_type,0		; real text mode?
	jne	setcbw			;  nope
	mov	ax,0720h		; blank with white attribute
	mov	cx,2000 		; 80x25
	rep	stosw			; clear it
	jmp	short setcdone
setcbw: xor	ax,ax			; graphics text
	mov	cx,4000 		; 640x200x2 / 8
	rep	stosw			; clear it
	mov	di,2000h		; second part
	mov	cx,4000
	rep	stosw			; clear it
setcdone:
	xor	ax,ax			; zero
	mov	textrbase,ax		; clear this
	mov	textcbase,ax		;  and this
	ret				; we done.
setclear	endp


disablevideo	proc	near		; wierd video trick to disable/enable
	push	dx			; save some registers
	push	ax			;  ...
	mov	dx,03bah		; set attribute comtroller flip-flop
	in	al,dx			;  regardless of video mode
	mov	dx,03dah		;  ...
	in	al,dx			;  ...
	mov	dx,03c0h		; attribute controller address
	pop	ax			; 00h = disable, 20h = enable
	out	dx,al			;  trust me.
	pop	dx			; restore DX and we done.
	ret
disablevideo	endp

; ************** Function findfont(n) ******************************

;	findfont(0) returns far pointer to 8x8 font table if it can
;		    find it, NULL otherwise;
;		    nonzero parameter reserved for future use

findfont	proc	uses es si di, fontparm:word
	mov	ax,01130h		; func 11, subfunc 30
	mov	bh,03h			; 8x8 font, bottom 128 chars
	sub	cx,cx			; so we can tell if anything happens
	int	10h			; ask bios
	sub	ax,ax			; default return, NULL
	sub	dx,dx			;  ...
	or	cx,cx			; did he set cx?
	jz	findfontret		; nope, return with NULL
	mov	dx,es			; yup, return far pointer
	mov	ax,bp			;  ...
findfontret:
	ret				; note that "uses" gets bp reset here
findfont	endp

; **************** Function home()  ********************************

;	Home the cursor (called before printfs)

home	proc
	mov	ax,0200h		; force the cursor
	mov	bx,0			; in page 0
	mov	dx,0			; to the home position
	mov	textrow,dx		; update our local values
	mov	textcol,dx		;  ...
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret
home	endp

; **************** Function movecursor(row, col)  **********************

;	Move the cursor (called before printfs)

movecursor	proc	row:word, col:word
	mov	ax,row			; row specified?
	cmp	ax,-1			;  ...
	je	mccol			;  nope, inherit it
	mov	textrow,ax		; yup, store it
mccol:	mov	ax,col			; col specified?
	cmp	ax,-1			;  ...
	je	mcdoit			;  nope, inherit it
	mov	textcol,ax		; yup, store it
mcdoit: mov	ax,0200h		; force the cursor
	mov	bx,0			; in page 0
	mov	dh,byte ptr textrow	; move to this row
	add	dh,byte ptr textrbase	;  ...
	mov	dl,byte ptr textcol	; move to this column
	add	dl,byte ptr textcbase	;  ...
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret
movecursor	endp

; **************** Function keycursor(row, col)  **********************

;	Subroutine to wait cx ticks, or till keystroke pending

tickwait  proc
	FRAME	<es>			; std stack frame for TC++ overlays
tickloop1:
	push	cx			; save loop ctr
	sub	ax,ax			; set ES to BIOS data area
	mov	es,ax			;  ...
	mov	bx,es:046ch		; obtain the current timer value
	push	bx
	call	far ptr keypressed	; check if keystroke pending
	pop	bx
	pop	cx			; restore loop ctr
	cmp	ax,0			; keystroke?
	jne	tickret 		;  yup, return
tickloop2:
	cmp	bx,es:046ch		; a new clock tick started yet?
	je	tickloop2		;  nope
	loop	tickloop1		; wait another tick?
	xor	ax,ax			; nope, exit no key, ticks done
tickret:
	UNFRAME <es>			; pop stack frame
	ret
tickwait	endp

;	Show cursor, wait for a key, disable cursor, return key

keycursor	proc   uses es si di, row:word, col:word
	mov	cursortyp,0607h 	; default cursor
	mov	ax,row			; row specified?
	cmp	ax,-1			;  ...
	je	ckcol			;  nope, inherit it
	test	ax,08000h		; top bit on?
	je	ckrow			;  nope
	and	ax,07fffh		; yup, clear it
	mov	cursortyp,0507h 	; and use a bigger cursor
ckrow:	mov	textrow,ax		; store row
ckcol:	mov	ax,col			; col specified?
	cmp	ax,-1			;  ...
	je	ckmode			;  nope, inherit it
	mov	textcol,ax		; yup, store it
ckmode: cmp	text_type,1		; are we in 640x200x2 mode?
	jne	ck_text 		;  nope.  do it the easy way
ck_bwloop:				; 640x200x2 cursor loop
	mov	cx,3			; wait 3 ticks for keystroke
	call	far ptr tickwait	;  ...
	cmp	ax,0			; got a keystroke?
	je	ckwait			;  nope
	jmp	ck_get			; yup, fetch it and return
ckwait: mov	ax,320			; offset in vid mem of top row 1st byte:
	mov	bx,textrow		;  row
	add	bx,textrbase		;  ...
	mul	bx			;  row*320 + col
	add	ax,textcol		;  ...
	add	ax,textcbase		;  ...
	mov	di,ax			;  ...
	mov	ax,0b800h		; set es to vid memory
	mov	es,ax			;  ...
	mov	ah,byte ptr es:00f0h[di]; row 6 of character
	mov	al,byte ptr es:20f0h[di]; row 7 of character
	push	ax			; save them
	mov	cx,8			; count on bits in orig value
	xor	bx,bx			;  ...
ckbits: shl	al,1			;  ...
	adc	bx,0			;  ...
	loop	ckbits			;  ...
	mov	al,0			; black cursor
	cmp	bx,4			; >= 4 on bits in orig value?
	jge	ckbwgo			;  yup, use black cursor
	not	al			; nope, use white cursor
ckbwgo: mov	byte ptr es:20f0h[di],al; turn on cursor, row 7
	cmp	cursortyp,0607h 	; small cursor?
	je	ckbwwt			;  yup
	mov	byte ptr es:00f0h[di],al; nope, turn on cursor row 6
ckbwwt: mov	cx,3			; wait 3 ticks for keystroke
	call	far ptr tickwait	;  ...
	pop	bx			; saved orig value
	mov	byte ptr es:00f0h[di],bh; turn off cursor, row 6
	mov	byte ptr es:20f0h[di],bl; turn off cursor, row 7
	cmp	ax,0			; got a keystroke?
	jne	ck_get			;  yup, fetch it and return
	jmp	short ck_bwloop 	; and keep waiting
ck_text:
	cmp	text_type,0		; real text mode?
	jne	ckgetw			;  nope, no cursor at all
	push	bp			; some bios's don't save this
	mov	ah,1			; set cursor type
	mov	cx,cursortyp		;  ...
	int	10h			;  ...
	mov	ah,02			; move cursor
	xor	bx,bx			;  page
	mov	dh,byte ptr textrow	;  row
	add	dh,byte ptr textrbase	;  ...
	mov	dl,byte ptr textcol	;  col
	add	dh,byte ptr textcbase	;  ...
	int	10h			;  ...
	pop	bp
ckgetw: call	far ptr keypressed	; not getakey, help/tab mey be enabled
	cmp	ax,0			; key available?
	je	ckgetw			;  nope, keep waiting
ck_get: call	far ptr getakey 	; get the keystroke
	cmp	text_type,0		; real text mode?
	jne	ck_ret			;  nope, done
	push	bp			; some bios's don't save this
	push	ax			; save it
	mov	ah,1			; make cursor normal size
	mov	cx,0607h		;  ...
	int	10h			;  ...
	mov	ah,02			; move cursor
	xor	bx,bx			;  page
	mov	dx,1950h		;  off the display
	int	10h			;  ...
	pop	ax			; keystroke value
	pop	bp
ck_ret:
	ret
keycursor	endp

; ************* Function scrollup(toprow, botrow) ******************

;	Scroll the screen up (from toprow to botrow)

scrollup	proc	uses	es, toprow:word, botrow:word

	mov	ax,0601h		; scropp up one line
	mov	bx,0700h		; new line is black
	mov	cx,toprow		; this row,
	mov	ch,cl			;  ...
	mov	cl,0			;  first column
	mov	dx,botrow		; to this row,
	mov	dh,dl			;  ...
	mov	dl,79			;  last column
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret				; we done.
scrollup	endp

; ************* Function scrolldown(toprow, botrow) ******************

;	Scroll the screen down (from toprow to botrow)

scrolldown	proc	uses	es, toprow:word, botrow:word

	mov	ax,0701h		; scropp down one line
	mov	bx,0700h		; new line is black
	mov	cx,toprow		; this row,
	mov	ch,cl			;  ...
	mov	cl,0			;  first column
	mov	dx,botrow		; to this row,
	mov	dh,dl			;  ...
	mov	dl,79			;  last column
	push	bp			; some BIOS's don't save this
	int	10h			; do it.
	pop	bp			; restore the saved register
	ret				; we done.
scrolldown	endp


; **************** Function getcolor(xdot, ydot) *******************

;	Return the color on the screen at the (xdot,ydot) point

getcolor	proc	uses di si es, xdot:word, ydot:word
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine
	mov	cx,xdot 		; load up the registers
	mov	dx,ydot 		;  for the video routine
	add	cx,sxoffs		;  ...
	add	dx,syoffs		;  ...
	call	dotread 		; read the dot via the approved method
	mov	ah,0			; clear the high-order bits
	ret				; we done.
getcolor	endp

; Fastcall version, called when C programs are compiled by MSC 6.00A:

@getcolor	proc	FORTRAN ; ax=xdot, dx=ydot
	push	si			; preserve these
	push	di			;  ...
	mov	cx,ax			; load up the registers
	add	cx,sxoffs		;  ...
	add	dx,syoffs		;  ...
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			;  ...
	call	dotread 		; read the dot via the approved method
	xor	ah,ah			; clear the high-order bits
	pop	di			; restore
	pop	si			;  ...
	ret				; we done.
@getcolor	endp

; ************** Function putcolor(xdot, ydot, color) *******************

;	write the color on the screen at the (xdot,ydot) point

putcolor	proc	uses di si es, xdot:word, ydot:word, xcolor:word
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine
	mov	cx,xdot 		; load up the registers
	mov	dx,ydot 		;  for the video routine
	add	cx,sxoffs		;  ...
	add	dx,syoffs		;  ...
	mov	ax,xcolor		;  ...
	and	ax,andcolor		; (ensure that 'color' is in the range)
	call	dotwrite		; write the dot via the approved method
;;;	call	videocleanup		; perform any video cleanup required
	ret				; we done.
putcolor	endp

; Fastcall version, called when C programs are compiled by MSC 6.00A:

@putcolor	proc	FORTRAN ; ax=xdot, dx=ydot, bx=color
	push	si			; preserve these
	push	di			;  ...
	mov	cx,ax			; load up the registers
	add	cx,sxoffs		;  ...
	add	dx,syoffs		;  ...
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			;  ...
	mov	ax,bx			; color
	and	ax,andcolor		; ensure that 'color' is in range
	call	dotwrite		; write the dot via the approved method
;;;	call	videocleanup		; perform any video cleanup required
	pop	di			; restore
	pop	si			;  ...
	ret				; we done.
@putcolor	endp


; ***************Function out_line(pixels,linelen) *********************

;	This routine is a 'line' analog of 'putcolor()', and sends an
;	entire line of pixels to the screen (0 <= xdot < xdots) at a clip
;	Called by the GIF decoder

out_line	proc	uses di si es, pixels:ptr byte, linelen:word
	mov	cx,sxoffs		; start at left side of logical screen
	mov	dx,rowcount		; sanity check: don't proceed
	add	dx,syoffs		;  ...
	cmp	dx,sydots		; beyond the end of the screen
	ja	out_lineret		;  ...
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine
	mov	ax, linelen		; last pixel column
	add	ax, sxoffs		;  ...
	dec	ax			;  ...
	mov	si,pixels		; get the color for dot 'x'
	call	linewrite		; mode-specific linewrite routine
	inc	rowcount		; next row
out_lineret:
	xor	ax,ax			; return 0
	ret

out_line	endp

; ***Function get_line(int row,int startcol,int stopcol, unsigned char *pixels) ***

;	This routine is a 'line' analog of 'getcolor()', and gets a segment
;	of a line from the screen and stores it in pixels[] at one byte per
;	pixel
;	Called by the GIF decoder

get_line	proc uses di si es, row:word, startcol:word, stopcol:word, pixels:ptr byte
	mov	cx,startcol		; sanity check: don't proceed
	add	cx,sxoffs		;  ...
	cmp	cx,sxdots		; beyond the right end of the screen
	ja	get_lineret		;  ...
	mov	dx,row			; sanity check: don't proceed
	add	dx,syoffs		;  ...
	cmp	dx,sydots		; beyond the bottom of the screen
	ja	get_lineret		;  ...
	mov	ax, stopcol		; last pixel to read
	add	ax, sxoffs		;  ...
	mov	di, pixels		; get the color for dot 'x'
	call	lineread		; mode-specific lineread routine
get_lineret:
	xor	ax,ax			; return 0
	ret
get_line	endp

; ***Function put_line(int row,int startcol,int stopcol, unsigned char *pixels) ***

;	This routine is a 'line' analog of 'putcolor()', and puts a segment
;	of a line from the screen and stores it in pixels[] at one byte per
;	pixel
;	Called by the GIF decoder

put_line	proc uses di si es, row:word, startcol:word, stopcol:word, pixels:ptr byte
	mov	cx,startcol		; sanity check: don't proceed
	add	cx,sxoffs		;  ...
	cmp	cx,sxdots		; beyond the right end of the screen
	ja	put_lineret		;  ...
	mov	dx,row			; sanity check: don't proceed
	add	dx,syoffs		;  ...
	cmp	dx,sydots		; beyond the bottom of the screen
	ja	put_lineret		;  ...
	mov	ax,0a000h		; EGA, VGA, MCGA starts here
	mov	es,ax			; save it here during this routine
	mov	ax, stopcol		; last column
	add	ax, sxoffs;		;  ...
	cmp	ax,sxdots		; beyond the right end of the screen?
	ja	put_lineret		;  ...
	mov	si,pixels		; put the color for dot 'x'
	call	linewrite		; mode-specific linewrite routine
put_lineret:
	xor	ax,ax			; return 0
	ret
put_line	endp


;-----------------------------------------------------------------

; setattr(row, col, attr, count) where
;	  row, col = row and column to start printing.
;	  attr = color attribute.
;	  count = number of characters to set
;	  This routine works only in real color text mode.

setattr 	proc uses es di, row:word, col:word, attr:word, count:word
	mov	ax,row			; row specified?
	cmp	ax,-1			;  ...
	je	setac			;  nope, inherit it
	mov	textrow,ax		; yup, store it
setac:	mov	ax,col			; col specified?
	cmp	ax,-1			;  ...
	je	setago			;  nope, inherit it
	mov	textcol,ax		; yup, store it
setago: cmp	text_type,0		; real color text mode?
	jne	setax			;  nope, do nothing
	mov	ax,textrow		; starting row
	add	ax,textrbase		;  ...
	mov	cx,160			; x 2 bytes/row (char & attr bytes)
	imul	cx
	mov	bx,textcol		; add starting column
	add	bx,textcbase		;  ...
	add	ax,bx			; twice since 2 bytes/char
	add	ax,bx			;  ...
	mov	di,ax			; di -> start location in Video segment
	mov	cx,count		; number of bytes to set
	jcxz	setax			; none?
	mov	ax,attr 		; get color attributes in al
	mov	dx,0b800h		; set video pointer
	cmp	mode7text,0		; egamono/hgc?
	je	setalstore		;  nope
	mov	dx,0b000h		; mode 7 address
	mov	al,07h			; normal mda ttribute
	cmp	ah,0			; inverse?
	jge	setalchkbright		;  nope
	mov	al,70h			; yup
	jmp	short setalstore
setalchkbright:
	test	ah,40h			; bright?
	jz	setalstore		;  nope
	mov	al,0Fh			; yup
setalstore:
	mov	es,dx			;  ...
setalp: mov	byte ptr es:1[di],al	; set attribute
	add	di,2			; for next one
	loop	setalp			; do next char
setax:	ret
setattr 	endp


;-----------------------------------------------------------------

; PUTSTR.asm puts a string directly to video display memory. Called from C by:
;    putstring(row, col, attr, string) where
;	  row, col = row and column to start printing.
;	  attr = color attribute.
;	  string = far pointer to the null terminated string to print.
;    Written for the A86 assembler (which has much less 'red tape' than MASM)
;    by Bob Montgomery, Orlando, Fla.		  7-11-88
;    Adapted for MASM 5.1 by Tim Wegner 	 12-11-89
;    Furthur mucked up to handle graphics
;	video modes by Bert Tyler		  1-07-90
;    Reworked for:  row,col update/inherit;
;	620x200x2 inverse video;  far ptr to string;
;	fix to avoid scrolling when last posn chgd;
;	divider removed;  newline ctl chars;  PB  9-25-90

putstring	proc uses es di si, row:word, col:word, attr:word, string:far ptr byte
	mov	ax,row			; row specified?
	cmp	ax,-1			;  ...
	je	putscol 		;  nope, inherit it
	mov	textrow,ax		; yup, store it
putscol:
	mov	ax,col			; col specified?
	cmp	ax,-1			;  ...
	je	putsmode		;  nope, inherit it
	mov	textcol,ax		; yup, store it
putsmode:
	les	si,string		; load buffer pointer
	cmp	text_type,0		; are we in color text mode?
	jne	short put_substring	;  nope
	jmp	put_text		; yup

put_substring:				; graphics mode substring loop
	push	si			; save start pointer
	push	textcol 		; save start column
put_loop:
	mov	al,byte ptr es:[si]	; get next char
	cmp	al,0			; end of string?
	je	puts_chk_invert 	;  yup
	cmp	al,10			; end of line?
	je	puts_chk_invert 	;  yup
	push	si			; save offset
	push	es			; save this
	push	bp			; and this
	push	ax			; and this last, needed soonest
	mov	ah,02h			; set up bios set cursor call
	xor	bh,bh			;  page 0
	mov	dl,byte ptr textcol	;  screen location
	add	dl,byte ptr textcbase	;   ...
	mov	dh,byte ptr textrow	;   ...
	add	dh,byte ptr textrbase	;   ...
	int	10h			;  invoke the bios
	pop	ax			; the character to write
	mov	ah,09h			; set up the bios write char call
	mov	bx,7			;  page zero, color
	mov	cx,1			;  write 1 character
	int	10h			;  invoke the bios
	pop	bp			; restore
	pop	es			; restore
	pop	si			; restore
	inc	si			; on to the next character
	inc	textcol 		;  ...
	jmp	short put_loop		;  ...
puts_chk_invert:
	pop	bx			; starting column number
	pop	dx			; restore start offset
	cmp	attr,0			; top bit of attribute on?
	jge	short puts_endsubstr	;  nope, nothing more to do
	cmp	text_type,1		; 640x200x2 mode?
	jne	short puts_endsubstr	;  nope, can't do anything more
	mov	cx,si			; calc string length
	sub	cx,dx			;  ...
	jcxz	short puts_endsubstr	; empty string?
	push	ax			; remember terminating char
	push	es			;  and this
	; make the string inverse video on display
	mov	ax,320			; offset in vid mem of 1st byte's top
	mov	di,textrow		;  row*320 + col
	add	di,textrbase		;  ...
	mul	di			;  ...
	add	ax,bx			;  ...
	add	ax,textcbase		;  ...
	mov	di,ax			;  ...
	mov	ax,0b800h		; set es to vid memory
	mov	es,ax			;  ...
puts_invert:
	not	byte ptr es:0000h[di]	; invert the 8x8 making up a character
	not	byte ptr es:2000h[di]
	not	byte ptr es:0050h[di]
	not	byte ptr es:2050h[di]
	not	byte ptr es:00a0h[di]
	not	byte ptr es:20a0h[di]
	not	byte ptr es:00f0h[di]
	not	byte ptr es:20f0h[di]
	inc	di
	loop	puts_invert		; on to the next character
	pop	es			; restore
	pop	ax			;  ...
puts_endsubstr:
	cmp	al,0			; the very end?
	je	short putstring_ret	; we done.
	inc	si			; go past the newline char
	mov	textcol,0		; do newline
	inc	textrow 		;  ...
	jmp	put_substring		; on to the next piece

put_text:				; text mode substring loop
	mov	ax,textrow		; starting row
	add	ax,textrbase		;  ...
	mov	cx,160			; x 2 bytes/row (char & attr bytes)
	imul	cx
	mov	bx,textcol		; add starting column
	add	bx,textcbase		;  ...
	add	ax,bx			; twice since 2 bytes/char
	add	ax,bx			;  ...
	mov	di,ax			; di -> start location in Video segment
	mov	ax,attr 		; get color attributes in ah
	cmp	mode7text,0		; egamono/hgc? (MDA)
	je	B0			; nope, use color attr
	mov	al,07h			; default, white on blank
	cmp	ah,0			; top bit of attr set?
	jge	mdachkbright		;  nope
	mov	al,70h			; inverse video
	jmp	short B0
mdachkbright:
	test	ah,40h			; 2nd bit of attr set?
	jz	B0			;  nope
	mov	al,0Fh			; bright
B0:	mov	ah,al
B1:	mov	al,byte ptr es:[si]	; get a char in al
	cmp	al,0			; end of string?
	je	putstring_ret		;  yes, done
	inc	si			; bump for next time
	cmp	al,10			; newline?
	jne	B2			;  nope
	mov	textcol,0		; yup, do it
	inc	textrow 		; ...
	jmp	short put_text		; on to the next substring
B2:	push	es			; No, store char & attribute
	mov	dx,textaddr		;  ...
	mov	es,dx			;  ...
	stosw				;  ...
	pop	es			;  ...
	inc	textcol 		; update local var
	jmp	short B1		; do next char

putstring_ret:
	ret
putstring endp


; ****************  EGA Palette <==> VGA DAC Conversion Routines **********

;	paltodac	converts a 16-palette EGA value to a 256-color VGA
;			value (duplicated 16 times)
;	dactopal	converts the first 16 VGA values to a 16-palette
;			EGA value

;	local routines called with register values
;		BH = VGA Red Color	xxRRRRRR
;		BL = VGA Green Color	xxGGGGGG
;		CH = VGA Blue Color	xxBBBBBB
;		CL = EGA Palette	xxrgbRGB
;
;	palettetodac	converts CL to BH/BL/CH
;	dactopalette	converte BH/BL/CH to CL

; *************************************************************************

palettetodac	proc	near
	mov	bx,0			; initialize RGB values to 0
	mov	ch,0			;  ...
	test	cl,20h			; low-red high?
	jz	palettetodac1		;  nope
	or	bh,10h			; set it
palettetodac1:
	test	cl,10h			; low-green high?
	jz	palettetodac2		;  nope
	or	bl,10h			; set it
palettetodac2:
	test	cl,08h			; low-blue high?
	jz	palettetodac3		;  nope
	or	ch,10h			; set it
palettetodac3:
	test	cl,04h			; high-red high?
	jz	palettetodac4		;  nope
	or	bh,20h			; set it
palettetodac4:
	test	cl,02h			; high-green high?
	jz	palettetodac5		;  nope
	or	bl,20h			; set it
palettetodac5:
	test	cl,01h			; high-blue high?
	jz	palettetodac6		;  nope
	or	ch,20h			; set it
palettetodac6:
	ret
palettetodac	endp

dactopalette	proc	near
	mov	cl,0			; initialize RGB values to 0
	test	bh,10h			; low-red high?
	jz	dactopalette1		;  nope
	or	cl,20h			; set it
dactopalette1:
	test	bl,10h			; low-green high?
	jz	dactopalette2		;  nope
	or	cl,10h			; set it
dactopalette2:
	test	ch,10h			; low-blue high?
	jz	dactopalette3		;  nope
	or	cl,08h			; set it
dactopalette3:
	test	bh,20h			; high-red high?
	jz	dactopalette4		;  nope
	or	cl,04h			; set it
dactopalette4:
	test	bl,20h			; high-green high?
	jz	dactopalette5		;  nope
	or	cl,02h			; set it
dactopalette5:
	test	ch,20h			; high-blue high?
	jz	dactopalette6		;  nope
	or	cl,01h			; set it
dactopalette6:
	ret
dactopalette	endp

paltodac	proc	uses es si di
	mov	si,0			; initialize the loop values
	mov	di,0
paltodacloop:
	mov	cl,palettega[si]	; load up a single palette register
	call	palettetodac		; convert it to VGA colors
	mov	dacbox+0[di],bh 	; save the red value
	mov	dacbox+1[di],bl 	;  and the green value
	mov	dacbox+2[di],ch 	;  and the blue value
	inc	si			; bump up the registers
	add	di,3			;  ...
	cmp	si,16			; more to go?
	jne	paltodacloop		;  yup.
	push	ds			; set ES to DS temporarily
	pop	es			;  ...
	mov	ax,15			; do this 15 times to get to 256
	mov	di,offset dacbox+48	; set up the first destination
paltodacloop2:
	mov	cx,24			; copy another block of 16 registers
	mov	si,offset dacbox	; set up for the copy
	rep	movsw			;  do it
	dec	ax			; need to do another block?
	jnz	paltodacloop2		;  yup.  do it.
	ret				;  we done.
paltodac	endp

dactopal	proc	uses es si di
	mov	si,0			; initialize the loop values
	mov	di,0
dactopalloop:
	mov	bh,dacbox+0[di] 	; load up the VGA red value
	mov	bl,dacbox+1[di] 	;  and the green value
	mov	ch,dacbox+2[di] 	;  and the blue value
	call	dactopalette		; convert it to an EGA palette
	mov	palettega[si],cl	; save as a single palette register
	inc	si			; bump up the registers
	add	di,3			;  ...
	cmp	si,16			; more to go?
	jne	dactopalloop		;  yup.
	mov	cl,palettega		; copy palette 0
	mov	palettega+16,cl 	;  to the overscan register
	ret				;  we done.
dactopal	endp


; *********************** Function loaddac() ****************************

;	Function to Load the dacbox[][] array, if it can
;	(sets gotrealdac to 0 if it can't, 1 if it can)

loaddac proc	uses es
	cmp	dotmode, 29		; truecolor?  MCP 5-29-91
	jne	NotTPlusLoaddac
	mov	ax,4402h
	push	ax
	mov	ax,256 * 3
	push	ax
	xor	ax,ax
	push	ax
	push	ds
	mov	ax,OFFSET dacbox
	push	ax
	call	far ptr TPlusLUT
	add	sp, 10
	or	ax, ax
	jz	NotTPlusLoaddac 	; Didn't work, try a regular palette
	jmp	loaddacdone
NotTPlusLoaddac:
	cmp	dotmode,19		; roll-your-own video mode?
	jne	loaddac_notyourown
	call	far ptr readvideopalette
	cmp	ax,-1			; palette-write handled yet?
	jne	go_loaddacdone		;  yup.
loaddac_notyourown:
	mov	reallyega,0		; set flag: not an EGA posing as a VGA
	cmp	dotmode,9		; TARGA 3 June 89 j mclain
	je	go_loaddacdone
	cmp	f85flag, 0
	jne	go_loaddacdone

	cmp	xga_isinmode,0		; XGA graphics mode?
	jne	go_loaddacdone

	mov	dacbox,255		; a flag value to detect invalid DAC
	cmp	debugflag,16		; pretend we're not a VGA?
	je	loaddacdebug		;  yup.
	push	ds			;  ...
	pop	es			;  ...
	mov	ax,1017h		; get the old DAC values
	mov	bx,0			;  (assuming, of course, they exist)
	mov	cx,256			;  ...
	mov	dx,offset dacbox	;  ...
	push	bp
	int	10h			; do it.
	pop	bp
loaddacdebug:
	cmp	dacbox,255		; did it work?	do we have a VGA?
	je	loaddacega		;  nope, go check ega
	cmp	colors,16		; 16 color vga?
	jne	go_loaddacdone		;  nope, all done
	cld				; yup, must straighten out dacbox,
	push	ds			;  16 color vga uses indirection thru
	pop	es			;  palette select
	mov	si,offset dacbox+60	; dac[20] is used for color 6 so
	mov	di,offset dacbox+18	;  copy dacbox[20] to dacbox[6]
	mov	cx,3			;  ...
	rep	movsb			;  ...
	mov	si,offset dacbox+168	; dac[56-63] are used for colors 8-15 so
	mov	di,offset dacbox+24	;  copy dacbox[56-63] to dacbox[8-15]
	mov	cx,24			;  ...
	rep	movsb			;  ...
go_loaddacdone:
	jmp	short loaddacdone
loaddacega:
	cmp	colors,16		; are we using 16 or more colors?
	jb	loaddacdone		;  nope.  forget it.
;;	cmp	sydots,350		; 640x350 range?
	cmp	video_type,3		; EGA or better?
	jb	loaddacdone		;  nope.  forget it.
	mov	bx,offset palettega	; make up a dummy palette
	mov	cx,3800h		; start with color 0 == black
loaddacega1:				; and	     color 8 == low-white
	mov	0[bx],cl		; save one color
	mov	8[bx],ch		; and another color
	inc	bx			; bump up the DAC
	add	cx,0101h		; and the colors
	cmp	cl,8			; finished 8 colors?
	jne	loaddacega1		;  nope.  get more.
	mov	reallyega,1		; note that this is really an EGA
	call	far ptr paltodac	; "convert" it to a VGA DAC
	mov	daclearn,1		; bypass learn mode
	mov	ax,cyclelimit		;  and spin as fast as he wants
	mov	daccount,ax		;  ...
loaddacdone:
	cmp	colors,16		; 16 color mode?
	jne	loaddacdone2		;  nope
	cld				; yup, clear the excess dacbox
	mov	cx,360			;  entries to all zeros for editpal
	sub	ax,ax
	push	ds
	pop	es
	mov	di,offset dacbox+48
	rep	stosw
loaddacdone2:
	cmp	tweakflag,0		; tweaked mode?
	je	loaddacdone3		;  nope
	mov	dx,3c4h 		; alter sequencer registers
	mov	ax,0604h		; disable chain 4
	out	dx,ax
loaddacdone3:
	mov	gotrealdac,1		; flag for whether mode supports DAC
	cmp	dacbox,255		; did DAC get loaded or fudged?
	jne	loaddacret		;  yup
	mov	gotrealdac,0		; nope
loaddacret:
	ret
loaddac endp

; *************** Function spindac(direction, rstep) ********************

;	Rotate the MCGA/VGA DAC in the (plus or minus) "direction"
;	in "rstep" increments - or, if "direction" is 0, just replace it.

spindac proc	uses di si es, direction:word, rstep:word
	cmp	dotmode,9		; TARGA 3 June 89 j mclain
	je	spinbailout
	cmp	dotmode,11		; disk video mode?
	je	spinbailout
	cmp	gotrealdac,0		; do we have DAC registers to spin?
	je	spinbailout		;  nope.  bail out.
	cmp	colors,16		; at least 16 colors?
	jge	spindacdoit		;  yup.  spin away.
spinbailout:
	jmp	spindacreturn		;  nope.  bail out.

spindacdoit:
	push	ds			; need ES == DS here
	pop	es			;  ...
	cmp	direction,0		; just replace it?
	je	newDAC			;  yup.

	mov	cx, rstep		; loop through the rotate "rstep" times
stepDAC:
	push	cx			; save the loop counter for a tad
	mov	si,offset dacbox
	mov	di,si
	mov	ax,rotate_lo		; calc low end of rotate range
	cmp	ax,colors		; safety check for 16 color mode
	jae	nextDAC 		;  out of range, none to rotate
	add	si,ax
	add	si,ax
	add	si,ax
	mov	ax,rotate_hi		; calc high end of rotate range
	cmp	ax,colors		; safety check for 16 color mode
	jb	stepDAC2		;  ok, in range
	mov	ax,colors		; out of range, use colors-1
	dec	ax			;  ...
stepDAC2:
	add	di,ax
	add	di,ax
	add	di,ax
	mov	cx,di			; size of rotate range - 1
	sub	cx,si
	jcxz	nextDAC 		; do nothing if range 0
	cmp	direction,1		; rotate upwards?
	jne	short downDAC		;  nope.  downwards
	mov	bx,word ptr [si]	; save the first entry
	mov	dl,byte ptr [si+2]	;  ...
	cld				; set the direction
	mov	di,si			; set up the rotate
	add	si,3			;  ...
	rep	movsb			; rotate it
	mov	word ptr [di],bx	; store the last entry
	mov	byte ptr [di+2],dl	;  ...
	jmp	short nextDAC		; set the new DAC
downDAC:
	std				; set the direction
	mov	bx,word ptr [di]	; save the last entry
	mov	dl,byte ptr [di+2]	;  ...
	mov	si,di			; set up the rotate
	dec	si			;  ...
	add	di,2			;  ...
	rep	movsb			; rotate it
	mov	word ptr [si+1],bx	; store the first entry
	mov	byte ptr [si+3],dl	;  ...
	cld				; reset the direction
nextDAC:
	pop	cx			; restore the loop counter
	loop	stepDAC 		; and loop until done.

newDAC:
	cmp	dotmode,19		; roll-your-own video?
	jne	spin_notyourown 	; nope
	call	far ptr writevideopalette
	cmp	ax,-1			; negative result?
	je	go_spindoit		; yup.	handle it locally.
	jmp	spindacreturn		; else we done.
go_spindoit:
	jmp	spindoit

spin_notyourown:
	cmp	dotmode, 29
	je	TPlusOrXGAspindac
	cmp	xga_isinmode,0		; XGA extended graphics?
	je	notxga

TPlusOrXGAspindac:
	mov	si,offset dacbox
	push	si
	mov	bx,0
xgalp1: mov	al,[si+bx]		; adjust VGA -> XGA
	shl	al,1
	shl	al,1
	mov	[si+bx],al
	inc	bx
	cmp	bx,768
	jne	xgalp1

	cmp	dotmode, 29		; Are we a TARGA+?
	jne	XGAPaletteCall		;  nope - XGA
	mov	ax,4403h
	push	ax
	mov	ax,256 * 3
	push	ax
	xor	ax,ax
	push	ax
	push	ds
	mov	ax,OFFSET dacbox
	push	ax
	call	far ptr TPlusLUT
	add	sp, 10
	jmp	TPlusOrXGASet

XGAPaletteCall:
	call	far ptr xga_setpalette

TPlusOrXGASet:
	pop	si
	mov	bx,0
xgalp2: mov	al,[si+bx]		; adjust XGA -> VGA
	shr	al,1
	shr	al,1
	mov	[si+bx],al
	inc	bx
	cmp	bx,768
	jne	xgalp2
	jmp	spindacreturn
notxga:

	cmp	bios_palette,0		; BIOS palette updates forced?
	je	not_bios_palette	;  nope
	mov	ax,1012h		; use a BIOS update
	mov	bx,0
	mov	cx,256
	push	ds
	pop	es
	mov	dx,offset dacbox
	int	10h
	jmp	spindacreturn
not_bios_palette:

	cmp	f85flag, 0		; if 8514a then update pallette
	je	spindoit
	jmp	spin8514

spindoit:
	cmp	colors,16		; 16 color vga?
	jne	spindoit2		;  nope
	cmp	reallyega,1		; is this really an EGA?
	je	spindoit2		;  yup
	cld				; vga 16 color, straighten out dacbox,
	push	ds			;  16 color vga uses indirection thru
	pop	es			;  palette select
	mov	si,offset dacbox+18	; dac[20] is used for color 6 so
	mov	di,offset dacbox+60	;  copy dacbox[6] to dacbox[20]
	mov	cx,3			;  ...
	rep	movsb			;  ...
	mov	si,offset dacbox+24	; dac[56-63] are used for colors 8-15 so
	mov	di,offset dacbox+168	;  copy dacbox[8-15] to dacbox[56-63]
	mov	cx,24			;  ...
	rep	movsb			;  ...
spindoit2:
	mov	bx,0			;  set up to update the DAC
	mov	dacnorm,0		;  indicate no overflow
dacupdate:
	mov	cx,daccount		;  ...
	mov	ax,256			; calculate 256 - BX
	sub	ax,bx			;  ...
	cmp	ax,cx			; is that less than the update count?
	jge	retrace1		;  nope.  no adjustment
	mov	cx,ax			;  else adjust
	mov	dacnorm,1		; and indicate overflow
retrace1:
	mov	dx,03dah		; wait for no retrace
	in	al,dx			;  ...
	and	al,8			; this bit is high during a retrace
	jnz	retrace1		;  so loop until it goes low
retrace2:
	in	al,dx			; wait for no retrace
	and	al,8			; this bit is high during a retrace
	jz	retrace2		;  so loop until it goes high
	cmp	reallyega,1		; is this really an EGA?
	je	spinega 		;  yup.  spin it that way.
	cmp	cpu,88			; are we on a (yuck, ugh) 8088/8086?
	jle	spinbios		;  yup. go through the BIOS
.186
	mov	dx,03c8h		; set up for a blitz-write
	mov	ax,bx			; from this register
	cli				; critical section:  no ints
	out	dx,al			; starting register
	inc	dx			; set up to update colors
	mov	si, offset dacbox	; get starting addr in SI
	add	si,bx			;  ...
	add	si,bx			;  ...
	add	si,bx			;  ...
	mov	ax,cx			; triple the value in CX
	add	cx,ax			;  ...
	add	cx,ax			;  ...
	rep	outsb			; whap!  Zango!  They're updated!
	sti				; end of critical section
	mov	cx,ax			; restore CX for code below
	jmp	spindone		; skip over the BIOS version.
.8086
spinbios:
	mov	dx,offset dacbox	; set up the DAC box offset
	add	dx,bx			;  ...
	add	dx,bx			;  ...
	add	dx,bx			;  ...
	push	bp			;  save some registers
	push	cx			;  (AMSTRAD might need this)
	push	dx			;  ...
	push	bx			;  ...
	mov	ax,1012h		; update the DAC
	int	10h			; do it.
	pop	bx			; restore the registers
	pop	dx			;  ...
	pop	cx			;  ...
	pop	bp			;  ...
	jmp	spindone		; jump to common code
spinega:
	cmp	bx,0			; skip this if not the first time thru
	jne	spindone		;  ...
	push	bx			; save some registers
	push	cx			;  aroud the call
	call	far ptr dactopal	; convert the VGA DAC to an EGA palette
	pop	cx			; restore the registers
	pop	bx			;  from prior to the call
	mov	ax,1002h		; update the EGA palette
	mov	dx,offset palettega	;  ...
	int	10h			; do it.
spindone:
	cmp	daclearn,0		; are we still in learn mode?
	jne	nolearn 		;  nope.
	mov	dx,03dah		; check for the retrace
	in	al,dx			;  ...
	and	al,1			; this bit is high if display disabled
	jz	donelearn		;  oops.  retrace finished first.
	cmp	dacnorm,0		; was this a "short" update?
	jne	short nolearn		;  then don't increment it
	inc	daccount		; increment the daccount value
	inc	daccount		; increment the daccount value
	inc	daccount		; increment the daccount value
	mov	ax,cyclelimit		; collect the cycle-limit value
	cmp	daccount,ax		; sanity check: don't update too far
	jle	short nolearn		;  proceed if reasonable.
donelearn:
	sub	daccount,6		; done learning: reduce the daccount
	mov	daclearn,1		; set flag: no more learning
	cmp	daccount,4		; there's a limit to how slow we go
	jge	nolearn 		;  ...
	mov	daccount,4		;  ...
nolearn:
	add	bx,cx			; set up for the next batch
	cmp	bx,256			; more to go?
	jge	spindacreturn		;  nope.  we done.
	jmp	dacupdate		;  yup.  do it.

spin8514:
	cmp	ai_8514, 0		;check afi flag JCO 4/11/92
	jne	spin85afi
	call	w8514hwpal		; AW
	jmp	spindacreturn
spin85afi:
	call	w8514pal		;use afi

spindacreturn:
	ret
spindac endp

; *************** Function find_special_colors ********************

;	Find the darkest and brightest colors in palette, and a medium
;	color which is reasonably bright and reasonably grey.

find_special_colors proc uses si
	mov	color_dark,0		; for default cases
	mov	color_medium,7		;  ...
	mov	color_bright,15 	;  ...
	cmp	colors,2		; 2 color mode?
	jg	fscnot2
	mov	color_medium,1		; yup, set assumed values and return
	mov	color_bright,1
	ret
fscnot2:
	cmp	colors,16		; < 16 color mode? (ie probably 4)
	jge	fscnot4
	mov	color_medium,2		; yup, set assumed values and return
	mov	color_bright,3
	ret
fscnot4:
	cmp	gotrealdac,0		; dac valid?
	je	fscret			; nope, return with defaults set earlier
	mov	bh,255			; bh is lowest brightness found yet
	sub	bl,bl			; bl is highest found yet
	sub	ah,ah			; ah is best found for medium choice yet
	mov	si,offset dacbox	; use si as pointer to dac
	sub	cx,cx			; use cx for color number
fscloop:
	mov	al,byte ptr 0[si]	; add red,green,blue (assumed all <= 63)
	add	al,byte ptr 1[si]	;  ...
	add	al,byte ptr 2[si]	;  ...
	cmp	al,bh			; less than lowest found so far?
	jae	fscchkbright
	mov	color_dark,cx		; yup, note new darkest
	mov	bh,al			;  ...
fscchkbright:
	cmp	al,bl			; > highest found so far?
	jbe	fscchkmedium
	mov	color_bright,cx 	; yup, note new brightest
	mov	bl,al			;  ...
fscchkmedium:
	cmp	al,150			; too bright?
	jae	fscnextcolor		; yup, don't check for medium
	add	al,80			; so the subtract below will be safe
	cmp	al,ah			; already less than best found?
	jbe	fscnextcolor
	mov	dh,byte ptr 0[si]	; penalize by (maxgun-mingun)/2
	mov	dl,byte ptr 1[si]
	cmp	dh,dl			; set dh to max gun
	jae	fscmed1
	xchg	dh,dl			; now dh=max(0,1), dl=min(0,1)
fscmed1:
	cmp	dh,byte ptr 2[si]	; 2 > dh?
	jae	fscmed2
	mov	dh,byte ptr 2[si]
fscmed2:
	cmp	dl,byte ptr 2[si]	; 2 < dl?
	jbe	fscmed3
	mov	dl,byte ptr 2[si]
fscmed3:
	sub	dh,dl			; now subtract the penalty
	shr	dh,1
	sub	al,dh
	cmp	al,ah			; a new best?
	jbe	fscnextcolor
	mov	color_medium,cx 	; yup, note new medium
	mov	ah,al			;  ...
fscnextcolor:
	add	si,3			; point to next dac entry
	inc	cx			; next color number
	cmp	cx,colors		; scanned them all?
	jl	fscloop 		; nope, go around again
	cmp	ah,0			; find any medium color?
	jne	fscret			; yup, all done
	mov	ax,color_bright 	; must be a pretty bright image,
	mov	color_medium,ax 	; use the brightest for medium
fscret:
	ret
find_special_colors endp


; *************** Functions get_a_char, put_a_char ********************

;	Get and put character and attribute at cursor
;	Hi nybble=character, low nybble attribute. Text mode only

get_a_char proc
	mov	ah,8
	xor	bh,bh
	int	10h
	ret
get_a_char endp

put_a_char proc character:word
	mov	ax,character
	mov	bl,ah
	mov	ah,9
	xor	bh,bh
	mov	cx,1
	int	10h
	ret
put_a_char endp

	end
