Source code for /engineering/rendsite/test/source/2XTILE/XTILE21!.ASMOriginal file XTILE21!.ASM
   1 ; XTile  Assembler routine lib
   2 ;
   3 ; COPYRIGHT (C) 1993 Erich P Gatejen 1993  All Rights Reserved
   4 ;
   5 ; File: XTILE.ASM
   6 ;
   7 ; Mode X graphics manager.
   8 
   9 ; Ver 1.1 : Add sprites
  10 ;           Add 4-Pixel font   
  11 ;                 Add mouse interface           
  12 ;           Add put pixel
  13 
  14 ; Ver 2.0 : Major rewrite!
  15 ;                 Add virtual size
  16 ;                 Split-screen
  17 ;           More modes
  18 
  19 ; Ver 2.1 : add some 386 support
  20 
  21 P386N
  22 
  23 IDEAL
  24 
  25 
  26 INCLUDE "XTILE21!.USE"
  27 
  28 
  29 DOSSEG
  30 
  31 ; LARGE memory model.
  32 			MODEL   LARGE
  33 
  34 ; ------------------------------------------------------------------------
  35 ; ----------------------------- Data Seg ---------------------------------
  36 ; ------------------------------------------------------------------------
  37 			FARDATA
  38 
  39 ; --- Mode set tables ----------------------------------------------------
  40 
  41 ; - Tables for each mode
  42 XMODE_320x200:
  43 	db      0e3h    ; dot clock
  44 	db      02      ; # to change
  45 	dw      00014h  ; turn off dword mode
  46 	dw      0e317h  ; turn on byte mode
  47 	dw      320     ; X
  48 	dw      200     ; Y
  49 
  50 XMODE_320x240:
  51 	db      0e3h    ; dot clock
  52 	db      10      ; # to change
  53 	dw      00d06h  ; v-total
  54 	dw      03e07h  ; overflow (bit 8 of vertical counts)
  55 	dw      04109h  ; cell height
  56 	dw      0ea10h  ; v-start
  57 	dw      0ac11h  ; v-end ( and protect bits 0-7 )
  58 	dw      0df12h  ; vertical displayed
  59 	dw      00014h  ; turn off dword mode
  60 	dw      0e715h  ; v-blank start
  61 	dw      00616h  ; v-blank end
  62 	dw      0e317h  ; turn on byte mode
  63 	dw      320     ; X
  64 	dw      240     ; Y
  65 
  66 XMODE_360x200:
  67 	db      0e7h    ; dot clock
  68 	db      08      ; # to change
  69 	dw      06b00h  ; h-total
  70 	dw      05901h  ; horz displayed
  71 	dw      05a02h  ; start horz blanking
  72 	dw      08e03h  ; end horz blanking
  73 	dw      05e04h  ; start h-sync
  74 	dw      08a05h  ; end h-sync
  75 	dw      00014h  ; turn off dword mode
  76 	dw      0e317h  ; turn on byte mode
  77 	dw      360     ; X
  78 	dw      200     ; Y
  79 
  80 XMODE_360x240:
  81 	db      0e7h    ; dot clock
  82 	db      17      ; # to change
  83 	dw         06b00h        ; h-total
  84 	dw         05901h        ; horz displayed
  85 	dw         05a02h        ; start horz blanking
  86 	dw         08e03h        ; end horz blanking
  87 	dw         05e04h        ; start h-sync
  88 	dw         08a05h        ; end h-sync
  89 	dw      00d06h  ; v-total
  90 	dw      03e07h  ; overflow of vertical counts
  91 	dw      04109h  ; cell height
  92 	dw      0ea10h  ; v-start
  93 	dw      0ac11h  ; v-end ( and protect bits 0-7 )
  94 	dw      0df12h  ; vertical displayed
  95 	dw         02d13h        ; offset
  96 	dw      00014h  ; turn off dword mode
  97 	dw      0e715h  ; v-blank start
  98 	dw      00616h  ; v-blank end
  99 	dw      0e317h  ; turn on byte mode
 100 	dw      360     ; X
 101 	dw      240     ; Y
 102 
 103 XMODE_376x282:
 104 	db      067h    ; dot clock
 105 	db      18      ; # to change
 106 	dw         06e00h        ; h-total
 107 	dw         05d01h        ; horz displayed
 108 	dw         05e02h        ; start horz blanking
 109 	dw         09103h        ; end horz blanking
 110 	dw         06204h        ; start h-sync
 111 	dw         08f05h        ; end h-sync
 112 	dw         06206h        ; v-total
 113 	dw         0f007h        ; overflow
 114 	dw      06109h  ; cell height
 115 	dw      0310fh  ; overflow
 116 	dw         03710h        ; v-start
 117 	dw         08911h        ; v-end
 118 	dw         03312h        ; vertical displayed
 119 	dw         02f13h        ; offset
 120 	dw         00014h        ; turn off dword mode
 121 	dw         03c15h        ; v-blank start
 122 	dw         05c16h        ; v-blank end
 123 	dw         0e317h        ; turn on byte mode
 124 	dw      376     ; X
 125 	dw      282      ; y
 126 
 127 
 128 XMODE_320x400:
 129 	db      0e3h    ; dot clock
 130 	db      03      ; # to change
 131 	dw         04009h        ; cell height
 132 	dw      00014h  ; turn off dword mode
 133 	dw      0e317h  ; turn on byte mode
 134 	dw      320     ; X
 135 	dw      400     ; Y
 136 
 137 XMODE_320x480:
 138 	db      0e3h    ; dot clock
 139 	db      10      ; # to change
 140 	dw      00d06h  ; v-total
 141 	dw      03e07h  ; overflow
 142 	dw      04009h  ; cell height
 143 	dw      0ea10h  ; v-sync start
 144 	dw      0ac11h  ; v-sync end
 145 	dw      0df12h  ; vertical displayed
 146 	dw      00014h  ; turn off dword mode
 147 	dw      0e715h  ; v-blank start
 148 	dw      00616h  ; v-blank end
 149 	dw      0e317h  ; turn on byte mode
 150 	dw      320     ; X
 151 	dw      480     ; Y
 152 
 153 XMODE_360x400:
 154 	db      0e7h    ; dot clock
 155 	db      09      ; # to change
 156 	dw      06b00h  ; h-total
 157 	dw      05901h  ; horz displayed
 158 	dw      05a02h  ; start horz blanking
 159 	dw      08e03h  ; end horz blanking
 160 	dw      05e04h  ; start h sync
 161 	dw      08a05h  ; end h sync
 162 	dw         04009h        ; cell height
 163 	dw      00014h  ; turn off dword mode
 164 	dw      0e317h  ; turn on byte mode
 165 	dw      360     ; X
 166 	dw      400     ; Y
 167 
 168 
 169 XMODE_360x480:
 170 	db      0e7h          ; dot clock
 171 	db      17            ; # to change
 172 	dw      06b00h        ; h-total
 173 	dw      05901h        ; horz displayed
 174 	dw      05a02h        ; start horz blanking
 175 	dw      08e03h        ; end horz blanking
 176 	dw      05e04h        ; start h-sync
 177 	dw      08a05h        ; end h-sync
 178 	dw      00d06h        ; V-total
 179 	dw      03e07h        ; overflow
 180 	dw      04009h        ; cell height
 181 	dw      0ea10h        ; v-sync start
 182 	dw      0ac11h        ; v-sync end
 183 	dw      0df12h        ; vertical displayed
 184 	dw      02d13h        ; offset
 185 	dw      00014h        ; turn off dword mode
 186 	dw      0e715h        ; v-blank start
 187 	dw      00616h        ; v-blank end
 188 	dw      0e317h        ; turn on byte mode
 189 	dw      360           ; X
 190 	dw      480     ; Y
 191 
 192 XMODE_360x360:
 193 	db      0e7h    ; dot clock
 194 	db      15      ; # to change
 195 	dw         06b00h        ; h-total
 196 	dw         05901h        ; horz displayed
 197 	dw         05a02h  ; start horz blanking
 198 	dw         08e03h        ; end horz blanking
 199 	dw         05e04h        ; start h sync
 200 	dw         08a05h        ; end h sync
 201 	dw         04009h        ; cell height
 202 	dw         08810h        ; v-sync start
 203 	dw         08511h        ; v-sync end
 204 	dw      06712h   ; vertical displayed
 205 	dw      02d13h  ; offset
 206 	dw         00014h        ; turn off dword mode
 207 	dw         06d15h        ; v-blank start
 208 	dw         0ba16h        ; v-blank end
 209 	dw         0e317h        ; turn on byte mode
 210 	dw      360     ; X
 211 	dw      360     ; Y
 212 
 213 
 214 XMODE_376x308:
 215 	db      0e7h    ; dot clock
 216 	db      18      ; # to change
 217 	dw         06e00h        ; h-total
 218 	dw         05d01h        ; horz displayed
 219 	dw         05e02h        ; start horz blanking
 220 	dw         09103h        ; end horz blanking
 221 	dw         06204h        ; start h sync
 222 	dw         08f05h        ; end h sync
 223 	dw         06206h        ; v-total
 224 	dw         00f07h        ; overflow
 225 	dw      04009h  ; cell height
 226 	dw      0310fh  ; overflow
 227 	dw         03710h        ; v-sync start
 228 	dw         08911h        ; v- sync end
 229 	dw         03312h        ; vertical displayed
 230 	dw         02f13h        ; offset
 231 	dw         00014h        ; turn off dword mode
 232 	dw         03c15h        ; v-blank start
 233 	dw         05c16h        ; v-blank end
 234 	dw         0e317h        ; turn on byte mode
 235 	dw      376     ; X
 236 	dw      308     ; Y
 237 
 238 XMODE_376x564:
 239 	db      0e7h    ; dot clock
 240 	db      18      ; # to change
 241 	dw         06e00h        ; h-total
 242 	dw         05d01h        ; horz displayed
 243 	dw         05e02h        ; start horz blanking
 244 	dw         09103h        ; end horz blanking
 245 	dw         06204h        ; start h sync
 246 	dw         08f05h        ; end h sync
 247 	dw         06206h        ; v-total
 248 	dw         0f007h        ; overflow
 249 	dw      06009h  ; v-blank start
 250 	dw      0310fh  ; overflow
 251 	dw         03710h        ; v-sync start
 252 	dw         08911h        ; v-sync end
 253 	dw         03312h        ; vertical displayed
 254 	dw         02f13h        ; offset
 255 	dw         00014h        ; turn off dword mode
 256 	dw         03c15h        ; v-blank start
 257 	dw         05c16h        ; v- blank end
 258 	dw         0e317h        ; turn on byte mode
 259 	dw      376
 260 	dw      564
 261 
 262 
 263 ; - Table of available modes.  Position relates to mode number       D-SCAN
 264 XMODE_TABLE:
 265 	dw  OFFSET      XMODE_320x240           ; Mode 0.           1:1                       X
 266 	dw  OFFSET      XMODE_320x200           ; Mode 1.                      X
 267 	dw  OFFSET      XMODE_360x200           ; Mode 2.                      X
 268 	dw  OFFSET      XMODE_360x240           ; Mode 3.                      X
 269 	dw  OFFSET      XMODE_376x282           ; Mode 4.     1:1     DONT
 270 	dw  OFFSET      XMODE_360x360           ; Mode 5.
 271 	dw  OFFSET      XMODE_376x308           ; Mode 6.
 272 	dw  OFFSET      XMODE_320x400           ; Mode 7.
 273 	dw  OFFSET      XMODE_360x400           ; Mode 8.
 274 	dw  OFFSET      XMODE_320x480           ; Mode 9.
 275 	dw  OFFSET      XMODE_360x480           ; Mode 10.
 276 	dw  OFFSET      XMODE_376x564           ; Mode 11.            DONT
 277 
 278 
 279 ; --- Other Tables --------------------------------------------------------
 280   ; Clip edge masks
 281 	Left_Clip_Mask      DB  0FH, 0EH, 0CH, 08H
 282 	Right_Clip_Mask     DB  01H, 03H, 07H, 0FH
 283 
 284 
 285 ; ---- Copyright notice --------------------------------------------------
 286 Banner  db         'COPYRIGHT (C) 1993 Erich P Gatejen' ; Do not remove
 287 	   db        ' All Rights Reserved '              ; Do not remove
 288 ID         db      ' !!!!'
 289 
 290 
 291 ; ---- XTile local data -------------------------------------------------- 
 292 
 293 ; --- Define the current write page
 294 Write_Page      dw      0       ; Offset into current write page
 295 WLine_Offset    dw      ?       ; Line size in the current write page
 296 
 297 ; --- Define the Alt write page
 298 Alt_Page        dw      0       ; Offset into the alternate write page
 299 ALine_Offset    dw      ?       ; Line size in the alternate page
 300 
 301 
 302 ; --- Define the current display page
 303 Display_Page    dw      ?       ; Offset into display page
 304 DLine_Offset    dw      ?       ; Line size in current display page
 305 DisplaySizeX    dw      ?       ; Size of display page (X)
 306 DisplaySizeY    dw      ?       ; Size of display page (Y)
 307 ViewXLoc        dw      ?       ; Starting X of view
 308 ViewYLoc        dw      ?       ; Starting Y of view
 309 MaxViewX        dw      ?       ; Maximum View X
 310 MaxViewY        dw      ?       ; Max     View Y
 311 ScreenSizeX     dw      ?       ; Actual screen size
 312 ScreenSizeY     dw      ?       ; Actual screen size (Minus split screen)
 313 
 314 ; --- Split screen data
 315 SplitY          dw      500     ; Split line.  If over screen size then no split
 316 DScan           dw      ?       ; Double scan flag
 317 OriginalY       dw      ?       ; The original Y screen size (Absolute size)
 318 
 319 ; --- Font data
 320 ; 8-pix font
 321 UpLoaded8       dw      1       ; Is it uploaded?  Assume not.
 322 Font_SiteU8     dw      ?       ; Offset of registered uploaded font
 323 LABEL Font_Addr8        DWORD   ; For loading the address of an non-uploaded font
 324 Font_SiteD8     dw      ?       ; Offset of registered not-uploaded font
 325 FSS8            dw      ?       ; Segment.  Don't change
 326 Char_Base8      dw      ?       ; Base character for font
 327 Font_Mask_S8    dw      ?       ; Seg with masks for font set
 328 Font_Mask_O8    dw      ?       ; Offset
 329 
 330 ; 4-pix font
 331 UpLoaded4               dw      1       ; Is it uploaded?  Assume not.
 332 Font_SiteU4     dw      ?       ; Offset of registered uploaded font
 333 LABEL Font_Addr4        DWORD  ; For loading the address of an non-uploaded font
 334 Font_SiteD4     dw      ?       ; Offset of registered not-uploaded font
 335 FSS4            dw      ?       ; Segment.  Don't change
 336 Char_Base4      dw      ?       ; Base character for font
 337 Font_Mask_S4    dw      ?       ; Seg with masks for font set
 338 Font_Mask_O4    dw      ?       ; Offset
 339 
 340 ; --- Mouse data
 341 MousePage       dw      ?    ; Address of the page the mouse is working on
 342 MouseLines      dw      ?    ; Number of lines in the mouses world
 343 Mouse_Hndlr_O   dd  FAR ?    ; Address of the user defined mouse handler
 344 LABEL MPointerMask DWORD     ; Address of the S:O for the next  two
 345 MPointerMask_O  dw      ?    ; Location in user data of the mouse pntr mask
 346 MPointerMask_S  dw      ?    ; Segment ^
 347 MUEventMask     dw      ?    ; Events user wishes to be reported
 348 MLastX          dw      ?    ; Last known X location of the mouse
 349 MLastY          dw      ?    ; Last known Y location of the mouse
 350 LockHandler     dw      0    ; Block re-entry into mouse handler
 351 SplitOffset     dw      ?    ; Offset into display page in which starts the
 352 			     ;  scan line that may be in the split page
 353 
 354 ; --- Clip Values
 355 ClipT          dw      20       ; Clip top        .. DEFAULTS .. Mode 0
 356 ClipB          dw      220      ; Clip bottom
 357 ClipL          dw      20       ; Clip left
 358 ClipR          dw      300      ; Clip right
 359 
 360 ENDS
 361 
 362 
 363 
 364 ; ------------------------------------------------------------------------
 365 ; ---------------------------- Code Seg ----------------------------------
 366 ; ------------------------------------------------------------------------
 367 			SEGMENT         CODE       WORD PUBLIC  'CODE'
 368 
 369 
 370 			ASSUME  cs:CODE
 371 
 372 
 373 ; --------------------------- _XInit_Mode -------------------------------
 374 ; - This will initialize Mode X.
 375 ; -
 376 public    _XInit_Mode
 377 
 378 PROC      _XInit_Mode   FAR
 379 
 380 	ARG     Mode:WORD
 381 
 382 	  push          bp
 383 	  mov           bp,   sp    ; Save Stack frame
 384 	  push         si di ds    ; Save calling frame
 385 
 386 	  ASSUME   ds:  @fardata
 387 	  mov    ax,  @fardata    ; Set DS to segment w/ Table
 388 	  mov    ds,  ax
 389 
 390 	  cld
 391 
 392     ; Get mode and decide if it is a double scan mode (one of first four )
 393 	  mov    ax,     FALSE             ; FALSE = 0, assume no double scan
 394 	  mov      cx,  [Mode]
 395 	  cmp      cx,  3
 396 	  jg       @@NotDoubleScan
 397 	  mov            ax,  TRUE        ; It is double scan
 398    @@NotDoubleScan:
 399 	  mov      [DScan],  ax    ; Set flag
 400 
 401     ; -- Set the mode
 402 
 403 	  ; Let BIOS set mode 13h
 404 	  mov            ax,     013h
 405 	  int      010h
 406 
 407 	  ; Disable Chain-4 and Synch reset
 408 	  mov      dx,  SC_INDEX
 409 	  mov      ax,  0604h
 410 	  out      dx,  ax
 411 	  mov      ax,  0100h
 412 	  out      dx,  ax
 413 
 414 	  ; Point to the mode table
 415 	  mov      bx,  OFFSET XMODE_TABLE
 416 	  shl      cx,  1                               ; Shift to word
 417 	  add      bx,  cx                              ; Point to entry
 418 	  mov      si,  [bx]                 ; Get address of specific mode table
 419 
 420 	  ; Set the MISC register
 421 	  lodsb                            ; Load dot clock
 422 	  mov      dx,  MISC_OUTPUT
 423 	  out      dx,  al                 ; Set the dot clock and H-Scanning
 424 
 425 	  ; Undo the reset ( restart the sequencer )
 426 	  mov      dx,  SC_INDEX
 427 	  mov      ax,  0300h
 428 	  out      dx,  ax
 429 
 430    ; -- Change the CRTC registers
 431 	  mov      dx,  CRTC_INDEX
 432 
 433 	  ; Unprotect the registers
 434 	  mov      al,  011h
 435 	  out      dx,  al
 436 	  inc      dx
 437 	  in       al,  dx
 438 	  and      al,  07fh
 439 	  out      dx,  al
 440 
 441 	  ; Find length of CRTC table entries
 442 	  dec      dx
 443 	  xor      cx,cx
 444 	  lodsb                  ; Get number
 445 	  mov      cl,al         ; Put in lower byte of CX
 446 
 447    @@CRTCLoop:
 448 	  lodsw                  ; Get output pair
 449 	  out   dx,ax
 450 	  loop  @@CRTCLoop
 451 
 452     ; -- Set local data
 453 
 454     ; - Set default page information
 455 
 456 	  ; Use X size
 457 	  lodsw                            ; Get X size
 458 	  mov   [DisplaySizeX], ax
 459 	  mov   [ScreenSizeX],  ax
 460 
 461 	  shr   ax, 1
 462 	  shr   ax, 1
 463 	  mov   [WLine_Offset], ax  ; Set line size in XBlocks
 464 	  mov   [DLine_Offset], ax  ; Set line size in XBlocks
 465 
 466 	  ; Use Y size
 467 	  lodsw                            ; Get Y size
 468 	  mov   [DisplaySizeY], ax
 469 	  mov   [ScreenSizeY],  ax
 470 	  mov   [OriginalY],    ax
 471 
 472 	  ; Zero the following
 473 	  mov   ax,             0
 474 	  mov   [Display_Page], ax  ; Display offset 0000
 475 	  mov   [Write_Page], ax           ; Write page offset 0000
 476 	  mov   [SplitY],       ax         ; No split screen
 477 	  mov   [ViewX],        ax         ; View at base
 478 	  mov   [ViewY],        ax         ; View at base
 479 	  mov   [MaxViewX],     ax         ; No room to move
 480 	  mov   [MaxViewY],     ax
 481 
 482 	  ; For split screen, suppress split panning
 483 	  mov   dx,          IN_STATUS0
 484 	  in    al,             dx                 ; Toggle to indexing mode
 485 
 486 	  mov   al,         010h+20h            ; Index10 (bit5 set to maintain display)
 487 	  mov   dx,             AC_INDEXR            ; AC Index register
 488 	  out   dx,             al
 489 	  inc   dx                         ; Point to Data register (read only)
 490 	  in    al,             dx             ; Get the current AC Mode Control
 491 	  or    al,             20h            ; Enable suppress, bit 6
 492 	  dec   dx                         ; Point to Data reg (for write)
 493 	  out   dx,             al             ; Do it.
 494 
 495 	  ; !!DONE!!
 496 	  pop     ds di si             ; Return state
 497 	  pop     bp
 498 	  ret
 499 
 500 
 501 ENDP                    _XInit_Mode
 502 
 503 
 504 ; --------------------------- _XSet_Write_Page ------------------------------
 505 ; - This will set a write page.  It will be the current write page for
 506 ; - most write operations ( the ones that don't use this page will say
 507 ; - so in thier discription )
 508 ; -
 509 public          _XSet_Write_Page
 510 
 511 PROC                    _XSet_Write_Page   FAR
 512 
 513 	ARG     Offst:WORD, XSize:WORD
 514 
 515 	push            bp
 516 	mov             bp,     sp              ; Save Stack frame
 517 	push            ds
 518 
 519 	; Set the DS to local data
 520 	ASSUME  ds:  @fardata
 521 	mov     ax,  @fardata
 522 	mov     ds,     ax
 523 
 524 	; First, load the page offset
 525 	mov     ax,           [Offst]   ; Get offset from pass
 526 	mov     [Write_Page], ax        ; Put it in var
 527 
 528 	; Calculate the line offset
 529 	mov     ax,     [XSize]         ; Get the total size
 530 	shr     ax, 1                   ; divided by 4 to make XBlocks
 531 	shr     ax, 1
 532 	mov     [WLine_Offset], ax      ; Set line size in XBlocks
 533 
 534      ; !!DONE!!
 535 	pop     ds             ; Return state
 536 	pop     bp
 537 	ret
 538 
 539 ENDP                    _XSet_Write_Page
 540 
 541 
 542 ; --------------------------- _XSet_Display_Page -------------------------------
 543 ; - This function set will set the display page.  The view will also be set
 544 ; -
 545 public  _XSet_Display_Page
 546 
 547 PROC    _XSet_Display_Page   FAR
 548 
 549 	ARG   Offst:WORD, XSize:WORD, YSize:WORD, ViewX:WORD, ViewY:WORD
 550 
 551 
 552 	push            bp
 553 	mov             bp,     sp      ; Set up stack frame
 554 	push            ds
 555 
 556 
 557 	; Set DS to local data
 558 	ASSUME  ds:  @fardata
 559 	mov     ax,  @fardata
 560 	mov     ds,  ax
 561 
 562 	; Wait for retrace to end
 563 	mov     dx, IN_STATUS1  ; Input Status #1 Register
 564    @@Wait:
 565 	in      al, dx
 566 	and     al, 08h
 567 	jnz     @@Wait
 568 
 569    ; Set line offset.  CRTC Offset register
 570      ; Calculate the line offset
 571 	mov     ax,             [XSize]  ; Get the total size
 572 	mov     [DisplaySizeX], ax      ; Save it
 573 	shr     ax, 1                   ; divide by 4 to make XBlocks
 574 	shr     ax, 1
 575 	mov     [DLine_Offset], ax      ; Save XBlocks per line
 576 	shr        ax, 1                        ; divide by 2 to get register value
 577 	
 578 	; Set it
 579 	mov        dx, CRTC_INDEX  ; Set port
 580 	mov     ah, 13h         ; CRTC Offset Register Index
 581 	xchg    al, ah          ; Swap format
 582 	out     dx, ax          ; Send it
 583 
 584    ; Set the Start Display Address to the new window
 585 	mov     cx, [ViewX]     ; Get X start for the view
 586 	mov     [ViewXLoc], cx  ; Save it for later
 587 	mov     ax, [ViewY]     ; Get Y start for the view
 588 	mov     [ViewYLoc], ax  ; Save it for later
 589 
 590 	; Compute proper Display start address to use
 591 	mul     [DLine_Offset]  ; AX = Y size (AX) * XBlocks per line
 592 	shr     cx, 1
 593 	shr     cx, 1               ; Convert CX to XBlocks.  Figure pan later
 594 	add     cx, ax          ; Find view upper left pixel
 595 	add     cx, [Offst]     ; Add page offset
 596 	; NOTE: This will leave any 0-3 pan  for later
 597 
 598 	; Change CRTC
 599 	mov        dx, CRTC_INDEX  ; Set port
 600 	mov     al, 0Dh         ; Start display low.
 601 	mov     ah, cl          ; Load low 8 bits
 602 	out     dx, ax
 603 	mov     al, 0Ch ; Start display high
 604 	mov     ah, ch      ; Load high 8 Bits
 605 	out     dx, ax
 606 
 607    ; Wait for a Vertical Retrace
 608 	mov     dx, IN_STATUS1
 609    @@Wait2:
 610 	in      al, dx
 611 	and     al, 08h             ; Vertical Retrace Start?
 612 	jz      @@Wait2         ; If Not, loop until it is
 613 
 614    ; Now Set the Horizontal Pixel Pan values
 615 	mov     dx, 03C0h       ; The Attribute controller
 616 	mov     al, 033h        ; Select Pixel Pan Register
 617 	out  dx, al
 618 
 619      ; Get the pan value and send it
 620 	mov     ax, [ViewX]     ; Get raw X View start
 621 	and     al, 03          ; Peel off the significant bits
 622 	shl     al, 1           ; Shift for 256 Color Mode
 623 	out     dx, al          ; Send it
 624 
 625    ; Set some data values for this display page
 626 
 627 	; Max View limits
 628 	mov     ax, [XSize]             ; Get the page size
 629 	sub      ax, [ScreenSizeX]      ; subtract the actual screen size
 630 	dec     ax                      ; Adjust for count from 0
 631 	mov     [MaxViewX], ax          ; Save
 632 
 633 	mov     ax, [YSize]             ; Get the page size
 634 	mov     [DisplaySizeY], ax      ; Save this
 635 	sub     ax, [ScreenSizeY]       ; subtract the actual screen size
 636 	dec     ax                      ; Adjust for count from 0
 637 	mov     [MaxViewY], ax          ; Save
 638 
 639 	; Save page offset
 640 	mov     ax, [Offst]
 641 	mov  [Display_Page], ax
 642 
 643 	; Calculate Split offset
 644 	mov     ax, [ViewY]             ; Get Y start
 645 	add     ax, [SplitY]            ; Add split line down in view
 646 	mul     [DLine_Offset]          ; Multiply times line size
 647 	add     ax, [Display_Page]      ; Add display page start
 648 	mov     [SplitOffset],  ax
 649 
 650    ; DONE!!
 651    @@Done:
 652 	pop     ds             ; Return state
 653 	pop     bp
 654 	ret
 655 
 656 ENDP                    _XSet_Display_Page
 657 
 658 ; --------------------------- _XSet_Display_PageP -------------------------------
 659 ; - This function set will set the display page.  The view will also be set
 660 ; - Anew palette will be loaded
 661 public  _XSet_Display_PageP
 662 
 663 PROC    _XSet_Display_PageP   FAR
 664 
 665 	ARG   Offst:WORD, XSize:WORD, YSize:WORD, ViewX:WORD, ViewY:WORD, START:WORD, NUMBER:WORD, PAL_O:DWORD
 666 
 667 	push            bp
 668 	mov             bp,     sp      ; Set up stack frame
 669 	push            si di ds
 670 
 671 
 672 	; Set DS to local data
 673 	ASSUME  ds:  @fardata
 674 	mov     ax,  @fardata
 675 	mov     ds,  ax
 676 
 677 	; Wait for retrace to end
 678 	mov     dx, IN_STATUS1  ; Input Status #1 Register
 679    @@Wait:
 680 	in      al, dx
 681 	and     al, 08h
 682 	jnz     @@Wait
 683 
 684    ; Set line offset.  CRTC Offset register
 685      ; Calculate the line offset
 686 	mov     ax,             [XSize]  ; Get the total size
 687 	mov     [DisplaySizeX], ax      ; Save it
 688 	shr     ax, 1                   ; divide by 4 to make XBlocks
 689 	shr     ax, 1
 690 	mov     [DLine_Offset], ax      ; Save XBlocks per line
 691 	shr        ax, 1                        ; divide by 2 to get register value
 692 	
 693 	; Set it
 694 	mov        dx, CRTC_INDEX  ; Set port
 695 	mov     ah, 13h         ; CRTC Offset Register Index
 696 	xchg    al, ah          ; Swap format
 697 	out     dx, ax          ; Send it
 698 
 699    ; Set the Start Display Address to the new window
 700 	mov     cx, [ViewX]     ; Get X start for the view
 701 	mov     [ViewXLoc], cx  ; Save it for later
 702 	mov     ax, [ViewY]     ; Get Y start for the view
 703 	mov     [ViewYLoc], ax  ; Save it for later
 704 
 705 	; Compute proper Display start address to use
 706 	mul     [DLine_Offset]  ; AX = Y size (AX) * XBlocks per line
 707 	shr     cx, 1
 708 	shr     cx, 1               ; Convert CX to XBlocks.  Figure pan later
 709 	add     cx, ax          ; Find view upper left pixel
 710 	add     cx, [Offst]     ; Add page offset
 711 	; NOTE: This will leave any 0-3 pan  for later
 712 
 713 	; Change CRTC
 714 	mov        dx, CRTC_INDEX  ; Set port
 715 	mov     al, 0Dh         ; Start display low.
 716 	mov     ah, cl          ; Load low 8 bits
 717 	out     dx, ax
 718 	mov     al, 0Ch ; Start display high
 719 	mov     ah, ch      ; Load high 8 Bits
 720 	out     dx, ax
 721 
 722    ; --- Set palette
 723 
 724 	; Set CX to number of colors and BX to current
 725 	mov     cx,     [NUMBER]
 726 	mov	bx,	[START]
 727 
 728 	; Set ds:si to pal data
 729 	lds     si,     [PAL_O]
 730 
 731       ; -- Wait retrace
 732 	mov     dx, IN_STATUS1
 733    @@WaitP:
 734 	in      al, dx
 735 	and     al, 08h     ; Vertical Retrace Start?
 736 	jz      @@WaitP     ; If Not, loop until it is
 737 
 738      ; ------- Main loop
 739    @@Another:
 740 
 741 	; Set color to change
 742 	mov	dx,	PAL_SET_COLOR
 743 	mov     al,	bl
 744 	out	dx,     al
 745 
 746 	; Set RGB
 747 	mov	dx,     PAL_RGB_COLOR
 748 	lodsb   			; Get byte
 749 	out	dx,     al              ; Red
 750 	lodsb
 751 	out	dx,     al              ; Green
 752 	lodsb
 753 	out	dx,     al              ; Blue
 754 
 755 	; Next values and loop if any left
 756 	inc	bx
 757 	dec	cx
 758 	jnz	@@Another
 759 
 760    ; ---  Now Set the Horizontal Pixel Pan values
 761 	; Set DS to local data
 762 	ASSUME  ds:  @fardata
 763 	mov     ax,  @fardata
 764 	mov     ds,  ax
 765 
 766 
 767 	mov     dx, 03C0h       ; The Attribute controller
 768 	mov     al, 033h        ; Select Pixel Pan Register
 769 	out  	dx, al
 770 
 771      ; Get the pan value and send it
 772 	mov     ax, [ViewX]     ; Get raw X View start
 773 	and     al, 03          ; Peel off the significant bits
 774 	shl     al, 1           ; Shift for 256 Color Mode
 775 	out     dx, al          ; Send it
 776 
 777    ; Set some data values for this display page
 778 
 779 	; Max View limits
 780 	mov     ax, [XSize]             ; Get the page size
 781 	sub     ax, [ScreenSizeX]      ; subtract the actual screen size
 782 	dec     ax                      ; Adjust for count from 0
 783 	mov     [MaxViewX], ax          ; Save
 784 
 785 	mov     ax, [YSize]             ; Get the page size
 786 	mov     [DisplaySizeY], ax      ; Save this
 787 	sub     ax, [ScreenSizeY]       ; subtract the actual screen size
 788 	dec     ax                      ; Adjust for count from 0
 789 	mov     [MaxViewY], ax          ; Save
 790 
 791 	; Save page offset
 792 	mov     ax, [Offst]
 793 	mov  [Display_Page], ax
 794 
 795 	; Calculate Split offset
 796 	mov     ax, [ViewY]             ; Get Y start
 797 	add     ax, [SplitY]            ; Add split line down in view
 798 	mul     [DLine_Offset]          ; Multiply times line size
 799 	add     ax, [Display_Page]      ; Add display page start
 800 	mov     [SplitOffset],  ax
 801 
 802    ; DONE!!
 803    @@Done:
 804 	pop     ds di si            ; Return state
 805 	pop     bp
 806 	ret
 807 
 808 ENDP    _XSet_Display_PageP
 809 
 810 
 811 ; --------------------------- _XSet_AltPage --------------------------------
 812 ; - This function sets the alternate page
 813 public  _XSet_AltPage
 814 
 815 PROC    _XSet_AltPage   FAR
 816 
 817 	ARG  XSize:WORD, Offst:WORD
 818 
 819 	push    bp
 820 	mov     bp,     sp      ; Set up stack frame
 821 	push    ds
 822 
 823 
 824 	; Set DS to local data
 825 	ASSUME  ds:  @fardata
 826 	mov     ax,  @fardata
 827 	mov     ds,  ax
 828 
 829 
 830 	; Set line size
 831 	mov     ax,     [XSize]
 832 	shr  ax,        1
 833 	shr     ax,  1
 834 	mov     [ALine_Offset], ax
 835 
 836 	; Set page
 837 	mov     ax,     [Offst]
 838 	mov     [Alt_Page], ax
 839 
 840    ; DONE!!
 841    @@Done:
 842 	pop     ds             ; Return state
 843 	pop     bp
 844 	ret
 845 
 846 ENDP                    _XSet_AltPage
 847 
 848 
 849 ; --------------------------- _XSet_View ----------------------------------
 850 ; - This function set will set the view port within the current page
 851 ; - Return 0 if successful, else 1 (TRUE for C)
 852 public  _XSet_View
 853 
 854 PROC    _XSet_View   FAR
 855 
 856 	ARG   ViewX:WORD, ViewY:WORD
 857 
 858 
 859 	push            bp
 860 	mov             bp,     sp      ; Set up stack frame
 861 	push            ds
 862 
 863 
 864 	; Set DS to local data
 865 	ASSUME  ds:  @fardata
 866 	mov     ax,  @fardata
 867 	mov     ds,  ax
 868 
 869 	; Wait for retrace to end
 870 	mov     dx, IN_STATUS1  ; Input Status #1 Register
 871    @@Wait:
 872 	in      al, dx
 873 	and     al, 08h
 874 	jnz     @@Wait           
 875  
 876 
 877    ; Set the Start Display Address to the new window
 878 	mov     cx, [ViewX]      ; Get X start for the view
 879 	cmp     cx, [MaxViewX]  ; Is it within range
 880 	ja      @@Error         ; No, jump out.
 881 	mov     [ViewXLoc], cx   ; Save the view location
 882 
 883 	mov     ax, [ViewY]      ; Get Y start for the view
 884 	cmp     ax, [MaxViewY]  ; Is it within range
 885 	ja      @@Error         ; No, jump out.
 886 	mov     [ViewYLoc], ax  ; Save the view loc
 887 
 888      ; Compute proper Display start address to use
 889 	mul     [DLine_Offset]  ; AX = Y size (AX) * XBlocks per line
 890 	shr     cx, 1           
 891 	shr     cx, 1               ; Conver CX to XBlocks.  Figure pan later
 892 	add     cx, ax             ; Find view upper left pixel
 893 	add     cx, [Display_Page] ; Add page offset
 894 	; NOTE: This will leave any 0-3 pan  for later
 895 
 896      ; Change CRTC
 897 	mov        dx, CRTC_INDEX  ; Set port
 898 	mov     al, 0Dh             ; Start display low.
 899 	mov     ah, cl              ; Load low 8 bits
 900 	out     dx, ax
 901 	mov     al, 0Ch     ; Start display high
 902 	mov     ah, ch          ; Load high 8 Bits
 903 	out     dx, ax
 904 
 905    ; Wait for a Vertical Retrace
 906 	mov     dx, IN_STATUS1
 907    @@Wait2:
 908 	in      al, dx
 909 	and     al, 08h         ; Vertical Retrace Start?
 910 	jz      @@Wait2     ; If Not, loop until it is
 911 
 912       ; Now Set the Horizontal Pixel Pan values
 913 	mov     dx, 03C0h       ; The Attribute controller
 914 	mov     al, 033h        ; Select Pixel Pan Register
 915 	out  dx, al
 916 
 917       ; Get the pan value and send it
 918 	mov     ax, [ViewX]     ; Get raw X View start
 919 	and     al, 03          ; Peel off the significant bits
 920 	shl     al, 1           ; Shift for 256 Color Mode
 921 	out     dx, al          ; Send it
 922 
 923       ; Calculate Split offset
 924 	mov     ax, [ViewY]             ; Get Y start
 925 	add     ax, [SplitY]            ; Add split line down in view
 926 	mul     [DLine_Offset]          ; Multiply times line size
 927 	add     ax, [Display_Page]      ; Add display page start
 928 	mov     [SplitOffset],  ax
 929 
 930    ; DONE!!
 931 	mov     ax,     0       ; No Error, Get outta here
 932 	jmp     @@Done
 933 
 934    @@Error:
 935 	mov     ax,     1       ; Error
 936 
 937    @@Done:
 938 	pop     ds             ; Return state
 939 	pop     bp
 940 	ret
 941 
 942 ENDP    _XSet_View
 943 
 944 
 945 ; --------------------------- _XWait_Retrace -------------------------------
 946 ; - Wait for vertical retrace
 947 public  _XWait_Retrace
 948 
 949 PROC    _XWait_Retrace   FAR
 950 
 951    ; Wait for a Vertical Retrace
 952 	mov     dx, IN_STATUS1
 953    @@Wait1:
 954 	in      al, dx
 955 	and     al, 08h         ; Vertical Retrace Start?
 956 	jz      @@Wait1     ; If Not, loop until it is
 957 
 958 	ret
 959 
 960 ENDP    _XWait_Retrace
 961 
 962 
 963 ; --------------------------- _XSet_SplitScreen ---------------------------
 964 ; - Set up the split screen.  !XTotal is slave to Display total!
 965 ; -
 966 public  _XSet_SplitScreen
 967 
 968 PROC    _XSet_SplitScreen   FAR
 969 
 970 	ARG   YSIZE:WORD
 971 
 972 	push            bp
 973 	mov             bp,     sp                      ; Save Stack frame
 974 	push            ds
 975 
 976     ; Set DS to local data
 977 	ASSUME  ds:  @fardata
 978 	mov     ax,  @fardata
 979 	mov     ds,  ax
 980 
 981 
 982     ; Get the split line and save it
 983 	mov     bx,       [OriginalY]
 984 	mov     ax,       [YSIZE]
 985 	sub     bx,       ax
 986 	dec     bx                              ; Count from 0
 987 	mov     [SplitY], bx                    ; Save it
 988 
 989     ; Adjust the screen size for the display page
 990 	mov     bx,             [OriginalY]     ; Get the ACTUAL screen size
 991 	sub     bx,             ax                      ; Subtract the split size
 992 	mov     [ScreenSizeY], bx               ; Save as the new screen size
 993 	   ; NOTE:  BX is now the starting line for the split
 994 
 995     ; Change the MAX Y view
 996 	mov     cx, [DisplaySizeY]  ; Get the page size
 997 	sub     cx, bx              ; subtract the actual screen size
 998 	dec     cx                  ; Adjust for count from 0
 999 	mov     [MaxViewY], cx      ; Save
1000 
1001 
1002     ; See if the double scan effects how we set the registers
1003 	mov  cx, [DScan]
1004 	shl  bx, cl             ; Shift up if so
1005 
1006       ; Wait for Vertical retrace to start
1007 	mov     dx, IN_STATUS1
1008    @@Wait:
1009 	in      al, dx
1010 	and     al, 08h             ; Vertical Retrace Start?
1011 	jz      @@Wait          ; If Not, loop until it is
1012 
1013 
1014       ; Set the registers
1015 	cli                     ; Disallow interrupts
1016 	mov  dx,  CRTC_INDEX
1017 	mov  ah,  bl
1018 	mov  al,  018h              ; Line compare register
1019 	out  dx,  ax             ; Do lower 8 bits of line compare
1020 
1021 	mov  ah,  bh
1022 	and  ah,  1
1023 	mov  cl,  4
1024 	shl  ah,  cl            ; Bit 4 for over flow
1025 
1026 	mov  al,  07h           ; Access overflow register
1027 	out  dx,  al
1028 	inc  dx
1029 	in   al,  dx            ; Read the overflow register
1030 
1031 	and  al,  not 10h       ; Or in our bit and send back
1032 	or   al,  ah
1033 	out  dx,  al
1034 	dec  dx
1035 
1036 	mov  ah,  bh
1037 	and  ah,  2
1038 				    ; optimize here!!!
1039 	ror  ah,  1                 ; Second overflow bit to set
1040 	ror  ah,  1
1041 	ror  ah,  1
1042 
1043 	mov  al,  09h       ; Bit 6 of the Max Scan line register
1044 	out  dx,  al
1045 	inc  dx
1046 	in   al,  dx            ; Read it
1047 
1048 	and  al,  not 40h       ; Or in our bit and send it
1049 	or   al,  ah
1050 	out  dx,  al
1051 
1052 	sti                     ; Reallow interrupts
1053 
1054       ; Calculate Split offset
1055 	mov     ax, [ViewYLoc]          ; Get Y start
1056 	add     ax, [SplitY]            ; Add split line down in view
1057 	mul     [DLine_Offset]          ; Multiply times line size
1058 	add     ax, [Display_Page]      ; Add display page start
1059 	mov     [SplitOffset],  ax
1060 
1061    ; - DONE!!
1062 	pop     ds             ; Return state
1063 	pop     bp
1064 	ret
1065 
1066 ENDP  _XSet_SplitScreen
1067 
1068 
1069 
1070 ; --------------------------- _XSet_Box --------------------------------
1071 ; - This function will draw a box to the passed value.  The X coord must
1072 ; - be MOD 4 aligned.
1073 ; -
1074 public  _XSet_Box
1075 
1076 PROC    _XSet_Box   FAR
1077 
1078 	ARG   X_S:WORD, Y_S:WORD, X_D:WORD, Y_D:WORD, COLOR:BYTE
1079 
1080 	push            bp
1081 	mov             bp,     sp                      ; Save Stack frame
1082 	push            ds di si
1083 
1084 	; Set DS to local data
1085 	ASSUME  ds:  @fardata
1086 	mov     ax,  @fardata
1087 	mov     ds,  ax
1088 
1089 	cld
1090 
1091 	; Set ES to display mem and DI to start of rectangle on screen
1092 	mov     ax,  SCREEN_SEG
1093 	mov     es,  ax
1094 
1095 	mov     ax,  [WLine_Offset]  ; Get the line length for write page
1096 	mov     bx,  ax              ; Save in BX for later             
1097 	mul     [Y_S]                ; Find Y offset value. Place in AX
1098 
1099 	mov     di,  [X_S]     ; Find X offset value. Place in DI
1100 	shr     di,  1
1101 	shr     di,  1         ; Adjust for planes
1102 
1103 	add     di,  ax             ; Add X and Y offsets
1104 	add     di,  [Write_Page]   ; Add in page offset
1105 
1106      ; Set all data from CPU and non from latches
1107 	mov     dx,  GC_INDEX
1108 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
1109 	out     dx,  ax
1110 
1111 	; Insure Map Mask is set to all planes
1112 	mov     ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
1113 	mov     dx,  SC_INDEX
1114 	out     dx,  ax
1115 
1116      ; Insure X dist isn't 0 and put number of XBlocks in CX
1117 	mov     cx,  [X_D]
1118 	shr     cx,  1          ; Div by 4 so we have
1119 	shr     cx,  1          ; the actual number addresses to fill
1120 				; per line
1121 	cmp     cx,  0
1122 	jle     @@Done          ; Jump to stop if invalid
1123 
1124 
1125      ; SI will contain the number lines
1126 	mov     si,     [Y_D]
1127 
1128      ; Load color into al
1129 	mov     al,  [COLOR]
1130 
1131      ; Set BX to contain the distance from one scan line to next
1132 	sub     bx,     cx    ; BX was already loaded with line length
1133 
1134    @@Rowloop:
1135 	push    cx      ; Push cx so we can restore for each iteration
1136 
1137      ; Do the actual line.  REP STOSB.
1138 	rep     stosb
1139 
1140      ; Adjust for next iteration
1141 	pop     cx              ; Restore CX. ( [Pix/line]/4 )
1142 	add     di,     bx      ; Point DI to start of next line
1143 
1144      ; End of Rowloop.  Dec SI, if it is NOT 0 then do next line
1145 	dec     si
1146 	jnz     @@Rowloop
1147 
1148      ; Else DONE!!
1149 
1150    @@Done:
1151 	pop     si di ds
1152 	pop     bp
1153 	ret
1154 
1155 ENDP                    _XSet_Box
1156 
1157 
1158 ; --------------------------- _XClear -------------------------------
1159 ; - This will clear all memory on the video card to the passed value
1160 ; -
1161 public  _XClear
1162 
1163 PROC    _XClear   FAR
1164 
1165 	ARG     COLOR:WORD
1166 
1167 	push    bp
1168 	mov     bp,     sp                      ; Save Stack frame
1169 	push    di
1170 
1171      ; Set MAP MASK to all planes
1172 	mov     dx,     SC_INDEX                
1173 	mov     ax,     0F02h
1174 	out     dx,     ax
1175 
1176      ; Clear the screen
1177 	mov     ax,  SCREEN_SEG
1178 	mov     es,  ax
1179 	sub     di,  di
1180 	sub     ax,  ax
1181 	mov     ax,  [COLOR]
1182 	mov     ah,  al
1183 	mov     cx,  8000h
1184 	rep     stosw
1185 
1186      ; DONE!
1187 	pop     di   ; Return state
1188 	pop     bp
1189 	ret
1190 
1191 ENDP                    _XClear
1192 
1193 
1194 ; --------------------------- _XPut_Tile -------------------------------
1195 ; - This function will place a tile on the current write screen
1196 ; - It will be done a plane at a time and will expect the image data
1197 ; - to be laid out one plane at a time.
1198 ; - If there is an even number of XBlocks then a word write will be used
1199 ; -
1200 public  _XPut_Tile
1201 
1202 PROC    _XPut_Tile   FAR
1203 
1204 	ARG  X_S:WORD,  Y_S:WORD, X_D:WORD, Y_D:WORD, IMAGE_OFF:DWORD
1205 
1206 	push    bp
1207 	mov     bp,     sp                      ; Save Stack frame
1208 	push    ds di si
1209 
1210 	cld
1211 
1212       ; Set all data from CPU and non from latches
1213 	mov     dx,  GC_INDEX
1214 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
1215 	out     dx,  ax
1216 
1217       ; Get the Screen Seg and put it in es and load ds to fardata
1218 	mov     ax,  SCREEN_SEG
1219 	mov     es,  ax
1220 
1221 	ASSUME  ds:  @fardata
1222 	mov     ax,  @fardata
1223 	mov     ds,  ax          ; Set DS to local fardata
1224 
1225       ; Load CX with the number of XBlocks per image line
1226 	mov     cx,    [X_D]
1227 	shr     cx,    1
1228 	shr     cx,    1         ; Divide by 4 to get
1229 	mov     [X_D], cx        ; Save CX as new Delta
1230 
1231       ; Load di with destination offset and save it in DEST
1232 	mov     ax,       [WLine_Offset]        ; Size of line in XBlocks
1233 	mov     bx,     ax                              ; Save in DX
1234 	mul     [Y_S]
1235 
1236 	mov     di,     [X_S]
1237 	shr     di,  1
1238 	shr     di,     1
1239 
1240 	add     di,     [Write_Page]
1241 	add     di,     ax            ; Di is now loaded
1242 
1243 	mov     [X_S],  di       ; Store it.  Steal X start
1244 
1245       ; Set [Y_S] to the distance from one scan line to next
1246 			sub             bx,             cx                   ; minus number of XBlocks
1247 			mov          [Y_S],    bx                       ; Move to store
1248 
1249 		; Set BX to the number of scan lines
1250 			mov             bx,     [Y_D]
1251 
1252 		; Load ds:si with source
1253 			lds             si,     [IMAGE_OFF]
1254 
1255 		; Set up DX and AX for plane selection
1256 			mov             al,  02h                ; Select Map Mask
1257 			mov             dx,     SC_INDEX
1258 			out             dx,     al
1259 			inc             dx
1260 			mov             al,     011h            ; Set for plane selection
1261 
1262 		; Save CX in AH
1263 			mov             ah,     cl
1264 
1265    ; This section is for the WRITES ------------------------------
1266 
1267    @@PlanesW:          ; Master plane loop.
1268 
1269 	out     dx,  al        ; Set map mask
1270 	mov     dx,  [Y_S]     ; Steal DX to speed up add
1271 
1272    @@RowloopW:          ; Scan line loop
1273 
1274       ; Do the actual line.  REP MOVSW.
1275 	shr     cx,     1       ; Shift for word
1276 	rep     movsw
1277 	adc     cx,     0       ; Add 1(carry) to CX if dangling byte
1278 	rep     movsb           ; Write dangle if there
1279 
1280       ; Adjust for next iteration
1281 	mov     cl,  ah         ; Restore CX
1282 	add     di,  dx         ; Point DI to start of next line
1283 
1284       ; !!End of Rowloop.  Dec BX, if it is NOT 0 then do next line
1285 	dec     bx
1286 	jnz     @@RowloopW
1287 
1288       ; Done with plane.  Reset Destination pointers.  Adjst plane
1289 	mov     di,     [X_S]    ; Restore destination
1290 	mov     bx,     [Y_D]    ; Restore scan line count
1291 
1292       ; !!End of Plane loop.
1293 	mov     dx, (SC_INDEX+1) ; Restore DX for next plane
1294 	shl     al, 1            ; Shift up a plane.
1295 	jnc     @@PlanesW        ; If carry set, drop out
1296 
1297       ; !!!DONE
1298 	pop             si di ds             ; Return state
1299 	pop             bp
1300 	ret
1301 
1302 ENDP                    _XPut_Tile
1303 
1304 
1305 ; --------------------------- _XPut_TileA -------------------------------
1306 ; - This function will place a tile on the current write screen
1307 ; - It will be done a plane at a time and will expect the image data
1308 ; - to be laid out one plane at a time.
1309 ; - If there is an even number of XBlocks then a word write will be used
1310 ; -
1311 ; - This will work for any X alignment
1312 public  _XPut_TileA
1313 
1314 PROC    _XPut_TileA   FAR
1315 
1316 	ARG  X_S:WORD,  Y_S:WORD, X_D:WORD, Y_D:WORD, IMAGE_OFF:DWORD
1317 
1318 	push    bp
1319 	mov     bp,     sp                      ; Save Stack frame
1320 	push    ds di si
1321 
1322 	cld
1323 
1324       ; Set all data from CPU and non from latches
1325 	mov     dx,  GC_INDEX
1326 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
1327 	out     dx,  ax
1328 
1329       ; Get the Screen Seg and put it in es and load ds to fardata
1330 	mov     ax,  SCREEN_SEG
1331 	mov     es,  ax
1332 
1333 	ASSUME  ds:  @fardata
1334 	mov     ax,  @fardata
1335 	mov     ds,  ax          ; Set DS to local fardata
1336 
1337       ; Determine the start plane and save on stack
1338 	mov     cx,  [X_S]
1339 	and     cx,  3           ; Mask all but 2 LSB
1340 	mov     al,  11h
1341 	shl     al,  cl          ; Shift to first plane
1342 	push    ax
1343 
1344       ; Load CX with the number of XBlocks per image line
1345 	mov     cx,    [X_D]
1346 	shr     cx,    1
1347 	shr     cx,    1         ; Divide by 4 to get
1348 
1349       ; Load di with destination offset and save it in DEST
1350 	mov     ax,    [WLine_Offset]   ; Size of line in XBlocks
1351 	mov     bx,    ax               ; Save in BX
1352 	mul     [Y_S]
1353 
1354 	mov     di,    [X_S]
1355 	shr     di,    1
1356 	shr     di,    1
1357 
1358 	add     di,    [Write_Page]
1359 	add     di,    ax               ; Di is now loaded
1360 
1361 	mov     [X_S], di               ; Store it.  Steal X start
1362 
1363       ; Set [Y_S] to the distance from one scan line to next
1364 	sub     bx,    cx               ; minus number of XBlocks
1365 	mov     [Y_S], bx               ; Move to store
1366 
1367       ; Set BX to the number of scan lines
1368 	mov     bx,  [Y_D]
1369 
1370       ; Load ds:si with source
1371 	lds     si,  [IMAGE_OFF]
1372 
1373       ; Set up DX and AX for plane selection
1374 	mov     al,  02h        ; Select Map Mask
1375 	mov     dx,  SC_INDEX
1376 	out     dx,  al
1377 	inc     dx
1378 	pop     ax              ; Pop off the plane selection
1379 
1380       ; Save CX in AH
1381 	mov     ah,     cl
1382 
1383 	mov     [X_D],  4       ; Number of planes to do
1384 
1385    ; This section is for the WRITES ------------------------------
1386 
1387    @@PlanesW:          ; Master plane loop.
1388 
1389 	out     dx,  al        ; Set map mask
1390 	mov     dx,  [Y_S]     ; Steal DX to speed up add
1391 
1392    @@RowloopW:          ; Scan line loop
1393 
1394       ; Do the actual line.  REP MOVSW.
1395 	shr     cx,     1       ; Shift for word
1396 	rep     movsw
1397 	adc     cx,     0       ; Add 1(carry) to CX if dangling byte
1398 	rep     movsb           ; Write dangle if there
1399 
1400       ; Adjust for next iteration
1401 	mov     cl,  ah         ; Restore CX
1402 	add     di,  dx         ; Point DI to start of next line
1403 
1404       ; !!End of Rowloop.  Dec BX, if it is NOT 0 then do next line
1405 	dec     bx
1406 	jnz     @@RowloopW
1407 
1408       ; Done with plane.  Reset Destination pointers.  Adjst plane
1409 	mov     di,     [X_S]    ; Restore destination
1410 	mov     bx,     [Y_D]    ; Restore scan line count
1411 
1412       ; !!End of Plane loop.
1413 	mov     dx, (SC_INDEX+1) ; Restore DX for next plane
1414 	rol     al, 1            ; Shift up a plane.
1415 	adc     di, 0            ; Adjust to next XBlock if neccessary
1416 	mov     [X_S], di        ; Save in case it moved
1417 	dec     [X_D]            ; Decremet number of planes to do
1418 	jnz     @@PlanesW        ; If no planes left drop out
1419 
1420       ; !!!DONE
1421 	pop             si di ds             ; Return state
1422 	pop             bp
1423 	ret
1424 
1425 ENDP   _XPut_TileA
1426 
1427 
1428 
1429 ; --------------------------- _XTile_Size -----------------------------------
1430 ; - This function will return the total number of bytes an image requires
1431 ; - Div by 4 will yield the number of XBlocks
1432 public          _XTile_Size
1433 
1434 PROC                    _XTile_Size   FAR
1435 
1436 	ARG      X_D:WORD,      Y_D:WORD
1437 
1438 
1439 			push            bp
1440 			mov             bp,     sp              ; Save Stack frame
1441 
1442 		; Load AX with the total number of bytes
1443 			mov             cx,     [X_D]
1444 			mov             ax,     [Y_D]
1445 			mul             cx                ; Yield is total bytes
1446 
1447 		; AX holds return
1448 			pop             bp
1449 	       ret
1450 
1451 ENDP                    _XTile_Size
1452 
1453 
1454 ; --------------------------- _XUpload_Tile -------------------------------
1455 ; - This function will place a tile in the display memory
1456 ; - It will be done a plane at a time and will expect the image data
1457 ; - to be laid out one plane at a time.
1458 ; - The tile will be laid out in a linear manner and even though it may be
1459 ; - sent to the current screen it will not be correctly displayed
1460 ; -
1461 public          _XUpload_Tile
1462 public          _XUpload_Sprite
1463 LABEL          _XUpload_Sprite  FAR
1464 
1465 PROC                    _XUpload_Tile   FAR
1466 
1467 	ARG       DEST:WORD, ISIZE:WORD, IMAGE_OFF:DWORD
1468 
1469 			push            bp
1470 			mov             bp,     sp                      ; Save Stack frame
1471 			push            ds di si
1472 
1473 			cld
1474 
1475 		; Get the Screen Seg and put it in es
1476 			mov             ax,  SCREEN_SEG
1477 			mov             es,  ax
1478 
1479 
1480 		; Load di with destination offset and save it in DEST
1481 			mov             di,             [DEST]
1482 			mov       bx,           di       ; Store it
1483 
1484 		; Load ds:si with source
1485 			lds             si,     [IMAGE_OFF]
1486 
1487 		; Get number of XBlocks per plane.
1488 			mov             cx,  [ISIZE]
1489 			shr             cx,  1
1490 			shr             cx,  1
1491 			mov             bp,  cx ; Save size in BP
1492 
1493 		; Set all data from CPU and non from latches
1494 			mov             dx,     GC_INDEX
1495 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
1496 			out             dx,     ax
1497 
1498 		; Set up DX and AX for plane selection
1499 			mov             al,     02h             ; Select the MAP MASK
1500 			mov             dx,     SC_INDEX
1501 			out             dx,  al
1502 			inc             dx
1503 			mov             al,     11h             ; Plane 0
1504 
1505 		; This section is for WRITES ------------------------------
1506 	@@BeginWrite:
1507 
1508 	@@PlanesW:                      ; Master plane loop.
1509 
1510 			out          dx,        al      ; Set the plane
1511 
1512 		; Do the actual line.  REP MOVSW.
1513 			shr             cx,     1       ; Set for word writes
1514 			rep             movsw
1515 			adc             cx,     0       ; Add 1(carry) to CX to see if dangle
1516 			rep       movsb ; Write the dangle if there.
1517 
1518 		; Done with plane.  Reset Destination pointers.  Adjst plane
1519 			mov             di,     bx              ; Restore Destination
1520 			mov             cx,  bp         ; Restore CX.
1521 
1522 		; !!End of Plane loop.
1523 			shl             al,     1               ; Shift plane selector
1524 			jnc             @@PlanesW               ; If no carry, then more to do
1525 
1526 
1527 		; !!DONE!!
1528 			pop             si di ds            ; Return state
1529 			pop             bp
1530 			ret
1531 
1532 ENDP                    _XUpload_Tile
1533 
1534 
1535 ; --------------------------- _XPaste_Tile -------------------------------
1536 ; - This function will place a tile from the display memory to current screen
1537 ; -
1538 public          _XPaste_Tile
1539 
1540 PROC                    _XPaste_Tile   FAR
1541 
1542 
1543 	ARG     X_S:WORD,       Y_S:WORD, X_D:WORD,     Y_D:WORD,       TILE:WORD
1544 
1545 			push            bp
1546 			mov             bp,     sp              ; Save Stack frame
1547 			push            ds di si
1548 
1549 	       cld
1550 
1551 		; Load DS.
1552 
1553 			ASSUME  ds:  @fardata
1554 			mov             ax,  @fardata
1555 			mov             ds,  ax                 ; Set DS to segment XTile data
1556 
1557 		; Set DI to start of rectangle on screen
1558 			mov             ax,  [WLine_Offset]
1559 			mul             [Y_S]              ; Find Y offset value. Place in AX
1560 
1561 			mov             di,  [X_S]        ; Find X offset value. Place in DI
1562 			shr             di,  1
1563 			shr             di,  1
1564 
1565 			add             di,  ax            ; Add X and Y offsets
1566 			add             di,  [Write_Page] ; Add in page offset
1567 
1568 		; Set all data from latches
1569 			mov             dx,     GC_INDEX
1570 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
1571 			out             dx,     ax
1572 
1573 		; Insure Map Mask is set to all planes
1574 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
1575 			mov             dx,     SC_INDEX
1576 			out             dx,     ax
1577 
1578 		; Load CX with XBlocks per scan line
1579 			mov             cx,  [X_D]
1580 			shr             cx,  1          ; Div by 4 so we have
1581 			shr             cx,  1         ; Xblock count
1582 
1583 		; Set AX to the distance from one scan line to next
1584 			mov             ax,             [WLine_Offset]
1585 			sub             ax,             cx
1586 
1587 		; Set SI to source
1588 			mov             si,             [TILE]
1589 
1590 		; Get the Screen Seg and put it in DS and ES
1591 			mov             dx,  SCREEN_SEG
1592 			mov             ds,  dx
1593 			mov             es,     dx
1594 
1595 		; Set DX to the number of scan lines
1596 			mov             dx,     [Y_D]
1597 
1598 		; Save the CX in BP
1599 			mov             bp,             cx
1600 
1601 		; This section is for WRITES ------------------------------
1602 	@@Rowloop:
1603 
1604 		; Do the actual line.  REP MOVSB.
1605 			rep             movsb
1606 
1607 		; Adjust for next iteration
1608 			mov             cx,  bp ; Restore CX.
1609 			add             di,     ax      ; Point DI to start of next line
1610 
1611 		; End of Rowloop.  Dec DX, if it is NOT 0 then do next line
1612 			dec             dx
1613 			jnz             @@Rowloop
1614 
1615 		; !!DONE!!
1616 			pop             si di ds             ; Return state
1617 			pop             bp
1618 			ret
1619 
1620 ENDP                    _XPaste_Tile;
1621 
1622 
1623 ;-------------------------- _XPaste_Sprite ------------------------------
1624 ; - This function will place a sprite from the display memory to current screen
1625 ; - It will NOT do masking
1626 public          _XPaste_Sprite
1627 
1628 PROC                    _XPaste_Sprite   FAR
1629 
1630 
1631 	ARG     X_S:WORD,       Y_S:WORD, X_D:WORD,     Y_D:WORD,       TILE:WORD
1632 
1633 			push            bp
1634 			mov             bp,     sp              ; Save Stack frame
1635 			push            ds di si
1636 
1637 	       cld
1638 
1639 		; Load DS.
1640 
1641 			ASSUME  ds:  @fardata
1642 			mov             ax,  @fardata
1643 			mov             ds,  ax                 ; Set DS to segment XTile data
1644 
1645 		; Set DI to start of rectangle on screen
1646 			mov             ax,  [WLine_Offset]
1647 			mul             [Y_S]              ; Find Y offset value. Place in AX
1648 
1649 			mov             di,  [X_S]        ; Find X offset value. Place in DI
1650 			shr             di,  1
1651 			shr             di,  1          
1652 
1653 			add             di,  ax            ; Add X and Y offsets
1654 			add             di,  [Write_Page] ; Add in page offset
1655 
1656 		; Set SI to source
1657 			mov             si,             [TILE]
1658 
1659 		; Find adjustment to source for alignment
1660 			mov             ax,     [X_D]
1661 			mov             cx,     [X_S]
1662 
1663 			shr             ax,     1          ; Number of XBlocks a line
1664 			shr             ax,     1
1665 			mul             [Y_D]        ; Find size of each sprite alignment
1666 			
1667 			and             cx,     3          ; Mask all but 2 LSBs
1668 			
1669 			mul             cx                 ; Find new offset                            
1670 
1671 			add             si,     ax         ; Adjust SI  
1672 
1673 		; Get the Screen Seg and put it in DS and ES
1674 			mov             ax,  SCREEN_SEG
1675 			mov             ds,  ax
1676 			mov             es,     ax
1677 
1678 		; Set all data from latches
1679 			mov             dx,     GC_INDEX
1680 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
1681 			out             dx,     ax
1682 
1683 		; Insure Map Mask is set to all planes
1684 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
1685 			mov             dx,     SC_INDEX
1686 			out             dx,     ax
1687 
1688 		; Load CX with XBlocks per scan line
1689 			mov             cx,  [X_D]
1690 			shr             cx,  1          ; Div by 4 so we have
1691 			shr             cx,  1         ; Xblock count
1692 
1693 		; Set AX to the distance from one scan line to next
1694 			mov             ax,             [WLine_Offset]
1695 			sub             ax,             cx
1696 
1697 		; Set DX to the number of scan lines
1698 			mov             dx,     [Y_D]
1699 
1700 		; Save CX in BP
1701 			mov             bp,             cx
1702 
1703 		; This section is for WRITES ------------------------------
1704 	@@Rowloop:
1705 
1706 		; Do the actual line.  REP MOVSB.
1707 			rep             movsb
1708 
1709 		; Adjust for next iteration
1710 			mov             cx,  bp ; Restore CX.
1711 			add             di,     ax      ; Point DI to start of next line
1712 
1713 		; End of Rowloop.  Dec DX, if it is NOT 0 then do next line
1714 			dec             dx
1715 			jnz             @@Rowloop
1716 
1717 		; !!DONE!!
1718 			pop             si di ds             ; Return state
1719 			pop             bp
1720 			ret
1721 
1722 ENDP                    _XPaste_Sprite
1723 
1724 
1725 ; --------------------------- _XPut_Tile_M -------------------------------
1726 ; - This function will place a tile on the current write screen
1727 ; - It will be done a plane at a time and will expect the image data
1728 ; - to be laid out one plane at a time.
1729 ; - All 0 pixels will leave the screen intact.
1730 ; -
1731 public  _XPut_Tile_M
1732 
1733 PROC    _XPut_Tile_M   FAR
1734 
1735 	ARG     X_S:WORD,       Y_S:WORD, X_D:WORD,     Y_D:WORD,       IMAGE_OFF:DWORD
1736 
1737 	push            bp
1738 	mov             bp,     sp                      ; Save Stack frame
1739 	push            ds di si
1740 
1741 	cld
1742 
1743       ; Get the Screen Seg and put it in es
1744 	mov             ax,  SCREEN_SEG
1745 	mov             es,  ax
1746 
1747 
1748       ; Load CX with the number of XBlocks per scan line
1749 	mov             cx,     [X_D]
1750 	shr             cx,     1
1751 	shr             cx,     1         ; Divide by 4 to get
1752 
1753       ; Load DS.
1754 	ASSUME  ds:  @fardata
1755 	mov             ax,  @fardata
1756 	mov             ds,  ax                 ; Set DS to fardata segment
1757 
1758       ; Set [X_D] to the distance from one scan line to next
1759 	mov             ax,             [WLine_Offset]
1760 	sub             ax,             cx
1761 	mov             [X_D],  ax
1762 
1763       ; Save number of XBlocks a line in upper cx
1764 	mov             ch,             cl
1765 
1766 		; Set BL to the number of scan lines and save
1767 			mov             bx,     [Y_D]
1768 
1769 		; Load di with destination offset and save it in DEST
1770 			mov             ax,             [WLine_Offset]
1771 			mul             [Y_S]
1772 
1773 			mov             di,     [X_S]
1774 			shr             di,  1
1775 			shr             di,     1             ; Adjust to number of XBlocks
1776 
1777 			add       di,   [Write_Page]
1778 			add             di,     ax            ; Di is now loaded
1779 
1780 			mov       [X_S],        di       ; Store it
1781 
1782 		; Load ds:si with source
1783 			lds             si,     [IMAGE_OFF]
1784 
1785 		; Set all data from CPU and non from latches
1786 			mov             dx,     GC_INDEX
1787 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
1788 			out             dx,     ax
1789 
1790 		; Set up DX and AX for plane selection
1791 			mov             al,     02h     ; Plane 0 selected
1792 			mov             dx,     SC_INDEX
1793 			inc             dx
1794 			mov             ax,     1111h   ; Set up AX
1795 
1796 		; This section is for the WRITE ------------------------------
1797 	@@PlanesB:          ; Master plane loop.
1798 
1799 			out             dx,     al   ; Set the plane
1800 			mov     dx,     [X_D]   ; Steal DX to speed up add
1801 
1802 	@@RowloopB:             ; Scan line line
1803 
1804 		; Do the actual line.
1805 	@@PixelLoop:
1806 			lodsb                           ; Get the pixel
1807 			or              al,     al              ; Is it zero
1808 			jz              @@NoDraw       ; If zero, don't draw it
1809 			mov             [es:di],        al      ; Else, do draw it
1810 
1811 	@@NoDraw:
1812 			inc             di
1813 			dec       cl
1814 			jnz             @@PixelLoop
1815 
1816 		; Adjust for next iteration
1817 			mov             cl,  ch         ; Restore CL. ( [Pix/line]/4 )
1818 			add             di,     dx      ; Point DI to start of next line
1819 
1820 		; !!End of Rowloop.  Dec SI, if it is NOT 0 then do next line
1821 			dec             bx
1822 			jnz             @@RowloopB
1823 
1824 		; Done with plane.  Reset Destination pointers.  Adjst plane
1825 			mov             di,     [X_S]     ; Restore destination
1826 			mov             bx,     [Y_D]   ; Restore scan line count
1827 			shl             ah,     1               ; Adjust plane
1828 			mov             al,  ah         ; Save the
1829 			mov             dx,     SC_INDEX+1 ; Restore SC ptr
1830 			jnc             @@PlanesB      ; If no carry, then more planes
1831 
1832 		; !!!DONE
1833 			pop             si di ds             ; Return state
1834 			pop             bp
1835 			ret
1836 
1837 ENDP                    _XPut_Tile_M
1838 
1839 
1840 ; --------------------------- _XPut_TileA_M -------------------------------
1841 ; - This function will place a tile on the current write screen
1842 ; - It will be done a plane at a time and will expect the image data
1843 ; - to be laid out one plane at a time.
1844 ; - If there is an even number of XBlocks then a word write will be used
1845 ; -
1846 ; - This will work for any X alignment
1847 public  _XPut_TileA_M
1848 
1849 PROC    _XPut_TileA_M   FAR
1850 
1851 	ARG  X_S:WORD,  Y_S:WORD, X_D:WORD, Y_D:WORD, IMAGE_OFF:DWORD
1852 
1853 	push    bp
1854 	mov     bp,     sp                      ; Save Stack frame
1855 	push    ds di si
1856 
1857 	cld
1858 
1859       ; Set all data from CPU and non from latches
1860 	mov     dx,  GC_INDEX
1861 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
1862 	out     dx,  ax
1863 
1864       ; Get the Screen Seg and put it in es and load ds to fardata
1865 	mov     ax,  SCREEN_SEG
1866 	mov     es,  ax
1867 
1868 	ASSUME  ds:  @fardata
1869 	mov     ax,  @fardata
1870 	mov     ds,  ax          ; Set DS to local fardata
1871 
1872       ; Determine the start plane and save on stack
1873 	mov     cx,  [X_S]
1874 	and     cx,  3           ; Mask all but 2 LSB
1875 	mov     ah,  11h
1876 	shl     ah,  cl          ; Shift to first plane
1877 	push    ax
1878 
1879       ; Load CX with the number of XBlocks per image line
1880 	mov     cx,    [X_D]
1881 	shr     cx,    1
1882 	shr     cx,    1         ; Divide by 4 to get
1883 
1884       ; Load di with destination offset and save it in DEST
1885 	mov     ax,    [WLine_Offset]   ; Size of line in XBlocks
1886 	mov     bx,    ax               ; Save in BX
1887 	mul     [Y_S]
1888 
1889 	mov     di,    [X_S]
1890 	shr     di,    1
1891 	shr     di,    1
1892 
1893 	add     di,    [Write_Page]
1894 	add     di,    ax               ; Di is now loaded
1895 
1896 	mov     [X_S], di               ; Store it.  Steal X start
1897 
1898       ; Set [Y_S] to the distance from one scan line to next
1899 	sub     bx,    cx               ; minus number of XBlocks
1900 	mov     [Y_S], bx               ; Move to store
1901 
1902       ; Set BX to the number of scan lines
1903 	mov     bx,  [Y_D]
1904 
1905       ; Load ds:si with source
1906 	lds     si,  [IMAGE_OFF]
1907 
1908       ; Set up DX and AX for plane selection
1909 	mov     al,  02h        ; Select Map Mask
1910 	mov     dx,  SC_INDEX
1911 	out     dx,  al
1912 	inc     dx
1913 	pop     ax              ; Pop off the plane selection
1914 
1915       ; Save CL in CH
1916 	mov     ch,     cl
1917 
1918 	mov     [X_D],  4       ; Number of planes to do
1919 
1920    ; This section is for the WRITES ------------------------------
1921 
1922    @@PlanesW:          ; Master plane loop.
1923 
1924 	mov     al,  ah        ; Prep ah
1925 	out     dx,  al        ; Set map mask
1926 	mov     dx,  [Y_S]     ; Steal DX to speed up add
1927 
1928    @@RowloopW:          ; Scan line loop
1929 
1930       ; Do the actual line.
1931    @@PixelLoop:
1932 	lodsb
1933 	or      al,      al    ; Is it zero
1934 	jz      @@NoDraw       ; If zero, don't draw it
1935 	mov     [es:di], al    ; Else, do draw it
1936 
1937    @@NoDraw:
1938 	inc     di
1939 	dec     cl
1940 	jnz     @@RowloopW
1941 
1942 
1943       ; Adjust for next iteration
1944 	mov     cl,  ch         ; Restore CX
1945 	add     di,  dx         ; Point DI to start of next line
1946 
1947       ; !!End of Rowloop.  Dec BX, if it is NOT 0 then do next line
1948 	dec     bx
1949 	jnz     @@RowloopW
1950 
1951       ; Done with plane.  Reset Destination pointers.  Adjst plane
1952 	mov     di,     [X_S]    ; Restore destination
1953 	mov     bx,     [Y_D]    ; Restore scan line count
1954 
1955       ; !!End of Plane loop.
1956 	mov     dx, (SC_INDEX+1) ; Restore DX for next plane
1957 	rol     ah, 1            ; Shift up a plane.
1958 	adc     di, 0            ; Adjust to next XBlock if neccessary
1959 	mov     [X_S], di        ; Save in case it moved
1960 	dec     [X_D]            ; Decremet number of planes to do
1961 	jnz     @@PlanesW        ; If no planes left drop out
1962 
1963       ; !!!DONE
1964 	pop             si di ds             ; Return state
1965 	pop             bp
1966 	ret
1967 
1968 ENDP   _XPut_TileA_M
1969 
1970 
1971 
1972 ; --------------------------- _XMove_Tile ----------------------------------
1973 ; - This function will move a tile about on the current write page
1974 ; - Coord, Size, and destination must be givin
1975 public          _XMove_Tile
1976 
1977 PROC                    _XMove_Tile   FAR
1978 
1979   ARG  X_S:WORD, Y_S:WORD, X_E:WORD, Y_E:WORD, X_D:WORD, Y_D:WORD
1980 
1981 	push            bp
1982 	mov             bp,     sp              ; Save Stack frame
1983 	push            ds si di
1984 
1985 	cld
1986 
1987       ; Load DS.
1988 	ASSUME  ds:  @fardata
1989 	mov     ax,  @fardata
1990 	mov     ds,  ax                 ; Set DS to fardata segment
1991 
1992 	mov	cl,  2
1993 
1994       ; Load si with source X in XBlocks
1995 	mov     si,  [X_S]
1996 	shr     si,  cl
1997 
1998       ; Load di with destination X in XBlocks
1999 	mov     di,  [X_D]
2000 	shr     di,  cl
2001 
2002       ; Convert [X_E] to width in XBlocks
2003 	mov     bx,  [X_E]
2004 	shr     bx,  cl
2005 
2006 	mov     ax,     bx   ; Save in AX
2007 	mov     [X_E],  bx   ; Put back
2008 
2009       ; Determine the X direction
2010 	cmp     si,     di
2011 	jge     @@GoLeft
2012 
2013       ; Going right.  Copy right to left
2014 	dec     ax
2015 	add     si,     ax   ; Source starts at right edge
2016 	add     di,     ax   ; Same with destination
2017 	neg     bx           ; Make negative
2018 	std                  ; Move backwards on string instructions
2019 
2020       ; Determine the Y direction
2021     @@GoLeft:
2022 	mov     cx,  [WLine_Offset]
2023 	mov     ax,  [Y_S]     	; Get the Y source start
2024 	mov     dx,  [Y_D]      ; Get the Y destination
2025 	cmp     ax,  dx         ; Going up or down
2026 	jge     @@GoUp
2027 
2028       ; Rectangle going down.  Copy bottom to top
2029 	mov     ax,  [Y_E]      ; Get the bottom coord
2030 	add     dx,  ax         ; Add it to the destination, so
2031 				;   it points to end of destination blk
2032 	neg     cx              ; Make CX negative
2033 	add     ax,     [Y_S]   ; Point AX to end of source blk
2034 				;   by adding size to start
2035 
2036       ; Calcuate the offsets
2037     @@GoUp:
2038 	push            dx              ; Save DX the torment of a multiply
2039 	mul             [WLine_Offset]  ; Find Y adder for source
2040 	add             si,     ax      ; Add it
2041 
2042 	pop             ax              ; Pop off the destination Y into AX
2043 	mul             [WLine_Offset]  ; Find Y adder for destination
2044 	add             di,     ax      ; Add it
2045 
2046 	sub             cx,     bx      ; Find the scan line data
2047 
2048       ; Add in the write page offset
2049 	add             si,     [Write_Page]
2050 	add             di,     [Write_Page]
2051 
2052       ; Get the Screen Seg and put it in DS and ES
2053 	mov             ax,  SCREEN_SEG
2054 	mov             ds,  ax
2055 	mov             es,     ax
2056 
2057       ; Set all data from latches
2058 	mov             dx,     GC_INDEX
2059 	mov             ax,     00000h + BIT_MASK  ; Set all latch writes
2060 	out             dx,     ax
2061 
2062       ; Insure Map Mask is set to all planes
2063 	mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
2064 	mov             dx,     SC_INDEX
2065 	out             dx,     ax
2066 
2067       ; Set AX to the Scan line lenghth
2068 	mov             ax,     [X_E]
2069 
2070       ; Set BX to the Y size
2071 	mov             bx,     [Y_E]
2072 
2073       ; Set DX to the Scan line differential
2074 	mov             dx,  cx
2075 
2076     ; Do the WRITES---------------------
2077     @@ScanLoop:
2078 
2079 	mov             cx,  ax ; Set cx to the Scan size
2080 	rep             movsb   ; Do the line
2081 
2082       ; Add the scan line differential to source and dest
2083 	add             si,     dx
2084 	add             di,     dx
2085 
2086       ; See if done with all lines
2087 	dec             bx
2088 	jnz             @@ScanLoop      ; No, then go and do another line
2089 
2090       ; !!DONE!!
2091 	pop             di si ds
2092 	pop             bp                      ; Return state
2093 			ret
2094 
2095 ENDP  _XMove_Tile
2096 
2097 
2098 ; --------------------------- _XMove_TileA --------------------------------
2099 ; - This function will move a tile to the alternate page
2100 ; - Coord, Size, and destination must be givin
2101 public          _XMove_TileA
2102 
2103 PROC                    _XMove_TileA   FAR
2104 
2105   ARG  X_S:WORD, Y_S:WORD, X_E:WORD, Y_E:WORD, X_D:WORD, Y_D:WORD
2106 
2107 			push            bp
2108 			mov             bp,     sp              ; Save Stack frame
2109 			push            ds si di
2110 
2111 			cld
2112 
2113 		; Load DS.
2114 			ASSUME  ds:  @fardata
2115 			mov             ax,  @fardata
2116 			mov             ds,  ax                 ; Set DS to fardata segment
2117 
2118 		; Set all data from latches
2119 			mov             dx,     GC_INDEX
2120 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
2121 			out             dx,     ax
2122 
2123 		; Insure Map Mask is set to all planes
2124 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
2125 			mov             dx,     SC_INDEX
2126 			out             dx,     ax
2127 
2128 		; Set SI to start of rectangle in write page
2129 			mov             ax,  [WLine_Offset] ; Get line size
2130 			mov             cx,     ax                      ; Save in CX
2131 			mul             [Y_S]                   ; Find Y offset
2132 
2133 			mov             si,  [X_S]          ; Find X offset value. Place in DI
2134 			shr             si,  1
2135 			shr             si,  1
2136 
2137 			add             si,  ax              ; Add X and Y offsets
2138 			add             si,  [Write_Page]   ; Add in page offset
2139 
2140 		; Set DI to start of rectangle in write page
2141 			mov             ax,  [ALine_Offset] ; Get line size
2142 			mov             bx,     ax                      ; Save in BX
2143 			mul             [Y_D]                   ; Find Y offset
2144 
2145 			mov             si,  [X_D]     ; Find X offset value. Place in DI
2146 			shr             si,  1
2147 			shr             si,  1
2148 
2149 			add             si,  ax              ; Add X and Y offsets
2150 			add             si,  [Alt_Page]     ; Add in page offset
2151 
2152 
2153 		; Set AX to the Scan line lenghth in XBlocks
2154 			mov             ax,     [X_E]
2155 			shr             ax,  1
2156 			shr             ax,     1
2157 
2158 		; Make BX the scan line differntial for the alt page
2159 			sub             bx,     ax
2160 
2161 		; Make DX the scan line differntial for the write page
2162 			sub             cx,     ax
2163 			mov             dx,     cx
2164 
2165 		; Set BP to the Y size
2166 			mov             bp,  [Y_E]
2167 
2168 		; Get the Screen Seg and put it in DS and ES
2169 			mov             cx,  SCREEN_SEG
2170 			mov             ds,  cx
2171 			mov             es,     cx
2172 
2173 	  ; Do the WRITES---------------------
2174 	@@ScanLoop:
2175 
2176 			mov             cx,  ax ; Set cx to the Scan size
2177 			rep             movsb   ; Do the line
2178 
2179 		; Add the scan line differential to source and dest
2180 			add             si,     dx
2181 			add             di,     bx
2182 
2183 		; See if done with all lines
2184 			dec             bp
2185 			jnz             @@ScanLoop      ; No, then go and do another line
2186 
2187 		; !!DONE!!
2188 			pop             di si ds
2189 			pop             bp                      ; Return state
2190 			ret
2191 
2192 ENDP                    _XMove_TileA
2193 
2194 
2195 ; --------------------------- _XRegister_Font8 ------------------------------
2196 ; - This function will register a 8-font.
2197 ; - The function will return in AX the actual number of bytes used.
2198 ; - The function expects each character to be laid out as for Upload_Tile,
2199 ; - one character at a time.  Each character is 8x by 10y.
2200 
2201 public          _XRegister_Font8
2202 
2203 PROC                    _XRegister_Font8   FAR
2204 
2205 	ARG       DEST:WORD, NUMBER:WORD, BASE:WORD, UPLOAD:WORD, FONT_OFF:DWORD
2206 
2207 			push            bp
2208 			mov             bp,     sp                      ; Save Stack frame
2209 			push            ds di si
2210 
2211 			cld
2212 
2213 		; Load DS.
2214 			ASSUME  ds:  @fardata
2215 			mov             ax,  @fardata
2216 			mov             ds,  ax                 ; Set DS to fardata segment
2217 
2218 		; Save the base char
2219 			mov             ax,                     [BASE]
2220 			mov             [Char_Base8],   ax
2221 
2222 		; Will we upload this font?
2223 			mov             cx,     [UPLOAD]
2224 			mov             [UpLoaded8], cx ; Flag it       ( 0 is uploaded )
2225 			jcxz            @@UploadFont            ; Yes!, then jump to it
2226 
2227 		; Don't upload this font.  Just register and return.
2228 			les             si,                       [FONT_OFF]
2229 			mov             [Font_SiteD8],   si
2230 			mov             ax,                       es
2231 			mov             [Font_SiteD8+2], ax
2232 			jmp       @@DONE
2233 
2234 	@@UploadFont:
2235 		; Check font size to insure no overrun
2236 			mov             dx,     20
2237 			mov             ax,     [NUMBER]
2238 			mul             dx                      ; Mul number of chars by 20bytes
2239 			add             ax,  [DEST]     ; Add destination to get proposed end
2240 			cmp             ax,     STORE   ; Where is it in relation to begin
2241 			ja              @@CONT          ; If above, no wrap of AX, OK
2242 			mov             ax,     0               ; Else leave 0 in AX, indicating ERR
2243 			jmp             @@DONE          ; And jump out
2244 
2245 	@@CONT:
2246 		; Save the size and location
2247 			mov             ax,            [DEST]
2248 			mov             [Font_SiteU8],  ax
2249 
2250 		; Load di with destination offset and save it in DX
2251 			mov             di,             ax          ; AX retains it from prev action
2252 			mov       dx,       ax       ; Store it
2253 
2254 		; Load ds:si with source
2255 			lds             si,  [FONT_OFF]
2256 
2257 		; Load es with SCREEN SEG
2258 			mov             ax,  SCREEN_SEG
2259 			mov             es,     ax
2260 
2261 		; This section iterates for each char----------------------------
2262 			mov             bx,     [NUMBER]        ; Set BL to number of characters
2263 
2264 		; Set BP to destination, as was in DX
2265 			mov             bp,  dx
2266 
2267 		; Set all data from CPU and non from latches
2268 			mov             dx,     GC_INDEX
2269 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
2270 			out             dx,     ax
2271 
2272 		; Set up DX plane selection
2273 			mov             dx,     SC_INDEX
2274 
2275 		; Set CX to number of scan lines in a char
2276 			mov             cx,     10        ; Set CX to 10 scan lines
2277 
2278 	@@BeginWrite:
2279 
2280 		; Set AX up for plane selection
2281 			mov             ax,     1102h   ; Plane 0 selected
2282 
2283 		; This section loops through the planes for each char -----------
2284 	@@PlanesW:                              ; Master plane loop.
2285 
2286 			out          dx,        ax      ; Set the plane
2287 
2288 		; Do the actual line.  REP MOVSW.  Move both XBlocks on each line
2289 			rep             movsw
2290 
2291 	  ; Done with plane.  Reset Destination pointers.  Adjst plane
2292 			mov             di,     bp
2293 			shl             ah,     1               ; Adjust plane. Carry set if done
2294 			mov             cx,  10      ; Restore CX.
2295 
2296 		; !!End of Plane loop.
2297 			jnc             @@PlanesW      ; If no carry, not done with char
2298 
2299 		; !!End of Char loop.
2300 
2301 			add             bp,     20              ; Adjust destination for next char
2302 			mov             di,     bp              ; Store it in DI
2303 
2304 			dec             bx             ; Another char done
2305 			jnz             @@BeginWrite   ; If not zero, not done with font set
2306 
2307 		; !!DONE!!
2308 		@@DONE:
2309 			pop             si di ds            ; Return state
2310 			pop             bp
2311 			ret
2312 
2313 ENDP                    _XRegister_Font8
2314 
2315 
2316 ; ----------------------------- _XChar8 ----------------------------------
2317 ; - This function will place a char from the current font to current screen
2318 ; - Uses the 8pix font
2319 public          _XChar8
2320 
2321 PROC                    _XChar8   FAR
2322 
2323 	ARG     X_S:WORD,       Y_S:WORD, CHAR:WORD
2324 
2325 			push            bp
2326 			mov             bp,     sp              ; Save Stack frame
2327 			push            ds di si
2328 
2329 			cld
2330 
2331 		; Load DS.
2332 			ASSUME  ds:  @fardata
2333 			mov             ax,  @fardata
2334 			mov             ds,  ax                 ; Set DS to segment w/ Table
2335 
2336 		; Set DI to start of character on screen
2337 			mov             ax,  [WLine_Offset]
2338 			mul             [Y_S]              ; Find Y offset value. Place in AX
2339 
2340 			mov             di,  [X_S]        ; Find X offset value. Place in DI
2341 			shr             di,  1
2342 			shr             di,  1             ; Adjust to number of XBlocks
2343 
2344 			add             di,  ax            ; Add X and Y offsets
2345 			add             di,  [Write_Page] ; Add in page offset
2346 
2347 		; Is the font uploaded or not
2348 			mov             ax,     [UpLoaded8]
2349 			cmp             ax,     UPLOADFONT
2350 			je              @@FontIsUploaded        ; The font is uploaded
2351 
2352 	  ; - Font is not uploaded
2353 		; Set CX to the scan line differential
2354 			mov             cx,  [WLine_Offset]
2355 			sub             cx,  2                  ; Subtract the XBlocks of a char
2356 
2357 		; Figure character offset and add to load ds:si font site
2358 			mov             ax,     80                      ; Put font size in ax
2359 			xor             bx,     bx                      ; Clear bx
2360 			mov             bx,     [CHAR]         ; Put character place in BX
2361 			sub             bx,     [Char_Base8]    ; Subtract base char
2362 			mul             bx                              ; Mul size by place
2363 			lds             si,  [Font_Addr8]
2364 			add             si,  ax
2365 
2366 		; Move the scan line differential from CX to BP
2367 			mov             bp,  cx
2368 
2369 		; Save the base destination in CX
2370 			mov             cx,  di
2371 
2372 		; Get the Screen Seg and put it in ES
2373 			mov             ax,  SCREEN_SEG
2374 			mov             es,     ax
2375 
2376 		; Set all data from CPU and non from latches
2377 			mov             dx,     GC_INDEX
2378 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
2379 			out             dx,     ax
2380 
2381 		; Set up DX and AX for plane selection
2382 			mov             ax,     1102h   ; Plane 0 selected
2383 			mov             dx,     SC_INDEX
2384 
2385 		; This section is for WRITES ------------------------------
2386 
2387 		; Set BH to number of lines to do
2388 			mov       bx,  10               ; 10 scan lines per 8-pix font
2389 
2390 	@@PlanesW:          ; Master plane loop.
2391 
2392 			out             dx,     ax      ; Set the plane
2393 
2394 	@@RowloopW:             ; Scan line loop
2395 
2396 		; Do the actual line.  MOVSW.
2397 			movsw
2398 
2399 		; Adjust for next iteration
2400 			add             di,     bp              ; Point DI to start of next line
2401 
2402 		; !!End of Rowloop.  Dec BH, if it is NOT 0 then do next line
2403 			dec             bx
2404 			jnz             @@RowloopW
2405 
2406 		; Done with plane.  Reset Destination pointers.  Adjst plane
2407 			mov             di,     cx              ; Restore the destination start
2408 			mov             bx,     10              ; Restore scan line count
2409 			shl             ah,     1               ; Adjust plane
2410 
2411 		; !!End of Plane loop.
2412 			jnc             @@PlanesW               ; If no carry, then more to do.
2413 
2414 
2415 
2416 		; Done with this
2417 			jmp             @@DONE
2418 
2419 
2420 	  ; - Font is uploaded
2421 	  @@FontIsUploaded:
2422 		; Calc the source and put in SI
2423 			mov             si,     [Font_SiteU8]   ; Get base location
2424 			mov             ax,     20                      ; Put font size in ax (in XBlock)
2425 			mov             bx,     [CHAR]         ; Put character place in BX
2426 			sub             bx,     [Char_Base8]    ; Subtract base char
2427 			mul             bx                              ; Mul size by place
2428 			add             si,     ax                      ; Put in SI
2429 
2430 		; Insure Map Mask is set to all planes
2431 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
2432 			mov             dx,     SC_INDEX
2433 			out             dx,     ax
2434 
2435 		; Set all data from latches
2436 			mov             dx,     GC_INDEX
2437 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
2438 			out             dx,     ax
2439 
2440 		; Set AX to line dif.
2441 			mov             ax,     [WLine_Offset]          ; Page width
2442 			sub          ax,  2                   ; minus XBlocks per char
2443 
2444 		; Get the Screen Seg and put it in DS and ES
2445 			mov             dx,  SCREEN_SEG
2446 			mov             ds,  dx
2447 			mov             es,     dx
2448 
2449 		; Set CX to the number of scan lines
2450 			mov             cx,             10
2451 
2452 		; This section is for WRITES ------------------------------
2453 	@@Rowloop:
2454 
2455 		; Do the actual line.  MOVSB.
2456 					movsb
2457 					movsb
2458 
2459 		; Adjust for next iteration
2460 			add             di,     ax      ; Point DI to start of next line
2461 
2462 		; End of Rowloop.
2463 			loop            @@Rowloop
2464 
2465 		; !!DONE!!
2466 	@@DONE:
2467 			pop             si di ds             ; Return state
2468 			pop             bp
2469 			ret
2470 
2471 ENDP                    _XChar8;
2472 
2473 
2474 ; ------------------------ _Register_Font_Masks8 ---------------------------
2475 ; - This function registers a font mask for the current 8pix font
2476 ; - This mask can be used for MFont character drawing
2477 public          _Register_Font_Masks8
2478 
2479 PROC                    _Register_Font_Masks8   FAR
2480 
2481 	ARG     MASK_OFF:WORD, MASK_SEG:WORD  
2482 
2483 			push            bp
2484 			mov             bp,     sp              ; Save Stack frame
2485 			push            ds
2486 
2487 		; Load DS.
2488 			ASSUME  ds:  @fardata
2489 			mov             ax,  @fardata
2490 			mov             ds,  ax                 ; Set DS to fardata segment 
2491 
2492 		; Move location to local
2493 			mov             ax,                     [MASK_OFF]
2494 			mov       [Font_Mask_O8], ax
2495 
2496 			mov             ax,                     [MASK_SEG]
2497 			mov       [Font_Mask_S8], ax
2498 
2499 		; !!DONE!!
2500 			pop             ds
2501 			pop             bp                      ; Return state
2502 			ret
2503 
2504 ENDP                    _Register_Font_Masks8
2505 
2506 
2507 ; ----------------------------- _XChar8_M ----------------------------------
2508 ; - This function will place a char from the current font to current screen
2509 ; - This function requires a font mask set to be registered.
2510 ; - Uses the 8pix font
2511 public  _XChar8_M
2512 
2513 PROC    _XChar8_M   FAR
2514 
2515 	ARG     X_S:WORD,       Y_S:WORD, CHAR:WORD
2516 
2517 
2518 	push    bp
2519 	mov     bp,     sp                      ; Save Stack frame
2520 	push    ds di si
2521 
2522 	cld
2523 
2524       ; Load DS.
2525 	ASSUME  ds:  @fardata
2526 	mov     ax,  @fardata
2527 	mov     ds,  ax                 ; Set DS to fardata segment
2528 
2529      ; Set DI to start of rectangle on screen
2530 	mov     ax,   [WLine_Offset]
2531 	mov     bx,   ax                ; Save in BX for later
2532 	mul     [Y_S]                   ; Find Y offset value. Place in AX
2533 	mov     di,   [X_S]             ; Find X offset value. Place in DI
2534 	shr     di,   1
2535 	shr     di,   1
2536 
2537 	add     di,   ax                ; Add X and Y offsets
2538 	add     di,   [Write_Page]      ; Add in page offset
2539 
2540       ; Is the font uploaded or not
2541 	mov     cx,     [UpLoaded8]     ; UPLOADED is 0!
2542 	jcxz    @@Uploaded              ; The font is uploaded
2543 
2544     ; - Font is not uploaded
2545 
2546       ; Figure character offset and add to load ds:si font site
2547 	mov     ax,  80                 ; Put font size in ax
2548 	mov     cx,  [CHAR]             ; Put character place in BX
2549 	sub     cx,  [Char_Base8]       ; Subtract base char
2550 	mul     cx                      ; Mul size by place
2551 	lds     si,  [Font_Addr8]
2552 	add     si,  ax
2553 
2554       ; Set BX to the line differential
2555 	dec     bx                      ; BX was set above - first XBlock
2556 
2557       ; Save the base destination in BP
2558 	mov     bp,  di
2559 
2560       ; Set all data from CPU and non from latches
2561 	mov     dx,  GC_INDEX
2562 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
2563 	out     dx,  ax
2564 
2565       ; Get the Screen Seg and put it in ES
2566 	mov     ax,  SCREEN_SEG
2567 	mov     es,     ax
2568 
2569       ; Set up DX and AX for plane selection
2570 	mov     ax,     0102h   ; Plane 0 selected
2571 	mov     dx,     SC_INDEX
2572 
2573     ; This section is for WORD WRITES ------------------------------
2574 
2575       ; Set CX to number of lines to do
2576 	mov     cx,  10         ; 10 scan lines per 8-pix font
2577 
2578     @@PlanesW:                  ; Master plane loop.
2579 
2580 	out     dx,  ax         ; Set the plane
2581 
2582     @@RowloopW:                 ; Scan line loop
2583 
2584       ; Do the actual DRAW.  MOV.
2585 	lodsb                   ; Get the pixel
2586 	or      al,       al    ; Is it zero
2587 	jz      @@NoDraw1       ; If zero, don't draw it
2588 	mov     [es:di],  al    ; Else, do draw it
2589 
2590     @@NoDraw1:
2591 	inc     di
2592 
2593 	lodsb                   ; Get the pixel
2594 	or      al,       al    ; Is it zero
2595 	jz      @@NoDraw2       ; If zero, don't draw it
2596 	mov     [es:di],  al    ; Else, do draw it
2597 
2598     @@NoDraw2:
2599       ; Adjust for next iteration
2600 	add     di,       bx    ; Point DI to start of next line
2601 
2602       ; !!End of Rowloop.  Dec CX, if it is NOT 0 then do next line
2603 	loop    @@RowloopW
2604 
2605       ; Done with plane.  Reset Destination pointers.  Adjst plane
2606 	mov     di,     bp      ; Restore the destination start
2607 	mov     cx,     10      ; Restore scan line count
2608 
2609 	mov     al,     02h     ; Restore MAP MASK pointer
2610 	shl     ah,     1       ; Adjust plane
2611 
2612       ; !!End of Plane loop. If carry not set, then not done
2613 	jnc     @@PlanesW
2614 
2615       ; Done with this
2616 	jmp     @@DONE
2617 
2618 
2619     @@Uploaded:
2620     ; - Font is uploaded
2621 
2622       ; Set SI to mask offset
2623 	mov     ax,     10              ; Put mask size in ax
2624 	mov     cx,     [CHAR]          ; Put character place in CX
2625 	sub     cx,     [Char_Base8]    ; Subtract base char
2626 	mul     cx                      ; Mul size by place
2627 	add     ax,     [Font_Mask_O8]  ; Find masks offset in mask set
2628 	mov     si,     ax              ; Save it
2629 
2630       ; Calc the source and put in BX
2631 	mov     bx,     [Font_SiteU8]   ; Get base location
2632 	mov     ax,     20              ; Put font size in ax
2633 	mov     cx,     [CHAR]          ; Put character place in CX
2634 	sub     cx,     [Char_Base8]    ; Subtract base char
2635 	mul     cx                      ; Mul size by place
2636 	add     bx,     ax              ; Put in BX
2637 
2638       ; Set BP to the scan line differential
2639 	mov     bp,     [WLine_Offset]
2640 	dec     bp
2641 
2642       ; Set DS to mask area
2643 	mov     ax,     [Font_Mask_S8]
2644 	mov     ds,     ax
2645 
2646       ; Get the Screen Seg and put it in ES
2647 	mov     ax,     SCREEN_SEG
2648 	mov     es,     ax
2649 
2650       ; Set all data from latches
2651 	mov     dx,     GC_INDEX
2652 	mov     ax,     00000h + BIT_MASK  ; Set all latch writes
2653 	out     dx,     ax
2654 
2655       ; Set up Map Mask
2656 	mov     al,     02h     ; 02 is Map Mask
2657 	mov     dx,     SC_INDEX
2658 	out     dx,     al
2659 	inc     dx
2660 
2661       ; Set CH to the number of scan lines
2662 	mov     ch,     10
2663 
2664       ; Set CL to shift spaces
2665 	mov     cl,     4
2666 
2667     ; This section is for WRITES ------------------------------
2668      @@Rowloop:
2669       ; This section prep the Map Mask
2670 	lodsb                           ; Get mask byte
2671 
2672       ; Set mask for first write
2673 	out     dx,     al              ; Set map mask
2674 
2675       ; Write the first byte
2676 	mov     ah,             [es:bx]
2677 	mov     [es:di],        ah
2678 
2679       ; Adjust di, bx
2680 	inc     di
2681 	inc     bx
2682 
2683       ; Set mask for second write
2684 	shr     al,     cl        ; Move upper nibble down
2685 	out     dx,     al        ; Set map mask
2686 
2687       ; Write the second byte
2688 	mov     ah,             [es:bx]
2689 	mov     [es:di],        ah
2690 
2691       ; Adjust bx
2692 	inc     bx
2693 
2694       ; Adjust for next iteration
2695 	add     di,     bp      ; Point DI to start of next line
2696 
2697       ; End of Rowloop.
2698 	dec     ch
2699 	jnz     @@Rowloop
2700 
2701       ; !!DONE!!
2702      @@DONE:
2703 	pop     si di ds             ; Return state
2704 	pop     bp
2705 	ret
2706 
2707 ENDP    _XChar8_M;
2708 
2709 ; ----------------------------- _XChar8_C ----------------------------------
2710 ; - This function will place a char from the current font to current screen
2711 ; - This function requires a font mask set to be registered.
2712 ; - Uses only the mask set to place one color characters
2713 public  _XChar8_C
2714 
2715 PROC    _XChar8_C   FAR
2716 
2717 	ARG     X_S:WORD, Y_S:WORD, CHAR:WORD, COLOR:WORD
2718 
2719 
2720 	push    bp
2721 	mov     bp,     sp                      ; Save Stack frame
2722 	push    ds di si
2723 
2724 	cld
2725 
2726       ; Load DS.
2727 	ASSUME  ds:  @fardata
2728 	mov     ax,  @fardata
2729 	mov     ds,  ax                 ; Set DS to fardata segment
2730 
2731      ; Set DI to start of rectangle on screen
2732 	mov     ax,   [WLine_Offset]
2733 	mov     bx,   ax                ; Save in BX for later
2734 	mul     [Y_S]                   ; Find Y offset value. Place in AX
2735 	mov     di,   [X_S]             ; Find X offset value. Place in DI
2736 	shr     di,   1
2737 	shr     di,   1
2738 
2739 	add     di,   ax                ; Add X and Y offsets
2740 	add     di,   [Write_Page]      ; Add in page offset
2741 
2742       ; Set SI to mask offset
2743 	mov     ax,     10              ; Put mask size in ax
2744 	mov     cx,     [CHAR]          ; Put character place in CX
2745 	sub     cx,     [Char_Base8]    ; Subtract base char
2746 	mul     cx                      ; Mul size by place
2747 	add     ax,     [Font_Mask_O8]  ; Find masks offset in mask set
2748 	mov     si,     ax              ; Save it
2749 
2750       ; Move the color into bx
2751 	mov     bx,     [COLOR]
2752 
2753       ; Set BP to the scan line differential
2754 	mov     bp,     [WLine_Offset]
2755 	dec     bp
2756 
2757       ; Set DS to mask area
2758 	mov     ax,     [Font_Mask_S8]
2759 	mov     ds,     ax
2760 
2761       ; Get the Screen Seg and put it in ES
2762 	mov     ax,     SCREEN_SEG
2763 	mov     es,     ax
2764 
2765       ; Set all data from CPU and non from latches
2766 	mov     dx,     GC_INDEX
2767 	mov     ax,     0FF00h + BIT_MASK  ; Set all CPU writes
2768 	out     dx,     ax
2769 
2770       ; Set up Map Mask
2771 	mov     al,     02h     ; 02 is Map Mask
2772 	mov     dx,     SC_INDEX
2773 	out     dx,     al
2774 	inc     dx
2775 
2776       ; Set CH to the number of scan lines
2777 	mov     ch,     10
2778 
2779       ; Set CL to shift spaces
2780 	mov     cl,     4
2781 
2782     ; This section is for WRITES ------------------------------
2783      @@Rowloop:
2784       ; This section prep the Map Mask
2785 	lodsb                           ; Get mask byte
2786 
2787       ; Set mask for first write
2788 	out     dx,       al            ; Set map mask
2789 
2790       ; Write the first set
2791 	mov     [es:di],  bl
2792 
2793       ; Adjust di
2794 	inc     di
2795 
2796       ; Set mask for second write
2797 	shr     al,     cl        ; Move upper nibble down
2798 	out     dx,     al        ; Set map mask
2799 
2800       ; Write the second set
2801 	mov     [es:di],  bl
2802 
2803       ; Adjust for next iteration
2804 	add     di,     bp      ; Point DI to start of next line
2805 
2806       ; End of Rowloop.
2807 	dec     ch
2808 	jnz     @@Rowloop
2809 
2810       ; !!DONE!!
2811      @@DONE:
2812 	pop     si di ds             ; Return state
2813 	pop     bp
2814 	ret
2815 
2816 ENDP    _XChar8_C;
2817 
2818 
2819 ;----------------------------- _XString8 ----------------------------------
2820 ; - This function will place a char from the current font to current screen
2821 ; - It will use the masked font on mask flag set to not 0.
2822 public          _XString8
2823 
2824 PROC                    _XString8   FAR
2825 
2826 	ARG     X_S:WORD,       Y_S:WORD, MASKIT:WORD, STR_OFF:DWORD
2827 
2828 			push            bp
2829 			mov             bp,     sp              ; Save Stack frame
2830 			push            ds di si
2831 
2832 		; Load DS.
2833 			ASSUME  ds:  @fardata
2834 			mov             ax,  @fardata
2835 			mov             ds,  ax                 ; Set DS to segment w/ Table
2836 
2837 		; Move flag into CX
2838 			mov             cx,  [MASKIT]
2839 
2840 		; Load DS:SI
2841 			lds             si,  [STR_OFF]
2842 
2843 		; !!! This is the master string loop
2844 	@@STRING:
2845 			xor       ax,   ax
2846 			mov             al,     [ds:si]         ; Get the char
2847 			cmp             al,     0                       ; Is it the EOS
2848 			je              @@DONE                  ; If so jump
2849 
2850 		 ; Save cx
2851 			push    cx
2852 
2853 		 ; Build stack frame
2854 			push            ax                              ; Push the char
2855 			push            [Y_S]                   ; Push the Y coor
2856 			push            [X_S]                   ; Push the X coor
2857 		 ; To mask or not to mask
2858 			jcxz            @@DontMask              ; If Flag = 0, dont mask
2859 			call            _XChar8_M                       ; Put the masked char
2860 			jmp             @@Continue
2861 
2862 	@@DontMask:
2863 			call      _XChar8                       ; Don't mask
2864 
2865 	@@Continue:
2866 			add             sp,     6                       ; Adjust the stack
2867 
2868 			pop             cx                              ; Restore cx
2869 
2870 			add             [X_S],  8               ; Move the cursor
2871 			inc             si                              ; Point to next char
2872 			jmp             @@STRING            ; Continue
2873 
2874 		; !!DONE!!
2875 	@@DONE:
2876 			pop             si di ds             ; Return state
2877 			pop             bp
2878 			ret
2879 
2880 ENDP                    _XString8
2881 
2882 
2883 ;----------------------------- _XString8_C ----------------------------------
2884 ; - This function will place a char from the current font to current screen
2885 ; - It will use the single color mask.
2886 public  _XString8_C
2887 
2888 PROC    _XString8_C   FAR
2889 
2890 	ARG     X_S:WORD, Y_S:WORD, COLOR:WORD, STR_OFF:DWORD
2891 
2892 	push    bp
2893 	mov     bp,     sp              ; Save Stack frame
2894 	push    ds di si
2895 
2896       ; Load DS.
2897 	ASSUME  ds:  @fardata
2898 	mov     ax,  @fardata
2899 	mov     ds,  ax                 ; Set DS to segment w/ Table
2900 
2901       ; Load DS:SI
2902 	lds             si,  [STR_OFF]
2903 
2904     ; !!! This is the master string loop
2905    @@STRING:
2906 	xor     ax,     ax
2907 	mov     al,     [ds:si]         ; Get the char
2908 	cmp     al,     0                       ; Is it the EOS
2909 	je      @@DONE                  ; If so jump
2910 
2911       ; Save cx
2912 	push    cx
2913 
2914       ; Build stack frame
2915 	push    [COLOR]                 ; Push the color
2916 	push    ax                      ; Push the char
2917 	push    [Y_S]                   ; Push the Y coor
2918 	push    [X_S]                   ; Push the X coor
2919 
2920       ; Call the char routine
2921 	call    _XChar8_C               ; Put the masked char
2922 
2923       ; Recover from call
2924 	add     sp,     8               ; Adjust the stack
2925 
2926 	pop     cx                      ; Restore cx
2927 
2928 	add     [X_S],  8               ; Move the cursor
2929 	inc     si                      ; Point to next char
2930 	jmp     @@STRING                ; Continue
2931 
2932       ; !!DONE!!
2933     @@DONE:
2934 	pop             si di ds             ; Return state
2935 	pop             bp
2936 	ret
2937 
2938 ENDP                    _XString8_C
2939 
2940 
2941 ; --------------------------- _XRegister_Font4 ------------------------------
2942 ; - This function will register a 4-font.
2943 ; - The function will return in AX the actual number of bytes used.
2944 ; - The function expects each character to be laid out as for Upload_Tile,
2945 ; - one character at a time.  Each character is 4x by 6y.
2946 
2947 public          _XRegister_Font4
2948 
2949 PROC                    _XRegister_Font4   FAR
2950 
2951 	ARG       DEST:WORD, NUMBER:WORD, BASE:WORD, UPLOAD:WORD, FONT_OFF:DWORD
2952 
2953 			push            bp
2954 			mov             bp,     sp                      ; Save Stack frame
2955 			push            ds di si
2956 
2957 			cld
2958 
2959 		; Load DS.
2960 			ASSUME  ds:  @fardata
2961 			mov             ax,  @fardata
2962 			mov             ds,  ax                 ; Set DS to fardata segment
2963 
2964 		; Save the base char
2965 			mov             ax,                     [BASE]
2966 			mov             [Char_Base4],   ax
2967 
2968 		; Will we upload this font?
2969 			mov             cx,     [UPLOAD]
2970 			mov             [UpLoaded4], cx ; Flag it       ( 0 is uploaded )
2971 			jcxz            @@UploadFont            ; Yes!, then jump to it
2972 
2973 		; Don't upload this font.  Just register and return.
2974 			les             si,                       [FONT_OFF]
2975 			mov             [Font_SiteD4],   si
2976 			mov             ax,                       es
2977 			mov             [Font_SiteD4+2], ax
2978 			jmp       @@DONE
2979 
2980 	@@UploadFont:
2981 		; Check font size to insure no overrun
2982 			mov             dx,     6
2983 			mov             ax,     [NUMBER]
2984 			mul             dx                      ; Mul number of chars by 20bytes
2985 			add             ax,  [DEST]     ; Add destination to get proposed end
2986 			cmp             ax,     STORE   ; Where is it in relation to begin
2987 			ja              @@CONT          ; If above, no wrap of AX, OK
2988 			mov             ax,     0               ; Else leave 0 in AX, indicating ERR
2989 			jmp             @@DONE          ; And jump out
2990 
2991 	@@CONT:
2992 		; Save the size and location
2993 			mov             ax,            [DEST]
2994 			mov             [Font_SiteU4],  ax
2995 
2996 		; Load di with destination offset and save it in DX
2997 			mov             di,             ax          ; AX retains it from prev action
2998 			mov       dx,           di       ; Store it
2999 
3000 		; Load ds:si with source
3001 			lds             si,  [FONT_OFF]
3002 
3003 		; Load es with SCREEN SEG
3004 			mov             ax,  SCREEN_SEG
3005 			mov             es,     ax
3006 
3007 		; This section iterates for each char----------------------------
3008 			mov             bx,     [NUMBER]        ; Set BX to number of characters
3009 
3010 		; Set BP to destination
3011 			mov             bp,  dx        ; From above.
3012 
3013 		; Set all data from CPU and non from latches
3014 			mov             dx,     GC_INDEX
3015 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
3016 			out             dx,     ax
3017 
3018 		; Set up DX plane selection
3019 			mov             dx,     SC_INDEX
3020 
3021 	@@BeginWrite:
3022 
3023 		; Set AX up for plane selection
3024 			mov             ax,     1102h   ; Plane 0 selected
3025 
3026 		; This section loops through the planes for each char -----------
3027 	@@PlanesB:                              ; Master plane loop.
3028 
3029 			out          dx,        ax      ; Set the plane
3030 
3031 		; Do the actual write.  MOVSB.  Move 6 single XBlocks on each line
3032 			movsb  ; 1
3033 			movsb  ; 2
3034 			movsb  ; 3
3035 			movsb  ; 4
3036 			movsb  ; 5
3037 			movsb  ; 6
3038 
3039 	@@EndPlane:
3040 		; Done with plane.  Reset Destination pointers.  Adjst plane
3041 			mov             di,     bp
3042 			shl             ah,     1               ; Adjust plane. Carry set if done
3043 
3044 		; !!End of Plane loop.
3045 			jnc             @@PlanesB      ; If no carry, not done with char
3046 
3047 		; !!End of Char loop.
3048 
3049 			add             bp,     6               ; Adjust destination for next char
3050 			mov             di,     bp              ; Store it in DI
3051 
3052 			dec             bx             ; Another char done
3053 			jnz             @@BeginWrite   ; If not zero, not done with font set
3054 
3055 		; !!DONE!!
3056 		@@DONE:
3057 			pop             si di ds            ; Return state
3058 			pop             bp
3059 			ret
3060 
3061 ENDP                    _XRegister_Font4
3062 
3063 
3064 ; ----------------------------- _XChar4 ----------------------------------
3065 ; - This function will place a char from the current font to current screen
3066 ; - Uses the 8pix font
3067 public          _XChar4
3068 
3069 PROC                    _XChar4   FAR
3070 
3071 	ARG     X_S:WORD,       Y_S:WORD, CHAR:WORD
3072 
3073 			push            bp
3074 			mov             bp,     sp              ; Save Stack frame
3075 			push            ds di si
3076 
3077 			cld
3078 
3079 		; Load DS.
3080 			ASSUME  ds:  @fardata
3081 			mov             ax,  @fardata
3082 			mov             ds,  ax                 ; Set DS to segment w/ Table
3083 
3084 		; Set DI to start of character on screen
3085 			mov             ax,  [WLine_Offset]
3086 			mul             [Y_S]              ; Find Y offset value. Place in AX
3087 
3088 			mov             di,  [X_S]        ; Find X offset value. Place in DI
3089 			shr             di,  1
3090 			shr             di,  1             ; Adjust to number of XBlocks
3091 
3092 			add             di,  ax            ; Add X and Y offsets
3093 			add             di,  [Write_Page] ; Add in page offset
3094 
3095 		; Is the font uploaded or not
3096 			mov             ax,     [UpLoaded4]
3097 			cmp             ax,     UPLOADFONT
3098 			je              @@FontIsUploaded        ; The font is uploaded
3099 
3100 	  ; - Font is not uploaded
3101 		; Set CX to the scan line differential
3102 			mov             cx,  [WLine_Offset]
3103 			dec             cx                      ; Subtract the XBlock of a char
3104 
3105 		; Figure character offset and add to load ds:si font site
3106 			mov             ax,     24                      ; Put font size in ax
3107 			mov             bx,     [CHAR]         ; Put character place in BX
3108 			sub             bx,     [Char_Base4]    ; Subtract base char
3109 			mul             bx                              ; Mul size by place
3110 			lds             si,  [Font_Addr4]
3111 			add             si,  ax
3112 
3113 		; Save the base destination in BX
3114 			mov             bx,  di
3115 
3116 		; Get the Screen Seg and put it in ES
3117 			mov             ax,  SCREEN_SEG
3118 			mov             es,     ax
3119 
3120 		; Set all data from CPU and non from latches
3121 			mov             dx,     GC_INDEX
3122 			mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
3123 			out             dx,     ax
3124 
3125 		; Set up DX and AX for plane selection
3126 			mov             ax,     1102h   ; Plane 0 selected
3127 			mov             dx,     SC_INDEX
3128 
3129 		; This section is for WRITES ------------------------------
3130 
3131 	@@PlanesW:          ; Master plane loop.
3132 
3133 			out             dx,     ax      ; Set the plane
3134 
3135 	; Put a plane.  Completely un-rolled
3136 
3137 		; Do line # 1
3138 			movsb
3139 			add             di,     cx              ; Point DI to start of next line
3140 
3141 		; Do line # 2
3142 			movsb
3143 			add             di,     cx              ; Point DI to start of next line
3144 
3145 		; Do line # 3
3146 			movsb
3147 			add             di,     cx              ; Point DI to start of next line
3148 
3149 		; Do line # 4
3150 			movsb
3151 			add             di,     cx              ; Point DI to start of next line
3152 
3153 		; Do line # 5
3154 			movsb
3155 			add             di,     cx              ; Point DI to start of next line
3156 
3157 		; Do line # 6
3158 			movsb
3159 
3160 
3161 		; Done with plane.  Reset Destination pointers.  Adjst plane
3162 			mov             di,     bx              ; Restore the destination start
3163 			shl             ah,     1               ; Adjust plane
3164 
3165 		; !!End of Plane loop.
3166 			jnc             @@PlanesW               ; If no carry, then more to do.
3167 
3168 
3169 		; Done with this
3170 			jmp             @@DONE
3171 
3172 
3173 	  ; - Font is uploaded
3174 	  @@FontIsUploaded:
3175 		; Calc the source and put in SI
3176 			mov             si,     [Font_SiteU4]   ; Get base location
3177 			mov             ax,     6                       ; Put font size in ax
3178 			xor             bx,     bx                      ; Clear bx
3179 			mov             bx,     [CHAR]         ; Put character place in BX
3180 			sub             bx,     [Char_Base4]    ; Subtract base char
3181 			mul             bx                              ; Mul size by place
3182 			add             si,     ax                      ; Put in SI
3183 
3184 		; Insure Map Mask is set to all planes
3185 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
3186 			mov             dx,     SC_INDEX
3187 			out             dx,     ax
3188 
3189 		; Set all data from latches
3190 			mov             dx,     GC_INDEX
3191 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
3192 			out             dx,     ax
3193 
3194 		; Set AX to line dif.
3195 			mov             ax,     [WLine_Offset]          ; Page width
3196 			dec          ax                     ; minus XBlocks per char
3197 
3198 		; Get the Screen Seg and put it in DS and ES
3199 			mov             dx,  SCREEN_SEG
3200 			mov             ds,  dx
3201 			mov             es,     dx
3202 
3203 		; This section is for WRITES ------------------------------
3204 
3205 	  ; - Completely un-rolled
3206 
3207 		; Scan line #1
3208 			movsb
3209 			add             di,     ax      ; Point DI to start of next line
3210 
3211 		; Scan line #2
3212 			movsb
3213 			add             di,     ax      ; Point DI to start of next line
3214 
3215 		; Scan line #3
3216 			movsb
3217 			add             di,     ax      ; Point DI to start of next line
3218 
3219 		; Scan line #4
3220 			movsb
3221 			add             di,     ax      ; Point DI to start of next line
3222 
3223 		; Scan line #5
3224 			movsb
3225 			add             di,     ax      ; Point DI to start of next line
3226 
3227 		; Scan line #6
3228 			movsb
3229 
3230 
3231 		; !!DONE!!
3232 	@@DONE:
3233 			pop             si di ds             ; Return state
3234 			pop             bp
3235 			ret
3236 
3237 ENDP                    _XChar4;
3238 
3239 
3240 ; ------------------------ _Register_Font_Masks4 ---------------------------
3241 ; - This function registers a font mask for the current 4pix font
3242 ; - This mask can be used for MFont character drawing
3243 public          _Register_Font_Masks4
3244 
3245 PROC                    _Register_Font_Masks4   FAR
3246 
3247 	ARG     MASK_OFF:WORD, MASK_SEG:WORD
3248 
3249 			push            bp
3250 			mov             bp,     sp              ; Save Stack frame
3251 			push            ds
3252 
3253 		; Load DS.
3254 			ASSUME  ds:  @fardata
3255 			mov             ax,  @fardata
3256 			mov             ds,  ax                 ; Set DS to fardata segment
3257 
3258 		; Move location to local
3259 			mov             ax,                     [MASK_OFF]
3260 			mov       [Font_Mask_O4], ax
3261 
3262 			mov             ax,                     [MASK_SEG]
3263 			mov       [Font_Mask_S4], ax
3264 
3265 		; !!DONE!!
3266 			pop             ds
3267 			pop             bp                      ; Return state
3268 			ret
3269 
3270 ENDP                    _Register_Font_Masks4
3271 
3272 
3273 ; ----------------------------- _XChar4_M ----------------------------------
3274 ; - This function will place a char from the current font to current screen
3275 ; - This function requires a font mask set to be registered.
3276 ; - Uses the 4pix font
3277 public   _XChar4_M
3278 
3279 PROC     _XChar4_M   FAR
3280 
3281 	ARG     X_S:WORD,       Y_S:WORD, CHAR:WORD
3282 
3283 	push    bp
3284 	mov     bp,     sp                      ; Save Stack frame
3285 	push    ds di si
3286 
3287 	cld
3288 
3289       ; Load DS.
3290 	ASSUME  ds:  @fardata
3291 	mov     ax,  @fardata
3292 	mov     ds,  ax                 ; Set DS to fardata segment
3293 
3294       ; Set DI to start of rectangle on screen
3295 	mov     ax,   [WLine_Offset]
3296 	mov     bx,   ax                ; Save in BX as S/L differential
3297 	mul     [Y_S]                   ; Find Y offset value. Place in AX
3298 
3299 	mov     di,  [X_S]         ; Find X offset value. Place in DI
3300 	shr     di,  1
3301 	shr     di,  1
3302 
3303 	add     di,  ax            ; Add X and Y offsets
3304 	add     di,  [Write_Page]  ; Add in page offset
3305 
3306       ; Is the font uploaded or not
3307 	mov     cx,  [UpLoaded4]   ; UPLOADED is 0!
3308 	jcxz    @@Uploaded         ; The font is uploaded
3309 
3310     ; - Font is not uploaded
3311 
3312       ; Figure character offset and add to load ds:si font site
3313 	mov     ax,  24            ; Put font size in ax
3314 	mov     cx,  [CHAR]        ; Put character place in BX
3315 	sub     cx,  [Char_Base4]  ; Subtract base char
3316 	mul     cx                 ; Mul size by place
3317 	lds     si,  [Font_Addr4]
3318 	add     si,  ax
3319 
3320       ; Save the base destination in CX
3321 	mov     cx,  di
3322 
3323       ; Get the Screen Seg and put it in ES
3324 	mov     ax,  SCREEN_SEG
3325 	mov     es,  ax
3326 
3327       ; Set all data from CPU and non from latches
3328 	mov     dx,  GC_INDEX
3329 	mov     ax,  0FF00h + BIT_MASK  ; Set all CPU writes
3330 	out     dx,  ax
3331 
3332       ; Set up DX and AX for plane selection
3333 	mov     ax,  0102h      ; Plane 0 selected
3334 	mov     dx,  SC_INDEX
3335 
3336       ; This section is for WRITES ------------------------------
3337 
3338    @@PlanesW:          ; Master plane loop.
3339 
3340 	out     dx,     ax      ; Set the plane
3341 
3342 
3343       ; Do the actual DRAW.  MOV.  Completely un-rolled!!
3344 
3345       ; Scan line #1
3346 	lodsb                   ; Get the pixel
3347 	or      al,       al    ; Is it zero
3348 	jz      @@NoDraw1       ; If zero, don't draw it
3349 	mov     [es:di],  al    ; Else, do draw it
3350 
3351       @@NoDraw1:
3352 	add     di,     bx      ; Point DI to start of next line
3353 
3354       ; Scan line #2
3355 	lodsb                   ; Get the pixel
3356 	or      al,       al    ; Is it zero
3357 	jz      @@NoDraw2       ; If zero, don't draw it
3358 	mov     [es:di],  al    ; Else, do draw it
3359 
3360       @@NoDraw2:
3361 	add     di,     bx      ; Point DI to start of next line
3362 
3363       ; Scan line #3
3364 	lodsb                   ; Get the pixel
3365 	or      al,       al    ; Is it zero
3366 	jz      @@NoDraw3       ; If zero, don't draw it
3367 	mov     [es:di],  al    ; Else, do draw it
3368 
3369       @@NoDraw3:
3370 	add     di,     bx      ; Point DI to start of next line
3371 
3372       ; Scan line #4
3373 	lodsb                   ; Get the pixel
3374 	or      al,       al    ; Is it zero
3375 	jz      @@NoDraw4       ; If zero, don't draw it
3376 	mov     [es:di],  al    ; Else, do draw it
3377 
3378       @@NoDraw4:
3379 	add     di,     bx      ; Point DI to start of next line
3380 
3381       ; Scan line #5
3382 	lodsb                   ; Get the pixel
3383 	or      al,       al    ; Is it zero
3384 	jz      @@NoDraw5       ; If zero, don't draw it
3385 	mov     [es:di],  al    ; Else, do draw it
3386 
3387       @@NoDraw5:
3388 	add     di,     bx      ; Point DI to start of next line
3389 
3390       ; Scan line #6
3391 	lodsb                   ; Get the pixel
3392 	or      al,       al    ; Is it zero
3393 	jz      @@NoDraw6       ; If zero, don't draw it
3394 	mov     [es:di],  al    ; Else, do draw it
3395 
3396       @@NoDraw6:
3397 
3398 
3399       ; Done with plane.  Reset Destination pointers.  Adjst plane
3400 	mov     di,  cx         ; Restore the destination start
3401 
3402 	mov     al,  02h        ; Restore MAP MASK pointer
3403 	shl     ah,  1          ; Adjust plane
3404 
3405       ; !!End of Plane loop. If carry not set, then not done
3406 	jnc     @@PlanesW
3407 
3408       ; Done with this
3409 	jmp     @@DONE
3410 
3411 
3412     @@Uploaded:
3413     ; - Font is uploaded
3414 
3415       ; Set SI to mask offset
3416 	mov     ax,     3              ; Put mask size in ax
3417 	mov     cx,     [CHAR]         ; Put character place in CX
3418 	sub     cx,     [Char_Base4]   ; Subtract base char
3419 	mul     cx                     ; Mul size by place
3420 	add     ax,     [Font_Mask_O4] ; Find masks offset in mask set
3421 	mov     si,     ax             ; Save it
3422 
3423       ; Calc the source and put in BX
3424 	mov     bx,     [Font_SiteU4]  ; Get base location
3425 	mov     ax,     6              ; Put font size in ax
3426 	mov     cx,     [CHAR]         ; Put character place in BX
3427 	sub     cx,     [Char_Base4]   ; Subtract base char
3428 	mul     cx                     ; Mul size by place
3429 	add     bx,     ax             ; Put in SI
3430 
3431       ; Set BP to the scan line differential
3432 	mov     bp,     [WLine_Offset]
3433 
3434       ; Set DS to mask area
3435 	mov     ax,     [Font_Mask_S4]
3436 	mov     ds,     ax
3437 
3438       ; Get the Screen Seg and put it in ES
3439 	mov     ax,  SCREEN_SEG
3440 	mov     es,     ax
3441 
3442       ; Set all data from latches
3443 	mov     dx,     GC_INDEX
3444 	mov     ax,     00000h + BIT_MASK  ; Set all latch writes
3445 	out     dx,     ax
3446 
3447       ; Set up Map Mask
3448 	mov     al,     02h                ; 02 is Map Mask
3449 	mov     dx,     SC_INDEX
3450 	out     dx,     al
3451 	inc     dx
3452 
3453       ; Set CL to shift spaces
3454 	mov             cl,     4
3455 
3456     ; This section is for WRITES ------------------------------
3457 
3458       ; -- Completely unrolled
3459 
3460       ; Scan Line #1
3461       ; This section prep the Map Mask
3462 	lodsb                      ; Get mask byte
3463 
3464       ; Set mask for first write
3465 	out     dx,       al       ; Set map mask
3466 
3467       ; Write the byte
3468 	mov     ah,       [es:bx]
3469 	mov     [es:di],  ah
3470 
3471       ; Scan Line #2
3472       ; Set mask for next write
3473 	shr     al,       cl       ; Move upper nibble down
3474 	out     dx,       al       ; Set map mask
3475 
3476       ; Adjust for next scan line
3477 	add     di,       bp       ; Point DI to start of next line
3478 	inc     bx
3479 
3480       ; Write the second byte
3481 	mov     al,       [es:bx]
3482 	mov     [es:di],  al
3483 
3484       ; Adjust for next scan line
3485 	add     di,       bp       ; Point DI to start of next line
3486 	inc     bx
3487 
3488       ; Scan Line #3
3489       ; This section prep the Map Mask
3490 	lodsb                      ; Get mask byte
3491 
3492       ; Set mask for first write
3493 	out     dx,       al       ; Set map mask
3494 
3495       ; Write the byte
3496 	mov     ah,       [es:bx]
3497 	mov     [es:di],  ah
3498 
3499       ; Scan Line #4
3500       ; Set mask for next write
3501 	shr     al,       cl       ; Move upper nibble down
3502 	out     dx,       al       ; Set map mask
3503 
3504       ; Adjust for next scan line
3505 	add     di,       bp       ; Point DI to start of next line
3506 	inc     bx
3507 
3508       ; Write the second byte
3509 	mov     al,       [es:bx]
3510 	mov     [es:di],  al
3511 
3512       ; Adjust for next scan line
3513 	add     di,       bp       ; Point DI to start of next line
3514 	inc     bx
3515 
3516       ; Scan Line #5
3517       ; This section prep the Map Mask
3518 	lodsb                      ; Get mask byte
3519 
3520       ; Set mask for first write
3521 	out     dx,       al       ; Set map mask
3522 
3523       ; Write the byte
3524 	mov     ah,       [es:bx]
3525 	mov     [es:di],  ah
3526 
3527       ; Scan Line #6
3528       ; Set mask for next write
3529 	shr     al,       cl       ; Move upper nibble down
3530 	out     dx,       al       ; Set map mask
3531 
3532       ; Adjust for next scan line
3533 	add     di,       bp       ; Point DI to start of next line
3534 	inc     bx
3535 
3536       ; Write the second byte
3537 	mov     al,       [es:bx]
3538 	mov     [es:di],  al
3539 
3540 
3541       ; !!DONE!!
3542     @@DONE:
3543 	pop     si di ds             ; Return state
3544 	pop     bp
3545 	ret
3546 
3547 ENDP    _XChar4_M;
3548 
3549 
3550 ; ----------------------------- _XChar4_C ----------------------------------
3551 ; - This function will place a char from the current font to current screen
3552 ; - This function requires a font mask set to be registered.
3553 ; - Uses the 4pix font and the color specified.
3554 public   _XChar4_C
3555 
3556 PROC     _XChar4_C   FAR
3557 
3558 	ARG     X_S:WORD,  Y_S:WORD, CHAR:WORD, COLOR:WORD
3559 
3560 	push    bp
3561 	mov     bp,     sp                      ; Save Stack frame
3562 	push    ds di si
3563 
3564 	cld
3565 
3566       ; Load DS.
3567 	ASSUME  ds:  @fardata
3568 	mov     ax,  @fardata
3569 	mov     ds,  ax                 ; Set DS to fardata segment
3570 
3571       ; Set DI to start of rectangle on screen
3572 	mov     ax,   [WLine_Offset]
3573 	mov     bx,   ax                ; Save in BX as S/L differential
3574 	mul     [Y_S]                   ; Find Y offset value. Place in AX
3575 
3576 	mov     di,  [X_S]         ; Find X offset value. Place in DI
3577 	shr     di,  1
3578 	shr     di,  1
3579 
3580 	add     di,  ax            ; Add X and Y offsets
3581 	add     di,  [Write_Page]  ; Add in page offset
3582 
3583       ; Set SI to mask offset
3584 	mov     ax,     3              ; Put mask size in ax
3585 	mov     cx,     [CHAR]         ; Put character place in CX
3586 	sub     cx,     [Char_Base4]   ; Subtract base char
3587 	mul     cx                     ; Mul size by place
3588 	add     ax,     [Font_Mask_O4] ; Find masks offset in mask set
3589 	mov     si,     ax             ; Save it
3590 
3591       ; Set BX to color
3592 	mov     bx,     [COLOR]
3593 
3594       ; Set BP to the scan line differential
3595 	mov     bp,     [WLine_Offset]
3596 
3597       ; Set DS to mask area
3598 	mov     ax,     [Font_Mask_S4]
3599 	mov     ds,     ax
3600 
3601       ; Get the Screen Seg and put it in ES
3602 	mov     ax,  SCREEN_SEG
3603 	mov     es,     ax
3604 
3605       ; Set all data from latches
3606 	mov     dx,     GC_INDEX
3607 	mov     ax,     0FF00h + BIT_MASK  ; Set all latch writes
3608 	out     dx,     ax
3609 
3610       ; Set up Map Mask
3611 	mov     al,     02h                ; 02 is Map Mask
3612 	mov     dx,     SC_INDEX
3613 	out     dx,     al
3614 	inc     dx
3615 
3616       ; Set CL to shift spaces
3617 	mov     cl,     4
3618 
3619     ; This section is for WRITES ------------------------------
3620 
3621       ; -- Completely unrolled
3622 
3623       ; Scan Line #1
3624       ; This section prep the Map Mask
3625 	lodsb                      ; Get mask byte
3626 
3627       ; Set mask for first write
3628 	out     dx,       al       ; Set map mask
3629 
3630       ; Write the byte
3631 	mov     [es:di],  bl
3632 
3633       ; Scan Line #2
3634       ; Set mask for next write
3635 	shr     al,       cl       ; Move upper nibble down
3636 	out     dx,       al       ; Set map mask
3637 
3638       ; Adjust for next scan line
3639 	add     di,       bp       ; Point DI to start of next line
3640 
3641       ; Write the second byte
3642 	mov     [es:di],  bl
3643 
3644       ; Adjust for next scan line
3645 	add     di,       bp       ; Point DI to start of next line
3646 
3647       ; Scan Line #3
3648       ; This section prep the Map Mask
3649 	lodsb                      ; Get mask byte
3650 
3651       ; Set mask for first write
3652 	out     dx,       al       ; Set map mask
3653 
3654       ; Write the byte
3655 	mov     [es:di],  bl
3656 
3657       ; Scan Line #4
3658       ; Set mask for next write
3659 	shr     al,       cl       ; Move upper nibble down
3660 	out     dx,       al       ; Set map mask
3661 
3662       ; Adjust for next scan line
3663 	add     di,       bp       ; Point DI to start of next line
3664 
3665       ; Write the second byte
3666 	mov     [es:di],  bl
3667 
3668       ; Adjust for next scan line
3669 	add     di,       bp       ; Point DI to start of next line
3670 
3671       ; Scan Line #5
3672       ; This section prep the Map Mask
3673 	lodsb                      ; Get mask byte
3674 
3675       ; Set mask for first write
3676 	out     dx,       al       ; Set map mask
3677 
3678       ; Write the byte
3679 	mov     [es:di],  bl
3680 
3681       ; Scan Line #6
3682       ; Set mask for next write
3683 	shr     al,       cl       ; Move upper nibble down
3684 	out     dx,       al       ; Set map mask
3685 
3686       ; Adjust for next scan line
3687 	add     di,       bp       ; Point DI to start of next line
3688 
3689       ; Write the second byte
3690 	mov     [es:di],  bl
3691 
3692 
3693       ; !!DONE!!
3694     @@DONE:
3695 	pop     si di ds             ; Return state
3696 	pop     bp
3697 	ret
3698 
3699 ENDP    _XChar4_C
3700 
3701 ;----------------------------- _XString4 ----------------------------------
3702 ; - This function will place a char from the current font to current screen
3703 ; - It will use the masked font on mask flag set to not 0.
3704 public          _XString4
3705 
3706 PROC                    _XString4   FAR
3707 
3708 	ARG     X_S:WORD,       Y_S:WORD, MASKIT:WORD, STR_OFF:DWORD
3709 
3710 			push            bp
3711 			mov             bp,     sp              ; Save Stack frame
3712 			push            ds di si
3713 
3714 		; Load DS.
3715 			ASSUME  ds:  @fardata
3716 			mov             ax,  @fardata
3717 			mov             ds,  ax                 ; Set DS to segment w/ Table
3718 
3719 		; Move flag into CX
3720 			mov             cx,  [MASKIT]
3721 
3722 		; Load DS:SI
3723 			lds             si,  [STR_OFF]
3724 
3725 		; !!! This is the master string loop
3726 	@@STRING:
3727 			xor       ax,   ax
3728 			mov             al,     [ds:si]         ; Get the char
3729 			cmp             al,     0                       ; Is it the EOS
3730 			je              @@DONE                  ; If so jump
3731 
3732 		 ; Save cx
3733 			push    cx
3734 
3735 		 ; Build stack frame
3736 			push            ax                              ; Push the char
3737 			push            [Y_S]                   ; Push the Y coor
3738 			push            [X_S]                   ; Push the X coor
3739 		 ; To mask or not to mask
3740 			jcxz            @@DontMask              ; If Flag = 0, dont mask
3741 			call            _XChar4_M                       ; Put the masked char
3742 			jmp             @@Continue
3743 
3744 	@@DontMask:
3745 			call      _XChar4                       ; Don't mask
3746 
3747 	@@Continue:
3748 			add             sp,     6                       ; Adjust the stack
3749 
3750 			pop             cx                              ; Restore cx
3751 
3752 			add             [X_S],  4               ; Move the cursor
3753 			inc             si                              ; Point to next char
3754 			jmp             @@STRING            ; Continue
3755 
3756 		; !!DONE!!
3757 	@@DONE:
3758 			pop             si di ds             ; Return state
3759 			pop             bp
3760 			ret
3761 
3762 ENDP                    _XString4
3763 
3764 
3765 ;----------------------------- _XString4_C ----------------------------------
3766 ; - This function will place a char from the current font to current screen
3767 ; - It will use the single color mask.
3768 public  _XString4_C
3769 
3770 PROC    _XString4_C   FAR
3771 
3772 	ARG     X_S:WORD, Y_S:WORD, COLOR:WORD, STR_OFF:DWORD
3773 
3774 	push    bp
3775 	mov     bp,     sp              ; Save Stack frame
3776 	push    ds di si
3777 
3778       ; Load DS.
3779 	ASSUME  ds:  @fardata
3780 	mov     ax,  @fardata
3781 	mov     ds,  ax                 ; Set DS to segment w/ Table
3782 
3783       ; Load DS:SI
3784 	lds             si,  [STR_OFF]
3785 
3786     ; !!! This is the master string loop
3787    @@STRING:
3788 	xor     ax,     ax
3789 	mov     al,     [ds:si]         ; Get the char
3790 	cmp     al,     0                       ; Is it the EOS
3791 	je      @@DONE                  ; If so jump
3792 
3793       ; Save cx
3794 	push    cx
3795 
3796       ; Build stack frame
3797 	push    [COLOR]                 ; Push the color
3798 	push    ax                      ; Push the char
3799 	push    [Y_S]                   ; Push the Y coor
3800 	push    [X_S]                   ; Push the X coor
3801 
3802       ; Call the char routine
3803 	call    _XChar4_C               ; Put the masked char
3804 
3805       ; Recover from call
3806 	add     sp,     8               ; Adjust the stack
3807 
3808 	pop     cx                      ; Restore cx
3809 
3810 	add     [X_S],  4               ; Move the cursor
3811 	inc     si                      ; Point to next char
3812 	jmp     @@STRING                ; Continue
3813 
3814       ; !!DONE!!
3815     @@DONE:
3816 	pop             si di ds             ; Return state
3817 	pop             bp
3818 	ret
3819 
3820 ENDP                    _XString4_C
3821 
3822 
3823 
3824 ; --------------------------- _XPaste_Tile_M -------------------------------
3825 ; - This function will place a tile from the display memory to current screen
3826 ; - It will use the mask passed to it to leave background transparent
3827 ; - Max Y size is 255
3828 
3829 public          _XPaste_Tile_M
3830 
3831 PROC                    _XPaste_Tile_M   FAR
3832 
3833  ARG    X_S:WORD,       Y_S:WORD, X_D:WORD,     Y_D:WORD,       TILE:WORD, MASK_O:DWORD
3834 
3835 			push            bp
3836 			mov             bp,     sp                      ; Save Stack frame
3837 			push            ds di si
3838 
3839 	       cld
3840  
3841 		; Load DS.
3842 			ASSUME  ds:  @fardata
3843 			mov             ax,  @fardata
3844 			mov             ds,  ax                 ; Set DS to fardata segment
3845 
3846 		; Set DI to start of rectangle on screen
3847 			mov             ax,  [WLine_Offset]
3848 			mul             [Y_S]              ; Find Y offset value. Place in AX
3849 
3850 			mov             di,  [X_S]        ; Find X offset value. Place in DI
3851 			shr             di,  1
3852 			shr             di,  1             ; Adjust to number of XBlocks
3853 
3854 			add             di,  ax            ; Add X and Y offsets
3855 			add             di,  [Write_Page] ; Add in page offset
3856 
3857 		; Put in source in BX
3858 			mov             bx,     [TILE]
3859 
3860 		; Get the Screen Seg and put it in ES
3861 			mov             ax,  SCREEN_SEG
3862 			mov             es,     ax
3863 
3864 		; Set all data from latches
3865 			mov             dx,     GC_INDEX
3866 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
3867 			out             dx,     ax
3868 
3869 		; Set CX to the number of XBlocks per line
3870 			mov             cx,     [X_D]
3871 			shr             cx,     1
3872 			shr             cx,     1
3873 
3874 		; Get distance from end of one line to start of other and save
3875 			mov             ax,             [WLine_Offset]  ; Get screen width
3876 			sub             ax,             cx                      ; Del number of XBlocks
3877 			mov             dx,       ax                    ; Save in DX
3878 
3879 		; Save cl in ch.
3880 			mov             ch,  cl ; Save in CH
3881 
3882 
3883 		; Set DS:SI to mask area
3884 			lds             si,     [MASK_O]
3885 
3886 		; Set AH to the rows to do
3887 			mov             ax,     [Y_D]   ; Puts number in AX
3888 			mov             ah,     al              ; Puts number in ah
3889 
3890 		; Move scan line differential from dx to bp
3891 			mov             bp,  dx
3892 
3893 		; Set up Map Mask
3894 			mov             al,  02h        ; 02 is Map Mask
3895 			mov             dx,     SC_INDEX
3896 			out             dx,     al
3897 			inc             dx
3898 
3899 		; This section is for WRITES ------------------------------
3900 	@@Rowloop:
3901 
3902 	@@ScanLine:
3903 		; This section prep the Map Mask
3904 			lodsb                           ; Get mask byte
3905 
3906 		; Set mask for write
3907 			out             dx,     al              ; Set map mask
3908 
3909 		; Write the XBlock
3910 			mov             al,             [es:bx]
3911 			mov             [es:di],        al
3912 
3913 		; Adjust bx and si
3914 			inc             bx
3915 			inc             di
3916 
3917 		; End of ScanLine
3918 			dec             cl
3919 			jnz             @@ScanLine
3920 
3921 		; Adjust for next iteration
3922 			add             di,     bp      ; Point DI to start of next line
3923 
3924 		; Restore cl
3925 			mov             cl,  ch
3926 
3927 		; End of Rowloop.
3928 			dec             ah
3929 			jnz             @@Rowloop
3930 
3931 		; !!DONE!!
3932 	@@DONE:
3933 			pop             si di ds             ; Return state
3934 			pop             bp
3935 			ret
3936 
3937 ENDP                    _XPaste_Tile_M;
3938 
3939 
3940 ; --------------------------- _XPaste_Sprite_M ----------------------------
3941 ; - This function will place a sprite from the display memory to current screen
3942 ; - It will use the mask passed to it to leave background transparent
3943 ; - Max Y size is 255
3944 public          _XPaste_Sprite_M
3945 
3946 PROC                    _XPaste_Sprite_M   FAR
3947 
3948  ARG    X_S:WORD,       Y_S:WORD, X_D:WORD,     Y_D:WORD,       TILE:WORD, MASK_O:DWORD
3949 
3950 			push            bp
3951 			mov             bp,     sp                      ; Save Stack frame
3952 			push            ds di si
3953 
3954 	       cld
3955  
3956 		; Load DS.
3957 			ASSUME  ds:  @fardata
3958 			mov             ax,  @fardata
3959 			mov             ds,  ax                 ; Set DS to fardata segment
3960 
3961 		; Set all data from latches
3962 			mov             dx,     GC_INDEX
3963 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
3964 			out             dx,     ax
3965 
3966 		; Set DI to start of rectangle on screen
3967 			mov             ax,  [WLine_Offset] ; Scan line size
3968 			mul             [Y_S]              ; Find Y offset value. Place in AX
3969 
3970 			mov             di,  [X_S]        ; Find X offset value. Place in DI
3971 			shr             di,  1
3972 			shr             di,  1             ; Adjust to number of XBlocks
3973 
3974 			add             di,  ax            ; Add X and Y offsets
3975 			add             di,  [Write_Page] ; Add in page offset
3976 
3977 		; Put source in BX
3978 			mov             bx,     [TILE]
3979 
3980 		; Find adjustment to source for alignment
3981 			mov             ax,     [X_D]
3982 			mov             cx,     [X_S]
3983 
3984 			shr             ax,     1          ; Number of XBlocks a line
3985 			shr             ax,     1
3986 			mul             [Y_D]        ; Find size of each sprite alignment
3987 
3988 			and             cx,     3          ; Mask all but 2 LSBs
3989 
3990 			mul             cx                 ; Find new offset
3991 
3992 			add             bx,     ax         ; Adjust BX
3993 
3994 		; Save adjustment for mask for alignment in DX
3995 			mov             dx,     ax         ; AX as calculated above
3996 
3997 		; Set CX to the number of XBlocks
3998 			mov             cx,     [X_D]
3999 			shr             cx,     1
4000 			shr             cx,     1
4001 
4002 		; Get distance from end of one line to start of other and save
4003 			mov             ax,     [WLine_Offset]  ; Get screen width
4004 			sub             ax,     cx                      ; Del number of XBlocks
4005 
4006 		; Set DS:SI to mask area
4007 			lds             si,     [MASK_O]
4008 
4009 		; Add alignment adjust to si
4010 			add             si,  dx
4011 
4012 		; Set AH to the rows to do
4013 			mov             dx,     [Y_D]   ; Puts number in AX
4014 			mov             bp,     ax              ; Move diff into BP
4015 			mov             ah,     dl              ; Puts number in ah
4016 
4017 		; Get the Screen Seg and put it in ES
4018 			mov             dx,  SCREEN_SEG
4019 			mov             es,     dx
4020 
4021 		; Set up Map Mask
4022 			mov             al,  02h        ; 02 is Map Mask
4023 			mov             dx,     SC_INDEX
4024 			out             dx,     al
4025 			inc             dx
4026 
4027 		; Save scan length (CL) in CH
4028 			mov             ch,     cl
4029 
4030 		; This section is for WRITES ------------------------------
4031 	@@Rowloop:
4032 
4033 	@@ScanLine:
4034 		; This section prep the Map Mask
4035 			lodsb                           ; Get mask byte
4036 
4037 		; Set mask for write
4038 			out             dx,     al              ; Set map mask
4039 
4040 		; Write the XBlock
4041 			mov             al,             [es:bx]
4042 			mov             [es:di],        al
4043 
4044 		; Adjust bx and si
4045 			inc             bx
4046 			inc             di
4047 
4048 		; End of ScanLine
4049 			dec             cl
4050 			jnz             @@ScanLine
4051 
4052 
4053 		; Adjust for next iteration
4054 			add             di,     bp      ; Point DI to start of next line
4055 
4056 		; Restore scan length
4057 			mov             cl,  ch
4058 
4059 		; End of Rowloop.
4060 			dec             ah
4061 			jnz             @@Rowloop
4062 
4063 		; !!DONE!!
4064 	@@DONE:
4065 			pop             si di ds             ; Return state
4066 			pop             bp
4067 			ret
4068 
4069 ENDP                    _XPaste_Sprite_M;
4070 
4071 
4072 ; ------------------------ _XSet_Pal_Color ---------------------------
4073 ; - This function uses the bios to set a single color in the palette
4074 ; - Does !not! wait for retrace
4075 public _XSet_Pal_Color
4076 
4077 PROC   _XSet_Pal_Color         FAR
4078 
4079    ARG     COLOR:WORD, RED:WORD, GREEN:WORD, BLUE:WORD
4080 
4081 	push            bp
4082 	mov             bp,     sp              ; Save Stack frame
4083 
4084 	; Set color to change
4085 	mov             ax,     [COLOR] 	; Load color number
4086 	mov 		dx,     PAL_SET_COLOR
4087 	out             dx,	al
4088 
4089 	; Set red
4090 	mov		dx,     PAL_RGB_COLOR
4091 	mov             ax,     [RED]
4092 	out             dx,	al
4093 
4094 	; Set green
4095 	mov             ax,     [GREEN]
4096 	out             dx,	al
4097 
4098 	; Set blue
4099 	mov             ax,     [BLUE]
4100 	out             dx,	al
4101 
4102 	pop             bp                      ; Return state
4103 	ret
4104 
4105 ENDP  _XSet_Pal_Color
4106 
4107 ; ------------------------ _XSet_Pal_Block ---------------------------
4108 ; - This function uses the bios to set a block of colors in the palette
4109 ; - !Does! wait for retrace
4110 public  _XSet_Pal_Block
4111 
4112 PROC    _XSet_Pal_Block FAR
4113 
4114   ARG     START:WORD, NUMBER:WORD, PAL_O:DWORD
4115 
4116 	push    bp
4117 	mov     bp,     sp              ; Save Stack frame
4118 
4119 	; Save registers
4120 	push	ds si
4121 
4122 	; Set CX to number of colors and BX to current
4123 	mov     cx,     [NUMBER]
4124 	mov	bx,	[START]
4125 
4126 	; Set ds:si to pal data
4127 	lds     si,     [PAL_O]
4128 
4129       ; -- Wait retrace
4130 	mov     dx, IN_STATUS1
4131    @@WaitP:
4132 	in      al, dx
4133 	and     al, 08h     ; Vertical Retrace Start?
4134 	jz      @@WaitP     ; If Not, loop until it is
4135 
4136    ; ------- Main loop
4137    @@Another:
4138 
4139 	; Set color to change
4140 	mov	dx,	PAL_SET_COLOR
4141 	mov     al,	bl
4142 	out	dx,     al
4143 
4144 	; Set RGB
4145 	mov	dx,     PAL_RGB_COLOR
4146 	lodsb   			; Get byte
4147 	out	dx,     al              ; Red
4148 	lodsb
4149 	out	dx,     al              ; Green
4150 	lodsb
4151 	out	dx,     al              ; Blue
4152 
4153 	; Next values and loop if any left
4154 	inc	bx
4155 	dec	cx
4156 	jnz	@@Another
4157 
4158    ; --- Done
4159 	pop     si ds
4160 	pop     bp                      ; Return state
4161 	ret
4162 
4163 ENDP                    _XSet_Pal_Block
4164 
4165 
4166 ; ------------------------ _XPut_Pixel ------------------------------------
4167 ; - Put a pixel to the screen.
4168 ; -
4169 public  _XPut_Pixel
4170 
4171 PROC    _XPut_Pixel  FAR
4172 
4173 	ARG     X_LOC:WORD, Y_LOC:WORD, COLOR:WORD
4174 
4175 	   push            bp
4176 	   mov             bp,     sp              ; Save Stack frame
4177 
4178 	   push            ds di
4179 
4180 
4181    ; Load DS.
4182 	   ASSUME  ds:  @fardata
4183 	   mov             ax,  @fardata
4184 	   mov             ds,  ax                 ; Set DS to fardata segment
4185 
4186    ; Set DI to the XBlock
4187 	   mov             ax,  [WLine_Offset]  ; Scan line size
4188 	   mul             [Y_LOC]              ; Find Y offset value. Place in AX
4189 
4190 	   mov             di,  [X_LOC]       ; Find X offset value. Place in DI
4191 	   mov       cx,   di                 ; For later to determine the mask
4192 	   shr             di,  2
4193 
4194 	   add             di,  ax           ; Add X and Y offsets
4195 	   add             di,  [Write_Page] ; Add in page offset
4196 
4197 
4198    ; Set ah to the mask
4199 	   and             cx,     03h       ; Get the lower 2 bits
4200 	   mov             ax,     0102h     ; MAP MASK
4201 	   shl             ah,     cl        ; Shift to app. plane
4202 
4203    ; Set up Map Mask
4204 	   mov             dx,     SC_INDEX
4205 	   out             dx,     ax
4206 
4207    ; Set all data from CPU and non from latches
4208 	   mov             dx,     GC_INDEX
4209 	   mov             ax,     0FF00h + BIT_MASK  ; Set all CPU writes
4210 	   out             dx,     ax
4211 
4212    ; Get the Screen Seg and put it in DS
4213 	   mov             ax,  SCREEN_SEG
4214 	   mov             ds,     ax
4215 
4216    ; Get the color
4217 	   mov             ax,     [COLOR]
4218 
4219    ; Put the Pixel
4220 	   mov             [di],   al
4221 
4222    ; !!DONE!!
4223 	   pop             di ds   ; Return state
4224 	   pop             bp
4225 	   ret
4226 
4227 ENDP            _XPut_Pixel
4228 
4229 
4230 ; ------------------------ _XPut_Line ------------------------------------
4231 ; - Put a line to the screen.
4232 ; -
4233 ; - Thanks to Matt Pritchard for some of this code
4234 public  _XPut_Line
4235 PROC    _XPut_Line      FAR
4236 
4237 	ARG  XSTART:WORD, YSTART:WORD, XEND:WORD, YEND:WORD, COLOR:WORD
4238 
4239 
4240 	push    bp
4241 	mov     bp,     sp              ; Save Stack frame
4242 	push    ds di si
4243 
4244       ; Load DS.
4245 	ASSUME  ds:  @fardata
4246 	mov     ax,  @fardata
4247 	mov     ds,  ax                 ; Set DS to fardata segment
4248 
4249 	cld
4250 
4251       ; Set all data from CPU
4252 	mov     dx,     GC_INDEX
4253 	mov     ax,     0FF00h + BIT_MASK
4254 	out     dx,     ax
4255 
4256       ; Set up ES
4257 	mov     ax,     SCREEN_SEG
4258 	mov     es,     ax
4259 
4260       ; Set up Map Mask
4261 	mov     al,  02h        ; 02 is Map Mask
4262 	mov     dx,  SC_INDEX
4263 	out     dx,  al
4264 	inc     dx
4265 
4266       ; Check Line Type
4267 
4268 	mov     si,  [XSTART]
4269 	mov     di,  [XEND]
4270 	cmp     si,  di         ; Is XSTART < XEND?
4271 	je      @@Vertical      ; If X1=X2, it is a vertical line
4272 	jl      @@NoSwap        ; If X1 < X2, no swap is needed
4273 
4274 	xchg    si,  di         ; Swap so lower is in SI
4275 
4276     @@NoSwap:
4277 
4278 	mov     ax,  [YSTART]   ;
4279 	cmp     ax,  [YEND]     ; YSTART = YEND?
4280 	je      @@Horizontal    ; If so, it is a horizontal line
4281 
4282 	jmp     @@Brezhem       ; Otherwise, use Brezhem's algorithm
4283 
4284     ; Draw a horizontal line
4285     @@Horizontal:
4286 	mul     [WLine_Offset]  ; Get Y offset into write page
4287 	mov     dx,     ax      ; Save in DX
4288 
4289 	mov     ax,     si
4290 	and     si,     3       ; Mask out plane bits
4291 
4292 	mov     bl, [Left_Clip_Mask+si] ; Get Left Edge Mask
4293 	mov     cx,     di              ; Get Right edge, Save XSTART
4294 	and     di,     3               ; Mask out scan
4295 	mov     bh, [Right_Clip_Mask+di] ; Get Right Edge Mask byte
4296 
4297       ; Convert AX and CX to XBlocks
4298 	shr     ax,     2
4299 	shr     cx,     2
4300 
4301       ; Find start address
4302 	mov     di,     [Write_Page]
4303 	add     di,     dx              ; Point to start of scan line
4304 	add     di,     ax              ; Point to start pixel
4305 
4306 	sub     cx,     ax              ; Set CX to number of XBlocks - 1
4307 	jnz     @@Long                  ; Jump if more that one XBlock
4308 
4309 	and     bl,     bh              ; Otherwise, merge clip masks
4310 
4311     @@Long:
4312 	mov     dx,     SC_INDEX+1      ; Point to SC data
4313 
4314       ; Set left mask
4315 	mov     al,     bl
4316 	out     dx,     al
4317 
4318       ; Get Color
4319 	mov     ax,     [COLOR]
4320 	mov     bl,     al      ; Save color in bl
4321 
4322       ; Set first XBlock
4323 	stosb
4324 
4325 	jcxz    @@DoneThis      ; Done if only one XBlock
4326 
4327       ; Dec cx and see if any middle XBlocks
4328 	dec     cx
4329 	jz      @@NoMiddleX
4330 
4331      ; Draw middle XBlocks
4332 
4333       ; Set map mask to all planes
4334 	mov     al,     0Fh
4335 	out     dx,     al
4336 
4337       ; Restore color and draw middle segments
4338 	mov     al,     bl
4339 	rep     stosb
4340 
4341     @@NoMiddleX:
4342       ; Do Left clip
4343 	mov     al,     bh
4344 	out     dx,     al
4345 	stosb
4346 
4347     @@DoneThis:
4348 	jmp     @@Done
4349 
4350     ; Draw vertical line
4351     @@Vertical:
4352 	mov     ax,     [YSTART]
4353 	mov     si,     [YEND]
4354 	cmp     ax,     si         ; Is Y1 < Y2?
4355 	jle     @@NoSwap2          ; if so, Don't Swap
4356 
4357 	xchg    ax,     si         ; Ok, swap lower into ax
4358 
4359     @@NoSwap2:
4360 	sub     si,     ax
4361 	inc     si
4362 
4363       ; Get start address
4364 	mul     [WLine_Offset]
4365 	mov     dx,     di      ; Save XSTART in dx
4366 	shr     di,     2       ; Convert to XBlocks
4367 
4368 	add     di,     ax
4369 	add     di,     [Write_Page]
4370 
4371       ; Select Plane
4372 	mov     cl,     dl      ; Get lower of XSTART
4373 	and     cl,     3       ; Mask of plane selectoin bits
4374 	mov     ax,     0102h   ; Map Mask register access
4375 	shl     ah,     cl      ; Shift to plane
4376 	mov     dx,     SC_INDEX
4377 	out     dx,     ax
4378 
4379       ; Setup for writes
4380 	mov     ax,      [COLOR]         ; Get color
4381 	mov     bx,      [WLine_Offset]  ; Scan line differential
4382 
4383     @@VertLoop:
4384 	mov     [es:di], al              ; Write a pixel
4385 	add     di     , bx              ; Next scan line
4386 	dec     si
4387 	jz      @@EndLoop                ; Done?
4388 
4389 	mov     [es:di], al              ; Write a pixel
4390 	add     di     , bx              ; Next scan line
4391 	dec     si
4392 	jnz     @@VertLoop               ; More?
4393 
4394     @@EndLoop:
4395 	jmp     @@Done
4396 
4397     ; Brezhem's algorithm
4398     @@Brezhem:
4399 
4400       ; Load write page into di
4401 	mov     di, [Write_Page]
4402 
4403       ; Load starting values
4404 	mov     ax, [YSTART]
4405 	mov     bx, [YEND]
4406 	mov     cx, [XSTART]
4407 
4408 	cmp     bx, ax          ; Is Y2 >= Y1 is?
4409 	jnc     @@YOK           ; If yes, OK!
4410 
4411 	xchg    bx, ax          ; Otherwise swap
4412 	mov     cx, [XEND]      ; Get New Starting X
4413 
4414     @@YOK:
4415       ; Find start address
4416 	mul     [WLine_Offset]
4417 	add     di, ax
4418 	mov     ax, cx
4419 	shr     ax, 2		; Convert to XBlocks
4420 	add     di, ax
4421 
4422       ; Push color and start mask in same word
4423 	mov     ax,     [COLOR]
4424 	xchg    ah,     al
4425 	mov     al,     11h
4426 	and     cl,     3
4427 	shl     al,     cl      ; Find mask
4428 	push    ax
4429 
4430       ; Prep map mask
4431 	xchg    ah,     al
4432 	mov     al,     02h     ; Map Mask register
4433 	mov     dx,     SC_INDEX
4434 	out     dx,     ax
4435 
4436       ; Load position values
4437 	mov     ax,     [XSTART]
4438 	mov     bx,     [YSTART]
4439 	mov     cx,     [XEND]
4440 	mov     dx,     [YEND]
4441 
4442       ; Load line size in BP
4443 	mov     bp,     [WLine_Offset]
4444 
4445       ; Check Y delta
4446 	sub     dx,     bx          ; Find delta
4447 	jnc     @@YDeltaOK          ; Jump if Y2 >= Y1, delta ok
4448 
4449 	add     bx,     dx          ; Otherwise fixup
4450 	neg     dx
4451 	xchg    ax,     cx
4452 
4453     @@YDeltaOK:
4454 	mov     bx, 08000H          ; Seed for fraction AC
4455 	sub     cx, ax              ; figure Delta_X
4456 	jc      @@DrawLeft          ; if negative, go left
4457 
4458 	jmp     @@DrawRight         ; Draw Line that slopes right
4459 
4460     @@DrawLeft:
4461 	neg     cx                  ; abs(Delta_X)
4462 	cmp     cx, dx              ; is Delta_X < Delta_Y?
4463 	jb      @@SteepLeft         ; yes, so go do steep line
4464 				    ; (Delta_Y iterations)
4465 
4466     ; Draw a Shallow line to the left
4467     @@ShallowLeft:
4468 	xor     ax, ax              ; zero low word of Delta_Y * 10000h
4469 	sub     ax, dx              ; DX:AX <- DX * 0FFFFh
4470 	sbb     dx, 0               ; include carry
4471 	div     cx                  ; divide by Delta_X
4472 
4473 	mov     si, bx              ; SI = Accumulator
4474 	mov     bx, ax              ; BX = Add fraction
4475 	pop     ax                  ; Get Color, Bit mask
4476 	mov     dx, SC_INDEX+1      ; Sequence controller data register
4477 	inc     cx                  ; Inc Delta_X so we can unroll loop
4478 
4479       ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
4480     @@SLLLoop:
4481 	mov     [es:di], ah
4482 	dec     cx
4483 	jz      @@SLLExit           ; Delta_X--, Exit if done
4484 
4485 	add     si, bx              ; add numerator to accumulator
4486 	jnc     @@SLLL2nc           ; move down on carry
4487 
4488 	add     di, bp              ; Move Down one line...
4489 
4490     @@SLLL2nc:
4491 	dec     di                  ; Left one addr
4492 	ror     al, 1               ; Move Left one plane, back on 0 1 2
4493 	cmp     al, 87h             ; wrap?, if AL <88 then Carry set
4494 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4495 	out     dx, al              ; Set up New Bit Plane mask
4496 
4497 	mov     [es:di], al         ; set pixel
4498 	dec     cx
4499 	jz      @@SLLExit           ; Delta_X--, Exit if done
4500 
4501 	add     si, bx              ; add numerator to accumulator,
4502 	jnc     @@SLLL3nc           ; move down on carry
4503 
4504 	add     di, bp              ; Move Down one line...
4505 
4506     @@SLLL3nc:                      ; Now move left a pixel...
4507 	dec     di                  ; Left one addr
4508 	ror     al, 1               ; Move Left one plane, back on 0 1 2
4509 	cmp     al, 87h             ; Wrap?, if AL <88 then Carry set
4510 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4511 	out     dx, al              ; Set up New Bit Plane mask
4512 	jmp     @@SLLLoop           ; loop until done
4513 
4514     @@SLLExit:
4515 	jmp     @@Done              ; Done
4516 
4517     ; Draw a steep line to the left
4518     @@SteepLeft:
4519 	xor     ax, ax              ; zero low word of Delta_Y * 10000h
4520 	xchg    dx, cx              ; Delta_Y switched with Delta_X
4521 	div     cx                  ; divide by Delta_Y
4522 
4523 	mov     si, bx              ; SI = Accumulator
4524 	mov     bx, ax              ; BX = Add Fraction
4525 	pop     ax                  ; Get Color, Bit mask
4526 	mov     dx, SC_INDEX+1      ; Sequence controller data register
4527 	inc     cx                  ; Inc Delta_Y so we can unroll loop
4528  
4529       ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
4530     @@STLLoop:
4531 
4532 	mov     [es:di], ah         ; set first pixel
4533 	dec     cx
4534 	jz      @@STLExit           ; Delta_Y--, Exit if done
4535 
4536 	add     si, bx              ; add numerator to accumulator
4537 	jnc     @@STLnc2            ; No carry, just move down!
4538 
4539 	dec     di                  ; Move Left one addr
4540 	ror     al, 1               ; Move Left one plane, back on 0 1 2
4541 	cmp     al, 87h             ; Wrap?, if AL <88 then Carry set
4542 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4543 	out     dx, al              ; Set up New Bit Plane mask
4544 
4545     @@STLnc2:
4546 	add     di, bp              ; advance to next line.
4547 
4548 	mov     [es:di], ah         ; set pixel
4549 	dec     cx
4550 	jz      @@STLExit           ; Delta_Y--, Exit if done
4551 
4552 	add     si, bx              ; add numerator to accumulator
4553 	jnc     @@STLnc3            ; No carry, just move down!
4554  
4555 	dec     di                  ; Move Left one addr
4556 	ror     al, 1               ; Move Left one plane, back on 0 1 2
4557 	cmp     al, 87h             ; Wrap?, if AL <88 then Carry set
4558 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4559 	out     dx, al              ; Set up New Bit Plane mask
4560  
4561     @@STLnc3:
4562 	add     di, bp              ; advance to next line.
4563 	jmp     @@STLLoop           ; Loop until done
4564 
4565     @@STLExit:
4566 	jmp     @@Done              ; Done!
4567 
4568     ; Draw a line that goes to the Right...
4569     @@DrawRight:
4570 	cmp     cx, dx              ; is Delta_X < Delta_Y?
4571 	jb      @@SteepRight        ; yes, so go do steep line
4572 				    ; (Delta_Y iterations)
4573 
4574     ; Draw a Shallow line to the Right in Mode X
4575     @@ShallowRight:
4576 	xor     ax, ax              ; zero low word of Delta_Y * 10000h
4577 	sub     ax, dx              ; DX:AX <- DX * 0FFFFh
4578 	sbb     dx, 0               ; include carry
4579 	div     cx                  ; divide by Delta_X
4580 
4581 	mov     si, bx              ; SI = Accumulator
4582 	mov     bx, ax              ; BX = Add Fraction
4583 	pop     ax                  ; Get Color, Bit mask
4584 	mov     dx, SC_INDEX+1      ; Sequence controller data register
4585 	inc     cx                  ; Inc Delta_X so we can unroll loop
4586 
4587       ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
4588     @@SLRLoop:
4589 	mov     [es:di], ah         ; set first pixel, mask is set up
4590 	dec     cx
4591 	jz      @@SLRExit           ; Delta_X--, Exit if done..
4592 
4593 	add     si, bx              ; add numerator to accumulator
4594 	jnc     @@SLR2nc            ; don't move down if carry not set
4595 
4596 	add     di, bp              ; Move Down one line...
4597 
4598     @@SLR2nc:                       ; Now move right a pixel...
4599 	rol     al, 1               ; Move Right one addr if Plane = 0
4600 	cmp     al, 12h             ; Wrap? if AL >12 then Carry not set
4601 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4602 	out     dx, al              ; Set up New Bit Plane mask
4603 
4604 	mov     [es:di], ah         ; set pixel
4605 	dec     cx
4606 	jz      @@SLRExit           ; Delta_X--, Exit if done..
4607 
4608 	add     si, bx              ; add numerator to accumulator
4609 	jnc     @@SLR3nc            ; don't move down if carry not set
4610 
4611 	add     di, bp              ; Move Down one line...
4612 
4613     @@SLR3nc:
4614 	rol     al, 1               ; Move Right one addr if Plane = 0
4615 	cmp     al, 12h             ; Wrap? if AL >12 then Carry not set
4616 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4617 	out     dx, al              ; Set up New Bit Plane mask
4618 	jmp     @@SLRLoop           ; loop till done
4619 
4620     @@SLRExit:
4621 	jmp     @@Done
4622 
4623     ; Draw a Steep line to the Right in Mode X
4624 
4625     @@SteepRight:
4626 	xor     ax, ax              ; zero low word of Delta_Y * 10000h
4627 	xchg    dx, cx              ; Delta_Y switched with Delta_X
4628 	div     cx                  ; divide by Delta_Y
4629 
4630 	mov     si, bx              ; SI = Accumulator
4631 	mov     bx, ax              ; BX = Add Fraction
4632 	pop     ax                  ; Get Color, Bit mask
4633 	mov     dx, SC_INDEX+1      ; Sequence controller data register
4634 	inc     cx                  ; Inc Delta_Y so we can unroll loop
4635 
4636     ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
4637 
4638     @@STRLoop:
4639 	mov     [es:di], ah         ; set first pixel, mask is set up
4640 	dec     cx
4641 	jz      @@Done              ; Delta_Y--, Exit if Done
4642 
4643 	add     si, bx              ; add numerator to accumulator
4644 	jnc     @@STRnc2            ; if no carry then just go down...
4645 
4646 	rol     al, 1               ; Move Right one addr if Plane = 0
4647 	cmp     al, 12h             ; Wrap? if AL >12 then Carry not set
4648 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4649 	out     dx, al              ; Set up New Bit Plane mask
4650 
4651     @@STRnc2:
4652 	add     di, bp              ; advance to next line.
4653 
4654 	mov     [es:di], ah         ; set pixel
4655 	dec     cx
4656 	jz      @@Done              ; Delta_Y--, Exit if Done
4657 
4658 	add     si, bx              ; add numerator to accumulator
4659 	jnc     @@STRnc3            ; if no carry then just go down...
4660 
4661 	rol     al, 1               ; Move Right one addr if Plane = 0
4662 	cmp     al, 12h             ; Wrap? if AL >12 then Carry not set
4663 	adc     di, 0               ; Adjust Address: DI = DI + Carry
4664 	out     dx, al              ; Set up New Bit Plane mask
4665 
4666     @@STRnc3:
4667 	add     di, bp              ; advance to next line.
4668 	jmp     @@STRLoop           ; loop till done
4669 
4670     ; !!DONE!!
4671     @@Done:
4672 	pop     si di ds             ; Return state
4673 	pop     bp
4674 	ret
4675 
4676 ENDP    _XPut_Line
4677 
4678 
4679 ; ------------------------ _MEvent_Handler ---------------------------
4680 ; - Xtile's mouse event handler
4681 ; - This one will NOT handle split screen
4682 ; -
4683 PROC    _MEvent_Handler
4684 
4685     ; Save thier DS
4686 	push ds di si
4687 
4688     ; This function is not callable from 'c' so we won't build a
4689     ; stack frame
4690 
4691     ; Save the event masks
4692 	push    ax
4693 
4694     ; Correct X pos
4695 	shr     cx,     1
4696 
4697     ; Save dx in SI
4698 	mov     si,     dx
4699 
4700     ; Load DS.
4701 	ASSUME  ds:  @fardata
4702 	mov     ax,  @fardata
4703 	mov     ds,  ax                 ; Set DS to fardata segment
4704 
4705     ; Check for Lock
4706 	cmp     [LockHandler],  NOTLOCKM        ; Is it locked
4707 	jz      @@NotLocked
4708 
4709 		; !!!Locked!!!  Jump out
4710 			pop             ax                                      ; Pull flags off stack
4711 			jmp             @@Done
4712 
4713 	@@NotLocked:
4714 		; Lock the handler
4715 			mov             ax,     LOCKM
4716 			mov             [LockHandler], ax
4717 
4718 	; Get and save the status of bit mask and map mask
4719 		; Get status of bit mask
4720 			mov             dx,     GC_INDEX
4721 			mov             ax,     0808h     ; 08 is bit mask
4722 			out             dx,     al
4723 			inc             dx
4724 			in              al,     dx              ; Get the bit mask
4725 			xchg            al,     ah
4726 			push            ax
4727 
4728 		; Get Map Mask
4729 			mov             ax,  0202h              ; 02 is Map Mask
4730 			mov             dx,     SC_INDEX
4731 			out             dx,     al
4732 			inc             dx
4733 			in              al,     dx
4734 	       xchg             al,  ah
4735 			push    ax
4736 
4737 	; -- Restore the the current background location ---
4738 	; This is a Save Site restore
4739 			cld
4740 
4741 		; Set DI to start of rectangle on screen
4742 			mov             ax,  [DLine_Offset] ; Get line size
4743 			mov             bx,  [MLastY]       ; Get Y into view
4744 			push      bx                            ; Save on stack
4745 			add          bx,  [ViewYLoc]     ; Add start of view
4746 			mul             bx                         ; Find Y offset value. Place in AX
4747 
4748 			mov             di,  [MLastX]     ; Find X offset value. Place in DI
4749 			mov             bp,  di            ; Save X in BP
4750 			add             di,  [ViewXLoc]   ; Get start of view and add it
4751 			shr             di,  2
4752 
4753 			add             di,  ax            ; Add X and Y offsets
4754 			add             di,  [MousePage]  ; Add in page offset
4755 
4756 		; Get DX back
4757 			mov             dx,     si
4758 
4759 		; Save the new location as the last known
4760 			mov             [MLastY],       dx
4761 			mov             [MLastX],       cx
4762 
4763 		; See if we need to clip Second XBlock
4764 			mov             cx,             2                       ; Assume 2 XBlocks to write
4765 			mov             dx,       [ScreenSizeX] ; Get screen size
4766 			sub             dx,             4                       ; Get 2nd to last XBlock
4767 			cmp             dx,             bp
4768 			jae       @@Continue                    ; Both blocks on reload
4769 			dec             cx                                      ; Only one block on reload
4770 
4771 	@@Continue:
4772 		; Set all data from latches
4773 			mov             dx,     GC_INDEX
4774 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
4775 			out             dx,     ax
4776 
4777 		; Insure Map Mask is set to all planes
4778 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
4779 			mov             dx,     SC_INDEX
4780 			out             dx,     ax
4781 
4782 		; Set DX to number of lines to display
4783 			mov             dx,     8               ; Assume 8 scan lines
4784 			pop             bx                      ; Get Y last and put in BX
4785 			mov             ax,     [MouseLines] ; Get Screen size Y and put in ax
4786 			sub             ax,     8               ; Subtract to make mimimum clip
4787 
4788 			cmp             ax,     bx              ; Does it need clipping?
4789 			ja              @@ContinueC     ; No, then go!
4790 
4791 			sub             bx,  ax         ; Needs clipping!  Find new DX
4792 			sub             dx,     bx
4793 
4794 	@@ContinueC:
4795 		; Set BP to the distance from one scan line to next
4796 			mov             bp,     [DLine_Offset]
4797 			sub             bp,  cx                 ; # XBlocks per scan line
4798 
4799 		; Get the Screen Seg and put it in DS and ES
4800 			mov             ax,  SCREEN_SEG
4801 			mov             ds,  ax
4802 			mov             es,     ax
4803 
4804 		; Set SI to source
4805 			mov             si,             MSAVEOFFSET
4806 
4807 		; Save number to move (CX) in BX
4808 			mov             bx,     cx
4809 
4810 	   ; This section is for WRITES ------------------------------
4811 	   ; The Reload will be clipped if appropriate
4812 
4813 	 @@RowLoop:
4814 		 ; Put 1 or 2 XBlocks
4815 			rep movsb
4816 
4817 		 ; Ready next iteration
4818 			add             di,     bp      ; Point DI to start of next line
4819 
4820 		 ; Reload CX
4821 			mov             cx,     bx
4822 
4823 		 ; Are we done?
4824 			dec             dx
4825 			jnz             @@RowLoop       ; No, then go and do another line
4826 
4827 
4828 	; ------ Now save the new area --------
4829 	; -- Do the reload
4830 
4831 		; Load DS.
4832 			ASSUME  ds:  @fardata
4833 			mov             ax,  @fardata
4834 			mov             ds,  ax                 ; Set DS to fardata segment
4835 
4836 		; Set SI to start of rectangle on screen
4837 			mov             ax,  [DLine_Offset] ; Get line size
4838 			mov             bx,  [MLastY]       ; Get Y into view
4839 			mov             di,     bx                      ; Save in DI
4840 			add          bx,  [ViewYLoc]     ; Add start of view
4841 			mul             bx                         ; Find Y offset value. Place in AX
4842 
4843 			mov             si,  [MLastX]     ; Find X offset value. Place in DI
4844 			mov             bp,  si            ; Save in BP for later
4845 			add             si,  [ViewXLoc]   ; Get start of view and add it
4846 			shr             si,  2
4847 
4848 			add             si,  ax            ; Add X and Y offsets
4849 			add             si,  [MousePage]  ; Add in page offset
4850 
4851 			push            si                              ; Save what will later be DI
4852 
4853 		; See if we need to clip Second XBlock
4854 			mov             cx,             2                       ; Assume 2 XBlocks to write
4855 			mov             dx,       [ScreenSizeX] ; Get screen size
4856 			sub             dx,             4                       ; Get 2nd to last XBlock
4857 			cmp             dx,             bp             ; BP from above.
4858 			jae        @@Continue3                  ; Both blocks on reload
4859 			dec             cx                                      ; Only one block on reload
4860 
4861 	@@Continue3:
4862 		; Set DX to number of lines to reload
4863 			mov             dx,     8               ; Assume 8 scan lines
4864 			mov             bx,     di              ; Get Y last and put in BX (from SI)
4865 			mov             ax,     [MouseLines] ; Get Screen size Y and put in ax
4866 			sub             ax,     8               ; Subtract to make mimimum clip
4867 
4868 			cmp             ax,     bx              ; Does it need clipping?
4869 			ja              @@Continue4     ; No, then go!
4870 
4871 			sub             bx,  ax         ; Needs clipping!  Find new DX
4872 			sub             dx,     bx
4873 
4874 	@@Continue4:
4875 		; Save DX ( as number of lines to do ) for later
4876 			push            dx
4877 
4878 		; Set BP to scan line dif.
4879 			mov             bp,     [DLine_Offset]
4880 			sub             bp,  cx
4881 
4882 		; Get the Screen Seg and put it in DS
4883 			mov             ax,  SCREEN_SEG
4884 			mov             ds,     ax
4885 
4886 		; Set destination
4887 			mov             di,     MSAVEOFFSET
4888 
4889 		; Save SI so we dont have to calc later
4890 			mov             ax,     si
4891 
4892 		; Save CX in BX
4893 			mov             bx,     cx
4894 
4895 	   ; This section is for the MOVE ------------------------------
4896 
4897 	@@RowLoop2:
4898 		; Do line
4899 			rep             movsb   ; One or two XBlocks
4900 
4901 		; Prep for next line
4902 			add             si,     bp      ; Point SI to start of next line
4903 			mov             cx,     bx      ; Restore CX
4904 
4905 		; Are we done?
4906 			dec             dx
4907 			jnz             @@RowLoop2      ; No, then go and do another
4908 
4909 
4910 	; -------- Put the pointer in the new position ---------
4911 
4912 		; Load DS.
4913 			ASSUME  ds:  @fardata
4914 			mov             ax,  @fardata
4915 			mov             ds,  ax                 ; Set DS to fardata segment
4916 
4917 
4918 		; Find adjustment to source for alignment
4919 			mov             bx,     [MLastX]         ; Put X loc into cx
4920 			add             bx,  [ViewXLoc] ; Add view start
4921 			mov             ax,     16              ; Alignment size ( 2XBlocks*8Scan )
4922 
4923 			and             bx,     3          ; Mask all but 2 LSBs
4924 			mul             bx                 ; Find offset into alignments (Put in AX)
4925 
4926 		; Put source into BX and add the alignment adj
4927 			mov             bx,     MOUSEOFFSET
4928 			add             bx,     ax         ; Adjust BX
4929 
4930 
4931 		; Set DS:SI to mask area
4932 			lds             si,     [MPointerMask]
4933 
4934 		; Add adjustment for mask for alignment
4935 			add             si,     ax         ; AX as calculated above
4936 
4937 		; Set ah to rows to do
4938 			pop             ax                 ; Was DX in the reload
4939 			mov             ah,  al    ;    Move to upper nibble
4940 
4941 		; Increment BP to account for no last inc
4942 			inc             bp
4943 
4944 		; Pop the destination, prev si, from the stack
4945 			pop             di
4946 
4947 		; Set up Map Mask
4948 			mov             al,  02h        ; 02 is Map Mask
4949 			mov             dx,     SC_INDEX
4950 			out             dx,     al
4951 			inc             dx
4952 
4953 		; Shift CX down to see if we need to write 2nd XBlock
4954 			shr             cx,     1
4955 
4956 		; This section is for WRITES ------------------------------
4957 	@@Rowloop3:
4958 
4959 
4960 		; Set mask for first XBlock write
4961 			lodsb                           ; Get mask byte
4962 			out             dx,     al              ; Set map mask
4963 
4964 		; Write the 1st XBlock
4965 			mov             al,             [es:bx]
4966 			mov             [es:di],        al
4967 
4968 		; Load the next mask
4969 			lodsb
4970 
4971 		; Increment source pointers
4972 			inc     bx
4973 
4974 		; If CX is zero, pointer is clipped.  Don't put next XBlock
4975 			jcxz            @@Clipped
4976 
4977 	   ; - Do another write
4978 		; Set the mask
4979 			out             dx,     al              ; Set map mask
4980 
4981 		; Increment destination pointers
4982 			inc     di
4983 
4984 		; Write the 2nd XBlock
4985 			mov             al,             [es:bx]
4986 			mov             [es:di],        al
4987 
4988 	 @@Clipped:
4989 		; Adjust for next iteration
4990 			add             di,      bp  ; Point to next scan line
4991 			inc             bx
4992 
4993 		; End of Rowloop.
4994 			dec             ah
4995 			jnz             @@Rowloop3
4996 
4997 	  ; -- Done with screen
4998 
4999 	  ; Restore the state of the bit mask and map mask
5000 		; Get Map Mask
5001 			mov             dx,     SC_INDEX
5002 			pop             ax
5003 			out             dx,     ax
5004 
5005 		; Do the BIT MASK
5006 			mov             dx,     GC_INDEX
5007 			pop             ax
5008 			out             dx,     ax
5009 
5010 	  ; -- See if we have to call the user's handler
5011 
5012 		; Make ES the local data
5013 			ASSUME  es:  @fardata
5014 			mov             ax,  @fardata
5015 			mov             es,  ax                 ; Set ES to fardata segment
5016 
5017 		; Restore event masks
5018 			pop             ax
5019 
5020 		; AND the mask with users mask
5021 			and             ax,     [es:MUEventMask]
5022 
5023 		; If zero then don't call user's
5024 			je              @@Done
5025 
5026 		; Otherwise set up stack and call users routine
5027 			push            ax           ; Push the event mask
5028 
5029 			mov     ax,  @data           ; Load users DGROUP
5030 			mov     ds,  ax
5031 
5032 			push            [es:MLastY]  ; Push Y location
5033 
5034 			push            [es:MLastX]  ; Push X location
5035 
5036 			call    [es:Mouse_Hndlr_O]      ; User pointer to call user handler
5037 
5038 					; Clean stack after call
5039 			add             sp,     6
5040 
5041 
5042 	  ; -- DONE!!
5043 
5044 	@@Done:
5045 		; Make DS the local data
5046 			ASSUME  ds:  @fardata
5047 			mov             ax,  @fardata
5048 			mov             ds,  ax                 ; Set DS to fardata segment
5049 
5050 		; Unlock the handler
5051 			mov             ax,     NOTLOCKM
5052 			mov             [LockHandler], ax
5053 
5054 			pop   si di ds     ; Pop mouses DS
5055 			ret
5056 
5057 ENDP                    _MEvent_Handler
5058 
5059 
5060 ; ------------------------ _XRegister_Mouse ---------------------------
5061 ; - This function sets up the use of the mouse
5062 ; - It returns FALSE (0) if it cannot
5063 ; -
5064 public          _XRegister_Mouse
5065 
5066 PROC                    _XRegister_Mouse
5067 
5068 	ARG     MPOINT:DWORD, MMASK:DWORD, HANDLER:DWORD
5069 
5070 			push            bp
5071 			mov             bp,     sp              ; Save Stack frame
5072 
5073 		; Save registers
5074 			push            ds si di
5075 
5076 		; First see if mouse is available
5077 			mov       ax,   0
5078 			int             33h
5079 
5080 			cmp             ax,     0FFFFh  ; If ax is FFFFh then mouse is present
5081 			je              @@Cont
5082 
5083 			mov             ax,     MOUSE_NOTPRES
5084 			jmp             @@Done          ; Otherwise, done
5085 
5086 		; Mouse is present so continue
5087 	@@Cont:
5088 
5089 	; ----------- Upload mouse pointer ------------
5090 
5091 		; Prep the stack for call to upload sprite
5092 			les             si,     [MPOINT]        ; Get the image offset
5093 			push            es
5094 			push            si
5095 
5096 			mov             si,     (64*4)          ; Mouse sprite size
5097 			push            si
5098 
5099 			mov             si,     MOUSEOFFSET    ; Mouse pointer site
5100 			push            si
5101 
5102 		; Call upload sprite
5103 			call    _XUpload_Sprite
5104 
5105 		; Fix the stack after call
5106 			add             sp,     8
5107 
5108 	; ---- Done uploading mouse pointer
5109 
5110 
5111 		; Load DS.
5112 			ASSUME  ds:  @fardata
5113 			mov             ax,  @fardata
5114 			mov             ds,  ax                 ; Set DS to fardata segment
5115 
5116 		; Get the pointer mask address
5117 			les             si,  [MMASK]
5118 			mov             [MPointerMask_O], si
5119 			mov             ax,  es
5120 			mov             [MPointerMask_S], ax
5121 
5122 		; Set up user handler
5123 			les             si,  [HANDLER]
5124 			mov             [OFFSET Mouse_Hndlr_O], si
5125 			mov             ax,  es
5126 			mov             [OFFSET Mouse_Hndlr_O+2], ax
5127 
5128 		; !!DONE!!
5129 			mov             ax,     MOUSE_PRESENT   ; Return the mouse is present
5130 
5131 
5132 		; Set the new mickey counts
5133 			mov             ax,     000Fh            ; Mouse driver routine
5134 			mov             cx,  8                   ; Double horizontal
5135 			mov             dx,  8                   ; Default vertical
5136 			int             033h                             ; Call routine
5137 
5138 	@@Done:
5139 			pop             di si ds
5140 
5141 			pop             bp                      ; Return state
5142 	       ret
5143 
5144 ENDP                    _XRegister_Mouse
5145 
5146 
5147 ; ------------------------ _Mouse_Active ---------------------------
5148 ; - Makes the mouse active and starts display of the pointer
5149 ; - It will not process for the split screen crossover, but can decided
5150 ; - between split page and normal page
5151 
5152 public  _XMouse_Active
5153 
5154 PROC    _XMouse_Active
5155 
5156       ARG       EMASK:WORD, STARTX:WORD, STARTY:WORD, SPLIT:WORD
5157 
5158 	push    bp
5159 	mov     bp,     sp              ; Save Stack frame
5160 
5161     ; Save regs
5162 	push    ds si di
5163 
5164     ; Load DS.
5165 	ASSUME  ds:  @fardata
5166 	mov     ax,  @fardata
5167 	mov     ds,  ax                 ; Set DS to fardata segment
5168 
5169 	cld
5170 
5171     ; Save the users mask
5172 	mov     cx,     [EMASK]         ; Get user's mask
5173 	push    cx
5174 
5175     ; Which page ?
5176 	mov     cx,     [SPLIT]
5177 	jcxz    @@NORMALPAGE
5178 
5179   ; - Split Page
5180 	mov     ax,             0
5181 	mov     [MousePage],    ax      ; Set page to 0, split page
5182 
5183 	mov     ax,   [OriginalY]       ; Get absolute size
5184 	sub     ax,   [SplitY]          ; Subtract split Y size
5185 	mov     [MouseLines],   ax      ; Save it as the number of lines
5186 
5187 	jmp     @@CONTINUE
5188 
5189   ; - Normal Page
5190   @@NORMALPAGE:
5191 	mov     ax,          [Display_Page]
5192 	mov     [MousePage], ax                 ; Set to display page
5193 
5194 	mov     ax,   [ScreenSizeY]     ;
5195 	mov     [MouseLines],   ax      ; Save it as the number of lines
5196 
5197     ; Set mouse reporting limits
5198   @@CONTINUE:
5199 	mov     ax,  0007h      	; Set X limits function
5200 	mov     cx,  0000h   		; X minimum
5201 	mov     dx,  [ScreenSizeX]      ; X maximum
5202 	dec     dx
5203 	shl     dx,  1           	; Comp for oddity
5204 	int     033h
5205 
5206 	mov     ax,     0008h           ; Set Y limits function
5207 	mov     cx,     0000h           ; Y minimum
5208 	mov     dx,     [MouseLines]    ; Y maximum
5209 	dec     dx                      ; Adjust for pointer size
5210 	int       033h
5211 
5212    ; -- Set up VGA Registers
5213      ; Set all data from latches
5214 	mov             dx,     GC_INDEX
5215 	mov             ax,     00000h + BIT_MASK  ; Set all latch writes
5216 	out             dx,     ax
5217 
5218      ; Insure Map Mask is set to all planes
5219 	     mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
5220 	     mov             dx,     SC_INDEX
5221 	     out             dx,     ax
5222 
5223 
5224 ; -- Set the mouse's position and display the pointer
5225 
5226      ; Let the driver know where the mouse pointer is
5227 	     mov             ax,     0004h   ; Set mouse pointer position func
5228 
5229 	     mov             cx,     [STARTX]        ; Set X coord
5230 	     mov             dx,     [STARTY]        ; Set Y coord
5231 
5232 	     mov       [MLastX], cx   ; Save as last location
5233 	     mov             [MLastY], dx
5234 
5235 	     shl             cx,     1               ; Comp
5236 
5237 	     int             033h                    ; Call function
5238 
5239      ; Return CX to actual coord
5240 	     shr             cx,     1
5241 
5242 
5243 
5244      ; Reload background & fake a mouse event to put the pointer
5245      ; on the screen the first time
5246 
5247 ; -- Do the reload ------------------------------
5248 
5249      ; Set SI to start of rectangle on screen
5250 	     mov             ax,  [DLine_Offset] ; Get line size
5251 	     mov             bx,  [MLastY]       ; Get Y into view
5252 	     mov             di,     bx                      ; Save in DI
5253 	     add          bx,  [ViewYLoc]     ; Add start of view
5254 	     mul             bx                         ; Find Y offset value. Place in AX
5255 
5256 	     mov             si,  [MLastX]     ; Find X offset value. Place in DI
5257 	     mov             bp,  si            ; Save in BP for later
5258 	     add             si,  [ViewXLoc]   ; Get start of view and add it
5259 	     shr             si,  2
5260 
5261 	     add             si,  ax              ; Add X and Y offsets
5262 	     add             si,  [MousePage]    ; Add in page offset
5263 
5264      ; See if we need to clip Second XBlock
5265 	     mov             cx,             2                       ; Assume 2 XBlocks to write
5266 	     mov             dx,       [ScreenSizeX] ; Get screen size
5267 	     sub             dx,             4                       ; Get 2nd to last XBlock
5268 	     cmp             dx,             bp             ; BP from above.
5269 	     jge       @@Continue3                   ; Both blocks on reload
5270 	     dec             cx                                      ; Only one block on reload
5271 
5272 @@Continue3:
5273      ; Set DX to number of lines to reload
5274 	     mov             dx,     8               ; Assume 8 scan lines
5275 	     mov             bx,     di              ; Get Y last and put in BX (from SI)
5276 	     mov             ax,     [MouseLines] ; Get Screen size Y and put in ax
5277 	     sub             ax,     8               ; Subtract to make mimimum clip
5278 
5279 	     cmp             ax,     bx              ; Does it need clipping?
5280 	     jg              @@Continue4     ; No, then go!
5281 
5282 	     sub             bx,  ax         ; Needs clipping!  Find new DX
5283 	     sub             dx,     bx
5284 
5285 @@Continue4:
5286 
5287      ; Set BP to scan line dif.
5288 	     mov             bp,     [DLine_Offset]
5289 	     sub             bp,  cx
5290 
5291      ; Get the Screen Seg and put it in DS and ES
5292 	     mov             ax,  SCREEN_SEG
5293 	     mov             ds,     ax
5294 	     mov             es,  ax
5295 
5296      ; Set destination
5297 	     mov             di,     MSAVEOFFSET
5298 
5299      ; Save CX in BX
5300 	     mov             bx,     cx
5301 
5302 ; This section is for the MOVE ------------------------------
5303 
5304 @@RowLoop3:
5305      ; Do line
5306 	     rep             movsb   ; One or two XBlocks
5307 
5308      ; Prep for next line
5309 	     add             si,     bp      ; Point SI to start of next line
5310 	     mov             cx,     bx      ; Restore CX
5311 
5312      ; Are we done?
5313 	     dec             dx
5314 	     jnz             @@RowLoop3      ; No, then go and do another
5315 
5316 
5317 ; - Done with Reload ---------------------------------------
5318 
5319      ; Load DS.
5320 	     ASSUME  ds:  @fardata
5321 	     mov             ax,  @fardata
5322 	     mov             ds,  ax                 ; Set DS to fardata segment
5323 
5324      ; Ensure the mouse is not locked
5325 	     mov             ax,                     NOTLOCKM
5326 	     mov             [LockHandler], ax
5327 
5328      ; Fake a mouse event and call handler
5329 	     mov             ax,     0001h   ; Indicate a move
5330 	     mov             bx,     0000h   ; No info
5331 	     mov             cx,  [MLastX]  ; X coord
5332 	     shl             cx,     1               ; Double, that's how it is expected
5333 	     mov             dx,     [MLastY]  ; Y coord
5334 
5335 	     call            _MEvent_Handler
5336 
5337      ; Get the users event mask, save, and build our mask in cx
5338 	     pop             cx                              ; Get the Mask back
5339 	     mov             [MUEventMask], cx   ; Save it
5340 	     or              cx,  0001h          ; Build ours
5341 				     ; We must make sure all moves are reported
5342 
5343      ; Define XTile's handler and register it with the mouse driver
5344 	     mov             ax,     0000Ch  ; Function number
5345 	     mov             dx,     cs              ; Get XTile's handler address
5346 	     mov             es,     dx
5347 	     mov             dx,  OFFSET _MEvent_Handler
5348 
5349 	     int             033h                    ; Call the mouse driver
5350      ; !!DONE!!
5351 
5352 	     pop             di si ds                ; Restore regs
5353 
5354 	     pop             bp                      ; Return state
5355 	     ret
5356 
5357 ENDP                    _XMouse_Active
5358 
5359 ; ------------------------ _XMouse_InActive ---------------------------
5360 ; - Turns off the mouse.  Restores background to last known mouse position.
5361 ; -
5362 public          _XMouse_InActive
5363 
5364 PROC                    _XMouse_InActive
5365 
5366 			push            bp
5367 			mov             bp,     sp              ; Save Stack frame
5368 
5369 		; Save regs
5370 			push            ds si di
5371 
5372 		; Register with mouse driver that we don't want any more reports
5373 			mov             ax,     0000Ch  ; Function number
5374 			mov             cx,     00000h  ; Clear flag
5375 			mov             dx,     00000h  ; Get XTile's handler address
5376 			mov             es,     dx
5377 			mov             dx,  00000h
5378 
5379 			int             033h                    ; Call the mouse driver
5380 
5381 		; Load DS with local segment
5382 			ASSUME  ds:  @fardata
5383 			mov             ax,  @fardata
5384 			mov             ds,  ax         ; Set DS to fardata segment
5385 
5386 		; Ensure the mouse is locked
5387 			mov             ax,                     LOCKM
5388 			mov             [LockHandler], ax
5389 
5390 		; Clear the users mask
5391 			mov             cx,     0000h                   ; Set to no events
5392 			mov             [MUEventMask], cx   ; Save it
5393 
5394 	; ---- This is the restore
5395 			cld
5396 
5397 		; Set DI to start of rectangle on screen
5398 			mov             ax,  [DLine_Offset] ; Get line size
5399 			mov             bx,  [MLastY]       ; Get Y into view
5400 			mov             si,  bx                         ; Save in SI
5401 			add          bx,  [ViewYLoc]     ; Add start of view
5402 			mul             bx                         ; Find Y offset value. Place in AX
5403 
5404 			mov             di,  [MLastX]     ; Find X offset value. Place in DI
5405 			mov             bp,  di            ; Save X in BP
5406 			add             di,  [ViewXLoc]   ; Get start of view and add it
5407 			shr             di,  2
5408 
5409 			add             di,  ax            ; Add X and Y offsets
5410 			add             di,  [MousePage]  ; Add in page offset
5411 
5412 
5413 		; See if we need to clip Second XBlock
5414 			mov             cx,             2                       ; Assume 2 XBlocks to write
5415 			mov             dx,       [ScreenSizeX] ; Get screen size
5416 			sub             dx,             4                       ; Get 2nd to last XBlock
5417 			cmp             dx,             bp
5418 			ja        @@Continue                    ; Both blocks on reload
5419 			dec             cx                                      ; Only one block on reload
5420 
5421 	@@Continue:
5422 		; Set all data from latches
5423 			mov             dx,     GC_INDEX
5424 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
5425 			out             dx,     ax
5426 
5427 		; Insure Map Mask is set to all planes
5428 			mov             ax,     0F02h    ; 0F sets all planes. 02 is Map Mask
5429 			mov             dx,     SC_INDEX
5430 			out             dx,     ax
5431 
5432 		; Set DX to number of lines to display
5433 			mov             dx,     8            ; Assume 8 scan lines
5434 			mov             ax,     [MouseLines] ; Get Screen size Y and put in ax
5435 			sub             ax,     8            ; Subtract to make mimimum clip
5436 
5437 			cmp             ax,     si      ; Does it need clipping? (SI = last Y)
5438 			ja              @@ContinueC     ; No, then go!
5439 
5440 			sub             si,  ax         ; Needs clipping!  Find new DX
5441 			sub             dx,     si
5442 
5443 	@@ContinueC:
5444 		; Set BP to the distance from one scan line to next
5445 			mov             bp,     [DLine_Offset]
5446 			sub             bp,  cx                 ; # XBlocks per scan line
5447 
5448 		; Get the Screen Seg and put it in DS and ES
5449 			mov             ax,  SCREEN_SEG
5450 			mov             ds,  ax
5451 			mov             es,     ax
5452 
5453 		; Set SI to source
5454 			mov             si,             MSAVEOFFSET
5455 
5456 		; Save number to move (CX) in BX
5457 			mov             bx,     cx
5458 
5459 	   ; This section is for WRITES ------------------------------
5460 	   ; The Reload will be clipped if appropriate
5461 
5462 	 @@RowLoop:
5463 		 ; Put 1 or 2 XBlocks
5464 			rep movsb
5465 
5466 		 ; Ready next iteration
5467 			add             di,     bp      ; Point DI to start of next line
5468 
5469 		 ; Reload CX
5470 			mov             cx,     bx
5471 
5472 		 ; Are we done?
5473 			dec             dx
5474 			jnz             @@RowLoop       ; No, then go and do another line
5475 
5476 
5477 	   ; -- DONE!!
5478 
5479 			pop             di si ds                ; Restore regs
5480 			pop             bp                      ; Return state
5481 	       ret
5482 
5483 ENDP                    _XMouse_InActive
5484 
5485 
5486 ; ------------------------ _XWhere_Mouse ---------------------------
5487 ; - Lets the user know the last known mouse location
5488 public  _XWhere_Mouse
5489 
5490 PROC    _XWhere_Mouse   FAR
5491 
5492 	ARG     X:DWORD, Y:DWORD
5493 
5494 	push    bp
5495 	mov     bp,     sp              ; Save Stack frame
5496 	push    ds si
5497 
5498       ; Load DS.
5499 	ASSUME  ds:  @fardata
5500 	mov     ax,  @fardata
5501 	mov     ds,  ax                 ; Set DS to fardata segment
5502 
5503       ; Load pointer to X
5504         les     si,  [X]
5505 
5506       ; Get value and save
5507         mov     ax,      [MLastX]
5508         mov     [es:si], ax
5509 
5510       ; Load pointer to Y
5511         les     si,  [Y]
5512 
5513       ; Get value and save
5514         mov     ax,      [MLastY]
5515         mov     [es:si], ax
5516 
5517       ; !!DONE!!
5518 	pop     si ds
5519 	pop     bp                      ; Return state
5520 	ret
5521 
5522 ENDP    _XWhere_Mouse
5523 
5524 
5525 ; ------------------------ _XReload_TileW ---------------------------
5526 ; - This will "reload" a tile from the write page to display memory
5527 ; - storeage
5528 ; -
5529 public          _XReload_TileW
5530 
5531 PROC                    _XReload_TileW
5532 
5533 	ARG     STARTX:WORD, STARTY:WORD, XDELTA:WORD, YDELTA:WORD, OFFST:WORD
5534 
5535 			push            bp
5536 			mov             bp,     sp              ; Save Stack frame
5537 
5538 		; Save regs
5539 			push            ds si di
5540 
5541 		; Load DS.
5542 			ASSUME  ds:  @fardata
5543 			mov             ax,  @fardata
5544 			mov             ds,  ax                 ; Set DS to fardata segment
5545 
5546 	; -- Do the reload
5547 
5548 		; Set SI to start of rectangle on screen
5549 			mov             ax,  [WLine_Offset] ; Get line size
5550 			mul             [STARTY]                        ; Find Y offset
5551 
5552 			mov             si,  [STARTX]     ; Find X offset value. Place in DI
5553 			shr             si,  2
5554 
5555 			add             si,  ax              ; Add X and Y offsets
5556 			add             si,  [Write_Page]   ; Add in page offset
5557 
5558 		; Set destination
5559 			mov             di,     [OFFST]
5560 
5561 		; Set all data from latches
5562 			mov             dx,     GC_INDEX
5563 			mov             ax,     00000h + BIT_MASK  ; Set all latch writes
5564 			out             dx,     ax
5565 
5566 		; Insure Map Mask is set to all planes
5567 			mov             ax,  0F02h      ; 0F sets all planes. 02 is Map Mask
5568 			mov             dx,     SC_INDEX
5569 			out             dx,     ax
5570 
5571 		; Set CX to the number of XBlocks to move per scan line
5572 			mov       cx,  [XDELTA]
5573 			shr             cx,  2
5574 
5575 		; Set BX to the number of scan lines to do
5576 			mov             bx,  [YDELTA]
5577 
5578 		; Set AX to scan line dif.
5579 			mov             ax,     [WLine_Offset]
5580 			sub             ax,  cx                 ; Scan size minus tile size
5581 
5582 		; Get the Screen Seg and put it in ES
5583 			mov             dx,  SCREEN_SEG
5584 			mov             es,     dx
5585 			mov             ds,     dx
5586 
5587 		; Save number of XBlocks (CX) in DX
5588 			mov             dx,  cx
5589 
5590 		; This section is for the MOVE ------------------------------
5591 		@@Rowloop:
5592 
5593 			rep  movsb
5594 
5595 		; Adjust for next iteration
5596 			add     si,     ax      ; Point DI to start of next line
5597 
5598 		; Re-load CX
5599 			mov  cx,  dx
5600 
5601 		; End of Rowloop.
5602 			dec       bx
5603 			jnz    @@Rowloop
5604 
5605 
5606 		; DONE!!!
5607 			pop    di si ds
5608 
5609 			pop       bp                    ; Return state
5610 			ret
5611 
5612 ENDP       _XReload_TileW
5613 
5614 
5615 ; ------------------------ _XDownload_TileS ---------------------------
5616 ; - This will "download" a tile from a store in video mem to system memory
5617 ; - This will not correctly download from an active screen!
5618 ; - WARNING!!! Only download one segments worth at a time!!!!
5619 ; -
5620 public  _XDownload_TileS
5621 
5622 PROC    _XDownload_TileS
5623 
5624 	ARG     STOREA:WORD, SIZEX:WORD, SIZEY:WORD, DEST:DWORD
5625 
5626 	push    bp
5627 	mov     bp,     sp              ; Save Stack frame
5628 
5629       ; Save regs
5630 	push    ds si di
5631 
5632       ; Set SI to the store position
5633 	mov     si,     [STOREA]
5634 	mov     bx,     si              ; Save in BX
5635 
5636       ; Load destination
5637 	les     di,     [DEST]
5638 
5639       ; Calculate bytes per plane and store in CX
5640 	mov     ax,     [SIZEX]
5641 	mul     [SIZEY]                 ; Total bytes
5642 	shr     ax,     2
5643 	mov     cx,     ax
5644 	mov     bp,     ax              ; Save in BP
5645 
5646      ; Set up store segment
5647 	mov     ax,     SCREEN_SEG
5648 	mov     ds,     ax
5649 
5650       ; Set up graphics controller for read page
5651 	mov     dx,     GC_INDEX
5652 	mov     al,     04h     ; Read map register
5653 	out     dx,     al
5654 	inc     dx
5655 
5656       ; Set AL to plane access
5657 	mov     al,     00h
5658 
5659       ; Set AH to planes left
5660 	mov     ah,     4
5661 
5662     ; This section is for the move ------------------------------
5663     @@PlaneLoop:
5664 
5665       ; Set MAP MASK
5666 	out     dx,     al
5667 
5668       ; Do the move
5669 	shr     cx,     1       ; Shift for word
5670 	rep     movsw
5671 	adc     cx,     0       ; Add 1(carry) to CX if dangling byte
5672 	rep     movsb           ; Write dangle if there
5673 
5674       ; Restore CX and source
5675 	mov     cx,     bp
5676 	mov     si,     bx
5677 
5678       ; !!End of Plane loop.
5679 	inc     al
5680 	dec     ah
5681 	jnz     @@PlaneLoop
5682 
5683       ; DONE!!!
5684 	pop     di si ds
5685 	pop     bp                      ; Return state
5686 	ret
5687 
5688 ENDP       _XDownload_TileS
5689 
5690 
5691 ; ------------------------ _XDownload_TileP ---------------------------
5692 ; - This will "download" a tile from the write page in video mem to system memory
5693 ; - WARNING!!! Only download one segments worth at a time!!!!
5694 ; -
5695 public  _XDownload_TileP
5696 
5697 PROC    _XDownload_TileP
5698 
5699 	ARG     STARTX:WORD, STARTY:WORD, SIZEX:WORD, SIZEY:WORD, DEST:DWORD
5700 
5701 	push    bp
5702 	mov     bp,     sp          ; Save Stack frame
5703 
5704       ; Save regs
5705 	push    ds si di
5706 
5707       ; Load DS.
5708 	ASSUME  ds:  @fardata
5709 	mov     ax,  @fardata
5710 	mov     ds,  ax             ; Set DS to fardata segment
5711 
5712       ; Set SI to start of rectangle on screen
5713 	mov     ax,  [WLine_Offset] ; Get line size
5714 	mul     [STARTY]            ; Find Y offset
5715 
5716 	mov     si,  [STARTX]       ; Find X offset value. Place in DI
5717 	push    si                  ; Save it
5718 	shr     si,  2
5719 
5720 	add     si,       ax             ; Add X and Y offsets
5721 	add     si,       [Write_Page]   ; Add in page offset
5722 	mov     [STARTX], si             ; Save SI
5723 
5724       ; Load destination
5725 	les     di,     [DEST]
5726 
5727       ; Calculate bytes per line and store in CX
5728 	mov     cx,     [SIZEX]
5729 	shr     cx,     1
5730 	shr     cx,     1               ; Total XBlocks
5731 
5732       ; Set [STARTY] to scan line dif.
5733 	mov     ax,       [WLine_Offset]
5734 	sub     ax,       cx            ; Scan size minus tile size
5735 	mov     [STARTY], ax
5736 
5737       ; Set up store segment
5738 	mov     ax,     SCREEN_SEG
5739 	mov     ds,     ax
5740 
5741       ; Set up graphics controller for read page
5742 	mov     dx,     GC_INDEX
5743 	mov     al,     04h     ; Read map register
5744 	out     dx,     al
5745 	inc     dx
5746 
5747       ; Set AL to plane access
5748 	pop     ax
5749 	and     al,     03h             ; Mask out plane selecting bits
5750 
5751       ; Save XBlocks per line (CL) in AH
5752 	mov     ah,     cl
5753 
5754       ; Set BX to number of lines to do
5755 	mov     bx,     [SIZEY]
5756 
5757       ; Set number of planes to do
5758 	mov     [SIZEX],  4
5759 
5760     ; This section is for the move ------------------------------
5761     @@PlaneLoop:
5762 
5763       ; Set READ MASK
5764 	out     dx,     al
5765 
5766       ; Steal dx to speed up add
5767 	mov     dx,     [STARTY]
5768 
5769     @@LineLoop:
5770       ; Do the move
5771 	shr     cx,     1       ; Shift for word
5772 	rep     movsw
5773 	adc     cx,     0       ; Add 1(carry) to CX if dangling byte
5774 	rep     movsb           ; Write dangle if there
5775 
5776       ; Adjust for next line
5777 	add     si,     dx      ; Next line
5778 	mov     cl,     ah      ; Reset items per line
5779 
5780       ; End of work for this plane?
5781 	dec     bx
5782 	jnz     @@LineLoop
5783 
5784       ; Transition back to plane 0?
5785 	inc     al
5786 	cmp     al,     4       ; Plane 3 is last valid
5787 	jne     @@Continue
5788 	mov     al,     0       ; Put back to planer 0
5789 	inc     [STARTX]        ; Move to next XBlock
5790 
5791     @@Continue:
5792       ; Adjust for another plane
5793 	mov     si,     [STARTX]        ; Reset source
5794 	mov     bx,     [SIZEY]         ; Reset number of lines
5795 
5796       ; Next plane?
5797 	mov     dx,     GC_INDEX+1      ; Restore DX
5798 	dec     [SIZEX]
5799 	jnz     @@PlaneLoop
5800 
5801       ; DONE!!!
5802 	pop     di si ds
5803 	pop     bp                      ; Return state
5804 	ret
5805 
5806 ENDP    _XDownload_TileP
5807 
5808 
5809 ; ------------------------ _XSet_Clip ---------------------------
5810 ; - This will set the clip boundries
5811 ; -
5812 public          _XSet_Clip
5813 
5814 PROC                    _XSet_Clip
5815 
5816 	ARG     LEFT:WORD, RIGHT:WORD, TOP:WORD, BOTTOM:WORD
5817 
5818 			push            bp
5819 			mov             bp,     sp              ; Save Stack frame
5820 
5821 		; Save regs
5822 			push            ds
5823 
5824 		; Load DS.
5825 			ASSUME  ds:  @fardata
5826 			mov             ax,  @fardata
5827 			mov             ds,  ax                 ; Set DS to fardata segment
5828 
5829 	; -- Load the values
5830 			mov             ax,            [LEFT]
5831 			mov             [ClipL],       ax
5832 			mov             ax,            [RIGHT]
5833 			mov             [ClipR],       ax
5834 			mov             ax,            [TOP]
5835 			mov             [ClipT],       ax
5836 			mov             ax,            [BOTTOM]
5837 			mov             [ClipB],       ax
5838 
5839 		; DONE!!!
5840 			pop    ds
5841 
5842 			pop       bp                    ; Return state
5843 			ret
5844 
5845 ENDP       _XSet_Clip
5846 
5847 
5848 SC_INDEX1   EQU 03C4h               ; Port number of VGA Sequencer Reg
5849 SC_INDEX2   EQU 03C5h               ; Port number of VGA Seqeuncer Data
5850 MAP_MASK    EQU 2                   ; Map Mask register index into Sequencer
5851 
5852 
5853 ; ------------------------ _XPut_ScaledBitmap ---------------------------
5854 ; - This will put a scaled bitmap to the screen.  It is clipped
5855 ; - The bitmap must be in linear form, not .PIX form.
5856 ; - BE SURE TO SET CLIP BOUNDRIES!!!
5857 public  _XPut_ScaledBitmap
5858 
5859 PROC    _XPut_ScaledBitmap
5860 
5861    ARG DESTX:WORD, DESTY:WORD, NEWX:WORD, NEWY:WORD, BITMAPX:WORD, BITMAPY:WORD, DATA:DWORD
5862 
5863  LOCAL DECIDEX:WORD, DECIDEY:WORD, CLIPX:WORD, CLIPY:WORD, SCAND:WORD = AUTOSIZE
5864 
5865 	push            bp
5866 	mov             bp,     sp              ; Save Stack frame
5867 	sub		sp,     AUTOSIZE
5868 
5869      ; Save regs
5870 	push            ds di si
5871 
5872      ; Load DS.
5873 	ASSUME  ds:  @fardata
5874 	mov     ax,  @fardata
5875 	mov     ds,  ax                 ; Set DS to fardata segment
5876 
5877      ; Dont draw less the two pixels a side
5878 	cmp     [NEWX], 2
5879 	jl      @@DONE
5880 	cmp     [NEWY], 2
5881 	jl      @@DONE
5882 
5883      ; Check clip bounds
5884 	mov     ax, [DESTY]
5885 	cmp     ax, [ClipB]
5886 	jg      @@DONE
5887 
5888 	add     ax, [NEWY]
5889 	dec     ax
5890 	cmp     ax, [ClipT]
5891 	jl      @@DONE
5892 
5893 	mov     ax, [DESTX]
5894 	mov     cx, [ClipR]
5895 	cmp     ax, [ClipR]
5896 	jg      @@DONE
5897 
5898 	add     ax, [NEWX]
5899 	dec     ax
5900 	cmp     ax, [ClipL]
5901 	jl      @@DONE
5902 
5903      ; init items
5904 	les     si, [DATA]     ; Load DS:SI
5905 
5906 	mov     ax, [NEWX]
5907 	mov     [CLIPX], ax
5908 
5909 	shl     ax,1           ; Init X decision
5910 	neg     ax
5911 	mov     [DECIDEX], ax
5912 
5913 	mov     ax, [NEWY]
5914 	mov     [CLIPY], ax
5915 
5916 	shl     ax,1           ; Init Y decision
5917 	neg     ax
5918 	mov     [DECIDEY], ax
5919 
5920      ; Check if we need to do top clip
5921 	movsx   eax, [ClipT]
5922 	mov     edx, eax
5923 	sub     dx,  [DESTY]
5924 	js      @@NoTopClip
5925 
5926 	mov     [DESTY], ax
5927 	sub     [CLIPY], dx
5928 	movsx   ecx, [BITMAPY]
5929 	imul    ecx, edx
5930 	mov     eax, ecx
5931 	mov     edx, 0
5932 	movsx   ebx, [NEWY]
5933 	idiv    ebx
5934 	movsx   edx, [BITMAPX]
5935 	imul    edx, eax
5936 	add     si,  dx
5937 	imul    eax, ebx
5938 	sub     ecx, eax
5939 	sub     ecx, ebx
5940 	shl     ecx, 1
5941 	mov     [DECIDEY], cx
5942 
5943    @@NoTopClip:
5944      ; Check if we need to do Bottom clip
5945 	mov     ax, [DESTY]
5946 	add     ax, [CLIPY]
5947 	dec     ax
5948 	cmp     ax, [ClipB]
5949 	jle     @@NoBottomClip
5950 
5951 	mov     ax, [ClipB]
5952 	sub     ax, [DESTY]
5953 	inc     ax
5954 	mov     [CLIPY], ax
5955 
5956    @@NoBottomClip:
5957      ; Check if we need to do Left clip
5958 	movsx   eax, [ClipL]
5959 	mov     edx, eax
5960 	sub     dx,  [DESTX]
5961 	js      @@NoLeftClip
5962 
5963 	mov     [DESTX], ax
5964 	sub     [CLIPX], dx
5965 	movsx   ecx, [BITMAPX]
5966 	imul    ecx, edx
5967 	mov     eax, ecx
5968 	mov     edx, 0
5969 	movsx   ebx, [NEWX]
5970 	idiv    ebx
5971 	add     si, ax
5972 	imul    eax, ebx
5973 	sub     ecx, eax
5974 	sub     ecx, ebx
5975 	shl     ecx, 1
5976 	mov     [DECIDEX], cx
5977 
5978    @@NoLeftClip:
5979      ; Check if we need to do Left clip
5980 	mov     ax, [DESTX]
5981 	add     ax, [CLIPX]
5982 	dec     ax
5983 	cmp     ax, [ClipR]
5984 	jle     @@NoClipRight
5985 
5986 	mov     ax, [ClipR]
5987 	sub     ax, [DESTX]
5988 	inc     ax
5989 	mov     [CLIPX], ax
5990 
5991    @@NoClipRight:
5992      ; Set DS:SI to write page
5993 	mov     ax,  [WLine_Offset] ; Get line size
5994 	mov     [SCAND], ax         ; Sae this nearer
5995 	mul     [DESTY]             ; Find Y offset
5996 	mov     di,  [DESTX]        ; Find X offset value. Place in DI
5997 	shr     di,  2
5998 	shr     di,  1
5999 	add     di,  ax             ; Add X and Y offsets
6000 	add     di,  [Write_Page]   ; Add in page offset
6001 
6002       ; Set up store segment
6003 	mov     ax,     SCREEN_SEG
6004 	mov     ds,     ax
6005 
6006      ; Set up Map mask
6007 	mov     dx, SC_INDEX
6008 	mov     al, MAP_MASK
6009 	out     dx, al
6010 
6011 	inc     dx
6012 	and     cx, 3
6013 	mov     al, 11h
6014 	shl     al, cl
6015 	out     dx, al
6016 
6017     @@RowLoop:
6018 	push    si
6019 	push    di
6020 	push    ax
6021 	push    bp
6022 
6023 	mov     ax, [CLIPY]
6024 	mov     bx, [DECIDEY]
6025 	mov     cx, [BITMAPX]
6026 	mov     dx, [BITMAPY]
6027 	shl     dx, 1
6028 	mov     bp, [NEWY]
6029 	shl     bp, 1
6030 	mov     ah, [es:si]
6031 
6032     @@ColumnLoop:
6033 	mov     [ds:di], ah
6034 	dec     al
6035 	jz      @@DONECOL
6036 	add     di, 80
6037 	add     bx, dx
6038 	js      @@ColumnLoop
6039 
6040     @@NewRow:
6041 	add     si, cx
6042 	sub     bx, bp
6043 	jns     @@NewRow
6044 	mov     ah, [es:si]
6045 	jmp     @@ColumnLoop
6046 
6047     @@DONECOL:
6048 	pop     bp
6049 	pop     ax
6050 	pop     di
6051 	pop     si
6052 
6053 	rol     al, 1
6054 	adc     di, 0
6055 	mov     dx, (SC_INDEX + 1)
6056 	out     dx, al
6057 
6058 	shl     cx, 1
6059 	mov     bx, [DECIDEX]
6060 	add     bx, cx
6061 	js      @@NextCol
6062 	mov     dx, [NEWX]
6063 	shl     dx, 1
6064     @@NewCol:
6065 	inc     si
6066 	sub     bx, dx
6067 	jns     @@NewCol
6068     @@NextCol:
6069 	mov     [DECIDEX], bx
6070 	dec     [CLIPX]
6071 	jnz     @@RowLoop
6072 
6073     @@DONE:
6074     ; DONE!!!
6075 	pop    si di ds
6076 
6077 	mov    sp,  bp
6078 	pop    bp                    ; Return state
6079 	ret
6080 
6081 ENDP    _XPut_ScaledBitmap
6082 
6083 
6084 ENDS
6085 
6086 END