Linux Audio

Check our new training course

Loading...
v6.8
   1|
   2|	res_func.sa 3.9 7/29/91
   3|
   4| Normalizes denormalized numbers if necessary and updates the
   5| stack frame.  The function is then restored back into the
   6| machine and the 040 completes the operation.  This routine
   7| is only used by the unsupported data type/format handler.
   8| (Exception vector 55).
   9|
  10| For packed move out (fmove.p fpm,<ea>) the operation is
  11| completed here; data is packed and moved to user memory.
  12| The stack is restored to the 040 only in the case of a
  13| reportable exception in the conversion.
  14|
  15|
  16|		Copyright (C) Motorola, Inc. 1990
  17|			All Rights Reserved
  18|
  19|       For details on the license for this file, please see the
  20|       file, README, in this same directory.
  21
  22RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
  23
  24	|section	8
  25
  26#include "fpsp.h"
  27
  28sp_bnds:	.short	0x3f81,0x407e
  29		.short	0x3f6a,0x0000
  30dp_bnds:	.short	0x3c01,0x43fe
  31		.short	0x3bcd,0x0000
  32
  33	|xref	mem_write
  34	|xref	bindec
  35	|xref	get_fline
  36	|xref	round
  37	|xref	denorm
  38	|xref	dest_ext
  39	|xref	dest_dbl
  40	|xref	dest_sgl
  41	|xref	unf_sub
  42	|xref	nrm_set
  43	|xref	dnrm_lp
  44	|xref	ovf_res
  45	|xref	reg_dest
  46	|xref	t_ovfl
  47	|xref	t_unfl
  48
  49	.global	res_func
  50	.global	p_move
  51
  52res_func:
  53	clrb	DNRM_FLG(%a6)
  54	clrb	RES_FLG(%a6)
  55	clrb	CU_ONLY(%a6)
  56	tstb	DY_MO_FLG(%a6)
  57	beqs	monadic
  58dyadic:
  59	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
  60|				;inf=010 or nan=011
  61	beqs	monadic		|then branch
  62|				;else denorm
  63| HANDLE DESTINATION DENORM HERE
  64|				;set dtag to norm
  65|				;write the tag & fpte15 to the fstack
  66	leal	FPTEMP(%a6),%a0
  67
  68	bclrb	#sign_bit,LOCAL_EX(%a0)
  69	sne	LOCAL_SGN(%a0)
  70
  71	bsr	nrm_set		|normalize number (exp will go negative)
  72	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
  73	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
  74	beqs	dpos
  75	bsetb	#sign_bit,LOCAL_EX(%a0)
  76dpos:
  77	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
  78	bsetb	#4,DTAG(%a6)	|set FPTE15
  79	orb	#0x0f,DNRM_FLG(%a6)
  80monadic:
  81	leal	ETEMP(%a6),%a0
  82	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
  83	bne	opclass3			|it is a mv out
  84|
  85| At this point, only opclass 0 and 2 possible
  86|
  87	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
  88|				;inf=010 or nan=011
  89	bne	mon_dnrm	|else denorm
  90	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
  91	bne	normal		|require normalization of denorm
  92
  93| At this point:
  94|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
  95|				fmove = $00  fsmove = $40  fdmove = $44
  96|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
  97|				(*fsqrt reencoded to $05)
  98|
  99	movew	CMDREG1B(%a6),%d0	|get command register
 100	andil	#0x7f,%d0			|strip to only command word
 101|
 102| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
 103| fdsqrt are possible.
 104| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
 105| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
 106|
 107	btstl	#0,%d0
 108	bne	normal			|weed out fsqrt instructions
 109|
 110| cu_norm handles fmove in instructions with normalized inputs.
 111| The routine round is used to correctly round the input for the
 112| destination precision and mode.
 113|
 114cu_norm:
 115	st	CU_ONLY(%a6)		|set cu-only inst flag
 116	movew	CMDREG1B(%a6),%d0
 117	andib	#0x3b,%d0		|isolate bits to select inst
 118	tstb	%d0
 119	beql	cu_nmove	|if zero, it is an fmove
 120	cmpib	#0x18,%d0
 121	beql	cu_nabs		|if $18, it is fabs
 122	cmpib	#0x1a,%d0
 123	beql	cu_nneg		|if $1a, it is fneg
 124|
 125| Inst is ftst.  Check the source operand and set the cc's accordingly.
 126| No write is done, so simply rts.
 127|
 128cu_ntst:
 129	movew	LOCAL_EX(%a0),%d0
 130	bclrl	#15,%d0
 131	sne	LOCAL_SGN(%a0)
 132	beqs	cu_ntpo
 133	orl	#neg_mask,USER_FPSR(%a6) |set N
 134cu_ntpo:
 135	cmpiw	#0x7fff,%d0	|test for inf/nan
 136	bnes	cu_ntcz
 137	tstl	LOCAL_HI(%a0)
 138	bnes	cu_ntn
 139	tstl	LOCAL_LO(%a0)
 140	bnes	cu_ntn
 141	orl	#inf_mask,USER_FPSR(%a6)
 142	rts
 143cu_ntn:
 144	orl	#nan_mask,USER_FPSR(%a6)
 145	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
 146|						;snan handler
 147
 148	rts
 149cu_ntcz:
 150	tstl	LOCAL_HI(%a0)
 151	bnel	cu_ntsx
 152	tstl	LOCAL_LO(%a0)
 153	bnel	cu_ntsx
 154	orl	#z_mask,USER_FPSR(%a6)
 155cu_ntsx:
 156	rts
 157|
 158| Inst is fabs.  Execute the absolute value function on the input.
 159| Branch to the fmove code.  If the operand is NaN, do nothing.
 160|
 161cu_nabs:
 162	moveb	STAG(%a6),%d0
 163	btstl	#5,%d0			|test for NaN or zero
 164	bne	wr_etemp		|if either, simply write it
 165	bclrb	#7,LOCAL_EX(%a0)		|do abs
 166	bras	cu_nmove		|fmove code will finish
 167|
 168| Inst is fneg.  Execute the negate value function on the input.
 169| Fall though to the fmove code.  If the operand is NaN, do nothing.
 170|
 171cu_nneg:
 172	moveb	STAG(%a6),%d0
 173	btstl	#5,%d0			|test for NaN or zero
 174	bne	wr_etemp		|if either, simply write it
 175	bchgb	#7,LOCAL_EX(%a0)		|do neg
 176|
 177| Inst is fmove.  This code also handles all result writes.
 178| If bit 2 is set, round is forced to double.  If it is clear,
 179| and bit 6 is set, round is forced to single.  If both are clear,
 180| the round precision is found in the fpcr.  If the rounding precision
 181| is double or single, round the result before the write.
 182|
 183cu_nmove:
 184	moveb	STAG(%a6),%d0
 185	andib	#0xe0,%d0			|isolate stag bits
 186	bne	wr_etemp		|if not norm, simply write it
 187	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 188	bne	cu_nmrd
 189	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 190	bne	cu_nmrs
 191|
 192| The move or operation is not with forced precision.  Test for
 193| nan or inf as the input; if so, simply write it to FPn.  Use the
 194| FPCR_MODE byte to get rounding on norms and zeros.
 195|
 196cu_nmnr:
 197	bfextu	FPCR_MODE(%a6){#0:#2},%d0
 198	tstb	%d0			|check for extended
 199	beq	cu_wrexn		|if so, just write result
 200	cmpib	#1,%d0			|check for single
 201	beq	cu_nmrs			|fall through to double
 202|
 203| The move is fdmove or round precision is double.
 204|
 205cu_nmrd:
 206	movel	#2,%d0			|set up the size for denorm
 207	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
 208	andw	#0x7fff,%d1
 209	cmpw	#0x3c01,%d1
 210	bls	cu_nunfl
 211	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 212	orl	#0x00020000,%d1		|or in rprec (double)
 213	clrl	%d0			|clear g,r,s for round
 214	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
 215	sne	LOCAL_SGN(%a0)
 216	bsrl	round
 217	bfclr	LOCAL_SGN(%a0){#0:#8}
 218	beqs	cu_nmrdc
 219	bsetb	#sign_bit,LOCAL_EX(%a0)
 220cu_nmrdc:
 221	movew	LOCAL_EX(%a0),%d1		|check for overflow
 222	andw	#0x7fff,%d1
 223	cmpw	#0x43ff,%d1
 224	bge	cu_novfl		|take care of overflow case
 225	bra	cu_wrexn
 226|
 227| The move is fsmove or round precision is single.
 228|
 229cu_nmrs:
 230	movel	#1,%d0
 231	movew	LOCAL_EX(%a0),%d1
 232	andw	#0x7fff,%d1
 233	cmpw	#0x3f81,%d1
 234	bls	cu_nunfl
 235	bfextu	FPCR_MODE(%a6){#2:#2},%d1
 236	orl	#0x00010000,%d1
 237	clrl	%d0
 238	bclrb	#sign_bit,LOCAL_EX(%a0)
 239	sne	LOCAL_SGN(%a0)
 240	bsrl	round
 241	bfclr	LOCAL_SGN(%a0){#0:#8}
 242	beqs	cu_nmrsc
 243	bsetb	#sign_bit,LOCAL_EX(%a0)
 244cu_nmrsc:
 245	movew	LOCAL_EX(%a0),%d1
 246	andw	#0x7FFF,%d1
 247	cmpw	#0x407f,%d1
 248	blt	cu_wrexn
 249|
 250| The operand is above precision boundaries.  Use t_ovfl to
 251| generate the correct value.
 252|
 253cu_novfl:
 254	bsr	t_ovfl
 255	bra	cu_wrexn
 256|
 257| The operand is below precision boundaries.  Use denorm to
 258| generate the correct value.
 259|
 260cu_nunfl:
 261	bclrb	#sign_bit,LOCAL_EX(%a0)
 262	sne	LOCAL_SGN(%a0)
 263	bsr	denorm
 264	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
 265	beqs	cu_nucont
 266	bsetb	#sign_bit,LOCAL_EX(%a0)
 267cu_nucont:
 268	bfextu	FPCR_MODE(%a6){#2:#2},%d1
 269	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 270	bne	inst_d
 271	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 272	bne	inst_s
 273	swap	%d1
 274	moveb	FPCR_MODE(%a6),%d1
 275	lsrb	#6,%d1
 276	swap	%d1
 277	bra	inst_sd
 278inst_d:
 279	orl	#0x00020000,%d1
 280	bra	inst_sd
 281inst_s:
 282	orl	#0x00010000,%d1
 283inst_sd:
 284	bclrb	#sign_bit,LOCAL_EX(%a0)
 285	sne	LOCAL_SGN(%a0)
 286	bsrl	round
 287	bfclr	LOCAL_SGN(%a0){#0:#8}
 288	beqs	cu_nuflp
 289	bsetb	#sign_bit,LOCAL_EX(%a0)
 290cu_nuflp:
 291	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
 292	beqs	cu_nuninx
 293	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
 294cu_nuninx:
 295	tstl	LOCAL_HI(%a0)		|test for zero
 296	bnes	cu_nunzro
 297	tstl	LOCAL_LO(%a0)
 298	bnes	cu_nunzro
 299|
 300| The mantissa is zero from the denorm loop.  Check sign and rmode
 301| to see if rounding should have occurred which would leave the lsb.
 302|
 303	movel	USER_FPCR(%a6),%d0
 304	andil	#0x30,%d0		|isolate rmode
 305	cmpil	#0x20,%d0
 306	blts	cu_nzro
 307	bnes	cu_nrp
 308cu_nrm:
 309	tstw	LOCAL_EX(%a0)	|if positive, set lsb
 310	bges	cu_nzro
 311	btstb	#7,FPCR_MODE(%a6) |check for double
 312	beqs	cu_nincs
 313	bras	cu_nincd
 314cu_nrp:
 315	tstw	LOCAL_EX(%a0)	|if positive, set lsb
 316	blts	cu_nzro
 317	btstb	#7,FPCR_MODE(%a6) |check for double
 318	beqs	cu_nincs
 319cu_nincd:
 320	orl	#0x800,LOCAL_LO(%a0) |inc for double
 321	bra	cu_nunzro
 322cu_nincs:
 323	orl	#0x100,LOCAL_HI(%a0) |inc for single
 324	bra	cu_nunzro
 325cu_nzro:
 326	orl	#z_mask,USER_FPSR(%a6)
 327	moveb	STAG(%a6),%d0
 328	andib	#0xe0,%d0
 329	cmpib	#0x40,%d0		|check if input was tagged zero
 330	beqs	cu_numv
 331cu_nunzro:
 332	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
 333cu_numv:
 334	movel	(%a0),ETEMP(%a6)
 335	movel	4(%a0),ETEMP_HI(%a6)
 336	movel	8(%a0),ETEMP_LO(%a6)
 337|
 338| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
 339| bypass cu_wrexn.
 340|
 341cu_wrexn:
 342	tstw	LOCAL_EX(%a0)		|test for zero
 343	beqs	cu_wrzero
 344	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
 345	bnes	cu_wreon
 346cu_wrzero:
 347	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
 348cu_wreon:
 349	tstw	LOCAL_EX(%a0)
 350	bpl	wr_etemp
 351	orl	#neg_mask,USER_FPSR(%a6)
 352	bra	wr_etemp
 353
 354|
 355| HANDLE SOURCE DENORM HERE
 356|
 357|				;clear denorm stag to norm
 358|				;write the new tag & ete15 to the fstack
 359mon_dnrm:
 360|
 361| At this point, check for the cases in which normalizing the
 362| denorm produces incorrect results.
 363|
 364	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
 365	bnes	nrm_src		|require normalization of denorm
 366
 367| At this point:
 368|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
 369|				fmove = $00  fsmove = $40  fdmove = $44
 370|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
 371|				(*fsqrt reencoded to $05)
 372|
 373	movew	CMDREG1B(%a6),%d0	|get command register
 374	andil	#0x7f,%d0			|strip to only command word
 375|
 376| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
 377| fdsqrt are possible.
 378| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
 379| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
 380|
 381	btstl	#0,%d0
 382	bnes	nrm_src		|weed out fsqrt instructions
 383	st	CU_ONLY(%a6)	|set cu-only inst flag
 384	bra	cu_dnrm		|fmove, fabs, fneg, ftst
 385|				;cases go to cu_dnrm
 386nrm_src:
 387	bclrb	#sign_bit,LOCAL_EX(%a0)
 388	sne	LOCAL_SGN(%a0)
 389	bsr	nrm_set		|normalize number (exponent will go
 390|				; negative)
 391	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
 392
 393	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
 394	beqs	spos
 395	bsetb	#sign_bit,LOCAL_EX(%a0)
 396spos:
 397	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
 398	bsetb	#4,STAG(%a6)	|set ETE15
 399	orb	#0xf0,DNRM_FLG(%a6)
 400normal:
 401	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
 402	bne	ck_wrap		|if so, check if it is a potential
 403|				;wrap-around case
 404fix_stk:
 405	moveb	#0xfe,CU_SAVEPC(%a6)
 406	bclrb	#E1,E_BYTE(%a6)
 407
 408	clrw	NMNEXC(%a6)
 409
 410	st	RES_FLG(%a6)	|indicate that a restore is needed
 411	rts
 412
 413|
 414| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
 415| ftst) completely in software without an frestore to the 040.
 416|
 417cu_dnrm:
 418	st	CU_ONLY(%a6)
 419	movew	CMDREG1B(%a6),%d0
 420	andib	#0x3b,%d0		|isolate bits to select inst
 421	tstb	%d0
 422	beql	cu_dmove	|if zero, it is an fmove
 423	cmpib	#0x18,%d0
 424	beql	cu_dabs		|if $18, it is fabs
 425	cmpib	#0x1a,%d0
 426	beql	cu_dneg		|if $1a, it is fneg
 427|
 428| Inst is ftst.  Check the source operand and set the cc's accordingly.
 429| No write is done, so simply rts.
 430|
 431cu_dtst:
 432	movew	LOCAL_EX(%a0),%d0
 433	bclrl	#15,%d0
 434	sne	LOCAL_SGN(%a0)
 435	beqs	cu_dtpo
 436	orl	#neg_mask,USER_FPSR(%a6) |set N
 437cu_dtpo:
 438	cmpiw	#0x7fff,%d0	|test for inf/nan
 439	bnes	cu_dtcz
 440	tstl	LOCAL_HI(%a0)
 441	bnes	cu_dtn
 442	tstl	LOCAL_LO(%a0)
 443	bnes	cu_dtn
 444	orl	#inf_mask,USER_FPSR(%a6)
 445	rts
 446cu_dtn:
 447	orl	#nan_mask,USER_FPSR(%a6)
 448	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
 449|						;snan handler
 450	rts
 451cu_dtcz:
 452	tstl	LOCAL_HI(%a0)
 453	bnel	cu_dtsx
 454	tstl	LOCAL_LO(%a0)
 455	bnel	cu_dtsx
 456	orl	#z_mask,USER_FPSR(%a6)
 457cu_dtsx:
 458	rts
 459|
 460| Inst is fabs.  Execute the absolute value function on the input.
 461| Branch to the fmove code.
 462|
 463cu_dabs:
 464	bclrb	#7,LOCAL_EX(%a0)		|do abs
 465	bras	cu_dmove		|fmove code will finish
 466|
 467| Inst is fneg.  Execute the negate value function on the input.
 468| Fall though to the fmove code.
 469|
 470cu_dneg:
 471	bchgb	#7,LOCAL_EX(%a0)		|do neg
 472|
 473| Inst is fmove.  This code also handles all result writes.
 474| If bit 2 is set, round is forced to double.  If it is clear,
 475| and bit 6 is set, round is forced to single.  If both are clear,
 476| the round precision is found in the fpcr.  If the rounding precision
 477| is double or single, the result is zero, and the mode is checked
 478| to determine if the lsb of the result should be set.
 479|
 480cu_dmove:
 481	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 482	bne	cu_dmrd
 483	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 484	bne	cu_dmrs
 485|
 486| The move or operation is not with forced precision.  Use the
 487| FPCR_MODE byte to get rounding.
 488|
 489cu_dmnr:
 490	bfextu	FPCR_MODE(%a6){#0:#2},%d0
 491	tstb	%d0			|check for extended
 492	beq	cu_wrexd		|if so, just write result
 493	cmpib	#1,%d0			|check for single
 494	beq	cu_dmrs			|fall through to double
 495|
 496| The move is fdmove or round precision is double.  Result is zero.
 497| Check rmode for rp or rm and set lsb accordingly.
 498|
 499cu_dmrd:
 500	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 501	tstw	LOCAL_EX(%a0)		|check sign
 502	blts	cu_dmdn
 503	cmpib	#3,%d1			|check for rp
 504	bne	cu_dpd			|load double pos zero
 505	bra	cu_dpdr			|load double pos zero w/lsb
 506cu_dmdn:
 507	cmpib	#2,%d1			|check for rm
 508	bne	cu_dnd			|load double neg zero
 509	bra	cu_dndr			|load double neg zero w/lsb
 510|
 511| The move is fsmove or round precision is single.  Result is zero.
 512| Check for rp or rm and set lsb accordingly.
 513|
 514cu_dmrs:
 515	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 516	tstw	LOCAL_EX(%a0)		|check sign
 517	blts	cu_dmsn
 518	cmpib	#3,%d1			|check for rp
 519	bne	cu_spd			|load single pos zero
 520	bra	cu_spdr			|load single pos zero w/lsb
 521cu_dmsn:
 522	cmpib	#2,%d1			|check for rm
 523	bne	cu_snd			|load single neg zero
 524	bra	cu_sndr			|load single neg zero w/lsb
 525|
 526| The precision is extended, so the result in etemp is correct.
 527| Simply set unfl (not inex2 or aunfl) and write the result to
 528| the correct fp register.
 529cu_wrexd:
 530	orl	#unfl_mask,USER_FPSR(%a6)
 531	tstw	LOCAL_EX(%a0)
 532	beq	wr_etemp
 533	orl	#neg_mask,USER_FPSR(%a6)
 534	bra	wr_etemp
 535|
 536| These routines write +/- zero in double format.  The routines
 537| cu_dpdr and cu_dndr set the double lsb.
 538|
 539cu_dpd:
 540	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
 541	clrl	LOCAL_HI(%a0)
 542	clrl	LOCAL_LO(%a0)
 543	orl	#z_mask,USER_FPSR(%a6)
 544	orl	#unfinx_mask,USER_FPSR(%a6)
 545	bra	wr_etemp
 546cu_dpdr:
 547	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
 548	clrl	LOCAL_HI(%a0)
 549	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
 550	orl	#unfinx_mask,USER_FPSR(%a6)
 551	bra	wr_etemp
 552cu_dnd:
 553	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
 554	clrl	LOCAL_HI(%a0)
 555	clrl	LOCAL_LO(%a0)
 556	orl	#z_mask,USER_FPSR(%a6)
 557	orl	#neg_mask,USER_FPSR(%a6)
 558	orl	#unfinx_mask,USER_FPSR(%a6)
 559	bra	wr_etemp
 560cu_dndr:
 561	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
 562	clrl	LOCAL_HI(%a0)
 563	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
 564	orl	#neg_mask,USER_FPSR(%a6)
 565	orl	#unfinx_mask,USER_FPSR(%a6)
 566	bra	wr_etemp
 567|
 568| These routines write +/- zero in single format.  The routines
 569| cu_dpdr and cu_dndr set the single lsb.
 570|
 571cu_spd:
 572	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
 573	clrl	LOCAL_HI(%a0)
 574	clrl	LOCAL_LO(%a0)
 575	orl	#z_mask,USER_FPSR(%a6)
 576	orl	#unfinx_mask,USER_FPSR(%a6)
 577	bra	wr_etemp
 578cu_spdr:
 579	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
 580	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
 581	clrl	LOCAL_LO(%a0)
 582	orl	#unfinx_mask,USER_FPSR(%a6)
 583	bra	wr_etemp
 584cu_snd:
 585	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
 586	clrl	LOCAL_HI(%a0)
 587	clrl	LOCAL_LO(%a0)
 588	orl	#z_mask,USER_FPSR(%a6)
 589	orl	#neg_mask,USER_FPSR(%a6)
 590	orl	#unfinx_mask,USER_FPSR(%a6)
 591	bra	wr_etemp
 592cu_sndr:
 593	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
 594	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
 595	clrl	LOCAL_LO(%a0)
 596	orl	#neg_mask,USER_FPSR(%a6)
 597	orl	#unfinx_mask,USER_FPSR(%a6)
 598	bra	wr_etemp
 599
 600|
 601| This code checks for 16-bit overflow conditions on dyadic
 602| operations which are not restorable into the floating-point
 603| unit and must be completed in software.  Basically, this
 604| condition exists with a very large norm and a denorm.  One
 605| of the operands must be denormalized to enter this code.
 606|
 607| Flags used:
 608|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
 609|	DNRM_FLG contains $00 for neither op denormalized
 610|	                  $0f for the destination op denormalized
 611|	                  $f0 for the source op denormalized
 612|	                  $ff for both ops denormalized
 613|
 614| The wrap-around condition occurs for add, sub, div, and cmp
 615| when
 616|
 617|	abs(dest_exp - src_exp) >= $8000
 618|
 619| and for mul when
 620|
 621|	(dest_exp + src_exp) < $0
 622|
 623| we must process the operation here if this case is true.
 624|
 625| The rts following the frcfpn routine is the exit from res_func
 626| for this condition.  The restore flag (RES_FLG) is left clear.
 627| No frestore is done unless an exception is to be reported.
 628|
 629| For fadd:
 630|	if(sign_of(dest) != sign_of(src))
 631|		replace exponent of src with $3fff (keep sign)
 632|		use fpu to perform dest+new_src (user's rmode and X)
 633|		clr sticky
 634|	else
 635|		set sticky
 636|	call round with user's precision and mode
 637|	move result to fpn and wbtemp
 638|
 639| For fsub:
 640|	if(sign_of(dest) == sign_of(src))
 641|		replace exponent of src with $3fff (keep sign)
 642|		use fpu to perform dest+new_src (user's rmode and X)
 643|		clr sticky
 644|	else
 645|		set sticky
 646|	call round with user's precision and mode
 647|	move result to fpn and wbtemp
 648|
 649| For fdiv/fsgldiv:
 650|	if(both operands are denorm)
 651|		restore_to_fpu;
 652|	if(dest is norm)
 653|		force_ovf;
 654|	else(dest is denorm)
 655|		force_unf:
 656|
 657| For fcmp:
 658|	if(dest is norm)
 659|		N = sign_of(dest);
 660|	else(dest is denorm)
 661|		N = sign_of(src);
 662|
 663| For fmul:
 664|	if(both operands are denorm)
 665|		force_unf;
 666|	if((dest_exp + src_exp) < 0)
 667|		force_unf:
 668|	else
 669|		restore_to_fpu;
 670|
 671| local equates:
 672	.set	addcode,0x22
 673	.set	subcode,0x28
 674	.set	mulcode,0x23
 675	.set	divcode,0x20
 676	.set	cmpcode,0x38
 677ck_wrap:
 678	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
 679	beq	fix_stk		|if zero, it is fsqrt
 680	movew	CMDREG1B(%a6),%d0
 681	andiw	#0x3b,%d0		|strip to command bits
 682	cmpiw	#addcode,%d0
 683	beq	wrap_add
 684	cmpiw	#subcode,%d0
 685	beq	wrap_sub
 686	cmpiw	#mulcode,%d0
 687	beq	wrap_mul
 688	cmpiw	#cmpcode,%d0
 689	beq	wrap_cmp
 690|
 691| Inst is fdiv.
 692|
 693wrap_div:
 694	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 695	beq	fix_stk		 |restore to fpu
 696|
 697| One of the ops is denormalized.  Test for wrap condition
 698| and force the result.
 699|
 700	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 701	bnes	div_srcd
 702div_destd:
 703	bsrl	ckinf_ns
 704	bne	fix_stk
 705	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 706	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 707	subl	%d1,%d0			|subtract dest from src
 708	cmpl	#0x7fff,%d0
 709	blt	fix_stk			|if less, not wrap case
 710	clrb	WBTEMP_SGN(%a6)
 711	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
 712	movew	FPTEMP_EX(%a6),%d1
 713	eorw	%d1,%d0
 714	andiw	#0x8000,%d0
 715	beq	force_unf
 716	st	WBTEMP_SGN(%a6)
 717	bra	force_unf
 718
 719ckinf_ns:
 720	moveb	STAG(%a6),%d0		|check source tag for inf or nan
 721	bra	ck_in_com
 722ckinf_nd:
 723	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
 724ck_in_com:
 725	andib	#0x60,%d0			|isolate tag bits
 726	cmpb	#0x40,%d0			|is it inf?
 727	beq	nan_or_inf		|not wrap case
 728	cmpb	#0x60,%d0			|is it nan?
 729	beq	nan_or_inf		|yes, not wrap case?
 730	cmpb	#0x20,%d0			|is it a zero?
 731	beq	nan_or_inf		|yes
 732	clrl	%d0
 733	rts				|then ; it is either a zero of norm,
 734|					;check wrap case
 735nan_or_inf:
 736	moveql	#-1,%d0
 737	rts
 738
 739
 740
 741div_srcd:
 742	bsrl	ckinf_nd
 743	bne	fix_stk
 744	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 745	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 746	subl	%d1,%d0			|subtract src from dest
 747	cmpl	#0x8000,%d0
 748	blt	fix_stk			|if less, not wrap case
 749	clrb	WBTEMP_SGN(%a6)
 750	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
 751	movew	FPTEMP_EX(%a6),%d1
 752	eorw	%d1,%d0
 753	andiw	#0x8000,%d0
 754	beqs	force_ovf
 755	st	WBTEMP_SGN(%a6)
 756|
 757| This code handles the case of the instruction resulting in
 758| an overflow condition.
 759|
 760force_ovf:
 761	bclrb	#E1,E_BYTE(%a6)
 762	orl	#ovfl_inx_mask,USER_FPSR(%a6)
 763	clrw	NMNEXC(%a6)
 764	leal	WBTEMP(%a6),%a0		|point a0 to memory location
 765	movew	CMDREG1B(%a6),%d0
 766	btstl	#6,%d0			|test for forced precision
 767	beqs	frcovf_fpcr
 768	btstl	#2,%d0			|check for double
 769	bnes	frcovf_dbl
 770	movel	#0x1,%d0			|inst is forced single
 771	bras	frcovf_rnd
 772frcovf_dbl:
 773	movel	#0x2,%d0			|inst is forced double
 774	bras	frcovf_rnd
 775frcovf_fpcr:
 776	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
 777frcovf_rnd:
 778
 779| The 881/882 does not set inex2 for the following case, so the
 780| line is commented out to be compatible with 881/882
 781|	tst.b	%d0
 782|	beq.b	frcovf_x
 783|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
 784
 785|frcovf_x:
 786	bsrl	ovf_res			|get correct result based on
 787|					;round precision/mode.  This
 788|					;sets FPSR_CC correctly
 789|					;returns in external format
 790	bfclr	WBTEMP_SGN(%a6){#0:#8}
 791	beq	frcfpn
 792	bsetb	#sign_bit,WBTEMP_EX(%a6)
 793	bra	frcfpn
 794|
 795| Inst is fadd.
 796|
 797wrap_add:
 798	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 799	beq	fix_stk		 |restore to fpu
 800|
 801| One of the ops is denormalized.  Test for wrap condition
 802| and complete the instruction.
 803|
 804	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 805	bnes	add_srcd
 806add_destd:
 807	bsrl	ckinf_ns
 808	bne	fix_stk
 809	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 810	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 811	subl	%d1,%d0			|subtract dest from src
 812	cmpl	#0x8000,%d0
 813	blt	fix_stk			|if less, not wrap case
 814	bra	add_wrap
 815add_srcd:
 816	bsrl	ckinf_nd
 817	bne	fix_stk
 818	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 819	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 820	subl	%d1,%d0			|subtract src from dest
 821	cmpl	#0x8000,%d0
 822	blt	fix_stk			|if less, not wrap case
 823|
 824| Check the signs of the operands.  If they are unlike, the fpu
 825| can be used to add the norm and 1.0 with the sign of the
 826| denorm and it will correctly generate the result in extended
 827| precision.  We can then call round with no sticky and the result
 828| will be correct for the user's rounding mode and precision.  If
 829| the signs are the same, we call round with the sticky bit set
 830| and the result will be correct for the user's rounding mode and
 831| precision.
 832|
 833add_wrap:
 834	movew	ETEMP_EX(%a6),%d0
 835	movew	FPTEMP_EX(%a6),%d1
 836	eorw	%d1,%d0
 837	andiw	#0x8000,%d0
 838	beq	add_same
 839|
 840| The signs are unlike.
 841|
 842	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
 843	bnes	add_u_srcd
 844	movew	FPTEMP_EX(%a6),%d0
 845	andiw	#0x8000,%d0
 846	orw	#0x3fff,%d0	|force the exponent to +/- 1
 847	movew	%d0,FPTEMP_EX(%a6) |in the denorm
 848	movel	USER_FPCR(%a6),%d0
 849	andil	#0x30,%d0
 850	fmovel	%d0,%fpcr		|set up users rmode and X
 851	fmovex	ETEMP(%a6),%fp0
 852	faddx	FPTEMP(%a6),%fp0
 853	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
 854	fmovel	%fpsr,%d1
 855	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
 856	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
 857	lsrl	#4,%d0		|put rmode in lower 2 bits
 858	movel	USER_FPCR(%a6),%d1
 859	andil	#0xc0,%d1
 860	lsrl	#6,%d1		|put precision in upper word
 861	swap	%d1
 862	orl	%d0,%d1		|set up for round call
 863	clrl	%d0		|force sticky to zero
 864	bclrb	#sign_bit,WBTEMP_EX(%a6)
 865	sne	WBTEMP_SGN(%a6)
 866	bsrl	round		|round result to users rmode & prec
 867	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 868	beq	frcfpnr
 869	bsetb	#sign_bit,WBTEMP_EX(%a6)
 870	bra	frcfpnr
 871add_u_srcd:
 872	movew	ETEMP_EX(%a6),%d0
 873	andiw	#0x8000,%d0
 874	orw	#0x3fff,%d0	|force the exponent to +/- 1
 875	movew	%d0,ETEMP_EX(%a6) |in the denorm
 876	movel	USER_FPCR(%a6),%d0
 877	andil	#0x30,%d0
 878	fmovel	%d0,%fpcr		|set up users rmode and X
 879	fmovex	ETEMP(%a6),%fp0
 880	faddx	FPTEMP(%a6),%fp0
 881	fmovel	%fpsr,%d1
 882	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
 883	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
 884	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
 885	lsrl	#4,%d0		|put rmode in lower 2 bits
 886	movel	USER_FPCR(%a6),%d1
 887	andil	#0xc0,%d1
 888	lsrl	#6,%d1		|put precision in upper word
 889	swap	%d1
 890	orl	%d0,%d1		|set up for round call
 891	clrl	%d0		|force sticky to zero
 892	bclrb	#sign_bit,WBTEMP_EX(%a6)
 893	sne	WBTEMP_SGN(%a6)	|use internal format for round
 894	bsrl	round		|round result to users rmode & prec
 895	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 896	beq	frcfpnr
 897	bsetb	#sign_bit,WBTEMP_EX(%a6)
 898	bra	frcfpnr
 899|
 900| Signs are alike:
 901|
 902add_same:
 903	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
 904	bnes	add_s_srcd
 905add_s_destd:
 906	leal	ETEMP(%a6),%a0
 907	movel	USER_FPCR(%a6),%d0
 908	andil	#0x30,%d0
 909	lsrl	#4,%d0		|put rmode in lower 2 bits
 910	movel	USER_FPCR(%a6),%d1
 911	andil	#0xc0,%d1
 912	lsrl	#6,%d1		|put precision in upper word
 913	swap	%d1
 914	orl	%d0,%d1		|set up for round call
 915	movel	#0x20000000,%d0	|set sticky for round
 916	bclrb	#sign_bit,ETEMP_EX(%a6)
 917	sne	ETEMP_SGN(%a6)
 918	bsrl	round		|round result to users rmode & prec
 919	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 920	beqs	add_s_dclr
 921	bsetb	#sign_bit,ETEMP_EX(%a6)
 922add_s_dclr:
 923	leal	WBTEMP(%a6),%a0
 924	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
 925	movel	ETEMP_HI(%a6),4(%a0)
 926	movel	ETEMP_LO(%a6),8(%a0)
 927	tstw	ETEMP_EX(%a6)
 928	bgt	add_ckovf
 929	orl	#neg_mask,USER_FPSR(%a6)
 930	bra	add_ckovf
 931add_s_srcd:
 932	leal	FPTEMP(%a6),%a0
 933	movel	USER_FPCR(%a6),%d0
 934	andil	#0x30,%d0
 935	lsrl	#4,%d0		|put rmode in lower 2 bits
 936	movel	USER_FPCR(%a6),%d1
 937	andil	#0xc0,%d1
 938	lsrl	#6,%d1		|put precision in upper word
 939	swap	%d1
 940	orl	%d0,%d1		|set up for round call
 941	movel	#0x20000000,%d0	|set sticky for round
 942	bclrb	#sign_bit,FPTEMP_EX(%a6)
 943	sne	FPTEMP_SGN(%a6)
 944	bsrl	round		|round result to users rmode & prec
 945	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 946	beqs	add_s_sclr
 947	bsetb	#sign_bit,FPTEMP_EX(%a6)
 948add_s_sclr:
 949	leal	WBTEMP(%a6),%a0
 950	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
 951	movel	FPTEMP_HI(%a6),4(%a0)
 952	movel	FPTEMP_LO(%a6),8(%a0)
 953	tstw	FPTEMP_EX(%a6)
 954	bgt	add_ckovf
 955	orl	#neg_mask,USER_FPSR(%a6)
 956add_ckovf:
 957	movew	WBTEMP_EX(%a6),%d0
 958	andiw	#0x7fff,%d0
 959	cmpiw	#0x7fff,%d0
 960	bne	frcfpnr
 961|
 962| The result has overflowed to $7fff exponent.  Set I, ovfl,
 963| and aovfl, and clr the mantissa (incorrectly set by the
 964| round routine.)
 965|
 966	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
 967	clrl	4(%a0)
 968	bra	frcfpnr
 969|
 970| Inst is fsub.
 971|
 972wrap_sub:
 973	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 974	beq	fix_stk		 |restore to fpu
 975|
 976| One of the ops is denormalized.  Test for wrap condition
 977| and complete the instruction.
 978|
 979	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 980	bnes	sub_srcd
 981sub_destd:
 982	bsrl	ckinf_ns
 983	bne	fix_stk
 984	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 985	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 986	subl	%d1,%d0			|subtract src from dest
 987	cmpl	#0x8000,%d0
 988	blt	fix_stk			|if less, not wrap case
 989	bra	sub_wrap
 990sub_srcd:
 991	bsrl	ckinf_nd
 992	bne	fix_stk
 993	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 994	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 995	subl	%d1,%d0			|subtract dest from src
 996	cmpl	#0x8000,%d0
 997	blt	fix_stk			|if less, not wrap case
 998|
 999| Check the signs of the operands.  If they are alike, the fpu
1000| can be used to subtract from the norm 1.0 with the sign of the
1001| denorm and it will correctly generate the result in extended
1002| precision.  We can then call round with no sticky and the result
1003| will be correct for the user's rounding mode and precision.  If
1004| the signs are unlike, we call round with the sticky bit set
1005| and the result will be correct for the user's rounding mode and
1006| precision.
1007|
1008sub_wrap:
1009	movew	ETEMP_EX(%a6),%d0
1010	movew	FPTEMP_EX(%a6),%d1
1011	eorw	%d1,%d0
1012	andiw	#0x8000,%d0
1013	bne	sub_diff
1014|
1015| The signs are alike.
1016|
1017	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
1018	bnes	sub_u_srcd
1019	movew	FPTEMP_EX(%a6),%d0
1020	andiw	#0x8000,%d0
1021	orw	#0x3fff,%d0	|force the exponent to +/- 1
1022	movew	%d0,FPTEMP_EX(%a6) |in the denorm
1023	movel	USER_FPCR(%a6),%d0
1024	andil	#0x30,%d0
1025	fmovel	%d0,%fpcr		|set up users rmode and X
1026	fmovex	FPTEMP(%a6),%fp0
1027	fsubx	ETEMP(%a6),%fp0
1028	fmovel	%fpsr,%d1
1029	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1030	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
1031	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
1032	lsrl	#4,%d0		|put rmode in lower 2 bits
1033	movel	USER_FPCR(%a6),%d1
1034	andil	#0xc0,%d1
1035	lsrl	#6,%d1		|put precision in upper word
1036	swap	%d1
1037	orl	%d0,%d1		|set up for round call
1038	clrl	%d0		|force sticky to zero
1039	bclrb	#sign_bit,WBTEMP_EX(%a6)
1040	sne	WBTEMP_SGN(%a6)
1041	bsrl	round		|round result to users rmode & prec
1042	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1043	beq	frcfpnr
1044	bsetb	#sign_bit,WBTEMP_EX(%a6)
1045	bra	frcfpnr
1046sub_u_srcd:
1047	movew	ETEMP_EX(%a6),%d0
1048	andiw	#0x8000,%d0
1049	orw	#0x3fff,%d0	|force the exponent to +/- 1
1050	movew	%d0,ETEMP_EX(%a6) |in the denorm
1051	movel	USER_FPCR(%a6),%d0
1052	andil	#0x30,%d0
1053	fmovel	%d0,%fpcr		|set up users rmode and X
1054	fmovex	FPTEMP(%a6),%fp0
1055	fsubx	ETEMP(%a6),%fp0
1056	fmovel	%fpsr,%d1
1057	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1058	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
1059	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
1060	lsrl	#4,%d0		|put rmode in lower 2 bits
1061	movel	USER_FPCR(%a6),%d1
1062	andil	#0xc0,%d1
1063	lsrl	#6,%d1		|put precision in upper word
1064	swap	%d1
1065	orl	%d0,%d1		|set up for round call
1066	clrl	%d0		|force sticky to zero
1067	bclrb	#sign_bit,WBTEMP_EX(%a6)
1068	sne	WBTEMP_SGN(%a6)
1069	bsrl	round		|round result to users rmode & prec
1070	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1071	beq	frcfpnr
1072	bsetb	#sign_bit,WBTEMP_EX(%a6)
1073	bra	frcfpnr
1074|
1075| Signs are unlike:
1076|
1077sub_diff:
1078	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
1079	bnes	sub_s_srcd
1080sub_s_destd:
1081	leal	ETEMP(%a6),%a0
1082	movel	USER_FPCR(%a6),%d0
1083	andil	#0x30,%d0
1084	lsrl	#4,%d0		|put rmode in lower 2 bits
1085	movel	USER_FPCR(%a6),%d1
1086	andil	#0xc0,%d1
1087	lsrl	#6,%d1		|put precision in upper word
1088	swap	%d1
1089	orl	%d0,%d1		|set up for round call
1090	movel	#0x20000000,%d0	|set sticky for round
1091|
1092| Since the dest is the denorm, the sign is the opposite of the
1093| norm sign.
1094|
1095	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
1096	tstw	ETEMP_EX(%a6)
1097	bgts	sub_s_dwr
1098	orl	#neg_mask,USER_FPSR(%a6)
1099sub_s_dwr:
1100	bclrb	#sign_bit,ETEMP_EX(%a6)
1101	sne	ETEMP_SGN(%a6)
1102	bsrl	round		|round result to users rmode & prec
1103	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1104	beqs	sub_s_dclr
1105	bsetb	#sign_bit,ETEMP_EX(%a6)
1106sub_s_dclr:
1107	leal	WBTEMP(%a6),%a0
1108	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
1109	movel	ETEMP_HI(%a6),4(%a0)
1110	movel	ETEMP_LO(%a6),8(%a0)
1111	bra	sub_ckovf
1112sub_s_srcd:
1113	leal	FPTEMP(%a6),%a0
1114	movel	USER_FPCR(%a6),%d0
1115	andil	#0x30,%d0
1116	lsrl	#4,%d0		|put rmode in lower 2 bits
1117	movel	USER_FPCR(%a6),%d1
1118	andil	#0xc0,%d1
1119	lsrl	#6,%d1		|put precision in upper word
1120	swap	%d1
1121	orl	%d0,%d1		|set up for round call
1122	movel	#0x20000000,%d0	|set sticky for round
1123	bclrb	#sign_bit,FPTEMP_EX(%a6)
1124	sne	FPTEMP_SGN(%a6)
1125	bsrl	round		|round result to users rmode & prec
1126	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1127	beqs	sub_s_sclr
1128	bsetb	#sign_bit,FPTEMP_EX(%a6)
1129sub_s_sclr:
1130	leal	WBTEMP(%a6),%a0
1131	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
1132	movel	FPTEMP_HI(%a6),4(%a0)
1133	movel	FPTEMP_LO(%a6),8(%a0)
1134	tstw	FPTEMP_EX(%a6)
1135	bgt	sub_ckovf
1136	orl	#neg_mask,USER_FPSR(%a6)
1137sub_ckovf:
1138	movew	WBTEMP_EX(%a6),%d0
1139	andiw	#0x7fff,%d0
1140	cmpiw	#0x7fff,%d0
1141	bne	frcfpnr
1142|
1143| The result has overflowed to $7fff exponent.  Set I, ovfl,
1144| and aovfl, and clr the mantissa (incorrectly set by the
1145| round routine.)
1146|
1147	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1148	clrl	4(%a0)
1149	bra	frcfpnr
1150|
1151| Inst is fcmp.
1152|
1153wrap_cmp:
1154	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
1155	beq	fix_stk		 |restore to fpu
1156|
1157| One of the ops is denormalized.  Test for wrap condition
1158| and complete the instruction.
1159|
1160	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
1161	bnes	cmp_srcd
1162cmp_destd:
1163	bsrl	ckinf_ns
1164	bne	fix_stk
1165	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
1166	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
1167	subl	%d1,%d0			|subtract dest from src
1168	cmpl	#0x8000,%d0
1169	blt	fix_stk			|if less, not wrap case
1170	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
1171	bge	cmp_setn
1172	rts
1173cmp_srcd:
1174	bsrl	ckinf_nd
1175	bne	fix_stk
1176	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
1177	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
1178	subl	%d1,%d0			|subtract src from dest
1179	cmpl	#0x8000,%d0
1180	blt	fix_stk			|if less, not wrap case
1181	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
1182	blt	cmp_setn
1183	rts
1184cmp_setn:
1185	orl	#neg_mask,USER_FPSR(%a6)
1186	rts
1187
1188|
1189| Inst is fmul.
1190|
1191wrap_mul:
1192	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
1193	beq	force_unf	|force an underflow (really!)
1194|
1195| One of the ops is denormalized.  Test for wrap condition
1196| and complete the instruction.
1197|
1198	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
1199	bnes	mul_srcd
1200mul_destd:
1201	bsrl	ckinf_ns
1202	bne	fix_stk
1203	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
1204	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
1205	addl	%d1,%d0			|subtract dest from src
1206	bgt	fix_stk
1207	bra	force_unf
1208mul_srcd:
1209	bsrl	ckinf_nd
1210	bne	fix_stk
1211	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
1212	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
1213	addl	%d1,%d0			|subtract src from dest
1214	bgt	fix_stk
1215
1216|
1217| This code handles the case of the instruction resulting in
1218| an underflow condition.
1219|
1220force_unf:
1221	bclrb	#E1,E_BYTE(%a6)
1222	orl	#unfinx_mask,USER_FPSR(%a6)
1223	clrw	NMNEXC(%a6)
1224	clrb	WBTEMP_SGN(%a6)
1225	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
1226	movew	FPTEMP_EX(%a6),%d1
1227	eorw	%d1,%d0
1228	andiw	#0x8000,%d0
1229	beqs	frcunfcont
1230	st	WBTEMP_SGN(%a6)
1231frcunfcont:
1232	lea	WBTEMP(%a6),%a0		|point a0 to memory location
1233	movew	CMDREG1B(%a6),%d0
1234	btstl	#6,%d0			|test for forced precision
1235	beqs	frcunf_fpcr
1236	btstl	#2,%d0			|check for double
1237	bnes	frcunf_dbl
1238	movel	#0x1,%d0			|inst is forced single
1239	bras	frcunf_rnd
1240frcunf_dbl:
1241	movel	#0x2,%d0			|inst is forced double
1242	bras	frcunf_rnd
1243frcunf_fpcr:
1244	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
1245frcunf_rnd:
1246	bsrl	unf_sub			|get correct result based on
1247|					;round precision/mode.  This
1248|					;sets FPSR_CC correctly
1249	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1250	beqs	frcfpn
1251	bsetb	#sign_bit,WBTEMP_EX(%a6)
1252	bra	frcfpn
1253
1254|
1255| Write the result to the user's fpn.  All results must be HUGE to be
1256| written; otherwise the results would have overflowed or underflowed.
1257| If the rounding precision is single or double, the ovf_res routine
1258| is needed to correctly supply the max value.
1259|
1260frcfpnr:
1261	movew	CMDREG1B(%a6),%d0
1262	btstl	#6,%d0			|test for forced precision
1263	beqs	frcfpn_fpcr
1264	btstl	#2,%d0			|check for double
1265	bnes	frcfpn_dbl
1266	movel	#0x1,%d0			|inst is forced single
1267	bras	frcfpn_rnd
1268frcfpn_dbl:
1269	movel	#0x2,%d0			|inst is forced double
1270	bras	frcfpn_rnd
1271frcfpn_fpcr:
1272	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
1273	tstb	%d0
1274	beqs	frcfpn			|if extended, write what you got
1275frcfpn_rnd:
1276	bclrb	#sign_bit,WBTEMP_EX(%a6)
1277	sne	WBTEMP_SGN(%a6)
1278	bsrl	ovf_res			|get correct result based on
1279|					;round precision/mode.  This
1280|					;sets FPSR_CC correctly
1281	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1282	beqs	frcfpn_clr
1283	bsetb	#sign_bit,WBTEMP_EX(%a6)
1284frcfpn_clr:
1285	orl	#ovfinx_mask,USER_FPSR(%a6)
1286|
1287| Perform the write.
1288|
1289frcfpn:
1290	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
1291	cmpib	#3,%d0
1292	bles	frc0123			|check if dest is fp0-fp3
1293	movel	#7,%d1
1294	subl	%d0,%d1
1295	clrl	%d0
1296	bsetl	%d1,%d0
1297	fmovemx WBTEMP(%a6),%d0
1298	rts
1299frc0123:
1300	cmpib	#0,%d0
1301	beqs	frc0_dst
1302	cmpib	#1,%d0
1303	beqs	frc1_dst
1304	cmpib	#2,%d0
1305	beqs	frc2_dst
1306frc3_dst:
1307	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
1308	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
1309	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
1310	rts
1311frc2_dst:
1312	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
1313	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
1314	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
1315	rts
1316frc1_dst:
1317	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
1318	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
1319	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
1320	rts
1321frc0_dst:
1322	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
1323	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
1324	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
1325	rts
1326
1327|
1328| Write etemp to fpn.
1329| A check is made on enabled and signalled snan exceptions,
1330| and the destination is not overwritten if this condition exists.
1331| This code is designed to make fmoveins of unsupported data types
1332| faster.
1333|
1334wr_etemp:
1335	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
1336	beqs	fmoveinc		|enabled, force restore
1337	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
1338	beqs	fmoveinc		|the dest
1339	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1340|						;snan handler
1341	tstb	ETEMP(%a6)		|check for negative
1342	blts	snan_neg
1343	rts
1344snan_neg:
1345	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
1346	rts
1347fmoveinc:
1348	clrw	NMNEXC(%a6)
1349	bclrb	#E1,E_BYTE(%a6)
1350	moveb	STAG(%a6),%d0		|check if stag is inf
1351	andib	#0xe0,%d0
1352	cmpib	#0x40,%d0
1353	bnes	fminc_cnan
1354	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1355	tstw	LOCAL_EX(%a0)		|check sign
1356	bges	fminc_con
1357	orl	#neg_mask,USER_FPSR(%a6)
1358	bra	fminc_con
1359fminc_cnan:
1360	cmpib	#0x60,%d0			|check if stag is NaN
1361	bnes	fminc_czero
1362	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
1363	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1364|						;snan handler
1365	tstw	LOCAL_EX(%a0)		|check sign
1366	bges	fminc_con
1367	orl	#neg_mask,USER_FPSR(%a6)
1368	bra	fminc_con
1369fminc_czero:
1370	cmpib	#0x20,%d0			|check if zero
1371	bnes	fminc_con
1372	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
1373	tstw	LOCAL_EX(%a0)		|check sign
1374	bges	fminc_con
1375	orl	#neg_mask,USER_FPSR(%a6)
1376fminc_con:
1377	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
1378	cmpib	#3,%d0
1379	bles	fp0123			|check if dest is fp0-fp3
1380	movel	#7,%d1
1381	subl	%d0,%d1
1382	clrl	%d0
1383	bsetl	%d1,%d0
1384	fmovemx ETEMP(%a6),%d0
1385	rts
1386
1387fp0123:
1388	cmpib	#0,%d0
1389	beqs	fp0_dst
1390	cmpib	#1,%d0
1391	beqs	fp1_dst
1392	cmpib	#2,%d0
1393	beqs	fp2_dst
1394fp3_dst:
1395	movel	ETEMP_EX(%a6),USER_FP3(%a6)
1396	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
1397	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
1398	rts
1399fp2_dst:
1400	movel	ETEMP_EX(%a6),USER_FP2(%a6)
1401	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
1402	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
1403	rts
1404fp1_dst:
1405	movel	ETEMP_EX(%a6),USER_FP1(%a6)
1406	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
1407	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
1408	rts
1409fp0_dst:
1410	movel	ETEMP_EX(%a6),USER_FP0(%a6)
1411	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
1412	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
1413	rts
1414
1415opclass3:
1416	st	CU_ONLY(%a6)
1417	movew	CMDREG1B(%a6),%d0	|check if packed moveout
1418	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
1419	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
1420	beq	pack_out	|else it is norm or denorm
1421	bra	mv_out
1422
1423
1424|
1425|	MOVE OUT
1426|
1427
1428mv_tbl:
1429	.long	li
1430	.long	sgp
1431	.long	xp
1432	.long	mvout_end	|should never be taken
1433	.long	wi
1434	.long	dp
1435	.long	bi
1436	.long	mvout_end	|should never be taken
1437mv_out:
1438	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
1439	leal	mv_tbl,%a0
1440	movel	%a0@(%d1:l:4),%a0
1441	jmp	(%a0)
1442
1443|
1444| This exit is for move-out to memory.  The aunfl bit is
1445| set if the result is inex and unfl is signalled.
1446|
1447mvout_end:
1448	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
1449	beqs	no_aufl
1450	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
1451	beqs	no_aufl
1452	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
1453no_aufl:
1454	clrw	NMNEXC(%a6)
1455	bclrb	#E1,E_BYTE(%a6)
1456	fmovel	#0,%FPSR			|clear any cc bits from res_func
1457|
1458| Return ETEMP to extended format from internal extended format so
1459| that gen_except will have a correctly signed value for ovfl/unfl
1460| handlers.
1461|
1462	bfclr	ETEMP_SGN(%a6){#0:#8}
1463	beqs	mvout_con
1464	bsetb	#sign_bit,ETEMP_EX(%a6)
1465mvout_con:
1466	rts
1467|
1468| This exit is for move-out to int register.  The aunfl bit is
1469| not set in any case for this move.
1470|
1471mvouti_end:
1472	clrw	NMNEXC(%a6)
1473	bclrb	#E1,E_BYTE(%a6)
1474	fmovel	#0,%FPSR			|clear any cc bits from res_func
1475|
1476| Return ETEMP to extended format from internal extended format so
1477| that gen_except will have a correctly signed value for ovfl/unfl
1478| handlers.
1479|
1480	bfclr	ETEMP_SGN(%a6){#0:#8}
1481	beqs	mvouti_con
1482	bsetb	#sign_bit,ETEMP_EX(%a6)
1483mvouti_con:
1484	rts
1485|
1486| li is used to handle a long integer source specifier
1487|
1488
1489li:
1490	moveql	#4,%d0		|set byte count
1491
1492	btstb	#7,STAG(%a6)	|check for extended denorm
1493	bne	int_dnrm	|if so, branch
1494
1495	fmovemx ETEMP(%a6),%fp0-%fp0
1496	fcmpd	#0x41dfffffffc00000,%fp0
1497| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1498	fbge	lo_plrg
1499	fcmpd	#0xc1e0000000000000,%fp0
1500| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1501	fble	lo_nlrg
1502|
1503| at this point, the answer is between the largest pos and neg values
1504|
1505	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1506	andil	#0x30,%d1
1507	fmovel	%d1,%fpcr
1508	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1509	fmovel %fpsr,%d1
1510	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1511	bra	int_wrt
1512
1513
1514lo_plrg:
1515	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
1516	fbeq	int_wrt			|exact answer
1517	fcmpd	#0x41dfffffffe00000,%fp0
1518| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1519	fbge	int_operr		|set operr
1520	bra	int_inx			|set inexact
1521
1522lo_nlrg:
1523	movel	#0x80000000,L_SCR1(%a6)
1524	fbeq	int_wrt			|exact answer
1525	fcmpd	#0xc1e0000000100000,%fp0
1526| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1527	fblt	int_operr		|set operr
1528	bra	int_inx			|set inexact
1529
1530|
1531| wi is used to handle a word integer source specifier
1532|
1533
1534wi:
1535	moveql	#2,%d0		|set byte count
1536
1537	btstb	#7,STAG(%a6)	|check for extended denorm
1538	bne	int_dnrm	|branch if so
1539
1540	fmovemx ETEMP(%a6),%fp0-%fp0
1541	fcmps	#0x46fffe00,%fp0
1542| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1543	fbge	wo_plrg
1544	fcmps	#0xc7000000,%fp0
1545| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1546	fble	wo_nlrg
1547
1548|
1549| at this point, the answer is between the largest pos and neg values
1550|
1551	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1552	andil	#0x30,%d1
1553	fmovel	%d1,%fpcr
1554	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1555	fmovel %fpsr,%d1
1556	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1557	bra	int_wrt
1558
1559wo_plrg:
1560	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
1561	fbeq	int_wrt			|exact answer
1562	fcmps	#0x46ffff00,%fp0
1563| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1564	fbge	int_operr		|set operr
1565	bra	int_inx			|set inexact
1566
1567wo_nlrg:
1568	movew	#0x8000,L_SCR1(%a6)
1569	fbeq	int_wrt			|exact answer
1570	fcmps	#0xc7000080,%fp0
1571| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1572	fblt	int_operr		|set operr
1573	bra	int_inx			|set inexact
1574
1575|
1576| bi is used to handle a byte integer source specifier
1577|
1578
1579bi:
1580	moveql	#1,%d0		|set byte count
1581
1582	btstb	#7,STAG(%a6)	|check for extended denorm
1583	bne	int_dnrm	|branch if so
1584
1585	fmovemx ETEMP(%a6),%fp0-%fp0
1586	fcmps	#0x42fe0000,%fp0
1587| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1588	fbge	by_plrg
1589	fcmps	#0xc3000000,%fp0
1590| c3000000 in sgl prec = c00600008000000000000000 in ext prec
1591	fble	by_nlrg
1592
1593|
1594| at this point, the answer is between the largest pos and neg values
1595|
1596	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1597	andil	#0x30,%d1
1598	fmovel	%d1,%fpcr
1599	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1600	fmovel %fpsr,%d1
1601	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1602	bra	int_wrt
1603
1604by_plrg:
1605	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
1606	fbeq	int_wrt			|exact answer
1607	fcmps	#0x42ff0000,%fp0
1608| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1609	fbge	int_operr		|set operr
1610	bra	int_inx			|set inexact
1611
1612by_nlrg:
1613	moveb	#0x80,L_SCR1(%a6)
1614	fbeq	int_wrt			|exact answer
1615	fcmps	#0xc3008000,%fp0
1616| c3008000 in sgl prec = c00600008080000000000000 in ext prec
1617	fblt	int_operr		|set operr
1618	bra	int_inx			|set inexact
1619
1620|
1621| Common integer routines
1622|
1623| int_drnrm---account for possible nonzero result for round up with positive
1624| operand and round down for negative answer.  In the first case (result = 1)
1625| byte-width (store in d0) of result must be honored.  In the second case,
1626| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1627
1628int_dnrm:
1629	movel	#0,L_SCR1(%a6)	| initialize result to 0
1630	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
1631	cmpb	#2,%d1
1632	bmis	int_inx		| if RN or RZ, done
1633	bnes	int_rp		| if RP, continue below
1634	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
1635	bpls	int_inx		| otherwise result is 0
1636	movel	#-1,L_SCR1(%a6)
1637	bras	int_inx
1638int_rp:
1639	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
1640|				; source is greater than 0
1641	bmis	int_inx		| otherwise, result is 0
1642	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
1643	addal	%d0,%a1		| offset by destination width -1
1644	subal	#1,%a1
1645	bsetb	#0,(%a1)		| set low bit at a1 address
1646int_inx:
1647	oril	#inx2a_mask,USER_FPSR(%a6)
1648	bras	int_wrt
1649int_operr:
1650	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
1651|				;precision source that needs to be
1652|				;converted to integer this is required
1653|				;if the operr exception is enabled.
1654|				;set operr/aiop (no inex2 on int ovfl)
1655
1656	oril	#opaop_mask,USER_FPSR(%a6)
1657|				;fall through to perform int_wrt
1658int_wrt:
1659	movel	EXC_EA(%a6),%a1	|load destination address
1660	tstl	%a1		|check to see if it is a dest register
1661	beqs	wrt_dn		|write data register
1662	lea	L_SCR1(%a6),%a0	|point to supervisor source address
1663	bsrl	mem_write
1664	bra	mvouti_end
1665
1666wrt_dn:
1667	movel	%d0,-(%sp)	|d0 currently contains the size to write
1668	bsrl	get_fline	|get_fline returns Dn in d0
1669	andiw	#0x7,%d0		|isolate register
1670	movel	(%sp)+,%d1	|get size
1671	cmpil	#4,%d1		|most frequent case
1672	beqs	sz_long
1673	cmpil	#2,%d1
1674	bnes	sz_con
1675	orl	#8,%d0		|add 'word' size to register#
1676	bras	sz_con
1677sz_long:
1678	orl	#0x10,%d0		|add 'long' size to register#
1679sz_con:
1680	movel	%d0,%d1		|reg_dest expects size:reg in d1
1681	bsrl	reg_dest	|load proper data register
1682	bra	mvouti_end
1683xp:
1684	lea	ETEMP(%a6),%a0
1685	bclrb	#sign_bit,LOCAL_EX(%a0)
1686	sne	LOCAL_SGN(%a0)
1687	btstb	#7,STAG(%a6)	|check for extended denorm
1688	bne	xdnrm
1689	clrl	%d0
1690	bras	do_fp		|do normal case
1691sgp:
1692	lea	ETEMP(%a6),%a0
1693	bclrb	#sign_bit,LOCAL_EX(%a0)
1694	sne	LOCAL_SGN(%a0)
1695	btstb	#7,STAG(%a6)	|check for extended denorm
1696	bne	sp_catas	|branch if so
1697	movew	LOCAL_EX(%a0),%d0
1698	lea	sp_bnds,%a1
1699	cmpw	(%a1),%d0
1700	blt	sp_under
1701	cmpw	2(%a1),%d0
1702	bgt	sp_over
1703	movel	#1,%d0		|set destination format to single
1704	bras	do_fp		|do normal case
1705dp:
1706	lea	ETEMP(%a6),%a0
1707	bclrb	#sign_bit,LOCAL_EX(%a0)
1708	sne	LOCAL_SGN(%a0)
1709
1710	btstb	#7,STAG(%a6)	|check for extended denorm
1711	bne	dp_catas	|branch if so
1712
1713	movew	LOCAL_EX(%a0),%d0
1714	lea	dp_bnds,%a1
1715
1716	cmpw	(%a1),%d0
1717	blt	dp_under
1718	cmpw	2(%a1),%d0
1719	bgt	dp_over
1720
1721	movel	#2,%d0		|set destination format to double
1722|				;fall through to do_fp
1723|
1724do_fp:
1725	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
1726	swap	%d0			|rnd prec in upper word
1727	addl	%d0,%d1			|d1 has PREC/MODE info
1728
1729	clrl	%d0			|clear g,r,s
1730
1731	bsrl	round			|round
1732
1733	movel	%a0,%a1
1734	movel	EXC_EA(%a6),%a0
1735
1736	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
1737|					;at this point only the dest
1738|					;formats sgl, dbl, ext are
1739|					;possible
1740	cmpb	#2,%d1
1741	bgts	ddbl			|double=5, extended=2, single=1
1742	bnes	dsgl
1743|					;fall through to dext
1744dext:
1745	bsrl	dest_ext
1746	bra	mvout_end
1747dsgl:
1748	bsrl	dest_sgl
1749	bra	mvout_end
1750ddbl:
1751	bsrl	dest_dbl
1752	bra	mvout_end
1753
1754|
1755| Handle possible denorm or catastrophic underflow cases here
1756|
1757xdnrm:
1758	bsr	set_xop		|initialize WBTEMP
1759	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
1760
1761	movel	%a0,%a1
1762	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1763	bsrl	dest_ext	|store to memory
1764	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1765	bra	mvout_end
1766
1767sp_under:
1768	bsetb	#etemp15_bit,STAG(%a6)
1769
1770	cmpw	4(%a1),%d0
1771	blts	sp_catas	|catastrophic underflow case
1772
1773	movel	#1,%d0		|load in round precision
1774	movel	#sgl_thresh,%d1	|load in single denorm threshold
1775	bsrl	dpspdnrm	|expects d1 to have the proper
1776|				;denorm threshold
1777	bsrl	dest_sgl	|stores value to destination
1778	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1779	bra	mvout_end	|exit
1780
1781dp_under:
1782	bsetb	#etemp15_bit,STAG(%a6)
1783
1784	cmpw	4(%a1),%d0
1785	blts	dp_catas	|catastrophic underflow case
1786
1787	movel	#dbl_thresh,%d1	|load in double precision threshold
1788	movel	#2,%d0
1789	bsrl	dpspdnrm	|expects d1 to have proper
1790|				;denorm threshold
1791|				;expects d0 to have round precision
1792	bsrl	dest_dbl	|store value to destination
1793	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1794	bra	mvout_end	|exit
1795
1796|
1797| Handle catastrophic underflow cases here
1798|
1799sp_catas:
1800| Temp fix for z bit set in unf_sub
1801	movel	USER_FPSR(%a6),-(%a7)
1802
1803	movel	#1,%d0		|set round precision to sgl
1804
1805	bsrl	unf_sub		|a0 points to result
1806
1807	movel	(%a7)+,USER_FPSR(%a6)
1808
1809	movel	#1,%d0
1810	subw	%d0,LOCAL_EX(%a0) |account for difference between
1811|				;denorm/norm bias
1812
1813	movel	%a0,%a1		|a1 has the operand input
1814	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1815
1816	bsrl	dest_sgl	|store the result
1817	oril	#unfinx_mask,USER_FPSR(%a6)
1818	bra	mvout_end
1819
1820dp_catas:
1821| Temp fix for z bit set in unf_sub
1822	movel	USER_FPSR(%a6),-(%a7)
1823
1824	movel	#2,%d0		|set round precision to dbl
1825	bsrl	unf_sub		|a0 points to result
1826
1827	movel	(%a7)+,USER_FPSR(%a6)
1828
1829	movel	#1,%d0
1830	subw	%d0,LOCAL_EX(%a0) |account for difference between
1831|				;denorm/norm bias
1832
1833	movel	%a0,%a1		|a1 has the operand input
1834	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1835
1836	bsrl	dest_dbl	|store the result
1837	oril	#unfinx_mask,USER_FPSR(%a6)
1838	bra	mvout_end
1839
1840|
1841| Handle catastrophic overflow cases here
1842|
1843sp_over:
1844| Temp fix for z bit set in unf_sub
1845	movel	USER_FPSR(%a6),-(%a7)
1846
1847	movel	#1,%d0
1848	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
1849	movel	ETEMP_EX(%a6),(%a0)
1850	movel	ETEMP_HI(%a6),4(%a0)
1851	movel	ETEMP_LO(%a6),8(%a0)
1852	bsrl	ovf_res
1853
1854	movel	(%a7)+,USER_FPSR(%a6)
1855
1856	movel	%a0,%a1
1857	movel	EXC_EA(%a6),%a0
1858	bsrl	dest_sgl
1859	orl	#ovfinx_mask,USER_FPSR(%a6)
1860	bra	mvout_end
1861
1862dp_over:
1863| Temp fix for z bit set in ovf_res
1864	movel	USER_FPSR(%a6),-(%a7)
1865
1866	movel	#2,%d0
1867	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
1868	movel	ETEMP_EX(%a6),(%a0)
1869	movel	ETEMP_HI(%a6),4(%a0)
1870	movel	ETEMP_LO(%a6),8(%a0)
1871	bsrl	ovf_res
1872
1873	movel	(%a7)+,USER_FPSR(%a6)
1874
1875	movel	%a0,%a1
1876	movel	EXC_EA(%a6),%a0
1877	bsrl	dest_dbl
1878	orl	#ovfinx_mask,USER_FPSR(%a6)
1879	bra	mvout_end
1880
1881|
1882|	DPSPDNRM
1883|
1884| This subroutine takes an extended normalized number and denormalizes
1885| it to the given round precision. This subroutine also decrements
1886| the input operand's exponent by 1 to account for the fact that
1887| dest_sgl or dest_dbl expects a normalized number's bias.
1888|
1889| Input: a0  points to a normalized number in internal extended format
1890|	 d0  is the round precision (=1 for sgl; =2 for dbl)
1891|	 d1  is the single precision or double precision
1892|	     denorm threshold
1893|
1894| Output: (In the format for dest_sgl or dest_dbl)
1895|	 a0   points to the destination
1896|	 a1   points to the operand
1897|
1898| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1899|
1900dpspdnrm:
1901	movel	%d0,-(%a7)	|save round precision
1902	clrl	%d0		|clear initial g,r,s
1903	bsrl	dnrm_lp		|careful with d0, it's needed by round
1904
1905	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
1906	swap	%d1
1907	movew	2(%a7),%d1	|set rounding precision
1908	swap	%d1		|at this point d1 has PREC/MODE info
1909	bsrl	round		|round result, sets the inex bit in
1910|				;USER_FPSR if needed
1911
1912	movew	#1,%d0
1913	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
1914|				;vs norm bias
1915
1916	movel	%a0,%a1		|a1 has the operand input
1917	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1918	addw	#4,%a7		|pop stack
1919	rts
1920|
1921| SET_XOP initialized WBTEMP with the value pointed to by a0
1922| input: a0 points to input operand in the internal extended format
1923|
1924set_xop:
1925	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
1926	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
1927	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
1928	bfclr	WBTEMP_SGN(%a6){#0:#8}
1929	beqs	sxop
1930	bsetb	#sign_bit,WBTEMP_EX(%a6)
1931sxop:
1932	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
1933	rts
1934|
1935|	P_MOVE
1936|
1937p_movet:
1938	.long	p_move
1939	.long	p_movez
1940	.long	p_movei
1941	.long	p_moven
1942	.long	p_move
1943p_regd:
1944	.long	p_dyd0
1945	.long	p_dyd1
1946	.long	p_dyd2
1947	.long	p_dyd3
1948	.long	p_dyd4
1949	.long	p_dyd5
1950	.long	p_dyd6
1951	.long	p_dyd7
1952
1953pack_out:
1954	leal	p_movet,%a0	|load jmp table address
1955	movew	STAG(%a6),%d0	|get source tag
1956	bfextu	%d0{#16:#3},%d0	|isolate source bits
1957	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
1958	jmp	(%a0)		|go to the routine
1959
1960p_write:
1961	movel	#0x0c,%d0	|get byte count
1962	movel	EXC_EA(%a6),%a1	|get the destination address
1963	bsr	mem_write	|write the user's destination
1964	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
1965
1966|
1967| Also note that the dtag must be set to norm here - this is because
1968| the 040 uses the dtag to execute the correct microcode.
1969|
1970        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
1971
1972	rts
1973
1974| Notes on handling of special case (zero, inf, and nan) inputs:
1975|	1. Operr is not signalled if the k-factor is greater than 18.
1976|	2. Per the manual, status bits are not set.
1977|
1978
1979p_move:
1980	movew	CMDREG1B(%a6),%d0
1981	btstl	#kfact_bit,%d0	|test for dynamic k-factor
1982	beqs	statick		|if clear, k-factor is static
1983dynamick:
1984	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
1985	lea	p_regd,%a0
1986	movel	%a0@(%d0:l:4),%a0
1987	jmp	(%a0)
1988statick:
1989	andiw	#0x007f,%d0	|get k-factor
1990	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
1991	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
1992	bsrl	bindec		|perform the convert; data at a6
1993	leal	FP_SCR1(%a6),%a0	|load a0 with result address
1994	bral	p_write
1995p_movez:
1996	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
1997	clrw	2(%a0)		|clear lower word of exp
1998	clrl	4(%a0)		|load second lword of ZERO
1999	clrl	8(%a0)		|load third lword of ZERO
2000	bra	p_write		|go write results
2001p_movei:
2002	fmovel	#0,%FPSR		|clear aiop
2003	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
2004	clrw	2(%a0)		|clear lower word of exp
2005	bra	p_write		|go write the result
2006p_moven:
2007	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
2008	clrw	2(%a0)		|clear lower word of exp
2009	bra	p_write		|go write the result
2010
2011|
2012| Routines to read the dynamic k-factor from Dn.
2013|
2014p_dyd0:
2015	movel	USER_D0(%a6),%d0
2016	bras	statick
2017p_dyd1:
2018	movel	USER_D1(%a6),%d0
2019	bras	statick
2020p_dyd2:
2021	movel	%d2,%d0
2022	bras	statick
2023p_dyd3:
2024	movel	%d3,%d0
2025	bras	statick
2026p_dyd4:
2027	movel	%d4,%d0
2028	bras	statick
2029p_dyd5:
2030	movel	%d5,%d0
2031	bras	statick
2032p_dyd6:
2033	movel	%d6,%d0
2034	bra	statick
2035p_dyd7:
2036	movel	%d7,%d0
2037	bra	statick
2038
2039	|end
v4.6
   1|
   2|	res_func.sa 3.9 7/29/91
   3|
   4| Normalizes denormalized numbers if necessary and updates the
   5| stack frame.  The function is then restored back into the
   6| machine and the 040 completes the operation.  This routine
   7| is only used by the unsupported data type/format handler.
   8| (Exception vector 55).
   9|
  10| For packed move out (fmove.p fpm,<ea>) the operation is
  11| completed here; data is packed and moved to user memory.
  12| The stack is restored to the 040 only in the case of a
  13| reportable exception in the conversion.
  14|
  15|
  16|		Copyright (C) Motorola, Inc. 1990
  17|			All Rights Reserved
  18|
  19|       For details on the license for this file, please see the
  20|       file, README, in this same directory.
  21
  22RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
  23
  24	|section	8
  25
  26#include "fpsp.h"
  27
  28sp_bnds:	.short	0x3f81,0x407e
  29		.short	0x3f6a,0x0000
  30dp_bnds:	.short	0x3c01,0x43fe
  31		.short	0x3bcd,0x0000
  32
  33	|xref	mem_write
  34	|xref	bindec
  35	|xref	get_fline
  36	|xref	round
  37	|xref	denorm
  38	|xref	dest_ext
  39	|xref	dest_dbl
  40	|xref	dest_sgl
  41	|xref	unf_sub
  42	|xref	nrm_set
  43	|xref	dnrm_lp
  44	|xref	ovf_res
  45	|xref	reg_dest
  46	|xref	t_ovfl
  47	|xref	t_unfl
  48
  49	.global	res_func
  50	.global	p_move
  51
  52res_func:
  53	clrb	DNRM_FLG(%a6)
  54	clrb	RES_FLG(%a6)
  55	clrb	CU_ONLY(%a6)
  56	tstb	DY_MO_FLG(%a6)
  57	beqs	monadic
  58dyadic:
  59	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
  60|				;inf=010 or nan=011
  61	beqs	monadic		|then branch
  62|				;else denorm
  63| HANDLE DESTINATION DENORM HERE
  64|				;set dtag to norm
  65|				;write the tag & fpte15 to the fstack
  66	leal	FPTEMP(%a6),%a0
  67
  68	bclrb	#sign_bit,LOCAL_EX(%a0)
  69	sne	LOCAL_SGN(%a0)
  70
  71	bsr	nrm_set		|normalize number (exp will go negative)
  72	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
  73	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
  74	beqs	dpos
  75	bsetb	#sign_bit,LOCAL_EX(%a0)
  76dpos:
  77	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
  78	bsetb	#4,DTAG(%a6)	|set FPTE15
  79	orb	#0x0f,DNRM_FLG(%a6)
  80monadic:
  81	leal	ETEMP(%a6),%a0
  82	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
  83	bne	opclass3			|it is a mv out
  84|
  85| At this point, only opclass 0 and 2 possible
  86|
  87	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
  88|				;inf=010 or nan=011
  89	bne	mon_dnrm	|else denorm
  90	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
  91	bne	normal		|require normalization of denorm
  92
  93| At this point:
  94|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
  95|				fmove = $00  fsmove = $40  fdmove = $44
  96|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
  97|				(*fsqrt reencoded to $05)
  98|
  99	movew	CMDREG1B(%a6),%d0	|get command register
 100	andil	#0x7f,%d0			|strip to only command word
 101|
 102| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
 103| fdsqrt are possible.
 104| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
 105| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
 106|
 107	btstl	#0,%d0
 108	bne	normal			|weed out fsqrt instructions
 109|
 110| cu_norm handles fmove in instructions with normalized inputs.
 111| The routine round is used to correctly round the input for the
 112| destination precision and mode.
 113|
 114cu_norm:
 115	st	CU_ONLY(%a6)		|set cu-only inst flag
 116	movew	CMDREG1B(%a6),%d0
 117	andib	#0x3b,%d0		|isolate bits to select inst
 118	tstb	%d0
 119	beql	cu_nmove	|if zero, it is an fmove
 120	cmpib	#0x18,%d0
 121	beql	cu_nabs		|if $18, it is fabs
 122	cmpib	#0x1a,%d0
 123	beql	cu_nneg		|if $1a, it is fneg
 124|
 125| Inst is ftst.  Check the source operand and set the cc's accordingly.
 126| No write is done, so simply rts.
 127|
 128cu_ntst:
 129	movew	LOCAL_EX(%a0),%d0
 130	bclrl	#15,%d0
 131	sne	LOCAL_SGN(%a0)
 132	beqs	cu_ntpo
 133	orl	#neg_mask,USER_FPSR(%a6) |set N
 134cu_ntpo:
 135	cmpiw	#0x7fff,%d0	|test for inf/nan
 136	bnes	cu_ntcz
 137	tstl	LOCAL_HI(%a0)
 138	bnes	cu_ntn
 139	tstl	LOCAL_LO(%a0)
 140	bnes	cu_ntn
 141	orl	#inf_mask,USER_FPSR(%a6)
 142	rts
 143cu_ntn:
 144	orl	#nan_mask,USER_FPSR(%a6)
 145	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
 146|						;snan handler
 147
 148	rts
 149cu_ntcz:
 150	tstl	LOCAL_HI(%a0)
 151	bnel	cu_ntsx
 152	tstl	LOCAL_LO(%a0)
 153	bnel	cu_ntsx
 154	orl	#z_mask,USER_FPSR(%a6)
 155cu_ntsx:
 156	rts
 157|
 158| Inst is fabs.  Execute the absolute value function on the input.
 159| Branch to the fmove code.  If the operand is NaN, do nothing.
 160|
 161cu_nabs:
 162	moveb	STAG(%a6),%d0
 163	btstl	#5,%d0			|test for NaN or zero
 164	bne	wr_etemp		|if either, simply write it
 165	bclrb	#7,LOCAL_EX(%a0)		|do abs
 166	bras	cu_nmove		|fmove code will finish
 167|
 168| Inst is fneg.  Execute the negate value function on the input.
 169| Fall though to the fmove code.  If the operand is NaN, do nothing.
 170|
 171cu_nneg:
 172	moveb	STAG(%a6),%d0
 173	btstl	#5,%d0			|test for NaN or zero
 174	bne	wr_etemp		|if either, simply write it
 175	bchgb	#7,LOCAL_EX(%a0)		|do neg
 176|
 177| Inst is fmove.  This code also handles all result writes.
 178| If bit 2 is set, round is forced to double.  If it is clear,
 179| and bit 6 is set, round is forced to single.  If both are clear,
 180| the round precision is found in the fpcr.  If the rounding precision
 181| is double or single, round the result before the write.
 182|
 183cu_nmove:
 184	moveb	STAG(%a6),%d0
 185	andib	#0xe0,%d0			|isolate stag bits
 186	bne	wr_etemp		|if not norm, simply write it
 187	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 188	bne	cu_nmrd
 189	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 190	bne	cu_nmrs
 191|
 192| The move or operation is not with forced precision.  Test for
 193| nan or inf as the input; if so, simply write it to FPn.  Use the
 194| FPCR_MODE byte to get rounding on norms and zeros.
 195|
 196cu_nmnr:
 197	bfextu	FPCR_MODE(%a6){#0:#2},%d0
 198	tstb	%d0			|check for extended
 199	beq	cu_wrexn		|if so, just write result
 200	cmpib	#1,%d0			|check for single
 201	beq	cu_nmrs			|fall through to double
 202|
 203| The move is fdmove or round precision is double.
 204|
 205cu_nmrd:
 206	movel	#2,%d0			|set up the size for denorm
 207	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
 208	andw	#0x7fff,%d1
 209	cmpw	#0x3c01,%d1
 210	bls	cu_nunfl
 211	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 212	orl	#0x00020000,%d1		|or in rprec (double)
 213	clrl	%d0			|clear g,r,s for round
 214	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
 215	sne	LOCAL_SGN(%a0)
 216	bsrl	round
 217	bfclr	LOCAL_SGN(%a0){#0:#8}
 218	beqs	cu_nmrdc
 219	bsetb	#sign_bit,LOCAL_EX(%a0)
 220cu_nmrdc:
 221	movew	LOCAL_EX(%a0),%d1		|check for overflow
 222	andw	#0x7fff,%d1
 223	cmpw	#0x43ff,%d1
 224	bge	cu_novfl		|take care of overflow case
 225	bra	cu_wrexn
 226|
 227| The move is fsmove or round precision is single.
 228|
 229cu_nmrs:
 230	movel	#1,%d0
 231	movew	LOCAL_EX(%a0),%d1
 232	andw	#0x7fff,%d1
 233	cmpw	#0x3f81,%d1
 234	bls	cu_nunfl
 235	bfextu	FPCR_MODE(%a6){#2:#2},%d1
 236	orl	#0x00010000,%d1
 237	clrl	%d0
 238	bclrb	#sign_bit,LOCAL_EX(%a0)
 239	sne	LOCAL_SGN(%a0)
 240	bsrl	round
 241	bfclr	LOCAL_SGN(%a0){#0:#8}
 242	beqs	cu_nmrsc
 243	bsetb	#sign_bit,LOCAL_EX(%a0)
 244cu_nmrsc:
 245	movew	LOCAL_EX(%a0),%d1
 246	andw	#0x7FFF,%d1
 247	cmpw	#0x407f,%d1
 248	blt	cu_wrexn
 249|
 250| The operand is above precision boundaries.  Use t_ovfl to
 251| generate the correct value.
 252|
 253cu_novfl:
 254	bsr	t_ovfl
 255	bra	cu_wrexn
 256|
 257| The operand is below precision boundaries.  Use denorm to
 258| generate the correct value.
 259|
 260cu_nunfl:
 261	bclrb	#sign_bit,LOCAL_EX(%a0)
 262	sne	LOCAL_SGN(%a0)
 263	bsr	denorm
 264	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
 265	beqs	cu_nucont
 266	bsetb	#sign_bit,LOCAL_EX(%a0)
 267cu_nucont:
 268	bfextu	FPCR_MODE(%a6){#2:#2},%d1
 269	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 270	bne	inst_d
 271	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 272	bne	inst_s
 273	swap	%d1
 274	moveb	FPCR_MODE(%a6),%d1
 275	lsrb	#6,%d1
 276	swap	%d1
 277	bra	inst_sd
 278inst_d:
 279	orl	#0x00020000,%d1
 280	bra	inst_sd
 281inst_s:
 282	orl	#0x00010000,%d1
 283inst_sd:
 284	bclrb	#sign_bit,LOCAL_EX(%a0)
 285	sne	LOCAL_SGN(%a0)
 286	bsrl	round
 287	bfclr	LOCAL_SGN(%a0){#0:#8}
 288	beqs	cu_nuflp
 289	bsetb	#sign_bit,LOCAL_EX(%a0)
 290cu_nuflp:
 291	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
 292	beqs	cu_nuninx
 293	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
 294cu_nuninx:
 295	tstl	LOCAL_HI(%a0)		|test for zero
 296	bnes	cu_nunzro
 297	tstl	LOCAL_LO(%a0)
 298	bnes	cu_nunzro
 299|
 300| The mantissa is zero from the denorm loop.  Check sign and rmode
 301| to see if rounding should have occurred which would leave the lsb.
 302|
 303	movel	USER_FPCR(%a6),%d0
 304	andil	#0x30,%d0		|isolate rmode
 305	cmpil	#0x20,%d0
 306	blts	cu_nzro
 307	bnes	cu_nrp
 308cu_nrm:
 309	tstw	LOCAL_EX(%a0)	|if positive, set lsb
 310	bges	cu_nzro
 311	btstb	#7,FPCR_MODE(%a6) |check for double
 312	beqs	cu_nincs
 313	bras	cu_nincd
 314cu_nrp:
 315	tstw	LOCAL_EX(%a0)	|if positive, set lsb
 316	blts	cu_nzro
 317	btstb	#7,FPCR_MODE(%a6) |check for double
 318	beqs	cu_nincs
 319cu_nincd:
 320	orl	#0x800,LOCAL_LO(%a0) |inc for double
 321	bra	cu_nunzro
 322cu_nincs:
 323	orl	#0x100,LOCAL_HI(%a0) |inc for single
 324	bra	cu_nunzro
 325cu_nzro:
 326	orl	#z_mask,USER_FPSR(%a6)
 327	moveb	STAG(%a6),%d0
 328	andib	#0xe0,%d0
 329	cmpib	#0x40,%d0		|check if input was tagged zero
 330	beqs	cu_numv
 331cu_nunzro:
 332	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
 333cu_numv:
 334	movel	(%a0),ETEMP(%a6)
 335	movel	4(%a0),ETEMP_HI(%a6)
 336	movel	8(%a0),ETEMP_LO(%a6)
 337|
 338| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
 339| bypass cu_wrexn.
 340|
 341cu_wrexn:
 342	tstw	LOCAL_EX(%a0)		|test for zero
 343	beqs	cu_wrzero
 344	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
 345	bnes	cu_wreon
 346cu_wrzero:
 347	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
 348cu_wreon:
 349	tstw	LOCAL_EX(%a0)
 350	bpl	wr_etemp
 351	orl	#neg_mask,USER_FPSR(%a6)
 352	bra	wr_etemp
 353
 354|
 355| HANDLE SOURCE DENORM HERE
 356|
 357|				;clear denorm stag to norm
 358|				;write the new tag & ete15 to the fstack
 359mon_dnrm:
 360|
 361| At this point, check for the cases in which normalizing the
 362| denorm produces incorrect results.
 363|
 364	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
 365	bnes	nrm_src		|require normalization of denorm
 366
 367| At this point:
 368|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
 369|				fmove = $00  fsmove = $40  fdmove = $44
 370|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
 371|				(*fsqrt reencoded to $05)
 372|
 373	movew	CMDREG1B(%a6),%d0	|get command register
 374	andil	#0x7f,%d0			|strip to only command word
 375|
 376| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
 377| fdsqrt are possible.
 378| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
 379| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
 380|
 381	btstl	#0,%d0
 382	bnes	nrm_src		|weed out fsqrt instructions
 383	st	CU_ONLY(%a6)	|set cu-only inst flag
 384	bra	cu_dnrm		|fmove, fabs, fneg, ftst
 385|				;cases go to cu_dnrm
 386nrm_src:
 387	bclrb	#sign_bit,LOCAL_EX(%a0)
 388	sne	LOCAL_SGN(%a0)
 389	bsr	nrm_set		|normalize number (exponent will go
 390|				; negative)
 391	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
 392
 393	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
 394	beqs	spos
 395	bsetb	#sign_bit,LOCAL_EX(%a0)
 396spos:
 397	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
 398	bsetb	#4,STAG(%a6)	|set ETE15
 399	orb	#0xf0,DNRM_FLG(%a6)
 400normal:
 401	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
 402	bne	ck_wrap		|if so, check if it is a potential
 403|				;wrap-around case
 404fix_stk:
 405	moveb	#0xfe,CU_SAVEPC(%a6)
 406	bclrb	#E1,E_BYTE(%a6)
 407
 408	clrw	NMNEXC(%a6)
 409
 410	st	RES_FLG(%a6)	|indicate that a restore is needed
 411	rts
 412
 413|
 414| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
 415| ftst) completely in software without an frestore to the 040.
 416|
 417cu_dnrm:
 418	st	CU_ONLY(%a6)
 419	movew	CMDREG1B(%a6),%d0
 420	andib	#0x3b,%d0		|isolate bits to select inst
 421	tstb	%d0
 422	beql	cu_dmove	|if zero, it is an fmove
 423	cmpib	#0x18,%d0
 424	beql	cu_dabs		|if $18, it is fabs
 425	cmpib	#0x1a,%d0
 426	beql	cu_dneg		|if $1a, it is fneg
 427|
 428| Inst is ftst.  Check the source operand and set the cc's accordingly.
 429| No write is done, so simply rts.
 430|
 431cu_dtst:
 432	movew	LOCAL_EX(%a0),%d0
 433	bclrl	#15,%d0
 434	sne	LOCAL_SGN(%a0)
 435	beqs	cu_dtpo
 436	orl	#neg_mask,USER_FPSR(%a6) |set N
 437cu_dtpo:
 438	cmpiw	#0x7fff,%d0	|test for inf/nan
 439	bnes	cu_dtcz
 440	tstl	LOCAL_HI(%a0)
 441	bnes	cu_dtn
 442	tstl	LOCAL_LO(%a0)
 443	bnes	cu_dtn
 444	orl	#inf_mask,USER_FPSR(%a6)
 445	rts
 446cu_dtn:
 447	orl	#nan_mask,USER_FPSR(%a6)
 448	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
 449|						;snan handler
 450	rts
 451cu_dtcz:
 452	tstl	LOCAL_HI(%a0)
 453	bnel	cu_dtsx
 454	tstl	LOCAL_LO(%a0)
 455	bnel	cu_dtsx
 456	orl	#z_mask,USER_FPSR(%a6)
 457cu_dtsx:
 458	rts
 459|
 460| Inst is fabs.  Execute the absolute value function on the input.
 461| Branch to the fmove code.
 462|
 463cu_dabs:
 464	bclrb	#7,LOCAL_EX(%a0)		|do abs
 465	bras	cu_dmove		|fmove code will finish
 466|
 467| Inst is fneg.  Execute the negate value function on the input.
 468| Fall though to the fmove code.
 469|
 470cu_dneg:
 471	bchgb	#7,LOCAL_EX(%a0)		|do neg
 472|
 473| Inst is fmove.  This code also handles all result writes.
 474| If bit 2 is set, round is forced to double.  If it is clear,
 475| and bit 6 is set, round is forced to single.  If both are clear,
 476| the round precision is found in the fpcr.  If the rounding precision
 477| is double or single, the result is zero, and the mode is checked
 478| to determine if the lsb of the result should be set.
 479|
 480cu_dmove:
 481	btstb	#2,CMDREG1B+1(%a6)	|check for rd
 482	bne	cu_dmrd
 483	btstb	#6,CMDREG1B+1(%a6)	|check for rs
 484	bne	cu_dmrs
 485|
 486| The move or operation is not with forced precision.  Use the
 487| FPCR_MODE byte to get rounding.
 488|
 489cu_dmnr:
 490	bfextu	FPCR_MODE(%a6){#0:#2},%d0
 491	tstb	%d0			|check for extended
 492	beq	cu_wrexd		|if so, just write result
 493	cmpib	#1,%d0			|check for single
 494	beq	cu_dmrs			|fall through to double
 495|
 496| The move is fdmove or round precision is double.  Result is zero.
 497| Check rmode for rp or rm and set lsb accordingly.
 498|
 499cu_dmrd:
 500	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 501	tstw	LOCAL_EX(%a0)		|check sign
 502	blts	cu_dmdn
 503	cmpib	#3,%d1			|check for rp
 504	bne	cu_dpd			|load double pos zero
 505	bra	cu_dpdr			|load double pos zero w/lsb
 506cu_dmdn:
 507	cmpib	#2,%d1			|check for rm
 508	bne	cu_dnd			|load double neg zero
 509	bra	cu_dndr			|load double neg zero w/lsb
 510|
 511| The move is fsmove or round precision is single.  Result is zero.
 512| Check for rp or rm and set lsb accordingly.
 513|
 514cu_dmrs:
 515	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
 516	tstw	LOCAL_EX(%a0)		|check sign
 517	blts	cu_dmsn
 518	cmpib	#3,%d1			|check for rp
 519	bne	cu_spd			|load single pos zero
 520	bra	cu_spdr			|load single pos zero w/lsb
 521cu_dmsn:
 522	cmpib	#2,%d1			|check for rm
 523	bne	cu_snd			|load single neg zero
 524	bra	cu_sndr			|load single neg zero w/lsb
 525|
 526| The precision is extended, so the result in etemp is correct.
 527| Simply set unfl (not inex2 or aunfl) and write the result to
 528| the correct fp register.
 529cu_wrexd:
 530	orl	#unfl_mask,USER_FPSR(%a6)
 531	tstw	LOCAL_EX(%a0)
 532	beq	wr_etemp
 533	orl	#neg_mask,USER_FPSR(%a6)
 534	bra	wr_etemp
 535|
 536| These routines write +/- zero in double format.  The routines
 537| cu_dpdr and cu_dndr set the double lsb.
 538|
 539cu_dpd:
 540	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
 541	clrl	LOCAL_HI(%a0)
 542	clrl	LOCAL_LO(%a0)
 543	orl	#z_mask,USER_FPSR(%a6)
 544	orl	#unfinx_mask,USER_FPSR(%a6)
 545	bra	wr_etemp
 546cu_dpdr:
 547	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
 548	clrl	LOCAL_HI(%a0)
 549	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
 550	orl	#unfinx_mask,USER_FPSR(%a6)
 551	bra	wr_etemp
 552cu_dnd:
 553	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
 554	clrl	LOCAL_HI(%a0)
 555	clrl	LOCAL_LO(%a0)
 556	orl	#z_mask,USER_FPSR(%a6)
 557	orl	#neg_mask,USER_FPSR(%a6)
 558	orl	#unfinx_mask,USER_FPSR(%a6)
 559	bra	wr_etemp
 560cu_dndr:
 561	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
 562	clrl	LOCAL_HI(%a0)
 563	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
 564	orl	#neg_mask,USER_FPSR(%a6)
 565	orl	#unfinx_mask,USER_FPSR(%a6)
 566	bra	wr_etemp
 567|
 568| These routines write +/- zero in single format.  The routines
 569| cu_dpdr and cu_dndr set the single lsb.
 570|
 571cu_spd:
 572	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
 573	clrl	LOCAL_HI(%a0)
 574	clrl	LOCAL_LO(%a0)
 575	orl	#z_mask,USER_FPSR(%a6)
 576	orl	#unfinx_mask,USER_FPSR(%a6)
 577	bra	wr_etemp
 578cu_spdr:
 579	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
 580	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
 581	clrl	LOCAL_LO(%a0)
 582	orl	#unfinx_mask,USER_FPSR(%a6)
 583	bra	wr_etemp
 584cu_snd:
 585	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
 586	clrl	LOCAL_HI(%a0)
 587	clrl	LOCAL_LO(%a0)
 588	orl	#z_mask,USER_FPSR(%a6)
 589	orl	#neg_mask,USER_FPSR(%a6)
 590	orl	#unfinx_mask,USER_FPSR(%a6)
 591	bra	wr_etemp
 592cu_sndr:
 593	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
 594	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
 595	clrl	LOCAL_LO(%a0)
 596	orl	#neg_mask,USER_FPSR(%a6)
 597	orl	#unfinx_mask,USER_FPSR(%a6)
 598	bra	wr_etemp
 599
 600|
 601| This code checks for 16-bit overflow conditions on dyadic
 602| operations which are not restorable into the floating-point
 603| unit and must be completed in software.  Basically, this
 604| condition exists with a very large norm and a denorm.  One
 605| of the operands must be denormalized to enter this code.
 606|
 607| Flags used:
 608|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
 609|	DNRM_FLG contains $00 for neither op denormalized
 610|	                  $0f for the destination op denormalized
 611|	                  $f0 for the source op denormalized
 612|	                  $ff for both ops denormalized
 613|
 614| The wrap-around condition occurs for add, sub, div, and cmp
 615| when
 616|
 617|	abs(dest_exp - src_exp) >= $8000
 618|
 619| and for mul when
 620|
 621|	(dest_exp + src_exp) < $0
 622|
 623| we must process the operation here if this case is true.
 624|
 625| The rts following the frcfpn routine is the exit from res_func
 626| for this condition.  The restore flag (RES_FLG) is left clear.
 627| No frestore is done unless an exception is to be reported.
 628|
 629| For fadd:
 630|	if(sign_of(dest) != sign_of(src))
 631|		replace exponent of src with $3fff (keep sign)
 632|		use fpu to perform dest+new_src (user's rmode and X)
 633|		clr sticky
 634|	else
 635|		set sticky
 636|	call round with user's precision and mode
 637|	move result to fpn and wbtemp
 638|
 639| For fsub:
 640|	if(sign_of(dest) == sign_of(src))
 641|		replace exponent of src with $3fff (keep sign)
 642|		use fpu to perform dest+new_src (user's rmode and X)
 643|		clr sticky
 644|	else
 645|		set sticky
 646|	call round with user's precision and mode
 647|	move result to fpn and wbtemp
 648|
 649| For fdiv/fsgldiv:
 650|	if(both operands are denorm)
 651|		restore_to_fpu;
 652|	if(dest is norm)
 653|		force_ovf;
 654|	else(dest is denorm)
 655|		force_unf:
 656|
 657| For fcmp:
 658|	if(dest is norm)
 659|		N = sign_of(dest);
 660|	else(dest is denorm)
 661|		N = sign_of(src);
 662|
 663| For fmul:
 664|	if(both operands are denorm)
 665|		force_unf;
 666|	if((dest_exp + src_exp) < 0)
 667|		force_unf:
 668|	else
 669|		restore_to_fpu;
 670|
 671| local equates:
 672	.set	addcode,0x22
 673	.set	subcode,0x28
 674	.set	mulcode,0x23
 675	.set	divcode,0x20
 676	.set	cmpcode,0x38
 677ck_wrap:
 678	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
 679	beq	fix_stk		|if zero, it is fsqrt
 680	movew	CMDREG1B(%a6),%d0
 681	andiw	#0x3b,%d0		|strip to command bits
 682	cmpiw	#addcode,%d0
 683	beq	wrap_add
 684	cmpiw	#subcode,%d0
 685	beq	wrap_sub
 686	cmpiw	#mulcode,%d0
 687	beq	wrap_mul
 688	cmpiw	#cmpcode,%d0
 689	beq	wrap_cmp
 690|
 691| Inst is fdiv.
 692|
 693wrap_div:
 694	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 695	beq	fix_stk		 |restore to fpu
 696|
 697| One of the ops is denormalized.  Test for wrap condition
 698| and force the result.
 699|
 700	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 701	bnes	div_srcd
 702div_destd:
 703	bsrl	ckinf_ns
 704	bne	fix_stk
 705	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 706	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 707	subl	%d1,%d0			|subtract dest from src
 708	cmpl	#0x7fff,%d0
 709	blt	fix_stk			|if less, not wrap case
 710	clrb	WBTEMP_SGN(%a6)
 711	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
 712	movew	FPTEMP_EX(%a6),%d1
 713	eorw	%d1,%d0
 714	andiw	#0x8000,%d0
 715	beq	force_unf
 716	st	WBTEMP_SGN(%a6)
 717	bra	force_unf
 718
 719ckinf_ns:
 720	moveb	STAG(%a6),%d0		|check source tag for inf or nan
 721	bra	ck_in_com
 722ckinf_nd:
 723	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
 724ck_in_com:
 725	andib	#0x60,%d0			|isolate tag bits
 726	cmpb	#0x40,%d0			|is it inf?
 727	beq	nan_or_inf		|not wrap case
 728	cmpb	#0x60,%d0			|is it nan?
 729	beq	nan_or_inf		|yes, not wrap case?
 730	cmpb	#0x20,%d0			|is it a zero?
 731	beq	nan_or_inf		|yes
 732	clrl	%d0
 733	rts				|then ; it is either a zero of norm,
 734|					;check wrap case
 735nan_or_inf:
 736	moveql	#-1,%d0
 737	rts
 738
 739
 740
 741div_srcd:
 742	bsrl	ckinf_nd
 743	bne	fix_stk
 744	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 745	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 746	subl	%d1,%d0			|subtract src from dest
 747	cmpl	#0x8000,%d0
 748	blt	fix_stk			|if less, not wrap case
 749	clrb	WBTEMP_SGN(%a6)
 750	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
 751	movew	FPTEMP_EX(%a6),%d1
 752	eorw	%d1,%d0
 753	andiw	#0x8000,%d0
 754	beqs	force_ovf
 755	st	WBTEMP_SGN(%a6)
 756|
 757| This code handles the case of the instruction resulting in
 758| an overflow condition.
 759|
 760force_ovf:
 761	bclrb	#E1,E_BYTE(%a6)
 762	orl	#ovfl_inx_mask,USER_FPSR(%a6)
 763	clrw	NMNEXC(%a6)
 764	leal	WBTEMP(%a6),%a0		|point a0 to memory location
 765	movew	CMDREG1B(%a6),%d0
 766	btstl	#6,%d0			|test for forced precision
 767	beqs	frcovf_fpcr
 768	btstl	#2,%d0			|check for double
 769	bnes	frcovf_dbl
 770	movel	#0x1,%d0			|inst is forced single
 771	bras	frcovf_rnd
 772frcovf_dbl:
 773	movel	#0x2,%d0			|inst is forced double
 774	bras	frcovf_rnd
 775frcovf_fpcr:
 776	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
 777frcovf_rnd:
 778
 779| The 881/882 does not set inex2 for the following case, so the
 780| line is commented out to be compatible with 881/882
 781|	tst.b	%d0
 782|	beq.b	frcovf_x
 783|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
 784
 785|frcovf_x:
 786	bsrl	ovf_res			|get correct result based on
 787|					;round precision/mode.  This
 788|					;sets FPSR_CC correctly
 789|					;returns in external format
 790	bfclr	WBTEMP_SGN(%a6){#0:#8}
 791	beq	frcfpn
 792	bsetb	#sign_bit,WBTEMP_EX(%a6)
 793	bra	frcfpn
 794|
 795| Inst is fadd.
 796|
 797wrap_add:
 798	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 799	beq	fix_stk		 |restore to fpu
 800|
 801| One of the ops is denormalized.  Test for wrap condition
 802| and complete the instruction.
 803|
 804	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 805	bnes	add_srcd
 806add_destd:
 807	bsrl	ckinf_ns
 808	bne	fix_stk
 809	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 810	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 811	subl	%d1,%d0			|subtract dest from src
 812	cmpl	#0x8000,%d0
 813	blt	fix_stk			|if less, not wrap case
 814	bra	add_wrap
 815add_srcd:
 816	bsrl	ckinf_nd
 817	bne	fix_stk
 818	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 819	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 820	subl	%d1,%d0			|subtract src from dest
 821	cmpl	#0x8000,%d0
 822	blt	fix_stk			|if less, not wrap case
 823|
 824| Check the signs of the operands.  If they are unlike, the fpu
 825| can be used to add the norm and 1.0 with the sign of the
 826| denorm and it will correctly generate the result in extended
 827| precision.  We can then call round with no sticky and the result
 828| will be correct for the user's rounding mode and precision.  If
 829| the signs are the same, we call round with the sticky bit set
 830| and the result will be correct for the user's rounding mode and
 831| precision.
 832|
 833add_wrap:
 834	movew	ETEMP_EX(%a6),%d0
 835	movew	FPTEMP_EX(%a6),%d1
 836	eorw	%d1,%d0
 837	andiw	#0x8000,%d0
 838	beq	add_same
 839|
 840| The signs are unlike.
 841|
 842	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
 843	bnes	add_u_srcd
 844	movew	FPTEMP_EX(%a6),%d0
 845	andiw	#0x8000,%d0
 846	orw	#0x3fff,%d0	|force the exponent to +/- 1
 847	movew	%d0,FPTEMP_EX(%a6) |in the denorm
 848	movel	USER_FPCR(%a6),%d0
 849	andil	#0x30,%d0
 850	fmovel	%d0,%fpcr		|set up users rmode and X
 851	fmovex	ETEMP(%a6),%fp0
 852	faddx	FPTEMP(%a6),%fp0
 853	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
 854	fmovel	%fpsr,%d1
 855	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
 856	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
 857	lsrl	#4,%d0		|put rmode in lower 2 bits
 858	movel	USER_FPCR(%a6),%d1
 859	andil	#0xc0,%d1
 860	lsrl	#6,%d1		|put precision in upper word
 861	swap	%d1
 862	orl	%d0,%d1		|set up for round call
 863	clrl	%d0		|force sticky to zero
 864	bclrb	#sign_bit,WBTEMP_EX(%a6)
 865	sne	WBTEMP_SGN(%a6)
 866	bsrl	round		|round result to users rmode & prec
 867	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 868	beq	frcfpnr
 869	bsetb	#sign_bit,WBTEMP_EX(%a6)
 870	bra	frcfpnr
 871add_u_srcd:
 872	movew	ETEMP_EX(%a6),%d0
 873	andiw	#0x8000,%d0
 874	orw	#0x3fff,%d0	|force the exponent to +/- 1
 875	movew	%d0,ETEMP_EX(%a6) |in the denorm
 876	movel	USER_FPCR(%a6),%d0
 877	andil	#0x30,%d0
 878	fmovel	%d0,%fpcr		|set up users rmode and X
 879	fmovex	ETEMP(%a6),%fp0
 880	faddx	FPTEMP(%a6),%fp0
 881	fmovel	%fpsr,%d1
 882	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
 883	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
 884	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
 885	lsrl	#4,%d0		|put rmode in lower 2 bits
 886	movel	USER_FPCR(%a6),%d1
 887	andil	#0xc0,%d1
 888	lsrl	#6,%d1		|put precision in upper word
 889	swap	%d1
 890	orl	%d0,%d1		|set up for round call
 891	clrl	%d0		|force sticky to zero
 892	bclrb	#sign_bit,WBTEMP_EX(%a6)
 893	sne	WBTEMP_SGN(%a6)	|use internal format for round
 894	bsrl	round		|round result to users rmode & prec
 895	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 896	beq	frcfpnr
 897	bsetb	#sign_bit,WBTEMP_EX(%a6)
 898	bra	frcfpnr
 899|
 900| Signs are alike:
 901|
 902add_same:
 903	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
 904	bnes	add_s_srcd
 905add_s_destd:
 906	leal	ETEMP(%a6),%a0
 907	movel	USER_FPCR(%a6),%d0
 908	andil	#0x30,%d0
 909	lsrl	#4,%d0		|put rmode in lower 2 bits
 910	movel	USER_FPCR(%a6),%d1
 911	andil	#0xc0,%d1
 912	lsrl	#6,%d1		|put precision in upper word
 913	swap	%d1
 914	orl	%d0,%d1		|set up for round call
 915	movel	#0x20000000,%d0	|set sticky for round
 916	bclrb	#sign_bit,ETEMP_EX(%a6)
 917	sne	ETEMP_SGN(%a6)
 918	bsrl	round		|round result to users rmode & prec
 919	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 920	beqs	add_s_dclr
 921	bsetb	#sign_bit,ETEMP_EX(%a6)
 922add_s_dclr:
 923	leal	WBTEMP(%a6),%a0
 924	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
 925	movel	ETEMP_HI(%a6),4(%a0)
 926	movel	ETEMP_LO(%a6),8(%a0)
 927	tstw	ETEMP_EX(%a6)
 928	bgt	add_ckovf
 929	orl	#neg_mask,USER_FPSR(%a6)
 930	bra	add_ckovf
 931add_s_srcd:
 932	leal	FPTEMP(%a6),%a0
 933	movel	USER_FPCR(%a6),%d0
 934	andil	#0x30,%d0
 935	lsrl	#4,%d0		|put rmode in lower 2 bits
 936	movel	USER_FPCR(%a6),%d1
 937	andil	#0xc0,%d1
 938	lsrl	#6,%d1		|put precision in upper word
 939	swap	%d1
 940	orl	%d0,%d1		|set up for round call
 941	movel	#0x20000000,%d0	|set sticky for round
 942	bclrb	#sign_bit,FPTEMP_EX(%a6)
 943	sne	FPTEMP_SGN(%a6)
 944	bsrl	round		|round result to users rmode & prec
 945	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
 946	beqs	add_s_sclr
 947	bsetb	#sign_bit,FPTEMP_EX(%a6)
 948add_s_sclr:
 949	leal	WBTEMP(%a6),%a0
 950	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
 951	movel	FPTEMP_HI(%a6),4(%a0)
 952	movel	FPTEMP_LO(%a6),8(%a0)
 953	tstw	FPTEMP_EX(%a6)
 954	bgt	add_ckovf
 955	orl	#neg_mask,USER_FPSR(%a6)
 956add_ckovf:
 957	movew	WBTEMP_EX(%a6),%d0
 958	andiw	#0x7fff,%d0
 959	cmpiw	#0x7fff,%d0
 960	bne	frcfpnr
 961|
 962| The result has overflowed to $7fff exponent.  Set I, ovfl,
 963| and aovfl, and clr the mantissa (incorrectly set by the
 964| round routine.)
 965|
 966	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
 967	clrl	4(%a0)
 968	bra	frcfpnr
 969|
 970| Inst is fsub.
 971|
 972wrap_sub:
 973	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
 974	beq	fix_stk		 |restore to fpu
 975|
 976| One of the ops is denormalized.  Test for wrap condition
 977| and complete the instruction.
 978|
 979	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
 980	bnes	sub_srcd
 981sub_destd:
 982	bsrl	ckinf_ns
 983	bne	fix_stk
 984	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
 985	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
 986	subl	%d1,%d0			|subtract src from dest
 987	cmpl	#0x8000,%d0
 988	blt	fix_stk			|if less, not wrap case
 989	bra	sub_wrap
 990sub_srcd:
 991	bsrl	ckinf_nd
 992	bne	fix_stk
 993	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
 994	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
 995	subl	%d1,%d0			|subtract dest from src
 996	cmpl	#0x8000,%d0
 997	blt	fix_stk			|if less, not wrap case
 998|
 999| Check the signs of the operands.  If they are alike, the fpu
1000| can be used to subtract from the norm 1.0 with the sign of the
1001| denorm and it will correctly generate the result in extended
1002| precision.  We can then call round with no sticky and the result
1003| will be correct for the user's rounding mode and precision.  If
1004| the signs are unlike, we call round with the sticky bit set
1005| and the result will be correct for the user's rounding mode and
1006| precision.
1007|
1008sub_wrap:
1009	movew	ETEMP_EX(%a6),%d0
1010	movew	FPTEMP_EX(%a6),%d1
1011	eorw	%d1,%d0
1012	andiw	#0x8000,%d0
1013	bne	sub_diff
1014|
1015| The signs are alike.
1016|
1017	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
1018	bnes	sub_u_srcd
1019	movew	FPTEMP_EX(%a6),%d0
1020	andiw	#0x8000,%d0
1021	orw	#0x3fff,%d0	|force the exponent to +/- 1
1022	movew	%d0,FPTEMP_EX(%a6) |in the denorm
1023	movel	USER_FPCR(%a6),%d0
1024	andil	#0x30,%d0
1025	fmovel	%d0,%fpcr		|set up users rmode and X
1026	fmovex	FPTEMP(%a6),%fp0
1027	fsubx	ETEMP(%a6),%fp0
1028	fmovel	%fpsr,%d1
1029	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1030	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
1031	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
1032	lsrl	#4,%d0		|put rmode in lower 2 bits
1033	movel	USER_FPCR(%a6),%d1
1034	andil	#0xc0,%d1
1035	lsrl	#6,%d1		|put precision in upper word
1036	swap	%d1
1037	orl	%d0,%d1		|set up for round call
1038	clrl	%d0		|force sticky to zero
1039	bclrb	#sign_bit,WBTEMP_EX(%a6)
1040	sne	WBTEMP_SGN(%a6)
1041	bsrl	round		|round result to users rmode & prec
1042	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1043	beq	frcfpnr
1044	bsetb	#sign_bit,WBTEMP_EX(%a6)
1045	bra	frcfpnr
1046sub_u_srcd:
1047	movew	ETEMP_EX(%a6),%d0
1048	andiw	#0x8000,%d0
1049	orw	#0x3fff,%d0	|force the exponent to +/- 1
1050	movew	%d0,ETEMP_EX(%a6) |in the denorm
1051	movel	USER_FPCR(%a6),%d0
1052	andil	#0x30,%d0
1053	fmovel	%d0,%fpcr		|set up users rmode and X
1054	fmovex	FPTEMP(%a6),%fp0
1055	fsubx	ETEMP(%a6),%fp0
1056	fmovel	%fpsr,%d1
1057	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1058	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
1059	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
1060	lsrl	#4,%d0		|put rmode in lower 2 bits
1061	movel	USER_FPCR(%a6),%d1
1062	andil	#0xc0,%d1
1063	lsrl	#6,%d1		|put precision in upper word
1064	swap	%d1
1065	orl	%d0,%d1		|set up for round call
1066	clrl	%d0		|force sticky to zero
1067	bclrb	#sign_bit,WBTEMP_EX(%a6)
1068	sne	WBTEMP_SGN(%a6)
1069	bsrl	round		|round result to users rmode & prec
1070	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1071	beq	frcfpnr
1072	bsetb	#sign_bit,WBTEMP_EX(%a6)
1073	bra	frcfpnr
1074|
1075| Signs are unlike:
1076|
1077sub_diff:
1078	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
1079	bnes	sub_s_srcd
1080sub_s_destd:
1081	leal	ETEMP(%a6),%a0
1082	movel	USER_FPCR(%a6),%d0
1083	andil	#0x30,%d0
1084	lsrl	#4,%d0		|put rmode in lower 2 bits
1085	movel	USER_FPCR(%a6),%d1
1086	andil	#0xc0,%d1
1087	lsrl	#6,%d1		|put precision in upper word
1088	swap	%d1
1089	orl	%d0,%d1		|set up for round call
1090	movel	#0x20000000,%d0	|set sticky for round
1091|
1092| Since the dest is the denorm, the sign is the opposite of the
1093| norm sign.
1094|
1095	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
1096	tstw	ETEMP_EX(%a6)
1097	bgts	sub_s_dwr
1098	orl	#neg_mask,USER_FPSR(%a6)
1099sub_s_dwr:
1100	bclrb	#sign_bit,ETEMP_EX(%a6)
1101	sne	ETEMP_SGN(%a6)
1102	bsrl	round		|round result to users rmode & prec
1103	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1104	beqs	sub_s_dclr
1105	bsetb	#sign_bit,ETEMP_EX(%a6)
1106sub_s_dclr:
1107	leal	WBTEMP(%a6),%a0
1108	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
1109	movel	ETEMP_HI(%a6),4(%a0)
1110	movel	ETEMP_LO(%a6),8(%a0)
1111	bra	sub_ckovf
1112sub_s_srcd:
1113	leal	FPTEMP(%a6),%a0
1114	movel	USER_FPCR(%a6),%d0
1115	andil	#0x30,%d0
1116	lsrl	#4,%d0		|put rmode in lower 2 bits
1117	movel	USER_FPCR(%a6),%d1
1118	andil	#0xc0,%d1
1119	lsrl	#6,%d1		|put precision in upper word
1120	swap	%d1
1121	orl	%d0,%d1		|set up for round call
1122	movel	#0x20000000,%d0	|set sticky for round
1123	bclrb	#sign_bit,FPTEMP_EX(%a6)
1124	sne	FPTEMP_SGN(%a6)
1125	bsrl	round		|round result to users rmode & prec
1126	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1127	beqs	sub_s_sclr
1128	bsetb	#sign_bit,FPTEMP_EX(%a6)
1129sub_s_sclr:
1130	leal	WBTEMP(%a6),%a0
1131	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
1132	movel	FPTEMP_HI(%a6),4(%a0)
1133	movel	FPTEMP_LO(%a6),8(%a0)
1134	tstw	FPTEMP_EX(%a6)
1135	bgt	sub_ckovf
1136	orl	#neg_mask,USER_FPSR(%a6)
1137sub_ckovf:
1138	movew	WBTEMP_EX(%a6),%d0
1139	andiw	#0x7fff,%d0
1140	cmpiw	#0x7fff,%d0
1141	bne	frcfpnr
1142|
1143| The result has overflowed to $7fff exponent.  Set I, ovfl,
1144| and aovfl, and clr the mantissa (incorrectly set by the
1145| round routine.)
1146|
1147	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1148	clrl	4(%a0)
1149	bra	frcfpnr
1150|
1151| Inst is fcmp.
1152|
1153wrap_cmp:
1154	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
1155	beq	fix_stk		 |restore to fpu
1156|
1157| One of the ops is denormalized.  Test for wrap condition
1158| and complete the instruction.
1159|
1160	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
1161	bnes	cmp_srcd
1162cmp_destd:
1163	bsrl	ckinf_ns
1164	bne	fix_stk
1165	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
1166	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
1167	subl	%d1,%d0			|subtract dest from src
1168	cmpl	#0x8000,%d0
1169	blt	fix_stk			|if less, not wrap case
1170	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
1171	bge	cmp_setn
1172	rts
1173cmp_srcd:
1174	bsrl	ckinf_nd
1175	bne	fix_stk
1176	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
1177	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
1178	subl	%d1,%d0			|subtract src from dest
1179	cmpl	#0x8000,%d0
1180	blt	fix_stk			|if less, not wrap case
1181	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
1182	blt	cmp_setn
1183	rts
1184cmp_setn:
1185	orl	#neg_mask,USER_FPSR(%a6)
1186	rts
1187
1188|
1189| Inst is fmul.
1190|
1191wrap_mul:
1192	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
1193	beq	force_unf	|force an underflow (really!)
1194|
1195| One of the ops is denormalized.  Test for wrap condition
1196| and complete the instruction.
1197|
1198	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
1199	bnes	mul_srcd
1200mul_destd:
1201	bsrl	ckinf_ns
1202	bne	fix_stk
1203	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
1204	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
1205	addl	%d1,%d0			|subtract dest from src
1206	bgt	fix_stk
1207	bra	force_unf
1208mul_srcd:
1209	bsrl	ckinf_nd
1210	bne	fix_stk
1211	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
1212	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
1213	addl	%d1,%d0			|subtract src from dest
1214	bgt	fix_stk
1215
1216|
1217| This code handles the case of the instruction resulting in
1218| an underflow condition.
1219|
1220force_unf:
1221	bclrb	#E1,E_BYTE(%a6)
1222	orl	#unfinx_mask,USER_FPSR(%a6)
1223	clrw	NMNEXC(%a6)
1224	clrb	WBTEMP_SGN(%a6)
1225	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
1226	movew	FPTEMP_EX(%a6),%d1
1227	eorw	%d1,%d0
1228	andiw	#0x8000,%d0
1229	beqs	frcunfcont
1230	st	WBTEMP_SGN(%a6)
1231frcunfcont:
1232	lea	WBTEMP(%a6),%a0		|point a0 to memory location
1233	movew	CMDREG1B(%a6),%d0
1234	btstl	#6,%d0			|test for forced precision
1235	beqs	frcunf_fpcr
1236	btstl	#2,%d0			|check for double
1237	bnes	frcunf_dbl
1238	movel	#0x1,%d0			|inst is forced single
1239	bras	frcunf_rnd
1240frcunf_dbl:
1241	movel	#0x2,%d0			|inst is forced double
1242	bras	frcunf_rnd
1243frcunf_fpcr:
1244	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
1245frcunf_rnd:
1246	bsrl	unf_sub			|get correct result based on
1247|					;round precision/mode.  This
1248|					;sets FPSR_CC correctly
1249	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1250	beqs	frcfpn
1251	bsetb	#sign_bit,WBTEMP_EX(%a6)
1252	bra	frcfpn
1253
1254|
1255| Write the result to the user's fpn.  All results must be HUGE to be
1256| written; otherwise the results would have overflowed or underflowed.
1257| If the rounding precision is single or double, the ovf_res routine
1258| is needed to correctly supply the max value.
1259|
1260frcfpnr:
1261	movew	CMDREG1B(%a6),%d0
1262	btstl	#6,%d0			|test for forced precision
1263	beqs	frcfpn_fpcr
1264	btstl	#2,%d0			|check for double
1265	bnes	frcfpn_dbl
1266	movel	#0x1,%d0			|inst is forced single
1267	bras	frcfpn_rnd
1268frcfpn_dbl:
1269	movel	#0x2,%d0			|inst is forced double
1270	bras	frcfpn_rnd
1271frcfpn_fpcr:
1272	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
1273	tstb	%d0
1274	beqs	frcfpn			|if extended, write what you got
1275frcfpn_rnd:
1276	bclrb	#sign_bit,WBTEMP_EX(%a6)
1277	sne	WBTEMP_SGN(%a6)
1278	bsrl	ovf_res			|get correct result based on
1279|					;round precision/mode.  This
1280|					;sets FPSR_CC correctly
1281	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
1282	beqs	frcfpn_clr
1283	bsetb	#sign_bit,WBTEMP_EX(%a6)
1284frcfpn_clr:
1285	orl	#ovfinx_mask,USER_FPSR(%a6)
1286|
1287| Perform the write.
1288|
1289frcfpn:
1290	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
1291	cmpib	#3,%d0
1292	bles	frc0123			|check if dest is fp0-fp3
1293	movel	#7,%d1
1294	subl	%d0,%d1
1295	clrl	%d0
1296	bsetl	%d1,%d0
1297	fmovemx WBTEMP(%a6),%d0
1298	rts
1299frc0123:
1300	cmpib	#0,%d0
1301	beqs	frc0_dst
1302	cmpib	#1,%d0
1303	beqs	frc1_dst
1304	cmpib	#2,%d0
1305	beqs	frc2_dst
1306frc3_dst:
1307	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
1308	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
1309	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
1310	rts
1311frc2_dst:
1312	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
1313	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
1314	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
1315	rts
1316frc1_dst:
1317	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
1318	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
1319	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
1320	rts
1321frc0_dst:
1322	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
1323	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
1324	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
1325	rts
1326
1327|
1328| Write etemp to fpn.
1329| A check is made on enabled and signalled snan exceptions,
1330| and the destination is not overwritten if this condition exists.
1331| This code is designed to make fmoveins of unsupported data types
1332| faster.
1333|
1334wr_etemp:
1335	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
1336	beqs	fmoveinc		|enabled, force restore
1337	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
1338	beqs	fmoveinc		|the dest
1339	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1340|						;snan handler
1341	tstb	ETEMP(%a6)		|check for negative
1342	blts	snan_neg
1343	rts
1344snan_neg:
1345	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
1346	rts
1347fmoveinc:
1348	clrw	NMNEXC(%a6)
1349	bclrb	#E1,E_BYTE(%a6)
1350	moveb	STAG(%a6),%d0		|check if stag is inf
1351	andib	#0xe0,%d0
1352	cmpib	#0x40,%d0
1353	bnes	fminc_cnan
1354	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1355	tstw	LOCAL_EX(%a0)		|check sign
1356	bges	fminc_con
1357	orl	#neg_mask,USER_FPSR(%a6)
1358	bra	fminc_con
1359fminc_cnan:
1360	cmpib	#0x60,%d0			|check if stag is NaN
1361	bnes	fminc_czero
1362	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
1363	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1364|						;snan handler
1365	tstw	LOCAL_EX(%a0)		|check sign
1366	bges	fminc_con
1367	orl	#neg_mask,USER_FPSR(%a6)
1368	bra	fminc_con
1369fminc_czero:
1370	cmpib	#0x20,%d0			|check if zero
1371	bnes	fminc_con
1372	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
1373	tstw	LOCAL_EX(%a0)		|check sign
1374	bges	fminc_con
1375	orl	#neg_mask,USER_FPSR(%a6)
1376fminc_con:
1377	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
1378	cmpib	#3,%d0
1379	bles	fp0123			|check if dest is fp0-fp3
1380	movel	#7,%d1
1381	subl	%d0,%d1
1382	clrl	%d0
1383	bsetl	%d1,%d0
1384	fmovemx ETEMP(%a6),%d0
1385	rts
1386
1387fp0123:
1388	cmpib	#0,%d0
1389	beqs	fp0_dst
1390	cmpib	#1,%d0
1391	beqs	fp1_dst
1392	cmpib	#2,%d0
1393	beqs	fp2_dst
1394fp3_dst:
1395	movel	ETEMP_EX(%a6),USER_FP3(%a6)
1396	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
1397	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
1398	rts
1399fp2_dst:
1400	movel	ETEMP_EX(%a6),USER_FP2(%a6)
1401	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
1402	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
1403	rts
1404fp1_dst:
1405	movel	ETEMP_EX(%a6),USER_FP1(%a6)
1406	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
1407	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
1408	rts
1409fp0_dst:
1410	movel	ETEMP_EX(%a6),USER_FP0(%a6)
1411	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
1412	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
1413	rts
1414
1415opclass3:
1416	st	CU_ONLY(%a6)
1417	movew	CMDREG1B(%a6),%d0	|check if packed moveout
1418	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
1419	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
1420	beq	pack_out	|else it is norm or denorm
1421	bra	mv_out
1422
1423
1424|
1425|	MOVE OUT
1426|
1427
1428mv_tbl:
1429	.long	li
1430	.long	sgp
1431	.long	xp
1432	.long	mvout_end	|should never be taken
1433	.long	wi
1434	.long	dp
1435	.long	bi
1436	.long	mvout_end	|should never be taken
1437mv_out:
1438	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
1439	leal	mv_tbl,%a0
1440	movel	%a0@(%d1:l:4),%a0
1441	jmp	(%a0)
1442
1443|
1444| This exit is for move-out to memory.  The aunfl bit is
1445| set if the result is inex and unfl is signalled.
1446|
1447mvout_end:
1448	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
1449	beqs	no_aufl
1450	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
1451	beqs	no_aufl
1452	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
1453no_aufl:
1454	clrw	NMNEXC(%a6)
1455	bclrb	#E1,E_BYTE(%a6)
1456	fmovel	#0,%FPSR			|clear any cc bits from res_func
1457|
1458| Return ETEMP to extended format from internal extended format so
1459| that gen_except will have a correctly signed value for ovfl/unfl
1460| handlers.
1461|
1462	bfclr	ETEMP_SGN(%a6){#0:#8}
1463	beqs	mvout_con
1464	bsetb	#sign_bit,ETEMP_EX(%a6)
1465mvout_con:
1466	rts
1467|
1468| This exit is for move-out to int register.  The aunfl bit is
1469| not set in any case for this move.
1470|
1471mvouti_end:
1472	clrw	NMNEXC(%a6)
1473	bclrb	#E1,E_BYTE(%a6)
1474	fmovel	#0,%FPSR			|clear any cc bits from res_func
1475|
1476| Return ETEMP to extended format from internal extended format so
1477| that gen_except will have a correctly signed value for ovfl/unfl
1478| handlers.
1479|
1480	bfclr	ETEMP_SGN(%a6){#0:#8}
1481	beqs	mvouti_con
1482	bsetb	#sign_bit,ETEMP_EX(%a6)
1483mvouti_con:
1484	rts
1485|
1486| li is used to handle a long integer source specifier
1487|
1488
1489li:
1490	moveql	#4,%d0		|set byte count
1491
1492	btstb	#7,STAG(%a6)	|check for extended denorm
1493	bne	int_dnrm	|if so, branch
1494
1495	fmovemx ETEMP(%a6),%fp0-%fp0
1496	fcmpd	#0x41dfffffffc00000,%fp0
1497| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1498	fbge	lo_plrg
1499	fcmpd	#0xc1e0000000000000,%fp0
1500| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1501	fble	lo_nlrg
1502|
1503| at this point, the answer is between the largest pos and neg values
1504|
1505	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1506	andil	#0x30,%d1
1507	fmovel	%d1,%fpcr
1508	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1509	fmovel %fpsr,%d1
1510	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1511	bra	int_wrt
1512
1513
1514lo_plrg:
1515	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
1516	fbeq	int_wrt			|exact answer
1517	fcmpd	#0x41dfffffffe00000,%fp0
1518| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1519	fbge	int_operr		|set operr
1520	bra	int_inx			|set inexact
1521
1522lo_nlrg:
1523	movel	#0x80000000,L_SCR1(%a6)
1524	fbeq	int_wrt			|exact answer
1525	fcmpd	#0xc1e0000000100000,%fp0
1526| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1527	fblt	int_operr		|set operr
1528	bra	int_inx			|set inexact
1529
1530|
1531| wi is used to handle a word integer source specifier
1532|
1533
1534wi:
1535	moveql	#2,%d0		|set byte count
1536
1537	btstb	#7,STAG(%a6)	|check for extended denorm
1538	bne	int_dnrm	|branch if so
1539
1540	fmovemx ETEMP(%a6),%fp0-%fp0
1541	fcmps	#0x46fffe00,%fp0
1542| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1543	fbge	wo_plrg
1544	fcmps	#0xc7000000,%fp0
1545| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1546	fble	wo_nlrg
1547
1548|
1549| at this point, the answer is between the largest pos and neg values
1550|
1551	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1552	andil	#0x30,%d1
1553	fmovel	%d1,%fpcr
1554	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1555	fmovel %fpsr,%d1
1556	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1557	bra	int_wrt
1558
1559wo_plrg:
1560	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
1561	fbeq	int_wrt			|exact answer
1562	fcmps	#0x46ffff00,%fp0
1563| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1564	fbge	int_operr		|set operr
1565	bra	int_inx			|set inexact
1566
1567wo_nlrg:
1568	movew	#0x8000,L_SCR1(%a6)
1569	fbeq	int_wrt			|exact answer
1570	fcmps	#0xc7000080,%fp0
1571| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1572	fblt	int_operr		|set operr
1573	bra	int_inx			|set inexact
1574
1575|
1576| bi is used to handle a byte integer source specifier
1577|
1578
1579bi:
1580	moveql	#1,%d0		|set byte count
1581
1582	btstb	#7,STAG(%a6)	|check for extended denorm
1583	bne	int_dnrm	|branch if so
1584
1585	fmovemx ETEMP(%a6),%fp0-%fp0
1586	fcmps	#0x42fe0000,%fp0
1587| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1588	fbge	by_plrg
1589	fcmps	#0xc3000000,%fp0
1590| c3000000 in sgl prec = c00600008000000000000000 in ext prec
1591	fble	by_nlrg
1592
1593|
1594| at this point, the answer is between the largest pos and neg values
1595|
1596	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
1597	andil	#0x30,%d1
1598	fmovel	%d1,%fpcr
1599	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
1600	fmovel %fpsr,%d1
1601	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
1602	bra	int_wrt
1603
1604by_plrg:
1605	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
1606	fbeq	int_wrt			|exact answer
1607	fcmps	#0x42ff0000,%fp0
1608| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1609	fbge	int_operr		|set operr
1610	bra	int_inx			|set inexact
1611
1612by_nlrg:
1613	moveb	#0x80,L_SCR1(%a6)
1614	fbeq	int_wrt			|exact answer
1615	fcmps	#0xc3008000,%fp0
1616| c3008000 in sgl prec = c00600008080000000000000 in ext prec
1617	fblt	int_operr		|set operr
1618	bra	int_inx			|set inexact
1619
1620|
1621| Common integer routines
1622|
1623| int_drnrm---account for possible nonzero result for round up with positive
1624| operand and round down for negative answer.  In the first case (result = 1)
1625| byte-width (store in d0) of result must be honored.  In the second case,
1626| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1627
1628int_dnrm:
1629	movel	#0,L_SCR1(%a6)	| initialize result to 0
1630	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
1631	cmpb	#2,%d1
1632	bmis	int_inx		| if RN or RZ, done
1633	bnes	int_rp		| if RP, continue below
1634	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
1635	bpls	int_inx		| otherwise result is 0
1636	movel	#-1,L_SCR1(%a6)
1637	bras	int_inx
1638int_rp:
1639	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
1640|				; source is greater than 0
1641	bmis	int_inx		| otherwise, result is 0
1642	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
1643	addal	%d0,%a1		| offset by destination width -1
1644	subal	#1,%a1
1645	bsetb	#0,(%a1)		| set low bit at a1 address
1646int_inx:
1647	oril	#inx2a_mask,USER_FPSR(%a6)
1648	bras	int_wrt
1649int_operr:
1650	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
1651|				;precision source that needs to be
1652|				;converted to integer this is required
1653|				;if the operr exception is enabled.
1654|				;set operr/aiop (no inex2 on int ovfl)
1655
1656	oril	#opaop_mask,USER_FPSR(%a6)
1657|				;fall through to perform int_wrt
1658int_wrt:
1659	movel	EXC_EA(%a6),%a1	|load destination address
1660	tstl	%a1		|check to see if it is a dest register
1661	beqs	wrt_dn		|write data register
1662	lea	L_SCR1(%a6),%a0	|point to supervisor source address
1663	bsrl	mem_write
1664	bra	mvouti_end
1665
1666wrt_dn:
1667	movel	%d0,-(%sp)	|d0 currently contains the size to write
1668	bsrl	get_fline	|get_fline returns Dn in d0
1669	andiw	#0x7,%d0		|isolate register
1670	movel	(%sp)+,%d1	|get size
1671	cmpil	#4,%d1		|most frequent case
1672	beqs	sz_long
1673	cmpil	#2,%d1
1674	bnes	sz_con
1675	orl	#8,%d0		|add 'word' size to register#
1676	bras	sz_con
1677sz_long:
1678	orl	#0x10,%d0		|add 'long' size to register#
1679sz_con:
1680	movel	%d0,%d1		|reg_dest expects size:reg in d1
1681	bsrl	reg_dest	|load proper data register
1682	bra	mvouti_end
1683xp:
1684	lea	ETEMP(%a6),%a0
1685	bclrb	#sign_bit,LOCAL_EX(%a0)
1686	sne	LOCAL_SGN(%a0)
1687	btstb	#7,STAG(%a6)	|check for extended denorm
1688	bne	xdnrm
1689	clrl	%d0
1690	bras	do_fp		|do normal case
1691sgp:
1692	lea	ETEMP(%a6),%a0
1693	bclrb	#sign_bit,LOCAL_EX(%a0)
1694	sne	LOCAL_SGN(%a0)
1695	btstb	#7,STAG(%a6)	|check for extended denorm
1696	bne	sp_catas	|branch if so
1697	movew	LOCAL_EX(%a0),%d0
1698	lea	sp_bnds,%a1
1699	cmpw	(%a1),%d0
1700	blt	sp_under
1701	cmpw	2(%a1),%d0
1702	bgt	sp_over
1703	movel	#1,%d0		|set destination format to single
1704	bras	do_fp		|do normal case
1705dp:
1706	lea	ETEMP(%a6),%a0
1707	bclrb	#sign_bit,LOCAL_EX(%a0)
1708	sne	LOCAL_SGN(%a0)
1709
1710	btstb	#7,STAG(%a6)	|check for extended denorm
1711	bne	dp_catas	|branch if so
1712
1713	movew	LOCAL_EX(%a0),%d0
1714	lea	dp_bnds,%a1
1715
1716	cmpw	(%a1),%d0
1717	blt	dp_under
1718	cmpw	2(%a1),%d0
1719	bgt	dp_over
1720
1721	movel	#2,%d0		|set destination format to double
1722|				;fall through to do_fp
1723|
1724do_fp:
1725	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
1726	swap	%d0			|rnd prec in upper word
1727	addl	%d0,%d1			|d1 has PREC/MODE info
1728
1729	clrl	%d0			|clear g,r,s
1730
1731	bsrl	round			|round
1732
1733	movel	%a0,%a1
1734	movel	EXC_EA(%a6),%a0
1735
1736	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
1737|					;at this point only the dest
1738|					;formats sgl, dbl, ext are
1739|					;possible
1740	cmpb	#2,%d1
1741	bgts	ddbl			|double=5, extended=2, single=1
1742	bnes	dsgl
1743|					;fall through to dext
1744dext:
1745	bsrl	dest_ext
1746	bra	mvout_end
1747dsgl:
1748	bsrl	dest_sgl
1749	bra	mvout_end
1750ddbl:
1751	bsrl	dest_dbl
1752	bra	mvout_end
1753
1754|
1755| Handle possible denorm or catastrophic underflow cases here
1756|
1757xdnrm:
1758	bsr	set_xop		|initialize WBTEMP
1759	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
1760
1761	movel	%a0,%a1
1762	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1763	bsrl	dest_ext	|store to memory
1764	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1765	bra	mvout_end
1766
1767sp_under:
1768	bsetb	#etemp15_bit,STAG(%a6)
1769
1770	cmpw	4(%a1),%d0
1771	blts	sp_catas	|catastrophic underflow case
1772
1773	movel	#1,%d0		|load in round precision
1774	movel	#sgl_thresh,%d1	|load in single denorm threshold
1775	bsrl	dpspdnrm	|expects d1 to have the proper
1776|				;denorm threshold
1777	bsrl	dest_sgl	|stores value to destination
1778	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1779	bra	mvout_end	|exit
1780
1781dp_under:
1782	bsetb	#etemp15_bit,STAG(%a6)
1783
1784	cmpw	4(%a1),%d0
1785	blts	dp_catas	|catastrophic underflow case
1786
1787	movel	#dbl_thresh,%d1	|load in double precision threshold
1788	movel	#2,%d0
1789	bsrl	dpspdnrm	|expects d1 to have proper
1790|				;denorm threshold
1791|				;expects d0 to have round precision
1792	bsrl	dest_dbl	|store value to destination
1793	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
1794	bra	mvout_end	|exit
1795
1796|
1797| Handle catastrophic underflow cases here
1798|
1799sp_catas:
1800| Temp fix for z bit set in unf_sub
1801	movel	USER_FPSR(%a6),-(%a7)
1802
1803	movel	#1,%d0		|set round precision to sgl
1804
1805	bsrl	unf_sub		|a0 points to result
1806
1807	movel	(%a7)+,USER_FPSR(%a6)
1808
1809	movel	#1,%d0
1810	subw	%d0,LOCAL_EX(%a0) |account for difference between
1811|				;denorm/norm bias
1812
1813	movel	%a0,%a1		|a1 has the operand input
1814	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1815
1816	bsrl	dest_sgl	|store the result
1817	oril	#unfinx_mask,USER_FPSR(%a6)
1818	bra	mvout_end
1819
1820dp_catas:
1821| Temp fix for z bit set in unf_sub
1822	movel	USER_FPSR(%a6),-(%a7)
1823
1824	movel	#2,%d0		|set round precision to dbl
1825	bsrl	unf_sub		|a0 points to result
1826
1827	movel	(%a7)+,USER_FPSR(%a6)
1828
1829	movel	#1,%d0
1830	subw	%d0,LOCAL_EX(%a0) |account for difference between
1831|				;denorm/norm bias
1832
1833	movel	%a0,%a1		|a1 has the operand input
1834	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1835
1836	bsrl	dest_dbl	|store the result
1837	oril	#unfinx_mask,USER_FPSR(%a6)
1838	bra	mvout_end
1839
1840|
1841| Handle catastrophic overflow cases here
1842|
1843sp_over:
1844| Temp fix for z bit set in unf_sub
1845	movel	USER_FPSR(%a6),-(%a7)
1846
1847	movel	#1,%d0
1848	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
1849	movel	ETEMP_EX(%a6),(%a0)
1850	movel	ETEMP_HI(%a6),4(%a0)
1851	movel	ETEMP_LO(%a6),8(%a0)
1852	bsrl	ovf_res
1853
1854	movel	(%a7)+,USER_FPSR(%a6)
1855
1856	movel	%a0,%a1
1857	movel	EXC_EA(%a6),%a0
1858	bsrl	dest_sgl
1859	orl	#ovfinx_mask,USER_FPSR(%a6)
1860	bra	mvout_end
1861
1862dp_over:
1863| Temp fix for z bit set in ovf_res
1864	movel	USER_FPSR(%a6),-(%a7)
1865
1866	movel	#2,%d0
1867	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
1868	movel	ETEMP_EX(%a6),(%a0)
1869	movel	ETEMP_HI(%a6),4(%a0)
1870	movel	ETEMP_LO(%a6),8(%a0)
1871	bsrl	ovf_res
1872
1873	movel	(%a7)+,USER_FPSR(%a6)
1874
1875	movel	%a0,%a1
1876	movel	EXC_EA(%a6),%a0
1877	bsrl	dest_dbl
1878	orl	#ovfinx_mask,USER_FPSR(%a6)
1879	bra	mvout_end
1880
1881|
1882|	DPSPDNRM
1883|
1884| This subroutine takes an extended normalized number and denormalizes
1885| it to the given round precision. This subroutine also decrements
1886| the input operand's exponent by 1 to account for the fact that
1887| dest_sgl or dest_dbl expects a normalized number's bias.
1888|
1889| Input: a0  points to a normalized number in internal extended format
1890|	 d0  is the round precision (=1 for sgl; =2 for dbl)
1891|	 d1  is the single precision or double precision
1892|	     denorm threshold
1893|
1894| Output: (In the format for dest_sgl or dest_dbl)
1895|	 a0   points to the destination
1896|	 a1   points to the operand
1897|
1898| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1899|
1900dpspdnrm:
1901	movel	%d0,-(%a7)	|save round precision
1902	clrl	%d0		|clear initial g,r,s
1903	bsrl	dnrm_lp		|careful with d0, it's needed by round
1904
1905	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
1906	swap	%d1
1907	movew	2(%a7),%d1	|set rounding precision
1908	swap	%d1		|at this point d1 has PREC/MODE info
1909	bsrl	round		|round result, sets the inex bit in
1910|				;USER_FPSR if needed
1911
1912	movew	#1,%d0
1913	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
1914|				;vs norm bias
1915
1916	movel	%a0,%a1		|a1 has the operand input
1917	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
1918	addw	#4,%a7		|pop stack
1919	rts
1920|
1921| SET_XOP initialized WBTEMP with the value pointed to by a0
1922| input: a0 points to input operand in the internal extended format
1923|
1924set_xop:
1925	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
1926	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
1927	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
1928	bfclr	WBTEMP_SGN(%a6){#0:#8}
1929	beqs	sxop
1930	bsetb	#sign_bit,WBTEMP_EX(%a6)
1931sxop:
1932	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
1933	rts
1934|
1935|	P_MOVE
1936|
1937p_movet:
1938	.long	p_move
1939	.long	p_movez
1940	.long	p_movei
1941	.long	p_moven
1942	.long	p_move
1943p_regd:
1944	.long	p_dyd0
1945	.long	p_dyd1
1946	.long	p_dyd2
1947	.long	p_dyd3
1948	.long	p_dyd4
1949	.long	p_dyd5
1950	.long	p_dyd6
1951	.long	p_dyd7
1952
1953pack_out:
1954	leal	p_movet,%a0	|load jmp table address
1955	movew	STAG(%a6),%d0	|get source tag
1956	bfextu	%d0{#16:#3},%d0	|isolate source bits
1957	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
1958	jmp	(%a0)		|go to the routine
1959
1960p_write:
1961	movel	#0x0c,%d0	|get byte count
1962	movel	EXC_EA(%a6),%a1	|get the destination address
1963	bsr	mem_write	|write the user's destination
1964	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
1965
1966|
1967| Also note that the dtag must be set to norm here - this is because
1968| the 040 uses the dtag to execute the correct microcode.
1969|
1970        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
1971
1972	rts
1973
1974| Notes on handling of special case (zero, inf, and nan) inputs:
1975|	1. Operr is not signalled if the k-factor is greater than 18.
1976|	2. Per the manual, status bits are not set.
1977|
1978
1979p_move:
1980	movew	CMDREG1B(%a6),%d0
1981	btstl	#kfact_bit,%d0	|test for dynamic k-factor
1982	beqs	statick		|if clear, k-factor is static
1983dynamick:
1984	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
1985	lea	p_regd,%a0
1986	movel	%a0@(%d0:l:4),%a0
1987	jmp	(%a0)
1988statick:
1989	andiw	#0x007f,%d0	|get k-factor
1990	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
1991	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
1992	bsrl	bindec		|perform the convert; data at a6
1993	leal	FP_SCR1(%a6),%a0	|load a0 with result address
1994	bral	p_write
1995p_movez:
1996	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
1997	clrw	2(%a0)		|clear lower word of exp
1998	clrl	4(%a0)		|load second lword of ZERO
1999	clrl	8(%a0)		|load third lword of ZERO
2000	bra	p_write		|go write results
2001p_movei:
2002	fmovel	#0,%FPSR		|clear aiop
2003	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
2004	clrw	2(%a0)		|clear lower word of exp
2005	bra	p_write		|go write the result
2006p_moven:
2007	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
2008	clrw	2(%a0)		|clear lower word of exp
2009	bra	p_write		|go write the result
2010
2011|
2012| Routines to read the dynamic k-factor from Dn.
2013|
2014p_dyd0:
2015	movel	USER_D0(%a6),%d0
2016	bras	statick
2017p_dyd1:
2018	movel	USER_D1(%a6),%d0
2019	bras	statick
2020p_dyd2:
2021	movel	%d2,%d0
2022	bras	statick
2023p_dyd3:
2024	movel	%d3,%d0
2025	bras	statick
2026p_dyd4:
2027	movel	%d4,%d0
2028	bras	statick
2029p_dyd5:
2030	movel	%d5,%d0
2031	bras	statick
2032p_dyd6:
2033	movel	%d6,%d0
2034	bra	statick
2035p_dyd7:
2036	movel	%d7,%d0
2037	bra	statick
2038
2039	|end