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