	TITLE	copybits

	.286p

X	EQU	4

IBM_TEXT	SEGMENT  WORD PUBLIC 'CODE'
IBM_TEXT	ENDS
IBM_TEXT	SEGMENT
	ASSUME	CS: IBM_TEXT

; copybits(psrc, pdst, soff, doff, n)
; u_char *psrc, *pdst;	/* byte pointers to src and dst memory */
; int soff, doff;	/* offset into src and dst 0 <= soff,doff <= 7 */
; int n;		/* number of bits to copy */

; DS:SI:	psrc
; ES:DI:	pdst
; CX:		n
; BH:		bitstoshift
; AX,DX		temporary registers

	PUBLIC	_copybits
_copybits	PROC NEAR
	push	bp
	mov	bp,sp
	push	si
	push	di
	push	ds
	lds	si,[bp+X]
	les	di,4[bp+X]
	mov	dx,12[bp+X]	; n
	mov	bh,10[bp+X]	; doff
	sub	bh,8[bp+X]	; doff-soff
	cld
	je	$L13		; if (bitstoshift == 0)
	jg	$L1		; if (bitstoshift > 0)
	jmp	$L6		; if (bitstoshift < 0)
$L13:

; bitstoshift == 0
	mov	cx,8[bp+X]	; cl = soff, ch = 0
	or	cx,cx
	jz	$L2
	add	dx,cx		; n = n + soff
	mov	bl,0ffh
	shr	bl,cl		; BL = 0xff >> soff
	sub	dx,8		; n = n - 8
	jge	$L3
	mov	cx,dx		; ch = 0xff, cl = -n
	neg	cl
	shl	ch,cl
	and	bl,ch
$L3:
	lodsb
	and	al,bl
	mov	ch,es:[di]
	not	bl
	and	ch,bl
	or	al,ch
	stosb
	cmp	dx,0
	jg	$L2
	jmp	$L0
$L2:
	mov	cx,dx		; n
	shr	cx,1
	shr	cx,1
	shr	cx,1
	shr	cx,1
	jnc	$L4		; sets ZF and CF accordingly
	movsb			; does not modify flags
$L4:
	jz	$L5
	rep	movsw
$L5:
	mov	cx,dx		; n
	and	cx,7		; cl = n & 7, ch = 0
	jnz	$L12
	jmp	$L0
$L12:
	not	ch		; ch = 0xff
	shr	ch,cl
	mov	al,es:[di]
	and	al,ch
	not	ch
	and	ch,ds:[si]
	or	al,ch
	stosb
	jmp	$L0

; bitstoshift > 0, doff must be positive
$L1:
	mov	bl,8
	sub	bl,bh		; BL = 8 - bitstoshift
	mov	al,ds:[si]
	mov	cl,bh		; bitstoshift
	shr	al,cl		; AL = *psrc >> bitstoshift

	mov	cx,10[bp+X]	; cl = doff, ch = 0
	add	dx,cx		; n += doff
	not	ch		; ch = 0xff
	shr	ch,cl		; BL = 0xff >> doff

	sub	dx,8		; n -= 8
	jge	$L7		; if (n < 0)
	mov	ah,ch
	mov	cx,dx		; cl = -n, ch = 0xff
	neg	cl		; -n
	shl	ch,cl		; CL = 0xff << -n
	and	ch,ah		; CH (mask) &= BL
$L7:
	and	al,ch		; temp &= mask
	not	ch		; ~mask
	mov	ah,es:[di]	; *dst
	and	ah,ch
	or	al,ah
	stosb			; dst++
	cmp	dx,0		; if (n <= 0)
	jg	$L19
	jmp	$L0
$L19:
	mov	cx,dx
	shr	cx,1
	shr	cx,1
	shr	cx,1		; CX = n >> 3;
	je	$L9		; while (cx--)
$L8:
	mov	dh,cl		; we don't need MSB of n anymore
	lodsb			; temp
	mov	cl,bl
	shl	al,cl		; temp <<= 8 - bitstoshift
	mov	ah,ds:[si]	; temp
	mov	cl,bh		; bitstoshift
	shr	ah,cl
	or	al,ah
	stosb			; pdst++
	mov	cl,dh
	loop	$L8
$L9:				; ch = 0
	and	dl,7		; n & 7
	jne	$L20
	jmp	$L0
$L20:
	lodsb			; temp = *psrc++
	mov	cl,bl
	shl	al,cl		; temp <<= 8 - bitstoshift
	cmp	dl,bh		; if (n > bitstoshift)
	jle	$L10
	mov	ah,ds:[si]
	mov	cl,bh		; bitstoshift
	shr	ah,cl		; AH >>= bitstoshift
	or	al,ah
$L10:
	not	ch		; ch = 0xff
	mov	cl,dl
	shr	ch,cl		; AH (mask) >>= n
	mov	ah,es:[di]	; *dst
	and	ah,ch		; *dst & mask
	not	ch		; ~mask
	and	al,ch		; temp &= ~mask
	or	al,ah
	stosb
	jmp	$L0

; bitstoshift < 0, soff must be positive
$L6:
	neg	bh		; -bitstoshift
	mov	bl,8
	sub	bl,bh		; BL = 8 - bitstoshift
	mov	cl,bh
	lodsb			; *psrc++
	shl	al,cl		; AL = *psrc << bitstoshift
	mov	cx,dx		; n
	add	cx,8[bp+X]	; soff
	sub	cx,8		; n = n + soff - 8
	jle	$L14		; if (n > 8 - soff)
	mov	ah,ds:[si]
	mov	cl,bl
	shr	ah,cl
	or	al,ah		; AL |= *psrc >> bitstoshift
$L14:
	mov	ah,0ffh
	mov	cx,10[bp+X]	; doff
	shr	ah,cl		; AH = 0xff >> doff
	add	dx,cx		; n += doff
	sub	dx,8		; n -= 8
	jge	$L15
	mov	cx,dx		; ch = 0xff, cl = n
	neg	cl		; CL = -n
	shl	ch,cl		; CH = 0xff << -n
	and	ah,ch		; mask &= 0xff << -n
$L15:
	and	al,ah		; temp &= mask
	mov	ch,es:[di]
	not	ah
	and	ch,ah
	or	al,ch
	stosb			; *pdst++ |= temp & mask;
	cmp	dx,0
	jle	$L0		; if (n <= 0) return
	mov	cx,dx		; n
	shr	cx,3
	je	$L17		; while (cx--)
$L16:
	lodsb			; temp = *psrc++
	xchg	cl,bh
	shl	al,cl		; temp <<= bitstoshift
	xchg	cl,bh
	mov	ah,ds:[si]	; temp
	xchg	cl,bl		; 8 - bitstoshift
	shr	ah,cl
	xchg	cl,bl
	or	al,ah		; temp |= *psrc >> 8 - bitstoshift
	stosb		; pdst++
	loop	$L16
$L17:
	and	dx,7		; n & 7
	mov	cx,dx		; n
	je	$L0
	not	ch		; ch = 0xff
	shr	ch,cl		; mask = 0xff >> n
	lodsb			; temp = *psrc
	mov	cl,bh
	shl	al,cl		; temp <<= bitstoshift
	cmp	dl,bl		; if (n > 8 - bitstoshift)
	jle	$L18
	mov	ah,ds:[si]	;
	mov	cl,bl		; 8 - bitstoshift
	shr	ah,cl		; CH >>= 8 - bitstoshift
	or	al,ah
$L18:
	mov	ah,es:[di]
	and	ah,ch		; *dst &= mask
	not	ch
	and	al,ch		; temp & ~mask
	or	ah,al
	mov	es:[di],ah
$L0:
	pop	ds
	pop	di
	pop	si
;	mov	sp,bp
	pop	bp
	ret
_copybits	ENDP
IBM_TEXT	ENDS
	END
