Annotation of ntddk/src/video/displays/vga/i386/alignblt.asm, revision 1.1

1.1     ! root        1: ;---------------------------Module-Header------------------------------;
        !             2: ; Module Name: alignblt.asm
        !             3: ;
        !             4: ; Copyright (c) 1992 Microsoft Corporation
        !             5: ;-----------------------------------------------------------------------;
        !             6: 
        !             7: ;-----------------------------------------------------------------------;
        !             8: ; VOID vAlignedSrcCopy(PDEVSURF pdsurf, RECTL * prcldst, PPOINTL * pptlsrc,
        !             9: ;                      INT icopydir);
        !            10: ; Input:
        !            11: ;  pdsurf - surface on which to copy
        !            12: ;  prcldest - pointer to destination rectangle
        !            13: ;  pptlsrc - pointer to source upper left corner
        !            14: ;  icopydir - direction in which copy must proceed to avoid overlap problems
        !            15: ;             and synchronize with the clip enumeration visually, according to
        !            16: ;             constants CD_RIGHTDOWN, CD_LEFTDOWN, CD_RIGHTUP, and CD_LEFTUP in
        !            17: ;             WINDDI.H
        !            18: ;
        !            19: ; Performs accelarated aligned SRCCOPY VGA-to-VGA blts.
        !            20: ;
        !            21: ;-----------------------------------------------------------------------;
        !            22: ;
        !            23: ; Note: Assumes all rectangles have positive heights and widths. Will not
        !            24: ; work properly if this is not the case.
        !            25: ;
        !            26: ;-----------------------------------------------------------------------;
        !            27: 
        !            28:         comment $
        !            29: 
        !            30: The overall approach of this module for each rectangle to copy is:
        !            31: 
        !            32: 1) Precalculate the masks and whole byte widths, and determine which of
        !            33: partial left edge, partial right edge, and whole middle bytes are required
        !            34: for this copy.
        !            35: 
        !            36: 2) Set up the starting pointers for each of the areas (left, whole middle,
        !            37: right), the start and stop scan lines, the copying direction (left-to-right
        !            38: or right-to-left, and top-to-bottom or bottom-to-top), the threading
        !            39: (sequence of calls required to do the left/whole/right components in the
        !            40: proper sequence), based on the passed-in copy direction, which in turn is
        !            41: dictated by the nature of the overlap between the source and destination.
        !            42: 
        !            43: 3) Execute a loop, based on adapter type (2 R/W windows, 1R/1W window,
        !            44: 1 R/W window, unbanked), that sequences through the intersection of each
        !            45: bank with the source and destination rectangles in the proper direction
        !            46: (top-to-bottom or bottom-to-top, based on the passed-in copy direction),
        !            47: and performs the copy in each such rectangle. The threading vector is used
        !            48: to call the required routines (copy left/whole/right bytes). For 1 R/W and
        !            49: 1R/1W adapters, there is a second threading vector that is called when the
        !            50: source and the destination are both adequately (for the copy purposes)
        !            51: addressable simultaneously (because they're in the same bank), so there's
        !            52: no need to copy through a temp buffer. Obviously, we want to avoid the temp
        !            53: buffer whenever we can, because it's much slower and doesn't let us take
        !            54: advantage of the VGA's hardware.
        !            55: 
        !            56: Note: 1 R/W and 1R/1W edges are copied through a temporary buffer. However,
        !            57: each plane's bytes are not stored in the corresponding plane's temp buffer, but
        !            58: rather consecutively in the plane 0 temp buffer. This is to reduce page
        !            59: faulting, and also so that 1R/1W adapters only need a temp buffer large enough
        !            60: to hold 4*tallest bank bytes (2K will do here, but nalgnblt.asm needs 4K).
        !            61: 1 R/W adapters still copy whole bytes through the full temp buffer, using all
        !            62: four planes' temp buffers, so they require a temp buffer big enough to hold a
        !            63: full bank (256K will do).
        !            64: 
        !            65:         commend $
        !            66: 
        !            67: ;-----------------------------------------------------------------------;
        !            68: ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want loops in
        !            69: ; this module unrolled. For example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8
        !            70: ; times unrolling. This is the only thing you need to change to control
        !            71: ; unrolling. Note: does not affect loops that process in chunks, like edge
        !            72: ; loops.
        !            73: 
        !            74: LOOP_UNROLL_SHIFT equ 2
        !            75: 
        !            76: ;-----------------------------------------------------------------------;
        !            77: ; Maximum # of edge bytes to process before switching to next plane. Larger
        !            78: ; means faster, but there's more potential for flicker, since the raster scan
        !            79: ; has a better chance of catching bytes that have changed in some planes but
        !            80: ; not all planes.
        !            81: 
        !            82: EDGE_CHUNK_SIZE equ     16
        !            83: 
        !            84: ;-----------------------------------------------------------------------;
        !            85: ; Macro to push the current threading sequence (string of routine calls) on the
        !            86: ; stack, then jump to the first threading entry. The threading pointer can be
        !            87: ; specified, or defaults to pCurrentThread. The return address can be
        !            88: ; immediately after the JMP, or can be specified.
        !            89: 
        !            90: THREAD_AND_START macro THREADING,RETURN_ADDR
        !            91:         local   push_base, return_address
        !            92: 
        !            93: ifb <&RETURN_ADDR&>
        !            94:         push    offset return_address   ;after all the threaded routines, we
        !            95:                                         ; return here
        !            96: else
        !            97:         push    offset &RETURN_ADDR&    ;return here
        !            98: endif
        !            99: 
        !           100: ifb <&THREADING&>
        !           101:         mov     eax,pCurrentThread
        !           102: else
        !           103:         mov     eax,&THREADING&
        !           104: endif
        !           105: 
        !           106:         mov     ecx,[eax]               ;# of routines to thread (at least 1)
        !           107:         lea     ecx,[ecx*2+ecx]         ;pushes below are 3 bytes each
        !           108:         mov     edx,offset push_base+3
        !           109:         sub     edx,ecx
        !           110:         jmp     edx                     ;branch to push or jmp below
        !           111: 
        !           112: ; Push the threading addresses on to the stack, so routines perform the
        !           113: ; threading as they return.
        !           114: 
        !           115:         push    dword ptr [eax+12]       ;3 byte instruction
        !           116:         push    dword ptr [eax+8]
        !           117: push_base:
        !           118:         jmp     dword ptr [eax+4]        ;jump to the first threaded routine
        !           119: 
        !           120:         align   4
        !           121: return_address:
        !           122:         endm
        !           123: 
        !           124: ;-----------------------------------------------------------------------;
        !           125: 
        !           126:                 .386
        !           127: 
        !           128: ifndef  DOS_PLATFORM
        !           129:         .model  small,c
        !           130: else
        !           131: ifdef   STD_CALL
        !           132:         .model  small,c
        !           133: else
        !           134:         .model  small,pascal
        !           135: endif;  STD_CALL
        !           136: endif;  DOS_PLATFORM
        !           137: 
        !           138:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        !           139:         assume fs:nothing,gs:nothing
        !           140: 
        !           141:         .xlist
        !           142:         include stdcall.inc             ;calling convention cmacros
        !           143:         include i386\egavga.inc
        !           144:         include i386\strucs.inc
        !           145:         include i386\unroll.inc
        !           146:         include i386\ropdefs.inc
        !           147: 
        !           148:         .list
        !           149: 
        !           150: ;-----------------------------------------------------------------------;
        !           151: 
        !           152:         .data
        !           153: 
        !           154: ; Threads for stringing together left, whole byte, and right operations
        !           155: ; in various orders, both using a temp buffer and not. Data format is:
        !           156: ;
        !           157: ; DWORD +0 = # of calls in thread (1, 2, or 3)
        !           158: ;       +4 = first call (required)
        !           159: ;       +8 = second call (optional)
        !           160: ;      +12 = third call (optional)
        !           161: 
        !           162:         align   4
        !           163: 
        !           164: ; Copies not involving the temp buffer.
        !           165: 
        !           166: Thread_L        dd      1
        !           167:                 dd      copy_left_edge
        !           168: 
        !           169: Thread_W        dd      1
        !           170:                 dd      copy_whole_bytes
        !           171: 
        !           172: Thread_R        dd      1
        !           173:                 dd      copy_right_edge
        !           174: 
        !           175: Thread_LR       dd      2
        !           176:                 dd      copy_left_edge
        !           177:                 dd      copy_right_edge
        !           178: 
        !           179: Thread_RL       dd      2
        !           180:                 dd      copy_right_edge
        !           181:                 dd      copy_left_edge
        !           182: 
        !           183: Thread_LW       dd      2
        !           184:                 dd      copy_left_edge
        !           185:                 dd      copy_whole_bytes
        !           186: 
        !           187: Thread_WL       dd      2
        !           188:                 dd      copy_whole_bytes
        !           189:                 dd      copy_left_edge
        !           190: 
        !           191: Thread_WR       dd      2
        !           192:                 dd      copy_whole_bytes
        !           193:                 dd      copy_right_edge
        !           194: 
        !           195: Thread_RW       dd      2
        !           196:                 dd      copy_right_edge
        !           197:                 dd      copy_whole_bytes
        !           198: 
        !           199: Thread_LWR      dd      3
        !           200:                 dd      copy_left_edge
        !           201:                 dd      copy_whole_bytes
        !           202:                 dd      copy_right_edge
        !           203: 
        !           204: Thread_RWL      dd      3
        !           205:                 dd      copy_right_edge
        !           206:                 dd      copy_whole_bytes
        !           207:                 dd      copy_left_edge
        !           208: 
        !           209: ; Copies involving the temp buffer.
        !           210: 
        !           211: Thread_Lb       dd      1
        !           212:                 dd      copy_left_edge_via_buffer
        !           213: 
        !           214: Thread_Wb       dd      1
        !           215:                 dd      copy_whole_bytes_via_buffer
        !           216: 
        !           217: Thread_Rb       dd      1
        !           218:                 dd      copy_right_edge_via_buffer
        !           219: 
        !           220: Thread_LbRb     dd      2
        !           221:                 dd      copy_left_edge_via_buffer
        !           222:                 dd      copy_right_edge_via_buffer
        !           223: 
        !           224: Thread_RbLb     dd      2
        !           225:                 dd      copy_right_edge_via_buffer
        !           226:                 dd      copy_left_edge_via_buffer
        !           227: 
        !           228: Thread_LbW      dd      2
        !           229:                 dd      copy_left_edge_via_buffer
        !           230:                 dd      copy_whole_bytes
        !           231: 
        !           232: Thread_LbWb     dd      2
        !           233:                 dd      copy_left_edge_via_buffer
        !           234:                 dd      copy_whole_bytes_via_buffer
        !           235: 
        !           236: Thread_WLb      dd      2
        !           237:                 dd      copy_whole_bytes
        !           238:                 dd      copy_left_edge_via_buffer
        !           239: 
        !           240: Thread_WbLb     dd      2
        !           241:                 dd      copy_whole_bytes_via_buffer
        !           242:                 dd      copy_left_edge_via_buffer
        !           243: 
        !           244: Thread_WRb      dd      2
        !           245:                 dd      copy_whole_bytes
        !           246:                 dd      copy_right_edge_via_buffer
        !           247: 
        !           248: Thread_WbRb     dd      2
        !           249:                 dd      copy_whole_bytes_via_buffer
        !           250:                 dd      copy_right_edge_via_buffer
        !           251: 
        !           252: Thread_RbW      dd      2
        !           253:                 dd      copy_right_edge_via_buffer
        !           254:                 dd      copy_whole_bytes
        !           255: 
        !           256: Thread_RbWb     dd      2
        !           257:                 dd      copy_right_edge_via_buffer
        !           258:                 dd      copy_whole_bytes_via_buffer
        !           259: 
        !           260: Thread_LbWRb    dd      3
        !           261:                 dd      copy_left_edge_via_buffer
        !           262:                 dd      copy_whole_bytes
        !           263:                 dd      copy_right_edge_via_buffer
        !           264: 
        !           265: Thread_LbWbRb   dd      3
        !           266:                 dd      copy_left_edge_via_buffer
        !           267:                 dd      copy_whole_bytes_via_buffer
        !           268:                 dd      copy_right_edge_via_buffer
        !           269: 
        !           270: Thread_RbWLb    dd      3
        !           271:                 dd      copy_right_edge_via_buffer
        !           272:                 dd      copy_whole_bytes
        !           273:                 dd      copy_left_edge_via_buffer
        !           274: 
        !           275: Thread_RbWbLb   dd      3
        !           276:                 dd      copy_right_edge_via_buffer
        !           277:                 dd      copy_whole_bytes_via_buffer
        !           278:                 dd      copy_left_edge_via_buffer
        !           279: 
        !           280: ;-----------------------------------------------------------------------;
        !           281: ; Table of thread selection for various horizontal copy directions, with
        !           282: ; the look-up index a 4-bit field as follows:
        !           283: ;
        !           284: ; Bit 3 = 1 if left-to-right copy, 0 if right-to-left
        !           285: ; Bit 2 = 1 if left edge must be copied
        !           286: ; Bit 1 = 1 if whole bytes must be copied
        !           287: ; Bit 0 = 1 if right edge must be copied
        !           288: ;
        !           289: ; This is used for all cases where both the source and destination are
        !           290: ; simultaneously addressable for our purposes, so there's no need to go
        !           291: ; through the temp buffer (unbanked, 2 R/W, and sometimes for 1 R/W and 1R/1W).
        !           292: 
        !           293: MasterThreadTable label dword
        !           294:                                 ;right-to-left
        !           295:         dd      0               ;<not used>
        !           296:         dd      Thread_R        ;R->L, R
        !           297:         dd      Thread_W        ;R->L, W
        !           298:         dd      Thread_RW       ;R->L, RW
        !           299:         dd      Thread_L        ;R->L, L
        !           300:         dd      Thread_RL       ;R->L, RL
        !           301:         dd      Thread_WL       ;R->L, WL
        !           302:         dd      Thread_RWL      ;R->L, RWL
        !           303:                                 ;left-to-right
        !           304:         dd      0               ;<not used>
        !           305:         dd      Thread_R        ;L->R, R
        !           306:         dd      Thread_W        ;L->R, W
        !           307:         dd      Thread_WR       ;L->R, WR
        !           308:         dd      Thread_L        ;L->R, L
        !           309:         dd      Thread_LR       ;L->R, LR
        !           310:         dd      Thread_LW       ;L->R, LW
        !           311:         dd      Thread_LWR      ;L->R, LWR
        !           312: 
        !           313: 
        !           314: ; Table of thread selection for various adapter types and horizontal
        !           315: ; copy directions, with the look-up index a 6-bit field as follows:
        !           316: ;
        !           317: ; Bit 5 = adapter type high bit
        !           318: ; Bit 4 = adapter type low bit
        !           319: ; Bit 3 = 1 if left-to-right copy, 0 if right-to-left
        !           320: ; Bit 2 = 1 if left edge must be copied
        !           321: ; Bit 1 = 1 if whole bytes must be copied
        !           322: ; Bit 0 = 1 if right edge must be copied
        !           323: ;
        !           324: ; This is used for all cases where the source and destination are not both
        !           325: ; simultaneously addressable for our purposes, so we need to go through the
        !           326: ; temp buffer (only for 1 R/W and 1R/1W, and only sometimes).
        !           327: 
        !           328: MasterThreadTableViaBuffer label dword
        !           329:                                 ;unbanked (no need for buffer)
        !           330:                                 ;right-to-left
        !           331:         dd      0               ;<not used>
        !           332:         dd      Thread_R        ;R->L, R
        !           333:         dd      Thread_W        ;R->L, W
        !           334:         dd      Thread_RW       ;R->L, RW
        !           335:         dd      Thread_L        ;R->L, L
        !           336:         dd      Thread_RL       ;R->L, RL
        !           337:         dd      Thread_WL       ;R->L, WL
        !           338:         dd      Thread_RWL      ;R->L, RWL
        !           339:                                 ;left-to-right
        !           340:         dd      0               ;<not used>
        !           341:         dd      Thread_R        ;L->R, R
        !           342:         dd      Thread_W        ;L->R, W
        !           343:         dd      Thread_WR       ;L->R, WR
        !           344:         dd      Thread_L        ;L->R, L
        !           345:         dd      Thread_LR       ;L->R, LR
        !           346:         dd      Thread_LW       ;L->R, LW
        !           347:         dd      Thread_LWR      ;L->R, LWR
        !           348: 
        !           349:                                 ;1 R/W banking window (everything goes through
        !           350:                                 ;                       buffer)
        !           351:                                 ;right-to-left
        !           352:         dd      0               ;<not used>
        !           353:         dd      Thread_Rb       ;R->L, R
        !           354:         dd      Thread_Wb       ;R->L, W
        !           355:         dd      Thread_RbWb     ;R->L, RW
        !           356:         dd      Thread_Lb       ;R->L, L
        !           357:         dd      Thread_RbLb     ;R->L, RL
        !           358:         dd      Thread_WbLb     ;R->L, WL
        !           359:         dd      Thread_RbWbLb   ;R->L, RWL
        !           360:                                 ;left-to-right
        !           361:         dd      0               ;<not used>
        !           362:         dd      Thread_Rb       ;L->R, R
        !           363:         dd      Thread_Wb       ;L->R, W
        !           364:         dd      Thread_WbRb     ;L->R, WR
        !           365:         dd      Thread_Lb       ;L->R, L
        !           366:         dd      Thread_LbRb     ;L->R, LR
        !           367:         dd      Thread_LbWb     ;L->R, LW
        !           368:         dd      Thread_LbWbRb   ;L->R, LWR
        !           369: 
        !           370:                                 ;1R/1W banking window (edge go through buffer)
        !           371:                                 ;right-to-left
        !           372:         dd      0               ;<not used>
        !           373:         dd      Thread_Rb       ;R->L, R
        !           374:         dd      Thread_W        ;R->L, W
        !           375:         dd      Thread_RbW      ;R->L, RW
        !           376:         dd      Thread_Lb       ;R->L, L
        !           377:         dd      Thread_RbLb     ;R->L, RL
        !           378:         dd      Thread_WLb      ;R->L, WL
        !           379:         dd      Thread_RbWLb    ;R->L, RWL
        !           380:                                 ;left-to-right
        !           381:         dd      0               ;<not used>
        !           382:         dd      Thread_Rb       ;L->R, R
        !           383:         dd      Thread_W        ;L->R, W
        !           384:         dd      Thread_WRb      ;L->R, WR
        !           385:         dd      Thread_Lb       ;L->R, L
        !           386:         dd      Thread_LbRb     ;L->R, LR
        !           387:         dd      Thread_LbW      ;L->R, LW
        !           388:         dd      Thread_LbWRb    ;L->R, LWR
        !           389: 
        !           390:                                 ;2 R/W banking window (no need for buffer)
        !           391:                                 ;right-to-left
        !           392:         dd      0               ;<not used>
        !           393:         dd      Thread_R        ;R->L, R
        !           394:         dd      Thread_W        ;R->L, W
        !           395:         dd      Thread_RW       ;R->L, RW
        !           396:         dd      Thread_L        ;R->L, L
        !           397:         dd      Thread_RL       ;R->L, RL
        !           398:         dd      Thread_WL       ;R->L, WL
        !           399:         dd      Thread_RWL      ;R->L, RWL
        !           400:                                 ;left-to-right
        !           401:         dd      0               ;<not used>
        !           402:         dd      Thread_R        ;L->R, R
        !           403:         dd      Thread_W        ;L->R, W
        !           404:         dd      Thread_WR       ;L->R, WR
        !           405:         dd      Thread_L        ;L->R, L
        !           406:         dd      Thread_LR       ;L->R, LR
        !           407:         dd      Thread_LW       ;L->R, LW
        !           408:         dd      Thread_LWR      ;L->R, LWR
        !           409: 
        !           410: 
        !           411: ; Amount to shift adapter type field left for use in MasterThreadTableViaBuffer.
        !           412: 
        !           413: ADAPTER_FIELD_SHIFT     equ     4
        !           414: 
        !           415: ; Mask for setting left-to-right bit to "left-to-right true" for use in both
        !           416: ; MasterThread tables.
        !           417: 
        !           418: LEFT_TO_RIGHT_FIELD_SET equ     1000b
        !           419: 
        !           420: 
        !           421: ; Table of top-to-bottom loops for adapter types.
        !           422: 
        !           423:         align   4
        !           424: TopToBottomLoopTable label dword
        !           425:         dd      top_to_bottom_2RW       ;unbanked is same as 2RW
        !           426:         dd      top_to_bottom_1RW
        !           427:         dd      top_to_bottom_1R1W
        !           428:         dd      top_to_bottom_2RW
        !           429: 
        !           430: 
        !           431: ; Table of bottom-to-top loops for adapter types.
        !           432: 
        !           433:         align   4
        !           434: BottomToTopLoopTable label dword
        !           435:         dd      bottom_to_top_2RW       ;unbanked is same as 2RW
        !           436:         dd      bottom_to_top_1RW
        !           437:         dd      bottom_to_top_1R1W
        !           438:         dd      bottom_to_top_2RW
        !           439: 
        !           440: 
        !           441: ; Table of routines for setting up to copy in various directions.
        !           442: 
        !           443:         align   4
        !           444: SetUpForCopyDirection   label   dword
        !           445:         dd      left_to_right_top_to_bottom     ;CD_RIGHTDOWN
        !           446:         dd      right_to_left_top_to_bottom     ;CD_LEFTDOWN
        !           447:         dd      left_to_right_bottom_to_top     ;CD_RIGHTUP
        !           448:         dd      right_to_left_bottom_to_top     ;CD_LEFTUP
        !           449: 
        !           450: ;-----------------------------------------------------------------------;
        !           451: ; Left edge clip masks for intrabyte start addresses 0 through 7.
        !           452: ; Whole byte cases are flagged as 0ffh.
        !           453: 
        !           454: jLeftMaskTable  label   byte
        !           455:         db      0ffh,07fh,03fh,01fh,00fh,007h,003h,001h
        !           456: 
        !           457: ;-----------------------------------------------------------------------;
        !           458: ; Right edge clip masks for intrabyte end addresses (non-inclusive)
        !           459: ; 0 through 7. Whole byte cases are flagged as 0ffh.
        !           460: 
        !           461: jRightMaskTable label   byte
        !           462:         db      0ffh,080h,0c0h,0e0h,0f0h,0f8h,0fch,0feh
        !           463: 
        !           464: ;-----------------------------------------------------------------------;
        !           465: 
        !           466:         .code
        !           467: 
        !           468: _TEXT$03   SEGMENT DWORD USE32 PUBLIC 'CODE'
        !           469:            ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        !           470: 
        !           471: ;-----------------------------------------------------------------------;
        !           472: 
        !           473: cProc   vAlignedSrcCopy,16,<        \
        !           474:         uses    esi edi ebx,    \
        !           475:         pdsurf: ptr DEVSURF,    \
        !           476:         prcldest : ptr RECTL,   \
        !           477:         pptlsrc : ptr POINTL,   \
        !           478:         icopydir : dword
        !           479: 
        !           480:         local   culWholeBytesWidth : dword ;# of bytes to copy across each scan
        !           481:         local   ulBlockHeight : dword   ;# of scans to copy per bank block
        !           482:         local   ulWholeScanDelta : dword;offset from end of one whole bytes
        !           483:                                         ; scan to start of next
        !           484:         local   ulWholeBytesSrc : dword ;offset in bitmap of first source whole
        !           485:                                         ; byte to copy from
        !           486:         local   ulWholeBytesDest : dword;offset in bitmap of first source whole
        !           487:                                         ; byte to copy to
        !           488:         local   ulLeftEdgeSrc : dword   ;offset in bitmap of first source left
        !           489:                                         ; edge byte to copy from
        !           490:         local   ulLeftEdgeDest : dword  ;offset in bitmap of first dest left
        !           491:                                         ; edge byte to copy to
        !           492:         local   ulRightEdgeSrc : dword  ;offset in bitmap of first source right
        !           493:                                         ; edge byte to copy from
        !           494:         local   ulRightEdgeDest : dword ;offset in bitmap of first dest right
        !           495:                                         ; edge byte to copy to
        !           496:         local   ulNextScan : dword      ;width of scan, in bytes
        !           497:         local   jLeftMask : dword       ;left edge clip mask
        !           498:         local   jRightMask : dword      ;right edge clip mask
        !           499:         local   culTempCount : dword    ;handy temporary counter
        !           500:         local   pTempEntry : dword      ;temporary storage for vector into
        !           501:                                         ; unrolled loop
        !           502:         local   pTempPlane : dword      ;pointer to storage in temp buffer for
        !           503:                                         ; edge bytes (which are stored
        !           504:                                         ; consecutively, not in each plane's
        !           505:                                         ; temp buffer, to reduce possible page
        !           506:                                         ; faulting
        !           507:         local   ppTempPlane0 : dword    ;pointer to pointer to storage in temp
        !           508:                                         ; buffer for plane 0, immediately
        !           509:                                         ; preceded by storage for planes 1, 2,
        !           510:                                         ; and 3
        !           511:         local   ppTempPlane3 : dword    ;like above, but for plane 3
        !           512:         local   ulOffsetInBank : dword  ;offset relative to bank start
        !           513:         local   pSrcAddr : dword        ;working pointer to first source
        !           514:                                         ; byte to copy from
        !           515:         local   pDestAddr : dword       ;working pointer to first dest
        !           516:                                         ; byte to copy to
        !           517:         local   ulCurrentJustification:dword ;justification used to map in
        !           518:                                              ; banks; top for top to bottom
        !           519:                                              ; copies, bottom for bottom to top
        !           520:         local   ulCurrentSrcScan :dword ;scan line used to map in current
        !           521:                                         ; source bank
        !           522:         local   ulCurrentDestScan:dword ;scan line used to map in current dest
        !           523:                                         ; bank
        !           524:         local   ulLastDestScan :dword   ;scan in target rect at which we stop
        !           525:                                         ; advancing through banks
        !           526:         local   pCurrentThread : dword  ;pointer to data describing the
        !           527:                                         ; threaded calls to be performed to
        !           528:                                         ; perform the current copy
        !           529:         local   pCurrentThreadViaBuffer:dword
        !           530:                                         ;pointer to data describing the
        !           531:                                         ; threaded calls to be performed to
        !           532:                                         ; perform the current copy in the case
        !           533:                                         ; where the source and destination are
        !           534:                                         ; not simultaneously adequately
        !           535:                                         ; accessible, so the copy has to go
        !           536:                                         ; through a temp buffer (used only for
        !           537:                                         ; 1 R/W and 1R/1W banking)
        !           538:         local   ulAdapterType : dword   ;adapter type code, per VIDEO_BANK_TYPE
        !           539:         local   ulLWRType : dword       ;whether left edge, whole bytes, and
        !           540:                                         ; right edge are involved in the
        !           541:                                         ; current operation;
        !           542:                                         ; bit 2 = 1 if left edge involved
        !           543:                                         ; bit 1 = 1 if whole bytes involved
        !           544:                                         ; bit 0 = 1 if right edge involved
        !           545:         local   ulLeftEdgeAdjust :dword ;used to bump the whole bytes start
        !           546:                                         ; address past the left edge when the
        !           547:                                         ; left edge is partial
        !           548: 
        !           549: ;-----------------------------------------------------------------------;
        !           550: 
        !           551: ; Set pointers to temp buffer plane pointers (used only by 1 R/W and 1R/1W
        !           552: ; adapters), and other rectangle-independent variables.
        !           553: 
        !           554:         mov     esi,pdsurf
        !           555:         mov     eax,[esi].dsurf_pvBankBufferPlane0
        !           556:         mov     pTempPlane,eax
        !           557:         lea     eax,[esi].dsurf_pvBankBufferPlane0
        !           558:         mov     ppTempPlane0,eax
        !           559:         lea     eax,[esi].dsurf_pvBankBufferPlane3
        !           560:         mov     ppTempPlane3,eax
        !           561: 
        !           562:         mov     eax,[esi].dsurf_vbtBankingType
        !           563:         mov     ulAdapterType,eax
        !           564: 
        !           565: ; Copy the rectangle.
        !           566: 
        !           567:         call    copy_rect
        !           568: 
        !           569: ;-----------------------------------------------------------------------;
        !           570: ; Set the VGA registers back to their default state.
        !           571: ;-----------------------------------------------------------------------;
        !           572: 
        !           573:         mov     edx,VGA_BASE + GRAF_ADDR
        !           574:         mov     eax,(0ffh shl 8) + GRAF_BIT_MASK
        !           575:         out     dx,ax           ;enable bit mask for all bits
        !           576: 
        !           577:         mov     dl,SEQ_DATA
        !           578:         mov     al,MM_ALL
        !           579:         out     dx,al           ;enable writes to all planes
        !           580: 
        !           581:         cld                     ;restore default direction flag
        !           582: 
        !           583:         cRet    vAlignedSrcCopy ;done
        !           584: 
        !           585: 
        !           586: ;***********************************************************************;
        !           587: ;
        !           588: ; Copies the specified rectangle.
        !           589: ;
        !           590: ;***********************************************************************;
        !           591: 
        !           592:         align   4
        !           593: copy_rect:
        !           594: 
        !           595: ; Set up masks and whole bytes count, and build left/whole/right index
        !           596: ; indicating which of those parts are involved in the copy.
        !           597: 
        !           598:         mov     edi,prcldest            ;point to rectangle to copy
        !           599: 
        !           600:         mov     ebx,[edi].xRight        ;right edge of fill (non-inclusive)
        !           601:         mov     ecx,ebx
        !           602:         and     ecx,0111b               ;intrabyte address of right edge
        !           603:         mov     ah,jRightMaskTable[ecx] ;right edge mask
        !           604: 
        !           605:         mov     esi,[edi].xLeft         ;left edge of fill (inclusive)
        !           606:         mov     ecx,esi
        !           607:         shr     ecx,3                   ;/8 for start offset from left edge
        !           608:                                         ; of scan line
        !           609:         sub     ebx,esi                 ;width in pixels of fill
        !           610: 
        !           611:         and     esi,0111b               ;intrabyte address of left edge
        !           612:         mov     al,jLeftMaskTable[esi]  ;left edge mask
        !           613: 
        !           614:         dec     ebx                     ;make inclusive on right
        !           615:         add     ebx,esi                 ;inclusive width, starting counting at
        !           616:                                         ; the beginning of the left edge byte
        !           617:         shr     ebx,3                   ;width of fill in bytes touched - 1
        !           618:         jnz     short more_than_1_byte  ;more than 1 byte is involved
        !           619: 
        !           620: ; Only one byte will be affected. Combine first/last masks.
        !           621: 
        !           622:         and     al,ah                   ;we'll use first byte mask only
        !           623:         xor     ah,ah                   ;want last byte mask to be 0 to
        !           624:                                         ; indicate right edge not involved
        !           625:         inc     ebx                     ;so there's one count to subtract below
        !           626:                                         ; if this isn't a whole edge byte
        !           627: more_than_1_byte:
        !           628: 
        !           629: ; If all pixels in the left edge are altered, combine the first byte into the
        !           630: ; whole byte count, because we can handle solid edge bytes faster as part of
        !           631: ; the whole bytes. Ditto for the right edge.
        !           632: 
        !           633:         sub     ecx,ecx                 ;edge whole-status accumulator
        !           634:         cmp     al,-1                   ;is left edge a whole byte or partial?
        !           635:         adc     ecx,ecx                 ;ECX=1 if left edge partial, 0 if whole
        !           636:         sub     ebx,ecx                 ;if left edge partial, deduct it from
        !           637:                                         ; the whole bytes count
        !           638:         mov     ulLeftEdgeAdjust,ecx    ;for skipping over the left edge if
        !           639:                                         ; it's partial when pointing to the
        !           640:                                         ; whole bytes
        !           641:         and     ah,ah                   ;is right edge mask 0, meaning this
        !           642:                                         ; fill is only 1 byte wide?
        !           643:         jz      short save_masks        ;yes, no need to do anything
        !           644:         or      ecx,40h                 ;assume there's a partial right edge
        !           645:         cmp     ah,-1                   ;is right edge a whole byte or partial?
        !           646:         jnz     short save_masks        ;partial
        !           647:                                         ;bit 1=0 if left edge partial, 1 whole
        !           648:         inc     ebx                     ;if right edge whole, include it in the
        !           649:                                         ; whole bytes count
        !           650:         and     ecx,not 40h             ;there's no partial right edge
        !           651: save_masks:
        !           652:         cmp     ebx,1                   ;do we have any whole bytes?
        !           653:         cmc                             ;CF set if whole byte count > 0
        !           654:         adc     ecx,ecx                 ;if any whole bytes, set whole bytes
        !           655:                                         ; bit in left/whole/right accumulator
        !           656:         rol     cl,1                    ;align the left/whole/right bits
        !           657:         mov     ulLWRType,ecx           ;save left/whole/right status
        !           658: 
        !           659:         mov     byte ptr jLeftMask,al   ;save left and right clip masks
        !           660:         mov     byte ptr jRightMask,ah
        !           661:         mov     culWholeBytesWidth,ebx  ;save # of whole bytes
        !           662: 
        !           663: ; Copy the rectangle in the specified direction.
        !           664: 
        !           665:         mov     eax,icopydir
        !           666:         jmp     SetUpForCopyDirection[eax*4]
        !           667: 
        !           668: 
        !           669: ;***********************************************************************;
        !           670: ;
        !           671: ; The following routines set up to handle the four possible copy
        !           672: ; directions.
        !           673: ;
        !           674: ;***********************************************************************;
        !           675: 
        !           676: 
        !           677: ;-----------------------------------------------------------------------;
        !           678: ; Set-up code for left-to-right, top-to-bottom copies.
        !           679: ;-----------------------------------------------------------------------;
        !           680: 
        !           681:         align   4
        !           682: left_to_right_top_to_bottom:
        !           683: 
        !           684:         cld                             ;we'll copy left to right
        !           685: 
        !           686:         mov     esi,pdsurf
        !           687:         mov     eax,[esi].dsurf_lNextScan
        !           688:         mov     ulNextScan,eax          ;copy top to bottom
        !           689:         sub     eax,culWholeBytesWidth  ;offset from end of one whole byte scan
        !           690:         mov     ulWholeScanDelta,eax    ; to start of next
        !           691: 
        !           692:         mov     esi,ulLWRType           ;3-bit flag field for left, whole, and
        !           693:                                         ; right involvement in operation
        !           694:         or      esi,LEFT_TO_RIGHT_FIELD_SET   ;add left-to-right into the index
        !           695:         mov     eax,MasterThreadTable[esi*4]
        !           696:         mov     pCurrentThread,eax      ;threading when no buffering is needed
        !           697:         mov     edx,ulAdapterType
        !           698:         shl     edx,ADAPTER_FIELD_SHIFT
        !           699:         or      esi,edx                 ;factor adapter type into the index
        !           700:         mov     eax,MasterThreadTableViaBuffer[esi*4]
        !           701:         mov     pCurrentThreadViaBuffer,eax ;threading when buffering is needed
        !           702: 
        !           703:         mov     ulCurrentJustification,JustifyTop ;copy top to bottom
        !           704: 
        !           705:         mov     esi,prcldest
        !           706:         mov     eax,[esi].yBottom
        !           707:         mov     ulLastDestScan,eax      ;end at bottom of dest copy rect
        !           708:         mov     eax,[esi].yTop
        !           709:         mov     ulCurrentDestScan,eax   ;start at top of dest copy rect
        !           710:         mul     ulNextScan              ;offset in bitmap of top dest rect scan
        !           711:         mov     edx,[esi].xLeft
        !           712:         shr     edx,3                   ;byte X address
        !           713:         add     eax,edx                 ;offset in bitmap of first dest byte
        !           714:         mov     ulLeftEdgeDest,eax      ;that's where the left dest edge is
        !           715:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           716:                                         ; byte, unless the left edge is a whole
        !           717:                                         ; byte and is thus part of the whole
        !           718:                                         ; bytes already
        !           719:         mov     ulWholeBytesDest,eax    ;where the whole dest bytes start
        !           720:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           721:         mov     ulRightEdgeDest,eax     ;where the right dest edge starts
        !           722: 
        !           723:         mov     esi,pptlsrc
        !           724:         mov     eax,[esi].ptl_y
        !           725:         mov     ulCurrentSrcScan,eax    ;start at top of source copy rect
        !           726:         mul     ulNextScan              ;offset in bitmap of top dest rect scan
        !           727:         mov     edx,[esi].ptl_x
        !           728:         shr     edx,3                   ;byte X address
        !           729:         add     eax,edx                 ;offset in bitmap of first source byte
        !           730:         mov     ulLeftEdgeSrc,eax       ;that's where the left src edge is
        !           731:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           732:                                         ; byte, unless the left edge is a whole
        !           733:                                         ; byte and is thus part of the whole
        !           734:                                         ; bytes already
        !           735:         mov     ulWholeBytesSrc,eax     ;where the src whole bytes start
        !           736:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           737:         mov     ulRightEdgeSrc,eax      ;where the right src edge starts
        !           738: 
        !           739: ; Branch to the appropriate top-to-bottom bank enumeration loop.
        !           740: 
        !           741:         mov     eax,ulAdapterType
        !           742:         jmp     TopToBottomLoopTable[eax*4]
        !           743: 
        !           744: 
        !           745: ;-----------------------------------------------------------------------;
        !           746: ; Set-up code for right-to-left, top-to-bottom copies.
        !           747: ;-----------------------------------------------------------------------;
        !           748: 
        !           749:         align   4
        !           750: right_to_left_top_to_bottom:
        !           751: 
        !           752:         std                             ;we'll copy right to left
        !           753: 
        !           754:         mov     esi,pdsurf
        !           755:         mov     eax,[esi].dsurf_lNextScan
        !           756:         mov     ulNextScan,eax          ;copy top to bottom
        !           757:         add     eax,culWholeBytesWidth  ;offset from end of one whole byte scan
        !           758:         mov     ulWholeScanDelta,eax    ; to start of next, given that we're
        !           759:                                         ; copying one way and going scan-to-
        !           760:                                         ; scan the other way
        !           761:         mov     esi,ulLWRType           ;3-bit flag field for left, whole, and
        !           762:                                         ; right involvement in operation
        !           763:                                         ;leave left-to-right field cleared, so
        !           764:                                         ; we look up right-to-left entries
        !           765:         mov     eax,MasterThreadTable[esi*4]
        !           766:         mov     pCurrentThread,eax      ;threading when no buffering is needed
        !           767:         mov     edx,ulAdapterType
        !           768:         shl     edx,ADAPTER_FIELD_SHIFT
        !           769:         or      esi,edx                 ;factor adapter type into the index
        !           770:         mov     eax,MasterThreadTableViaBuffer[esi*4]
        !           771:         mov     pCurrentThreadViaBuffer,eax ;threading when buffering is needed
        !           772: 
        !           773:         mov     ulCurrentJustification,JustifyTop ;copy top to bottom
        !           774: 
        !           775:         mov     esi,prcldest
        !           776:         mov     eax,[esi].yBottom
        !           777:         mov     ulLastDestScan,eax      ;end at bottom of dest copy rect
        !           778:         mov     eax,[esi].yTop
        !           779:         mov     ulCurrentDestScan,eax   ;start at top of dest copy rect
        !           780:         mul     ulNextScan              ;offset in bitmap of top dest rect scan
        !           781:         mov     edx,[esi].xLeft
        !           782:         shr     edx,3                   ;byte X address
        !           783:         add     eax,edx                 ;offset in bitmap of first dest byte
        !           784:         mov     ulLeftEdgeDest,eax      ;that's where the left dest edge is
        !           785:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           786:                                         ; byte, unless the left edge is a whole
        !           787:                                         ; byte and is thus part of the whole
        !           788:                                         ; bytes already
        !           789:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           790:         mov     ulRightEdgeDest,eax     ;where the right dest edge starts
        !           791:         dec     eax                     ;back up to the last whole byte
        !           792:         mov     ulWholeBytesDest,eax    ;where the whole dest bytes start
        !           793: 
        !           794:         mov     esi,pptlsrc
        !           795:         mov     eax,[esi].ptl_y
        !           796:         mov     ulCurrentSrcScan,eax    ;start at top of source copy rect
        !           797:         mul     ulNextScan              ;offset in bitmap of top dest rect scan
        !           798:         mov     edx,[esi].ptl_x
        !           799:         shr     edx,3                   ;byte X address
        !           800:         add     eax,edx                 ;offset in bitmap of first source byte
        !           801:         mov     ulLeftEdgeSrc,eax       ;that's where the left src edge is
        !           802:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           803:                                         ; byte, unless the left edge is a whole
        !           804:                                         ; byte and is thus part of the whole
        !           805:                                         ; bytes already
        !           806:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           807:         mov     ulRightEdgeSrc,eax      ;where the right src edge starts
        !           808:         dec     eax                     ;back up to the last whole byte
        !           809:         mov     ulWholeBytesSrc,eax     ;where the src whole bytes start
        !           810: 
        !           811: ; Branch to the appropriate top-to-bottom bank enumeration loop.
        !           812: 
        !           813:         mov     eax,ulAdapterType
        !           814:         jmp     TopToBottomLoopTable[eax*4]
        !           815: 
        !           816: 
        !           817: 
        !           818: ;-----------------------------------------------------------------------;
        !           819: ; Set-up code for left-to-right, bottom-to-top copies.
        !           820: ;-----------------------------------------------------------------------;
        !           821: 
        !           822:         align   4
        !           823: left_to_right_bottom_to_top:
        !           824: 
        !           825:         cld                             ;we'll copy left to right
        !           826: 
        !           827:         mov     edi,pdsurf
        !           828:         mov     eax,[edi].dsurf_lNextScan
        !           829:         neg     eax
        !           830:         mov     ulNextScan,eax          ;copy bottom to top
        !           831:         sub     eax,culWholeBytesWidth  ;offset from end of one whole byte scan
        !           832:         mov     ulWholeScanDelta,eax    ; to start of next, given that we're
        !           833:                                         ; copying one way and going scan-to-
        !           834:                                         ; scan the other way
        !           835:         mov     esi,ulLWRType           ;3-bit flag field for left, whole, and
        !           836:                                         ; right involvement in operation
        !           837:         or      esi,LEFT_TO_RIGHT_FIELD_SET   ;add left-to-right into the index
        !           838:         mov     eax,MasterThreadTable[esi*4]
        !           839:         mov     pCurrentThread,eax      ;threading when no buffering is needed
        !           840:         mov     edx,ulAdapterType
        !           841:         shl     edx,ADAPTER_FIELD_SHIFT
        !           842:         or      esi,edx                 ;factor adapter type into the index
        !           843:         mov     eax,MasterThreadTableViaBuffer[esi*4]
        !           844:         mov     pCurrentThreadViaBuffer,eax ;threading when buffering is needed
        !           845: 
        !           846:         mov     ulCurrentJustification,JustifyBottom ;copy bottom to top
        !           847: 
        !           848:         mov     esi,prcldest
        !           849:         mov     edx,[esi].yTop
        !           850:         mov     ulLastDestScan,edx      ;end at top of dest copy rect
        !           851:         mov     eax,[esi].yBottom
        !           852:         dec     eax                     ;rectangle definition is non-inclusive,
        !           853:                                         ; so advance to first scan we'll copy
        !           854:         sub     edx,eax                 ;-(offset from rect top to bottom)
        !           855:         push    edx                     ;remember for use with source
        !           856:         mov     ulCurrentDestScan,eax   ;start at bottom of dest copy rect
        !           857:         mul     [edi].dsurf_lNextScan   ;offset in bitmap of bottom dest rect
        !           858:                                         ; scan (first scan to which to copy)
        !           859:         mov     edx,[esi].xLeft
        !           860:         shr     edx,3                   ;byte X address
        !           861:         add     eax,edx                 ;offset in bitmap of first dest byte
        !           862:         mov     ulLeftEdgeDest,eax      ;that's where the left dest edge is
        !           863:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           864:                                         ; byte, unless the left edge is a whole
        !           865:                                         ; byte and is thus part of the whole
        !           866:                                         ; bytes already
        !           867:         mov     ulWholeBytesDest,eax    ;where the whole dest bytes start
        !           868:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           869:         mov     ulRightEdgeDest,eax     ;where the right dest edge starts
        !           870: 
        !           871:         mov     esi,pptlsrc
        !           872:         mov     eax,[esi].ptl_y
        !           873:         pop     edx                     ;retrieve -(offset from top to bottom)
        !           874:         sub     eax,edx                 ;advance to bottom of source rect
        !           875:                                         ; (inclusive; this is first scan from
        !           876:                                         ; which to copy)
        !           877:         mov     ulCurrentSrcScan,eax    ;start at bottom of source copy rect
        !           878:         mul     [edi].dsurf_lNextScan   ;offset in bitmap of bottom dest rect
        !           879:                                         ; scan
        !           880:         mov     edx,[esi].ptl_x
        !           881:         shr     edx,3                   ;byte X address
        !           882:         add     eax,edx                 ;offset in bitmap of first source byte
        !           883:         mov     ulLeftEdgeSrc,eax       ;that's where the left src edge is
        !           884:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           885:                                         ; byte, unless the left edge is a whole
        !           886:                                         ; byte and is thus part of the whole
        !           887:                                         ; bytes already
        !           888:         mov     ulWholeBytesSrc,eax     ;where the src whole bytes start
        !           889:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           890:         mov     ulRightEdgeSrc,eax      ;where the right src edge starts
        !           891: 
        !           892: ; Branch to the appropriate bottom-to-top bank enumeration loop.
        !           893: 
        !           894:         mov     eax,ulAdapterType
        !           895:         jmp     BottomToTopLoopTable[eax*4]
        !           896: 
        !           897: 
        !           898: ;-----------------------------------------------------------------------;
        !           899: ; Set-up code for right-to-left, bottom-to-top copies.
        !           900: ;-----------------------------------------------------------------------;
        !           901: 
        !           902:         align   4
        !           903: right_to_left_bottom_to_top:
        !           904: 
        !           905:         std                             ;we'll copy right to left
        !           906: 
        !           907:         mov     edi,pdsurf
        !           908:         mov     eax,[edi].dsurf_lNextScan
        !           909:         neg     eax
        !           910:         mov     ulNextScan,eax          ;copy bottom to top
        !           911:         add     eax,culWholeBytesWidth  ;offset from end of one whole byte scan
        !           912:         mov     ulWholeScanDelta,eax    ; to start of next
        !           913:         mov     esi,ulLWRType           ;3-bit flag field for left, whole, and
        !           914:                                         ; right involvement in operation
        !           915:                                         ;leave left-to-right field cleared, so
        !           916:                                         ; we look up right-to-left entries
        !           917:         mov     eax,MasterThreadTable[esi*4]
        !           918:         mov     pCurrentThread,eax      ;threading when no buffering is needed
        !           919:         mov     edx,ulAdapterType
        !           920:         shl     edx,ADAPTER_FIELD_SHIFT
        !           921:         or      esi,edx                 ;factor adapter type into the index
        !           922:         mov     eax,MasterThreadTableViaBuffer[esi*4]
        !           923:         mov     pCurrentThreadViaBuffer,eax ;threading when buffering is needed
        !           924: 
        !           925:         mov     ulCurrentJustification,JustifyBottom ;copy bottom to top
        !           926: 
        !           927:         mov     esi,prcldest
        !           928:         mov     edx,[esi].yTop
        !           929:         mov     ulLastDestScan,edx      ;end at top of dest copy rect
        !           930:         mov     eax,[esi].yBottom
        !           931:         dec     eax                     ;rectangle definition is non-inclusive,
        !           932:                                         ; so advance to first scan we'll copy
        !           933:         sub     edx,eax                 ;-(offset from rect top to bottom)
        !           934:         push    edx                     ;remember for use with source
        !           935:         mov     ulCurrentDestScan,eax   ;start at bottom of dest copy rect
        !           936:         mul     [edi].dsurf_lNextScan   ;offset in bitmap of bottom dest rect
        !           937:                                         ; scan (first scan to which to copy)
        !           938:         mov     edx,[esi].xLeft
        !           939:         shr     edx,3                   ;byte X address
        !           940:         add     eax,edx
        !           941:         mov     ulLeftEdgeDest,eax      ;that's where the left dest edge is
        !           942:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           943:                                         ; byte, unless the left edge is a whole
        !           944:                                         ; byte and is thus part of the whole
        !           945:                                         ; bytes already
        !           946:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           947:         mov     ulRightEdgeDest,eax     ;where the right dest edge starts
        !           948:         dec     eax                     ;back up to the last whole byte
        !           949:         mov     ulWholeBytesDest,eax    ;where the whole dest bytes start
        !           950: 
        !           951:         mov     esi,pptlsrc
        !           952:         mov     eax,[esi].ptl_y
        !           953:         pop     edx                     ;retrieve -(offset from top to bottom)
        !           954:         sub     eax,edx                 ;advance to bottom of source rect
        !           955:                                         ; (inclusive; this is first scan from
        !           956:                                         ; which to copy)
        !           957:         mov     ulCurrentSrcScan,eax    ;start at bottom of source copy rect
        !           958:         mul     [edi].dsurf_lNextScan   ;offset in bitmap of bottom dest rect
        !           959:                                         ; scan
        !           960:         mov     edx,[esi].ptl_x
        !           961:         shr     edx,3                   ;byte X address
        !           962:         add     eax,edx                 ;offset in bitmap of first source byte
        !           963:         mov     ulLeftEdgeSrc,eax       ;that's where the left src edge is
        !           964:         add     eax,ulLeftEdgeAdjust    ;the whole bytes start at the next
        !           965:                                         ; byte, unless the left edge is a whole
        !           966:                                         ; byte and is thus part of the whole
        !           967:                                         ; bytes already
        !           968:         add     eax,culWholeBytesWidth  ;point to the right edge
        !           969:         mov     ulRightEdgeSrc,eax      ;where the right src edge starts
        !           970:         dec     eax                     ;back up to the last whole byte
        !           971:         mov     ulWholeBytesSrc,eax     ;where the src whole bytes start
        !           972: 
        !           973: ; Branch to the appropriate bottom-to-top bank enumeration loop.
        !           974: 
        !           975:         mov     eax,ulAdapterType
        !           976:         jmp     BottomToTopLoopTable[eax*4]
        !           977: 
        !           978: 
        !           979: ;***********************************************************************;
        !           980: ;
        !           981: ; The following routines are the banking loops.
        !           982: ;
        !           983: ;***********************************************************************;
        !           984: 
        !           985: 
        !           986: ;-----------------------------------------------------------------------;
        !           987: ; Banking for 2 R/W and unbanked adapters, top to bottom.
        !           988: ;-----------------------------------------------------------------------;
        !           989:         align   4
        !           990: top_to_bottom_2RW:
        !           991: 
        !           992: ; We're going top to bottom. Map in the source and dest, top-justified.
        !           993: 
        !           994:         mov     ebx,pdsurf
        !           995:         mov     edx,ulCurrentSrcScan
        !           996:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is source top less than
        !           997:                                                      ; current source bank?
        !           998:         jl      short top_2RW_map_init_src_bank      ;yes, map in proper bank
        !           999:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;source top greater than
        !          1000:                                                         ; current source bank?
        !          1001:         jl      short top_2RW_init_src_bank_mapped
        !          1002:                                                 ;no, proper bank already mapped
        !          1003: top_2RW_map_init_src_bank:
        !          1004: 
        !          1005: ; Map bank containing the top source scan line into source window.
        !          1006: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1007: 
        !          1008:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1009:                 <ebx,edx,JustifyTop,MapSourceBank>
        !          1010: 
        !          1011: top_2RW_init_src_bank_mapped:
        !          1012: 
        !          1013:         mov     edx,ulCurrentDestScan
        !          1014:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is dest top less than
        !          1015:                                                      ; current dest bank?
        !          1016:         jl      short top_2RW_map_init_dest_bank     ;yes, map in proper bank
        !          1017:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest top greater than
        !          1018:                                                         ; current dest bank?
        !          1019:         jl      short top_2RW_init_dest_bank_mapped
        !          1020:                                                 ;no, proper bank already mapped
        !          1021: top_2RW_map_init_dest_bank:
        !          1022: 
        !          1023: ; Map bank containing the top dest scan line into source window.
        !          1024: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1025: 
        !          1026:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1027:                 <ebx,edx,JustifyTop,MapDestBank>
        !          1028: 
        !          1029: top_2RW_init_dest_bank_mapped:
        !          1030: 
        !          1031: ; Bank-by-bank top-to-bottom copy loop.
        !          1032: 
        !          1033: top_2RW_bank_loop:
        !          1034: 
        !          1035: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1036: 
        !          1037:         mov     edx,ulLastDestScan
        !          1038:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom
        !          1039:         jl      short @F        ;copy rectangle bottom is in this bank
        !          1040:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest extends to end
        !          1041:                                                         ; of bank, at least
        !          1042: @@:
        !          1043:         sub     edx,ulCurrentDestScan   ;# of scans we can and want to do in
        !          1044:                                         ; the dest bank
        !          1045:         mov     eax,[ebx].dsurf_rcl2WindowClipS.yBottom
        !          1046:         sub     eax,ulCurrentSrcScan    ;# of scans we can do in the src bank
        !          1047: 
        !          1048:         cmp     edx,eax
        !          1049:         jb      short @F        ;source bank isn't limiting
        !          1050:         mov     edx,eax         ;source bank is limiting
        !          1051: @@:
        !          1052:         mov     ulBlockHeight,edx ;# of scans we'll do in this bank
        !          1053: 
        !          1054: ; We're ready to copy this block.
        !          1055: 
        !          1056:         THREAD_AND_START
        !          1057: 
        !          1058: ; Any more scans to copy?
        !          1059: 
        !          1060:         mov     eax,ulCurrentDestScan
        !          1061:         mov     esi,ulBlockHeight
        !          1062:         add     eax,esi                 ;we've copied to dest up to here
        !          1063:         cmp     ulLastDestScan,eax      ;are we at the dest rect bottom?
        !          1064:         jz      short top_2RW_done      ;yes, we're done
        !          1065:         mov     ulCurrentDestScan,eax
        !          1066: 
        !          1067: ; Now advance either or both banks, as needed.
        !          1068: 
        !          1069:         mov     ebx,pdsurf
        !          1070:         cmp     eax,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest scan greater than
        !          1071:                                                         ; current dest bank?
        !          1072:         jl      short top_2RW_dest_bank_mapped    ;no, proper bank still mapped
        !          1073: 
        !          1074: ; Map bank containing the current dest scan line into source window.
        !          1075: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1076: 
        !          1077:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1078:                 <ebx,eax,JustifyTop,MapDestBank>
        !          1079: 
        !          1080: top_2RW_dest_bank_mapped:
        !          1081: 
        !          1082:         add     esi,ulCurrentSrcScan    ;we've copied from source up to here
        !          1083:         mov     ulCurrentSrcScan,esi
        !          1084: 
        !          1085:         cmp     esi,[ebx].dsurf_rcl2WindowClipS.yBottom ;src scan greater than
        !          1086:                                                         ; current src bank?
        !          1087:         jl      short top_2RW_src_bank_mapped     ;no, proper bank still mapped
        !          1088: 
        !          1089: ; Map bank containing the current source scan line into source window.
        !          1090: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1091: 
        !          1092:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1093:                 <ebx,esi,JustifyTop,MapSourceBank>
        !          1094: 
        !          1095: top_2RW_src_bank_mapped:
        !          1096: 
        !          1097:         jmp     top_2RW_bank_loop
        !          1098: 
        !          1099: top_2RW_done:
        !          1100:         PLAIN_RET
        !          1101: 
        !          1102: 
        !          1103: ;-----------------------------------------------------------------------;
        !          1104: ; Banking for 2 R/W and unbanked adapters, bottom to top.
        !          1105: ;-----------------------------------------------------------------------;
        !          1106:         align   4
        !          1107: bottom_to_top_2RW:
        !          1108: 
        !          1109: ; We're going bottom to top. Map in the source and dest, bottom-justified.
        !          1110: 
        !          1111:         mov     ebx,pdsurf
        !          1112:         mov     edx,ulCurrentSrcScan
        !          1113:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is source bottom less than
        !          1114:                                                      ; current source bank?
        !          1115:         jl      short bot_2RW_map_init_src_bank      ;yes, map in proper bank
        !          1116:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;source bottom greater
        !          1117:                                                         ; than current src bank?
        !          1118:         jl      short bot_2RW_init_src_bank_mapped
        !          1119:                                                 ;no, proper bank already mapped
        !          1120: bot_2RW_map_init_src_bank:
        !          1121: 
        !          1122: ; Map bank containing the bottom source scan line into source window.
        !          1123: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1124: 
        !          1125:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1126:                 <ebx,edx,JustifyBottom,MapSourceBank>
        !          1127: 
        !          1128: bot_2RW_init_src_bank_mapped:
        !          1129: 
        !          1130:         mov     edx,ulCurrentDestScan
        !          1131:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is dest bottom less than
        !          1132:                                                      ; current dest bank?
        !          1133:         jl      short bot_2RW_map_init_dest_bank     ;yes, map in proper bank
        !          1134:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest bottom greater
        !          1135:                                                         ; than current dst bank?
        !          1136:         jl      short bot_2RW_init_dest_bank_mapped
        !          1137:                                                 ;no, proper bank already mapped
        !          1138: bot_2RW_map_init_dest_bank:
        !          1139: 
        !          1140: ; Map bank containing the bottom dest scan line into source window.
        !          1141: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1142: 
        !          1143:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1144:                 <ebx,edx,JustifyBottom,MapDestBank>
        !          1145: 
        !          1146: bot_2RW_init_dest_bank_mapped:
        !          1147: 
        !          1148: ; Bank-by-bank bottom-to-top copy loop.
        !          1149: 
        !          1150: bot_2RW_bank_loop:
        !          1151: 
        !          1152: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1153: 
        !          1154:         mov     edx,ulLastDestScan
        !          1155:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop
        !          1156:         jg      short @F        ;copy rectangle top is in this bank
        !          1157:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;dest extends to end
        !          1158:                                                      ; of bank, at least
        !          1159: @@:
        !          1160:         neg     edx
        !          1161:         add     edx,ulCurrentDestScan   ;# of scans we can and want to do in
        !          1162:         inc     edx                     ; the dest bank
        !          1163: 
        !          1164:         mov     eax,ulCurrentSrcScan
        !          1165:         sub     eax,[ebx].dsurf_rcl2WindowClipS.yTop
        !          1166:         inc     eax                     ;# of scans we can do in the src bank
        !          1167: 
        !          1168:         cmp     edx,eax
        !          1169:         jb      short @F        ;source bank isn't limiting
        !          1170:         mov     edx,eax         ;source bank is limiting
        !          1171: @@:
        !          1172:         mov     ulBlockHeight,edx ;# of scans we'll do in this bank
        !          1173: 
        !          1174: ; We're ready to copy this block.
        !          1175: 
        !          1176:         THREAD_AND_START
        !          1177: 
        !          1178: ; Any more scans to copy?
        !          1179: 
        !          1180:         mov     eax,ulCurrentDestScan
        !          1181:         mov     esi,ulBlockHeight
        !          1182:         sub     eax,esi                 ;we've copied to dest up to here
        !          1183:         cmp     ulLastDestScan,eax      ;are we past the dest rect top?
        !          1184:         jg      short bot_2RW_done      ;yes, we're done
        !          1185:         mov     ulCurrentDestScan,eax
        !          1186: 
        !          1187: ; Now advance either or both banks, as needed.
        !          1188: 
        !          1189:         mov     ebx,pdsurf
        !          1190:         cmp     eax,[ebx].dsurf_rcl2WindowClipD.yTop ;dest scan less than
        !          1191:                                                      ; current dest bank?
        !          1192:         jge     short bot_2RW_dest_bank_mapped    ;no, proper bank still mapped
        !          1193: 
        !          1194: ; Map bank containing the current dest scan line into source window.
        !          1195: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1196: 
        !          1197:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1198:                 <ebx,eax,JustifyBottom,MapDestBank>
        !          1199: 
        !          1200: bot_2RW_dest_bank_mapped:
        !          1201: 
        !          1202:         mov     eax,ulCurrentSrcScan
        !          1203:         sub     eax,esi         ;we've copied from source up to here
        !          1204:         mov     ulCurrentSrcScan,eax
        !          1205: 
        !          1206:         cmp     eax,[ebx].dsurf_rcl2WindowClipS.yTop ;src scan less than
        !          1207:                                                      ; current src bank?
        !          1208:         jge     short bot_2RW_src_bank_mapped     ;no, proper bank still mapped
        !          1209: 
        !          1210: ; Map bank containing the current source scan line into source window.
        !          1211: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1212: 
        !          1213:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1214:                 <ebx,eax,JustifyBottom,MapSourceBank>
        !          1215: 
        !          1216: bot_2RW_src_bank_mapped:
        !          1217: 
        !          1218:         jmp     bot_2RW_bank_loop
        !          1219: 
        !          1220: bot_2RW_done:
        !          1221:         PLAIN_RET
        !          1222: 
        !          1223: 
        !          1224: ;-----------------------------------------------------------------------;
        !          1225: ; Banking for 1R/1W adapters, top to bottom.
        !          1226: ;-----------------------------------------------------------------------;
        !          1227:         align   4
        !          1228: top_to_bottom_1R1W:
        !          1229: 
        !          1230: ; We're going top to bottom. Map in the source and dest, top-justified.
        !          1231: 
        !          1232:         mov     ebx,pdsurf
        !          1233:         mov     edx,ulCurrentSrcScan
        !          1234:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is source top less than
        !          1235:                                                      ; current source bank?
        !          1236:         jl      short top_1R1W_map_init_src_bank      ;yes, map in proper bank
        !          1237:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;source top greater than
        !          1238:                                                         ; current source bank?
        !          1239:         jl      short top_1R1W_init_src_bank_mapped
        !          1240:                                                 ;no, proper bank already mapped
        !          1241: top_1R1W_map_init_src_bank:
        !          1242: 
        !          1243: ; Map bank containing the top source scan line into source window.
        !          1244: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1245: 
        !          1246:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1247:                 <ebx,edx,JustifyTop,MapSourceBank>
        !          1248: 
        !          1249: top_1R1W_init_src_bank_mapped:
        !          1250: 
        !          1251:         mov     edx,ulCurrentDestScan
        !          1252:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is dest top less than
        !          1253:                                                      ; current dest bank?
        !          1254:         jl      short top_1R1W_map_init_dest_bank     ;yes, map in proper bank
        !          1255:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest top greater than
        !          1256:                                                         ; current dest bank?
        !          1257:         jl      short top_1R1W_init_dest_bank_mapped
        !          1258:                                                 ;no, proper bank already mapped
        !          1259: top_1R1W_map_init_dest_bank:
        !          1260: 
        !          1261: ; Map bank containing the top dest scan line into source window.
        !          1262: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1263: 
        !          1264:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1265:                 <ebx,edx,JustifyTop,MapDestBank>
        !          1266: 
        !          1267: top_1R1W_init_dest_bank_mapped:
        !          1268: 
        !          1269: ; Bank-by-bank top-to-bottom copy loop.
        !          1270: 
        !          1271: top_1R1W_bank_loop:
        !          1272: 
        !          1273: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1274: 
        !          1275:         mov     edx,ulLastDestScan
        !          1276:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom
        !          1277:         jl      short @F        ;copy rectangle bottom is in this bank
        !          1278:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest extends to end
        !          1279:                                                         ; of bank, at least
        !          1280: @@:
        !          1281:         sub     edx,ulCurrentDestScan   ;# of scans we can and want to do in
        !          1282:                                         ; the dest bank
        !          1283:         mov     eax,[ebx].dsurf_rcl2WindowClipS.yBottom
        !          1284:         sub     eax,ulCurrentSrcScan    ;# of scans we can do in the src bank
        !          1285: 
        !          1286:         cmp     edx,eax
        !          1287:         jb      short @F        ;source bank isn't limiting
        !          1288:         mov     edx,eax         ;source bank is limiting
        !          1289: @@:
        !          1290:         mov     ulBlockHeight,edx ;# of scans we'll do in this bank
        !          1291: 
        !          1292: ; We're ready to copy this block.
        !          1293: ; Select different threading, depending on whether the source and destination
        !          1294: ; are currently in the same bank; we can do edges faster if they are.
        !          1295: 
        !          1296:         mov     eax,[ebx].dsurf_ulWindowBank
        !          1297:         cmp     eax,[ebx].dsurf_ulWindowBank[4]
        !          1298:         jz      short top_1R1W_copy_same_bank
        !          1299: 
        !          1300: ; Source and dest are currently in different banks, must go through temp buffer.
        !          1301: 
        !          1302:         THREAD_AND_START pCurrentThreadViaBuffer,top_1R1W_check_more_scans
        !          1303: 
        !          1304: ; Source and dest are currently in the same bank.
        !          1305: 
        !          1306:         align   4
        !          1307: top_1R1W_copy_same_bank:
        !          1308:         THREAD_AND_START
        !          1309: 
        !          1310: ; Any more scans to copy?
        !          1311: 
        !          1312: top_1R1W_check_more_scans:
        !          1313: 
        !          1314:         mov     eax,ulCurrentDestScan
        !          1315:         mov     esi,ulBlockHeight
        !          1316:         add     eax,esi                 ;we've copied to dest up to here
        !          1317:         cmp     ulLastDestScan,eax      ;are we at the dest rect bottom?
        !          1318:         jz      short top_1R1W_done     ;yes, we're done
        !          1319:         mov     ulCurrentDestScan,eax
        !          1320: 
        !          1321: ; Now advance either or both banks, as needed.
        !          1322: 
        !          1323:         mov     ebx,pdsurf
        !          1324:         cmp     eax,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest scan greater than
        !          1325:                                                         ; current dest bank?
        !          1326:         jl      short top_1R1W_dest_bank_mapped   ;no, proper bank still mapped
        !          1327: 
        !          1328: ; Map bank containing the current dest scan line into source window.
        !          1329: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1330: 
        !          1331:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1332:                 <ebx,eax,JustifyTop,MapDestBank>
        !          1333: 
        !          1334: top_1R1W_dest_bank_mapped:
        !          1335: 
        !          1336:         add     esi,ulCurrentSrcScan    ;we've copied from source up to here
        !          1337:         mov     ulCurrentSrcScan,esi
        !          1338: 
        !          1339:         cmp     esi,[ebx].dsurf_rcl2WindowClipS.yBottom ;src scan greater than
        !          1340:                                                         ; current src bank?
        !          1341:         jl      short top_1R1W_src_bank_mapped     ;no, proper bank still mapped
        !          1342: 
        !          1343: ; Map bank containing the current source scan line into source window.
        !          1344: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1345: 
        !          1346:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1347:                 <ebx,esi,JustifyTop,MapSourceBank>
        !          1348: 
        !          1349: top_1R1W_src_bank_mapped:
        !          1350: 
        !          1351:         jmp     top_1R1W_bank_loop
        !          1352: 
        !          1353: top_1R1W_done:
        !          1354:         PLAIN_RET
        !          1355: 
        !          1356: 
        !          1357: ;-----------------------------------------------------------------------;
        !          1358: ; Banking for 1R/1W adapters, bottom to top.
        !          1359: ;-----------------------------------------------------------------------;
        !          1360:         align   4
        !          1361: bottom_to_top_1R1W:
        !          1362: 
        !          1363: ; We're going bottom to top. Map in the source and dest, bottom-justified.
        !          1364: 
        !          1365:         mov     ebx,pdsurf
        !          1366:         mov     edx,ulCurrentSrcScan
        !          1367:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is source bottom less than
        !          1368:                                                      ; current source bank?
        !          1369:         jl      short bot_1R1W_map_init_src_bank      ;yes, map in proper bank
        !          1370:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;source bottom greater
        !          1371:                                                         ; than current src bank?
        !          1372:         jl      short bot_1R1W_init_src_bank_mapped
        !          1373:                                                 ;no, proper bank already mapped
        !          1374: bot_1R1W_map_init_src_bank:
        !          1375: 
        !          1376: ; Map bank containing the bottom source scan line into source window.
        !          1377: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1378: 
        !          1379:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1380:                 <ebx,edx,JustifyBottom,MapSourceBank>
        !          1381: 
        !          1382: bot_1R1W_init_src_bank_mapped:
        !          1383: 
        !          1384:         mov     edx,ulCurrentDestScan
        !          1385:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is dest bottom less than
        !          1386:                                                      ; current dest bank?
        !          1387:         jl      short bot_1R1W_map_init_dest_bank     ;yes, map in proper bank
        !          1388:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;dest bottom greater
        !          1389:                                                         ; than current dst bank?
        !          1390:         jl      short bot_1R1W_init_dest_bank_mapped
        !          1391:                                                 ;no, proper bank already mapped
        !          1392: bot_1R1W_map_init_dest_bank:
        !          1393: 
        !          1394: ; Map bank containing the bottom dest scan line into source window.
        !          1395: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1396: 
        !          1397:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1398:                 <ebx,edx,JustifyBottom,MapDestBank>
        !          1399: 
        !          1400: bot_1R1W_init_dest_bank_mapped:
        !          1401: 
        !          1402: ; Bank-by-bank bottom-to-top copy loop.
        !          1403: 
        !          1404: bot_1R1W_bank_loop:
        !          1405: 
        !          1406: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1407: 
        !          1408:         mov     edx,ulLastDestScan
        !          1409:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop
        !          1410:         jg      short @F        ;copy rectangle top is in this bank
        !          1411:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;dest extends to end
        !          1412:                                                      ; of bank, at least
        !          1413: @@:
        !          1414:         neg     edx
        !          1415:         add     edx,ulCurrentDestScan   ;# of scans we can and want to do in
        !          1416:         inc     edx                     ; the dest bank
        !          1417: 
        !          1418:         mov     eax,ulCurrentSrcScan
        !          1419:         sub     eax,[ebx].dsurf_rcl2WindowClipS.yTop
        !          1420:         inc     eax                     ;# of scans we can do in the src bank
        !          1421: 
        !          1422:         cmp     edx,eax
        !          1423:         jb      short @F        ;source bank isn't limiting
        !          1424:         mov     edx,eax         ;source bank is limiting
        !          1425: @@:
        !          1426:         mov     ulBlockHeight,edx ;# of scans we'll do in this bank
        !          1427: 
        !          1428: ; We're ready to copy this block.
        !          1429: ; Select different threading, depending on whether the source and destination
        !          1430: ; are currently in the same bank; we can do edges faster if they are.
        !          1431: 
        !          1432:         mov     al,byte ptr [ebx].dsurf_ulWindowBank
        !          1433:         cmp     al,byte ptr [ebx].dsurf_ulWindowBank[4]
        !          1434:         jz      short bot_1R1W_copy_same_bank
        !          1435: 
        !          1436: ; Source and dest are currently in different banks, must go through temp buffer.
        !          1437: 
        !          1438:         THREAD_AND_START pCurrentThreadViaBuffer,bot_1R1W_check_more_scans
        !          1439: 
        !          1440: ; Source and dest are currently in the same bank.
        !          1441: 
        !          1442:         align   4
        !          1443: bot_1R1W_copy_same_bank:
        !          1444:         THREAD_AND_START
        !          1445: 
        !          1446: ; Any more scans to copy?
        !          1447: 
        !          1448:         align   4
        !          1449: bot_1R1W_check_more_scans:
        !          1450: 
        !          1451:         mov     eax,ulCurrentDestScan
        !          1452:         mov     esi,ulBlockHeight
        !          1453:         sub     eax,esi                 ;we've copied to dest up to here
        !          1454:         cmp     ulLastDestScan,eax      ;are we past the dest rect top?
        !          1455:         jg      short bot_1R1W_done     ;yes, we're done
        !          1456:         mov     ulCurrentDestScan,eax
        !          1457: 
        !          1458: ; Now advance either or both banks, as needed.
        !          1459: 
        !          1460:         mov     ebx,pdsurf
        !          1461:         cmp     eax,[ebx].dsurf_rcl2WindowClipD.yTop ;dest scan less than
        !          1462:                                                      ; current dest bank?
        !          1463:         jge     short bot_1R1W_dest_bank_mapped   ;no, proper bank still mapped
        !          1464: 
        !          1465: ; Map bank containing the current dest scan line into source window.
        !          1466: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1467: 
        !          1468:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1469:                 <ebx,eax,JustifyBottom,MapDestBank>
        !          1470: 
        !          1471: bot_1R1W_dest_bank_mapped:
        !          1472: 
        !          1473:         mov     eax,ulCurrentSrcScan
        !          1474:         sub     eax,esi         ;we've copied from source up to here
        !          1475:         mov     ulCurrentSrcScan,eax
        !          1476: 
        !          1477:         cmp     eax,[ebx].dsurf_rcl2WindowClipS.yTop ;src scan less than
        !          1478:                                                      ; current src bank?
        !          1479:         jge     short bot_1R1W_src_bank_mapped    ;no, proper bank still mapped
        !          1480: 
        !          1481: ; Map bank containing the current source scan line into source window.
        !          1482: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1483: 
        !          1484:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          1485:                 <ebx,eax,JustifyBottom,MapSourceBank>
        !          1486: 
        !          1487: bot_1R1W_src_bank_mapped:
        !          1488: 
        !          1489:         jmp     bot_1R1W_bank_loop
        !          1490: 
        !          1491: bot_1R1W_done:
        !          1492:         PLAIN_RET
        !          1493: 
        !          1494: 
        !          1495: ;-----------------------------------------------------------------------;
        !          1496: ; Banking for 1 R/W adapters, top to bottom.
        !          1497: ;-----------------------------------------------------------------------;
        !          1498:         align   4
        !          1499: top_to_bottom_1RW:
        !          1500: 
        !          1501: ; We're going top to bottom. Map in the dest, top-justified.
        !          1502: 
        !          1503:         mov     ebx,pdsurf
        !          1504:         mov     esi,ulCurrentDestScan
        !          1505:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop  ;is dest top less than
        !          1506:                                                      ; current bank?
        !          1507:         jl      short top_1RW_map_init_dest_bank     ;yes, map in proper bank
        !          1508:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;dest top greater than
        !          1509:                                                         ; current bank?
        !          1510:         jl      short top_1RW_init_dest_bank_mapped
        !          1511:                                                 ;no, proper bank already mapped
        !          1512: top_1RW_map_init_dest_bank:
        !          1513: 
        !          1514: ; Map bank containing the top dest scan line into source window.
        !          1515: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1516: 
        !          1517:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyTop>
        !          1518: 
        !          1519: top_1RW_init_dest_bank_mapped:
        !          1520: 
        !          1521: ; Bank-by-bank top-to-bottom copy loop.
        !          1522: 
        !          1523: top_1RW_bank_loop:
        !          1524: 
        !          1525: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1526: 
        !          1527:         mov     edi,ulLastDestScan
        !          1528:         cmp     edi,[ebx].dsurf_rcl1WindowClip.yBottom
        !          1529:         jl      short @F        ;copy rectangle bottom is in this bank
        !          1530:         mov     edi,[ebx].dsurf_rcl1WindowClip.yBottom ;dest extends to end
        !          1531:                                                        ; of bank, at least
        !          1532: @@:
        !          1533:         sub     edi,esi   ;# of scans we can and want to do in the dest bank
        !          1534: 
        !          1535: ; Now make sure source is mapped in. This is the condition the copying routines
        !          1536: ; expect, and we need to figure out how far we can go in the source.
        !          1537: 
        !          1538:         sub     edx,edx                 ;assume source and dest are in the same
        !          1539:                                         ; bank
        !          1540:         mov     esi,ulCurrentSrcScan
        !          1541:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop ;src scan less than
        !          1542:                                                     ; current bank?
        !          1543:         jl      short top_1RW_map_src_Bank          ;yes, must map in
        !          1544:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;src scan greater than
        !          1545:                                                        ; current bank?
        !          1546:         jl      short top_1RW_src_bank_mapped     ;no, proper bank still mapped
        !          1547: 
        !          1548: top_1RW_map_src_Bank:
        !          1549: 
        !          1550: ; Map bank containing the current source scan line into source window.
        !          1551: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1552: 
        !          1553:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyTop>
        !          1554: 
        !          1555:         mov     edx,1                   ;mark that source and dest are not in
        !          1556:                                         ; the same bank
        !          1557: top_1RW_src_bank_mapped:
        !          1558: 
        !          1559:         mov     eax,[ebx].dsurf_rcl1WindowClip.yBottom
        !          1560:         sub     eax,esi         ;# of scans we can do in the src bank
        !          1561: 
        !          1562:         cmp     edi,eax
        !          1563:         jb      short @F        ;source bank isn't limiting
        !          1564:         mov     edi,eax         ;source bank is limiting
        !          1565: @@:
        !          1566:         mov     ulBlockHeight,edi ;# of scans we'll do in this bank
        !          1567: 
        !          1568: ; We're ready to copy this block.
        !          1569: ; Select different threading, depending on whether the source and destination
        !          1570: ; are currently in the same bank; we can do edges faster if they are.
        !          1571: 
        !          1572:         and     edx,edx
        !          1573:         jz      short top_1RW_copy_same_bank
        !          1574: 
        !          1575: ; Source and dest are currently in different banks, must go through temp buffer.
        !          1576: 
        !          1577:         THREAD_AND_START pCurrentThreadViaBuffer,top_1RW_check_more_scans
        !          1578: 
        !          1579: ; Source and dest are currently in the same bank.
        !          1580: 
        !          1581:         align   4
        !          1582: top_1RW_copy_same_bank:
        !          1583:         THREAD_AND_START
        !          1584: 
        !          1585: ; Any more scans to copy?
        !          1586: 
        !          1587: top_1RW_check_more_scans:
        !          1588: 
        !          1589:         mov     esi,ulCurrentDestScan
        !          1590:         mov     edi,ulBlockHeight
        !          1591:         add     esi,edi                 ;we've copied to dest up to here
        !          1592:         cmp     ulLastDestScan,esi      ;are we at the dest rect bottom?
        !          1593:         jz      short top_1RW_done      ;yes, we're done
        !          1594:         mov     ulCurrentDestScan,esi
        !          1595: 
        !          1596: ; Now make sure the dest bank is mapped in.
        !          1597: 
        !          1598:         mov     ebx,pdsurf
        !          1599:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop ;dest scan less than
        !          1600:                                                     ; current bank?
        !          1601:         jl      short top_1RW_map_dest_bank         ;yes, map in dest bank
        !          1602:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;dest scan greater than
        !          1603:                                                         ; current bank?
        !          1604:         jl      short top_1RW_dest_bank_mapped   ;no, proper bank mapped
        !          1605: 
        !          1606: top_1RW_map_dest_bank:
        !          1607: 
        !          1608: ; Map bank containing the current dest scan line into source window.
        !          1609: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1610: 
        !          1611:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyTop>
        !          1612: 
        !          1613: top_1RW_dest_bank_mapped:
        !          1614: 
        !          1615:         add     ulCurrentSrcScan,edi    ;we've copied from source up to here
        !          1616: 
        !          1617:         jmp     top_1RW_bank_loop
        !          1618: 
        !          1619: top_1RW_done:
        !          1620:         PLAIN_RET
        !          1621: 
        !          1622: 
        !          1623: ;-----------------------------------------------------------------------;
        !          1624: ; Banking for 1 R/W adapters, bottom to top.
        !          1625: ;-----------------------------------------------------------------------;
        !          1626:         align   4
        !          1627: bottom_to_top_1RW:
        !          1628: 
        !          1629: ; We're going bottom to top. Map in the dest, bottom-justified.
        !          1630: 
        !          1631:         mov     ebx,pdsurf
        !          1632:         mov     esi,ulCurrentDestScan
        !          1633:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop  ;is dest bottom less than
        !          1634:                                                      ; current dest bank?
        !          1635:         jl      short bot_1RW_map_init_dest_bank     ;yes, map in proper bank
        !          1636:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;dest bottom greater
        !          1637:                                                        ; than current dst bank?
        !          1638:         jl      short bot_1RW_init_dest_bank_mapped
        !          1639:                                                 ;no, proper bank already mapped
        !          1640: bot_1RW_map_init_dest_bank:
        !          1641: 
        !          1642: ; Map bank containing the bottom dest scan line into source window.
        !          1643: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1644: 
        !          1645:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyBottom>
        !          1646: 
        !          1647: bot_1RW_init_dest_bank_mapped:
        !          1648: 
        !          1649: ; Bank-by-bank bottom-to-top copy loop.
        !          1650: 
        !          1651: bot_1RW_bank_loop:
        !          1652: 
        !          1653: ; Decide how far we can go before we run out of bank or rectangle to copy.
        !          1654: 
        !          1655:         mov     edi,ulLastDestScan
        !          1656:         cmp     edi,[ebx].dsurf_rcl1WindowClip.yTop
        !          1657:         jg      short @F        ;copy rectangle top is in this bank
        !          1658:         mov     edi,[ebx].dsurf_rcl1WindowClip.yTop ;dest extends to end
        !          1659:                                                     ; of bank, at least
        !          1660: @@:
        !          1661:         neg     edi
        !          1662:         add     edi,esi                 ;# of scans we can and want to do in
        !          1663:         inc     edi                     ; the dest bank
        !          1664: 
        !          1665: ; Now make sure source is mapped in. This is the condition the copying routines
        !          1666: ; expect, and we need to figure out how far we can go in the source.
        !          1667: 
        !          1668:         sub     edx,edx                 ;assume source and dest are in the same
        !          1669:                                         ; bank
        !          1670:         mov     esi,ulCurrentSrcScan
        !          1671:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop ;src scan less than
        !          1672:                                                     ; current bank?
        !          1673:         jl      short bot_1RW_map_src_Bank          ;yes, must map in
        !          1674:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;src scan greater than
        !          1675:                                                        ; current bank?
        !          1676:         jl      short bot_1RW_src_bank_mapped     ;no, proper bank still mapped
        !          1677: 
        !          1678: bot_1RW_map_src_Bank:
        !          1679: 
        !          1680: ; Map bank containing the current source scan line into source window.
        !          1681: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1682: 
        !          1683:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyBottom>
        !          1684: 
        !          1685:         mov     edx,1                   ;mark that source and dest are not in
        !          1686:                                         ; the same bank
        !          1687: bot_1RW_src_bank_mapped:
        !          1688: 
        !          1689:         sub     esi,[ebx].dsurf_rcl1WindowClip.yTop
        !          1690:         inc     esi                     ;# of scans we can do in the src bank
        !          1691: 
        !          1692:         cmp     edi,esi
        !          1693:         jb      short @F        ;source bank isn't limiting
        !          1694:         mov     edi,esi         ;source bank is limiting
        !          1695: @@:
        !          1696:         mov     ulBlockHeight,edi ;# of scans we'll do in this bank
        !          1697: 
        !          1698: ; We're ready to copy this block.
        !          1699: ; Select different threading, depending on whether the source and destination
        !          1700: ; are currently in the same bank; we can copy much faster if they are.
        !          1701: 
        !          1702:         and     edx,edx
        !          1703:         jz      short bot_1RW_copy_same_bank
        !          1704: 
        !          1705: ; Source and dest are currently in different banks, must go through temp buffer.
        !          1706: 
        !          1707:         THREAD_AND_START pCurrentThreadViaBuffer,bot_1RW_check_more_scans
        !          1708: 
        !          1709: ; Source and dest are currently in the same bank.
        !          1710: 
        !          1711:         align   4
        !          1712: bot_1RW_copy_same_bank:
        !          1713:         THREAD_AND_START
        !          1714: 
        !          1715: ; Any more scans to copy?
        !          1716: 
        !          1717:         align   4
        !          1718: bot_1RW_check_more_scans:
        !          1719: 
        !          1720:         mov     esi,ulCurrentDestScan
        !          1721:         mov     edi,ulBlockHeight
        !          1722:         sub     esi,edi                 ;we've copied to dest up to here
        !          1723:         cmp     ulLastDestScan,esi      ;are we past the dest rect top?
        !          1724:         jg      short bot_1RW_done      ;yes, we're done
        !          1725:         mov     ulCurrentDestScan,esi
        !          1726: 
        !          1727: ; Now make sure the dest bank is mapped in.
        !          1728: 
        !          1729:         mov     ebx,pdsurf
        !          1730:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yTop ;dest scan less than
        !          1731:                                                     ; current bank?
        !          1732:         jl      short bot_1RW_map_dest_bank         ;yes, map in dest bank
        !          1733:         cmp     esi,[ebx].dsurf_rcl1WindowClip.yBottom ;dest scan greater than
        !          1734:                                                         ; current bank?
        !          1735:         jl      short bot_1RW_dest_bank_mapped   ;no, proper bank mapped
        !          1736: 
        !          1737: bot_1RW_map_dest_bank:
        !          1738: 
        !          1739: ; Map bank containing the current dest scan line into source window.
        !          1740: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1741: 
        !          1742:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,esi,JustifyBottom>
        !          1743: 
        !          1744: bot_1RW_dest_bank_mapped:
        !          1745: 
        !          1746:         sub     ulCurrentSrcScan,edi    ;we've copied from source up to here
        !          1747: 
        !          1748:         jmp     bot_1RW_bank_loop
        !          1749: 
        !          1750: bot_1RW_done:
        !          1751:         PLAIN_RET
        !          1752: 
        !          1753: 
        !          1754: ;***********************************************************************;
        !          1755: ;
        !          1756: ; The following routines are the low-level copying routines. They know
        !          1757: ; almost nothing about banks (the routines that copy through a temp
        !          1758: ; buffer know how to switch banks after filling the temp buffer, but
        !          1759: ; that's it). Banking should be taken care of at a higher level.
        !          1760: ;
        !          1761: ;***********************************************************************;
        !          1762: 
        !          1763: ;-----------------------------------------------------------------------;
        !          1764: ; Copies a block of solid bytes from the source to the destination via the
        !          1765: ; latches. Can only be used by 2 R/W or 1R/1W window banking, or by
        !          1766: ; unbanked modes, or by 1 R/W adapters when the source and dest are in the
        !          1767: ; same bank. 1 R/W adapters must go through an intermediate local buffer
        !          1768: ; when the source and the destination aren't in the same bank.
        !          1769: ;
        !          1770: ; Input:
        !          1771: ;       Direction Flag set for desired direction of copy
        !          1772: ;       culWholeBytesWidth = # of bytes to copy across each scan line
        !          1773: ;       ulWholeScanDelta = distance to start of next scan from end of current
        !          1774: ;       ulBlockHeight = # of scans to copy
        !          1775: ;       ulWholeBytesSrc = start source offset in bitmap
        !          1776: ;       ulWholeBytesDest = start dest offset in bitmap
        !          1777: ;
        !          1778: ; Output:
        !          1779: ;       Advances ulWholeBytesSrc and ulWholeBytesDest to scan after last
        !          1780: ;               scan processed
        !          1781: ;-----------------------------------------------------------------------;
        !          1782: 
        !          1783:         align   4
        !          1784: copy_whole_bytes:
        !          1785: 
        !          1786: ; Set the bit mask to disable all bits, so we can copy through the latches.
        !          1787: 
        !          1788:         mov     edx,VGA_BASE + GRAF_ADDR
        !          1789:         mov     eax,(000h shl 8) + GRAF_BIT_MASK
        !          1790:         out     dx,ax
        !          1791: 
        !          1792: ; Set Map Mask to enable writes to all planes.
        !          1793: 
        !          1794:         mov     dl,SEQ_DATA
        !          1795:         mov     al,MM_ALL
        !          1796:         out     dx,al
        !          1797: 
        !          1798: ; Set up to copy the whole bytes via the latches.
        !          1799: 
        !          1800:         mov     eax,culWholeBytesWidth
        !          1801:         mov     ebx,ulBlockHeight
        !          1802:         mov     edx,ulWholeScanDelta
        !          1803: 
        !          1804: ; Calculate full start addresses.
        !          1805: 
        !          1806:         mov     ecx,pdsurf
        !          1807:         mov     esi,ulWholeBytesSrc
        !          1808:         add     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          1809:         mov     edi,ulWholeBytesDest
        !          1810:         add     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          1811: 
        !          1812:         SET_UP_UNROLL_VARS ebx,ecx,ebx,pfnCopyWholeLatchesEntry, \
        !          1813:                                 LOOP_UNROLL_SHIFT
        !          1814:         jmp    ecx      ;copy the whole bytes
        !          1815: 
        !          1816: ;-----------------------------------------------------------------------;
        !          1817: ; Table of unrolled whole latched loop entry points.
        !          1818: ;-----------------------------------------------------------------------;
        !          1819: 
        !          1820:         UNROLL_LOOP_ENTRY_TABLE pfnCopyWholeLatchesEntry,WHOLE_LATCHES, \
        !          1821:                                 LOOP_UNROLL_COUNT
        !          1822: 
        !          1823: ;-----------------------------------------------------------------------;
        !          1824: ; Unrolled loop for copying a block of whole bytes via the latches.
        !          1825: ;-----------------------------------------------------------------------;
        !          1826: 
        !          1827: COPY_WHOLE_LATCHES macro ENTRY_LABEL,ENTRY_INDEX
        !          1828: &ENTRY_LABEL&ENTRY_INDEX&:
        !          1829:         mov     ecx,eax         ;# of whole bytes to copy
        !          1830:         rep     movsb           ;copy the bytes via the latches
        !          1831:         add     esi,edx         ;point to next source scan
        !          1832:         add     edi,edx         ;point to next dest scan
        !          1833:         endm    ;-----------------------------------;
        !          1834: 
        !          1835: ;  EAX = # of bytes to copy
        !          1836: ;  EBX = count of unrolled loop iterations
        !          1837: ;  EDX = offset from end of one scan's fill to start of next
        !          1838: ;  ESI = source address to copy from
        !          1839: ;  EDI = target address to copy to
        !          1840: 
        !          1841:         align   4
        !          1842: whole_latches_loop:
        !          1843:         UNROLL_LOOP     COPY_WHOLE_LATCHES,WHOLE_LATCHES,LOOP_UNROLL_COUNT
        !          1844:         dec     ebx
        !          1845:         jnz     whole_latches_loop
        !          1846: 
        !          1847: ; Remember where we left off, for next time.
        !          1848: 
        !          1849:         mov     ecx,pdsurf
        !          1850:         sub     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          1851:         mov     ulWholeBytesSrc,esi
        !          1852:         sub     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          1853:         mov     ulWholeBytesDest,edi
        !          1854: 
        !          1855:         PLAIN_RET
        !          1856: 
        !          1857: 
        !          1858: ;-----------------------------------------------------------------------;
        !          1859: ; Copies a block of solid bytes from the source to the destination via
        !          1860: ; the temp buffer. This should only be used by 1 R/W adapters, and then
        !          1861: ; only when the source and dest are in different banks.
        !          1862: ;
        !          1863: ; All relevant bytes are copied from the source to a temp buffer that's an
        !          1864: ; image of the source first. Then, we copy each of the four planes for one scan
        !          1865: ; line from the temp buffer to the screen before going on to the next scan line.
        !          1866: ; It would be faster to do all scans in one plane, then all in the next, and so
        !          1867: ; on, but that would give nasty color effects from pixels that were changed in
        !          1868: ; some planes but not in others. A compromise would be to do several scans at a
        !          1869: ; pop per plane, as is done with the edge bytes; however, given that there can
        !          1870: ; be 128 (or more) bytes across a single whole-bytes scan, if we do 16 scan
        !          1871: ; lines per chunk, we're going to be performing up to 128*4*16 accesses per
        !          1872: ; chunk; at an assumed 1 microsecond per access, that's 8 millisecond per scan
        !          1873: ; line, or about 1/2 of a frame time. We're definitely going to see flicker or
        !          1874: ; sparkles from partially updated bytes at that point, in my opinion. Another
        !          1875: ; alternative would be to dynamically adjust the number of scans processed at a
        !          1876: ; pop per plane, depending on the copy width, with more scans copied for
        !          1877: ; narrower widths. For all but very narrow copies, though, it seems to me that
        !          1878: ; the actual copy time would far outweigh the time for the OUTs to switch
        !          1879: ; planes, and the return for some rather complex code would be marginal.
        !          1880: ;
        !          1881: ; It would be nice if we copied bytes a word or dword at a time. However, it
        !          1882: ; becomes rather complex handling fractional words or dwords, especially when
        !          1883: ; copying right-to-left, so this is left for LATER. I haven't unrolled these
        !          1884: ; loops because of the possibility of this further word/dword optimization;
        !          1885: ; no point in fine-tuning sub-optimal code.
        !          1886: ;
        !          1887: ; Input:
        !          1888: ;       Direction Flag set for desired direction of copy
        !          1889: ;       culWholeBytesWidth = # of bytes to copy across each scan line
        !          1890: ;       ulWholeScanDelta = distance to start of next scan from end of current
        !          1891: ;       ulBlockHeight = # of scans to copy
        !          1892: ;       ulWholeBytesSrc = start source offset in bitmap
        !          1893: ;       ulWholeBytesDest = start dest offset in bitmap
        !          1894: ;       ppTempPlane0 = pointer to pointer to plane 0 storage in temp buffer
        !          1895: ;       ppTempPlane3 = pointer to pointer to plane 3 storage in temp buffer
        !          1896: ;       Expects the source bank to be mapped in; source bank is mapped in on
        !          1897: ;               exit
        !          1898: ;
        !          1899: ; Output:
        !          1900: ;       Advances ulWholeBytesSrc and ulWholeBytesDest to scan after last
        !          1901: ;               scan processed
        !          1902: ;-----------------------------------------------------------------------;
        !          1903: 
        !          1904:         align   4
        !          1905: copy_whole_bytes_via_buffer:
        !          1906: 
        !          1907: ; Calculate start source address from bitmap start address and offset within
        !          1908: ; bitmap.
        !          1909: 
        !          1910:         mov     ecx,pdsurf
        !          1911:         mov     eax,ulWholeBytesSrc
        !          1912:         add     eax,[ecx].dsurf_pvBitmapStart
        !          1913:         mov     pSrcAddr,eax
        !          1914:         sub     eax,[ecx].dsurf_pvStart
        !          1915:         mov     ulOffsetInBank,eax ;will come in handy because we treat the
        !          1916:                                    ; temp buffer as an image of the current
        !          1917:                                    ; bank
        !          1918: 
        !          1919: ; First, copy all the bytes into the temporary buffer.
        !          1920: 
        !          1921: ; Leave the GC Index pointing to the Read Map.
        !          1922: 
        !          1923:         mov     edx,VGA_BASE + GRAF_ADDR
        !          1924:         mov     al,GRAF_READ_MAP
        !          1925:         out     dx,al
        !          1926: 
        !          1927:         mov     eax,3           ;start by copying plane 3
        !          1928: copy_whole_to_buffer_plane_loop:
        !          1929:         mov     ebx,ulBlockHeight  ;# of scans to copy
        !          1930:         mov     esi,pSrcAddr       ;source offset in screen
        !          1931:         mov     edi,ppTempPlane0
        !          1932:         mov     edi,[edi+eax*4]    ;pointer to current plane in temp buffer
        !          1933:         add     edi,ulOffsetInBank ;dest for plane in temp buffer
        !          1934: 
        !          1935:         mov     edx,VGA_BASE + GRAF_DATA
        !          1936:         out     dx,al            ;set Read Map to plane we're copying from.
        !          1937: 
        !          1938:         push    eax             ;remember plane index
        !          1939:         mov     eax,ulWholeScanDelta ;offset to next scan
        !          1940:         mov     edx,culWholeBytesWidth ;# of bytes per scan
        !          1941: copy_whole_to_buffer_scan_loop:
        !          1942:         mov     ecx,edx         ;# of bytes per scan
        !          1943:         rep     movsb           ;copy the scan line to the temp buffer
        !          1944:         add     esi,eax         ;point to next source scan
        !          1945:         add     edi,eax         ;point to next dest scan
        !          1946: 
        !          1947:         dec     ebx              ;count down scan lines
        !          1948:         jnz     copy_whole_to_buffer_scan_loop
        !          1949: 
        !          1950:         pop     eax             ;get back plane index
        !          1951:         dec     eax             ;count down planes
        !          1952:         jns     copy_whole_to_buffer_plane_loop
        !          1953: 
        !          1954: ; Remember where we left off, for next time.
        !          1955: 
        !          1956:         mov     ebx,pdsurf
        !          1957:         sub     esi,[ebx].dsurf_pvBitmapStart
        !          1958:         mov     ulWholeBytesSrc,esi
        !          1959: 
        !          1960: 
        !          1961: ; Now copy the temp buffer to the screen.
        !          1962: 
        !          1963: ; Map in the destination bank, so we can read/write to it  and let the Bit Mask
        !          1964: ; work.
        !          1965: 
        !          1966:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>, \
        !          1967:                 <ebx,ulCurrentDestScan,ulCurrentJustification>
        !          1968: 
        !          1969: ; Calculate dest start address (if this is a 1 R/W adapter, we had to wait
        !          1970: ; until now to calculate this, because the dest bank wasn't mapped earlier).
        !          1971: 
        !          1972:         mov     eax,ulWholeBytesDest
        !          1973:         add     eax,[ebx].dsurf_pvBitmapStart
        !          1974:         mov     pDestAddr,eax
        !          1975: 
        !          1976: ; Set the bit mask to enable all bits.
        !          1977: 
        !          1978:         mov     edx,VGA_BASE + GRAF_ADDR
        !          1979:         mov     eax,(0ffh shl 8) + GRAF_BIT_MASK
        !          1980:         out     dx,ax
        !          1981: 
        !          1982:         mov     dl,SEQ_DATA     ;leave DX pointing to the SC Data reg
        !          1983: 
        !          1984: ; Set up to copy the whole bytes from the buffer.
        !          1985: 
        !          1986:         mov     eax,ulBlockHeight ;# of scans to copy
        !          1987:         mov     culTempCount,eax
        !          1988: 
        !          1989: copy_whole_from_buffer_scan_loop:
        !          1990: 
        !          1991:         mov     ebx,ppTempPlane3  ;point to plane 3's temp buffer offset
        !          1992:         mov     al,MM_C3        ;start by copying plane 3
        !          1993: 
        !          1994: copy_whole_from_buffer_plane_loop:
        !          1995: 
        !          1996: ; Set Map Mask to enable writes to the plane we're copying.
        !          1997: 
        !          1998:         out     dx,al
        !          1999: 
        !          2000: ; Select the corresponding plane from the temp buffer.
        !          2001: 
        !          2002:         mov     esi,[ebx]          ;point to plane start in temp buffer
        !          2003:         add     esi,ulOffsetInBank ;point to current scan start in temp buffer
        !          2004:         mov     edi,pDestAddr      ;point to destination start
        !          2005: 
        !          2006:         mov     ecx,culWholeBytesWidth  ;# of whole bytes to copy
        !          2007:         rep     movsb           ;copy the bytes from the buffer to the screen
        !          2008: 
        !          2009: ; Do next plane, if any.
        !          2010: 
        !          2011:         sub     ebx,4                   ;point to next temp buffer plane ptr
        !          2012:         shr     al,1                    ;advance to next plane
        !          2013:         jnz     copy_whole_from_buffer_plane_loop
        !          2014: 
        !          2015: ; Remember where we left off, for next scan.
        !          2016: 
        !          2017:         add     edi,ulWholeScanDelta    ;point to next dest scan
        !          2018:         mov     pDestAddr,edi
        !          2019:         mov     eax,ulNextScan
        !          2020:         add     ulOffsetInBank,eax      ;next scan's start in temp buffer,
        !          2021:                                         ; relative to start of plane's storage
        !          2022: 
        !          2023: ; Count down scan lines.
        !          2024: 
        !          2025:         dec     culTempCount
        !          2026:         jnz     copy_whole_from_buffer_scan_loop
        !          2027: 
        !          2028: ; Remember where we left off, for next time.
        !          2029: 
        !          2030:         mov     ebx,pdsurf
        !          2031:         sub     edi,[ebx].dsurf_pvBitmapStart
        !          2032:         mov     ulWholeBytesDest,edi
        !          2033: 
        !          2034: ; Put back the original source bank.
        !          2035: 
        !          2036:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl>, \
        !          2037:                 <ebx,ulCurrentSrcScan,ulCurrentJustification>
        !          2038: 
        !          2039:         PLAIN_RET
        !          2040: 
        !          2041: 
        !          2042: ;-----------------------------------------------------------------------;
        !          2043: ; Copies a strip of left edge bytes from the source to the destination,
        !          2044: ; assuming both the source and the destination are both readable and
        !          2045: ; writable. Can only be used by 2 R/W window banking, or by unbanked
        !          2046: ; modes. 1 R/W and 1R/1W adapters must go through an intermediate local
        !          2047: ; buffer when the source and dest are in different banks. Processes up to
        !          2048: ; EDGE_CHUNK_SIZE bytes in each plane at a pop; more bytes might cause
        !          2049: ; flicker.
        !          2050: ;
        !          2051: ; Input:
        !          2052: ;       ulNextScan = width of scan, in bytes
        !          2053: ;       ulBlockHeight = # of scans to copy
        !          2054: ;       ulLeftEdgeSrc = start source offset in bitmap
        !          2055: ;       ulLeftEdgeDest = start dest offset in bitmap
        !          2056: ;       jLeftMask = left edge clip mask
        !          2057: ;
        !          2058: ; Output:
        !          2059: ;       Advances ulLeftEdgeSrc and ulLeftEdgeDest to scan after last
        !          2060: ;               scan processed
        !          2061: ;-----------------------------------------------------------------------;
        !          2062: 
        !          2063:         align   4
        !          2064: copy_left_edge:
        !          2065: 
        !          2066: ; Calculate start source and dest addresses from bitmap start addresses and
        !          2067: ; offsets within bitmap.
        !          2068: 
        !          2069:         mov     ecx,pdsurf
        !          2070:         mov     esi,ulLeftEdgeSrc
        !          2071:         add     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2072:         mov     edi,ulLeftEdgeDest
        !          2073:         add     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          2074: 
        !          2075: ; Copy the edge.
        !          2076: 
        !          2077:         mov     ah,byte ptr jLeftMask   ;clip mask for this edge
        !          2078:         call    copy_edge
        !          2079: 
        !          2080: ; Remember where we left off, for next time.
        !          2081: 
        !          2082:         mov     ecx,pdsurf
        !          2083:         sub     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2084:         mov     ulLeftEdgeSrc,esi
        !          2085:         sub     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          2086:         mov     ulLeftEdgeDest,edi
        !          2087: 
        !          2088:         PLAIN_RET
        !          2089: 
        !          2090: 
        !          2091: ;-----------------------------------------------------------------------;
        !          2092: ; Copies a strip of right edge bytes from the source to the destination,
        !          2093: ; assuming both the source and the destination are both readable and
        !          2094: ; writable. Can only be used by 2 R/W window banking, or by unbanked
        !          2095: ; modes. 1 R/W and 1R/1W adapters must go through an intermediate local
        !          2096: ; buffer when the source and dest are in different banks. Processes up to
        !          2097: ; EDGE_CHUNK_SIZE bytes in each plane at a pop; more bytes might cause
        !          2098: ; flicker.
        !          2099: ;
        !          2100: ; Input:
        !          2101: ;       ulNextScan = width of scan, in bytes
        !          2102: ;       ulBlockHeight = # of scans to copy
        !          2103: ;       ulRightEdgeSrc = start source offset in bitmap
        !          2104: ;       ulRightEdgeDest = start dest offset in bitmap
        !          2105: ;       jRightMask = right edge clip mask
        !          2106: ;
        !          2107: ; Output:
        !          2108: ;       Advances ulRightEdgeSrc and ulRightEdgeDest to scan after last
        !          2109: ;               scan processed
        !          2110: ;-----------------------------------------------------------------------;
        !          2111: 
        !          2112:         align   4
        !          2113: copy_right_edge:
        !          2114: 
        !          2115: ; Calculate start source and dest addresses from bitmap start addresses and
        !          2116: ; offsets within bitmap.
        !          2117: 
        !          2118:         mov     ecx,pdsurf
        !          2119:         mov     esi,ulRightEdgeSrc
        !          2120:         add     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2121:         mov     edi,ulRightEdgeDest
        !          2122:         add     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          2123: 
        !          2124: ; Copy the edge.
        !          2125: 
        !          2126:         mov     ah,byte ptr jRightMask  ;clip mask for this edge
        !          2127:         call    copy_edge
        !          2128: 
        !          2129: ; Remember where we left off, for next time
        !          2130: 
        !          2131:         mov     ecx,pdsurf
        !          2132:         sub     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2133:         mov     ulRightEdgeSrc,esi
        !          2134:         sub     edi,[ecx].dsurf_pvBitmapStart2WindowD
        !          2135:         mov     ulRightEdgeDest,edi
        !          2136: 
        !          2137:         PLAIN_RET
        !          2138: 
        !          2139: 
        !          2140: ;-----------------------------------------------------------------------;
        !          2141: ; Copies an edge from the source to the destination on the screen.
        !          2142: ; Entry:
        !          2143: ;       AH = bit mask setting for edge
        !          2144: ;       ESI = source address
        !          2145: ;       EDI = destination address
        !          2146: ;       ulBlockHeight = # of bytes to copy per plane
        !          2147: ;       ulNextScan = scan width
        !          2148: ;       Source readable, and destination readable and writable
        !          2149: ; Exit:
        !          2150: ;       ESI = next source address
        !          2151: ;       EDI = next destination address
        !          2152: ;
        !          2153: ; Preserved: EBP
        !          2154: ;-----------------------------------------------------------------------;
        !          2155: 
        !          2156:         align   4
        !          2157: copy_edge:
        !          2158:         mov     pSrcAddr,esi
        !          2159:         mov     pDestAddr,edi
        !          2160: 
        !          2161: ; Set the clip mask for this edge.
        !          2162: 
        !          2163:         mov     edx,VGA_BASE + GRAF_ADDR
        !          2164:         mov     al,GRAF_BIT_MASK
        !          2165:         out     dx,ax
        !          2166: 
        !          2167: ; Leave the GC Index pointing to the Read Map.
        !          2168: 
        !          2169:         mov     al,GRAF_READ_MAP
        !          2170:         out     dx,al
        !          2171: 
        !          2172:         mov     ecx,offset copy_edge_rw_full_chunk
        !          2173:                                 ;entry point into unrolled loop to copy first
        !          2174:                                 ; chunk, assuming it's a full chunk
        !          2175:         mov     ebx,ulBlockHeight
        !          2176: 
        !          2177: ; Copy the edge in a series of chunks.
        !          2178: 
        !          2179: copy_edge_chunk_loop:
        !          2180: 
        !          2181:         sub     ebx,EDGE_CHUNK_SIZE ;scans remaining after this chunk, assuming
        !          2182:                                     ; a full chunk
        !          2183:         jge     short @F            ;do a full chunk
        !          2184:         add     ebx,EDGE_CHUNK_SIZE ;not a full chunk; process all remaining
        !          2185:                                     ; scans
        !          2186:         mov     ecx,pfnCopyEdgeRWEntry[-4][ebx*4]
        !          2187:                                 ;entry point into unrolled loop to copy desired
        !          2188:                                 ; chunk size
        !          2189:         sub     ebx,ebx         ;no scans after this
        !          2190: @@:
        !          2191:         push    ebx             ;remember remaining scan count
        !          2192: 
        !          2193:         mov     ah,MM_C3        ;start by copying plane 3
        !          2194:         mov     ebx,ulNextScan
        !          2195: 
        !          2196: copy_edge_plane_loop:
        !          2197: 
        !          2198: ; Set Map Mask to enable writes to plane we're copying.
        !          2199: 
        !          2200:         mov     al,ah
        !          2201:         mov     dl,SEQ_DATA
        !          2202:         out     dx,al
        !          2203: 
        !          2204: ; Set Read Map to same plane.
        !          2205: 
        !          2206:         shr     al,1                    ;map plane into ReadMask
        !          2207:         cmp     al,100b                 ;set Carry if not C3 (plane 3)
        !          2208:         adc     al,-1                   ;sub 1 only if C3
        !          2209:         mov     dl,GRAF_DATA
        !          2210:         out     dx,al
        !          2211: 
        !          2212:         mov     esi,pSrcAddr
        !          2213:         mov     edi,pDestAddr
        !          2214: 
        !          2215:         jmp     ecx                     ;copy the left edge
        !          2216: 
        !          2217: 
        !          2218: ;-----------------------------------------------------------------------;
        !          2219: ; Table of unrolled edge loop entry points. First entry point is to copy
        !          2220: ; 1 byte, last entry point is to copy EDGE_CHUNK_SIZE bytes.
        !          2221: ;-----------------------------------------------------------------------;
        !          2222: 
        !          2223: pfnCopyEdgeRWEntry label dword
        !          2224: INDEX = 1
        !          2225:         rept    EDGE_CHUNK_SIZE
        !          2226:         DEFINE_DD       EDGE_RW,%INDEX
        !          2227: INDEX = INDEX+1
        !          2228:         endm
        !          2229: 
        !          2230: 
        !          2231: ;-----------------------------------------------------------------------;
        !          2232: ; Unrolled loop for copying a strip of edge bytes, with source and
        !          2233: ; destination both readable and writable.
        !          2234: ;-----------------------------------------------------------------------;
        !          2235: 
        !          2236: COPY_EDGE_RW macro ENTRY_LABEL,ENTRY_INDEX
        !          2237: &ENTRY_LABEL&ENTRY_INDEX&:
        !          2238:         mov     al,[esi]        ;get byte to copy
        !          2239:         add     esi,ebx         ;point to next source scan
        !          2240:         xchg    [edi],al        ;read before write so Bit Mask can operate
        !          2241:         add     edi,ebx         ;point to next dest scan
        !          2242:         endm    ;-----------------------------------;
        !          2243: 
        !          2244: ;  EBX = scan line width
        !          2245: ;  ESI = source address to copy from
        !          2246: ;  EDI = target address to copy to
        !          2247: ;  Bit Mask set to desired clipping
        !          2248: ;  Read Map and Map Mask set to enable the desired plane for read and write
        !          2249: 
        !          2250:         align   4
        !          2251: copy_edge_rw_full_chunk:
        !          2252:         UNROLL_LOOP     COPY_EDGE_RW,EDGE_RW,EDGE_CHUNK_SIZE
        !          2253: 
        !          2254: ; Do next plane within this chunk, if any.
        !          2255: 
        !          2256:         shr     ah,1                    ;advance to next plane
        !          2257:         jnz     copy_edge_plane_loop
        !          2258: 
        !          2259: ; Remember where we left off, for the next chunk.
        !          2260: 
        !          2261:         mov     pSrcAddr,esi
        !          2262:         mov     pDestAddr,edi
        !          2263: 
        !          2264: ; Do next chunk within this bank block, if any.
        !          2265: 
        !          2266:         pop     ebx                     ;retrieve remaining scan count
        !          2267:         and     ebx,ebx                 ;any scans left?
        !          2268:         jnz     copy_edge_chunk_loop    ;more scans to do
        !          2269: 
        !          2270:         PLAIN_RET
        !          2271: 
        !          2272: 
        !          2273: ;-----------------------------------------------------------------------;
        !          2274: ; Copies a strip of left edge bytes from the source to the destination
        !          2275: ; through an intermediate RAM buffer. This is the approach required by
        !          2276: ; 1 R/W and 1R/1W adapters when the source and dest are in different banks.
        !          2277: ; Writes up to EDGE_CHUNK_SIZE bytes in each plane at a pop; more bytes might
        !          2278: ; cause flicker.
        !          2279: ;
        !          2280: ; Input:
        !          2281: ;       ulNextScan = width of scan, in bytes
        !          2282: ;       ulBlockHeight = # of scans to copy
        !          2283: ;       ulLeftEdgeSrc = start source offset in bitmap
        !          2284: ;       ulLeftEdgeDest = start dest offset in bitmap
        !          2285: ;       jLeftMask = left edge clip mask
        !          2286: ;       pTempPlane = pointer to temp storage buffer
        !          2287: ;       ulCurrentSrcScan = scan used to map in source bank
        !          2288: ;       ulCurrentDestScan = scan used to map in dest bank
        !          2289: ;       ulCurrentJustification = justification used to map in current bank
        !          2290: ;       For 1 R/W adapters, expects the source bank to be mapped in; banking
        !          2291: ;               is the same at exit as it was at entry
        !          2292: ;
        !          2293: ; Output:
        !          2294: ;       Advances ulLeftEdgeSrc and ulLeftEdgeDest to scan after last
        !          2295: ;               scan processed
        !          2296: ;
        !          2297: ; Note that this should never be called for an unbanked or 2 R/W adapter,
        !          2298: ; because the source and dest are always both addressable simultaneously then.
        !          2299: ;-----------------------------------------------------------------------;
        !          2300: 
        !          2301:         align   4
        !          2302: copy_left_edge_via_buffer:
        !          2303: 
        !          2304: ; First, copy all the bytes into the temporary buffer.
        !          2305: 
        !          2306: ; Calculate start source and dest addresses from bitmap start addresses and
        !          2307: ; offsets within bitmap.
        !          2308: 
        !          2309:         mov     ecx,pdsurf
        !          2310:         mov     esi,ulLeftEdgeSrc
        !          2311:         add     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2312: 
        !          2313: ; Copy the edge from the source to the temp buffer.
        !          2314: 
        !          2315:         call    copy_screen_to_buffered_edge
        !          2316: 
        !          2317: ; Remember where we left off, for next time
        !          2318: 
        !          2319:         mov     ebx,pdsurf
        !          2320:         sub     esi,[ebx].dsurf_pvBitmapStart2WindowS
        !          2321:         mov     ulLeftEdgeSrc,esi
        !          2322: 
        !          2323: ; Now copy the temp buffer to the screen.
        !          2324: 
        !          2325: ; Map in the source bank to match the destination, so we can read/write to it
        !          2326: ; and let the Bit Mask work. Note that on a 1 R/W adapter, both banks will be
        !          2327: ; mapped by this call, which is fine.
        !          2328: 
        !          2329:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          2330:                 <ebx,ulCurrentDestScan,ulCurrentJustification,MapSourceBank>
        !          2331: 
        !          2332: ; Calculate dest start address (if this is a 1 R/W adapter, we had to wait
        !          2333: ; until now to calculate this, because the dest bank wasn't mapped earlier).
        !          2334: 
        !          2335:         mov     edi,ulLeftEdgeDest
        !          2336:         add     edi,[ebx].dsurf_pvBitmapStart2WindowD
        !          2337: 
        !          2338:         mov     ah,byte ptr jLeftMask           ;clip mask for this edge
        !          2339:         call    copy_buffered_edge_to_screen    ;do the copy
        !          2340: 
        !          2341: ; Remember where we left off, for next time.
        !          2342: 
        !          2343:         mov     ebx,pdsurf
        !          2344:         sub     edi,[ebx].dsurf_pvBitmapStart2WindowD
        !          2345:         mov     ulLeftEdgeDest,edi
        !          2346: 
        !          2347: ; Put back the original source bank.  Note that on a 1 R/W adapter, both banks
        !          2348: ; will be mapped by this call, which is fine.
        !          2349: 
        !          2350:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          2351:                 <ebx,ulCurrentSrcScan,ulCurrentJustification,MapSourceBank>
        !          2352: 
        !          2353:         PLAIN_RET
        !          2354: 
        !          2355: 
        !          2356: ;-----------------------------------------------------------------------;
        !          2357: ; Copies a strip of right edge bytes from the source to the destination
        !          2358: ; through an intermediate RAM buffer. This is the approach required by
        !          2359: ; 1 R/W and 1R/1W adapters when the source and dest are in different banks.
        !          2360: ; Writes up to EDGE_CHUNK_SIZE bytes in each plane at a pop; more bytes might
        !          2361: ; cause flicker.
        !          2362: ;
        !          2363: ; Input:
        !          2364: ;       ulNextScan = width of scan, in bytes
        !          2365: ;       ulBlockHeight = # of scans to copy
        !          2366: ;       ulRightEdgeSrc = start source offset in bitmap
        !          2367: ;       ulRightEdgeDest = start dest offset in bitmap
        !          2368: ;       jRightMask = right edge clip mask
        !          2369: ;       pTempPlane = pointer to temp storage buffer
        !          2370: ;       ulCurrentSrcScan = scan used to map in source bank
        !          2371: ;       ulCurrentDestScan = scan used to map in dest bank
        !          2372: ;       ulCurrentJustification = justification used to map in current bank
        !          2373: ;       For 1 R/W adapters, expects the source bank to be mapped in; banking
        !          2374: ;               is the same at exit as it was at entry
        !          2375: ;
        !          2376: ; Output:
        !          2377: ;       Advances ulRightEdgeSrc and ulRightEdgeDest to scan after last
        !          2378: ;               scan processed
        !          2379: ;
        !          2380: ; Note that this should never be called for an unbanked or 2 R/W adapter,
        !          2381: ; because the source and dest are always both addressable simultaneously then.
        !          2382: ;-----------------------------------------------------------------------;
        !          2383: 
        !          2384:         align   4
        !          2385: copy_right_edge_via_buffer:
        !          2386: 
        !          2387: ; First, copy all the bytes into the temporary buffer.
        !          2388: 
        !          2389: ; Calculate start source address from bitmap start addresses and
        !          2390: ; offsets within bitmap.
        !          2391: 
        !          2392:         mov     ecx,pdsurf
        !          2393:         mov     esi,ulRightEdgeSrc
        !          2394:         add     esi,[ecx].dsurf_pvBitmapStart2WindowS
        !          2395: 
        !          2396: ; Copy the edge from the source to the temp buffer.
        !          2397: 
        !          2398:         call    copy_screen_to_buffered_edge
        !          2399: 
        !          2400: ; Remember where we left off, for next time
        !          2401: 
        !          2402:         mov     ebx,pdsurf
        !          2403:         sub     esi,[ebx].dsurf_pvBitmapStart2WindowS
        !          2404:         mov     ulRightEdgeSrc,esi
        !          2405: 
        !          2406: ; Now copy the temp buffer to the screen.
        !          2407: 
        !          2408: ; Map in the source bank to match the destination, so we can read/write to it
        !          2409: ; and let the Bit Mask work. Note that on a 1 R/W adapter, both banks will be
        !          2410: ; mapped by this call, which is correct.
        !          2411: 
        !          2412:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          2413:                 <ebx,ulCurrentDestScan,ulCurrentJustification,MapSourceBank>
        !          2414: 
        !          2415: ; Calculate dest start address (if this is a 1 R/W adapter, we had to wait
        !          2416: ; until now to calculate this, because the dest bank wasn't mapped earlier).
        !          2417: 
        !          2418:         mov     edi,ulRightEdgeDest
        !          2419:         add     edi,[ebx].dsurf_pvBitmapStart2WindowD
        !          2420: 
        !          2421:         mov     ah,byte ptr jRightMask          ;clip mask for this edge
        !          2422:         call    copy_buffered_edge_to_screen    ;do the copy
        !          2423: 
        !          2424: ; Remember where we left off, for next time.
        !          2425: 
        !          2426:         mov     ebx,pdsurf
        !          2427:         sub     edi,[ebx].dsurf_pvBitmapStart2WindowD
        !          2428:         mov     ulRightEdgeDest,edi
        !          2429: 
        !          2430: ; Put back the original source bank.  Note that on a 1 R/W adapter, both banks
        !          2431: ; will be mapped by this call, which is fine.
        !          2432: 
        !          2433:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
        !          2434:                 <ebx,ulCurrentSrcScan,ulCurrentJustification,MapSourceBank>
        !          2435: 
        !          2436:         PLAIN_RET
        !          2437: 
        !          2438: 
        !          2439: ;-----------------------------------------------------------------------;
        !          2440: ; Copies an edge from the temp buffer to the screen.
        !          2441: ; Entry:
        !          2442: ;       AH = bit mask setting for edge
        !          2443: ;       DH = VGA_BASE SHR 8
        !          2444: ;       EDI = destination address
        !          2445: ;       pTempPlane = temp buffer from which to copy
        !          2446: ;       ulBlockHeight = # of bytes to copy per plane
        !          2447: ;       ulNextScan = scan width
        !          2448: ;       Source and dest banks both pointing to destination
        !          2449: ; Exit:
        !          2450: ;       EDI = next destination address
        !          2451: ;
        !          2452: ; Preserved: EBP
        !          2453: ;-----------------------------------------------------------------------;
        !          2454: 
        !          2455:         align   4
        !          2456: copy_buffered_edge_to_screen:
        !          2457: 
        !          2458:         mov     pDestAddr,edi
        !          2459: 
        !          2460:         mov     dl,GRAF_ADDR
        !          2461:         mov     al,GRAF_BIT_MASK
        !          2462:         out     dx,ax
        !          2463: 
        !          2464:         mov     pTempEntry,offset copy_edge_from_buf_full_chunk
        !          2465:                                 ;entry point into unrolled loop to copy first
        !          2466:                                 ; chunk, assuming it's a full chunk
        !          2467:         mov     ecx,pTempPlane  ;temp buffer start (copy from here)
        !          2468:         mov     ebx,ulBlockHeight ;total # of scans to copy
        !          2469: 
        !          2470: ; Copy the edge in a series of chunks, to avoid flicker.
        !          2471: 
        !          2472: copy_from_buffer_chunk_loop:
        !          2473: 
        !          2474:         sub     ebx,EDGE_CHUNK_SIZE ;scans remaining after this chunk, assuming
        !          2475:                                     ; a full chunk
        !          2476:         jge     short @F            ;do a full chunk
        !          2477:         add     ebx,EDGE_CHUNK_SIZE ;not a full chunk; process all remaining
        !          2478:                                     ; scans
        !          2479:         mov     ebx,pfnCopyEdgesFromBufferEntry[-4][ebx*4]
        !          2480:         mov     pTempEntry,ebx  ;entry point into unrolled loop to copy desired
        !          2481:                                 ; chunk size
        !          2482:         sub     ebx,ebx         ;no scans after this
        !          2483: @@:
        !          2484:         push    ebx             ;remember remaining scan count
        !          2485: 
        !          2486:         mov     al,MM_C3        ;start by copying plane 3
        !          2487:         mov     ebx,ulNextScan
        !          2488: 
        !          2489:         push    ecx             ;remember current temp buffer start
        !          2490: 
        !          2491:         mov     dl,SEQ_DATA     ;leave DX pointing to Sequencer Data reg
        !          2492: copy_from_buffer_plane_loop:
        !          2493: 
        !          2494: ; Set Map Mask to enable writes to plane we're copying.
        !          2495: 
        !          2496:         out     dx,al
        !          2497: 
        !          2498: ; Calculate the equivalent Read Map, and use that to select the correct plane
        !          2499: ; from the temp buffer.
        !          2500: 
        !          2501:         mov     esi,ecx                 ;point to current plane's source byte
        !          2502:         add     ecx,ulBlockHeight       ;point to next plane's source byte
        !          2503: 
        !          2504:         mov     edi,pDestAddr
        !          2505: 
        !          2506:         jmp     pTempEntry              ;copy the left edge
        !          2507: 
        !          2508: 
        !          2509: ;-----------------------------------------------------------------------;
        !          2510: ; Table of unrolled edge copy-from-buffer loop entry points. First entry
        !          2511: ; point is to copy 1 byte, last entry point is to copy EDGE_CHUNK_SIZE
        !          2512: ; bytes.
        !          2513: ;-----------------------------------------------------------------------;
        !          2514: 
        !          2515: pfnCopyEdgesFromBufferEntry label dword
        !          2516: INDEX = 1
        !          2517:         rept    EDGE_CHUNK_SIZE
        !          2518:         DEFINE_DD       EDGE_FROM_BUFFER,%INDEX
        !          2519: INDEX = INDEX+1
        !          2520:         endm
        !          2521: 
        !          2522: 
        !          2523: ;-----------------------------------------------------------------------;
        !          2524: ; Unrolled loop for copying a strip of edge bytes from the temp buffer.
        !          2525: ;-----------------------------------------------------------------------;
        !          2526: 
        !          2527: COPY_EDGE_FROM_BUFFER macro ENTRY_LABEL,ENTRY_INDEX
        !          2528: &ENTRY_LABEL&ENTRY_INDEX&:
        !          2529:         mov     ah,[esi]        ;get byte to copy
        !          2530:         inc     esi             ;point to next source (temp buffer) byte
        !          2531:         xchg    [edi],ah        ;read before write so Bit Mask can operate
        !          2532:         add     edi,ebx         ;point to next dest (screen) scna
        !          2533:         endm    ;-----------------------------------;
        !          2534: 
        !          2535: ;  EBX = scan line width
        !          2536: ;  ESI = source address to copy from (temp buffer)
        !          2537: ;  EDI = target address to copy to (screen)
        !          2538: ;  Bit Mask set to desired clipping
        !          2539: ;  Map Mask set to enable the desired plane for write
        !          2540: 
        !          2541:         align   4
        !          2542: copy_edge_from_buf_full_chunk:
        !          2543:         UNROLL_LOOP     COPY_EDGE_FROM_BUFFER,EDGE_FROM_BUFFER,EDGE_CHUNK_SIZE
        !          2544: 
        !          2545: ; Do next plane within this chunk, if any.
        !          2546: 
        !          2547:         shr     al,1                    ;advance to next plane
        !          2548:         jnz     copy_from_buffer_plane_loop
        !          2549: 
        !          2550: ; Remember where we left off, for next chunk.
        !          2551: 
        !          2552:         mov     pDestAddr,edi
        !          2553:         pop     ecx             ;get back current temp buffer start
        !          2554:         add     ecx,EDGE_CHUNK_SIZE ;point to next chunk's start
        !          2555: 
        !          2556: ; Do next chunk within this bank block, if any.
        !          2557: 
        !          2558:         pop     ebx                     ;retrieve remaining scan count
        !          2559:         and     ebx,ebx                 ;any scans left?
        !          2560:         jnz     copy_from_buffer_chunk_loop    ;more scans to do
        !          2561: 
        !          2562:         PLAIN_RET
        !          2563: 
        !          2564: 
        !          2565: ;-----------------------------------------------------------------------;
        !          2566: ; Copies an edge from the screen to the temp buffer.
        !          2567: ; Entry:
        !          2568: ;       ESI = source address
        !          2569: ;       pTempPlane = temp buffer from which to copy
        !          2570: ;       ulBlockHeight = # of bytes to copy per plane
        !          2571: ;       ulNextScan = scan width
        !          2572: ;       Source bank pointing to source
        !          2573: ; Exit:
        !          2574: ;       DH = VGA_BASE SHR 8
        !          2575: ;       ESI = next source address
        !          2576: ;
        !          2577: ; Preserved: EBP
        !          2578: ;-----------------------------------------------------------------------;
        !          2579: 
        !          2580:         align   4
        !          2581: copy_screen_to_buffered_edge:
        !          2582: 
        !          2583:         mov     pSrcAddr,esi
        !          2584: 
        !          2585: ; Leave the GC Index pointing to the Read Map.
        !          2586: 
        !          2587:         mov     edx,VGA_BASE + GRAF_ADDR
        !          2588:         mov     al,GRAF_READ_MAP
        !          2589:         out     dx,al
        !          2590: 
        !          2591:         mov     ebx,ulBlockHeight
        !          2592:         SET_UP_UNROLL_VARS ebx,ecx,ebx,pfnCopyEdgeToTempEntry, \
        !          2593:                                 LOOP_UNROLL_SHIFT
        !          2594:         mov     culTempCount,ebx ;remember # of unrolled loop iterations
        !          2595:         mov     pTempEntry,ecx   ;ditto for entry point
        !          2596: 
        !          2597:         mov     ecx,ulNextScan
        !          2598:         mov     edi,pTempPlane  ;dest offset in temp buffer for plane 3 bytes.
        !          2599:                                 ;The rest of the planes are stored
        !          2600:                                 ; consecutively
        !          2601:         mov     al,3            ;start by copying plane 3
        !          2602:         mov     dl,GRAF_DATA    ;leave DX pointing to GC Data reg
        !          2603: copy_edge_to_buffer_plane_loop:
        !          2604:         mov     esi,pSrcAddr ;source pointer
        !          2605: 
        !          2606:         out     dx,al            ;set Read Map to plane we're copying from.
        !          2607: 
        !          2608:         mov     ebx,culTempCount ;# of unrolled loop iterations
        !          2609:         jmp     pTempEntry       ;copy the edge bytes for this plane to the
        !          2610:                                  ; temp buffer
        !          2611: 
        !          2612: ;-----------------------------------------------------------------------;
        !          2613: ; Table of unrolled edge copy to temp buffer loop entry points.
        !          2614: ;-----------------------------------------------------------------------;
        !          2615: 
        !          2616:         UNROLL_LOOP_ENTRY_TABLE pfnCopyEdgeToTempEntry,EDGE_TO_TEMP, \
        !          2617:                                 LOOP_UNROLL_COUNT
        !          2618: 
        !          2619: ;-----------------------------------------------------------------------;
        !          2620: ; Unrolled loop for copying edge bytes to the temp buffer.
        !          2621: ;-----------------------------------------------------------------------;
        !          2622: 
        !          2623: COPY_EDGE_TO_TEMP macro ENTRY_LABEL,ENTRY_INDEX
        !          2624: &ENTRY_LABEL&ENTRY_INDEX&:
        !          2625:         mov     ah,[esi]        ;get byte to copy
        !          2626:         add     esi,ecx         ;point to next source scan
        !          2627:         mov     [edi],ah        ;copy byte to temp buffer
        !          2628:         inc     edi             ;point to next temp buffer byte
        !          2629:         endm    ;-----------------------------------;
        !          2630: 
        !          2631: ;  EBX = count of unrolled loop iterations
        !          2632: ;  ECX = offset from end of one scan's fill to start of next
        !          2633: ;  ESI = source address to copy from (screen)
        !          2634: ;  EDI = target address to copy to (temp buffer)
        !          2635: ;  Read Map set to enable the desired plane for read
        !          2636: 
        !          2637:         align   4
        !          2638: edge_to_buffer_loop:
        !          2639:         UNROLL_LOOP     COPY_EDGE_TO_TEMP,EDGE_TO_TEMP,LOOP_UNROLL_COUNT
        !          2640:         dec     ebx
        !          2641:         jnz     edge_to_buffer_loop
        !          2642: 
        !          2643:         dec     al               ;count down planes
        !          2644:         jns     copy_edge_to_buffer_plane_loop
        !          2645: 
        !          2646:         PLAIN_RET
        !          2647: 
        !          2648: 
        !          2649: ;-----------------------------------------------------------------------;
        !          2650: 
        !          2651: endProc vAlignedSrcCopy
        !          2652: 
        !          2653: _TEXT$03   ends
        !          2654: 
        !          2655:         end
        !          2656: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.