
;	void _Near copy(srcx, srcy, dstx, dsty, width, height, scrwidth, gran)
;	int srcx;	/* EAX */
;	int srcy;	/* EDX */
;	int dstx;	/* EBX */
;	int dsty;	/* ECX */
;	int width, height;	/* pushed on stack */
;	int scrwidth;		/* pushed on stack */
;	u_char gran;		/* ignored */
;
;	copy rectangles
;
c_width	=	8
c_height =	12
c_scrwidth =	16
c_gran =	20
VGA_SEG =	0a0000h

CCOPY	PROC NEAR
	push	ebp
	mov	ebp,esp
	push	esi
	push	edi

	mov	edi,ebx		; save EBX (dstx)
	mov	esi,eax		; save EAX (srcx)

	mov	ebx,c_scrwidth[ebp]

	movzx	eax,dx		; srcy
	mul	bx		; multiply it by screen width
	add	ax,si		; srcy * screen_width + srcx
	adc	dx,0		; add overlap into src page (DL)
	mov	esi,VGA_SEG
	mov	si,ax		; offset

	movzx	eax,cx		; dsty
	mov	cl,dl		; save src page in CL
	mul	bx		; multiply it by 640 (screen width)
	add	ax,di		; add dstx
	adc	dx,0
	mov	edi,VGA_SEG
	mov	di,ax
	mov	dh,cl		; dh = src page
				; dl = dst page
	;	reg DL has the dst page number
	;	reg DH has the src page number
	;	reg SI has the src data pointer
	;	reg DI has the dst data pointer
	;	reg BX has the screen width

	cmp	dh,dl		; compare src and dst page numbers
	ja	short $C10
	jb	short backward
	cmp	edi,esi		; overlap can occur
	ja	short backward		; if dst < src, forward
$C10:				; reverse it
	sub	ebx,c_width[ebp]	; bytes to next scan line
	setpage	dh,dl		; setup VGA paging register
	jmp	forward

backward:
	push	edx		; save src & dst pages

	; Move the pointers to the last byte to be copied.  First,
	; put the page offset in cl and the byte offset in ax.  Second,
	; add these to the pointers.
	mov	eax,c_height[ebp]	; get height
	dec	eax
	mul	bx		; dx:ax = (height - 1) * screen_width

	mov	ecx,c_width[ebp]
	sub	ebx,ecx		; bytes to next scan line

	; now add the width - 1
	dec	ecx
	add	ax,cx
	adc	dl,0
	mov	cl,dl
	pop	edx

	add	si,ax		; have source point to end
	adc	dh,cl		; fixup src page number
	add	di,ax		; have dest point to end
	adc	dl,cl		; fixup dst page number

	; At this point dh:si and dl:di point to the last source and dst byte
	; on the screen.

	setpage	dh,dl

	std			; copy backwords
$again:
	mov	eax,c_width[ebp]	; width
	cmp	si,ax		; if (srcoff < width)
	jb	$R70		; jmp if possible split page at src
	cmp	di,ax		; if (dstoff < width) {
	jb	short $R80		; jmp if possible split page at dst

	mov	ecx,eax
	rep	movsb		; copy a scan line minus 1

	sub	si,bx		; goto next scan line
	jc	short $R91		; need to fixup page number
	sub	di,bx
	jc	short $R92
$R95:
	dec	word ptr c_height[ebp]	; decrement the height
	jnz	short $again
$R99:				; were done, go home
	pop	edi
	pop	esi
	leave
	cld
	ret	16

$R91:
	dec	dh		; fixup src page
	sub	di,bx
$R92:
	sbb	dl,0		; fixup dst page
	setpage	dh,dl
	jmp	short $R95

$R80:				; dstoff split page
	movsx	ecx,di		; get dstoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG+0ffffh	; EDI will have carried
	mov	ecx,eax		; cx = rest of scan line, could be zero

	dec	dl
	setpage	dh,dl

	rep	movsb		; finish scan line
	sub	di,bx		; CY can't occur

	sub	si,bx

	jnc	short $R95
$R97:
	dec	dh		; fixup src page
	setpage	dh,dl

	jmp	short $R95

$R70:				; split page at src
	cmp	di,ax		; if (dstoff < width)
	jae	short $R60		; jump if no dest overlap, just src
	cmp	edi,esi		; if (srcoff == dstoff)
	jb	short $R50
;	ja	short $R40	; break occurs twice, at srcoff and dstoff

	je	short $R30
	jmp	$R40
$R30:
		; break occurs simultaneously at srcoff and dstoff
	dec	dl		; goto next dest page
$R60:				; break occurs only at srcoff
	movsx	ecx,si		; get srcoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG+0ffffh
	inc	edi		; if we get here via $R30
	dec	di
	mov	ecx,eax		; ax has number of bytes left to copy

	dec	dh		; goto next src page
	setpage	dh,dl

	rep	movsb		; finish scan line

	sub	si,bx		; can't CY
	sub	di,bx
	jnc	short $R65
	dec	dl
	setpage	dh,dl
$R65:
	jmp	$R95

$R50:
				; break occurs at dstoff first, then srcoff
	movsx	ecx,di		; get srcoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG+0ffffh
	mov	ecx,eax

	dec	dl		; goto next dst page
	setpage	dh,dl

	mov	eax,ecx		; setup count info
	movsx	ecx,si		; get srcoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG+0ffffh
	mov	ecx,eax		; ax has number of bytes left to copy

	dec	dh		; goto next src page
	setpage	dh,dl

	rep	movsb		; finish scan line

	sub	esi,ebx		; can't CY
	sub	edi,ebx		; can't CY
	jmp	$R95

$R40:				; break occurs at srcoff, then dstoff
	movsx	ecx,si		; get srcoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG+0ffffh
	mov	ecx,eax

	dec	dh		; goto next src page
	setpage	dh,dl

	mov	eax,ecx
	movsx	ecx,di		; get dstoff
	inc	ecx		; cx has bytes to copy
	sub	eax,ecx		; ax has rest of scan line

	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG+0ffffh
	mov	ecx,eax		; cx = rest of scan line, could be zero

	dec	dl		; next dst page
	setpage	dh,dl

	rep	movsb		; finish scan line

	sub	edi,ebx		; CY can't occur
	sub	esi,ebx		; can't CY
	jmp	$R95

forward:			; bx = bytes to next scan line
	mov	ecx,c_width[ebp]
	movzx	eax,si		; if (srcoff + width > 0xffffL)
	add	ax,cx
	jc	$C70		; branch if split page at src
	movzx	eax,di		; if (dstoff + width > 0xffffL)
	add	ax,cx		; dx = dstoff + width
	jc	short $C80		; branch if split page at dst

	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd		; copy a scan line
	shld	ecx,eax,2	; get them back
	rep	movsb		; finish a scan line

	add	si,bx		; goto next scan line
	jc	short $C91		; need to fixup page number
	add	di,bx
	jc	short $C92
$C95:
	dec	word ptr c_height[ebp]	; decrement the height
	jnz	short forward
				; were done, go home
	pop	edi
	pop	esi
	leave
	ret	16

$C91:
	inc	dh		; fixup src page info
	add	di,bx
$C92:
	adc	dl,0		; fixup dst page
$C94:
	setpage	dh,dl
	jmp	short $C95

$C80:				; dstoff split page only, ax has what's left
	movsx	ecx,di		; get dstoff, will be negative
	neg	ecx

	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG	; edi will has wrapped to 0b0000h
	mov	ecx,eax		; ax has number of bytes left to copy
				; it could be zero

	inc	dl		; goto next dest page
	setpage	dh,dl

	shr	ecx,1
	rep	movsw		; finish the scan line
	adc	ecx,ecx
	rep	movsb		; finish the scan line

	add	di,bx		; goto next scan line, can't CY
	add	si,bx		; This can.
	jnc	short $C95
	inc	dh		; goto next src page
	jmp	short $C94

$C70:				; split page at src
				; ax = # bytes in next src page
	cmp	esi,edi		; if (srcoff == dstoff)
	ja	$C60		; break occurs at srcoff first
	jb	short $C50	; break occurs at dstoff then srcoff

				; break occurs at same place
	movsx	ecx,di		; DI will be negative
	neg	ecx
	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG	; they both have wrapped
	mov	esi,VGA_SEG
	mov	ecx,eax

	inc	dl		; goto next dst page
	inc	dh		; goto next src page
	setpage	dh,dl

	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd		; copy a scan line
	shld	ecx,eax,2	; get them back
	rep	movsb		; finish a scan line

	add	si,bx		; can't cause a CY
	add	di,bx		; can't CY
	jmp	$C95

$C50:
				; ax = number of bytes left in src page
				; cx = width
				; break occurs at dstoff first, then srcoff
	movsx	ecx,di		; di is negative
	neg	ecx

	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG
	mov	ecx,eax		; save extra bytes

	inc	dl		; goto next dest page
	setpage	dh,dl

	mov	eax,ecx		; restore

	movsx	ecx,si
	neg	ecx

	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG
	mov	ecx,eax		; cx has number of bytes left to copy

	inc	dh		; goto next src page
	setpage	dh,dl

	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd		; copy a scan line
	shld	ecx,eax,2	; get them back
	rep	movsb		; finish a scan line

	add	si,bx		; can't CY
	add	di,bx		; can't CY
	jmp	$C95

$C60:				; break occurs at srcoff then maybe dstoff
	movsx	ecx,si		; get srcoff
	neg	ecx

	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG
	mov	ecx,eax		; cx has number of bytes left to copy

	inc	dh		; goto next src page
	setpage	dh,dl

	movzx	eax,di		; get dstoff
	add	ax,cx
	jnc	short $C63		; jmp if no split page at dstoff
	movsx	ecx,di
	neg	cx

	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG
	mov	ecx,eax		; cx has number of bytes left to copy

	inc	dl		; goto next dst page
	setpage	dh,dl
$C63:
	shr	ecx,1
	rep	movsw		; copy to end of page
	adc	ecx,ecx
	rep	movsb		; copy to end of page

	add	si,bx		; can't CY
	add	di,bx
	jnc	short $C65
	inc	dl
	setpage	dh,dl
$C65:
	jmp	$C95
ccl	EQU	$ - offset CCOPY
CCOPY	ENDP
