File: dos\video.asm

    1 ;       Generic assembler routines having to do with video adapter
    2 ;
    3 ; ---- Video Routines
    4 ;
    5 ;       setvideomode()
    6 ;       setvideotext()
    7 ;       getcolor()
    8 ;       putcolor_a()
    9 ;       gettruecolor()
   10 ;       puttruecolor()
   11 ;       rgb_to_dac()
   12 ;       dac_to_rgb()
   13 ;       out_line()
   14 ;       drawbox()
   15 ;       home()
   16 ;       movecursor()
   17 ;       keycursor()
   18 ;       putstring()
   19 ;       setattr()
   20 ;       scrollup()
   21 ;       scrolldown()
   22 ;       putstr()
   23 ;       loaddac()
   24 ;       spindac()
   25 ;       adapter_init
   26 ;       adapter_detect
   27 ;       setnullvideo
   28 ;       scroll_center()
   29 ;       scroll_relative()
   30 ;       scroll_state()
   31 ;
   32 ; ---- Help (Video) Support
   33 ;
   34 ;       setfortext()
   35 ;       setforgraphics()
   36 ;       setclear()
   37 ;       findfont()
   38 ;
   39 
   40 ;                        required for compatibility if Turbo ASM
   41 IFDEF ??version
   42         MASM51
   43         QUIRKS
   44 ENDIF
   45 
   46         .MODEL  medium,c
   47 
   48         .8086
   49 
   50         ; these must NOT be in any segment!!
   51         ; 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
;   And back to far, JCO 4/13/97
        extrn   open8514  :far     ; start 8514a
        extrn   reopen8514:far     ; restart 8514a
        extrn   close8514 :far     ; stop 8514a
        extrn   fr85wdot  :far     ; 8514a write dot
        extrn   fr85wbox  :far     ; 8514a write box
        extrn   fr85rdot  :far     ; 8514a read dot
        extrn   fr85rbox  :far     ; 8514a read box
        extrn   w8514pal  :far     ; 8514a pallete update

; HW Compatible 8514/A routines    ; AW, made near JCO 4/11/92
;   And back to far, JCO 4/13/97
        extrn   open8514hw  :far      ; start 8514a
        extrn   reopen8514hw:far      ; restart 8514a
        extrn   close8514hw :far      ; stop 8514a
        extrn   fr85hwwdot  :far      ; 8514a write dot
        extrn   fr85hwwbox  :far      ; 8514a write box
        extrn   fr85hwrdot  :far      ; 8514a read dot
        extrn   fr85hwrbox  :far      ; 8514a read box
        extrn   w8514hwpal  :far      ; 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   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   realcoloriter:dword
        extrn   coloriter:dword
        extrn   truemode:word

        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          goodmode                ; video mode ok?
public          text_type               ; current mode's type of text
   52 public          textrow                 ; current row in text mode
   53 public          textcol                 ; current column in text mode
   54 public          textrbase               ; textrow is relative to this
   55 public          textcbase               ; textcol is relative to this
   56 
   57 public          color_dark              ; darkest color in palette
   58 public          color_bright            ; brightest color in palette
   59 public          color_medium            ; nearest to medbright grey in palette
   60 
   61 public          swapsetup               ; for savegraphics/restoregraphics
   62 
   63 public          TPlusInstalled
   64 
   65 public          vesa_detect             ; set to 0 to disable VESA-detection
   66 public          vesa_xres               ; real screen width
   67 public          vesa_yres               ; real screen height
   68 
   69 public          vxdots                  ; virtual scan line length
   70 public          video_scroll            ; is-scrolling-on? flag
   71 public          video_startx            ; scrolled horizontaly this far
   72 public          video_starty            ; scrolled verticaly this far
   73 public          video_vram              ; VRAM size
   74 public          virtual                 ; enable/disable virtual screen mode
   75 public          chkd_vvs                ; we've run VESAvirtscan once

public          istruecolor             ; 1 if VESA truecolor mode, 0 otherwise

;               arrays declared here, used elsewhere
;               arrays not used simultaneously are deliberately overlapped

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

vxdots          dw      0               ; virtual scan line length (bytes)
video_scroll    dw      0               ; is-scrolling-on? flag
video_vram      dw      0               ; VRAM size
virtual         dw      1               ; enable/disable virtual screen mode

video_startx    dw      0               ; scrolled horizontaly this far
video_starty    dw      0               ; scrolled verticaly this far
video_cofs_x    dw      0               ; half of the physical screen width
video_cofs_y    dw      0               ; half of the physical screen height
video_slim_x    dw      0               ; left-col limit for scrolling right
video_slim_y    dw      0               ; top-line limit for scrolling down
scroll_savex    dw      0               ; for restoring screen center position
scroll_savey    dw      0               ; when unstacking the scrolled screen
wait_retrace    dw      0               ; wait for retrace (80h) or not (00h)?

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)
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
dacnorm         db      0               ; 0 if "normal" DAC update
daclearn        dw      0               ; 0 if "learning" DAC speed
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:
   76                                         ;   0  = real text, mode 3 (or 7)
   77                                         ;   1  = 640x200x2, mode 6
   78                                         ;   2  = some other mode, graphics
   79 video_entries   dw      0               ; offset into video_entries table
   80 video_bankadr   dw      0               ; offset  of  video_banking routine
   81 video_bankseg   dw      0               ; segment of  video_banking routine
   82 
   83 textrow         dw      0               ; for putstring(-1,...)
   84 textcol         dw      0               ; for putstring(..,-1,...)
   85 textrbase       dw      0               ; textrow is relative to this
   86 textcbase       dw      0               ; textcol is relative to this
   87 cursortyp       dw      0
   88 
   89 tandyseg        dw      ?               ;Tandy 1000 video segment address
   90 tandyofs        dw      ?               ;Tandy 1000 Offset into video buffer
   91 tandyscan       dw      ?               ;Tandy 1000 scan line address pointer
   92 
   93 
   94 ; ******************* "Tweaked" VGA mode variables ************************
   95 
   96                                                 ; 704 x 528 mode
   97 x704y528        db      704/8                   ; number of screen columns
   98                 db      528/16                  ; number of screen rows
   99                 db       68h, 57h, 58h, 8Bh     ; CRTC Registers
  100                 db       59h, 86h, 3EH,0F0h
  101                 db        0h, 60h,  0h,  0h
  102                 db        0h,  0h,  2h, 3Dh
  103                 db       19h, 8Bh, 0Fh, 2Ch
  104                 db        0h, 18h, 38h,0E3h
  105                 db      0FFh
  106                                                 ; 720 x 540 mode
  107 x720y540        db      720/8                   ; number of screen columns
  108                 db      540/16                  ; number of screen rows
  109                 db       6Ah, 59h, 5Ah, 8Dh     ; CRTC Registers
  110                 db       5Eh, 8Bh, 4AH,0F0h
  111                 db        0h, 60h,  0h,  0h
  112                 db        0h,  0h,  2h, 49h
  113                 db       24h, 86h, 1Bh, 2Dh
  114                 db        0h, 24h, 44h,0E3h
  115                 db      0FFh
  116                                                 ; 736 x 552 mode
  117 x736y552        db      736/8                   ; number of screen columns
  118                 db      552/16                  ; number of screen rows
  119                 db       6Ch, 5Bh, 5Ch, 8Fh     ; CRTC Registers
  120                 db       5Fh, 8Ch, 56H,0F0h
  121                 db        0h, 60h,  0h,  0h
  122                 db        0h,  0h,  2h, 55h
  123                 db       2Bh, 8Dh, 27h, 2Eh
  124                 db        0h, 30h, 50h,0E3h
  125                 db      0FFh
  126                                                 ; 752 x 564 mode
  127 x752y564        db      752/8                   ; number of screen columns
  128                 db      564/16                  ; number of screen rows
  129                 db       6Eh, 5Dh, 5Eh, 91h     ; CRTC Registers
  130                 db       62h, 8Fh, 62H,0F0h
  131                 db        0h, 60h,  0h,  0h
  132                 db        0h,  0h,  2h, 61h
  133                 db       37h, 89h, 33h, 2Fh
  134                 db        0h, 3Ch, 5Ch,0E3h
  135                 db      0FFh
  136                                                 ; 768 x 576 mode
  137 x768y576        db      768/8                   ; number of screen columns
  138                 db      576/16                  ; number of screen rows
  139                 db       70h, 5Fh, 60h, 93h     ; CRTC Registers
  140                 db       66h, 93h, 6EH,0F0h
  141                 db        0h, 60h,  0h,  0h
  142                 db        0h,  0h,  2h, 6Dh
  143                 db       43h, 85h, 3Fh, 30h
  144                 db        0h, 48h, 68h,0E3h
  145                 db      0FFh
  146                                                 ; 784 x 588 mode
  147 x784y588        db      784/8                   ; number of screen columns
  148                 db      588/16                  ; number of screen rows
  149                 db       72h, 61h, 62h, 95h     ; CRTC Registers
  150                 db       69h, 96h, 7AH,0F0h
  151                 db        0h, 60h,  0h,  0h
  152                 db        0h,  0h,  2h, 79h
  153                 db       4Fh, 81h, 4Bh, 31h
  154                 db        0h, 54h, 74h,0E3h
  155                 db      0FFh
  156                                                 ; 800 x 600 mode
  157 x800y600        db      800/8                   ; number of screen columns
  158                 db      600/16                  ; number of screen rows
  159                 db       74h, 63h, 64h, 97h     ; CRTC Registers
  160                 db       68h, 95h, 86H,0F0h
  161                 db        0h, 60h,  0h,  0h
  162                 db        0h,  0h,  2h, 85h
  163                 db       5Bh, 8Dh, 57h, 32h
  164                 db        0h, 60h, 80h,0E3h
  165                 db      0FFh
  166 
  167 x360y480        db      360/8                   ; number of screen columns
  168                 db      480/16                  ; number of screen rows
  169                 db       6bh, 59h, 5ah, 8eh     ; CRTC Registers
  170                 db       5eh, 8ah, 0DH,03Eh
  171                 db        0h, 40h, 00h,  0h
  172                 db        0h,  0h,  0h, 31h
  173                 db      0EAh, 0ACh, 0DFh, 2Dh
  174                 db        0h,0E7h, 06h,0E3h
  175                 db      0FFh
  176 
  177 x320y480        db      320/8                   ; number of screen columns
  178                 db      480/16                  ; number of screen rows
  179                 db       5fh, 4fh, 50h, 82h     ; CRTC Registers
  180                 db       54h, 80h, 0DH,03Eh
  181                 db        0h, 40h, 00h,  0h
  182                 db        0h,  0h,  0h,  0h
  183                 db      0EAh, 0AEh, 0DFh, 28h
  184                 db        0h,0E7h, 006h,0E3h
  185                 db      0FFh
  186 
  187 ; mode x from Michael Abrash
  188 x320y240        db      320/8                   ; number of screen columns
  189                 db      240/16                  ; number of screen rows
  190                 db      05fh, 04fh, 050h, 082h
  191                 db      054h, 080h, 0dh, 03eh
  192                 db      00h, 041h, 00h, 00h
  193                 db      00h, 00h, 00h, 00h
  194                 db      0eah, 0ach, 0dfh, 028h
  195                 db      00h, 0e7h, 06h, 0e3h
  196                 db       0ffh
  197 
  198 x320y400        db      320/8                   ; number of screen columns
  199                 db      400/16                  ; number of screen rows
  200                 db       5fh, 4fh, 50h, 82h     ; CRTC Registers
  201                 db       54h, 80h,0bfh, 1fh
  202                 db       00h, 40h, 00h, 00h
  203                 db       00h, 00h, 00h, 00h
  204                 db       9ch, 8eh, 8fh, 28h
  205                 db       00h, 96h,0b9h,0E3h
  206                 db      0FFh
  207 
  208 x640y400        db      640/8                   ; number of screen columns
  209                 db      400/16                  ; number of screen rows
  210                 db       5eh, 4fh, 50h, 01h     ; CRTC Registers
  211                 db       54h, 9fh,0c0h, 1fh
  212                 db       00h, 40h, 00h, 00h
  213                 db       00h, 00h, 00h, 00h
  214                 db       9ch,08eh, 8fh, 28h
  215                 db       00h, 95h,0bch,0c3h
  216                 db       0ffh
  217 ;for VGA
  218 x400y600        db      400/8
  219                 db      600/16
  220                 db      74h,63h,64h,97h
  221                 db      68h,95h,86h,0F0h
  222                 db      00h,60h,00h,00h
  223                 db      00h,00h,00h,31h
  224                 db      5Bh,8Dh,57h,32h
  225                 db      0h,60h,80h,0E3h
  226                 db      0FFh
  227 ;for VGA
  228 x376y564        db      376/8
  229                 db      564/16
  230                 db      6eh,5dh,5eh,91h
  231                 db      62h,8fh,62h,0F0h
  232                 db      00h,60h,00h,00h
  233                 db      00h,00h,00h,31h
  234                 db      37h,89h,33h,2fh
  235                 db      0h,3ch,5ch,0E3h
  236                 db      0FFh
  237 ;for VGA
  238 x400y564        db      400/8
  239                 db      564/16
  240                 db      74h,63h,64h,97h
  241                 db      68h,95h,62h,0F0h
  242                 db      00h,60h,00h,00h
  243                 db      00h,00h,00h,31h
  244                 db      37h,89h,33h,32h
  245                 db      0h,3ch,5ch,0E3h
  246                 db      0FFh
  247 
  248 testati         db      832/8
  249                 db      612/16
  250                 db      7dh,65h,68h,9fh
  251                 db      69h,92h,44h,1Fh
  252                 db      00h,00h,00h,00h
  253                 db      00h,00h,00h,00h
  254                 db      34h,86h,37h,34h
  255                 db      0fh,34h,40h,0E7h
  256                 db      0FFh
  257 
  258                 align   2
  259 
  260 tweaks          dw      offset x704y528         ; tweak table
  261                 dw      offset x704y528
  262                 dw      offset x720y540
  263                 dw      offset x736y552
  264                 dw      offset x752y564
  265                 dw      offset x768y576
  266                 dw      offset x784y588
  267                 dw      offset x800y600
  268                 dw      offset x360y480
  269                 dw      offset x320y400
  270                 dw      offset x640y400         ; Tseng Super VGA
  271                 dw      offset x400y600         ; new tweak (VGA)
  272                 dw      offset x376y564         ; new tweak (VGA)
  273                 dw      offset x400y564         ; new tweak (VGA)
  274                 dw      offset x720y540         ; ATI Tweak
  275                 dw      offset x736y552         ; ATI Tweak
  276                 dw      offset x752y564         ; ATI Tweak
  277                 dw      offset testati          ; ATI 832x816 (works!)
  278                 dw      offset x320y480
  279                 dw      offset x320y240
  280 
  281 tweakflag       dw      0                       ; tweak mode active flag
  282 tweaktype       dw      0                       ; 8 or 9 (320x400 or 360x480)
  283 
  284 bios_vidsave    dw      0                       ; for setfortext/graphics
  285 setting_text    dw      0                       ; flag for setting text mode
  286 chkd_vvs        dw      0                       ; we checked VESAvirtscan
  287 
  288 .CODE
  289 
  290 FRAME   MACRO regs
  291         push    bp
  292         mov     bp, sp
  293         IRP     reg, 
  294           push  reg
  295           ENDM
  296         ENDM
  297 
  298 UNFRAME MACRO regs
  299         IRP     reg, 
  300           pop reg
  301           ENDM
  302         pop bp
  303         ENDM
  304 
  305 
  306 ;                       Video Table Entries
  307 ;
  308 ;       The Video Table has been moved to a FARDATA segment to relieve
  309 ;       some of the pressure on the poor little overloaded 64K DATA segment.
  310 
  311 .code
  312 
  313 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
  314 ;               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
  315         dw 1097,  0eh,   0,   0,   0,   2, 640, 200,  16
  316         db      "IBM VGA (non-std)        ",0,"Register Compatibles ONLY",0
  317         dw 1098,   0h,   0,   0,  18,   7, 320, 480, 256
  318         db      "Hercules Graphics        ",0,"OK: Timothy Wegner       ",0
  319         dw 1099,   8h,   0,   0,   0,  10, 720, 348,   2
  320         db      "Tandy 1000               ",0,"OK: Joseph Albrecht      ",0
  321         dw 1100,   9h,   0,   0,   0,  14, 320, 200,  16
  322         db      "Pdise/AST/COMPAQ VGA     ",0,"OK: Phil Wilson          ",0
  323         dw 1101,  59h,   0,   0,   0,   1, 800, 600,   2
  324         db      140     dup(0)  ; 2 unused slots here default table
  325         db      "Disk/RAM 'Video'         ",0,"Full-Page L-Jet @  75DPI ",0
  326         dw 1104,   3h,   0,   0,   0,  11, 800, 600,   2
  327         db      "Disk/RAM 'Video'         ",0,"Full-Page L-Jet @ 150DPI ",0
  328         dw 1105,   3h,   0,   0,   0,  11,1600,1200,   2
  329         db      "Disk/RAM 'Video'         ",0,"Full-Page Epson @ 120DPI ",0
  330         dw 1106,   3h,   0,   0,   0,  11, 768, 960,   2
  331         db      "Disk/RAM 'Video'         ",0,"Full-Page Paintjet 90DPI ",0
  332         dw 1107,   3h,   0,   0,   0,  11, 960, 720, 256
  333         db      "Disk/RAM 'Video'         ",0,"For Background Fractals  ",0
  334         dw 1108,   3h,   0,   0,   0,  11, 800, 600, 256
  335         db      "Disk/RAM 'Video'         ",0,"For Background Fractals  ",0
  336         dw 1109,   3h,   0,   0,   0,  11,2048,2048, 256
  337         db      280     dup(0)  ; 4 unused slots here default table
  338         db       70     dup(0)  ; 1 slot reserved for unassigned current mode
  339 
  340 
  341 bios_savebuf db 256 dup(0)  ; enough for 4 blocks (64 bytes/block)
  342 
  343 .code
  344 
  345 ;               XGA Graphics mode setup values
  346 ;               (the first two entries in each line
  347 ;               indicate where the table values are to be stored)
  348 ;
  349 ;               1024x768x256 vvv
  350 ;               1024x768x16  -----vvvv
  351 ;               640x480x256  -----------vvvv
  352 ;               640x480x65536 ----------------vvvv
  353 ;               800x600x16   -----------------------vvvv
  354 ;               800x600x256  -----------------------------vvvv
  355 ;               800x600x65536 ----------------------------------vvvv
  356 
  357 xga_twidth dw   9                                       ; width of these tables
  358 
  359 xga_requir dw      0,    0,  0dh,  05h,  01h,  09h,  01h,  01h,  09h    ; adapter requirements
  360 xga_colors dw      0,    0,  256,   16,  256,    0,   16,  256,    0    ; 0 means 64K colors
  361 xga_swidth dw      0,    0, 1024,  512,  640, 1280,  400,  800, 1600    ; bytes / scan line
  362 
  363 xga_val db      004h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; interrupt enable
  364         db      005h, 000h, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh    ; interrupt status
  365         db      000h, 000h, 004h, 004h, 004h, 004h, 004h, 004h, 004h    ; operating mode
  366         db      00ah, 064h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; palette mask
  367         db      001h, 000h, 001h, 001h, 001h, 001h, 001h, 001h, 001h    ; vid mem aper cntl
  368         db      008h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; vid mem aper indx
  369         db      006h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; virt mem ctl
  370         db      009h, 000h, 003h, 002h, 003h, 004h, 002h, 003h, 004h    ; mem access mode
  371         db      00ah, 050h, 001h, 001h, 001h, 001h, 001h, 001h, 001h    ; disp mode 1
  372         db      00ah, 050h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; disp mode 1
  373         db      00ah, 010h, 09dh, 09dh, 063h, 063h, 088h, 088h, 088h    ; horiz tot lo.
  374         db      00ah, 011h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; horiz tot hi.
  375         db      00ah, 012h, 07fh, 07fh, 04fh, 04fh, 063h, 063h, 063h    ; hor disp end lo
  376         db      00ah, 013h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; hor disp end hi
  377         db      00ah, 014h, 080h, 080h, 050h, 050h, 064h, 064h, 064h    ; hor blank start lo
  378         db      00ah, 015h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; hor blank start hi
  379         db      00ah, 016h, 09ch, 09ch, 062h, 062h, 087h, 087h, 087h    ; hor blank end lo
  380         db      00ah, 017h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; hor blank end hi
  381         db      00ah, 018h, 087h, 087h, 055h, 055h, 06ah, 06ah, 06ah    ; hor sync start lo
  382         db      00ah, 019h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; hor sync start hi
  383         db      00ah, 01ah, 09ch, 09ch, 061h, 061h, 084h, 084h, 084h    ; hor sync end lo
  384         db      00ah, 01bh, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; hor sync end hi
  385         db      00ah, 01ch, 040h, 040h, 000h, 000h, 000h, 000h, 000h    ; hor sync pos
  386         db      00ah, 01eh, 004h, 004h, 000h, 000h, 000h, 000h, 000h    ; hor sync pos
  387         db      00ah, 020h, 030h, 030h, 00ch, 00ch, 086h, 086h, 086h    ; vert tot lo
  388         db      00ah, 021h, 003h, 003h, 002h, 002h, 002h, 002h, 002h    ; vert tot hi
  389         db      00ah, 022h, 0ffh, 0ffh, 0dfh, 0dfh, 057h, 057h, 057h    ; vert disp end lo
  390         db      00ah, 023h, 002h, 002h, 001h, 001h, 002h, 002h, 002h    ; vert disp end hi
  391         db      00ah, 024h, 000h, 000h, 0e0h, 0e0h, 058h, 058h, 058h    ; vert blank start lo
  392         db      00ah, 025h, 003h, 003h, 001h, 001h, 002h, 002h, 002h    ; vert blank start hi
  393         db      00ah, 026h, 02fh, 02fh, 00bh, 00bh, 085h, 085h, 085h    ; vert blank end lo
  394         db      00ah, 027h, 003h, 003h, 002h, 002h, 002h, 002h, 002h    ; vert blank end hi
  395         db      00ah, 028h, 000h, 000h, 0eah, 0eah, 058h, 058h, 058h    ; vert sync start lo
  396         db      00ah, 029h, 003h, 003h, 001h, 001h, 002h, 002h, 002h    ; vert sync start hi
  397         db      00ah, 02ah, 008h, 008h, 0ech, 0ech, 06eh, 06eh, 06eh    ; vert sync end
  398         db      00ah, 02ch, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh    ; vert line comp lo
  399         db      00ah, 02dh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh    ; vert line comp hi
  400         db      00ah, 036h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; sprite cntl
  401         db      00ah, 040h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; start addr lo
  402         db      00ah, 041h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; start addr me
  403         db      00ah, 042h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; start addr hi
  404         db      00ah, 043h, 080h, 040h, 050h, 0a0h, 032h, 064h, 0c8h    ; pixel map width lo
  405         db      00ah, 044h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; pixel map width hi
  406         db      00ah, 054h, 00dh, 00dh, 000h, 000h, 001h, 001h, 001h    ; clock sel
  407         db      00ah, 051h, 003h, 002h, 003h, 004h, 002h, 003h, 004h    ; display mode 2
  408         db      00ah, 070h, 000h, 000h, 000h, 000h, 080h, 080h, 080h    ; ext clock sel
  409         db      00ah, 050h, 00fh, 00fh, 0c7h, 0c7h, 007h, 007h, 007h    ; display mode 1
  410         db      00ah, 055h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; Border Color
  411         db      00ah, 060h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; Sprite Pal Lo
  412         db      00ah, 061h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; Sprite Pal hi
  413         db      00ah, 062h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; Sprite Pre Lo
  414         db      00ah, 063h, 000h, 000h, 000h, 000h, 000h, 000h, 000h    ; Sprite Pre hi
  415         db      00ah, 064h, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh    ; Palette Mask
  416         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh    ; end of the list
  417 
  418 
  419 xga_newbank     proc                    ; XGA-specific bank-switching routine
  420         cmp     xga_isinmode,2          ; are we in an XGA-specific mode?
  421         jl      return                  ;  nope.  bail out.
  422         mov     curbk,ax                ; save the new current bank value
  423         mov     dx,xga_reg_base         ; Select Page
  424         add     dx,08h
  425         out     dx,al                   ; assumes bank number is in al
  426 return: ret
  427 xga_newbank     endp
  428 
  429 xga_16linewrite proc    near            ; 16-color Line Write
  430         mov     bx,ax                   ; calculate the # of columns
  431         sub     bx,cx
  432         mov     ax,xga_xdots            ; this many dots / line
  433         mul     dx                      ; times this many lines - ans in dx:ax
  434         push    cx                      ; save the X-value for a tad
  435         shr     cx,1                    ; and adjust for two bits per pixel
  436         add     ax,cx                   ; plus this many x-dots
  437         adc     dx,0                    ; answer in dx:ax - dl=bank, ax=offset
  438         mov     di,ax                   ; save offset in DI
  439         pop     cx                      ; restore the X-value
  440         mov     ax,dx                   ; xga_newbank expects bank in al
  441 new_bank:
  442         call    far ptr xga_newbank
  443 same_bank:
  444         mov     ah,es:[di]              ; grab the old byte value
  445         mov     al,[si]                 ; and the new color value
  446         and     al,0fh                  ; isolate the bits we want
  447         test    cx,1                    ; odd pixel address?
  448         jnz     xga_sk1                 ;  yup
  449         and     ah,0f0h                 ; isolate the low-order
  450         jmp     short   xga_sk2
  451 xga_sk1:and     ah,0fh                  ; isolate the high-order
  452         shl     al,1
  453         shl     al,1
  454         shl     al,1
  455         shl     al,1
  456 xga_sk2:or      al,ah                   ; combine the two nibbles
  457         mov     es:[di],al              ; write the dot
  458         inc     si                      ; increment the source addr
  459         dec     bx                      ; more to go?
  460         jz      done                    ; nope
  461         inc     cx                      ; next pixel
  462         test    cx,1                    ; odd pixel?
  463         jnz     same_bank               ;  yup
  464         inc     di                      ; increment the destination
  465         cmp     di,0                    ; segment wrap?
  466         jnz     same_bank               ;  nope
  467         mov     ax,curbk                ; update the bank cvalue
  468         inc     ax
  469         jmp     new_bank
  470 done:   ret
  471 xga_16linewrite         endp
  472 
  473 xga_super16addr proc near               ; can be put in-line but shared by
  474                                         ; read and write routines
  475         clc                             ; clear carry flag
  476         push    ax                      ; save this for a tad
  477         mov     ax,xga_xdots            ; this many dots / line
  478         mul     dx                      ; times this many lines - ans in dx:ax
  479         push    cx                      ; save the X-value for a tad
  480         shr     cx,1                    ; and adjust for two bits per pixel
  481         add     ax,cx                   ; plus this many x-dots
  482         adc     dx,0                    ; answer in dx:ax - dl=bank, ax=offset
  483         pop     cx                      ; restore the X-value
  484         mov     bx,ax                   ; save this in BX
  485         cmp     dx,curbk                ; see if bank changed
  486         je      same_bank               ; jump if old bank ok
  487         mov     ax,dx                   ; xga_newbank expects bank in al
  488         call    far ptr xga_newbank
  489 same_bank:
  490         pop     ax                      ; restore AX
  491         ret
  492 xga_super16addr endp
  493 
  494 xga_16write     proc near               ; XGA 256 colors write-a-dot
  495         call    xga_super16addr         ; calculate address and switch banks
  496         mov     ah,es:[bx]              ; grab the old byte value
  497         and     al,0fh                  ; isolate the bits we want
  498         test    cx,1                    ; odd pixel address?
  499         jnz     xga_sk1                 ;  yup
  500         and     ah,0f0h                 ; isolate the low-order
  501         jmp     short   xga_sk2
  502 xga_sk1:and     ah,0fh                  ; isolate the high-order
  503         shl     al,1
  504         shl     al,1
  505         shl     al,1
  506         shl     al,1
  507 xga_sk2:or      al,ah                   ; combine the two nibbles
  508         mov     es:[bx],al              ; write the dot
  509         ret                             ; we done.
  510 xga_16write     endp
  511 
  512 xga_16read      proc near               ; XGA 256 colors read-a-dot
  513         call    xga_super16addr         ; calculate address and switch banks
  514         mov     al,es:[bx]              ; read the dot
  515         test    cx,1                    ; odd number of pixels?
  516         jz      xga_sk1                 ;  nope
  517         shr     ax,1                    ; adjust for odd pixel count
  518         shr     ax,1
  519         shr     ax,1
  520         shr     ax,1
  521 xga_sk1:and     ax,0fh                  ; isolate the byte value
  522         ret                             ; we done.
  523 xga_16read      endp
  524 
  525 xga_clear       proc    uses es si di   ; clear the XGA memory
  526         cmp     xga_clearvideo,0        ; should we really do this?
  527         jne     return                  ;  nope.  skip it.
  528         mov     bx,xga_result           ; find out how much memory we have
  529         and     bx,08h                  ;  in 64K pages
  530         add     bx,08h
  531         mov     ax,0a000h               ; set up to clear 0a0000-0affff
  532         push    ax
  533         pop     es
  534 xloop:  mov     ax,bx                   ; initialize the bank addr
  535         call    xga_newbank
  536         mov     ax,0
  537         mov     cx,16384                ; clear out 32K
  538         mov     di,0
  539         rep     stosw
  540         mov     cx,16384                ; clear out 32K
  541         rep     stosw
  542         dec     bx                      ; another page?
  543         cmp     bx,0
  544         jge     xloop
  545 return: ret
  546 xga_clear       endp
  547 
  548 xga_setpalette  proc    uses es si di, palette:word     ; set the XGA palette
  549         cmp     xga_isinmode,2          ; are we in an XGA graphics mode?
  550         jl      return                  ;  nope
  551 
  552         mov     dx,xga_reg_base         ; wait for a retrace
  553         add     dx,5
  554         mov     al,1                    ; clear the start-of-blanking
  555         out     dx,al
  556 bloop:  in      al,dx
  557         test    al,01h                  ; blanking started?
  558         jz      bloop                   ;  nope - try again
  559 
  560         mov     dx,xga_reg_base         ; set up for a palette load
  561         add     dx,0ah
  562         mov     ax,0064h                ; make invisible
  563         out     dx,ax
  564         mov     ax,0055h                ; border color
  565         out     dx,ax
  566         mov     ax,0066h                ; palette mode
  567         out     dx,ax
  568         mov     ax,0060h                ; start at palette 0
  569         out     dx,ax
  570         mov     ax,0061h
  571         out     dx,ax
  572 
  573         mov     si,palette
  574         mov     cx,768
  575         mov     ax,065h                 ; palette update
  576         out     dx,al
  577         inc     dx                      ; palette data
  578 .186
  579         rep     outsb
  580 .8086
  581         dec     dx
  582 
  583         mov     ax,0ff64h               ; make visible
  584         out     dx,ax
  585 
  586 return: ret
  587 xga_setpalette  endp
  588 
  589 xga_detect      proc    uses es di si
  590 
  591         cmp     xga_reg_base,-2         ; has the XGA detector already failed?
  592         jne     xga_sk1                 ; ne = not yet
  593         jmp     xga_notfound            ; e = yes, fail again
  594 xga_sk1:cmp     xga_reg_base,-1         ; have we already found the XGA?
  595         je      xga_loc                 ; e = no
  596         jmp     xga_found               ; yes, process it
  597 
  598 xga_loc:push    bp                      ; save around int 10H calls
  599         mov     ax,1f00h                ; XGA-2 detect:
  600         int     10h                     ;  get DMQS length
  601         pop     bp                      ; restore BP
  602         cmp     al,1fh                  ; did this work?
  603         jne     xga_man                 ;  nope - try the older, manual approach
  604         cmp     bx,768                  ; room for the results?
  605         ja      xga_man                 ;  no?!?  try the older approach
  606         mov     ax,1f01h                ; get DMQS info
  607         push    ds                      ;  into here
  608         pop     es                      ;  ...
  609         mov     di, offset dacbox       ;  ...
  610         int     10h                     ;  ...
  611         cmp     al,1fh                  ; safety first
  612         jne     xga_man                 ; ?? try the older approach
  613         mov     bx, word ptr dacbox+09h ; get the register base
  614         mov     xga_reg_base,bx         ; save the results
  615         mov     xga_result,1            ; say we found an adapter
  616         cmp     byte ptr dacbox+15h,4   ; do we have 1MB of adapter RAM?
  617         jb      @F                      ;  nope
  618         or      xga_result,8h           ;  yup - say so.
  619 @@:     mov     bx, word ptr dacbox+13h ; get the composite monitor ID
  620         and     bx,0f00h                ; high-rez-monitor?
  621         cmp     bx,0f00h                ;  ..
  622         je      @F                      ;  nope
  623         or      xga_result,4            ;  yup
  624 @@:     jmp     xga_found               ; say we found the adapter
  625 
  626 xga_man:mov     ah,35h                  ; DOS get interrupt vector
  627         mov     al,15h                  ; Int 15h
  628         int     21h                     ; returns vector in es:bx
  629         mov     ax,es                   ; segment part
  630         or      ax,ax                   ; undefined vector?
  631         jnz     xga_sk2                 ; nz = no, OK so far
  632         jmp     xga_notfound            ; z = yes - not an MCA machine
  633 xga_sk2:mov     dx,-1                   ; start with an invalid POS address
  634         mov     ax,0c400h               ; look for POS base address
  635         int     15h                     ;  (Microchannel machines only)
  636         jnc     xga_sk3                 ; nc = success
  637         jmp     xga_notfound            ; error - not an MC machine
  638 xga_sk3:mov     xga_pos_base,dx         ; save pos_base_address
  639         xor     cx,cx                   ; check all MCA slots & motherboard
  640         cmp     dx,-1                   ; do we have a good POS?
  641         jne     xga_lp1                 ; ne = yes, proceed with MCA checks
  642         jmp     xga_notfound            ; no, fail
  643 xga_lp1:cli                             ; no interrupts, please
  644         cmp     cx,0                    ; treat the motherboard differently?
  645         jne     xga_sk4                 ; ne = yes
  646         mov     al,0dfh                 ; enable the motherboard for setup
  647         mov     dx,94h
  648         out     dx,al
  649         jmp     short xga_sk5
  650 xga_sk4:mov     ax,0c401h               ; enable an MCA slot for setup
  651         mov     bx,cx                   ;  this slot
  652         int     15h
  653 xga_sk5:mov     dx,xga_pos_base         ; get pos record for the slot ID
  654         in      ax,dx
  655         mov     xga_cardid,ax
  656         add     dx,2                    ; compute IO Res Base
  657         in      al,dx                   ;  get POS data byte1
  658         mov     byte ptr xga_1mb,al     ;   save it temporarily
  659         inc     dx                      ; switch to byte 2
  660         in      al,dx                   ;  get POS data
  661         mov     byte ptr xga_1mb+1,al   ;   save it temporarily
  662         inc     dx                      ; switch to byte 3
  663         in      al,dx                   ;  get POS data
  664         mov     byte ptr xga_1mb+2,al   ;   save it temporarily
  665         inc     dx                      ; switch to byte 4
  666         in      al,dx                   ;  get POS data
  667         mov     byte ptr xga_1mb+3,al   ;   save it temporarily
  668         cmp     cx,0                    ; treat the motherboard differently
  669         jne     xga_sk6                 ; ne = yes
  670         mov     al,0ffh                 ; enable the motherboard for normal
  671         out     094h,al
  672         jmp     short xga_sk7
  673 xga_sk6:mov     ax,0c402h               ; enable the MCA slot for normal
  674         mov     bx,cx                   ;  this slot
  675         int     15h
  676 xga_sk7:sti                             ; interrupts on again
  677 
  678         mov     ax,xga_cardid           ; is an XGA adapter on this slot?
  679         cmp     ax,08fd8h
  680         jae     xga_sk8                 ; ae = yes
  681         jmp     xga_lp2                 ; try another slot
  682 xga_sk8:cmp     ax,08fdbh               ; still within range?
  683         jbe     xga_sk9                 ; be = yes
  684         jmp     xga_lp2                 ; no, try another slot
  685 
  686 xga_sk9:mov     al,byte ptr xga_1mb     ;  restore POS data byte 1
  687         and     ax,0eh                  ;  muck about with it to get reg base
  688         shl     ax,1
  689         shl     ax,1
  690         shl     ax,1
  691         add     ax,2100h
  692         mov     xga_reg_base,ax
  693         mov     dx,xga_reg_base         ; is there a monitor on this slot?
  694         add     dx,0ah
  695         mov     al,052h
  696         out     dx,al
  697         mov     dx,xga_reg_base
  698         add     dx,0bh
  699         in      al,dx
  700         and     al,0fh
  701         cmp     al,00h                  ; illegal value, returned under Win 3.0
  702         je      xga_lp2
  703         cmp     al,0fh
  704         jne     xga_isthere             ; ne = yes
  705 
  706 xga_lp2:inc     cx                      ; try another adapter?
  707         cmp     cx,9                    ; done all slots?
  708         ja      xga_ska                 ; a = yes
  709         jmp     xga_lp1                 ; no, try another slot
  710 
  711 xga_ska:jmp     xga_notfound            ; forget it - no XGA here
  712 
  713 xga_isthere:
  714         and     ax,06h                  ; strip off the low & high bit
  715         xor     ax,05h                  ; reverse the 3rd & low bits
  716         mov     xga_result,ax           ; save the result flag
  717 
  718         mov     dx,xga_reg_base         ; is this XGA in VGA mode?
  719         in      al,dx
  720         test    al,1
  721         jnz     xga_skb                 ; nz = yes - single-monitor setup
  722         or      xga_result,10h          ;  dual-monitor setup
  723 xga_skb:
  724 
  725         mov     ah,byte ptr xga_1mb+2   ; retrieve POS data byte 3
  726         and     ax,0fe00h               ; eliminate the low-order bits
  727         mov     bl,byte ptr xga_1mb     ; retrieve POS data byte 1
  728         and     bx,0eh                  ; strip it down to the IODA
  729         mov     cx,5                    ; shift it up 5 bits
  730         shl     bx,cl
  731         or      ax,bx                   ; compute the 4MB aperture value
  732         mov     word ptr xga_4mb+2,ax   ; save the result
  733 
  734         mov     al, byte ptr xga_1mb+3  ; retrieve POS data byte 4
  735         and     ax,0fh                  ; select the 1MB aperture bits
  736         mov     cx,4                    ; shift it up 4 bits
  737         shl     ax,cl
  738         mov     word ptr xga_1mb+2,ax   ; save the result
  739         mov     ax,0
  740         mov     word ptr xga_1mb,ax
  741 
  742         mov     dx,xga_reg_base         ; Interrupt Disable
  743         add     dx,4
  744         xor     al,al
  745         out     dx,al
  746 
  747         mov     dx,xga_reg_base         ; Switch to Extended Mode
  748 ;;      add     dx,00h
  749         mov     al,4
  750         out     dx,al
  751 
  752         mov     dx,xga_reg_base         ; Aperture Control
  753         add     dx,01h
  754         mov     al,1
  755         out     dx,al
  756 
  757         mov     dx,xga_reg_base         ; disable Palette Mask
  758         add     dx,0ah
  759         mov     ax,0064h
  760         out     dx,ax
  761 
  762         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
  763 
  764         mov     dx,xga_reg_base         ; Switch to VGA Mode
  765 ;;      add     dx,00h
  766         mov     al,1
  767         out     dx,al
  768 
  769         mov     dx,03c3h                ; Enable VGA Address Code
  770         mov     al,1
  771         out     dx,al
  772 
  773         jmp     short   xga_found
  774 
  775 xga_notfound:
  776         mov     xga_reg_base,-2         ; set failure flag
  777 xga_found:
  778         mov     ax,xga_result           ; return the result
  779         ret
  780 
  781 xga_detect      endp
  782 
  783 xga_mode        proc    uses es di si, mode:word
  784 
  785         mov     curbk,-1                ; preload impossible bank number
  786 
  787         call    xga_detect              ; is an XGA adapter present?
  788         cmp     ax,0
  789         jne     whichmode
  790         jmp     nope                    ;  nope
  791 whichmode:
  792         mov     bx,mode
  793         cmp     bx,xga_twidth           ; mode number out of range?
  794         jb      whichmode0
  795         jmp     nope                    ;  yup - fail right now.
  796 whichmode0:
  797         cmp     mode,0                  ; 80-col VGA text mode?
  798         jne     whichmode1
  799         jmp     mode_0                  ;  yup
  800 whichmode1:
  801         cmp     mode,1                  ; 132-col VGA text mode?
  802         jne     whichmode2
  803         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
  804         call    xga_clear               ; clear out the memory
  805         mov     curbk,-1                ; reset the bank counter
  806 
  807         mov     dx,xga_reg_base         ; set up for final loads
  808         add     dx,0ah
  809         mov     bx,mode                 ; how many colors do we have?
  810         add     bx,mode
  811         cmp     xga_colors[bx],0        ; "true color" mode?
  812         jne     modsk4                  ; nope - skip the funny palette load
  813 
  814         mov     ax,0064h                ; make invisible
  815         out     dx,ax
  816         mov     ax,8055h                ; border color
  817         out     dx,ax
  818         mov     ax,0066h                ; palette mode
  819         out     dx,ax
  820         mov     ax,0060h                ; start at palette 0
  821         out     dx,ax
  822         mov     ax,0061h                ; ""
  823         out     dx,ax
  824 
  825         mov     cx,0                    ; ready to update the palette
  826         mov     al,065h                 ; palette update
  827         out     dx,al
  828         inc     dx                      ; palette data
  829 model3: mov     al,0                    ; zero out the...
  830         out     dx,al                   ;  red value
  831         out     dx,al                   ;  and the green value
  832         mov     al,cl                   ; klooge up the blue value
  833         and     al,1fh                  ; convert to 1,2,...1f
  834         shl     al,1                    ; convert to 2,4,...3e
  835         shl     al,1                    ; convert to 4,8,...7c
  836         shl     al,1                    ; convert to 8,16,..fd
  837         out     dx,al                   ; blue value
  838         inc     cx                      ; another palette value to go?
  839         cmp     cx,128
  840         jb      model3
  841         dec     dx                      ; back to normal
  842 
  843         mov     ax,0ff64h               ; make the palette visible
  844         out     dx,ax
  845         jmp     ok
  846 
  847 modsk4: mov     bx, offset paldata      ; reset the palette
  848         push    bx
  849         mov     xga_isinmode,2
  850         call    xga_setpalette
  851         pop     bx
  852         jmp     ok
  853 
  854 mode_0:                                 ; Set 80 column mode
  855         mov     dx,xga_reg_base         ; Aperture Control
  856         add     dx,01h
  857         xor     al,al                   ; (disable the XGA 64K aperture)
  858         out     dx,al
  859 
  860         mov     dx,xga_reg_base         ; Interrupt Disable
  861         add     dx,4
  862         xor     al,al
  863         out     dx,al
  864 
  865         mov     dx,xga_reg_base         ; Clear Interrupts
  866         add     dx,5
  867         mov     al,0ffh
  868         out     dx,al
  869 
  870         test    xga_result,10h          ; dual monitor setup?
  871         jz      mode_0a
  872         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
  873 
  874 nope:
  875         mov     xga_isinmode,0
  876         mov     ax,0                    ; return failure
  877         ret
  878 ok:
  879         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
  880 ;       the January/February 1989 "Programmer's Journal" and files uploaded
  881 ;       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.
  882 
  883 VGA_SEGMENT       EQU   0A000h
  884 SC_INDEX          EQU   3C4h     ;Sequence Controller Index register
  885 GC_INDEX          EQU   3CEh     ;Graphics Controller Index register
  886 CRTC_INDEX        EQU   3D4h     ;CRT Controller Index register
  887 MAP_MASK          EQU   2        ;Map Mask register index in SC
  888 MEMORY_MODE       EQU   4        ;Memory Mode register in SC
  889 MAX_SCAN_LINE     EQU   9        ;Maximum Scan Line reg index in CRTC
  890                                  ;Use 9 for 2 pages of 320x400
  891 ;MAX_SCAN_LINE    EQU   1        ;Use 1 for 4 pages of 320x200
  892 START_ADD_HIGH    EQU   0Ch      ;Start Address High reg index in CRTC
  893 UNDERLINE         EQU   14h      ;Underline Location reg index in CRTC
  894 MODE_CONTROL      EQU   17h      ;Mode Control reg index in CRTC
  895 READ_MAP          EQU   4        ;Read Mask register index in SC
  896 GRAPHICS_MODE     EQU   5        ;Graphics Mode register index in SC
  897 MISC              EQU   6        ;Miscellaneous register index in SC
  898 WORD_OUTS_OK      EQU   1        ;set to 0 to assemble for computers
  899                                  ;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
  900         clc                             ; clear carry flag
  901         push    ax                      ; save this for a tad
  902         mov     ax,vxdots               ; this many dots / line
  903         mul     dx                      ; times this many lines - ans in dx:ax
  904         add     ax,cx                   ; plus this many x-dots
  905         adc     dx,0                    ; answer in dx:ax
  906         shr     dx,1                    ; shift the answer right one bit
  907         rcr     ax,1                    ;  .. in the 32-bit DX:AX combo
  908         mov     bx,ax                   ; save this in BX
  909         cmp     dx,curbk                ; see if bank changed
  910         je      atisame_bank            ; jump if old bank ok
  911         mov     ax,dx                   ; newbank expects bank in al
  912         call    far ptr newbank
  913 atisame_bank:
  914         pop     ax                      ; restore AX
  915         ret
  916 ati1024addr     endp
  917 
  918 ;
  919 ;	VESA true-color routines
  920 
  921 ; ************** Function dac_to_rgb() *******************
  922 
  923 ;       returns the rgb values (in bl, dh & dl) corresponding to the
  924 ;       color (passed in ax) entry in dacbox
  925 
  926 ; dac_to_rgb -----------------------------------------------------------------
  927 ; * changed to return dl=blue, dh=green (was dl=green, dh=blue) - bl=red stays
  928 ; (is called only by VESAtruewrite, and videoram bgr layout needs this change)
  929 ; ------------------------------------------------------------30-06-2002-ChCh-
  930 
  931 dac_to_rgb      proc    uses di
  932         cmp     truemode,0
  933         jne     @f
  934         mov     bx,ax
  935         add     ax,bx
  936         add     ax,bx                   ; ax * 3
  937         mov     di,ax
  938         mov     bl,dacbox+0[di]         ; red
  939         mov     dh,dacbox+1[di]         ; green
  940         mov     dl,dacbox+2[di]         ; blue
  941         ret                             ; we done.
  942 @@:
  943         cmp     truemode,1
  944         jne     @f
  945         mov     dx,word ptr realcoloriter
  946 ;        xchg    dh,dl
  947         mov     ax,word ptr realcoloriter+2
  948         mov     bl,al                   ; red
  949         ret                             ; we done.
  950 @@:                                     ; truemode = 2
  951         cmp     truemode,2
  952         jne     @f
  953         mov     dx,word ptr coloriter
  954 ;        xchg    dh,dl
  955         mov     ax,word ptr coloriter+2
  956         mov     bl,al                   ; red
  957         ret                             ; we done.
  958 @@:                                     ; truemode = 3
  959         mov     ax,word ptr coloriter
  960         mov     dl,al                   ; blue
  961         mov     cx,4
  962         shl     ax,cl
  963         mov     dh,ah                   ; green
  964 ;        mov     ax,word ptr coloriter+2
  965         neg     ax
  966         mov     bl,ah                   ; red
  967         ret                             ; we done.
  968 dac_to_rgb      endp
  969 
  970 ; ************** Function rgb_to_dac() *******************
  971 
  972 ;       returns the dac index value (in al, ah=0) corresponding to the
  973 ;       rgb values (passed in bl, dh & dl)
  974 
  975 ; rgb_to_dac -----------------------------------------------------------------
  976 ; * changed to await dl=blue, dh=green (was dl=green, dh=blue) - bl=red stays
  977 ; (is called only by VESAtrueread, and videoram bgr layout needs this change)
  978 ; ------------------------------------------------------------30-06-2002-ChCh-
  979 
  980 rgb_to_dac      proc
  981 LOCAL red:word, green:word, blue:word
  982         xor     bh,bh
  983         mov     red,bx
  984         mov     bl,dh
  985         mov     green,bx
  986         mov     bl,dl
  987         mov     blue,bx
  988         mov     si,0                    ; look for the nearest DAC value
  989         mov     di,0                    ; di = closest DAC
  990         mov     cx,65535                ; cx = closest squared error
  991 nextentry:
  992 ;        mov     bx,0                    ; bx = this entry's squared error
        mov     ax,red                  ; ax = red portion
        mov     dh,0
        mov     dl,dacbox[si]
        sub     ax,dx                   ; ax = (color - DAC color)
        mov     dx,ax
        imul    dx                      ; ax = color squared error
        mov     bx,ax                   ; bx = total squared error
        mov     ax,green                ; ax = green portion
        mov     dh,0
        mov     dl,dacbox+1[si]
        sub     ax,dx                   ; ax = (color - DAC color)
        mov     dx,ax
        imul    dx                      ; ax = color squared error
        add     bx,ax                   ; bx = total squared error
        mov     ax,blue                 ; ax = blue portion
        mov     dh,0
        mov     dl,dacbox+2[si]
        sub     ax,dx                   ; ax = (color - DAC color)
        mov     dx,ax
        imul    dx                      ; ax = color squared error
        add     bx,ax                   ; bx = total squared error
        cmp     bx,cx                   ; new closest value?
        jae     @f                      ;  nope
        mov     di,si                   ; yes - save this entry
        mov     cx,bx                   ;  and its error
@@:     cmp     cx,0                    ; did we find a perfect match?
        je      @f                      ;  yup - we're done!
  993         add     si,3                    ; move to a new DAC entry
  994         cmp     si,256*3                ; are we out of entries?
  995         jb      nextentry               ;  nope
  996 @@:     mov     ax,di                   ; convert DI back into a palette value
  997         mov     bx,3                    ;  by dividing by 3
  998         div     bl
  999         mov     ah,0
 1000         ret                             ; we done.
 1001 rgb_to_dac      endp
 1002 
 1003 ; VESAtruewrite --------------------------------------------------------------
 1004 ; * the major change is calling VESAtrueaddr just once (was three times!)
 1005 ; * this also frees use of some registers, so local variables are removed
 1006 ; * a minor fix in unusual r-g-b layout (was b-g-b) does any card use it?
 1007 ; ------------------------------------------------------------30-06-2002-ChCh-
 1008 
 1009 VESAtruewrite   proc near               ; VESA true-color write-a-dot
 1010 ; color index is passed in ax
 1011         push    ax
 1012         call    VESAtrueaddr            ; calculate address and switch banks
 1013         pop     ax
 1014         push    dx                      ; bank needed later
 1015         push    bx                      ; offset as well
 1016         call    dac_to_rgb              ; ax=color -> dx=gb, bl=r
 1017         mov     ax,vesa_winaseg         ; VESA video starts here
 1018         cmp     vesa_bitsppixel,17      ; 8-8-8 and 8-8-8-8
 1019         mov     es,ax
 1020         jnb     over_hi
 1021         mov     cx,111111b              ; mask
 1022         mov     al,dh                   ; green
 1023         and     dx,cx                   ; blue
 1024         and     bx,cx                   ; red
 1025         and     ax,cx
 1026         mov     cl,vesa_redpos
 1027         cmp     vesa_greensize,6        ; 5-5-5 or 5-6-5
 1028         je      got_6g
 1029         shr     ax,1
 1030 got_6g:
 1031         shr     bx,1
 1032         shr     dx,1
 1033         shl     bx,cl
 1034         mov     cl,vesa_greenpos
 1035         or      dx,bx                   ; r-_-b
 1036         shl     ax,cl
 1037         pop     bx
 1038         or      dx,ax                   ; r-g-b
 1039         pop     ax
 1040         mov     word ptr es:[bx],dx     ; write two bytes for the dot
 1041         jmp     short wedone
 1042 over_hi:                                ; 8-8-8 or 8-8-8-8?
 1043         mov     cx,bx                   ; r
 1044         shl     dx,1                    ; well, 6-6-6 is not true-true
 1045         shl     cx,1
 1046         shl     dx,1                    ; b-g
 1047         shl     cx,1
 1048         cmp     vesa_redpos,0           ; common b-g-r model?
 1049         jne     doit_slow
 1050         xchg    dl,cl                   ; else turn to unusual r-g-b
 1051 doit_slow:
 1052         pop     bx                      ; get offset
 1053         pop     ax                      ; get bank
 1054         inc     bx                      ; does a word fit to this bank?
 1055         jz      badbank1                ; no, switch one byte after
 1056         mov     word ptr es:[bx-1],dx   ; else plot that word
 1057         push    cx                      ; hand it over to the switch
 1058         inc     bx                      ; bank-end?
 1059         jz      badbank2                ; yes, switch it
 1060         mov     es:[bx],cl              ; else write the third byte
 1061         pop     cx                      ; wasn't needed - no switching
        jmp     short wedone
badbank1:
        dec     bx                      ; bx=0ffffh
        mov     es:[bx],dl              ; plot the first byte
        xchg    dh,dl                   ; second color for badbank2
        push    dx                      ; hand it over
badbank2:
        inc     ax                      ; next bank needed
        call    far ptr newbank
        pop     ax                      ; get next color
        inc     bx                      ; badbank1 or badbank2?
        mov     es:[0],al               ; plot that color
        jnz     wedone                  ; badbank2 - nothing more to do
        mov     es:[1],cl               ; badbank1 - plot the last byte
wedone:
        ret                             ; we done.
VESAtruewrite   endp

; VESAtrueread ---------------------------------------------------------------
; * similar changes as in VESAtruewrite
; * hi-color-word rgb extraction quite shortened
; ------------------------------------------------------------30-06-2002-ChCh-

VESAtrueread    proc near               ; VESA true-color read-a-dot
; color index is returned in ax
        call    VESAtrueaddr            ; calculate address and switch banks
        mov     ax,vesa_winaseg         ; VESA video starts here
        cmp     vesa_bitsppixel,17      ; 8-8-8 and 8-8-8-8
        mov     es,ax
        jnb     over_hi
        mov     dx,word ptr es:[bx]     ; read two bytes
        mov     cl,3
        mov     bx,dx
        shl     dx,cl
        mov     cl,vesa_redpos
        shr     dl,1
        shr     bx,cl
        shr     dl,1                    ; blue in dl
        cmp     vesa_greensize,6
        je      got_6g
        shl     dh,1
got_6g:
        shl     bx,1                    ; red in bl
        and     dh,111111b              ; green in dh
        jmp     short wedone
over_hi:                                ; 8-8-8 or 8-8-8-8?
        mov     ax,dx                   ; newbank expects bank in ax
        inc     bx                      ; does a word fit to this bank?
        jz      badbank1                ; no, switch one byte after
        mov     dx,word ptr es:[bx-1]   ; else read that word
        inc     bx                      ; bank-end?
        jz      badbank2                ; yes, switch it
        mov     bl,es:[bx]              ; else read the third byte
        jmp     short colors_in
badbank1:
        dec     bx                      ; bx=0ffffh
        mov     dl,es:[bx]              ; read the first byte
badbank2:
        inc     ax                      ; next bank needed
        call    far ptr newbank
        inc     bx                      ; badbank1 or badbank2?
        mov     bl,es:[0]               ; read next color
        jnz     colors_in               ; badbank2 - nothing more to do
        mov     dh,bl
        mov     bl,es:[1]               ; badbank1 - read the last byte
colors_in:
        and     dx,0FCFCh               ; mask-out 2 g & 2 b lsbs for shift
        shr     bl,1
        shr     dx,1
        shr     bl,1
        shr     dx,1
        cmp     vesa_redpos,0
        jne     wedone
        xchg    bl,dl
wedone:
        call    rgb_to_dac              ; put dac index in ax
        ret                             ; we done.
VESAtrueread    endp

; VESAtrueaddr ---------------------------------------------------------------
; * changed to not to take into account vesabyteoffset
; ------------------------------------------------------------30-06-2002-ChCh-

VESAtrueaddr    proc near
        mov     bx,cx                   ; adjust the pixel location
        cmp     vesa_bitsppixel,17      ; 2 bytes/pixel
        jb      depth_ok                ; write a word at a time, no offset
        shl     bx,1                    ; +x
        cmp     vesa_bitsppixel,25      ; 3 bytes/pixel
        jb      depth_ok                ; else 4 bytes/pixel
        add     bx,cx                   ; +x
depth_ok:
        mov     ax,vxdots               ; this many dots / line
        add     bx,cx                   ; +x
        mul     dx                      ; times this many lines - ans in dx:ax
        add     bx,ax                   ; plus this many x-dots
        adc     dx,0                    ; answer in dx:ax - dl=bank, ax=offset
        cmp     dx,curbk                ; see if bank changed
        je      same_bank               ; jump if old bank not ok
        mov     ax,dx                   ; newbank expects bank in al
        call    far ptr newbank
same_bank:
        ret                             ; we done.
VESAtrueaddr    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)
 1062 ;       (switched to John's 1/5/90 version on 1/9/90  - Bert)
;       (switched to John's version 3 on 4/27/90  - Bert)
 1063 ;       (added logic for various resolution on 9/10/90 - Bert)
 1064 ;       (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

istruecolor		dw	0	; set to 1 if VESA truecolor mode
align 2
; vesabytes		db	0,0,0,0	; our true-color pixel
; vesabyteoffset		dw	0	; used in true-color routines

;	the first 40 bytes of the 256-byte VESA mode-info block

vesa_mode_info	dw	0		; mode info: attributes
vesa_winaattrib	db	0		; Win AA attribs 
vesa_winbattrib	db	0		; Win BB attribs 
vesa_wingran	dw	0		; window granularity
vesa_winsize	dw	0		; window size
vesa_winaseg	dw	0		; window AA segment
vesa_winbseg	dw	0		; window BB segment
vesa_funcptr	dd	0		; bank_switcher
vesa_bytespscan	dw	0		; bytes per scan line
vesa_xres	dw	0		; X-resolution
vesa_yres	dw	0		; Y-resolution
vesa_xcharsize	db	0		; X charsize
vesa_ycharsize	db	0		; Y charsize
vesa_numplanes	db	0		; number of planes
vesa_bitsppixel	db	0		; bits / pixel
vesa_numbanks	db	0		; number of banks
vesa_memmodel	db	0		; memory-model type
vesa_banksize	db	0		; bank size in KB
vesa_numpages	db	0		; number of complete images
vesa_rsvd	db	0		; reserved for page function
vesa_redsize	db	0		; red mask size
vesa_redpos	db	0		; red mask position
vesa_greensize	db	0		; green mask size
vesa_greenpos	db	0		; green mask position
vesa_bluesize	db	0		; blue mask size
vesa_bluepos	db	0		; blue mask position
vesa_rsvdsize	db	0		; reserved mask size
vesa_rsvdpos	db	0		; reserved mask position
vesa_directinfo	db	0		; direct-color-mode attributes

        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)
 1065         out     dx,ax
 1066         mov     dx,46e8h        ;bring chip out of setup mode
 1067         mov     ax,0eh
 1068         out     dx,ax
 1069         mov     ah,byte ptr OSEG[curbk]
 1070         shl     ah,1            ;change 64k bank number into 16k bank number
 1071         shl     ah,1
 1072         mov     al,10h
 1073         mov     dx,3d6h
 1074         out     dx,ax
 1075         sti
 1076         pop     dx
 1077         pop     ax
 1078         ret
 1079 $chipstech endp
 1080 
 1081 $ativga proc            ;ATI VGA Wonder
 1082         push    ax
 1083         push    dx
 1084         mov     ah,al
 1085         mov     dx,1ceh
 1086         mov     al,0b2h
 1087         out     dx,al
 1088         inc     dl
 1089         in      al,dx
 1090         shl     ah,1
 1091         and     al,0e1h
 1092         or      ah,al
 1093         mov     al,0b2h
 1094         dec     dl
 1095         out     dx,ax
 1096         sti
 1097         pop     dx
 1098         pop     ax
 1099         ret
 1100 $ativga endp
 1101 
 1102 $everex proc            ;Everex
 1103         push    ax
 1104         push    dx
 1105         push    cx
 1106         mov     cl,al
 1107         mov     dx,3c4h
 1108         mov     al,8
 1109         out     dx,al
 1110         inc     dl
 1111         in      al,dx
 1112         dec     dl
 1113         shl     al,1
 1114         shr     cl,1
 1115         rcr     al,1
 1116         mov     ah,al
 1117         mov     al,8
 1118         out     dx,ax
 1119         mov     dl,0cch
 1120         in      al,dx
 1121         mov     dl,0c2h
 1122         and     al,0dfh
 1123         shr     cl,1
 1124         jc      nob2
 1125         or      al,20h
 1126 nob2:   out     dx,al
 1127         sti
 1128         pop     cx
 1129         pop     dx
 1130         pop     ax
 1131         ret
 1132 $everex endp
 1133 
 1134 $aheada proc
 1135         push    ax
 1136         push    dx
 1137         push    cx
 1138         mov     ch,al
 1139         mov     dx,3ceh         ;Enable extended registers
 1140         mov     ax,200fh
 1141         out     dx,ax
 1142         mov     dl,0cch         ;bit 0
 1143         in      al,dx
 1144         mov     dl,0c2h
 1145         and     al,11011111b
 1146         shr     ch,1
 1147         jnc     temp_1
 1148         or      al,00100000b
 1149 temp_1: out     dx,al
 1150         mov     dl,0cfh         ;bits 1,2,3
 1151         mov     al,0
 1152         out     dx,al
 1153         inc     dx
 1154         in      al,dx
 1155         dec     dx
 1156         and     al,11111000b
 1157         or      al,ch
 1158         mov     ah,al
 1159         mov     al,0
 1160         out     dx,ax
 1161         sti
 1162         pop     cx
 1163         pop     dx
 1164         pop     ax
 1165         ret
 1166 $aheada endp
 1167 
 1168 $aheadb proc
 1169         push    ax
 1170         push    dx
 1171         push    cx
 1172         mov     ch,al
 1173         mov     dx,3ceh         ;Enable extended registers
 1174         mov     ax,200fh
 1175         out     dx,ax
 1176         mov     ah,ch
 1177         mov     cl,4
 1178         shl     ah,cl
 1179         or      ah,ch
 1180         mov     al,0dh
 1181         out     dx,ax
 1182         sti
 1183         pop     cx
 1184         pop     dx
 1185         pop     ax
 1186         ret
 1187 $aheadb endp
 1188 
 1189 $oaktech proc           ;Oak Technology Inc OTI-067
 1190         push    ax
 1191         push    dx
 1192         and     al,15
 1193         mov     ah,al
 1194         shl     al,1
 1195         shl     al,1
 1196         shl     al,1
 1197         shl     al,1
 1198         or      ah,al
 1199         mov     al,11h
 1200         mov     dx,3deh
 1201         out     dx,ax
 1202         sti
 1203         pop     dx
 1204         pop     ax
 1205         ret
 1206 $oaktech endp
 1207 
 1208 $genoa  proc                    ;GENOA GVGA
 1209         push    ax
 1210         push    dx
 1211         mov     ah,al
 1212         shl     al,1
 1213         shl     al,1
 1214         shl     al,1
 1215         or      ah,al
 1216         mov     al,6
 1217         or      ah,40h
 1218         mov     dx,3c4h
 1219         out     dx,ax
 1220         sti
 1221         pop     dx
 1222         pop     ax
 1223         ret
 1224 $genoa  endp
 1225 
 1226 $ncr    proc                            ;NCR 77C22E
 1227         push    ax
 1228         push    dx
 1229         shl     al,1            ;change 64k bank number into 16k bank number
 1230         shl     al,1
 1231         mov     ah,al
 1232         mov     al,18h
 1233         mov     dx,3c4h
 1234         out     dx,ax
 1235         mov     ax,19h
 1236         out     dx,ax
 1237         sti
 1238         pop     dx
 1239         pop     ax
 1240         ret
 1241 $ncr    endp
 1242 
 1243 $compaq proc                    ;Compaq
 1244         push    ax
 1245         push    dx
 1246         mov     dx,3ceh
 1247         mov     ax,50fh         ;unlock extended registers
 1248         out     dx,ax
 1249         mov     ah,byte ptr OSEG[curbk]
 1250         shl     ah,1            ;change 64k bank number into 4k bank number
 1251         shl     ah,1
 1252         shl     ah,1
 1253         shl     ah,1
 1254         mov     al,45h
 1255         out     dx,ax
 1256         sti
 1257         pop     dx
 1258         pop     ax
 1259         ret
 1260 $compaq endp
 1261 
 1262 ;
 1263 ;  Read/Write 64K pages
 1264 ;
 1265 $vesa1  proc                            ; VESA bank switching
 1266         push    ax
 1267         push    bx
 1268         push    dx
 1269         mul     vesa_granularity        ; Adjust for the granularity factor
 1270         mov     dx,ax                   ; Select window position
 1271         mov     bx,0                    ; select window (bank) sub-command
 1272         call    dword ptr vesa_bankswitch  ; do it!
 1273         pop     dx
 1274         pop     bx
 1275         pop     ax
 1276         sti
 1277         ret
 1278 $vesa1  endp
 1279 ;
 1280 ;  Read-only/Write-only 64K pages
 1281 ;
 1282 $vesa2  proc                            ; VESA bank switching
 1283         push    ax
 1284         push    bx
 1285         push    dx
 1286         mul     vesa_granularity        ; Adjust for the granularity factor
 1287         mov     dx,ax                   ; Select window position
 1288         push    dx
 1289         mov     bx,0                    ; select window (bank) sub-command
 1290         call    dword ptr vesa_bankswitch  ; do it!
 1291         pop     dx
 1292         inc     bx
 1293         call    dword ptr vesa_bankswitch
 1294         pop     dx
 1295         pop     bx
 1296         pop     ax
 1297         sti
 1298         ret
 1299 $vesa2  endp
 1300 ;
 1301 ;  Read/Write 32K pages
 1302 ;
 1303 $vesa3  proc                            ; VESA bank switching
 1304         push    ax
 1305         push    bx
 1306         push    dx
 1307         mul     vesa_granularity        ; Adjust for the granularity factor
 1308         mov     dx,ax                   ; Select window position
 1309         push    dx
 1310         mov     bx,vesa_low_window      ; select window (bank) sub-command
 1311         call    dword ptr vesa_bankswitch  ; do it!
 1312         pop     dx
 1313         add     dx,vesa_gran_offset     ; 2nd window is at 32K offset from 1st
 1314         mov     bx,vesa_high_window
 1315         call    dword ptr vesa_bankswitch
 1316         pop     dx
 1317         pop     bx
 1318         pop     ax
 1319         sti
 1320         ret
 1321 $vesa3  endp
 1322 
 1323 $vesa_nullbank proc ; null routine for vesa_bankswitch when unknown
 1324         ret
 1325 $vesa_nullbank endp
 1326 
 1327 $nobank proc
 1328         sti
 1329         ret
 1330 $nobank endp
 1331 
 1332 bkadr   macro   flag,func,entries               ; Bert
 1333         mov     video_entries, offset entries   ; Bert
 1334         mov     [flag],1
 1335         mov     [bankadr],offset func
 1336 if @CodeSize
 1337         mov     [bankseg],seg func
 1338 endif
 1339         endm
 1340 
 1341 nojmp   macro
 1342         local   lbl
 1343         jmp     lbl
 1344 lbl:
 1345         endm
 1346 
 1347 whichvga proc   near
 1348         push    bp                      ; save it around all the int 10s
 1349 
 1350         cmp     svga_type,0             ; was a SuperVGA adapter forced?
 1351         jne     type1_forced            ;  yup - wade through the options
 1352         jmp     not_forced              ;  nope - skip this section
 1353 type1_forced:
 1354         cmp     svga_type,1
 1355         jne     type2_forced
 1356         bkadr   aheada,$aheada,ahead_entries
 1357 type2_forced:
 1358         cmp     svga_type,2
 1359         jne     type3_forced
 1360         bkadr   ativga,$ativga,ati_entries
 1361 type3_forced:
 1362         cmp     svga_type,3
 1363         jne     type4_forced
 1364         bkadr   chipstech,$chipstech,chips_entries
 1365 type4_forced:
 1366         cmp     svga_type,4
 1367         jne     type5_forced
 1368         bkadr   everex,$everex,everex_entries
 1369 type5_forced:
 1370         cmp     svga_type,5
 1371         jne     type6_forced
 1372         bkadr   genoa,$genoa,genoa_entries
 1373 type6_forced:
 1374         cmp     svga_type,6
 1375         jne     type7_forced
 1376         bkadr   ncr,$ncr,ncr_entries
 1377 type7_forced:
 1378         cmp     svga_type,7
 1379         jne     type8_forced
 1380         bkadr   oaktech,$oaktech,oaktech_entries
 1381 type8_forced:
 1382         cmp     svga_type,8
 1383         jne     type9_forced
 1384         bkadr   paradise,$paradise,paradise_entries
 1385 type9_forced:
 1386         cmp     svga_type,9
 1387         jne     type10_forced
 1388         bkadr   trident,$trident,trident_entries
 1389 type10_forced:
 1390         cmp     svga_type,10
 1391         jne     type11_forced
 1392         bkadr   tseng,$tseng,tseng_entries
 1393 type11_forced:
 1394         cmp     svga_type,11
 1395         jne     type12_forced
 1396         bkadr   tseng4,$tseng4,tseng4_entries
 1397 type12_forced:
 1398         cmp     svga_type,12
 1399         jne     type13_forced
 1400         bkadr   video7,$video7,video7_entries
 1401 type13_forced:
 1402         cmp     svga_type,13
 1403         jne     type14_forced
 1404         bkadr   aheadb,$aheadb,ahead_entries
 1405 type14_forced:
 1406         jmp     fini
 1407 not_forced:
 1408 
 1409         cmp     vesa_detect,0           ; is VESA-detection disabled?
 1410         je      notvesa                 ;  yup - skip this
 1411         mov     ax,4f00h                ; check for VESA adapter
 1412         push    ds                      ; set ES == DS
 1413         pop     es                      ;  ...
 1414         mov     di, offset dacbox       ; answer goes here (a safe place)
 1415         int     10h                     ; do it.
 1416         cmp     ax,004fh                ; successful response?
 1417         jne     notvesa                 ; nope.  Not a VESA adapter
 1418 
 1419         cmp     byte ptr 0[di],'V'      ; string == 'VESA'?
 1420         jne     notvesa                 ; nope.  Not a VESA adapter
 1421         cmp     byte ptr 1[di],'E'      ; string == 'VESA'?
 1422         jne     notvesa                 ; nope.  Not a VESA adapter
 1423         cmp     byte ptr 2[di],'S'      ; string == 'VESA'?
 1424         jne     notvesa                 ; nope.  Not a VESA adapter
 1425         cmp     byte ptr 3[di],'A'      ; string == 'VESA'?
 1426         jne     notvesa                 ; nope.  Not a VESA adapter
 1427         mov     ax,word ptr 18[di]
 1428         mov     video_vram,ax           ; store video memory size
 1429         bkadr   vesa,$vesa_nullbank, vesa_entries
 1430         jmp     fini
 1431 notvesa:
 1432 
 1433         call    xga_detect              ; XGA Adapter?
 1434         cmp     ax,0
 1435         je      notxga                  ; nope
 1436         bkadr   xga,xga_newbank, xga_entries
 1437         jmp     fini
 1438 notxga:
 1439 
 1440         mov     si,1
 1441         mov     ax,0c000h
 1442         mov     es,ax
 1443         cmp     word ptr es:[40h],'13'
 1444         jnz     noati
 1445         bkadr   ativga,$ativga,ati_entries              ; Bert
 1446         mov     dx,es:[10h]             ; Get value of ATI extended register
 1447         mov     bl,es:[43h]             ; Get value of ATI chip version
 1448         cmp     bl,'3'
 1449         jae     v6up                    ; Use different method to determine
 1450         mov     al,0bbh                 ; memory size of chip version is 3 or higher
 1451         cli
 1452         out     dx,al
 1453         inc     dx
 1454         in      al,dx                   ; Get ramsize byte for chip versions 1 & 2
 1455         sti
 1456         test    al,20h
 1457         jz      no512
 1458         mov     [vga512],1
 1459         jmp     short no512
 1460 
 1461 v6up:   mov     al,0b0h                 ; Method used for newer ATI chip versions
 1462         cli
 1463         out     dx,al
 1464         inc     dx
 1465         in      al,dx                   ; Get ramsize byte for versions 3-5
 1466         sti
 1467         test    al,10h                  ; Check if ramsize byte indicates 256K or 512K bytes
 1468         jz      v7up
 1469         mov     [vga512],1
 1470 v7up:   cmp     bl,'4'                  ; Check for ramsize for ATI chip versions 4 & 5
 1471         jb      no512
 1472         test    al,8                    ; Check if version 5 ATI chip has 1024K
 1473         jz      no512
 1474         mov     [vga1024],1
 1475 no512:  jmp     fini
 1476 
 1477 noati:  mov     ax,7000h                ;Test for Everex
 1478         xor     bx,bx
 1479         cld
 1480         int     10h
 1481         cmp     al,70h
 1482         jnz     noev
 1483         bkadr   everex,$everex, everex_entries          ; Bert
 1484         and     ch,11000000b
 1485         jz      temp_2
 1486         mov     [vga512],1
 1487 temp_2: and     dx,0fff0h
 1488         cmp     dx,6780h
 1489         jz      yeste
 1490         cmp     dx,2360h
 1491         jnz     note
 1492 yeste:  bkadr   trident,$trident, everex_entries        ; Bert
 1493         mov     everex,0
 1494 note:   jmp     fini
 1495 
 1496 noev:
 1497         mov     ax,0bf03h               ;Test for Compaq
 1498         xor     bx,bx
 1499         mov     cx,bx
 1500         int     10h
 1501         cmp     ax,0bf03h
 1502         jnz     nocp
 1503         test    cl,40h                  ;is 640x480x256 available? ;(??)
 1504         jz      nocp
 1505         bkadr   compaq,$compaq,compaq_entries           ; Bert
 1506         mov     [vga512],1
 1507         jmp     fini
 1508 
 1509 nocp:   mov     dx,3c4h                 ;Test for NCR 77C22E
 1510         mov     ax,0ff05h
 1511         call    $isport2
 1512         jnz     noncr
 1513         mov     ax,5                    ;Disable extended registers
 1514         out     dx,ax
 1515         mov     ax,0ff10h               ;Try to write to extended register 10
 1516         call    $isport2                ;If it writes then not NCR
 1517         jz      noncr
 1518         mov     ax,105h                 ;Enable extended registers
 1519         out     dx,ax
 1520         mov     ax,0ff10h
 1521         call    $isport2
 1522         jnz     noncr                   ;If it does NOT write then not NCR
 1523         bkadr   ncr,$ncr,ncr_entries            ; Bert
 1524         mov     [vga512],1
 1525         jmp     fini
 1526 
 1527 noncr:  mov     dx,3c4h                 ;Test for Trident
 1528         mov     al,0bh
 1529         out     dx,al
 1530         inc     dl
 1531         in      al,dx
 1532         and     al,0fh
 1533         cmp     al,06h
 1534         ja      notri
 1535         cmp     al,2
 1536         jb      notri
 1537         bkadr   trident,$trident, trident_entries       ; Bert
 1538         cmp     al,3
 1539         jb      no89
 1540         mov     [t8900],1
 1541         mov     dx,3d4h         ; (was 3d5h in version 17.2)
 1542         mov     al,1fh
 1543         out     dx,al
 1544         inc     dx
 1545         in      al,dx
 1546         and     al,3
 1547         cmp     al,1
 1548         jb      notmem
 1549         mov     [vga512],1
 1550         je      notmem
 1551         mov     [vga1024],1
 1552 notmem: jmp     fini
 1553 
 1554 no89:   mov     [vga512],1
 1555         jmp     fini
 1556 
 1557 notri:  mov     ax,6f00h                ;Test for Video 7
 1558         xor     bx,bx
 1559         cld
 1560         int     10h
 1561         cmp     bx,'V7'
 1562         jnz     nov7
 1563         bkadr   video7,$video7, video7_entries          ; Bert
 1564         mov     ax,6f07h
 1565         cld
 1566         int     10h
 1567         and     ah,7fh
 1568         cmp     ah,1
 1569         jbe     temp_3
 1570         mov     [vga512],1
 1571 temp_3: cmp     ah,3
 1572         jbe     temp_4
 1573         mov     [vga1024],1
 1574 temp_4: jmp     fini
 1575 
 1576 nov7:   mov     dx,3d4h                 ;Test for GENOA GVGA
 1577         mov     al,2eh                  ;check for Herchi Register top 6 bits
 1578         out     dx,al
 1579         inc     dx
 1580         in      al,dx
 1581         dec     dx
 1582         test    al,11111100b            ;top 6 bits should be zero
 1583         jnz     nogn
 1584         mov     ax,032eh                ;check for Herchi Register
 1585         call    $isport2
 1586         jnz     nogn
 1587         mov     dx,3c4h
 1588         mov     al,7
 1589         out     dx,al
 1590         inc     dx
 1591         in      al,dx
 1592         dec     dx
 1593         test    al,10001000b
 1594         jnz     nogn
 1595         mov     al,10h
 1596         out     dx,al
 1597         inc     dx
 1598         in      al,dx
 1599         dec     dx
 1600         and     al,00110000b
 1601         cmp     al,00100000b
 1602         jnz     nogn
 1603         mov     dx,3ceh
 1604         mov     ax,0ff0bh
 1605         call    $isport2
 1606         jnz     nogn
 1607         mov     dx,3c4h                 ;check for memory segment register
 1608         mov     ax,3f06h
 1609         call    $isport2
 1610         jnz     nogn
 1611         mov     dx,3ceh
 1612         mov     ax,0ff0ah
 1613         call    $isport2
 1614         jnz     nogn
 1615         bkadr   genoa,$genoa, genoa_entries             ; Bert
 1616         mov     [vga512],1
 1617         jmp     fini
 1618 
 1619 nogn:   call    $cirrus                 ;Test for Cirrus
 1620         cmp     [cirrus],0
 1621         je      noci
 1622         jmp     fini
 1623 
 1624 noci:   mov     dx,3ceh                 ;Test for Paradise
 1625         mov     al,9                    ;check Bank switch register
 1626         out     dx,al
 1627         inc     dx
 1628         in      al,dx
 1629         dec     dx
 1630         or      al,al
 1631         jnz     nopd
 1632 
 1633         mov     ax,50fh                 ;turn off write protect on VGA registers
 1634         out     dx,ax
 1635         mov     dx,offset $pdrsub
 1636         mov     cx,1
 1637         call    $chkbk
 1638         jc      nopd                    ;if bank 0 and 1 same not paradise
 1639         bkadr   paradise,$paradise, paradise_entries    ; Bert
 1640         mov     dx,3ceh
 1641         mov     al,0bh                  ;512k detect from Bob Berry
 1642         out     dx,al
 1643         inc     dx
 1644         in      al,dx
 1645         test    al,80h                  ;if top bit set then 512k
 1646         jz      nop512
 1647         test    al,40h
 1648         jz      nop1024
 1649         mov     [vga1024],1
 1650         jmp     fini
 1651 nop1024:
 1652         mov     [vga512],1
 1653 nop512: jmp     fini
 1654 
 1655 nopd:   mov     ax,5f00h                ;Test for Chips & Tech
 1656         xor     bx,bx
 1657         cld
 1658         int     10h
 1659         cmp     al,5fh
 1660         jnz     noct
 1661         bkadr   chipstech,$chipstech, chips_entries     ; Bert
 1662         cmp     bh,1
 1663         jb      temp_5
 1664         mov     [vga512],1
 1665 temp_5:
 1666         jmp     fini
 1667 
 1668 noct:   mov     ch,0
 1669         mov     dx,3dah                 ;Test for Tseng 4000 & 3000
 1670         in      al,dx                   ;bit 8 is opposite of bit 4
 1671         mov     ah,al                   ;(vertical retrace bit)
 1672         shr     ah,1
 1673         shr     ah,1
 1674         shr     ah,1
 1675         shr     ah,1
 1676         xor     al,ah
 1677         test    al,00001000b
 1678 ;       jz      nots
 1679         jnz     @F
 1680         jmp     nots
 1681 @@:
 1682         mov     dx,3d4h                 ;check for Tseng 4000 series
 1683         mov     ax,0f33h
 1684         call    $isport2
 1685         jnz     not4
 1686         mov     ax,0ff33h               ;top 4 bits should not be there
 1687         call    $isport2
 1688 ;       jz      nots
 1689         jnz     @F
 1690         jmp     nots
 1691 @@:
 1692         mov     ch,1
 1693 
 1694 not4:   mov     dx,3bfh                 ;Enable access to extended registers
 1695         mov     al,3
 1696         out     dx,al
 1697         mov     dx,3d8h
 1698         mov     al,0a0h
 1699         out     dx,al
 1700         cmp     ch,0
 1701         jnz     yes4
 1702 
 1703         mov     dx,3d4h                 ;Test for Tseng 3000 or 4000
 1704         mov     ax,1f25h                ;is the Overflow High register there?
 1705         call    $isport2
 1706         jnz     nots
 1707         mov     al,03fh                 ;bottom six bits only
 1708         jmp     short yes3
 1709 yes4:   mov     al,0ffh
 1710 yes3:   mov     dx,3cdh                 ;test bank switch register
 1711         call    $isport1
 1712         jnz     nots
 1713         bkadr   tseng,$tseng, tseng_entries             ; Bert
 1714         cmp     ch,0
 1715         jnz     t4mem
 1716 ;       mov     [vga512],1
 1717         call    $t3memchk
 1718         jmp     fini
 1719 
 1720 t4mem:  mov     dx,3d4h                 ;Tseng 4000 memory detect 1meg
 1721         mov     al,37h
 1722         out     dx,al
 1723         inc     dx
 1724         in      al,dx
 1725         test    al,1000b                ;if using 64kx4 RAMs then no more than 256k
 1726         jz      nomem
 1727         and     al,3
 1728         cmp     al,1                    ;if 8 bit wide bus then only two 256kx4 RAMs
 1729         jbe     nomem
 1730         mov     [vga512],1
 1731         cmp     al,2                    ;if 16 bit wide bus then four 256kx4 RAMs
 1732         je      nomem
 1733         mov     [vga1024],1             ;full meg with eight 256kx4 RAMs
 1734 nomem:  bkadr   tseng4,$tseng4, tseng4_entries          ; Bert
 1735         jmp     fini
 1736 
 1737 nots:
 1738         mov     dx,3ceh         ;Test for Above A or B chipsets
 1739         mov     ax,0ff0fh               ;register should not be fully available
 1740         call    $isport2
 1741         jz      noab
 1742         mov     ax,200fh
 1743         out     dx,ax
 1744         inc     dx
 1745         nojmp
 1746         in      al,dx
 1747         cmp     al,21h
 1748         jz      verb
 1749         cmp     al,20h
 1750         jnz     noab
 1751         bkadr   aheada,$aheada, ahead_entries           ; Bert
 1752         mov     [vga512],1
 1753         jmp     short fini
 1754 
 1755 verb:   bkadr   aheadb,$aheadb, ahead_entries           ; Bert
 1756         mov     [vga512],1
 1757         jmp     short fini
 1758 
 1759 noab:   mov     dx,3deh                 ;Test for Oak Technology
 1760         mov     ax,0ff11h               ;look for bank switch register
 1761         call    $isport2
 1762         jnz     nooak
 1763         bkadr   oaktech,$oaktech, oaktech_entries               ; Bert
 1764         mov     al,0dh
 1765         out     dx,al
 1766         inc     dx
 1767         nojmp
 1768         in      al,dx
 1769         test    al,11000000b
 1770         jz      no4ram
 1771         mov     [vga512],1
 1772         test    al,01000000b
 1773         jz      no4ram
 1774         mov     [vga1024],1
 1775 no4ram: jmp     short fini
 1776 
 1777 nooak:  mov     si,0
 1778 
 1779 fini:   mov     ax,si
 1780         pop     bp
 1781         ret
 1782 whichvga endp
 1783 
 1784 
 1785 ;Segment to access video buffer (based on GR[6])
 1786 buftbl  dw      0A000h,0A000h,0B000h,0B800h
 1787 
 1788 $t3memchk proc near                     ;[Charles Marslett -- ET3000 memory ck]
 1789         mov     dx,3dah
 1790         in      al,dx                   ;Reset the attribute flop (read 0x3DA)
 1791         mov     dx,03c0h
 1792         mov     al,36h
 1793         out     dx,al
 1794         inc     dx
 1795         in      al,dx                   ;Save contents of ATTR[0x16]
 1796         push    ax
 1797         or      al,10h
 1798         dec     dx
 1799         out     dx,al
 1800         mov     dx,3ceh                 ;Find the RAM buffer...
 1801         mov     al,6
 1802         out     dx,al
 1803         inc     dx
 1804         in      al,dx
 1805         and     ax,000Ch
 1806         shr     ax,1
 1807 
 1808         mov     bx,ax
 1809         push    es
 1810         mov     es,cs:buftbl[bx]
 1811         mov     ax,09C65h
 1812         mov     bx,1
 1813         mov     es:[bx],ax
 1814         mov     es:[bx+2],ax
 1815         inc     bx
 1816         mov     ax,es:[bx]
 1817         pop     es
 1818         cmp     ax,0659Ch
 1819         jne     et3k_256
 1820         mov     [vga512],1
 1821 et3k_256:
 1822         mov     dx,3c0h
 1823         mov     al,36h
 1824         out     dx,al
 1825         pop     ax
 1826         out     dx,al                   ;Restore ATTR[16h]
 1827         ret
 1828 $t3memchk endp
 1829 
 1830 
 1831 $cirrus proc    near
 1832         mov     dx,3d4h         ; assume 3dx addressing
 1833         mov     al,0ch          ; screen a start address hi
 1834         out     dx,al           ; select index
 1835         inc     dx              ; point to data
 1836         mov     ah,al           ; save index in ah
 1837         in      al,dx           ; get screen a start address hi
 1838         xchg    ah,al           ; swap index and data
 1839         push    ax              ; save old value
 1840         push    dx              ; save crtc address
 1841         xor     al,al           ; clear crc
 1842         out     dx,al           ; and out to the crtc
 1843 
 1844         mov     al,1fh          ; Eagle ID register
 1845         dec     dx              ; back to index
 1846         out     dx,al           ; select index
 1847         inc     dx              ; point to data
 1848         in      al,dx           ; read the id register
 1849         mov     bh,al           ; and save it in bh
 1850 
 1851         mov     cl,4            ; nibble swap rotate count
 1852         mov     dx,3c4h         ; sequencer/extensions
 1853         mov     bl,6            ; extensions enable register
 1854 
 1855         ror     bh,cl           ; compute extensions disable value
 1856         mov     ax,bx           ; extensions disable
 1857         out     dx,ax           ; disable extensions
 1858         inc     dx              ; point to data
 1859         in      al,dx           ; read enable flag
 1860         or      al,al           ; disabled ?
 1861         jnz     exit            ; nope, not an cirrus
 1862 
 1863         ror     bh,cl           ; compute extensions enable value
 1864         dec     dx              ; point to index
 1865         mov     ax,bx           ; extensions enable
 1866         out     dx,ax           ; enable extensions
 1867         inc     dx              ; point to data
 1868         in      al,dx           ; read enable flag
 1869         cmp     al,1            ; enabled ?
 1870         jne     exit            ; nope, not an cirrus
 1871         mov     [cirrus],1
 1872         mov     video_entries, offset no_entries        ; Bert
 1873         mov     [bankadr],offset $nobank
 1874 if @CodeSize
 1875         mov     [bankseg],seg $nobank
 1876 endif
 1877 exit:   pop     dx              ; restore crtc address
 1878         dec     dx              ; point to index
 1879         pop     ax              ; recover crc index and data
 1880         out     dx,ax           ; restore crc value
 1881         ret
 1882 $cirrus endp
 1883 
 1884 $chkbk  proc    near            ;paradise bank switch check
 1885         mov     di,0b800h
 1886         mov     es,di
 1887         xor     di,di
 1888         mov     bx,1234h
 1889         call    $gochk
 1890         jnz     nopd
 1891         mov     bx,4321h
 1892         call    $gochk
 1893         jnz     nopd
 1894         clc
 1895         ret
 1896 nopd:   stc
 1897         ret
 1898 $chkbk  endp
 1899 
 1900 $gochk  proc    near
 1901         push    si
 1902         mov     si,bx
 1903 
 1904         mov     al,cl
 1905         call    dx
 1906         xchg    bl,es:[di]
 1907         mov     al,ch
 1908         call    dx
 1909         xchg    bh,es:[di]
 1910 
 1911         xchg    si,bx
 1912 
 1913         mov     al,cl
 1914         call    dx
 1915         xor     bl,es:[di]
 1916         mov     al,ch
 1917         call    dx
 1918         xor     bh,es:[di]
 1919 
 1920         xchg    si,bx
 1921 
 1922         mov     al,ch
 1923         call    dx
 1924         mov     es:[di],bh
 1925         mov     al,cl
 1926         call    dx
 1927         mov     es:[di],bl
 1928 
 1929         mov     al,0
 1930         call    dx
 1931         or      si,si
 1932         pop     si
 1933         ret
 1934 $gochk  endp
 1935 
 1936 
 1937 $pdrsub proc    near            ;Paradise
 1938         push    dx
 1939         mov     ah,al
 1940         mov     dx,3ceh
 1941         mov     al,9
 1942         out     dx,ax
 1943         pop     dx
 1944         ret
 1945 $pdrsub endp
 1946 
 1947 $isport2 proc   near
 1948         push    bx
 1949         mov     bx,ax
 1950         out     dx,al
 1951         mov     ah,al
 1952         inc     dx
 1953         in      al,dx
 1954         dec     dx
 1955         xchg    al,ah
 1956         push    ax
 1957         mov     ax,bx
 1958         out     dx,ax
 1959         out     dx,al
 1960         mov     ah,al
 1961         inc     dx
 1962         in      al,dx
 1963         dec     dx
 1964         and     al,bh
 1965         cmp     al,bh
 1966         jnz     noport
 1967         mov     al,ah
 1968         mov     ah,0
 1969         out     dx,ax
 1970         out     dx,al
 1971         mov     ah,al
 1972         inc     dx
 1973         in      al,dx
 1974         dec     dx
 1975         and     al,bh
 1976         cmp     al,0
 1977 noport: pop     ax
 1978         out     dx,ax
 1979         pop     bx
 1980         ret
 1981 $isport2 endp
 1982 
 1983 $isport1 proc   near
 1984         mov     ah,al
 1985         in      al,dx
 1986         push    ax
 1987         mov     al,ah
 1988         out     dx,al
 1989         in      al,dx
 1990         and     al,ah
 1991         cmp     al,ah
 1992         jnz     noport
 1993         mov     al,0
 1994         out     dx,al
 1995         in      al,dx
 1996         and     al,ah
 1997         cmp     al,0
 1998 noport: pop     ax
 1999         out     dx,al
 2000         ret
 2001 $isport1 endp
 2002 
 2003 videowrite      proc    near            ; your-own-video write routine
 2004         mov     ah,0                    ; clear the high-order color byte
 2005         push    ax                      ; colors parameter
 2006         push    dx                      ; 'y' parameter
 2007         push    cx                      ; 'x' parameter
 2008         call    far ptr writevideo      ; let the external routine do it
 2009         add     sp,6                    ; pop the parameters
 2010         ret                             ; we done.
 2011 videowrite      endp
 2012 
 2013 videoread       proc    near            ; your-own-video read routine
 2014         push    dx                      ; 'y' parameter
 2015         push    cx                      ; 'x' parameter
 2016         call    far ptr readvideo       ; let the external routine do it
 2017         add     sp,4                    ; pop the parameters
 2018         ret                             ; we done.
 2019 videoread       endp
 2020 
 2021 diskwrite       proc    near            ; disk-video write routine
 2022         push    ax                      ; colors parameter
 2023         push    dx                      ; 'y' parameter
 2024         push    cx                      ; 'x' parameter
 2025         call    far ptr writedisk       ; let the external routine do it
 2026         add     sp,6                    ; pop the parameters
 2027         ret                             ; we done.
 2028 diskwrite       endp
 2029 
 2030 diskread        proc    near            ; disk-video read routine
 2031         push    dx                      ; 'y' parameter
 2032         push    cx                      ; 'x' parameter
 2033         call    far ptr readdisk        ; let the external routine do it
 2034         add     sp,4                    ; pop the parameters
 2035         ret                             ; we done.
 2036 diskread        endp
 2037 
 2038 
 2039 ; ***********************************************************************
 2040 ;
 2041 ; TARGA MODIFIED 1 JUNE 89 - j mclain
 2042 ;
 2043 tgawrite        proc    near
 2044         push    ax                      ; colors parameter
 2045         push    dx                      ; 'y' parameter
 2046         push    cx                      ; 'x' parameter
 2047         call    far ptr WriteTGA        ; writeTGA( x, y, color )
 2048         add     sp,6                    ; pop the parameters
 2049         ret
 2050 tgawrite        endp
 2051 
 2052 tgaread         proc    near
 2053         push    dx                      ; 'y' parameter
 2054         push    cx                      ; 'x' parameter
 2055         call    far ptr ReadTGA         ; readTGA( x, y )
 2056         add     sp,4                    ; pop the parameters
 2057         ret
 2058 tgaread endp
 2059 
 2060 
 2061 ; TARGA+ Code 2-11-91, Mark Peterson
 2062 
 2063 TPlusWrite      PROC    NEAR
 2064         push    ax
 2065         push    dx
 2066         push    cx
 2067         call    FAR PTR WriteTPlusBankedPixel
 2068         add     sp, 6
 2069         ret
 2070 TPlusWrite     ENDP
 2071 
 2072 TPlusRead      PROC    NEAR
 2073         push    dx
 2074         push    cx
 2075         call    FAR PTR ReadTPlusBankedPixel
 2076         add     sp, 4
 2077         ret
 2078 TPlusRead      ENDP
 2079 
 2080 ; 8514/a afi routines JCO, not needed, 4/11/92
 2081 ;f85start    proc    near
 2082 ;       call   far ptr open8514
 2083 ;       ret
 2084 ;f85start    endp
 2085 
 2086 ;f85end proc    near
 2087 ;       call   far ptr close8514
 2088 ;       ret
 2089 ;f85end endp
 2090 
 2091 ; hardware
 2092 f85hwwrite     proc    near
 2093        call   far ptr fr85hwwdot
 2094        ret
 2095 f85hwwrite    endp
 2096 
 2097 f85hwread proc   near
 2098        call   far ptr fr85hwrdot
 2099        ret
 2100 f85hwread endp
 2101 
 2102 f85hwline proc   near
 2103        call    far ptr fr85hwwbox        ;put out the box
 2104        ret
 2105 f85hwline endp
 2106 
 2107 f85hwreadline proc    near
 2108        call    far ptr fr85hwrbox        ;read the box
 2109        ret
 2110 f85hwreadline endp
 2111 
 2112 ; afi
 2113 f85write     proc    near
 2114        call   far ptr fr85wdot
 2115        ret
 2116 f85write    endp
 2117 
 2118 f85read proc   near
 2119        call   far ptr fr85rdot
 2120        ret
 2121 f85read endp
 2122 
 2123 f85line proc   near
 2124        call    far ptr fr85wbox        ;put out the box
 2125        ret
 2126 f85line endp
 2127 
 2128 f85readline proc    near
 2129        call    far ptr fr85rbox        ;read the box
 2130        ret
 2131 f85readline endp
 2132 
 2133 hgcwrite proc near
 2134         mov     ah,0                    ; clear the high-order color byte
 2135         push    ax                      ; colors parameter
 2136         push    dx                      ; 'y' parameter
 2137         push    cx                      ; 'x' parameter
 2138         call    far ptr writehgc        ; let the Herc. Write dot routine do it
 2139         add     sp,6                    ; pop the parameters
 2140         ret
 2141 hgcwrite endp
 2142 
 2143 hgcread proc near
 2144         push    dx                      ; 'y' parameter
 2145         push    cx                      ; 'x' parameter
 2146         call    far ptr readhgc         ; call the Hercules Read dot routine
 2147         add     sp,4                    ; pop the parameters
 2148         ret
 2149 hgcread endp
 2150 
 2151 hgcstart        proc    near            ; hercules start routine
 2152         call    far ptr inithgc         ; let the external routine do it
 2153         ret                             ; we done.
 2154 hgcstart        endp
 2155 
 2156 hgcend          proc    near            ; hercules end routine
 2157         call    far ptr termhgc         ; let the external routine do it
 2158         ret                             ; we done.
 2159 hgcend          endp
 2160 
 2161 ; **************** video adapter initialization *******************
 2162 ;
 2163 ; adapter_init:
 2164 ;       called from general.asm once per run
 2165 
 2166 adapter_init    proc    far             ; initialize the video adapter (to VGA)
 2167         mov     ax,[bankadr]            ; Initialize the bank-switching
 2168         mov     video_bankadr,ax        ;  logic to the do-nothing routine
 2169         mov     ax,[bankseg]            ;  ...
 2170         mov     video_bankseg,ax        ;  ...
 2171         mov     bx,0                    ; clear out all of the 256-mode flags
 2172         mov     tseng,bx                ;  ...
 2173         mov     trident,bx              ;  ...
 2174         mov     video7,bx               ;  ...
 2175         mov     paradise,bx             ;  ...
 2176         mov     chipstech,bx    ;  ...
 2177         mov     ativga,bx               ;  ...
 2178         mov     everex,bx               ;  ...
 2179         mov     cirrus,bx               ;  ...
 2180         mov     aheada,bx               ;  ...
 2181         mov     aheadb,bx               ;  ...
 2182         mov     tseng4,bx               ;  ...
 2183         mov     oaktech,bx              ;  ...
 2184         mov     [bankadr],offset $nobank
 2185         mov     [bankseg],seg $nobank
 2186         mov     video_entries, offset no_entries        ; ...
 2187         ret
 2188 adapter_init    endp
 2189 
 2190 ; adapter_detect:
 2191 ;       This routine performs a few quick checks on the type of
 2192 ;       video adapter installed.
 2193 ;       It sets variables video_type and textsafe,
 2194 ;       and fills in a few bank-switching routines.
 2195 
 2196 adapter_detect  proc    uses di si es
 2197         push    bp                      ; some bios's don't save during int 10h
 2198         cmp     done_detect,0           ; been called already?
 2199         je      adapter_detect2         ;  nope
 2200         jmp     adapter_ret             ; yup, do nothing
 2201 adapter_detect2:
 2202         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
 2203 
 2204         cmp     TPlusFlag, 0
 2205         je      NotTPlus
 2206         call    far ptr CheckForTPlus
 2207         or      ax, ax
 2208         jz      NotTPlus
 2209         mov     TPlusInstalled, 1       ; flag it and check for primary adapter
 2210 
 2211 NotTPlus:
 2212         mov     ax,1a00h                ; start by trying int 10 func 1A
 2213         int     10h                     ;  ...
 2214         cmp     al,1ah                  ; was AL modified?
 2215         je      adapter_detect_4        ;  yup. go decode what we got
 2216         mov     ax,1200h                ; try this vga-only function
 2217         mov     bl,34h                  ;  enable cursor emulation
 2218         int     10h                     ;  ...
 2219         cmp     al,12h                  ; did it work?
 2220         je      adapter_detect_vga      ;  yup, vga
 2221         mov     ah,12h                  ; look for an EGA
 2222         mov     bl,10h                  ;  by using an EGA-specific call
 2223         int     10h                     ;  ...
 2224         cmp     bl,10h                  ; was BL modified?
 2225         je      adapter_detect_notega   ;  nope, < EGA
 2226         mov     video_type,3            ; set the video type: EGA
 2227         cmp     bh,1                    ; monochrome monitor?
 2228         jne     go_adapter_set          ;  nope
 2229         mov     mode7text,1             ; yup, use mode 7 for text
 2230         jmp     short go_adapter_set    ; We done.
 2231 adapter_detect_4:
 2232         cmp     bl,1                    ; =1?
 2233         jne     adapter_detect_4a       ;  nope
 2234         jmp     adapter_detect_hgc      ; MDA, assume HGC (nothing else works)
 2235 adapter_detect_4a:
 2236         mov     video_type,2            ; set the video type: CGA
 2237         cmp     bl,3                    ; <=2?
 2238         jb      go_adapter_set          ;  exit with type CGA
 2239         mov     video_type,3            ; set the video type: EGA
 2240         cmp     bl,5                    ; =5?
 2241         jne     adapter_detect_5        ;  nope
 2242         mov     mode7text,1             ; yup, monochrome monitor, mode 7 text
 2243 go_adapter_set:
 2244         jmp     adapter_set
 2245 adapter_detect_5:
 2246         cmp     bl,6                    ; <=5?
 2247         jb      go_adapter_set          ;  exit with type EGA
 2248         cmp     bl,10                   ; <=9?
 2249         jb      adapter_detect_vga      ;  vga, go check which kind
 2250         mov     video_type,4            ; set the video type: MCGA
 2251         cmp     bl,13                   ; <=12?
 2252         jb      go_adapter_set          ;  exit with type MCGA
 2253 adapter_detect_vga:
 2254         mov     video_type,5            ; set the video type: VGA
 2255         call    whichvga                ; autodetect which VGA is there
 2256         mov     ax,[bankadr]            ; save the results
 2257         mov     video_bankadr,ax        ;  ...
 2258         mov     ax,[bankseg]            ;  ...
 2259         mov     video_bankseg,ax        ;  ...
 2260         jmp     adapter_set
 2261 adapter_detect_notega:
 2262         mov     video_type,2            ; set the video type: CGA
 2263         ; HGC detect code from book by Richard Wilton follows
 2264         mov     dx,3B4h                 ; check for MDA, use MDA CRTC address
 2265         mov     al,0Fh                  ; select 6845 reg 0Fh (Cursor Low)
 2266         out     dx,al
 2267         inc     dx
 2268         in      al,dx                   ; AL := current Cursor Low value
 2269         mov     ah,al                   ; preserve in AH
 2270         mov     al,66h                  ; AL := arbitrary value
 2271         out     dx,al                   ; try to write to 6845
 2272         mov     cx,200h
 2273 mdalp:  loop    mdalp                   ; wait for 6845 to respond
 2274         in      al,dx                   ; read cursor low again
 2275         xchg    ah,al
 2276         out     dx,al                   ; restore original value
 2277         cmp     ah,66h                  ; test whether 6845 responded
 2278         jne     adapter_set             ;  nope, exit with type CGA
 2279         mov     dl,0BAh                 ; DX := 3BAh (status port)
 2280         in      al,dx
 2281         and     al,80h
 2282         mov     ah,al                   ; AH := bit 7 (vertical sync on HGC)
 2283         mov     cx,8000h                ; do this 32768 times
 2284 mdalp2: in      al,dx
 2285         and     al,80h                  ; isolate bit 7
 2286         cmp     ah,al
 2287         loope   mdalp2                  ; wait for bit 7 to change
 2288         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
 2289 ;; 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
 2290         ret                             ;  work. This depends on no bank
 2291 vgaline endp                            ;  change mid line (ok for 1024 wide)
 2292 
 2293 vgareadline     proc    near            ; Bank Switch EGA/VGA line read
 2294         push    cx                      ; save a few registers
 2295         push    ax                      ;  ...
 2296         push    dx                      ;  ...
 2297 
 2298         mov     bx,dx                   ; save the rowcount
 2299         mov     ax,vxdots               ; compute # of dots / pass
 2300         shr     ax,1                    ;  (given 8 passes)
 2301         shr     ax,1                    ;  ...
 2302         shr     ax,1                    ;  ...
 2303         mul     bx                      ; now calc first video addr
 2304         cmp     dx,curbk                ; see if bank changed
 2305         jne     bank_is_changing        ; if bank change call normaline
 2306 
 2307         mov     si,cx                   ; compute the starting destination
 2308         shr     si,1                    ; divide by 8
 2309         shr     si,1                    ;  ...
 2310         shr     si,1                    ;  ...
 2311         add     si,ax                   ; add the first pixel offset
 2312 
 2313         and     cx,7                    ; adjust for the first pixel offset
 2314         mov     ch,cl                   ; save the original offset value
 2315 
 2316         pop     bx                      ; flush old DX value
 2317         pop     bx                      ; flush old AX value
 2318         pop     ax                      ; flush old CX value
 2319         sub     bx,ax                   ; convert to a length value
 2320         add     bx,di                   ; locate the last dest locn
 2321 
 2322         mov     ax,0a000h               ; EGA/VGA screen starts here
 2323         mov     es,ax                   ;  ...
 2324 
 2325         mov     dx,03ceh                ; set up graphics cntrlr addr
 2326 
 2327 vgaline1:
 2328         push    bx                      ; save BX for a tad
 2329         mov     ch,80h                  ; bit mask to shift
 2330         shr     ch,cl                   ;  ...
 2331         mov     bx,0                    ; initialize bits-read value (none)
 2332         mov     ax,0304h                ; set up controller address register
 2333 vgareadloop:
 2334         out     dx,ax                   ; do it
 2335         mov     bh,es:[si]              ; retrieve the old value
 2336         and     bh,ch                   ; mask one bit
 2337         neg     bh                      ; set bit 7 correctly
 2338         rol     bx,1                    ; rotate the bit into bl
 2339         dec     ah                      ; go for another bit?
 2340         jge     vgareadloop             ;  sure, why not.
 2341         mov     ds:[di],bl              ; returned pixel value
 2342         pop     bx                      ; restore BX
 2343         inc     di                      ; set up the next dest addr
 2344         cmp     di,bx                   ; are we beyond the end?
 2345         ja      vgaline3                ;  yup.  We done.
 2346         inc     cl                      ; alter bit mask value
 2347         cmp     cl,8                    ; time to update SI:
 2348         jne     vgaline2                ;  nope
 2349         inc     si                      ;  yup
 2350         mov     cl,0                    ;  ...
 2351 vgaline2:
 2352         jmp     short vgaline1          ;  do another one.
 2353 
 2354 vgaline3:
 2355 ;;;     call    videocleanup            ; else cleanup time.
 2356         ret                             ;  and we done.
 2357 
 2358 bank_is_changing:
 2359         pop     dx                      ; restore the registers
 2360         pop     ax                      ;  ...
 2361         pop     cx                      ;  ...
 2362         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
 2363         call    normaline               ;  - give up and call normaline
 2364         ret                             ; we done
 2365 nottoosmall:                            ; at least four points - go for it!
 2366         push    bx                      ; save number of pixels
 2367         and     bx,3                    ;  pixels modulo 4 = no of extra pts
 2368         mov     ax,vxdots               ; width of video row
 2369 ;;      shr     ax, 1
 2370 ;;      shr     ax, 1                   ; now ax = vxdots/4
 2371         mul     dx                      ; ax points to start of desired row
 2372         push    cx                      ; Save starting column for later
 2373         shr     cx,1                    ; There are 4 pixels at each address
 2374         shr     cx,1                    ;   so divide X by 4
 2375         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
 2376         inc     cx                      ; yup - add one more pixel
 2377 tweak256line1:
 2378         OUT      DX,AX                  ; set up VGA registers for plane
 2379         push    cx                      ; save registers changed by movsb
 2380         push    si                      ;  ...
 2381         push    di                      ;  ...
 2382 tweak256line2:
 2383         movsb                           ; move the next pixel
 2384         add     si,3                    ; adjust the source addr (+4, not +1)
 2385         loop    tweak256line2           ; loop if more dots this pass
 2386         pop     di                      ; restore the saved registers
 2387         pop     si                      ;  ...
 2388         pop     cx                      ;  ...
 2389         dec     bx                      ; one less extra pixel
 2390         cmp     bx,0                    ; out of extra pixels?
 2391         jne     noextra
 2392         dec     cx                      ; yup - next time one fewer to write
 2393 noextra:
 2394         inc     si                      ; offset the source 1 byte
 2395         shl     ah,1                    ; set up for the next video plane
 2396         cmp     ah,16                   ; at last plane?
 2397         jne     notlastplane
 2398         mov     ah,1                    ; start over with plane 0
 2399         inc     di                      ; bump up video memory
 2400 notlastplane:
 2401         cmp     ah,plane                ; back to first plane?
 2402         jne     tweak256line1           ;  nope.  perform another loop.
 2403         ret
 2404 tweak256line    endp
 2405 
 2406 tweak256readline        proc    near            ; Normal Line:  no assumptions
 2407   local plane:byte
 2408         mov     bx,ax                   ; bx = stop col
 2409         sub     bx,cx                   ; bx = stop-start
 2410         inc     bx                      ; bx = how many pixels to write
 2411         cmp     bx,3                    ; less than four points?
 2412         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
 2413         mov     si,ax
 2414         pop     cx                      ; Retrieve starting column
 2415         and     cl,3                    ; Get the plane number of the pixel
 2416         mov     ah,cl
 2417         mov     plane,ah                ; Save starting plane
 2418         mov     al,READ_MAP
 2419         mov     dx,GC_INDEX
 2420         pop     cx                      ; number of pixels to write
 2421         shr     cx,1
 2422         shr     cx,1                    ; cx = number of pixels/4
 2423         cmp     bx,0                    ; extra pixels?
 2424         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


; ******************** 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

; ********************** 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
        xor     ax,ax
        mov     istruecolor,ax          ; assume not truecolor
        mov     vesa_xres,ax            ; reset indicators used for
        mov     vesa_yres,ax            ;  virtual screen limits estimation

        cmp     dotmode,0
        je      its_text
        mov     setting_text,0          ; try to set virtual stuff
        jmp     short its_graphics
its_text:
        mov     setting_text,1          ; don't set virtual stuff
 2425 its_graphics:
 2426 
 2427         cmp     dotmode, 29		; Targa truecolor mode?
 2428         jne     NotTrueColorMode
 2429         jmp     TrueColorAuto		; yup.
 2430 NotTrueColorMode:
 2431         cmp     diskflag,1              ; is disk video active?
 2432         jne     nodiskvideo             ;  nope.
 2433         call    far ptr enddisk         ; yup, external disk-video end routine
 2434 nodiskvideo:
 2435         cmp     videoflag,1             ; say, was the last video your-own?
 2436         jne     novideovideo            ;  nope.
 2437         call    far ptr endvideo        ; yup, external your-own end routine
 2438         mov     videoflag,0             ; set flag: no your-own-video
 2439         jmp     short notarga
 2440 novideovideo:
 2441         cmp     tgaflag,1               ; TARGA MODIFIED 2 June 89 j mclain
 2442         jne     notarga
 2443         call    far ptr EndTGA          ; endTGA( void )
 2444         mov     tgaflag,0               ; set flag: targa cleaned up
 2445 notarga:
 2446 
 2447         cmp     xga_isinmode,0          ; XGA in graphics mode?
 2448         je      noxga                   ; nope
 2449         mov     ax,0                    ; pull it out of graphics mode
 2450         push    ax
 2451         mov     xga_clearvideo,al
 2452         call    far ptr xga_mode
 2453         pop     ax
 2454 noxga:
 2455 
 2456         cmp     f85flag, 1              ; was the last video 8514?
 2457         jne     no8514                  ; nope.
 2458         cmp     ai_8514, 0              ;check afi flag, JCO 4/11/92
 2459         jne     f85endafi
 2460         call    far ptr close8514hw     ;use registers, JCO 4/11/92
 2461         jmp     f85enddone
 2462 f85endafi:
 2463         call    far ptr close8514       ;use afi, JCO 4/11/92
 2464 ;       call    f85end          ;use afi
 2465 f85enddone:
 2466         mov     f85flag, 0
 2467 no8514:
 2468         cmp     HGCflag, 1              ; was last video Hercules
 2469         jne     noHGC                   ; nope
 2470         call    hgcend
 2471         mov     HGCflag, 0
 2472 noHGC:
 2473         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
        cmp     vesa_bitsppixel,15
        jae     VESAtruecolormode
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

VESAtruecolormode:
        mov     istruecolor,1
	mov	ax, offset VESAtruewrite   ; set up VESA true-color write-a-dot routine	
	mov	bx, offset VESAtrueread    ; set up VESA true-color read-a-dot routine	
	mov	cx, offset normaline       ; set up dullnormal linewrite routine	
	mov	dx, offset normalineread   ; set up dullnormal lineread routine	
        mov     si,offset swap256          ; set up the swap routine
        jmp     videomode                  ; return to common code

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    far ptr open8514hw      ; start the 8514a, try registers first JCO
        jnc     f85ok
        mov     ai_8514, 1              ; set afi flag
f85afi:
        call    far ptr 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 f85hwwrite    ;use register routines
        mov     bx,offset f85hwread    ;changed to near calls
        mov     cx,offset f85hwline    ;
        mov     dx,offset f85hwreadline    ;
        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 f85write      ;use afi routines, JCO 4/11/92
        mov     bx,offset f85read      ;changed to near calls
        mov     cx,offset f85line      ;
        mov     dx,offset f85readline      ;
        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.
 2474         shl     ax, cl
 2475         mov     colors, ax
 2476 
 2477 SetTPlusRoutines:
 2478         mov     goodmode, 1
 2479         mov     oktoprint, 1
 2480         mov     ax, offset TPlusWrite
 2481         mov     bx, offset TPlusRead
 2482         mov     cx, offset normaline
 2483         mov     dx, offset normalineread
 2484         mov     si, offset swapnormread
 2485         jmp     videomode
 2486 
 2487 NoTPlus:
 2488 NoTrueColorCard:
 2489         mov     goodmode, 0
 2490         jmp     videomode
 2491 
 2492 videomode:
 2493         mov     dotwrite,ax             ; save the results
 2494         mov     dotread,bx              ;  ...
 2495         mov     linewrite,cx            ;  ...
 2496         mov     lineread,dx             ;  ...
 2497         mov     word ptr swapsetup,si   ;  ...
 2498         mov     ax,cs                   ;  ...
 2499         mov     word ptr swapsetup+2,ax ;  ...
 2500 
 2501         mov     ax,colors               ; calculate the "and" value
 2502         dec     ax                      ; to use for eventual color
 2503         mov     andcolor,ax             ; selection
 2504 
 2505         mov     boxcount,0              ; clear the zoom-box counter
 2506 
 2507         mov     daclearn,0              ; set the DAC rotates to learn mode
 2508         mov     daccount,6              ; initialize the DAC counter
 2509         cmp     cpu,88                  ; say, are we on a 186/286/386?
 2510         jbe     setvideoslow            ;  boo!  hiss!
 2511         mov     daclearn,1              ; yup.  bypass learn mode
 2512         mov     ax,cyclelimit           ;  and go as fast as he wants
 2513         mov     daccount,ax             ;  ...
 2514 setvideoslow:
 2515         call    far ptr loaddac         ; load the video dac, if we can
 2516         ret
 2517 setvideomode    endp
 2518 
 2519 set_vesa_mapping_func proc near
 2520         mov     cx, word ptr vesa_winaattrib  ; puts vesa_winbattrib in ch
 2521         and     cx,0707h                      ; so we can check them together
 2522         cmp     cx,0305h
 2523         je      use_vesa2
 2524         cmp     cx,0503h
 2525         je      use_vesa2
 2526         test    ch,01h
 2527         jz      use_vesa1
 2528         cmp     vesa_winsize,32    ; None of the above -- 2 32K R/W?
 2529         jne     use_vesa1               ;    if not, use original 1 64K R/W!
 2530         mov     word ptr vesa_mapper,offset $vesa3
 2531         mov     ax,32
 2532         div     vesa_wingran       ; Get number of pages in 32K
 2533         mov     vesa_gran_offset,ax     ; Save it for mapping function
 2534         xor     dx,dx
 2535         mov     ax,1
 2536         test    vesa_winaseg, 00800h
 2537         jz      low_high_seq
 2538         xchg    ax,dx
 2539 low_high_seq:
 2540         mov     vesa_low_window,dx      ; Window number at A000-A7FF
 2541         mov     vesa_high_window,ax     ; Window number at A800-AFFF
 2542         jmp     short vesamapselected
 2543 use_vesa2:
 2544         mov     word ptr vesa_mapper,offset $vesa2
 2545         jmp     short vesamapselected
 2546 use_vesa1:
 2547         mov     word ptr vesa_mapper,offset $vesa1
 2548 vesamapselected:
 2549         mov     word ptr vesa_mapper+2,seg $vesa1
 2550         ret
 2551 set_vesa_mapping_func endp
 2552 
 2553 setnullvideo proc
 2554         mov     ax,offset nullwrite     ; set up null write-a-dot routine
 2555         mov     dotwrite,ax             ;  ...
 2556         mov     ax,offset nullread      ; set up null read-a-dot routine
 2557         mov     dotread,ax              ;  ...
 2558         ret
 2559 setnullvideo endp
 2560 
 2561 setvideo        proc    near            ; local set-video more
 2562 
 2563         cmp     xga_isinmode,0          ; XGA in graphics mode?
 2564         je      noxga                   ; nope
 2565         push    ax
 2566         push    bx
 2567         push    cx
 2568         push    dx
 2569         mov     ax,0                    ; pull it out of graphics mode
 2570         push    ax
 2571         mov     xga_clearvideo,al
 2572         call    far ptr xga_mode
 2573         pop     ax
 2574         pop     dx
 2575         pop     cx
 2576         pop     bx
 2577         pop     ax
 2578 noxga:
 2579 
 2580         push    bp                      ; save it around all the int 10s
 2581         mov     text_type,2             ; set to this for most exit paths
 2582         mov     si,offset $vesa_nullbank ; set to do nothing if mode not vesa
 2583         mov     word ptr vesa_bankswitch,si
 2584         mov     si,seg $vesa_nullbank
 2585         mov     word ptr vesa_bankswitch+2,si
 2586         mov     word ptr vesa_mapper,offset $nobank
 2587         mov     word ptr vesa_mapper+2,seg $nobank
 2588 	mov	vesa_bitsppixel,8
 2589 	mov	istruecolor,0
 2590 ;	mov	vesabyteoffset,0
 2591         mov     tweakflag,0
 2592 
 2593         cmp     ax,0                    ; TWEAK?:  look for AX==BX==CX==0
 2594         jne     short setvideobios      ;  ...
 2595         cmp     bx,0                    ;  ...
 2596         jne     short setvideobios      ;  ...
 2597         cmp     cx,0                    ;  ...
 2598         jne     short setvideobios      ;  ...
 2599 
 2600         cmp     dotmode, 27             ; check for auto-detect modes
 2601         je      setvideoauto1
 2602         cmp     dotmode, 20             ; check for auto-detect modes
 2603         je      setvideoauto1
 2604         cmp     dotmode, 4              ; check for auto-detect modes
 2605         je      setvideoauto1
 2606         cmp     dotmode, 28             ; check for auto-detect modes
 2607         je      setvideoauto1
 2608 
 2609         jmp     setvideoregs            ; anything else - assume register tweak
 2610 
 2611 setvideoauto1:
 2612         jmp     setvideoauto            ; stupid short 'je' instruction!!
 2613 
 2614 setvideobios:
 2615         mov     text_type,0             ; if next branch taken this is true
 2616         cmp     ax,3                    ; text mode?
 2617         jne     setvideobios2           ;  nope
 2618         mov     textaddr,0b800h
 2619         cmp     mode7text,0             ; egamono/hgc?
 2620         je      setvideobios_doit       ;  nope.  Just do it.
 2621         mov     textaddr,0b000h
 2622         mov     ax,7                    ; use mode 7
 2623         call    maybeor                 ; maybe or AL or (for Video-7s) BL
 2624         push    bp                      ; weird but necessary, set mode twice
 2625         int     10h                     ;  get colors right on vga systems
 2626         pop     bp                      ;  ..
 2627         mov     ax,7                    ; for the 2nd hit
 2628         jmp     short setvideobios_doit
 2629 setvideobios2:
 2630         mov     text_type,1             ; if next branch taken this is true
 2631         cmp     ax,6                    ; 640x200x2 mode?
 2632         je      setvideobios_doit       ;  yup.  Just do it.
 2633         mov     text_type,2             ; not mode 3 nor 6, so this is true
 2634         mov     si,dotmode              ; compare the dotmode against
 2635         mov     di,video_type           ; the video type
 2636         add     si,si                   ; (convert to a word pointer)
 2637         cmp     cs:video_requirements[si],di
 2638         jbe     setvideobios_doit       ; ok
 2639         jmp     setvideoerror           ;  Error.
 2640 setvideobios_doit:
 2641         cmp     dotmode,14              ; check for Tandy 1000 mode
 2642         jne     setvideobios_doit2      ; ..
 2643         cmp     ax,0ah                  ; check for Tandy 640x200x4 color mode
 2644         jne     setvideobios_doit1      ; ..
 2645         push    bp                      ; setup Tandy 640x200x4 color mode
 2646         int     10h                     ; ..
 2647         pop     bp                      ; ..
 2648         mov     di,16                   ;port offset for palette registers
 2649         mov     bx,0b01h                ; remap colors for better display on
 2650         call    settandypal             ; .. Tandy 640x200x4 color mode
 2651         mov     di,16                   ;port offset for palette registers
 2652         mov     bx,0d02h                ; ..
 2653         call    settandypal             ; ..
 2654         mov     di,16                   ;port offset for palette registers
 2655         mov     bx,0f03h                ; ..
 2656         call    settandypal             ; ..
 2657         jmp     setvideobios_worked
 2658 setvideobios_doit1:
 2659         cmp     ax,0bh                  ; check for Tandy 640x200x16 color mode
 2660         jne     setvideobios_doit2      ; ..
 2661         call    tandysetup              ; setup Tandy 640x200x16 color mode
 2662         jmp     setvideobios_worked
 2663 setvideobios_doit2:
 2664         call    maybeor                 ; maybe or AL or (for Video-7s) BL
 2665         push    bp                      ; some BIOS's don't save this
 2666         int     10h                     ; do it via the BIOS.
 2667         pop     bp                      ; restore the saved register
 2668         cmp     dotmode,28              ; VESA mode?
 2669 ;        jne     setvideobios_worked     ;  Nope. Return.
 2670         je      over_setvideobios
 2671         jmp     setvideobios_worked     ;  Nope. Return.
 2672 over_setvideobios:
 2673         cmp     ah,0                    ; did it work?
 2674 ;        jne     setvideoerror           ;  Nope. Failed.
 2675         je      over_setvideoerror
 2676         jmp     setvideoerror           ;  Nope. Failed.
 2677 over_setvideoerror:
 2678         mov     vesa_granularity,1      ; say use 64K granules
 2679         push    es                      ; set ES == DS
 2680         mov     ax,ds                   ;  ...
 2681         mov     es,ax                   ;  ...
 2682         mov     ax,4f01h                ; ask about this video mode
 2683         mov     cx,bx                   ;  this mode
 2684         and     cx,07fffh               ; (oops - correct for the high-bit)
 2685         mov     di, offset suffix       ; (a safe spot for 256 bytes)
 2686         int     10h                     ; do it
 2687         cmp     ax,004fh                ; did the call work?
 2688         je      okaysofar
 2689         jmp     nogoodvesamode          ;  nope
 2690 okaysofar:
 2691         mov     si, offset suffix  ; save the first 40 bytes of the mode info
 2692         mov     di, offset vesa_mode_info ; (the truecolor routines need it)
 2693         mov     cx,40                   ; but since we have them, we'll use
        rep     movsb                   ; the variables in the first 40 bytes
        mov     cx, vesa_mode_info      ; get the attributes
        test    cx,1                    ; available video mode?
        jnz     overnogood
        jmp     nogoodvesamode          ; nope.  skip some code
overnogood:
;;;    A sanity check, which ATI cards don't pass.  JCO  12 MAY 2001
 2694 ;;;     test    cx,60h                  ; not vga compatible or not windowed
 2695 ;;;     jnz     nogoodvesamode          ; yup.  skip some code
 2696         call    set_vesa_mapping_func
 2697         mov     cx, word ptr vesa_funcptr  ; get the Bank-switching routine
 2698         cmp     cx,0    ; could make this use the bios, bailout for now JCO
 2699         jz      nogoodvesamode          ; nope.  skip some code
 2700         mov     word ptr vesa_bankswitch, cx  ;  ...
 2701         mov     cx, word ptr vesa_funcptr+2      ;   ...
 2702         mov     word ptr vesa_bankswitch+2, cx  ;  ...
 2703         mov     cx, vesa_bytespscan     ; get the bytes / scan line
 2704         cmp     cx,0                    ; is this entry filled in?
 2705         je      skipvesafix             ;  nope
 2706 ;;;     cmp     colors,256              ; 256-color mode?
 2707 ;;;     jne     skipvesafix             ;  nope
 2708         cmp     vesa_numplanes,1
 2709         jbe     store_vesa_bytes
 2710         shl     cx,1                    ; if a planar mode, bits are pixels
 2711         shl     cx,1                    ; so we multiply bytes by 8
 2712         shl     cx,1
 2713 store_vesa_bytes:
 2714         mov     vxdots,cx               ; adjust the screen width accordingly XXX
 2715 ;       cmp     cx,sxdots               ; 8/93 JRS textsafe=save fix
 2716 ;       je      skipvesafix
 2717 ;       mov     ax,offset swapnormread  ; use the slow swap routine
 2718 ;       mov     word ptr swapsetup,ax   ;  ...
 2719 skipvesafix:
 2720         cmp     virtual,0               ; virtual modes turned off
 2721         jne     check_next
 2722         cmp     video_scroll,0          ; not turned on
 2723         je      dont_go_there           ;  don't need next
        mov     ax,vesa_xres            ; get the physical resolution
        mov     bx,vesa_yres
        mov     sxdots,ax
        mov     sydots,bx
check_next:
        cmp     setting_text,1          ; don't set virtual stuff
 2724         je      dont_go_there
 2725         mov     video_scroll,0          ; reset scrolling flag
 2726         cmp     dotmode,28
 2727         jne     dont_go_there
 2728         call    VESAvirtscan            ; virtual scanline setup
 2729 dont_go_there:
 2730         mov     cx, vesa_wingran        ; get the granularity
 2731         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
        cmp     vesa_bitsppixel,15      ; true-color mode?
        jb      nogoodvesamode
        mov     istruecolor,1           ;  yup
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
 2732         int     10h                     ; let the bios clear the video memory
 2733         mov     dx,3c2h                 ; misc output
 2734         mov     al,063h                 ; dot clock
 2735         out     dx,al                   ; select it
 2736         mov     dx,3c4h                 ; sequencer again
 2737         mov     ax,0300h                ; restart sequencer
 2738         out     dx,ax                   ; running again
 2739         jmp     is256;
 2740 ATItweak:
 2741         mov     ax,62h
 2742 ;; pb, why no maybeor call here?
 2743         int     10h
 2744         mov     dx,3c2h
 2745         mov     al,0e3h
 2746         out     dx,al
 2747         mov     dx,3c4h
 2748         mov     ax,0300h
 2749         out     dx,ax
 2750         jmp     is256
 2751 
 2752 ATItweak2:
 2753         mov     ax,63h
 2754 ;; pb, why no maybeor call here?
 2755         int     10h
 2756         mov     dx,3c4h
 2757         mov     ax,0300h
 2758         out     dx,ax
 2759         jmp     is256
 2760 
 2761 isatweaktype:
 2762         mov     tweakflag,1
 2763         mov     ax,0013h                ; invoke video mode 13h
 2764         call    maybeor                 ; maybe or AL or (for Video-7s) BL
 2765         int     10h                     ; do it
 2766 
 2767         mov     dx,3c4h                 ; alter sequencer registers
 2768         mov     ax,0604h                ; disable chain 4
 2769         out     dx,ax
 2770 
 2771         cmp     orvideo,0               ; are we supposed to clear RAM?
 2772         jne     noclear256              ;  (nope)
 2773 
 2774         mov     dx,03c4h                ; alter sequencer registers
 2775         mov     ax,0f02h                ; enable writes to all planes
 2776         OUT_WORD
 2777 
 2778         push    es                      ; save ES for a tad
 2779         mov     ax,VGA_SEGMENT          ; clear out all 256K of
 2780         mov     es,ax                   ;  video memory
 2781         sub     di,di                   ;  (64K at a time, but with
 2782         mov     ax,di                   ;  all planes enabled)
 2783         mov     cx,8000h                ;# of words in 64K
 2784         cld
 2785         rep stosw                       ;clear all of display memory
 2786         pop     es                      ; restore ES
 2787 
 2788 noclear256:
 2789         mov     dx,3c4h                 ; alter sequencer registers
 2790         mov     ax,0604h                ; disable chain 4
 2791         out     dx,ax
 2792 
 2793         jmp     short is256             ; forget the ROM characters
 2794 
 2795 not256:
 2796 
 2797         mov     ax,0012h                ; invoke video mode 12h
 2798         call    maybeor                 ; maybe or AL or (for Video-7s) BL
 2799         int     10h                     ; do it.
 2800 
 2801 is256:  push    es                      ; save ES for a tad
 2802         mov     ax,40h                  ; Video BIOS DATA area
 2803         mov     es,ax                   ;  ...
 2804 
 2805         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!
 2806         test    al,8                    ;   ...
 2807         jz      vrdly2                  ;   ...
 2808 
 2809         cli                             ; turn off all interrupts
 2810         mov     dx,tweaktype
 2811         cmp     dx,9                    ; 320x400 mode?
 2812         je      not256mode              ; yup - skip this stuff
 2813         cmp     dx,10                   ; Tseng tweak mode?
 2814         je      not256mode              ; yup - skip this stuff
 2815 ;patch #2 (M. Burkey 5/22/90)
 2816         cmp     dx,17                   ; for 832x616 ATI Mode
 2817         je      not256mode
 2818 ;patch end
 2819         mov     cl,0E7h                 ; value for misc output reg
 2820         cmp     dx,18                   ; 320x480 mode?
 2821         je      setmisc320              ;  nope, use above value
 2822         cmp     dx,19                   ; 320x240 mode?
 2823         jne     setmiscoreg             ;  nope, use above value
 2824 setmisc320:
 2825         mov     cl,0E3h                 ; value for misc output reg
 2826 setmiscoreg:
 2827         mov     dx,03c4h                ; Sequencer Synchronous reset
 2828         mov     ax,0100h                ; set sequencer reset
 2829         out     dx,ax
 2830         mov     dx,03c2h                ; Update Misc Output Reg
 2831         mov     al,cl
 2832         out     dx,al
 2833         mov     dx,03c4h                ; Sequencer Synchronous reset
 2834         mov     ax,0300h                ; clear sequencer reset
 2835         out     dx,ax
 2836 not256mode:
 2837         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


; ************* function scroll_center(tocol, torow) *************************

; scroll_center --------------------------------------------------------------
; * this is meant to be an universal scrolling redirection routine
;   (if scrolling will be coded for the other modes too, the VESAscroll
;   call should be replaced by a preset variable (like in proc newbank))
; * arguments passed are the coords of the screen center because
;   there is no universal way to determine physical screen resolution
; ------------------------------------------------------------12-08-2002-ChCh-

scroll_center   proc    tocol: word, torow: word
        cmp     video_scroll,0        ; is the scrolling on?
        jne     okletsmove              ;  ok, lets move
        jmp     staystill               ;  no, stay still
okletsmove:
        mov     cx,tocol                ; send center-x to the routine
        mov     dx,torow                ; send center-y to the routine
        call    VESAscroll              ; replace this later with a variable
staystill:
        ret
scroll_center   endp

; ************* function scroll_relative(bycol, byrow) ***********************

; scroll_relative ------------------------------------------------------------
; * relative screen center scrolling, arguments passed are signed deltas
; ------------------------------------------------------------16-08-2002-ChCh-

scroll_relative proc    bycol: word, byrow: word
        cmp     video_scroll,0        ; is the scrolling on?
        jne     okletsmove              ;  ok, lets move
        jmp     staystill               ;  no, stay still
okletsmove:
        mov     cx,video_startx         ; where we already are..
        mov     dx,video_starty
        add     cx,video_cofs_x         ; find the screen center
        add     dx,video_cofs_y
        add     cx,bycol                ; add the relative shift
        add     dx,byrow
        call    VESAscroll              ; replace this later with a variable
staystill:
        ret
scroll_relative endp

; ************* function scroll_state(what) **********************************

; scroll_state ---------------------------------------------------------------
; * what == 0: saves the position of the scrolled screen center
; * what != 0: restores saved position and scrolls the screen
; ------------------------------------------------------------16-08-2002-ChCh-

scroll_state    proc    what: word
        cmp     what,0                  ; save or restore?
        jne     restore
        mov     cx,video_startx         ; where we already are..
        mov     dx,video_starty
        add     cx,video_cofs_x         ; find the screen center
        add     dx,video_cofs_y
        mov     scroll_savex,cx         ; save it for restoring
        mov     scroll_savey,dx
        jmp     wedone                  ; return
restore:
        mov     cx,scroll_savex         ; get the saved coords
        mov     dx,scroll_savey
        call    VESAscroll              ; scroll there
wedone:
        ret
scroll_state    endp

; VESAscroll ---------------------------------------------------------------
; * this does the scrolling of the screen center then (cx=to_col, dx=to_row)
;   (first, it has to figure out the top-left corner coords)
; ------------------------------------------------------------12-08-2002-ChCh-

VESAscroll      proc      near
        sub     cx,video_cofs_x
        js      colbad                  ; to_col too small
        cmp     cx,video_slim_x
        jna     colok
        mov     cx,video_slim_x         ; to_col too big
        jmp     short colok
colbad:
        xor     cx,cx
colok:
        sub     dx,video_cofs_y
        js      rowbad                  ; to_row too small
        cmp     dx,video_slim_y
        jna     rowok
        mov     dx,video_slim_y         ; to_row too big
        jmp     short rowok
rowbad:
        xor     dx,dx
rowok:
        cmp     cx,video_startx         ; moves left/right?
        jne     ok_letsmove
        cmp     dx,video_starty         ; move up/down?
        jne     ok_letsmove
        jmp     short stay_still        ;  otherwise do nothing
ok_letsmove:
        mov     ax,4f07h                ; fn set display start
;        mov     bx,0080h                ; subfn 80 during the vertical retrace
;        xor     bx,bx                   ; subfn 0 instantly (if sf 80 doesn't work)
 2838         mov     bx,wait_retrace         ; wait for retrace?
 2839         int     10h                     ; move there the left-top corner
 2840         mov     video_startx,cx         ; what was really set?
 2841         mov     video_starty,dx         ; (save the result)
 2842 stay_still:
 2843         ret
 2844 VESAscroll      endp
 2845 
 2846 ; VESAvirtscan ---------------------------------------------------------------
 2847 ; * tests whether the virtual scanline is needed and tries to set it up;
 2848 ;   when nothing fails it sets the video_scroll flag to 1, else to 0
 2849 ; * if sxdots is too small, vesa_xres is used instead to preserve nice
 2850 ;   current behavior (small window by small sx/ydots got from cfgfile)
 2851 ; ------------------------------------------------------------12-08-2002-ChCh-
 2852 
 2853 VESAvirtscan    proc    near
 2854         xor     ax,ax
 2855 once_again:
 2856         mov     cx,sxdots               ; this should be passed twice
 2857         mov     dx,sydots
 2858         cmp     cx,vesa_xres            ; asked wider than screen x?
 2859         ja      setvirtscan
 2860         cmp     dx,vesa_yres            ; asked higher than screen y?
 2861         ja      setvirtscan
 2862         jmp     wedone                  ;  otherwise do nothing
 2863 setvirtscan:
 2864         cmp     ax,004fh                ; is this second pass?
 2865         je      secondpass
 2866         mov     chkd_vvs,1
 2867         mov     ax,4f06h                ; VESA fn 6 scanline length
 2868         mov     bx,1                    ; subfn 1 get line width
 2869         int     10h
 2870         cmp     ax,004fh                ; did that work?
 2871 ;;        jne     bad_vesa                ;  bad vesa.. try it anyway
 2872         je      over_bailout
 2873         jmp     wedonebad               ; bailout now
 2874 over_bailout:
 2875         mov     ax,4f06h                ; VESA fn 6 scanline length
 2876         mov     bx,3                    ; subfn 3 get max line width
 2877         int     10h
 2878         cmp     ax,004fh                ; did that work?
 2879         jne     bad_vesa                ;  bad vesa.. try it anyway
 2880         mov     ax,4f06h
 2881         mov     cx,bx                   ; get the max width in bytes
 2882         mov     bx,2                    ; subfn 2 set width in bytes
 2883         and     cx,0fff8h               ; 8 bytes width align
 2884         int     10h
 2885         cmp     ax,004fh                ; did that work?
 2886         jne     bad_vesa                ;  bad vesa.. try it anyway
 2887         cmp     sxdots,cx               ; max width in pixels in cx
 2888         jae     alreadyset              ;  can't set more
bad_vesa:
        mov     ax,4f06h
        mov     cx,sxdots
        xor     bx,bx                   ; subfn 0 set width in pixels
        cmp     cx,vesa_xres            ; asked more than screen's width?
 2889         jnb     width_ok
 2890         mov     cx,vesa_xres            ;  can't set less
        int     10h
        cmp     ax,004fh                ; did that work?
        je      nofullscr               ;  don't update sxdots
 2891         jmp     wedonebad               ;  bad luck..
 2892 width_ok:
 2893         int     10h                     ; set the virtual scanline
 2894         cmp     ax,004fh                ; did that work?
 2895         je      alreadyset
 2896         jmp     wedonebad               ;  bad luck..
 2897 alreadyset:
 2898         mov     sxdots,cx               ; update sxdots to what was set
 2899 nofullscr:
 2900         cmp     sydots,dx               ; enough lines available?
 2901         jna     once_more
 2902         mov     sydots,dx               ;  no, save the limit
 2903 once_more:
 2904         jmp     once_again              ; go compare the result
 2905 secondpass:
 2906         mov     video_scroll,1          ; turn on the scroll flag
 2907         mov     vxdots,bx               ; save the line byte size
 2908         mov     xdots,cx                ;  save it
 2909         mov     ydots,dx                ;  save it
 2910         mov     ax,vesa_xres            ; get the physical resolution
 2911         mov     bx,vesa_yres
 2912         sub     cx,ax                   ; cx=sxdots-vesa_xres
 2913         jns     slimxok
 2914         xor     cx,cx                   ; line too short
 2915 slimxok:
 2916         sub     dx,bx                   ; dx=sydots-vesa_yres
 2917         jns     slimyok
 2918         xor     dx,dx                   ; too few lines
 2919 slimyok:
 2920         mov     video_slim_x,cx         ; save scrolling limits
 2921         mov     video_slim_y,dx
 2922         shr     ax,1                    ; the middle of the screen
 2923         shr     bx,1
 2924         mov     video_cofs_x,ax         ; save screen center offset
 2925         mov     video_cofs_y,bx
 2926         mov     cx,sxdots               ; get virtual resolution
 2927         mov     dx,sydots
 2928 ;;        xor     ax,ax
 2929         mov     ax,1                    ; try to move a tad
 2930         shr     cx,1                    ; find the center of it
 2931         shr     dx,1
 2932         dec     cx                      ; zero-based coords
 2933         dec     dx                      ; (no sf, s?dots is always >= 2)
 2934         mov     video_startx,ax         ; video didn't scroll yet
        mov     video_starty,ax
        push    dx                      ; store the center coords
        push    cx
        mov     wait_retrace,0080h      ; wait for vertical retrace
        call    VESAscroll              ; scroll there the screen
        pop     cx                      ; restore the center coords
        pop     dx
        cmp     ax,004fh                ; did it scroll?
        jne     noretrace               ;  no, try it another way..
        jmp     short wedone
noretrace:
;;        xor     ax,ax
        mov     ax,2                    ; try to move a tad
        mov     wait_retrace,0          ; don't wait for v. retrace
 2935         mov     video_startx,ax         ; video didn't scroll yet
        mov     video_starty,ax
        call    VESAscroll              ; try the instant scrolling
        cmp     ax,004fh                ; did this scroll?
        je      wedone
bad_luck:
        mov     cx,vesa_xres            ; VESA failed.. restore dimensions
        mov     dx,vesa_yres
        cmp     sxdots,cx               ; asked wider than screen?
        jna     width_notbad
        mov     sxdots,cx               ;  correct it
width_notbad:
        cmp     sydots,dx               ; asked higher than screen?
        jna     wedonebad
        mov     sydots,dx               ;  correct it
wedonebad:
        mov     video_scroll,0          ;  no, disable the scrolling
wedone:
        ret
VESAvirtscan    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
        mov     setting_text,1
        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    far ptr close8514hw             ;close adapter if not, with registers
        jmp     done85close
not85reg:
        call    far ptr 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!
 2936         mov     ax,0                    ; switch to VGA (graphics) mode
 2937         push    ax
 2938         call    far ptr xga_mode
 2939         pop     ax                      ; proceed on like nothing happened
 2940         mov     xga_clearvideo,0        ; reset the clear-video flag
 2941 noxga:
 2942 
 2943         cmp     dotmode,14              ; (klooge for Tandy 640x200x16)
 2944         je      setfortextcga
 2945         cmp     videoax,0               ; check for CGA modes
 2946         je      go_setfortextnocga      ;  not this one
 2947         cmp     dotmode,10              ; Hercules?
 2948         je      setfortextcga           ;  yup
 2949         cmp     videoax,7               ; <= vid mode 7?
 2950         jbe     setfortextcga           ;  yup
 2951 go_setfortextnocga:
 2952         jmp     setfortextnocga         ;  not this one
 2953 setfortextcga:  ; from mode ensures we can go to mode 3, so do it
 2954         mov     ax,extraseg             ; set ES == Extra Segment
 2955         add     ax,1000h                ; (plus 64K)
 2956         mov     es,ax                   ;  ...
 2957         mov     di,4000h                ; save the video data here
 2958         mov     ax,0b800h               ; video data starts here 
 2959         mov     si,0                    ;  ...
 2960         cmp     videoax,3               ; from mode 3?
 2961         jne     setfortextcga2          ;  nope
 2962         cmp     mode7text,0             ; egamono/hgc?
 2963         je      setfortextcga2          ;  nope
 2964         mov     ax,0b000h               ; video data starts here
 2965 setfortextcga2:
 2966         mov     cx,2000h                ; save this many words
 2967         cmp     dotmode,10              ; Hercules?
 2968         jne     setfortextcganoherc     ;  nope
 2969         mov     di,0                    ; (save 32K)
 2970         mov     ax,0b000h               ; (from here)
 2971         mov     cx,4000h                ; (save this many words)
 2972 setfortextcganoherc:
 2973         cmp     dotmode,14              ; check for Tandy 1000 specific modes
 2974         jne     setfortextnotandy       ; ..
 2975         mov     ax,tandyseg             ; video data starts here
 2976         mov     si,tandyofs             ; save video data here
 2977         mov     di,0                    ; save the video data here
 2978         mov     cx,4000h                ; save this many words
 2979 setfortextnotandy:
 2980         push    ds                      ; save DS for a tad
 2981         mov     ds,ax                   ;  reset DS
 2982         cld                             ; clear the direction flag
 2983         rep     movsw                   ;  save them.
 2984         pop     ds                      ; restore DS
 2985         cmp     dotmode,10              ; Hercules?
 2986         jne     dosettext               ;  nope
 2987         cmp     HGCflag, 0              ; check HGC active flag
 2988         je      dosettext
 2989         call    hgcend                  ; close adapter
 2990         mov     HGCflag, 0
 2991 dosettext:
 2992         mov     ax,3                    ; set up the text call
 2993         mov     bx,0                    ;  ...
 2994         mov     cx,0                    ;  ...
 2995         mov     dx,0                    ;  ...
 2996         call    setvideo                ; set the video
 2997         jmp     setfortextreturn
 2998 setfortextnocga:
 2999         mov     bios_vidsave,0          ; default, not using bios for state save
 3000         mov     ax,textsafe2            ; videotable override?
 3001         cmp     ax,0                    ;  ...
 3002         jne     setfortextsafe          ;  yup
 3003         mov     ax,textsafe             ; nope, use general setting
 3004 setfortextsafe:
 3005         cmp     ax,2                    ; textsafe=no?
 3006         jne     setforcolortext         ;  nope
 3007         jmp     setfordummytext         ;  yup, use 640x200x2
 3008 setforcolortext:
 3009         ; 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
        mov     setting_text,0
        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    far ptr reopen8514hw    ;use registers
        jmp     reopen85done
reopenafi:
        call    far ptr 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
 3010         cmp     ax,4                    ; textsafe=save?
 3011         jne     setforgraphicsnocga3    ;  nope
 3012 ;; pb, always clear video here:
 3013 ;;  need if for ega/vga with < 16 colors to clear unused planes
 3014 ;;  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
 3015 swap256ret:
 3016         ret
 3017 swap256         endp
 3018 
 3019 swapvga         proc uses es si di      ; 4 (or less) planes version
 3020         xor     si,si                   ; this will be plane number
 3021         mov     ax,word ptr swaptotlen  ; dx,ax = total length
 3022         mov     dx,word ptr swaptotlen+2
 3023         mov     cx,word ptr swapoffset  ; bx,cx = offset
 3024         mov     bx,word ptr swapoffset+2
 3025         cmp     colors,4                ; 4 or 2 color mode?
 3026         jle     swapvga_2               ;  yup, no plane 2/3
 3027         shr     dx,1                    ; 1/2 of total
 3028         rcr     ax,1                    ;  ...
 3029         cmp     dx,bx                   ; 1/2 total <= offset?
 3030         jb      swapvga_1               ;  yup
 3031         ja      swapvga_2               ;  nope
 3032         cmp     ax,cx                   ; ...
 3033         ja      swapvga_2               ;  nope
 3034 swapvga_1:
 3035         mov     si,2                    ; plane 2
 3036         sub     cx,ax                   ; subtract 1/2 total from offset
 3037         sbb     bx,dx                   ;  ...
 3038 swapvga_2:
 3039         cmp     colors,2                ; 2 color mode?
 3040         jle     swapvga_4               ;  yup, just plane 0
 3041         shr     dx,1                    ; 1/4 of total (or 1/2 if 4 colors)
 3042         rcr     ax,1                    ;  ...
 3043         cmp     dx,bx                   ; 1/4 total <= remaining offset?
 3044         jb      swapvga_3               ;  yup
 3045         ja      swapvga_4               ;  nope
 3046         cmp     ax,cx                   ; ...
 3047         ja      swapvga_4               ;  nope
 3048 swapvga_3:
 3049         inc     si                      ; plane 1 or 3
 3050         sub     cx,ax                   ; subtract 1/4 total from offset
 3051         sbb     bx,dx                   ;  ...
 3052 swapvga_4:
 3053         mov     di,0                    ; bank size (65536 actually)
 3054         cmp     bx,dx                   ; in last bank?
 3055         jne     swapvga_5               ;  nope
 3056         mov     di,ax                   ; yup, note its size
 3057 swapvga_5:
 3058         mov     ax,0a000h               ; high word of vid addr
 3059         mov     word ptr swapvidbuf+2,ax; store it
 3060         mov     word ptr swapvidbuf,cx  ; low word of vid addr (offset in bank)
 3061         sub     di,cx                   ; bank size - offset
 3062         je      swapvga_6               ; 0 implies bank = 65536
 3063         cmp     di,swaplength           ; rest of bank smaller than req length?
 3064         jae     swapvga_6               ;  nope
 3065         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
 3066         mov     bl,savebyte             ; load the byte being built
 3067 swapnorm_shift:
 3068         shr     al,1                    ; shift pixel into byte
 3069         rcr     bl,1                    ;  ...
 3070         loop    swapnorm_shift          ; for number of bits/pixel
 3071         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,fontparm             ; to quiet warning
        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                       ; 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                     ; 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                ; scroll 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                ; scroll 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

; ********* Function gettruecolor(xdot, ydot, &red, &green, &blue) **************

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

; gettruecolor ---------------------------------------------------------------
; * this is just version of VESAtrueread, so the changes are identical
; ------------------------------------------------------------30/06/2002/ChCh-

gettruecolor    proc    uses es, xdot:word, ydot:word, red:ptr word, green:ptr word, blue:ptr word
        cmp     istruecolor,1           ; are we in a truecolor mode?
        je      overdone
        jmp     wedone
overdone:
        mov     cx,xdot                 ; load up the registers
        mov     dx,ydot                 ; for the video routine
        add     cx,sxoffs               ; add window offsets
        add     dx,syoffs               ; (dotwrite does this for VESAtrueread)
        call    VESAtrueaddr            ; calculate address and switch banks
        mov     ax,vesa_winaseg         ; VESA video starts here
        cmp     vesa_bitsppixel,17
        mov     es,ax
        jge     over_hi
        mov     ax,word ptr es:[bx]     ; read two bytes
        mov     cl,3
        mov     dx,ax
        shl     ax,cl
        mov     cl,vesa_redpos
        shr     al,1
        shr     dx,cl
        shr     al,1                    ; blue in al
        cmp     vesa_greensize,6
        je      got_6g
        shl     ah,1
got_6g:
        shl     dx,1                    ; red in dl
        and     ah,111111b              ; green in ah
        jmp     short give_out
over_hi:                                ; 8-8-8 or 8-8-8-8?
        inc     bx                      ; does a word fit to this bank?
        jz      badbank1                ; no, switch one byte after
        mov     ax,word ptr es:[bx-1]   ; else read that word
        inc     bx                      ; bank-end?
        jz      badbank2                ; yes, switch it
        mov     dl,es:[bx]              ; else read the third byte
        jmp     short colors_in
badbank1:
        dec     bx                      ; bx=0ffffh
        mov     al,es:[bx]              ; read the first byte
badbank2:
        inc     dx                      ; next bank needed
        push    ax
        mov     ax,dx                   ; newbank expects bank in ax
        call    far ptr newbank
        pop     ax
        mov     dl,es:[0]               ; read next color
        inc     bx                      ; badbank1 or badbank2?
        jnz     colors_in               ; badbank2 - nothing more to do
        mov     ah,dl
        mov     dl,es:[1]               ; badbank1 - read the last byte
colors_in:
        cmp     vesa_redpos,0
        jne     layout_ok
        xchg    al,dl
layout_ok:
        mov     cl,2
        xor     dh,dh
        and     ax,0FCFCh               ; mask-out 2 g & 2 b lsbs for shift
        shr     dx,cl
        shr     ax,cl
give_out:                               ; both for hi- & true- color,
        mov     bx,red
        mov     [bx],dx                 ; return red
        mov     bx,green
        mov     dl,ah
        mov     [bx],dx                 ; return green
        mov     bx,blue
        mov     dl,al
        mov     [bx],dx                 ; return blue
wedone:
        ret                             ; we done.
gettruecolor    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_a(xdot, ydot, color) *******************

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

putcolor_a      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_a      endp


; ******* Function puttruecolor(xdot, ydot, red, green, blue) *************

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

; puttruecolor ---------------------------------------------------------------
; * this is just version of VESAtruewrite, so the changes are identical
; ------------------------------------------------------------30-06-2002-ChCh-

puttruecolor    proc    uses es, xdot:word, ydot:word, red:word, green:word, blue:word
        cmp     istruecolor,1           ; are we in a truecolor mode?
        je      overdone
        jmp     wedone
overdone:
        mov     cx,xdot                 ; load up the registers
        mov     dx,ydot                 ; for the video routine
        add     cx,sxoffs               ; add window offsets
        add     dx,syoffs               ; (dotwrite does this for VESAtruewrite)
        call    VESAtrueaddr            ; calculate address and switch banks
        mov     ax,vesa_winaseg
        cmp     vesa_bitsppixel,17      ; 8-8-8 and 8-8-8-8
        mov     es,ax
        jge     over_hi
        push    bx
        mov     cx,111111b              ; mask - possibly a public variable
        mov     dx,green
        mov     bx,red
        mov     ax,blue
        and     dx,cx
        and     bx,cx
        and     ax,cx
        mov     cl,vesa_redpos
        cmp     vesa_greensize,6        ; 5-5-5 or 5-6-5
        je      got_6g
        shr     dx,1
got_6g:
        shr     bx,1
        shr     ax,1
        shl     bx,cl
        mov     cl,vesa_greenpos
        or      ax,bx                   ; r-_-b
        shl     dx,cl
        pop     bx
        or      ax,dx                   ; r-g-b
        mov     word ptr es:[bx],ax     ; write two bytes for the dot
        jmp     short wedone
over_hi:
        mov     al,byte ptr blue        ; 8-8-8 (and 8-8-8-8) style
        mov     cx,red
        mov     ah,byte ptr green
        shl     cx,1                    ; well, 6-6-6 is not true-true
        shl     ax,1
        shl     cx,1
        shl     ax,1
        cmp     vesa_redpos,0           ; common b-g-r model?
        jne     doit_slow
        xchg    al,cl                   ; else turn to unusual r-g-b
doit_slow:
        inc     bx                      ; does a word fit to the current bank?
        jz      badbank1                ; no, switch one byte after
        mov     word ptr es:[bx-1],ax   ; else plot that word
        push    cx                      ; hand it over to the switch
        inc     bx                      ; bank-end?
        jz      badbank2                ; yes, switch it
        mov     es:[bx],cl              ; else write the third byte
        pop     cx                      ; wasn't needed - no switching
 3072         jmp     short wedone
 3073 badbank1:
 3074         dec     bx                      ; bx=0ffffh
 3075         mov     es:[bx],al              ; plot the first byte
 3076         xchg    ah,al                   ; second color for badbank2
 3077         push    ax                      ; hand it over
 3078 badbank2:
 3079         inc     dx                      ; next bank needed
 3080         mov     ax,dx                   ; newbank expects bank in ax
 3081         call    far ptr newbank
 3082         pop     ax                      ; get next color
 3083         inc     bx                      ; badbank1 or badbank2?
 3084         mov     es:[0],al               ; plot that color
 3085         jnz     wedone                  ; badbank2 - nothing more to do
 3086         mov     es:[1],cl               ; badbank1 - plot the last byte
 3087 wedone:
 3088         ret                             ; we done.
 3089 puttruecolor    endp
 3090 
 3091 ; Fastcall version, called when C programs are compiled by MSC 6.00A:
 3092 
 3093 @putcolor_a     proc    FORTRAN ; ax=xdot, dx=ydot, bx=color
 3094         push    si                      ; preserve these
 3095         push    di                      ;  ...
 3096         mov     cx,ax                   ; load up the registers
 3097         add     cx,sxoffs               ;  ...
 3098         add     dx,syoffs               ;  ...
 3099         mov     ax,0a000h               ; EGA, VGA, MCGA starts here
 3100         mov     es,ax                   ;  ...
 3101         mov     ax,bx                   ; color
 3102         and     ax,andcolor             ; ensure that 'color' is in range
 3103         call    dotwrite                ; write the dot via the approved method
 3104 ;;;     call    videocleanup            ; perform any video cleanup required
 3105         pop     di                      ; restore
 3106         pop     si                      ;  ...
 3107         ret                             ; we done.
 3108 @putcolor_a     endp
 3109 
 3110 ; ***************Function out_line(pixels,linelen) *********************
 3111 
 3112 ;       This routine is a 'line' analog of 'putcolor_a()', and sends an
 3113 ;       entire line of pixels to the screen (0 <= xdot < xdots) at a clip
 3114 ;       Called by the GIF decoder
 3115 
 3116 out_line        proc    uses di si es, pixels:ptr byte, linelen:word
 3117         mov     cx,sxoffs               ; start at left side of logical screen
 3118         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
 3119         add     cx,sxoffs               ;  ...
 3120         cmp     cx,sxdots               ; beyond the right end of the screen
 3121         ja      get_lineret             ;  ...
 3122         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_a()', 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
 3123         add     cx,sxoffs               ;  ...
 3124         cmp     cx,sxdots               ; beyond the right end of the screen
 3125         ja      put_lineret             ;  ...
 3126         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
 3127         mov     cx,si                   ; calc string length
 3128         sub     cx,dx                   ;  ...
 3129         jcxz    short puts_endsubstr    ; empty string?
 3130         push    ax                      ; remember terminating char
 3131         push    es                      ;  and this
 3132         ; make the string inverse video on display
 3133         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)
 3134 
 3135 loaddac proc    uses es
 3136         cmp     dotmode, 29             ; truecolor?  MCP 5-29-91
 3137         jne     NotTPlusLoaddac
 3138         mov     ax,4402h
 3139         push    ax
 3140         mov     ax,256 * 3
 3141         push    ax
 3142         xor     ax,ax
 3143         push    ax
 3144         push    ds
 3145         mov     ax,OFFSET dacbox
 3146         push    ax
 3147         call    far ptr TPlusLUT
 3148         add     sp, 10
 3149         or      ax, ax
 3150         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

        cmp     istruecolor,0           ; truecolor graphics mode?
        jne     go_loaddacdone

        mov     dacbox,255              ; a flag value to detect invalid DAC
        cmp     debugflag,16            ; pretend we're not a VGA?
 3151         je      loaddacdebug            ;  yup.
 3152         push    ds                      ;  ...
 3153         pop     es                      ;  ...
 3154         mov     ax,1017h                ; get the old DAC values
 3155         mov     bx,0                    ;  (assuming, of course, they exist)
 3156         mov     cx,256                  ;  ...
 3157         mov     dx,offset dacbox        ;  ...
 3158         push    bp
 3159         int     10h                     ; do it.
 3160         pop     bp
 3161 loaddacdebug:
 3162         cmp     dacbox,255              ; did it work?  do we have a VGA?
 3163         je      loaddacega              ;  nope, go check ega
 3164         cmp     colors,16               ; 16 color vga?
 3165         jne     go_loaddacdone          ;  nope, all done
 3166         cld                             ; yup, must straighten out dacbox,
 3167         push    ds                      ;  16 color vga uses indirection thru
 3168         pop     es                      ;  palette select
 3169         mov     si,offset dacbox+60     ; dac[20] is used for color 6 so
 3170         mov     di,offset dacbox+18     ;  copy dacbox[20] to dacbox[6]
 3171         mov     cx,3                    ;  ...
 3172         rep     movsb                   ;  ...
 3173         mov     si,offset dacbox+168    ; dac[56-63] are used for colors 8-15 so
 3174         mov     di,offset dacbox+24     ;  copy dacbox[56-63] to dacbox[8-15]
 3175         mov     cx,24                   ;  ...
 3176         rep     movsb                   ;  ...
 3177 go_loaddacdone:
 3178         jmp     short loaddacdone
 3179 loaddacega:
 3180         cmp     colors,16               ; are we using 16 or more colors?
 3181         jb      loaddacdone             ;  nope.  forget it.
 3182 ;;      cmp     sydots,350              ; 640x350 range?
 3183         cmp     video_type,3            ; EGA or better?
 3184         jb      loaddacdone             ;  nope.  forget it.
 3185         mov     bx,offset palettega     ; make up a dummy palette
 3186         mov     cx,3800h                ; start with color 0 == black
 3187 loaddacega1:                            ; and        color 8 == low-white
 3188         mov     0[bx],cl                ; save one color
 3189         mov     8[bx],ch                ; and another color
 3190         inc     bx                      ; bump up the DAC
 3191         add     cx,0101h                ; and the colors
 3192         cmp     cl,8                    ; finished 8 colors?
 3193         jne     loaddacega1             ;  nope.  get more.
 3194         mov     reallyega,1             ; note that this is really an EGA
 3195         call    far ptr paltodac        ; "convert" it to a VGA DAC
 3196         mov     daclearn,1              ; bypass learn mode
 3197         mov     ax,cyclelimit           ;  and spin as fast as he wants
 3198         mov     daccount,ax             ;  ...
 3199 loaddacdone:
 3200         cmp     colors,16               ; 16 color mode?
 3201         jne     loaddacdone2            ;  nope
 3202         cld                             ; yup, clear the excess dacbox
 3203         mov     cx,360                  ;  entries to all zeros for editpal
 3204         sub     ax,ax
 3205         push    ds
 3206         pop     es
 3207         mov     di,offset dacbox+48
 3208         rep     stosw
 3209 loaddacdone2:
 3210         cld                             ; clear the top 8 entries in dacbox
 3211         mov     cx,12                   ; bios doesn't reset them to 0's
 3212         sub     ax,ax
 3213         push    ds
 3214         pop     es
 3215         mov     di,offset dacbox+744
 3216         rep     stosw
 3217         cmp     tweakflag,0             ; tweaked mode?
 3218         je      loaddacdone3            ;  nope
 3219         mov     dx,3c4h                 ; alter sequencer registers
 3220         mov     ax,0604h                ; disable chain 4
 3221         out     dx,ax
 3222 loaddacdone3:
 3223         mov     gotrealdac,1            ; flag for whether mode supports DAC
 3224         cmp     dacbox,255              ; did DAC get loaded or fudged?
 3225         jne     loaddacret              ;  yup
 3226         mov     gotrealdac,0            ; nope
 3227 loaddacret:
 3228         ret
 3229 loaddac endp
 3230 
 3231 ; *************** Function spindac(direction, rstep) ********************
 3232 
 3233 ;       Rotate the MCGA/VGA DAC in the (plus or minus) "direction"
 3234 ;       in "rstep" increments - or, if "direction" is 0, just replace it.
 3235 
 3236 spindac proc    uses di si es, direction:word, rstep:word
 3237         cmp     dotmode,9               ; TARGA 3 June 89 j mclain
 3238         je      spinbailout
 3239         cmp     dotmode,11              ; disk video mode?
 3240         je      spinbailout
 3241         cmp     istruecolor,1           ; truecolor mode:
 3242         je      spinbailout
 3243         cmp     gotrealdac,0            ; do we have DAC registers to spin?
 3244         je      spinbailout             ;  nope.  bail out.
 3245         cmp     colors,16               ; at least 16 colors?
 3246         jge     spindacdoit             ;  yup.  spin away.
 3247 spinbailout:
 3248         jmp     spindacreturn           ;  nope.  bail out.
 3249 
 3250 spindacdoit:
 3251         push    ds                      ; need ES == DS here
 3252         pop     es                      ;  ...
 3253         cmp     direction,0             ; just replace it?
 3254         je      newDAC                  ;  yup.
 3255 
 3256         mov     cx, rstep               ; loop through the rotate "rstep" times
 3257 stepDAC:
 3258         push    cx                      ; save the loop counter for a tad
 3259         mov     si,offset dacbox
 3260         mov     di,si
 3261         mov     ax,rotate_lo            ; calc low end of rotate range
 3262         cmp     ax,colors               ; safety check for 16 color mode
 3263         jae     nextDAC                 ;  out of range, none to rotate
 3264         add     si,ax
 3265         add     si,ax
 3266         add     si,ax
 3267         mov     ax,rotate_hi            ; calc high end of rotate range
 3268         cmp     ax,colors               ; safety check for 16 color mode
 3269         jb      stepDAC2                ;  ok, in range
 3270         mov     ax,colors               ; out of range, use colors-1
 3271         dec     ax                      ;  ...
 3272 stepDAC2:
 3273         add     di,ax
 3274         add     di,ax
 3275         add     di,ax
 3276         mov     cx,di                   ; size of rotate range - 1
 3277         sub     cx,si
 3278         jcxz    nextDAC                 ; do nothing if range 0
 3279         cmp     direction,1             ; rotate upwards?
 3280         jne     short downDAC           ;  nope.  downwards
 3281         mov     bx,word ptr [si]        ; save the first entry
 3282         mov     dl,byte ptr [si+2]      ;  ...
 3283         cld                             ; set the direction
 3284         mov     di,si                   ; set up the rotate
 3285         add     si,3                    ;  ...
 3286         rep     movsb                   ; rotate it
 3287         mov     word ptr [di],bx        ; store the last entry
 3288         mov     byte ptr [di+2],dl      ;  ...
 3289         jmp     short nextDAC           ; set the new DAC
 3290 downDAC:
 3291         std                             ; set the direction
 3292         mov     bx,word ptr [di]        ; save the last entry
 3293         mov     dl,byte ptr [di+2]      ;  ...
 3294         mov     si,di                   ; set up the rotate
 3295         dec     si                      ;  ...
 3296         add     di,2                    ;  ...
 3297         rep     movsb                   ; rotate it
 3298         mov     word ptr [si+1],bx      ; store the first entry
 3299         mov     byte ptr [si+3],dl      ;  ...
 3300         cld                             ; reset the direction
 3301 nextDAC:
 3302         pop     cx                      ; restore the loop counter
 3303         loop    stepDAC                 ; and loop until done.
 3304 
 3305 newDAC:
 3306         cmp     dotmode,19              ; roll-your-own video?
 3307         jne     spin_notyourown         ; nope
 3308         call    far ptr writevideopalette
 3309         cmp     ax,-1                   ; negative result?
 3310         je      go_spindoit             ; yup.  handle it locally.
 3311         jmp     spindacreturn           ; else we done.
 3312 go_spindoit:
 3313         jmp     spindoit
 3314 
 3315 spin_notyourown:
 3316         cmp     dotmode, 29
 3317         je      TPlusOrXGAspindac
 3318         cmp     xga_isinmode,0          ; XGA extended graphics?
 3319         je      notxga
 3320 
 3321 TPlusOrXGAspindac:
 3322         mov     si,offset dacbox
 3323         push    si
 3324         mov     bx,0
 3325 xgalp1: mov     al,[si+bx]              ; adjust VGA -> XGA
 3326         shl     al,1
 3327         shl     al,1
 3328         mov     [si+bx],al
 3329         inc     bx
 3330         cmp     bx,768
 3331         jne     xgalp1
 3332 
 3333         cmp     dotmode, 29             ; Are we a TARGA+?
 3334         jne     XGAPaletteCall          ;  nope - XGA
 3335         mov     ax,4403h
 3336         push    ax
 3337         mov     ax,256 * 3
 3338         push    ax
 3339         xor     ax,ax
 3340         push    ax
 3341         push    ds
 3342         mov     ax,OFFSET dacbox
 3343         push    ax
 3344         call    far ptr TPlusLUT
 3345         add     sp, 10
 3346         jmp     TPlusOrXGASet
 3347 
 3348 XGAPaletteCall:
 3349         call    far ptr xga_setpalette
 3350 
 3351 TPlusOrXGASet:
 3352         pop     si
 3353         mov     bx,0
 3354 xgalp2: mov     al,[si+bx]              ; adjust XGA -> VGA
 3355         shr     al,1
 3356         shr     al,1
 3357         mov     [si+bx],al
 3358         inc     bx
 3359         cmp     bx,768
 3360         jne     xgalp2
 3361         jmp     spindacreturn
 3362 notxga:
 3363 
 3364         cmp     bios_palette,0          ; BIOS palette updates forced?
 3365         je      not_bios_palette        ;  nope
 3366         mov     ax,1012h                ; use a BIOS update
 3367         mov     bx,0
 3368         mov     cx,256
 3369         push    ds
 3370         pop     es
 3371         mov     dx,offset dacbox
 3372         int     10h
 3373         jmp     spindacreturn
 3374 not_bios_palette:
 3375 
 3376         cmp     f85flag, 0              ; if 8514a then update pallette
 3377         je      spindoit
 3378         jmp     spin8514
 3379 
 3380 spindoit:
 3381         cmp     colors,16               ; 16 color vga?
 3382         jne     spindoit2               ;  nope
 3383         cmp     reallyega,1             ; is this really an EGA?
 3384         je      spindoit2               ;  yup
 3385         cld                             ; vga 16 color, straighten out dacbox,
 3386         push    ds                      ;  16 color vga uses indirection thru
 3387         pop     es                      ;  palette select
 3388         mov     si,offset dacbox+18     ; dac[20] is used for color 6 so
 3389         mov     di,offset dacbox+60     ;  copy dacbox[6] to dacbox[20]
 3390         mov     cx,3                    ;  ...
 3391         rep     movsb                   ;  ...
 3392         mov     si,offset dacbox+24     ; dac[56-63] are used for colors 8-15 so
 3393         mov     di,offset dacbox+168    ;  copy dacbox[8-15] to dacbox[56-63]
 3394         mov     cx,24                   ;  ...
 3395         rep     movsb                   ;  ...
 3396 spindoit2:
 3397         mov     bx,0                    ;  set up to update the DAC
 3398         mov     dacnorm,0               ;  indicate no overflow
 3399 dacupdate:
 3400         cmp     direction,0             ; just replace it?
 3401         je      fastupdate              ;  yup.
 3402         mov     cx,daccount             ;  ...
 3403         jmp     short overfast
 3404 fastupdate:
 3405         mov     cx,256
 3406 overfast:
 3407         mov     ax,256                  ; calculate 256 - BX
 3408         sub     ax,bx                   ;  ...
 3409         cmp     ax,cx                   ; is that less than the update count?
 3410         jge     retrace1                ;  nope.  no adjustment
 3411         mov     cx,ax                   ;  else adjust
 3412         mov     dacnorm,1               ; and indicate overflow
 3413 retrace1:
 3414         mov     dx,03dah                ; wait for no retrace
 3415         in      al,dx                   ;  ...
 3416         and     al,8                    ; this bit is high during a retrace
 3417         jnz     retrace1                ;  so loop until it goes low
 3418 retrace2:
 3419         in      al,dx                   ; wait for no retrace
 3420         and     al,8                    ; this bit is high during a retrace
 3421         jz      retrace2                ;  so loop until it goes high
 3422         cmp     reallyega,1             ; is this really an EGA?
 3423         je      spinega                 ;  yup.  spin it that way.
 3424         cmp     cpu,88                  ; are we on a (yuck, ugh) 8088/8086?
 3425         jle     spinbios                ;  yup. go through the BIOS
 3426 .186
 3427         mov     dx,03c8h                ; set up for a blitz-write
 3428         mov     ax,bx                   ; from this register
 3429         cli                             ; critical section:  no ints
 3430         out     dx,al                   ; starting register
 3431         inc     dx                      ; set up to update colors
 3432         mov     si, offset dacbox       ; get starting addr in SI
 3433         add     si,bx                   ;  ...
 3434         add     si,bx                   ;  ...
 3435         add     si,bx                   ;  ...
 3436         mov     ax,cx                   ; triple the value in CX
 3437         add     cx,ax                   ;  ...
 3438         add     cx,ax                   ;  ...
 3439         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
 3440         inc     daccount                ; increment the daccount value
 3441         inc     daccount                ; increment the daccount value
 3442         inc     daccount                ; increment the daccount value
 3443         mov     ax,cyclelimit           ; collect the cycle-limit value
 3444         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
 3445         jge     nolearn                 ;  ...
 3446         mov     daccount,4              ;  ...
 3447 nolearn:
 3448         add     bx,cx                   ; set up for the next batch
 3449         cmp     bx,256                  ; more to go?
 3450         jge     spindacreturn           ;  nope.  we done.
 3451         jmp     dacupdate               ;  yup.  do it.
 3452 
 3453 spin8514:
 3454         cmp     ai_8514, 0              ;check afi flag JCO 4/11/92
 3455         jne     spin85afi
 3456         call    far ptr w8514hwpal              ; AW
 3457         jmp     spindacreturn
 3458 spin85afi:
 3459         call    far ptr w8514pal                ;use afi
 3460 
 3461 spindacreturn:
 3462         ret
 3463 spindac endp
 3464 
 3465 ; *************** Function find_special_colors ********************
 3466 
 3467 ;       Find the darkest and brightest colors in palette, and a medium
 3468 ;       color which is reasonably bright and reasonably grey.
 3469 
 3470 find_special_colors proc uses si
 3471         mov     color_dark,0            ; for default cases
 3472         mov     color_medium,7          ;  ...
 3473         mov     color_bright,15         ;  ...
 3474         cmp     colors,2                ; 2 color mode?
 3475         jg      fscnot2
 3476         mov     color_medium,1          ; yup, set assumed values and return
 3477         mov     color_bright,1
 3478         ret
 3479 fscnot2:
 3480         cmp     colors,16               ; < 16 color mode? (ie probably 4)
 3481         jge     fscnot4
 3482         mov     color_medium,2          ; yup, set assumed values and return
 3483         mov     color_bright,3
 3484         ret
 3485 fscnot4:
 3486         cmp     gotrealdac,0            ; dac valid?
 3487         je      fscret                  ; nope, return with defaults set earlier
 3488         mov     bh,255                  ; bh is lowest brightness found yet
 3489         sub     bl,bl                   ; bl is highest found yet
 3490         sub     ah,ah                   ; ah is best found for medium choice yet
 3491         mov     si,offset dacbox        ; use si as pointer to dac
 3492         sub     cx,cx                   ; use cx for color number
 3493 fscloop:
 3494         mov     al,byte ptr 0[si]       ; add red,green,blue (assumed all <= 63)
 3495         add     al,byte ptr 1[si]       ;  ...
 3496         add     al,byte ptr 2[si]       ;  ...
 3497         cmp     al,bh                   ; less than lowest found so far?
 3498         jae     fscchkbright
 3499         mov     color_dark,cx           ; yup, note new darkest
 3500         mov     bh,al                   ;  ...
 3501 fscchkbright:
 3502         cmp     al,bl                   ; > highest found so far?
 3503         jbe     fscchkmedium
 3504         mov     color_bright,cx         ; yup, note new brightest
 3505         mov     bl,al                   ;  ...
 3506 fscchkmedium:
 3507         cmp     al,150                  ; too bright?
 3508         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