/* --- Copyright University of Sussex 1998. All rights reserved. ----------
 * File:	    C.power/src/amove.s
 * Purpose:
 * Author:          John Gibson, Feb  6 1998
 */

;;; ---------------- ROUTINES TO MOVE MEMORY, ETC ------------------------

;;;	***********************************************
;;;	****         NOTE ASSEMBLER BUG:          *****
;;;	****  (___reg) DOES NOT ASSEMBLE AS 0(___reg)   *****
;;;	***********************************************

#_<

#_INCLUDE 'asm.ph'

>_#


ASM_START_FILE


ASM_CODE_PSECT


;;; --- COMPARE ROUTINES ------------------------------------------------

	;;; _bcmp(_______boffs, _______bptr1, _______bptr2) -> ____bool
	;;; compare two byte regions of the same length
ASM_ALIGN_QUAD
DEF_C_LAB (_bcmp)
	ldW	rt1, _WOFFS(rusp)	;;; ______ptr1
	ldW	rt2, 0(rusp)		;;; ______ptr2
	ldWu	rt0, _WOFFS*2(rusp)	;;; ______offs (tos after)
	mr.	rt0, rt0
	bz-	cmp_same		;;; return true if zero length
	mtctr	rt0
	la	rt1, -1(rt1)
	la	rt2, -1(rt2)

ASM_ALIGN_QUAD
La1:	lbzu	rt3, 1(rt1)
	lbzu	rt4, 1(rt2)
	cmplw	CR0, rt3, rt4
	bdneq	La1			;;; loop if decr ctr /=0 and equal
	beq	cmp_same

	;;; not same
	stW	rfalse, 0(rusp)		;;; return false
	blr

	;;; same
cmp_same:
	la	rt0, _TRUEOFFS(rfalse)
	stW	rt0, 0(rusp)
	blr


	;;; _scmp(_______soffs, _______sptr1, _______sptr2) -> ____bool
	;;; compare two short regions of the same length
ASM_ALIGN_QUAD
DEF_C_LAB (_scmp)
	ldW	rt1, _WOFFS(rusp)	;;; ______ptr1
	ldW	rt2, 0(rusp)		;;; ______ptr2
	ldWu	rt0, _WOFFS*2(rusp)	;;; ______offs (tos after)
	srwi.	rt0, rt0, 1		;;; number of shorts
	bz-	cmp_same		;;; return true if zero length
	mtctr	rt0
	la	rt1, -2(rt1)
	la	rt2, -2(rt2)

ASM_ALIGN_QUAD
Lb1:	lhzu	rt3, 2(rt1)
	lhzu	rt4, 2(rt2)
	cmplw	CR0, rt3, rt4
	bdneq	Lb1			;;; loop if decr ctr /=0 and equal
	beq	cmp_same

	;;; not same
	stW	rfalse, 0(rusp)		;;; return false
	blr


	;;; _icmp(_______ioffs, _______iptr1, _______iptr2) -> ____bool
	;;; compare two int regions of the same length
ASM_ALIGN_QUAD
DEF_C_LAB (_icmp)
#_IF WORD_BITS/==DOUBLE_BITS
DEF_C_LAB (_cmp)
#_ENDIF
	ldW	rt1, _WOFFS(rusp)	;;; ______ptr1
	ldW	rt2, 0(rusp)		;;; ______ptr2
	ldWu	rt0, _WOFFS*2(rusp)	;;; ______offs (tos after)
	srwi.	rt0, rt0, 2		;;; number of ints
	bz-	cmp_same		;;; return true if zero length
	mtctr	rt0
	la	rt1, -4(rt1)
	la	rt2, -4(rt2)

ASM_ALIGN_QUAD
Lc1:	lwzu	rt3, 4(rt1)
	lwzu	rt4, 4(rt2)
	cmplw	CR0, rt3, rt4
	bdneq	Lc1			;;; loop if decr ctr /=0 and equal
	beq	cmp_same

	;;; not same
	stW	rfalse, 0(rusp)		;;; return false
	blr


#_IF WORD_BITS==DOUBLE_BITS

	;;; _cmp(_______doffs, _______dptr1, _______dptr2) -> ____bool
	;;; compare two word (double) regions of the same length
ASM_ALIGN_QUAD
DEF_C_LAB (_cmp)

#_ENDIF


;;; --- LOCATE CHARACTER ----------------------------------------------------

	;;; _locc(______bptr, _______boffs, ______byte) -> _____________boffs_or_-1
	;;; search string for character
ASM_ALIGN_QUAD
DEF_C_LAB (_locc)
	ldW	rt2, 0(rusp)		;;; ______byte
	ldW	rt0, _WOFFS(rusp)	;;; _______boffs
	ldWu	rt1, _WOFFS*2(rusp)	;;; ______bptr
	mr.	rt0, rt0
	bz-	Le4			;;; return not found if zero length
	mtctr	rt0			;;; string len in count reg
	mr	rt4, rt1		;;; save ______bptr
	lbz	rt3, 0(rt1)		;;; load first char
	bdz-	Le3			;;; br if only one char

ASM_ALIGN_QUAD
Le1:	cmplw	CR0, rt3, rt2		;;; compare this char
	lbzu	rt3, 1(rt1)		;;; load next char
	bdnne+	Le1			;;; loop if decr ctr /=0 and not equal

	bne	Le3			;;; not found -- try last char
	la	rt1, -1(rt1)		;;; else step back ptr

	;;; found
Le2:	subfc	rt0, rt4, rt1		;;; offset to char
	stW	rt0, 0(rusp)		;;; return it
	blr

	;;; try last char
Le3:	cmplw	CR0, rt3, rt2
	beq	Le2			;;; found

	;;; not found
Le4:	li	rt0, -1			;;; return -1
	stW	rt0, 0(rusp)
	blr


	;;; _skpc(______bptr, _______boffs, ______byte) -> _____________boffs_or_-1
	;;; skip string for character
ASM_ALIGN_QUAD
DEF_C_LAB (_skpc)
	ldW	rt2, 0(rusp)		;;; ______byte
	ldW	rt0, _WOFFS(rusp)	;;; _______boffs
	ldWu	rt1, _WOFFS*2(rusp)	;;; ______bptr
	cmplWi	CR0, rt0, 0
	beq-	Lf4			;;; return nothing else found if zero length
	mtctr	rt0			;;; string len in count reg
	mr	rt4, rt1		;;; save ______bptr
	lbz	rt3, 0(rt1)		;;; load first char
	bdz-	Lf3			;;; br if only one char

ASM_ALIGN_QUAD
Lf1:	cmplw	CR0, rt3, rt2		;;; compare this char
	lbzu	rt3, 1(rt1)		;;; load next char
	bdneq+	Lf1			;;; loop if decr ctr /=0 and equal

	beq	Lf3			;;; found -- try last char
	la	rt1, -1(rt1)		;;; else step back ptr

	;;; not (ie something else) found
Lf2:	subfc	rt0, rt4, rt1		;;; offset to other char
	stW	rt0, 0(rusp)		;;; return it
	blr

	;;; try last char
Lf3:	cmplw	CR0, rt3, rt2
	bne	Lf2			;;; not found

	;;; (nothing else) found
Lf4:	li	rt0, -1			;;; return -1
	stW	rt0, 0(rusp)
	blr


;;; --- MOVE ROUTINES ------------------------------------------------------

	;;; _bmove(_______boffs, __________bptr_src, __________bptr_dst) -> __________next_dst
	;;; move bytes
ASM_ALIGN_QUAD
DEF_C_LAB (_bmove)
	ldW	rt2, 0(rusp)		;;; __________wptr_dst
	ldW	rt1, _WOFFS(rusp)	;;; __________wptr_src
	ldWu	rt0, _WOFFS*2(rusp)	;;; _______boffs
	add	rt4, rt2, rt0		;;; next destination
	stW	rt4, 0(rusp)		;;; next destination result
	srwi.	rt4, rt0, 1	;;; _______boffs as number of byte pairs
	bz-	Lg2		;;; br if less than 2 bytes ...
	mtctr	rt4		;;; ... else move to count reg

	;;; can use forward move if moving down or dest beyond end of src
	subfc	rt4, rt1, rt2	;;; dst - src
	cmplW	CR0, rt0, rt4 	;;; boffs unsigned <= dst - src ?
	bgt-	b_movback	;;; no -- do backward move

	;;; no overlap -- do the move forwards
ASM_ALIGN_QUAD
Lg1:	lbz	rt3, 0(rt1)
	lbz	rt4, 1(rt1)
	la	rt1, 2(rt1)
	stb	rt3, 0(rt2)
	stb	rt4, 1(rt2)
	la	rt2, 2(rt2)
	bdnz+	Lg1

Lg2:	andi.	R0, rt0, 1	;;; odd byte to move?
	bzlr			;;; return if not
	lbz	rt3, 0(rt1)	;;; else move one byte
	stb	rt3, 0(rt2)
	blr

	;;; src and dst overlap -- do the move backwards
ASM_ALIGN_QUAD
b_movback:
	add	rt1, rt1, rt0
	add	rt2, rt2, rt0

ASM_ALIGN_QUAD
Lg3:	lbz	rt3, -2(rt1)
	lbz	rt4, -1(rt1)
	la	rt1, -2(rt1)
	stb	rt3, -2(rt2)
	stb	rt4, -1(rt2)
	la	rt2, -2(rt2)
	bdnz+	Lg3

	andi.	R0, rt0, 1	;;; odd byte to move?
	bzlr			;;; return if not
	lbz	rt3, -1(rt1)	;;; else move one byte
	stb	rt3, -1(rt2)
	blr


	;;; _smove(_______soffs, __________sptr_src, __________sptr_dst) -> __________next_dst
	;;; move bytes or shorts
ASM_ALIGN_QUAD
DEF_C_LAB (_smove)
	ldW	rt2, 0(rusp)		;;; __________wptr_dst
	ldW	rt1, _WOFFS(rusp)	;;; __________wptr_src
	ldWu	rt0, _WOFFS*2(rusp)	;;; _______soffs
	add	rt4, rt2, rt0		;;; next destination
	stW	rt4, 0(rusp)		;;; next destination result
	srwi.	rt4, rt0, 2	;;; _______soffs as number of short pairs
	bz-	Lh2		;;; br if less than 2 shorts ...
	mtctr	rt4		;;; ... else move to count reg

	;;; can use forward move if moving down or dest beyond end of src
	subfc	rt4, rt1, rt2	;;; dst - src
	cmplW	CR0, rt0, rt4 	;;; soffs unsigned <= dst - src ?
	bgt-	s_movback	;;; no -- do backward move

	;;; no overlap -- do the move forwards
ASM_ALIGN_QUAD
Lh1:	lhz	rt3, 0(rt1)
	lhz	rt4, 2(rt1)
	la	rt1, 4(rt1)
	sth	rt3, 0(rt2)
	sth	rt4, 2(rt2)
	la	rt2, 4(rt2)
	bdnz+	Lh1

Lh2:	andi.	R0, rt0, 2	;;; odd short to move?
	bzlr			;;; return if not
	lhz	rt3, 0(rt1)	;;; else move one short
	sth	rt3, 0(rt2)
	blr

	;;; src and dst overlap -- do the move backwards
ASM_ALIGN_QUAD
s_movback:
	add	rt1, rt1, rt0
	add	rt2, rt2, rt0

ASM_ALIGN_QUAD
Lh3:	lhz	rt3, -4(rt1)
	lhz	rt4, -2(rt1)
	la	rt1, -4(rt1)
	sth	rt3, -4(rt2)
	sth	rt4, -2(rt2)
	la	rt2, -4(rt2)
	bdnz+	Lh3

	andi.	R0, rt0, 2	;;; odd short to move?
	bzlr			;;; return if not
	lhz	rt3, -2(rt1)	;;; else move one short
	sth	rt3, -2(rt2)
	blr


	;;; _imove(_______ioffs, ___________iptr_src, __________iptr_dst) -> __________next_dst
	;;; _dmove(_______doffs, __________dptr_src, __________dptr_dst) -> __________next_dst
	;;; _move(_______woffs, __________wptr_src, __________wptr_dst) -> __________next_dst
	;;; move ints or doubles (i.e. Alpha longwords/quads).
	;;; _moveq is the same.

ASM_ALIGN_QUAD
DEF_C_LAB (_imove)
DEF_C_LAB (_dmove)
DEF_C_LAB (_move)
DEF_C_LAB (_moveq)
	ldW	rt2, 0(rusp)		;;; __________wptr_dst R9
	ldW	rt1, _WOFFS(rusp)	;;; __________wptr_src R10
	ldWu	rt0, _WOFFS*2(rusp)	;;; _______woffs    R11
	add	rt4, rt2, rt0		;;; next destination
	stW	rt4, 0(rusp)		;;; next destination result
	;;; drop thru to movwords

	;;; Do doubleword/word move.
	;;; word offset to move in rt0, source in rt1, dest in rt2
	;;; Uses rt3, rt4, rt5
movwords:
	srwi.	rt4, rt0, 3	;;; _______woffs as number of doublewords
	bz-	Li2		;;; br if less than 2 words ...
	mtctr	rt4		;;; ... else move to count reg

	;;; can use forward move if moving down or dest beyond end of src
	subfc	rt4, rt1, rt2	;;; dst - src
	cmplW	CR0, rt0, rt4 	;;; woffs unsigned <= dst - src ?
	bgt-	movback		;;; no -- do backward move

	;;; no overlap -- do the move forwards
ASM_ALIGN_QUAD
Li1:	lwz	rt3, 0(rt1)
	lwz	rt4, 4(rt1)
	la	rt1, 8(rt1)
	stw	rt3, 0(rt2)
	stw	rt4, 4(rt2)
	la	rt2, 8(rt2)
	bdnz+	Li1

Li2:	andi.	R0, rt0, 4	;;; odd word to move?
	bzlr			;;; return if not
	lwz	rt3, 0(rt1)	;;; else move one word
	stw	rt3, 0(rt2)
	blr


	;;; src and dst overlap -- do the move backwards
ASM_ALIGN_QUAD
movback:
	add	rt1, rt1, rt0
	add	rt2, rt2, rt0

ASM_ALIGN_QUAD
Li3:	lwz	rt3, -8(rt1)
	lwz	rt4, -4(rt1)
	la	rt1, -8(rt1)
	stw	rt3, -8(rt2)
	stw	rt4, -4(rt2)
	la	rt2, -8(rt2)
	bdnz+	Li3

	andi.	R0, rt0, 4	;;; odd word to move?
	bzlr			;;; return if not
	lwz	rt3, -4(rt1)	;;; else move one word
	stw	rt3, -4(rt2)
	blr


;;; --- FILL ROUTINES ----------------------------------------------------

	;;; _bfill(______byte, _______boffs, ______bptr)
	;;; fill a region of bytes with a given byte

ASM_ALIGN_QUAD
DEF_C_LAB (_bfill)
	ldW	rt2, 0(rusp)		;;; ______bptr
	ldW	rt1, _WOFFS(rusp)	;;; _______boffs
	ldW	rt0, _WOFFS*2(rusp)	;;; ______byte
	la	rusp, _WOFFS*3(rusp)
	mr.	rt1, rt1
	bzlr-				;;; return if zero length
	mtctr	rt1			;;; length to count reg
	la	rt2, -1(rt2)

ASM_ALIGN_QUAD
Lj1:	stbu	rt0, 1(rt2)
	bdnz+	Lj1
	blr


	;;; _ifill(_____int, _______ioffs, ______iptr)
	;;; fill a region of ints with a given int

ASM_ALIGN_QUAD
DEF_C_LAB (_ifill)
#_IF WORD_BITS/==DOUBLE_BITS
DEF_C_LAB (_fill)
#_ENDIF
	ldW	rt2, 0(rusp)		;;; ______wptr
	ldW	rt1, _WOFFS(rusp)	;;; _______woffs
	ldW	rt0, _WOFFS*2(rusp)	;;; ______word
	la	rusp, _WOFFS*3(rusp)
	srwi.	rt1, rt1, 2		;;; number of words
	bzlr-				;;; return if zero length
	mtctr	rt1			;;; length to count reg
	la	rt2, -4(rt2)

ASM_ALIGN_QUAD
Lk1:	stwu	rt0, 4(rt2)
	bdnz+	Lk1
	blr


#_IF WORD_BITS==DOUBLE_BITS

	;;; _fill(______word, ________woffs, ______wptr)
	;;; fill a region of words (quads) with a given quadword

ASM_ALIGN_QUAD
DEF_C_LAB (_fill)
#_ENDIF


;;;--------------------------------------------------------------------------

	;;; _move_userstack(_______woffs)
	;;; move the user stack up or down by word offset _______woffs

ASM_ALIGN_QUAD
DEF_C_LAB (_move_userstack)
	ldW	rt2, 0(rusp)		;;; _______woffs
	ldW	rt3, _SVB_OFFS(_userhi)(rsvb)	;;; _userhi value
	la	rusp, _WOFFS(rusp)
	subfc	rt0, rusp, rt3		;;; length of u/s to move in rt0
	mr	rt1, rusp		;;; u/s top -- src for move
	add	rt3, rt3, rt2		;;; _userhi + _______woffs = new _userhi
	add	rt2, rusp, rt2		;;; top + _______woffs = destination for move
	stW	rt3, _SVB_OFFS(_userhi)(rsvb)	;;; update _userhi
	mr	rusp, rt2		;;; and new stack top
	b	movwords		;;; do the move (return to caller)


;;; --- ROUTINES TO HANDLE USERSTACK SWAPPING -------------------------------

	;;; _ussave(_______woffs, _________saveptr)
	;;; save and erase a given offset at the end of the userstack

ASM_ALIGN_QUAD
DEF_C_LAB (_ussave)
	;;; copy the area to be saved
	ldW	rt2, 0(rusp)		;;; _________saveptr = dst for move
	ldW	rt0, _WOFFS(rusp)	;;; _______woffs = offset to move
	ldW	rt6, _SVB_OFFS(_userhi)(rsvb)	;;; stack base
	la	rusp, _WOFFS*2(rusp)
	mflr	rchain			;;; save return in rchain
	subfc	rt1, rt0, rt6		;;; _userhi - _______woffs = src for move ...
	mr	rt6, rt1		;;; ... remembered in rt6
	bl	movwords		;;; save the area

	;;; now shift up the remaining stack contents
	ldW	rt2, _SVB_OFFS(_userhi)(rsvb)	;;; _userhi again
	mr	rt1, rusp		;;; stack top = src for move
	subfc	rt0, rt1, rt6		;;; save src - stack top = offs to move
	subfc	rt2, rt0, rt2		;;; _userhi - offs = dst for move ...
	mr	rusp, rt2		;;; ... and new stack top afterwards
	mtlr	rchain			;;; set return to caller
	b	movwords		;;; do the move


	;;; _usrestore(_______woffs, _________restptr)
	;;; restore a given offset at the end of the userstack

ASM_ALIGN_QUAD
DEF_C_LAB (_usrestore)
	;;; shift down the current stack contents to make room
	ldW	rt0, _SVB_OFFS(_userhi)(rsvb)	;;; stack base
	ldW	rt6, _WOFFS(rusp)	;;; _______woffs (keep for next part)
	mflr	rchain			;;; save return in rchain
	subfc	rt0, rusp, rt0		;;; _userhi - top = offset to move
	mr	rt1, rusp		;;; stack top = src for move
	subfc	rt2, rt6, rusp		;;; top - _______woffs = dst for move ...
	mr	rusp, rt2		;;; ... and new stack top afterwards
	bl	movwords		;;; save the area

	;;; now move in the area to be restored
	ldW	rt2, _SVB_OFFS(_userhi)(rsvb)	;;; stack base again
	ldW	rt1, 0(rusp)		;;; _________restptr = src for move
	la	rusp, _WOFFS*2(rusp)	;;; remove args
	mr	rt0, rt6		;;; _______woffs = offset for move
	subfc	rt2, rt0, rt2		;;; _userhi - _______woffs = dst for move
	mtlr	rchain			;;; set return to caller
	b	movwords		;;; do the move


	;;; _userasund(_______woffs)
	;;; erase a given offset at the end of the userstack

ASM_ALIGN_QUAD
DEF_C_LAB (_userasund)
	ldW	rt2, 0(rusp)		;;; _______woffs
	ldW	rt0, _SVB_OFFS(_userhi)(rsvb)	;;; stack base
	la	rt1, _WOFFS(rusp)	;;; stack top + _WOFFS = src for move
	add	rt2, rt1, rt2		;;; plus _______woffs = dst for move ...
	mr	rusp, rt2		;;; ... and new stack top afterwards
	subfc	rt0, rt2, rt0		;;; _userhi - new top = size to move
	b	movwords		;;; do the move


;;; ------------------------------------------------------------------------

	;;; _move_callstack(_______woffs, _________limaddr)
	;;; move the callstack from sp to _________limaddr by a signed offset _______woffs

ASM_ALIGN_QUAD
DEF_C_LAB(_move_callstack)
	ldW	rt0, 0(rusp)		;;; _________limaddr
	ldW	rt2, _WOFFS(rusp)	;;; _______woffs
	la	rusp, _WOFFS*2(rusp)
	subfc	rt0, rsp, rt0		;;; _________limaddr - sp = offset to move in rt0
	mr	rt1, rsp		;;; sp = src for move in rt1
	add	rt2, rsp, rt2		;;; sp + _______woffs = destination in rt2 ...
	mr	rsp, rt2		;;; ... and new sp afterwards
	b	movwords		;;; do the move


;;; --- BITFIELD ROUTINES ------------------------------------------------

	;;; Access an unsigned bit field
	;;; rt0 = struct address, rt1 = bitoffset, rt2 = field width W
	;;; returns field value in rt0
ASM_ALIGN_QUAD
DEF_C_LAB (_bfield)
	subfic	rt2, rt2, 32		;;; 32-W = field shift-down
	andi.	rt3, rt1, 31		;;; get bitoffs within start word
	srawi	rt1, rt1, 3		;;; get word offset to start word ...
	rlwinm	rt1, rt1, 0, ~3		;;; ... in rt1
	add	rt0, rt0, rt1		;;; add to struct addr in rt0
	lwz	rt1, 0(rt0)		;;; load first word into rt1
	cmplw	rt2, rt3		;;; all bits in 1st word?
	slw	rt1, rt1, rt3		;;; shift 1st word bits to top
	bge	Ll1			;;; branch if all bits in first word
	lwz	rt4, 4(rt0)		;;; else next word of field in rt4
	subfic	rt3, rt3, 32		;;; 32-bitoffs (no of bits in 1st word)
	srw	rt4, rt4, rt3		;;; shift 2nd word down by that
	or	rt1, rt4, rt1		;;; or in rest of field
Ll1:	srw	rt0, rt1, rt2		;;; bring down to bottom (32-W)
	blr


	;;; Access a signed bit field (same except for final shift down)
	;;; rt0 = struct address, rt1 = bitoffset, rt2 = field width W,
	;;; returns field value in rt0
ASM_ALIGN_QUAD
DEF_C_LAB (_sbfield)
	subfic	rt2, rt2, 32		;;; 32-W = field shift-down
	andi.	rt3, rt1, 31		;;; get bitoffs within start word
	srawi	rt1, rt1, 3		;;; get word offset to start word ...
	rlwinm	rt1, rt1, 0, ~3		;;; ... in rt1
	add	rt0, rt0, rt1		;;; add to struct addr in rt0
	lwz	rt1, 0(rt0)		;;; load first word into rt1
	cmplw	rt2, rt3		;;; all bits in 1st word?
	slw	rt1, rt1, rt3		;;; shift 1st word bits to top
	bge	Lm1			;;; branch if all bits in first word
	lwz	rt4, 4(rt0)		;;; else next word of field in rt4
	subfic	rt3, rt3, 32		;;; 32-bitoffs (no of bits in 1st word)
	srw	rt4, rt4, rt3		;;; shift 2nd word down by that
	or	rt1, rt4, rt1		;;; or in rest of field
Lm1:	sraw	rt0, rt1, rt2		;;; sign-extend down to bottom (32-W)
	blr


	;;; Update a bit field
	;;; rt0 = struct address, rt1 = bitoffset, rt2 = field width W,
	;;; field updated from value off stack
ASM_ALIGN_QUAD
DEF_C_LAB (_ubfield)
	subfic	rt2, rt2, 32		;;; 32-W = field shift-down
	andi.	rt3, rt1, 31		;;; get bitoffs within start word
	srawi	rt1, rt1, 3		;;; get word offset to start word ...
	rlwinm	rt1, rt1, 0, ~3		;;; ... in rt1
	add	rt0, rt0, rt1		;;; add to struct addr in rt0
	lwz	rt1, 0(rt0)		;;; load first word into rt1
	ldW	rt5, 0(rusp)		;;; get new field value
	la	rusp, _WOFFS(rusp)
	li	rt6, -1			;;; all ones
	slw	rt6, rt6, rt2		;;; left by 32-W = W bits at top
	srw	rt6, rt6, rt3		;;; right by bitoffs = field mask
	subfc.	rt4, rt3, rt2		;;; 32-W-bitoffs (bits below field)
	blt-	Ln2			;;; br if some bits in second word
	slw	rt5, rt5, rt4		;;; else shift up new value

Ln1:	andc	rt1, rt1, rt6		;;; remove old field
	and	rt5, rt5, rt6		;;; mask new field
	or	rt1, rt1, rt5		;;; insert new field
	stw	rt1, 0(rt0)		;;; store new first word
	blr				;;; return

	;;; field occupies second word
Ln2:	addi	rt2, rt4, 32		;;; 32 - (number of overshoot bits)
	slw	rt2, rt5, rt2		;;; get new value bits at top
	lwz	rt3, 4(rt0)		;;; get overshoot word
	neg	rt4, rt4		;;; number of overshoot bits
	slw	rt3, rt3, rt4		;;; clear those ...
	srw	rt3, rt3, rt4		;;; ... at top of old value
	or	rt3, rt3, rt2		;;; or in new top bits
	stw	rt3, 4(rt0)		;;; update in second word
	srw	rt5, rt5, rt4		;;; remove overshoot from 1st word val
	b	Ln1



ASM_END_FILE
