Annotation of ntddk/src/video/displays/vga256/i386/scroll.asm, revision 1.1

1.1     ! root        1: ;---------------------------Module-Header------------------------------;
        !             2: ; Module Name: scroll.asm
        !             3: ;
        !             4: ; Copyright (c) 1992-1993 Microsoft Corporation
        !             5: ;-----------------------------------------------------------------------;
        !             6: 
        !             7: ;-----------------------------------------------------------------------;
        !             8: ; VOID vPlanarCopyBits(ppdev, prclDest, pptlSrc);
        !             9: ;
        !            10: ; Input:
        !            11: ;
        !            12: ;  ppdev    - surface on which to copy
        !            13: ;  prcldest - pointer to destination rectangle
        !            14: ;  pptlsrc  - pointer to source upper left corner
        !            15: ;
        !            16: ; Performs accelerated SRCCOPY screen-to-screen blts.
        !            17: ;
        !            18: ;-----------------------------------------------------------------------;
        !            19: ;
        !            20: ; NOTE: This handles only quad-pixel aligned blits!
        !            21: ;
        !            22: ; NOTE: Assumes all rectangles have positive heights and widths. Will
        !            23: ; not work properly if this is not the case.
        !            24: ;
        !            25: ;-----------------------------------------------------------------------;
        !            26: 
        !            27: 
        !            28: ;-----------------------------------------------------------------------;
        !            29: ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want loops in
        !            30: ; this module unrolled. For example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8
        !            31: ; times unrolling. This is the only thing you need to change to control
        !            32: ; unrolling.
        !            33: 
        !            34: LOOP_UNROLL_SHIFT equ 2
        !            35: 
        !            36: ;-----------------------------------------------------------------------;
        !            37: 
        !            38:         .386
        !            39: 
        !            40:         .model  small,c
        !            41: 
        !            42:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        !            43:         assume fs:nothing,gs:nothing
        !            44: 
        !            45:         .xlist
        !            46:         include stdcall.inc             ;calling convention cmacros
        !            47:         include i386\strucs.inc
        !            48:         include i386\driver.inc
        !            49:         include i386\unroll.inc
        !            50:         include i386\egavga.inc
        !            51: 
        !            52:         .list
        !            53: 
        !            54: ;-----------------------------------------------------------------------;
        !            55: 
        !            56:         .data
        !            57: 
        !            58:         EXTRNP          bPuntScreenToScreenCopyBits,20
        !            59: 
        !            60: ; Bits for block copier tables:
        !            61: 
        !            62: BLOCK_RIGHT_TO_LEFT     equ 4
        !            63: BLOCK_LEFT_EDGE         equ 2
        !            64: BLOCK_RIGHT_EDGE        equ 1
        !            65: 
        !            66: ;-----------------------------------------------------------------------;
        !            67: ; Table of block copiers for various horizontal directions, with the
        !            68: ; look-up index a 3-bit field as follows:
        !            69: ;
        !            70: ; Bit 2 (BLOCK_RIGHT_TO_LEFT) = 1 if right-to-left copy
        !            71: ; Bit 1 (BLOCK_LEFT_EDGE)     = 1 if left edge must be copied
        !            72: ; Bit 0 (BLOCK_RIGHT_EDGE)    = 1 if right edge must be copied
        !            73: 
        !            74:         align   4
        !            75: MasterBlockTable label dword
        !            76: 
        !            77:         dd      copy_just_middle_block
        !            78:         dd      Block_WR
        !            79:         dd      Block_LW
        !            80:         dd      Block_LWR
        !            81: 
        !            82:         dd      copy_just_middle_block
        !            83:         dd      Block_RW
        !            84:         dd      Block_WL
        !            85:         dd      Block_RWL
        !            86: 
        !            87:         align   4
        !            88: TopToBottomLoopTable label dword
        !            89:         dd      0                               ;Not used - unbanked case
        !            90:         dd      top_to_bottom_1RW
        !            91:         dd      top_to_bottom_2RW
        !            92:         dd      top_to_bottom_2RW
        !            93: 
        !            94:         align   4
        !            95: BottomToTopLoopTable label dword
        !            96:         dd      0                               ;Not used - unbanked case
        !            97:         dd      bottom_to_top_1RW
        !            98:         dd      bottom_to_top_2RW
        !            99:         dd      bottom_to_top_2RW
        !           100: 
        !           101:         align   4
        !           102: SetUpForCopyDirection label dword
        !           103:         dd      left_to_right_top_to_bottom     ;CD_RIGHTDOWN
        !           104:         dd      right_to_left_top_to_bottom     ;CD_LEFTDOWN
        !           105:         dd      left_to_right_bottom_to_top     ;CD_RIGHTUP
        !           106:         dd      right_to_left_bottom_to_top     ;CD_LEFTUP
        !           107: 
        !           108: LeftMaskTable label dword
        !           109:         dd      01111b
        !           110:         dd      01110b
        !           111:         dd      01100b
        !           112:         dd      01000b
        !           113: 
        !           114: RightMaskTable label dword
        !           115:         dd      00000b
        !           116:         dd      00001b
        !           117:         dd      00011b
        !           118:         dd      00111b
        !           119: 
        !           120: ;-----------------------------------------------------------------------;
        !           121: 
        !           122:         .code
        !           123: 
        !           124:         align   4
        !           125: Block_WR:
        !           126:         push    offset copy_right_block
        !           127:         jmp     copy_middle_block
        !           128: 
        !           129:         align   4
        !           130: Block_LW:
        !           131:         push    offset copy_middle_block
        !           132:         jmp     copy_left_block
        !           133: 
        !           134:         align   4
        !           135: Block_LWR:
        !           136:         push    offset copy_right_block
        !           137:         push    offset copy_middle_block
        !           138:         jmp     copy_left_block
        !           139: 
        !           140:         align   4
        !           141: Block_RW:
        !           142:         push    offset copy_middle_block
        !           143:         jmp     copy_right_block
        !           144: 
        !           145:         align   4
        !           146: Block_WL:
        !           147:         push    offset copy_left_block
        !           148:         jmp     copy_middle_block
        !           149: 
        !           150:         align   4
        !           151: Block_RWL:
        !           152:         push    offset copy_left_block
        !           153:         push    offset copy_middle_block
        !           154:         jmp     copy_right_block
        !           155: 
        !           156: ;-----------------------------------------------------------------------;
        !           157: 
        !           158: cProc   vPlanarCopyBits,12,<    \
        !           159:         uses esi edi ebx,       \
        !           160:         ppdev:    ptr PDEV,     \
        !           161:         prclDest: ptr RECTL,    \
        !           162:         pptlSrc:  ptr POINTL    >
        !           163: 
        !           164: ; Variables used in block copiers:
        !           165: 
        !           166:         local pfnCopyBlocks:       ptr   ;pointer to block copy routines
        !           167: 
        !           168:         local ulMiddleSrc:         dword ;bitmap offset to 1st source
        !           169:         local ulMiddleDest:        dword ;bitmap offset to 1st dest
        !           170:         local lMiddleDelta:        dword ;delta from end of middle scan to next
        !           171:         local ulBlockHeight:       dword ;number of scans to be copied in block
        !           172:         local cjMiddle:            dword ;number of bytes to be copied on scan
        !           173: 
        !           174:         local ulLeftSrc:           dword ;bitmap offset to left source byte edge
        !           175:         local ulLeftDest:          dword ;bitmap offset to left dest byte edge
        !           176:         local ulRightSrc:          dword ;bitmap offset to right source byte edge
        !           177:         local ulRightDest:         dword ;bitmap offset to right dest byte edge
        !           178:         local lDelta:              dword ;delta between scans
        !           179: 
        !           180:         local ulLeftMask:          dword ;byte mask for left-edge copies
        !           181:         local ulRightMask:         dword ;byte mask for right-edge copies
        !           182: 
        !           183:         local rclDest[size RECTL]: byte  ;left and right values always valid
        !           184:         local ptlSrc[size POINTL]: byte  ;x value always valid
        !           185: 
        !           186:         local ulCurrentSrcScan:    dword ;real current source scan
        !           187:         local ulCurrentDestScan:   dword ;real current destination scan
        !           188:         local ulLastDestScan:      dword ;last destination scan
        !           189: 
        !           190: ; Set the bit mask to disable all bits, so we can copy through the latches:
        !           191: 
        !           192:         mov     edx,VGA_BASE + GRAF_ADDR
        !           193:         mov     eax,(0 shl 8) + GRAF_BIT_MASK
        !           194:         out     dx,ax
        !           195: 
        !           196: ; Figure out which direction to do the copies:
        !           197: 
        !           198:         mov     esi,pptlSrc
        !           199:         mov     edi,prclDest
        !           200:         mov     eax,[esi].ptl_y
        !           201:         cmp     eax,[edi].yTop
        !           202:         jl      planar_bottom_to_top
        !           203: 
        !           204:         mov     eax,[esi].ptl_x
        !           205:         cmp     eax,[edi].xLeft
        !           206:         jge     short left_to_right_top_to_bottom       ; CD_RIGHTDOWN
        !           207:         jmp     right_to_left_top_to_bottom             ; CD_LEFTDOWN
        !           208: 
        !           209:         align   4
        !           210: planar_bottom_to_top:
        !           211:         mov     eax,[esi].ptl_x
        !           212:         cmp     eax,[edi].xLeft
        !           213:         jge     left_to_right_bottom_to_top             ; CD_RIGHTUP
        !           214:         jmp     right_to_left_bottom_to_top             ; CD_LEFTUP
        !           215: 
        !           216:         align   4
        !           217: all_done:
        !           218: 
        !           219: ; Enable bit mask for all bits:
        !           220: 
        !           221:         mov     edx,VGA_BASE + GRAF_ADDR
        !           222:         mov     eax,(0ffh shl 8) + GRAF_BIT_MASK
        !           223:         out     dx,ax
        !           224: 
        !           225: ; Enable writes to all planes and reset direction flag:
        !           226: 
        !           227:         mov     edx,VGA_BASE + SEQ_DATA
        !           228:         mov     al,MM_ALL
        !           229:         out     dx,al
        !           230: 
        !           231:         cld
        !           232: 
        !           233:         cRet    vPlanarCopyBits
        !           234: 
        !           235: ;=======================================================================;
        !           236: ;==================== Direction Dependent Setup ========================;
        !           237: ;=======================================================================;
        !           238: 
        !           239: ;-----------------------------------------------------------------------;
        !           240: ; Set-up code for left-to-right, top-to-bottom copies.
        !           241: ;
        !           242: ; Input:
        !           243: ;       esi - pptlSrc
        !           244: ;       edi - prclDest
        !           245: ;-----------------------------------------------------------------------;
        !           246: 
        !           247:         align   4
        !           248:         public left_to_right_top_to_bottom
        !           249: left_to_right_top_to_bottom:
        !           250: 
        !           251: ; Need to set-up: ulMiddleSrc, ulMiddleDest, lMiddleDelta, cjMiddle
        !           252: ;                 ulLeftSrc, ulLeftDest, ulLeftMask
        !           253: ;                 lDelta
        !           254: ;                 ulRightSrc, ulRightDest, ulRightMask
        !           255: ;                 ulCurrentDestScan, ulLastDestScan
        !           256: ;                 pfnCopyBlocks
        !           257: ;                 ptlSrc.x, rclDest.left, rclDest.right
        !           258: 
        !           259: ; lDelta = ppdev->lPlanarScan
        !           260: ; ulCurrentSrcScan  = pptl->y
        !           261: ; ulLeftSrc         = pptl->y       * lDelta + (pptl->x >> 2)
        !           262: ; ulCurrentDestScan = prclDest->top
        !           263: ; ulLeftDest        = prclDest->top * lDelta + (prclDest->left >> 2)
        !           264: ;
        !           265: ; ulMiddleSrc  = ulLeftSrc
        !           266: ; ulMiddleDest = ulLeftDest
        !           267: ;
        !           268: ; cjMiddle = (prclDest->right >> 2) - (prclDest->left >> 2)
        !           269: ; if (prclDest->left & 3)
        !           270: ;     ulLeftMask = LeftMaskTable[prclDest->left & 3]
        !           271: ;     fl |= BLOCK_LEFT_EDGE
        !           272: ;     ulMiddleSrc++
        !           273: ;     ulMiddleDest++
        !           274: ;     cjMiddle--
        !           275: ;
        !           276: ; lMiddleDelta = lDelta - cjMiddle
        !           277: ;
        !           278: ; if (prclDest->right & 3)
        !           279: ;     ulRightMask = RightMaskTable[prclDest->right & 3]
        !           280: ;     fl |= BLOCK_RIGHT_EDGE
        !           281: ;     ulRightSrc  = ulMiddleSrc  + cjMiddle
        !           282: ;     ulRightDest = ulMiddleDest + cjMiddle
        !           283: 
        !           284:         mov     edx,ppdev
        !           285:         mov     eax,[edi].yBottom
        !           286:         mov     edx,[edx].pdev_lPlanarNextScan ;edx = lDelta
        !           287:         mov     ulLastDestScan,eax      ;ulLastDestScan = prclDest->bottom
        !           288: 
        !           289:         mov     ecx,[esi].ptl_y
        !           290:         mov     eax,edx
        !           291:         mov     ulCurrentSrcScan,ecx    ;ulCurrentSrcScan = pptlSrc->y
        !           292:         imul    eax,ecx
        !           293:         mov     ecx,[esi].ptl_x
        !           294:         mov     ptlSrc.ptl_x,ecx        ;ptlSrc.x = pptlSrc->x
        !           295:         shr     ecx,2
        !           296:         add     eax,ecx                 ;eax = ulLeftSrc = pptlSrc->y *
        !           297:                                         ;  lDelta + (pptlSrc->x >> 2)
        !           298: 
        !           299:         xor     esi,esi                 ;initialize flags
        !           300: 
        !           301:         mov     ecx,[edi].yTop
        !           302:         mov     ebx,edx
        !           303:         mov     ulCurrentDestScan,ecx   ;ulCurrentDestScan = prclDest->top
        !           304:         imul    ebx,ecx
        !           305:         mov     ecx,[edi].xLeft
        !           306:         mov     rclDest.xLeft,ecx       ;rclDest.left = prclDest->left
        !           307:         shr     ecx,2
        !           308:         add     ebx,ecx                 ;ebx = ulLeftDest = prclDest->top *
        !           309:                                         ;  lDelta + (prclDest->left >> 2)
        !           310: 
        !           311:         mov     edi,[edi].xRight
        !           312:         mov     rclDest.xRight,edi
        !           313:         shr     edi,2
        !           314:         sub     edi,ecx                 ;cjMiddle = (prclDest->right >> 2) -
        !           315:                                         ;  (prclDest->left >> 2)
        !           316: 
        !           317:         mov     ecx,rclDest.xLeft
        !           318:         and     ecx,3
        !           319:         jz      short l_t_done_left_edge ;skip if we don't need a left edge
        !           320: 
        !           321:         or      esi,BLOCK_LEFT_EDGE
        !           322:         mov     ecx,LeftMaskTable[ecx*4]
        !           323:         mov     ulLeftMask,ecx          ;ulLeftMask =
        !           324:                                         ;  LeftMaskTable[prclDest->left & 3]
        !           325: 
        !           326:         mov     ulLeftSrc,eax           ;ulLeftSrc
        !           327:         mov     ulLeftDest,ebx          ;ulLeftDest
        !           328:         inc     eax
        !           329:         inc     ebx
        !           330:         dec     edi
        !           331: 
        !           332: l_t_done_left_edge:
        !           333:         mov     ulMiddleSrc,eax         ;ulMiddleSrc
        !           334:         mov     ulMiddleDest,ebx        ;ulMiddleDest
        !           335: 
        !           336:         mov     ecx,rclDest.xRight
        !           337:         and     ecx,3
        !           338:         jz      short l_t_done_right_edge ;skip if we don't need a right edge
        !           339: 
        !           340:         or      esi,BLOCK_RIGHT_EDGE
        !           341:         mov     ecx,RightMaskTable[ecx*4]
        !           342:         mov     ulRightMask,ecx         ;ulRightMask =
        !           343:                                         ;  RightMaskTable[prclDest->right & 3]
        !           344: 
        !           345:         add     eax,edi
        !           346:         add     ebx,edi
        !           347:         mov     ulRightSrc,eax          ;ulRightSrc = ulMiddleSrc + cjMiddle
        !           348:         mov     ulRightDest,ebx         ;ulRightDest = ulMiddleDest + cjMiddle
        !           349: 
        !           350: ; We special case here blits that are less than 4 pels wide and begin and end
        !           351: ; in the same 4-pel quadruple:
        !           352: 
        !           353:         cmp     edi,0
        !           354:         jge     l_t_done_right_edge
        !           355: 
        !           356: ; We make sure the 'middle' count of bytes is zero (we'll just let the code
        !           357: ; fall through the 'middle' copy code), turn off the right-edge flag, and
        !           358: ; give ulLeftMask the composite mask:
        !           359: 
        !           360:         inc     edi
        !           361:         xor     esi,BLOCK_RIGHT_EDGE
        !           362:         and     ecx,ulLeftMask
        !           363:         mov     ulLeftMask,ecx
        !           364: 
        !           365:         align   4
        !           366: l_t_done_right_edge:
        !           367:         mov     cjMiddle,edi            ;cjMiddle
        !           368: 
        !           369:         mov     lDelta,edx              ;lDelta = ppdev->lPlanarNextScan
        !           370:         sub     edx,edi
        !           371:         mov     lMiddleDelta,edx        ;lMiddleDelta = lDelta - cjMiddle
        !           372: 
        !           373:         mov     ebx,ppdev
        !           374:         mov     eax,MasterBlockTable[esi*4]
        !           375:         mov     pfnCopyBlocks,eax       ;copy blocks between video memory
        !           376: 
        !           377: ; Branch to the appropriate top-to-bottom bank enumeration loop:
        !           378: 
        !           379:         mov     eax,[ebx].pdev_vbtPlanarType
        !           380:         jmp     TopToBottomLoopTable[eax*4]
        !           381: 
        !           382: ;-----------------------------------------------------------------------;
        !           383: ; Set-up code for right-to-left, top-to-bottom copies.
        !           384: ;
        !           385: ; Input:
        !           386: ;       esi - pptlSrc
        !           387: ;       edi - prclDest
        !           388: ;-----------------------------------------------------------------------;
        !           389: 
        !           390:         align   4
        !           391:         public right_to_left_top_to_bottom
        !           392: right_to_left_top_to_bottom:
        !           393: 
        !           394:         std                             ;copy middle blocks right-to-left
        !           395: 
        !           396:         mov     edx,ppdev
        !           397:         mov     eax,[edi].yBottom
        !           398:         mov     edx,[edx].pdev_lPlanarNextScan ;edx = lDelta
        !           399:         mov     ulLastDestScan,eax      ;ulLastDestScan = prclDest->bottom
        !           400: 
        !           401:         mov     ecx,[esi].ptl_y
        !           402:         mov     eax,edx
        !           403:         mov     ulCurrentSrcScan,ecx    ;ulCurrentSrcScan = pptlSrc->y
        !           404:         imul    eax,ecx
        !           405:         mov     ecx,[esi].ptl_x
        !           406:         mov     ptlSrc.ptl_x,ecx        ;ptlSrc.x = pptlSrc->x
        !           407:         add     ecx,[edi].xRight
        !           408:         sub     ecx,[edi].xLeft
        !           409:         shr     ecx,2
        !           410:         add     eax,ecx                 ;eax = ulRightSrc = pptlSrc->y *
        !           411:                                         ; lDelta + (pptlSrc->x +
        !           412:                                         ; prclDest->right - prclDest->left) / 4
        !           413: 
        !           414:         mov     esi,BLOCK_RIGHT_TO_LEFT ;initialize flags
        !           415: 
        !           416:         mov     ecx,[edi].yTop
        !           417:         mov     ebx,edx
        !           418:         mov     ulCurrentDestScan,ecx   ;ulCurrentDestScan = prclDest->top
        !           419:         imul    ebx,ecx
        !           420:         mov     ecx,[edi].xRight
        !           421:         mov     rclDest.xRight,ecx      ;rclDest.right = prclDest->right
        !           422:         shr     ecx,2
        !           423:         add     ebx,ecx                 ;ebx = ulRightDest = prclDest->top *
        !           424:                                         ; lDelta + prclDest->right / 4
        !           425: 
        !           426:         mov     edi,[edi].xLeft
        !           427:         mov     rclDest.xLeft,edi
        !           428:         shr     edi,2
        !           429:         neg     edi
        !           430:         add     edi,ecx                 ;cjMiddle = prclDest->right / 4 -
        !           431:                                         ;  prclDest->left / 4
        !           432: 
        !           433:         mov     ecx,rclDest.xRight
        !           434:         and     ecx,3
        !           435:         jz      short r_t_done_right_edge ;skip if we don't need a right edge
        !           436: 
        !           437:         or      esi,BLOCK_RIGHT_EDGE
        !           438:         mov     ecx,RightMaskTable[ecx*4]
        !           439:         mov     ulRightMask,ecx         ;ulRightMask =
        !           440:                                         ;  RightMaskTable[prclDest->right & 3]
        !           441: 
        !           442:         mov     ulRightSrc,eax          ;ulRightSrc
        !           443:         mov     ulRightDest,ebx         ;ulRightDest
        !           444: 
        !           445: r_t_done_right_edge:
        !           446:         dec     eax
        !           447:         dec     ebx
        !           448:         mov     ulMiddleSrc,eax         ;ulMiddleSrc
        !           449:         mov     ulMiddleDest,ebx        ;ulMiddleDest
        !           450: 
        !           451:         mov     ecx,rclDest.xLeft
        !           452:         and     ecx,3
        !           453:         jz      short r_t_done_left_edge ;skip if we don't need a right edge
        !           454:         or      esi,BLOCK_LEFT_EDGE
        !           455:         mov     ecx,LeftMaskTable[ecx*4]
        !           456:         mov     ulLeftMask,ecx          ;ulLeftMask =
        !           457:                                         ;  LeftMaskTable[prclDest->left & 3]
        !           458: 
        !           459:         dec     edi                     ;adjust middle block length because
        !           460:                                         ;  we're effectively doing one less
        !           461:                                         ;  middle byte
        !           462: 
        !           463:         sub     eax,edi
        !           464:         sub     ebx,edi
        !           465:         mov     ulLeftSrc,eax           ;ulLeftSrc = ulMiddleSrc - cjMiddle
        !           466:         mov     ulLeftDest,ebx          ;ulLeftDest = ulMiddleDest - cjMiddle
        !           467: 
        !           468: ; We special case here blits that are less than 4 pels wide and begin and end
        !           469: ; in the same 4-pel quadruple:
        !           470: 
        !           471:         cmp     edi,0
        !           472:         jge     r_t_done_left_edge
        !           473: 
        !           474: ; We make sure the 'middle' count of bytes is zero (we'll just let the code
        !           475: ; fall through the 'middle' copy code), turn off the right-edge flag, and
        !           476: ; give ulRightMask the composite mask:
        !           477: 
        !           478:         inc     edi
        !           479:         xor     esi,BLOCK_LEFT_EDGE
        !           480:         and     ecx,ulRightMask
        !           481:         mov     ulRightMask,ecx
        !           482: 
        !           483:         align   4
        !           484: r_t_done_left_edge:
        !           485:         mov     cjMiddle,edi            ;cjMiddle
        !           486: 
        !           487:         mov     lDelta,edx              ;lDelta = ppdev->lPlanarNextScan
        !           488:         add     edx,edi
        !           489:         mov     lMiddleDelta,edx        ;lMiddleDelta = lDelta + cjMiddle
        !           490: 
        !           491:         mov     ebx,ppdev
        !           492:         mov     eax,MasterBlockTable[esi*4]
        !           493:         mov     pfnCopyBlocks,eax       ;copy blocks between video memory
        !           494: 
        !           495: ; Branch to the appropriate top-to-bottom bank enumeration loop:
        !           496: 
        !           497:         mov     eax,[ebx].pdev_vbtPlanarType
        !           498:         jmp     TopToBottomLoopTable[eax*4]
        !           499: 
        !           500: ;-----------------------------------------------------------------------;
        !           501: ; Set-up code for left-to-right, bottom-to-top copies.
        !           502: ;
        !           503: ; Input:
        !           504: ;       esi - pptlSrc
        !           505: ;       edi - prclDest
        !           506: ;-----------------------------------------------------------------------;
        !           507: 
        !           508:         align   4
        !           509:         public left_to_right_bottom_to_top
        !           510: left_to_right_bottom_to_top:
        !           511: 
        !           512:         mov     edx,ppdev
        !           513:         mov     eax,[edi].yTop
        !           514:         mov     edx,[edx].pdev_lPlanarNextScan ;edx = lDelta
        !           515:         mov     ulLastDestScan,eax      ;ulLastDestScan = prclDest->top
        !           516: 
        !           517:         mov     ecx,[esi].ptl_y
        !           518:         add     ecx,[edi].yBottom
        !           519:         sub     ecx,[edi].yTop
        !           520:         mov     eax,edx
        !           521:         mov     ulCurrentSrcScan,ecx    ;ulCurrentSrcScan = pptlSrc->y +
        !           522:                                         ;  (prclDest->bottom - prclDest->top)
        !           523:         dec     ecx
        !           524:         imul    eax,ecx
        !           525:         mov     ecx,[esi].ptl_x
        !           526:         mov     ptlSrc.ptl_x,ecx        ;ptlSrc.x = pptlSrc->x
        !           527:         shr     ecx,2
        !           528:         add     eax,ecx                 ;eax = ulLeftSrc = (ulCurrentSrcScan - 1)
        !           529:                                         ;  * lDelta + (pptlSrc->x >> 2)
        !           530: 
        !           531:         xor     esi,esi                 ;initialize flags
        !           532: 
        !           533:         mov     ecx,[edi].yBottom
        !           534:         mov     ebx,edx
        !           535:         mov     ulCurrentDestScan,ecx   ;ulCurrentDestScan = prclDest->bottom
        !           536:         dec     ecx
        !           537:         imul    ebx,ecx
        !           538:         mov     ecx,[edi].xLeft
        !           539:         mov     rclDest.xLeft,ecx       ;rclDest.left = prclDest->left
        !           540:         shr     ecx,2
        !           541:         add     ebx,ecx                 ;ebx = ulLeftDest = (prclDest->bottom - 1)
        !           542:                                         ;  * lDelta + (prclDest->left >> 2)
        !           543: 
        !           544:         mov     edi,[edi].xRight
        !           545:         mov     rclDest.xRight,edi
        !           546:         shr     edi,2
        !           547:         sub     edi,ecx                 ;cjMiddle = (prclDest->right >> 2) -
        !           548:                                         ;  (prclDest->left >> 2)
        !           549: 
        !           550:         mov     ecx,rclDest.xLeft
        !           551:         and     ecx,3
        !           552:         jz      short l_b_done_left_edge ;skip if we don't need a left edge
        !           553: 
        !           554:         or      esi,BLOCK_LEFT_EDGE
        !           555:         mov     ecx,LeftMaskTable[ecx*4]
        !           556:         mov     ulLeftMask,ecx          ;ulLeftMask =
        !           557:                                         ;  LeftMaskTable[prclDest->left & 3]
        !           558: 
        !           559:         mov     ulLeftSrc,eax           ;ulLeftSrc
        !           560:         mov     ulLeftDest,ebx          ;ulLeftDest
        !           561:         inc     eax
        !           562:         inc     ebx
        !           563:         dec     edi
        !           564: 
        !           565: l_b_done_left_edge:
        !           566:         mov     ulMiddleSrc,eax         ;ulMiddleSrc
        !           567:         mov     ulMiddleDest,ebx        ;ulMiddleDest
        !           568: 
        !           569:         mov     ecx,rclDest.xRight
        !           570:         and     ecx,3
        !           571:         jz      short l_b_done_right_edge ;skip if we don't need a right edge
        !           572: 
        !           573:         or      esi,BLOCK_RIGHT_EDGE
        !           574:         mov     ecx,RightMaskTable[ecx*4]
        !           575:         mov     ulRightMask,ecx         ;ulRightMask =
        !           576:                                         ;  RightMaskTable[prclDest->right & 3]
        !           577: 
        !           578:         add     eax,edi
        !           579:         add     ebx,edi
        !           580:         mov     ulRightSrc,eax          ;ulRightSrc = ulMiddleSrc + cjMiddle
        !           581:         mov     ulRightDest,ebx         ;ulRightDest = ulMiddleDest + cjMiddle
        !           582: 
        !           583: ; We special case here blits that are less than 4 pels wide and begin and end
        !           584: ; in the same 4-pel quadruple:
        !           585: 
        !           586:         cmp     edi,0
        !           587:         jge     l_b_done_right_edge
        !           588: 
        !           589: ; We make sure the 'middle' count of bytes is zero (we'll just let the code
        !           590: ; fall through the 'middle' copy code), turn off the right-edge flag, and
        !           591: ; give ulLeftMask the composite mask:
        !           592: 
        !           593:         inc     edi
        !           594:         xor     esi,BLOCK_RIGHT_EDGE
        !           595:         and     ecx,ulLeftMask
        !           596:         mov     ulLeftMask,ecx
        !           597: 
        !           598:         align   4
        !           599: l_b_done_right_edge:
        !           600:         mov     cjMiddle,edi            ;cjMiddle
        !           601: 
        !           602:         neg     edx
        !           603:         mov     lDelta,edx              ;lDelta = -ppdev->lPlanarNextScan
        !           604:         sub     edx,edi
        !           605:         mov     lMiddleDelta,edx        ;lMiddleDelta = lDelta - cjMiddle
        !           606: 
        !           607:         mov     ebx,ppdev
        !           608:         mov     eax,MasterBlockTable[esi*4]
        !           609:         mov     pfnCopyBlocks,eax       ;copy blocks between video memory
        !           610: 
        !           611: ; Branch to the appropriate top-to-bottom bank enumeration loop:
        !           612: 
        !           613:         mov     eax,[ebx].pdev_vbtPlanarType
        !           614:         jmp     BottomToTopLoopTable[eax*4]
        !           615: 
        !           616: ;-----------------------------------------------------------------------;
        !           617: ; Set-up code for right-to-left, bottom-to-top copies.
        !           618: ;
        !           619: ; Input:
        !           620: ;       esi - pptlSrc
        !           621: ;       edi - prclDest
        !           622: ;-----------------------------------------------------------------------;
        !           623: 
        !           624:         align   4
        !           625:         public right_to_left_bottom_to_top
        !           626: right_to_left_bottom_to_top:
        !           627: 
        !           628:         std                             ;copy middle blocks right-to-left
        !           629: 
        !           630:         mov     edx,ppdev
        !           631:         mov     eax,[edi].yTop
        !           632:         mov     edx,[edx].pdev_lPlanarNextScan ;edx = lDelta
        !           633:         mov     ulLastDestScan,eax      ;ulLastDestScan = prclDest->top
        !           634: 
        !           635:         mov     ecx,[esi].ptl_y
        !           636:         add     ecx,[edi].yBottom
        !           637:         sub     ecx,[edi].yTop
        !           638:         mov     eax,edx
        !           639:         mov     ulCurrentSrcScan,ecx    ;ulCurrentSrcScan = pptlSrc->y +
        !           640:                                         ;  (prclDest->bottom - prclDest->top)
        !           641:         dec     ecx
        !           642:         imul    eax,ecx
        !           643:         mov     ecx,[esi].ptl_x
        !           644:         mov     ptlSrc.ptl_x,ecx        ;ptlSrc.x = pptlSrc->x
        !           645:         add     ecx,[edi].xRight
        !           646:         sub     ecx,[edi].xLeft
        !           647:         shr     ecx,2
        !           648:         add     eax,ecx                 ;eax = ulRightSrc = (ulCurrentSrcScan
        !           649:                                         ; - 1) * lDelta + (pptlSrc->x +
        !           650:                                         ; prclDest->right - prclDest->left) / 4
        !           651: 
        !           652:         mov     esi,BLOCK_RIGHT_TO_LEFT ;initialize flags
        !           653: 
        !           654:         mov     ecx,[edi].yBottom
        !           655:         mov     ebx,edx
        !           656:         mov     ulCurrentDestScan,ecx   ;ulCurrentDestScan = prclDest->bottom
        !           657:         dec     ecx
        !           658:         imul    ebx,ecx
        !           659:         mov     ecx,[edi].xRight
        !           660:         mov     rclDest.xRight,ecx      ;rclDest.right = prclDest->right
        !           661:         shr     ecx,2
        !           662:         add     ebx,ecx                 ;ebx = ulRightDest = (ulCurrentDestScan
        !           663:                                         ; - 1) * lDelta + prclDest->right / 4
        !           664: 
        !           665:         mov     edi,[edi].xLeft
        !           666:         mov     rclDest.xLeft,edi
        !           667:         shr     edi,2
        !           668:         neg     edi
        !           669:         add     edi,ecx                 ;cjMiddle = prclDest->right / 4 -
        !           670:                                         ;  prclDest->left / 4
        !           671: 
        !           672:         mov     ecx,rclDest.xRight
        !           673:         and     ecx,3
        !           674:         jz      short r_b_done_right_edge ;skip if we don't need a right edge
        !           675: 
        !           676:         or      esi,BLOCK_RIGHT_EDGE
        !           677:         mov     ecx,RightMaskTable[ecx*4]
        !           678:         mov     ulRightMask,ecx         ;ulRightMask =
        !           679:                                         ;  RightMaskTable[prclDest->right & 3]
        !           680: 
        !           681:         mov     ulRightSrc,eax          ;ulRightSrc
        !           682:         mov     ulRightDest,ebx         ;ulRightDest
        !           683: 
        !           684: r_b_done_right_edge:
        !           685:         dec     eax
        !           686:         dec     ebx
        !           687:         mov     ulMiddleSrc,eax         ;ulMiddleSrc
        !           688:         mov     ulMiddleDest,ebx        ;ulMiddleDest
        !           689: 
        !           690:         mov     ecx,rclDest.xLeft
        !           691:         and     ecx,3
        !           692:         jz      short r_b_done_left_edge ;skip if we don't need a right edge
        !           693: 
        !           694:         or      esi,BLOCK_LEFT_EDGE
        !           695:         mov     ecx,LeftMaskTable[ecx*4]
        !           696:         mov     ulLeftMask,ecx          ;ulLeftMask =
        !           697:                                         ;  LeftMaskTable[prclDest->left & 3]
        !           698: 
        !           699:         dec     edi                     ;adjust middle block length because
        !           700:                                         ;  we're effectively doing one less
        !           701:                                         ;  middle byte
        !           702: 
        !           703:         sub     eax,edi
        !           704:         sub     ebx,edi
        !           705:         mov     ulLeftSrc,eax           ;ulLeftSrc = ulMiddleSrc - cjMiddle
        !           706:         mov     ulLeftDest,ebx          ;ulLeftDest = ulMiddleDest - cjMiddle
        !           707: 
        !           708: ; We special case here blits that are less than 4 pels wide and begin and end
        !           709: ; in the same 4-pel quadruple:
        !           710: 
        !           711:         cmp     edi,0
        !           712:         jge     r_b_done_left_edge
        !           713: 
        !           714: ; We make sure the 'middle' count of bytes is zero (we'll just let the code
        !           715: ; fall through the 'middle' copy code), turn off the right-edge flag, and
        !           716: ; give ulRightMask the composite mask:
        !           717: 
        !           718:         inc     edi
        !           719:         xor     esi,BLOCK_LEFT_EDGE
        !           720:         and     ecx,ulRightMask
        !           721:         mov     ulRightMask,ecx
        !           722: 
        !           723:         align   4
        !           724: r_b_done_left_edge:
        !           725:         mov     cjMiddle,edi            ;cjMiddle
        !           726: 
        !           727:         neg     edx
        !           728:         mov     lDelta,edx              ;lDelta = -ppdev->lPlanarNextScan
        !           729:         add     edx,edi
        !           730:         mov     lMiddleDelta,edx        ;lMiddleDelta = lDelta + cjMiddle
        !           731: 
        !           732:         mov     ebx,ppdev
        !           733:         mov     eax,MasterBlockTable[esi*4]
        !           734:         mov     pfnCopyBlocks,eax       ;copy blocks between video memory
        !           735: 
        !           736: ; Branch to the appropriate top-to-bottom bank enumeration loop:
        !           737: 
        !           738:         mov     eax,[ebx].pdev_vbtPlanarType
        !           739:         jmp     BottomToTopLoopTable[eax*4]
        !           740: 
        !           741: ;=======================================================================;
        !           742: ;============================= Banking =================================;
        !           743: ;=======================================================================;
        !           744: 
        !           745: ;-----------------------------------------------------------------------;
        !           746: ; Banking for 1 R/W adapters, top to bottom.
        !           747: ;
        !           748: ; Input:
        !           749: ;       ulCurrentSrcScan
        !           750: ;       ulCurrentDestScan
        !           751: ;       ulLastDestScan
        !           752: ;       Plus some other stuff for split rasters and block copiers
        !           753: ;-----------------------------------------------------------------------;
        !           754:         align   4
        !           755:         public  top_to_bottom_1RW
        !           756: top_to_bottom_1RW:
        !           757: 
        !           758: ; LATER: Should check to see if there's any chance that the source and
        !           759: ;     destination overlap in the same window, so that we can use planar
        !           760: ;     copies -- otherwise, it's faster to directly call of to
        !           761: ;     bPuntScreenToScreenCopyBits
        !           762: 
        !           763: ; We're going top to bottom. Map in the source and dest, top-justified.
        !           764: 
        !           765:         mov     ebx,ppdev
        !           766:         mov     edi,ulCurrentDestScan
        !           767: 
        !           768:         cmp     edi,[ebx].pdev_rcl1PlanarClip.yTop
        !           769:         jl      short top_1RW_map_init_bank
        !           770: 
        !           771:         cmp     edi,[ebx].pdev_rcl1PlanarClip.yBottom
        !           772:         jl      short top_1RW_init_bank_mapped
        !           773: 
        !           774: top_1RW_map_init_bank:
        !           775: 
        !           776: ; Map bank containing the top destination scan line into window.
        !           777: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !           778: 
        !           779:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
        !           780:                 <ebx,edi,JustifyTop>
        !           781: 
        !           782: top_1RW_init_bank_mapped:
        !           783: 
        !           784:         mov     eax,ulCurrentSrcScan
        !           785:         cmp     eax,[ebx].pdev_rcl1PlanarClip.yBottom
        !           786: 
        !           787:         jl      short top_1RW_do_planar_copy
        !           788: 
        !           789: ; ulCurrentSrcScan >= ppdev->rcl1PlanarClip.bottom, which means that
        !           790: ; the window can't overlap the source and destination at all.  We'll
        !           791: ; have to use an intermediate temporary buffer:
        !           792: 
        !           793: ; ebx = ppdev
        !           794: ; eax = ulCurrentSrcScan
        !           795: ; edi = ulCurrentDestScan
        !           796: 
        !           797:         mov     ptlSrc.ptl_y,eax        ;ptlSrc.y = ulCurrentSrcScan
        !           798:         mov     rclDest.yTop,edi        ;rclDest.top = ulCurrentDestScan
        !           799: 
        !           800:         mov     esi,[ebx].pdev_rcl1PlanarClip.yBottom
        !           801:         mov     eax,ulLastDestScan
        !           802:         sub     eax,esi
        !           803:         sbb     ecx,ecx
        !           804:         and     ecx,eax
        !           805:         add     esi,ecx
        !           806:         mov     rclDest.yBottom,esi     ;rclDest.bottom = min(ulLastDestScan,
        !           807:                                         ;  ppdev->pdev_rcl1PlanarClip.bottom)
        !           808: 
        !           809: ; Enable bit mask for all bits:
        !           810: 
        !           811:         mov     edx,VGA_BASE + GRAF_ADDR
        !           812:         mov     eax,(0ffh shl 8) + GRAF_BIT_MASK
        !           813:         out     dx,ax
        !           814: 
        !           815: ; Enable writes to all planes and reset direction flag:
        !           816: 
        !           817:         mov     edx,VGA_BASE + SEQ_DATA
        !           818:         mov     al,MM_ALL
        !           819:         out     dx,al
        !           820: 
        !           821:         pushfd
        !           822:         cld
        !           823: 
        !           824: ; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI
        !           825: ; according to C calling conventions:
        !           826: 
        !           827:         lea     ecx,rclDest
        !           828:         lea     edx,ptlSrc
        !           829: 
        !           830:         cCall   bPuntScreenToScreenCopyBits,<ebx,0,0,ecx,edx>
        !           831: 
        !           832:         popfd
        !           833: 
        !           834: ; Set the bit mask to disable all bits, so we can copy through latches again:
        !           835: 
        !           836:         mov     edx,VGA_BASE + GRAF_ADDR
        !           837:         mov     eax,(000h shl 8) + GRAF_BIT_MASK
        !           838:         out     dx,ax
        !           839: 
        !           840: ; Update our position variables:
        !           841: 
        !           842:         mov     ulCurrentDestScan,esi   ;ulCurrentDestScan = rclDest.bottom
        !           843: 
        !           844:         sub     esi,edi                 ;ulBlockHeight = rclDest.bottom -
        !           845:                                         ;  rclDest.top
        !           846: 
        !           847:         add     ulCurrentSrcScan,esi    ;ulCurrentSrcScan += ulBlockHeight
        !           848: 
        !           849: ; We have to adjust the offsets for all our block copiers, according to the
        !           850: ; number of scans we copied:
        !           851: 
        !           852:         mov     edx,lDelta
        !           853:         imul    edx,esi                 ;edx = lDelta * ulBlockHeight
        !           854:         add     ulLeftSrc,edx
        !           855:         add     ulLeftDest,edx
        !           856:         add     ulMiddleSrc,edx
        !           857:         add     ulMiddleDest,edx
        !           858:         add     ulRightSrc,edx
        !           859:         add     ulRightDest,edx
        !           860: 
        !           861:         jmp     short top_1RW_see_if_done
        !           862: 
        !           863: top_1RW_do_planar_copy:
        !           864: 
        !           865: ; ebx = ppdev
        !           866: ; eax = ulCurrentSrcScan
        !           867: ; edi = ulCurrentDestScan
        !           868: 
        !           869:         mov     ebx,[ebx].pdev_rcl1PlanarClip.yBottom
        !           870:         sub     ebx,eax                 ;ebx = ppdev->rcl1PlanarClip.bottom -
        !           871:                                         ;  ulCurrentSrcScan
        !           872:                                         ;ebx is the available number of scans
        !           873:                                         ;  we have in the source
        !           874: 
        !           875:         mov     edx,ulLastDestScan
        !           876:         sub     edx,edi                 ;edx = ulLastDestScan - ulCurrentDestScan
        !           877:                                         ;edx is the available number of scans
        !           878:                                         ;  in the destination
        !           879: 
        !           880: ; (Because the source starts lower in the window than the destination,
        !           881: ; the bottom of the bank always limits the source number of scans before
        !           882: ; it does the destination.)
        !           883: 
        !           884:         sub     ebx,edx
        !           885:         sbb     ecx,ecx
        !           886:         and     ecx,ebx
        !           887:         add     edx,ecx                 ;edx = min(source available,
        !           888:                                         ;  destination available)
        !           889:         mov     ulBlockHeight,edx
        !           890: 
        !           891:         add     eax,edx                 ;We have to adjust our current scans
        !           892:         add     edi,edx
        !           893:         mov     ulCurrentSrcScan,eax
        !           894:         mov     ulCurrentDestScan,edi
        !           895: 
        !           896: ; Now copy the puppy:
        !           897: 
        !           898:         call    pfnCopyBlocks
        !           899: 
        !           900: ; See if we're done:
        !           901: 
        !           902: top_1RW_see_if_done:
        !           903:         mov     edi,ulCurrentDestScan
        !           904:         cmp     edi,ulLastDestScan
        !           905:         jge     all_done
        !           906: 
        !           907:         mov     ebx,ppdev
        !           908: 
        !           909: ; Map bank containing the top destination scan line into window.
        !           910: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !           911: 
        !           912:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
        !           913:                 <ebx,edi,JustifyTop>
        !           914: 
        !           915:         jmp     top_1RW_init_bank_mapped
        !           916: 
        !           917: ;-----------------------------------------------------------------------;
        !           918: ; Banking for 1 R/W adapters, bottom to top.
        !           919: ;
        !           920: ; Input:
        !           921: ;       ulCurrentSrcScan  - Actually, 1 more current source scan
        !           922: ;       ulCurrentDestScan - Actually, 1 more current destination scan
        !           923: ;       ulLastDestScan
        !           924: ;       Plus some other stuff for split rasters and block copiers
        !           925: ;-----------------------------------------------------------------------;
        !           926:         align   4
        !           927:         public  bottom_to_top_1RW
        !           928: bottom_to_top_1RW:
        !           929: 
        !           930: ; We're going top to bottom. Map in the source and dest, top-justified.
        !           931: 
        !           932:         mov     ebx,ppdev
        !           933:         mov     edi,ulCurrentDestScan
        !           934: 
        !           935:         cmp     edi,[ebx].pdev_rcl1PlanarClip.yTop
        !           936:         jle     short bot_1RW_map_init_bank
        !           937: 
        !           938:         cmp     edi,[ebx].pdev_rcl1PlanarClip.yBottom
        !           939:         jle     short bot_1RW_init_bank_mapped
        !           940: 
        !           941: bot_1RW_map_init_bank:
        !           942: 
        !           943: ; Map bank containing the top destination scan line into window.
        !           944: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !           945: 
        !           946:         dec     edi
        !           947:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
        !           948:                 <ebx,edi,JustifyTop>
        !           949:         inc     edi
        !           950: 
        !           951: bot_1RW_init_bank_mapped:
        !           952: 
        !           953:         mov     eax,ulCurrentSrcScan
        !           954:         cmp     eax,[ebx].pdev_rcl1PlanarClip.yTop
        !           955: 
        !           956:         jg      short bot_1RW_do_planar_copy
        !           957: 
        !           958: ; ulCurrentSrcScan <= ppdev->rcl1PlanarClip.top, which means that
        !           959: ; the window can't overlap the source and destination at all.  We'll
        !           960: ; have to use an intermediate temporary buffer:
        !           961: 
        !           962: ; ebx = ppdev
        !           963: ; eax = ulCurrentSrcScan
        !           964: ; edi = ulCurrentDestScan
        !           965: 
        !           966:         mov     esi,[ebx].pdev_rcl1PlanarClip.yTop
        !           967:         mov     edx,ulLastDestScan
        !           968:         cmp     esi,edx
        !           969:         jg      @F
        !           970:         mov     esi,edx
        !           971: @@:
        !           972:         mov     rclDest.yTop,esi        ;rclDest.top = max(ulLastDestScan,
        !           973:                                         ;  ppdev->rcl1PlanarClip.top)
        !           974: 
        !           975:         mov     rclDest.yBottom,edi     ;rclDest.bottom = ulCurrentDestScan
        !           976:         add     eax,esi
        !           977:         sub     eax,edi
        !           978:         mov     ptlSrc.ptl_y,eax        ;ptlSrc.y = ulCurrentSrcScan -
        !           979:                                         ;  (rclDest.bottom - rclDest.top)
        !           980: 
        !           981: ; Enable bit mask for all bits:
        !           982: 
        !           983:         mov     edx,VGA_BASE + GRAF_ADDR
        !           984:         mov     eax,(0ffh shl 8) + GRAF_BIT_MASK
        !           985:         out     dx,ax
        !           986: 
        !           987: ; Enable writes to all planes and reset direction flag:
        !           988: 
        !           989:         mov     edx,VGA_BASE + SEQ_DATA
        !           990:         mov     al,MM_ALL
        !           991:         out     dx,al
        !           992: 
        !           993:         pushfd
        !           994:         cld
        !           995: 
        !           996: ; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI
        !           997: ; according to C calling conventions:
        !           998: 
        !           999:         lea     ecx,rclDest
        !          1000:         lea     edx,ptlSrc
        !          1001: 
        !          1002:         cCall   bPuntScreenToScreenCopyBits,<ebx,0,0,ecx,edx>
        !          1003: 
        !          1004:         popfd
        !          1005: 
        !          1006: ; Set the bit mask to disable all bits, so we can copy through latches again:
        !          1007: 
        !          1008:         mov     edx,VGA_BASE + GRAF_ADDR
        !          1009:         mov     eax,(000h shl 8) + GRAF_BIT_MASK
        !          1010:         out     dx,ax
        !          1011: 
        !          1012: ; Update our position variables:
        !          1013: 
        !          1014:         mov     ulCurrentDestScan,esi   ;ulCurrentDestScan = rclDest.top
        !          1015: 
        !          1016:         sub     edi,esi                 ;ulBlockHeight = rclDest.bottom -
        !          1017:                                         ;  rclDest.top
        !          1018: 
        !          1019:         sub     ulCurrentSrcScan,edi    ;ulCurrentSrcScan -= ulBlockHeight
        !          1020: 
        !          1021: ; We have to adjust the offsets for all our block copiers, according to the
        !          1022: ; number of scans we copied:
        !          1023: 
        !          1024:         mov     edx,lDelta
        !          1025:         imul    edx,edi                 ;edx = lDelta * ulBlockHeight
        !          1026:         add     ulLeftSrc,edx
        !          1027:         add     ulLeftDest,edx
        !          1028:         add     ulMiddleSrc,edx
        !          1029:         add     ulMiddleDest,edx
        !          1030:         add     ulRightSrc,edx
        !          1031:         add     ulRightDest,edx
        !          1032: 
        !          1033:         jmp     short bot_1RW_see_if_done
        !          1034: 
        !          1035: bot_1RW_do_planar_copy:
        !          1036: 
        !          1037: ; ebx = ppdev
        !          1038: ; eax = ulCurrentSrcScan
        !          1039: ; edi = ulCurrentDestScan
        !          1040: 
        !          1041:         sub     eax,[ebx].pdev_rcl1PlanarClip.yTop
        !          1042:                                         ;eax = ulCurrentSrcScan -
        !          1043:                                         ;  ppdev->rcl1PlanarClip.top
        !          1044: 
        !          1045:         sub     edi,ulLastDestScan      ;edi = ulCurrentDestScan - ulLastDestScan
        !          1046:                                         ;edi is the available number of scans
        !          1047:                                         ;  in the destination
        !          1048: 
        !          1049: 
        !          1050: ; (Because the source starts higher in the window than the destination,
        !          1051: ; the bottom of the bank always limits the source number of scans before
        !          1052: ; it does the destination.)
        !          1053: 
        !          1054:         sub     eax,edi
        !          1055:         sbb     ecx,ecx
        !          1056:         and     ecx,eax
        !          1057:         add     edi,ecx                 ;edi = min(source available,
        !          1058:                                         ;  destination available)
        !          1059: 
        !          1060:         mov     ulBlockHeight,edi
        !          1061: 
        !          1062:         sub     ulCurrentSrcScan,edi    ;We have to adjust our current scans
        !          1063:         sub     ulCurrentDestScan,edi
        !          1064: 
        !          1065: ; Now copy the puppy:
        !          1066: 
        !          1067:         call    pfnCopyBlocks
        !          1068: 
        !          1069: ; See if we're done:
        !          1070: 
        !          1071: bot_1RW_see_if_done:
        !          1072:         mov     edi,ulCurrentDestScan
        !          1073:         cmp     edi,ulLastDestScan
        !          1074:         jle     all_done
        !          1075: 
        !          1076:         mov     ebx,ppdev
        !          1077: 
        !          1078: ; Map bank containing the top destination scan line into window.
        !          1079: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1080: 
        !          1081:         dec     edi
        !          1082:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
        !          1083:                 <ebx,edi,JustifyTop>
        !          1084:         inc     edi
        !          1085: 
        !          1086:         jmp     bot_1RW_init_bank_mapped
        !          1087: 
        !          1088: ;-----------------------------------------------------------------------;
        !          1089: ; Banking for 1R/1W or 2R/W adapters, top to bottom.
        !          1090: ;
        !          1091: ; Input:
        !          1092: ;       ulCurrentSrcScan
        !          1093: ;       ulCurrentDestScan
        !          1094: ;       ulLastDestScan
        !          1095: ;       Plus some other stuff for split rasters and block copiers
        !          1096: ;-----------------------------------------------------------------------;
        !          1097:         align   4
        !          1098:         public  top_to_bottom_2RW
        !          1099: top_to_bottom_2RW:
        !          1100: 
        !          1101: ; We're going top to bottom. Map in the destination, top-justified.
        !          1102: 
        !          1103:         mov     ebx,ppdev
        !          1104:         mov     edi,ulCurrentDestScan
        !          1105:         mov     esi,ulCurrentSrcScan
        !          1106: 
        !          1107:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yTop
        !          1108:         jl      short top_2RW_map_init_dest_bank
        !          1109: 
        !          1110:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yBottom
        !          1111:         jl      short top_2RW_init_dest_bank_mapped
        !          1112: 
        !          1113: top_2RW_map_init_dest_bank:
        !          1114: 
        !          1115: ; Map bank containing the top destination scan line into window.
        !          1116: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1117: 
        !          1118:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1119:                 <ebx,edi,JustifyTop,MapDestBank>
        !          1120: 
        !          1121: top_2RW_init_dest_bank_mapped:
        !          1122: 
        !          1123:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yTop
        !          1124:         jl      short top_2RW_map_init_src_bank
        !          1125: 
        !          1126:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yBottom
        !          1127:         jl      short top_2RW_main_loop
        !          1128: 
        !          1129: top_2RW_map_init_src_bank:
        !          1130: 
        !          1131: ; Map bank containing the top source scan line into window.
        !          1132: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1133: 
        !          1134:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1135:                 <ebx,esi,JustifyTop,MapSourceBank>
        !          1136: 
        !          1137: top_2RW_main_loop:
        !          1138:         mov     ecx,[ebx].pdev_rcl2PlanarClipD.yBottom
        !          1139:         mov     edx,ulLastDestScan
        !          1140: 
        !          1141:         sub     ecx,edx
        !          1142:         sbb     eax,eax
        !          1143:         and     eax,ecx
        !          1144:         add     edx,eax                 ;edx = min(ulLastDestScan,
        !          1145:                                         ;  ppdev->rcl2PlanarClipD.bottom)
        !          1146: 
        !          1147:         mov     ecx,[ebx].pdev_rcl2PlanarClipS.yBottom
        !          1148: 
        !          1149:         sub     edx,edi                 ;edx = available scans in destination
        !          1150:                                         ;  bank
        !          1151:         sub     ecx,esi                 ;ecx = available scans in source bank
        !          1152: 
        !          1153:         sub     ecx,edx
        !          1154:         sbb     eax,eax
        !          1155:         and     eax,ecx
        !          1156:         add     edx,eax
        !          1157: 
        !          1158:         mov     ulBlockHeight,edx       ;ulBlockHeight = min(source available,
        !          1159:                                         ;  dest available)
        !          1160: 
        !          1161:         add     esi,edx                 ;adjust our currents scans accordingly
        !          1162:         add     edi,edx
        !          1163:         mov     ulCurrentSrcScan,esi
        !          1164:         mov     ulCurrentDestScan,edi
        !          1165: 
        !          1166: ; Do the actual copy:
        !          1167: 
        !          1168:         call    pfnCopyBlocks
        !          1169: 
        !          1170:         mov     edi,ulCurrentDestScan   ;check if done
        !          1171:         cmp     edi,ulLastDestScan
        !          1172:         jge     all_done
        !          1173: 
        !          1174:         mov     ebx,ppdev
        !          1175: 
        !          1176: ; We'll have to map a new source bank, destination bank, or both:
        !          1177: 
        !          1178:         mov     esi,ulCurrentSrcScan
        !          1179:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yBottom
        !          1180:         jl      short top_2RW_map_next_src_bank
        !          1181: 
        !          1182: ; Map bank containing the top destination scan line into window.
        !          1183: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1184: 
        !          1185:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1186:                 <ebx,edi,JustifyTop,MapDestBank>
        !          1187: 
        !          1188:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yBottom
        !          1189:         jl      short top_2RW_main_loop
        !          1190: 
        !          1191: top_2RW_map_next_src_bank:
        !          1192: 
        !          1193: ; Map bank containing the top source scan line into window.
        !          1194: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1195: 
        !          1196:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1197:                 <ebx,esi,JustifyTop,MapSourceBank>
        !          1198: 
        !          1199:         jmp     short top_2RW_main_loop
        !          1200: 
        !          1201: ;-----------------------------------------------------------------------;
        !          1202: ; Banking for 1R/1W or 2R/W adapters, bottom to top.
        !          1203: ;
        !          1204: ; Input:
        !          1205: ;       ulCurrentSrcScan
        !          1206: ;       ulCurrentDestScan
        !          1207: ;       ulLastDestScan
        !          1208: ;       Plus some other stuff for split rasters and block copiers
        !          1209: ;-----------------------------------------------------------------------;
        !          1210:         align   4
        !          1211:         public  bottom_to_top_2RW
        !          1212: bottom_to_top_2RW:
        !          1213: 
        !          1214: ; We're going bottom to top. Map in the destination, bottom-justified.
        !          1215: 
        !          1216:         mov     ebx,ppdev
        !          1217:         mov     edi,ulCurrentDestScan   ; 1 more than actual destination scan
        !          1218:         mov     esi,ulCurrentSrcScan    ; 1 more than actual source scan
        !          1219: 
        !          1220:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yTop
        !          1221:         jle     short bot_2RW_map_init_dest_bank
        !          1222: 
        !          1223:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yBottom
        !          1224:         jle     short bot_2RW_init_dest_bank_mapped
        !          1225: 
        !          1226: bot_2RW_map_init_dest_bank:
        !          1227: 
        !          1228: ; Map bank containing the top destination scan line into window.
        !          1229: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1230: 
        !          1231:         dec     edi
        !          1232:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1233:                 <ebx,edi,JustifyBottom,MapDestBank>
        !          1234:         inc     edi
        !          1235: 
        !          1236: bot_2RW_init_dest_bank_mapped:
        !          1237: 
        !          1238:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yTop
        !          1239:         jle     short bot_2RW_map_init_src_bank
        !          1240: 
        !          1241:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yBottom
        !          1242:         jle     short bot_2RW_main_loop
        !          1243: 
        !          1244: bot_2RW_map_init_src_bank:
        !          1245: 
        !          1246: ; Map bank containing the top source scan line into window.
        !          1247: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1248: 
        !          1249:         dec     esi
        !          1250:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1251:                 <ebx,esi,JustifyBottom,MapSourceBank>
        !          1252:         inc     esi
        !          1253: 
        !          1254: bot_2RW_main_loop:
        !          1255:         mov     ecx,[ebx].pdev_rcl2PlanarClipD.yTop
        !          1256:         mov     edx,ulLastDestScan
        !          1257: 
        !          1258:         cmp     edx,ecx
        !          1259:         jg      @F
        !          1260:         mov     edx,ecx                 ;edx = max(ulLastDestScan,
        !          1261: @@:                                     ;  ppdev->rcl2PlanarClipD.top)
        !          1262: 
        !          1263:         sub     edi,edx                 ;edi = available scans in destination
        !          1264:                                         ;  bank
        !          1265:         sub     esi,[ebx].pdev_rcl2PlanarClipS.yTop
        !          1266:                                         ;esi = available scans in source bank
        !          1267: 
        !          1268:         sub     esi,edi
        !          1269:         sbb     eax,eax
        !          1270:         and     eax,esi
        !          1271:         add     edi,eax
        !          1272: 
        !          1273:         mov     ulBlockHeight,edi       ;ulBlockHeight = min(source available,
        !          1274:                                         ;  dest available)
        !          1275: 
        !          1276:         sub     ulCurrentSrcScan,edi    ;adjust our current scans
        !          1277:         sub     ulCurrentDestScan,edi
        !          1278: 
        !          1279: ; Do the actual copy:
        !          1280: 
        !          1281:         call    pfnCopyBlocks
        !          1282: 
        !          1283:         mov     edi,ulCurrentDestScan   ;check if done
        !          1284:         cmp     edi,ulLastDestScan
        !          1285:         jle     all_done
        !          1286: 
        !          1287:         mov     ebx,ppdev
        !          1288: 
        !          1289: ; We'll have to map a new source bank, destination bank, or both:
        !          1290: 
        !          1291:         mov     esi,ulCurrentSrcScan
        !          1292:         cmp     edi,[ebx].pdev_rcl2PlanarClipD.yTop
        !          1293:         jg      short bot_2RW_map_next_src_bank
        !          1294: 
        !          1295: ; Map bank containing the top destination scan line into window.
        !          1296: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1297: 
        !          1298:         dec     edi
        !          1299:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1300:                 <ebx,edi,JustifyBottom,MapDestBank>
        !          1301:         inc     edi
        !          1302: 
        !          1303:         cmp     esi,[ebx].pdev_rcl2PlanarClipS.yTop
        !          1304:         jg      short bot_2RW_main_loop
        !          1305: 
        !          1306: bot_2RW_map_next_src_bank:
        !          1307: 
        !          1308: ; Map bank containing the top source scan line into window.
        !          1309: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
        !          1310: 
        !          1311:         dec     esi
        !          1312:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \
        !          1313:                 <ebx,esi,JustifyBottom,MapSourceBank>
        !          1314:         inc     esi
        !          1315: 
        !          1316:         jmp     short bot_2RW_main_loop
        !          1317: 
        !          1318: ;=======================================================================;
        !          1319: ;=========================== Block Copiers =============================;
        !          1320: ;=======================================================================;
        !          1321: 
        !          1322: ;-----------------------------------------------------------------------;
        !          1323: ; Input:
        !          1324: ;       Direction flag  - set to the appropriate direction
        !          1325: ;       ulMiddleSrc     - offset in bitmap to source
        !          1326: ;       ulMiddleDest    - offset in bitmap to destination
        !          1327: ;       lMiddleDelta    - distance from end of current scan to start of next
        !          1328: ;       ulBlockHeight   - # of scans to copy
        !          1329: ;       cjMiddle        - # of planar bytes to copy on every scan
        !          1330: ;
        !          1331: ; Output:
        !          1332: ;       Advances ulMiddleSrc and ulMiddleDest to next strip
        !          1333: ;-----------------------------------------------------------------------;
        !          1334: 
        !          1335:         align   4
        !          1336:         public  copy_middle_block
        !          1337: copy_middle_block:
        !          1338: 
        !          1339: ; We only have to reset which planes are enabled if we do edges too:
        !          1340: 
        !          1341:         mov     edx,VGA_BASE + SEQ_DATA
        !          1342:         mov     al,MM_ALL
        !          1343:         out     dx,al
        !          1344: 
        !          1345:         align   4
        !          1346: copy_just_middle_block:
        !          1347: 
        !          1348: ; Calculate full start addresses:
        !          1349: 
        !          1350:         mov     edi,ppdev
        !          1351:         mov     eax,cjMiddle
        !          1352:         mov     ebx,ulBlockHeight
        !          1353:         mov     edx,lMiddleDelta
        !          1354:         mov     esi,[edi].pdev_pvBitmapStart2WindowS
        !          1355:         mov     edi,[edi].pdev_pvBitmapStart2WindowD
        !          1356:         add     esi,ulMiddleSrc
        !          1357:         add     edi,ulMiddleDest
        !          1358: 
        !          1359:         SET_UP_UNROLL_VARS ebx,ecx,ebx,pfnCopyMiddleEntry, \
        !          1360:                                 LOOP_UNROLL_SHIFT
        !          1361: 
        !          1362:         jmp     ecx
        !          1363: 
        !          1364:         UNROLL_LOOP_ENTRY_TABLE pfnCopyMiddleEntry,MIDDLE, \
        !          1365:                                 LOOP_UNROLL_COUNT
        !          1366: 
        !          1367: COPY_MIDDLE macro ENTRY_LABEL,ENTRY_INDEX
        !          1368: &ENTRY_LABEL&ENTRY_INDEX&:
        !          1369:         mov     ecx,eax
        !          1370:         rep     movsb
        !          1371:         add     esi,edx
        !          1372:         add     edi,edx
        !          1373:         endm    ;-----------------------------------;
        !          1374: 
        !          1375: ;  EAX = # of bytes to copy
        !          1376: ;  EBX = count of unrolled loop iterations
        !          1377: ;  EDX = offset from end of one scan's fill to start of next
        !          1378: ;  ESI = source address from which to copy
        !          1379: ;  EDI = target address to which to copy
        !          1380: 
        !          1381:         align   4
        !          1382: middle_loop:
        !          1383:         UNROLL_LOOP     COPY_MIDDLE,MIDDLE,LOOP_UNROLL_COUNT
        !          1384:         dec     ebx
        !          1385:         jnz     middle_loop
        !          1386: 
        !          1387: ; get ready for next time:
        !          1388: 
        !          1389:         mov     ecx,ppdev
        !          1390:         sub     esi,[ecx].pdev_pvBitmapStart2WindowS
        !          1391:         sub     edi,[ecx].pdev_pvBitmapStart2WindowD
        !          1392:         mov     ulMiddleSrc,esi
        !          1393:         mov     ulMiddleDest,edi
        !          1394: 
        !          1395:         PLAIN_RET
        !          1396: 
        !          1397: ;-----------------------------------------------------------------------;
        !          1398: ; Input:
        !          1399: ;       ulLeftSrc     - offset in bitmap to source
        !          1400: ;       ulLeftDest    - offset in bitmap to destination
        !          1401: ;       lDelta        - distance from between planar scans
        !          1402: ;       ulBlockHeight - # of scans to copy
        !          1403: ;
        !          1404: ; Output:
        !          1405: ;       Advances ulLeftSrc and ulLeftDest to next strip
        !          1406: ;-----------------------------------------------------------------------;
        !          1407: 
        !          1408:         align   4
        !          1409:         public  copy_left_block
        !          1410: copy_left_block:
        !          1411: 
        !          1412: ; Set left mask by disabling some planes:
        !          1413: 
        !          1414:         mov     edx,VGA_BASE + SEQ_DATA
        !          1415:         mov     eax,ulLeftMask
        !          1416:         out     dx,al
        !          1417: 
        !          1418: ; Calculate full start addresses:
        !          1419: 
        !          1420:         mov     ecx,ppdev
        !          1421:         mov     ebx,ulBlockHeight
        !          1422:         mov     edx,lDelta
        !          1423:         mov     esi,[ecx].pdev_pvBitmapStart2WindowS
        !          1424:         mov     edi,[ecx].pdev_pvBitmapStart2WindowD
        !          1425:         add     esi,ulLeftSrc
        !          1426:         add     edi,ulLeftDest
        !          1427: 
        !          1428:         SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyLeftEntry, \
        !          1429:                                 LOOP_UNROLL_SHIFT
        !          1430: 
        !          1431:         jmp     eax
        !          1432: 
        !          1433:         UNROLL_LOOP_ENTRY_TABLE pfnCopyLeftEntry,LEFT, \
        !          1434:                                 LOOP_UNROLL_COUNT
        !          1435: 
        !          1436: COPY_LEFT macro ENTRY_LABEL,ENTRY_INDEX
        !          1437: &ENTRY_LABEL&ENTRY_INDEX&:
        !          1438:         mov     al,[esi]
        !          1439:         mov     [edi],al
        !          1440:         add     esi,edx
        !          1441:         add     edi,edx
        !          1442:         endm    ;-----------------------------------;
        !          1443: 
        !          1444: ;  EBX = count of unrolled loop iterations
        !          1445: ;  EDX = offset from one scan to next
        !          1446: ;  ESI = source address from which to copy
        !          1447: ;  EDI = target address to which to copy
        !          1448: 
        !          1449:         align   4
        !          1450: left_loop:
        !          1451:         UNROLL_LOOP     COPY_LEFT,LEFT,LOOP_UNROLL_COUNT
        !          1452:         dec     ebx
        !          1453:         jnz     left_loop
        !          1454: 
        !          1455: ; get ready for next time:
        !          1456: 
        !          1457:         sub     esi,[ecx].pdev_pvBitmapStart2WindowS
        !          1458:         sub     edi,[ecx].pdev_pvBitmapStart2WindowD
        !          1459:         mov     ulLeftSrc,esi
        !          1460:         mov     ulLeftDest,edi
        !          1461: 
        !          1462:         PLAIN_RET
        !          1463: 
        !          1464: ;-----------------------------------------------------------------------;
        !          1465: ; Input:
        !          1466: ;       ulRightSrc    - offset in bitmap to source
        !          1467: ;       ulRightDest   - offset in bitmap to destination
        !          1468: ;       lDelta        - distance from between planar scans
        !          1469: ;       ulBlockHeight - # of scans to copy
        !          1470: ;
        !          1471: ; Output:
        !          1472: ;       Advances ulRightSrc and ulRightDest to next strip
        !          1473: ;-----------------------------------------------------------------------;
        !          1474: 
        !          1475:         align   4
        !          1476:         public  copy_right_block
        !          1477: copy_right_block:
        !          1478: 
        !          1479: ; Set right mask by disabling some planes:
        !          1480: 
        !          1481:         mov     edx,VGA_BASE + SEQ_DATA
        !          1482:         mov     eax,ulRightMask
        !          1483:         out     dx,al
        !          1484: 
        !          1485: ; Calculate full start addresses:
        !          1486: 
        !          1487:         mov     ecx,ppdev
        !          1488:         mov     ebx,ulBlockHeight
        !          1489:         mov     edx,lDelta
        !          1490:         mov     esi,[ecx].pdev_pvBitmapStart2WindowS
        !          1491:         mov     edi,[ecx].pdev_pvBitmapStart2WindowD
        !          1492:         add     esi,ulRightSrc
        !          1493:         add     edi,ulRightDest
        !          1494: 
        !          1495:         SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyRightEntry, \
        !          1496:                                 LOOP_UNROLL_SHIFT
        !          1497: 
        !          1498:         jmp     eax
        !          1499: 
        !          1500:         UNROLL_LOOP_ENTRY_TABLE pfnCopyRightEntry,RIGHT, \
        !          1501:                                 LOOP_UNROLL_COUNT
        !          1502: 
        !          1503: COPY_RIGHT macro ENTRY_LABEL,ENTRY_INDEX
        !          1504: &ENTRY_LABEL&ENTRY_INDEX&:
        !          1505:         mov     al,[esi]
        !          1506:         mov     [edi],al
        !          1507:         add     esi,edx
        !          1508:         add     edi,edx
        !          1509:         endm    ;-----------------------------------;
        !          1510: 
        !          1511: ;  EBX = count of unrolled loop iterations
        !          1512: ;  EDX = offset from one scan to next
        !          1513: ;  ESI = source address from which to copy
        !          1514: ;  EDI = target address to which to copy
        !          1515: 
        !          1516:         align   4
        !          1517: right_loop:
        !          1518:         UNROLL_LOOP     COPY_RIGHT,RIGHT,LOOP_UNROLL_COUNT
        !          1519:         dec     ebx
        !          1520:         jnz     right_loop
        !          1521: 
        !          1522: ; get ready for next time:
        !          1523: 
        !          1524:         sub     esi,[ecx].pdev_pvBitmapStart2WindowS
        !          1525:         sub     edi,[ecx].pdev_pvBitmapStart2WindowD
        !          1526:         mov     ulRightSrc,esi
        !          1527:         mov     ulRightDest,edi
        !          1528: 
        !          1529:         PLAIN_RET
        !          1530: 
        !          1531: ;-----------------------------------------------------------------------;
        !          1532: 
        !          1533: endProc vPlanarCopyBits
        !          1534: 
        !          1535:         end
        !          1536: 

unix.superglobalmegacorp.com

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