/*	$OpenBSD: emulate.s,v 1.5 2013/07/05 21:11:57 miod Exp $ */
/*	$NetBSD: emulate.s,v 1.2 1997/03/15 16:14:25 ragge Exp $ */
/*
 * Copyright (c) 1986, 1987 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Mt. Xinu.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)emulate.s	7.5 (Berkeley) 6/28/90
 */

#include <machine/asm.h>

/*
 * String instruction emulation - MicroVAX only.  These routines are called
 * from locore.s when an "emulate" fault occurs on the MicroVAX.  They are
 * called with the stack set up as follows:
 *
 *	  (sp):	Return address of trap handler
 *	 4(sp):	Instruction Opcode	(also holds PSL result from emulator)
 *	 8(sp):	Instruction PC
 *	12(sp):	Operand 1
 *	16(sp):	Operand 2
 *	20(sp):	Operand 3
 *	24(sp):	Operand 4
 *	28(sp):	Operand 5
 *	32(sp):	Operand 6
 *	36(sp):	old Register 11
 *	40(sp):	old Register 10
 *	44(sp):	Return PC
 *	48(sp):	Return PSL
 *	52(sp): TOS before instruction
 *
 * R11 and r10 are available for use.  If any routine needs to use r9-r1
 * they need to save them first (unless those registers are SUPPOSED to be
 * messed with by the "instruction").  These routines leave their results
 * in registers 0-5 explicitly, as needed, and use the macros defined below
 * to link up with calling routine.
 */

#define return		rsb
#define savepsl		movpsl	4(%sp)
#define setpsl(reg)	movl	reg,4(%sp)
#define overflowpsl	movl	$2,4(%sp)
#define arg1		12(%sp)
#define arg2		16(%sp)
#define arg3		20(%sp)
#define arg4		24(%sp)
#define arg5		28(%sp)
#define arg6		32(%sp)
#define argub(num,reg)	movzbl	8+4*num(%sp),reg
#define arguw(num,reg)	movzwl	8+4*num(%sp),reg
#define argul(num,reg)	movl	8+4*num(%sp),reg
#define argb(num,reg)	cvtbl	8+4*num(%sp),reg
#define argw(num,reg)	cvtwl	8+4*num(%sp),reg
#define argl(num,reg)	movl	8+4*num(%sp),reg
#define toarg(reg,num)	movl	reg,8+4*num(%sp)


	.text
	_ALIGN_TEXT
ALTENTRY(EMcrc)
	argl(1,%r11)		# (1) table address == r11
	argl(2,%r0)		# (2) initial crc == r0
	argl(4,%r3)		# (4) source address == r3
	arguw(3,%r2)		# (3) source length == r2
	jeql	Lcrc_out
Lcrc_loop:
	xorb2	(%r3)+,%r0
	extzv	$0,$4,%r0,%r10
	extzv	$4,$28,%r0,%r1
	xorl3	%r1,(%r11)[%r10],%r0
	extzv	$0,$4,%r0,%r10
	extzv	$4,$28,%r0,%r1
	xorl3	%r1,(%r11)[%r10],%r0
	sobgtr	%r2,Lcrc_loop
	tstl	%r0
Lcrc_out:
	savepsl
	clrl	%r1
	return


	_ALIGN_TEXT
ALTENTRY(EMmovtc)
	arguw(1,%r0)		# (1) source length == r0
	argl(2,%r1)		# (2) source address == r1
	argub(3,%r11)		# (3) fill character == r11
	argl(4,%r3)		# (4) table address == r3
	argl(6,%r5)		# (6) destination address == r5
	arguw(5,%r4)		# (5) destination length == r4
	jeql	Lmovtc_out
Lmovtc_loop:
	tstl	%r0
	jeql	Lmovtc_2loop
	movzbl	(%r1)+,%r2
	movb	(%r3)[%r2],(%r5)+
	decl	%r0
	sobgtr	%r4,Lmovtc_loop
	jbr	Lmovtc_out
Lmovtc_2loop:
	movb	%r11,(%r5)+
	sobgtr	%r4,Lmovtc_2loop
Lmovtc_out:
	cmpl	%r4,%r0
	savepsl
	clrl	%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMmovtuc)
	arguw(1,%r0)		# (1) source length == r0
	argl(2,%r1)		# (2) source address == r1
	argub(3,%r11)		# (3) escape character == r11
	argl(4,%r3)		# (4) table address == r3
	argl(6,%r5)		# (6) destination address == r5
	arguw(5,%r4)		# (5) destination length == r4
	jeql	Lmovtuc_out
Lmovtuc_loop:
	tstl	%r0
	jeql	Lmovtuc_out
	movzbl	(%r1),%r2
	movzbl	(%r3)[%r2],%r2
	cmpl	%r2,%r11
	jeql	Lmovtuc_out
	movzbl	(%r1)+,%r2
	movb	(%r3)[%r2],(%r5)+
	decl	%r0
	sobgtr	%r4,Lmovtuc_loop
Lmovtuc_out:
	cmpl	%r4,%r0
	savepsl
	clrl	%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMmatchc)
	argl(2,%r10)		# (2) substring address == r10
	arguw(3,%r2)		# (3) source length == r2
	argl(4,%r3)		# (4) source address == r3
	arguw(1,%r11)		# (1) substring length == r11
	jeql	Lmatchc_out	# temp source address == r1
	addl2	%r10,%r11	# temp substring address == r0
	tstl	%r2
	jeql	Lmatchc_out
Lmatchc_loop:
	cmpb	(%r10),(%r3)
	jneq	Lmatchc_fail
	movl	%r3,%r1
	movl	%r10,%r0
Lmatchc_2loop:
	cmpl	%r0,%r11
	jeql	Lmatchc_succ
	cmpb	(%r0)+,(%r1)+
	jeql	Lmatchc_2loop
Lmatchc_fail:
	incl	%r3
	sobgtr	%r2,Lmatchc_loop
	movl	%r10,%r1
	subl3	%r10,%r11,%r0
	jbr	Lmatchc_out
Lmatchc_succ:	
	movl	%r1,%r3
	movl	%r11,%r1
	clrl	%r0
Lmatchc_out:
	savepsl
	return


	_ALIGN_TEXT
ALTENTRY(EMspanc)
	argl(2,%r1)		# (2) string address == r1
	argub(4,%r2)		# (4) character-mask == r2
	argl(3,%r3)		# (3) table address == r3
	arguw(1,%r0)		# (1) string length == r0
	jeql	Lspanc_out
Lspanc_loop:
	movzbl	(%r1),%r11
	mcomb	(%r3)[%r11],%r11
	bicb3	%r11,%r2,%r11
	jeql	Lspanc_out
	incl	%r1
	sobgtr	%r0,Lspanc_loop
Lspanc_out:
	savepsl
	clrl	%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMscanc)
	argl(2,%r1)		# (2) string address == r1
	argub(4,%r2)		# (4) character-mask == r2
	argl(3,%r3)		# (3) table address == r3
	arguw(1,%r0)		# (1) string length == r0
	jeql	Lscanc_out
Lscanc_loop:
	movzbl	(%r1),%r11
	mcomb	(%r3)[%r11],%r11
	bicb3	%r11,%r2,%r11
	jneq	Lscanc_out
	incl	%r1
	sobgtr	%r0,Lscanc_loop
Lscanc_out:
	savepsl
	clrl	%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMskpc)
	argub(1,%r11)		# (1) character == r11
	argl(3,%r1)		# (3) string address == r1
	arguw(2,%r0)		# (2) string length == r0
	jeql	Lskpc_out	# forget zero length strings
Lskpc_loop:
	cmpb	(%r1),%r11
	jneq	Lskpc_out
	incl	%r1
	sobgtr	%r0,Lskpc_loop
Lskpc_out:
	tstl	%r0		# be sure of condition codes
	savepsl
	return


	_ALIGN_TEXT
ALTENTRY(EMlocc)
	argub(1,%r11)		# (1) character == r11
	argl(3,%r1)		# (3) string address == r1
	arguw(2,%r0)		# (2) string length == r0
	jeql	Lskpc_out	# forget zero length strings
Llocc_loop:
	cmpb	(%r1),%r11
	jeql	Llocc_out
	incl	%r1
	sobgtr  %r0,Llocc_loop
Llocc_out:
	tstl	%r0		# be sure of condition codes
	savepsl
	return


	_ALIGN_TEXT
ALTENTRY(EMcmpc3)
	argl(2,%r1)		# (2) string1 address == r1
	argl(3,%r3)		# (3) string2 address == r3
	arguw(1,%r0)		# (1) strings length == r0
	jeql	Lcmpc3_out
Lcmpc3_loop:
	cmpb	(%r1),(%r3)
	jneq	Lcmpc3_out
	incl	%r1
	incl	%r3
	sobgtr	%r0,Lcmpc3_loop
Lcmpc3_out:
	savepsl
	movl	%r0,%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMcmpc5)
	argl(2,%r1)		# (2) string1 address == r1
	argub(3,%r11)		# (1) fill character == r11
	arguw(4,%r2)		# (1) string2 length == r2
	argl(5,%r3)		# (3) string2 address == r3
	arguw(1,%r0)		# (1) string1 length == r0
	jeql	Lcmpc5_str2
Lcmpc5_loop:
	tstl	%r2
	jeql	Lcmpc5_str1loop
	cmpb	(%r1),(%r3)
	jneq	Lcmpc5_out
	incl	%r1
	incl	%r3
	decl	%r2
	sobgtr	%r0,Lcmpc5_loop
Lcmpc5_str2:
	tstl	%r2
	jeql	Lcmpc5_out
Lcmpc5_str2loop:
	cmpb	%r11,(%r3)
	jneq	Lcmpc5_out
	incl	%r3
	sobgtr	%r2,Lcmpc5_str2loop
	jbr	Lcmpc5_out
Lcmpc5_str1loop:
	cmpb	(%r1),%r11
	jneq	Lcmpc5_out
	incl	%r1
	sobgtr	%r0,Lcmpc5_str1loop
Lcmpc5_out:
	savepsl
	return


/*
 * Packed Decimal string operations
 */

#define POSITIVE	$12
#define NEGATIVE	$13
#define NEGATIVEalt	$11


	_ALIGN_TEXT
ALTENTRY(EMaddp4)
	toarg(%r9,6)		# save register r9 in arg6 spot
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	arguw(3,%r9)		# (3) destination length == r9
	argl(4,%r3)		# (4) destination address == r3
	ashl	$-1,%r11,%r11
	addl2	%r11,%r10	# source address of LSNibble
	incl	%r11		# source length is in bytes
	ashl	$-1,%r9,%r9
	addl2	%r9,%r3		# r3 = destination address of LSNibble
	incl	%r9		# destination length is in bytes
	toarg(%r3,5)
	extzv	$0,$4,(%r3),%r2	# set standard +/- indicators in destination
	cmpl	%r2,NEGATIVE
	jeql	L112
	cmpl	%r2,NEGATIVEalt
	jeql	L111
	insv	POSITIVE,$0,$4,(%r3)
	jbr	L112
L111:
	insv	NEGATIVE,$0,$4,(%r3)
L112:
	extzv	$0,$4,(%r10),%r2 # r2 = standard +/- of source
	cmpl	%r2,NEGATIVE
	jeql	L114
	cmpl	%r2,NEGATIVEalt
	jeql	L113
	movl	POSITIVE,%r2
	jbr	L114
L113:
	movl	NEGATIVE,%r2
L114:
	cmpl	%r11,%r9	# if source is longer than destination
	jleq	L115
	movl	%r9,%r11	#	set source length == destination length
L115:
	extzv	$4,$4,(%r3),%r9	# r9 = LSDigit of destination
	extzv	$4,$4,(%r10),%r1 # r1 = LSDigit of source
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,%r2		# if signs of operands are not equal
	jeql	Laddp4_same	#	do a subtraction
	clrl	%r2		# r2 is non-zero if result is non-zero
	subl2	%r1,%r9		# r9 = "addition" of operands high nibble
	jbr	L119		# jump into addition loop
Laddp4_diff_loop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 = carry + next (low) nibble of source
	decl	%r10
	extzv	$0,$4,(%r10),%r0
	subl2	%r0,%r1		# r1 -= next (low) nibble of destination
	jgeq	L121		# if negative result
	mnegl	$1,%r9		#	r9 == carry = -1
	addl2	$10,%r1		#	r1 == result += 10
	jbr	L122		# else
L121:
	clrl	%r9		#	r9 == carry = 0
L122:
	insv	%r1,$0,$4,(%r3)	# store result low nibble
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9		# r9 = carry + next (high) nibble of source
	extzv	$4,$4,(%r10),%r0
	subl2	%r0,%r9		# r9 -= next (high) nibble of destination
L119:
	jgeq	L117		# if negative result
	mnegl	$1,%r1		#	r1 == carry = -1
	addl2	$10,%r9		#	r9 == result += 10
	jbr	L118		# else
L117:
	clrl	%r1		#	r1 == carry = 0
L118:
	insv	%r9,$4,$4,(%r3)	# store result high nibble
	bisl2	%r9,%r2		# r2 is non-zero if result is non-zero
	decl	%r11		# while (--source length)
	jneq	Laddp4_diff_loop
	argl(4,%r10)		# r10 = address of destination MSNibble
	jbr	Laddp4_diff_carry
Laddp4_diff_carlop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 == carry += next (low) nibble
	jgeq	L127		# if less than zero
	movl	%r1,%r9		#	r9 == carry (must be -1)
	movl	$9,%r1		#	r1 == result = 9
	jbr	L128
L127:				# else
	clrl	%r9		#	r9 == carry = 0
L128:
	insv	%r1,$0,$4,(%r3)	# store result
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9		# r9 == carry += next (high) nibble
	jgeq	L129		# if less than zero
	movl	%r9,%r1		# r1 == carry (must be -1)
	movl	$9,%r9		# r9 == result = 9
	jbr	L130
L129:
	clrl	%r1
L130:
	insv	%r9,$4,$4,(%r3)	# store result
	bisl2	%r9,%r2
Laddp4_diff_carry:
	cmpl	%r3,%r10
	jneq	Laddp4_diff_carlop
	tstl	%r1		#	if carry out of MSN then fix up result
	jeql	Laddp4_add_done
	argl(5,%r3)		# r3 == address of LSN of destination
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,NEGATIVE	# switch sign of result
	jneq	L132
	insv	POSITIVE,$0,$4,(%r3)
	jbr	L133
L132:
	insv	NEGATIVE,$0,$4,(%r3)
L133:
	extzv	$4,$4,(%r3),%r0	# normalize result (carry out of MSN into LSN)
	subl3	%r0,$10,%r9	# r9 = 10 - destination LSNibble
	jbr	L134
L137:
	movl	$9,%r1
Laddp4_diff_norm:
	insv	%r9,$4,$4,(%r3)
	cmpl	%r3,%r10	# while (not at MSNibble)
	jeql	Laddp4_add_done
	decl	%r3
	extzv	$0,$4,(%r3),%r0	# low nibble = (9 + carry) - low nibble
	subl2	%r0,%r1
	cmpl	%r1,$9
	jleq	L135
	clrl	%r1
	movl	$10,%r9
	jbr	L136
L135:
	movl	$9,%r9
L136:
	insv	%r1,$0,$4,(%r3)
	extzv	$4,$4,(%r3),%r0	# high nibble = (9 + carry) - high nibble
	subl2	%r0,%r9
L134:
	cmpl	%r9,$9
	jleq	L137
	clrl	%r9
	movl	$10,%r1
	jbr	Laddp4_diff_norm

Laddp4_same:			# operands are of the same sign
	clrl	%r2
	addl2	%r1,%r9
	jbr	L139
Laddp4_same_loop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 == carry += next (low) nibble of dest
	decl	%r10
	extzv	$0,$4,(%r10),%r0
	addl2	%r0,%r1		# r1 += next (low) nibble of source
	cmpl	%r1,$9		# if result > 9
	jleq	L141
	movl	$1,%r9		#	r9 == carry = 1
	subl2	$10,%r1		#	r1 == result -= 10
	jbr	L142
L141:				# else
	clrl	%r9		#	r9 == carry = 0
L142:
	insv	%r1,$0,$4,(%r3)	# store result
	bisl2	%r1,%r2
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r9		# ditto for high nibble
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9
L139:
	cmpl	%r9,$9
	jleq	L143
	movl	$1,%r1
	subl2	$10,%r9
	jbr	L144
L143:
	clrl	%r1
L144:
	insv	%r9,$4,$4,(%r3)
	bisl2	%r9,%r2
	sobgtr	%r11,Laddp4_same_loop	# while (--source length)
	argl(4,%r10)		# r10 = destination address of MSNibble
	jbr	Laddp4_same_carry
Laddp4_same_cloop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0	# propagate carry up to MSNibble of destination
	addl2	%r0,%r1
	cmpl	%r1,$10
	jneq	L147
	movl	$1,%r9
	clrl	%r1
	jbr	L148
L147:
	clrl	%r9
L148:
	insv	%r1,$0,$4,(%r3)
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9
	cmpl	%r9,$10
	jneq	L149
	movl	$1,%r1
	clrl	%r9
	jbr	L150
L149:
	clrl	%r1
L150:
	insv	%r9,$4,$4,(%r3)
	bisl2	%r9,%r2
Laddp4_same_carry:
	cmpl	%r3,%r10
	jneq	Laddp4_same_cloop

Laddp4_add_done:
	argl(5,%r3)		# r3 = destination address of LSNibble
	tstl	%r2		# if zero result
	jneq	L151
	savepsl			#	remember that for condition codes
	insv	POSITIVE,$0,$4,(%r3) #	make sure sign of result is positive
	jbr	Laddp4_out
L151:				# else
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,NEGATIVE	#	if result is negative
	jneq	Laddp4_out
	mnegl	%r2,%r2		#		remember THAT in Cond Codes
	savepsl
Laddp4_out:
	argl(4,%r3)
	argl(2,%r1)
	clrl	%r0
	clrl	%r2
	argl(6,%r9)		# restore r9 from stack
	return


	_ALIGN_TEXT
ALTENTRY(EMmovp)
	arguw(1,%r11)		# (1) string length == r11
	argl(2,%r10)		# (1) source address == r10
	argl(3,%r3)		# (1) destination address == r3
			# we will need arg2 and arg3 later
	clrl	%r2		# r2 == non-zero if source is non-zero
	ashl	$-1,%r11,%r11	# length is number of bytes, not nibbles
	jeql	Lmovp_zlen
Lmovp_copy:
	bisb2	(%r10),%r2	# keep track of non-zero source
	movb	(%r10)+,(%r3)+	# move two nibbles
	sobgtr	%r11,Lmovp_copy	# loop for length of source
Lmovp_zlen:
	extzv	$4,$4,(%r10),%r0 # look at least significant nibble
	bisl2	%r0,%r2
	extzv	$0,$4,(%r10),%r0 # check sign nibble
	cmpl	%r0,NEGATIVEalt
	jeql	Lmovp_neg
	cmpl	%r0,NEGATIVE
	jneq	Lmovp_pos
Lmovp_neg:			# source was negative
	mnegl	%r2,%r2
Lmovp_pos:
	tstl	%r2		# set condition codes
	savepsl
	jeql	Lmovp_zero
	movb	(%r10),(%r3)	# move last byte if non-zero result
	jbr	Lmovp_out
Lmovp_zero:
	movb	POSITIVE,(%r3)	#	otherwise, make result zero and positive
Lmovp_out:
	clrl	%r0
	argl(2,%r1)
	clrl	%r2
	argl(3,%r3)
	return


/*
 *	Definitions for Editpc instruction
 *
 *  Here are the commands and their corresponding hex values:
 *
 *	EPend		0x00
 *	EPend_float	0x01
 *	EPclear_signif	0x02
 *	EPset_signif	0x03
 *	EPstore_sign	0x04
 *	EPload_fill	0x40
 *	EPload_sign	0x41
 *	EPload_plus	0x42
 *	EPload_minus	0x43
 *	EPinsert	0x44
 *	EPblank_zero	0x45
 *	EPreplace_sign	0x46
 *	EPadjust_input	0x47
 *	EPfill		0x80
 *	EPmove		0x90
 *	EPfloat		0xa0
 *
 *
 *  r4 is carved up as follows:
 *
 *	------------------------------------------- 
 *     |                                   N Z V C |
 *	-------------------------------------------
 *
 *	fill character is stuffed into arg5 space
 *	sign character is stuffed into arg6 space
 */

#define SIGNIFBIT	$0
#define setsignif	bisl2	$1,%r4
#define clsignif	bicl2	$1,%r4
#define OVERFLOWBIT	$1
#define setoverflow	bisl2	$2,%r4
#define cloverflow	bicl2	$2,%r4
#define ZEROBIT		$2
#define setzero		bisl2	$4,%r4
#define clzero		bicl2	$4,%r4
#define NEGATIVEBIT	$3
#define setnegative	bisl2	$8,%r4
#define clnegative	bicl2	$8,%r4
#define putfill		movb	arg5,(%r5)+
#define setfill(reg)	movb	reg,arg5
#define putsign		movb	arg6,(%r5)+
#define setsign(reg)	movb	reg,arg6


	_ALIGN_TEXT
ALTENTRY(EMeditpc)
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	argl(3,%r3)		# (3) pattern address == r3
	argl(4,%r5)		# (4) destination address == r5
/*		# we will need arg1 and arg2 later */
/*		# arg5 and arg6 are used for fill and sign - r0 is free */
	setfill($32)		# fill character is ' '
	setsign($32)		# sign character is ' '
	clrl	%r4		# clear flags
	ashl	$-1,%r11,%r11	# source length / 2
	addl3	%r11,%r10,%r2
	extzv	$4,$4,(%r2),%r1	# r1 == least significant nibble of source
L169:
	cmpl	%r2,%r10
	jeql	L170
	tstb	-(%r2)		# loop over source packed decimal number
	jeql	L169
	incl	%r1		# r1 is non-zero if source is non-zero
L170:
	addl3	%r11,%r10,%r2
	tstl	%r1
	jeql	L172		# source is zero - set flags
	extzv	$0,$4,(%r2),%r11
	cmpl	%r11,NEGATIVEalt
	jeql	L9998		# source is negative - set sign and flags
	cmpl	%r11,NEGATIVE
	jneq	L175
L9998:
	setnegative
	setsign($45)		# sign character is '-'
	jbr	L175
L172:
	setzero
L175:
	arguw(1,%r2)		# (1) source length == r2
Ledit_case:
	movzbl	(%r3)+,%r11	# get next edit command (pattern)
	cmpl	%r11,$128
	jlss	L180
	extzv	$0,$4,%r11,%r1	# command has a "count" arg - into r1
	ashl	$-4,%r11,%r11	# and shift over
L180:
	jbc	$6,%r11,L181	# "shift" those commands > 64 to 16 and up
	subl2	$48,%r11
L181:
	caseb	%r11,$0,$0x18	# "do" the command
				# r11 is available for use, r1 has "count" in it
Lcaseb_label:
	.word	Le_end - Lcaseb_label		# 00
	.word	Le_end_float - Lcaseb_label	# 01
	.word	Le_clear_signif - Lcaseb_label	# 02
	.word	Le_set_signif - Lcaseb_label	# 03
	.word	Le_store_sign - Lcaseb_label	# 04
	.word	Le_end - Lcaseb_label		# 05
	.word	Le_end - Lcaseb_label		# 06
	.word	Le_end - Lcaseb_label		# 07
	.word	Le_fill - Lcaseb_label		# 80
	.word	Le_move - Lcaseb_label		# 90
	.word	Le_float - Lcaseb_label		# a0
	.word	Le_end - Lcaseb_label		# b0
	.word	Le_end - Lcaseb_label		# c0
	.word	Le_end - Lcaseb_label		# d0
	.word	Le_end - Lcaseb_label		# e0
	.word	Le_end - Lcaseb_label		# f0
	.word	Le_load_fill - Lcaseb_label	# 40
	.word	Le_load_sign - Lcaseb_label	# 41
	.word	Le_load_plus - Lcaseb_label	# 42
	.word	Le_load_minus - Lcaseb_label	# 43
	.word	Le_insert - Lcaseb_label	# 44
	.word	Le_blank_zero - Lcaseb_label	# 45
	.word	Le_replace_sign - Lcaseb_label	# 46
	.word	Le_adjust_input - Lcaseb_label	# 47
Le_end:
	arguw(1,%r0)
	argl(2,%r1)
	clrl	%r2
	decl	%r3
	setpsl(%r4)
	clrl	%r4
	return

Le_end_float:
	jbs	SIGNIFBIT,%r4,Ledit_case # if significance not set
	putsign				# drop in the sign
					# fall into...
Le_set_signif:
	setsignif
	jbr	Ledit_case

Le_clear_signif:
	clsignif
	jbr	Ledit_case

Le_store_sign:
	putsign
	jbr	Ledit_case

Le_load_fill:
	setfill((%r3)+)
	jbr	Ledit_case

Le_load_plus:
	jbs	NEGATIVEBIT,%r4,Lpattern_inc	# if non-negative
					# fall into...
Le_load_sign:
	setsign((%r3)+)
	jbr	Ledit_case

Le_load_minus:
	jbs	NEGATIVEBIT,%r4,Le_load_sign	# if negative load the sign
	incl	%r3			# else increment pattern
	jbr	Ledit_case

Le_insert:
	jbc	SIGNIFBIT,%r4,L196	# if significance set, put next byte
	movb	(%r3)+,(%r5)+
	jbr	Ledit_case
L196:					# else put in fill character
	putfill
					# and throw away character in pattern
Le_replace_sign:			# we dont do anything with
Lpattern_inc:				# replace sign cause we dont
	incl	%r3			# get negative zero
	jbr	Ledit_case

Le_blank_zero:
	jbc	ZEROBIT,%r4,Lpattern_inc # if zero
	movzbl	(%r3)+,%r11		# next byte is a count
	jeql	Ledit_case
	subl2	%r11,%r5		# to back up over output and replace
L200:
	putfill				# with fill character
	sobgtr	%r11,L200
	jbr	Ledit_case

Le_adjust_input:
	movzbl	(%r3)+,%r0		# get count of nibbles from pattern
	subl3	%r2,%r0,%r11
	jgeq	Ledit_case		# if length of source is > this number
L204:					# discard digits in source
	jlbc	%r2,L206		# use low bit of length to choose nibble
	bitb	$0xf0,(%r10)		# high nibble
	jeql	L208
	setsignif			# set significance and overflow if
	setoverflow			#    wasted digit is non-zero
	jbr	L208
L206:
	bitb	$0xf,(%r10)		# low nibble
	jeql	L209
	setsignif
	setoverflow
L209:
	incl	%r10			# increment to next byte
L208:
	decl	%r2			# decrement source length
	incl	%r11			# continue till were out of excess
	jlss	L204
	jbr	Ledit_case

Le_fill:
	tstl	%r1			# put (count in r1) fill characters
	jeql	Ledit_case
Le_fill_loop:
	putfill
	sobgtr	%r1,Le_fill_loop
	jbr	Ledit_case

Le_move:
	tstl	%r1			# move (count in r1) characters
	jeql	Ledit_case		# from source to destination
L214:
	jlbc	%r2,L215		# read a nibble
	extzv	$4,$4,(%r10),%r11
	jbr	L216
L215:
	extzv	$0,$4,(%r10),%r11
	incl	%r10
L216:
	decl	%r2			# source length CAN go negative here...
	tstl	%r11
	jeql	L218			# if non-zero
	setsignif			# set significance
L218:
	jbc	SIGNIFBIT,%r4,L219	# if significance set
	addb3	$48,%r11,(%r5)+		# put 0 + digit into destination
	jbr	L220
L219:					# else put fill character
	putfill
L220:
	sobgtr	%r1,L214
	jbr	Ledit_case

Le_float:				# move with floating sign character
	tstl	%r1
	jeql	Ledit_case
L221:
	jlbc	%r2,L222
	extzv	$4,$4,(%r10),%r11
	jbr	L223
L222:
	extzv	$0,$4,(%r10),%r11
	incl	%r10
L223:
	decl	%r2			# source length CAN go negative here...
	tstl	%r11
	jeql	L225
	jbs	SIGNIFBIT,%r4,L226
	putsign
L226:
	setsignif
L225:
	jbc	SIGNIFBIT,%r4,L227
	addb3	$48,%r11,(%r5)+
	jbr	L228
L227:
	putfill
L228:
	sobgtr	%r1,L221
	jbr	Ledit_case


	_ALIGN_TEXT
ALTENTRY(EMashp)
	argb(1,%r11)		# (1) scale (number to shift) == r11
	arguw(2,%r10)		# (2) source length == r10
	argl(3,%r1)		# (3) source address == r1
	argub(4,%r2)		# (4) rounding factor == r2
	arguw(5,%r3)		# (5) destination length == r3
	toarg(%r6,3)/* 	# arg3 holds register 6 from caller */
	argl(6,%r6)		# (6) destination address == r6
/*
			# we need arg6 for later
			# arg1 is used for temporary storage
			# arg2 holds "even or odd" destination length
			# arg4 is used as general storage
			# arg5 is used as general storage
*/
	ashl	$-1,%r3,%r0	# destination length is number of bytes
	addl2	%r0,%r6		# destination address == least sig nibble
	toarg(%r6,1)		# save in arg1 spot for later
	ashl	$-1,%r10,%r0
	addl2	%r0,%r1		# source address == least sig nibble
	extzv	$0,$4,(%r1),%r0	# determine sign of source
	cmpl	%r0,NEGATIVEalt
	jeql	Lashp_neg
	cmpl	%r0,NEGATIVE
	jeql	Lashp_neg
	movb	POSITIVE,(%r6)
	jbr	L245
Lashp_neg:
	movb	NEGATIVE,(%r6)
L245:
	clrl	arg2		# arg2 is 1 if dstlen is even, 0 if odd
	blbs	%r3,L246
	incl	arg2
	bisl2	$1,%r3		# r3<0> counts digits going into destination
L246:				#	and is flip-flop for which nibble to
	tstl	%r11		#	write in destination (1 = high, 0 = low)
	jgeq	Lashp_left	#	(it must start out odd)
	addl2	%r11,%r10	# scale is negative (right shift)
	jgeq	Lashp_right
	clrl	%r10		# test for shifting whole number out
	jbr	Lashp_setround
Lashp_right:
	divl3	$2,%r11,%r0
	addl2	%r0,%r1		# source address == MSNibble to be shifted off
	jlbc	%r11,L249
	extzv	$4,$4,(%r1),%r0
	addl2	%r0,%r2		# round = last nibble to be shifted off + round
	jbr	Lashp_setround
L249:
	extzv	$0,$4,(%r1),%r0
	addl2	%r0,%r2		# round = last nibble to be shifted off + round
Lashp_setround:			# r11<0> now is flip-flop for which nibble to
	incl	%r11		#    read from source (1 == high, 0 == low)
	cmpl	%r2,$9		# set rounding factor to one if nibble shifted
	jleq	Lashp_noround	#    off + round argument was 10 or greater
	movl	$1,%r2
	jbr	Lashp_shift
Lashp_zloop:
	jlbs	%r3,L257	# dont need to clear high nibble twice
	clrb	-(%r6)		# clear low (and high) nib of next byte in dest
L257:
	sobgtr	%r3,L258		# move to next nibble in destination, but
	incl	%r3		#	dont go beyond the end.
L258:
	decl	%r11
Lashp_left:			# while scale is positive
	jneq	Lashp_zloop
	incl	%r11		# r11<0> is flip-plop ... (incl sets it to one)
Lashp_noround:
	clrl	%r2		# no more rounding
Lashp_shift:
	clrl	arg4		# arg4 will be used for result condition codes
	tstl	%r10
	jeql	Lashp_round
Lashp_shloop:
	jlbc	%r11,L260
	extzv	$4,$4,(%r1),%r0
	jbr	L261
L260:
	decl	%r1
	extzv	$0,$4,(%r1),%r0
L261:
	incl	%r11		# flip the source nibble flip/flop
	addl2	%r0,%r2		# round += next nibble
	cmpl	%r2,$10		# if round == 10
	jneq	L262
	clrl	arg5		#	then result = 0 and round = 1
	movl	$1,%r2
	jbr	L263
L262:				# else
	movl	%r2,arg5	#	store result and round = 0
	clrl	%r2
L263:
	bisl2	arg5,arg4	# remember if result was nonzero in arg4
	decl	%r3		# move to next nibble early to check
	cmpl	%r3,arg2	# if weve moved passed destination limits
	jgeq	Lashp_noovfl	#	test the result for possible overflow
	movl	arg2,%r3	#	ignore zero nibbles
	tstl	arg5		#	if the nibble was non-zero, overflow
	jeql	L265
	jbr	Lashp_overfl
Lashp_noovfl:			# else
	jlbs	%r3,L264
	insv	arg5,$4,$4,(%r6) # put the result into destination (high or low)
	jbr	L265
L264:
	movb	arg5,-(%r6)
L265:
	sobgtr	%r10,Lashp_shloop	# loop for length of source

Lashp_round:
	tstl	%r2		# take care of round out of high nibble
	jeql	Lashp_zeroround
	decl	%r3
	cmpl	%r3,arg2	# if weve moved passed destination limits
	jlss	Lashp_overfl	#	then overflow
	jlbs	%r3,L266
	insv	arg5,$4,$4,(%r6) # put the round into destination (high or low)
	jbr	Lashp_zeroround
L266:
	movb	arg5,-(%r6)

Lashp_zeroround:
	argl(1,%r10)		# r10 = address of destination LSNibble
	argl(6,%r3)		# r3 = address of destination MSNibble
	movl	arg4,%r11	# r11 = non-zero if destination == non-zero
	savepsl
	jbr	L267
Lashp_zerofill:
	clrb	-(%r6)		# fill up MSNs of destination with zeros
L267:
	cmpl	%r3,%r6
	jneq	Lashp_zerofill
	extzv	$0,$4,(%r10),%r0 # test for negative result
	cmpl	%r0,NEGATIVE
	jneq	Lashp_out
	mnegl	%r11,%r11
	savepsl
	jneq	Lashp_out	# turn -0 into 0
	insv	POSITIVE,$0,$4,(%r10)
Lashp_out:
	clrl	%r0
	argl(3,%r6)		# restore r6 from stack
	return
Lashp_overfl:			#    do overflow
	clrl	%r2
	overflowpsl
	jbr	Lashp_out


	_ALIGN_TEXT
ALTENTRY(EMcvtlp)
	arguw(2,%r10)		# (2) destination length == r10
	argl(3,%r3)		# (3) destination address == r3
	ashl	$-1,%r10,%r10
	addl2	%r10,%r3	# destination address points to Least Sig byte
	incl	%r10		# length is # of bytes, not nibbles
	argl(1,%r11)		# (1) source == r11
	savepsl
	jgeq	Lcvtlp_pos
	movb	NEGATIVE,(%r3)	# source is negative
	divl3	$10,%r11,%r0
	mull3	$10,%r0,%r1
	subl3	%r11,%r1,%r2	# r2 = source mod 10
	mnegl	%r0,%r11	# source = -(source / 10)
	jbr	Lcvtlp_cvt
Lcvtlp_pos:
	movb	POSITIVE,(%r3)	# source is non-negative
	divl3	$10,%r11,%r0
	mull3	$10,%r0,%r1
	subl3	%r1,%r11,%r2	# r2 = source mod 10
	movl	%r0,%r11	# source = source / 10
Lcvtlp_cvt:
	insv	%r2,$4,$4,(%r3)	# store least significant digit
	tstl	%r11
	jeql	Lcvtlp_zloop
Lcvtlp_loop:			# while source is non-zero
	decl	%r10		#   and for length of destination ...
	jeql	Lcvtlp_over
	divl3	$10,%r11,%r1	# r1 = source / 10
	mull3	$10,%r1,%r0
	subl2	%r0,%r11	# source = source mod 10
	movb	%r11,-(%r3)	# store low "nibble" in next significant byte
	divl3	$10,%r1,%r11	# source = r1 / 10
	mull3	$10,%r11,%r0
	subl2	%r0,%r1		# r1 = source mod 10
	insv	%r1,$4,$4,(%r3)	# store high nibble
	tstl	%r11
	jneq	Lcvtlp_loop	# quit if source becomes zero
Lcvtlp_zloop:			# fill any remaining bytes with zeros
	decl	%r10
	jeql	Lcvtlp_out
	clrb	-(%r3)
	jbr	Lcvtlp_zloop
Lcvtlp_over:
	overflowpsl
Lcvtlp_out:
	clrl	%r1		# r0 is already zero
	clrl	%r2
	return


	_ALIGN_TEXT
ALTENTRY(EMcvtpl)
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	clrl	%r3		# r3 == destination
	movl	%r10,%r1	# r1 set up now for return
	ashl	$-1,%r11,%r11	# source length is number of bytes
	jeql	Lcvtpl_zero
Lcvtpl_loop:			# for source length
	mull2	$10,%r3		# destination *= 10
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r3		# destination += high nibble
	mull2	$10,%r3		# destination *= 10
	extzv	$0,$4,(%r10),%r0
	addl2	%r0,%r3		# destination += low nibble
	incl	%r10
	sobgtr	%r11,Lcvtpl_loop
Lcvtpl_zero:			# least significant byte
	mull2	$10,%r3
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r3		# dest = 10 * dest + high nibble
	savepsl
	extzv	$0,$4,(%r10),%r2 # test sign nibble
	cmpl	%r2,NEGATIVE
	jeql	Lcvtpl_neg
	cmpl	%r2,NEGATIVEalt
	jneq	Lcvtpl_out
Lcvtpl_neg:			# source was negative - negate destination
	mnegl	%r3,%r3
	savepsl
Lcvtpl_out:
	toarg(%r3,3)
	clrl	%r0
	clrl	%r2
	clrl	%r3
	return


	_ALIGN_TEXT
ALTENTRY(EMcvtps)
	return


	_ALIGN_TEXT
ALTENTRY(EMcvtsp)
	return


	_ALIGN_TEXT
ALTENTRY(EMaddp6)
	return


	_ALIGN_TEXT
ALTENTRY(EMsubp4)
	return


	_ALIGN_TEXT
ALTENTRY(EMsubp6)
	return


	_ALIGN_TEXT
ALTENTRY(EMcvtpt)
	return


	_ALIGN_TEXT
ALTENTRY(EMmulp)
	return


	_ALIGN_TEXT
ALTENTRY(EMcvttp)
	return


	_ALIGN_TEXT
ALTENTRY(EMdivp)
	return


	_ALIGN_TEXT
ALTENTRY(EMcmpp3)
	return


	_ALIGN_TEXT
ALTENTRY(EMcmpp4)
	return



#ifdef notdef
/*
 * Emulation OpCode jump table:
 *	ONLY GOES FROM 0xf8 (-8) TO 0x3B (59)
 */
#define EMUTABLE	0x43
#define NOEMULATE	.long noemulate
#define	EMULATE(a)	.long _C_LABEL(__CONCAT(EM,a))
	.globl	_C_LABEL(emJUMPtable)
_C_LABEL(emJUMPtable):
/* f8 */	EMULATE(ashp);	EMULATE(cvtlp);	NOEMULATE;	NOEMULATE
/* fc */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 00 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 04 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 08 */	EMULATE(cvtps);	EMULATE(cvtsp);	NOEMULATE;	EMULATE(crc)
/* 0c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 10 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 14 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 18 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 1c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 20 */	EMULATE(addp4);	EMULATE(addp6);	EMULATE(subp4);	EMULATE(subp6)
/* 24 */	EMULATE(cvtpt);	EMULATE(mulp);	EMULATE(cvttp);	EMULATE(divp)
/* 28 */	NOEMULATE;	EMULATE(cmpc3);	EMULATE(scanc);	EMULATE(spanc)
/* 2c */	NOEMULATE;	EMULATE(cmpc5);	EMULATE(movtc);	EMULATE(movtuc)
/* 30 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 34 */	EMULATE(movp);	EMULATE(cmpp3);	EMULATE(cvtpl);	EMULATE(cmpp4)
/* 38 */	EMULATE(editpc); EMULATE(matchc); EMULATE(locc); EMULATE(skpc)

/*
 * The following is called with the stack set up as follows:
 *
 *	  (sp):	Opcode
 *	 4(sp):	Instruction PC
 *	 8(sp):	Operand 1
 *	12(sp):	Operand 2
 *	16(sp):	Operand 3
 *	20(sp):	Operand 4
 *	24(sp):	Operand 5
 *	28(sp):	Operand 6
 *	32(sp):	Operand 7 (unused)
 *	36(sp):	Operand 8 (unused)
 *	40(sp):	Return PC
 *	44(sp):	Return PSL
 *	48(sp): TOS before instruction
 *
 * Each individual routine is called with the stack set up as follows:
 *
 *	  (sp):	Return address of trap handler
 *	 4(sp):	Opcode (will get return PSL)
 *	 8(sp):	Instruction PC
 *	12(sp):	Operand 1
 *	16(sp):	Operand 2
 *	20(sp):	Operand 3
 *	24(sp):	Operand 4
 *	28(sp):	Operand 5
 *	32(sp):	Operand 6
 *	36(sp):	saved register 11
 *	40(sp):	saved register 10
 *	44(sp):	Return PC
 *	48(sp):	Return PSL
 *	52(sp): TOS before instruction
 */

SCBVEC(emulate):
	movl	%r11,32(%sp)		# save register r11 in unused operand
	movl	%r10,36(%sp)		# save register r10 in unused operand
	cvtbl	(%sp),%r10		# get opcode
	addl2	$8,%r10			# shift negative opcodes
	subl3	%r10,$EMUTABLE,%r11	# forget it if opcode is out of range
	bcs	noemulate
	movl	_C_LABEL(emJUMPtable)[%r10],%r10
					# call appropriate emulation routine
	jsb	(%r10)		# routines put return values into regs 0-5
	movl	32(%sp),%r11		# restore register r11
	movl	36(%sp),%r10		# restore register r10
	insv	(%sp),$0,$4,44(%sp)	# and condition codes in Opcode spot
	addl2	$40,%sp			# adjust stack for return
	rei
noemulate:
	addl2	$48,%sp			# adjust stack for
	.word	0xffff			# "reserved instruction fault"
SCBVEC(emulateFPD):
	.word	0xffff			# "reserved instruction fault"
#endif
