	TITLE	orbits

	.386p

;_text	SEGMENT	word public use32 'CODE'

CGROUP	GROUP	_TEXT

_TEXT	SEGMENT	dword public use32 'CODE'
	ASSUME	cs:_TEXT
X	equ	4

; orbits(psrc, pdst, soff, doff, n)
; u_char _Far *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 */
psrc	EQU	4
pdst	EQU	12
soff	EQU	20
doff	EQU	24
n	EQU	28

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

	PUBLIC	orbits
orbits	PROC NEAR
	push	ebp
	mov	ebp,esp
	push	esi
	push	edi
	push	ebx
	push	ds
	push	es
	lds	esi,psrc[ebp+X]
	les	edi,pdst[ebp+X]
	mov	edx,n[ebp+X]	; n
	mov	bh,doff[ebp+X]	; doff
	sub	bh,soff[ebp+X]	; doff-soff
	je	$L13		; if (bitstoshift == 0)
	jg	$L1		; if (bitstoshift > 0)
	jmp	$L6		; if (bitstoshift < 0)
$L13:

; bitstoshift == 0
	mov	ecx,soff[ebp+X]	; cl = soff, ch = 0
	jcxz	$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
	or	es:[edi],al
	inc	edi

	cmp	dx,0
	jg	$L2
	jmp	$L0
$L2:
	mov	ecx,edx		; n
	shr	ecx,1
	shr	ecx,1
	shr	ecx,1
	shr	ecx,1
	jnc	$L4		; sets ZF and CF accordingly
	lodsb
	or	es:[edi],al
	inc	edi
$L4:
	jcxz	$L5
$L21:
	lodsw
	or	es:[edi],ax
	inc	edi
	inc	edi
	loop	$L21
$L5:
	mov	ecx,edx		; n
	and	ecx,7		; cl = n & 7, ch = 0
	jnz	$L12
	jmp	$L0
$L12:
	not	ch		; ch = 0xff
	shr	ch,cl
	not	ch
	and	ch,ds:[esi]
	or	es:[edi],ch
	jmp	$L0

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

	mov	ecx,doff[ebp+X]	; cl = doff, ch = 0
	add	edx,ecx		; 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
	or	es:[edi],al
	inc	edi
	cmp	dx,0		; if (n <= 0)
	jg	$L19
	jmp	$L0
$L19:
	mov	ecx,edx
	shr	ecx,1
	shr	ecx,1
	shr	ecx,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:[esi]	; temp
	mov	cl,bh		; bitstoshift
	shr	ah,cl
	or	al,ah
	or	es:[edi],al
	inc	edi
	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:[esi]
	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
	not	ch		; ~mask
	and	al,ch		; temp &= ~mask
	or	es:[edi],al
	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	ecx,edx		; n
	add	ecx,soff[ebp+X]	; soff
	sub	ecx,8		; n = n + soff - 8
	jle	$L14		; if (n > 8 - soff)
	mov	ah,ds:[esi]
	mov	cl,bl
	shr	ah,cl
	or	al,ah		; AL |= *psrc >> bitstoshift
$L14:
	mov	ah,0ffh
	mov	ecx,doff[ebp+X]	; doff
	shr	ah,cl		; AH = 0xff >> doff
	add	edx,ecx		; n += doff
	sub	edx,8		; n -= 8
	jge	$L15
	mov	cx,dx		; cx = 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
	or	es:[edi],al
	inc	edi
	cmp	dx,0
	jle	$L0		; if (n <= 0) return
	mov	ecx,edx		; n
	shr	ecx,3
	jcxz	$L17		; while (cx--)
$L16:
	lodsb			; temp = *psrc++
	xchg	cl,bh
	shl	al,cl		; temp <<= bitstoshift
	xchg	cl,bh
	mov	ah,ds:[esi]	; temp
	xchg	cl,bl		; 8 - bitstoshift
	shr	ah,cl
	xchg	cl,bl
	or	al,ah		; temp |= *psrc >> 8 - bitstoshift
	or	es:[edi],al
	inc	edi
	loop	$L16
$L17:
	and	edx,7		; n & 7
	mov	ecx,edx		; n
	je	$L0
	not	ch
	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:[esi]	;
	mov	cl,bl		; 8 - bitstoshift
	shr	ah,cl		; CH >>= 8 - bitstoshift
	or	al,ah
$L18:
	not	ch
	and	al,ch		; *dst & ~mask
	or	es:[edi],al
$L0:
	pop	es
	pop	ds
	pop	ebx
	pop	edi
	pop	esi
;	mov	esp,ebp
	pop	ebp
	ret
orbits	ENDP
_TEXT	ENDS
	END
