;---------------------------Module-Header------------------------------; ; Module Name: scroll.asm ; ; Copyright (c) 1992-1993 Microsoft Corporation ;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------; ; VOID vPlanarCopyBits(ppdev, prclDest, pptlSrc); ; ; Input: ; ; ppdev - surface on which to copy ; prcldest - pointer to destination rectangle ; pptlsrc - pointer to source upper left corner ; ; Performs accelerated SRCCOPY screen-to-screen blts. ; ;-----------------------------------------------------------------------; ; ; NOTE: This handles only quad-pixel aligned blits! ; ; NOTE: Assumes all rectangles have positive heights and widths. Will ; not work properly if this is not the case. ; ;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------; ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want loops in ; this module unrolled. For example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8 ; times unrolling. This is the only thing you need to change to control ; unrolling. LOOP_UNROLL_SHIFT equ 1 ;-----------------------------------------------------------------------; .386 .model small,c assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT assume fs:nothing,gs:nothing .xlist include stdcall.inc ;calling convention cmacros include i386\strucs.inc include i386\driver.inc include i386\unroll.inc include i386\egavga.inc .list ;-----------------------------------------------------------------------; .code EXTRNP bPuntScreenToScreenCopyBits,20 .data ; Bits for block copier tables: BLOCK_RIGHT_TO_LEFT equ 4 BLOCK_LEFT_EDGE equ 2 BLOCK_RIGHT_EDGE equ 1 ;-----------------------------------------------------------------------; ; Table of block copiers for various horizontal directions, with the ; look-up index a 3-bit field as follows: ; ; Bit 2 (BLOCK_RIGHT_TO_LEFT) = 1 if right-to-left copy ; Bit 1 (BLOCK_LEFT_EDGE) = 1 if left edge must be copied ; Bit 0 (BLOCK_RIGHT_EDGE) = 1 if right edge must be copied align 4 MasterBlockTable label dword dd copy_just_middle_block dd Block_WR dd Block_LW dd Block_LWR dd copy_just_middle_block dd Block_RW dd Block_WL dd Block_RWL align 4 TopToBottomLoopTable label dword dd 0 ;Not used - unbanked case dd top_to_bottom_1RW dd top_to_bottom_2RW dd top_to_bottom_2RW align 4 BottomToTopLoopTable label dword dd 0 ;Not used - unbanked case dd bottom_to_top_1RW dd bottom_to_top_2RW dd bottom_to_top_2RW align 4 SetUpForCopyDirection label dword dd left_to_right_top_to_bottom ;CD_RIGHTDOWN dd right_to_left_top_to_bottom ;CD_LEFTDOWN dd left_to_right_bottom_to_top ;CD_RIGHTUP dd right_to_left_bottom_to_top ;CD_LEFTUP LeftMaskTable label dword dd 01111b dd 01100b RightMaskTable label dword dd 00000b dd 00011b ;-----------------------------------------------------------------------; .code Block_WR: push offset copy_right_block jmp copy_middle_block Block_LW: push offset copy_middle_block jmp copy_left_block Block_LWR: push offset copy_right_block push offset copy_middle_block jmp copy_left_block Block_RW: push offset copy_middle_block jmp copy_right_block Block_WL: push offset copy_left_block jmp copy_middle_block Block_RWL: push offset copy_left_block push offset copy_middle_block jmp copy_right_block ;-----------------------------------------------------------------------; cProc vPlanarCopyBits,12,< \ uses esi edi ebx, \ ppdev: ptr PDEV, \ prclDest: ptr RECTL, \ pptlSrc: ptr POINTL > ; Variables used in block copiers: local pfnCopyBlocks: ptr ;pointer to block copy routines local ulMiddleSrc: dword ;bitmap offset to 1st source local ulMiddleDest: dword ;bitmap offset to 1st dest local lMiddleDelta: dword ;delta from end of middle scan to next local ulBlockHeight: dword ;number of scans to be copied in block local cjMiddle: dword ;number of bytes to be copied on scan local ulLeftSrc: dword ;bitmap offset to left source byte edge local ulLeftDest: dword ;bitmap offset to left dest byte edge local ulRightSrc: dword ;bitmap offset to right source byte edge local ulRightDest: dword ;bitmap offset to right dest byte edge local lDelta: dword ;delta between scans local ulLeftMask: dword ;byte mask for left-edge copies local ulRightMask: dword ;byte mask for right-edge copies local rclDest[size RECTL]: byte ;left and right values always valid local ptlSrc[size POINTL]: byte ;x value always valid local ulCurrentSrcScan: dword ;real current source scan local ulCurrentDestScan: dword ;real current destination scan local ulLastDestScan: dword ;last destination scan ; Set the bit mask to disable all bits, so we can copy through the latches: mov edx,VGA_BASE + GRAF_ADDR mov eax,(0 shl 8) + GRAF_BIT_MASK out dx,ax ; Figure out which direction to do the copies: mov esi,pptlSrc mov edi,prclDest mov eax,[esi].ptl_y cmp eax,[edi].yTop jl planar_bottom_to_top mov eax,[esi].ptl_x cmp eax,[edi].xLeft jge short left_to_right_top_to_bottom ; CD_RIGHTDOWN jmp right_to_left_top_to_bottom ; CD_LEFTDOWN planar_bottom_to_top: mov eax,[esi].ptl_x cmp eax,[edi].xLeft jge left_to_right_bottom_to_top ; CD_RIGHTUP jmp right_to_left_bottom_to_top ; CD_LEFTUP all_done: ; Enable bit mask for all bits: mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax ; Enable writes to all planes and reset direction flag: mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al cld cRet vPlanarCopyBits ;=======================================================================; ;==================== Direction Dependent Setup ========================; ;=======================================================================; ;-----------------------------------------------------------------------; ; Set-up code for left-to-right, top-to-bottom copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------; public left_to_right_top_to_bottom left_to_right_top_to_bottom:: ; Need to set-up: ulMiddleSrc, ulMiddleDest, lMiddleDelta, cjMiddle ; ulLeftSrc, ulLeftDest, ulLeftMask ; lDelta ; ulRightSrc, ulRightDest, ulRightMask ; ulCurrentDestScan, ulLastDestScan ; pfnCopyBlocks ; ptlSrc.x, rclDest.left, rclDest.right ; lDelta = ppdev->lPlanarScan ; ulCurrentSrcScan = pptl->y ; ulLeftSrc = pptl->y * lDelta + (pptl->x >> 1) ; ulCurrentDestScan = prclDest->top ; ulLeftDest = prclDest->top * lDelta + (prclDest->left >> 1) ; ; ulMiddleSrc = ulLeftSrc ; ulMiddleDest = ulLeftDest ; ; cjMiddle = (prclDest->right >> 1) - (prclDest->left >> 1) ; if (prclDest->left & 3) ; ulLeftMask = LeftMaskTable[prclDest->left & 1] ; fl |= BLOCK_LEFT_EDGE ; ulMiddleSrc++ ; ulMiddleDest++ ; cjMiddle-- ; ; lMiddleDelta = lDelta - cjMiddle ; ; if (prclDest->right & 1) ; ulRightMask = RightMaskTable[prclDest->right & 1] ; fl |= BLOCK_RIGHT_EDGE ; ulRightSrc = ulMiddleSrc + cjMiddle ; ulRightDest = ulMiddleDest + cjMiddle mov edx,ppdev mov eax,[edi].yBottom mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->bottom mov ecx,[esi].ptl_y mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x shr ecx,1 add eax,ecx ;eax = ulLeftSrc = pptlSrc->y * ; lDelta + (pptlSrc->x >> 1) xor esi,esi ;initialize flags mov ecx,[edi].yTop mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->top imul ebx,ecx mov ecx,[edi].xLeft mov rclDest.xLeft,ecx ;rclDest.left = prclDest->left shr ecx,1 add ebx,ecx ;ebx = ulLeftDest = prclDest->top * ; lDelta + (prclDest->left >> 1) mov edi,[edi].xRight mov rclDest.xRight,edi shr edi,1 sub edi,ecx ;cjMiddle = (prclDest->right >> 1) - ; (prclDest->left >> 1) mov ecx,rclDest.xLeft and ecx,1 jz short l_t_done_left_edge ;skip if we don't need a left edge or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1] mov ulLeftSrc,eax ;ulLeftSrc mov ulLeftDest,ebx ;ulLeftDest inc eax inc ebx dec edi l_t_done_left_edge: mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest mov ecx,rclDest.xRight and ecx,1 jz short l_t_done_right_edge ;skip if we don't need a right edge or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1] add eax,edi add ebx,edi mov ulRightSrc,eax ;ulRightSrc = ulMiddleSrc + cjMiddle mov ulRightDest,ebx ;ulRightDest = ulMiddleDest + cjMiddle ; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple: cmp edi,0 jge l_t_done_right_edge ; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulLeftMask the composite mask: inc edi xor esi,BLOCK_RIGHT_EDGE and ecx,ulLeftMask mov ulLeftMask,ecx l_t_done_right_edge: mov cjMiddle,edi ;cjMiddle mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan sub edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta - cjMiddle mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory ; Branch to the appropriate top-to-bottom bank enumeration loop: mov eax,[ebx].pdev_vbtPlanarType jmp TopToBottomLoopTable[eax*4] ;-----------------------------------------------------------------------; ; Set-up code for right-to-left, top-to-bottom copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------; public right_to_left_top_to_bottom right_to_left_top_to_bottom:: std ;copy middle blocks right-to-left mov edx,ppdev mov eax,[edi].yBottom mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->bottom mov ecx,[esi].ptl_y mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x add ecx,[edi].xRight sub ecx,[edi].xLeft shr ecx,1 add eax,ecx ;eax = ulRightSrc = pptlSrc->y * ; lDelta + (pptlSrc->x + ; prclDest->right - prclDest->left) / 2 mov esi,BLOCK_RIGHT_TO_LEFT ;initialize flags mov ecx,[edi].yTop mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->top imul ebx,ecx mov ecx,[edi].xRight mov rclDest.xRight,ecx ;rclDest.right = prclDest->right shr ecx,1 add ebx,ecx ;ebx = ulRightDest = prclDest->top * ; lDelta + prclDest->right / 2 mov edi,[edi].xLeft mov rclDest.xLeft,edi shr edi,1 neg edi add edi,ecx ;cjMiddle = prclDest->right / 2 - ; prclDest->left / 2 mov ecx,rclDest.xRight and ecx,1 jz short r_t_done_right_edge ;skip if we don't need a right edge or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1] mov ulRightSrc,eax ;ulRightSrc mov ulRightDest,ebx ;ulRightDest r_t_done_right_edge: dec eax dec ebx mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest mov ecx,rclDest.xLeft and ecx,1 jz short r_t_done_left_edge ;skip if we don't need a right edge or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1] dec edi ;adjust middle block length because ; we're effectively doing one less ; middle byte sub eax,edi sub ebx,edi mov ulLeftSrc,eax ;ulLeftSrc = ulMiddleSrc - cjMiddle mov ulLeftDest,ebx ;ulLeftDest = ulMiddleDest - cjMiddle ; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple: cmp edi,0 jge r_t_done_left_edge ; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulRightMask the composite mask: inc edi xor esi,BLOCK_LEFT_EDGE and ecx,ulRightMask mov ulRightMask,ecx r_t_done_left_edge: mov cjMiddle,edi ;cjMiddle mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan add edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta + cjMiddle mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory ; Branch to the appropriate top-to-bottom bank enumeration loop: mov eax,[ebx].pdev_vbtPlanarType jmp TopToBottomLoopTable[eax*4] ;-----------------------------------------------------------------------; ; Set-up code for left-to-right, bottom-to-top copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------; public left_to_right_bottom_to_top left_to_right_bottom_to_top:: mov edx,ppdev mov eax,[edi].yTop mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->top mov ecx,[esi].ptl_y add ecx,[edi].yBottom sub ecx,[edi].yTop mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y + ; (prclDest->bottom - prclDest->top) dec ecx imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x shr ecx,1 add eax,ecx ;eax = ulLeftSrc = (ulCurrentSrcScan - 1) ; * lDelta + (pptlSrc->x >> 1) xor esi,esi ;initialize flags mov ecx,[edi].yBottom mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->bottom dec ecx imul ebx,ecx mov ecx,[edi].xLeft mov rclDest.xLeft,ecx ;rclDest.left = prclDest->left shr ecx,1 add ebx,ecx ;ebx = ulLeftDest = (prclDest->bottom - 1) ; * lDelta + (prclDest->left >> 1) mov edi,[edi].xRight mov rclDest.xRight,edi shr edi,1 sub edi,ecx ;cjMiddle = (prclDest->right >> 1) - ; (prclDest->left >> 1) mov ecx,rclDest.xLeft and ecx,1 jz short l_b_done_left_edge ;skip if we don't need a left edge or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 3] mov ulLeftSrc,eax ;ulLeftSrc mov ulLeftDest,ebx ;ulLeftDest inc eax inc ebx dec edi l_b_done_left_edge: mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest mov ecx,rclDest.xRight and ecx,1 jz short l_b_done_right_edge ;skip if we don't need a right edge or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1] add eax,edi add ebx,edi mov ulRightSrc,eax ;ulRightSrc = ulMiddleSrc + cjMiddle mov ulRightDest,ebx ;ulRightDest = ulMiddleDest + cjMiddle ; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple: cmp edi,0 jge l_b_done_right_edge ; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulLeftMask the composite mask: inc edi xor esi,BLOCK_RIGHT_EDGE and ecx,ulLeftMask mov ulLeftMask,ecx l_b_done_right_edge: mov cjMiddle,edi ;cjMiddle neg edx mov lDelta,edx ;lDelta = -ppdev->lPlanarNextScan sub edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta - cjMiddle mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory ; Branch to the appropriate top-to-bottom bank enumeration loop: mov eax,[ebx].pdev_vbtPlanarType jmp BottomToTopLoopTable[eax*4] ;-----------------------------------------------------------------------; ; Set-up code for right-to-left, bottom-to-top copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------; public right_to_left_bottom_to_top right_to_left_bottom_to_top:: std ;copy middle blocks right-to-left mov edx,ppdev mov eax,[edi].yTop mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->top mov ecx,[esi].ptl_y add ecx,[edi].yBottom sub ecx,[edi].yTop mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y + ; (prclDest->bottom - prclDest->top) dec ecx imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x add ecx,[edi].xRight sub ecx,[edi].xLeft shr ecx,1 add eax,ecx ;eax = ulRightSrc = (ulCurrentSrcScan ; - 1) * lDelta + (pptlSrc->x + ; prclDest->right - prclDest->left) / 2 mov esi,BLOCK_RIGHT_TO_LEFT ;initialize flags mov ecx,[edi].yBottom mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->bottom dec ecx imul ebx,ecx mov ecx,[edi].xRight mov rclDest.xRight,ecx ;rclDest.right = prclDest->right shr ecx,1 add ebx,ecx ;ebx = ulRightDest = (ulCurrentDestScan ; - 1) * lDelta + prclDest->right / 2 mov edi,[edi].xLeft mov rclDest.xLeft,edi shr edi,1 neg edi add edi,ecx ;cjMiddle = prclDest->right / 2 - ; prclDest->left / 2 mov ecx,rclDest.xRight and ecx,1 jz short r_b_done_right_edge ;skip if we don't need a right edge or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1] mov ulRightSrc,eax ;ulRightSrc mov ulRightDest,ebx ;ulRightDest r_b_done_right_edge: dec eax dec ebx mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest mov ecx,rclDest.xLeft and ecx,1 jz short r_b_done_left_edge ;skip if we don't need a right edge or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1] dec edi ;adjust middle block length because ; we're effectively doing one less ; middle byte sub eax,edi sub ebx,edi mov ulLeftSrc,eax ;ulLeftSrc = ulMiddleSrc - cjMiddle mov ulLeftDest,ebx ;ulLeftDest = ulMiddleDest - cjMiddle ; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple: cmp edi,0 jge r_b_done_left_edge ; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulRightMask the composite mask: inc edi xor esi,BLOCK_LEFT_EDGE and ecx,ulRightMask mov ulRightMask,ecx r_b_done_left_edge: mov cjMiddle,edi ;cjMiddle neg edx mov lDelta,edx ;lDelta = -ppdev->lPlanarNextScan add edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta + cjMiddle mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory ; Branch to the appropriate top-to-bottom bank enumeration loop: mov eax,[ebx].pdev_vbtPlanarType jmp BottomToTopLoopTable[eax*4] ;=======================================================================; ;============================= Banking =================================; ;=======================================================================; ;-----------------------------------------------------------------------; ; Banking for 1 R/W adapters, top to bottom. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public top_to_bottom_1RW top_to_bottom_1RW:: ; LATER: Should check to see if there's any chance that the source and ; destination overlap in the same window, so that we can use planar ; copies -- otherwise, it's faster to directly call of to ; bPuntScreenToScreenCopyBits ; We're going top to bottom. Map in the source and dest, top-justified. mov ebx,ppdev mov edi,ulCurrentDestScan cmp edi,[ebx].pdev_rcl1PlanarClip.yTop jl short top_1RW_map_init_bank cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom jl short top_1RW_init_bank_mapped top_1RW_map_init_bank: ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ top_1RW_init_bank_mapped: mov eax,ulCurrentSrcScan cmp eax,[ebx].pdev_rcl1PlanarClip.yBottom jl short top_1RW_do_planar_copy ; ulCurrentSrcScan >= ppdev->rcl1PlanarClip.bottom, which means that ; the window can't overlap the source and destination at all. We'll ; have to use an intermediate temporary buffer: ; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan mov ptlSrc.ptl_y,eax ;ptlSrc.y = ulCurrentSrcScan mov rclDest.yTop,edi ;rclDest.top = ulCurrentDestScan mov esi,[ebx].pdev_rcl1PlanarClip.yBottom mov eax,ulLastDestScan sub eax,esi sbb ecx,ecx and ecx,eax add esi,ecx mov rclDest.yBottom,esi ;rclDest.bottom = min(ulLastDestScan, ; ppdev->pdev_rcl1PlanarClip.bottom) ; Enable bit mask for all bits: mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax ; Enable writes to all planes and reset direction flag: mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al pushfd cld ; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI ; according to C calling conventions: lea ecx,rclDest lea edx,ptlSrc cCall bPuntScreenToScreenCopyBits, popfd ; Set the bit mask to disable all bits, so we can copy through latches again: mov edx,VGA_BASE + GRAF_ADDR mov eax,(000h shl 8) + GRAF_BIT_MASK out dx,ax ; Update our position variables: mov ulCurrentDestScan,esi ;ulCurrentDestScan = rclDest.bottom sub esi,edi ;ulBlockHeight = rclDest.bottom - ; rclDest.top add ulCurrentSrcScan,esi ;ulCurrentSrcScan += ulBlockHeight ; We have to adjust the offsets for all our block copiers, according to the ; number of scans we copied: mov edx,lDelta imul edx,esi ;edx = lDelta * ulBlockHeight add ulLeftSrc,edx add ulLeftDest,edx add ulMiddleSrc,edx add ulMiddleDest,edx add ulRightSrc,edx add ulRightDest,edx jmp short top_1RW_see_if_done top_1RW_do_planar_copy: ; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan mov ebx,[ebx].pdev_rcl1PlanarClip.yBottom sub ebx,eax ;ebx = ppdev->rcl1PlanarClip.bottom - ; ulCurrentSrcScan ;ebx is the available number of scans ; we have in the source mov edx,ulLastDestScan sub edx,edi ;edx = ulLastDestScan - ulCurrentDestScan ;edx is the available number of scans ; in the destination ; (Because the source starts lower in the window than the destination, ; the bottom of the bank always limits the source number of scans before ; it does the destination.) sub ebx,edx sbb ecx,ecx and ecx,ebx add edx,ecx ;edx = min(source available, ; destination available) mov ulBlockHeight,edx add eax,edx ;We have to adjust our current scans add edi,edx mov ulCurrentSrcScan,eax mov ulCurrentDestScan,edi ; Now copy the puppy: call pfnCopyBlocks ; See if we're done: top_1RW_see_if_done: mov edi,ulCurrentDestScan cmp edi,ulLastDestScan jge all_done mov ebx,ppdev ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ jmp top_1RW_init_bank_mapped ;-----------------------------------------------------------------------; ; Banking for 1 R/W adapters, bottom to top. ; ; Input: ; ulCurrentSrcScan - Actually, 1 more current source scan ; ulCurrentDestScan - Actually, 1 more current destination scan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public bottom_to_top_1RW bottom_to_top_1RW:: ; We're going top to bottom. Map in the source and dest, top-justified. mov ebx,ppdev mov edi,ulCurrentDestScan cmp edi,[ebx].pdev_rcl1PlanarClip.yTop jle short bot_1RW_map_init_bank cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom jle short bot_1RW_init_bank_mapped bot_1RW_map_init_bank: ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec edi ptrCall , \ inc edi bot_1RW_init_bank_mapped: mov eax,ulCurrentSrcScan cmp eax,[ebx].pdev_rcl1PlanarClip.yTop jg short bot_1RW_do_planar_copy ; ulCurrentSrcScan <= ppdev->rcl1PlanarClip.top, which means that ; the window can't overlap the source and destination at all. We'll ; have to use an intermediate temporary buffer: ; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan mov esi,[ebx].pdev_rcl1PlanarClip.yTop mov edx,ulLastDestScan cmp esi,edx jg @F mov esi,edx @@: mov rclDest.yTop,esi ;rclDest.top = max(ulLastDestScan, ; ppdev->rcl1PlanarClip.top) mov rclDest.yBottom,edi ;rclDest.bottom = ulCurrentDestScan add eax,esi sub eax,edi mov ptlSrc.ptl_y,eax ;ptlSrc.y = ulCurrentSrcScan - ; (rclDest.bottom - rclDest.top) ; Enable bit mask for all bits: mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax ; Enable writes to all planes and reset direction flag: mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al pushfd cld ; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI ; according to C calling conventions: lea ecx,rclDest lea edx,ptlSrc cCall bPuntScreenToScreenCopyBits, popfd ; Set the bit mask to disable all bits, so we can copy through latches again: mov edx,VGA_BASE + GRAF_ADDR mov eax,(000h shl 8) + GRAF_BIT_MASK out dx,ax ; Update our position variables: mov ulCurrentDestScan,esi ;ulCurrentDestScan = rclDest.top sub edi,esi ;ulBlockHeight = rclDest.bottom - ; rclDest.top sub ulCurrentSrcScan,edi ;ulCurrentSrcScan -= ulBlockHeight ; We have to adjust the offsets for all our block copiers, according to the ; number of scans we copied: mov edx,lDelta imul edx,edi ;edx = lDelta * ulBlockHeight add ulLeftSrc,edx add ulLeftDest,edx add ulMiddleSrc,edx add ulMiddleDest,edx add ulRightSrc,edx add ulRightDest,edx jmp short bot_1RW_see_if_done bot_1RW_do_planar_copy: ; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan sub eax,[ebx].pdev_rcl1PlanarClip.yTop ;eax = ulCurrentSrcScan - ; ppdev->rcl1PlanarClip.top sub edi,ulLastDestScan ;edi = ulCurrentDestScan - ulLastDestScan ;edi is the available number of scans ; in the destination ; (Because the source starts higher in the window than the destination, ; the bottom of the bank always limits the source number of scans before ; it does the destination.) sub eax,edi sbb ecx,ecx and ecx,eax add edi,ecx ;edi = min(source available, ; destination available) mov ulBlockHeight,edi sub ulCurrentSrcScan,edi ;We have to adjust our current scans sub ulCurrentDestScan,edi ; Now copy the puppy: call pfnCopyBlocks ; See if we're done: bot_1RW_see_if_done: mov edi,ulCurrentDestScan cmp edi,ulLastDestScan jle all_done mov ebx,ppdev ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec edi ptrCall , \ inc edi jmp bot_1RW_init_bank_mapped ;-----------------------------------------------------------------------; ; Banking for 1R/1W or 2R/W adapters, top to bottom. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public top_to_bottom_2RW top_to_bottom_2RW:: ; We're going top to bottom. Map in the destination, top-justified. mov ebx,ppdev mov edi,ulCurrentDestScan mov esi,ulCurrentSrcScan cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jl short top_2RW_map_init_dest_bank cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jl short top_2RW_init_dest_bank_mapped top_2RW_map_init_dest_bank: ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ top_2RW_init_dest_bank_mapped: cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jl short top_2RW_map_init_src_bank cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jl short top_2RW_main_loop top_2RW_map_init_src_bank: ; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ top_2RW_main_loop: mov ecx,[ebx].pdev_rcl2PlanarClipD.yBottom mov edx,ulLastDestScan sub ecx,edx sbb eax,eax and eax,ecx add edx,eax ;edx = min(ulLastDestScan, ; ppdev->rcl2PlanarClipD.bottom) mov ecx,[ebx].pdev_rcl2PlanarClipS.yBottom sub edx,edi ;edx = available scans in destination ; bank sub ecx,esi ;ecx = available scans in source bank sub ecx,edx sbb eax,eax and eax,ecx add edx,eax mov ulBlockHeight,edx ;ulBlockHeight = min(source available, ; dest available) add esi,edx ;adjust our currents scans accordingly add edi,edx mov ulCurrentSrcScan,esi mov ulCurrentDestScan,edi ; Do the actual copy: call pfnCopyBlocks mov edi,ulCurrentDestScan ;check if done cmp edi,ulLastDestScan jge all_done mov ebx,ppdev ; We'll have to map a new source bank, destination bank, or both: mov esi,ulCurrentSrcScan cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jl short top_2RW_map_next_src_bank ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jl short top_2RW_main_loop top_2RW_map_next_src_bank: ; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. ptrCall , \ jmp short top_2RW_main_loop ;-----------------------------------------------------------------------; ; Banking for 1R/1W or 2R/W adapters, bottom to top. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public bottom_to_top_2RW bottom_to_top_2RW:: ; We're going bottom to top. Map in the destination, bottom-justified. mov ebx,ppdev mov edi,ulCurrentDestScan ; 1 more than actual destination scan mov esi,ulCurrentSrcScan ; 1 more than actual source scan cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jle short bot_2RW_map_init_dest_bank cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jle short bot_2RW_init_dest_bank_mapped bot_2RW_map_init_dest_bank: ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec edi ptrCall , \ inc edi bot_2RW_init_dest_bank_mapped: cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jle short bot_2RW_map_init_src_bank cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jle short bot_2RW_main_loop bot_2RW_map_init_src_bank: ; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec esi ptrCall , \ inc esi bot_2RW_main_loop: mov ecx,[ebx].pdev_rcl2PlanarClipD.yTop mov edx,ulLastDestScan cmp edx,ecx jg @F mov edx,ecx ;edx = max(ulLastDestScan, @@: ; ppdev->rcl2PlanarClipD.top) sub edi,edx ;edi = available scans in destination ; bank sub esi,[ebx].pdev_rcl2PlanarClipS.yTop ;esi = available scans in source bank sub esi,edi sbb eax,eax and eax,esi add edi,eax mov ulBlockHeight,edi ;ulBlockHeight = min(source available, ; dest available) sub ulCurrentSrcScan,edi ;adjust our current scans sub ulCurrentDestScan,edi ; Do the actual copy: call pfnCopyBlocks mov edi,ulCurrentDestScan ;check if done cmp edi,ulLastDestScan jle all_done mov ebx,ppdev ; We'll have to map a new source bank, destination bank, or both: mov esi,ulCurrentSrcScan cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jg short bot_2RW_map_next_src_bank ; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec edi ptrCall , \ inc edi cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jg short bot_2RW_main_loop bot_2RW_map_next_src_bank: ; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions. dec esi ptrCall , \ inc esi jmp short bot_2RW_main_loop ;=======================================================================; ;=========================== Block Copiers =============================; ;=======================================================================; ;-----------------------------------------------------------------------; ; Input: ; Direction flag - set to the appropriate direction ; ulMiddleSrc - offset in bitmap to source ; ulMiddleDest - offset in bitmap to destination ; lMiddleDelta - distance from end of current scan to start of next ; ulBlockHeight - # of scans to copy ; cjMiddle - # of planar bytes to copy on every scan ; ; Output: ; Advances ulMiddleSrc and ulMiddleDest to next strip ;-----------------------------------------------------------------------; public copy_middle_block copy_middle_block:: ; We only have to reset which planes are enabled if we do edges too: mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al copy_just_middle_block:: ; Calculate full start addresses: mov edi,ppdev mov eax,cjMiddle mov ebx,ulBlockHeight mov edx,lMiddleDelta mov esi,[edi].pdev_pvBitmapStart2WindowS mov edi,[edi].pdev_pvBitmapStart2WindowD add esi,ulMiddleSrc add edi,ulMiddleDest SET_UP_UNROLL_VARS ebx,ecx,ebx,pfnCopyMiddleEntry, \ LOOP_UNROLL_SHIFT jmp ecx UNROLL_LOOP_ENTRY_TABLE pfnCopyMiddleEntry,MIDDLE, \ LOOP_UNROLL_COUNT COPY_MIDDLE macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov ecx,eax rep movsb add esi,edx add edi,edx endm ;-----------------------------------; ; EAX = # of bytes to copy ; EBX = count of unrolled loop iterations ; EDX = offset from end of one scan's fill to start of next ; ESI = source address from which to copy ; EDI = target address to which to copy middle_loop: UNROLL_LOOP COPY_MIDDLE,MIDDLE,LOOP_UNROLL_COUNT dec ebx jnz middle_loop ; get ready for next time: mov ecx,ppdev sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulMiddleSrc,esi mov ulMiddleDest,edi PLAIN_RET ;-----------------------------------------------------------------------; ; Input: ; ulLeftSrc - offset in bitmap to source ; ulLeftDest - offset in bitmap to destination ; lDelta - distance from between planar scans ; ulBlockHeight - # of scans to copy ; ; Output: ; Advances ulLeftSrc and ulLeftDest to next strip ;-----------------------------------------------------------------------; public copy_left_block copy_left_block:: ; Set left mask by disabling some planes: mov edx,VGA_BASE + SEQ_DATA mov eax,ulLeftMask out dx,al ; Calculate full start addresses: mov ecx,ppdev mov ebx,ulBlockHeight mov edx,lDelta mov esi,[ecx].pdev_pvBitmapStart2WindowS mov edi,[ecx].pdev_pvBitmapStart2WindowD add esi,ulLeftSrc add edi,ulLeftDest SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyLeftEntry, \ LOOP_UNROLL_SHIFT jmp eax UNROLL_LOOP_ENTRY_TABLE pfnCopyLeftEntry,LEFT, \ LOOP_UNROLL_COUNT COPY_LEFT macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov al,[esi] mov [edi],al add esi,edx add edi,edx endm ;-----------------------------------; ; EBX = count of unrolled loop iterations ; EDX = offset from one scan to next ; ESI = source address from which to copy ; EDI = target address to which to copy left_loop: UNROLL_LOOP COPY_LEFT,LEFT,LOOP_UNROLL_COUNT dec ebx jnz left_loop ; get ready for next time: sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulLeftSrc,esi mov ulLeftDest,edi PLAIN_RET ;-----------------------------------------------------------------------; ; Input: ; ulRightSrc - offset in bitmap to source ; ulRightDest - offset in bitmap to destination ; lDelta - distance from between planar scans ; ulBlockHeight - # of scans to copy ; ; Output: ; Advances ulRightSrc and ulRightDest to next strip ;-----------------------------------------------------------------------; public copy_right_block copy_right_block:: ; Set right mask by disabling some planes: mov edx,VGA_BASE + SEQ_DATA mov eax,ulRightMask out dx,al ; Calculate full start addresses: mov ecx,ppdev mov ebx,ulBlockHeight mov edx,lDelta mov esi,[ecx].pdev_pvBitmapStart2WindowS mov edi,[ecx].pdev_pvBitmapStart2WindowD add esi,ulRightSrc add edi,ulRightDest SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyRightEntry, \ LOOP_UNROLL_SHIFT jmp eax UNROLL_LOOP_ENTRY_TABLE pfnCopyRightEntry,RIGHT, \ LOOP_UNROLL_COUNT COPY_RIGHT macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov al,[esi] mov [edi],al add esi,edx add edi,edx endm ;-----------------------------------; ; EBX = count of unrolled loop iterations ; EDX = offset from one scan to next ; ESI = source address from which to copy ; EDI = target address to which to copy right_loop: UNROLL_LOOP COPY_RIGHT,RIGHT,LOOP_UNROLL_COUNT dec ebx jnz right_loop ; get ready for next time: sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulRightSrc,esi mov ulRightDest,edi PLAIN_RET ;-----------------------------------------------------------------------; endProc vPlanarCopyBits end