File Index
Files and directories
Sign in
FILE

pfpsp.S

File preview with syntax highlighting.

linux-6.19.14/arch/m68k/ifpsp060/src/pfpsp.S S
    1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
    3M68000 Hi-Performance Microprocessor Division
    4M68060 Software Package
    5Production Release P1.00 -- October 10, 1994
    6
    7M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
    8
    9THE SOFTWARE is provided on an "AS IS" basis and without warranty.
   10To the maximum extent permitted by applicable law,
   11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
   12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
   13and any warranty against infringement with regard to the SOFTWARE
   14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
   15
   16To the maximum extent permitted by applicable law,
   17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
   18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
   19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
   20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
   21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
   22
   23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
   24so long as this entire notice is retained without alteration in any modified and/or
   25redistributed versions, and that such modified versions are clearly identified as such.
   26No licenses are granted by implication, estoppel or otherwise under any patents
   27or trademarks of Motorola, Inc.
   28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   29# freal.s:
   30#	This file is appended to the top of the 060FPSP package
   31# and contains the entry points into the package. The user, in
   32# effect, branches to one of the branch table entries located
   33# after _060FPSP_TABLE.
   34#	Also, subroutine stubs exist in this file (_fpsp_done for
   35# example) that are referenced by the FPSP package itself in order
   36# to call a given routine. The stub routine actually performs the
   37# callout. The FPSP code does a "bsr" to the stub routine. This
   38# extra layer of hierarchy adds a slight performance penalty but
   39# it makes the FPSP code easier to read and more mainatinable.
   40#
   41
   42set	_off_bsun,	0x00
   43set	_off_snan,	0x04
   44set	_off_operr,	0x08
   45set	_off_ovfl,	0x0c
   46set	_off_unfl,	0x10
   47set	_off_dz,	0x14
   48set	_off_inex,	0x18
   49set	_off_fline,	0x1c
   50set	_off_fpu_dis,	0x20
   51set	_off_trap,	0x24
   52set	_off_trace,	0x28
   53set	_off_access,	0x2c
   54set	_off_done,	0x30
   55
   56set	_off_imr,	0x40
   57set	_off_dmr,	0x44
   58set	_off_dmw,	0x48
   59set	_off_irw,	0x4c
   60set	_off_irl,	0x50
   61set	_off_drb,	0x54
   62set	_off_drw,	0x58
   63set	_off_drl,	0x5c
   64set	_off_dwb,	0x60
   65set	_off_dww,	0x64
   66set	_off_dwl,	0x68
   67
   68_060FPSP_TABLE:
   69
   70###############################################################
   71
   72# Here's the table of ENTRY POINTS for those linking the package.
   73	bra.l		_fpsp_snan
   74	short		0x0000
   75	bra.l		_fpsp_operr
   76	short		0x0000
   77	bra.l		_fpsp_ovfl
   78	short		0x0000
   79	bra.l		_fpsp_unfl
   80	short		0x0000
   81	bra.l		_fpsp_dz
   82	short		0x0000
   83	bra.l		_fpsp_inex
   84	short		0x0000
   85	bra.l		_fpsp_fline
   86	short		0x0000
   87	bra.l		_fpsp_unsupp
   88	short		0x0000
   89	bra.l		_fpsp_effadd
   90	short		0x0000
   91
   92	space		56
   93
   94###############################################################
   95	global		_fpsp_done
   96_fpsp_done:
   97	mov.l		%d0,-(%sp)
   98	mov.l		(_060FPSP_TABLE-0x80+_off_done,%pc),%d0
   99	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  100	mov.l		0x4(%sp),%d0
  101	rtd		&0x4
  102
  103	global		_real_ovfl
  104_real_ovfl:
  105	mov.l		%d0,-(%sp)
  106	mov.l		(_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
  107	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  108	mov.l		0x4(%sp),%d0
  109	rtd		&0x4
  110
  111	global		_real_unfl
  112_real_unfl:
  113	mov.l		%d0,-(%sp)
  114	mov.l		(_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
  115	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  116	mov.l		0x4(%sp),%d0
  117	rtd		&0x4
  118
  119	global		_real_inex
  120_real_inex:
  121	mov.l		%d0,-(%sp)
  122	mov.l		(_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
  123	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  124	mov.l		0x4(%sp),%d0
  125	rtd		&0x4
  126
  127	global		_real_bsun
  128_real_bsun:
  129	mov.l		%d0,-(%sp)
  130	mov.l		(_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
  131	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  132	mov.l		0x4(%sp),%d0
  133	rtd		&0x4
  134
  135	global		_real_operr
  136_real_operr:
  137	mov.l		%d0,-(%sp)
  138	mov.l		(_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
  139	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  140	mov.l		0x4(%sp),%d0
  141	rtd		&0x4
  142
  143	global		_real_snan
  144_real_snan:
  145	mov.l		%d0,-(%sp)
  146	mov.l		(_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
  147	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  148	mov.l		0x4(%sp),%d0
  149	rtd		&0x4
  150
  151	global		_real_dz
  152_real_dz:
  153	mov.l		%d0,-(%sp)
  154	mov.l		(_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
  155	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  156	mov.l		0x4(%sp),%d0
  157	rtd		&0x4
  158
  159	global		_real_fline
  160_real_fline:
  161	mov.l		%d0,-(%sp)
  162	mov.l		(_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
  163	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  164	mov.l		0x4(%sp),%d0
  165	rtd		&0x4
  166
  167	global		_real_fpu_disabled
  168_real_fpu_disabled:
  169	mov.l		%d0,-(%sp)
  170	mov.l		(_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
  171	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  172	mov.l		0x4(%sp),%d0
  173	rtd		&0x4
  174
  175	global		_real_trap
  176_real_trap:
  177	mov.l		%d0,-(%sp)
  178	mov.l		(_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
  179	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  180	mov.l		0x4(%sp),%d0
  181	rtd		&0x4
  182
  183	global		_real_trace
  184_real_trace:
  185	mov.l		%d0,-(%sp)
  186	mov.l		(_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
  187	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  188	mov.l		0x4(%sp),%d0
  189	rtd		&0x4
  190
  191	global		_real_access
  192_real_access:
  193	mov.l		%d0,-(%sp)
  194	mov.l		(_060FPSP_TABLE-0x80+_off_access,%pc),%d0
  195	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  196	mov.l		0x4(%sp),%d0
  197	rtd		&0x4
  198
  199#######################################
  200
  201	global		_imem_read
  202_imem_read:
  203	mov.l		%d0,-(%sp)
  204	mov.l		(_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
  205	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  206	mov.l		0x4(%sp),%d0
  207	rtd		&0x4
  208
  209	global		_dmem_read
  210_dmem_read:
  211	mov.l		%d0,-(%sp)
  212	mov.l		(_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
  213	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  214	mov.l		0x4(%sp),%d0
  215	rtd		&0x4
  216
  217	global		_dmem_write
  218_dmem_write:
  219	mov.l		%d0,-(%sp)
  220	mov.l		(_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
  221	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  222	mov.l		0x4(%sp),%d0
  223	rtd		&0x4
  224
  225	global		_imem_read_word
  226_imem_read_word:
  227	mov.l		%d0,-(%sp)
  228	mov.l		(_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
  229	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  230	mov.l		0x4(%sp),%d0
  231	rtd		&0x4
  232
  233	global		_imem_read_long
  234_imem_read_long:
  235	mov.l		%d0,-(%sp)
  236	mov.l		(_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
  237	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  238	mov.l		0x4(%sp),%d0
  239	rtd		&0x4
  240
  241	global		_dmem_read_byte
  242_dmem_read_byte:
  243	mov.l		%d0,-(%sp)
  244	mov.l		(_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
  245	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  246	mov.l		0x4(%sp),%d0
  247	rtd		&0x4
  248
  249	global		_dmem_read_word
  250_dmem_read_word:
  251	mov.l		%d0,-(%sp)
  252	mov.l		(_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
  253	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  254	mov.l		0x4(%sp),%d0
  255	rtd		&0x4
  256
  257	global		_dmem_read_long
  258_dmem_read_long:
  259	mov.l		%d0,-(%sp)
  260	mov.l		(_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
  261	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  262	mov.l		0x4(%sp),%d0
  263	rtd		&0x4
  264
  265	global		_dmem_write_byte
  266_dmem_write_byte:
  267	mov.l		%d0,-(%sp)
  268	mov.l		(_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
  269	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  270	mov.l		0x4(%sp),%d0
  271	rtd		&0x4
  272
  273	global		_dmem_write_word
  274_dmem_write_word:
  275	mov.l		%d0,-(%sp)
  276	mov.l		(_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
  277	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  278	mov.l		0x4(%sp),%d0
  279	rtd		&0x4
  280
  281	global		_dmem_write_long
  282_dmem_write_long:
  283	mov.l		%d0,-(%sp)
  284	mov.l		(_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
  285	pea.l		(_060FPSP_TABLE-0x80,%pc,%d0)
  286	mov.l		0x4(%sp),%d0
  287	rtd		&0x4
  288
  289#
  290# This file contains a set of define statements for constants
  291# in order to promote readability within the corecode itself.
  292#
  293
  294set LOCAL_SIZE,		192			# stack frame size(bytes)
  295set LV,			-LOCAL_SIZE		# stack offset
  296
  297set EXC_SR,		0x4			# stack status register
  298set EXC_PC,		0x6			# stack pc
  299set EXC_VOFF,		0xa			# stacked vector offset
  300set EXC_EA,		0xc			# stacked <ea>
  301
  302set EXC_FP,		0x0			# frame pointer
  303
  304set EXC_AREGS,		-68			# offset of all address regs
  305set EXC_DREGS,		-100			# offset of all data regs
  306set EXC_FPREGS,		-36			# offset of all fp regs
  307
  308set EXC_A7,		EXC_AREGS+(7*4)		# offset of saved a7
  309set OLD_A7,		EXC_AREGS+(6*4)		# extra copy of saved a7
  310set EXC_A6,		EXC_AREGS+(6*4)		# offset of saved a6
  311set EXC_A5,		EXC_AREGS+(5*4)
  312set EXC_A4,		EXC_AREGS+(4*4)
  313set EXC_A3,		EXC_AREGS+(3*4)
  314set EXC_A2,		EXC_AREGS+(2*4)
  315set EXC_A1,		EXC_AREGS+(1*4)
  316set EXC_A0,		EXC_AREGS+(0*4)
  317set EXC_D7,		EXC_DREGS+(7*4)
  318set EXC_D6,		EXC_DREGS+(6*4)
  319set EXC_D5,		EXC_DREGS+(5*4)
  320set EXC_D4,		EXC_DREGS+(4*4)
  321set EXC_D3,		EXC_DREGS+(3*4)
  322set EXC_D2,		EXC_DREGS+(2*4)
  323set EXC_D1,		EXC_DREGS+(1*4)
  324set EXC_D0,		EXC_DREGS+(0*4)
  325
  326set EXC_FP0,		EXC_FPREGS+(0*12)	# offset of saved fp0
  327set EXC_FP1,		EXC_FPREGS+(1*12)	# offset of saved fp1
  328set EXC_FP2,		EXC_FPREGS+(2*12)	# offset of saved fp2 (not used)
  329
  330set FP_SCR1,		LV+80			# fp scratch 1
  331set FP_SCR1_EX,		FP_SCR1+0
  332set FP_SCR1_SGN,	FP_SCR1+2
  333set FP_SCR1_HI,		FP_SCR1+4
  334set FP_SCR1_LO,		FP_SCR1+8
  335
  336set FP_SCR0,		LV+68			# fp scratch 0
  337set FP_SCR0_EX,		FP_SCR0+0
  338set FP_SCR0_SGN,	FP_SCR0+2
  339set FP_SCR0_HI,		FP_SCR0+4
  340set FP_SCR0_LO,		FP_SCR0+8
  341
  342set FP_DST,		LV+56			# fp destination operand
  343set FP_DST_EX,		FP_DST+0
  344set FP_DST_SGN,		FP_DST+2
  345set FP_DST_HI,		FP_DST+4
  346set FP_DST_LO,		FP_DST+8
  347
  348set FP_SRC,		LV+44			# fp source operand
  349set FP_SRC_EX,		FP_SRC+0
  350set FP_SRC_SGN,		FP_SRC+2
  351set FP_SRC_HI,		FP_SRC+4
  352set FP_SRC_LO,		FP_SRC+8
  353
  354set USER_FPIAR,		LV+40			# FP instr address register
  355
  356set USER_FPSR,		LV+36			# FP status register
  357set FPSR_CC,		USER_FPSR+0		# FPSR condition codes
  358set FPSR_QBYTE,		USER_FPSR+1		# FPSR qoutient byte
  359set FPSR_EXCEPT,	USER_FPSR+2		# FPSR exception status byte
  360set FPSR_AEXCEPT,	USER_FPSR+3		# FPSR accrued exception byte
  361
  362set USER_FPCR,		LV+32			# FP control register
  363set FPCR_ENABLE,	USER_FPCR+2		# FPCR exception enable
  364set FPCR_MODE,		USER_FPCR+3		# FPCR rounding mode control
  365
  366set L_SCR3,		LV+28			# integer scratch 3
  367set L_SCR2,		LV+24			# integer scratch 2
  368set L_SCR1,		LV+20			# integer scratch 1
  369
  370set STORE_FLG,		LV+19			# flag: operand store (ie. not fcmp/ftst)
  371
  372set EXC_TEMP2,		LV+24			# temporary space
  373set EXC_TEMP,		LV+16			# temporary space
  374
  375set DTAG,		LV+15			# destination operand type
  376set STAG,		LV+14			# source operand type
  377
  378set SPCOND_FLG,		LV+10			# flag: special case (see below)
  379
  380set EXC_CC,		LV+8			# saved condition codes
  381set EXC_EXTWPTR,	LV+4			# saved current PC (active)
  382set EXC_EXTWORD,	LV+2			# saved extension word
  383set EXC_CMDREG,		LV+2			# saved extension word
  384set EXC_OPWORD,		LV+0			# saved operation word
  385
  386################################
  387
  388# Helpful macros
  389
  390set FTEMP,		0			# offsets within an
  391set FTEMP_EX,		0			# extended precision
  392set FTEMP_SGN,		2			# value saved in memory.
  393set FTEMP_HI,		4
  394set FTEMP_LO,		8
  395set FTEMP_GRS,		12
  396
  397set LOCAL,		0			# offsets within an
  398set LOCAL_EX,		0			# extended precision
  399set LOCAL_SGN,		2			# value saved in memory.
  400set LOCAL_HI,		4
  401set LOCAL_LO,		8
  402set LOCAL_GRS,		12
  403
  404set DST,		0			# offsets within an
  405set DST_EX,		0			# extended precision
  406set DST_HI,		4			# value saved in memory.
  407set DST_LO,		8
  408
  409set SRC,		0			# offsets within an
  410set SRC_EX,		0			# extended precision
  411set SRC_HI,		4			# value saved in memory.
  412set SRC_LO,		8
  413
  414set SGL_LO,		0x3f81			# min sgl prec exponent
  415set SGL_HI,		0x407e			# max sgl prec exponent
  416set DBL_LO,		0x3c01			# min dbl prec exponent
  417set DBL_HI,		0x43fe			# max dbl prec exponent
  418set EXT_LO,		0x0			# min ext prec exponent
  419set EXT_HI,		0x7ffe			# max ext prec exponent
  420
  421set EXT_BIAS,		0x3fff			# extended precision bias
  422set SGL_BIAS,		0x007f			# single precision bias
  423set DBL_BIAS,		0x03ff			# double precision bias
  424
  425set NORM,		0x00			# operand type for STAG/DTAG
  426set ZERO,		0x01			# operand type for STAG/DTAG
  427set INF,		0x02			# operand type for STAG/DTAG
  428set QNAN,		0x03			# operand type for STAG/DTAG
  429set DENORM,		0x04			# operand type for STAG/DTAG
  430set SNAN,		0x05			# operand type for STAG/DTAG
  431set UNNORM,		0x06			# operand type for STAG/DTAG
  432
  433##################
  434# FPSR/FPCR bits #
  435##################
  436set neg_bit,		0x3			# negative result
  437set z_bit,		0x2			# zero result
  438set inf_bit,		0x1			# infinite result
  439set nan_bit,		0x0			# NAN result
  440
  441set q_sn_bit,		0x7			# sign bit of quotient byte
  442
  443set bsun_bit,		7			# branch on unordered
  444set snan_bit,		6			# signalling NAN
  445set operr_bit,		5			# operand error
  446set ovfl_bit,		4			# overflow
  447set unfl_bit,		3			# underflow
  448set dz_bit,		2			# divide by zero
  449set inex2_bit,		1			# inexact result 2
  450set inex1_bit,		0			# inexact result 1
  451
  452set aiop_bit,		7			# accrued inexact operation bit
  453set aovfl_bit,		6			# accrued overflow bit
  454set aunfl_bit,		5			# accrued underflow bit
  455set adz_bit,		4			# accrued dz bit
  456set ainex_bit,		3			# accrued inexact bit
  457
  458#############################
  459# FPSR individual bit masks #
  460#############################
  461set neg_mask,		0x08000000		# negative bit mask (lw)
  462set inf_mask,		0x02000000		# infinity bit mask (lw)
  463set z_mask,		0x04000000		# zero bit mask (lw)
  464set nan_mask,		0x01000000		# nan bit mask (lw)
  465
  466set neg_bmask,		0x08			# negative bit mask (byte)
  467set inf_bmask,		0x02			# infinity bit mask (byte)
  468set z_bmask,		0x04			# zero bit mask (byte)
  469set nan_bmask,		0x01			# nan bit mask (byte)
  470
  471set bsun_mask,		0x00008000		# bsun exception mask
  472set snan_mask,		0x00004000		# snan exception mask
  473set operr_mask,		0x00002000		# operr exception mask
  474set ovfl_mask,		0x00001000		# overflow exception mask
  475set unfl_mask,		0x00000800		# underflow exception mask
  476set dz_mask,		0x00000400		# dz exception mask
  477set inex2_mask,		0x00000200		# inex2 exception mask
  478set inex1_mask,		0x00000100		# inex1 exception mask
  479
  480set aiop_mask,		0x00000080		# accrued illegal operation
  481set aovfl_mask,		0x00000040		# accrued overflow
  482set aunfl_mask,		0x00000020		# accrued underflow
  483set adz_mask,		0x00000010		# accrued divide by zero
  484set ainex_mask,		0x00000008		# accrued inexact
  485
  486######################################
  487# FPSR combinations used in the FPSP #
  488######################################
  489set dzinf_mask,		inf_mask+dz_mask+adz_mask
  490set opnan_mask,		nan_mask+operr_mask+aiop_mask
  491set nzi_mask,		0x01ffffff		#clears N, Z, and I
  492set unfinx_mask,	unfl_mask+inex2_mask+aunfl_mask+ainex_mask
  493set unf2inx_mask,	unfl_mask+inex2_mask+ainex_mask
  494set ovfinx_mask,	ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
  495set inx1a_mask,		inex1_mask+ainex_mask
  496set inx2a_mask,		inex2_mask+ainex_mask
  497set snaniop_mask,	nan_mask+snan_mask+aiop_mask
  498set snaniop2_mask,	snan_mask+aiop_mask
  499set naniop_mask,	nan_mask+aiop_mask
  500set neginf_mask,	neg_mask+inf_mask
  501set infaiop_mask,	inf_mask+aiop_mask
  502set negz_mask,		neg_mask+z_mask
  503set opaop_mask,		operr_mask+aiop_mask
  504set unfl_inx_mask,	unfl_mask+aunfl_mask+ainex_mask
  505set ovfl_inx_mask,	ovfl_mask+aovfl_mask+ainex_mask
  506
  507#########
  508# misc. #
  509#########
  510set rnd_stky_bit,	29			# stky bit pos in longword
  511
  512set sign_bit,		0x7			# sign bit
  513set signan_bit,		0x6			# signalling nan bit
  514
  515set sgl_thresh,		0x3f81			# minimum sgl exponent
  516set dbl_thresh,		0x3c01			# minimum dbl exponent
  517
  518set x_mode,		0x0			# extended precision
  519set s_mode,		0x4			# single precision
  520set d_mode,		0x8			# double precision
  521
  522set rn_mode,		0x0			# round-to-nearest
  523set rz_mode,		0x1			# round-to-zero
  524set rm_mode,		0x2			# round-tp-minus-infinity
  525set rp_mode,		0x3			# round-to-plus-infinity
  526
  527set mantissalen,	64			# length of mantissa in bits
  528
  529set BYTE,		1			# len(byte) == 1 byte
  530set WORD,		2			# len(word) == 2 bytes
  531set LONG,		4			# len(longword) == 2 bytes
  532
  533set BSUN_VEC,		0xc0			# bsun    vector offset
  534set INEX_VEC,		0xc4			# inexact vector offset
  535set DZ_VEC,		0xc8			# dz      vector offset
  536set UNFL_VEC,		0xcc			# unfl    vector offset
  537set OPERR_VEC,		0xd0			# operr   vector offset
  538set OVFL_VEC,		0xd4			# ovfl    vector offset
  539set SNAN_VEC,		0xd8			# snan    vector offset
  540
  541###########################
  542# SPecial CONDition FLaGs #
  543###########################
  544set ftrapcc_flg,	0x01			# flag bit: ftrapcc exception
  545set fbsun_flg,		0x02			# flag bit: bsun exception
  546set mia7_flg,		0x04			# flag bit: (a7)+ <ea>
  547set mda7_flg,		0x08			# flag bit: -(a7) <ea>
  548set fmovm_flg,		0x40			# flag bit: fmovm instruction
  549set immed_flg,		0x80			# flag bit: &<data> <ea>
  550
  551set ftrapcc_bit,	0x0
  552set fbsun_bit,		0x1
  553set mia7_bit,		0x2
  554set mda7_bit,		0x3
  555set immed_bit,		0x7
  556
  557##################################
  558# TRANSCENDENTAL "LAST-OP" FLAGS #
  559##################################
  560set FMUL_OP,		0x0			# fmul instr performed last
  561set FDIV_OP,		0x1			# fdiv performed last
  562set FADD_OP,		0x2			# fadd performed last
  563set FMOV_OP,		0x3			# fmov performed last
  564
  565#############
  566# CONSTANTS #
  567#############
  568T1:	long		0x40C62D38,0xD3D64634	# 16381 LOG2 LEAD
  569T2:	long		0x3D6F90AE,0xB1E75CC7	# 16381 LOG2 TRAIL
  570
  571PI:	long		0x40000000,0xC90FDAA2,0x2168C235,0x00000000
  572PIBY2:	long		0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
  573
  574TWOBYPI:
  575	long		0x3FE45F30,0x6DC9C883
  576
  577#########################################################################
  578# XDEF ****************************************************************	#
  579#	_fpsp_ovfl(): 060FPSP entry point for FP Overflow exception.	#
  580#									#
  581#	This handler should be the first code executed upon taking the	#
  582#	FP Overflow exception in an operating system.			#
  583#									#
  584# XREF ****************************************************************	#
  585#	_imem_read_long() - read instruction longword			#
  586#	fix_skewed_ops() - adjust src operand in fsave frame		#
  587#	set_tag_x() - determine optype of src/dst operands		#
  588#	store_fpreg() - store opclass 0 or 2 result to FP regfile	#
  589#	unnorm_fix() - change UNNORM operands to NORM or ZERO		#
  590#	load_fpn2() - load dst operand from FP regfile			#
  591#	fout() - emulate an opclass 3 instruction			#
  592#	tbl_unsupp - add of table of emulation routines for opclass 0,2	#
  593#	_fpsp_done() - "callout" for 060FPSP exit (all work done!)	#
  594#	_real_ovfl() - "callout" for Overflow exception enabled code	#
  595#	_real_inex() - "callout" for Inexact exception enabled code	#
  596#	_real_trace() - "callout" for Trace exception code		#
  597#									#
  598# INPUT ***************************************************************	#
  599#	- The system stack contains the FP Ovfl exception stack frame	#
  600#	- The fsave frame contains the source operand			#
  601#									#
  602# OUTPUT **************************************************************	#
  603#	Overflow Exception enabled:					#
  604#	- The system stack is unchanged					#
  605#	- The fsave frame contains the adjusted src op for opclass 0,2	#
  606#	Overflow Exception disabled:					#
  607#	- The system stack is unchanged					#
  608#	- The "exception present" flag in the fsave frame is cleared	#
  609#									#
  610# ALGORITHM ***********************************************************	#
  611#	On the 060, if an FP overflow is present as the result of any	#
  612# instruction, the 060 will take an overflow exception whether the	#
  613# exception is enabled or disabled in the FPCR. For the disabled case,	#
  614# This handler emulates the instruction to determine what the correct	#
  615# default result should be for the operation. This default result is	#
  616# then stored in either the FP regfile, data regfile, or memory.	#
  617# Finally, the handler exits through the "callout" _fpsp_done()		#
  618# denoting that no exceptional conditions exist within the machine.	#
  619#	If the exception is enabled, then this handler must create the	#
  620# exceptional operand and plave it in the fsave state frame, and store	#
  621# the default result (only if the instruction is opclass 3). For	#
  622# exceptions enabled, this handler must exit through the "callout"	#
  623# _real_ovfl() so that the operating system enabled overflow handler	#
  624# can handle this case.							#
  625#	Two other conditions exist. First, if overflow was disabled	#
  626# but the inexact exception was enabled, this handler must exit		#
  627# through the "callout" _real_inex() regardless of whether the result	#
  628# was inexact.								#
  629#	Also, in the case of an opclass three instruction where		#
  630# overflow was disabled and the trace exception was enabled, this	#
  631# handler must exit through the "callout" _real_trace().		#
  632#									#
  633#########################################################################
  634
  635	global		_fpsp_ovfl
  636_fpsp_ovfl:
  637
  638#$#	sub.l		&24,%sp			# make room for src/dst
  639
  640	link.w		%a6,&-LOCAL_SIZE	# init stack frame
  641
  642	fsave		FP_SRC(%a6)		# grab the "busy" frame
  643
  644	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
  645	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
  646	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
  647
  648# the FPIAR holds the "current PC" of the faulting instruction
  649	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
  650	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
  651	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
  652	bsr.l		_imem_read_long		# fetch the instruction words
  653	mov.l		%d0,EXC_OPWORD(%a6)
  654
  655##############################################################################
  656
  657	btst		&0x5,EXC_CMDREG(%a6)	# is instr an fmove out?
  658	bne.w		fovfl_out
  659
  660
  661	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
  662	bsr.l		fix_skewed_ops		# fix src op
  663
  664# since, I believe, only NORMs and DENORMs can come through here,
  665# maybe we can avoid the subroutine call.
  666	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
  667	bsr.l		set_tag_x		# tag the operand type
  668	mov.b		%d0,STAG(%a6)		# maybe NORM,DENORM
  669
  670# bit five of the fp extension word separates the monadic and dyadic operations
  671# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
  672# will never take this exception.
  673	btst		&0x5,1+EXC_CMDREG(%a6)	# is operation monadic or dyadic?
  674	beq.b		fovfl_extract		# monadic
  675
  676	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
  677	bsr.l		load_fpn2		# load dst into FP_DST
  678
  679	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
  680	bsr.l		set_tag_x		# tag the operand type
  681	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
  682	bne.b		fovfl_op2_done		# no
  683	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
  684fovfl_op2_done:
  685	mov.b		%d0,DTAG(%a6)		# save dst optype tag
  686
  687fovfl_extract:
  688
  689#$#	mov.l		FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
  690#$#	mov.l		FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
  691#$#	mov.l		FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
  692#$#	mov.l		FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
  693#$#	mov.l		FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
  694#$#	mov.l		FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
  695
  696	clr.l		%d0
  697	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec/mode
  698
  699	mov.b		1+EXC_CMDREG(%a6),%d1
  700	andi.w		&0x007f,%d1		# extract extension
  701
  702	andi.l		&0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
  703
  704	fmov.l		&0x0,%fpcr		# zero current control regs
  705	fmov.l		&0x0,%fpsr
  706
  707	lea		FP_SRC(%a6),%a0
  708	lea		FP_DST(%a6),%a1
  709
  710# maybe we can make these entry points ONLY the OVFL entry points of each routine.
  711	mov.l		(tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
  712	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
  713
  714# the operation has been emulated. the result is in fp0.
  715# the EXOP, if an exception occurred, is in fp1.
  716# we must save the default result regardless of whether
  717# traps are enabled or disabled.
  718	bfextu		EXC_CMDREG(%a6){&6:&3},%d0
  719	bsr.l		store_fpreg
  720
  721# the exceptional possibilities we have left ourselves with are ONLY overflow
  722# and inexact. and, the inexact is such that overflow occurred and was disabled
  723# but inexact was enabled.
  724	btst		&ovfl_bit,FPCR_ENABLE(%a6)
  725	bne.b		fovfl_ovfl_on
  726
  727	btst		&inex2_bit,FPCR_ENABLE(%a6)
  728	bne.b		fovfl_inex_on
  729
  730	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
  731	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
  732	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
  733
  734	unlk		%a6
  735#$#	add.l		&24,%sp
  736	bra.l		_fpsp_done
  737
  738# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
  739# in fp1. now, simply jump to _real_ovfl()!
  740fovfl_ovfl_on:
  741	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP (fp1) to stack
  742
  743	mov.w		&0xe005,2+FP_SRC(%a6)	# save exc status
  744
  745	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
  746	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
  747	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
  748
  749	frestore	FP_SRC(%a6)		# do this after fmovm,other f<op>s!
  750
  751	unlk		%a6
  752
  753	bra.l		_real_ovfl
  754
  755# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
  756# we must jump to real_inex().
  757fovfl_inex_on:
  758
  759	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP (fp1) to stack
  760
  761	mov.b		&0xc4,1+EXC_VOFF(%a6)	# vector offset = 0xc4
  762	mov.w		&0xe001,2+FP_SRC(%a6)	# save exc status
  763
  764	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
  765	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
  766	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
  767
  768	frestore	FP_SRC(%a6)		# do this after fmovm,other f<op>s!
  769
  770	unlk		%a6
  771
  772	bra.l		_real_inex
  773
  774########################################################################
  775fovfl_out:
  776
  777
  778#$#	mov.l		FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
  779#$#	mov.l		FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
  780#$#	mov.l		FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
  781
  782# the src operand is definitely a NORM(!), so tag it as such
  783	mov.b		&NORM,STAG(%a6)		# set src optype tag
  784
  785	clr.l		%d0
  786	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec/mode
  787
  788	and.l		&0xffff00ff,USER_FPSR(%a6) # zero all but accured field
  789
  790	fmov.l		&0x0,%fpcr		# zero current control regs
  791	fmov.l		&0x0,%fpsr
  792
  793	lea		FP_SRC(%a6),%a0		# pass ptr to src operand
  794
  795	bsr.l		fout
  796
  797	btst		&ovfl_bit,FPCR_ENABLE(%a6)
  798	bne.w		fovfl_ovfl_on
  799
  800	btst		&inex2_bit,FPCR_ENABLE(%a6)
  801	bne.w		fovfl_inex_on
  802
  803	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
  804	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
  805	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
  806
  807	unlk		%a6
  808#$#	add.l		&24,%sp
  809
  810	btst		&0x7,(%sp)		# is trace on?
  811	beq.l		_fpsp_done		# no
  812
  813	fmov.l		%fpiar,0x8(%sp)		# "Current PC" is in FPIAR
  814	mov.w		&0x2024,0x6(%sp)	# stk fmt = 0x2; voff = 0x024
  815	bra.l		_real_trace
  816
  817#########################################################################
  818# XDEF ****************************************************************	#
  819#	_fpsp_unfl(): 060FPSP entry point for FP Underflow exception.	#
  820#									#
  821#	This handler should be the first code executed upon taking the	#
  822#	FP Underflow exception in an operating system.			#
  823#									#
  824# XREF ****************************************************************	#
  825#	_imem_read_long() - read instruction longword			#
  826#	fix_skewed_ops() - adjust src operand in fsave frame		#
  827#	set_tag_x() - determine optype of src/dst operands		#
  828#	store_fpreg() - store opclass 0 or 2 result to FP regfile	#
  829#	unnorm_fix() - change UNNORM operands to NORM or ZERO		#
  830#	load_fpn2() - load dst operand from FP regfile			#
  831#	fout() - emulate an opclass 3 instruction			#
  832#	tbl_unsupp - add of table of emulation routines for opclass 0,2	#
  833#	_fpsp_done() - "callout" for 060FPSP exit (all work done!)	#
  834#	_real_ovfl() - "callout" for Overflow exception enabled code	#
  835#	_real_inex() - "callout" for Inexact exception enabled code	#
  836#	_real_trace() - "callout" for Trace exception code		#
  837#									#
  838# INPUT ***************************************************************	#
  839#	- The system stack contains the FP Unfl exception stack frame	#
  840#	- The fsave frame contains the source operand			#
  841#									#
  842# OUTPUT **************************************************************	#
  843#	Underflow Exception enabled:					#
  844#	- The system stack is unchanged					#
  845#	- The fsave frame contains the adjusted src op for opclass 0,2	#
  846#	Underflow Exception disabled:					#
  847#	- The system stack is unchanged					#
  848#	- The "exception present" flag in the fsave frame is cleared	#
  849#									#
  850# ALGORITHM ***********************************************************	#
  851#	On the 060, if an FP underflow is present as the result of any	#
  852# instruction, the 060 will take an underflow exception whether the	#
  853# exception is enabled or disabled in the FPCR. For the disabled case,	#
  854# This handler emulates the instruction to determine what the correct	#
  855# default result should be for the operation. This default result is	#
  856# then stored in either the FP regfile, data regfile, or memory.	#
  857# Finally, the handler exits through the "callout" _fpsp_done()		#
  858# denoting that no exceptional conditions exist within the machine.	#
  859#	If the exception is enabled, then this handler must create the	#
  860# exceptional operand and plave it in the fsave state frame, and store	#
  861# the default result (only if the instruction is opclass 3). For	#
  862# exceptions enabled, this handler must exit through the "callout"	#
  863# _real_unfl() so that the operating system enabled overflow handler	#
  864# can handle this case.							#
  865#	Two other conditions exist. First, if underflow was disabled	#
  866# but the inexact exception was enabled and the result was inexact,	#
  867# this handler must exit through the "callout" _real_inex().		#
  868# was inexact.								#
  869#	Also, in the case of an opclass three instruction where		#
  870# underflow was disabled and the trace exception was enabled, this	#
  871# handler must exit through the "callout" _real_trace().		#
  872#									#
  873#########################################################################
  874
  875	global		_fpsp_unfl
  876_fpsp_unfl:
  877
  878#$#	sub.l		&24,%sp			# make room for src/dst
  879
  880	link.w		%a6,&-LOCAL_SIZE	# init stack frame
  881
  882	fsave		FP_SRC(%a6)		# grab the "busy" frame
  883
  884	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
  885	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
  886	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
  887
  888# the FPIAR holds the "current PC" of the faulting instruction
  889	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
  890	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
  891	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
  892	bsr.l		_imem_read_long		# fetch the instruction words
  893	mov.l		%d0,EXC_OPWORD(%a6)
  894
  895##############################################################################
  896
  897	btst		&0x5,EXC_CMDREG(%a6)	# is instr an fmove out?
  898	bne.w		funfl_out
  899
  900
  901	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
  902	bsr.l		fix_skewed_ops		# fix src op
  903
  904	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
  905	bsr.l		set_tag_x		# tag the operand type
  906	mov.b		%d0,STAG(%a6)		# maybe NORM,DENORM
  907
  908# bit five of the fp ext word separates the monadic and dyadic operations
  909# that can pass through fpsp_unfl(). remember that fcmp, and ftst
  910# will never take this exception.
  911	btst		&0x5,1+EXC_CMDREG(%a6)	# is op monadic or dyadic?
  912	beq.b		funfl_extract		# monadic
  913
  914# now, what's left that's not dyadic is fsincos. we can distinguish it
  915# from all dyadics by the '0110xxx pattern
  916	btst		&0x4,1+EXC_CMDREG(%a6)	# is op an fsincos?
  917	bne.b		funfl_extract		# yes
  918
  919	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
  920	bsr.l		load_fpn2		# load dst into FP_DST
  921
  922	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
  923	bsr.l		set_tag_x		# tag the operand type
  924	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
  925	bne.b		funfl_op2_done		# no
  926	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
  927funfl_op2_done:
  928	mov.b		%d0,DTAG(%a6)		# save dst optype tag
  929
  930funfl_extract:
  931
  932#$#	mov.l		FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
  933#$#	mov.l		FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
  934#$#	mov.l		FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
  935#$#	mov.l		FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
  936#$#	mov.l		FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
  937#$#	mov.l		FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
  938
  939	clr.l		%d0
  940	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec/mode
  941
  942	mov.b		1+EXC_CMDREG(%a6),%d1
  943	andi.w		&0x007f,%d1		# extract extension
  944
  945	andi.l		&0x00ff01ff,USER_FPSR(%a6)
  946
  947	fmov.l		&0x0,%fpcr		# zero current control regs
  948	fmov.l		&0x0,%fpsr
  949
  950	lea		FP_SRC(%a6),%a0
  951	lea		FP_DST(%a6),%a1
  952
  953# maybe we can make these entry points ONLY the OVFL entry points of each routine.
  954	mov.l		(tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
  955	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
  956
  957	bfextu		EXC_CMDREG(%a6){&6:&3},%d0
  958	bsr.l		store_fpreg
  959
  960# The `060 FPU multiplier hardware is such that if the result of a
  961# multiply operation is the smallest possible normalized number
  962# (0x00000000_80000000_00000000), then the machine will take an
  963# underflow exception. Since this is incorrect, we need to check
  964# if our emulation, after re-doing the operation, decided that
  965# no underflow was called for. We do these checks only in
  966# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
  967# special case will simply exit gracefully with the correct result.
  968
  969# the exceptional possibilities we have left ourselves with are ONLY overflow
  970# and inexact. and, the inexact is such that overflow occurred and was disabled
  971# but inexact was enabled.
  972	btst		&unfl_bit,FPCR_ENABLE(%a6)
  973	bne.b		funfl_unfl_on
  974
  975funfl_chkinex:
  976	btst		&inex2_bit,FPCR_ENABLE(%a6)
  977	bne.b		funfl_inex_on
  978
  979funfl_exit:
  980	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
  981	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
  982	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
  983
  984	unlk		%a6
  985#$#	add.l		&24,%sp
  986	bra.l		_fpsp_done
  987
  988# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
  989# in fp1 (don't forget to save fp0). what to do now?
  990# well, we simply have to get to go to _real_unfl()!
  991funfl_unfl_on:
  992
  993# The `060 FPU multiplier hardware is such that if the result of a
  994# multiply operation is the smallest possible normalized number
  995# (0x00000000_80000000_00000000), then the machine will take an
  996# underflow exception. Since this is incorrect, we check here to see
  997# if our emulation, after re-doing the operation, decided that
  998# no underflow was called for.
  999	btst		&unfl_bit,FPSR_EXCEPT(%a6)
 1000	beq.w		funfl_chkinex
 1001
 1002funfl_unfl_on2:
 1003	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP (fp1) to stack
 1004
 1005	mov.w		&0xe003,2+FP_SRC(%a6)	# save exc status
 1006
 1007	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 1008	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1009	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1010
 1011	frestore	FP_SRC(%a6)		# do this after fmovm,other f<op>s!
 1012
 1013	unlk		%a6
 1014
 1015	bra.l		_real_unfl
 1016
 1017# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
 1018# we must jump to real_inex().
 1019funfl_inex_on:
 1020
 1021# The `060 FPU multiplier hardware is such that if the result of a
 1022# multiply operation is the smallest possible normalized number
 1023# (0x00000000_80000000_00000000), then the machine will take an
 1024# underflow exception.
 1025# But, whether bogus or not, if inexact is enabled AND it occurred,
 1026# then we have to branch to real_inex.
 1027
 1028	btst		&inex2_bit,FPSR_EXCEPT(%a6)
 1029	beq.w		funfl_exit
 1030
 1031funfl_inex_on2:
 1032
 1033	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP to stack
 1034
 1035	mov.b		&0xc4,1+EXC_VOFF(%a6)	# vector offset = 0xc4
 1036	mov.w		&0xe001,2+FP_SRC(%a6)	# save exc status
 1037
 1038	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 1039	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1040	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1041
 1042	frestore	FP_SRC(%a6)		# do this after fmovm,other f<op>s!
 1043
 1044	unlk		%a6
 1045
 1046	bra.l		_real_inex
 1047
 1048#######################################################################
 1049funfl_out:
 1050
 1051
 1052#$#	mov.l		FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 1053#$#	mov.l		FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 1054#$#	mov.l		FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 1055
 1056# the src operand is definitely a NORM(!), so tag it as such
 1057	mov.b		&NORM,STAG(%a6)		# set src optype tag
 1058
 1059	clr.l		%d0
 1060	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec/mode
 1061
 1062	and.l		&0xffff00ff,USER_FPSR(%a6) # zero all but accured field
 1063
 1064	fmov.l		&0x0,%fpcr		# zero current control regs
 1065	fmov.l		&0x0,%fpsr
 1066
 1067	lea		FP_SRC(%a6),%a0		# pass ptr to src operand
 1068
 1069	bsr.l		fout
 1070
 1071	btst		&unfl_bit,FPCR_ENABLE(%a6)
 1072	bne.w		funfl_unfl_on2
 1073
 1074	btst		&inex2_bit,FPCR_ENABLE(%a6)
 1075	bne.w		funfl_inex_on2
 1076
 1077	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 1078	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1079	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1080
 1081	unlk		%a6
 1082#$#	add.l		&24,%sp
 1083
 1084	btst		&0x7,(%sp)		# is trace on?
 1085	beq.l		_fpsp_done		# no
 1086
 1087	fmov.l		%fpiar,0x8(%sp)		# "Current PC" is in FPIAR
 1088	mov.w		&0x2024,0x6(%sp)	# stk fmt = 0x2; voff = 0x024
 1089	bra.l		_real_trace
 1090
 1091#########################################################################
 1092# XDEF ****************************************************************	#
 1093#	_fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented	#
 1094#		        Data Type" exception.				#
 1095#									#
 1096#	This handler should be the first code executed upon taking the	#
 1097#	FP Unimplemented Data Type exception in an operating system.	#
 1098#									#
 1099# XREF ****************************************************************	#
 1100#	_imem_read_{word,long}() - read instruction word/longword	#
 1101#	fix_skewed_ops() - adjust src operand in fsave frame		#
 1102#	set_tag_x() - determine optype of src/dst operands		#
 1103#	store_fpreg() - store opclass 0 or 2 result to FP regfile	#
 1104#	unnorm_fix() - change UNNORM operands to NORM or ZERO		#
 1105#	load_fpn2() - load dst operand from FP regfile			#
 1106#	load_fpn1() - load src operand from FP regfile			#
 1107#	fout() - emulate an opclass 3 instruction			#
 1108#	tbl_unsupp - add of table of emulation routines for opclass 0,2	#
 1109#	_real_inex() - "callout" to operating system inexact handler	#
 1110#	_fpsp_done() - "callout" for exit; work all done		#
 1111#	_real_trace() - "callout" for Trace enabled exception		#
 1112#	funimp_skew() - adjust fsave src ops to "incorrect" value	#
 1113#	_real_snan() - "callout" for SNAN exception			#
 1114#	_real_operr() - "callout" for OPERR exception			#
 1115#	_real_ovfl() - "callout" for OVFL exception			#
 1116#	_real_unfl() - "callout" for UNFL exception			#
 1117#	get_packed() - fetch packed operand from memory			#
 1118#									#
 1119# INPUT ***************************************************************	#
 1120#	- The system stack contains the "Unimp Data Type" stk frame	#
 1121#	- The fsave frame contains the ssrc op (for UNNORM/DENORM)	#
 1122#									#
 1123# OUTPUT **************************************************************	#
 1124#	If Inexact exception (opclass 3):				#
 1125#	- The system stack is changed to an Inexact exception stk frame	#
 1126#	If SNAN exception (opclass 3):					#
 1127#	- The system stack is changed to an SNAN exception stk frame	#
 1128#	If OPERR exception (opclass 3):					#
 1129#	- The system stack is changed to an OPERR exception stk frame	#
 1130#	If OVFL exception (opclass 3):					#
 1131#	- The system stack is changed to an OVFL exception stk frame	#
 1132#	If UNFL exception (opclass 3):					#
 1133#	- The system stack is changed to an UNFL exception stack frame	#
 1134#	If Trace exception enabled:					#
 1135#	- The system stack is changed to a Trace exception stack frame	#
 1136#	Else: (normal case)						#
 1137#	- Correct result has been stored as appropriate			#
 1138#									#
 1139# ALGORITHM ***********************************************************	#
 1140#	Two main instruction types can enter here: (1) DENORM or UNNORM	#
 1141# unimplemented data types. These can be either opclass 0,2 or 3	#
 1142# instructions, and (2) PACKED unimplemented data format instructions	#
 1143# also of opclasses 0,2, or 3.						#
 1144#	For UNNORM/DENORM opclass 0 and 2, the handler fetches the src	#
 1145# operand from the fsave state frame and the dst operand (if dyadic)	#
 1146# from the FP register file. The instruction is then emulated by	#
 1147# choosing an emulation routine from a table of routines indexed by	#
 1148# instruction type. Once the instruction has been emulated and result	#
 1149# saved, then we check to see if any enabled exceptions resulted from	#
 1150# instruction emulation. If none, then we exit through the "callout"	#
 1151# _fpsp_done(). If there is an enabled FP exception, then we insert	#
 1152# this exception into the FPU in the fsave state frame and then exit	#
 1153# through _fpsp_done().							#
 1154#	PACKED opclass 0 and 2 is similar in how the instruction is	#
 1155# emulated and exceptions handled. The differences occur in how the	#
 1156# handler loads the packed op (by calling get_packed() routine) and	#
 1157# by the fact that a Trace exception could be pending for PACKED ops.	#
 1158# If a Trace exception is pending, then the current exception stack	#
 1159# frame is changed to a Trace exception stack frame and an exit is	#
 1160# made through _real_trace().						#
 1161#	For UNNORM/DENORM opclass 3, the actual move out to memory is	#
 1162# performed by calling the routine fout(). If no exception should occur	#
 1163# as the result of emulation, then an exit either occurs through	#
 1164# _fpsp_done() or through _real_trace() if a Trace exception is pending	#
 1165# (a Trace stack frame must be created here, too). If an FP exception	#
 1166# should occur, then we must create an exception stack frame of that	#
 1167# type and jump to either _real_snan(), _real_operr(), _real_inex(),	#
 1168# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3	#
 1169# emulation is performed in a similar manner.				#
 1170#									#
 1171#########################################################################
 1172
 1173#
 1174# (1) DENORM and UNNORM (unimplemented) data types:
 1175#
 1176#				post-instruction
 1177#				*****************
 1178#				*      EA	*
 1179#	 pre-instruction	*		*
 1180#	*****************	*****************
 1181#	* 0x0 *  0x0dc  *	* 0x3 *  0x0dc  *
 1182#	*****************	*****************
 1183#	*     Next	*	*     Next	*
 1184#	*      PC	*	*      PC	*
 1185#	*****************	*****************
 1186#	*      SR	*	*      SR	*
 1187#	*****************	*****************
 1188#
 1189# (2) PACKED format (unsupported) opclasses two and three:
 1190#	*****************
 1191#	*      EA	*
 1192#	*		*
 1193#	*****************
 1194#	* 0x2 *  0x0dc	*
 1195#	*****************
 1196#	*     Next	*
 1197#	*      PC	*
 1198#	*****************
 1199#	*      SR	*
 1200#	*****************
 1201#
 1202	global		_fpsp_unsupp
 1203_fpsp_unsupp:
 1204
 1205	link.w		%a6,&-LOCAL_SIZE	# init stack frame
 1206
 1207	fsave		FP_SRC(%a6)		# save fp state
 1208
 1209	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 1210	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 1211	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 1212
 1213	btst		&0x5,EXC_SR(%a6)	# user or supervisor mode?
 1214	bne.b		fu_s
 1215fu_u:
 1216	mov.l		%usp,%a0		# fetch user stack pointer
 1217	mov.l		%a0,EXC_A7(%a6)		# save on stack
 1218	bra.b		fu_cont
 1219# if the exception is an opclass zero or two unimplemented data type
 1220# exception, then the a7' calculated here is wrong since it doesn't
 1221# stack an ea. however, we don't need an a7' for this case anyways.
 1222fu_s:
 1223	lea		0x4+EXC_EA(%a6),%a0	# load old a7'
 1224	mov.l		%a0,EXC_A7(%a6)		# save on stack
 1225
 1226fu_cont:
 1227
 1228# the FPIAR holds the "current PC" of the faulting instruction
 1229# the FPIAR should be set correctly for ALL exceptions passing through
 1230# this point.
 1231	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 1232	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 1233	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 1234	bsr.l		_imem_read_long		# fetch the instruction words
 1235	mov.l		%d0,EXC_OPWORD(%a6)	# store OPWORD and EXTWORD
 1236
 1237############################
 1238
 1239	clr.b		SPCOND_FLG(%a6)		# clear special condition flag
 1240
 1241# Separate opclass three (fpn-to-mem) ops since they have a different
 1242# stack frame and protocol.
 1243	btst		&0x5,EXC_CMDREG(%a6)	# is it an fmove out?
 1244	bne.w		fu_out			# yes
 1245
 1246# Separate packed opclass two instructions.
 1247	bfextu		EXC_CMDREG(%a6){&0:&6},%d0
 1248	cmpi.b		%d0,&0x13
 1249	beq.w		fu_in_pack
 1250
 1251
 1252# I'm not sure at this point what FPSR bits are valid for this instruction.
 1253# so, since the emulation routines re-create them anyways, zero exception field
 1254	andi.l		&0x00ff00ff,USER_FPSR(%a6) # zero exception field
 1255
 1256	fmov.l		&0x0,%fpcr		# zero current control regs
 1257	fmov.l		&0x0,%fpsr
 1258
 1259# Opclass two w/ memory-to-fpn operation will have an incorrect extended
 1260# precision format if the src format was single or double and the
 1261# source data type was an INF, NAN, DENORM, or UNNORM
 1262	lea		FP_SRC(%a6),%a0		# pass ptr to input
 1263	bsr.l		fix_skewed_ops
 1264
 1265# we don't know whether the src operand or the dst operand (or both) is the
 1266# UNNORM or DENORM. call the function that tags the operand type. if the
 1267# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
 1268	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 1269	bsr.l		set_tag_x		# tag the operand type
 1270	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 1271	bne.b		fu_op2			# no
 1272	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
 1273
 1274fu_op2:
 1275	mov.b		%d0,STAG(%a6)		# save src optype tag
 1276
 1277	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 1278
 1279# bit five of the fp extension word separates the monadic and dyadic operations
 1280# at this point
 1281	btst		&0x5,1+EXC_CMDREG(%a6)	# is operation monadic or dyadic?
 1282	beq.b		fu_extract		# monadic
 1283	cmpi.b		1+EXC_CMDREG(%a6),&0x3a	# is operation an ftst?
 1284	beq.b		fu_extract		# yes, so it's monadic, too
 1285
 1286	bsr.l		load_fpn2		# load dst into FP_DST
 1287
 1288	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
 1289	bsr.l		set_tag_x		# tag the operand type
 1290	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 1291	bne.b		fu_op2_done		# no
 1292	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
 1293fu_op2_done:
 1294	mov.b		%d0,DTAG(%a6)		# save dst optype tag
 1295
 1296fu_extract:
 1297	clr.l		%d0
 1298	mov.b		FPCR_MODE(%a6),%d0	# fetch rnd mode/prec
 1299
 1300	bfextu		1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
 1301
 1302	lea		FP_SRC(%a6),%a0
 1303	lea		FP_DST(%a6),%a1
 1304
 1305	mov.l		(tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
 1306	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
 1307
 1308#
 1309# Exceptions in order of precedence:
 1310#	BSUN	: none
 1311#	SNAN	: all dyadic ops
 1312#	OPERR	: fsqrt(-NORM)
 1313#	OVFL	: all except ftst,fcmp
 1314#	UNFL	: all except ftst,fcmp
 1315#	DZ	: fdiv
 1316#	INEX2	: all except ftst,fcmp
 1317#	INEX1	: none (packed doesn't go through here)
 1318#
 1319
 1320# we determine the highest priority exception(if any) set by the
 1321# emulation routine that has also been enabled by the user.
 1322	mov.b		FPCR_ENABLE(%a6),%d0	# fetch exceptions set
 1323	bne.b		fu_in_ena		# some are enabled
 1324
 1325fu_in_cont:
 1326# fcmp and ftst do not store any result.
 1327	mov.b		1+EXC_CMDREG(%a6),%d0	# fetch extension
 1328	andi.b		&0x38,%d0		# extract bits 3-5
 1329	cmpi.b		%d0,&0x38		# is instr fcmp or ftst?
 1330	beq.b		fu_in_exit		# yes
 1331
 1332	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 1333	bsr.l		store_fpreg		# store the result
 1334
 1335fu_in_exit:
 1336
 1337	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1338	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1339	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1340
 1341	unlk		%a6
 1342
 1343	bra.l		_fpsp_done
 1344
 1345fu_in_ena:
 1346	and.b		FPSR_EXCEPT(%a6),%d0	# keep only ones enabled
 1347	bfffo		%d0{&24:&8},%d0		# find highest priority exception
 1348	bne.b		fu_in_exc		# there is at least one set
 1349
 1350#
 1351# No exceptions occurred that were also enabled. Now:
 1352#
 1353#	if (OVFL && ovfl_disabled && inexact_enabled) {
 1354#	    branch to _real_inex() (even if the result was exact!);
 1355#	} else {
 1356#	    save the result in the proper fp reg (unless the op is fcmp or ftst);
 1357#	    return;
 1358#	}
 1359#
 1360	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 1361	beq.b		fu_in_cont		# no
 1362
 1363fu_in_ovflchk:
 1364	btst		&inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 1365	beq.b		fu_in_cont		# no
 1366	bra.w		fu_in_exc_ovfl		# go insert overflow frame
 1367
 1368#
 1369# An exception occurred and that exception was enabled:
 1370#
 1371#	shift enabled exception field into lo byte of d0;
 1372#	if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
 1373#	    ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
 1374#		/*
 1375#		 * this is the case where we must call _real_inex() now or else
 1376#		 * there will be no other way to pass it the exceptional operand
 1377#		 */
 1378#		call _real_inex();
 1379#	} else {
 1380#		restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
 1381#	}
 1382#
 1383fu_in_exc:
 1384	subi.l		&24,%d0			# fix offset to be 0-8
 1385	cmpi.b		%d0,&0x6		# is exception INEX? (6)
 1386	bne.b		fu_in_exc_exit		# no
 1387
 1388# the enabled exception was inexact
 1389	btst		&unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
 1390	bne.w		fu_in_exc_unfl		# yes
 1391	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
 1392	bne.w		fu_in_exc_ovfl		# yes
 1393
 1394# here, we insert the correct fsave status value into the fsave frame for the
 1395# corresponding exception. the operand in the fsave frame should be the original
 1396# src operand.
 1397fu_in_exc_exit:
 1398	mov.l		%d0,-(%sp)		# save d0
 1399	bsr.l		funimp_skew		# skew sgl or dbl inputs
 1400	mov.l		(%sp)+,%d0		# restore d0
 1401
 1402	mov.w		(tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
 1403
 1404	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1405	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1406	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1407
 1408	frestore	FP_SRC(%a6)		# restore src op
 1409
 1410	unlk		%a6
 1411
 1412	bra.l		_fpsp_done
 1413
 1414tbl_except:
 1415	short		0xe000,0xe006,0xe004,0xe005
 1416	short		0xe003,0xe002,0xe001,0xe001
 1417
 1418fu_in_exc_unfl:
 1419	mov.w		&0x4,%d0
 1420	bra.b		fu_in_exc_exit
 1421fu_in_exc_ovfl:
 1422	mov.w		&0x03,%d0
 1423	bra.b		fu_in_exc_exit
 1424
 1425# If the input operand to this operation was opclass two and a single
 1426# or double precision denorm, inf, or nan, the operand needs to be
 1427# "corrected" in order to have the proper equivalent extended precision
 1428# number.
 1429	global		fix_skewed_ops
 1430fix_skewed_ops:
 1431	bfextu		EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
 1432	cmpi.b		%d0,&0x11		# is class = 2 & fmt = sgl?
 1433	beq.b		fso_sgl			# yes
 1434	cmpi.b		%d0,&0x15		# is class = 2 & fmt = dbl?
 1435	beq.b		fso_dbl			# yes
 1436	rts					# no
 1437
 1438fso_sgl:
 1439	mov.w		LOCAL_EX(%a0),%d0	# fetch src exponent
 1440	andi.w		&0x7fff,%d0		# strip sign
 1441	cmpi.w		%d0,&0x3f80		# is |exp| == $3f80?
 1442	beq.b		fso_sgl_dnrm_zero	# yes
 1443	cmpi.w		%d0,&0x407f		# no; is |exp| == $407f?
 1444	beq.b		fso_infnan		# yes
 1445	rts					# no
 1446
 1447fso_sgl_dnrm_zero:
 1448	andi.l		&0x7fffffff,LOCAL_HI(%a0) # clear j-bit
 1449	beq.b		fso_zero		# it's a skewed zero
 1450fso_sgl_dnrm:
 1451# here, we count on norm not to alter a0...
 1452	bsr.l		norm			# normalize mantissa
 1453	neg.w		%d0			# -shft amt
 1454	addi.w		&0x3f81,%d0		# adjust new exponent
 1455	andi.w		&0x8000,LOCAL_EX(%a0)	# clear old exponent
 1456	or.w		%d0,LOCAL_EX(%a0)	# insert new exponent
 1457	rts
 1458
 1459fso_zero:
 1460	andi.w		&0x8000,LOCAL_EX(%a0)	# clear bogus exponent
 1461	rts
 1462
 1463fso_infnan:
 1464	andi.b		&0x7f,LOCAL_HI(%a0)	# clear j-bit
 1465	ori.w		&0x7fff,LOCAL_EX(%a0)	# make exponent = $7fff
 1466	rts
 1467
 1468fso_dbl:
 1469	mov.w		LOCAL_EX(%a0),%d0	# fetch src exponent
 1470	andi.w		&0x7fff,%d0		# strip sign
 1471	cmpi.w		%d0,&0x3c00		# is |exp| == $3c00?
 1472	beq.b		fso_dbl_dnrm_zero	# yes
 1473	cmpi.w		%d0,&0x43ff		# no; is |exp| == $43ff?
 1474	beq.b		fso_infnan		# yes
 1475	rts					# no
 1476
 1477fso_dbl_dnrm_zero:
 1478	andi.l		&0x7fffffff,LOCAL_HI(%a0) # clear j-bit
 1479	bne.b		fso_dbl_dnrm		# it's a skewed denorm
 1480	tst.l		LOCAL_LO(%a0)		# is it a zero?
 1481	beq.b		fso_zero		# yes
 1482fso_dbl_dnrm:
 1483# here, we count on norm not to alter a0...
 1484	bsr.l		norm			# normalize mantissa
 1485	neg.w		%d0			# -shft amt
 1486	addi.w		&0x3c01,%d0		# adjust new exponent
 1487	andi.w		&0x8000,LOCAL_EX(%a0)	# clear old exponent
 1488	or.w		%d0,LOCAL_EX(%a0)	# insert new exponent
 1489	rts
 1490
 1491#################################################################
 1492
 1493# fmove out took an unimplemented data type exception.
 1494# the src operand is in FP_SRC. Call _fout() to write out the result and
 1495# to determine which exceptions, if any, to take.
 1496fu_out:
 1497
 1498# Separate packed move outs from the UNNORM and DENORM move outs.
 1499	bfextu		EXC_CMDREG(%a6){&3:&3},%d0
 1500	cmpi.b		%d0,&0x3
 1501	beq.w		fu_out_pack
 1502	cmpi.b		%d0,&0x7
 1503	beq.w		fu_out_pack
 1504
 1505
 1506# I'm not sure at this point what FPSR bits are valid for this instruction.
 1507# so, since the emulation routines re-create them anyways, zero exception field.
 1508# fmove out doesn't affect ccodes.
 1509	and.l		&0xffff00ff,USER_FPSR(%a6) # zero exception field
 1510
 1511	fmov.l		&0x0,%fpcr		# zero current control regs
 1512	fmov.l		&0x0,%fpsr
 1513
 1514# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
 1515# call here. just figure out what it is...
 1516	mov.w		FP_SRC_EX(%a6),%d0	# get exponent
 1517	andi.w		&0x7fff,%d0		# strip sign
 1518	beq.b		fu_out_denorm		# it's a DENORM
 1519
 1520	lea		FP_SRC(%a6),%a0
 1521	bsr.l		unnorm_fix		# yes; fix it
 1522
 1523	mov.b		%d0,STAG(%a6)
 1524
 1525	bra.b		fu_out_cont
 1526fu_out_denorm:
 1527	mov.b		&DENORM,STAG(%a6)
 1528fu_out_cont:
 1529
 1530	clr.l		%d0
 1531	mov.b		FPCR_MODE(%a6),%d0	# fetch rnd mode/prec
 1532
 1533	lea		FP_SRC(%a6),%a0		# pass ptr to src operand
 1534
 1535	mov.l		(%a6),EXC_A6(%a6)	# in case a6 changes
 1536	bsr.l		fout			# call fmove out routine
 1537
 1538# Exceptions in order of precedence:
 1539#	BSUN	: none
 1540#	SNAN	: none
 1541#	OPERR	: fmove.{b,w,l} out of large UNNORM
 1542#	OVFL	: fmove.{s,d}
 1543#	UNFL	: fmove.{s,d,x}
 1544#	DZ	: none
 1545#	INEX2	: all
 1546#	INEX1	: none (packed doesn't travel through here)
 1547
 1548# determine the highest priority exception(if any) set by the
 1549# emulation routine that has also been enabled by the user.
 1550	mov.b		FPCR_ENABLE(%a6),%d0	# fetch exceptions enabled
 1551	bne.w		fu_out_ena		# some are enabled
 1552
 1553fu_out_done:
 1554
 1555	mov.l		EXC_A6(%a6),(%a6)	# in case a6 changed
 1556
 1557# on extended precision opclass three instructions using pre-decrement or
 1558# post-increment addressing mode, the address register is not updated. is the
 1559# address register was the stack pointer used from user mode, then let's update
 1560# it here. if it was used from supervisor mode, then we have to handle this
 1561# as a special case.
 1562	btst		&0x5,EXC_SR(%a6)
 1563	bne.b		fu_out_done_s
 1564
 1565	mov.l		EXC_A7(%a6),%a0		# restore a7
 1566	mov.l		%a0,%usp
 1567
 1568fu_out_done_cont:
 1569	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1570	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1571	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1572
 1573	unlk		%a6
 1574
 1575	btst		&0x7,(%sp)		# is trace on?
 1576	bne.b		fu_out_trace		# yes
 1577
 1578	bra.l		_fpsp_done
 1579
 1580# is the ea mode pre-decrement of the stack pointer from supervisor mode?
 1581# ("fmov.x fpm,-(a7)") if so,
 1582fu_out_done_s:
 1583	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 1584	bne.b		fu_out_done_cont
 1585
 1586# the extended precision result is still in fp0. but, we need to save it
 1587# somewhere on the stack until we can copy it to its final resting place.
 1588# here, we're counting on the top of the stack to be the old place-holders
 1589# for fp0/fp1 which have already been restored. that way, we can write
 1590# over those destinations with the shifted stack frame.
 1591	fmovm.x		&0x80,FP_SRC(%a6)	# put answer on stack
 1592
 1593	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1594	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1595	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1596
 1597	mov.l		(%a6),%a6		# restore frame pointer
 1598
 1599	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 1600	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 1601
 1602# now, copy the result to the proper place on the stack
 1603	mov.l		LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
 1604	mov.l		LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
 1605	mov.l		LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
 1606
 1607	add.l		&LOCAL_SIZE-0x8,%sp
 1608
 1609	btst		&0x7,(%sp)
 1610	bne.b		fu_out_trace
 1611
 1612	bra.l		_fpsp_done
 1613
 1614fu_out_ena:
 1615	and.b		FPSR_EXCEPT(%a6),%d0	# keep only ones enabled
 1616	bfffo		%d0{&24:&8},%d0		# find highest priority exception
 1617	bne.b		fu_out_exc		# there is at least one set
 1618
 1619# no exceptions were set.
 1620# if a disabled overflow occurred and inexact was enabled but the result
 1621# was exact, then a branch to _real_inex() is made.
 1622	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 1623	beq.w		fu_out_done		# no
 1624
 1625fu_out_ovflchk:
 1626	btst		&inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 1627	beq.w		fu_out_done		# no
 1628	bra.w		fu_inex			# yes
 1629
 1630#
 1631# The fp move out that took the "Unimplemented Data Type" exception was
 1632# being traced. Since the stack frames are similar, get the "current" PC
 1633# from FPIAR and put it in the trace stack frame then jump to _real_trace().
 1634#
 1635#		  UNSUPP FRAME		   TRACE FRAME
 1636#		*****************	*****************
 1637#		*      EA	*	*    Current	*
 1638#		*		*	*      PC	*
 1639#		*****************	*****************
 1640#		* 0x3 *  0x0dc	*	* 0x2 *  0x024	*
 1641#		*****************	*****************
 1642#		*     Next	*	*     Next	*
 1643#		*      PC	*	*      PC	*
 1644#		*****************	*****************
 1645#		*      SR	*	*      SR	*
 1646#		*****************	*****************
 1647#
 1648fu_out_trace:
 1649	mov.w		&0x2024,0x6(%sp)
 1650	fmov.l		%fpiar,0x8(%sp)
 1651	bra.l		_real_trace
 1652
 1653# an exception occurred and that exception was enabled.
 1654fu_out_exc:
 1655	subi.l		&24,%d0			# fix offset to be 0-8
 1656
 1657# we don't mess with the existing fsave frame. just re-insert it and
 1658# jump to the "_real_{}()" handler...
 1659	mov.w		(tbl_fu_out.b,%pc,%d0.w*2),%d0
 1660	jmp		(tbl_fu_out.b,%pc,%d0.w*1)
 1661
 1662	swbeg		&0x8
 1663tbl_fu_out:
 1664	short		tbl_fu_out	- tbl_fu_out	# BSUN can't happen
 1665	short		tbl_fu_out	- tbl_fu_out	# SNAN can't happen
 1666	short		fu_operr	- tbl_fu_out	# OPERR
 1667	short		fu_ovfl		- tbl_fu_out	# OVFL
 1668	short		fu_unfl		- tbl_fu_out	# UNFL
 1669	short		tbl_fu_out	- tbl_fu_out	# DZ can't happen
 1670	short		fu_inex		- tbl_fu_out	# INEX2
 1671	short		tbl_fu_out	- tbl_fu_out	# INEX1 won't make it here
 1672
 1673# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
 1674# frestore it.
 1675fu_snan:
 1676	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1677	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1678	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1679
 1680	mov.w		&0x30d8,EXC_VOFF(%a6)	# vector offset = 0xd8
 1681	mov.w		&0xe006,2+FP_SRC(%a6)
 1682
 1683	frestore	FP_SRC(%a6)
 1684
 1685	unlk		%a6
 1686
 1687
 1688	bra.l		_real_snan
 1689
 1690fu_operr:
 1691	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1692	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1693	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1694
 1695	mov.w		&0x30d0,EXC_VOFF(%a6)	# vector offset = 0xd0
 1696	mov.w		&0xe004,2+FP_SRC(%a6)
 1697
 1698	frestore	FP_SRC(%a6)
 1699
 1700	unlk		%a6
 1701
 1702
 1703	bra.l		_real_operr
 1704
 1705fu_ovfl:
 1706	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP to the stack
 1707
 1708	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1709	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1710	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1711
 1712	mov.w		&0x30d4,EXC_VOFF(%a6)	# vector offset = 0xd4
 1713	mov.w		&0xe005,2+FP_SRC(%a6)
 1714
 1715	frestore	FP_SRC(%a6)		# restore EXOP
 1716
 1717	unlk		%a6
 1718
 1719	bra.l		_real_ovfl
 1720
 1721# underflow can happen for extended precision. extended precision opclass
 1722# three instruction exceptions don't update the stack pointer. so, if the
 1723# exception occurred from user mode, then simply update a7 and exit normally.
 1724# if the exception occurred from supervisor mode, check if
 1725fu_unfl:
 1726	mov.l		EXC_A6(%a6),(%a6)	# restore a6
 1727
 1728	btst		&0x5,EXC_SR(%a6)
 1729	bne.w		fu_unfl_s
 1730
 1731	mov.l		EXC_A7(%a6),%a0		# restore a7 whether we need
 1732	mov.l		%a0,%usp		# to or not...
 1733
 1734fu_unfl_cont:
 1735	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP to the stack
 1736
 1737	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1738	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1739	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1740
 1741	mov.w		&0x30cc,EXC_VOFF(%a6)	# vector offset = 0xcc
 1742	mov.w		&0xe003,2+FP_SRC(%a6)
 1743
 1744	frestore	FP_SRC(%a6)		# restore EXOP
 1745
 1746	unlk		%a6
 1747
 1748	bra.l		_real_unfl
 1749
 1750fu_unfl_s:
 1751	cmpi.b		SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
 1752	bne.b		fu_unfl_cont
 1753
 1754# the extended precision result is still in fp0. but, we need to save it
 1755# somewhere on the stack until we can copy it to its final resting place
 1756# (where the exc frame is currently). make sure it's not at the top of the
 1757# frame or it will get overwritten when the exc stack frame is shifted "down".
 1758	fmovm.x		&0x80,FP_SRC(%a6)	# put answer on stack
 1759	fmovm.x		&0x40,FP_DST(%a6)	# put EXOP on stack
 1760
 1761	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1762	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1763	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1764
 1765	mov.w		&0x30cc,EXC_VOFF(%a6)	# vector offset = 0xcc
 1766	mov.w		&0xe003,2+FP_DST(%a6)
 1767
 1768	frestore	FP_DST(%a6)		# restore EXOP
 1769
 1770	mov.l		(%a6),%a6		# restore frame pointer
 1771
 1772	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 1773	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 1774	mov.l		LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
 1775
 1776# now, copy the result to the proper place on the stack
 1777	mov.l		LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
 1778	mov.l		LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
 1779	mov.l		LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
 1780
 1781	add.l		&LOCAL_SIZE-0x8,%sp
 1782
 1783	bra.l		_real_unfl
 1784
 1785# fmove in and out enter here.
 1786fu_inex:
 1787	fmovm.x		&0x40,FP_SRC(%a6)	# save EXOP to the stack
 1788
 1789	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1790	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1791	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1792
 1793	mov.w		&0x30c4,EXC_VOFF(%a6)	# vector offset = 0xc4
 1794	mov.w		&0xe001,2+FP_SRC(%a6)
 1795
 1796	frestore	FP_SRC(%a6)		# restore EXOP
 1797
 1798	unlk		%a6
 1799
 1800
 1801	bra.l		_real_inex
 1802
 1803#########################################################################
 1804#########################################################################
 1805fu_in_pack:
 1806
 1807
 1808# I'm not sure at this point what FPSR bits are valid for this instruction.
 1809# so, since the emulation routines re-create them anyways, zero exception field
 1810	andi.l		&0x0ff00ff,USER_FPSR(%a6) # zero exception field
 1811
 1812	fmov.l		&0x0,%fpcr		# zero current control regs
 1813	fmov.l		&0x0,%fpsr
 1814
 1815	bsr.l		get_packed		# fetch packed src operand
 1816
 1817	lea		FP_SRC(%a6),%a0		# pass ptr to src
 1818	bsr.l		set_tag_x		# set src optype tag
 1819
 1820	mov.b		%d0,STAG(%a6)		# save src optype tag
 1821
 1822	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 1823
 1824# bit five of the fp extension word separates the monadic and dyadic operations
 1825# at this point
 1826	btst		&0x5,1+EXC_CMDREG(%a6)	# is operation monadic or dyadic?
 1827	beq.b		fu_extract_p		# monadic
 1828	cmpi.b		1+EXC_CMDREG(%a6),&0x3a	# is operation an ftst?
 1829	beq.b		fu_extract_p		# yes, so it's monadic, too
 1830
 1831	bsr.l		load_fpn2		# load dst into FP_DST
 1832
 1833	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
 1834	bsr.l		set_tag_x		# tag the operand type
 1835	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 1836	bne.b		fu_op2_done_p		# no
 1837	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
 1838fu_op2_done_p:
 1839	mov.b		%d0,DTAG(%a6)		# save dst optype tag
 1840
 1841fu_extract_p:
 1842	clr.l		%d0
 1843	mov.b		FPCR_MODE(%a6),%d0	# fetch rnd mode/prec
 1844
 1845	bfextu		1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
 1846
 1847	lea		FP_SRC(%a6),%a0
 1848	lea		FP_DST(%a6),%a1
 1849
 1850	mov.l		(tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
 1851	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
 1852
 1853#
 1854# Exceptions in order of precedence:
 1855#	BSUN	: none
 1856#	SNAN	: all dyadic ops
 1857#	OPERR	: fsqrt(-NORM)
 1858#	OVFL	: all except ftst,fcmp
 1859#	UNFL	: all except ftst,fcmp
 1860#	DZ	: fdiv
 1861#	INEX2	: all except ftst,fcmp
 1862#	INEX1	: all
 1863#
 1864
 1865# we determine the highest priority exception(if any) set by the
 1866# emulation routine that has also been enabled by the user.
 1867	mov.b		FPCR_ENABLE(%a6),%d0	# fetch exceptions enabled
 1868	bne.w		fu_in_ena_p		# some are enabled
 1869
 1870fu_in_cont_p:
 1871# fcmp and ftst do not store any result.
 1872	mov.b		1+EXC_CMDREG(%a6),%d0	# fetch extension
 1873	andi.b		&0x38,%d0		# extract bits 3-5
 1874	cmpi.b		%d0,&0x38		# is instr fcmp or ftst?
 1875	beq.b		fu_in_exit_p		# yes
 1876
 1877	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 1878	bsr.l		store_fpreg		# store the result
 1879
 1880fu_in_exit_p:
 1881
 1882	btst		&0x5,EXC_SR(%a6)	# user or supervisor?
 1883	bne.w		fu_in_exit_s_p		# supervisor
 1884
 1885	mov.l		EXC_A7(%a6),%a0		# update user a7
 1886	mov.l		%a0,%usp
 1887
 1888fu_in_exit_cont_p:
 1889	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1890	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1891	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1892
 1893	unlk		%a6			# unravel stack frame
 1894
 1895	btst		&0x7,(%sp)		# is trace on?
 1896	bne.w		fu_trace_p		# yes
 1897
 1898	bra.l		_fpsp_done		# exit to os
 1899
 1900# the exception occurred in supervisor mode. check to see if the
 1901# addressing mode was (a7)+. if so, we'll need to shift the
 1902# stack frame "up".
 1903fu_in_exit_s_p:
 1904	btst		&mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
 1905	beq.b		fu_in_exit_cont_p	# no
 1906
 1907	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1908	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1909	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1910
 1911	unlk		%a6			# unravel stack frame
 1912
 1913# shift the stack frame "up". we don't really care about the <ea> field.
 1914	mov.l		0x4(%sp),0x10(%sp)
 1915	mov.l		0x0(%sp),0xc(%sp)
 1916	add.l		&0xc,%sp
 1917
 1918	btst		&0x7,(%sp)		# is trace on?
 1919	bne.w		fu_trace_p		# yes
 1920
 1921	bra.l		_fpsp_done		# exit to os
 1922
 1923fu_in_ena_p:
 1924	and.b		FPSR_EXCEPT(%a6),%d0	# keep only ones enabled & set
 1925	bfffo		%d0{&24:&8},%d0		# find highest priority exception
 1926	bne.b		fu_in_exc_p		# at least one was set
 1927
 1928#
 1929# No exceptions occurred that were also enabled. Now:
 1930#
 1931#	if (OVFL && ovfl_disabled && inexact_enabled) {
 1932#	    branch to _real_inex() (even if the result was exact!);
 1933#	} else {
 1934#	    save the result in the proper fp reg (unless the op is fcmp or ftst);
 1935#	    return;
 1936#	}
 1937#
 1938	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 1939	beq.w		fu_in_cont_p		# no
 1940
 1941fu_in_ovflchk_p:
 1942	btst		&inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 1943	beq.w		fu_in_cont_p		# no
 1944	bra.w		fu_in_exc_ovfl_p	# do _real_inex() now
 1945
 1946#
 1947# An exception occurred and that exception was enabled:
 1948#
 1949#	shift enabled exception field into lo byte of d0;
 1950#	if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
 1951#	    ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
 1952#		/*
 1953#		 * this is the case where we must call _real_inex() now or else
 1954#		 * there will be no other way to pass it the exceptional operand
 1955#		 */
 1956#		call _real_inex();
 1957#	} else {
 1958#		restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
 1959#	}
 1960#
 1961fu_in_exc_p:
 1962	subi.l		&24,%d0			# fix offset to be 0-8
 1963	cmpi.b		%d0,&0x6		# is exception INEX? (6 or 7)
 1964	blt.b		fu_in_exc_exit_p	# no
 1965
 1966# the enabled exception was inexact
 1967	btst		&unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
 1968	bne.w		fu_in_exc_unfl_p	# yes
 1969	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
 1970	bne.w		fu_in_exc_ovfl_p	# yes
 1971
 1972# here, we insert the correct fsave status value into the fsave frame for the
 1973# corresponding exception. the operand in the fsave frame should be the original
 1974# src operand.
 1975# as a reminder for future predicted pain and agony, we are passing in fsave the
 1976# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
 1977# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
 1978fu_in_exc_exit_p:
 1979	btst		&0x5,EXC_SR(%a6)	# user or supervisor?
 1980	bne.w		fu_in_exc_exit_s_p	# supervisor
 1981
 1982	mov.l		EXC_A7(%a6),%a0		# update user a7
 1983	mov.l		%a0,%usp
 1984
 1985fu_in_exc_exit_cont_p:
 1986	mov.w		(tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
 1987
 1988	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 1989	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 1990	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 1991
 1992	frestore	FP_SRC(%a6)		# restore src op
 1993
 1994	unlk		%a6
 1995
 1996	btst		&0x7,(%sp)		# is trace enabled?
 1997	bne.w		fu_trace_p		# yes
 1998
 1999	bra.l		_fpsp_done
 2000
 2001tbl_except_p:
 2002	short		0xe000,0xe006,0xe004,0xe005
 2003	short		0xe003,0xe002,0xe001,0xe001
 2004
 2005fu_in_exc_ovfl_p:
 2006	mov.w		&0x3,%d0
 2007	bra.w		fu_in_exc_exit_p
 2008
 2009fu_in_exc_unfl_p:
 2010	mov.w		&0x4,%d0
 2011	bra.w		fu_in_exc_exit_p
 2012
 2013fu_in_exc_exit_s_p:
 2014	btst		&mia7_bit,SPCOND_FLG(%a6)
 2015	beq.b		fu_in_exc_exit_cont_p
 2016
 2017	mov.w		(tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
 2018
 2019	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2020	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2021	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2022
 2023	frestore	FP_SRC(%a6)		# restore src op
 2024
 2025	unlk		%a6			# unravel stack frame
 2026
 2027# shift stack frame "up". who cares about <ea> field.
 2028	mov.l		0x4(%sp),0x10(%sp)
 2029	mov.l		0x0(%sp),0xc(%sp)
 2030	add.l		&0xc,%sp
 2031
 2032	btst		&0x7,(%sp)		# is trace on?
 2033	bne.b		fu_trace_p		# yes
 2034
 2035	bra.l		_fpsp_done		# exit to os
 2036
 2037#
 2038# The opclass two PACKED instruction that took an "Unimplemented Data Type"
 2039# exception was being traced. Make the "current" PC the FPIAR and put it in the
 2040# trace stack frame then jump to _real_trace().
 2041#
 2042#		  UNSUPP FRAME		   TRACE FRAME
 2043#		*****************	*****************
 2044#		*      EA	*	*    Current	*
 2045#		*		*	*      PC	*
 2046#		*****************	*****************
 2047#		* 0x2 *	0x0dc	*	* 0x2 *  0x024	*
 2048#		*****************	*****************
 2049#		*     Next	*	*     Next	*
 2050#		*      PC	*	*      PC	*
 2051#		*****************	*****************
 2052#		*      SR	*	*      SR	*
 2053#		*****************	*****************
 2054fu_trace_p:
 2055	mov.w		&0x2024,0x6(%sp)
 2056	fmov.l		%fpiar,0x8(%sp)
 2057
 2058	bra.l		_real_trace
 2059
 2060#########################################################
 2061#########################################################
 2062fu_out_pack:
 2063
 2064
 2065# I'm not sure at this point what FPSR bits are valid for this instruction.
 2066# so, since the emulation routines re-create them anyways, zero exception field.
 2067# fmove out doesn't affect ccodes.
 2068	and.l		&0xffff00ff,USER_FPSR(%a6) # zero exception field
 2069
 2070	fmov.l		&0x0,%fpcr		# zero current control regs
 2071	fmov.l		&0x0,%fpsr
 2072
 2073	bfextu		EXC_CMDREG(%a6){&6:&3},%d0
 2074	bsr.l		load_fpn1
 2075
 2076# unlike other opclass 3, unimplemented data type exceptions, packed must be
 2077# able to detect all operand types.
 2078	lea		FP_SRC(%a6),%a0
 2079	bsr.l		set_tag_x		# tag the operand type
 2080	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 2081	bne.b		fu_op2_p		# no
 2082	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
 2083
 2084fu_op2_p:
 2085	mov.b		%d0,STAG(%a6)		# save src optype tag
 2086
 2087	clr.l		%d0
 2088	mov.b		FPCR_MODE(%a6),%d0	# fetch rnd mode/prec
 2089
 2090	lea		FP_SRC(%a6),%a0		# pass ptr to src operand
 2091
 2092	mov.l		(%a6),EXC_A6(%a6)	# in case a6 changes
 2093	bsr.l		fout			# call fmove out routine
 2094
 2095# Exceptions in order of precedence:
 2096#	BSUN	: no
 2097#	SNAN	: yes
 2098#	OPERR	: if ((k_factor > +17) || (dec. exp exceeds 3 digits))
 2099#	OVFL	: no
 2100#	UNFL	: no
 2101#	DZ	: no
 2102#	INEX2	: yes
 2103#	INEX1	: no
 2104
 2105# determine the highest priority exception(if any) set by the
 2106# emulation routine that has also been enabled by the user.
 2107	mov.b		FPCR_ENABLE(%a6),%d0	# fetch exceptions enabled
 2108	bne.w		fu_out_ena_p		# some are enabled
 2109
 2110fu_out_exit_p:
 2111	mov.l		EXC_A6(%a6),(%a6)	# restore a6
 2112
 2113	btst		&0x5,EXC_SR(%a6)	# user or supervisor?
 2114	bne.b		fu_out_exit_s_p		# supervisor
 2115
 2116	mov.l		EXC_A7(%a6),%a0		# update user a7
 2117	mov.l		%a0,%usp
 2118
 2119fu_out_exit_cont_p:
 2120	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2121	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2122	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2123
 2124	unlk		%a6			# unravel stack frame
 2125
 2126	btst		&0x7,(%sp)		# is trace on?
 2127	bne.w		fu_trace_p		# yes
 2128
 2129	bra.l		_fpsp_done		# exit to os
 2130
 2131# the exception occurred in supervisor mode. check to see if the
 2132# addressing mode was -(a7). if so, we'll need to shift the
 2133# stack frame "down".
 2134fu_out_exit_s_p:
 2135	btst		&mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
 2136	beq.b		fu_out_exit_cont_p	# no
 2137
 2138	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2139	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2140	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2141
 2142	mov.l		(%a6),%a6		# restore frame pointer
 2143
 2144	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 2145	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 2146
 2147# now, copy the result to the proper place on the stack
 2148	mov.l		LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
 2149	mov.l		LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
 2150	mov.l		LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
 2151
 2152	add.l		&LOCAL_SIZE-0x8,%sp
 2153
 2154	btst		&0x7,(%sp)
 2155	bne.w		fu_trace_p
 2156
 2157	bra.l		_fpsp_done
 2158
 2159fu_out_ena_p:
 2160	and.b		FPSR_EXCEPT(%a6),%d0	# keep only ones enabled
 2161	bfffo		%d0{&24:&8},%d0		# find highest priority exception
 2162	beq.w		fu_out_exit_p
 2163
 2164	mov.l		EXC_A6(%a6),(%a6)	# restore a6
 2165
 2166# an exception occurred and that exception was enabled.
 2167# the only exception possible on packed move out are INEX, OPERR, and SNAN.
 2168fu_out_exc_p:
 2169	cmpi.b		%d0,&0x1a
 2170	bgt.w		fu_inex_p2
 2171	beq.w		fu_operr_p
 2172
 2173fu_snan_p:
 2174	btst		&0x5,EXC_SR(%a6)
 2175	bne.b		fu_snan_s_p
 2176
 2177	mov.l		EXC_A7(%a6),%a0
 2178	mov.l		%a0,%usp
 2179	bra.w		fu_snan
 2180
 2181fu_snan_s_p:
 2182	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 2183	bne.w		fu_snan
 2184
 2185# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
 2186# the strategy is to move the exception frame "down" 12 bytes. then, we
 2187# can store the default result where the exception frame was.
 2188	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2189	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2190	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2191
 2192	mov.w		&0x30d8,EXC_VOFF(%a6)	# vector offset = 0xd0
 2193	mov.w		&0xe006,2+FP_SRC(%a6)	# set fsave status
 2194
 2195	frestore	FP_SRC(%a6)		# restore src operand
 2196
 2197	mov.l		(%a6),%a6		# restore frame pointer
 2198
 2199	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 2200	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 2201	mov.l		LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
 2202
 2203# now, we copy the default result to its proper location
 2204	mov.l		LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
 2205	mov.l		LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
 2206	mov.l		LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
 2207
 2208	add.l		&LOCAL_SIZE-0x8,%sp
 2209
 2210
 2211	bra.l		_real_snan
 2212
 2213fu_operr_p:
 2214	btst		&0x5,EXC_SR(%a6)
 2215	bne.w		fu_operr_p_s
 2216
 2217	mov.l		EXC_A7(%a6),%a0
 2218	mov.l		%a0,%usp
 2219	bra.w		fu_operr
 2220
 2221fu_operr_p_s:
 2222	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 2223	bne.w		fu_operr
 2224
 2225# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
 2226# the strategy is to move the exception frame "down" 12 bytes. then, we
 2227# can store the default result where the exception frame was.
 2228	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2229	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2230	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2231
 2232	mov.w		&0x30d0,EXC_VOFF(%a6)	# vector offset = 0xd0
 2233	mov.w		&0xe004,2+FP_SRC(%a6)	# set fsave status
 2234
 2235	frestore	FP_SRC(%a6)		# restore src operand
 2236
 2237	mov.l		(%a6),%a6		# restore frame pointer
 2238
 2239	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 2240	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 2241	mov.l		LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
 2242
 2243# now, we copy the default result to its proper location
 2244	mov.l		LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
 2245	mov.l		LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
 2246	mov.l		LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
 2247
 2248	add.l		&LOCAL_SIZE-0x8,%sp
 2249
 2250
 2251	bra.l		_real_operr
 2252
 2253fu_inex_p2:
 2254	btst		&0x5,EXC_SR(%a6)
 2255	bne.w		fu_inex_s_p2
 2256
 2257	mov.l		EXC_A7(%a6),%a0
 2258	mov.l		%a0,%usp
 2259	bra.w		fu_inex
 2260
 2261fu_inex_s_p2:
 2262	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 2263	bne.w		fu_inex
 2264
 2265# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
 2266# the strategy is to move the exception frame "down" 12 bytes. then, we
 2267# can store the default result where the exception frame was.
 2268	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0/fp1
 2269	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2270	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2271
 2272	mov.w		&0x30c4,EXC_VOFF(%a6)	# vector offset = 0xc4
 2273	mov.w		&0xe001,2+FP_SRC(%a6)	# set fsave status
 2274
 2275	frestore	FP_SRC(%a6)		# restore src operand
 2276
 2277	mov.l		(%a6),%a6		# restore frame pointer
 2278
 2279	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 2280	mov.l		LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 2281	mov.l		LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
 2282
 2283# now, we copy the default result to its proper location
 2284	mov.l		LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
 2285	mov.l		LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
 2286	mov.l		LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
 2287
 2288	add.l		&LOCAL_SIZE-0x8,%sp
 2289
 2290
 2291	bra.l		_real_inex
 2292
 2293#########################################################################
 2294
 2295#
 2296# if we're stuffing a source operand back into an fsave frame then we
 2297# have to make sure that for single or double source operands that the
 2298# format stuffed is as weird as the hardware usually makes it.
 2299#
 2300	global		funimp_skew
 2301funimp_skew:
 2302	bfextu		EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
 2303	cmpi.b		%d0,&0x1		# was src sgl?
 2304	beq.b		funimp_skew_sgl		# yes
 2305	cmpi.b		%d0,&0x5		# was src dbl?
 2306	beq.b		funimp_skew_dbl		# yes
 2307	rts
 2308
 2309funimp_skew_sgl:
 2310	mov.w		FP_SRC_EX(%a6),%d0	# fetch DENORM exponent
 2311	andi.w		&0x7fff,%d0		# strip sign
 2312	beq.b		funimp_skew_sgl_not
 2313	cmpi.w		%d0,&0x3f80
 2314	bgt.b		funimp_skew_sgl_not
 2315	neg.w		%d0			# make exponent negative
 2316	addi.w		&0x3f81,%d0		# find amt to shift
 2317	mov.l		FP_SRC_HI(%a6),%d1	# fetch DENORM hi(man)
 2318	lsr.l		%d0,%d1			# shift it
 2319	bset		&31,%d1			# set j-bit
 2320	mov.l		%d1,FP_SRC_HI(%a6)	# insert new hi(man)
 2321	andi.w		&0x8000,FP_SRC_EX(%a6)	# clear old exponent
 2322	ori.w		&0x3f80,FP_SRC_EX(%a6)	# insert new "skewed" exponent
 2323funimp_skew_sgl_not:
 2324	rts
 2325
 2326funimp_skew_dbl:
 2327	mov.w		FP_SRC_EX(%a6),%d0	# fetch DENORM exponent
 2328	andi.w		&0x7fff,%d0		# strip sign
 2329	beq.b		funimp_skew_dbl_not
 2330	cmpi.w		%d0,&0x3c00
 2331	bgt.b		funimp_skew_dbl_not
 2332
 2333	tst.b		FP_SRC_EX(%a6)		# make "internal format"
 2334	smi.b		0x2+FP_SRC(%a6)
 2335	mov.w		%d0,FP_SRC_EX(%a6)	# insert exponent with cleared sign
 2336	clr.l		%d0			# clear g,r,s
 2337	lea		FP_SRC(%a6),%a0		# pass ptr to src op
 2338	mov.w		&0x3c01,%d1		# pass denorm threshold
 2339	bsr.l		dnrm_lp			# denorm it
 2340	mov.w		&0x3c00,%d0		# new exponent
 2341	tst.b		0x2+FP_SRC(%a6)		# is sign set?
 2342	beq.b		fss_dbl_denorm_done	# no
 2343	bset		&15,%d0			# set sign
 2344fss_dbl_denorm_done:
 2345	bset		&0x7,FP_SRC_HI(%a6)	# set j-bit
 2346	mov.w		%d0,FP_SRC_EX(%a6)	# insert new exponent
 2347funimp_skew_dbl_not:
 2348	rts
 2349
 2350#########################################################################
 2351	global		_mem_write2
 2352_mem_write2:
 2353	btst		&0x5,EXC_SR(%a6)
 2354	beq.l		_dmem_write
 2355	mov.l		0x0(%a0),FP_DST_EX(%a6)
 2356	mov.l		0x4(%a0),FP_DST_HI(%a6)
 2357	mov.l		0x8(%a0),FP_DST_LO(%a6)
 2358	clr.l		%d1
 2359	rts
 2360
 2361#########################################################################
 2362# XDEF ****************************************************************	#
 2363#	_fpsp_effadd(): 060FPSP entry point for FP "Unimplemented	#
 2364#			effective address" exception.			#
 2365#									#
 2366#	This handler should be the first code executed upon taking the	#
 2367#	FP Unimplemented Effective Address exception in an operating	#
 2368#	system.								#
 2369#									#
 2370# XREF ****************************************************************	#
 2371#	_imem_read_long() - read instruction longword			#
 2372#	fix_skewed_ops() - adjust src operand in fsave frame		#
 2373#	set_tag_x() - determine optype of src/dst operands		#
 2374#	store_fpreg() - store opclass 0 or 2 result to FP regfile	#
 2375#	unnorm_fix() - change UNNORM operands to NORM or ZERO		#
 2376#	load_fpn2() - load dst operand from FP regfile			#
 2377#	tbl_unsupp - add of table of emulation routines for opclass 0,2	#
 2378#	decbin() - convert packed data to FP binary data		#
 2379#	_real_fpu_disabled() - "callout" for "FPU disabled" exception	#
 2380#	_real_access() - "callout" for access error exception		#
 2381#	_mem_read() - read extended immediate operand from memory	#
 2382#	_fpsp_done() - "callout" for exit; work all done		#
 2383#	_real_trace() - "callout" for Trace enabled exception		#
 2384#	fmovm_dynamic() - emulate dynamic fmovm instruction		#
 2385#	fmovm_ctrl() - emulate fmovm control instruction		#
 2386#									#
 2387# INPUT ***************************************************************	#
 2388#	- The system stack contains the "Unimplemented <ea>" stk frame	#
 2389#									#
 2390# OUTPUT **************************************************************	#
 2391#	If access error:						#
 2392#	- The system stack is changed to an access error stack frame	#
 2393#	If FPU disabled:						#
 2394#	- The system stack is changed to an FPU disabled stack frame	#
 2395#	If Trace exception enabled:					#
 2396#	- The system stack is changed to a Trace exception stack frame	#
 2397#	Else: (normal case)						#
 2398#	- None (correct result has been stored as appropriate)		#
 2399#									#
 2400# ALGORITHM ***********************************************************	#
 2401#	This exception handles 3 types of operations:			#
 2402# (1) FP Instructions using extended precision or packed immediate	#
 2403#     addressing mode.							#
 2404# (2) The "fmovm.x" instruction w/ dynamic register specification.	#
 2405# (3) The "fmovm.l" instruction w/ 2 or 3 control registers.		#
 2406#									#
 2407#	For immediate data operations, the data is read in w/ a		#
 2408# _mem_read() "callout", converted to FP binary (if packed), and used	#
 2409# as the source operand to the instruction specified by the instruction	#
 2410# word. If no FP exception should be reported ads a result of the	#
 2411# emulation, then the result is stored to the destination register and	#
 2412# the handler exits through _fpsp_done(). If an enabled exc has been	#
 2413# signalled as a result of emulation, then an fsave state frame		#
 2414# corresponding to the FP exception type must be entered into the 060	#
 2415# FPU before exiting. In either the enabled or disabled cases, we	#
 2416# must also check if a Trace exception is pending, in which case, we	#
 2417# must create a Trace exception stack frame from the current exception	#
 2418# stack frame. If no Trace is pending, we simply exit through		#
 2419# _fpsp_done().								#
 2420#	For "fmovm.x", call the routine fmovm_dynamic() which will	#
 2421# decode and emulate the instruction. No FP exceptions can be pending	#
 2422# as a result of this operation emulation. A Trace exception can be	#
 2423# pending, though, which means the current stack frame must be changed	#
 2424# to a Trace stack frame and an exit made through _real_trace().	#
 2425# For the case of "fmovm.x Dn,-(a7)", where the offending instruction	#
 2426# was executed from supervisor mode, this handler must store the FP	#
 2427# register file values to the system stack by itself since		#
 2428# fmovm_dynamic() can't handle this. A normal exit is made through	#
 2429# fpsp_done().								#
 2430#	For "fmovm.l", fmovm_ctrl() is used to emulate the instruction.	#
 2431# Again, a Trace exception may be pending and an exit made through	#
 2432# _real_trace(). Else, a normal exit is made through _fpsp_done().	#
 2433#									#
 2434#	Before any of the above is attempted, it must be checked to	#
 2435# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken	#
 2436# before the "FPU disabled" exception, but the "FPU disabled" exception	#
 2437# has higher priority, we check the disabled bit in the PCR. If set,	#
 2438# then we must create an 8 word "FPU disabled" exception stack frame	#
 2439# from the current 4 word exception stack frame. This includes		#
 2440# reproducing the effective address of the instruction to put on the	#
 2441# new stack frame.							#
 2442#									#
 2443#	In the process of all emulation work, if a _mem_read()		#
 2444# "callout" returns a failing result indicating an access error, then	#
 2445# we must create an access error stack frame from the current stack	#
 2446# frame. This information includes a faulting address and a fault-	#
 2447# status-longword. These are created within this handler.		#
 2448#									#
 2449#########################################################################
 2450
 2451	global		_fpsp_effadd
 2452_fpsp_effadd:
 2453
 2454# This exception type takes priority over the "Line F Emulator"
 2455# exception. Therefore, the FPU could be disabled when entering here.
 2456# So, we must check to see if it's disabled and handle that case separately.
 2457	mov.l		%d0,-(%sp)		# save d0
 2458	movc		%pcr,%d0		# load proc cr
 2459	btst		&0x1,%d0		# is FPU disabled?
 2460	bne.w		iea_disabled		# yes
 2461	mov.l		(%sp)+,%d0		# restore d0
 2462
 2463	link		%a6,&-LOCAL_SIZE	# init stack frame
 2464
 2465	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 2466	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 2467	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 2468
 2469# PC of instruction that took the exception is the PC in the frame
 2470	mov.l		EXC_PC(%a6),EXC_EXTWPTR(%a6)
 2471
 2472	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 2473	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 2474	bsr.l		_imem_read_long		# fetch the instruction words
 2475	mov.l		%d0,EXC_OPWORD(%a6)	# store OPWORD and EXTWORD
 2476
 2477#########################################################################
 2478
 2479	tst.w		%d0			# is operation fmovem?
 2480	bmi.w		iea_fmovm		# yes
 2481
 2482#
 2483# here, we will have:
 2484#	fabs	fdabs	fsabs		facos		fmod
 2485#	fadd	fdadd	fsadd		fasin		frem
 2486#	fcmp				fatan		fscale
 2487#	fdiv	fddiv	fsdiv		fatanh		fsin
 2488#	fint				fcos		fsincos
 2489#	fintrz				fcosh		fsinh
 2490#	fmove	fdmove	fsmove		fetox		ftan
 2491#	fmul	fdmul	fsmul		fetoxm1		ftanh
 2492#	fneg	fdneg	fsneg		fgetexp		ftentox
 2493#	fsgldiv				fgetman		ftwotox
 2494#	fsglmul				flog10
 2495#	fsqrt				flog2
 2496#	fsub	fdsub	fssub		flogn
 2497#	ftst				flognp1
 2498# which can all use f<op>.{x,p}
 2499# so, now it's immediate data extended precision AND PACKED FORMAT!
 2500#
 2501iea_op:
 2502	andi.l		&0x00ff00ff,USER_FPSR(%a6)
 2503
 2504	btst		&0xa,%d0		# is src fmt x or p?
 2505	bne.b		iea_op_pack		# packed
 2506
 2507
 2508	mov.l		EXC_EXTWPTR(%a6),%a0	# pass: ptr to #<data>
 2509	lea		FP_SRC(%a6),%a1		# pass: ptr to super addr
 2510	mov.l		&0xc,%d0		# pass: 12 bytes
 2511	bsr.l		_imem_read		# read extended immediate
 2512
 2513	tst.l		%d1			# did ifetch fail?
 2514	bne.w		iea_iacc		# yes
 2515
 2516	bra.b		iea_op_setsrc
 2517
 2518iea_op_pack:
 2519
 2520	mov.l		EXC_EXTWPTR(%a6),%a0	# pass: ptr to #<data>
 2521	lea		FP_SRC(%a6),%a1		# pass: ptr to super dst
 2522	mov.l		&0xc,%d0		# pass: 12 bytes
 2523	bsr.l		_imem_read		# read packed operand
 2524
 2525	tst.l		%d1			# did ifetch fail?
 2526	bne.w		iea_iacc		# yes
 2527
 2528# The packed operand is an INF or a NAN if the exponent field is all ones.
 2529	bfextu		FP_SRC(%a6){&1:&15},%d0	# get exp
 2530	cmpi.w		%d0,&0x7fff		# INF or NAN?
 2531	beq.b		iea_op_setsrc		# operand is an INF or NAN
 2532
 2533# The packed operand is a zero if the mantissa is all zero, else it's
 2534# a normal packed op.
 2535	mov.b		3+FP_SRC(%a6),%d0	# get byte 4
 2536	andi.b		&0x0f,%d0		# clear all but last nybble
 2537	bne.b		iea_op_gp_not_spec	# not a zero
 2538	tst.l		FP_SRC_HI(%a6)		# is lw 2 zero?
 2539	bne.b		iea_op_gp_not_spec	# not a zero
 2540	tst.l		FP_SRC_LO(%a6)		# is lw 3 zero?
 2541	beq.b		iea_op_setsrc		# operand is a ZERO
 2542iea_op_gp_not_spec:
 2543	lea		FP_SRC(%a6),%a0		# pass: ptr to packed op
 2544	bsr.l		decbin			# convert to extended
 2545	fmovm.x		&0x80,FP_SRC(%a6)	# make this the srcop
 2546
 2547iea_op_setsrc:
 2548	addi.l		&0xc,EXC_EXTWPTR(%a6)	# update extension word pointer
 2549
 2550# FP_SRC now holds the src operand.
 2551	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 2552	bsr.l		set_tag_x		# tag the operand type
 2553	mov.b		%d0,STAG(%a6)		# could be ANYTHING!!!
 2554	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 2555	bne.b		iea_op_getdst		# no
 2556	bsr.l		unnorm_fix		# yes; convert to NORM/DENORM/ZERO
 2557	mov.b		%d0,STAG(%a6)		# set new optype tag
 2558iea_op_getdst:
 2559	clr.b		STORE_FLG(%a6)		# clear "store result" boolean
 2560
 2561	btst		&0x5,1+EXC_CMDREG(%a6)	# is operation monadic or dyadic?
 2562	beq.b		iea_op_extract		# monadic
 2563	btst		&0x4,1+EXC_CMDREG(%a6)	# is operation fsincos,ftst,fcmp?
 2564	bne.b		iea_op_spec		# yes
 2565
 2566iea_op_loaddst:
 2567	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
 2568	bsr.l		load_fpn2		# load dst operand
 2569
 2570	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
 2571	bsr.l		set_tag_x		# tag the operand type
 2572	mov.b		%d0,DTAG(%a6)		# could be ANYTHING!!!
 2573	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 2574	bne.b		iea_op_extract		# no
 2575	bsr.l		unnorm_fix		# yes; convert to NORM/DENORM/ZERO
 2576	mov.b		%d0,DTAG(%a6)		# set new optype tag
 2577	bra.b		iea_op_extract
 2578
 2579# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
 2580iea_op_spec:
 2581	btst		&0x3,1+EXC_CMDREG(%a6)	# is operation fsincos?
 2582	beq.b		iea_op_extract		# yes
 2583# now, we're left with ftst and fcmp. so, first let's tag them so that they don't
 2584# store a result. then, only fcmp will branch back and pick up a dst operand.
 2585	st		STORE_FLG(%a6)		# don't store a final result
 2586	btst		&0x1,1+EXC_CMDREG(%a6)	# is operation fcmp?
 2587	beq.b		iea_op_loaddst		# yes
 2588
 2589iea_op_extract:
 2590	clr.l		%d0
 2591	mov.b		FPCR_MODE(%a6),%d0	# pass: rnd mode,prec
 2592
 2593	mov.b		1+EXC_CMDREG(%a6),%d1
 2594	andi.w		&0x007f,%d1		# extract extension
 2595
 2596	fmov.l		&0x0,%fpcr
 2597	fmov.l		&0x0,%fpsr
 2598
 2599	lea		FP_SRC(%a6),%a0
 2600	lea		FP_DST(%a6),%a1
 2601
 2602	mov.l		(tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 2603	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
 2604
 2605#
 2606# Exceptions in order of precedence:
 2607#	BSUN	: none
 2608#	SNAN	: all operations
 2609#	OPERR	: all reg-reg or mem-reg operations that can normally operr
 2610#	OVFL	: same as OPERR
 2611#	UNFL	: same as OPERR
 2612#	DZ	: same as OPERR
 2613#	INEX2	: same as OPERR
 2614#	INEX1	: all packed immediate operations
 2615#
 2616
 2617# we determine the highest priority exception(if any) set by the
 2618# emulation routine that has also been enabled by the user.
 2619	mov.b		FPCR_ENABLE(%a6),%d0	# fetch exceptions enabled
 2620	bne.b		iea_op_ena		# some are enabled
 2621
 2622# now, we save the result, unless, of course, the operation was ftst or fcmp.
 2623# these don't save results.
 2624iea_op_save:
 2625	tst.b		STORE_FLG(%a6)		# does this op store a result?
 2626	bne.b		iea_op_exit1		# exit with no frestore
 2627
 2628iea_op_store:
 2629	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
 2630	bsr.l		store_fpreg		# store the result
 2631
 2632iea_op_exit1:
 2633	mov.l		EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
 2634	mov.l		EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
 2635
 2636	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 2637	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2638	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2639
 2640	unlk		%a6			# unravel the frame
 2641
 2642	btst		&0x7,(%sp)		# is trace on?
 2643	bne.w		iea_op_trace		# yes
 2644
 2645	bra.l		_fpsp_done		# exit to os
 2646
 2647iea_op_ena:
 2648	and.b		FPSR_EXCEPT(%a6),%d0	# keep only ones enable and set
 2649	bfffo		%d0{&24:&8},%d0		# find highest priority exception
 2650	bne.b		iea_op_exc		# at least one was set
 2651
 2652# no exception occurred. now, did a disabled, exact overflow occur with inexact
 2653# enabled? if so, then we have to stuff an overflow frame into the FPU.
 2654	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
 2655	beq.b		iea_op_save
 2656
 2657iea_op_ovfl:
 2658	btst		&inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
 2659	beq.b		iea_op_store		# no
 2660	bra.b		iea_op_exc_ovfl		# yes
 2661
 2662# an enabled exception occurred. we have to insert the exception type back into
 2663# the machine.
 2664iea_op_exc:
 2665	subi.l		&24,%d0			# fix offset to be 0-8
 2666	cmpi.b		%d0,&0x6		# is exception INEX?
 2667	bne.b		iea_op_exc_force	# no
 2668
 2669# the enabled exception was inexact. so, if it occurs with an overflow
 2670# or underflow that was disabled, then we have to force an overflow or
 2671# underflow frame.
 2672	btst		&ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
 2673	bne.b		iea_op_exc_ovfl		# yes
 2674	btst		&unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
 2675	bne.b		iea_op_exc_unfl		# yes
 2676
 2677iea_op_exc_force:
 2678	mov.w		(tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
 2679	bra.b		iea_op_exit2		# exit with frestore
 2680
 2681tbl_iea_except:
 2682	short		0xe002, 0xe006, 0xe004, 0xe005
 2683	short		0xe003, 0xe002, 0xe001, 0xe001
 2684
 2685iea_op_exc_ovfl:
 2686	mov.w		&0xe005,2+FP_SRC(%a6)
 2687	bra.b		iea_op_exit2
 2688
 2689iea_op_exc_unfl:
 2690	mov.w		&0xe003,2+FP_SRC(%a6)
 2691
 2692iea_op_exit2:
 2693	mov.l		EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
 2694	mov.l		EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
 2695
 2696	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 2697	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2698	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2699
 2700	frestore	FP_SRC(%a6)		# restore exceptional state
 2701
 2702	unlk		%a6			# unravel the frame
 2703
 2704	btst		&0x7,(%sp)		# is trace on?
 2705	bne.b		iea_op_trace		# yes
 2706
 2707	bra.l		_fpsp_done		# exit to os
 2708
 2709#
 2710# The opclass two instruction that took an "Unimplemented Effective Address"
 2711# exception was being traced. Make the "current" PC the FPIAR and put it in
 2712# the trace stack frame then jump to _real_trace().
 2713#
 2714#		 UNIMP EA FRAME		   TRACE FRAME
 2715#		*****************	*****************
 2716#		* 0x0 *  0x0f0	*	*    Current	*
 2717#		*****************	*      PC	*
 2718#		*    Current	*	*****************
 2719#		*      PC	*	* 0x2 *  0x024	*
 2720#		*****************	*****************
 2721#		*      SR	*	*     Next	*
 2722#		*****************	*      PC	*
 2723#					*****************
 2724#					*      SR	*
 2725#					*****************
 2726iea_op_trace:
 2727	mov.l		(%sp),-(%sp)		# shift stack frame "down"
 2728	mov.w		0x8(%sp),0x4(%sp)
 2729	mov.w		&0x2024,0x6(%sp)	# stk fmt = 0x2; voff = 0x024
 2730	fmov.l		%fpiar,0x8(%sp)		# "Current PC" is in FPIAR
 2731
 2732	bra.l		_real_trace
 2733
 2734#########################################################################
 2735iea_fmovm:
 2736	btst		&14,%d0			# ctrl or data reg
 2737	beq.w		iea_fmovm_ctrl
 2738
 2739iea_fmovm_data:
 2740
 2741	btst		&0x5,EXC_SR(%a6)	# user or supervisor mode
 2742	bne.b		iea_fmovm_data_s
 2743
 2744iea_fmovm_data_u:
 2745	mov.l		%usp,%a0
 2746	mov.l		%a0,EXC_A7(%a6)		# store current a7
 2747	bsr.l		fmovm_dynamic		# do dynamic fmovm
 2748	mov.l		EXC_A7(%a6),%a0		# load possibly new a7
 2749	mov.l		%a0,%usp		# update usp
 2750	bra.w		iea_fmovm_exit
 2751
 2752iea_fmovm_data_s:
 2753	clr.b		SPCOND_FLG(%a6)
 2754	lea		0x2+EXC_VOFF(%a6),%a0
 2755	mov.l		%a0,EXC_A7(%a6)
 2756	bsr.l		fmovm_dynamic		# do dynamic fmovm
 2757
 2758	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 2759	beq.w		iea_fmovm_data_predec
 2760	cmpi.b		SPCOND_FLG(%a6),&mia7_flg
 2761	bne.w		iea_fmovm_exit
 2762
 2763# right now, d0 = the size.
 2764# the data has been fetched from the supervisor stack, but we have not
 2765# incremented the stack pointer by the appropriate number of bytes.
 2766# do it here.
 2767iea_fmovm_data_postinc:
 2768	btst		&0x7,EXC_SR(%a6)
 2769	bne.b		iea_fmovm_data_pi_trace
 2770
 2771	mov.w		EXC_SR(%a6),(EXC_SR,%a6,%d0)
 2772	mov.l		EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
 2773	mov.w		&0x00f0,(EXC_VOFF,%a6,%d0)
 2774
 2775	lea		(EXC_SR,%a6,%d0),%a0
 2776	mov.l		%a0,EXC_SR(%a6)
 2777
 2778	fmovm.x		EXC_FP0(%a6),&0xc0	# restore fp0-fp1
 2779	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2780	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2781
 2782	unlk		%a6
 2783	mov.l		(%sp)+,%sp
 2784	bra.l		_fpsp_done
 2785
 2786iea_fmovm_data_pi_trace:
 2787	mov.w		EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
 2788	mov.l		EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
 2789	mov.w		&0x2024,(EXC_VOFF-0x4,%a6,%d0)
 2790	mov.l		EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
 2791
 2792	lea		(EXC_SR-0x4,%a6,%d0),%a0
 2793	mov.l		%a0,EXC_SR(%a6)
 2794
 2795	fmovm.x		EXC_FP0(%a6),&0xc0	# restore fp0-fp1
 2796	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2797	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2798
 2799	unlk		%a6
 2800	mov.l		(%sp)+,%sp
 2801	bra.l		_real_trace
 2802
 2803# right now, d1 = size and d0 = the strg.
 2804iea_fmovm_data_predec:
 2805	mov.b		%d1,EXC_VOFF(%a6)	# store strg
 2806	mov.b		%d0,0x1+EXC_VOFF(%a6)	# store size
 2807
 2808	fmovm.x		EXC_FP0(%a6),&0xc0	# restore fp0-fp1
 2809	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2810	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2811
 2812	mov.l		(%a6),-(%sp)		# make a copy of a6
 2813	mov.l		%d0,-(%sp)		# save d0
 2814	mov.l		%d1,-(%sp)		# save d1
 2815	mov.l		EXC_EXTWPTR(%a6),-(%sp)	# make a copy of Next PC
 2816
 2817	clr.l		%d0
 2818	mov.b		0x1+EXC_VOFF(%a6),%d0	# fetch size
 2819	neg.l		%d0			# get negative of size
 2820
 2821	btst		&0x7,EXC_SR(%a6)	# is trace enabled?
 2822	beq.b		iea_fmovm_data_p2
 2823
 2824	mov.w		EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
 2825	mov.l		EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
 2826	mov.l		(%sp)+,(EXC_PC-0x4,%a6,%d0)
 2827	mov.w		&0x2024,(EXC_VOFF-0x4,%a6,%d0)
 2828
 2829	pea		(%a6,%d0)		# create final sp
 2830	bra.b		iea_fmovm_data_p3
 2831
 2832iea_fmovm_data_p2:
 2833	mov.w		EXC_SR(%a6),(EXC_SR,%a6,%d0)
 2834	mov.l		(%sp)+,(EXC_PC,%a6,%d0)
 2835	mov.w		&0x00f0,(EXC_VOFF,%a6,%d0)
 2836
 2837	pea		(0x4,%a6,%d0)		# create final sp
 2838
 2839iea_fmovm_data_p3:
 2840	clr.l		%d1
 2841	mov.b		EXC_VOFF(%a6),%d1	# fetch strg
 2842
 2843	tst.b		%d1
 2844	bpl.b		fm_1
 2845	fmovm.x		&0x80,(0x4+0x8,%a6,%d0)
 2846	addi.l		&0xc,%d0
 2847fm_1:
 2848	lsl.b		&0x1,%d1
 2849	bpl.b		fm_2
 2850	fmovm.x		&0x40,(0x4+0x8,%a6,%d0)
 2851	addi.l		&0xc,%d0
 2852fm_2:
 2853	lsl.b		&0x1,%d1
 2854	bpl.b		fm_3
 2855	fmovm.x		&0x20,(0x4+0x8,%a6,%d0)
 2856	addi.l		&0xc,%d0
 2857fm_3:
 2858	lsl.b		&0x1,%d1
 2859	bpl.b		fm_4
 2860	fmovm.x		&0x10,(0x4+0x8,%a6,%d0)
 2861	addi.l		&0xc,%d0
 2862fm_4:
 2863	lsl.b		&0x1,%d1
 2864	bpl.b		fm_5
 2865	fmovm.x		&0x08,(0x4+0x8,%a6,%d0)
 2866	addi.l		&0xc,%d0
 2867fm_5:
 2868	lsl.b		&0x1,%d1
 2869	bpl.b		fm_6
 2870	fmovm.x		&0x04,(0x4+0x8,%a6,%d0)
 2871	addi.l		&0xc,%d0
 2872fm_6:
 2873	lsl.b		&0x1,%d1
 2874	bpl.b		fm_7
 2875	fmovm.x		&0x02,(0x4+0x8,%a6,%d0)
 2876	addi.l		&0xc,%d0
 2877fm_7:
 2878	lsl.b		&0x1,%d1
 2879	bpl.b		fm_end
 2880	fmovm.x		&0x01,(0x4+0x8,%a6,%d0)
 2881fm_end:
 2882	mov.l		0x4(%sp),%d1
 2883	mov.l		0x8(%sp),%d0
 2884	mov.l		0xc(%sp),%a6
 2885	mov.l		(%sp)+,%sp
 2886
 2887	btst		&0x7,(%sp)		# is trace enabled?
 2888	beq.l		_fpsp_done
 2889	bra.l		_real_trace
 2890
 2891#########################################################################
 2892iea_fmovm_ctrl:
 2893
 2894	bsr.l		fmovm_ctrl		# load ctrl regs
 2895
 2896iea_fmovm_exit:
 2897	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 2898	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 2899	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2900
 2901	btst		&0x7,EXC_SR(%a6)	# is trace on?
 2902	bne.b		iea_fmovm_trace		# yes
 2903
 2904	mov.l		EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
 2905
 2906	unlk		%a6			# unravel the frame
 2907
 2908	bra.l		_fpsp_done		# exit to os
 2909
 2910#
 2911# The control reg instruction that took an "Unimplemented Effective Address"
 2912# exception was being traced. The "Current PC" for the trace frame is the
 2913# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
 2914# After fixing the stack frame, jump to _real_trace().
 2915#
 2916#		 UNIMP EA FRAME		   TRACE FRAME
 2917#		*****************	*****************
 2918#		* 0x0 *  0x0f0	*	*    Current	*
 2919#		*****************	*      PC	*
 2920#		*    Current	*	*****************
 2921#		*      PC	*	* 0x2 *  0x024	*
 2922#		*****************	*****************
 2923#		*      SR	*	*     Next	*
 2924#		*****************	*      PC	*
 2925#					*****************
 2926#					*      SR	*
 2927#					*****************
 2928# this ain't a pretty solution, but it works:
 2929# -restore a6 (not with unlk)
 2930# -shift stack frame down over where old a6 used to be
 2931# -add LOCAL_SIZE to stack pointer
 2932iea_fmovm_trace:
 2933	mov.l		(%a6),%a6		# restore frame pointer
 2934	mov.w		EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
 2935	mov.l		EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
 2936	mov.l		EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
 2937	mov.w		&0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
 2938	add.l		&LOCAL_SIZE,%sp		# clear stack frame
 2939
 2940	bra.l		_real_trace
 2941
 2942#########################################################################
 2943# The FPU is disabled and so we should really have taken the "Line
 2944# F Emulator" exception. So, here we create an 8-word stack frame
 2945# from our 4-word stack frame. This means we must calculate the length
 2946# the faulting instruction to get the "next PC". This is trivial for
 2947# immediate operands but requires some extra work for fmovm dynamic
 2948# which can use most addressing modes.
 2949iea_disabled:
 2950	mov.l		(%sp)+,%d0		# restore d0
 2951
 2952	link		%a6,&-LOCAL_SIZE	# init stack frame
 2953
 2954	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 2955
 2956# PC of instruction that took the exception is the PC in the frame
 2957	mov.l		EXC_PC(%a6),EXC_EXTWPTR(%a6)
 2958	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 2959	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 2960	bsr.l		_imem_read_long		# fetch the instruction words
 2961	mov.l		%d0,EXC_OPWORD(%a6)	# store OPWORD and EXTWORD
 2962
 2963	tst.w		%d0			# is instr fmovm?
 2964	bmi.b		iea_dis_fmovm		# yes
 2965# instruction is using an extended precision immediate operand. Therefore,
 2966# the total instruction length is 16 bytes.
 2967iea_dis_immed:
 2968	mov.l		&0x10,%d0		# 16 bytes of instruction
 2969	bra.b		iea_dis_cont
 2970iea_dis_fmovm:
 2971	btst		&0xe,%d0		# is instr fmovm ctrl
 2972	bne.b		iea_dis_fmovm_data	# no
 2973# the instruction is a fmovm.l with 2 or 3 registers.
 2974	bfextu		%d0{&19:&3},%d1
 2975	mov.l		&0xc,%d0
 2976	cmpi.b		%d1,&0x7		# move all regs?
 2977	bne.b		iea_dis_cont
 2978	addq.l		&0x4,%d0
 2979	bra.b		iea_dis_cont
 2980# the instruction is an fmovm.x dynamic which can use many addressing
 2981# modes and thus can have several different total instruction lengths.
 2982# call fmovm_calc_ea which will go through the ea calc process and,
 2983# as a by-product, will tell us how long the instruction is.
 2984iea_dis_fmovm_data:
 2985	clr.l		%d0
 2986	bsr.l		fmovm_calc_ea
 2987	mov.l		EXC_EXTWPTR(%a6),%d0
 2988	sub.l		EXC_PC(%a6),%d0
 2989iea_dis_cont:
 2990	mov.w		%d0,EXC_VOFF(%a6)	# store stack shift value
 2991
 2992	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 2993
 2994	unlk		%a6
 2995
 2996# here, we actually create the 8-word frame from the 4-word frame,
 2997# with the "next PC" as additional info.
 2998# the <ea> field is let as undefined.
 2999	subq.l		&0x8,%sp		# make room for new stack
 3000	mov.l		%d0,-(%sp)		# save d0
 3001	mov.w		0xc(%sp),0x4(%sp)	# move SR
 3002	mov.l		0xe(%sp),0x6(%sp)	# move Current PC
 3003	clr.l		%d0
 3004	mov.w		0x12(%sp),%d0
 3005	mov.l		0x6(%sp),0x10(%sp)	# move Current PC
 3006	add.l		%d0,0x6(%sp)		# make Next PC
 3007	mov.w		&0x402c,0xa(%sp)	# insert offset,frame format
 3008	mov.l		(%sp)+,%d0		# restore d0
 3009
 3010	bra.l		_real_fpu_disabled
 3011
 3012##########
 3013
 3014iea_iacc:
 3015	movc		%pcr,%d0
 3016	btst		&0x1,%d0
 3017	bne.b		iea_iacc_cont
 3018	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3019	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1 on stack
 3020iea_iacc_cont:
 3021	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3022
 3023	unlk		%a6
 3024
 3025	subq.w		&0x8,%sp		# make stack frame bigger
 3026	mov.l		0x8(%sp),(%sp)		# store SR,hi(PC)
 3027	mov.w		0xc(%sp),0x4(%sp)	# store lo(PC)
 3028	mov.w		&0x4008,0x6(%sp)	# store voff
 3029	mov.l		0x2(%sp),0x8(%sp)	# store ea
 3030	mov.l		&0x09428001,0xc(%sp)	# store fslw
 3031
 3032iea_acc_done:
 3033	btst		&0x5,(%sp)		# user or supervisor mode?
 3034	beq.b		iea_acc_done2		# user
 3035	bset		&0x2,0xd(%sp)		# set supervisor TM bit
 3036
 3037iea_acc_done2:
 3038	bra.l		_real_access
 3039
 3040iea_dacc:
 3041	lea		-LOCAL_SIZE(%a6),%sp
 3042
 3043	movc		%pcr,%d1
 3044	btst		&0x1,%d1
 3045	bne.b		iea_dacc_cont
 3046	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1 on stack
 3047	fmovm.l		LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3048iea_dacc_cont:
 3049	mov.l		(%a6),%a6
 3050
 3051	mov.l		0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
 3052	mov.w		0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
 3053	mov.w		&0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
 3054	mov.l		%a0,-0x8+0xc+LOCAL_SIZE(%sp)
 3055	mov.w		%d0,-0x8+0x10+LOCAL_SIZE(%sp)
 3056	mov.w		&0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
 3057
 3058	movm.l		LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
 3059	add.w		&LOCAL_SIZE-0x4,%sp
 3060
 3061	bra.b		iea_acc_done
 3062
 3063#########################################################################
 3064# XDEF ****************************************************************	#
 3065#	_fpsp_operr(): 060FPSP entry point for FP Operr exception.	#
 3066#									#
 3067#	This handler should be the first code executed upon taking the	#
 3068#	FP Operand Error exception in an operating system.		#
 3069#									#
 3070# XREF ****************************************************************	#
 3071#	_imem_read_long() - read instruction longword			#
 3072#	fix_skewed_ops() - adjust src operand in fsave frame		#
 3073#	_real_operr() - "callout" to operating system operr handler	#
 3074#	_dmem_write_{byte,word,long}() - store data to mem (opclass 3)	#
 3075#	store_dreg_{b,w,l}() - store data to data regfile (opclass 3)	#
 3076#	facc_out_{b,w,l}() - store to memory took access error (opcl 3)	#
 3077#									#
 3078# INPUT ***************************************************************	#
 3079#	- The system stack contains the FP Operr exception frame	#
 3080#	- The fsave frame contains the source operand			#
 3081#									#
 3082# OUTPUT **************************************************************	#
 3083#	No access error:						#
 3084#	- The system stack is unchanged					#
 3085#	- The fsave frame contains the adjusted src op for opclass 0,2	#
 3086#									#
 3087# ALGORITHM ***********************************************************	#
 3088#	In a system where the FP Operr exception is enabled, the goal	#
 3089# is to get to the handler specified at _real_operr(). But, on the 060,	#
 3090# for opclass zero and two instruction taking this exception, the	#
 3091# input operand in the fsave frame may be incorrect for some cases	#
 3092# and needs to be corrected. This handler calls fix_skewed_ops() to	#
 3093# do just this and then exits through _real_operr().			#
 3094#	For opclass 3 instructions, the 060 doesn't store the default	#
 3095# operr result out to memory or data register file as it should.	#
 3096# This code must emulate the move out before finally exiting through	#
 3097# _real_inex(). The move out, if to memory, is performed using		#
 3098# _mem_write() "callout" routines that may return a failing result.	#
 3099# In this special case, the handler must exit through facc_out()	#
 3100# which creates an access error stack frame from the current operr	#
 3101# stack frame.								#
 3102#									#
 3103#########################################################################
 3104
 3105	global		_fpsp_operr
 3106_fpsp_operr:
 3107
 3108	link.w		%a6,&-LOCAL_SIZE	# init stack frame
 3109
 3110	fsave		FP_SRC(%a6)		# grab the "busy" frame
 3111
 3112	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 3113	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 3114	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 3115
 3116# the FPIAR holds the "current PC" of the faulting instruction
 3117	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 3118
 3119	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 3120	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 3121	bsr.l		_imem_read_long		# fetch the instruction words
 3122	mov.l		%d0,EXC_OPWORD(%a6)
 3123
 3124##############################################################################
 3125
 3126	btst		&13,%d0			# is instr an fmove out?
 3127	bne.b		foperr_out		# fmove out
 3128
 3129
 3130# here, we simply see if the operand in the fsave frame needs to be "unskewed".
 3131# this would be the case for opclass two operations with a source infinity or
 3132# denorm operand in the sgl or dbl format. NANs also become skewed, but can't
 3133# cause an operr so we don't need to check for them here.
 3134	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 3135	bsr.l		fix_skewed_ops		# fix src op
 3136
 3137foperr_exit:
 3138	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 3139	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3140	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3141
 3142	frestore	FP_SRC(%a6)
 3143
 3144	unlk		%a6
 3145	bra.l		_real_operr
 3146
 3147########################################################################
 3148
 3149#
 3150# the hardware does not save the default result to memory on enabled
 3151# operand error exceptions. we do this here before passing control to
 3152# the user operand error handler.
 3153#
 3154# byte, word, and long destination format operations can pass
 3155# through here. we simply need to test the sign of the src
 3156# operand and save the appropriate minimum or maximum integer value
 3157# to the effective address as pointed to by the stacked effective address.
 3158#
 3159# although packed opclass three operations can take operand error
 3160# exceptions, they won't pass through here since they are caught
 3161# first by the unsupported data format exception handler. that handler
 3162# sends them directly to _real_operr() if necessary.
 3163#
 3164foperr_out:
 3165
 3166	mov.w		FP_SRC_EX(%a6),%d1	# fetch exponent
 3167	andi.w		&0x7fff,%d1
 3168	cmpi.w		%d1,&0x7fff
 3169	bne.b		foperr_out_not_qnan
 3170# the operand is either an infinity or a QNAN.
 3171	tst.l		FP_SRC_LO(%a6)
 3172	bne.b		foperr_out_qnan
 3173	mov.l		FP_SRC_HI(%a6),%d1
 3174	andi.l		&0x7fffffff,%d1
 3175	beq.b		foperr_out_not_qnan
 3176foperr_out_qnan:
 3177	mov.l		FP_SRC_HI(%a6),L_SCR1(%a6)
 3178	bra.b		foperr_out_jmp
 3179
 3180foperr_out_not_qnan:
 3181	mov.l		&0x7fffffff,%d1
 3182	tst.b		FP_SRC_EX(%a6)
 3183	bpl.b		foperr_out_not_qnan2
 3184	addq.l		&0x1,%d1
 3185foperr_out_not_qnan2:
 3186	mov.l		%d1,L_SCR1(%a6)
 3187
 3188foperr_out_jmp:
 3189	bfextu		%d0{&19:&3},%d0		# extract dst format field
 3190	mov.b		1+EXC_OPWORD(%a6),%d1	# extract <ea> mode,reg
 3191	mov.w		(tbl_operr.b,%pc,%d0.w*2),%a0
 3192	jmp		(tbl_operr.b,%pc,%a0)
 3193
 3194tbl_operr:
 3195	short		foperr_out_l - tbl_operr # long word integer
 3196	short		tbl_operr    - tbl_operr # sgl prec shouldn't happen
 3197	short		tbl_operr    - tbl_operr # ext prec shouldn't happen
 3198	short		foperr_exit  - tbl_operr # packed won't enter here
 3199	short		foperr_out_w - tbl_operr # word integer
 3200	short		tbl_operr    - tbl_operr # dbl prec shouldn't happen
 3201	short		foperr_out_b - tbl_operr # byte integer
 3202	short		tbl_operr    - tbl_operr # packed won't enter here
 3203
 3204foperr_out_b:
 3205	mov.b		L_SCR1(%a6),%d0		# load positive default result
 3206	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3207	ble.b		foperr_out_b_save_dn	# yes
 3208	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3209	bsr.l		_dmem_write_byte	# write the default result
 3210
 3211	tst.l		%d1			# did dstore fail?
 3212	bne.l		facc_out_b		# yes
 3213
 3214	bra.w		foperr_exit
 3215foperr_out_b_save_dn:
 3216	andi.w		&0x0007,%d1
 3217	bsr.l		store_dreg_b		# store result to regfile
 3218	bra.w		foperr_exit
 3219
 3220foperr_out_w:
 3221	mov.w		L_SCR1(%a6),%d0		# load positive default result
 3222	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3223	ble.b		foperr_out_w_save_dn	# yes
 3224	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3225	bsr.l		_dmem_write_word	# write the default result
 3226
 3227	tst.l		%d1			# did dstore fail?
 3228	bne.l		facc_out_w		# yes
 3229
 3230	bra.w		foperr_exit
 3231foperr_out_w_save_dn:
 3232	andi.w		&0x0007,%d1
 3233	bsr.l		store_dreg_w		# store result to regfile
 3234	bra.w		foperr_exit
 3235
 3236foperr_out_l:
 3237	mov.l		L_SCR1(%a6),%d0		# load positive default result
 3238	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3239	ble.b		foperr_out_l_save_dn	# yes
 3240	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3241	bsr.l		_dmem_write_long	# write the default result
 3242
 3243	tst.l		%d1			# did dstore fail?
 3244	bne.l		facc_out_l		# yes
 3245
 3246	bra.w		foperr_exit
 3247foperr_out_l_save_dn:
 3248	andi.w		&0x0007,%d1
 3249	bsr.l		store_dreg_l		# store result to regfile
 3250	bra.w		foperr_exit
 3251
 3252#########################################################################
 3253# XDEF ****************************************************************	#
 3254#	_fpsp_snan(): 060FPSP entry point for FP SNAN exception.	#
 3255#									#
 3256#	This handler should be the first code executed upon taking the	#
 3257#	FP Signalling NAN exception in an operating system.		#
 3258#									#
 3259# XREF ****************************************************************	#
 3260#	_imem_read_long() - read instruction longword			#
 3261#	fix_skewed_ops() - adjust src operand in fsave frame		#
 3262#	_real_snan() - "callout" to operating system SNAN handler	#
 3263#	_dmem_write_{byte,word,long}() - store data to mem (opclass 3)	#
 3264#	store_dreg_{b,w,l}() - store data to data regfile (opclass 3)	#
 3265#	facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3)	#
 3266#	_calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea>	#
 3267#									#
 3268# INPUT ***************************************************************	#
 3269#	- The system stack contains the FP SNAN exception frame		#
 3270#	- The fsave frame contains the source operand			#
 3271#									#
 3272# OUTPUT **************************************************************	#
 3273#	No access error:						#
 3274#	- The system stack is unchanged					#
 3275#	- The fsave frame contains the adjusted src op for opclass 0,2	#
 3276#									#
 3277# ALGORITHM ***********************************************************	#
 3278#	In a system where the FP SNAN exception is enabled, the goal	#
 3279# is to get to the handler specified at _real_snan(). But, on the 060,	#
 3280# for opclass zero and two instructions taking this exception, the	#
 3281# input operand in the fsave frame may be incorrect for some cases	#
 3282# and needs to be corrected. This handler calls fix_skewed_ops() to	#
 3283# do just this and then exits through _real_snan().			#
 3284#	For opclass 3 instructions, the 060 doesn't store the default	#
 3285# SNAN result out to memory or data register file as it should.		#
 3286# This code must emulate the move out before finally exiting through	#
 3287# _real_snan(). The move out, if to memory, is performed using		#
 3288# _mem_write() "callout" routines that may return a failing result.	#
 3289# In this special case, the handler must exit through facc_out()	#
 3290# which creates an access error stack frame from the current SNAN	#
 3291# stack frame.								#
 3292#	For the case of an extended precision opclass 3 instruction,	#
 3293# if the effective addressing mode was -() or ()+, then the address	#
 3294# register must get updated by calling _calc_ea_fout(). If the <ea>	#
 3295# was -(a7) from supervisor mode, then the exception frame currently	#
 3296# on the system stack must be carefully moved "down" to make room	#
 3297# for the operand being moved.						#
 3298#									#
 3299#########################################################################
 3300
 3301	global		_fpsp_snan
 3302_fpsp_snan:
 3303
 3304	link.w		%a6,&-LOCAL_SIZE	# init stack frame
 3305
 3306	fsave		FP_SRC(%a6)		# grab the "busy" frame
 3307
 3308	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 3309	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 3310	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 3311
 3312# the FPIAR holds the "current PC" of the faulting instruction
 3313	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 3314
 3315	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 3316	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 3317	bsr.l		_imem_read_long		# fetch the instruction words
 3318	mov.l		%d0,EXC_OPWORD(%a6)
 3319
 3320##############################################################################
 3321
 3322	btst		&13,%d0			# is instr an fmove out?
 3323	bne.w		fsnan_out		# fmove out
 3324
 3325
 3326# here, we simply see if the operand in the fsave frame needs to be "unskewed".
 3327# this would be the case for opclass two operations with a source infinity or
 3328# denorm operand in the sgl or dbl format. NANs also become skewed and must be
 3329# fixed here.
 3330	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 3331	bsr.l		fix_skewed_ops		# fix src op
 3332
 3333fsnan_exit:
 3334	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 3335	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3336	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3337
 3338	frestore	FP_SRC(%a6)
 3339
 3340	unlk		%a6
 3341	bra.l		_real_snan
 3342
 3343########################################################################
 3344
 3345#
 3346# the hardware does not save the default result to memory on enabled
 3347# snan exceptions. we do this here before passing control to
 3348# the user snan handler.
 3349#
 3350# byte, word, long, and packed destination format operations can pass
 3351# through here. since packed format operations already were handled by
 3352# fpsp_unsupp(), then we need to do nothing else for them here.
 3353# for byte, word, and long, we simply need to test the sign of the src
 3354# operand and save the appropriate minimum or maximum integer value
 3355# to the effective address as pointed to by the stacked effective address.
 3356#
 3357fsnan_out:
 3358
 3359	bfextu		%d0{&19:&3},%d0		# extract dst format field
 3360	mov.b		1+EXC_OPWORD(%a6),%d1	# extract <ea> mode,reg
 3361	mov.w		(tbl_snan.b,%pc,%d0.w*2),%a0
 3362	jmp		(tbl_snan.b,%pc,%a0)
 3363
 3364tbl_snan:
 3365	short		fsnan_out_l - tbl_snan # long word integer
 3366	short		fsnan_out_s - tbl_snan # sgl prec shouldn't happen
 3367	short		fsnan_out_x - tbl_snan # ext prec shouldn't happen
 3368	short		tbl_snan    - tbl_snan # packed needs no help
 3369	short		fsnan_out_w - tbl_snan # word integer
 3370	short		fsnan_out_d - tbl_snan # dbl prec shouldn't happen
 3371	short		fsnan_out_b - tbl_snan # byte integer
 3372	short		tbl_snan    - tbl_snan # packed needs no help
 3373
 3374fsnan_out_b:
 3375	mov.b		FP_SRC_HI(%a6),%d0	# load upper byte of SNAN
 3376	bset		&6,%d0			# set SNAN bit
 3377	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3378	ble.b		fsnan_out_b_dn		# yes
 3379	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3380	bsr.l		_dmem_write_byte	# write the default result
 3381
 3382	tst.l		%d1			# did dstore fail?
 3383	bne.l		facc_out_b		# yes
 3384
 3385	bra.w		fsnan_exit
 3386fsnan_out_b_dn:
 3387	andi.w		&0x0007,%d1
 3388	bsr.l		store_dreg_b		# store result to regfile
 3389	bra.w		fsnan_exit
 3390
 3391fsnan_out_w:
 3392	mov.w		FP_SRC_HI(%a6),%d0	# load upper word of SNAN
 3393	bset		&14,%d0			# set SNAN bit
 3394	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3395	ble.b		fsnan_out_w_dn		# yes
 3396	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3397	bsr.l		_dmem_write_word	# write the default result
 3398
 3399	tst.l		%d1			# did dstore fail?
 3400	bne.l		facc_out_w		# yes
 3401
 3402	bra.w		fsnan_exit
 3403fsnan_out_w_dn:
 3404	andi.w		&0x0007,%d1
 3405	bsr.l		store_dreg_w		# store result to regfile
 3406	bra.w		fsnan_exit
 3407
 3408fsnan_out_l:
 3409	mov.l		FP_SRC_HI(%a6),%d0	# load upper longword of SNAN
 3410	bset		&30,%d0			# set SNAN bit
 3411	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3412	ble.b		fsnan_out_l_dn		# yes
 3413	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3414	bsr.l		_dmem_write_long	# write the default result
 3415
 3416	tst.l		%d1			# did dstore fail?
 3417	bne.l		facc_out_l		# yes
 3418
 3419	bra.w		fsnan_exit
 3420fsnan_out_l_dn:
 3421	andi.w		&0x0007,%d1
 3422	bsr.l		store_dreg_l		# store result to regfile
 3423	bra.w		fsnan_exit
 3424
 3425fsnan_out_s:
 3426	cmpi.b		%d1,&0x7		# is <ea> mode a data reg?
 3427	ble.b		fsnan_out_d_dn		# yes
 3428	mov.l		FP_SRC_EX(%a6),%d0	# fetch SNAN sign
 3429	andi.l		&0x80000000,%d0		# keep sign
 3430	ori.l		&0x7fc00000,%d0		# insert new exponent,SNAN bit
 3431	mov.l		FP_SRC_HI(%a6),%d1	# load mantissa
 3432	lsr.l		&0x8,%d1		# shift mantissa for sgl
 3433	or.l		%d1,%d0			# create sgl SNAN
 3434	mov.l		EXC_EA(%a6),%a0		# pass: <ea> of default result
 3435	bsr.l		_dmem_write_long	# write the default result
 3436
 3437	tst.l		%d1			# did dstore fail?
 3438	bne.l		facc_out_l		# yes
 3439
 3440	bra.w		fsnan_exit
 3441fsnan_out_d_dn:
 3442	mov.l		FP_SRC_EX(%a6),%d0	# fetch SNAN sign
 3443	andi.l		&0x80000000,%d0		# keep sign
 3444	ori.l		&0x7fc00000,%d0		# insert new exponent,SNAN bit
 3445	mov.l		%d1,-(%sp)
 3446	mov.l		FP_SRC_HI(%a6),%d1	# load mantissa
 3447	lsr.l		&0x8,%d1		# shift mantissa for sgl
 3448	or.l		%d1,%d0			# create sgl SNAN
 3449	mov.l		(%sp)+,%d1
 3450	andi.w		&0x0007,%d1
 3451	bsr.l		store_dreg_l		# store result to regfile
 3452	bra.w		fsnan_exit
 3453
 3454fsnan_out_d:
 3455	mov.l		FP_SRC_EX(%a6),%d0	# fetch SNAN sign
 3456	andi.l		&0x80000000,%d0		# keep sign
 3457	ori.l		&0x7ff80000,%d0		# insert new exponent,SNAN bit
 3458	mov.l		FP_SRC_HI(%a6),%d1	# load hi mantissa
 3459	mov.l		%d0,FP_SCR0_EX(%a6)	# store to temp space
 3460	mov.l		&11,%d0			# load shift amt
 3461	lsr.l		%d0,%d1
 3462	or.l		%d1,FP_SCR0_EX(%a6)	# create dbl hi
 3463	mov.l		FP_SRC_HI(%a6),%d1	# load hi mantissa
 3464	andi.l		&0x000007ff,%d1
 3465	ror.l		%d0,%d1
 3466	mov.l		%d1,FP_SCR0_HI(%a6)	# store to temp space
 3467	mov.l		FP_SRC_LO(%a6),%d1	# load lo mantissa
 3468	lsr.l		%d0,%d1
 3469	or.l		%d1,FP_SCR0_HI(%a6)	# create dbl lo
 3470	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 3471	mov.l		EXC_EA(%a6),%a1		# pass: dst addr
 3472	movq.l		&0x8,%d0		# pass: size of 8 bytes
 3473	bsr.l		_dmem_write		# write the default result
 3474
 3475	tst.l		%d1			# did dstore fail?
 3476	bne.l		facc_out_d		# yes
 3477
 3478	bra.w		fsnan_exit
 3479
 3480# for extended precision, if the addressing mode is pre-decrement or
 3481# post-increment, then the address register did not get updated.
 3482# in addition, for pre-decrement, the stacked <ea> is incorrect.
 3483fsnan_out_x:
 3484	clr.b		SPCOND_FLG(%a6)		# clear special case flag
 3485
 3486	mov.w		FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
 3487	clr.w		2+FP_SCR0(%a6)
 3488	mov.l		FP_SRC_HI(%a6),%d0
 3489	bset		&30,%d0
 3490	mov.l		%d0,FP_SCR0_HI(%a6)
 3491	mov.l		FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
 3492
 3493	btst		&0x5,EXC_SR(%a6)	# supervisor mode exception?
 3494	bne.b		fsnan_out_x_s		# yes
 3495
 3496	mov.l		%usp,%a0		# fetch user stack pointer
 3497	mov.l		%a0,EXC_A7(%a6)		# save on stack for calc_ea()
 3498	mov.l		(%a6),EXC_A6(%a6)
 3499
 3500	bsr.l		_calc_ea_fout		# find the correct ea,update An
 3501	mov.l		%a0,%a1
 3502	mov.l		%a0,EXC_EA(%a6)		# stack correct <ea>
 3503
 3504	mov.l		EXC_A7(%a6),%a0
 3505	mov.l		%a0,%usp		# restore user stack pointer
 3506	mov.l		EXC_A6(%a6),(%a6)
 3507
 3508fsnan_out_x_save:
 3509	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 3510	movq.l		&0xc,%d0		# pass: size of extended
 3511	bsr.l		_dmem_write		# write the default result
 3512
 3513	tst.l		%d1			# did dstore fail?
 3514	bne.l		facc_out_x		# yes
 3515
 3516	bra.w		fsnan_exit
 3517
 3518fsnan_out_x_s:
 3519	mov.l		(%a6),EXC_A6(%a6)
 3520
 3521	bsr.l		_calc_ea_fout		# find the correct ea,update An
 3522	mov.l		%a0,%a1
 3523	mov.l		%a0,EXC_EA(%a6)		# stack correct <ea>
 3524
 3525	mov.l		EXC_A6(%a6),(%a6)
 3526
 3527	cmpi.b		SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
 3528	bne.b		fsnan_out_x_save	# no
 3529
 3530# the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
 3531	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 3532	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3533	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3534
 3535	frestore	FP_SRC(%a6)
 3536
 3537	mov.l		EXC_A6(%a6),%a6		# restore frame pointer
 3538
 3539	mov.l		LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 3540	mov.l		LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
 3541	mov.l		LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
 3542
 3543	mov.l		LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
 3544	mov.l		LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
 3545	mov.l		LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
 3546
 3547	add.l		&LOCAL_SIZE-0x8,%sp
 3548
 3549	bra.l		_real_snan
 3550
 3551#########################################################################
 3552# XDEF ****************************************************************	#
 3553#	_fpsp_inex(): 060FPSP entry point for FP Inexact exception.	#
 3554#									#
 3555#	This handler should be the first code executed upon taking the	#
 3556#	FP Inexact exception in an operating system.			#
 3557#									#
 3558# XREF ****************************************************************	#
 3559#	_imem_read_long() - read instruction longword			#
 3560#	fix_skewed_ops() - adjust src operand in fsave frame		#
 3561#	set_tag_x() - determine optype of src/dst operands		#
 3562#	store_fpreg() - store opclass 0 or 2 result to FP regfile	#
 3563#	unnorm_fix() - change UNNORM operands to NORM or ZERO		#
 3564#	load_fpn2() - load dst operand from FP regfile			#
 3565#	smovcr() - emulate an "fmovcr" instruction			#
 3566#	fout() - emulate an opclass 3 instruction			#
 3567#	tbl_unsupp - add of table of emulation routines for opclass 0,2	#
 3568#	_real_inex() - "callout" to operating system inexact handler	#
 3569#									#
 3570# INPUT ***************************************************************	#
 3571#	- The system stack contains the FP Inexact exception frame	#
 3572#	- The fsave frame contains the source operand			#
 3573#									#
 3574# OUTPUT **************************************************************	#
 3575#	- The system stack is unchanged					#
 3576#	- The fsave frame contains the adjusted src op for opclass 0,2	#
 3577#									#
 3578# ALGORITHM ***********************************************************	#
 3579#	In a system where the FP Inexact exception is enabled, the goal	#
 3580# is to get to the handler specified at _real_inex(). But, on the 060,	#
 3581# for opclass zero and two instruction taking this exception, the	#
 3582# hardware doesn't store the correct result to the destination FP	#
 3583# register as did the '040 and '881/2. This handler must emulate the	#
 3584# instruction in order to get this value and then store it to the	#
 3585# correct register before calling _real_inex().				#
 3586#	For opclass 3 instructions, the 060 doesn't store the default	#
 3587# inexact result out to memory or data register file as it should.	#
 3588# This code must emulate the move out by calling fout() before finally	#
 3589# exiting through _real_inex().						#
 3590#									#
 3591#########################################################################
 3592
 3593	global		_fpsp_inex
 3594_fpsp_inex:
 3595
 3596	link.w		%a6,&-LOCAL_SIZE	# init stack frame
 3597
 3598	fsave		FP_SRC(%a6)		# grab the "busy" frame
 3599
 3600	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 3601	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 3602	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 3603
 3604# the FPIAR holds the "current PC" of the faulting instruction
 3605	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 3606
 3607	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 3608	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 3609	bsr.l		_imem_read_long		# fetch the instruction words
 3610	mov.l		%d0,EXC_OPWORD(%a6)
 3611
 3612##############################################################################
 3613
 3614	btst		&13,%d0			# is instr an fmove out?
 3615	bne.w		finex_out		# fmove out
 3616
 3617
 3618# the hardware, for "fabs" and "fneg" w/ a long source format, puts the
 3619# longword integer directly into the upper longword of the mantissa along
 3620# w/ an exponent value of 0x401e. we convert this to extended precision here.
 3621	bfextu		%d0{&19:&3},%d0		# fetch instr size
 3622	bne.b		finex_cont		# instr size is not long
 3623	cmpi.w		FP_SRC_EX(%a6),&0x401e	# is exponent 0x401e?
 3624	bne.b		finex_cont		# no
 3625	fmov.l		&0x0,%fpcr
 3626	fmov.l		FP_SRC_HI(%a6),%fp0	# load integer src
 3627	fmov.x		%fp0,FP_SRC(%a6)	# store integer as extended precision
 3628	mov.w		&0xe001,0x2+FP_SRC(%a6)
 3629
 3630finex_cont:
 3631	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 3632	bsr.l		fix_skewed_ops		# fix src op
 3633
 3634# Here, we zero the ccode and exception byte field since we're going to
 3635# emulate the whole instruction. Notice, though, that we don't kill the
 3636# INEX1 bit. This is because a packed op has long since been converted
 3637# to extended before arriving here. Therefore, we need to retain the
 3638# INEX1 bit from when the operand was first converted.
 3639	andi.l		&0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
 3640
 3641	fmov.l		&0x0,%fpcr		# zero current control regs
 3642	fmov.l		&0x0,%fpsr
 3643
 3644	bfextu		EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
 3645	cmpi.b		%d1,&0x17		# is op an fmovecr?
 3646	beq.w		finex_fmovcr		# yes
 3647
 3648	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 3649	bsr.l		set_tag_x		# tag the operand type
 3650	mov.b		%d0,STAG(%a6)		# maybe NORM,DENORM
 3651
 3652# bits four and five of the fp extension word separate the monadic and dyadic
 3653# operations that can pass through fpsp_inex(). remember that fcmp and ftst
 3654# will never take this exception, but fsincos will.
 3655	btst		&0x5,1+EXC_CMDREG(%a6)	# is operation monadic or dyadic?
 3656	beq.b		finex_extract		# monadic
 3657
 3658	btst		&0x4,1+EXC_CMDREG(%a6)	# is operation an fsincos?
 3659	bne.b		finex_extract		# yes
 3660
 3661	bfextu		EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 3662	bsr.l		load_fpn2		# load dst into FP_DST
 3663
 3664	lea		FP_DST(%a6),%a0		# pass: ptr to dst op
 3665	bsr.l		set_tag_x		# tag the operand type
 3666	cmpi.b		%d0,&UNNORM		# is operand an UNNORM?
 3667	bne.b		finex_op2_done		# no
 3668	bsr.l		unnorm_fix		# yes; convert to NORM,DENORM,or ZERO
 3669finex_op2_done:
 3670	mov.b		%d0,DTAG(%a6)		# save dst optype tag
 3671
 3672finex_extract:
 3673	clr.l		%d0
 3674	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec/mode
 3675
 3676	mov.b		1+EXC_CMDREG(%a6),%d1
 3677	andi.w		&0x007f,%d1		# extract extension
 3678
 3679	lea		FP_SRC(%a6),%a0
 3680	lea		FP_DST(%a6),%a1
 3681
 3682	mov.l		(tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 3683	jsr		(tbl_unsupp.l,%pc,%d1.l*1)
 3684
 3685# the operation has been emulated. the result is in fp0.
 3686finex_save:
 3687	bfextu		EXC_CMDREG(%a6){&6:&3},%d0
 3688	bsr.l		store_fpreg
 3689
 3690finex_exit:
 3691	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 3692	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3693	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3694
 3695	frestore	FP_SRC(%a6)
 3696
 3697	unlk		%a6
 3698	bra.l		_real_inex
 3699
 3700finex_fmovcr:
 3701	clr.l		%d0
 3702	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec,mode
 3703	mov.b		1+EXC_CMDREG(%a6),%d1
 3704	andi.l		&0x0000007f,%d1		# pass rom offset
 3705	bsr.l		smovcr
 3706	bra.b		finex_save
 3707
 3708########################################################################
 3709
 3710#
 3711# the hardware does not save the default result to memory on enabled
 3712# inexact exceptions. we do this here before passing control to
 3713# the user inexact handler.
 3714#
 3715# byte, word, and long destination format operations can pass
 3716# through here. so can double and single precision.
 3717# although packed opclass three operations can take inexact
 3718# exceptions, they won't pass through here since they are caught
 3719# first by the unsupported data format exception handler. that handler
 3720# sends them directly to _real_inex() if necessary.
 3721#
 3722finex_out:
 3723
 3724	mov.b		&NORM,STAG(%a6)		# src is a NORM
 3725
 3726	clr.l		%d0
 3727	mov.b		FPCR_MODE(%a6),%d0	# pass rnd prec,mode
 3728
 3729	andi.l		&0xffff00ff,USER_FPSR(%a6) # zero exception field
 3730
 3731	lea		FP_SRC(%a6),%a0		# pass ptr to src operand
 3732
 3733	bsr.l		fout			# store the default result
 3734
 3735	bra.b		finex_exit
 3736
 3737#########################################################################
 3738# XDEF ****************************************************************	#
 3739#	_fpsp_dz(): 060FPSP entry point for FP DZ exception.		#
 3740#									#
 3741#	This handler should be the first code executed upon taking	#
 3742#	the FP DZ exception in an operating system.			#
 3743#									#
 3744# XREF ****************************************************************	#
 3745#	_imem_read_long() - read instruction longword from memory	#
 3746#	fix_skewed_ops() - adjust fsave operand				#
 3747#	_real_dz() - "callout" exit point from FP DZ handler		#
 3748#									#
 3749# INPUT ***************************************************************	#
 3750#	- The system stack contains the FP DZ exception stack.		#
 3751#	- The fsave frame contains the source operand.			#
 3752#									#
 3753# OUTPUT **************************************************************	#
 3754#	- The system stack contains the FP DZ exception stack.		#
 3755#	- The fsave frame contains the adjusted source operand.		#
 3756#									#
 3757# ALGORITHM ***********************************************************	#
 3758#	In a system where the DZ exception is enabled, the goal is to	#
 3759# get to the handler specified at _real_dz(). But, on the 060, when the	#
 3760# exception is taken, the input operand in the fsave state frame may	#
 3761# be incorrect for some cases and need to be adjusted. So, this package	#
 3762# adjusts the operand using fix_skewed_ops() and then branches to	#
 3763# _real_dz().								#
 3764#									#
 3765#########################################################################
 3766
 3767	global		_fpsp_dz
 3768_fpsp_dz:
 3769
 3770	link.w		%a6,&-LOCAL_SIZE	# init stack frame
 3771
 3772	fsave		FP_SRC(%a6)		# grab the "busy" frame
 3773
 3774	movm.l		&0x0303,EXC_DREGS(%a6)	# save d0-d1/a0-a1
 3775	fmovm.l		%fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 3776	fmovm.x		&0xc0,EXC_FPREGS(%a6)	# save fp0-fp1 on stack
 3777
 3778# the FPIAR holds the "current PC" of the faulting instruction
 3779	mov.l		USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 3780
 3781	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 3782	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 3783	bsr.l		_imem_read_long		# fetch the instruction words
 3784	mov.l		%d0,EXC_OPWORD(%a6)
 3785
 3786##############################################################################
 3787
 3788
 3789# here, we simply see if the operand in the fsave frame needs to be "unskewed".
 3790# this would be the case for opclass two operations with a source zero
 3791# in the sgl or dbl format.
 3792	lea		FP_SRC(%a6),%a0		# pass: ptr to src op
 3793	bsr.l		fix_skewed_ops		# fix src op
 3794
 3795fdz_exit:
 3796	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
 3797	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 3798	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
 3799
 3800	frestore	FP_SRC(%a6)
 3801
 3802	unlk		%a6
 3803	bra.l		_real_dz
 3804
 3805#########################################################################
 3806# XDEF ****************************************************************	#
 3807#	_fpsp_fline(): 060FPSP entry point for "Line F emulator"	#
 3808#		       exception when the "reduced" version of the	#
 3809#		       FPSP is implemented that does not emulate	#
 3810#		       FP unimplemented instructions.			#
 3811#									#
 3812#	This handler should be the first code executed upon taking a	#
 3813#	"Line F Emulator" exception in an operating system integrating	#
 3814#	the reduced version of 060FPSP.					#
 3815#									#
 3816# XREF ****************************************************************	#
 3817#	_real_fpu_disabled() - Handle "FPU disabled" exceptions		#
 3818#	_real_fline() - Handle all other cases (treated equally)	#
 3819#									#
 3820# INPUT ***************************************************************	#
 3821#	- The system stack contains a "Line F Emulator" exception	#
 3822#	  stack frame.							#
 3823#									#
 3824# OUTPUT **************************************************************	#
 3825#	- The system stack is unchanged.				#
 3826#									#
 3827# ALGORITHM ***********************************************************	#
 3828#	When a "Line F Emulator" exception occurs in a system where	#
 3829# "FPU Unimplemented" instructions will not be emulated, the exception	#
 3830# can occur because then FPU is disabled or the instruction is to be	#
 3831# classifed as "Line F". This module determines which case exists and	#
 3832# calls the appropriate "callout".					#
 3833#									#
 3834#########################################################################
 3835
 3836	global		_fpsp_fline
 3837_fpsp_fline:
 3838
 3839# check to see if the FPU is disabled. if so, jump to the OS entry
 3840# point for that condition.
 3841	cmpi.w		0x6(%sp),&0x402c
 3842	beq.l		_real_fpu_disabled
 3843
 3844	bra.l		_real_fline
 3845
 3846#########################################################################
 3847# XDEF ****************************************************************	#
 3848#	_dcalc_ea(): calc correct <ea> from <ea> stacked on exception	#
 3849#									#
 3850# XREF ****************************************************************	#
 3851#	inc_areg() - increment an address register			#
 3852#	dec_areg() - decrement an address register			#
 3853#									#
 3854# INPUT ***************************************************************	#
 3855#	d0 = number of bytes to adjust <ea> by				#
 3856#									#
 3857# OUTPUT **************************************************************	#
 3858#	None								#
 3859#									#
 3860# ALGORITHM ***********************************************************	#
 3861# "Dummy" CALCulate Effective Address:					#
 3862#	The stacked <ea> for FP unimplemented instructions and opclass	#
 3863#	two packed instructions is correct with the exception of...	#
 3864#									#
 3865#	1) -(An)   : The register is not updated regardless of size.	#
 3866#		     Also, for extended precision and packed, the	#
 3867#		     stacked <ea> value is 8 bytes too big		#
 3868#	2) (An)+   : The register is not updated.			#
 3869#	3) #<data> : The upper longword of the immediate operand is	#
 3870#		     stacked b,w,l and s sizes are completely stacked.	#
 3871#		     d,x, and p are not.				#
 3872#									#
 3873#########################################################################
 3874
 3875	global		_dcalc_ea
 3876_dcalc_ea:
 3877	mov.l		%d0, %a0		# move # bytes to %a0
 3878
 3879	mov.b		1+EXC_OPWORD(%a6), %d0	# fetch opcode word
 3880	mov.l		%d0, %d1		# make a copy
 3881
 3882	andi.w		&0x38, %d0		# extract mode field
 3883	andi.l		&0x7, %d1		# extract reg  field
 3884
 3885	cmpi.b		%d0,&0x18		# is mode (An)+ ?
 3886	beq.b		dcea_pi			# yes
 3887
 3888	cmpi.b		%d0,&0x20		# is mode -(An) ?
 3889	beq.b		dcea_pd			# yes
 3890
 3891	or.w		%d1,%d0			# concat mode,reg
 3892	cmpi.b		%d0,&0x3c		# is mode #<data>?
 3893
 3894	beq.b		dcea_imm		# yes
 3895
 3896	mov.l		EXC_EA(%a6),%a0		# return <ea>
 3897	rts
 3898
 3899# need to set immediate data flag here since we'll need to do
 3900# an imem_read to fetch this later.
 3901dcea_imm:
 3902	mov.b		&immed_flg,SPCOND_FLG(%a6)
 3903	lea		([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
 3904	rts
 3905
 3906# here, the <ea> is stacked correctly. however, we must update the
 3907# address register...
 3908dcea_pi:
 3909	mov.l		%a0,%d0			# pass amt to inc by
 3910	bsr.l		inc_areg		# inc addr register
 3911
 3912	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 3913	rts
 3914
 3915# the <ea> is stacked correctly for all but extended and packed which
 3916# the <ea>s are 8 bytes too large.
 3917# it would make no sense to have a pre-decrement to a7 in supervisor
 3918# mode so we don't even worry about this tricky case here : )
 3919dcea_pd:
 3920	mov.l		%a0,%d0			# pass amt to dec by
 3921	bsr.l		dec_areg		# dec addr register
 3922
 3923	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 3924
 3925	cmpi.b		%d0,&0xc		# is opsize ext or packed?
 3926	beq.b		dcea_pd2		# yes
 3927	rts
 3928dcea_pd2:
 3929	sub.l		&0x8,%a0		# correct <ea>
 3930	mov.l		%a0,EXC_EA(%a6)		# put correct <ea> on stack
 3931	rts
 3932
 3933#########################################################################
 3934# XDEF ****************************************************************	#
 3935#	_calc_ea_fout(): calculate correct stacked <ea> for extended	#
 3936#			 and packed data opclass 3 operations.		#
 3937#									#
 3938# XREF ****************************************************************	#
 3939#	None								#
 3940#									#
 3941# INPUT ***************************************************************	#
 3942#	None								#
 3943#									#
 3944# OUTPUT **************************************************************	#
 3945#	a0 = return correct effective address				#
 3946#									#
 3947# ALGORITHM ***********************************************************	#
 3948#	For opclass 3 extended and packed data operations, the <ea>	#
 3949# stacked for the exception is incorrect for -(an) and (an)+ addressing	#
 3950# modes. Also, while we're at it, the index register itself must get	#
 3951# updated.								#
 3952#	So, for -(an), we must subtract 8 off of the stacked <ea> value	#
 3953# and return that value as the correct <ea> and store that value in An.	#
 3954# For (an)+, the stacked <ea> is correct but we must adjust An by +12.	#
 3955#									#
 3956#########################################################################
 3957
 3958# This calc_ea is currently used to retrieve the correct <ea>
 3959# for fmove outs of type extended and packed.
 3960	global		_calc_ea_fout
 3961_calc_ea_fout:
 3962	mov.b		1+EXC_OPWORD(%a6),%d0	# fetch opcode word
 3963	mov.l		%d0,%d1			# make a copy
 3964
 3965	andi.w		&0x38,%d0		# extract mode field
 3966	andi.l		&0x7,%d1		# extract reg  field
 3967
 3968	cmpi.b		%d0,&0x18		# is mode (An)+ ?
 3969	beq.b		ceaf_pi			# yes
 3970
 3971	cmpi.b		%d0,&0x20		# is mode -(An) ?
 3972	beq.w		ceaf_pd			# yes
 3973
 3974	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 3975	rts
 3976
 3977# (An)+ : extended and packed fmove out
 3978#	: stacked <ea> is correct
 3979#	: "An" not updated
 3980ceaf_pi:
 3981	mov.w		(tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
 3982	mov.l		EXC_EA(%a6),%a0
 3983	jmp		(tbl_ceaf_pi.b,%pc,%d1.w*1)
 3984
 3985	swbeg		&0x8
 3986tbl_ceaf_pi:
 3987	short		ceaf_pi0 - tbl_ceaf_pi
 3988	short		ceaf_pi1 - tbl_ceaf_pi
 3989	short		ceaf_pi2 - tbl_ceaf_pi
 3990	short		ceaf_pi3 - tbl_ceaf_pi
 3991	short		ceaf_pi4 - tbl_ceaf_pi
 3992	short		ceaf_pi5 - tbl_ceaf_pi
 3993	short		ceaf_pi6 - tbl_ceaf_pi
 3994	short		ceaf_pi7 - tbl_ceaf_pi
 3995
 3996ceaf_pi0:
 3997	addi.l		&0xc,EXC_DREGS+0x8(%a6)
 3998	rts
 3999ceaf_pi1:
 4000	addi.l		&0xc,EXC_DREGS+0xc(%a6)
 4001	rts
 4002ceaf_pi2:
 4003	add.l		&0xc,%a2
 4004	rts
 4005ceaf_pi3:
 4006	add.l		&0xc,%a3
 4007	rts
 4008ceaf_pi4:
 4009	add.l		&0xc,%a4
 4010	rts
 4011ceaf_pi5:
 4012	add.l		&0xc,%a5
 4013	rts
 4014ceaf_pi6:
 4015	addi.l		&0xc,EXC_A6(%a6)
 4016	rts
 4017ceaf_pi7:
 4018	mov.b		&mia7_flg,SPCOND_FLG(%a6)
 4019	addi.l		&0xc,EXC_A7(%a6)
 4020	rts
 4021
 4022# -(An) : extended and packed fmove out
 4023#	: stacked <ea> = actual <ea> + 8
 4024#	: "An" not updated
 4025ceaf_pd:
 4026	mov.w		(tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
 4027	mov.l		EXC_EA(%a6),%a0
 4028	sub.l		&0x8,%a0
 4029	sub.l		&0x8,EXC_EA(%a6)
 4030	jmp		(tbl_ceaf_pd.b,%pc,%d1.w*1)
 4031
 4032	swbeg		&0x8
 4033tbl_ceaf_pd:
 4034	short		ceaf_pd0 - tbl_ceaf_pd
 4035	short		ceaf_pd1 - tbl_ceaf_pd
 4036	short		ceaf_pd2 - tbl_ceaf_pd
 4037	short		ceaf_pd3 - tbl_ceaf_pd
 4038	short		ceaf_pd4 - tbl_ceaf_pd
 4039	short		ceaf_pd5 - tbl_ceaf_pd
 4040	short		ceaf_pd6 - tbl_ceaf_pd
 4041	short		ceaf_pd7 - tbl_ceaf_pd
 4042
 4043ceaf_pd0:
 4044	mov.l		%a0,EXC_DREGS+0x8(%a6)
 4045	rts
 4046ceaf_pd1:
 4047	mov.l		%a0,EXC_DREGS+0xc(%a6)
 4048	rts
 4049ceaf_pd2:
 4050	mov.l		%a0,%a2
 4051	rts
 4052ceaf_pd3:
 4053	mov.l		%a0,%a3
 4054	rts
 4055ceaf_pd4:
 4056	mov.l		%a0,%a4
 4057	rts
 4058ceaf_pd5:
 4059	mov.l		%a0,%a5
 4060	rts
 4061ceaf_pd6:
 4062	mov.l		%a0,EXC_A6(%a6)
 4063	rts
 4064ceaf_pd7:
 4065	mov.l		%a0,EXC_A7(%a6)
 4066	mov.b		&mda7_flg,SPCOND_FLG(%a6)
 4067	rts
 4068
 4069#
 4070# This table holds the offsets of the emulation routines for each individual
 4071# math operation relative to the address of this table. Included are
 4072# routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because
 4073# this table is for the version if the 060FPSP without transcendentals.
 4074# The location within the table is determined by the extension bits of the
 4075# operation longword.
 4076#
 4077
 4078	swbeg		&109
 4079tbl_unsupp:
 4080	long		fin		- tbl_unsupp	# 00: fmove
 4081	long		fint		- tbl_unsupp	# 01: fint
 4082	long		tbl_unsupp	- tbl_unsupp	# 02: fsinh
 4083	long		fintrz		- tbl_unsupp	# 03: fintrz
 4084	long		fsqrt		- tbl_unsupp	# 04: fsqrt
 4085	long		tbl_unsupp	- tbl_unsupp
 4086	long		tbl_unsupp	- tbl_unsupp	# 06: flognp1
 4087	long		tbl_unsupp	- tbl_unsupp
 4088	long		tbl_unsupp	- tbl_unsupp	# 08: fetoxm1
 4089	long		tbl_unsupp	- tbl_unsupp	# 09: ftanh
 4090	long		tbl_unsupp	- tbl_unsupp	# 0a: fatan
 4091	long		tbl_unsupp	- tbl_unsupp
 4092	long		tbl_unsupp	- tbl_unsupp	# 0c: fasin
 4093	long		tbl_unsupp	- tbl_unsupp	# 0d: fatanh
 4094	long		tbl_unsupp	- tbl_unsupp	# 0e: fsin
 4095	long		tbl_unsupp	- tbl_unsupp	# 0f: ftan
 4096	long		tbl_unsupp	- tbl_unsupp	# 10: fetox
 4097	long		tbl_unsupp	- tbl_unsupp	# 11: ftwotox
 4098	long		tbl_unsupp	- tbl_unsupp	# 12: ftentox
 4099	long		tbl_unsupp	- tbl_unsupp
 4100	long		tbl_unsupp	- tbl_unsupp	# 14: flogn
 4101	long		tbl_unsupp	- tbl_unsupp	# 15: flog10
 4102	long		tbl_unsupp	- tbl_unsupp	# 16: flog2
 4103	long		tbl_unsupp	- tbl_unsupp
 4104	long		fabs		- tbl_unsupp	# 18: fabs
 4105	long		tbl_unsupp	- tbl_unsupp	# 19: fcosh
 4106	long		fneg		- tbl_unsupp	# 1a: fneg
 4107	long		tbl_unsupp	- tbl_unsupp
 4108	long		tbl_unsupp	- tbl_unsupp	# 1c: facos
 4109	long		tbl_unsupp	- tbl_unsupp	# 1d: fcos
 4110	long		tbl_unsupp	- tbl_unsupp	# 1e: fgetexp
 4111	long		tbl_unsupp	- tbl_unsupp	# 1f: fgetman
 4112	long		fdiv		- tbl_unsupp	# 20: fdiv
 4113	long		tbl_unsupp	- tbl_unsupp	# 21: fmod
 4114	long		fadd		- tbl_unsupp	# 22: fadd
 4115	long		fmul		- tbl_unsupp	# 23: fmul
 4116	long		fsgldiv		- tbl_unsupp	# 24: fsgldiv
 4117	long		tbl_unsupp	- tbl_unsupp	# 25: frem
 4118	long		tbl_unsupp	- tbl_unsupp	# 26: fscale
 4119	long		fsglmul		- tbl_unsupp	# 27: fsglmul
 4120	long		fsub		- tbl_unsupp	# 28: fsub
 4121	long		tbl_unsupp	- tbl_unsupp
 4122	long		tbl_unsupp	- tbl_unsupp
 4123	long		tbl_unsupp	- tbl_unsupp
 4124	long		tbl_unsupp	- tbl_unsupp
 4125	long		tbl_unsupp	- tbl_unsupp
 4126	long		tbl_unsupp	- tbl_unsupp
 4127	long		tbl_unsupp	- tbl_unsupp
 4128	long		tbl_unsupp	- tbl_unsupp	# 30: fsincos
 4129	long		tbl_unsupp	- tbl_unsupp	# 31: fsincos
 4130	long		tbl_unsupp	- tbl_unsupp	# 32: fsincos
 4131	long		tbl_unsupp	- tbl_unsupp	# 33: fsincos
 4132	long		tbl_unsupp	- tbl_unsupp	# 34: fsincos
 4133	long		tbl_unsupp	- tbl_unsupp	# 35: fsincos
 4134	long		tbl_unsupp	- tbl_unsupp	# 36: fsincos
 4135	long		tbl_unsupp	- tbl_unsupp	# 37: fsincos
 4136	long		fcmp		- tbl_unsupp	# 38: fcmp
 4137	long		tbl_unsupp	- tbl_unsupp
 4138	long		ftst		- tbl_unsupp	# 3a: ftst
 4139	long		tbl_unsupp	- tbl_unsupp
 4140	long		tbl_unsupp	- tbl_unsupp
 4141	long		tbl_unsupp	- tbl_unsupp
 4142	long		tbl_unsupp	- tbl_unsupp
 4143	long		tbl_unsupp	- tbl_unsupp
 4144	long		fsin		- tbl_unsupp	# 40: fsmove
 4145	long		fssqrt		- tbl_unsupp	# 41: fssqrt
 4146	long		tbl_unsupp	- tbl_unsupp
 4147	long		tbl_unsupp	- tbl_unsupp
 4148	long		fdin		- tbl_unsupp	# 44: fdmove
 4149	long		fdsqrt		- tbl_unsupp	# 45: fdsqrt
 4150	long		tbl_unsupp	- tbl_unsupp
 4151	long		tbl_unsupp	- tbl_unsupp
 4152	long		tbl_unsupp	- tbl_unsupp
 4153	long		tbl_unsupp	- tbl_unsupp
 4154	long		tbl_unsupp	- tbl_unsupp
 4155	long		tbl_unsupp	- tbl_unsupp
 4156	long		tbl_unsupp	- tbl_unsupp
 4157	long		tbl_unsupp	- tbl_unsupp
 4158	long		tbl_unsupp	- tbl_unsupp
 4159	long		tbl_unsupp	- tbl_unsupp
 4160	long		tbl_unsupp	- tbl_unsupp
 4161	long		tbl_unsupp	- tbl_unsupp
 4162	long		tbl_unsupp	- tbl_unsupp
 4163	long		tbl_unsupp	- tbl_unsupp
 4164	long		tbl_unsupp	- tbl_unsupp
 4165	long		tbl_unsupp	- tbl_unsupp
 4166	long		tbl_unsupp	- tbl_unsupp
 4167	long		tbl_unsupp	- tbl_unsupp
 4168	long		fsabs		- tbl_unsupp	# 58: fsabs
 4169	long		tbl_unsupp	- tbl_unsupp
 4170	long		fsneg		- tbl_unsupp	# 5a: fsneg
 4171	long		tbl_unsupp	- tbl_unsupp
 4172	long		fdabs		- tbl_unsupp	# 5c: fdabs
 4173	long		tbl_unsupp	- tbl_unsupp
 4174	long		fdneg		- tbl_unsupp	# 5e: fdneg
 4175	long		tbl_unsupp	- tbl_unsupp
 4176	long		fsdiv		- tbl_unsupp	# 60: fsdiv
 4177	long		tbl_unsupp	- tbl_unsupp
 4178	long		fsadd		- tbl_unsupp	# 62: fsadd
 4179	long		fsmul		- tbl_unsupp	# 63: fsmul
 4180	long		fddiv		- tbl_unsupp	# 64: fddiv
 4181	long		tbl_unsupp	- tbl_unsupp
 4182	long		fdadd		- tbl_unsupp	# 66: fdadd
 4183	long		fdmul		- tbl_unsupp	# 67: fdmul
 4184	long		fssub		- tbl_unsupp	# 68: fssub
 4185	long		tbl_unsupp	- tbl_unsupp
 4186	long		tbl_unsupp	- tbl_unsupp
 4187	long		tbl_unsupp	- tbl_unsupp
 4188	long		fdsub		- tbl_unsupp	# 6c: fdsub
 4189
 4190#################################################
 4191# Add this here so non-fp modules can compile.
 4192# (smovcr is called from fpsp_inex.)
 4193	global		smovcr
 4194smovcr:
 4195	bra.b		smovcr
 4196
 4197#########################################################################
 4198# XDEF ****************************************************************	#
 4199#	fmovm_dynamic(): emulate "fmovm" dynamic instruction		#
 4200#									#
 4201# XREF ****************************************************************	#
 4202#	fetch_dreg() - fetch data register				#
 4203#	{i,d,}mem_read() - fetch data from memory			#
 4204#	_mem_write() - write data to memory				#
 4205#	iea_iacc() - instruction memory access error occurred		#
 4206#	iea_dacc() - data memory access error occurred			#
 4207#	restore() - restore An index regs if access error occurred	#
 4208#									#
 4209# INPUT ***************************************************************	#
 4210#	None								#
 4211#									#
 4212# OUTPUT **************************************************************	#
 4213#	If instr is "fmovm Dn,-(A7)" from supervisor mode,		#
 4214#		d0 = size of dump					#
 4215#		d1 = Dn							#
 4216#	Else if instruction access error,				#
 4217#		d0 = FSLW						#
 4218#	Else if data access error,					#
 4219#		d0 = FSLW						#
 4220#		a0 = address of fault					#
 4221#	Else								#
 4222#		none.							#
 4223#									#
 4224# ALGORITHM ***********************************************************	#
 4225#	The effective address must be calculated since this is entered	#
 4226# from an "Unimplemented Effective Address" exception handler. So, we	#
 4227# have our own fcalc_ea() routine here. If an access error is flagged	#
 4228# by a _{i,d,}mem_read() call, we must exit through the special		#
 4229# handler.								#
 4230#	The data register is determined and its value loaded to get the	#
 4231# string of FP registers affected. This value is used as an index into	#
 4232# a lookup table such that we can determine the number of bytes		#
 4233# involved.								#
 4234#	If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used	#
 4235# to read in all FP values. Again, _mem_read() may fail and require a	#
 4236# special exit.								#
 4237#	If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used	#
 4238# to write all FP values. _mem_write() may also fail.			#
 4239#	If the instruction is "fmovm.x DN,-(a7)" from supervisor mode,	#
 4240# then we return the size of the dump and the string to the caller	#
 4241# so that the move can occur outside of this routine. This special	#
 4242# case is required so that moves to the system stack are handled	#
 4243# correctly.								#
 4244#									#
 4245# DYNAMIC:								#
 4246#	fmovm.x	dn, <ea>						#
 4247#	fmovm.x	<ea>, dn						#
 4248#									#
 4249#	      <WORD 1>		      <WORD2>				#
 4250#	1111 0010 00 |<ea>|	11@& 1000 0$$$ 0000			#
 4251#									#
 4252#	& = (0): predecrement addressing mode				#
 4253#	    (1): postincrement or control addressing mode		#
 4254#	@ = (0): move listed regs from memory to the FPU		#
 4255#	    (1): move listed regs from the FPU to memory		#
 4256#	$$$    : index of data register holding reg select mask		#
 4257#									#
 4258# NOTES:								#
 4259#	If the data register holds a zero, then the			#
 4260#	instruction is a nop.						#
 4261#									#
 4262#########################################################################
 4263
 4264	global		fmovm_dynamic
 4265fmovm_dynamic:
 4266
 4267# extract the data register in which the bit string resides...
 4268	mov.b		1+EXC_EXTWORD(%a6),%d1	# fetch extword
 4269	andi.w		&0x70,%d1		# extract reg bits
 4270	lsr.b		&0x4,%d1		# shift into lo bits
 4271
 4272# fetch the bit string into d0...
 4273	bsr.l		fetch_dreg		# fetch reg string
 4274
 4275	andi.l		&0x000000ff,%d0		# keep only lo byte
 4276
 4277	mov.l		%d0,-(%sp)		# save strg
 4278	mov.b		(tbl_fmovm_size.w,%pc,%d0),%d0
 4279	mov.l		%d0,-(%sp)		# save size
 4280	bsr.l		fmovm_calc_ea		# calculate <ea>
 4281	mov.l		(%sp)+,%d0		# restore size
 4282	mov.l		(%sp)+,%d1		# restore strg
 4283
 4284# if the bit string is a zero, then the operation is a no-op
 4285# but, make sure that we've calculated ea and advanced the opword pointer
 4286	beq.w		fmovm_data_done
 4287
 4288# separate move ins from move outs...
 4289	btst		&0x5,EXC_EXTWORD(%a6)	# is it a move in or out?
 4290	beq.w		fmovm_data_in		# it's a move out
 4291
 4292#############
 4293# MOVE OUT: #
 4294#############
 4295fmovm_data_out:
 4296	btst		&0x4,EXC_EXTWORD(%a6)	# control or predecrement?
 4297	bne.w		fmovm_out_ctrl		# control
 4298
 4299############################
 4300fmovm_out_predec:
 4301# for predecrement mode, the bit string is the opposite of both control
 4302# operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
 4303# here, we convert it to be just like the others...
 4304	mov.b		(tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
 4305
 4306	btst		&0x5,EXC_SR(%a6)	# user or supervisor mode?
 4307	beq.b		fmovm_out_ctrl		# user
 4308
 4309fmovm_out_predec_s:
 4310	cmpi.b		SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
 4311	bne.b		fmovm_out_ctrl
 4312
 4313# the operation was unfortunately an: fmovm.x dn,-(sp)
 4314# called from supervisor mode.
 4315# we're also passing "size" and "strg" back to the calling routine
 4316	rts
 4317
 4318############################
 4319fmovm_out_ctrl:
 4320	mov.l		%a0,%a1			# move <ea> to a1
 4321
 4322	sub.l		%d0,%sp			# subtract size of dump
 4323	lea		(%sp),%a0
 4324
 4325	tst.b		%d1			# should FP0 be moved?
 4326	bpl.b		fmovm_out_ctrl_fp1	# no
 4327
 4328	mov.l		0x0+EXC_FP0(%a6),(%a0)+	# yes
 4329	mov.l		0x4+EXC_FP0(%a6),(%a0)+
 4330	mov.l		0x8+EXC_FP0(%a6),(%a0)+
 4331
 4332fmovm_out_ctrl_fp1:
 4333	lsl.b		&0x1,%d1		# should FP1 be moved?
 4334	bpl.b		fmovm_out_ctrl_fp2	# no
 4335
 4336	mov.l		0x0+EXC_FP1(%a6),(%a0)+	# yes
 4337	mov.l		0x4+EXC_FP1(%a6),(%a0)+
 4338	mov.l		0x8+EXC_FP1(%a6),(%a0)+
 4339
 4340fmovm_out_ctrl_fp2:
 4341	lsl.b		&0x1,%d1		# should FP2 be moved?
 4342	bpl.b		fmovm_out_ctrl_fp3	# no
 4343
 4344	fmovm.x		&0x20,(%a0)		# yes
 4345	add.l		&0xc,%a0
 4346
 4347fmovm_out_ctrl_fp3:
 4348	lsl.b		&0x1,%d1		# should FP3 be moved?
 4349	bpl.b		fmovm_out_ctrl_fp4	# no
 4350
 4351	fmovm.x		&0x10,(%a0)		# yes
 4352	add.l		&0xc,%a0
 4353
 4354fmovm_out_ctrl_fp4:
 4355	lsl.b		&0x1,%d1		# should FP4 be moved?
 4356	bpl.b		fmovm_out_ctrl_fp5	# no
 4357
 4358	fmovm.x		&0x08,(%a0)		# yes
 4359	add.l		&0xc,%a0
 4360
 4361fmovm_out_ctrl_fp5:
 4362	lsl.b		&0x1,%d1		# should FP5 be moved?
 4363	bpl.b		fmovm_out_ctrl_fp6	# no
 4364
 4365	fmovm.x		&0x04,(%a0)		# yes
 4366	add.l		&0xc,%a0
 4367
 4368fmovm_out_ctrl_fp6:
 4369	lsl.b		&0x1,%d1		# should FP6 be moved?
 4370	bpl.b		fmovm_out_ctrl_fp7	# no
 4371
 4372	fmovm.x		&0x02,(%a0)		# yes
 4373	add.l		&0xc,%a0
 4374
 4375fmovm_out_ctrl_fp7:
 4376	lsl.b		&0x1,%d1		# should FP7 be moved?
 4377	bpl.b		fmovm_out_ctrl_done	# no
 4378
 4379	fmovm.x		&0x01,(%a0)		# yes
 4380	add.l		&0xc,%a0
 4381
 4382fmovm_out_ctrl_done:
 4383	mov.l		%a1,L_SCR1(%a6)
 4384
 4385	lea		(%sp),%a0		# pass: supervisor src
 4386	mov.l		%d0,-(%sp)		# save size
 4387	bsr.l		_dmem_write		# copy data to user mem
 4388
 4389	mov.l		(%sp)+,%d0
 4390	add.l		%d0,%sp			# clear fpreg data from stack
 4391
 4392	tst.l		%d1			# did dstore err?
 4393	bne.w		fmovm_out_err		# yes
 4394
 4395	rts
 4396
 4397############
 4398# MOVE IN: #
 4399############
 4400fmovm_data_in:
 4401	mov.l		%a0,L_SCR1(%a6)
 4402
 4403	sub.l		%d0,%sp			# make room for fpregs
 4404	lea		(%sp),%a1
 4405
 4406	mov.l		%d1,-(%sp)		# save bit string for later
 4407	mov.l		%d0,-(%sp)		# save # of bytes
 4408
 4409	bsr.l		_dmem_read		# copy data from user mem
 4410
 4411	mov.l		(%sp)+,%d0		# retrieve # of bytes
 4412
 4413	tst.l		%d1			# did dfetch fail?
 4414	bne.w		fmovm_in_err		# yes
 4415
 4416	mov.l		(%sp)+,%d1		# load bit string
 4417
 4418	lea		(%sp),%a0		# addr of stack
 4419
 4420	tst.b		%d1			# should FP0 be moved?
 4421	bpl.b		fmovm_data_in_fp1	# no
 4422
 4423	mov.l		(%a0)+,0x0+EXC_FP0(%a6)	# yes
 4424	mov.l		(%a0)+,0x4+EXC_FP0(%a6)
 4425	mov.l		(%a0)+,0x8+EXC_FP0(%a6)
 4426
 4427fmovm_data_in_fp1:
 4428	lsl.b		&0x1,%d1		# should FP1 be moved?
 4429	bpl.b		fmovm_data_in_fp2	# no
 4430
 4431	mov.l		(%a0)+,0x0+EXC_FP1(%a6)	# yes
 4432	mov.l		(%a0)+,0x4+EXC_FP1(%a6)
 4433	mov.l		(%a0)+,0x8+EXC_FP1(%a6)
 4434
 4435fmovm_data_in_fp2:
 4436	lsl.b		&0x1,%d1		# should FP2 be moved?
 4437	bpl.b		fmovm_data_in_fp3	# no
 4438
 4439	fmovm.x		(%a0)+,&0x20		# yes
 4440
 4441fmovm_data_in_fp3:
 4442	lsl.b		&0x1,%d1		# should FP3 be moved?
 4443	bpl.b		fmovm_data_in_fp4	# no
 4444
 4445	fmovm.x		(%a0)+,&0x10		# yes
 4446
 4447fmovm_data_in_fp4:
 4448	lsl.b		&0x1,%d1		# should FP4 be moved?
 4449	bpl.b		fmovm_data_in_fp5	# no
 4450
 4451	fmovm.x		(%a0)+,&0x08		# yes
 4452
 4453fmovm_data_in_fp5:
 4454	lsl.b		&0x1,%d1		# should FP5 be moved?
 4455	bpl.b		fmovm_data_in_fp6	# no
 4456
 4457	fmovm.x		(%a0)+,&0x04		# yes
 4458
 4459fmovm_data_in_fp6:
 4460	lsl.b		&0x1,%d1		# should FP6 be moved?
 4461	bpl.b		fmovm_data_in_fp7	# no
 4462
 4463	fmovm.x		(%a0)+,&0x02		# yes
 4464
 4465fmovm_data_in_fp7:
 4466	lsl.b		&0x1,%d1		# should FP7 be moved?
 4467	bpl.b		fmovm_data_in_done	# no
 4468
 4469	fmovm.x		(%a0)+,&0x01		# yes
 4470
 4471fmovm_data_in_done:
 4472	add.l		%d0,%sp			# remove fpregs from stack
 4473	rts
 4474
 4475#####################################
 4476
 4477fmovm_data_done:
 4478	rts
 4479
 4480##############################################################################
 4481
 4482#
 4483# table indexed by the operation's bit string that gives the number
 4484# of bytes that will be moved.
 4485#
 4486# number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
 4487#
 4488tbl_fmovm_size:
 4489	byte	0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
 4490	byte	0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
 4491	byte	0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
 4492	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4493	byte	0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
 4494	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4495	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4496	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4497	byte	0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
 4498	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4499	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4500	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4501	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4502	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4503	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4504	byte	0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
 4505	byte	0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
 4506	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4507	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4508	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4509	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4510	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4511	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4512	byte	0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
 4513	byte	0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
 4514	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4515	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4516	byte	0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
 4517	byte	0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
 4518	byte	0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
 4519	byte	0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
 4520	byte	0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
 4521
 4522#
 4523# table to convert a pre-decrement bit string into a post-increment
 4524# or control bit string.
 4525# ex:	0x00	==>	0x00
 4526#	0x01	==>	0x80
 4527#	0x02	==>	0x40
 4528#		.
 4529#		.
 4530#	0xfd	==>	0xbf
 4531#	0xfe	==>	0x7f
 4532#	0xff	==>	0xff
 4533#
 4534tbl_fmovm_convert:
 4535	byte	0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
 4536	byte	0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
 4537	byte	0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
 4538	byte	0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
 4539	byte	0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
 4540	byte	0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
 4541	byte	0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
 4542	byte	0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
 4543	byte	0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
 4544	byte	0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
 4545	byte	0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
 4546	byte	0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
 4547	byte	0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
 4548	byte	0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
 4549	byte	0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
 4550	byte	0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
 4551	byte	0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
 4552	byte	0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
 4553	byte	0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
 4554	byte	0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
 4555	byte	0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
 4556	byte	0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
 4557	byte	0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
 4558	byte	0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
 4559	byte	0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
 4560	byte	0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
 4561	byte	0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
 4562	byte	0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
 4563	byte	0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
 4564	byte	0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
 4565	byte	0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
 4566	byte	0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
 4567
 4568	global		fmovm_calc_ea
 4569###############################################
 4570# _fmovm_calc_ea: calculate effective address #
 4571###############################################
 4572fmovm_calc_ea:
 4573	mov.l		%d0,%a0			# move # bytes to a0
 4574
 4575# currently, MODE and REG are taken from the EXC_OPWORD. this could be
 4576# easily changed if they were inputs passed in registers.
 4577	mov.w		EXC_OPWORD(%a6),%d0	# fetch opcode word
 4578	mov.w		%d0,%d1			# make a copy
 4579
 4580	andi.w		&0x3f,%d0		# extract mode field
 4581	andi.l		&0x7,%d1		# extract reg  field
 4582
 4583# jump to the corresponding function for each {MODE,REG} pair.
 4584	mov.w		(tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
 4585	jmp		(tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
 4586
 4587	swbeg		&64
 4588tbl_fea_mode:
 4589	short		tbl_fea_mode	-	tbl_fea_mode
 4590	short		tbl_fea_mode	-	tbl_fea_mode
 4591	short		tbl_fea_mode	-	tbl_fea_mode
 4592	short		tbl_fea_mode	-	tbl_fea_mode
 4593	short		tbl_fea_mode	-	tbl_fea_mode
 4594	short		tbl_fea_mode	-	tbl_fea_mode
 4595	short		tbl_fea_mode	-	tbl_fea_mode
 4596	short		tbl_fea_mode	-	tbl_fea_mode
 4597
 4598	short		tbl_fea_mode	-	tbl_fea_mode
 4599	short		tbl_fea_mode	-	tbl_fea_mode
 4600	short		tbl_fea_mode	-	tbl_fea_mode
 4601	short		tbl_fea_mode	-	tbl_fea_mode
 4602	short		tbl_fea_mode	-	tbl_fea_mode
 4603	short		tbl_fea_mode	-	tbl_fea_mode
 4604	short		tbl_fea_mode	-	tbl_fea_mode
 4605	short		tbl_fea_mode	-	tbl_fea_mode
 4606
 4607	short		faddr_ind_a0	-	tbl_fea_mode
 4608	short		faddr_ind_a1	-	tbl_fea_mode
 4609	short		faddr_ind_a2	-	tbl_fea_mode
 4610	short		faddr_ind_a3	-	tbl_fea_mode
 4611	short		faddr_ind_a4	-	tbl_fea_mode
 4612	short		faddr_ind_a5	-	tbl_fea_mode
 4613	short		faddr_ind_a6	-	tbl_fea_mode
 4614	short		faddr_ind_a7	-	tbl_fea_mode
 4615
 4616	short		faddr_ind_p_a0	-	tbl_fea_mode
 4617	short		faddr_ind_p_a1	-	tbl_fea_mode
 4618	short		faddr_ind_p_a2	-	tbl_fea_mode
 4619	short		faddr_ind_p_a3	-	tbl_fea_mode
 4620	short		faddr_ind_p_a4	-	tbl_fea_mode
 4621	short		faddr_ind_p_a5	-	tbl_fea_mode
 4622	short		faddr_ind_p_a6	-	tbl_fea_mode
 4623	short		faddr_ind_p_a7	-	tbl_fea_mode
 4624
 4625	short		faddr_ind_m_a0	-	tbl_fea_mode
 4626	short		faddr_ind_m_a1	-	tbl_fea_mode
 4627	short		faddr_ind_m_a2	-	tbl_fea_mode
 4628	short		faddr_ind_m_a3	-	tbl_fea_mode
 4629	short		faddr_ind_m_a4	-	tbl_fea_mode
 4630	short		faddr_ind_m_a5	-	tbl_fea_mode
 4631	short		faddr_ind_m_a6	-	tbl_fea_mode
 4632	short		faddr_ind_m_a7	-	tbl_fea_mode
 4633
 4634	short		faddr_ind_disp_a0	-	tbl_fea_mode
 4635	short		faddr_ind_disp_a1	-	tbl_fea_mode
 4636	short		faddr_ind_disp_a2	-	tbl_fea_mode
 4637	short		faddr_ind_disp_a3	-	tbl_fea_mode
 4638	short		faddr_ind_disp_a4	-	tbl_fea_mode
 4639	short		faddr_ind_disp_a5	-	tbl_fea_mode
 4640	short		faddr_ind_disp_a6	-	tbl_fea_mode
 4641	short		faddr_ind_disp_a7	-	tbl_fea_mode
 4642
 4643	short		faddr_ind_ext	-	tbl_fea_mode
 4644	short		faddr_ind_ext	-	tbl_fea_mode
 4645	short		faddr_ind_ext	-	tbl_fea_mode
 4646	short		faddr_ind_ext	-	tbl_fea_mode
 4647	short		faddr_ind_ext	-	tbl_fea_mode
 4648	short		faddr_ind_ext	-	tbl_fea_mode
 4649	short		faddr_ind_ext	-	tbl_fea_mode
 4650	short		faddr_ind_ext	-	tbl_fea_mode
 4651
 4652	short		fabs_short	-	tbl_fea_mode
 4653	short		fabs_long	-	tbl_fea_mode
 4654	short		fpc_ind		-	tbl_fea_mode
 4655	short		fpc_ind_ext	-	tbl_fea_mode
 4656	short		tbl_fea_mode	-	tbl_fea_mode
 4657	short		tbl_fea_mode	-	tbl_fea_mode
 4658	short		tbl_fea_mode	-	tbl_fea_mode
 4659	short		tbl_fea_mode	-	tbl_fea_mode
 4660
 4661###################################
 4662# Address register indirect: (An) #
 4663###################################
 4664faddr_ind_a0:
 4665	mov.l		EXC_DREGS+0x8(%a6),%a0	# Get current a0
 4666	rts
 4667
 4668faddr_ind_a1:
 4669	mov.l		EXC_DREGS+0xc(%a6),%a0	# Get current a1
 4670	rts
 4671
 4672faddr_ind_a2:
 4673	mov.l		%a2,%a0			# Get current a2
 4674	rts
 4675
 4676faddr_ind_a3:
 4677	mov.l		%a3,%a0			# Get current a3
 4678	rts
 4679
 4680faddr_ind_a4:
 4681	mov.l		%a4,%a0			# Get current a4
 4682	rts
 4683
 4684faddr_ind_a5:
 4685	mov.l		%a5,%a0			# Get current a5
 4686	rts
 4687
 4688faddr_ind_a6:
 4689	mov.l		(%a6),%a0		# Get current a6
 4690	rts
 4691
 4692faddr_ind_a7:
 4693	mov.l		EXC_A7(%a6),%a0		# Get current a7
 4694	rts
 4695
 4696#####################################################
 4697# Address register indirect w/ postincrement: (An)+ #
 4698#####################################################
 4699faddr_ind_p_a0:
 4700	mov.l		EXC_DREGS+0x8(%a6),%d0	# Get current a0
 4701	mov.l		%d0,%d1
 4702	add.l		%a0,%d1			# Increment
 4703	mov.l		%d1,EXC_DREGS+0x8(%a6)	# Save incr value
 4704	mov.l		%d0,%a0
 4705	rts
 4706
 4707faddr_ind_p_a1:
 4708	mov.l		EXC_DREGS+0xc(%a6),%d0	# Get current a1
 4709	mov.l		%d0,%d1
 4710	add.l		%a0,%d1			# Increment
 4711	mov.l		%d1,EXC_DREGS+0xc(%a6)	# Save incr value
 4712	mov.l		%d0,%a0
 4713	rts
 4714
 4715faddr_ind_p_a2:
 4716	mov.l		%a2,%d0			# Get current a2
 4717	mov.l		%d0,%d1
 4718	add.l		%a0,%d1			# Increment
 4719	mov.l		%d1,%a2			# Save incr value
 4720	mov.l		%d0,%a0
 4721	rts
 4722
 4723faddr_ind_p_a3:
 4724	mov.l		%a3,%d0			# Get current a3
 4725	mov.l		%d0,%d1
 4726	add.l		%a0,%d1			# Increment
 4727	mov.l		%d1,%a3			# Save incr value
 4728	mov.l		%d0,%a0
 4729	rts
 4730
 4731faddr_ind_p_a4:
 4732	mov.l		%a4,%d0			# Get current a4
 4733	mov.l		%d0,%d1
 4734	add.l		%a0,%d1			# Increment
 4735	mov.l		%d1,%a4			# Save incr value
 4736	mov.l		%d0,%a0
 4737	rts
 4738
 4739faddr_ind_p_a5:
 4740	mov.l		%a5,%d0			# Get current a5
 4741	mov.l		%d0,%d1
 4742	add.l		%a0,%d1			# Increment
 4743	mov.l		%d1,%a5			# Save incr value
 4744	mov.l		%d0,%a0
 4745	rts
 4746
 4747faddr_ind_p_a6:
 4748	mov.l		(%a6),%d0		# Get current a6
 4749	mov.l		%d0,%d1
 4750	add.l		%a0,%d1			# Increment
 4751	mov.l		%d1,(%a6)		# Save incr value
 4752	mov.l		%d0,%a0
 4753	rts
 4754
 4755faddr_ind_p_a7:
 4756	mov.b		&mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
 4757
 4758	mov.l		EXC_A7(%a6),%d0		# Get current a7
 4759	mov.l		%d0,%d1
 4760	add.l		%a0,%d1			# Increment
 4761	mov.l		%d1,EXC_A7(%a6)		# Save incr value
 4762	mov.l		%d0,%a0
 4763	rts
 4764
 4765####################################################
 4766# Address register indirect w/ predecrement: -(An) #
 4767####################################################
 4768faddr_ind_m_a0:
 4769	mov.l		EXC_DREGS+0x8(%a6),%d0	# Get current a0
 4770	sub.l		%a0,%d0			# Decrement
 4771	mov.l		%d0,EXC_DREGS+0x8(%a6)	# Save decr value
 4772	mov.l		%d0,%a0
 4773	rts
 4774
 4775faddr_ind_m_a1:
 4776	mov.l		EXC_DREGS+0xc(%a6),%d0	# Get current a1
 4777	sub.l		%a0,%d0			# Decrement
 4778	mov.l		%d0,EXC_DREGS+0xc(%a6)	# Save decr value
 4779	mov.l		%d0,%a0
 4780	rts
 4781
 4782faddr_ind_m_a2:
 4783	mov.l		%a2,%d0			# Get current a2
 4784	sub.l		%a0,%d0			# Decrement
 4785	mov.l		%d0,%a2			# Save decr value
 4786	mov.l		%d0,%a0
 4787	rts
 4788
 4789faddr_ind_m_a3:
 4790	mov.l		%a3,%d0			# Get current a3
 4791	sub.l		%a0,%d0			# Decrement
 4792	mov.l		%d0,%a3			# Save decr value
 4793	mov.l		%d0,%a0
 4794	rts
 4795
 4796faddr_ind_m_a4:
 4797	mov.l		%a4,%d0			# Get current a4
 4798	sub.l		%a0,%d0			# Decrement
 4799	mov.l		%d0,%a4			# Save decr value
 4800	mov.l		%d0,%a0
 4801	rts
 4802
 4803faddr_ind_m_a5:
 4804	mov.l		%a5,%d0			# Get current a5
 4805	sub.l		%a0,%d0			# Decrement
 4806	mov.l		%d0,%a5			# Save decr value
 4807	mov.l		%d0,%a0
 4808	rts
 4809
 4810faddr_ind_m_a6:
 4811	mov.l		(%a6),%d0		# Get current a6
 4812	sub.l		%a0,%d0			# Decrement
 4813	mov.l		%d0,(%a6)		# Save decr value
 4814	mov.l		%d0,%a0
 4815	rts
 4816
 4817faddr_ind_m_a7:
 4818	mov.b		&mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
 4819
 4820	mov.l		EXC_A7(%a6),%d0		# Get current a7
 4821	sub.l		%a0,%d0			# Decrement
 4822	mov.l		%d0,EXC_A7(%a6)		# Save decr value
 4823	mov.l		%d0,%a0
 4824	rts
 4825
 4826########################################################
 4827# Address register indirect w/ displacement: (d16, An) #
 4828########################################################
 4829faddr_ind_disp_a0:
 4830	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4831	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4832	bsr.l		_imem_read_word
 4833
 4834	tst.l		%d1			# did ifetch fail?
 4835	bne.l		iea_iacc		# yes
 4836
 4837	mov.w		%d0,%a0			# sign extend displacement
 4838
 4839	add.l		EXC_DREGS+0x8(%a6),%a0	# a0 + d16
 4840	rts
 4841
 4842faddr_ind_disp_a1:
 4843	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4844	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4845	bsr.l		_imem_read_word
 4846
 4847	tst.l		%d1			# did ifetch fail?
 4848	bne.l		iea_iacc		# yes
 4849
 4850	mov.w		%d0,%a0			# sign extend displacement
 4851
 4852	add.l		EXC_DREGS+0xc(%a6),%a0	# a1 + d16
 4853	rts
 4854
 4855faddr_ind_disp_a2:
 4856	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4857	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4858	bsr.l		_imem_read_word
 4859
 4860	tst.l		%d1			# did ifetch fail?
 4861	bne.l		iea_iacc		# yes
 4862
 4863	mov.w		%d0,%a0			# sign extend displacement
 4864
 4865	add.l		%a2,%a0			# a2 + d16
 4866	rts
 4867
 4868faddr_ind_disp_a3:
 4869	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4870	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4871	bsr.l		_imem_read_word
 4872
 4873	tst.l		%d1			# did ifetch fail?
 4874	bne.l		iea_iacc		# yes
 4875
 4876	mov.w		%d0,%a0			# sign extend displacement
 4877
 4878	add.l		%a3,%a0			# a3 + d16
 4879	rts
 4880
 4881faddr_ind_disp_a4:
 4882	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4883	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4884	bsr.l		_imem_read_word
 4885
 4886	tst.l		%d1			# did ifetch fail?
 4887	bne.l		iea_iacc		# yes
 4888
 4889	mov.w		%d0,%a0			# sign extend displacement
 4890
 4891	add.l		%a4,%a0			# a4 + d16
 4892	rts
 4893
 4894faddr_ind_disp_a5:
 4895	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4896	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4897	bsr.l		_imem_read_word
 4898
 4899	tst.l		%d1			# did ifetch fail?
 4900	bne.l		iea_iacc		# yes
 4901
 4902	mov.w		%d0,%a0			# sign extend displacement
 4903
 4904	add.l		%a5,%a0			# a5 + d16
 4905	rts
 4906
 4907faddr_ind_disp_a6:
 4908	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4909	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4910	bsr.l		_imem_read_word
 4911
 4912	tst.l		%d1			# did ifetch fail?
 4913	bne.l		iea_iacc		# yes
 4914
 4915	mov.w		%d0,%a0			# sign extend displacement
 4916
 4917	add.l		(%a6),%a0		# a6 + d16
 4918	rts
 4919
 4920faddr_ind_disp_a7:
 4921	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4922	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4923	bsr.l		_imem_read_word
 4924
 4925	tst.l		%d1			# did ifetch fail?
 4926	bne.l		iea_iacc		# yes
 4927
 4928	mov.w		%d0,%a0			# sign extend displacement
 4929
 4930	add.l		EXC_A7(%a6),%a0		# a7 + d16
 4931	rts
 4932
 4933########################################################################
 4934# Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
 4935#    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
 4936# Memory indirect postindexed: ([bd, An], Xn, od)		       #
 4937# Memory indirect preindexed: ([bd, An, Xn], od)		       #
 4938########################################################################
 4939faddr_ind_ext:
 4940	addq.l		&0x8,%d1
 4941	bsr.l		fetch_dreg		# fetch base areg
 4942	mov.l		%d0,-(%sp)
 4943
 4944	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4945	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4946	bsr.l		_imem_read_word		# fetch extword in d0
 4947
 4948	tst.l		%d1			# did ifetch fail?
 4949	bne.l		iea_iacc		# yes
 4950
 4951	mov.l		(%sp)+,%a0
 4952
 4953	btst		&0x8,%d0
 4954	bne.w		fcalc_mem_ind
 4955
 4956	mov.l		%d0,L_SCR1(%a6)		# hold opword
 4957
 4958	mov.l		%d0,%d1
 4959	rol.w		&0x4,%d1
 4960	andi.w		&0xf,%d1		# extract index regno
 4961
 4962# count on fetch_dreg() not to alter a0...
 4963	bsr.l		fetch_dreg		# fetch index
 4964
 4965	mov.l		%d2,-(%sp)		# save d2
 4966	mov.l		L_SCR1(%a6),%d2		# fetch opword
 4967
 4968	btst		&0xb,%d2		# is it word or long?
 4969	bne.b		faii8_long
 4970	ext.l		%d0			# sign extend word index
 4971faii8_long:
 4972	mov.l		%d2,%d1
 4973	rol.w		&0x7,%d1
 4974	andi.l		&0x3,%d1		# extract scale value
 4975
 4976	lsl.l		%d1,%d0			# shift index by scale
 4977
 4978	extb.l		%d2			# sign extend displacement
 4979	add.l		%d2,%d0			# index + disp
 4980	add.l		%d0,%a0			# An + (index + disp)
 4981
 4982	mov.l		(%sp)+,%d2		# restore old d2
 4983	rts
 4984
 4985###########################
 4986# Absolute short: (XXX).W #
 4987###########################
 4988fabs_short:
 4989	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 4990	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 4991	bsr.l		_imem_read_word		# fetch short address
 4992
 4993	tst.l		%d1			# did ifetch fail?
 4994	bne.l		iea_iacc		# yes
 4995
 4996	mov.w		%d0,%a0			# return <ea> in a0
 4997	rts
 4998
 4999##########################
 5000# Absolute long: (XXX).L #
 5001##########################
 5002fabs_long:
 5003	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5004	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5005	bsr.l		_imem_read_long		# fetch long address
 5006
 5007	tst.l		%d1			# did ifetch fail?
 5008	bne.l		iea_iacc		# yes
 5009
 5010	mov.l		%d0,%a0			# return <ea> in a0
 5011	rts
 5012
 5013#######################################################
 5014# Program counter indirect w/ displacement: (d16, PC) #
 5015#######################################################
 5016fpc_ind:
 5017	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5018	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5019	bsr.l		_imem_read_word		# fetch word displacement
 5020
 5021	tst.l		%d1			# did ifetch fail?
 5022	bne.l		iea_iacc		# yes
 5023
 5024	mov.w		%d0,%a0			# sign extend displacement
 5025
 5026	add.l		EXC_EXTWPTR(%a6),%a0	# pc + d16
 5027
 5028# _imem_read_word() increased the extwptr by 2. need to adjust here.
 5029	subq.l		&0x2,%a0		# adjust <ea>
 5030	rts
 5031
 5032##########################################################
 5033# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
 5034# "     "     w/   "  (base displacement): (bd, PC, An)  #
 5035# PC memory indirect postindexed: ([bd, PC], Xn, od)     #
 5036# PC memory indirect preindexed: ([bd, PC, Xn], od)      #
 5037##########################################################
 5038fpc_ind_ext:
 5039	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5040	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5041	bsr.l		_imem_read_word		# fetch ext word
 5042
 5043	tst.l		%d1			# did ifetch fail?
 5044	bne.l		iea_iacc		# yes
 5045
 5046	mov.l		EXC_EXTWPTR(%a6),%a0	# put base in a0
 5047	subq.l		&0x2,%a0		# adjust base
 5048
 5049	btst		&0x8,%d0		# is disp only 8 bits?
 5050	bne.w		fcalc_mem_ind		# calc memory indirect
 5051
 5052	mov.l		%d0,L_SCR1(%a6)		# store opword
 5053
 5054	mov.l		%d0,%d1			# make extword copy
 5055	rol.w		&0x4,%d1		# rotate reg num into place
 5056	andi.w		&0xf,%d1		# extract register number
 5057
 5058# count on fetch_dreg() not to alter a0...
 5059	bsr.l		fetch_dreg		# fetch index
 5060
 5061	mov.l		%d2,-(%sp)		# save d2
 5062	mov.l		L_SCR1(%a6),%d2		# fetch opword
 5063
 5064	btst		&0xb,%d2		# is index word or long?
 5065	bne.b		fpii8_long		# long
 5066	ext.l		%d0			# sign extend word index
 5067fpii8_long:
 5068	mov.l		%d2,%d1
 5069	rol.w		&0x7,%d1		# rotate scale value into place
 5070	andi.l		&0x3,%d1		# extract scale value
 5071
 5072	lsl.l		%d1,%d0			# shift index by scale
 5073
 5074	extb.l		%d2			# sign extend displacement
 5075	add.l		%d2,%d0			# disp + index
 5076	add.l		%d0,%a0			# An + (index + disp)
 5077
 5078	mov.l		(%sp)+,%d2		# restore temp register
 5079	rts
 5080
 5081# d2 = index
 5082# d3 = base
 5083# d4 = od
 5084# d5 = extword
 5085fcalc_mem_ind:
 5086	btst		&0x6,%d0		# is the index suppressed?
 5087	beq.b		fcalc_index
 5088
 5089	movm.l		&0x3c00,-(%sp)		# save d2-d5
 5090
 5091	mov.l		%d0,%d5			# put extword in d5
 5092	mov.l		%a0,%d3			# put base in d3
 5093
 5094	clr.l		%d2			# yes, so index = 0
 5095	bra.b		fbase_supp_ck
 5096
 5097# index:
 5098fcalc_index:
 5099	mov.l		%d0,L_SCR1(%a6)		# save d0 (opword)
 5100	bfextu		%d0{&16:&4},%d1		# fetch dreg index
 5101	bsr.l		fetch_dreg
 5102
 5103	movm.l		&0x3c00,-(%sp)		# save d2-d5
 5104	mov.l		%d0,%d2			# put index in d2
 5105	mov.l		L_SCR1(%a6),%d5
 5106	mov.l		%a0,%d3
 5107
 5108	btst		&0xb,%d5		# is index word or long?
 5109	bne.b		fno_ext
 5110	ext.l		%d2
 5111
 5112fno_ext:
 5113	bfextu		%d5{&21:&2},%d0
 5114	lsl.l		%d0,%d2
 5115
 5116# base address (passed as parameter in d3):
 5117# we clear the value here if it should actually be suppressed.
 5118fbase_supp_ck:
 5119	btst		&0x7,%d5		# is the bd suppressed?
 5120	beq.b		fno_base_sup
 5121	clr.l		%d3
 5122
 5123# base displacement:
 5124fno_base_sup:
 5125	bfextu		%d5{&26:&2},%d0		# get bd size
 5126#	beq.l		fmovm_error		# if (size == 0) it's reserved
 5127
 5128	cmpi.b		%d0,&0x2
 5129	blt.b		fno_bd
 5130	beq.b		fget_word_bd
 5131
 5132	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5133	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5134	bsr.l		_imem_read_long
 5135
 5136	tst.l		%d1			# did ifetch fail?
 5137	bne.l		fcea_iacc		# yes
 5138
 5139	bra.b		fchk_ind
 5140
 5141fget_word_bd:
 5142	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5143	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5144	bsr.l		_imem_read_word
 5145
 5146	tst.l		%d1			# did ifetch fail?
 5147	bne.l		fcea_iacc		# yes
 5148
 5149	ext.l		%d0			# sign extend bd
 5150
 5151fchk_ind:
 5152	add.l		%d0,%d3			# base += bd
 5153
 5154# outer displacement:
 5155fno_bd:
 5156	bfextu		%d5{&30:&2},%d0		# is od suppressed?
 5157	beq.w		faii_bd
 5158
 5159	cmpi.b		%d0,&0x2
 5160	blt.b		fnull_od
 5161	beq.b		fword_od
 5162
 5163	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5164	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5165	bsr.l		_imem_read_long
 5166
 5167	tst.l		%d1			# did ifetch fail?
 5168	bne.l		fcea_iacc		# yes
 5169
 5170	bra.b		fadd_them
 5171
 5172fword_od:
 5173	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5174	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5175	bsr.l		_imem_read_word
 5176
 5177	tst.l		%d1			# did ifetch fail?
 5178	bne.l		fcea_iacc		# yes
 5179
 5180	ext.l		%d0			# sign extend od
 5181	bra.b		fadd_them
 5182
 5183fnull_od:
 5184	clr.l		%d0
 5185
 5186fadd_them:
 5187	mov.l		%d0,%d4
 5188
 5189	btst		&0x2,%d5		# pre or post indexing?
 5190	beq.b		fpre_indexed
 5191
 5192	mov.l		%d3,%a0
 5193	bsr.l		_dmem_read_long
 5194
 5195	tst.l		%d1			# did dfetch fail?
 5196	bne.w		fcea_err		# yes
 5197
 5198	add.l		%d2,%d0			# <ea> += index
 5199	add.l		%d4,%d0			# <ea> += od
 5200	bra.b		fdone_ea
 5201
 5202fpre_indexed:
 5203	add.l		%d2,%d3			# preindexing
 5204	mov.l		%d3,%a0
 5205	bsr.l		_dmem_read_long
 5206
 5207	tst.l		%d1			# did dfetch fail?
 5208	bne.w		fcea_err		# yes
 5209
 5210	add.l		%d4,%d0			# ea += od
 5211	bra.b		fdone_ea
 5212
 5213faii_bd:
 5214	add.l		%d2,%d3			# ea = (base + bd) + index
 5215	mov.l		%d3,%d0
 5216fdone_ea:
 5217	mov.l		%d0,%a0
 5218
 5219	movm.l		(%sp)+,&0x003c		# restore d2-d5
 5220	rts
 5221
 5222#########################################################
 5223fcea_err:
 5224	mov.l		%d3,%a0
 5225
 5226	movm.l		(%sp)+,&0x003c		# restore d2-d5
 5227	mov.w		&0x0101,%d0
 5228	bra.l		iea_dacc
 5229
 5230fcea_iacc:
 5231	movm.l		(%sp)+,&0x003c		# restore d2-d5
 5232	bra.l		iea_iacc
 5233
 5234fmovm_out_err:
 5235	bsr.l		restore
 5236	mov.w		&0x00e1,%d0
 5237	bra.b		fmovm_err
 5238
 5239fmovm_in_err:
 5240	bsr.l		restore
 5241	mov.w		&0x0161,%d0
 5242
 5243fmovm_err:
 5244	mov.l		L_SCR1(%a6),%a0
 5245	bra.l		iea_dacc
 5246
 5247#########################################################################
 5248# XDEF ****************************************************************	#
 5249#	fmovm_ctrl(): emulate fmovm.l of control registers instr	#
 5250#									#
 5251# XREF ****************************************************************	#
 5252#	_imem_read_long() - read longword from memory			#
 5253#	iea_iacc() - _imem_read_long() failed; error recovery		#
 5254#									#
 5255# INPUT ***************************************************************	#
 5256#	None								#
 5257#									#
 5258# OUTPUT **************************************************************	#
 5259#	If _imem_read_long() doesn't fail:				#
 5260#		USER_FPCR(a6)  = new FPCR value				#
 5261#		USER_FPSR(a6)  = new FPSR value				#
 5262#		USER_FPIAR(a6) = new FPIAR value			#
 5263#									#
 5264# ALGORITHM ***********************************************************	#
 5265#	Decode the instruction type by looking at the extension word	#
 5266# in order to see how many control registers to fetch from memory.	#
 5267# Fetch them using _imem_read_long(). If this fetch fails, exit through	#
 5268# the special access error exit handler iea_iacc().			#
 5269#									#
 5270# Instruction word decoding:						#
 5271#									#
 5272#	fmovem.l #<data>, {FPIAR&|FPCR&|FPSR}				#
 5273#									#
 5274#		WORD1			WORD2				#
 5275#	1111 0010 00 111100	100$ $$00 0000 0000			#
 5276#									#
 5277#	$$$ (100): FPCR							#
 5278#	    (010): FPSR							#
 5279#	    (001): FPIAR						#
 5280#	    (000): FPIAR						#
 5281#									#
 5282#########################################################################
 5283
 5284	global		fmovm_ctrl
 5285fmovm_ctrl:
 5286	mov.b		EXC_EXTWORD(%a6),%d0	# fetch reg select bits
 5287	cmpi.b		%d0,&0x9c		# fpcr & fpsr & fpiar ?
 5288	beq.w		fctrl_in_7		# yes
 5289	cmpi.b		%d0,&0x98		# fpcr & fpsr ?
 5290	beq.w		fctrl_in_6		# yes
 5291	cmpi.b		%d0,&0x94		# fpcr & fpiar ?
 5292	beq.b		fctrl_in_5		# yes
 5293
 5294# fmovem.l #<data>, fpsr/fpiar
 5295fctrl_in_3:
 5296	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5297	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5298	bsr.l		_imem_read_long		# fetch FPSR from mem
 5299
 5300	tst.l		%d1			# did ifetch fail?
 5301	bne.l		iea_iacc		# yes
 5302
 5303	mov.l		%d0,USER_FPSR(%a6)	# store new FPSR to stack
 5304	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5305	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5306	bsr.l		_imem_read_long		# fetch FPIAR from mem
 5307
 5308	tst.l		%d1			# did ifetch fail?
 5309	bne.l		iea_iacc		# yes
 5310
 5311	mov.l		%d0,USER_FPIAR(%a6)	# store new FPIAR to stack
 5312	rts
 5313
 5314# fmovem.l #<data>, fpcr/fpiar
 5315fctrl_in_5:
 5316	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5317	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5318	bsr.l		_imem_read_long		# fetch FPCR from mem
 5319
 5320	tst.l		%d1			# did ifetch fail?
 5321	bne.l		iea_iacc		# yes
 5322
 5323	mov.l		%d0,USER_FPCR(%a6)	# store new FPCR to stack
 5324	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5325	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5326	bsr.l		_imem_read_long		# fetch FPIAR from mem
 5327
 5328	tst.l		%d1			# did ifetch fail?
 5329	bne.l		iea_iacc		# yes
 5330
 5331	mov.l		%d0,USER_FPIAR(%a6)	# store new FPIAR to stack
 5332	rts
 5333
 5334# fmovem.l #<data>, fpcr/fpsr
 5335fctrl_in_6:
 5336	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5337	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5338	bsr.l		_imem_read_long		# fetch FPCR from mem
 5339
 5340	tst.l		%d1			# did ifetch fail?
 5341	bne.l		iea_iacc		# yes
 5342
 5343	mov.l		%d0,USER_FPCR(%a6)	# store new FPCR to mem
 5344	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5345	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5346	bsr.l		_imem_read_long		# fetch FPSR from mem
 5347
 5348	tst.l		%d1			# did ifetch fail?
 5349	bne.l		iea_iacc		# yes
 5350
 5351	mov.l		%d0,USER_FPSR(%a6)	# store new FPSR to mem
 5352	rts
 5353
 5354# fmovem.l #<data>, fpcr/fpsr/fpiar
 5355fctrl_in_7:
 5356	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5357	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5358	bsr.l		_imem_read_long		# fetch FPCR from mem
 5359
 5360	tst.l		%d1			# did ifetch fail?
 5361	bne.l		iea_iacc		# yes
 5362
 5363	mov.l		%d0,USER_FPCR(%a6)	# store new FPCR to mem
 5364	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5365	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5366	bsr.l		_imem_read_long		# fetch FPSR from mem
 5367
 5368	tst.l		%d1			# did ifetch fail?
 5369	bne.l		iea_iacc		# yes
 5370
 5371	mov.l		%d0,USER_FPSR(%a6)	# store new FPSR to mem
 5372	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
 5373	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
 5374	bsr.l		_imem_read_long		# fetch FPIAR from mem
 5375
 5376	tst.l		%d1			# did ifetch fail?
 5377	bne.l		iea_iacc		# yes
 5378
 5379	mov.l		%d0,USER_FPIAR(%a6)	# store new FPIAR to mem
 5380	rts
 5381
 5382##########################################################################
 5383
 5384#########################################################################
 5385# XDEF ****************************************************************	#
 5386#	addsub_scaler2(): scale inputs to fadd/fsub such that no	#
 5387#			  OVFL/UNFL exceptions will result		#
 5388#									#
 5389# XREF ****************************************************************	#
 5390#	norm() - normalize mantissa after adjusting exponent		#
 5391#									#
 5392# INPUT ***************************************************************	#
 5393#	FP_SRC(a6) = fp op1(src)					#
 5394#	FP_DST(a6) = fp op2(dst)					#
 5395#									#
 5396# OUTPUT **************************************************************	#
 5397#	FP_SRC(a6) = fp op1 scaled(src)					#
 5398#	FP_DST(a6) = fp op2 scaled(dst)					#
 5399#	d0         = scale amount					#
 5400#									#
 5401# ALGORITHM ***********************************************************	#
 5402#	If the DST exponent is > the SRC exponent, set the DST exponent	#
 5403# equal to 0x3fff and scale the SRC exponent by the value that the	#
 5404# DST exponent was scaled by. If the SRC exponent is greater or equal,	#
 5405# do the opposite. Return this scale factor in d0.			#
 5406#	If the two exponents differ by > the number of mantissa bits	#
 5407# plus two, then set the smallest exponent to a very small value as a	#
 5408# quick shortcut.							#
 5409#									#
 5410#########################################################################
 5411
 5412	global		addsub_scaler2
 5413addsub_scaler2:
 5414	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 5415	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
 5416	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 5417	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
 5418	mov.w		SRC_EX(%a0),%d0
 5419	mov.w		DST_EX(%a1),%d1
 5420	mov.w		%d0,FP_SCR0_EX(%a6)
 5421	mov.w		%d1,FP_SCR1_EX(%a6)
 5422
 5423	andi.w		&0x7fff,%d0
 5424	andi.w		&0x7fff,%d1
 5425	mov.w		%d0,L_SCR1(%a6)		# store src exponent
 5426	mov.w		%d1,2+L_SCR1(%a6)	# store dst exponent
 5427
 5428	cmp.w		%d0, %d1		# is src exp >= dst exp?
 5429	bge.l		src_exp_ge2
 5430
 5431# dst exp is >  src exp; scale dst to exp = 0x3fff
 5432dst_exp_gt2:
 5433	bsr.l		scale_to_zero_dst
 5434	mov.l		%d0,-(%sp)		# save scale factor
 5435
 5436	cmpi.b		STAG(%a6),&DENORM	# is dst denormalized?
 5437	bne.b		cmpexp12
 5438
 5439	lea		FP_SCR0(%a6),%a0
 5440	bsr.l		norm			# normalize the denorm; result is new exp
 5441	neg.w		%d0			# new exp = -(shft val)
 5442	mov.w		%d0,L_SCR1(%a6)		# inset new exp
 5443
 5444cmpexp12:
 5445	mov.w		2+L_SCR1(%a6),%d0
 5446	subi.w		&mantissalen+2,%d0	# subtract mantissalen+2 from larger exp
 5447
 5448	cmp.w		%d0,L_SCR1(%a6)		# is difference >= len(mantissa)+2?
 5449	bge.b		quick_scale12
 5450
 5451	mov.w		L_SCR1(%a6),%d0
 5452	add.w		0x2(%sp),%d0		# scale src exponent by scale factor
 5453	mov.w		FP_SCR0_EX(%a6),%d1
 5454	and.w		&0x8000,%d1
 5455	or.w		%d1,%d0			# concat {sgn,new exp}
 5456	mov.w		%d0,FP_SCR0_EX(%a6)	# insert new dst exponent
 5457
 5458	mov.l		(%sp)+,%d0		# return SCALE factor
 5459	rts
 5460
 5461quick_scale12:
 5462	andi.w		&0x8000,FP_SCR0_EX(%a6)	# zero src exponent
 5463	bset		&0x0,1+FP_SCR0_EX(%a6)	# set exp = 1
 5464
 5465	mov.l		(%sp)+,%d0		# return SCALE factor
 5466	rts
 5467
 5468# src exp is >= dst exp; scale src to exp = 0x3fff
 5469src_exp_ge2:
 5470	bsr.l		scale_to_zero_src
 5471	mov.l		%d0,-(%sp)		# save scale factor
 5472
 5473	cmpi.b		DTAG(%a6),&DENORM	# is dst denormalized?
 5474	bne.b		cmpexp22
 5475	lea		FP_SCR1(%a6),%a0
 5476	bsr.l		norm			# normalize the denorm; result is new exp
 5477	neg.w		%d0			# new exp = -(shft val)
 5478	mov.w		%d0,2+L_SCR1(%a6)	# inset new exp
 5479
 5480cmpexp22:
 5481	mov.w		L_SCR1(%a6),%d0
 5482	subi.w		&mantissalen+2,%d0	# subtract mantissalen+2 from larger exp
 5483
 5484	cmp.w		%d0,2+L_SCR1(%a6)	# is difference >= len(mantissa)+2?
 5485	bge.b		quick_scale22
 5486
 5487	mov.w		2+L_SCR1(%a6),%d0
 5488	add.w		0x2(%sp),%d0		# scale dst exponent by scale factor
 5489	mov.w		FP_SCR1_EX(%a6),%d1
 5490	andi.w		&0x8000,%d1
 5491	or.w		%d1,%d0			# concat {sgn,new exp}
 5492	mov.w		%d0,FP_SCR1_EX(%a6)	# insert new dst exponent
 5493
 5494	mov.l		(%sp)+,%d0		# return SCALE factor
 5495	rts
 5496
 5497quick_scale22:
 5498	andi.w		&0x8000,FP_SCR1_EX(%a6)	# zero dst exponent
 5499	bset		&0x0,1+FP_SCR1_EX(%a6)	# set exp = 1
 5500
 5501	mov.l		(%sp)+,%d0		# return SCALE factor
 5502	rts
 5503
 5504##########################################################################
 5505
 5506#########################################################################
 5507# XDEF ****************************************************************	#
 5508#	scale_to_zero_src(): scale the exponent of extended precision	#
 5509#			     value at FP_SCR0(a6).			#
 5510#									#
 5511# XREF ****************************************************************	#
 5512#	norm() - normalize the mantissa if the operand was a DENORM	#
 5513#									#
 5514# INPUT ***************************************************************	#
 5515#	FP_SCR0(a6) = extended precision operand to be scaled		#
 5516#									#
 5517# OUTPUT **************************************************************	#
 5518#	FP_SCR0(a6) = scaled extended precision operand			#
 5519#	d0	    = scale value					#
 5520#									#
 5521# ALGORITHM ***********************************************************	#
 5522#	Set the exponent of the input operand to 0x3fff. Save the value	#
 5523# of the difference between the original and new exponent. Then,	#
 5524# normalize the operand if it was a DENORM. Add this normalization	#
 5525# value to the previous value. Return the result.			#
 5526#									#
 5527#########################################################################
 5528
 5529	global		scale_to_zero_src
 5530scale_to_zero_src:
 5531	mov.w		FP_SCR0_EX(%a6),%d1	# extract operand's {sgn,exp}
 5532	mov.w		%d1,%d0			# make a copy
 5533
 5534	andi.l		&0x7fff,%d1		# extract operand's exponent
 5535
 5536	andi.w		&0x8000,%d0		# extract operand's sgn
 5537	or.w		&0x3fff,%d0		# insert new operand's exponent(=0)
 5538
 5539	mov.w		%d0,FP_SCR0_EX(%a6)	# insert biased exponent
 5540
 5541	cmpi.b		STAG(%a6),&DENORM	# is operand normalized?
 5542	beq.b		stzs_denorm		# normalize the DENORM
 5543
 5544stzs_norm:
 5545	mov.l		&0x3fff,%d0
 5546	sub.l		%d1,%d0			# scale = BIAS + (-exp)
 5547
 5548	rts
 5549
 5550stzs_denorm:
 5551	lea		FP_SCR0(%a6),%a0	# pass ptr to src op
 5552	bsr.l		norm			# normalize denorm
 5553	neg.l		%d0			# new exponent = -(shft val)
 5554	mov.l		%d0,%d1			# prepare for op_norm call
 5555	bra.b		stzs_norm		# finish scaling
 5556
 5557###
 5558
 5559#########################################################################
 5560# XDEF ****************************************************************	#
 5561#	scale_sqrt(): scale the input operand exponent so a subsequent	#
 5562#		      fsqrt operation won't take an exception.		#
 5563#									#
 5564# XREF ****************************************************************	#
 5565#	norm() - normalize the mantissa if the operand was a DENORM	#
 5566#									#
 5567# INPUT ***************************************************************	#
 5568#	FP_SCR0(a6) = extended precision operand to be scaled		#
 5569#									#
 5570# OUTPUT **************************************************************	#
 5571#	FP_SCR0(a6) = scaled extended precision operand			#
 5572#	d0	    = scale value					#
 5573#									#
 5574# ALGORITHM ***********************************************************	#
 5575#	If the input operand is a DENORM, normalize it.			#
 5576#	If the exponent of the input operand is even, set the exponent	#
 5577# to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the	#
 5578# exponent of the input operand is off, set the exponent to ox3fff and	#
 5579# return a scale factor of "(exp-0x3fff)/2".				#
 5580#									#
 5581#########################################################################
 5582
 5583	global		scale_sqrt
 5584scale_sqrt:
 5585	cmpi.b		STAG(%a6),&DENORM	# is operand normalized?
 5586	beq.b		ss_denorm		# normalize the DENORM
 5587
 5588	mov.w		FP_SCR0_EX(%a6),%d1	# extract operand's {sgn,exp}
 5589	andi.l		&0x7fff,%d1		# extract operand's exponent
 5590
 5591	andi.w		&0x8000,FP_SCR0_EX(%a6)	# extract operand's sgn
 5592
 5593	btst		&0x0,%d1		# is exp even or odd?
 5594	beq.b		ss_norm_even
 5595
 5596	ori.w		&0x3fff,FP_SCR0_EX(%a6)	# insert new operand's exponent(=0)
 5597
 5598	mov.l		&0x3fff,%d0
 5599	sub.l		%d1,%d0			# scale = BIAS + (-exp)
 5600	asr.l		&0x1,%d0		# divide scale factor by 2
 5601	rts
 5602
 5603ss_norm_even:
 5604	ori.w		&0x3ffe,FP_SCR0_EX(%a6)	# insert new operand's exponent(=0)
 5605
 5606	mov.l		&0x3ffe,%d0
 5607	sub.l		%d1,%d0			# scale = BIAS + (-exp)
 5608	asr.l		&0x1,%d0		# divide scale factor by 2
 5609	rts
 5610
 5611ss_denorm:
 5612	lea		FP_SCR0(%a6),%a0	# pass ptr to src op
 5613	bsr.l		norm			# normalize denorm
 5614
 5615	btst		&0x0,%d0		# is exp even or odd?
 5616	beq.b		ss_denorm_even
 5617
 5618	ori.w		&0x3fff,FP_SCR0_EX(%a6)	# insert new operand's exponent(=0)
 5619
 5620	add.l		&0x3fff,%d0
 5621	asr.l		&0x1,%d0		# divide scale factor by 2
 5622	rts
 5623
 5624ss_denorm_even:
 5625	ori.w		&0x3ffe,FP_SCR0_EX(%a6)	# insert new operand's exponent(=0)
 5626
 5627	add.l		&0x3ffe,%d0
 5628	asr.l		&0x1,%d0		# divide scale factor by 2
 5629	rts
 5630
 5631###
 5632
 5633#########################################################################
 5634# XDEF ****************************************************************	#
 5635#	scale_to_zero_dst(): scale the exponent of extended precision	#
 5636#			     value at FP_SCR1(a6).			#
 5637#									#
 5638# XREF ****************************************************************	#
 5639#	norm() - normalize the mantissa if the operand was a DENORM	#
 5640#									#
 5641# INPUT ***************************************************************	#
 5642#	FP_SCR1(a6) = extended precision operand to be scaled		#
 5643#									#
 5644# OUTPUT **************************************************************	#
 5645#	FP_SCR1(a6) = scaled extended precision operand			#
 5646#	d0	    = scale value					#
 5647#									#
 5648# ALGORITHM ***********************************************************	#
 5649#	Set the exponent of the input operand to 0x3fff. Save the value	#
 5650# of the difference between the original and new exponent. Then,	#
 5651# normalize the operand if it was a DENORM. Add this normalization	#
 5652# value to the previous value. Return the result.			#
 5653#									#
 5654#########################################################################
 5655
 5656	global		scale_to_zero_dst
 5657scale_to_zero_dst:
 5658	mov.w		FP_SCR1_EX(%a6),%d1	# extract operand's {sgn,exp}
 5659	mov.w		%d1,%d0			# make a copy
 5660
 5661	andi.l		&0x7fff,%d1		# extract operand's exponent
 5662
 5663	andi.w		&0x8000,%d0		# extract operand's sgn
 5664	or.w		&0x3fff,%d0		# insert new operand's exponent(=0)
 5665
 5666	mov.w		%d0,FP_SCR1_EX(%a6)	# insert biased exponent
 5667
 5668	cmpi.b		DTAG(%a6),&DENORM	# is operand normalized?
 5669	beq.b		stzd_denorm		# normalize the DENORM
 5670
 5671stzd_norm:
 5672	mov.l		&0x3fff,%d0
 5673	sub.l		%d1,%d0			# scale = BIAS + (-exp)
 5674	rts
 5675
 5676stzd_denorm:
 5677	lea		FP_SCR1(%a6),%a0	# pass ptr to dst op
 5678	bsr.l		norm			# normalize denorm
 5679	neg.l		%d0			# new exponent = -(shft val)
 5680	mov.l		%d0,%d1			# prepare for op_norm call
 5681	bra.b		stzd_norm		# finish scaling
 5682
 5683##########################################################################
 5684
 5685#########################################################################
 5686# XDEF ****************************************************************	#
 5687#	res_qnan(): return default result w/ QNAN operand for dyadic	#
 5688#	res_snan(): return default result w/ SNAN operand for dyadic	#
 5689#	res_qnan_1op(): return dflt result w/ QNAN operand for monadic	#
 5690#	res_snan_1op(): return dflt result w/ SNAN operand for monadic	#
 5691#									#
 5692# XREF ****************************************************************	#
 5693#	None								#
 5694#									#
 5695# INPUT ***************************************************************	#
 5696#	FP_SRC(a6) = pointer to extended precision src operand		#
 5697#	FP_DST(a6) = pointer to extended precision dst operand		#
 5698#									#
 5699# OUTPUT **************************************************************	#
 5700#	fp0 = default result						#
 5701#									#
 5702# ALGORITHM ***********************************************************	#
 5703#	If either operand (but not both operands) of an operation is a	#
 5704# nonsignalling NAN, then that NAN is returned as the result. If both	#
 5705# operands are nonsignalling NANs, then the destination operand		#
 5706# nonsignalling NAN is returned as the result.				#
 5707#	If either operand to an operation is a signalling NAN (SNAN),	#
 5708# then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap	#
 5709# enable bit is set in the FPCR, then the trap is taken and the		#
 5710# destination is not modified. If the SNAN trap enable bit is not set,	#
 5711# then the SNAN is converted to a nonsignalling NAN (by setting the	#
 5712# SNAN bit in the operand to one), and the operation continues as	#
 5713# described in the preceding paragraph, for nonsignalling NANs.		#
 5714#	Make sure the appropriate FPSR bits are set before exiting.	#
 5715#									#
 5716#########################################################################
 5717
 5718	global		res_qnan
 5719	global		res_snan
 5720res_qnan:
 5721res_snan:
 5722	cmp.b		DTAG(%a6), &SNAN	# is the dst an SNAN?
 5723	beq.b		dst_snan2
 5724	cmp.b		DTAG(%a6), &QNAN	# is the dst a  QNAN?
 5725	beq.b		dst_qnan2
 5726src_nan:
 5727	cmp.b		STAG(%a6), &QNAN
 5728	beq.b		src_qnan2
 5729	global		res_snan_1op
 5730res_snan_1op:
 5731src_snan2:
 5732	bset		&0x6, FP_SRC_HI(%a6)	# set SNAN bit
 5733	or.l		&nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
 5734	lea		FP_SRC(%a6), %a0
 5735	bra.b		nan_comp
 5736	global		res_qnan_1op
 5737res_qnan_1op:
 5738src_qnan2:
 5739	or.l		&nan_mask, USER_FPSR(%a6)
 5740	lea		FP_SRC(%a6), %a0
 5741	bra.b		nan_comp
 5742dst_snan2:
 5743	or.l		&nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
 5744	bset		&0x6, FP_DST_HI(%a6)	# set SNAN bit
 5745	lea		FP_DST(%a6), %a0
 5746	bra.b		nan_comp
 5747dst_qnan2:
 5748	lea		FP_DST(%a6), %a0
 5749	cmp.b		STAG(%a6), &SNAN
 5750	bne		nan_done
 5751	or.l		&aiop_mask+snan_mask, USER_FPSR(%a6)
 5752nan_done:
 5753	or.l		&nan_mask, USER_FPSR(%a6)
 5754nan_comp:
 5755	btst		&0x7, FTEMP_EX(%a0)	# is NAN neg?
 5756	beq.b		nan_not_neg
 5757	or.l		&neg_mask, USER_FPSR(%a6)
 5758nan_not_neg:
 5759	fmovm.x		(%a0), &0x80
 5760	rts
 5761
 5762#########################################################################
 5763# XDEF ****************************************************************	#
 5764#	res_operr(): return default result during operand error		#
 5765#									#
 5766# XREF ****************************************************************	#
 5767#	None								#
 5768#									#
 5769# INPUT ***************************************************************	#
 5770#	None								#
 5771#									#
 5772# OUTPUT **************************************************************	#
 5773#	fp0 = default operand error result				#
 5774#									#
 5775# ALGORITHM ***********************************************************	#
 5776#	An nonsignalling NAN is returned as the default result when	#
 5777# an operand error occurs for the following cases:			#
 5778#									#
 5779#	Multiply: (Infinity x Zero)					#
 5780#	Divide  : (Zero / Zero) || (Infinity / Infinity)		#
 5781#									#
 5782#########################################################################
 5783
 5784	global		res_operr
 5785res_operr:
 5786	or.l		&nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6)
 5787	fmovm.x		nan_return(%pc), &0x80
 5788	rts
 5789
 5790nan_return:
 5791	long		0x7fff0000, 0xffffffff, 0xffffffff
 5792
 5793#########################################################################
 5794# XDEF ****************************************************************	#
 5795#	_denorm(): denormalize an intermediate result			#
 5796#									#
 5797# XREF ****************************************************************	#
 5798#	None								#
 5799#									#
 5800# INPUT *************************************************************** #
 5801#	a0 = points to the operand to be denormalized			#
 5802#		(in the internal extended format)			#
 5803#									#
 5804#	d0 = rounding precision						#
 5805#									#
 5806# OUTPUT **************************************************************	#
 5807#	a0 = pointer to the denormalized result				#
 5808#		(in the internal extended format)			#
 5809#									#
 5810#	d0 = guard,round,sticky						#
 5811#									#
 5812# ALGORITHM ***********************************************************	#
 5813#	According to the exponent underflow threshold for the given	#
 5814# precision, shift the mantissa bits to the right in order raise the	#
 5815# exponent of the operand to the threshold value. While shifting the	#
 5816# mantissa bits right, maintain the value of the guard, round, and	#
 5817# sticky bits.								#
 5818# other notes:								#
 5819#	(1) _denorm() is called by the underflow routines		#
 5820#	(2) _denorm() does NOT affect the status register		#
 5821#									#
 5822#########################################################################
 5823
 5824#
 5825# table of exponent threshold values for each precision
 5826#
 5827tbl_thresh:
 5828	short		0x0
 5829	short		sgl_thresh
 5830	short		dbl_thresh
 5831
 5832	global		_denorm
 5833_denorm:
 5834#
 5835# Load the exponent threshold for the precision selected and check
 5836# to see if (threshold - exponent) is > 65 in which case we can
 5837# simply calculate the sticky bit and zero the mantissa. otherwise
 5838# we have to call the denormalization routine.
 5839#
 5840	lsr.b		&0x2, %d0		# shift prec to lo bits
 5841	mov.w		(tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
 5842	mov.w		%d1, %d0		# copy d1 into d0
 5843	sub.w		FTEMP_EX(%a0), %d0	# diff = threshold - exp
 5844	cmpi.w		%d0, &66		# is diff > 65? (mant + g,r bits)
 5845	bpl.b		denorm_set_stky		# yes; just calc sticky
 5846
 5847	clr.l		%d0			# clear g,r,s
 5848	btst		&inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
 5849	beq.b		denorm_call		# no; don't change anything
 5850	bset		&29, %d0		# yes; set sticky bit
 5851
 5852denorm_call:
 5853	bsr.l		dnrm_lp			# denormalize the number
 5854	rts
 5855
 5856#
 5857# all bit would have been shifted off during the denorm so simply
 5858# calculate if the sticky should be set and clear the entire mantissa.
 5859#
 5860denorm_set_stky:
 5861	mov.l		&0x20000000, %d0	# set sticky bit in return value
 5862	mov.w		%d1, FTEMP_EX(%a0)	# load exp with threshold
 5863	clr.l		FTEMP_HI(%a0)		# set d1 = 0 (ms mantissa)
 5864	clr.l		FTEMP_LO(%a0)		# set d2 = 0 (ms mantissa)
 5865	rts
 5866
 5867#									#
 5868# dnrm_lp(): normalize exponent/mantissa to specified threshold		#
 5869#									#
 5870# INPUT:								#
 5871#	%a0	   : points to the operand to be denormalized		#
 5872#	%d0{31:29} : initial guard,round,sticky				#
 5873#	%d1{15:0}  : denormalization threshold				#
 5874# OUTPUT:								#
 5875#	%a0	   : points to the denormalized operand			#
 5876#	%d0{31:29} : final guard,round,sticky				#
 5877#									#
 5878
 5879# *** Local Equates *** #
 5880set	GRS,		L_SCR2			# g,r,s temp storage
 5881set	FTEMP_LO2,	L_SCR1			# FTEMP_LO copy
 5882
 5883	global		dnrm_lp
 5884dnrm_lp:
 5885
 5886#
 5887# make a copy of FTEMP_LO and place the g,r,s bits directly after it
 5888# in memory so as to make the bitfield extraction for denormalization easier.
 5889#
 5890	mov.l		FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
 5891	mov.l		%d0, GRS(%a6)		# place g,r,s after it
 5892
 5893#
 5894# check to see how much less than the underflow threshold the operand
 5895# exponent is.
 5896#
 5897	mov.l		%d1, %d0		# copy the denorm threshold
 5898	sub.w		FTEMP_EX(%a0), %d1	# d1 = threshold - uns exponent
 5899	ble.b		dnrm_no_lp		# d1 <= 0
 5900	cmpi.w		%d1, &0x20		# is ( 0 <= d1 < 32) ?
 5901	blt.b		case_1			# yes
 5902	cmpi.w		%d1, &0x40		# is (32 <= d1 < 64) ?
 5903	blt.b		case_2			# yes
 5904	bra.w		case_3			# (d1 >= 64)
 5905
 5906#
 5907# No normalization necessary
 5908#
 5909dnrm_no_lp:
 5910	mov.l		GRS(%a6), %d0		# restore original g,r,s
 5911	rts
 5912
 5913#
 5914# case (0<d1<32)
 5915#
 5916# %d0 = denorm threshold
 5917# %d1 = "n" = amt to shift
 5918#
 5919#	---------------------------------------------------------
 5920#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
 5921#	---------------------------------------------------------
 5922#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
 5923#	\	   \		      \			 \
 5924#	 \	    \		       \		  \
 5925#	  \	     \			\		   \
 5926#	   \	      \			 \		    \
 5927#	    \	       \		  \		     \
 5928#	     \		\		   \		      \
 5929#	      \		 \		    \		       \
 5930#	       \	  \		     \			\
 5931#	<-(n)-><-(32 - n)-><------(32)-------><------(32)------->
 5932#	---------------------------------------------------------
 5933#	|0.....0| NEW_HI  |  NEW_FTEMP_LO     |grs		|
 5934#	---------------------------------------------------------
 5935#
 5936case_1:
 5937	mov.l		%d2, -(%sp)		# create temp storage
 5938
 5939	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
 5940	mov.l		&32, %d0
 5941	sub.w		%d1, %d0		# %d0 = 32 - %d1
 5942
 5943	cmpi.w		%d1, &29		# is shft amt >= 29
 5944	blt.b		case1_extract		# no; no fix needed
 5945	mov.b		GRS(%a6), %d2
 5946	or.b		%d2, 3+FTEMP_LO2(%a6)
 5947
 5948case1_extract:
 5949	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
 5950	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
 5951	bfextu		FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S
 5952
 5953	mov.l		%d2, FTEMP_HI(%a0)	# store new FTEMP_HI
 5954	mov.l		%d1, FTEMP_LO(%a0)	# store new FTEMP_LO
 5955
 5956	bftst		%d0{&2:&30}		# were bits shifted off?
 5957	beq.b		case1_sticky_clear	# no; go finish
 5958	bset		&rnd_stky_bit, %d0	# yes; set sticky bit
 5959
 5960case1_sticky_clear:
 5961	and.l		&0xe0000000, %d0	# clear all but G,R,S
 5962	mov.l		(%sp)+, %d2		# restore temp register
 5963	rts
 5964
 5965#
 5966# case (32<=d1<64)
 5967#
 5968# %d0 = denorm threshold
 5969# %d1 = "n" = amt to shift
 5970#
 5971#	---------------------------------------------------------
 5972#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
 5973#	---------------------------------------------------------
 5974#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
 5975#	\	   \		      \
 5976#	 \	    \		       \
 5977#	  \	     \			-------------------
 5978#	   \	      --------------------		   \
 5979#	    -------------------		  \		    \
 5980#			       \	   \		     \
 5981#				\	    \		      \
 5982#				 \	     \		       \
 5983#	<-------(32)------><-(n)-><-(32 - n)-><------(32)------->
 5984#	---------------------------------------------------------
 5985#	|0...............0|0....0| NEW_LO     |grs		|
 5986#	---------------------------------------------------------
 5987#
 5988case_2:
 5989	mov.l		%d2, -(%sp)		# create temp storage
 5990
 5991	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
 5992	subi.w		&0x20, %d1		# %d1 now between 0 and 32
 5993	mov.l		&0x20, %d0
 5994	sub.w		%d1, %d0		# %d0 = 32 - %d1
 5995
 5996# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
 5997# the number of bits to check for the sticky detect.
 5998# it only plays a role in shift amounts of 61-63.
 5999	mov.b		GRS(%a6), %d2
 6000	or.b		%d2, 3+FTEMP_LO2(%a6)
 6001
 6002	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
 6003	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S
 6004
 6005	bftst		%d1{&2:&30}		# were any bits shifted off?
 6006	bne.b		case2_set_sticky	# yes; set sticky bit
 6007	bftst		FTEMP_LO2(%a6){%d0:&31}	# were any bits shifted off?
 6008	bne.b		case2_set_sticky	# yes; set sticky bit
 6009
 6010	mov.l		%d1, %d0		# move new G,R,S to %d0
 6011	bra.b		case2_end
 6012
 6013case2_set_sticky:
 6014	mov.l		%d1, %d0		# move new G,R,S to %d0
 6015	bset		&rnd_stky_bit, %d0	# set sticky bit
 6016
 6017case2_end:
 6018	clr.l		FTEMP_HI(%a0)		# store FTEMP_HI = 0
 6019	mov.l		%d2, FTEMP_LO(%a0)	# store FTEMP_LO
 6020	and.l		&0xe0000000, %d0	# clear all but G,R,S
 6021
 6022	mov.l		(%sp)+,%d2		# restore temp register
 6023	rts
 6024
 6025#
 6026# case (d1>=64)
 6027#
 6028# %d0 = denorm threshold
 6029# %d1 = amt to shift
 6030#
 6031case_3:
 6032	mov.w		%d0, FTEMP_EX(%a0)	# insert denorm threshold
 6033
 6034	cmpi.w		%d1, &65		# is shift amt > 65?
 6035	blt.b		case3_64		# no; it's == 64
 6036	beq.b		case3_65		# no; it's == 65
 6037
 6038#
 6039# case (d1>65)
 6040#
 6041# Shift value is > 65 and out of range. All bits are shifted off.
 6042# Return a zero mantissa with the sticky bit set
 6043#
 6044	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
 6045	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
 6046	mov.l		&0x20000000, %d0	# set sticky bit
 6047	rts
 6048
 6049#
 6050# case (d1 == 64)
 6051#
 6052#	---------------------------------------------------------
 6053#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
 6054#	---------------------------------------------------------
 6055#	<-------(32)------>
 6056#	\		   \
 6057#	 \		    \
 6058#	  \		     \
 6059#	   \		      ------------------------------
 6060#	    -------------------------------		    \
 6061#					   \		     \
 6062#					    \		      \
 6063#					     \		       \
 6064#					      <-------(32)------>
 6065#	---------------------------------------------------------
 6066#	|0...............0|0................0|grs		|
 6067#	---------------------------------------------------------
 6068#
 6069case3_64:
 6070	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
 6071	mov.l		%d0, %d1		# make a copy
 6072	and.l		&0xc0000000, %d0	# extract G,R
 6073	and.l		&0x3fffffff, %d1	# extract other bits
 6074
 6075	bra.b		case3_complete
 6076
 6077#
 6078# case (d1 == 65)
 6079#
 6080#	---------------------------------------------------------
 6081#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
 6082#	---------------------------------------------------------
 6083#	<-------(32)------>
 6084#	\		   \
 6085#	 \		    \
 6086#	  \		     \
 6087#	   \		      ------------------------------
 6088#	    --------------------------------		    \
 6089#					    \		     \
 6090#					     \		      \
 6091#					      \		       \
 6092#					       <-------(31)----->
 6093#	---------------------------------------------------------
 6094#	|0...............0|0................0|0rs		|
 6095#	---------------------------------------------------------
 6096#
 6097case3_65:
 6098	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
 6099	and.l		&0x80000000, %d0	# extract R bit
 6100	lsr.l		&0x1, %d0		# shift high bit into R bit
 6101	and.l		&0x7fffffff, %d1	# extract other bits
 6102
 6103case3_complete:
 6104# last operation done was an "and" of the bits shifted off so the condition
 6105# codes are already set so branch accordingly.
 6106	bne.b		case3_set_sticky	# yes; go set new sticky
 6107	tst.l		FTEMP_LO(%a0)		# were any bits shifted off?
 6108	bne.b		case3_set_sticky	# yes; go set new sticky
 6109	tst.b		GRS(%a6)		# were any bits shifted off?
 6110	bne.b		case3_set_sticky	# yes; go set new sticky
 6111
 6112#
 6113# no bits were shifted off so don't set the sticky bit.
 6114# the guard and
 6115# the entire mantissa is zero.
 6116#
 6117	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
 6118	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
 6119	rts
 6120
 6121#
 6122# some bits were shifted off so set the sticky bit.
 6123# the entire mantissa is zero.
 6124#
 6125case3_set_sticky:
 6126	bset		&rnd_stky_bit,%d0	# set new sticky bit
 6127	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
 6128	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
 6129	rts
 6130
 6131#########################################################################
 6132# XDEF ****************************************************************	#
 6133#	_round(): round result according to precision/mode		#
 6134#									#
 6135# XREF ****************************************************************	#
 6136#	None								#
 6137#									#
 6138# INPUT ***************************************************************	#
 6139#	a0	  = ptr to input operand in internal extended format	#
 6140#	d1(hi)    = contains rounding precision:			#
 6141#			ext = $0000xxxx					#
 6142#			sgl = $0004xxxx					#
 6143#			dbl = $0008xxxx					#
 6144#	d1(lo)	  = contains rounding mode:				#
 6145#			RN  = $xxxx0000					#
 6146#			RZ  = $xxxx0001					#
 6147#			RM  = $xxxx0002					#
 6148#			RP  = $xxxx0003					#
 6149#	d0{31:29} = contains the g,r,s bits (extended)			#
 6150#									#
 6151# OUTPUT **************************************************************	#
 6152#	a0 = pointer to rounded result					#
 6153#									#
 6154# ALGORITHM ***********************************************************	#
 6155#	On return the value pointed to by a0 is correctly rounded,	#
 6156#	a0 is preserved and the g-r-s bits in d0 are cleared.		#
 6157#	The result is not typed - the tag field is invalid.  The	#
 6158#	result is still in the internal extended format.		#
 6159#									#
 6160#	The INEX bit of USER_FPSR will be set if the rounded result was	#
 6161#	inexact (i.e. if any of the g-r-s bits were set).		#
 6162#									#
 6163#########################################################################
 6164
 6165	global		_round
 6166_round:
 6167#
 6168# ext_grs() looks at the rounding precision and sets the appropriate
 6169# G,R,S bits.
 6170# If (G,R,S == 0) then result is exact and round is done, else set
 6171# the inex flag in status reg and continue.
 6172#
 6173	bsr.l		ext_grs			# extract G,R,S
 6174
 6175	tst.l		%d0			# are G,R,S zero?
 6176	beq.w		truncate		# yes; round is complete
 6177
 6178	or.w		&inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex
 6179
 6180#
 6181# Use rounding mode as an index into a jump table for these modes.
 6182# All of the following assumes grs != 0.
 6183#
 6184	mov.w		(tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
 6185	jmp		(tbl_mode.b,%pc,%a1)	# jmp to rnd mode handler
 6186
 6187tbl_mode:
 6188	short		rnd_near - tbl_mode
 6189	short		truncate - tbl_mode	# RZ always truncates
 6190	short		rnd_mnus - tbl_mode
 6191	short		rnd_plus - tbl_mode
 6192
 6193#################################################################
 6194#	ROUND PLUS INFINITY					#
 6195#								#
 6196#	If sign of fp number = 0 (positive), then add 1 to l.	#
 6197#################################################################
 6198rnd_plus:
 6199	tst.b		FTEMP_SGN(%a0)		# check for sign
 6200	bmi.w		truncate		# if positive then truncate
 6201
 6202	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
 6203	swap		%d1			# set up d1 for round prec.
 6204
 6205	cmpi.b		%d1, &s_mode		# is prec = sgl?
 6206	beq.w		add_sgl			# yes
 6207	bgt.w		add_dbl			# no; it's dbl
 6208	bra.w		add_ext			# no; it's ext
 6209
 6210#################################################################
 6211#	ROUND MINUS INFINITY					#
 6212#								#
 6213#	If sign of fp number = 1 (negative), then add 1 to l.	#
 6214#################################################################
 6215rnd_mnus:
 6216	tst.b		FTEMP_SGN(%a0)		# check for sign
 6217	bpl.w		truncate		# if negative then truncate
 6218
 6219	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
 6220	swap		%d1			# set up d1 for round prec.
 6221
 6222	cmpi.b		%d1, &s_mode		# is prec = sgl?
 6223	beq.w		add_sgl			# yes
 6224	bgt.w		add_dbl			# no; it's dbl
 6225	bra.w		add_ext			# no; it's ext
 6226
 6227#################################################################
 6228#	ROUND NEAREST						#
 6229#								#
 6230#	If (g=1), then add 1 to l and if (r=s=0), then clear l	#
 6231#	Note that this will round to even in case of a tie.	#
 6232#################################################################
 6233rnd_near:
 6234	asl.l		&0x1, %d0		# shift g-bit to c-bit
 6235	bcc.w		truncate		# if (g=1) then
 6236
 6237	swap		%d1			# set up d1 for round prec.
 6238
 6239	cmpi.b		%d1, &s_mode		# is prec = sgl?
 6240	beq.w		add_sgl			# yes
 6241	bgt.w		add_dbl			# no; it's dbl
 6242	bra.w		add_ext			# no; it's ext
 6243
 6244# *** LOCAL EQUATES ***
 6245set	ad_1_sgl,	0x00000100	# constant to add 1 to l-bit in sgl prec
 6246set	ad_1_dbl,	0x00000800	# constant to add 1 to l-bit in dbl prec
 6247
 6248#########################
 6249#	ADD SINGLE	#
 6250#########################
 6251add_sgl:
 6252	add.l		&ad_1_sgl, FTEMP_HI(%a0)
 6253	bcc.b		scc_clr			# no mantissa overflow
 6254	roxr.w		FTEMP_HI(%a0)		# shift v-bit back in
 6255	roxr.w		FTEMP_HI+2(%a0)		# shift v-bit back in
 6256	add.w		&0x1, FTEMP_EX(%a0)	# and incr exponent
 6257scc_clr:
 6258	tst.l		%d0			# test for rs = 0
 6259	bne.b		sgl_done
 6260	and.w		&0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
 6261sgl_done:
 6262	and.l		&0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
 6263	clr.l		FTEMP_LO(%a0)		# clear d2
 6264	rts
 6265
 6266#########################
 6267#	ADD EXTENDED	#
 6268#########################
 6269add_ext:
 6270	addq.l		&1,FTEMP_LO(%a0)	# add 1 to l-bit
 6271	bcc.b		xcc_clr			# test for carry out
 6272	addq.l		&1,FTEMP_HI(%a0)	# propagate carry
 6273	bcc.b		xcc_clr
 6274	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
 6275	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
 6276	roxr.w		FTEMP_LO(%a0)
 6277	roxr.w		FTEMP_LO+2(%a0)
 6278	add.w		&0x1,FTEMP_EX(%a0)	# and inc exp
 6279xcc_clr:
 6280	tst.l		%d0			# test rs = 0
 6281	bne.b		add_ext_done
 6282	and.b		&0xfe,FTEMP_LO+3(%a0)	# clear the l bit
 6283add_ext_done:
 6284	rts
 6285
 6286#########################
 6287#	ADD DOUBLE	#
 6288#########################
 6289add_dbl:
 6290	add.l		&ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
 6291	bcc.b		dcc_clr			# no carry
 6292	addq.l		&0x1, FTEMP_HI(%a0)	# propagate carry
 6293	bcc.b		dcc_clr			# no carry
 6294
 6295	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
 6296	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
 6297	roxr.w		FTEMP_LO(%a0)
 6298	roxr.w		FTEMP_LO+2(%a0)
 6299	addq.w		&0x1, FTEMP_EX(%a0)	# incr exponent
 6300dcc_clr:
 6301	tst.l		%d0			# test for rs = 0
 6302	bne.b		dbl_done
 6303	and.w		&0xf000, FTEMP_LO+2(%a0) # clear the l-bit
 6304
 6305dbl_done:
 6306	and.l		&0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
 6307	rts
 6308
 6309###########################
 6310# Truncate all other bits #
 6311###########################
 6312truncate:
 6313	swap		%d1			# select rnd prec
 6314
 6315	cmpi.b		%d1, &s_mode		# is prec sgl?
 6316	beq.w		sgl_done		# yes
 6317	bgt.b		dbl_done		# no; it's dbl
 6318	rts					# no; it's ext
 6319
 6320
 6321#
 6322# ext_grs(): extract guard, round and sticky bits according to
 6323#	     rounding precision.
 6324#
 6325# INPUT
 6326#	d0	   = extended precision g,r,s (in d0{31:29})
 6327#	d1	   = {PREC,ROUND}
 6328# OUTPUT
 6329#	d0{31:29}  = guard, round, sticky
 6330#
 6331# The ext_grs extract the guard/round/sticky bits according to the
 6332# selected rounding precision. It is called by the round subroutine
 6333# only.  All registers except d0 are kept intact. d0 becomes an
 6334# updated guard,round,sticky in d0{31:29}
 6335#
 6336# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
 6337#	 prior to usage, and needs to restore d1 to original. this
 6338#	 routine is tightly tied to the round routine and not meant to
 6339#	 uphold standard subroutine calling practices.
 6340#
 6341
 6342ext_grs:
 6343	swap		%d1			# have d1.w point to round precision
 6344	tst.b		%d1			# is rnd prec = extended?
 6345	bne.b		ext_grs_not_ext		# no; go handle sgl or dbl
 6346
 6347#
 6348# %d0 actually already hold g,r,s since _round() had it before calling
 6349# this function. so, as long as we don't disturb it, we are "returning" it.
 6350#
 6351ext_grs_ext:
 6352	swap		%d1			# yes; return to correct positions
 6353	rts
 6354
 6355ext_grs_not_ext:
 6356	movm.l		&0x3000, -(%sp)		# make some temp registers {d2/d3}
 6357
 6358	cmpi.b		%d1, &s_mode		# is rnd prec = sgl?
 6359	bne.b		ext_grs_dbl		# no; go handle dbl
 6360
 6361#
 6362# sgl:
 6363#	96		64	  40	32		0
 6364#	-----------------------------------------------------
 6365#	| EXP	|XXXXXXX|	  |xx	|		|grs|
 6366#	-----------------------------------------------------
 6367#			<--(24)--->nn\			   /
 6368#				   ee ---------------------
 6369#				   ww		|
 6370#						v
 6371#				   gr	   new sticky
 6372#
 6373ext_grs_sgl:
 6374	bfextu		FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
 6375	mov.l		&30, %d2		# of the sgl prec. limits
 6376	lsl.l		%d2, %d3		# shift g-r bits to MSB of d3
 6377	mov.l		FTEMP_HI(%a0), %d2	# get word 2 for s-bit test
 6378	and.l		&0x0000003f, %d2	# s bit is the or of all other
 6379	bne.b		ext_grs_st_stky		# bits to the right of g-r
 6380	tst.l		FTEMP_LO(%a0)		# test lower mantissa
 6381	bne.b		ext_grs_st_stky		# if any are set, set sticky
 6382	tst.l		%d0			# test original g,r,s
 6383	bne.b		ext_grs_st_stky		# if any are set, set sticky
 6384	bra.b		ext_grs_end_sd		# if words 3 and 4 are clr, exit
 6385
 6386#
 6387# dbl:
 6388#	96		64		32	 11	0
 6389#	-----------------------------------------------------
 6390#	| EXP	|XXXXXXX|		|	 |xx	|grs|
 6391#	-----------------------------------------------------
 6392#						  nn\	    /
 6393#						  ee -------
 6394#						  ww	|
 6395#							v
 6396#						  gr	new sticky
 6397#
 6398ext_grs_dbl:
 6399	bfextu		FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
 6400	mov.l		&30, %d2		# of the dbl prec. limits
 6401	lsl.l		%d2, %d3		# shift g-r bits to the MSB of d3
 6402	mov.l		FTEMP_LO(%a0), %d2	# get lower mantissa  for s-bit test
 6403	and.l		&0x000001ff, %d2	# s bit is the or-ing of all
 6404	bne.b		ext_grs_st_stky		# other bits to the right of g-r
 6405	tst.l		%d0			# test word original g,r,s
 6406	bne.b		ext_grs_st_stky		# if any are set, set sticky
 6407	bra.b		ext_grs_end_sd		# if clear, exit
 6408
 6409ext_grs_st_stky:
 6410	bset		&rnd_stky_bit, %d3	# set sticky bit
 6411ext_grs_end_sd:
 6412	mov.l		%d3, %d0		# return grs to d0
 6413
 6414	movm.l		(%sp)+, &0xc		# restore scratch registers {d2/d3}
 6415
 6416	swap		%d1			# restore d1 to original
 6417	rts
 6418
 6419#########################################################################
 6420# norm(): normalize the mantissa of an extended precision input. the	#
 6421#	  input operand should not be normalized already.		#
 6422#									#
 6423# XDEF ****************************************************************	#
 6424#	norm()								#
 6425#									#
 6426# XREF **************************************************************** #
 6427#	none								#
 6428#									#
 6429# INPUT *************************************************************** #
 6430#	a0 = pointer fp extended precision operand to normalize		#
 6431#									#
 6432# OUTPUT ************************************************************** #
 6433#	d0 = number of bit positions the mantissa was shifted		#
 6434#	a0 = the input operand's mantissa is normalized; the exponent	#
 6435#	     is unchanged.						#
 6436#									#
 6437#########################################################################
 6438	global		norm
 6439norm:
 6440	mov.l		%d2, -(%sp)		# create some temp regs
 6441	mov.l		%d3, -(%sp)
 6442
 6443	mov.l		FTEMP_HI(%a0), %d0	# load hi(mantissa)
 6444	mov.l		FTEMP_LO(%a0), %d1	# load lo(mantissa)
 6445
 6446	bfffo		%d0{&0:&32}, %d2	# how many places to shift?
 6447	beq.b		norm_lo			# hi(man) is all zeroes!
 6448
 6449norm_hi:
 6450	lsl.l		%d2, %d0		# left shift hi(man)
 6451	bfextu		%d1{&0:%d2}, %d3	# extract lo bits
 6452
 6453	or.l		%d3, %d0		# create hi(man)
 6454	lsl.l		%d2, %d1		# create lo(man)
 6455
 6456	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
 6457	mov.l		%d1, FTEMP_LO(%a0)	# store new lo(man)
 6458
 6459	mov.l		%d2, %d0		# return shift amount
 6460
 6461	mov.l		(%sp)+, %d3		# restore temp regs
 6462	mov.l		(%sp)+, %d2
 6463
 6464	rts
 6465
 6466norm_lo:
 6467	bfffo		%d1{&0:&32}, %d2	# how many places to shift?
 6468	lsl.l		%d2, %d1		# shift lo(man)
 6469	add.l		&32, %d2		# add 32 to shft amount
 6470
 6471	mov.l		%d1, FTEMP_HI(%a0)	# store hi(man)
 6472	clr.l		FTEMP_LO(%a0)		# lo(man) is now zero
 6473
 6474	mov.l		%d2, %d0		# return shift amount
 6475
 6476	mov.l		(%sp)+, %d3		# restore temp regs
 6477	mov.l		(%sp)+, %d2
 6478
 6479	rts
 6480
 6481#########################################################################
 6482# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO	#
 6483#		- returns corresponding optype tag			#
 6484#									#
 6485# XDEF ****************************************************************	#
 6486#	unnorm_fix()							#
 6487#									#
 6488# XREF **************************************************************** #
 6489#	norm() - normalize the mantissa					#
 6490#									#
 6491# INPUT *************************************************************** #
 6492#	a0 = pointer to unnormalized extended precision number		#
 6493#									#
 6494# OUTPUT ************************************************************** #
 6495#	d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO	#
 6496#	a0 = input operand has been converted to a norm, denorm, or	#
 6497#	     zero; both the exponent and mantissa are changed.		#
 6498#									#
 6499#########################################################################
 6500
 6501	global		unnorm_fix
 6502unnorm_fix:
 6503	bfffo		FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
 6504	bne.b		unnorm_shift		# hi(man) is not all zeroes
 6505
 6506#
 6507# hi(man) is all zeroes so see if any bits in lo(man) are set
 6508#
 6509unnorm_chk_lo:
 6510	bfffo		FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
 6511	beq.w		unnorm_zero		# yes
 6512
 6513	add.w		&32, %d0		# no; fix shift distance
 6514
 6515#
 6516# d0 = # shifts needed for complete normalization
 6517#
 6518unnorm_shift:
 6519	clr.l		%d1			# clear top word
 6520	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
 6521	and.w		&0x7fff, %d1		# strip off sgn
 6522
 6523	cmp.w		%d0, %d1		# will denorm push exp < 0?
 6524	bgt.b		unnorm_nrm_zero		# yes; denorm only until exp = 0
 6525
 6526#
 6527# exponent would not go < 0. Therefore, number stays normalized
 6528#
 6529	sub.w		%d0, %d1		# shift exponent value
 6530	mov.w		FTEMP_EX(%a0), %d0	# load old exponent
 6531	and.w		&0x8000, %d0		# save old sign
 6532	or.w		%d0, %d1		# {sgn,new exp}
 6533	mov.w		%d1, FTEMP_EX(%a0)	# insert new exponent
 6534
 6535	bsr.l		norm			# normalize UNNORM
 6536
 6537	mov.b		&NORM, %d0		# return new optype tag
 6538	rts
 6539
 6540#
 6541# exponent would go < 0, so only denormalize until exp = 0
 6542#
 6543unnorm_nrm_zero:
 6544	cmp.b		%d1, &32		# is exp <= 32?
 6545	bgt.b		unnorm_nrm_zero_lrg	# no; go handle large exponent
 6546
 6547	bfextu		FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
 6548	mov.l		%d0, FTEMP_HI(%a0)	# save new hi(man)
 6549
 6550	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
 6551	lsl.l		%d1, %d0		# extract new lo(man)
 6552	mov.l		%d0, FTEMP_LO(%a0)	# save new lo(man)
 6553
 6554	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0
 6555
 6556	mov.b		&DENORM, %d0		# return new optype tag
 6557	rts
 6558
 6559#
 6560# only mantissa bits set are in lo(man)
 6561#
 6562unnorm_nrm_zero_lrg:
 6563	sub.w		&32, %d1		# adjust shft amt by 32
 6564
 6565	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
 6566	lsl.l		%d1, %d0		# left shift lo(man)
 6567
 6568	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
 6569	clr.l		FTEMP_LO(%a0)		# lo(man) = 0
 6570
 6571	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0
 6572
 6573	mov.b		&DENORM, %d0		# return new optype tag
 6574	rts
 6575
 6576#
 6577# whole mantissa is zero so this UNNORM is actually a zero
 6578#
 6579unnorm_zero:
 6580	and.w		&0x8000, FTEMP_EX(%a0)	# force exponent to zero
 6581
 6582	mov.b		&ZERO, %d0		# fix optype tag
 6583	rts
 6584
 6585#########################################################################
 6586# XDEF ****************************************************************	#
 6587#	set_tag_x(): return the optype of the input ext fp number	#
 6588#									#
 6589# XREF ****************************************************************	#
 6590#	None								#
 6591#									#
 6592# INPUT ***************************************************************	#
 6593#	a0 = pointer to extended precision operand			#
 6594#									#
 6595# OUTPUT **************************************************************	#
 6596#	d0 = value of type tag						#
 6597#		one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO	#
 6598#									#
 6599# ALGORITHM ***********************************************************	#
 6600#	Simply test the exponent, j-bit, and mantissa values to		#
 6601# determine the type of operand.					#
 6602#	If it's an unnormalized zero, alter the operand and force it	#
 6603# to be a normal zero.							#
 6604#									#
 6605#########################################################################
 6606
 6607	global		set_tag_x
 6608set_tag_x:
 6609	mov.w		FTEMP_EX(%a0), %d0	# extract exponent
 6610	andi.w		&0x7fff, %d0		# strip off sign
 6611	cmpi.w		%d0, &0x7fff		# is (EXP == MAX)?
 6612	beq.b		inf_or_nan_x
 6613not_inf_or_nan_x:
 6614	btst		&0x7,FTEMP_HI(%a0)
 6615	beq.b		not_norm_x
 6616is_norm_x:
 6617	mov.b		&NORM, %d0
 6618	rts
 6619not_norm_x:
 6620	tst.w		%d0			# is exponent = 0?
 6621	bne.b		is_unnorm_x
 6622not_unnorm_x:
 6623	tst.l		FTEMP_HI(%a0)
 6624	bne.b		is_denorm_x
 6625	tst.l		FTEMP_LO(%a0)
 6626	bne.b		is_denorm_x
 6627is_zero_x:
 6628	mov.b		&ZERO, %d0
 6629	rts
 6630is_denorm_x:
 6631	mov.b		&DENORM, %d0
 6632	rts
 6633# must distinguish now "Unnormalized zeroes" which we
 6634# must convert to zero.
 6635is_unnorm_x:
 6636	tst.l		FTEMP_HI(%a0)
 6637	bne.b		is_unnorm_reg_x
 6638	tst.l		FTEMP_LO(%a0)
 6639	bne.b		is_unnorm_reg_x
 6640# it's an "unnormalized zero". let's convert it to an actual zero...
 6641	andi.w		&0x8000,FTEMP_EX(%a0)	# clear exponent
 6642	mov.b		&ZERO, %d0
 6643	rts
 6644is_unnorm_reg_x:
 6645	mov.b		&UNNORM, %d0
 6646	rts
 6647inf_or_nan_x:
 6648	tst.l		FTEMP_LO(%a0)
 6649	bne.b		is_nan_x
 6650	mov.l		FTEMP_HI(%a0), %d0
 6651	and.l		&0x7fffffff, %d0	# msb is a don't care!
 6652	bne.b		is_nan_x
 6653is_inf_x:
 6654	mov.b		&INF, %d0
 6655	rts
 6656is_nan_x:
 6657	btst		&0x6, FTEMP_HI(%a0)
 6658	beq.b		is_snan_x
 6659	mov.b		&QNAN, %d0
 6660	rts
 6661is_snan_x:
 6662	mov.b		&SNAN, %d0
 6663	rts
 6664
 6665#########################################################################
 6666# XDEF ****************************************************************	#
 6667#	set_tag_d(): return the optype of the input dbl fp number	#
 6668#									#
 6669# XREF ****************************************************************	#
 6670#	None								#
 6671#									#
 6672# INPUT ***************************************************************	#
 6673#	a0 = points to double precision operand				#
 6674#									#
 6675# OUTPUT **************************************************************	#
 6676#	d0 = value of type tag						#
 6677#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
 6678#									#
 6679# ALGORITHM ***********************************************************	#
 6680#	Simply test the exponent, j-bit, and mantissa values to		#
 6681# determine the type of operand.					#
 6682#									#
 6683#########################################################################
 6684
 6685	global		set_tag_d
 6686set_tag_d:
 6687	mov.l		FTEMP(%a0), %d0
 6688	mov.l		%d0, %d1
 6689
 6690	andi.l		&0x7ff00000, %d0
 6691	beq.b		zero_or_denorm_d
 6692
 6693	cmpi.l		%d0, &0x7ff00000
 6694	beq.b		inf_or_nan_d
 6695
 6696is_norm_d:
 6697	mov.b		&NORM, %d0
 6698	rts
 6699zero_or_denorm_d:
 6700	and.l		&0x000fffff, %d1
 6701	bne		is_denorm_d
 6702	tst.l		4+FTEMP(%a0)
 6703	bne		is_denorm_d
 6704is_zero_d:
 6705	mov.b		&ZERO, %d0
 6706	rts
 6707is_denorm_d:
 6708	mov.b		&DENORM, %d0
 6709	rts
 6710inf_or_nan_d:
 6711	and.l		&0x000fffff, %d1
 6712	bne		is_nan_d
 6713	tst.l		4+FTEMP(%a0)
 6714	bne		is_nan_d
 6715is_inf_d:
 6716	mov.b		&INF, %d0
 6717	rts
 6718is_nan_d:
 6719	btst		&19, %d1
 6720	bne		is_qnan_d
 6721is_snan_d:
 6722	mov.b		&SNAN, %d0
 6723	rts
 6724is_qnan_d:
 6725	mov.b		&QNAN, %d0
 6726	rts
 6727
 6728#########################################################################
 6729# XDEF ****************************************************************	#
 6730#	set_tag_s(): return the optype of the input sgl fp number	#
 6731#									#
 6732# XREF ****************************************************************	#
 6733#	None								#
 6734#									#
 6735# INPUT ***************************************************************	#
 6736#	a0 = pointer to single precision operand			#
 6737#									#
 6738# OUTPUT **************************************************************	#
 6739#	d0 = value of type tag						#
 6740#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
 6741#									#
 6742# ALGORITHM ***********************************************************	#
 6743#	Simply test the exponent, j-bit, and mantissa values to		#
 6744# determine the type of operand.					#
 6745#									#
 6746#########################################################################
 6747
 6748	global		set_tag_s
 6749set_tag_s:
 6750	mov.l		FTEMP(%a0), %d0
 6751	mov.l		%d0, %d1
 6752
 6753	andi.l		&0x7f800000, %d0
 6754	beq.b		zero_or_denorm_s
 6755
 6756	cmpi.l		%d0, &0x7f800000
 6757	beq.b		inf_or_nan_s
 6758
 6759is_norm_s:
 6760	mov.b		&NORM, %d0
 6761	rts
 6762zero_or_denorm_s:
 6763	and.l		&0x007fffff, %d1
 6764	bne		is_denorm_s
 6765is_zero_s:
 6766	mov.b		&ZERO, %d0
 6767	rts
 6768is_denorm_s:
 6769	mov.b		&DENORM, %d0
 6770	rts
 6771inf_or_nan_s:
 6772	and.l		&0x007fffff, %d1
 6773	bne		is_nan_s
 6774is_inf_s:
 6775	mov.b		&INF, %d0
 6776	rts
 6777is_nan_s:
 6778	btst		&22, %d1
 6779	bne		is_qnan_s
 6780is_snan_s:
 6781	mov.b		&SNAN, %d0
 6782	rts
 6783is_qnan_s:
 6784	mov.b		&QNAN, %d0
 6785	rts
 6786
 6787#########################################################################
 6788# XDEF ****************************************************************	#
 6789#	unf_res(): routine to produce default underflow result of a	#
 6790#		   scaled extended precision number; this is used by	#
 6791#		   fadd/fdiv/fmul/etc. emulation routines.		#
 6792#	unf_res4(): same as above but for fsglmul/fsgldiv which use	#
 6793#		    single round prec and extended prec mode.		#
 6794#									#
 6795# XREF ****************************************************************	#
 6796#	_denorm() - denormalize according to scale factor		#
 6797#	_round() - round denormalized number according to rnd prec	#
 6798#									#
 6799# INPUT ***************************************************************	#
 6800#	a0 = pointer to extended precison operand			#
 6801#	d0 = scale factor						#
 6802#	d1 = rounding precision/mode					#
 6803#									#
 6804# OUTPUT **************************************************************	#
 6805#	a0 = pointer to default underflow result in extended precision	#
 6806#	d0.b = result FPSR_cc which caller may or may not want to save	#
 6807#									#
 6808# ALGORITHM ***********************************************************	#
 6809#	Convert the input operand to "internal format" which means the	#
 6810# exponent is extended to 16 bits and the sign is stored in the unused	#
 6811# portion of the extended precison operand. Denormalize the number	#
 6812# according to the scale factor passed in d0. Then, round the		#
 6813# denormalized result.							#
 6814#	Set the FPSR_exc bits as appropriate but return the cc bits in	#
 6815# d0 in case the caller doesn't want to save them (as is the case for	#
 6816# fmove out).								#
 6817#	unf_res4() for fsglmul/fsgldiv forces the denorm to extended	#
 6818# precision and the rounding mode to single.				#
 6819#									#
 6820#########################################################################
 6821	global		unf_res
 6822unf_res:
 6823	mov.l		%d1, -(%sp)		# save rnd prec,mode on stack
 6824
 6825	btst		&0x7, FTEMP_EX(%a0)	# make "internal" format
 6826	sne		FTEMP_SGN(%a0)
 6827
 6828	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
 6829	and.w		&0x7fff, %d1
 6830	sub.w		%d0, %d1
 6831	mov.w		%d1, FTEMP_EX(%a0)	# insert 16 bit exponent
 6832
 6833	mov.l		%a0, -(%sp)		# save operand ptr during calls
 6834
 6835	mov.l		0x4(%sp),%d0		# pass rnd prec.
 6836	andi.w		&0x00c0,%d0
 6837	lsr.w		&0x4,%d0
 6838	bsr.l		_denorm			# denorm result
 6839
 6840	mov.l		(%sp),%a0
 6841	mov.w		0x6(%sp),%d1		# load prec:mode into %d1
 6842	andi.w		&0xc0,%d1		# extract rnd prec
 6843	lsr.w		&0x4,%d1
 6844	swap		%d1
 6845	mov.w		0x6(%sp),%d1
 6846	andi.w		&0x30,%d1
 6847	lsr.w		&0x4,%d1
 6848	bsr.l		_round			# round the denorm
 6849
 6850	mov.l		(%sp)+, %a0
 6851
 6852# result is now rounded properly. convert back to normal format
 6853	bclr		&0x7, FTEMP_EX(%a0)	# clear sgn first; may have residue
 6854	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
 6855	beq.b		unf_res_chkifzero	# no; result is positive
 6856	bset		&0x7, FTEMP_EX(%a0)	# set result sgn
 6857	clr.b		FTEMP_SGN(%a0)		# clear temp sign
 6858
 6859# the number may have become zero after rounding. set ccodes accordingly.
 6860unf_res_chkifzero:
 6861	clr.l		%d0
 6862	tst.l		FTEMP_HI(%a0)		# is value now a zero?
 6863	bne.b		unf_res_cont		# no
 6864	tst.l		FTEMP_LO(%a0)
 6865	bne.b		unf_res_cont		# no
 6866#	bset		&z_bit, FPSR_CC(%a6)	# yes; set zero ccode bit
 6867	bset		&z_bit, %d0		# yes; set zero ccode bit
 6868
 6869unf_res_cont:
 6870
 6871#
 6872# can inex1 also be set along with unfl and inex2???
 6873#
 6874# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
 6875#
 6876	btst		&inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
 6877	beq.b		unf_res_end		# no
 6878	bset		&aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl
 6879
 6880unf_res_end:
 6881	add.l		&0x4, %sp		# clear stack
 6882	rts
 6883
 6884# unf_res() for fsglmul() and fsgldiv().
 6885	global		unf_res4
 6886unf_res4:
 6887	mov.l		%d1,-(%sp)		# save rnd prec,mode on stack
 6888
 6889	btst		&0x7,FTEMP_EX(%a0)	# make "internal" format
 6890	sne		FTEMP_SGN(%a0)
 6891
 6892	mov.w		FTEMP_EX(%a0),%d1	# extract exponent
 6893	and.w		&0x7fff,%d1
 6894	sub.w		%d0,%d1
 6895	mov.w		%d1,FTEMP_EX(%a0)	# insert 16 bit exponent
 6896
 6897	mov.l		%a0,-(%sp)		# save operand ptr during calls
 6898
 6899	clr.l		%d0			# force rnd prec = ext
 6900	bsr.l		_denorm			# denorm result
 6901
 6902	mov.l		(%sp),%a0
 6903	mov.w		&s_mode,%d1		# force rnd prec = sgl
 6904	swap		%d1
 6905	mov.w		0x6(%sp),%d1		# load rnd mode
 6906	andi.w		&0x30,%d1		# extract rnd prec
 6907	lsr.w		&0x4,%d1
 6908	bsr.l		_round			# round the denorm
 6909
 6910	mov.l		(%sp)+,%a0
 6911
 6912# result is now rounded properly. convert back to normal format
 6913	bclr		&0x7,FTEMP_EX(%a0)	# clear sgn first; may have residue
 6914	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
 6915	beq.b		unf_res4_chkifzero	# no; result is positive
 6916	bset		&0x7,FTEMP_EX(%a0)	# set result sgn
 6917	clr.b		FTEMP_SGN(%a0)		# clear temp sign
 6918
 6919# the number may have become zero after rounding. set ccodes accordingly.
 6920unf_res4_chkifzero:
 6921	clr.l		%d0
 6922	tst.l		FTEMP_HI(%a0)		# is value now a zero?
 6923	bne.b		unf_res4_cont		# no
 6924	tst.l		FTEMP_LO(%a0)
 6925	bne.b		unf_res4_cont		# no
 6926#	bset		&z_bit,FPSR_CC(%a6)	# yes; set zero ccode bit
 6927	bset		&z_bit,%d0		# yes; set zero ccode bit
 6928
 6929unf_res4_cont:
 6930
 6931#
 6932# can inex1 also be set along with unfl and inex2???
 6933#
 6934# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
 6935#
 6936	btst		&inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
 6937	beq.b		unf_res4_end		# no
 6938	bset		&aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl
 6939
 6940unf_res4_end:
 6941	add.l		&0x4,%sp		# clear stack
 6942	rts
 6943
 6944#########################################################################
 6945# XDEF ****************************************************************	#
 6946#	ovf_res(): routine to produce the default overflow result of	#
 6947#		   an overflowing number.				#
 6948#	ovf_res2(): same as above but the rnd mode/prec are passed	#
 6949#		    differently.					#
 6950#									#
 6951# XREF ****************************************************************	#
 6952#	none								#
 6953#									#
 6954# INPUT ***************************************************************	#
 6955#	d1.b	= '-1' => (-); '0' => (+)				#
 6956#   ovf_res():								#
 6957#	d0	= rnd mode/prec						#
 6958#   ovf_res2():								#
 6959#	hi(d0)	= rnd prec						#
 6960#	lo(d0)	= rnd mode						#
 6961#									#
 6962# OUTPUT **************************************************************	#
 6963#	a0	= points to extended precision result			#
 6964#	d0.b	= condition code bits					#
 6965#									#
 6966# ALGORITHM ***********************************************************	#
 6967#	The default overflow result can be determined by the sign of	#
 6968# the result and the rounding mode/prec in effect. These bits are	#
 6969# concatenated together to create an index into the default result	#
 6970# table. A pointer to the correct result is returned in a0. The		#
 6971# resulting condition codes are returned in d0 in case the caller	#
 6972# doesn't want FPSR_cc altered (as is the case for fmove out).		#
 6973#									#
 6974#########################################################################
 6975
 6976	global		ovf_res
 6977ovf_res:
 6978	andi.w		&0x10,%d1		# keep result sign
 6979	lsr.b		&0x4,%d0		# shift prec/mode
 6980	or.b		%d0,%d1			# concat the two
 6981	mov.w		%d1,%d0			# make a copy
 6982	lsl.b		&0x1,%d1		# multiply d1 by 2
 6983	bra.b		ovf_res_load
 6984
 6985	global		ovf_res2
 6986ovf_res2:
 6987	and.w		&0x10, %d1		# keep result sign
 6988	or.b		%d0, %d1		# insert rnd mode
 6989	swap		%d0
 6990	or.b		%d0, %d1		# insert rnd prec
 6991	mov.w		%d1, %d0		# make a copy
 6992	lsl.b		&0x1, %d1		# shift left by 1
 6993
 6994#
 6995# use the rounding mode, precision, and result sign as in index into the
 6996# two tables below to fetch the default result and the result ccodes.
 6997#
 6998ovf_res_load:
 6999	mov.b		(tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
 7000	lea		(tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr
 7001
 7002	rts
 7003
 7004tbl_ovfl_cc:
 7005	byte		0x2, 0x0, 0x0, 0x2
 7006	byte		0x2, 0x0, 0x0, 0x2
 7007	byte		0x2, 0x0, 0x0, 0x2
 7008	byte		0x0, 0x0, 0x0, 0x0
 7009	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
 7010	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
 7011	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
 7012
 7013tbl_ovfl_result:
 7014	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
 7015	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
 7016	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
 7017	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
 7018
 7019	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
 7020	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
 7021	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
 7022	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
 7023
 7024	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
 7025	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
 7026	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
 7027	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
 7028
 7029	long		0x00000000,0x00000000,0x00000000,0x00000000
 7030	long		0x00000000,0x00000000,0x00000000,0x00000000
 7031	long		0x00000000,0x00000000,0x00000000,0x00000000
 7032	long		0x00000000,0x00000000,0x00000000,0x00000000
 7033
 7034	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
 7035	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
 7036	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
 7037	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP
 7038
 7039	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
 7040	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
 7041	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
 7042	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP
 7043
 7044	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
 7045	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
 7046	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
 7047	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP
 7048
 7049#########################################################################
 7050# XDEF ****************************************************************	#
 7051#	fout(): move from fp register to memory or data register	#
 7052#									#
 7053# XREF ****************************************************************	#
 7054#	_round() - needed to create EXOP for sgl/dbl precision		#
 7055#	norm() - needed to create EXOP for extended precision		#
 7056#	ovf_res() - create default overflow result for sgl/dbl precision#
 7057#	unf_res() - create default underflow result for sgl/dbl prec.	#
 7058#	dst_dbl() - create rounded dbl precision result.		#
 7059#	dst_sgl() - create rounded sgl precision result.		#
 7060#	fetch_dreg() - fetch dynamic k-factor reg for packed.		#
 7061#	bindec() - convert FP binary number to packed number.		#
 7062#	_mem_write() - write data to memory.				#
 7063#	_mem_write2() - write data to memory unless supv mode -(a7) exc.#
 7064#	_dmem_write_{byte,word,long}() - write data to memory.		#
 7065#	store_dreg_{b,w,l}() - store data to data register file.	#
 7066#	facc_out_{b,w,l,d,x}() - data access error occurred.		#
 7067#									#
 7068# INPUT ***************************************************************	#
 7069#	a0 = pointer to extended precision source operand		#
 7070#	d0 = round prec,mode						#
 7071#									#
 7072# OUTPUT **************************************************************	#
 7073#	fp0 : intermediate underflow or overflow result if		#
 7074#	      OVFL/UNFL occurred for a sgl or dbl operand		#
 7075#									#
 7076# ALGORITHM ***********************************************************	#
 7077#	This routine is accessed by many handlers that need to do an	#
 7078# opclass three move of an operand out to memory.			#
 7079#	Decode an fmove out (opclass 3) instruction to determine if	#
 7080# it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data	#
 7081# register or memory. The algorithm uses a standard "fmove" to create	#
 7082# the rounded result. Also, since exceptions are disabled, this also	#
 7083# create the correct OPERR default result if appropriate.		#
 7084#	For sgl or dbl precision, overflow or underflow can occur. If	#
 7085# either occurs and is enabled, the EXOP.				#
 7086#	For extended precision, the stacked <ea> must be fixed along	#
 7087# w/ the address index register as appropriate w/ _calc_ea_fout(). If	#
 7088# the source is a denorm and if underflow is enabled, an EXOP must be	#
 7089# created.								#
 7090#	For packed, the k-factor must be fetched from the instruction	#
 7091# word or a data register. The <ea> must be fixed as w/ extended	#
 7092# precision. Then, bindec() is called to create the appropriate		#
 7093# packed result.							#
 7094#	If at any time an access error is flagged by one of the move-	#
 7095# to-memory routines, then a special exit must be made so that the	#
 7096# access error can be handled properly.					#
 7097#									#
 7098#########################################################################
 7099
 7100	global		fout
 7101fout:
 7102	bfextu		EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt
 7103	mov.w		(tbl_fout.b,%pc,%d1.w*2),%a1 # use as index
 7104	jmp		(tbl_fout.b,%pc,%a1)	# jump to routine
 7105
 7106	swbeg		&0x8
 7107tbl_fout:
 7108	short		fout_long	-	tbl_fout
 7109	short		fout_sgl	-	tbl_fout
 7110	short		fout_ext	-	tbl_fout
 7111	short		fout_pack	-	tbl_fout
 7112	short		fout_word	-	tbl_fout
 7113	short		fout_dbl	-	tbl_fout
 7114	short		fout_byte	-	tbl_fout
 7115	short		fout_pack	-	tbl_fout
 7116
 7117#################################################################
 7118# fmove.b out ###################################################
 7119#################################################################
 7120
 7121# Only "Unimplemented Data Type" exceptions enter here. The operand
 7122# is either a DENORM or a NORM.
 7123fout_byte:
 7124	tst.b		STAG(%a6)		# is operand normalized?
 7125	bne.b		fout_byte_denorm	# no
 7126
 7127	fmovm.x		SRC(%a0),&0x80		# load value
 7128
 7129fout_byte_norm:
 7130	fmov.l		%d0,%fpcr		# insert rnd prec,mode
 7131
 7132	fmov.b		%fp0,%d0		# exec move out w/ correct rnd mode
 7133
 7134	fmov.l		&0x0,%fpcr		# clear FPCR
 7135	fmov.l		%fpsr,%d1		# fetch FPSR
 7136	or.w		%d1,2+USER_FPSR(%a6)	# save new exc,accrued bits
 7137
 7138	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7139	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7140	beq.b		fout_byte_dn		# must save to integer regfile
 7141
 7142	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7143	bsr.l		_dmem_write_byte	# write byte
 7144
 7145	tst.l		%d1			# did dstore fail?
 7146	bne.l		facc_out_b		# yes
 7147
 7148	rts
 7149
 7150fout_byte_dn:
 7151	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7152	andi.w		&0x7,%d1
 7153	bsr.l		store_dreg_b
 7154	rts
 7155
 7156fout_byte_denorm:
 7157	mov.l		SRC_EX(%a0),%d1
 7158	andi.l		&0x80000000,%d1		# keep DENORM sign
 7159	ori.l		&0x00800000,%d1		# make smallest sgl
 7160	fmov.s		%d1,%fp0
 7161	bra.b		fout_byte_norm
 7162
 7163#################################################################
 7164# fmove.w out ###################################################
 7165#################################################################
 7166
 7167# Only "Unimplemented Data Type" exceptions enter here. The operand
 7168# is either a DENORM or a NORM.
 7169fout_word:
 7170	tst.b		STAG(%a6)		# is operand normalized?
 7171	bne.b		fout_word_denorm	# no
 7172
 7173	fmovm.x		SRC(%a0),&0x80		# load value
 7174
 7175fout_word_norm:
 7176	fmov.l		%d0,%fpcr		# insert rnd prec:mode
 7177
 7178	fmov.w		%fp0,%d0		# exec move out w/ correct rnd mode
 7179
 7180	fmov.l		&0x0,%fpcr		# clear FPCR
 7181	fmov.l		%fpsr,%d1		# fetch FPSR
 7182	or.w		%d1,2+USER_FPSR(%a6)	# save new exc,accrued bits
 7183
 7184	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7185	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7186	beq.b		fout_word_dn		# must save to integer regfile
 7187
 7188	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7189	bsr.l		_dmem_write_word	# write word
 7190
 7191	tst.l		%d1			# did dstore fail?
 7192	bne.l		facc_out_w		# yes
 7193
 7194	rts
 7195
 7196fout_word_dn:
 7197	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7198	andi.w		&0x7,%d1
 7199	bsr.l		store_dreg_w
 7200	rts
 7201
 7202fout_word_denorm:
 7203	mov.l		SRC_EX(%a0),%d1
 7204	andi.l		&0x80000000,%d1		# keep DENORM sign
 7205	ori.l		&0x00800000,%d1		# make smallest sgl
 7206	fmov.s		%d1,%fp0
 7207	bra.b		fout_word_norm
 7208
 7209#################################################################
 7210# fmove.l out ###################################################
 7211#################################################################
 7212
 7213# Only "Unimplemented Data Type" exceptions enter here. The operand
 7214# is either a DENORM or a NORM.
 7215fout_long:
 7216	tst.b		STAG(%a6)		# is operand normalized?
 7217	bne.b		fout_long_denorm	# no
 7218
 7219	fmovm.x		SRC(%a0),&0x80		# load value
 7220
 7221fout_long_norm:
 7222	fmov.l		%d0,%fpcr		# insert rnd prec:mode
 7223
 7224	fmov.l		%fp0,%d0		# exec move out w/ correct rnd mode
 7225
 7226	fmov.l		&0x0,%fpcr		# clear FPCR
 7227	fmov.l		%fpsr,%d1		# fetch FPSR
 7228	or.w		%d1,2+USER_FPSR(%a6)	# save new exc,accrued bits
 7229
 7230fout_long_write:
 7231	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7232	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7233	beq.b		fout_long_dn		# must save to integer regfile
 7234
 7235	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7236	bsr.l		_dmem_write_long	# write long
 7237
 7238	tst.l		%d1			# did dstore fail?
 7239	bne.l		facc_out_l		# yes
 7240
 7241	rts
 7242
 7243fout_long_dn:
 7244	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7245	andi.w		&0x7,%d1
 7246	bsr.l		store_dreg_l
 7247	rts
 7248
 7249fout_long_denorm:
 7250	mov.l		SRC_EX(%a0),%d1
 7251	andi.l		&0x80000000,%d1		# keep DENORM sign
 7252	ori.l		&0x00800000,%d1		# make smallest sgl
 7253	fmov.s		%d1,%fp0
 7254	bra.b		fout_long_norm
 7255
 7256#################################################################
 7257# fmove.x out ###################################################
 7258#################################################################
 7259
 7260# Only "Unimplemented Data Type" exceptions enter here. The operand
 7261# is either a DENORM or a NORM.
 7262# The DENORM causes an Underflow exception.
 7263fout_ext:
 7264
 7265# we copy the extended precision result to FP_SCR0 so that the reserved
 7266# 16-bit field gets zeroed. we do this since we promise not to disturb
 7267# what's at SRC(a0).
 7268	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 7269	clr.w		2+FP_SCR0_EX(%a6)	# clear reserved field
 7270	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 7271	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 7272
 7273	fmovm.x		SRC(%a0),&0x80		# return result
 7274
 7275	bsr.l		_calc_ea_fout		# fix stacked <ea>
 7276
 7277	mov.l		%a0,%a1			# pass: dst addr
 7278	lea		FP_SCR0(%a6),%a0	# pass: src addr
 7279	mov.l		&0xc,%d0		# pass: opsize is 12 bytes
 7280
 7281# we must not yet write the extended precision data to the stack
 7282# in the pre-decrement case from supervisor mode or else we'll corrupt
 7283# the stack frame. so, leave it in FP_SRC for now and deal with it later...
 7284	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 7285	beq.b		fout_ext_a7
 7286
 7287	bsr.l		_dmem_write		# write ext prec number to memory
 7288
 7289	tst.l		%d1			# did dstore fail?
 7290	bne.w		fout_ext_err		# yes
 7291
 7292	tst.b		STAG(%a6)		# is operand normalized?
 7293	bne.b		fout_ext_denorm		# no
 7294	rts
 7295
 7296# the number is a DENORM. must set the underflow exception bit
 7297fout_ext_denorm:
 7298	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit
 7299
 7300	mov.b		FPCR_ENABLE(%a6),%d0
 7301	andi.b		&0x0a,%d0		# is UNFL or INEX enabled?
 7302	bne.b		fout_ext_exc		# yes
 7303	rts
 7304
 7305# we don't want to do the write if the exception occurred in supervisor mode
 7306# so _mem_write2() handles this for us.
 7307fout_ext_a7:
 7308	bsr.l		_mem_write2		# write ext prec number to memory
 7309
 7310	tst.l		%d1			# did dstore fail?
 7311	bne.w		fout_ext_err		# yes
 7312
 7313	tst.b		STAG(%a6)		# is operand normalized?
 7314	bne.b		fout_ext_denorm		# no
 7315	rts
 7316
 7317fout_ext_exc:
 7318	lea		FP_SCR0(%a6),%a0
 7319	bsr.l		norm			# normalize the mantissa
 7320	neg.w		%d0			# new exp = -(shft amt)
 7321	andi.w		&0x7fff,%d0
 7322	andi.w		&0x8000,FP_SCR0_EX(%a6)	# keep only old sign
 7323	or.w		%d0,FP_SCR0_EX(%a6)	# insert new exponent
 7324	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 7325	rts
 7326
 7327fout_ext_err:
 7328	mov.l		EXC_A6(%a6),(%a6)	# fix stacked a6
 7329	bra.l		facc_out_x
 7330
 7331#########################################################################
 7332# fmove.s out ###########################################################
 7333#########################################################################
 7334fout_sgl:
 7335	andi.b		&0x30,%d0		# clear rnd prec
 7336	ori.b		&s_mode*0x10,%d0	# insert sgl prec
 7337	mov.l		%d0,L_SCR3(%a6)		# save rnd prec,mode on stack
 7338
 7339#
 7340# operand is a normalized number. first, we check to see if the move out
 7341# would cause either an underflow or overflow. these cases are handled
 7342# separately. otherwise, set the FPCR to the proper rounding mode and
 7343# execute the move.
 7344#
 7345	mov.w		SRC_EX(%a0),%d0		# extract exponent
 7346	andi.w		&0x7fff,%d0		# strip sign
 7347
 7348	cmpi.w		%d0,&SGL_HI		# will operand overflow?
 7349	bgt.w		fout_sgl_ovfl		# yes; go handle OVFL
 7350	beq.w		fout_sgl_may_ovfl	# maybe; go handle possible OVFL
 7351	cmpi.w		%d0,&SGL_LO		# will operand underflow?
 7352	blt.w		fout_sgl_unfl		# yes; go handle underflow
 7353
 7354#
 7355# NORMs(in range) can be stored out by a simple "fmov.s"
 7356# Unnormalized inputs can come through this point.
 7357#
 7358fout_sgl_exg:
 7359	fmovm.x		SRC(%a0),&0x80		# fetch fop from stack
 7360
 7361	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 7362	fmov.l		&0x0,%fpsr		# clear FPSR
 7363
 7364	fmov.s		%fp0,%d0		# store does convert and round
 7365
 7366	fmov.l		&0x0,%fpcr		# clear FPCR
 7367	fmov.l		%fpsr,%d1		# save FPSR
 7368
 7369	or.w		%d1,2+USER_FPSR(%a6)	# set possible inex2/ainex
 7370
 7371fout_sgl_exg_write:
 7372	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7373	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7374	beq.b		fout_sgl_exg_write_dn	# must save to integer regfile
 7375
 7376	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7377	bsr.l		_dmem_write_long	# write long
 7378
 7379	tst.l		%d1			# did dstore fail?
 7380	bne.l		facc_out_l		# yes
 7381
 7382	rts
 7383
 7384fout_sgl_exg_write_dn:
 7385	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7386	andi.w		&0x7,%d1
 7387	bsr.l		store_dreg_l
 7388	rts
 7389
 7390#
 7391# here, we know that the operand would UNFL if moved out to single prec,
 7392# so, denorm and round and then use generic store single routine to
 7393# write the value to memory.
 7394#
 7395fout_sgl_unfl:
 7396	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
 7397
 7398	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 7399	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 7400	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 7401	mov.l		%a0,-(%sp)
 7402
 7403	clr.l		%d0			# pass: S.F. = 0
 7404
 7405	cmpi.b		STAG(%a6),&DENORM	# fetch src optype tag
 7406	bne.b		fout_sgl_unfl_cont	# let DENORMs fall through
 7407
 7408	lea		FP_SCR0(%a6),%a0
 7409	bsr.l		norm			# normalize the DENORM
 7410
 7411fout_sgl_unfl_cont:
 7412	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 7413	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 7414	bsr.l		unf_res			# calc default underflow result
 7415
 7416	lea		FP_SCR0(%a6),%a0	# pass: ptr to fop
 7417	bsr.l		dst_sgl			# convert to single prec
 7418
 7419	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7420	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7421	beq.b		fout_sgl_unfl_dn	# must save to integer regfile
 7422
 7423	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7424	bsr.l		_dmem_write_long	# write long
 7425
 7426	tst.l		%d1			# did dstore fail?
 7427	bne.l		facc_out_l		# yes
 7428
 7429	bra.b		fout_sgl_unfl_chkexc
 7430
 7431fout_sgl_unfl_dn:
 7432	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7433	andi.w		&0x7,%d1
 7434	bsr.l		store_dreg_l
 7435
 7436fout_sgl_unfl_chkexc:
 7437	mov.b		FPCR_ENABLE(%a6),%d1
 7438	andi.b		&0x0a,%d1		# is UNFL or INEX enabled?
 7439	bne.w		fout_sd_exc_unfl	# yes
 7440	addq.l		&0x4,%sp
 7441	rts
 7442
 7443#
 7444# it's definitely an overflow so call ovf_res to get the correct answer
 7445#
 7446fout_sgl_ovfl:
 7447	tst.b		3+SRC_HI(%a0)		# is result inexact?
 7448	bne.b		fout_sgl_ovfl_inex2
 7449	tst.l		SRC_LO(%a0)		# is result inexact?
 7450	bne.b		fout_sgl_ovfl_inex2
 7451	ori.w		&ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
 7452	bra.b		fout_sgl_ovfl_cont
 7453fout_sgl_ovfl_inex2:
 7454	ori.w		&ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
 7455
 7456fout_sgl_ovfl_cont:
 7457	mov.l		%a0,-(%sp)
 7458
 7459# call ovf_res() w/ sgl prec and the correct rnd mode to create the default
 7460# overflow result. DON'T save the returned ccodes from ovf_res() since
 7461# fmove out doesn't alter them.
 7462	tst.b		SRC_EX(%a0)		# is operand negative?
 7463	smi		%d1			# set if so
 7464	mov.l		L_SCR3(%a6),%d0		# pass: sgl prec,rnd mode
 7465	bsr.l		ovf_res			# calc OVFL result
 7466	fmovm.x		(%a0),&0x80		# load default overflow result
 7467	fmov.s		%fp0,%d0		# store to single
 7468
 7469	mov.b		1+EXC_OPWORD(%a6),%d1	# extract dst mode
 7470	andi.b		&0x38,%d1		# is mode == 0? (Dreg dst)
 7471	beq.b		fout_sgl_ovfl_dn	# must save to integer regfile
 7472
 7473	mov.l		EXC_EA(%a6),%a0		# stacked <ea> is correct
 7474	bsr.l		_dmem_write_long	# write long
 7475
 7476	tst.l		%d1			# did dstore fail?
 7477	bne.l		facc_out_l		# yes
 7478
 7479	bra.b		fout_sgl_ovfl_chkexc
 7480
 7481fout_sgl_ovfl_dn:
 7482	mov.b		1+EXC_OPWORD(%a6),%d1	# extract Dn
 7483	andi.w		&0x7,%d1
 7484	bsr.l		store_dreg_l
 7485
 7486fout_sgl_ovfl_chkexc:
 7487	mov.b		FPCR_ENABLE(%a6),%d1
 7488	andi.b		&0x0a,%d1		# is UNFL or INEX enabled?
 7489	bne.w		fout_sd_exc_ovfl	# yes
 7490	addq.l		&0x4,%sp
 7491	rts
 7492
 7493#
 7494# move out MAY overflow:
 7495# (1) force the exp to 0x3fff
 7496# (2) do a move w/ appropriate rnd mode
 7497# (3) if exp still equals zero, then insert original exponent
 7498#	for the correct result.
 7499#     if exp now equals one, then it overflowed so call ovf_res.
 7500#
 7501fout_sgl_may_ovfl:
 7502	mov.w		SRC_EX(%a0),%d1		# fetch current sign
 7503	andi.w		&0x8000,%d1		# keep it,clear exp
 7504	ori.w		&0x3fff,%d1		# insert exp = 0
 7505	mov.w		%d1,FP_SCR0_EX(%a6)	# insert scaled exp
 7506	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
 7507	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
 7508
 7509	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 7510
 7511	fmov.x		FP_SCR0(%a6),%fp0	# force fop to be rounded
 7512	fmov.l		&0x0,%fpcr		# clear FPCR
 7513
 7514	fabs.x		%fp0			# need absolute value
 7515	fcmp.b		%fp0,&0x2		# did exponent increase?
 7516	fblt.w		fout_sgl_exg		# no; go finish NORM
 7517	bra.w		fout_sgl_ovfl		# yes; go handle overflow
 7518
 7519################
 7520
 7521fout_sd_exc_unfl:
 7522	mov.l		(%sp)+,%a0
 7523
 7524	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 7525	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 7526	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 7527
 7528	cmpi.b		STAG(%a6),&DENORM	# was src a DENORM?
 7529	bne.b		fout_sd_exc_cont	# no
 7530
 7531	lea		FP_SCR0(%a6),%a0
 7532	bsr.l		norm
 7533	neg.l		%d0
 7534	andi.w		&0x7fff,%d0
 7535	bfins		%d0,FP_SCR0_EX(%a6){&1:&15}
 7536	bra.b		fout_sd_exc_cont
 7537
 7538fout_sd_exc:
 7539fout_sd_exc_ovfl:
 7540	mov.l		(%sp)+,%a0		# restore a0
 7541
 7542	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 7543	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 7544	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 7545
 7546fout_sd_exc_cont:
 7547	bclr		&0x7,FP_SCR0_EX(%a6)	# clear sign bit
 7548	sne.b		2+FP_SCR0_EX(%a6)	# set internal sign bit
 7549	lea		FP_SCR0(%a6),%a0	# pass: ptr to DENORM
 7550
 7551	mov.b		3+L_SCR3(%a6),%d1
 7552	lsr.b		&0x4,%d1
 7553	andi.w		&0x0c,%d1
 7554	swap		%d1
 7555	mov.b		3+L_SCR3(%a6),%d1
 7556	lsr.b		&0x4,%d1
 7557	andi.w		&0x03,%d1
 7558	clr.l		%d0			# pass: zero g,r,s
 7559	bsr.l		_round			# round the DENORM
 7560
 7561	tst.b		2+FP_SCR0_EX(%a6)	# is EXOP negative?
 7562	beq.b		fout_sd_exc_done	# no
 7563	bset		&0x7,FP_SCR0_EX(%a6)	# yes
 7564
 7565fout_sd_exc_done:
 7566	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 7567	rts
 7568
 7569#################################################################
 7570# fmove.d out ###################################################
 7571#################################################################
 7572fout_dbl:
 7573	andi.b		&0x30,%d0		# clear rnd prec
 7574	ori.b		&d_mode*0x10,%d0	# insert dbl prec
 7575	mov.l		%d0,L_SCR3(%a6)		# save rnd prec,mode on stack
 7576
 7577#
 7578# operand is a normalized number. first, we check to see if the move out
 7579# would cause either an underflow or overflow. these cases are handled
 7580# separately. otherwise, set the FPCR to the proper rounding mode and
 7581# execute the move.
 7582#
 7583	mov.w		SRC_EX(%a0),%d0		# extract exponent
 7584	andi.w		&0x7fff,%d0		# strip sign
 7585
 7586	cmpi.w		%d0,&DBL_HI		# will operand overflow?
 7587	bgt.w		fout_dbl_ovfl		# yes; go handle OVFL
 7588	beq.w		fout_dbl_may_ovfl	# maybe; go handle possible OVFL
 7589	cmpi.w		%d0,&DBL_LO		# will operand underflow?
 7590	blt.w		fout_dbl_unfl		# yes; go handle underflow
 7591
 7592#
 7593# NORMs(in range) can be stored out by a simple "fmov.d"
 7594# Unnormalized inputs can come through this point.
 7595#
 7596fout_dbl_exg:
 7597	fmovm.x		SRC(%a0),&0x80		# fetch fop from stack
 7598
 7599	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 7600	fmov.l		&0x0,%fpsr		# clear FPSR
 7601
 7602	fmov.d		%fp0,L_SCR1(%a6)	# store does convert and round
 7603
 7604	fmov.l		&0x0,%fpcr		# clear FPCR
 7605	fmov.l		%fpsr,%d0		# save FPSR
 7606
 7607	or.w		%d0,2+USER_FPSR(%a6)	# set possible inex2/ainex
 7608
 7609	mov.l		EXC_EA(%a6),%a1		# pass: dst addr
 7610	lea		L_SCR1(%a6),%a0		# pass: src addr
 7611	movq.l		&0x8,%d0		# pass: opsize is 8 bytes
 7612	bsr.l		_dmem_write		# store dbl fop to memory
 7613
 7614	tst.l		%d1			# did dstore fail?
 7615	bne.l		facc_out_d		# yes
 7616
 7617	rts					# no; so we're finished
 7618
 7619#
 7620# here, we know that the operand would UNFL if moved out to double prec,
 7621# so, denorm and round and then use generic store double routine to
 7622# write the value to memory.
 7623#
 7624fout_dbl_unfl:
 7625	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
 7626
 7627	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 7628	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 7629	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 7630	mov.l		%a0,-(%sp)
 7631
 7632	clr.l		%d0			# pass: S.F. = 0
 7633
 7634	cmpi.b		STAG(%a6),&DENORM	# fetch src optype tag
 7635	bne.b		fout_dbl_unfl_cont	# let DENORMs fall through
 7636
 7637	lea		FP_SCR0(%a6),%a0
 7638	bsr.l		norm			# normalize the DENORM
 7639
 7640fout_dbl_unfl_cont:
 7641	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 7642	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 7643	bsr.l		unf_res			# calc default underflow result
 7644
 7645	lea		FP_SCR0(%a6),%a0	# pass: ptr to fop
 7646	bsr.l		dst_dbl			# convert to single prec
 7647	mov.l		%d0,L_SCR1(%a6)
 7648	mov.l		%d1,L_SCR2(%a6)
 7649
 7650	mov.l		EXC_EA(%a6),%a1		# pass: dst addr
 7651	lea		L_SCR1(%a6),%a0		# pass: src addr
 7652	movq.l		&0x8,%d0		# pass: opsize is 8 bytes
 7653	bsr.l		_dmem_write		# store dbl fop to memory
 7654
 7655	tst.l		%d1			# did dstore fail?
 7656	bne.l		facc_out_d		# yes
 7657
 7658	mov.b		FPCR_ENABLE(%a6),%d1
 7659	andi.b		&0x0a,%d1		# is UNFL or INEX enabled?
 7660	bne.w		fout_sd_exc_unfl	# yes
 7661	addq.l		&0x4,%sp
 7662	rts
 7663
 7664#
 7665# it's definitely an overflow so call ovf_res to get the correct answer
 7666#
 7667fout_dbl_ovfl:
 7668	mov.w		2+SRC_LO(%a0),%d0
 7669	andi.w		&0x7ff,%d0
 7670	bne.b		fout_dbl_ovfl_inex2
 7671
 7672	ori.w		&ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
 7673	bra.b		fout_dbl_ovfl_cont
 7674fout_dbl_ovfl_inex2:
 7675	ori.w		&ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
 7676
 7677fout_dbl_ovfl_cont:
 7678	mov.l		%a0,-(%sp)
 7679
 7680# call ovf_res() w/ dbl prec and the correct rnd mode to create the default
 7681# overflow result. DON'T save the returned ccodes from ovf_res() since
 7682# fmove out doesn't alter them.
 7683	tst.b		SRC_EX(%a0)		# is operand negative?
 7684	smi		%d1			# set if so
 7685	mov.l		L_SCR3(%a6),%d0		# pass: dbl prec,rnd mode
 7686	bsr.l		ovf_res			# calc OVFL result
 7687	fmovm.x		(%a0),&0x80		# load default overflow result
 7688	fmov.d		%fp0,L_SCR1(%a6)	# store to double
 7689
 7690	mov.l		EXC_EA(%a6),%a1		# pass: dst addr
 7691	lea		L_SCR1(%a6),%a0		# pass: src addr
 7692	movq.l		&0x8,%d0		# pass: opsize is 8 bytes
 7693	bsr.l		_dmem_write		# store dbl fop to memory
 7694
 7695	tst.l		%d1			# did dstore fail?
 7696	bne.l		facc_out_d		# yes
 7697
 7698	mov.b		FPCR_ENABLE(%a6),%d1
 7699	andi.b		&0x0a,%d1		# is UNFL or INEX enabled?
 7700	bne.w		fout_sd_exc_ovfl	# yes
 7701	addq.l		&0x4,%sp
 7702	rts
 7703
 7704#
 7705# move out MAY overflow:
 7706# (1) force the exp to 0x3fff
 7707# (2) do a move w/ appropriate rnd mode
 7708# (3) if exp still equals zero, then insert original exponent
 7709#	for the correct result.
 7710#     if exp now equals one, then it overflowed so call ovf_res.
 7711#
 7712fout_dbl_may_ovfl:
 7713	mov.w		SRC_EX(%a0),%d1		# fetch current sign
 7714	andi.w		&0x8000,%d1		# keep it,clear exp
 7715	ori.w		&0x3fff,%d1		# insert exp = 0
 7716	mov.w		%d1,FP_SCR0_EX(%a6)	# insert scaled exp
 7717	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
 7718	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
 7719
 7720	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 7721
 7722	fmov.x		FP_SCR0(%a6),%fp0	# force fop to be rounded
 7723	fmov.l		&0x0,%fpcr		# clear FPCR
 7724
 7725	fabs.x		%fp0			# need absolute value
 7726	fcmp.b		%fp0,&0x2		# did exponent increase?
 7727	fblt.w		fout_dbl_exg		# no; go finish NORM
 7728	bra.w		fout_dbl_ovfl		# yes; go handle overflow
 7729
 7730#########################################################################
 7731# XDEF ****************************************************************	#
 7732#	dst_dbl(): create double precision value from extended prec.	#
 7733#									#
 7734# XREF ****************************************************************	#
 7735#	None								#
 7736#									#
 7737# INPUT ***************************************************************	#
 7738#	a0 = pointer to source operand in extended precision		#
 7739#									#
 7740# OUTPUT **************************************************************	#
 7741#	d0 = hi(double precision result)				#
 7742#	d1 = lo(double precision result)				#
 7743#									#
 7744# ALGORITHM ***********************************************************	#
 7745#									#
 7746#  Changes extended precision to double precision.			#
 7747#  Note: no attempt is made to round the extended value to double.	#
 7748#	dbl_sign = ext_sign						#
 7749#	dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)		#
 7750#	get rid of ext integer bit					#
 7751#	dbl_mant = ext_mant{62:12}					#
 7752#									#
 7753#		---------------   ---------------    ---------------	#
 7754#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |	#
 7755#		---------------   ---------------    ---------------	#
 7756#		 95	    64    63 62	      32      31     11	  0	#
 7757#				     |			     |		#
 7758#				     |			     |		#
 7759#				     |			     |		#
 7760#			             v			     v		#
 7761#			      ---------------   ---------------		#
 7762#  double   ->		      |s|exp| mant  |   |  mant       |		#
 7763#			      ---------------   ---------------		#
 7764#			      63     51   32   31	       0	#
 7765#									#
 7766#########################################################################
 7767
 7768dst_dbl:
 7769	clr.l		%d0			# clear d0
 7770	mov.w		FTEMP_EX(%a0),%d0	# get exponent
 7771	subi.w		&EXT_BIAS,%d0		# subtract extended precision bias
 7772	addi.w		&DBL_BIAS,%d0		# add double precision bias
 7773	tst.b		FTEMP_HI(%a0)		# is number a denorm?
 7774	bmi.b		dst_get_dupper		# no
 7775	subq.w		&0x1,%d0		# yes; denorm bias = DBL_BIAS - 1
 7776dst_get_dupper:
 7777	swap		%d0			# d0 now in upper word
 7778	lsl.l		&0x4,%d0		# d0 in proper place for dbl prec exp
 7779	tst.b		FTEMP_EX(%a0)		# test sign
 7780	bpl.b		dst_get_dman		# if positive, go process mantissa
 7781	bset		&0x1f,%d0		# if negative, set sign
 7782dst_get_dman:
 7783	mov.l		FTEMP_HI(%a0),%d1	# get ms mantissa
 7784	bfextu		%d1{&1:&20},%d1		# get upper 20 bits of ms
 7785	or.l		%d1,%d0			# put these bits in ms word of double
 7786	mov.l		%d0,L_SCR1(%a6)		# put the new exp back on the stack
 7787	mov.l		FTEMP_HI(%a0),%d1	# get ms mantissa
 7788	mov.l		&21,%d0			# load shift count
 7789	lsl.l		%d0,%d1			# put lower 11 bits in upper bits
 7790	mov.l		%d1,L_SCR2(%a6)		# build lower lword in memory
 7791	mov.l		FTEMP_LO(%a0),%d1	# get ls mantissa
 7792	bfextu		%d1{&0:&21},%d0		# get ls 21 bits of double
 7793	mov.l		L_SCR2(%a6),%d1
 7794	or.l		%d0,%d1			# put them in double result
 7795	mov.l		L_SCR1(%a6),%d0
 7796	rts
 7797
 7798#########################################################################
 7799# XDEF ****************************************************************	#
 7800#	dst_sgl(): create single precision value from extended prec	#
 7801#									#
 7802# XREF ****************************************************************	#
 7803#									#
 7804# INPUT ***************************************************************	#
 7805#	a0 = pointer to source operand in extended precision		#
 7806#									#
 7807# OUTPUT **************************************************************	#
 7808#	d0 = single precision result					#
 7809#									#
 7810# ALGORITHM ***********************************************************	#
 7811#									#
 7812# Changes extended precision to single precision.			#
 7813#	sgl_sign = ext_sign						#
 7814#	sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)		#
 7815#	get rid of ext integer bit					#
 7816#	sgl_mant = ext_mant{62:12}					#
 7817#									#
 7818#		---------------   ---------------    ---------------	#
 7819#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |	#
 7820#		---------------   ---------------    ---------------	#
 7821#		 95	    64    63 62	   40 32      31     12	  0	#
 7822#				     |	   |				#
 7823#				     |	   |				#
 7824#				     |	   |				#
 7825#			             v     v				#
 7826#			      ---------------				#
 7827#  single   ->		      |s|exp| mant  |				#
 7828#			      ---------------				#
 7829#			      31     22     0				#
 7830#									#
 7831#########################################################################
 7832
 7833dst_sgl:
 7834	clr.l		%d0
 7835	mov.w		FTEMP_EX(%a0),%d0	# get exponent
 7836	subi.w		&EXT_BIAS,%d0		# subtract extended precision bias
 7837	addi.w		&SGL_BIAS,%d0		# add single precision bias
 7838	tst.b		FTEMP_HI(%a0)		# is number a denorm?
 7839	bmi.b		dst_get_supper		# no
 7840	subq.w		&0x1,%d0		# yes; denorm bias = SGL_BIAS - 1
 7841dst_get_supper:
 7842	swap		%d0			# put exp in upper word of d0
 7843	lsl.l		&0x7,%d0		# shift it into single exp bits
 7844	tst.b		FTEMP_EX(%a0)		# test sign
 7845	bpl.b		dst_get_sman		# if positive, continue
 7846	bset		&0x1f,%d0		# if negative, put in sign first
 7847dst_get_sman:
 7848	mov.l		FTEMP_HI(%a0),%d1	# get ms mantissa
 7849	andi.l		&0x7fffff00,%d1		# get upper 23 bits of ms
 7850	lsr.l		&0x8,%d1		# and put them flush right
 7851	or.l		%d1,%d0			# put these bits in ms word of single
 7852	rts
 7853
 7854##############################################################################
 7855fout_pack:
 7856	bsr.l		_calc_ea_fout		# fetch the <ea>
 7857	mov.l		%a0,-(%sp)
 7858
 7859	mov.b		STAG(%a6),%d0		# fetch input type
 7860	bne.w		fout_pack_not_norm	# input is not NORM
 7861
 7862fout_pack_norm:
 7863	btst		&0x4,EXC_CMDREG(%a6)	# static or dynamic?
 7864	beq.b		fout_pack_s		# static
 7865
 7866fout_pack_d:
 7867	mov.b		1+EXC_CMDREG(%a6),%d1	# fetch dynamic reg
 7868	lsr.b		&0x4,%d1
 7869	andi.w		&0x7,%d1
 7870
 7871	bsr.l		fetch_dreg		# fetch Dn w/ k-factor
 7872
 7873	bra.b		fout_pack_type
 7874fout_pack_s:
 7875	mov.b		1+EXC_CMDREG(%a6),%d0	# fetch static field
 7876
 7877fout_pack_type:
 7878	bfexts		%d0{&25:&7},%d0		# extract k-factor
 7879	mov.l	%d0,-(%sp)
 7880
 7881	lea		FP_SRC(%a6),%a0		# pass: ptr to input
 7882
 7883# bindec is currently scrambling FP_SRC for denorm inputs.
 7884# we'll have to change this, but for now, tough luck!!!
 7885	bsr.l		bindec			# convert xprec to packed
 7886
 7887#	andi.l		&0xcfff000f,FP_SCR0(%a6) # clear unused fields
 7888	andi.l		&0xcffff00f,FP_SCR0(%a6) # clear unused fields
 7889
 7890	mov.l	(%sp)+,%d0
 7891
 7892	tst.b		3+FP_SCR0_EX(%a6)
 7893	bne.b		fout_pack_set
 7894	tst.l		FP_SCR0_HI(%a6)
 7895	bne.b		fout_pack_set
 7896	tst.l		FP_SCR0_LO(%a6)
 7897	bne.b		fout_pack_set
 7898
 7899# add the extra condition that only if the k-factor was zero, too, should
 7900# we zero the exponent
 7901	tst.l		%d0
 7902	bne.b		fout_pack_set
 7903# "mantissa" is all zero which means that the answer is zero. but, the '040
 7904# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore,
 7905# if the mantissa is zero, I will zero the exponent, too.
 7906# the question now is whether the exponents sign bit is allowed to be non-zero
 7907# for a zero, also...
 7908	andi.w		&0xf000,FP_SCR0(%a6)
 7909
 7910fout_pack_set:
 7911
 7912	lea		FP_SCR0(%a6),%a0	# pass: src addr
 7913
 7914fout_pack_write:
 7915	mov.l		(%sp)+,%a1		# pass: dst addr
 7916	mov.l		&0xc,%d0		# pass: opsize is 12 bytes
 7917
 7918	cmpi.b		SPCOND_FLG(%a6),&mda7_flg
 7919	beq.b		fout_pack_a7
 7920
 7921	bsr.l		_dmem_write		# write ext prec number to memory
 7922
 7923	tst.l		%d1			# did dstore fail?
 7924	bne.w		fout_ext_err		# yes
 7925
 7926	rts
 7927
 7928# we don't want to do the write if the exception occurred in supervisor mode
 7929# so _mem_write2() handles this for us.
 7930fout_pack_a7:
 7931	bsr.l		_mem_write2		# write ext prec number to memory
 7932
 7933	tst.l		%d1			# did dstore fail?
 7934	bne.w		fout_ext_err		# yes
 7935
 7936	rts
 7937
 7938fout_pack_not_norm:
 7939	cmpi.b		%d0,&DENORM		# is it a DENORM?
 7940	beq.w		fout_pack_norm		# yes
 7941	lea		FP_SRC(%a6),%a0
 7942	clr.w		2+FP_SRC_EX(%a6)
 7943	cmpi.b		%d0,&SNAN		# is it an SNAN?
 7944	beq.b		fout_pack_snan		# yes
 7945	bra.b		fout_pack_write		# no
 7946
 7947fout_pack_snan:
 7948	ori.w		&snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP
 7949	bset		&0x6,FP_SRC_HI(%a6)	# set snan bit
 7950	bra.b		fout_pack_write
 7951
 7952#########################################################################
 7953# XDEF ****************************************************************	#
 7954#	fmul(): emulates the fmul instruction				#
 7955#	fsmul(): emulates the fsmul instruction				#
 7956#	fdmul(): emulates the fdmul instruction				#
 7957#									#
 7958# XREF ****************************************************************	#
 7959#	scale_to_zero_src() - scale src exponent to zero		#
 7960#	scale_to_zero_dst() - scale dst exponent to zero		#
 7961#	unf_res() - return default underflow result			#
 7962#	ovf_res() - return default overflow result			#
 7963#	res_qnan() - return QNAN result					#
 7964#	res_snan() - return SNAN result					#
 7965#									#
 7966# INPUT ***************************************************************	#
 7967#	a0 = pointer to extended precision source operand		#
 7968#	a1 = pointer to extended precision destination operand		#
 7969#	d0  rnd prec,mode						#
 7970#									#
 7971# OUTPUT **************************************************************	#
 7972#	fp0 = result							#
 7973#	fp1 = EXOP (if exception occurred)				#
 7974#									#
 7975# ALGORITHM ***********************************************************	#
 7976#	Handle NANs, infinities, and zeroes as special cases. Divide	#
 7977# norms/denorms into ext/sgl/dbl precision.				#
 7978#	For norms/denorms, scale the exponents such that a multiply	#
 7979# instruction won't cause an exception. Use the regular fmul to		#
 7980# compute a result. Check if the regular operands would have taken	#
 7981# an exception. If so, return the default overflow/underflow result	#
 7982# and return the EXOP if exceptions are enabled. Else, scale the	#
 7983# result operand to the proper exponent.				#
 7984#									#
 7985#########################################################################
 7986
 7987	align		0x10
 7988tbl_fmul_ovfl:
 7989	long		0x3fff - 0x7ffe		# ext_max
 7990	long		0x3fff - 0x407e		# sgl_max
 7991	long		0x3fff - 0x43fe		# dbl_max
 7992tbl_fmul_unfl:
 7993	long		0x3fff + 0x0001		# ext_unfl
 7994	long		0x3fff - 0x3f80		# sgl_unfl
 7995	long		0x3fff - 0x3c00		# dbl_unfl
 7996
 7997	global		fsmul
 7998fsmul:
 7999	andi.b		&0x30,%d0		# clear rnd prec
 8000	ori.b		&s_mode*0x10,%d0	# insert sgl prec
 8001	bra.b		fmul
 8002
 8003	global		fdmul
 8004fdmul:
 8005	andi.b		&0x30,%d0
 8006	ori.b		&d_mode*0x10,%d0	# insert dbl prec
 8007
 8008	global		fmul
 8009fmul:
 8010	mov.l		%d0,L_SCR3(%a6)		# store rnd info
 8011
 8012	clr.w		%d1
 8013	mov.b		DTAG(%a6),%d1
 8014	lsl.b		&0x3,%d1
 8015	or.b		STAG(%a6),%d1		# combine src tags
 8016	bne.w		fmul_not_norm		# optimize on non-norm input
 8017
 8018fmul_norm:
 8019	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
 8020	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
 8021	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
 8022
 8023	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 8024	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 8025	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 8026
 8027	bsr.l		scale_to_zero_src	# scale src exponent
 8028	mov.l		%d0,-(%sp)		# save scale factor 1
 8029
 8030	bsr.l		scale_to_zero_dst	# scale dst exponent
 8031
 8032	add.l		%d0,(%sp)		# SCALE_FACTOR = scale1 + scale2
 8033
 8034	mov.w		2+L_SCR3(%a6),%d1	# fetch precision
 8035	lsr.b		&0x6,%d1		# shift to lo bits
 8036	mov.l		(%sp)+,%d0		# load S.F.
 8037	cmp.l		%d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl?
 8038	beq.w		fmul_may_ovfl		# result may rnd to overflow
 8039	blt.w		fmul_ovfl		# result will overflow
 8040
 8041	cmp.l		%d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl?
 8042	beq.w		fmul_may_unfl		# result may rnd to no unfl
 8043	bgt.w		fmul_unfl		# result will underflow
 8044
 8045#
 8046# NORMAL:
 8047# - the result of the multiply operation will neither overflow nor underflow.
 8048# - do the multiply to the proper precision and rounding mode.
 8049# - scale the result exponent using the scale factor. if both operands were
 8050# normalized then we really don't need to go through this scaling. but for now,
 8051# this will do.
 8052#
 8053fmul_normal:
 8054	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8055
 8056	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8057	fmov.l		&0x0,%fpsr		# clear FPSR
 8058
 8059	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8060
 8061	fmov.l		%fpsr,%d1		# save status
 8062	fmov.l		&0x0,%fpcr		# clear FPCR
 8063
 8064	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8065
 8066fmul_normal_exit:
 8067	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 8068	mov.l		%d2,-(%sp)		# save d2
 8069	mov.w		FP_SCR0_EX(%a6),%d1	# load {sgn,exp}
 8070	mov.l		%d1,%d2			# make a copy
 8071	andi.l		&0x7fff,%d1		# strip sign
 8072	andi.w		&0x8000,%d2		# keep old sign
 8073	sub.l		%d0,%d1			# add scale factor
 8074	or.w		%d2,%d1			# concat old sign,new exp
 8075	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8076	mov.l		(%sp)+,%d2		# restore d2
 8077	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 8078	rts
 8079
 8080#
 8081# OVERFLOW:
 8082# - the result of the multiply operation is an overflow.
 8083# - do the multiply to the proper precision and rounding mode in order to
 8084# set the inexact bits.
 8085# - calculate the default result and return it in fp0.
 8086# - if overflow or inexact is enabled, we need a multiply result rounded to
 8087# extended precision. if the original operation was extended, then we have this
 8088# result. if the original operation was single or double, we have to do another
 8089# multiply using extended precision and the correct rounding mode. the result
 8090# of this operation then has its exponent scaled by -0x6000 to create the
 8091# exceptional operand.
 8092#
 8093fmul_ovfl:
 8094	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8095
 8096	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8097	fmov.l		&0x0,%fpsr		# clear FPSR
 8098
 8099	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8100
 8101	fmov.l		%fpsr,%d1		# save status
 8102	fmov.l		&0x0,%fpcr		# clear FPCR
 8103
 8104	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8105
 8106# save setting this until now because this is where fmul_may_ovfl may jump in
 8107fmul_ovfl_tst:
 8108	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
 8109
 8110	mov.b		FPCR_ENABLE(%a6),%d1
 8111	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
 8112	bne.b		fmul_ovfl_ena		# yes
 8113
 8114# calculate the default result
 8115fmul_ovfl_dis:
 8116	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
 8117	sne		%d1			# set sign param accordingly
 8118	mov.l		L_SCR3(%a6),%d0		# pass rnd prec,mode
 8119	bsr.l		ovf_res			# calculate default result
 8120	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
 8121	fmovm.x		(%a0),&0x80		# return default result in fp0
 8122	rts
 8123
 8124#
 8125# OVFL is enabled; Create EXOP:
 8126# - if precision is extended, then we have the EXOP. simply bias the exponent
 8127# with an extra -0x6000. if the precision is single or double, we need to
 8128# calculate a result rounded to extended precision.
 8129#
 8130fmul_ovfl_ena:
 8131	mov.l		L_SCR3(%a6),%d1
 8132	andi.b		&0xc0,%d1		# test the rnd prec
 8133	bne.b		fmul_ovfl_ena_sd	# it's sgl or dbl
 8134
 8135fmul_ovfl_ena_cont:
 8136	fmovm.x		&0x80,FP_SCR0(%a6)	# move result to stack
 8137
 8138	mov.l		%d2,-(%sp)		# save d2
 8139	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 8140	mov.w		%d1,%d2			# make a copy
 8141	andi.l		&0x7fff,%d1		# strip sign
 8142	sub.l		%d0,%d1			# add scale factor
 8143	subi.l		&0x6000,%d1		# subtract bias
 8144	andi.w		&0x7fff,%d1		# clear sign bit
 8145	andi.w		&0x8000,%d2		# keep old sign
 8146	or.w		%d2,%d1			# concat old sign,new exp
 8147	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8148	mov.l		(%sp)+,%d2		# restore d2
 8149	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 8150	bra.b		fmul_ovfl_dis
 8151
 8152fmul_ovfl_ena_sd:
 8153	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8154
 8155	mov.l		L_SCR3(%a6),%d1
 8156	andi.b		&0x30,%d1		# keep rnd mode only
 8157	fmov.l		%d1,%fpcr		# set FPCR
 8158
 8159	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8160
 8161	fmov.l		&0x0,%fpcr		# clear FPCR
 8162	bra.b		fmul_ovfl_ena_cont
 8163
 8164#
 8165# may OVERFLOW:
 8166# - the result of the multiply operation MAY overflow.
 8167# - do the multiply to the proper precision and rounding mode in order to
 8168# set the inexact bits.
 8169# - calculate the default result and return it in fp0.
 8170#
 8171fmul_may_ovfl:
 8172	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
 8173
 8174	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8175	fmov.l		&0x0,%fpsr		# clear FPSR
 8176
 8177	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8178
 8179	fmov.l		%fpsr,%d1		# save status
 8180	fmov.l		&0x0,%fpcr		# clear FPCR
 8181
 8182	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8183
 8184	fabs.x		%fp0,%fp1		# make a copy of result
 8185	fcmp.b		%fp1,&0x2		# is |result| >= 2.b?
 8186	fbge.w		fmul_ovfl_tst		# yes; overflow has occurred
 8187
 8188# no, it didn't overflow; we have correct result
 8189	bra.w		fmul_normal_exit
 8190
 8191#
 8192# UNDERFLOW:
 8193# - the result of the multiply operation is an underflow.
 8194# - do the multiply to the proper precision and rounding mode in order to
 8195# set the inexact bits.
 8196# - calculate the default result and return it in fp0.
 8197# - if overflow or inexact is enabled, we need a multiply result rounded to
 8198# extended precision. if the original operation was extended, then we have this
 8199# result. if the original operation was single or double, we have to do another
 8200# multiply using extended precision and the correct rounding mode. the result
 8201# of this operation then has its exponent scaled by -0x6000 to create the
 8202# exceptional operand.
 8203#
 8204fmul_unfl:
 8205	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 8206
 8207# for fun, let's use only extended precision, round to zero. then, let
 8208# the unf_res() routine figure out all the rest.
 8209# will we get the correct answer.
 8210	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8211
 8212	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
 8213	fmov.l		&0x0,%fpsr		# clear FPSR
 8214
 8215	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8216
 8217	fmov.l		%fpsr,%d1		# save status
 8218	fmov.l		&0x0,%fpcr		# clear FPCR
 8219
 8220	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8221
 8222	mov.b		FPCR_ENABLE(%a6),%d1
 8223	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
 8224	bne.b		fmul_unfl_ena		# yes
 8225
 8226fmul_unfl_dis:
 8227	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 8228
 8229	lea		FP_SCR0(%a6),%a0	# pass: result addr
 8230	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 8231	bsr.l		unf_res			# calculate default result
 8232	or.b		%d0,FPSR_CC(%a6)	# unf_res2 may have set 'Z'
 8233	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 8234	rts
 8235
 8236#
 8237# UNFL is enabled.
 8238#
 8239fmul_unfl_ena:
 8240	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op
 8241
 8242	mov.l		L_SCR3(%a6),%d1
 8243	andi.b		&0xc0,%d1		# is precision extended?
 8244	bne.b		fmul_unfl_ena_sd	# no, sgl or dbl
 8245
 8246# if the rnd mode is anything but RZ, then we have to re-do the above
 8247# multiplication because we used RZ for all.
 8248	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8249
 8250fmul_unfl_ena_cont:
 8251	fmov.l		&0x0,%fpsr		# clear FPSR
 8252
 8253	fmul.x		FP_SCR0(%a6),%fp1	# execute multiply
 8254
 8255	fmov.l		&0x0,%fpcr		# clear FPCR
 8256
 8257	fmovm.x		&0x40,FP_SCR0(%a6)	# save result to stack
 8258	mov.l		%d2,-(%sp)		# save d2
 8259	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 8260	mov.l		%d1,%d2			# make a copy
 8261	andi.l		&0x7fff,%d1		# strip sign
 8262	andi.w		&0x8000,%d2		# keep old sign
 8263	sub.l		%d0,%d1			# add scale factor
 8264	addi.l		&0x6000,%d1		# add bias
 8265	andi.w		&0x7fff,%d1
 8266	or.w		%d2,%d1			# concat old sign,new exp
 8267	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8268	mov.l		(%sp)+,%d2		# restore d2
 8269	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 8270	bra.w		fmul_unfl_dis
 8271
 8272fmul_unfl_ena_sd:
 8273	mov.l		L_SCR3(%a6),%d1
 8274	andi.b		&0x30,%d1		# use only rnd mode
 8275	fmov.l		%d1,%fpcr		# set FPCR
 8276
 8277	bra.b		fmul_unfl_ena_cont
 8278
 8279# MAY UNDERFLOW:
 8280# -use the correct rounding mode and precision. this code favors operations
 8281# that do not underflow.
 8282fmul_may_unfl:
 8283	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8284
 8285	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8286	fmov.l		&0x0,%fpsr		# clear FPSR
 8287
 8288	fmul.x		FP_SCR0(%a6),%fp0	# execute multiply
 8289
 8290	fmov.l		%fpsr,%d1		# save status
 8291	fmov.l		&0x0,%fpcr		# clear FPCR
 8292
 8293	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8294
 8295	fabs.x		%fp0,%fp1		# make a copy of result
 8296	fcmp.b		%fp1,&0x2		# is |result| > 2.b?
 8297	fbgt.w		fmul_normal_exit	# no; no underflow occurred
 8298	fblt.w		fmul_unfl		# yes; underflow occurred
 8299
 8300#
 8301# we still don't know if underflow occurred. result is ~ equal to 2. but,
 8302# we don't know if the result was an underflow that rounded up to a 2 or
 8303# a normalized number that rounded down to a 2. so, redo the entire operation
 8304# using RZ as the rounding mode to see what the pre-rounded result is.
 8305# this case should be relatively rare.
 8306#
 8307	fmovm.x		FP_SCR1(%a6),&0x40	# load dst operand
 8308
 8309	mov.l		L_SCR3(%a6),%d1
 8310	andi.b		&0xc0,%d1		# keep rnd prec
 8311	ori.b		&rz_mode*0x10,%d1	# insert RZ
 8312
 8313	fmov.l		%d1,%fpcr		# set FPCR
 8314	fmov.l		&0x0,%fpsr		# clear FPSR
 8315
 8316	fmul.x		FP_SCR0(%a6),%fp1	# execute multiply
 8317
 8318	fmov.l		&0x0,%fpcr		# clear FPCR
 8319	fabs.x		%fp1			# make absolute value
 8320	fcmp.b		%fp1,&0x2		# is |result| < 2.b?
 8321	fbge.w		fmul_normal_exit	# no; no underflow occurred
 8322	bra.w		fmul_unfl		# yes, underflow occurred
 8323
 8324################################################################################
 8325
 8326#
 8327# Multiply: inputs are not both normalized; what are they?
 8328#
 8329fmul_not_norm:
 8330	mov.w		(tbl_fmul_op.b,%pc,%d1.w*2),%d1
 8331	jmp		(tbl_fmul_op.b,%pc,%d1.w)
 8332
 8333	swbeg		&48
 8334tbl_fmul_op:
 8335	short		fmul_norm	- tbl_fmul_op # NORM x NORM
 8336	short		fmul_zero	- tbl_fmul_op # NORM x ZERO
 8337	short		fmul_inf_src	- tbl_fmul_op # NORM x INF
 8338	short		fmul_res_qnan	- tbl_fmul_op # NORM x QNAN
 8339	short		fmul_norm	- tbl_fmul_op # NORM x DENORM
 8340	short		fmul_res_snan	- tbl_fmul_op # NORM x SNAN
 8341	short		tbl_fmul_op	- tbl_fmul_op #
 8342	short		tbl_fmul_op	- tbl_fmul_op #
 8343
 8344	short		fmul_zero	- tbl_fmul_op # ZERO x NORM
 8345	short		fmul_zero	- tbl_fmul_op # ZERO x ZERO
 8346	short		fmul_res_operr	- tbl_fmul_op # ZERO x INF
 8347	short		fmul_res_qnan	- tbl_fmul_op # ZERO x QNAN
 8348	short		fmul_zero	- tbl_fmul_op # ZERO x DENORM
 8349	short		fmul_res_snan	- tbl_fmul_op # ZERO x SNAN
 8350	short		tbl_fmul_op	- tbl_fmul_op #
 8351	short		tbl_fmul_op	- tbl_fmul_op #
 8352
 8353	short		fmul_inf_dst	- tbl_fmul_op # INF x NORM
 8354	short		fmul_res_operr	- tbl_fmul_op # INF x ZERO
 8355	short		fmul_inf_dst	- tbl_fmul_op # INF x INF
 8356	short		fmul_res_qnan	- tbl_fmul_op # INF x QNAN
 8357	short		fmul_inf_dst	- tbl_fmul_op # INF x DENORM
 8358	short		fmul_res_snan	- tbl_fmul_op # INF x SNAN
 8359	short		tbl_fmul_op	- tbl_fmul_op #
 8360	short		tbl_fmul_op	- tbl_fmul_op #
 8361
 8362	short		fmul_res_qnan	- tbl_fmul_op # QNAN x NORM
 8363	short		fmul_res_qnan	- tbl_fmul_op # QNAN x ZERO
 8364	short		fmul_res_qnan	- tbl_fmul_op # QNAN x INF
 8365	short		fmul_res_qnan	- tbl_fmul_op # QNAN x QNAN
 8366	short		fmul_res_qnan	- tbl_fmul_op # QNAN x DENORM
 8367	short		fmul_res_snan	- tbl_fmul_op # QNAN x SNAN
 8368	short		tbl_fmul_op	- tbl_fmul_op #
 8369	short		tbl_fmul_op	- tbl_fmul_op #
 8370
 8371	short		fmul_norm	- tbl_fmul_op # NORM x NORM
 8372	short		fmul_zero	- tbl_fmul_op # NORM x ZERO
 8373	short		fmul_inf_src	- tbl_fmul_op # NORM x INF
 8374	short		fmul_res_qnan	- tbl_fmul_op # NORM x QNAN
 8375	short		fmul_norm	- tbl_fmul_op # NORM x DENORM
 8376	short		fmul_res_snan	- tbl_fmul_op # NORM x SNAN
 8377	short		tbl_fmul_op	- tbl_fmul_op #
 8378	short		tbl_fmul_op	- tbl_fmul_op #
 8379
 8380	short		fmul_res_snan	- tbl_fmul_op # SNAN x NORM
 8381	short		fmul_res_snan	- tbl_fmul_op # SNAN x ZERO
 8382	short		fmul_res_snan	- tbl_fmul_op # SNAN x INF
 8383	short		fmul_res_snan	- tbl_fmul_op # SNAN x QNAN
 8384	short		fmul_res_snan	- tbl_fmul_op # SNAN x DENORM
 8385	short		fmul_res_snan	- tbl_fmul_op # SNAN x SNAN
 8386	short		tbl_fmul_op	- tbl_fmul_op #
 8387	short		tbl_fmul_op	- tbl_fmul_op #
 8388
 8389fmul_res_operr:
 8390	bra.l		res_operr
 8391fmul_res_snan:
 8392	bra.l		res_snan
 8393fmul_res_qnan:
 8394	bra.l		res_qnan
 8395
 8396#
 8397# Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm)
 8398#
 8399	global		fmul_zero		# global for fsglmul
 8400fmul_zero:
 8401	mov.b		SRC_EX(%a0),%d0		# exclusive or the signs
 8402	mov.b		DST_EX(%a1),%d1
 8403	eor.b		%d0,%d1
 8404	bpl.b		fmul_zero_p		# result ZERO is pos.
 8405fmul_zero_n:
 8406	fmov.s		&0x80000000,%fp0	# load -ZERO
 8407	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
 8408	rts
 8409fmul_zero_p:
 8410	fmov.s		&0x00000000,%fp0	# load +ZERO
 8411	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
 8412	rts
 8413
 8414#
 8415# Multiply: (inf x inf) || (inf x norm) || (inf x denorm)
 8416#
 8417# Note: The j-bit for an infinity is a don't-care. However, to be
 8418# strictly compatible w/ the 68881/882, we make sure to return an
 8419# INF w/ the j-bit set if the input INF j-bit was set. Destination
 8420# INFs take priority.
 8421#
 8422	global		fmul_inf_dst		# global for fsglmul
 8423fmul_inf_dst:
 8424	fmovm.x		DST(%a1),&0x80		# return INF result in fp0
 8425	mov.b		SRC_EX(%a0),%d0		# exclusive or the signs
 8426	mov.b		DST_EX(%a1),%d1
 8427	eor.b		%d0,%d1
 8428	bpl.b		fmul_inf_dst_p		# result INF is pos.
 8429fmul_inf_dst_n:
 8430	fabs.x		%fp0			# clear result sign
 8431	fneg.x		%fp0			# set result sign
 8432	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
 8433	rts
 8434fmul_inf_dst_p:
 8435	fabs.x		%fp0			# clear result sign
 8436	mov.b		&inf_bmask,FPSR_CC(%a6)	# set INF
 8437	rts
 8438
 8439	global		fmul_inf_src		# global for fsglmul
 8440fmul_inf_src:
 8441	fmovm.x		SRC(%a0),&0x80		# return INF result in fp0
 8442	mov.b		SRC_EX(%a0),%d0		# exclusive or the signs
 8443	mov.b		DST_EX(%a1),%d1
 8444	eor.b		%d0,%d1
 8445	bpl.b		fmul_inf_dst_p		# result INF is pos.
 8446	bra.b		fmul_inf_dst_n
 8447
 8448#########################################################################
 8449# XDEF ****************************************************************	#
 8450#	fin(): emulates the fmove instruction				#
 8451#	fsin(): emulates the fsmove instruction				#
 8452#	fdin(): emulates the fdmove instruction				#
 8453#									#
 8454# XREF ****************************************************************	#
 8455#	norm() - normalize mantissa for EXOP on denorm			#
 8456#	scale_to_zero_src() - scale src exponent to zero		#
 8457#	ovf_res() - return default overflow result			#
 8458#	unf_res() - return default underflow result			#
 8459#	res_qnan_1op() - return QNAN result				#
 8460#	res_snan_1op() - return SNAN result				#
 8461#									#
 8462# INPUT ***************************************************************	#
 8463#	a0 = pointer to extended precision source operand		#
 8464#	d0 = round prec/mode						#
 8465#									#
 8466# OUTPUT **************************************************************	#
 8467#	fp0 = result							#
 8468#	fp1 = EXOP (if exception occurred)				#
 8469#									#
 8470# ALGORITHM ***********************************************************	#
 8471#	Handle NANs, infinities, and zeroes as special cases. Divide	#
 8472# norms into extended, single, and double precision.			#
 8473#	Norms can be emulated w/ a regular fmove instruction. For	#
 8474# sgl/dbl, must scale exponent and perform an "fmove". Check to see	#
 8475# if the result would have overflowed/underflowed. If so, use unf_res()	#
 8476# or ovf_res() to return the default result. Also return EXOP if	#
 8477# exception is enabled. If no exception, return the default result.	#
 8478#	Unnorms don't pass through here.				#
 8479#									#
 8480#########################################################################
 8481
 8482	global		fsin
 8483fsin:
 8484	andi.b		&0x30,%d0		# clear rnd prec
 8485	ori.b		&s_mode*0x10,%d0	# insert sgl precision
 8486	bra.b		fin
 8487
 8488	global		fdin
 8489fdin:
 8490	andi.b		&0x30,%d0		# clear rnd prec
 8491	ori.b		&d_mode*0x10,%d0	# insert dbl precision
 8492
 8493	global		fin
 8494fin:
 8495	mov.l		%d0,L_SCR3(%a6)		# store rnd info
 8496
 8497	mov.b		STAG(%a6),%d1		# fetch src optype tag
 8498	bne.w		fin_not_norm		# optimize on non-norm input
 8499
 8500#
 8501# FP MOVE IN: NORMs and DENORMs ONLY!
 8502#
 8503fin_norm:
 8504	andi.b		&0xc0,%d0		# is precision extended?
 8505	bne.w		fin_not_ext		# no, so go handle dbl or sgl
 8506
 8507#
 8508# precision selected is extended. so...we cannot get an underflow
 8509# or overflow because of rounding to the correct precision. so...
 8510# skip the scaling and unscaling...
 8511#
 8512	tst.b		SRC_EX(%a0)		# is the operand negative?
 8513	bpl.b		fin_norm_done		# no
 8514	bset		&neg_bit,FPSR_CC(%a6)	# yes, so set 'N' ccode bit
 8515fin_norm_done:
 8516	fmovm.x		SRC(%a0),&0x80		# return result in fp0
 8517	rts
 8518
 8519#
 8520# for an extended precision DENORM, the UNFL exception bit is set
 8521# the accrued bit is NOT set in this instance(no inexactness!)
 8522#
 8523fin_denorm:
 8524	andi.b		&0xc0,%d0		# is precision extended?
 8525	bne.w		fin_not_ext		# no, so go handle dbl or sgl
 8526
 8527	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 8528	tst.b		SRC_EX(%a0)		# is the operand negative?
 8529	bpl.b		fin_denorm_done		# no
 8530	bset		&neg_bit,FPSR_CC(%a6)	# yes, so set 'N' ccode bit
 8531fin_denorm_done:
 8532	fmovm.x		SRC(%a0),&0x80		# return result in fp0
 8533	btst		&unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
 8534	bne.b		fin_denorm_unfl_ena	# yes
 8535	rts
 8536
 8537#
 8538# the input is an extended DENORM and underflow is enabled in the FPCR.
 8539# normalize the mantissa and add the bias of 0x6000 to the resulting negative
 8540# exponent and insert back into the operand.
 8541#
 8542fin_denorm_unfl_ena:
 8543	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 8544	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 8545	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 8546	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 8547	bsr.l		norm			# normalize result
 8548	neg.w		%d0			# new exponent = -(shft val)
 8549	addi.w		&0x6000,%d0		# add new bias to exponent
 8550	mov.w		FP_SCR0_EX(%a6),%d1	# fetch old sign,exp
 8551	andi.w		&0x8000,%d1		# keep old sign
 8552	andi.w		&0x7fff,%d0		# clear sign position
 8553	or.w		%d1,%d0			# concat new exo,old sign
 8554	mov.w		%d0,FP_SCR0_EX(%a6)	# insert new exponent
 8555	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 8556	rts
 8557
 8558#
 8559# operand is to be rounded to single or double precision
 8560#
 8561fin_not_ext:
 8562	cmpi.b		%d0,&s_mode*0x10	# separate sgl/dbl prec
 8563	bne.b		fin_dbl
 8564
 8565#
 8566# operand is to be rounded to single precision
 8567#
 8568fin_sgl:
 8569	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 8570	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 8571	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 8572	bsr.l		scale_to_zero_src	# calculate scale factor
 8573
 8574	cmpi.l		%d0,&0x3fff-0x3f80	# will move in underflow?
 8575	bge.w		fin_sd_unfl		# yes; go handle underflow
 8576	cmpi.l		%d0,&0x3fff-0x407e	# will move in overflow?
 8577	beq.w		fin_sd_may_ovfl		# maybe; go check
 8578	blt.w		fin_sd_ovfl		# yes; go handle overflow
 8579
 8580#
 8581# operand will NOT overflow or underflow when moved into the fp reg file
 8582#
 8583fin_sd_normal:
 8584	fmov.l		&0x0,%fpsr		# clear FPSR
 8585	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8586
 8587	fmov.x		FP_SCR0(%a6),%fp0	# perform move
 8588
 8589	fmov.l		%fpsr,%d1		# save FPSR
 8590	fmov.l		&0x0,%fpcr		# clear FPCR
 8591
 8592	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8593
 8594fin_sd_normal_exit:
 8595	mov.l		%d2,-(%sp)		# save d2
 8596	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 8597	mov.w		FP_SCR0_EX(%a6),%d1	# load {sgn,exp}
 8598	mov.w		%d1,%d2			# make a copy
 8599	andi.l		&0x7fff,%d1		# strip sign
 8600	sub.l		%d0,%d1			# add scale factor
 8601	andi.w		&0x8000,%d2		# keep old sign
 8602	or.w		%d1,%d2			# concat old sign,new exponent
 8603	mov.w		%d2,FP_SCR0_EX(%a6)	# insert new exponent
 8604	mov.l		(%sp)+,%d2		# restore d2
 8605	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
 8606	rts
 8607
 8608#
 8609# operand is to be rounded to double precision
 8610#
 8611fin_dbl:
 8612	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 8613	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 8614	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 8615	bsr.l		scale_to_zero_src	# calculate scale factor
 8616
 8617	cmpi.l		%d0,&0x3fff-0x3c00	# will move in underflow?
 8618	bge.w		fin_sd_unfl		# yes; go handle underflow
 8619	cmpi.l		%d0,&0x3fff-0x43fe	# will move in overflow?
 8620	beq.w		fin_sd_may_ovfl		# maybe; go check
 8621	blt.w		fin_sd_ovfl		# yes; go handle overflow
 8622	bra.w		fin_sd_normal		# no; ho handle normalized op
 8623
 8624#
 8625# operand WILL underflow when moved in to the fp register file
 8626#
 8627fin_sd_unfl:
 8628	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 8629
 8630	tst.b		FP_SCR0_EX(%a6)		# is operand negative?
 8631	bpl.b		fin_sd_unfl_tst
 8632	bset		&neg_bit,FPSR_CC(%a6)	# set 'N' ccode bit
 8633
 8634# if underflow or inexact is enabled, then go calculate the EXOP first.
 8635fin_sd_unfl_tst:
 8636	mov.b		FPCR_ENABLE(%a6),%d1
 8637	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
 8638	bne.b		fin_sd_unfl_ena		# yes
 8639
 8640fin_sd_unfl_dis:
 8641	lea		FP_SCR0(%a6),%a0	# pass: result addr
 8642	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 8643	bsr.l		unf_res			# calculate default result
 8644	or.b		%d0,FPSR_CC(%a6)	# unf_res may have set 'Z'
 8645	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 8646	rts
 8647
 8648#
 8649# operand will underflow AND underflow or inexact is enabled.
 8650# Therefore, we must return the result rounded to extended precision.
 8651#
 8652fin_sd_unfl_ena:
 8653	mov.l		FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
 8654	mov.l		FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
 8655	mov.w		FP_SCR0_EX(%a6),%d1	# load current exponent
 8656
 8657	mov.l		%d2,-(%sp)		# save d2
 8658	mov.w		%d1,%d2			# make a copy
 8659	andi.l		&0x7fff,%d1		# strip sign
 8660	sub.l		%d0,%d1			# subtract scale factor
 8661	andi.w		&0x8000,%d2		# extract old sign
 8662	addi.l		&0x6000,%d1		# add new bias
 8663	andi.w		&0x7fff,%d1
 8664	or.w		%d1,%d2			# concat old sign,new exp
 8665	mov.w		%d2,FP_SCR1_EX(%a6)	# insert new exponent
 8666	fmovm.x		FP_SCR1(%a6),&0x40	# return EXOP in fp1
 8667	mov.l		(%sp)+,%d2		# restore d2
 8668	bra.b		fin_sd_unfl_dis
 8669
 8670#
 8671# operand WILL overflow.
 8672#
 8673fin_sd_ovfl:
 8674	fmov.l		&0x0,%fpsr		# clear FPSR
 8675	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8676
 8677	fmov.x		FP_SCR0(%a6),%fp0	# perform move
 8678
 8679	fmov.l		&0x0,%fpcr		# clear FPCR
 8680	fmov.l		%fpsr,%d1		# save FPSR
 8681
 8682	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8683
 8684fin_sd_ovfl_tst:
 8685	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
 8686
 8687	mov.b		FPCR_ENABLE(%a6),%d1
 8688	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
 8689	bne.b		fin_sd_ovfl_ena		# yes
 8690
 8691#
 8692# OVFL is not enabled; therefore, we must create the default result by
 8693# calling ovf_res().
 8694#
 8695fin_sd_ovfl_dis:
 8696	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
 8697	sne		%d1			# set sign param accordingly
 8698	mov.l		L_SCR3(%a6),%d0		# pass: prec,mode
 8699	bsr.l		ovf_res			# calculate default result
 8700	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
 8701	fmovm.x		(%a0),&0x80		# return default result in fp0
 8702	rts
 8703
 8704#
 8705# OVFL is enabled.
 8706# the INEX2 bit has already been updated by the round to the correct precision.
 8707# now, round to extended(and don't alter the FPSR).
 8708#
 8709fin_sd_ovfl_ena:
 8710	mov.l		%d2,-(%sp)		# save d2
 8711	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 8712	mov.l		%d1,%d2			# make a copy
 8713	andi.l		&0x7fff,%d1		# strip sign
 8714	andi.w		&0x8000,%d2		# keep old sign
 8715	sub.l		%d0,%d1			# add scale factor
 8716	sub.l		&0x6000,%d1		# subtract bias
 8717	andi.w		&0x7fff,%d1
 8718	or.w		%d2,%d1
 8719	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8720	mov.l		(%sp)+,%d2		# restore d2
 8721	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 8722	bra.b		fin_sd_ovfl_dis
 8723
 8724#
 8725# the move in MAY overflow. so...
 8726#
 8727fin_sd_may_ovfl:
 8728	fmov.l		&0x0,%fpsr		# clear FPSR
 8729	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8730
 8731	fmov.x		FP_SCR0(%a6),%fp0	# perform the move
 8732
 8733	fmov.l		%fpsr,%d1		# save status
 8734	fmov.l		&0x0,%fpcr		# clear FPCR
 8735
 8736	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8737
 8738	fabs.x		%fp0,%fp1		# make a copy of result
 8739	fcmp.b		%fp1,&0x2		# is |result| >= 2.b?
 8740	fbge.w		fin_sd_ovfl_tst		# yes; overflow has occurred
 8741
 8742# no, it didn't overflow; we have correct result
 8743	bra.w		fin_sd_normal_exit
 8744
 8745##########################################################################
 8746
 8747#
 8748# operand is not a NORM: check its optype and branch accordingly
 8749#
 8750fin_not_norm:
 8751	cmpi.b		%d1,&DENORM		# weed out DENORM
 8752	beq.w		fin_denorm
 8753	cmpi.b		%d1,&SNAN		# weed out SNANs
 8754	beq.l		res_snan_1op
 8755	cmpi.b		%d1,&QNAN		# weed out QNANs
 8756	beq.l		res_qnan_1op
 8757
 8758#
 8759# do the fmove in; at this point, only possible ops are ZERO and INF.
 8760# use fmov to determine ccodes.
 8761# prec:mode should be zero at this point but it won't affect answer anyways.
 8762#
 8763	fmov.x		SRC(%a0),%fp0		# do fmove in
 8764	fmov.l		%fpsr,%d0		# no exceptions possible
 8765	rol.l		&0x8,%d0		# put ccodes in lo byte
 8766	mov.b		%d0,FPSR_CC(%a6)	# insert correct ccodes
 8767	rts
 8768
 8769#########################################################################
 8770# XDEF ****************************************************************	#
 8771#	fdiv(): emulates the fdiv instruction				#
 8772#	fsdiv(): emulates the fsdiv instruction				#
 8773#	fddiv(): emulates the fddiv instruction				#
 8774#									#
 8775# XREF ****************************************************************	#
 8776#	scale_to_zero_src() - scale src exponent to zero		#
 8777#	scale_to_zero_dst() - scale dst exponent to zero		#
 8778#	unf_res() - return default underflow result			#
 8779#	ovf_res() - return default overflow result			#
 8780#	res_qnan() - return QNAN result					#
 8781#	res_snan() - return SNAN result					#
 8782#									#
 8783# INPUT ***************************************************************	#
 8784#	a0 = pointer to extended precision source operand		#
 8785#	a1 = pointer to extended precision destination operand		#
 8786#	d0  rnd prec,mode						#
 8787#									#
 8788# OUTPUT **************************************************************	#
 8789#	fp0 = result							#
 8790#	fp1 = EXOP (if exception occurred)				#
 8791#									#
 8792# ALGORITHM ***********************************************************	#
 8793#	Handle NANs, infinities, and zeroes as special cases. Divide	#
 8794# norms/denorms into ext/sgl/dbl precision.				#
 8795#	For norms/denorms, scale the exponents such that a divide	#
 8796# instruction won't cause an exception. Use the regular fdiv to		#
 8797# compute a result. Check if the regular operands would have taken	#
 8798# an exception. If so, return the default overflow/underflow result	#
 8799# and return the EXOP if exceptions are enabled. Else, scale the	#
 8800# result operand to the proper exponent.				#
 8801#									#
 8802#########################################################################
 8803
 8804	align		0x10
 8805tbl_fdiv_unfl:
 8806	long		0x3fff - 0x0000		# ext_unfl
 8807	long		0x3fff - 0x3f81		# sgl_unfl
 8808	long		0x3fff - 0x3c01		# dbl_unfl
 8809
 8810tbl_fdiv_ovfl:
 8811	long		0x3fff - 0x7ffe		# ext overflow exponent
 8812	long		0x3fff - 0x407e		# sgl overflow exponent
 8813	long		0x3fff - 0x43fe		# dbl overflow exponent
 8814
 8815	global		fsdiv
 8816fsdiv:
 8817	andi.b		&0x30,%d0		# clear rnd prec
 8818	ori.b		&s_mode*0x10,%d0	# insert sgl prec
 8819	bra.b		fdiv
 8820
 8821	global		fddiv
 8822fddiv:
 8823	andi.b		&0x30,%d0		# clear rnd prec
 8824	ori.b		&d_mode*0x10,%d0	# insert dbl prec
 8825
 8826	global		fdiv
 8827fdiv:
 8828	mov.l		%d0,L_SCR3(%a6)		# store rnd info
 8829
 8830	clr.w		%d1
 8831	mov.b		DTAG(%a6),%d1
 8832	lsl.b		&0x3,%d1
 8833	or.b		STAG(%a6),%d1		# combine src tags
 8834
 8835	bne.w		fdiv_not_norm		# optimize on non-norm input
 8836
 8837#
 8838# DIVIDE: NORMs and DENORMs ONLY!
 8839#
 8840fdiv_norm:
 8841	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
 8842	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
 8843	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
 8844
 8845	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 8846	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 8847	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 8848
 8849	bsr.l		scale_to_zero_src	# scale src exponent
 8850	mov.l		%d0,-(%sp)		# save scale factor 1
 8851
 8852	bsr.l		scale_to_zero_dst	# scale dst exponent
 8853
 8854	neg.l		(%sp)			# SCALE FACTOR = scale1 - scale2
 8855	add.l		%d0,(%sp)
 8856
 8857	mov.w		2+L_SCR3(%a6),%d1	# fetch precision
 8858	lsr.b		&0x6,%d1		# shift to lo bits
 8859	mov.l		(%sp)+,%d0		# load S.F.
 8860	cmp.l		%d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow?
 8861	ble.w		fdiv_may_ovfl		# result will overflow
 8862
 8863	cmp.l		%d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow?
 8864	beq.w		fdiv_may_unfl		# maybe
 8865	bgt.w		fdiv_unfl		# yes; go handle underflow
 8866
 8867fdiv_normal:
 8868	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
 8869
 8870	fmov.l		L_SCR3(%a6),%fpcr	# save FPCR
 8871	fmov.l		&0x0,%fpsr		# clear FPSR
 8872
 8873	fdiv.x		FP_SCR0(%a6),%fp0	# perform divide
 8874
 8875	fmov.l		%fpsr,%d1		# save FPSR
 8876	fmov.l		&0x0,%fpcr		# clear FPCR
 8877
 8878	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8879
 8880fdiv_normal_exit:
 8881	fmovm.x		&0x80,FP_SCR0(%a6)	# store result on stack
 8882	mov.l		%d2,-(%sp)		# store d2
 8883	mov.w		FP_SCR0_EX(%a6),%d1	# load {sgn,exp}
 8884	mov.l		%d1,%d2			# make a copy
 8885	andi.l		&0x7fff,%d1		# strip sign
 8886	andi.w		&0x8000,%d2		# keep old sign
 8887	sub.l		%d0,%d1			# add scale factor
 8888	or.w		%d2,%d1			# concat old sign,new exp
 8889	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8890	mov.l		(%sp)+,%d2		# restore d2
 8891	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
 8892	rts
 8893
 8894tbl_fdiv_ovfl2:
 8895	long		0x7fff
 8896	long		0x407f
 8897	long		0x43ff
 8898
 8899fdiv_no_ovfl:
 8900	mov.l		(%sp)+,%d0		# restore scale factor
 8901	bra.b		fdiv_normal_exit
 8902
 8903fdiv_may_ovfl:
 8904	mov.l		%d0,-(%sp)		# save scale factor
 8905
 8906	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
 8907
 8908	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 8909	fmov.l		&0x0,%fpsr		# set FPSR
 8910
 8911	fdiv.x		FP_SCR0(%a6),%fp0	# execute divide
 8912
 8913	fmov.l		%fpsr,%d0
 8914	fmov.l		&0x0,%fpcr
 8915
 8916	or.l		%d0,USER_FPSR(%a6)	# save INEX,N
 8917
 8918	fmovm.x		&0x01,-(%sp)		# save result to stack
 8919	mov.w		(%sp),%d0		# fetch new exponent
 8920	add.l		&0xc,%sp		# clear result from stack
 8921	andi.l		&0x7fff,%d0		# strip sign
 8922	sub.l		(%sp),%d0		# add scale factor
 8923	cmp.l		%d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4)
 8924	blt.b		fdiv_no_ovfl
 8925	mov.l		(%sp)+,%d0
 8926
 8927fdiv_ovfl_tst:
 8928	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
 8929
 8930	mov.b		FPCR_ENABLE(%a6),%d1
 8931	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
 8932	bne.b		fdiv_ovfl_ena		# yes
 8933
 8934fdiv_ovfl_dis:
 8935	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
 8936	sne		%d1			# set sign param accordingly
 8937	mov.l		L_SCR3(%a6),%d0		# pass prec:rnd
 8938	bsr.l		ovf_res			# calculate default result
 8939	or.b		%d0,FPSR_CC(%a6)	# set INF if applicable
 8940	fmovm.x		(%a0),&0x80		# return default result in fp0
 8941	rts
 8942
 8943fdiv_ovfl_ena:
 8944	mov.l		L_SCR3(%a6),%d1
 8945	andi.b		&0xc0,%d1		# is precision extended?
 8946	bne.b		fdiv_ovfl_ena_sd	# no, do sgl or dbl
 8947
 8948fdiv_ovfl_ena_cont:
 8949	fmovm.x		&0x80,FP_SCR0(%a6)	# move result to stack
 8950
 8951	mov.l		%d2,-(%sp)		# save d2
 8952	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 8953	mov.w		%d1,%d2			# make a copy
 8954	andi.l		&0x7fff,%d1		# strip sign
 8955	sub.l		%d0,%d1			# add scale factor
 8956	subi.l		&0x6000,%d1		# subtract bias
 8957	andi.w		&0x7fff,%d1		# clear sign bit
 8958	andi.w		&0x8000,%d2		# keep old sign
 8959	or.w		%d2,%d1			# concat old sign,new exp
 8960	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 8961	mov.l		(%sp)+,%d2		# restore d2
 8962	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 8963	bra.b		fdiv_ovfl_dis
 8964
 8965fdiv_ovfl_ena_sd:
 8966	fmovm.x		FP_SCR1(%a6),&0x80	# load dst operand
 8967
 8968	mov.l		L_SCR3(%a6),%d1
 8969	andi.b		&0x30,%d1		# keep rnd mode
 8970	fmov.l		%d1,%fpcr		# set FPCR
 8971
 8972	fdiv.x		FP_SCR0(%a6),%fp0	# execute divide
 8973
 8974	fmov.l		&0x0,%fpcr		# clear FPCR
 8975	bra.b		fdiv_ovfl_ena_cont
 8976
 8977fdiv_unfl:
 8978	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 8979
 8980	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
 8981
 8982	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
 8983	fmov.l		&0x0,%fpsr		# clear FPSR
 8984
 8985	fdiv.x		FP_SCR0(%a6),%fp0	# execute divide
 8986
 8987	fmov.l		%fpsr,%d1		# save status
 8988	fmov.l		&0x0,%fpcr		# clear FPCR
 8989
 8990	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 8991
 8992	mov.b		FPCR_ENABLE(%a6),%d1
 8993	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
 8994	bne.b		fdiv_unfl_ena		# yes
 8995
 8996fdiv_unfl_dis:
 8997	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 8998
 8999	lea		FP_SCR0(%a6),%a0	# pass: result addr
 9000	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 9001	bsr.l		unf_res			# calculate default result
 9002	or.b		%d0,FPSR_CC(%a6)	# 'Z' may have been set
 9003	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 9004	rts
 9005
 9006#
 9007# UNFL is enabled.
 9008#
 9009fdiv_unfl_ena:
 9010	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op
 9011
 9012	mov.l		L_SCR3(%a6),%d1
 9013	andi.b		&0xc0,%d1		# is precision extended?
 9014	bne.b		fdiv_unfl_ena_sd	# no, sgl or dbl
 9015
 9016	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9017
 9018fdiv_unfl_ena_cont:
 9019	fmov.l		&0x0,%fpsr		# clear FPSR
 9020
 9021	fdiv.x		FP_SCR0(%a6),%fp1	# execute divide
 9022
 9023	fmov.l		&0x0,%fpcr		# clear FPCR
 9024
 9025	fmovm.x		&0x40,FP_SCR0(%a6)	# save result to stack
 9026	mov.l		%d2,-(%sp)		# save d2
 9027	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 9028	mov.l		%d1,%d2			# make a copy
 9029	andi.l		&0x7fff,%d1		# strip sign
 9030	andi.w		&0x8000,%d2		# keep old sign
 9031	sub.l		%d0,%d1			# add scale factoer
 9032	addi.l		&0x6000,%d1		# add bias
 9033	andi.w		&0x7fff,%d1
 9034	or.w		%d2,%d1			# concat old sign,new exp
 9035	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exp
 9036	mov.l		(%sp)+,%d2		# restore d2
 9037	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 9038	bra.w		fdiv_unfl_dis
 9039
 9040fdiv_unfl_ena_sd:
 9041	mov.l		L_SCR3(%a6),%d1
 9042	andi.b		&0x30,%d1		# use only rnd mode
 9043	fmov.l		%d1,%fpcr		# set FPCR
 9044
 9045	bra.b		fdiv_unfl_ena_cont
 9046
 9047#
 9048# the divide operation MAY underflow:
 9049#
 9050fdiv_may_unfl:
 9051	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
 9052
 9053	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9054	fmov.l		&0x0,%fpsr		# clear FPSR
 9055
 9056	fdiv.x		FP_SCR0(%a6),%fp0	# execute divide
 9057
 9058	fmov.l		%fpsr,%d1		# save status
 9059	fmov.l		&0x0,%fpcr		# clear FPCR
 9060
 9061	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 9062
 9063	fabs.x		%fp0,%fp1		# make a copy of result
 9064	fcmp.b		%fp1,&0x1		# is |result| > 1.b?
 9065	fbgt.w		fdiv_normal_exit	# no; no underflow occurred
 9066	fblt.w		fdiv_unfl		# yes; underflow occurred
 9067
 9068#
 9069# we still don't know if underflow occurred. result is ~ equal to 1. but,
 9070# we don't know if the result was an underflow that rounded up to a 1
 9071# or a normalized number that rounded down to a 1. so, redo the entire
 9072# operation using RZ as the rounding mode to see what the pre-rounded
 9073# result is. this case should be relatively rare.
 9074#
 9075	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op into fp1
 9076
 9077	mov.l		L_SCR3(%a6),%d1
 9078	andi.b		&0xc0,%d1		# keep rnd prec
 9079	ori.b		&rz_mode*0x10,%d1	# insert RZ
 9080
 9081	fmov.l		%d1,%fpcr		# set FPCR
 9082	fmov.l		&0x0,%fpsr		# clear FPSR
 9083
 9084	fdiv.x		FP_SCR0(%a6),%fp1	# execute divide
 9085
 9086	fmov.l		&0x0,%fpcr		# clear FPCR
 9087	fabs.x		%fp1			# make absolute value
 9088	fcmp.b		%fp1,&0x1		# is |result| < 1.b?
 9089	fbge.w		fdiv_normal_exit	# no; no underflow occurred
 9090	bra.w		fdiv_unfl		# yes; underflow occurred
 9091
 9092############################################################################
 9093
 9094#
 9095# Divide: inputs are not both normalized; what are they?
 9096#
 9097fdiv_not_norm:
 9098	mov.w		(tbl_fdiv_op.b,%pc,%d1.w*2),%d1
 9099	jmp		(tbl_fdiv_op.b,%pc,%d1.w*1)
 9100
 9101	swbeg		&48
 9102tbl_fdiv_op:
 9103	short		fdiv_norm	- tbl_fdiv_op # NORM / NORM
 9104	short		fdiv_inf_load	- tbl_fdiv_op # NORM / ZERO
 9105	short		fdiv_zero_load	- tbl_fdiv_op # NORM / INF
 9106	short		fdiv_res_qnan	- tbl_fdiv_op # NORM / QNAN
 9107	short		fdiv_norm	- tbl_fdiv_op # NORM / DENORM
 9108	short		fdiv_res_snan	- tbl_fdiv_op # NORM / SNAN
 9109	short		tbl_fdiv_op	- tbl_fdiv_op #
 9110	short		tbl_fdiv_op	- tbl_fdiv_op #
 9111
 9112	short		fdiv_zero_load	- tbl_fdiv_op # ZERO / NORM
 9113	short		fdiv_res_operr	- tbl_fdiv_op # ZERO / ZERO
 9114	short		fdiv_zero_load	- tbl_fdiv_op # ZERO / INF
 9115	short		fdiv_res_qnan	- tbl_fdiv_op # ZERO / QNAN
 9116	short		fdiv_zero_load	- tbl_fdiv_op # ZERO / DENORM
 9117	short		fdiv_res_snan	- tbl_fdiv_op # ZERO / SNAN
 9118	short		tbl_fdiv_op	- tbl_fdiv_op #
 9119	short		tbl_fdiv_op	- tbl_fdiv_op #
 9120
 9121	short		fdiv_inf_dst	- tbl_fdiv_op # INF / NORM
 9122	short		fdiv_inf_dst	- tbl_fdiv_op # INF / ZERO
 9123	short		fdiv_res_operr	- tbl_fdiv_op # INF / INF
 9124	short		fdiv_res_qnan	- tbl_fdiv_op # INF / QNAN
 9125	short		fdiv_inf_dst	- tbl_fdiv_op # INF / DENORM
 9126	short		fdiv_res_snan	- tbl_fdiv_op # INF / SNAN
 9127	short		tbl_fdiv_op	- tbl_fdiv_op #
 9128	short		tbl_fdiv_op	- tbl_fdiv_op #
 9129
 9130	short		fdiv_res_qnan	- tbl_fdiv_op # QNAN / NORM
 9131	short		fdiv_res_qnan	- tbl_fdiv_op # QNAN / ZERO
 9132	short		fdiv_res_qnan	- tbl_fdiv_op # QNAN / INF
 9133	short		fdiv_res_qnan	- tbl_fdiv_op # QNAN / QNAN
 9134	short		fdiv_res_qnan	- tbl_fdiv_op # QNAN / DENORM
 9135	short		fdiv_res_snan	- tbl_fdiv_op # QNAN / SNAN
 9136	short		tbl_fdiv_op	- tbl_fdiv_op #
 9137	short		tbl_fdiv_op	- tbl_fdiv_op #
 9138
 9139	short		fdiv_norm	- tbl_fdiv_op # DENORM / NORM
 9140	short		fdiv_inf_load	- tbl_fdiv_op # DENORM / ZERO
 9141	short		fdiv_zero_load	- tbl_fdiv_op # DENORM / INF
 9142	short		fdiv_res_qnan	- tbl_fdiv_op # DENORM / QNAN
 9143	short		fdiv_norm	- tbl_fdiv_op # DENORM / DENORM
 9144	short		fdiv_res_snan	- tbl_fdiv_op # DENORM / SNAN
 9145	short		tbl_fdiv_op	- tbl_fdiv_op #
 9146	short		tbl_fdiv_op	- tbl_fdiv_op #
 9147
 9148	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / NORM
 9149	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / ZERO
 9150	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / INF
 9151	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / QNAN
 9152	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / DENORM
 9153	short		fdiv_res_snan	- tbl_fdiv_op # SNAN / SNAN
 9154	short		tbl_fdiv_op	- tbl_fdiv_op #
 9155	short		tbl_fdiv_op	- tbl_fdiv_op #
 9156
 9157fdiv_res_qnan:
 9158	bra.l		res_qnan
 9159fdiv_res_snan:
 9160	bra.l		res_snan
 9161fdiv_res_operr:
 9162	bra.l		res_operr
 9163
 9164	global		fdiv_zero_load		# global for fsgldiv
 9165fdiv_zero_load:
 9166	mov.b		SRC_EX(%a0),%d0		# result sign is exclusive
 9167	mov.b		DST_EX(%a1),%d1		# or of input signs.
 9168	eor.b		%d0,%d1
 9169	bpl.b		fdiv_zero_load_p	# result is positive
 9170	fmov.s		&0x80000000,%fp0	# load a -ZERO
 9171	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6)	# set Z/N
 9172	rts
 9173fdiv_zero_load_p:
 9174	fmov.s		&0x00000000,%fp0	# load a +ZERO
 9175	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
 9176	rts
 9177
 9178#
 9179# The destination was In Range and the source was a ZERO. The result,
 9180# Therefore, is an INF w/ the proper sign.
 9181# So, determine the sign and return a new INF (w/ the j-bit cleared).
 9182#
 9183	global		fdiv_inf_load		# global for fsgldiv
 9184fdiv_inf_load:
 9185	ori.w		&dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ
 9186	mov.b		SRC_EX(%a0),%d0		# load both signs
 9187	mov.b		DST_EX(%a1),%d1
 9188	eor.b		%d0,%d1
 9189	bpl.b		fdiv_inf_load_p		# result is positive
 9190	fmov.s		&0xff800000,%fp0	# make result -INF
 9191	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
 9192	rts
 9193fdiv_inf_load_p:
 9194	fmov.s		&0x7f800000,%fp0	# make result +INF
 9195	mov.b		&inf_bmask,FPSR_CC(%a6)	# set INF
 9196	rts
 9197
 9198#
 9199# The destination was an INF w/ an In Range or ZERO source, the result is
 9200# an INF w/ the proper sign.
 9201# The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the
 9202# dst INF is set, then then j-bit of the result INF is also set).
 9203#
 9204	global		fdiv_inf_dst		# global for fsgldiv
 9205fdiv_inf_dst:
 9206	mov.b		DST_EX(%a1),%d0		# load both signs
 9207	mov.b		SRC_EX(%a0),%d1
 9208	eor.b		%d0,%d1
 9209	bpl.b		fdiv_inf_dst_p		# result is positive
 9210
 9211	fmovm.x		DST(%a1),&0x80		# return result in fp0
 9212	fabs.x		%fp0			# clear sign bit
 9213	fneg.x		%fp0			# set sign bit
 9214	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG
 9215	rts
 9216
 9217fdiv_inf_dst_p:
 9218	fmovm.x		DST(%a1),&0x80		# return result in fp0
 9219	fabs.x		%fp0			# return positive INF
 9220	mov.b		&inf_bmask,FPSR_CC(%a6) # set INF
 9221	rts
 9222
 9223#########################################################################
 9224# XDEF ****************************************************************	#
 9225#	fneg(): emulates the fneg instruction				#
 9226#	fsneg(): emulates the fsneg instruction				#
 9227#	fdneg(): emulates the fdneg instruction				#
 9228#									#
 9229# XREF ****************************************************************	#
 9230#	norm() - normalize a denorm to provide EXOP			#
 9231#	scale_to_zero_src() - scale sgl/dbl source exponent		#
 9232#	ovf_res() - return default overflow result			#
 9233#	unf_res() - return default underflow result			#
 9234#	res_qnan_1op() - return QNAN result				#
 9235#	res_snan_1op() - return SNAN result				#
 9236#									#
 9237# INPUT ***************************************************************	#
 9238#	a0 = pointer to extended precision source operand		#
 9239#	d0 = rnd prec,mode						#
 9240#									#
 9241# OUTPUT **************************************************************	#
 9242#	fp0 = result							#
 9243#	fp1 = EXOP (if exception occurred)				#
 9244#									#
 9245# ALGORITHM ***********************************************************	#
 9246#	Handle NANs, zeroes, and infinities as special cases. Separate	#
 9247# norms/denorms into ext/sgl/dbl precisions. Extended precision can be	#
 9248# emulated by simply setting sign bit. Sgl/dbl operands must be scaled	#
 9249# and an actual fneg performed to see if overflow/underflow would have	#
 9250# occurred. If so, return default underflow/overflow result. Else,	#
 9251# scale the result exponent and return result. FPSR gets set based on	#
 9252# the result value.							#
 9253#									#
 9254#########################################################################
 9255
 9256	global		fsneg
 9257fsneg:
 9258	andi.b		&0x30,%d0		# clear rnd prec
 9259	ori.b		&s_mode*0x10,%d0	# insert sgl precision
 9260	bra.b		fneg
 9261
 9262	global		fdneg
 9263fdneg:
 9264	andi.b		&0x30,%d0		# clear rnd prec
 9265	ori.b		&d_mode*0x10,%d0	# insert dbl prec
 9266
 9267	global		fneg
 9268fneg:
 9269	mov.l		%d0,L_SCR3(%a6)		# store rnd info
 9270	mov.b		STAG(%a6),%d1
 9271	bne.w		fneg_not_norm		# optimize on non-norm input
 9272
 9273#
 9274# NEGATE SIGN : norms and denorms ONLY!
 9275#
 9276fneg_norm:
 9277	andi.b		&0xc0,%d0		# is precision extended?
 9278	bne.w		fneg_not_ext		# no; go handle sgl or dbl
 9279
 9280#
 9281# precision selected is extended. so...we can not get an underflow
 9282# or overflow because of rounding to the correct precision. so...
 9283# skip the scaling and unscaling...
 9284#
 9285	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9286	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9287	mov.w		SRC_EX(%a0),%d0
 9288	eori.w		&0x8000,%d0		# negate sign
 9289	bpl.b		fneg_norm_load		# sign is positive
 9290	mov.b		&neg_bmask,FPSR_CC(%a6)	# set 'N' ccode bit
 9291fneg_norm_load:
 9292	mov.w		%d0,FP_SCR0_EX(%a6)
 9293	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
 9294	rts
 9295
 9296#
 9297# for an extended precision DENORM, the UNFL exception bit is set
 9298# the accrued bit is NOT set in this instance(no inexactness!)
 9299#
 9300fneg_denorm:
 9301	andi.b		&0xc0,%d0		# is precision extended?
 9302	bne.b		fneg_not_ext		# no; go handle sgl or dbl
 9303
 9304	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 9305
 9306	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9307	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9308	mov.w		SRC_EX(%a0),%d0
 9309	eori.w		&0x8000,%d0		# negate sign
 9310	bpl.b		fneg_denorm_done	# no
 9311	mov.b		&neg_bmask,FPSR_CC(%a6)	# yes, set 'N' ccode bit
 9312fneg_denorm_done:
 9313	mov.w		%d0,FP_SCR0_EX(%a6)
 9314	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 9315
 9316	btst		&unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
 9317	bne.b		fneg_ext_unfl_ena	# yes
 9318	rts
 9319
 9320#
 9321# the input is an extended DENORM and underflow is enabled in the FPCR.
 9322# normalize the mantissa and add the bias of 0x6000 to the resulting negative
 9323# exponent and insert back into the operand.
 9324#
 9325fneg_ext_unfl_ena:
 9326	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 9327	bsr.l		norm			# normalize result
 9328	neg.w		%d0			# new exponent = -(shft val)
 9329	addi.w		&0x6000,%d0		# add new bias to exponent
 9330	mov.w		FP_SCR0_EX(%a6),%d1	# fetch old sign,exp
 9331	andi.w		&0x8000,%d1		# keep old sign
 9332	andi.w		&0x7fff,%d0		# clear sign position
 9333	or.w		%d1,%d0			# concat old sign, new exponent
 9334	mov.w		%d0,FP_SCR0_EX(%a6)	# insert new exponent
 9335	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 9336	rts
 9337
 9338#
 9339# operand is either single or double
 9340#
 9341fneg_not_ext:
 9342	cmpi.b		%d0,&s_mode*0x10	# separate sgl/dbl prec
 9343	bne.b		fneg_dbl
 9344
 9345#
 9346# operand is to be rounded to single precision
 9347#
 9348fneg_sgl:
 9349	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 9350	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9351	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9352	bsr.l		scale_to_zero_src	# calculate scale factor
 9353
 9354	cmpi.l		%d0,&0x3fff-0x3f80	# will move in underflow?
 9355	bge.w		fneg_sd_unfl		# yes; go handle underflow
 9356	cmpi.l		%d0,&0x3fff-0x407e	# will move in overflow?
 9357	beq.w		fneg_sd_may_ovfl	# maybe; go check
 9358	blt.w		fneg_sd_ovfl		# yes; go handle overflow
 9359
 9360#
 9361# operand will NOT overflow or underflow when moved in to the fp reg file
 9362#
 9363fneg_sd_normal:
 9364	fmov.l		&0x0,%fpsr		# clear FPSR
 9365	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9366
 9367	fneg.x		FP_SCR0(%a6),%fp0	# perform negation
 9368
 9369	fmov.l		%fpsr,%d1		# save FPSR
 9370	fmov.l		&0x0,%fpcr		# clear FPCR
 9371
 9372	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 9373
 9374fneg_sd_normal_exit:
 9375	mov.l		%d2,-(%sp)		# save d2
 9376	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 9377	mov.w		FP_SCR0_EX(%a6),%d1	# load sgn,exp
 9378	mov.w		%d1,%d2			# make a copy
 9379	andi.l		&0x7fff,%d1		# strip sign
 9380	sub.l		%d0,%d1			# add scale factor
 9381	andi.w		&0x8000,%d2		# keep old sign
 9382	or.w		%d1,%d2			# concat old sign,new exp
 9383	mov.w		%d2,FP_SCR0_EX(%a6)	# insert new exponent
 9384	mov.l		(%sp)+,%d2		# restore d2
 9385	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
 9386	rts
 9387
 9388#
 9389# operand is to be rounded to double precision
 9390#
 9391fneg_dbl:
 9392	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 9393	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9394	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9395	bsr.l		scale_to_zero_src	# calculate scale factor
 9396
 9397	cmpi.l		%d0,&0x3fff-0x3c00	# will move in underflow?
 9398	bge.b		fneg_sd_unfl		# yes; go handle underflow
 9399	cmpi.l		%d0,&0x3fff-0x43fe	# will move in overflow?
 9400	beq.w		fneg_sd_may_ovfl	# maybe; go check
 9401	blt.w		fneg_sd_ovfl		# yes; go handle overflow
 9402	bra.w		fneg_sd_normal		# no; ho handle normalized op
 9403
 9404#
 9405# operand WILL underflow when moved in to the fp register file
 9406#
 9407fneg_sd_unfl:
 9408	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 9409
 9410	eori.b		&0x80,FP_SCR0_EX(%a6)	# negate sign
 9411	bpl.b		fneg_sd_unfl_tst
 9412	bset		&neg_bit,FPSR_CC(%a6)	# set 'N' ccode bit
 9413
 9414# if underflow or inexact is enabled, go calculate EXOP first.
 9415fneg_sd_unfl_tst:
 9416	mov.b		FPCR_ENABLE(%a6),%d1
 9417	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
 9418	bne.b		fneg_sd_unfl_ena	# yes
 9419
 9420fneg_sd_unfl_dis:
 9421	lea		FP_SCR0(%a6),%a0	# pass: result addr
 9422	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
 9423	bsr.l		unf_res			# calculate default result
 9424	or.b		%d0,FPSR_CC(%a6)	# unf_res may have set 'Z'
 9425	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 9426	rts
 9427
 9428#
 9429# operand will underflow AND underflow is enabled.
 9430# Therefore, we must return the result rounded to extended precision.
 9431#
 9432fneg_sd_unfl_ena:
 9433	mov.l		FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
 9434	mov.l		FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
 9435	mov.w		FP_SCR0_EX(%a6),%d1	# load current exponent
 9436
 9437	mov.l		%d2,-(%sp)		# save d2
 9438	mov.l		%d1,%d2			# make a copy
 9439	andi.l		&0x7fff,%d1		# strip sign
 9440	andi.w		&0x8000,%d2		# keep old sign
 9441	sub.l		%d0,%d1			# subtract scale factor
 9442	addi.l		&0x6000,%d1		# add new bias
 9443	andi.w		&0x7fff,%d1
 9444	or.w		%d2,%d1			# concat new sign,new exp
 9445	mov.w		%d1,FP_SCR1_EX(%a6)	# insert new exp
 9446	fmovm.x		FP_SCR1(%a6),&0x40	# return EXOP in fp1
 9447	mov.l		(%sp)+,%d2		# restore d2
 9448	bra.b		fneg_sd_unfl_dis
 9449
 9450#
 9451# operand WILL overflow.
 9452#
 9453fneg_sd_ovfl:
 9454	fmov.l		&0x0,%fpsr		# clear FPSR
 9455	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9456
 9457	fneg.x		FP_SCR0(%a6),%fp0	# perform negation
 9458
 9459	fmov.l		&0x0,%fpcr		# clear FPCR
 9460	fmov.l		%fpsr,%d1		# save FPSR
 9461
 9462	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 9463
 9464fneg_sd_ovfl_tst:
 9465	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
 9466
 9467	mov.b		FPCR_ENABLE(%a6),%d1
 9468	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
 9469	bne.b		fneg_sd_ovfl_ena	# yes
 9470
 9471#
 9472# OVFL is not enabled; therefore, we must create the default result by
 9473# calling ovf_res().
 9474#
 9475fneg_sd_ovfl_dis:
 9476	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
 9477	sne		%d1			# set sign param accordingly
 9478	mov.l		L_SCR3(%a6),%d0		# pass: prec,mode
 9479	bsr.l		ovf_res			# calculate default result
 9480	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
 9481	fmovm.x		(%a0),&0x80		# return default result in fp0
 9482	rts
 9483
 9484#
 9485# OVFL is enabled.
 9486# the INEX2 bit has already been updated by the round to the correct precision.
 9487# now, round to extended(and don't alter the FPSR).
 9488#
 9489fneg_sd_ovfl_ena:
 9490	mov.l		%d2,-(%sp)		# save d2
 9491	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
 9492	mov.l		%d1,%d2			# make a copy
 9493	andi.l		&0x7fff,%d1		# strip sign
 9494	andi.w		&0x8000,%d2		# keep old sign
 9495	sub.l		%d0,%d1			# add scale factor
 9496	subi.l		&0x6000,%d1		# subtract bias
 9497	andi.w		&0x7fff,%d1
 9498	or.w		%d2,%d1			# concat sign,exp
 9499	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
 9500	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 9501	mov.l		(%sp)+,%d2		# restore d2
 9502	bra.b		fneg_sd_ovfl_dis
 9503
 9504#
 9505# the move in MAY underflow. so...
 9506#
 9507fneg_sd_may_ovfl:
 9508	fmov.l		&0x0,%fpsr		# clear FPSR
 9509	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9510
 9511	fneg.x		FP_SCR0(%a6),%fp0	# perform negation
 9512
 9513	fmov.l		%fpsr,%d1		# save status
 9514	fmov.l		&0x0,%fpcr		# clear FPCR
 9515
 9516	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 9517
 9518	fabs.x		%fp0,%fp1		# make a copy of result
 9519	fcmp.b		%fp1,&0x2		# is |result| >= 2.b?
 9520	fbge.w		fneg_sd_ovfl_tst	# yes; overflow has occurred
 9521
 9522# no, it didn't overflow; we have correct result
 9523	bra.w		fneg_sd_normal_exit
 9524
 9525##########################################################################
 9526
 9527#
 9528# input is not normalized; what is it?
 9529#
 9530fneg_not_norm:
 9531	cmpi.b		%d1,&DENORM		# weed out DENORM
 9532	beq.w		fneg_denorm
 9533	cmpi.b		%d1,&SNAN		# weed out SNAN
 9534	beq.l		res_snan_1op
 9535	cmpi.b		%d1,&QNAN		# weed out QNAN
 9536	beq.l		res_qnan_1op
 9537
 9538#
 9539# do the fneg; at this point, only possible ops are ZERO and INF.
 9540# use fneg to determine ccodes.
 9541# prec:mode should be zero at this point but it won't affect answer anyways.
 9542#
 9543	fneg.x		SRC_EX(%a0),%fp0	# do fneg
 9544	fmov.l		%fpsr,%d0
 9545	rol.l		&0x8,%d0		# put ccodes in lo byte
 9546	mov.b		%d0,FPSR_CC(%a6)	# insert correct ccodes
 9547	rts
 9548
 9549#########################################################################
 9550# XDEF ****************************************************************	#
 9551#	ftst(): emulates the ftest instruction				#
 9552#									#
 9553# XREF ****************************************************************	#
 9554#	res{s,q}nan_1op() - set NAN result for monadic instruction	#
 9555#									#
 9556# INPUT ***************************************************************	#
 9557#	a0 = pointer to extended precision source operand		#
 9558#									#
 9559# OUTPUT **************************************************************	#
 9560#	none								#
 9561#									#
 9562# ALGORITHM ***********************************************************	#
 9563#	Check the source operand tag (STAG) and set the FPCR according	#
 9564# to the operand type and sign.						#
 9565#									#
 9566#########################################################################
 9567
 9568	global		ftst
 9569ftst:
 9570	mov.b		STAG(%a6),%d1
 9571	bne.b		ftst_not_norm		# optimize on non-norm input
 9572
 9573#
 9574# Norm:
 9575#
 9576ftst_norm:
 9577	tst.b		SRC_EX(%a0)		# is operand negative?
 9578	bmi.b		ftst_norm_m		# yes
 9579	rts
 9580ftst_norm_m:
 9581	mov.b		&neg_bmask,FPSR_CC(%a6)	# set 'N' ccode bit
 9582	rts
 9583
 9584#
 9585# input is not normalized; what is it?
 9586#
 9587ftst_not_norm:
 9588	cmpi.b		%d1,&ZERO		# weed out ZERO
 9589	beq.b		ftst_zero
 9590	cmpi.b		%d1,&INF		# weed out INF
 9591	beq.b		ftst_inf
 9592	cmpi.b		%d1,&SNAN		# weed out SNAN
 9593	beq.l		res_snan_1op
 9594	cmpi.b		%d1,&QNAN		# weed out QNAN
 9595	beq.l		res_qnan_1op
 9596
 9597#
 9598# Denorm:
 9599#
 9600ftst_denorm:
 9601	tst.b		SRC_EX(%a0)		# is operand negative?
 9602	bmi.b		ftst_denorm_m		# yes
 9603	rts
 9604ftst_denorm_m:
 9605	mov.b		&neg_bmask,FPSR_CC(%a6)	# set 'N' ccode bit
 9606	rts
 9607
 9608#
 9609# Infinity:
 9610#
 9611ftst_inf:
 9612	tst.b		SRC_EX(%a0)		# is operand negative?
 9613	bmi.b		ftst_inf_m		# yes
 9614ftst_inf_p:
 9615	mov.b		&inf_bmask,FPSR_CC(%a6)	# set 'I' ccode bit
 9616	rts
 9617ftst_inf_m:
 9618	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits
 9619	rts
 9620
 9621#
 9622# Zero:
 9623#
 9624ftst_zero:
 9625	tst.b		SRC_EX(%a0)		# is operand negative?
 9626	bmi.b		ftst_zero_m		# yes
 9627ftst_zero_p:
 9628	mov.b		&z_bmask,FPSR_CC(%a6)	# set 'N' ccode bit
 9629	rts
 9630ftst_zero_m:
 9631	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6)	# set 'Z','N' ccode bits
 9632	rts
 9633
 9634#########################################################################
 9635# XDEF ****************************************************************	#
 9636#	fint(): emulates the fint instruction				#
 9637#									#
 9638# XREF ****************************************************************	#
 9639#	res_{s,q}nan_1op() - set NAN result for monadic operation	#
 9640#									#
 9641# INPUT ***************************************************************	#
 9642#	a0 = pointer to extended precision source operand		#
 9643#	d0 = round precision/mode					#
 9644#									#
 9645# OUTPUT **************************************************************	#
 9646#	fp0 = result							#
 9647#									#
 9648# ALGORITHM ***********************************************************	#
 9649#	Separate according to operand type. Unnorms don't pass through	#
 9650# here. For norms, load the rounding mode/prec, execute a "fint", then	#
 9651# store the resulting FPSR bits.					#
 9652#	For denorms, force the j-bit to a one and do the same as for	#
 9653# norms. Denorms are so low that the answer will either be a zero or a	#
 9654# one.									#
 9655#	For zeroes/infs/NANs, return the same while setting the FPSR	#
 9656# as appropriate.							#
 9657#									#
 9658#########################################################################
 9659
 9660	global		fint
 9661fint:
 9662	mov.b		STAG(%a6),%d1
 9663	bne.b		fint_not_norm		# optimize on non-norm input
 9664
 9665#
 9666# Norm:
 9667#
 9668fint_norm:
 9669	andi.b		&0x30,%d0		# set prec = ext
 9670
 9671	fmov.l		%d0,%fpcr		# set FPCR
 9672	fmov.l		&0x0,%fpsr		# clear FPSR
 9673
 9674	fint.x		SRC(%a0),%fp0		# execute fint
 9675
 9676	fmov.l		&0x0,%fpcr		# clear FPCR
 9677	fmov.l		%fpsr,%d0		# save FPSR
 9678	or.l		%d0,USER_FPSR(%a6)	# set exception bits
 9679
 9680	rts
 9681
 9682#
 9683# input is not normalized; what is it?
 9684#
 9685fint_not_norm:
 9686	cmpi.b		%d1,&ZERO		# weed out ZERO
 9687	beq.b		fint_zero
 9688	cmpi.b		%d1,&INF		# weed out INF
 9689	beq.b		fint_inf
 9690	cmpi.b		%d1,&DENORM		# weed out DENORM
 9691	beq.b		fint_denorm
 9692	cmpi.b		%d1,&SNAN		# weed out SNAN
 9693	beq.l		res_snan_1op
 9694	bra.l		res_qnan_1op		# weed out QNAN
 9695
 9696#
 9697# Denorm:
 9698#
 9699# for DENORMs, the result will be either (+/-)ZERO or (+/-)1.
 9700# also, the INEX2 and AINEX exception bits will be set.
 9701# so, we could either set these manually or force the DENORM
 9702# to a very small NORM and ship it to the NORM routine.
 9703# I do the latter.
 9704#
 9705fint_denorm:
 9706	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
 9707	mov.b		&0x80,FP_SCR0_HI(%a6)	# force DENORM ==> small NORM
 9708	lea		FP_SCR0(%a6),%a0
 9709	bra.b		fint_norm
 9710
 9711#
 9712# Zero:
 9713#
 9714fint_zero:
 9715	tst.b		SRC_EX(%a0)		# is ZERO negative?
 9716	bmi.b		fint_zero_m		# yes
 9717fint_zero_p:
 9718	fmov.s		&0x00000000,%fp0	# return +ZERO in fp0
 9719	mov.b		&z_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
 9720	rts
 9721fint_zero_m:
 9722	fmov.s		&0x80000000,%fp0	# return -ZERO in fp0
 9723	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
 9724	rts
 9725
 9726#
 9727# Infinity:
 9728#
 9729fint_inf:
 9730	fmovm.x		SRC(%a0),&0x80		# return result in fp0
 9731	tst.b		SRC_EX(%a0)		# is INF negative?
 9732	bmi.b		fint_inf_m		# yes
 9733fint_inf_p:
 9734	mov.b		&inf_bmask,FPSR_CC(%a6)	# set 'I' ccode bit
 9735	rts
 9736fint_inf_m:
 9737	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
 9738	rts
 9739
 9740#########################################################################
 9741# XDEF ****************************************************************	#
 9742#	fintrz(): emulates the fintrz instruction			#
 9743#									#
 9744# XREF ****************************************************************	#
 9745#	res_{s,q}nan_1op() - set NAN result for monadic operation	#
 9746#									#
 9747# INPUT ***************************************************************	#
 9748#	a0 = pointer to extended precision source operand		#
 9749#	d0 = round precision/mode					#
 9750#									#
 9751# OUTPUT **************************************************************	#
 9752#	fp0 = result							#
 9753#									#
 9754# ALGORITHM ***********************************************************	#
 9755#	Separate according to operand type. Unnorms don't pass through	#
 9756# here. For norms, load the rounding mode/prec, execute a "fintrz",	#
 9757# then store the resulting FPSR bits.					#
 9758#	For denorms, force the j-bit to a one and do the same as for	#
 9759# norms. Denorms are so low that the answer will either be a zero or a	#
 9760# one.									#
 9761#	For zeroes/infs/NANs, return the same while setting the FPSR	#
 9762# as appropriate.							#
 9763#									#
 9764#########################################################################
 9765
 9766	global		fintrz
 9767fintrz:
 9768	mov.b		STAG(%a6),%d1
 9769	bne.b		fintrz_not_norm		# optimize on non-norm input
 9770
 9771#
 9772# Norm:
 9773#
 9774fintrz_norm:
 9775	fmov.l		&0x0,%fpsr		# clear FPSR
 9776
 9777	fintrz.x	SRC(%a0),%fp0		# execute fintrz
 9778
 9779	fmov.l		%fpsr,%d0		# save FPSR
 9780	or.l		%d0,USER_FPSR(%a6)	# set exception bits
 9781
 9782	rts
 9783
 9784#
 9785# input is not normalized; what is it?
 9786#
 9787fintrz_not_norm:
 9788	cmpi.b		%d1,&ZERO		# weed out ZERO
 9789	beq.b		fintrz_zero
 9790	cmpi.b		%d1,&INF		# weed out INF
 9791	beq.b		fintrz_inf
 9792	cmpi.b		%d1,&DENORM		# weed out DENORM
 9793	beq.b		fintrz_denorm
 9794	cmpi.b		%d1,&SNAN		# weed out SNAN
 9795	beq.l		res_snan_1op
 9796	bra.l		res_qnan_1op		# weed out QNAN
 9797
 9798#
 9799# Denorm:
 9800#
 9801# for DENORMs, the result will be (+/-)ZERO.
 9802# also, the INEX2 and AINEX exception bits will be set.
 9803# so, we could either set these manually or force the DENORM
 9804# to a very small NORM and ship it to the NORM routine.
 9805# I do the latter.
 9806#
 9807fintrz_denorm:
 9808	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
 9809	mov.b		&0x80,FP_SCR0_HI(%a6)	# force DENORM ==> small NORM
 9810	lea		FP_SCR0(%a6),%a0
 9811	bra.b		fintrz_norm
 9812
 9813#
 9814# Zero:
 9815#
 9816fintrz_zero:
 9817	tst.b		SRC_EX(%a0)		# is ZERO negative?
 9818	bmi.b		fintrz_zero_m		# yes
 9819fintrz_zero_p:
 9820	fmov.s		&0x00000000,%fp0	# return +ZERO in fp0
 9821	mov.b		&z_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
 9822	rts
 9823fintrz_zero_m:
 9824	fmov.s		&0x80000000,%fp0	# return -ZERO in fp0
 9825	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
 9826	rts
 9827
 9828#
 9829# Infinity:
 9830#
 9831fintrz_inf:
 9832	fmovm.x		SRC(%a0),&0x80		# return result in fp0
 9833	tst.b		SRC_EX(%a0)		# is INF negative?
 9834	bmi.b		fintrz_inf_m		# yes
 9835fintrz_inf_p:
 9836	mov.b		&inf_bmask,FPSR_CC(%a6)	# set 'I' ccode bit
 9837	rts
 9838fintrz_inf_m:
 9839	mov.b		&inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
 9840	rts
 9841
 9842#########################################################################
 9843# XDEF ****************************************************************	#
 9844#	fabs():  emulates the fabs instruction				#
 9845#	fsabs(): emulates the fsabs instruction				#
 9846#	fdabs(): emulates the fdabs instruction				#
 9847#									#
 9848# XREF **************************************************************** #
 9849#	norm() - normalize denorm mantissa to provide EXOP		#
 9850#	scale_to_zero_src() - make exponent. = 0; get scale factor	#
 9851#	unf_res() - calculate underflow result				#
 9852#	ovf_res() - calculate overflow result				#
 9853#	res_{s,q}nan_1op() - set NAN result for monadic operation	#
 9854#									#
 9855# INPUT *************************************************************** #
 9856#	a0 = pointer to extended precision source operand		#
 9857#	d0 = rnd precision/mode						#
 9858#									#
 9859# OUTPUT ************************************************************** #
 9860#	fp0 = result							#
 9861#	fp1 = EXOP (if exception occurred)				#
 9862#									#
 9863# ALGORITHM ***********************************************************	#
 9864#	Handle NANs, infinities, and zeroes as special cases. Divide	#
 9865# norms into extended, single, and double precision.			#
 9866#	Simply clear sign for extended precision norm. Ext prec denorm	#
 9867# gets an EXOP created for it since it's an underflow.			#
 9868#	Double and single precision can overflow and underflow. First,	#
 9869# scale the operand such that the exponent is zero. Perform an "fabs"	#
 9870# using the correct rnd mode/prec. Check to see if the original		#
 9871# exponent would take an exception. If so, use unf_res() or ovf_res()	#
 9872# to calculate the default result. Also, create the EXOP for the	#
 9873# exceptional case. If no exception should occur, insert the correct	#
 9874# result exponent and return.						#
 9875#	Unnorms don't pass through here.				#
 9876#									#
 9877#########################################################################
 9878
 9879	global		fsabs
 9880fsabs:
 9881	andi.b		&0x30,%d0		# clear rnd prec
 9882	ori.b		&s_mode*0x10,%d0	# insert sgl precision
 9883	bra.b		fabs
 9884
 9885	global		fdabs
 9886fdabs:
 9887	andi.b		&0x30,%d0		# clear rnd prec
 9888	ori.b		&d_mode*0x10,%d0	# insert dbl precision
 9889
 9890	global		fabs
 9891fabs:
 9892	mov.l		%d0,L_SCR3(%a6)		# store rnd info
 9893	mov.b		STAG(%a6),%d1
 9894	bne.w		fabs_not_norm		# optimize on non-norm input
 9895
 9896#
 9897# ABSOLUTE VALUE: norms and denorms ONLY!
 9898#
 9899fabs_norm:
 9900	andi.b		&0xc0,%d0		# is precision extended?
 9901	bne.b		fabs_not_ext		# no; go handle sgl or dbl
 9902
 9903#
 9904# precision selected is extended. so...we can not get an underflow
 9905# or overflow because of rounding to the correct precision. so...
 9906# skip the scaling and unscaling...
 9907#
 9908	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9909	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9910	mov.w		SRC_EX(%a0),%d1
 9911	bclr		&15,%d1			# force absolute value
 9912	mov.w		%d1,FP_SCR0_EX(%a6)	# insert exponent
 9913	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
 9914	rts
 9915
 9916#
 9917# for an extended precision DENORM, the UNFL exception bit is set
 9918# the accrued bit is NOT set in this instance(no inexactness!)
 9919#
 9920fabs_denorm:
 9921	andi.b		&0xc0,%d0		# is precision extended?
 9922	bne.b		fabs_not_ext		# no
 9923
 9924	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
 9925
 9926	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9927	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9928	mov.w		SRC_EX(%a0),%d0
 9929	bclr		&15,%d0			# clear sign
 9930	mov.w		%d0,FP_SCR0_EX(%a6)	# insert exponent
 9931
 9932	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
 9933
 9934	btst		&unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
 9935	bne.b		fabs_ext_unfl_ena
 9936	rts
 9937
 9938#
 9939# the input is an extended DENORM and underflow is enabled in the FPCR.
 9940# normalize the mantissa and add the bias of 0x6000 to the resulting negative
 9941# exponent and insert back into the operand.
 9942#
 9943fabs_ext_unfl_ena:
 9944	lea		FP_SCR0(%a6),%a0	# pass: ptr to operand
 9945	bsr.l		norm			# normalize result
 9946	neg.w		%d0			# new exponent = -(shft val)
 9947	addi.w		&0x6000,%d0		# add new bias to exponent
 9948	mov.w		FP_SCR0_EX(%a6),%d1	# fetch old sign,exp
 9949	andi.w		&0x8000,%d1		# keep old sign
 9950	andi.w		&0x7fff,%d0		# clear sign position
 9951	or.w		%d1,%d0			# concat old sign, new exponent
 9952	mov.w		%d0,FP_SCR0_EX(%a6)	# insert new exponent
 9953	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
 9954	rts
 9955
 9956#
 9957# operand is either single or double
 9958#
 9959fabs_not_ext:
 9960	cmpi.b		%d0,&s_mode*0x10	# separate sgl/dbl prec
 9961	bne.b		fabs_dbl
 9962
 9963#
 9964# operand is to be rounded to single precision
 9965#
 9966fabs_sgl:
 9967	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
 9968	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
 9969	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
 9970	bsr.l		scale_to_zero_src	# calculate scale factor
 9971
 9972	cmpi.l		%d0,&0x3fff-0x3f80	# will move in underflow?
 9973	bge.w		fabs_sd_unfl		# yes; go handle underflow
 9974	cmpi.l		%d0,&0x3fff-0x407e	# will move in overflow?
 9975	beq.w		fabs_sd_may_ovfl	# maybe; go check
 9976	blt.w		fabs_sd_ovfl		# yes; go handle overflow
 9977
 9978#
 9979# operand will NOT overflow or underflow when moved in to the fp reg file
 9980#
 9981fabs_sd_normal:
 9982	fmov.l		&0x0,%fpsr		# clear FPSR
 9983	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
 9984
 9985	fabs.x		FP_SCR0(%a6),%fp0	# perform absolute
 9986
 9987	fmov.l		%fpsr,%d1		# save FPSR
 9988	fmov.l		&0x0,%fpcr		# clear FPCR
 9989
 9990	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
 9991
 9992fabs_sd_normal_exit:
 9993	mov.l		%d2,-(%sp)		# save d2
 9994	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
 9995	mov.w		FP_SCR0_EX(%a6),%d1	# load sgn,exp
 9996	mov.l		%d1,%d2			# make a copy
 9997	andi.l		&0x7fff,%d1		# strip sign
 9998	sub.l		%d0,%d1			# add scale factor
 9999	andi.w		&0x8000,%d2		# keep old sign
10000	or.w		%d1,%d2			# concat old sign,new exp
10001	mov.w		%d2,FP_SCR0_EX(%a6)	# insert new exponent
10002	mov.l		(%sp)+,%d2		# restore d2
10003	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
10004	rts
10005
10006#
10007# operand is to be rounded to double precision
10008#
10009fabs_dbl:
10010	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
10011	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
10012	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
10013	bsr.l		scale_to_zero_src	# calculate scale factor
10014
10015	cmpi.l		%d0,&0x3fff-0x3c00	# will move in underflow?
10016	bge.b		fabs_sd_unfl		# yes; go handle underflow
10017	cmpi.l		%d0,&0x3fff-0x43fe	# will move in overflow?
10018	beq.w		fabs_sd_may_ovfl	# maybe; go check
10019	blt.w		fabs_sd_ovfl		# yes; go handle overflow
10020	bra.w		fabs_sd_normal		# no; ho handle normalized op
10021
10022#
10023# operand WILL underflow when moved in to the fp register file
10024#
10025fabs_sd_unfl:
10026	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10027
10028	bclr		&0x7,FP_SCR0_EX(%a6)	# force absolute value
10029
10030# if underflow or inexact is enabled, go calculate EXOP first.
10031	mov.b		FPCR_ENABLE(%a6),%d1
10032	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
10033	bne.b		fabs_sd_unfl_ena	# yes
10034
10035fabs_sd_unfl_dis:
10036	lea		FP_SCR0(%a6),%a0	# pass: result addr
10037	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
10038	bsr.l		unf_res			# calculate default result
10039	or.b		%d0,FPSR_CC(%a6)	# set possible 'Z' ccode
10040	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
10041	rts
10042
10043#
10044# operand will underflow AND underflow is enabled.
10045# Therefore, we must return the result rounded to extended precision.
10046#
10047fabs_sd_unfl_ena:
10048	mov.l		FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
10049	mov.l		FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
10050	mov.w		FP_SCR0_EX(%a6),%d1	# load current exponent
10051
10052	mov.l		%d2,-(%sp)		# save d2
10053	mov.l		%d1,%d2			# make a copy
10054	andi.l		&0x7fff,%d1		# strip sign
10055	andi.w		&0x8000,%d2		# keep old sign
10056	sub.l		%d0,%d1			# subtract scale factor
10057	addi.l		&0x6000,%d1		# add new bias
10058	andi.w		&0x7fff,%d1
10059	or.w		%d2,%d1			# concat new sign,new exp
10060	mov.w		%d1,FP_SCR1_EX(%a6)	# insert new exp
10061	fmovm.x		FP_SCR1(%a6),&0x40	# return EXOP in fp1
10062	mov.l		(%sp)+,%d2		# restore d2
10063	bra.b		fabs_sd_unfl_dis
10064
10065#
10066# operand WILL overflow.
10067#
10068fabs_sd_ovfl:
10069	fmov.l		&0x0,%fpsr		# clear FPSR
10070	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10071
10072	fabs.x		FP_SCR0(%a6),%fp0	# perform absolute
10073
10074	fmov.l		&0x0,%fpcr		# clear FPCR
10075	fmov.l		%fpsr,%d1		# save FPSR
10076
10077	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10078
10079fabs_sd_ovfl_tst:
10080	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
10081
10082	mov.b		FPCR_ENABLE(%a6),%d1
10083	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
10084	bne.b		fabs_sd_ovfl_ena	# yes
10085
10086#
10087# OVFL is not enabled; therefore, we must create the default result by
10088# calling ovf_res().
10089#
10090fabs_sd_ovfl_dis:
10091	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
10092	sne		%d1			# set sign param accordingly
10093	mov.l		L_SCR3(%a6),%d0		# pass: prec,mode
10094	bsr.l		ovf_res			# calculate default result
10095	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
10096	fmovm.x		(%a0),&0x80		# return default result in fp0
10097	rts
10098
10099#
10100# OVFL is enabled.
10101# the INEX2 bit has already been updated by the round to the correct precision.
10102# now, round to extended(and don't alter the FPSR).
10103#
10104fabs_sd_ovfl_ena:
10105	mov.l		%d2,-(%sp)		# save d2
10106	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
10107	mov.l		%d1,%d2			# make a copy
10108	andi.l		&0x7fff,%d1		# strip sign
10109	andi.w		&0x8000,%d2		# keep old sign
10110	sub.l		%d0,%d1			# add scale factor
10111	subi.l		&0x6000,%d1		# subtract bias
10112	andi.w		&0x7fff,%d1
10113	or.w		%d2,%d1			# concat sign,exp
10114	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10115	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
10116	mov.l		(%sp)+,%d2		# restore d2
10117	bra.b		fabs_sd_ovfl_dis
10118
10119#
10120# the move in MAY underflow. so...
10121#
10122fabs_sd_may_ovfl:
10123	fmov.l		&0x0,%fpsr		# clear FPSR
10124	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10125
10126	fabs.x		FP_SCR0(%a6),%fp0	# perform absolute
10127
10128	fmov.l		%fpsr,%d1		# save status
10129	fmov.l		&0x0,%fpcr		# clear FPCR
10130
10131	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10132
10133	fabs.x		%fp0,%fp1		# make a copy of result
10134	fcmp.b		%fp1,&0x2		# is |result| >= 2.b?
10135	fbge.w		fabs_sd_ovfl_tst	# yes; overflow has occurred
10136
10137# no, it didn't overflow; we have correct result
10138	bra.w		fabs_sd_normal_exit
10139
10140##########################################################################
10141
10142#
10143# input is not normalized; what is it?
10144#
10145fabs_not_norm:
10146	cmpi.b		%d1,&DENORM		# weed out DENORM
10147	beq.w		fabs_denorm
10148	cmpi.b		%d1,&SNAN		# weed out SNAN
10149	beq.l		res_snan_1op
10150	cmpi.b		%d1,&QNAN		# weed out QNAN
10151	beq.l		res_qnan_1op
10152
10153	fabs.x		SRC(%a0),%fp0		# force absolute value
10154
10155	cmpi.b		%d1,&INF		# weed out INF
10156	beq.b		fabs_inf
10157fabs_zero:
10158	mov.b		&z_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
10159	rts
10160fabs_inf:
10161	mov.b		&inf_bmask,FPSR_CC(%a6)	# set 'I' ccode bit
10162	rts
10163
10164#########################################################################
10165# XDEF ****************************************************************	#
10166#	fcmp(): fp compare op routine					#
10167#									#
10168# XREF ****************************************************************	#
10169#	res_qnan() - return QNAN result					#
10170#	res_snan() - return SNAN result					#
10171#									#
10172# INPUT ***************************************************************	#
10173#	a0 = pointer to extended precision source operand		#
10174#	a1 = pointer to extended precision destination operand		#
10175#	d0 = round prec/mode						#
10176#									#
10177# OUTPUT ************************************************************** #
10178#	None								#
10179#									#
10180# ALGORITHM ***********************************************************	#
10181#	Handle NANs and denorms as special cases. For everything else,	#
10182# just use the actual fcmp instruction to produce the correct condition	#
10183# codes.								#
10184#									#
10185#########################################################################
10186
10187	global		fcmp
10188fcmp:
10189	clr.w		%d1
10190	mov.b		DTAG(%a6),%d1
10191	lsl.b		&0x3,%d1
10192	or.b		STAG(%a6),%d1
10193	bne.b		fcmp_not_norm		# optimize on non-norm input
10194
10195#
10196# COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs
10197#
10198fcmp_norm:
10199	fmovm.x		DST(%a1),&0x80		# load dst op
10200
10201	fcmp.x		%fp0,SRC(%a0)		# do compare
10202
10203	fmov.l		%fpsr,%d0		# save FPSR
10204	rol.l		&0x8,%d0		# extract ccode bits
10205	mov.b		%d0,FPSR_CC(%a6)	# set ccode bits(no exc bits are set)
10206
10207	rts
10208
10209#
10210# fcmp: inputs are not both normalized; what are they?
10211#
10212fcmp_not_norm:
10213	mov.w		(tbl_fcmp_op.b,%pc,%d1.w*2),%d1
10214	jmp		(tbl_fcmp_op.b,%pc,%d1.w*1)
10215
10216	swbeg		&48
10217tbl_fcmp_op:
10218	short		fcmp_norm	- tbl_fcmp_op # NORM - NORM
10219	short		fcmp_norm	- tbl_fcmp_op # NORM - ZERO
10220	short		fcmp_norm	- tbl_fcmp_op # NORM - INF
10221	short		fcmp_res_qnan	- tbl_fcmp_op # NORM - QNAN
10222	short		fcmp_nrm_dnrm	- tbl_fcmp_op # NORM - DENORM
10223	short		fcmp_res_snan	- tbl_fcmp_op # NORM - SNAN
10224	short		tbl_fcmp_op	- tbl_fcmp_op #
10225	short		tbl_fcmp_op	- tbl_fcmp_op #
10226
10227	short		fcmp_norm	- tbl_fcmp_op # ZERO - NORM
10228	short		fcmp_norm	- tbl_fcmp_op # ZERO - ZERO
10229	short		fcmp_norm	- tbl_fcmp_op # ZERO - INF
10230	short		fcmp_res_qnan	- tbl_fcmp_op # ZERO - QNAN
10231	short		fcmp_dnrm_s	- tbl_fcmp_op # ZERO - DENORM
10232	short		fcmp_res_snan	- tbl_fcmp_op # ZERO - SNAN
10233	short		tbl_fcmp_op	- tbl_fcmp_op #
10234	short		tbl_fcmp_op	- tbl_fcmp_op #
10235
10236	short		fcmp_norm	- tbl_fcmp_op # INF - NORM
10237	short		fcmp_norm	- tbl_fcmp_op # INF - ZERO
10238	short		fcmp_norm	- tbl_fcmp_op # INF - INF
10239	short		fcmp_res_qnan	- tbl_fcmp_op # INF - QNAN
10240	short		fcmp_dnrm_s	- tbl_fcmp_op # INF - DENORM
10241	short		fcmp_res_snan	- tbl_fcmp_op # INF - SNAN
10242	short		tbl_fcmp_op	- tbl_fcmp_op #
10243	short		tbl_fcmp_op	- tbl_fcmp_op #
10244
10245	short		fcmp_res_qnan	- tbl_fcmp_op # QNAN - NORM
10246	short		fcmp_res_qnan	- tbl_fcmp_op # QNAN - ZERO
10247	short		fcmp_res_qnan	- tbl_fcmp_op # QNAN - INF
10248	short		fcmp_res_qnan	- tbl_fcmp_op # QNAN - QNAN
10249	short		fcmp_res_qnan	- tbl_fcmp_op # QNAN - DENORM
10250	short		fcmp_res_snan	- tbl_fcmp_op # QNAN - SNAN
10251	short		tbl_fcmp_op	- tbl_fcmp_op #
10252	short		tbl_fcmp_op	- tbl_fcmp_op #
10253
10254	short		fcmp_dnrm_nrm	- tbl_fcmp_op # DENORM - NORM
10255	short		fcmp_dnrm_d	- tbl_fcmp_op # DENORM - ZERO
10256	short		fcmp_dnrm_d	- tbl_fcmp_op # DENORM - INF
10257	short		fcmp_res_qnan	- tbl_fcmp_op # DENORM - QNAN
10258	short		fcmp_dnrm_sd	- tbl_fcmp_op # DENORM - DENORM
10259	short		fcmp_res_snan	- tbl_fcmp_op # DENORM - SNAN
10260	short		tbl_fcmp_op	- tbl_fcmp_op #
10261	short		tbl_fcmp_op	- tbl_fcmp_op #
10262
10263	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - NORM
10264	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - ZERO
10265	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - INF
10266	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - QNAN
10267	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - DENORM
10268	short		fcmp_res_snan	- tbl_fcmp_op # SNAN - SNAN
10269	short		tbl_fcmp_op	- tbl_fcmp_op #
10270	short		tbl_fcmp_op	- tbl_fcmp_op #
10271
10272# unlike all other functions for QNAN and SNAN, fcmp does NOT set the
10273# 'N' bit for a negative QNAN or SNAN input so we must squelch it here.
10274fcmp_res_qnan:
10275	bsr.l		res_qnan
10276	andi.b		&0xf7,FPSR_CC(%a6)
10277	rts
10278fcmp_res_snan:
10279	bsr.l		res_snan
10280	andi.b		&0xf7,FPSR_CC(%a6)
10281	rts
10282
10283#
10284# DENORMs are a little more difficult.
10285# If you have a 2 DENORMs, then you can just force the j-bit to a one
10286# and use the fcmp_norm routine.
10287# If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one
10288# and use the fcmp_norm routine.
10289# If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also.
10290# But with a DENORM and a NORM of the same sign, the neg bit is set if the
10291# (1) signs are (+) and the DENORM is the dst or
10292# (2) signs are (-) and the DENORM is the src
10293#
10294
10295fcmp_dnrm_s:
10296	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
10297	mov.l		SRC_HI(%a0),%d0
10298	bset		&31,%d0			# DENORM src; make into small norm
10299	mov.l		%d0,FP_SCR0_HI(%a6)
10300	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
10301	lea		FP_SCR0(%a6),%a0
10302	bra.w		fcmp_norm
10303
10304fcmp_dnrm_d:
10305	mov.l		DST_EX(%a1),FP_SCR0_EX(%a6)
10306	mov.l		DST_HI(%a1),%d0
10307	bset		&31,%d0			# DENORM src; make into small norm
10308	mov.l		%d0,FP_SCR0_HI(%a6)
10309	mov.l		DST_LO(%a1),FP_SCR0_LO(%a6)
10310	lea		FP_SCR0(%a6),%a1
10311	bra.w		fcmp_norm
10312
10313fcmp_dnrm_sd:
10314	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
10315	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
10316	mov.l		DST_HI(%a1),%d0
10317	bset		&31,%d0			# DENORM dst; make into small norm
10318	mov.l		%d0,FP_SCR1_HI(%a6)
10319	mov.l		SRC_HI(%a0),%d0
10320	bset		&31,%d0			# DENORM dst; make into small norm
10321	mov.l		%d0,FP_SCR0_HI(%a6)
10322	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
10323	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
10324	lea		FP_SCR1(%a6),%a1
10325	lea		FP_SCR0(%a6),%a0
10326	bra.w		fcmp_norm
10327
10328fcmp_nrm_dnrm:
10329	mov.b		SRC_EX(%a0),%d0		# determine if like signs
10330	mov.b		DST_EX(%a1),%d1
10331	eor.b		%d0,%d1
10332	bmi.w		fcmp_dnrm_s
10333
10334# signs are the same, so must determine the answer ourselves.
10335	tst.b		%d0			# is src op negative?
10336	bmi.b		fcmp_nrm_dnrm_m		# yes
10337	rts
10338fcmp_nrm_dnrm_m:
10339	mov.b		&neg_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
10340	rts
10341
10342fcmp_dnrm_nrm:
10343	mov.b		SRC_EX(%a0),%d0		# determine if like signs
10344	mov.b		DST_EX(%a1),%d1
10345	eor.b		%d0,%d1
10346	bmi.w		fcmp_dnrm_d
10347
10348# signs are the same, so must determine the answer ourselves.
10349	tst.b		%d0			# is src op negative?
10350	bpl.b		fcmp_dnrm_nrm_m		# no
10351	rts
10352fcmp_dnrm_nrm_m:
10353	mov.b		&neg_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
10354	rts
10355
10356#########################################################################
10357# XDEF ****************************************************************	#
10358#	fsglmul(): emulates the fsglmul instruction			#
10359#									#
10360# XREF ****************************************************************	#
10361#	scale_to_zero_src() - scale src exponent to zero		#
10362#	scale_to_zero_dst() - scale dst exponent to zero		#
10363#	unf_res4() - return default underflow result for sglop		#
10364#	ovf_res() - return default overflow result			#
10365#	res_qnan() - return QNAN result					#
10366#	res_snan() - return SNAN result					#
10367#									#
10368# INPUT ***************************************************************	#
10369#	a0 = pointer to extended precision source operand		#
10370#	a1 = pointer to extended precision destination operand		#
10371#	d0  rnd prec,mode						#
10372#									#
10373# OUTPUT **************************************************************	#
10374#	fp0 = result							#
10375#	fp1 = EXOP (if exception occurred)				#
10376#									#
10377# ALGORITHM ***********************************************************	#
10378#	Handle NANs, infinities, and zeroes as special cases. Divide	#
10379# norms/denorms into ext/sgl/dbl precision.				#
10380#	For norms/denorms, scale the exponents such that a multiply	#
10381# instruction won't cause an exception. Use the regular fsglmul to	#
10382# compute a result. Check if the regular operands would have taken	#
10383# an exception. If so, return the default overflow/underflow result	#
10384# and return the EXOP if exceptions are enabled. Else, scale the	#
10385# result operand to the proper exponent.				#
10386#									#
10387#########################################################################
10388
10389	global		fsglmul
10390fsglmul:
10391	mov.l		%d0,L_SCR3(%a6)		# store rnd info
10392
10393	clr.w		%d1
10394	mov.b		DTAG(%a6),%d1
10395	lsl.b		&0x3,%d1
10396	or.b		STAG(%a6),%d1
10397
10398	bne.w		fsglmul_not_norm	# optimize on non-norm input
10399
10400fsglmul_norm:
10401	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
10402	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
10403	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
10404
10405	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
10406	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
10407	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
10408
10409	bsr.l		scale_to_zero_src	# scale exponent
10410	mov.l		%d0,-(%sp)		# save scale factor 1
10411
10412	bsr.l		scale_to_zero_dst	# scale dst exponent
10413
10414	add.l		(%sp)+,%d0		# SCALE_FACTOR = scale1 + scale2
10415
10416	cmpi.l		%d0,&0x3fff-0x7ffe	# would result ovfl?
10417	beq.w		fsglmul_may_ovfl	# result may rnd to overflow
10418	blt.w		fsglmul_ovfl		# result will overflow
10419
10420	cmpi.l		%d0,&0x3fff+0x0001	# would result unfl?
10421	beq.w		fsglmul_may_unfl	# result may rnd to no unfl
10422	bgt.w		fsglmul_unfl		# result will underflow
10423
10424fsglmul_normal:
10425	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10426
10427	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10428	fmov.l		&0x0,%fpsr		# clear FPSR
10429
10430	fsglmul.x	FP_SCR0(%a6),%fp0	# execute sgl multiply
10431
10432	fmov.l		%fpsr,%d1		# save status
10433	fmov.l		&0x0,%fpcr		# clear FPCR
10434
10435	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10436
10437fsglmul_normal_exit:
10438	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
10439	mov.l		%d2,-(%sp)		# save d2
10440	mov.w		FP_SCR0_EX(%a6),%d1	# load {sgn,exp}
10441	mov.l		%d1,%d2			# make a copy
10442	andi.l		&0x7fff,%d1		# strip sign
10443	andi.w		&0x8000,%d2		# keep old sign
10444	sub.l		%d0,%d1			# add scale factor
10445	or.w		%d2,%d1			# concat old sign,new exp
10446	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10447	mov.l		(%sp)+,%d2		# restore d2
10448	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
10449	rts
10450
10451fsglmul_ovfl:
10452	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10453
10454	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10455	fmov.l		&0x0,%fpsr		# clear FPSR
10456
10457	fsglmul.x	FP_SCR0(%a6),%fp0	# execute sgl multiply
10458
10459	fmov.l		%fpsr,%d1		# save status
10460	fmov.l		&0x0,%fpcr		# clear FPCR
10461
10462	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10463
10464fsglmul_ovfl_tst:
10465
10466# save setting this until now because this is where fsglmul_may_ovfl may jump in
10467	or.l		&ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex
10468
10469	mov.b		FPCR_ENABLE(%a6),%d1
10470	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
10471	bne.b		fsglmul_ovfl_ena	# yes
10472
10473fsglmul_ovfl_dis:
10474	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
10475	sne		%d1			# set sign param accordingly
10476	mov.l		L_SCR3(%a6),%d0		# pass prec:rnd
10477	andi.b		&0x30,%d0		# force prec = ext
10478	bsr.l		ovf_res			# calculate default result
10479	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
10480	fmovm.x		(%a0),&0x80		# return default result in fp0
10481	rts
10482
10483fsglmul_ovfl_ena:
10484	fmovm.x		&0x80,FP_SCR0(%a6)	# move result to stack
10485
10486	mov.l		%d2,-(%sp)		# save d2
10487	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
10488	mov.l		%d1,%d2			# make a copy
10489	andi.l		&0x7fff,%d1		# strip sign
10490	sub.l		%d0,%d1			# add scale factor
10491	subi.l		&0x6000,%d1		# subtract bias
10492	andi.w		&0x7fff,%d1
10493	andi.w		&0x8000,%d2		# keep old sign
10494	or.w		%d2,%d1			# concat old sign,new exp
10495	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10496	mov.l		(%sp)+,%d2		# restore d2
10497	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
10498	bra.b		fsglmul_ovfl_dis
10499
10500fsglmul_may_ovfl:
10501	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10502
10503	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10504	fmov.l		&0x0,%fpsr		# clear FPSR
10505
10506	fsglmul.x	FP_SCR0(%a6),%fp0	# execute sgl multiply
10507
10508	fmov.l		%fpsr,%d1		# save status
10509	fmov.l		&0x0,%fpcr		# clear FPCR
10510
10511	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10512
10513	fabs.x		%fp0,%fp1		# make a copy of result
10514	fcmp.b		%fp1,&0x2		# is |result| >= 2.b?
10515	fbge.w		fsglmul_ovfl_tst	# yes; overflow has occurred
10516
10517# no, it didn't overflow; we have correct result
10518	bra.w		fsglmul_normal_exit
10519
10520fsglmul_unfl:
10521	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10522
10523	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10524
10525	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
10526	fmov.l		&0x0,%fpsr		# clear FPSR
10527
10528	fsglmul.x	FP_SCR0(%a6),%fp0	# execute sgl multiply
10529
10530	fmov.l		%fpsr,%d1		# save status
10531	fmov.l		&0x0,%fpcr		# clear FPCR
10532
10533	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10534
10535	mov.b		FPCR_ENABLE(%a6),%d1
10536	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
10537	bne.b		fsglmul_unfl_ena	# yes
10538
10539fsglmul_unfl_dis:
10540	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
10541
10542	lea		FP_SCR0(%a6),%a0	# pass: result addr
10543	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
10544	bsr.l		unf_res4		# calculate default result
10545	or.b		%d0,FPSR_CC(%a6)	# 'Z' bit may have been set
10546	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
10547	rts
10548
10549#
10550# UNFL is enabled.
10551#
10552fsglmul_unfl_ena:
10553	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op
10554
10555	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10556	fmov.l		&0x0,%fpsr		# clear FPSR
10557
10558	fsglmul.x	FP_SCR0(%a6),%fp1	# execute sgl multiply
10559
10560	fmov.l		&0x0,%fpcr		# clear FPCR
10561
10562	fmovm.x		&0x40,FP_SCR0(%a6)	# save result to stack
10563	mov.l		%d2,-(%sp)		# save d2
10564	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
10565	mov.l		%d1,%d2			# make a copy
10566	andi.l		&0x7fff,%d1		# strip sign
10567	andi.w		&0x8000,%d2		# keep old sign
10568	sub.l		%d0,%d1			# add scale factor
10569	addi.l		&0x6000,%d1		# add bias
10570	andi.w		&0x7fff,%d1
10571	or.w		%d2,%d1			# concat old sign,new exp
10572	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10573	mov.l		(%sp)+,%d2		# restore d2
10574	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
10575	bra.w		fsglmul_unfl_dis
10576
10577fsglmul_may_unfl:
10578	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10579
10580	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10581	fmov.l		&0x0,%fpsr		# clear FPSR
10582
10583	fsglmul.x	FP_SCR0(%a6),%fp0	# execute sgl multiply
10584
10585	fmov.l		%fpsr,%d1		# save status
10586	fmov.l		&0x0,%fpcr		# clear FPCR
10587
10588	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10589
10590	fabs.x		%fp0,%fp1		# make a copy of result
10591	fcmp.b		%fp1,&0x2		# is |result| > 2.b?
10592	fbgt.w		fsglmul_normal_exit	# no; no underflow occurred
10593	fblt.w		fsglmul_unfl		# yes; underflow occurred
10594
10595#
10596# we still don't know if underflow occurred. result is ~ equal to 2. but,
10597# we don't know if the result was an underflow that rounded up to a 2 or
10598# a normalized number that rounded down to a 2. so, redo the entire operation
10599# using RZ as the rounding mode to see what the pre-rounded result is.
10600# this case should be relatively rare.
10601#
10602	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op into fp1
10603
10604	mov.l		L_SCR3(%a6),%d1
10605	andi.b		&0xc0,%d1		# keep rnd prec
10606	ori.b		&rz_mode*0x10,%d1	# insert RZ
10607
10608	fmov.l		%d1,%fpcr		# set FPCR
10609	fmov.l		&0x0,%fpsr		# clear FPSR
10610
10611	fsglmul.x	FP_SCR0(%a6),%fp1	# execute sgl multiply
10612
10613	fmov.l		&0x0,%fpcr		# clear FPCR
10614	fabs.x		%fp1			# make absolute value
10615	fcmp.b		%fp1,&0x2		# is |result| < 2.b?
10616	fbge.w		fsglmul_normal_exit	# no; no underflow occurred
10617	bra.w		fsglmul_unfl		# yes, underflow occurred
10618
10619##############################################################################
10620
10621#
10622# Single Precision Multiply: inputs are not both normalized; what are they?
10623#
10624fsglmul_not_norm:
10625	mov.w		(tbl_fsglmul_op.b,%pc,%d1.w*2),%d1
10626	jmp		(tbl_fsglmul_op.b,%pc,%d1.w*1)
10627
10628	swbeg		&48
10629tbl_fsglmul_op:
10630	short		fsglmul_norm		- tbl_fsglmul_op # NORM x NORM
10631	short		fsglmul_zero		- tbl_fsglmul_op # NORM x ZERO
10632	short		fsglmul_inf_src		- tbl_fsglmul_op # NORM x INF
10633	short		fsglmul_res_qnan	- tbl_fsglmul_op # NORM x QNAN
10634	short		fsglmul_norm		- tbl_fsglmul_op # NORM x DENORM
10635	short		fsglmul_res_snan	- tbl_fsglmul_op # NORM x SNAN
10636	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10637	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10638
10639	short		fsglmul_zero		- tbl_fsglmul_op # ZERO x NORM
10640	short		fsglmul_zero		- tbl_fsglmul_op # ZERO x ZERO
10641	short		fsglmul_res_operr	- tbl_fsglmul_op # ZERO x INF
10642	short		fsglmul_res_qnan	- tbl_fsglmul_op # ZERO x QNAN
10643	short		fsglmul_zero		- tbl_fsglmul_op # ZERO x DENORM
10644	short		fsglmul_res_snan	- tbl_fsglmul_op # ZERO x SNAN
10645	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10646	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10647
10648	short		fsglmul_inf_dst		- tbl_fsglmul_op # INF x NORM
10649	short		fsglmul_res_operr	- tbl_fsglmul_op # INF x ZERO
10650	short		fsglmul_inf_dst		- tbl_fsglmul_op # INF x INF
10651	short		fsglmul_res_qnan	- tbl_fsglmul_op # INF x QNAN
10652	short		fsglmul_inf_dst		- tbl_fsglmul_op # INF x DENORM
10653	short		fsglmul_res_snan	- tbl_fsglmul_op # INF x SNAN
10654	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10655	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10656
10657	short		fsglmul_res_qnan	- tbl_fsglmul_op # QNAN x NORM
10658	short		fsglmul_res_qnan	- tbl_fsglmul_op # QNAN x ZERO
10659	short		fsglmul_res_qnan	- tbl_fsglmul_op # QNAN x INF
10660	short		fsglmul_res_qnan	- tbl_fsglmul_op # QNAN x QNAN
10661	short		fsglmul_res_qnan	- tbl_fsglmul_op # QNAN x DENORM
10662	short		fsglmul_res_snan	- tbl_fsglmul_op # QNAN x SNAN
10663	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10664	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10665
10666	short		fsglmul_norm		- tbl_fsglmul_op # NORM x NORM
10667	short		fsglmul_zero		- tbl_fsglmul_op # NORM x ZERO
10668	short		fsglmul_inf_src		- tbl_fsglmul_op # NORM x INF
10669	short		fsglmul_res_qnan	- tbl_fsglmul_op # NORM x QNAN
10670	short		fsglmul_norm		- tbl_fsglmul_op # NORM x DENORM
10671	short		fsglmul_res_snan	- tbl_fsglmul_op # NORM x SNAN
10672	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10673	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10674
10675	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x NORM
10676	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x ZERO
10677	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x INF
10678	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x QNAN
10679	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x DENORM
10680	short		fsglmul_res_snan	- tbl_fsglmul_op # SNAN x SNAN
10681	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10682	short		tbl_fsglmul_op		- tbl_fsglmul_op #
10683
10684fsglmul_res_operr:
10685	bra.l		res_operr
10686fsglmul_res_snan:
10687	bra.l		res_snan
10688fsglmul_res_qnan:
10689	bra.l		res_qnan
10690fsglmul_zero:
10691	bra.l		fmul_zero
10692fsglmul_inf_src:
10693	bra.l		fmul_inf_src
10694fsglmul_inf_dst:
10695	bra.l		fmul_inf_dst
10696
10697#########################################################################
10698# XDEF ****************************************************************	#
10699#	fsgldiv(): emulates the fsgldiv instruction			#
10700#									#
10701# XREF ****************************************************************	#
10702#	scale_to_zero_src() - scale src exponent to zero		#
10703#	scale_to_zero_dst() - scale dst exponent to zero		#
10704#	unf_res4() - return default underflow result for sglop		#
10705#	ovf_res() - return default overflow result			#
10706#	res_qnan() - return QNAN result					#
10707#	res_snan() - return SNAN result					#
10708#									#
10709# INPUT ***************************************************************	#
10710#	a0 = pointer to extended precision source operand		#
10711#	a1 = pointer to extended precision destination operand		#
10712#	d0  rnd prec,mode						#
10713#									#
10714# OUTPUT **************************************************************	#
10715#	fp0 = result							#
10716#	fp1 = EXOP (if exception occurred)				#
10717#									#
10718# ALGORITHM ***********************************************************	#
10719#	Handle NANs, infinities, and zeroes as special cases. Divide	#
10720# norms/denorms into ext/sgl/dbl precision.				#
10721#	For norms/denorms, scale the exponents such that a divide	#
10722# instruction won't cause an exception. Use the regular fsgldiv to	#
10723# compute a result. Check if the regular operands would have taken	#
10724# an exception. If so, return the default overflow/underflow result	#
10725# and return the EXOP if exceptions are enabled. Else, scale the	#
10726# result operand to the proper exponent.				#
10727#									#
10728#########################################################################
10729
10730	global		fsgldiv
10731fsgldiv:
10732	mov.l		%d0,L_SCR3(%a6)		# store rnd info
10733
10734	clr.w		%d1
10735	mov.b		DTAG(%a6),%d1
10736	lsl.b		&0x3,%d1
10737	or.b		STAG(%a6),%d1		# combine src tags
10738
10739	bne.w		fsgldiv_not_norm	# optimize on non-norm input
10740
10741#
10742# DIVIDE: NORMs and DENORMs ONLY!
10743#
10744fsgldiv_norm:
10745	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
10746	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
10747	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
10748
10749	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
10750	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
10751	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
10752
10753	bsr.l		scale_to_zero_src	# calculate scale factor 1
10754	mov.l		%d0,-(%sp)		# save scale factor 1
10755
10756	bsr.l		scale_to_zero_dst	# calculate scale factor 2
10757
10758	neg.l		(%sp)			# S.F. = scale1 - scale2
10759	add.l		%d0,(%sp)
10760
10761	mov.w		2+L_SCR3(%a6),%d1	# fetch precision,mode
10762	lsr.b		&0x6,%d1
10763	mov.l		(%sp)+,%d0
10764	cmpi.l		%d0,&0x3fff-0x7ffe
10765	ble.w		fsgldiv_may_ovfl
10766
10767	cmpi.l		%d0,&0x3fff-0x0000	# will result underflow?
10768	beq.w		fsgldiv_may_unfl	# maybe
10769	bgt.w		fsgldiv_unfl		# yes; go handle underflow
10770
10771fsgldiv_normal:
10772	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10773
10774	fmov.l		L_SCR3(%a6),%fpcr	# save FPCR
10775	fmov.l		&0x0,%fpsr		# clear FPSR
10776
10777	fsgldiv.x	FP_SCR0(%a6),%fp0	# perform sgl divide
10778
10779	fmov.l		%fpsr,%d1		# save FPSR
10780	fmov.l		&0x0,%fpcr		# clear FPCR
10781
10782	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10783
10784fsgldiv_normal_exit:
10785	fmovm.x		&0x80,FP_SCR0(%a6)	# store result on stack
10786	mov.l		%d2,-(%sp)		# save d2
10787	mov.w		FP_SCR0_EX(%a6),%d1	# load {sgn,exp}
10788	mov.l		%d1,%d2			# make a copy
10789	andi.l		&0x7fff,%d1		# strip sign
10790	andi.w		&0x8000,%d2		# keep old sign
10791	sub.l		%d0,%d1			# add scale factor
10792	or.w		%d2,%d1			# concat old sign,new exp
10793	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10794	mov.l		(%sp)+,%d2		# restore d2
10795	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
10796	rts
10797
10798fsgldiv_may_ovfl:
10799	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10800
10801	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10802	fmov.l		&0x0,%fpsr		# set FPSR
10803
10804	fsgldiv.x	FP_SCR0(%a6),%fp0	# execute divide
10805
10806	fmov.l		%fpsr,%d1
10807	fmov.l		&0x0,%fpcr
10808
10809	or.l		%d1,USER_FPSR(%a6)	# save INEX,N
10810
10811	fmovm.x		&0x01,-(%sp)		# save result to stack
10812	mov.w		(%sp),%d1		# fetch new exponent
10813	add.l		&0xc,%sp		# clear result
10814	andi.l		&0x7fff,%d1		# strip sign
10815	sub.l		%d0,%d1			# add scale factor
10816	cmp.l		%d1,&0x7fff		# did divide overflow?
10817	blt.b		fsgldiv_normal_exit
10818
10819fsgldiv_ovfl_tst:
10820	or.w		&ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
10821
10822	mov.b		FPCR_ENABLE(%a6),%d1
10823	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
10824	bne.b		fsgldiv_ovfl_ena	# yes
10825
10826fsgldiv_ovfl_dis:
10827	btst		&neg_bit,FPSR_CC(%a6)	# is result negative
10828	sne		%d1			# set sign param accordingly
10829	mov.l		L_SCR3(%a6),%d0		# pass prec:rnd
10830	andi.b		&0x30,%d0		# kill precision
10831	bsr.l		ovf_res			# calculate default result
10832	or.b		%d0,FPSR_CC(%a6)	# set INF if applicable
10833	fmovm.x		(%a0),&0x80		# return default result in fp0
10834	rts
10835
10836fsgldiv_ovfl_ena:
10837	fmovm.x		&0x80,FP_SCR0(%a6)	# move result to stack
10838
10839	mov.l		%d2,-(%sp)		# save d2
10840	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
10841	mov.l		%d1,%d2			# make a copy
10842	andi.l		&0x7fff,%d1		# strip sign
10843	andi.w		&0x8000,%d2		# keep old sign
10844	sub.l		%d0,%d1			# add scale factor
10845	subi.l		&0x6000,%d1		# subtract new bias
10846	andi.w		&0x7fff,%d1		# clear ms bit
10847	or.w		%d2,%d1			# concat old sign,new exp
10848	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10849	mov.l		(%sp)+,%d2		# restore d2
10850	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
10851	bra.b		fsgldiv_ovfl_dis
10852
10853fsgldiv_unfl:
10854	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10855
10856	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10857
10858	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
10859	fmov.l		&0x0,%fpsr		# clear FPSR
10860
10861	fsgldiv.x	FP_SCR0(%a6),%fp0	# execute sgl divide
10862
10863	fmov.l		%fpsr,%d1		# save status
10864	fmov.l		&0x0,%fpcr		# clear FPCR
10865
10866	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10867
10868	mov.b		FPCR_ENABLE(%a6),%d1
10869	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
10870	bne.b		fsgldiv_unfl_ena	# yes
10871
10872fsgldiv_unfl_dis:
10873	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
10874
10875	lea		FP_SCR0(%a6),%a0	# pass: result addr
10876	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
10877	bsr.l		unf_res4		# calculate default result
10878	or.b		%d0,FPSR_CC(%a6)	# 'Z' bit may have been set
10879	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
10880	rts
10881
10882#
10883# UNFL is enabled.
10884#
10885fsgldiv_unfl_ena:
10886	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op
10887
10888	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10889	fmov.l		&0x0,%fpsr		# clear FPSR
10890
10891	fsgldiv.x	FP_SCR0(%a6),%fp1	# execute sgl divide
10892
10893	fmov.l		&0x0,%fpcr		# clear FPCR
10894
10895	fmovm.x		&0x40,FP_SCR0(%a6)	# save result to stack
10896	mov.l		%d2,-(%sp)		# save d2
10897	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
10898	mov.l		%d1,%d2			# make a copy
10899	andi.l		&0x7fff,%d1		# strip sign
10900	andi.w		&0x8000,%d2		# keep old sign
10901	sub.l		%d0,%d1			# add scale factor
10902	addi.l		&0x6000,%d1		# add bias
10903	andi.w		&0x7fff,%d1		# clear top bit
10904	or.w		%d2,%d1			# concat old sign, new exp
10905	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
10906	mov.l		(%sp)+,%d2		# restore d2
10907	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
10908	bra.b		fsgldiv_unfl_dis
10909
10910#
10911# the divide operation MAY underflow:
10912#
10913fsgldiv_may_unfl:
10914	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
10915
10916	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
10917	fmov.l		&0x0,%fpsr		# clear FPSR
10918
10919	fsgldiv.x	FP_SCR0(%a6),%fp0	# execute sgl divide
10920
10921	fmov.l		%fpsr,%d1		# save status
10922	fmov.l		&0x0,%fpcr		# clear FPCR
10923
10924	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
10925
10926	fabs.x		%fp0,%fp1		# make a copy of result
10927	fcmp.b		%fp1,&0x1		# is |result| > 1.b?
10928	fbgt.w		fsgldiv_normal_exit	# no; no underflow occurred
10929	fblt.w		fsgldiv_unfl		# yes; underflow occurred
10930
10931#
10932# we still don't know if underflow occurred. result is ~ equal to 1. but,
10933# we don't know if the result was an underflow that rounded up to a 1
10934# or a normalized number that rounded down to a 1. so, redo the entire
10935# operation using RZ as the rounding mode to see what the pre-rounded
10936# result is. this case should be relatively rare.
10937#
10938	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op into %fp1
10939
10940	clr.l		%d1			# clear scratch register
10941	ori.b		&rz_mode*0x10,%d1	# force RZ rnd mode
10942
10943	fmov.l		%d1,%fpcr		# set FPCR
10944	fmov.l		&0x0,%fpsr		# clear FPSR
10945
10946	fsgldiv.x	FP_SCR0(%a6),%fp1	# execute sgl divide
10947
10948	fmov.l		&0x0,%fpcr		# clear FPCR
10949	fabs.x		%fp1			# make absolute value
10950	fcmp.b		%fp1,&0x1		# is |result| < 1.b?
10951	fbge.w		fsgldiv_normal_exit	# no; no underflow occurred
10952	bra.w		fsgldiv_unfl		# yes; underflow occurred
10953
10954############################################################################
10955
10956#
10957# Divide: inputs are not both normalized; what are they?
10958#
10959fsgldiv_not_norm:
10960	mov.w		(tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1
10961	jmp		(tbl_fsgldiv_op.b,%pc,%d1.w*1)
10962
10963	swbeg		&48
10964tbl_fsgldiv_op:
10965	short		fsgldiv_norm		- tbl_fsgldiv_op # NORM / NORM
10966	short		fsgldiv_inf_load	- tbl_fsgldiv_op # NORM / ZERO
10967	short		fsgldiv_zero_load	- tbl_fsgldiv_op # NORM / INF
10968	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # NORM / QNAN
10969	short		fsgldiv_norm		- tbl_fsgldiv_op # NORM / DENORM
10970	short		fsgldiv_res_snan	- tbl_fsgldiv_op # NORM / SNAN
10971	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10972	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10973
10974	short		fsgldiv_zero_load	- tbl_fsgldiv_op # ZERO / NORM
10975	short		fsgldiv_res_operr	- tbl_fsgldiv_op # ZERO / ZERO
10976	short		fsgldiv_zero_load	- tbl_fsgldiv_op # ZERO / INF
10977	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # ZERO / QNAN
10978	short		fsgldiv_zero_load	- tbl_fsgldiv_op # ZERO / DENORM
10979	short		fsgldiv_res_snan	- tbl_fsgldiv_op # ZERO / SNAN
10980	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10981	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10982
10983	short		fsgldiv_inf_dst		- tbl_fsgldiv_op # INF / NORM
10984	short		fsgldiv_inf_dst		- tbl_fsgldiv_op # INF / ZERO
10985	short		fsgldiv_res_operr	- tbl_fsgldiv_op # INF / INF
10986	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # INF / QNAN
10987	short		fsgldiv_inf_dst		- tbl_fsgldiv_op # INF / DENORM
10988	short		fsgldiv_res_snan	- tbl_fsgldiv_op # INF / SNAN
10989	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10990	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10991
10992	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # QNAN / NORM
10993	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # QNAN / ZERO
10994	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # QNAN / INF
10995	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # QNAN / QNAN
10996	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # QNAN / DENORM
10997	short		fsgldiv_res_snan	- tbl_fsgldiv_op # QNAN / SNAN
10998	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
10999	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
11000
11001	short		fsgldiv_norm		- tbl_fsgldiv_op # DENORM / NORM
11002	short		fsgldiv_inf_load	- tbl_fsgldiv_op # DENORM / ZERO
11003	short		fsgldiv_zero_load	- tbl_fsgldiv_op # DENORM / INF
11004	short		fsgldiv_res_qnan	- tbl_fsgldiv_op # DENORM / QNAN
11005	short		fsgldiv_norm		- tbl_fsgldiv_op # DENORM / DENORM
11006	short		fsgldiv_res_snan	- tbl_fsgldiv_op # DENORM / SNAN
11007	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
11008	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
11009
11010	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / NORM
11011	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / ZERO
11012	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / INF
11013	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / QNAN
11014	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / DENORM
11015	short		fsgldiv_res_snan	- tbl_fsgldiv_op # SNAN / SNAN
11016	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
11017	short		tbl_fsgldiv_op		- tbl_fsgldiv_op #
11018
11019fsgldiv_res_qnan:
11020	bra.l		res_qnan
11021fsgldiv_res_snan:
11022	bra.l		res_snan
11023fsgldiv_res_operr:
11024	bra.l		res_operr
11025fsgldiv_inf_load:
11026	bra.l		fdiv_inf_load
11027fsgldiv_zero_load:
11028	bra.l		fdiv_zero_load
11029fsgldiv_inf_dst:
11030	bra.l		fdiv_inf_dst
11031
11032#########################################################################
11033# XDEF ****************************************************************	#
11034#	fadd(): emulates the fadd instruction				#
11035#	fsadd(): emulates the fadd instruction				#
11036#	fdadd(): emulates the fdadd instruction				#
11037#									#
11038# XREF ****************************************************************	#
11039#	addsub_scaler2() - scale the operands so they won't take exc	#
11040#	ovf_res() - return default overflow result			#
11041#	unf_res() - return default underflow result			#
11042#	res_qnan() - set QNAN result					#
11043#	res_snan() - set SNAN result					#
11044#	res_operr() - set OPERR result					#
11045#	scale_to_zero_src() - set src operand exponent equal to zero	#
11046#	scale_to_zero_dst() - set dst operand exponent equal to zero	#
11047#									#
11048# INPUT ***************************************************************	#
11049#	a0 = pointer to extended precision source operand		#
11050#	a1 = pointer to extended precision destination operand		#
11051#									#
11052# OUTPUT **************************************************************	#
11053#	fp0 = result							#
11054#	fp1 = EXOP (if exception occurred)				#
11055#									#
11056# ALGORITHM ***********************************************************	#
11057#	Handle NANs, infinities, and zeroes as special cases. Divide	#
11058# norms into extended, single, and double precision.			#
11059#	Do addition after scaling exponents such that exception won't	#
11060# occur. Then, check result exponent to see if exception would have	#
11061# occurred. If so, return default result and maybe EXOP. Else, insert	#
11062# the correct result exponent and return. Set FPSR bits as appropriate.	#
11063#									#
11064#########################################################################
11065
11066	global		fsadd
11067fsadd:
11068	andi.b		&0x30,%d0		# clear rnd prec
11069	ori.b		&s_mode*0x10,%d0	# insert sgl prec
11070	bra.b		fadd
11071
11072	global		fdadd
11073fdadd:
11074	andi.b		&0x30,%d0		# clear rnd prec
11075	ori.b		&d_mode*0x10,%d0	# insert dbl prec
11076
11077	global		fadd
11078fadd:
11079	mov.l		%d0,L_SCR3(%a6)		# store rnd info
11080
11081	clr.w		%d1
11082	mov.b		DTAG(%a6),%d1
11083	lsl.b		&0x3,%d1
11084	or.b		STAG(%a6),%d1		# combine src tags
11085
11086	bne.w		fadd_not_norm		# optimize on non-norm input
11087
11088#
11089# ADD: norms and denorms
11090#
11091fadd_norm:
11092	bsr.l		addsub_scaler2		# scale exponents
11093
11094fadd_zero_entry:
11095	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11096
11097	fmov.l		&0x0,%fpsr		# clear FPSR
11098	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
11099
11100	fadd.x		FP_SCR0(%a6),%fp0	# execute add
11101
11102	fmov.l		&0x0,%fpcr		# clear FPCR
11103	fmov.l		%fpsr,%d1		# fetch INEX2,N,Z
11104
11105	or.l		%d1,USER_FPSR(%a6)	# save exc and ccode bits
11106
11107	fbeq.w		fadd_zero_exit		# if result is zero, end now
11108
11109	mov.l		%d2,-(%sp)		# save d2
11110
11111	fmovm.x		&0x01,-(%sp)		# save result to stack
11112
11113	mov.w		2+L_SCR3(%a6),%d1
11114	lsr.b		&0x6,%d1
11115
11116	mov.w		(%sp),%d2		# fetch new sign, exp
11117	andi.l		&0x7fff,%d2		# strip sign
11118	sub.l		%d0,%d2			# add scale factor
11119
11120	cmp.l		%d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11121	bge.b		fadd_ovfl		# yes
11122
11123	cmp.l		%d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow?
11124	blt.w		fadd_unfl		# yes
11125	beq.w		fadd_may_unfl		# maybe; go find out
11126
11127fadd_normal:
11128	mov.w		(%sp),%d1
11129	andi.w		&0x8000,%d1		# keep sign
11130	or.w		%d2,%d1			# concat sign,new exp
11131	mov.w		%d1,(%sp)		# insert new exponent
11132
11133	fmovm.x		(%sp)+,&0x80		# return result in fp0
11134
11135	mov.l		(%sp)+,%d2		# restore d2
11136	rts
11137
11138fadd_zero_exit:
11139#	fmov.s		&0x00000000,%fp0	# return zero in fp0
11140	rts
11141
11142tbl_fadd_ovfl:
11143	long		0x7fff			# ext ovfl
11144	long		0x407f			# sgl ovfl
11145	long		0x43ff			# dbl ovfl
11146
11147tbl_fadd_unfl:
11148	long	        0x0000			# ext unfl
11149	long		0x3f81			# sgl unfl
11150	long		0x3c01			# dbl unfl
11151
11152fadd_ovfl:
11153	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11154
11155	mov.b		FPCR_ENABLE(%a6),%d1
11156	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
11157	bne.b		fadd_ovfl_ena		# yes
11158
11159	add.l		&0xc,%sp
11160fadd_ovfl_dis:
11161	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
11162	sne		%d1			# set sign param accordingly
11163	mov.l		L_SCR3(%a6),%d0		# pass prec:rnd
11164	bsr.l		ovf_res			# calculate default result
11165	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
11166	fmovm.x		(%a0),&0x80		# return default result in fp0
11167	mov.l		(%sp)+,%d2		# restore d2
11168	rts
11169
11170fadd_ovfl_ena:
11171	mov.b		L_SCR3(%a6),%d1
11172	andi.b		&0xc0,%d1		# is precision extended?
11173	bne.b		fadd_ovfl_ena_sd	# no; prec = sgl or dbl
11174
11175fadd_ovfl_ena_cont:
11176	mov.w		(%sp),%d1
11177	andi.w		&0x8000,%d1		# keep sign
11178	subi.l		&0x6000,%d2		# add extra bias
11179	andi.w		&0x7fff,%d2
11180	or.w		%d2,%d1			# concat sign,new exp
11181	mov.w		%d1,(%sp)		# insert new exponent
11182
11183	fmovm.x		(%sp)+,&0x40		# return EXOP in fp1
11184	bra.b		fadd_ovfl_dis
11185
11186fadd_ovfl_ena_sd:
11187	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11188
11189	mov.l		L_SCR3(%a6),%d1
11190	andi.b		&0x30,%d1		# keep rnd mode
11191	fmov.l		%d1,%fpcr		# set FPCR
11192
11193	fadd.x		FP_SCR0(%a6),%fp0	# execute add
11194
11195	fmov.l		&0x0,%fpcr		# clear FPCR
11196
11197	add.l		&0xc,%sp
11198	fmovm.x		&0x01,-(%sp)
11199	bra.b		fadd_ovfl_ena_cont
11200
11201fadd_unfl:
11202	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11203
11204	add.l		&0xc,%sp
11205
11206	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11207
11208	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
11209	fmov.l		&0x0,%fpsr		# clear FPSR
11210
11211	fadd.x		FP_SCR0(%a6),%fp0	# execute add
11212
11213	fmov.l		&0x0,%fpcr		# clear FPCR
11214	fmov.l		%fpsr,%d1		# save status
11215
11216	or.l		%d1,USER_FPSR(%a6)	# save INEX,N
11217
11218	mov.b		FPCR_ENABLE(%a6),%d1
11219	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
11220	bne.b		fadd_unfl_ena		# yes
11221
11222fadd_unfl_dis:
11223	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
11224
11225	lea		FP_SCR0(%a6),%a0	# pass: result addr
11226	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
11227	bsr.l		unf_res			# calculate default result
11228	or.b		%d0,FPSR_CC(%a6)	# 'Z' bit may have been set
11229	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
11230	mov.l		(%sp)+,%d2		# restore d2
11231	rts
11232
11233fadd_unfl_ena:
11234	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op
11235
11236	mov.l		L_SCR3(%a6),%d1
11237	andi.b		&0xc0,%d1		# is precision extended?
11238	bne.b		fadd_unfl_ena_sd	# no; sgl or dbl
11239
11240	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
11241
11242fadd_unfl_ena_cont:
11243	fmov.l		&0x0,%fpsr		# clear FPSR
11244
11245	fadd.x		FP_SCR0(%a6),%fp1	# execute multiply
11246
11247	fmov.l		&0x0,%fpcr		# clear FPCR
11248
11249	fmovm.x		&0x40,FP_SCR0(%a6)	# save result to stack
11250	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
11251	mov.l		%d1,%d2			# make a copy
11252	andi.l		&0x7fff,%d1		# strip sign
11253	andi.w		&0x8000,%d2		# keep old sign
11254	sub.l		%d0,%d1			# add scale factor
11255	addi.l		&0x6000,%d1		# add new bias
11256	andi.w		&0x7fff,%d1		# clear top bit
11257	or.w		%d2,%d1			# concat sign,new exp
11258	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
11259	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
11260	bra.w		fadd_unfl_dis
11261
11262fadd_unfl_ena_sd:
11263	mov.l		L_SCR3(%a6),%d1
11264	andi.b		&0x30,%d1		# use only rnd mode
11265	fmov.l		%d1,%fpcr		# set FPCR
11266
11267	bra.b		fadd_unfl_ena_cont
11268
11269#
11270# result is equal to the smallest normalized number in the selected precision
11271# if the precision is extended, this result could not have come from an
11272# underflow that rounded up.
11273#
11274fadd_may_unfl:
11275	mov.l		L_SCR3(%a6),%d1
11276	andi.b		&0xc0,%d1
11277	beq.w		fadd_normal		# yes; no underflow occurred
11278
11279	mov.l		0x4(%sp),%d1		# extract hi(man)
11280	cmpi.l		%d1,&0x80000000		# is hi(man) = 0x80000000?
11281	bne.w		fadd_normal		# no; no underflow occurred
11282
11283	tst.l		0x8(%sp)		# is lo(man) = 0x0?
11284	bne.w		fadd_normal		# no; no underflow occurred
11285
11286	btst		&inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11287	beq.w		fadd_normal		# no; no underflow occurred
11288
11289#
11290# ok, so now the result has a exponent equal to the smallest normalized
11291# exponent for the selected precision. also, the mantissa is equal to
11292# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11293# g,r,s.
11294# now, we must determine whether the pre-rounded result was an underflow
11295# rounded "up" or a normalized number rounded "down".
11296# so, we do this be re-executing the add using RZ as the rounding mode and
11297# seeing if the new result is smaller or equal to the current result.
11298#
11299	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op into fp1
11300
11301	mov.l		L_SCR3(%a6),%d1
11302	andi.b		&0xc0,%d1		# keep rnd prec
11303	ori.b		&rz_mode*0x10,%d1	# insert rnd mode
11304	fmov.l		%d1,%fpcr		# set FPCR
11305	fmov.l		&0x0,%fpsr		# clear FPSR
11306
11307	fadd.x		FP_SCR0(%a6),%fp1	# execute add
11308
11309	fmov.l		&0x0,%fpcr		# clear FPCR
11310
11311	fabs.x		%fp0			# compare absolute values
11312	fabs.x		%fp1
11313	fcmp.x		%fp0,%fp1		# is first result > second?
11314
11315	fbgt.w		fadd_unfl		# yes; it's an underflow
11316	bra.w		fadd_normal		# no; it's not an underflow
11317
11318##########################################################################
11319
11320#
11321# Add: inputs are not both normalized; what are they?
11322#
11323fadd_not_norm:
11324	mov.w		(tbl_fadd_op.b,%pc,%d1.w*2),%d1
11325	jmp		(tbl_fadd_op.b,%pc,%d1.w*1)
11326
11327	swbeg		&48
11328tbl_fadd_op:
11329	short		fadd_norm	- tbl_fadd_op # NORM + NORM
11330	short		fadd_zero_src	- tbl_fadd_op # NORM + ZERO
11331	short		fadd_inf_src	- tbl_fadd_op # NORM + INF
11332	short		fadd_res_qnan	- tbl_fadd_op # NORM + QNAN
11333	short		fadd_norm	- tbl_fadd_op # NORM + DENORM
11334	short		fadd_res_snan	- tbl_fadd_op # NORM + SNAN
11335	short		tbl_fadd_op	- tbl_fadd_op #
11336	short		tbl_fadd_op	- tbl_fadd_op #
11337
11338	short		fadd_zero_dst	- tbl_fadd_op # ZERO + NORM
11339	short		fadd_zero_2	- tbl_fadd_op # ZERO + ZERO
11340	short		fadd_inf_src	- tbl_fadd_op # ZERO + INF
11341	short		fadd_res_qnan	- tbl_fadd_op # NORM + QNAN
11342	short		fadd_zero_dst	- tbl_fadd_op # ZERO + DENORM
11343	short		fadd_res_snan	- tbl_fadd_op # NORM + SNAN
11344	short		tbl_fadd_op	- tbl_fadd_op #
11345	short		tbl_fadd_op	- tbl_fadd_op #
11346
11347	short		fadd_inf_dst	- tbl_fadd_op # INF + NORM
11348	short		fadd_inf_dst	- tbl_fadd_op # INF + ZERO
11349	short		fadd_inf_2	- tbl_fadd_op # INF + INF
11350	short		fadd_res_qnan	- tbl_fadd_op # NORM + QNAN
11351	short		fadd_inf_dst	- tbl_fadd_op # INF + DENORM
11352	short		fadd_res_snan	- tbl_fadd_op # NORM + SNAN
11353	short		tbl_fadd_op	- tbl_fadd_op #
11354	short		tbl_fadd_op	- tbl_fadd_op #
11355
11356	short		fadd_res_qnan	- tbl_fadd_op # QNAN + NORM
11357	short		fadd_res_qnan	- tbl_fadd_op # QNAN + ZERO
11358	short		fadd_res_qnan	- tbl_fadd_op # QNAN + INF
11359	short		fadd_res_qnan	- tbl_fadd_op # QNAN + QNAN
11360	short		fadd_res_qnan	- tbl_fadd_op # QNAN + DENORM
11361	short		fadd_res_snan	- tbl_fadd_op # QNAN + SNAN
11362	short		tbl_fadd_op	- tbl_fadd_op #
11363	short		tbl_fadd_op	- tbl_fadd_op #
11364
11365	short		fadd_norm	- tbl_fadd_op # DENORM + NORM
11366	short		fadd_zero_src	- tbl_fadd_op # DENORM + ZERO
11367	short		fadd_inf_src	- tbl_fadd_op # DENORM + INF
11368	short		fadd_res_qnan	- tbl_fadd_op # NORM + QNAN
11369	short		fadd_norm	- tbl_fadd_op # DENORM + DENORM
11370	short		fadd_res_snan	- tbl_fadd_op # NORM + SNAN
11371	short		tbl_fadd_op	- tbl_fadd_op #
11372	short		tbl_fadd_op	- tbl_fadd_op #
11373
11374	short		fadd_res_snan	- tbl_fadd_op # SNAN + NORM
11375	short		fadd_res_snan	- tbl_fadd_op # SNAN + ZERO
11376	short		fadd_res_snan	- tbl_fadd_op # SNAN + INF
11377	short		fadd_res_snan	- tbl_fadd_op # SNAN + QNAN
11378	short		fadd_res_snan	- tbl_fadd_op # SNAN + DENORM
11379	short		fadd_res_snan	- tbl_fadd_op # SNAN + SNAN
11380	short		tbl_fadd_op	- tbl_fadd_op #
11381	short		tbl_fadd_op	- tbl_fadd_op #
11382
11383fadd_res_qnan:
11384	bra.l		res_qnan
11385fadd_res_snan:
11386	bra.l		res_snan
11387
11388#
11389# both operands are ZEROes
11390#
11391fadd_zero_2:
11392	mov.b		SRC_EX(%a0),%d0		# are the signs opposite
11393	mov.b		DST_EX(%a1),%d1
11394	eor.b		%d0,%d1
11395	bmi.w		fadd_zero_2_chk_rm	# weed out (-ZERO)+(+ZERO)
11396
11397# the signs are the same. so determine whether they are positive or negative
11398# and return the appropriately signed zero.
11399	tst.b		%d0			# are ZEROes positive or negative?
11400	bmi.b		fadd_zero_rm		# negative
11401	fmov.s		&0x00000000,%fp0	# return +ZERO
11402	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
11403	rts
11404
11405#
11406# the ZEROes have opposite signs:
11407# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
11408# - -ZERO is returned in the case of RM.
11409#
11410fadd_zero_2_chk_rm:
11411	mov.b		3+L_SCR3(%a6),%d1
11412	andi.b		&0x30,%d1		# extract rnd mode
11413	cmpi.b		%d1,&rm_mode*0x10	# is rnd mode == RM?
11414	beq.b		fadd_zero_rm		# yes
11415	fmov.s		&0x00000000,%fp0	# return +ZERO
11416	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
11417	rts
11418
11419fadd_zero_rm:
11420	fmov.s		&0x80000000,%fp0	# return -ZERO
11421	mov.b		&neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z
11422	rts
11423
11424#
11425# one operand is a ZERO and the other is a DENORM or NORM. scale
11426# the DENORM or NORM and jump to the regular fadd routine.
11427#
11428fadd_zero_dst:
11429	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
11430	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
11431	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
11432	bsr.l		scale_to_zero_src	# scale the operand
11433	clr.w		FP_SCR1_EX(%a6)
11434	clr.l		FP_SCR1_HI(%a6)
11435	clr.l		FP_SCR1_LO(%a6)
11436	bra.w		fadd_zero_entry		# go execute fadd
11437
11438fadd_zero_src:
11439	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
11440	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
11441	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
11442	bsr.l		scale_to_zero_dst	# scale the operand
11443	clr.w		FP_SCR0_EX(%a6)
11444	clr.l		FP_SCR0_HI(%a6)
11445	clr.l		FP_SCR0_LO(%a6)
11446	bra.w		fadd_zero_entry		# go execute fadd
11447
11448#
11449# both operands are INFs. an OPERR will result if the INFs have
11450# different signs. else, an INF of the same sign is returned
11451#
11452fadd_inf_2:
11453	mov.b		SRC_EX(%a0),%d0		# exclusive or the signs
11454	mov.b		DST_EX(%a1),%d1
11455	eor.b		%d1,%d0
11456	bmi.l		res_operr		# weed out (-INF)+(+INF)
11457
11458# ok, so it's not an OPERR. but, we do have to remember to return the
11459# src INF since that's where the 881/882 gets the j-bit from...
11460
11461#
11462# operands are INF and one of {ZERO, INF, DENORM, NORM}
11463#
11464fadd_inf_src:
11465	fmovm.x		SRC(%a0),&0x80		# return src INF
11466	tst.b		SRC_EX(%a0)		# is INF positive?
11467	bpl.b		fadd_inf_done		# yes; we're done
11468	mov.b		&neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11469	rts
11470
11471#
11472# operands are INF and one of {ZERO, INF, DENORM, NORM}
11473#
11474fadd_inf_dst:
11475	fmovm.x		DST(%a1),&0x80		# return dst INF
11476	tst.b		DST_EX(%a1)		# is INF positive?
11477	bpl.b		fadd_inf_done		# yes; we're done
11478	mov.b		&neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11479	rts
11480
11481fadd_inf_done:
11482	mov.b		&inf_bmask,FPSR_CC(%a6) # set INF
11483	rts
11484
11485#########################################################################
11486# XDEF ****************************************************************	#
11487#	fsub(): emulates the fsub instruction				#
11488#	fssub(): emulates the fssub instruction				#
11489#	fdsub(): emulates the fdsub instruction				#
11490#									#
11491# XREF ****************************************************************	#
11492#	addsub_scaler2() - scale the operands so they won't take exc	#
11493#	ovf_res() - return default overflow result			#
11494#	unf_res() - return default underflow result			#
11495#	res_qnan() - set QNAN result					#
11496#	res_snan() - set SNAN result					#
11497#	res_operr() - set OPERR result					#
11498#	scale_to_zero_src() - set src operand exponent equal to zero	#
11499#	scale_to_zero_dst() - set dst operand exponent equal to zero	#
11500#									#
11501# INPUT ***************************************************************	#
11502#	a0 = pointer to extended precision source operand		#
11503#	a1 = pointer to extended precision destination operand		#
11504#									#
11505# OUTPUT **************************************************************	#
11506#	fp0 = result							#
11507#	fp1 = EXOP (if exception occurred)				#
11508#									#
11509# ALGORITHM ***********************************************************	#
11510#	Handle NANs, infinities, and zeroes as special cases. Divide	#
11511# norms into extended, single, and double precision.			#
11512#	Do subtraction after scaling exponents such that exception won't#
11513# occur. Then, check result exponent to see if exception would have	#
11514# occurred. If so, return default result and maybe EXOP. Else, insert	#
11515# the correct result exponent and return. Set FPSR bits as appropriate.	#
11516#									#
11517#########################################################################
11518
11519	global		fssub
11520fssub:
11521	andi.b		&0x30,%d0		# clear rnd prec
11522	ori.b		&s_mode*0x10,%d0	# insert sgl prec
11523	bra.b		fsub
11524
11525	global		fdsub
11526fdsub:
11527	andi.b		&0x30,%d0		# clear rnd prec
11528	ori.b		&d_mode*0x10,%d0	# insert dbl prec
11529
11530	global		fsub
11531fsub:
11532	mov.l		%d0,L_SCR3(%a6)		# store rnd info
11533
11534	clr.w		%d1
11535	mov.b		DTAG(%a6),%d1
11536	lsl.b		&0x3,%d1
11537	or.b		STAG(%a6),%d1		# combine src tags
11538
11539	bne.w		fsub_not_norm		# optimize on non-norm input
11540
11541#
11542# SUB: norms and denorms
11543#
11544fsub_norm:
11545	bsr.l		addsub_scaler2		# scale exponents
11546
11547fsub_zero_entry:
11548	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11549
11550	fmov.l		&0x0,%fpsr		# clear FPSR
11551	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
11552
11553	fsub.x		FP_SCR0(%a6),%fp0	# execute subtract
11554
11555	fmov.l		&0x0,%fpcr		# clear FPCR
11556	fmov.l		%fpsr,%d1		# fetch INEX2, N, Z
11557
11558	or.l		%d1,USER_FPSR(%a6)	# save exc and ccode bits
11559
11560	fbeq.w		fsub_zero_exit		# if result zero, end now
11561
11562	mov.l		%d2,-(%sp)		# save d2
11563
11564	fmovm.x		&0x01,-(%sp)		# save result to stack
11565
11566	mov.w		2+L_SCR3(%a6),%d1
11567	lsr.b		&0x6,%d1
11568
11569	mov.w		(%sp),%d2		# fetch new exponent
11570	andi.l		&0x7fff,%d2		# strip sign
11571	sub.l		%d0,%d2			# add scale factor
11572
11573	cmp.l		%d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11574	bge.b		fsub_ovfl		# yes
11575
11576	cmp.l		%d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow?
11577	blt.w		fsub_unfl		# yes
11578	beq.w		fsub_may_unfl		# maybe; go find out
11579
11580fsub_normal:
11581	mov.w		(%sp),%d1
11582	andi.w		&0x8000,%d1		# keep sign
11583	or.w		%d2,%d1			# insert new exponent
11584	mov.w		%d1,(%sp)		# insert new exponent
11585
11586	fmovm.x		(%sp)+,&0x80		# return result in fp0
11587
11588	mov.l		(%sp)+,%d2		# restore d2
11589	rts
11590
11591fsub_zero_exit:
11592#	fmov.s		&0x00000000,%fp0	# return zero in fp0
11593	rts
11594
11595tbl_fsub_ovfl:
11596	long		0x7fff			# ext ovfl
11597	long		0x407f			# sgl ovfl
11598	long		0x43ff			# dbl ovfl
11599
11600tbl_fsub_unfl:
11601	long	        0x0000			# ext unfl
11602	long		0x3f81			# sgl unfl
11603	long		0x3c01			# dbl unfl
11604
11605fsub_ovfl:
11606	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11607
11608	mov.b		FPCR_ENABLE(%a6),%d1
11609	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
11610	bne.b		fsub_ovfl_ena		# yes
11611
11612	add.l		&0xc,%sp
11613fsub_ovfl_dis:
11614	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
11615	sne		%d1			# set sign param accordingly
11616	mov.l		L_SCR3(%a6),%d0		# pass prec:rnd
11617	bsr.l		ovf_res			# calculate default result
11618	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
11619	fmovm.x		(%a0),&0x80		# return default result in fp0
11620	mov.l		(%sp)+,%d2		# restore d2
11621	rts
11622
11623fsub_ovfl_ena:
11624	mov.b		L_SCR3(%a6),%d1
11625	andi.b		&0xc0,%d1		# is precision extended?
11626	bne.b		fsub_ovfl_ena_sd	# no
11627
11628fsub_ovfl_ena_cont:
11629	mov.w		(%sp),%d1		# fetch {sgn,exp}
11630	andi.w		&0x8000,%d1		# keep sign
11631	subi.l		&0x6000,%d2		# subtract new bias
11632	andi.w		&0x7fff,%d2		# clear top bit
11633	or.w		%d2,%d1			# concat sign,exp
11634	mov.w		%d1,(%sp)		# insert new exponent
11635
11636	fmovm.x		(%sp)+,&0x40		# return EXOP in fp1
11637	bra.b		fsub_ovfl_dis
11638
11639fsub_ovfl_ena_sd:
11640	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11641
11642	mov.l		L_SCR3(%a6),%d1
11643	andi.b		&0x30,%d1		# clear rnd prec
11644	fmov.l		%d1,%fpcr		# set FPCR
11645
11646	fsub.x		FP_SCR0(%a6),%fp0	# execute subtract
11647
11648	fmov.l		&0x0,%fpcr		# clear FPCR
11649
11650	add.l		&0xc,%sp
11651	fmovm.x		&0x01,-(%sp)
11652	bra.b		fsub_ovfl_ena_cont
11653
11654fsub_unfl:
11655	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11656
11657	add.l		&0xc,%sp
11658
11659	fmovm.x		FP_SCR1(%a6),&0x80	# load dst op
11660
11661	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
11662	fmov.l		&0x0,%fpsr		# clear FPSR
11663
11664	fsub.x		FP_SCR0(%a6),%fp0	# execute subtract
11665
11666	fmov.l		&0x0,%fpcr		# clear FPCR
11667	fmov.l		%fpsr,%d1		# save status
11668
11669	or.l		%d1,USER_FPSR(%a6)
11670
11671	mov.b		FPCR_ENABLE(%a6),%d1
11672	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
11673	bne.b		fsub_unfl_ena		# yes
11674
11675fsub_unfl_dis:
11676	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
11677
11678	lea		FP_SCR0(%a6),%a0	# pass: result addr
11679	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
11680	bsr.l		unf_res			# calculate default result
11681	or.b		%d0,FPSR_CC(%a6)	# 'Z' may have been set
11682	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
11683	mov.l		(%sp)+,%d2		# restore d2
11684	rts
11685
11686fsub_unfl_ena:
11687	fmovm.x		FP_SCR1(%a6),&0x40
11688
11689	mov.l		L_SCR3(%a6),%d1
11690	andi.b		&0xc0,%d1		# is precision extended?
11691	bne.b		fsub_unfl_ena_sd	# no
11692
11693	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
11694
11695fsub_unfl_ena_cont:
11696	fmov.l		&0x0,%fpsr		# clear FPSR
11697
11698	fsub.x		FP_SCR0(%a6),%fp1	# execute subtract
11699
11700	fmov.l		&0x0,%fpcr		# clear FPCR
11701
11702	fmovm.x		&0x40,FP_SCR0(%a6)	# store result to stack
11703	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
11704	mov.l		%d1,%d2			# make a copy
11705	andi.l		&0x7fff,%d1		# strip sign
11706	andi.w		&0x8000,%d2		# keep old sign
11707	sub.l		%d0,%d1			# add scale factor
11708	addi.l		&0x6000,%d1		# subtract new bias
11709	andi.w		&0x7fff,%d1		# clear top bit
11710	or.w		%d2,%d1			# concat sgn,exp
11711	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
11712	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
11713	bra.w		fsub_unfl_dis
11714
11715fsub_unfl_ena_sd:
11716	mov.l		L_SCR3(%a6),%d1
11717	andi.b		&0x30,%d1		# clear rnd prec
11718	fmov.l		%d1,%fpcr		# set FPCR
11719
11720	bra.b		fsub_unfl_ena_cont
11721
11722#
11723# result is equal to the smallest normalized number in the selected precision
11724# if the precision is extended, this result could not have come from an
11725# underflow that rounded up.
11726#
11727fsub_may_unfl:
11728	mov.l		L_SCR3(%a6),%d1
11729	andi.b		&0xc0,%d1		# fetch rnd prec
11730	beq.w		fsub_normal		# yes; no underflow occurred
11731
11732	mov.l		0x4(%sp),%d1
11733	cmpi.l		%d1,&0x80000000		# is hi(man) = 0x80000000?
11734	bne.w		fsub_normal		# no; no underflow occurred
11735
11736	tst.l		0x8(%sp)		# is lo(man) = 0x0?
11737	bne.w		fsub_normal		# no; no underflow occurred
11738
11739	btst		&inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11740	beq.w		fsub_normal		# no; no underflow occurred
11741
11742#
11743# ok, so now the result has a exponent equal to the smallest normalized
11744# exponent for the selected precision. also, the mantissa is equal to
11745# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11746# g,r,s.
11747# now, we must determine whether the pre-rounded result was an underflow
11748# rounded "up" or a normalized number rounded "down".
11749# so, we do this be re-executing the add using RZ as the rounding mode and
11750# seeing if the new result is smaller or equal to the current result.
11751#
11752	fmovm.x		FP_SCR1(%a6),&0x40	# load dst op into fp1
11753
11754	mov.l		L_SCR3(%a6),%d1
11755	andi.b		&0xc0,%d1		# keep rnd prec
11756	ori.b		&rz_mode*0x10,%d1	# insert rnd mode
11757	fmov.l		%d1,%fpcr		# set FPCR
11758	fmov.l		&0x0,%fpsr		# clear FPSR
11759
11760	fsub.x		FP_SCR0(%a6),%fp1	# execute subtract
11761
11762	fmov.l		&0x0,%fpcr		# clear FPCR
11763
11764	fabs.x		%fp0			# compare absolute values
11765	fabs.x		%fp1
11766	fcmp.x		%fp0,%fp1		# is first result > second?
11767
11768	fbgt.w		fsub_unfl		# yes; it's an underflow
11769	bra.w		fsub_normal		# no; it's not an underflow
11770
11771##########################################################################
11772
11773#
11774# Sub: inputs are not both normalized; what are they?
11775#
11776fsub_not_norm:
11777	mov.w		(tbl_fsub_op.b,%pc,%d1.w*2),%d1
11778	jmp		(tbl_fsub_op.b,%pc,%d1.w*1)
11779
11780	swbeg		&48
11781tbl_fsub_op:
11782	short		fsub_norm	- tbl_fsub_op # NORM - NORM
11783	short		fsub_zero_src	- tbl_fsub_op # NORM - ZERO
11784	short		fsub_inf_src	- tbl_fsub_op # NORM - INF
11785	short		fsub_res_qnan	- tbl_fsub_op # NORM - QNAN
11786	short		fsub_norm	- tbl_fsub_op # NORM - DENORM
11787	short		fsub_res_snan	- tbl_fsub_op # NORM - SNAN
11788	short		tbl_fsub_op	- tbl_fsub_op #
11789	short		tbl_fsub_op	- tbl_fsub_op #
11790
11791	short		fsub_zero_dst	- tbl_fsub_op # ZERO - NORM
11792	short		fsub_zero_2	- tbl_fsub_op # ZERO - ZERO
11793	short		fsub_inf_src	- tbl_fsub_op # ZERO - INF
11794	short		fsub_res_qnan	- tbl_fsub_op # NORM - QNAN
11795	short		fsub_zero_dst	- tbl_fsub_op # ZERO - DENORM
11796	short		fsub_res_snan	- tbl_fsub_op # NORM - SNAN
11797	short		tbl_fsub_op	- tbl_fsub_op #
11798	short		tbl_fsub_op	- tbl_fsub_op #
11799
11800	short		fsub_inf_dst	- tbl_fsub_op # INF - NORM
11801	short		fsub_inf_dst	- tbl_fsub_op # INF - ZERO
11802	short		fsub_inf_2	- tbl_fsub_op # INF - INF
11803	short		fsub_res_qnan	- tbl_fsub_op # NORM - QNAN
11804	short		fsub_inf_dst	- tbl_fsub_op # INF - DENORM
11805	short		fsub_res_snan	- tbl_fsub_op # NORM - SNAN
11806	short		tbl_fsub_op	- tbl_fsub_op #
11807	short		tbl_fsub_op	- tbl_fsub_op #
11808
11809	short		fsub_res_qnan	- tbl_fsub_op # QNAN - NORM
11810	short		fsub_res_qnan	- tbl_fsub_op # QNAN - ZERO
11811	short		fsub_res_qnan	- tbl_fsub_op # QNAN - INF
11812	short		fsub_res_qnan	- tbl_fsub_op # QNAN - QNAN
11813	short		fsub_res_qnan	- tbl_fsub_op # QNAN - DENORM
11814	short		fsub_res_snan	- tbl_fsub_op # QNAN - SNAN
11815	short		tbl_fsub_op	- tbl_fsub_op #
11816	short		tbl_fsub_op	- tbl_fsub_op #
11817
11818	short		fsub_norm	- tbl_fsub_op # DENORM - NORM
11819	short		fsub_zero_src	- tbl_fsub_op # DENORM - ZERO
11820	short		fsub_inf_src	- tbl_fsub_op # DENORM - INF
11821	short		fsub_res_qnan	- tbl_fsub_op # NORM - QNAN
11822	short		fsub_norm	- tbl_fsub_op # DENORM - DENORM
11823	short		fsub_res_snan	- tbl_fsub_op # NORM - SNAN
11824	short		tbl_fsub_op	- tbl_fsub_op #
11825	short		tbl_fsub_op	- tbl_fsub_op #
11826
11827	short		fsub_res_snan	- tbl_fsub_op # SNAN - NORM
11828	short		fsub_res_snan	- tbl_fsub_op # SNAN - ZERO
11829	short		fsub_res_snan	- tbl_fsub_op # SNAN - INF
11830	short		fsub_res_snan	- tbl_fsub_op # SNAN - QNAN
11831	short		fsub_res_snan	- tbl_fsub_op # SNAN - DENORM
11832	short		fsub_res_snan	- tbl_fsub_op # SNAN - SNAN
11833	short		tbl_fsub_op	- tbl_fsub_op #
11834	short		tbl_fsub_op	- tbl_fsub_op #
11835
11836fsub_res_qnan:
11837	bra.l		res_qnan
11838fsub_res_snan:
11839	bra.l		res_snan
11840
11841#
11842# both operands are ZEROes
11843#
11844fsub_zero_2:
11845	mov.b		SRC_EX(%a0),%d0
11846	mov.b		DST_EX(%a1),%d1
11847	eor.b		%d1,%d0
11848	bpl.b		fsub_zero_2_chk_rm
11849
11850# the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO
11851	tst.b		%d0			# is dst negative?
11852	bmi.b		fsub_zero_2_rm		# yes
11853	fmov.s		&0x00000000,%fp0	# no; return +ZERO
11854	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
11855	rts
11856
11857#
11858# the ZEROes have the same signs:
11859# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
11860# - -ZERO is returned in the case of RM.
11861#
11862fsub_zero_2_chk_rm:
11863	mov.b		3+L_SCR3(%a6),%d1
11864	andi.b		&0x30,%d1		# extract rnd mode
11865	cmpi.b		%d1,&rm_mode*0x10	# is rnd mode = RM?
11866	beq.b		fsub_zero_2_rm		# yes
11867	fmov.s		&0x00000000,%fp0	# no; return +ZERO
11868	mov.b		&z_bmask,FPSR_CC(%a6)	# set Z
11869	rts
11870
11871fsub_zero_2_rm:
11872	fmov.s		&0x80000000,%fp0	# return -ZERO
11873	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6)	# set Z/NEG
11874	rts
11875
11876#
11877# one operand is a ZERO and the other is a DENORM or a NORM.
11878# scale the DENORM or NORM and jump to the regular fsub routine.
11879#
11880fsub_zero_dst:
11881	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
11882	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
11883	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
11884	bsr.l		scale_to_zero_src	# scale the operand
11885	clr.w		FP_SCR1_EX(%a6)
11886	clr.l		FP_SCR1_HI(%a6)
11887	clr.l		FP_SCR1_LO(%a6)
11888	bra.w		fsub_zero_entry		# go execute fsub
11889
11890fsub_zero_src:
11891	mov.w		DST_EX(%a1),FP_SCR1_EX(%a6)
11892	mov.l		DST_HI(%a1),FP_SCR1_HI(%a6)
11893	mov.l		DST_LO(%a1),FP_SCR1_LO(%a6)
11894	bsr.l		scale_to_zero_dst	# scale the operand
11895	clr.w		FP_SCR0_EX(%a6)
11896	clr.l		FP_SCR0_HI(%a6)
11897	clr.l		FP_SCR0_LO(%a6)
11898	bra.w		fsub_zero_entry		# go execute fsub
11899
11900#
11901# both operands are INFs. an OPERR will result if the INFs have the
11902# same signs. else,
11903#
11904fsub_inf_2:
11905	mov.b		SRC_EX(%a0),%d0		# exclusive or the signs
11906	mov.b		DST_EX(%a1),%d1
11907	eor.b		%d1,%d0
11908	bpl.l		res_operr		# weed out (-INF)+(+INF)
11909
11910# ok, so it's not an OPERR. but we do have to remember to return
11911# the src INF since that's where the 881/882 gets the j-bit.
11912
11913fsub_inf_src:
11914	fmovm.x		SRC(%a0),&0x80		# return src INF
11915	fneg.x		%fp0			# invert sign
11916	fbge.w		fsub_inf_done		# sign is now positive
11917	mov.b		&neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11918	rts
11919
11920fsub_inf_dst:
11921	fmovm.x		DST(%a1),&0x80		# return dst INF
11922	tst.b		DST_EX(%a1)		# is INF negative?
11923	bpl.b		fsub_inf_done		# no
11924	mov.b		&neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11925	rts
11926
11927fsub_inf_done:
11928	mov.b		&inf_bmask,FPSR_CC(%a6)	# set INF
11929	rts
11930
11931#########################################################################
11932# XDEF ****************************************************************	#
11933#	fsqrt(): emulates the fsqrt instruction				#
11934#	fssqrt(): emulates the fssqrt instruction			#
11935#	fdsqrt(): emulates the fdsqrt instruction			#
11936#									#
11937# XREF ****************************************************************	#
11938#	scale_sqrt() - scale the source operand				#
11939#	unf_res() - return default underflow result			#
11940#	ovf_res() - return default overflow result			#
11941#	res_qnan_1op() - return QNAN result				#
11942#	res_snan_1op() - return SNAN result				#
11943#									#
11944# INPUT ***************************************************************	#
11945#	a0 = pointer to extended precision source operand		#
11946#	d0  rnd prec,mode						#
11947#									#
11948# OUTPUT **************************************************************	#
11949#	fp0 = result							#
11950#	fp1 = EXOP (if exception occurred)				#
11951#									#
11952# ALGORITHM ***********************************************************	#
11953#	Handle NANs, infinities, and zeroes as special cases. Divide	#
11954# norms/denorms into ext/sgl/dbl precision.				#
11955#	For norms/denorms, scale the exponents such that a sqrt		#
11956# instruction won't cause an exception. Use the regular fsqrt to	#
11957# compute a result. Check if the regular operands would have taken	#
11958# an exception. If so, return the default overflow/underflow result	#
11959# and return the EXOP if exceptions are enabled. Else, scale the	#
11960# result operand to the proper exponent.				#
11961#									#
11962#########################################################################
11963
11964	global		fssqrt
11965fssqrt:
11966	andi.b		&0x30,%d0		# clear rnd prec
11967	ori.b		&s_mode*0x10,%d0	# insert sgl precision
11968	bra.b		fsqrt
11969
11970	global		fdsqrt
11971fdsqrt:
11972	andi.b		&0x30,%d0		# clear rnd prec
11973	ori.b		&d_mode*0x10,%d0	# insert dbl precision
11974
11975	global		fsqrt
11976fsqrt:
11977	mov.l		%d0,L_SCR3(%a6)		# store rnd info
11978	clr.w		%d1
11979	mov.b		STAG(%a6),%d1
11980	bne.w		fsqrt_not_norm		# optimize on non-norm input
11981
11982#
11983# SQUARE ROOT: norms and denorms ONLY!
11984#
11985fsqrt_norm:
11986	tst.b		SRC_EX(%a0)		# is operand negative?
11987	bmi.l		res_operr		# yes
11988
11989	andi.b		&0xc0,%d0		# is precision extended?
11990	bne.b		fsqrt_not_ext		# no; go handle sgl or dbl
11991
11992	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
11993	fmov.l		&0x0,%fpsr		# clear FPSR
11994
11995	fsqrt.x		(%a0),%fp0		# execute square root
11996
11997	fmov.l		%fpsr,%d1
11998	or.l		%d1,USER_FPSR(%a6)	# set N,INEX
11999
12000	rts
12001
12002fsqrt_denorm:
12003	tst.b		SRC_EX(%a0)		# is operand negative?
12004	bmi.l		res_operr		# yes
12005
12006	andi.b		&0xc0,%d0		# is precision extended?
12007	bne.b		fsqrt_not_ext		# no; go handle sgl or dbl
12008
12009	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
12010	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
12011	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
12012
12013	bsr.l		scale_sqrt		# calculate scale factor
12014
12015	bra.w		fsqrt_sd_normal
12016
12017#
12018# operand is either single or double
12019#
12020fsqrt_not_ext:
12021	cmpi.b		%d0,&s_mode*0x10	# separate sgl/dbl prec
12022	bne.w		fsqrt_dbl
12023
12024#
12025# operand is to be rounded to single precision
12026#
12027fsqrt_sgl:
12028	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
12029	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
12030	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
12031
12032	bsr.l		scale_sqrt		# calculate scale factor
12033
12034	cmpi.l		%d0,&0x3fff-0x3f81	# will move in underflow?
12035	beq.w		fsqrt_sd_may_unfl
12036	bgt.w		fsqrt_sd_unfl		# yes; go handle underflow
12037	cmpi.l		%d0,&0x3fff-0x407f	# will move in overflow?
12038	beq.w		fsqrt_sd_may_ovfl	# maybe; go check
12039	blt.w		fsqrt_sd_ovfl		# yes; go handle overflow
12040
12041#
12042# operand will NOT overflow or underflow when moved in to the fp reg file
12043#
12044fsqrt_sd_normal:
12045	fmov.l		&0x0,%fpsr		# clear FPSR
12046	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
12047
12048	fsqrt.x		FP_SCR0(%a6),%fp0	# perform absolute
12049
12050	fmov.l		%fpsr,%d1		# save FPSR
12051	fmov.l		&0x0,%fpcr		# clear FPCR
12052
12053	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
12054
12055fsqrt_sd_normal_exit:
12056	mov.l		%d2,-(%sp)		# save d2
12057	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
12058	mov.w		FP_SCR0_EX(%a6),%d1	# load sgn,exp
12059	mov.l		%d1,%d2			# make a copy
12060	andi.l		&0x7fff,%d1		# strip sign
12061	sub.l		%d0,%d1			# add scale factor
12062	andi.w		&0x8000,%d2		# keep old sign
12063	or.w		%d1,%d2			# concat old sign,new exp
12064	mov.w		%d2,FP_SCR0_EX(%a6)	# insert new exponent
12065	mov.l		(%sp)+,%d2		# restore d2
12066	fmovm.x		FP_SCR0(%a6),&0x80	# return result in fp0
12067	rts
12068
12069#
12070# operand is to be rounded to double precision
12071#
12072fsqrt_dbl:
12073	mov.w		SRC_EX(%a0),FP_SCR0_EX(%a6)
12074	mov.l		SRC_HI(%a0),FP_SCR0_HI(%a6)
12075	mov.l		SRC_LO(%a0),FP_SCR0_LO(%a6)
12076
12077	bsr.l		scale_sqrt		# calculate scale factor
12078
12079	cmpi.l		%d0,&0x3fff-0x3c01	# will move in underflow?
12080	beq.w		fsqrt_sd_may_unfl
12081	bgt.b		fsqrt_sd_unfl		# yes; go handle underflow
12082	cmpi.l		%d0,&0x3fff-0x43ff	# will move in overflow?
12083	beq.w		fsqrt_sd_may_ovfl	# maybe; go check
12084	blt.w		fsqrt_sd_ovfl		# yes; go handle overflow
12085	bra.w		fsqrt_sd_normal		# no; ho handle normalized op
12086
12087# we're on the line here and the distinguising characteristic is whether
12088# the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number
12089# elsewise fall through to underflow.
12090fsqrt_sd_may_unfl:
12091	btst		&0x0,1+FP_SCR0_EX(%a6)	# is exponent 0x3fff?
12092	bne.w		fsqrt_sd_normal		# yes, so no underflow
12093
12094#
12095# operand WILL underflow when moved in to the fp register file
12096#
12097fsqrt_sd_unfl:
12098	bset		&unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12099
12100	fmov.l		&rz_mode*0x10,%fpcr	# set FPCR
12101	fmov.l		&0x0,%fpsr		# clear FPSR
12102
12103	fsqrt.x		FP_SCR0(%a6),%fp0	# execute square root
12104
12105	fmov.l		%fpsr,%d1		# save status
12106	fmov.l		&0x0,%fpcr		# clear FPCR
12107
12108	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
12109
12110# if underflow or inexact is enabled, go calculate EXOP first.
12111	mov.b		FPCR_ENABLE(%a6),%d1
12112	andi.b		&0x0b,%d1		# is UNFL or INEX enabled?
12113	bne.b		fsqrt_sd_unfl_ena	# yes
12114
12115fsqrt_sd_unfl_dis:
12116	fmovm.x		&0x80,FP_SCR0(%a6)	# store out result
12117
12118	lea		FP_SCR0(%a6),%a0	# pass: result addr
12119	mov.l		L_SCR3(%a6),%d1		# pass: rnd prec,mode
12120	bsr.l		unf_res			# calculate default result
12121	or.b		%d0,FPSR_CC(%a6)	# set possible 'Z' ccode
12122	fmovm.x		FP_SCR0(%a6),&0x80	# return default result in fp0
12123	rts
12124
12125#
12126# operand will underflow AND underflow is enabled.
12127# Therefore, we must return the result rounded to extended precision.
12128#
12129fsqrt_sd_unfl_ena:
12130	mov.l		FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
12131	mov.l		FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
12132	mov.w		FP_SCR0_EX(%a6),%d1	# load current exponent
12133
12134	mov.l		%d2,-(%sp)		# save d2
12135	mov.l		%d1,%d2			# make a copy
12136	andi.l		&0x7fff,%d1		# strip sign
12137	andi.w		&0x8000,%d2		# keep old sign
12138	sub.l		%d0,%d1			# subtract scale factor
12139	addi.l		&0x6000,%d1		# add new bias
12140	andi.w		&0x7fff,%d1
12141	or.w		%d2,%d1			# concat new sign,new exp
12142	mov.w		%d1,FP_SCR1_EX(%a6)	# insert new exp
12143	fmovm.x		FP_SCR1(%a6),&0x40	# return EXOP in fp1
12144	mov.l		(%sp)+,%d2		# restore d2
12145	bra.b		fsqrt_sd_unfl_dis
12146
12147#
12148# operand WILL overflow.
12149#
12150fsqrt_sd_ovfl:
12151	fmov.l		&0x0,%fpsr		# clear FPSR
12152	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
12153
12154	fsqrt.x		FP_SCR0(%a6),%fp0	# perform square root
12155
12156	fmov.l		&0x0,%fpcr		# clear FPCR
12157	fmov.l		%fpsr,%d1		# save FPSR
12158
12159	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
12160
12161fsqrt_sd_ovfl_tst:
12162	or.l		&ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12163
12164	mov.b		FPCR_ENABLE(%a6),%d1
12165	andi.b		&0x13,%d1		# is OVFL or INEX enabled?
12166	bne.b		fsqrt_sd_ovfl_ena	# yes
12167
12168#
12169# OVFL is not enabled; therefore, we must create the default result by
12170# calling ovf_res().
12171#
12172fsqrt_sd_ovfl_dis:
12173	btst		&neg_bit,FPSR_CC(%a6)	# is result negative?
12174	sne		%d1			# set sign param accordingly
12175	mov.l		L_SCR3(%a6),%d0		# pass: prec,mode
12176	bsr.l		ovf_res			# calculate default result
12177	or.b		%d0,FPSR_CC(%a6)	# set INF,N if applicable
12178	fmovm.x		(%a0),&0x80		# return default result in fp0
12179	rts
12180
12181#
12182# OVFL is enabled.
12183# the INEX2 bit has already been updated by the round to the correct precision.
12184# now, round to extended(and don't alter the FPSR).
12185#
12186fsqrt_sd_ovfl_ena:
12187	mov.l		%d2,-(%sp)		# save d2
12188	mov.w		FP_SCR0_EX(%a6),%d1	# fetch {sgn,exp}
12189	mov.l		%d1,%d2			# make a copy
12190	andi.l		&0x7fff,%d1		# strip sign
12191	andi.w		&0x8000,%d2		# keep old sign
12192	sub.l		%d0,%d1			# add scale factor
12193	subi.l		&0x6000,%d1		# subtract bias
12194	andi.w		&0x7fff,%d1
12195	or.w		%d2,%d1			# concat sign,exp
12196	mov.w		%d1,FP_SCR0_EX(%a6)	# insert new exponent
12197	fmovm.x		FP_SCR0(%a6),&0x40	# return EXOP in fp1
12198	mov.l		(%sp)+,%d2		# restore d2
12199	bra.b		fsqrt_sd_ovfl_dis
12200
12201#
12202# the move in MAY underflow. so...
12203#
12204fsqrt_sd_may_ovfl:
12205	btst		&0x0,1+FP_SCR0_EX(%a6)	# is exponent 0x3fff?
12206	bne.w		fsqrt_sd_ovfl		# yes, so overflow
12207
12208	fmov.l		&0x0,%fpsr		# clear FPSR
12209	fmov.l		L_SCR3(%a6),%fpcr	# set FPCR
12210
12211	fsqrt.x		FP_SCR0(%a6),%fp0	# perform absolute
12212
12213	fmov.l		%fpsr,%d1		# save status
12214	fmov.l		&0x0,%fpcr		# clear FPCR
12215
12216	or.l		%d1,USER_FPSR(%a6)	# save INEX2,N
12217
12218	fmov.x		%fp0,%fp1		# make a copy of result
12219	fcmp.b		%fp1,&0x1		# is |result| >= 1.b?
12220	fbge.w		fsqrt_sd_ovfl_tst	# yes; overflow has occurred
12221
12222# no, it didn't overflow; we have correct result
12223	bra.w		fsqrt_sd_normal_exit
12224
12225##########################################################################
12226
12227#
12228# input is not normalized; what is it?
12229#
12230fsqrt_not_norm:
12231	cmpi.b		%d1,&DENORM		# weed out DENORM
12232	beq.w		fsqrt_denorm
12233	cmpi.b		%d1,&ZERO		# weed out ZERO
12234	beq.b		fsqrt_zero
12235	cmpi.b		%d1,&INF		# weed out INF
12236	beq.b		fsqrt_inf
12237	cmpi.b		%d1,&SNAN		# weed out SNAN
12238	beq.l		res_snan_1op
12239	bra.l		res_qnan_1op
12240
12241#
12242#	fsqrt(+0) = +0
12243#	fsqrt(-0) = -0
12244#	fsqrt(+INF) = +INF
12245#	fsqrt(-INF) = OPERR
12246#
12247fsqrt_zero:
12248	tst.b		SRC_EX(%a0)		# is ZERO positive or negative?
12249	bmi.b		fsqrt_zero_m		# negative
12250fsqrt_zero_p:
12251	fmov.s		&0x00000000,%fp0	# return +ZERO
12252	mov.b		&z_bmask,FPSR_CC(%a6)	# set 'Z' ccode bit
12253	rts
12254fsqrt_zero_m:
12255	fmov.s		&0x80000000,%fp0	# return -ZERO
12256	mov.b		&z_bmask+neg_bmask,FPSR_CC(%a6)	# set 'Z','N' ccode bits
12257	rts
12258
12259fsqrt_inf:
12260	tst.b		SRC_EX(%a0)		# is INF positive or negative?
12261	bmi.l		res_operr		# negative
12262fsqrt_inf_p:
12263	fmovm.x		SRC(%a0),&0x80		# return +INF in fp0
12264	mov.b		&inf_bmask,FPSR_CC(%a6)	# set 'I' ccode bit
12265	rts
12266
12267#########################################################################
12268# XDEF ****************************************************************	#
12269#	fetch_dreg(): fetch register according to index in d1		#
12270#									#
12271# XREF ****************************************************************	#
12272#	None								#
12273#									#
12274# INPUT ***************************************************************	#
12275#	d1 = index of register to fetch from				#
12276#									#
12277# OUTPUT **************************************************************	#
12278#	d0 = value of register fetched					#
12279#									#
12280# ALGORITHM ***********************************************************	#
12281#	According to the index value in d1 which can range from zero	#
12282# to fifteen, load the corresponding register file value (where		#
12283# address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the	#
12284# stack. The rest should still be in their original places.		#
12285#									#
12286#########################################################################
12287
12288# this routine leaves d1 intact for subsequent store_dreg calls.
12289	global		fetch_dreg
12290fetch_dreg:
12291	mov.w		(tbl_fdreg.b,%pc,%d1.w*2),%d0
12292	jmp		(tbl_fdreg.b,%pc,%d0.w*1)
12293
12294tbl_fdreg:
12295	short		fdreg0 - tbl_fdreg
12296	short		fdreg1 - tbl_fdreg
12297	short		fdreg2 - tbl_fdreg
12298	short		fdreg3 - tbl_fdreg
12299	short		fdreg4 - tbl_fdreg
12300	short		fdreg5 - tbl_fdreg
12301	short		fdreg6 - tbl_fdreg
12302	short		fdreg7 - tbl_fdreg
12303	short		fdreg8 - tbl_fdreg
12304	short		fdreg9 - tbl_fdreg
12305	short		fdrega - tbl_fdreg
12306	short		fdregb - tbl_fdreg
12307	short		fdregc - tbl_fdreg
12308	short		fdregd - tbl_fdreg
12309	short		fdrege - tbl_fdreg
12310	short		fdregf - tbl_fdreg
12311
12312fdreg0:
12313	mov.l		EXC_DREGS+0x0(%a6),%d0
12314	rts
12315fdreg1:
12316	mov.l		EXC_DREGS+0x4(%a6),%d0
12317	rts
12318fdreg2:
12319	mov.l		%d2,%d0
12320	rts
12321fdreg3:
12322	mov.l		%d3,%d0
12323	rts
12324fdreg4:
12325	mov.l		%d4,%d0
12326	rts
12327fdreg5:
12328	mov.l		%d5,%d0
12329	rts
12330fdreg6:
12331	mov.l		%d6,%d0
12332	rts
12333fdreg7:
12334	mov.l		%d7,%d0
12335	rts
12336fdreg8:
12337	mov.l		EXC_DREGS+0x8(%a6),%d0
12338	rts
12339fdreg9:
12340	mov.l		EXC_DREGS+0xc(%a6),%d0
12341	rts
12342fdrega:
12343	mov.l		%a2,%d0
12344	rts
12345fdregb:
12346	mov.l		%a3,%d0
12347	rts
12348fdregc:
12349	mov.l		%a4,%d0
12350	rts
12351fdregd:
12352	mov.l		%a5,%d0
12353	rts
12354fdrege:
12355	mov.l		(%a6),%d0
12356	rts
12357fdregf:
12358	mov.l		EXC_A7(%a6),%d0
12359	rts
12360
12361#########################################################################
12362# XDEF ****************************************************************	#
12363#	store_dreg_l(): store longword to data register specified by d1	#
12364#									#
12365# XREF ****************************************************************	#
12366#	None								#
12367#									#
12368# INPUT ***************************************************************	#
12369#	d0 = longowrd value to store					#
12370#	d1 = index of register to fetch from				#
12371#									#
12372# OUTPUT **************************************************************	#
12373#	(data register is updated)					#
12374#									#
12375# ALGORITHM ***********************************************************	#
12376#	According to the index value in d1, store the longword value	#
12377# in d0 to the corresponding data register. D0/D1 are on the stack	#
12378# while the rest are in their initial places.				#
12379#									#
12380#########################################################################
12381
12382	global		store_dreg_l
12383store_dreg_l:
12384	mov.w		(tbl_sdregl.b,%pc,%d1.w*2),%d1
12385	jmp		(tbl_sdregl.b,%pc,%d1.w*1)
12386
12387tbl_sdregl:
12388	short		sdregl0 - tbl_sdregl
12389	short		sdregl1 - tbl_sdregl
12390	short		sdregl2 - tbl_sdregl
12391	short		sdregl3 - tbl_sdregl
12392	short		sdregl4 - tbl_sdregl
12393	short		sdregl5 - tbl_sdregl
12394	short		sdregl6 - tbl_sdregl
12395	short		sdregl7 - tbl_sdregl
12396
12397sdregl0:
12398	mov.l		%d0,EXC_DREGS+0x0(%a6)
12399	rts
12400sdregl1:
12401	mov.l		%d0,EXC_DREGS+0x4(%a6)
12402	rts
12403sdregl2:
12404	mov.l		%d0,%d2
12405	rts
12406sdregl3:
12407	mov.l		%d0,%d3
12408	rts
12409sdregl4:
12410	mov.l		%d0,%d4
12411	rts
12412sdregl5:
12413	mov.l		%d0,%d5
12414	rts
12415sdregl6:
12416	mov.l		%d0,%d6
12417	rts
12418sdregl7:
12419	mov.l		%d0,%d7
12420	rts
12421
12422#########################################################################
12423# XDEF ****************************************************************	#
12424#	store_dreg_w(): store word to data register specified by d1	#
12425#									#
12426# XREF ****************************************************************	#
12427#	None								#
12428#									#
12429# INPUT ***************************************************************	#
12430#	d0 = word value to store					#
12431#	d1 = index of register to fetch from				#
12432#									#
12433# OUTPUT **************************************************************	#
12434#	(data register is updated)					#
12435#									#
12436# ALGORITHM ***********************************************************	#
12437#	According to the index value in d1, store the word value	#
12438# in d0 to the corresponding data register. D0/D1 are on the stack	#
12439# while the rest are in their initial places.				#
12440#									#
12441#########################################################################
12442
12443	global		store_dreg_w
12444store_dreg_w:
12445	mov.w		(tbl_sdregw.b,%pc,%d1.w*2),%d1
12446	jmp		(tbl_sdregw.b,%pc,%d1.w*1)
12447
12448tbl_sdregw:
12449	short		sdregw0 - tbl_sdregw
12450	short		sdregw1 - tbl_sdregw
12451	short		sdregw2 - tbl_sdregw
12452	short		sdregw3 - tbl_sdregw
12453	short		sdregw4 - tbl_sdregw
12454	short		sdregw5 - tbl_sdregw
12455	short		sdregw6 - tbl_sdregw
12456	short		sdregw7 - tbl_sdregw
12457
12458sdregw0:
12459	mov.w		%d0,2+EXC_DREGS+0x0(%a6)
12460	rts
12461sdregw1:
12462	mov.w		%d0,2+EXC_DREGS+0x4(%a6)
12463	rts
12464sdregw2:
12465	mov.w		%d0,%d2
12466	rts
12467sdregw3:
12468	mov.w		%d0,%d3
12469	rts
12470sdregw4:
12471	mov.w		%d0,%d4
12472	rts
12473sdregw5:
12474	mov.w		%d0,%d5
12475	rts
12476sdregw6:
12477	mov.w		%d0,%d6
12478	rts
12479sdregw7:
12480	mov.w		%d0,%d7
12481	rts
12482
12483#########################################################################
12484# XDEF ****************************************************************	#
12485#	store_dreg_b(): store byte to data register specified by d1	#
12486#									#
12487# XREF ****************************************************************	#
12488#	None								#
12489#									#
12490# INPUT ***************************************************************	#
12491#	d0 = byte value to store					#
12492#	d1 = index of register to fetch from				#
12493#									#
12494# OUTPUT **************************************************************	#
12495#	(data register is updated)					#
12496#									#
12497# ALGORITHM ***********************************************************	#
12498#	According to the index value in d1, store the byte value	#
12499# in d0 to the corresponding data register. D0/D1 are on the stack	#
12500# while the rest are in their initial places.				#
12501#									#
12502#########################################################################
12503
12504	global		store_dreg_b
12505store_dreg_b:
12506	mov.w		(tbl_sdregb.b,%pc,%d1.w*2),%d1
12507	jmp		(tbl_sdregb.b,%pc,%d1.w*1)
12508
12509tbl_sdregb:
12510	short		sdregb0 - tbl_sdregb
12511	short		sdregb1 - tbl_sdregb
12512	short		sdregb2 - tbl_sdregb
12513	short		sdregb3 - tbl_sdregb
12514	short		sdregb4 - tbl_sdregb
12515	short		sdregb5 - tbl_sdregb
12516	short		sdregb6 - tbl_sdregb
12517	short		sdregb7 - tbl_sdregb
12518
12519sdregb0:
12520	mov.b		%d0,3+EXC_DREGS+0x0(%a6)
12521	rts
12522sdregb1:
12523	mov.b		%d0,3+EXC_DREGS+0x4(%a6)
12524	rts
12525sdregb2:
12526	mov.b		%d0,%d2
12527	rts
12528sdregb3:
12529	mov.b		%d0,%d3
12530	rts
12531sdregb4:
12532	mov.b		%d0,%d4
12533	rts
12534sdregb5:
12535	mov.b		%d0,%d5
12536	rts
12537sdregb6:
12538	mov.b		%d0,%d6
12539	rts
12540sdregb7:
12541	mov.b		%d0,%d7
12542	rts
12543
12544#########################################################################
12545# XDEF ****************************************************************	#
12546#	inc_areg(): increment an address register by the value in d0	#
12547#									#
12548# XREF ****************************************************************	#
12549#	None								#
12550#									#
12551# INPUT ***************************************************************	#
12552#	d0 = amount to increment by					#
12553#	d1 = index of address register to increment			#
12554#									#
12555# OUTPUT **************************************************************	#
12556#	(address register is updated)					#
12557#									#
12558# ALGORITHM ***********************************************************	#
12559#	Typically used for an instruction w/ a post-increment <ea>,	#
12560# this routine adds the increment value in d0 to the address register	#
12561# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside	#
12562# in their original places.						#
12563#	For a7, if the increment amount is one, then we have to		#
12564# increment by two. For any a7 update, set the mia7_flag so that if	#
12565# an access error exception occurs later in emulation, this address	#
12566# register update can be undone.					#
12567#									#
12568#########################################################################
12569
12570	global		inc_areg
12571inc_areg:
12572	mov.w		(tbl_iareg.b,%pc,%d1.w*2),%d1
12573	jmp		(tbl_iareg.b,%pc,%d1.w*1)
12574
12575tbl_iareg:
12576	short		iareg0 - tbl_iareg
12577	short		iareg1 - tbl_iareg
12578	short		iareg2 - tbl_iareg
12579	short		iareg3 - tbl_iareg
12580	short		iareg4 - tbl_iareg
12581	short		iareg5 - tbl_iareg
12582	short		iareg6 - tbl_iareg
12583	short		iareg7 - tbl_iareg
12584
12585iareg0:	add.l		%d0,EXC_DREGS+0x8(%a6)
12586	rts
12587iareg1:	add.l		%d0,EXC_DREGS+0xc(%a6)
12588	rts
12589iareg2:	add.l		%d0,%a2
12590	rts
12591iareg3:	add.l		%d0,%a3
12592	rts
12593iareg4:	add.l		%d0,%a4
12594	rts
12595iareg5:	add.l		%d0,%a5
12596	rts
12597iareg6:	add.l		%d0,(%a6)
12598	rts
12599iareg7:	mov.b		&mia7_flg,SPCOND_FLG(%a6)
12600	cmpi.b		%d0,&0x1
12601	beq.b		iareg7b
12602	add.l		%d0,EXC_A7(%a6)
12603	rts
12604iareg7b:
12605	addq.l		&0x2,EXC_A7(%a6)
12606	rts
12607
12608#########################################################################
12609# XDEF ****************************************************************	#
12610#	dec_areg(): decrement an address register by the value in d0	#
12611#									#
12612# XREF ****************************************************************	#
12613#	None								#
12614#									#
12615# INPUT ***************************************************************	#
12616#	d0 = amount to decrement by					#
12617#	d1 = index of address register to decrement			#
12618#									#
12619# OUTPUT **************************************************************	#
12620#	(address register is updated)					#
12621#									#
12622# ALGORITHM ***********************************************************	#
12623#	Typically used for an instruction w/ a pre-decrement <ea>,	#
12624# this routine adds the decrement value in d0 to the address register	#
12625# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside	#
12626# in their original places.						#
12627#	For a7, if the decrement amount is one, then we have to		#
12628# decrement by two. For any a7 update, set the mda7_flag so that if	#
12629# an access error exception occurs later in emulation, this address	#
12630# register update can be undone.					#
12631#									#
12632#########################################################################
12633
12634	global		dec_areg
12635dec_areg:
12636	mov.w		(tbl_dareg.b,%pc,%d1.w*2),%d1
12637	jmp		(tbl_dareg.b,%pc,%d1.w*1)
12638
12639tbl_dareg:
12640	short		dareg0 - tbl_dareg
12641	short		dareg1 - tbl_dareg
12642	short		dareg2 - tbl_dareg
12643	short		dareg3 - tbl_dareg
12644	short		dareg4 - tbl_dareg
12645	short		dareg5 - tbl_dareg
12646	short		dareg6 - tbl_dareg
12647	short		dareg7 - tbl_dareg
12648
12649dareg0:	sub.l		%d0,EXC_DREGS+0x8(%a6)
12650	rts
12651dareg1:	sub.l		%d0,EXC_DREGS+0xc(%a6)
12652	rts
12653dareg2:	sub.l		%d0,%a2
12654	rts
12655dareg3:	sub.l		%d0,%a3
12656	rts
12657dareg4:	sub.l		%d0,%a4
12658	rts
12659dareg5:	sub.l		%d0,%a5
12660	rts
12661dareg6:	sub.l		%d0,(%a6)
12662	rts
12663dareg7:	mov.b		&mda7_flg,SPCOND_FLG(%a6)
12664	cmpi.b		%d0,&0x1
12665	beq.b		dareg7b
12666	sub.l		%d0,EXC_A7(%a6)
12667	rts
12668dareg7b:
12669	subq.l		&0x2,EXC_A7(%a6)
12670	rts
12671
12672##############################################################################
12673
12674#########################################################################
12675# XDEF ****************************************************************	#
12676#	load_fpn1(): load FP register value into FP_SRC(a6).		#
12677#									#
12678# XREF ****************************************************************	#
12679#	None								#
12680#									#
12681# INPUT ***************************************************************	#
12682#	d0 = index of FP register to load				#
12683#									#
12684# OUTPUT **************************************************************	#
12685#	FP_SRC(a6) = value loaded from FP register file			#
12686#									#
12687# ALGORITHM ***********************************************************	#
12688#	Using the index in d0, load FP_SRC(a6) with a number from the	#
12689# FP register file.							#
12690#									#
12691#########################################################################
12692
12693	global		load_fpn1
12694load_fpn1:
12695	mov.w		(tbl_load_fpn1.b,%pc,%d0.w*2), %d0
12696	jmp		(tbl_load_fpn1.b,%pc,%d0.w*1)
12697
12698tbl_load_fpn1:
12699	short		load_fpn1_0 - tbl_load_fpn1
12700	short		load_fpn1_1 - tbl_load_fpn1
12701	short		load_fpn1_2 - tbl_load_fpn1
12702	short		load_fpn1_3 - tbl_load_fpn1
12703	short		load_fpn1_4 - tbl_load_fpn1
12704	short		load_fpn1_5 - tbl_load_fpn1
12705	short		load_fpn1_6 - tbl_load_fpn1
12706	short		load_fpn1_7 - tbl_load_fpn1
12707
12708load_fpn1_0:
12709	mov.l		0+EXC_FP0(%a6), 0+FP_SRC(%a6)
12710	mov.l		4+EXC_FP0(%a6), 4+FP_SRC(%a6)
12711	mov.l		8+EXC_FP0(%a6), 8+FP_SRC(%a6)
12712	lea		FP_SRC(%a6), %a0
12713	rts
12714load_fpn1_1:
12715	mov.l		0+EXC_FP1(%a6), 0+FP_SRC(%a6)
12716	mov.l		4+EXC_FP1(%a6), 4+FP_SRC(%a6)
12717	mov.l		8+EXC_FP1(%a6), 8+FP_SRC(%a6)
12718	lea		FP_SRC(%a6), %a0
12719	rts
12720load_fpn1_2:
12721	fmovm.x		&0x20, FP_SRC(%a6)
12722	lea		FP_SRC(%a6), %a0
12723	rts
12724load_fpn1_3:
12725	fmovm.x		&0x10, FP_SRC(%a6)
12726	lea		FP_SRC(%a6), %a0
12727	rts
12728load_fpn1_4:
12729	fmovm.x		&0x08, FP_SRC(%a6)
12730	lea		FP_SRC(%a6), %a0
12731	rts
12732load_fpn1_5:
12733	fmovm.x		&0x04, FP_SRC(%a6)
12734	lea		FP_SRC(%a6), %a0
12735	rts
12736load_fpn1_6:
12737	fmovm.x		&0x02, FP_SRC(%a6)
12738	lea		FP_SRC(%a6), %a0
12739	rts
12740load_fpn1_7:
12741	fmovm.x		&0x01, FP_SRC(%a6)
12742	lea		FP_SRC(%a6), %a0
12743	rts
12744
12745#############################################################################
12746
12747#########################################################################
12748# XDEF ****************************************************************	#
12749#	load_fpn2(): load FP register value into FP_DST(a6).		#
12750#									#
12751# XREF ****************************************************************	#
12752#	None								#
12753#									#
12754# INPUT ***************************************************************	#
12755#	d0 = index of FP register to load				#
12756#									#
12757# OUTPUT **************************************************************	#
12758#	FP_DST(a6) = value loaded from FP register file			#
12759#									#
12760# ALGORITHM ***********************************************************	#
12761#	Using the index in d0, load FP_DST(a6) with a number from the	#
12762# FP register file.							#
12763#									#
12764#########################################################################
12765
12766	global		load_fpn2
12767load_fpn2:
12768	mov.w		(tbl_load_fpn2.b,%pc,%d0.w*2), %d0
12769	jmp		(tbl_load_fpn2.b,%pc,%d0.w*1)
12770
12771tbl_load_fpn2:
12772	short		load_fpn2_0 - tbl_load_fpn2
12773	short		load_fpn2_1 - tbl_load_fpn2
12774	short		load_fpn2_2 - tbl_load_fpn2
12775	short		load_fpn2_3 - tbl_load_fpn2
12776	short		load_fpn2_4 - tbl_load_fpn2
12777	short		load_fpn2_5 - tbl_load_fpn2
12778	short		load_fpn2_6 - tbl_load_fpn2
12779	short		load_fpn2_7 - tbl_load_fpn2
12780
12781load_fpn2_0:
12782	mov.l		0+EXC_FP0(%a6), 0+FP_DST(%a6)
12783	mov.l		4+EXC_FP0(%a6), 4+FP_DST(%a6)
12784	mov.l		8+EXC_FP0(%a6), 8+FP_DST(%a6)
12785	lea		FP_DST(%a6), %a0
12786	rts
12787load_fpn2_1:
12788	mov.l		0+EXC_FP1(%a6), 0+FP_DST(%a6)
12789	mov.l		4+EXC_FP1(%a6), 4+FP_DST(%a6)
12790	mov.l		8+EXC_FP1(%a6), 8+FP_DST(%a6)
12791	lea		FP_DST(%a6), %a0
12792	rts
12793load_fpn2_2:
12794	fmovm.x		&0x20, FP_DST(%a6)
12795	lea		FP_DST(%a6), %a0
12796	rts
12797load_fpn2_3:
12798	fmovm.x		&0x10, FP_DST(%a6)
12799	lea		FP_DST(%a6), %a0
12800	rts
12801load_fpn2_4:
12802	fmovm.x		&0x08, FP_DST(%a6)
12803	lea		FP_DST(%a6), %a0
12804	rts
12805load_fpn2_5:
12806	fmovm.x		&0x04, FP_DST(%a6)
12807	lea		FP_DST(%a6), %a0
12808	rts
12809load_fpn2_6:
12810	fmovm.x		&0x02, FP_DST(%a6)
12811	lea		FP_DST(%a6), %a0
12812	rts
12813load_fpn2_7:
12814	fmovm.x		&0x01, FP_DST(%a6)
12815	lea		FP_DST(%a6), %a0
12816	rts
12817
12818#############################################################################
12819
12820#########################################################################
12821# XDEF ****************************************************************	#
12822#	store_fpreg(): store an fp value to the fpreg designated d0.	#
12823#									#
12824# XREF ****************************************************************	#
12825#	None								#
12826#									#
12827# INPUT ***************************************************************	#
12828#	fp0 = extended precision value to store				#
12829#	d0  = index of floating-point register				#
12830#									#
12831# OUTPUT **************************************************************	#
12832#	None								#
12833#									#
12834# ALGORITHM ***********************************************************	#
12835#	Store the value in fp0 to the FP register designated by the	#
12836# value in d0. The FP number can be DENORM or SNAN so we have to be	#
12837# careful that we don't take an exception here.				#
12838#									#
12839#########################################################################
12840
12841	global		store_fpreg
12842store_fpreg:
12843	mov.w		(tbl_store_fpreg.b,%pc,%d0.w*2), %d0
12844	jmp		(tbl_store_fpreg.b,%pc,%d0.w*1)
12845
12846tbl_store_fpreg:
12847	short		store_fpreg_0 - tbl_store_fpreg
12848	short		store_fpreg_1 - tbl_store_fpreg
12849	short		store_fpreg_2 - tbl_store_fpreg
12850	short		store_fpreg_3 - tbl_store_fpreg
12851	short		store_fpreg_4 - tbl_store_fpreg
12852	short		store_fpreg_5 - tbl_store_fpreg
12853	short		store_fpreg_6 - tbl_store_fpreg
12854	short		store_fpreg_7 - tbl_store_fpreg
12855
12856store_fpreg_0:
12857	fmovm.x		&0x80, EXC_FP0(%a6)
12858	rts
12859store_fpreg_1:
12860	fmovm.x		&0x80, EXC_FP1(%a6)
12861	rts
12862store_fpreg_2:
12863	fmovm.x		&0x01, -(%sp)
12864	fmovm.x		(%sp)+, &0x20
12865	rts
12866store_fpreg_3:
12867	fmovm.x		&0x01, -(%sp)
12868	fmovm.x		(%sp)+, &0x10
12869	rts
12870store_fpreg_4:
12871	fmovm.x		&0x01, -(%sp)
12872	fmovm.x		(%sp)+, &0x08
12873	rts
12874store_fpreg_5:
12875	fmovm.x		&0x01, -(%sp)
12876	fmovm.x		(%sp)+, &0x04
12877	rts
12878store_fpreg_6:
12879	fmovm.x		&0x01, -(%sp)
12880	fmovm.x		(%sp)+, &0x02
12881	rts
12882store_fpreg_7:
12883	fmovm.x		&0x01, -(%sp)
12884	fmovm.x		(%sp)+, &0x01
12885	rts
12886
12887#########################################################################
12888# XDEF ****************************************************************	#
12889#	get_packed(): fetch a packed operand from memory and then	#
12890#		      convert it to a floating-point binary number.	#
12891#									#
12892# XREF ****************************************************************	#
12893#	_dcalc_ea() - calculate the correct <ea>			#
12894#	_mem_read() - fetch the packed operand from memory		#
12895#	facc_in_x() - the fetch failed so jump to special exit code	#
12896#	decbin()    - convert packed to binary extended precision	#
12897#									#
12898# INPUT ***************************************************************	#
12899#	None								#
12900#									#
12901# OUTPUT **************************************************************	#
12902#	If no failure on _mem_read():					#
12903#	FP_SRC(a6) = packed operand now as a binary FP number		#
12904#									#
12905# ALGORITHM ***********************************************************	#
12906#	Get the correct <ea> which is the value on the exception stack	#
12907# frame w/ maybe a correction factor if the <ea> is -(an) or (an)+.	#
12908# Then, fetch the operand from memory. If the fetch fails, exit		#
12909# through facc_in_x().							#
12910#	If the packed operand is a ZERO,NAN, or INF, convert it to	#
12911# its binary representation here. Else, call decbin() which will	#
12912# convert the packed value to an extended precision binary value.	#
12913#									#
12914#########################################################################
12915
12916# the stacked <ea> for packed is correct except for -(An).
12917# the base reg must be updated for both -(An) and (An)+.
12918	global		get_packed
12919get_packed:
12920	mov.l		&0xc,%d0		# packed is 12 bytes
12921	bsr.l		_dcalc_ea		# fetch <ea>; correct An
12922
12923	lea		FP_SRC(%a6),%a1		# pass: ptr to super dst
12924	mov.l		&0xc,%d0		# pass: 12 bytes
12925	bsr.l		_dmem_read		# read packed operand
12926
12927	tst.l		%d1			# did dfetch fail?
12928	bne.l		facc_in_x		# yes
12929
12930# The packed operand is an INF or a NAN if the exponent field is all ones.
12931	bfextu		FP_SRC(%a6){&1:&15},%d0	# get exp
12932	cmpi.w		%d0,&0x7fff		# INF or NAN?
12933	bne.b		gp_try_zero		# no
12934	rts					# operand is an INF or NAN
12935
12936# The packed operand is a zero if the mantissa is all zero, else it's
12937# a normal packed op.
12938gp_try_zero:
12939	mov.b		3+FP_SRC(%a6),%d0	# get byte 4
12940	andi.b		&0x0f,%d0		# clear all but last nybble
12941	bne.b		gp_not_spec		# not a zero
12942	tst.l		FP_SRC_HI(%a6)		# is lw 2 zero?
12943	bne.b		gp_not_spec		# not a zero
12944	tst.l		FP_SRC_LO(%a6)		# is lw 3 zero?
12945	bne.b		gp_not_spec		# not a zero
12946	rts					# operand is a ZERO
12947gp_not_spec:
12948	lea		FP_SRC(%a6),%a0		# pass: ptr to packed op
12949	bsr.l		decbin			# convert to extended
12950	fmovm.x		&0x80,FP_SRC(%a6)	# make this the srcop
12951	rts
12952
12953#########################################################################
12954# decbin(): Converts normalized packed bcd value pointed to by register	#
12955#	    a0 to extended-precision value in fp0.			#
12956#									#
12957# INPUT ***************************************************************	#
12958#	a0 = pointer to normalized packed bcd value			#
12959#									#
12960# OUTPUT **************************************************************	#
12961#	fp0 = exact fp representation of the packed bcd value.		#
12962#									#
12963# ALGORITHM ***********************************************************	#
12964#	Expected is a normal bcd (i.e. non-exceptional; all inf, zero,	#
12965#	and NaN operands are dispatched without entering this routine)	#
12966#	value in 68881/882 format at location (a0).			#
12967#									#
12968#	A1. Convert the bcd exponent to binary by successive adds and	#
12969#	muls. Set the sign according to SE. Subtract 16 to compensate	#
12970#	for the mantissa which is to be interpreted as 17 integer	#
12971#	digits, rather than 1 integer and 16 fraction digits.		#
12972#	Note: this operation can never overflow.			#
12973#									#
12974#	A2. Convert the bcd mantissa to binary by successive		#
12975#	adds and muls in FP0. Set the sign according to SM.		#
12976#	The mantissa digits will be converted with the decimal point	#
12977#	assumed following the least-significant digit.			#
12978#	Note: this operation can never overflow.			#
12979#									#
12980#	A3. Count the number of leading/trailing zeros in the		#
12981#	bcd string.  If SE is positive, count the leading zeros;	#
12982#	if negative, count the trailing zeros.  Set the adjusted	#
12983#	exponent equal to the exponent from A1 and the zero count	#
12984#	added if SM = 1 and subtracted if SM = 0.  Scale the		#
12985#	mantissa the equivalent of forcing in the bcd value:		#
12986#									#
12987#	SM = 0	a non-zero digit in the integer position		#
12988#	SM = 1	a non-zero digit in Mant0, lsd of the fraction		#
12989#									#
12990#	this will insure that any value, regardless of its		#
12991#	representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted	#
12992#	consistently.							#
12993#									#
12994#	A4. Calculate the factor 10^exp in FP1 using a table of		#
12995#	10^(2^n) values.  To reduce the error in forming factors	#
12996#	greater than 10^27, a directed rounding scheme is used with	#
12997#	tables rounded to RN, RM, and RP, according to the table	#
12998#	in the comments of the pwrten section.				#
12999#									#
13000#	A5. Form the final binary number by scaling the mantissa by	#
13001#	the exponent factor.  This is done by multiplying the		#
13002#	mantissa in FP0 by the factor in FP1 if the adjusted		#
13003#	exponent sign is positive, and dividing FP0 by FP1 if		#
13004#	it is negative.							#
13005#									#
13006#	Clean up and return. Check if the final mul or div was inexact.	#
13007#	If so, set INEX1 in USER_FPSR.					#
13008#									#
13009#########################################################################
13010
13011#
13012#	PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
13013#	to nearest, minus, and plus, respectively.  The tables include
13014#	10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
13015#	is required until the power is greater than 27, however, all
13016#	tables include the first 5 for ease of indexing.
13017#
13018RTABLE:
13019	byte		0,0,0,0
13020	byte		2,3,2,3
13021	byte		2,3,3,2
13022	byte		3,2,2,3
13023
13024	set		FNIBS,7
13025	set		FSTRT,0
13026
13027	set		ESTRT,4
13028	set		EDIGITS,2
13029
13030	global		decbin
13031decbin:
13032	mov.l		0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input
13033	mov.l		0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it
13034	mov.l		0x8(%a0),FP_SCR0_LO(%a6)
13035
13036	lea		FP_SCR0(%a6),%a0
13037
13038	movm.l		&0x3c00,-(%sp)		# save d2-d5
13039	fmovm.x		&0x1,-(%sp)		# save fp1
13040#
13041# Calculate exponent:
13042#  1. Copy bcd value in memory for use as a working copy.
13043#  2. Calculate absolute value of exponent in d1 by mul and add.
13044#  3. Correct for exponent sign.
13045#  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
13046#     (i.e., all digits assumed left of the decimal point.)
13047#
13048# Register usage:
13049#
13050#  calc_e:
13051#	(*)  d0: temp digit storage
13052#	(*)  d1: accumulator for binary exponent
13053#	(*)  d2: digit count
13054#	(*)  d3: offset pointer
13055#	( )  d4: first word of bcd
13056#	( )  a0: pointer to working bcd value
13057#	( )  a6: pointer to original bcd value
13058#	(*)  FP_SCR1: working copy of original bcd value
13059#	(*)  L_SCR1: copy of original exponent word
13060#
13061calc_e:
13062	mov.l		&EDIGITS,%d2		# # of nibbles (digits) in fraction part
13063	mov.l		&ESTRT,%d3		# counter to pick up digits
13064	mov.l		(%a0),%d4		# get first word of bcd
13065	clr.l		%d1			# zero d1 for accumulator
13066e_gd:
13067	mulu.l		&0xa,%d1		# mul partial product by one digit place
13068	bfextu		%d4{%d3:&4},%d0		# get the digit and zero extend into d0
13069	add.l		%d0,%d1			# d1 = d1 + d0
13070	addq.b		&4,%d3			# advance d3 to the next digit
13071	dbf.w		%d2,e_gd		# if we have used all 3 digits, exit loop
13072	btst		&30,%d4			# get SE
13073	beq.b		e_pos			# don't negate if pos
13074	neg.l		%d1			# negate before subtracting
13075e_pos:
13076	sub.l		&16,%d1			# sub to compensate for shift of mant
13077	bge.b		e_save			# if still pos, do not neg
13078	neg.l		%d1			# now negative, make pos and set SE
13079	or.l		&0x40000000,%d4		# set SE in d4,
13080	or.l		&0x40000000,(%a0)	# and in working bcd
13081e_save:
13082	mov.l		%d1,-(%sp)		# save exp on stack
13083#
13084#
13085# Calculate mantissa:
13086#  1. Calculate absolute value of mantissa in fp0 by mul and add.
13087#  2. Correct for mantissa sign.
13088#     (i.e., all digits assumed left of the decimal point.)
13089#
13090# Register usage:
13091#
13092#  calc_m:
13093#	(*)  d0: temp digit storage
13094#	(*)  d1: lword counter
13095#	(*)  d2: digit count
13096#	(*)  d3: offset pointer
13097#	( )  d4: words 2 and 3 of bcd
13098#	( )  a0: pointer to working bcd value
13099#	( )  a6: pointer to original bcd value
13100#	(*) fp0: mantissa accumulator
13101#	( )  FP_SCR1: working copy of original bcd value
13102#	( )  L_SCR1: copy of original exponent word
13103#
13104calc_m:
13105	mov.l		&1,%d1			# word counter, init to 1
13106	fmov.s		&0x00000000,%fp0	# accumulator
13107#
13108#
13109#  Since the packed number has a long word between the first & second parts,
13110#  get the integer digit then skip down & get the rest of the
13111#  mantissa.  We will unroll the loop once.
13112#
13113	bfextu		(%a0){&28:&4},%d0	# integer part is ls digit in long word
13114	fadd.b		%d0,%fp0		# add digit to sum in fp0
13115#
13116#
13117#  Get the rest of the mantissa.
13118#
13119loadlw:
13120	mov.l		(%a0,%d1.L*4),%d4	# load mantissa lonqword into d4
13121	mov.l		&FSTRT,%d3		# counter to pick up digits
13122	mov.l		&FNIBS,%d2		# reset number of digits per a0 ptr
13123md2b:
13124	fmul.s		&0x41200000,%fp0	# fp0 = fp0 * 10
13125	bfextu		%d4{%d3:&4},%d0		# get the digit and zero extend
13126	fadd.b		%d0,%fp0		# fp0 = fp0 + digit
13127#
13128#
13129#  If all the digits (8) in that long word have been converted (d2=0),
13130#  then inc d1 (=2) to point to the next long word and reset d3 to 0
13131#  to initialize the digit offset, and set d2 to 7 for the digit count;
13132#  else continue with this long word.
13133#
13134	addq.b		&4,%d3			# advance d3 to the next digit
13135	dbf.w		%d2,md2b		# check for last digit in this lw
13136nextlw:
13137	addq.l		&1,%d1			# inc lw pointer in mantissa
13138	cmp.l		%d1,&2			# test for last lw
13139	ble.b		loadlw			# if not, get last one
13140#
13141#  Check the sign of the mant and make the value in fp0 the same sign.
13142#
13143m_sign:
13144	btst		&31,(%a0)		# test sign of the mantissa
13145	beq.b		ap_st_z			# if clear, go to append/strip zeros
13146	fneg.x		%fp0			# if set, negate fp0
13147#
13148# Append/strip zeros:
13149#
13150#  For adjusted exponents which have an absolute value greater than 27*,
13151#  this routine calculates the amount needed to normalize the mantissa
13152#  for the adjusted exponent.  That number is subtracted from the exp
13153#  if the exp was positive, and added if it was negative.  The purpose
13154#  of this is to reduce the value of the exponent and the possibility
13155#  of error in calculation of pwrten.
13156#
13157#  1. Branch on the sign of the adjusted exponent.
13158#  2p.(positive exp)
13159#   2. Check M16 and the digits in lwords 2 and 3 in descending order.
13160#   3. Add one for each zero encountered until a non-zero digit.
13161#   4. Subtract the count from the exp.
13162#   5. Check if the exp has crossed zero in #3 above; make the exp abs
13163#	   and set SE.
13164#	6. Multiply the mantissa by 10**count.
13165#  2n.(negative exp)
13166#   2. Check the digits in lwords 3 and 2 in descending order.
13167#   3. Add one for each zero encountered until a non-zero digit.
13168#   4. Add the count to the exp.
13169#   5. Check if the exp has crossed zero in #3 above; clear SE.
13170#   6. Divide the mantissa by 10**count.
13171#
13172#  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
13173#   any adjustment due to append/strip zeros will drive the resultane
13174#   exponent towards zero.  Since all pwrten constants with a power
13175#   of 27 or less are exact, there is no need to use this routine to
13176#   attempt to lessen the resultant exponent.
13177#
13178# Register usage:
13179#
13180#  ap_st_z:
13181#	(*)  d0: temp digit storage
13182#	(*)  d1: zero count
13183#	(*)  d2: digit count
13184#	(*)  d3: offset pointer
13185#	( )  d4: first word of bcd
13186#	(*)  d5: lword counter
13187#	( )  a0: pointer to working bcd value
13188#	( )  FP_SCR1: working copy of original bcd value
13189#	( )  L_SCR1: copy of original exponent word
13190#
13191#
13192# First check the absolute value of the exponent to see if this
13193# routine is necessary.  If so, then check the sign of the exponent
13194# and do append (+) or strip (-) zeros accordingly.
13195# This section handles a positive adjusted exponent.
13196#
13197ap_st_z:
13198	mov.l		(%sp),%d1		# load expA for range test
13199	cmp.l		%d1,&27			# test is with 27
13200	ble.w		pwrten			# if abs(expA) <28, skip ap/st zeros
13201	btst		&30,(%a0)		# check sign of exp
13202	bne.b		ap_st_n			# if neg, go to neg side
13203	clr.l		%d1			# zero count reg
13204	mov.l		(%a0),%d4		# load lword 1 to d4
13205	bfextu		%d4{&28:&4},%d0		# get M16 in d0
13206	bne.b		ap_p_fx			# if M16 is non-zero, go fix exp
13207	addq.l		&1,%d1			# inc zero count
13208	mov.l		&1,%d5			# init lword counter
13209	mov.l		(%a0,%d5.L*4),%d4	# get lword 2 to d4
13210	bne.b		ap_p_cl			# if lw 2 is zero, skip it
13211	addq.l		&8,%d1			# and inc count by 8
13212	addq.l		&1,%d5			# inc lword counter
13213	mov.l		(%a0,%d5.L*4),%d4	# get lword 3 to d4
13214ap_p_cl:
13215	clr.l		%d3			# init offset reg
13216	mov.l		&7,%d2			# init digit counter
13217ap_p_gd:
13218	bfextu		%d4{%d3:&4},%d0		# get digit
13219	bne.b		ap_p_fx			# if non-zero, go to fix exp
13220	addq.l		&4,%d3			# point to next digit
13221	addq.l		&1,%d1			# inc digit counter
13222	dbf.w		%d2,ap_p_gd		# get next digit
13223ap_p_fx:
13224	mov.l		%d1,%d0			# copy counter to d2
13225	mov.l		(%sp),%d1		# get adjusted exp from memory
13226	sub.l		%d0,%d1			# subtract count from exp
13227	bge.b		ap_p_fm			# if still pos, go to pwrten
13228	neg.l		%d1			# now its neg; get abs
13229	mov.l		(%a0),%d4		# load lword 1 to d4
13230	or.l		&0x40000000,%d4		# and set SE in d4
13231	or.l		&0x40000000,(%a0)	# and in memory
13232#
13233# Calculate the mantissa multiplier to compensate for the striping of
13234# zeros from the mantissa.
13235#
13236ap_p_fm:
13237	lea.l		PTENRN(%pc),%a1		# get address of power-of-ten table
13238	clr.l		%d3			# init table index
13239	fmov.s		&0x3f800000,%fp1	# init fp1 to 1
13240	mov.l		&3,%d2			# init d2 to count bits in counter
13241ap_p_el:
13242	asr.l		&1,%d0			# shift lsb into carry
13243	bcc.b		ap_p_en			# if 1, mul fp1 by pwrten factor
13244	fmul.x		(%a1,%d3),%fp1		# mul by 10**(d3_bit_no)
13245ap_p_en:
13246	add.l		&12,%d3			# inc d3 to next rtable entry
13247	tst.l		%d0			# check if d0 is zero
13248	bne.b		ap_p_el			# if not, get next bit
13249	fmul.x		%fp1,%fp0		# mul mantissa by 10**(no_bits_shifted)
13250	bra.b		pwrten			# go calc pwrten
13251#
13252# This section handles a negative adjusted exponent.
13253#
13254ap_st_n:
13255	clr.l		%d1			# clr counter
13256	mov.l		&2,%d5			# set up d5 to point to lword 3
13257	mov.l		(%a0,%d5.L*4),%d4	# get lword 3
13258	bne.b		ap_n_cl			# if not zero, check digits
13259	sub.l		&1,%d5			# dec d5 to point to lword 2
13260	addq.l		&8,%d1			# inc counter by 8
13261	mov.l		(%a0,%d5.L*4),%d4	# get lword 2
13262ap_n_cl:
13263	mov.l		&28,%d3			# point to last digit
13264	mov.l		&7,%d2			# init digit counter
13265ap_n_gd:
13266	bfextu		%d4{%d3:&4},%d0		# get digit
13267	bne.b		ap_n_fx			# if non-zero, go to exp fix
13268	subq.l		&4,%d3			# point to previous digit
13269	addq.l		&1,%d1			# inc digit counter
13270	dbf.w		%d2,ap_n_gd		# get next digit
13271ap_n_fx:
13272	mov.l		%d1,%d0			# copy counter to d0
13273	mov.l		(%sp),%d1		# get adjusted exp from memory
13274	sub.l		%d0,%d1			# subtract count from exp
13275	bgt.b		ap_n_fm			# if still pos, go fix mantissa
13276	neg.l		%d1			# take abs of exp and clr SE
13277	mov.l		(%a0),%d4		# load lword 1 to d4
13278	and.l		&0xbfffffff,%d4		# and clr SE in d4
13279	and.l		&0xbfffffff,(%a0)	# and in memory
13280#
13281# Calculate the mantissa multiplier to compensate for the appending of
13282# zeros to the mantissa.
13283#
13284ap_n_fm:
13285	lea.l		PTENRN(%pc),%a1		# get address of power-of-ten table
13286	clr.l		%d3			# init table index
13287	fmov.s		&0x3f800000,%fp1	# init fp1 to 1
13288	mov.l		&3,%d2			# init d2 to count bits in counter
13289ap_n_el:
13290	asr.l		&1,%d0			# shift lsb into carry
13291	bcc.b		ap_n_en			# if 1, mul fp1 by pwrten factor
13292	fmul.x		(%a1,%d3),%fp1		# mul by 10**(d3_bit_no)
13293ap_n_en:
13294	add.l		&12,%d3			# inc d3 to next rtable entry
13295	tst.l		%d0			# check if d0 is zero
13296	bne.b		ap_n_el			# if not, get next bit
13297	fdiv.x		%fp1,%fp0		# div mantissa by 10**(no_bits_shifted)
13298#
13299#
13300# Calculate power-of-ten factor from adjusted and shifted exponent.
13301#
13302# Register usage:
13303#
13304#  pwrten:
13305#	(*)  d0: temp
13306#	( )  d1: exponent
13307#	(*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
13308#	(*)  d3: FPCR work copy
13309#	( )  d4: first word of bcd
13310#	(*)  a1: RTABLE pointer
13311#  calc_p:
13312#	(*)  d0: temp
13313#	( )  d1: exponent
13314#	(*)  d3: PWRTxx table index
13315#	( )  a0: pointer to working copy of bcd
13316#	(*)  a1: PWRTxx pointer
13317#	(*) fp1: power-of-ten accumulator
13318#
13319# Pwrten calculates the exponent factor in the selected rounding mode
13320# according to the following table:
13321#
13322#	Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
13323#
13324#	ANY	  ANY	RN	RN
13325#
13326#	 +	   +	RP	RP
13327#	 -	   +	RP	RM
13328#	 +	   -	RP	RM
13329#	 -	   -	RP	RP
13330#
13331#	 +	   +	RM	RM
13332#	 -	   +	RM	RP
13333#	 +	   -	RM	RP
13334#	 -	   -	RM	RM
13335#
13336#	 +	   +	RZ	RM
13337#	 -	   +	RZ	RM
13338#	 +	   -	RZ	RP
13339#	 -	   -	RZ	RP
13340#
13341#
13342pwrten:
13343	mov.l		USER_FPCR(%a6),%d3	# get user's FPCR
13344	bfextu		%d3{&26:&2},%d2		# isolate rounding mode bits
13345	mov.l		(%a0),%d4		# reload 1st bcd word to d4
13346	asl.l		&2,%d2			# format d2 to be
13347	bfextu		%d4{&0:&2},%d0		# {FPCR[6],FPCR[5],SM,SE}
13348	add.l		%d0,%d2			# in d2 as index into RTABLE
13349	lea.l		RTABLE(%pc),%a1		# load rtable base
13350	mov.b		(%a1,%d2),%d0		# load new rounding bits from table
13351	clr.l		%d3			# clear d3 to force no exc and extended
13352	bfins		%d0,%d3{&26:&2}		# stuff new rounding bits in FPCR
13353	fmov.l		%d3,%fpcr		# write new FPCR
13354	asr.l		&1,%d0			# write correct PTENxx table
13355	bcc.b		not_rp			# to a1
13356	lea.l		PTENRP(%pc),%a1		# it is RP
13357	bra.b		calc_p			# go to init section
13358not_rp:
13359	asr.l		&1,%d0			# keep checking
13360	bcc.b		not_rm
13361	lea.l		PTENRM(%pc),%a1		# it is RM
13362	bra.b		calc_p			# go to init section
13363not_rm:
13364	lea.l		PTENRN(%pc),%a1		# it is RN
13365calc_p:
13366	mov.l		%d1,%d0			# copy exp to d0;use d0
13367	bpl.b		no_neg			# if exp is negative,
13368	neg.l		%d0			# invert it
13369	or.l		&0x40000000,(%a0)	# and set SE bit
13370no_neg:
13371	clr.l		%d3			# table index
13372	fmov.s		&0x3f800000,%fp1	# init fp1 to 1
13373e_loop:
13374	asr.l		&1,%d0			# shift next bit into carry
13375	bcc.b		e_next			# if zero, skip the mul
13376	fmul.x		(%a1,%d3),%fp1		# mul by 10**(d3_bit_no)
13377e_next:
13378	add.l		&12,%d3			# inc d3 to next rtable entry
13379	tst.l		%d0			# check if d0 is zero
13380	bne.b		e_loop			# not zero, continue shifting
13381#
13382#
13383#  Check the sign of the adjusted exp and make the value in fp0 the
13384#  same sign. If the exp was pos then multiply fp1*fp0;
13385#  else divide fp0/fp1.
13386#
13387# Register Usage:
13388#  norm:
13389#	( )  a0: pointer to working bcd value
13390#	(*) fp0: mantissa accumulator
13391#	( ) fp1: scaling factor - 10**(abs(exp))
13392#
13393pnorm:
13394	btst		&30,(%a0)		# test the sign of the exponent
13395	beq.b		mul			# if clear, go to multiply
13396div:
13397	fdiv.x		%fp1,%fp0		# exp is negative, so divide mant by exp
13398	bra.b		end_dec
13399mul:
13400	fmul.x		%fp1,%fp0		# exp is positive, so multiply by exp
13401#
13402#
13403# Clean up and return with result in fp0.
13404#
13405# If the final mul/div in decbin incurred an inex exception,
13406# it will be inex2, but will be reported as inex1 by get_op.
13407#
13408end_dec:
13409	fmov.l		%fpsr,%d0		# get status register
13410	bclr		&inex2_bit+8,%d0	# test for inex2 and clear it
13411	beq.b		no_exc			# skip this if no exc
13412	ori.w		&inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX
13413no_exc:
13414	add.l		&0x4,%sp		# clear 1 lw param
13415	fmovm.x		(%sp)+,&0x40		# restore fp1
13416	movm.l		(%sp)+,&0x3c		# restore d2-d5
13417	fmov.l		&0x0,%fpcr
13418	fmov.l		&0x0,%fpsr
13419	rts
13420
13421#########################################################################
13422# bindec(): Converts an input in extended precision format to bcd format#
13423#									#
13424# INPUT ***************************************************************	#
13425#	a0 = pointer to the input extended precision value in memory.	#
13426#	     the input may be either normalized, unnormalized, or	#
13427#	     denormalized.						#
13428#	d0 = contains the k-factor sign-extended to 32-bits.		#
13429#									#
13430# OUTPUT **************************************************************	#
13431#	FP_SCR0(a6) = bcd format result on the stack.			#
13432#									#
13433# ALGORITHM ***********************************************************	#
13434#									#
13435#	A1.	Set RM and size ext;  Set SIGMA = sign of input.	#
13436#		The k-factor is saved for use in d7. Clear the		#
13437#		BINDEC_FLG for separating normalized/denormalized	#
13438#		input.  If input is unnormalized or denormalized,	#
13439#		normalize it.						#
13440#									#
13441#	A2.	Set X = abs(input).					#
13442#									#
13443#	A3.	Compute ILOG.						#
13444#		ILOG is the log base 10 of the input value.  It is	#
13445#		approximated by adding e + 0.f when the original	#
13446#		value is viewed as 2^^e * 1.f in extended precision.	#
13447#		This value is stored in d6.				#
13448#									#
13449#	A4.	Clr INEX bit.						#
13450#		The operation in A3 above may have set INEX2.		#
13451#									#
13452#	A5.	Set ICTR = 0;						#
13453#		ICTR is a flag used in A13.  It must be set before the	#
13454#		loop entry A6.						#
13455#									#
13456#	A6.	Calculate LEN.						#
13457#		LEN is the number of digits to be displayed.  The	#
13458#		k-factor can dictate either the total number of digits,	#
13459#		if it is a positive number, or the number of digits	#
13460#		after the decimal point which are to be included as	#
13461#		significant.  See the 68882 manual for examples.	#
13462#		If LEN is computed to be greater than 17, set OPERR in	#
13463#		USER_FPSR.  LEN is stored in d4.			#
13464#									#
13465#	A7.	Calculate SCALE.					#
13466#		SCALE is equal to 10^ISCALE, where ISCALE is the number	#
13467#		of decimal places needed to insure LEN integer digits	#
13468#		in the output before conversion to bcd. LAMBDA is the	#
13469#		sign of ISCALE, used in A9. Fp1 contains		#
13470#		10^^(abs(ISCALE)) using a rounding mode which is a	#
13471#		function of the original rounding mode and the signs	#
13472#		of ISCALE and X.  A table is given in the code.		#
13473#									#
13474#	A8.	Clr INEX; Force RZ.					#
13475#		The operation in A3 above may have set INEX2.		#
13476#		RZ mode is forced for the scaling operation to insure	#
13477#		only one rounding error.  The grs bits are collected in #
13478#		the INEX flag for use in A10.				#
13479#									#
13480#	A9.	Scale X -> Y.						#
13481#		The mantissa is scaled to the desired number of		#
13482#		significant digits.  The excess digits are collected	#
13483#		in INEX2.						#
13484#									#
13485#	A10.	Or in INEX.						#
13486#		If INEX is set, round error occurred.  This is		#
13487#		compensated for by 'or-ing' in the INEX2 flag to	#
13488#		the lsb of Y.						#
13489#									#
13490#	A11.	Restore original FPCR; set size ext.			#
13491#		Perform FINT operation in the user's rounding mode.	#
13492#		Keep the size to extended.				#
13493#									#
13494#	A12.	Calculate YINT = FINT(Y) according to user's rounding	#
13495#		mode.  The FPSP routine sintd0 is used.  The output	#
13496#		is in fp0.						#
13497#									#
13498#	A13.	Check for LEN digits.					#
13499#		If the int operation results in more than LEN digits,	#
13500#		or less than LEN -1 digits, adjust ILOG and repeat from	#
13501#		A6.  This test occurs only on the first pass.  If the	#
13502#		result is exactly 10^LEN, decrement ILOG and divide	#
13503#		the mantissa by 10.					#
13504#									#
13505#	A14.	Convert the mantissa to bcd.				#
13506#		The binstr routine is used to convert the LEN digit	#
13507#		mantissa to bcd in memory.  The input to binstr is	#
13508#		to be a fraction; i.e. (mantissa)/10^LEN and adjusted	#
13509#		such that the decimal point is to the left of bit 63.	#
13510#		The bcd digits are stored in the correct position in	#
13511#		the final string area in memory.			#
13512#									#
13513#	A15.	Convert the exponent to bcd.				#
13514#		As in A14 above, the exp is converted to bcd and the	#
13515#		digits are stored in the final string.			#
13516#		Test the length of the final exponent string.  If the	#
13517#		length is 4, set operr.					#
13518#									#
13519#	A16.	Write sign bits to final string.			#
13520#									#
13521#########################################################################
13522
13523set	BINDEC_FLG,	EXC_TEMP	# DENORM flag
13524
13525# Constants in extended precision
13526PLOG2:
13527	long		0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
13528PLOG2UP1:
13529	long		0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
13530
13531# Constants in single precision
13532FONE:
13533	long		0x3F800000,0x00000000,0x00000000,0x00000000
13534FTWO:
13535	long		0x40000000,0x00000000,0x00000000,0x00000000
13536FTEN:
13537	long		0x41200000,0x00000000,0x00000000,0x00000000
13538F4933:
13539	long		0x459A2800,0x00000000,0x00000000,0x00000000
13540
13541RBDTBL:
13542	byte		0,0,0,0
13543	byte		3,3,2,2
13544	byte		3,2,2,3
13545	byte		2,3,3,2
13546
13547#	Implementation Notes:
13548#
13549#	The registers are used as follows:
13550#
13551#		d0: scratch; LEN input to binstr
13552#		d1: scratch
13553#		d2: upper 32-bits of mantissa for binstr
13554#		d3: scratch;lower 32-bits of mantissa for binstr
13555#		d4: LEN
13556#		d5: LAMBDA/ICTR
13557#		d6: ILOG
13558#		d7: k-factor
13559#		a0: ptr for original operand/final result
13560#		a1: scratch pointer
13561#		a2: pointer to FP_X; abs(original value) in ext
13562#		fp0: scratch
13563#		fp1: scratch
13564#		fp2: scratch
13565#		F_SCR1:
13566#		F_SCR2:
13567#		L_SCR1:
13568#		L_SCR2:
13569
13570	global		bindec
13571bindec:
13572	movm.l		&0x3f20,-(%sp)	#  {%d2-%d7/%a2}
13573	fmovm.x		&0x7,-(%sp)	#  {%fp0-%fp2}
13574
13575# A1. Set RM and size ext. Set SIGMA = sign input;
13576#     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
13577#     separating  normalized/denormalized input.  If the input
13578#     is a denormalized number, set the BINDEC_FLG memory word
13579#     to signal denorm.  If the input is unnormalized, normalize
13580#     the input and test for denormalized result.
13581#
13582	fmov.l		&rm_mode*0x10,%fpcr	# set RM and ext
13583	mov.l		(%a0),L_SCR2(%a6)	# save exponent for sign check
13584	mov.l		%d0,%d7		# move k-factor to d7
13585
13586	clr.b		BINDEC_FLG(%a6)	# clr norm/denorm flag
13587	cmpi.b		STAG(%a6),&DENORM # is input a DENORM?
13588	bne.w		A2_str		# no; input is a NORM
13589
13590#
13591# Normalize the denorm
13592#
13593un_de_norm:
13594	mov.w		(%a0),%d0
13595	and.w		&0x7fff,%d0	# strip sign of normalized exp
13596	mov.l		4(%a0),%d1
13597	mov.l		8(%a0),%d2
13598norm_loop:
13599	sub.w		&1,%d0
13600	lsl.l		&1,%d2
13601	roxl.l		&1,%d1
13602	tst.l		%d1
13603	bge.b		norm_loop
13604#
13605# Test if the normalized input is denormalized
13606#
13607	tst.w		%d0
13608	bgt.b		pos_exp		# if greater than zero, it is a norm
13609	st		BINDEC_FLG(%a6)	# set flag for denorm
13610pos_exp:
13611	and.w		&0x7fff,%d0	# strip sign of normalized exp
13612	mov.w		%d0,(%a0)
13613	mov.l		%d1,4(%a0)
13614	mov.l		%d2,8(%a0)
13615
13616# A2. Set X = abs(input).
13617#
13618A2_str:
13619	mov.l		(%a0),FP_SCR1(%a6)	# move input to work space
13620	mov.l		4(%a0),FP_SCR1+4(%a6)	# move input to work space
13621	mov.l		8(%a0),FP_SCR1+8(%a6)	# move input to work space
13622	and.l		&0x7fffffff,FP_SCR1(%a6)	# create abs(X)
13623
13624# A3. Compute ILOG.
13625#     ILOG is the log base 10 of the input value.  It is approx-
13626#     imated by adding e + 0.f when the original value is viewed
13627#     as 2^^e * 1.f in extended precision.  This value is stored
13628#     in d6.
13629#
13630# Register usage:
13631#	Input/Output
13632#	d0: k-factor/exponent
13633#	d2: x/x
13634#	d3: x/x
13635#	d4: x/x
13636#	d5: x/x
13637#	d6: x/ILOG
13638#	d7: k-factor/Unchanged
13639#	a0: ptr for original operand/final result
13640#	a1: x/x
13641#	a2: x/x
13642#	fp0: x/float(ILOG)
13643#	fp1: x/x
13644#	fp2: x/x
13645#	F_SCR1:x/x
13646#	F_SCR2:Abs(X)/Abs(X) with $3fff exponent
13647#	L_SCR1:x/x
13648#	L_SCR2:first word of X packed/Unchanged
13649
13650	tst.b		BINDEC_FLG(%a6)	# check for denorm
13651	beq.b		A3_cont		# if clr, continue with norm
13652	mov.l		&-4933,%d6	# force ILOG = -4933
13653	bra.b		A4_str
13654A3_cont:
13655	mov.w		FP_SCR1(%a6),%d0	# move exp to d0
13656	mov.w		&0x3fff,FP_SCR1(%a6)	# replace exponent with 0x3fff
13657	fmov.x		FP_SCR1(%a6),%fp0	# now fp0 has 1.f
13658	sub.w		&0x3fff,%d0	# strip off bias
13659	fadd.w		%d0,%fp0	# add in exp
13660	fsub.s		FONE(%pc),%fp0	# subtract off 1.0
13661	fbge.w		pos_res		# if pos, branch
13662	fmul.x		PLOG2UP1(%pc),%fp0	# if neg, mul by LOG2UP1
13663	fmov.l		%fp0,%d6	# put ILOG in d6 as a lword
13664	bra.b		A4_str		# go move out ILOG
13665pos_res:
13666	fmul.x		PLOG2(%pc),%fp0	# if pos, mul by LOG2
13667	fmov.l		%fp0,%d6	# put ILOG in d6 as a lword
13668
13669
13670# A4. Clr INEX bit.
13671#     The operation in A3 above may have set INEX2.
13672
13673A4_str:
13674	fmov.l		&0,%fpsr	# zero all of fpsr - nothing needed
13675
13676
13677# A5. Set ICTR = 0;
13678#     ICTR is a flag used in A13.  It must be set before the
13679#     loop entry A6. The lower word of d5 is used for ICTR.
13680
13681	clr.w		%d5		# clear ICTR
13682
13683# A6. Calculate LEN.
13684#     LEN is the number of digits to be displayed.  The k-factor
13685#     can dictate either the total number of digits, if it is
13686#     a positive number, or the number of digits after the
13687#     original decimal point which are to be included as
13688#     significant.  See the 68882 manual for examples.
13689#     If LEN is computed to be greater than 17, set OPERR in
13690#     USER_FPSR.  LEN is stored in d4.
13691#
13692# Register usage:
13693#	Input/Output
13694#	d0: exponent/Unchanged
13695#	d2: x/x/scratch
13696#	d3: x/x
13697#	d4: exc picture/LEN
13698#	d5: ICTR/Unchanged
13699#	d6: ILOG/Unchanged
13700#	d7: k-factor/Unchanged
13701#	a0: ptr for original operand/final result
13702#	a1: x/x
13703#	a2: x/x
13704#	fp0: float(ILOG)/Unchanged
13705#	fp1: x/x
13706#	fp2: x/x
13707#	F_SCR1:x/x
13708#	F_SCR2:Abs(X) with $3fff exponent/Unchanged
13709#	L_SCR1:x/x
13710#	L_SCR2:first word of X packed/Unchanged
13711
13712A6_str:
13713	tst.l		%d7		# branch on sign of k
13714	ble.b		k_neg		# if k <= 0, LEN = ILOG + 1 - k
13715	mov.l		%d7,%d4		# if k > 0, LEN = k
13716	bra.b		len_ck		# skip to LEN check
13717k_neg:
13718	mov.l		%d6,%d4		# first load ILOG to d4
13719	sub.l		%d7,%d4		# subtract off k
13720	addq.l		&1,%d4		# add in the 1
13721len_ck:
13722	tst.l		%d4		# LEN check: branch on sign of LEN
13723	ble.b		LEN_ng		# if neg, set LEN = 1
13724	cmp.l		%d4,&17		# test if LEN > 17
13725	ble.b		A7_str		# if not, forget it
13726	mov.l		&17,%d4		# set max LEN = 17
13727	tst.l		%d7		# if negative, never set OPERR
13728	ble.b		A7_str		# if positive, continue
13729	or.l		&opaop_mask,USER_FPSR(%a6)	# set OPERR & AIOP in USER_FPSR
13730	bra.b		A7_str		# finished here
13731LEN_ng:
13732	mov.l		&1,%d4		# min LEN is 1
13733
13734
13735# A7. Calculate SCALE.
13736#     SCALE is equal to 10^ISCALE, where ISCALE is the number
13737#     of decimal places needed to insure LEN integer digits
13738#     in the output before conversion to bcd. LAMBDA is the sign
13739#     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
13740#     the rounding mode as given in the following table (see
13741#     Coonen, p. 7.23 as ref.; however, the SCALE variable is
13742#     of opposite sign in bindec.sa from Coonen).
13743#
13744#	Initial					USE
13745#	FPCR[6:5]	LAMBDA	SIGN(X)		FPCR[6:5]
13746#	----------------------------------------------
13747#	 RN	00	   0	   0		00/0	RN
13748#	 RN	00	   0	   1		00/0	RN
13749#	 RN	00	   1	   0		00/0	RN
13750#	 RN	00	   1	   1		00/0	RN
13751#	 RZ	01	   0	   0		11/3	RP
13752#	 RZ	01	   0	   1		11/3	RP
13753#	 RZ	01	   1	   0		10/2	RM
13754#	 RZ	01	   1	   1		10/2	RM
13755#	 RM	10	   0	   0		11/3	RP
13756#	 RM	10	   0	   1		10/2	RM
13757#	 RM	10	   1	   0		10/2	RM
13758#	 RM	10	   1	   1		11/3	RP
13759#	 RP	11	   0	   0		10/2	RM
13760#	 RP	11	   0	   1		11/3	RP
13761#	 RP	11	   1	   0		11/3	RP
13762#	 RP	11	   1	   1		10/2	RM
13763#
13764# Register usage:
13765#	Input/Output
13766#	d0: exponent/scratch - final is 0
13767#	d2: x/0 or 24 for A9
13768#	d3: x/scratch - offset ptr into PTENRM array
13769#	d4: LEN/Unchanged
13770#	d5: 0/ICTR:LAMBDA
13771#	d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
13772#	d7: k-factor/Unchanged
13773#	a0: ptr for original operand/final result
13774#	a1: x/ptr to PTENRM array
13775#	a2: x/x
13776#	fp0: float(ILOG)/Unchanged
13777#	fp1: x/10^ISCALE
13778#	fp2: x/x
13779#	F_SCR1:x/x
13780#	F_SCR2:Abs(X) with $3fff exponent/Unchanged
13781#	L_SCR1:x/x
13782#	L_SCR2:first word of X packed/Unchanged
13783
13784A7_str:
13785	tst.l		%d7		# test sign of k
13786	bgt.b		k_pos		# if pos and > 0, skip this
13787	cmp.l		%d7,%d6		# test k - ILOG
13788	blt.b		k_pos		# if ILOG >= k, skip this
13789	mov.l		%d7,%d6		# if ((k<0) & (ILOG < k)) ILOG = k
13790k_pos:
13791	mov.l		%d6,%d0		# calc ILOG + 1 - LEN in d0
13792	addq.l		&1,%d0		# add the 1
13793	sub.l		%d4,%d0		# sub off LEN
13794	swap		%d5		# use upper word of d5 for LAMBDA
13795	clr.w		%d5		# set it zero initially
13796	clr.w		%d2		# set up d2 for very small case
13797	tst.l		%d0		# test sign of ISCALE
13798	bge.b		iscale		# if pos, skip next inst
13799	addq.w		&1,%d5		# if neg, set LAMBDA true
13800	cmp.l		%d0,&0xffffecd4	# test iscale <= -4908
13801	bgt.b		no_inf		# if false, skip rest
13802	add.l		&24,%d0		# add in 24 to iscale
13803	mov.l		&24,%d2		# put 24 in d2 for A9
13804no_inf:
13805	neg.l		%d0		# and take abs of ISCALE
13806iscale:
13807	fmov.s		FONE(%pc),%fp1	# init fp1 to 1
13808	bfextu		USER_FPCR(%a6){&26:&2},%d1	# get initial rmode bits
13809	lsl.w		&1,%d1		# put them in bits 2:1
13810	add.w		%d5,%d1		# add in LAMBDA
13811	lsl.w		&1,%d1		# put them in bits 3:1
13812	tst.l		L_SCR2(%a6)	# test sign of original x
13813	bge.b		x_pos		# if pos, don't set bit 0
13814	addq.l		&1,%d1		# if neg, set bit 0
13815x_pos:
13816	lea.l		RBDTBL(%pc),%a2	# load rbdtbl base
13817	mov.b		(%a2,%d1),%d3	# load d3 with new rmode
13818	lsl.l		&4,%d3		# put bits in proper position
13819	fmov.l		%d3,%fpcr	# load bits into fpu
13820	lsr.l		&4,%d3		# put bits in proper position
13821	tst.b		%d3		# decode new rmode for pten table
13822	bne.b		not_rn		# if zero, it is RN
13823	lea.l		PTENRN(%pc),%a1	# load a1 with RN table base
13824	bra.b		rmode		# exit decode
13825not_rn:
13826	lsr.b		&1,%d3		# get lsb in carry
13827	bcc.b		not_rp2		# if carry clear, it is RM
13828	lea.l		PTENRP(%pc),%a1	# load a1 with RP table base
13829	bra.b		rmode		# exit decode
13830not_rp2:
13831	lea.l		PTENRM(%pc),%a1	# load a1 with RM table base
13832rmode:
13833	clr.l		%d3		# clr table index
13834e_loop2:
13835	lsr.l		&1,%d0		# shift next bit into carry
13836	bcc.b		e_next2		# if zero, skip the mul
13837	fmul.x		(%a1,%d3),%fp1	# mul by 10**(d3_bit_no)
13838e_next2:
13839	add.l		&12,%d3		# inc d3 to next pwrten table entry
13840	tst.l		%d0		# test if ISCALE is zero
13841	bne.b		e_loop2		# if not, loop
13842
13843# A8. Clr INEX; Force RZ.
13844#     The operation in A3 above may have set INEX2.
13845#     RZ mode is forced for the scaling operation to insure
13846#     only one rounding error.  The grs bits are collected in
13847#     the INEX flag for use in A10.
13848#
13849# Register usage:
13850#	Input/Output
13851
13852	fmov.l		&0,%fpsr	# clr INEX
13853	fmov.l		&rz_mode*0x10,%fpcr	# set RZ rounding mode
13854
13855# A9. Scale X -> Y.
13856#     The mantissa is scaled to the desired number of significant
13857#     digits.  The excess digits are collected in INEX2. If mul,
13858#     Check d2 for excess 10 exponential value.  If not zero,
13859#     the iscale value would have caused the pwrten calculation
13860#     to overflow.  Only a negative iscale can cause this, so
13861#     multiply by 10^(d2), which is now only allowed to be 24,
13862#     with a multiply by 10^8 and 10^16, which is exact since
13863#     10^24 is exact.  If the input was denormalized, we must
13864#     create a busy stack frame with the mul command and the
13865#     two operands, and allow the fpu to complete the multiply.
13866#
13867# Register usage:
13868#	Input/Output
13869#	d0: FPCR with RZ mode/Unchanged
13870#	d2: 0 or 24/unchanged
13871#	d3: x/x
13872#	d4: LEN/Unchanged
13873#	d5: ICTR:LAMBDA
13874#	d6: ILOG/Unchanged
13875#	d7: k-factor/Unchanged
13876#	a0: ptr for original operand/final result
13877#	a1: ptr to PTENRM array/Unchanged
13878#	a2: x/x
13879#	fp0: float(ILOG)/X adjusted for SCALE (Y)
13880#	fp1: 10^ISCALE/Unchanged
13881#	fp2: x/x
13882#	F_SCR1:x/x
13883#	F_SCR2:Abs(X) with $3fff exponent/Unchanged
13884#	L_SCR1:x/x
13885#	L_SCR2:first word of X packed/Unchanged
13886
13887A9_str:
13888	fmov.x		(%a0),%fp0	# load X from memory
13889	fabs.x		%fp0		# use abs(X)
13890	tst.w		%d5		# LAMBDA is in lower word of d5
13891	bne.b		sc_mul		# if neg (LAMBDA = 1), scale by mul
13892	fdiv.x		%fp1,%fp0	# calculate X / SCALE -> Y to fp0
13893	bra.w		A10_st		# branch to A10
13894
13895sc_mul:
13896	tst.b		BINDEC_FLG(%a6)	# check for denorm
13897	beq.w		A9_norm		# if norm, continue with mul
13898
13899# for DENORM, we must calculate:
13900#	fp0 = input_op * 10^ISCALE * 10^24
13901# since the input operand is a DENORM, we can't multiply it directly.
13902# so, we do the multiplication of the exponents and mantissas separately.
13903# in this way, we avoid underflow on intermediate stages of the
13904# multiplication and guarantee a result without exception.
13905	fmovm.x		&0x2,-(%sp)	# save 10^ISCALE to stack
13906
13907	mov.w		(%sp),%d3	# grab exponent
13908	andi.w		&0x7fff,%d3	# clear sign
13909	ori.w		&0x8000,(%a0)	# make DENORM exp negative
13910	add.w		(%a0),%d3	# add DENORM exp to 10^ISCALE exp
13911	subi.w		&0x3fff,%d3	# subtract BIAS
13912	add.w		36(%a1),%d3
13913	subi.w		&0x3fff,%d3	# subtract BIAS
13914	add.w		48(%a1),%d3
13915	subi.w		&0x3fff,%d3	# subtract BIAS
13916
13917	bmi.w		sc_mul_err	# is result is DENORM, punt!!!
13918
13919	andi.w		&0x8000,(%sp)	# keep sign
13920	or.w		%d3,(%sp)	# insert new exponent
13921	andi.w		&0x7fff,(%a0)	# clear sign bit on DENORM again
13922	mov.l		0x8(%a0),-(%sp) # put input op mantissa on stk
13923	mov.l		0x4(%a0),-(%sp)
13924	mov.l		&0x3fff0000,-(%sp) # force exp to zero
13925	fmovm.x		(%sp)+,&0x80	# load normalized DENORM into fp0
13926	fmul.x		(%sp)+,%fp0
13927
13928#	fmul.x	36(%a1),%fp0	# multiply fp0 by 10^8
13929#	fmul.x	48(%a1),%fp0	# multiply fp0 by 10^16
13930	mov.l		36+8(%a1),-(%sp) # get 10^8 mantissa
13931	mov.l		36+4(%a1),-(%sp)
13932	mov.l		&0x3fff0000,-(%sp) # force exp to zero
13933	mov.l		48+8(%a1),-(%sp) # get 10^16 mantissa
13934	mov.l		48+4(%a1),-(%sp)
13935	mov.l		&0x3fff0000,-(%sp)# force exp to zero
13936	fmul.x		(%sp)+,%fp0	# multiply fp0 by 10^8
13937	fmul.x		(%sp)+,%fp0	# multiply fp0 by 10^16
13938	bra.b		A10_st
13939
13940sc_mul_err:
13941	bra.b		sc_mul_err
13942
13943A9_norm:
13944	tst.w		%d2		# test for small exp case
13945	beq.b		A9_con		# if zero, continue as normal
13946	fmul.x		36(%a1),%fp0	# multiply fp0 by 10^8
13947	fmul.x		48(%a1),%fp0	# multiply fp0 by 10^16
13948A9_con:
13949	fmul.x		%fp1,%fp0	# calculate X * SCALE -> Y to fp0
13950
13951# A10. Or in INEX.
13952#      If INEX is set, round error occurred.  This is compensated
13953#      for by 'or-ing' in the INEX2 flag to the lsb of Y.
13954#
13955# Register usage:
13956#	Input/Output
13957#	d0: FPCR with RZ mode/FPSR with INEX2 isolated
13958#	d2: x/x
13959#	d3: x/x
13960#	d4: LEN/Unchanged
13961#	d5: ICTR:LAMBDA
13962#	d6: ILOG/Unchanged
13963#	d7: k-factor/Unchanged
13964#	a0: ptr for original operand/final result
13965#	a1: ptr to PTENxx array/Unchanged
13966#	a2: x/ptr to FP_SCR1(a6)
13967#	fp0: Y/Y with lsb adjusted
13968#	fp1: 10^ISCALE/Unchanged
13969#	fp2: x/x
13970
13971A10_st:
13972	fmov.l		%fpsr,%d0	# get FPSR
13973	fmov.x		%fp0,FP_SCR1(%a6)	# move Y to memory
13974	lea.l		FP_SCR1(%a6),%a2	# load a2 with ptr to FP_SCR1
13975	btst		&9,%d0		# check if INEX2 set
13976	beq.b		A11_st		# if clear, skip rest
13977	or.l		&1,8(%a2)	# or in 1 to lsb of mantissa
13978	fmov.x		FP_SCR1(%a6),%fp0	# write adjusted Y back to fpu
13979
13980
13981# A11. Restore original FPCR; set size ext.
13982#      Perform FINT operation in the user's rounding mode.  Keep
13983#      the size to extended.  The sintdo entry point in the sint
13984#      routine expects the FPCR value to be in USER_FPCR for
13985#      mode and precision.  The original FPCR is saved in L_SCR1.
13986
13987A11_st:
13988	mov.l		USER_FPCR(%a6),L_SCR1(%a6)	# save it for later
13989	and.l		&0x00000030,USER_FPCR(%a6)	# set size to ext,
13990#					;block exceptions
13991
13992
13993# A12. Calculate YINT = FINT(Y) according to user's rounding mode.
13994#      The FPSP routine sintd0 is used.  The output is in fp0.
13995#
13996# Register usage:
13997#	Input/Output
13998#	d0: FPSR with AINEX cleared/FPCR with size set to ext
13999#	d2: x/x/scratch
14000#	d3: x/x
14001#	d4: LEN/Unchanged
14002#	d5: ICTR:LAMBDA/Unchanged
14003#	d6: ILOG/Unchanged
14004#	d7: k-factor/Unchanged
14005#	a0: ptr for original operand/src ptr for sintdo
14006#	a1: ptr to PTENxx array/Unchanged
14007#	a2: ptr to FP_SCR1(a6)/Unchanged
14008#	a6: temp pointer to FP_SCR1(a6) - orig value saved and restored
14009#	fp0: Y/YINT
14010#	fp1: 10^ISCALE/Unchanged
14011#	fp2: x/x
14012#	F_SCR1:x/x
14013#	F_SCR2:Y adjusted for inex/Y with original exponent
14014#	L_SCR1:x/original USER_FPCR
14015#	L_SCR2:first word of X packed/Unchanged
14016
14017A12_st:
14018	movm.l	&0xc0c0,-(%sp)	# save regs used by sintd0	 {%d0-%d1/%a0-%a1}
14019	mov.l	L_SCR1(%a6),-(%sp)
14020	mov.l	L_SCR2(%a6),-(%sp)
14021
14022	lea.l		FP_SCR1(%a6),%a0	# a0 is ptr to FP_SCR1(a6)
14023	fmov.x		%fp0,(%a0)	# move Y to memory at FP_SCR1(a6)
14024	tst.l		L_SCR2(%a6)	# test sign of original operand
14025	bge.b		do_fint12		# if pos, use Y
14026	or.l		&0x80000000,(%a0)	# if neg, use -Y
14027do_fint12:
14028	mov.l	USER_FPSR(%a6),-(%sp)
14029#	bsr	sintdo		# sint routine returns int in fp0
14030
14031	fmov.l	USER_FPCR(%a6),%fpcr
14032	fmov.l	&0x0,%fpsr			# clear the AEXC bits!!!
14033##	mov.l		USER_FPCR(%a6),%d0	# ext prec/keep rnd mode
14034##	andi.l		&0x00000030,%d0
14035##	fmov.l		%d0,%fpcr
14036	fint.x		FP_SCR1(%a6),%fp0	# do fint()
14037	fmov.l	%fpsr,%d0
14038	or.w	%d0,FPSR_EXCEPT(%a6)
14039##	fmov.l		&0x0,%fpcr
14040##	fmov.l		%fpsr,%d0		# don't keep ccodes
14041##	or.w		%d0,FPSR_EXCEPT(%a6)
14042
14043	mov.b	(%sp),USER_FPSR(%a6)
14044	add.l	&4,%sp
14045
14046	mov.l	(%sp)+,L_SCR2(%a6)
14047	mov.l	(%sp)+,L_SCR1(%a6)
14048	movm.l	(%sp)+,&0x303	# restore regs used by sint	 {%d0-%d1/%a0-%a1}
14049
14050	mov.l	L_SCR2(%a6),FP_SCR1(%a6)	# restore original exponent
14051	mov.l	L_SCR1(%a6),USER_FPCR(%a6)	# restore user's FPCR
14052
14053# A13. Check for LEN digits.
14054#      If the int operation results in more than LEN digits,
14055#      or less than LEN -1 digits, adjust ILOG and repeat from
14056#      A6.  This test occurs only on the first pass.  If the
14057#      result is exactly 10^LEN, decrement ILOG and divide
14058#      the mantissa by 10.  The calculation of 10^LEN cannot
14059#      be inexact, since all powers of ten up to 10^27 are exact
14060#      in extended precision, so the use of a previous power-of-ten
14061#      table will introduce no error.
14062#
14063#
14064# Register usage:
14065#	Input/Output
14066#	d0: FPCR with size set to ext/scratch final = 0
14067#	d2: x/x
14068#	d3: x/scratch final = x
14069#	d4: LEN/LEN adjusted
14070#	d5: ICTR:LAMBDA/LAMBDA:ICTR
14071#	d6: ILOG/ILOG adjusted
14072#	d7: k-factor/Unchanged
14073#	a0: pointer into memory for packed bcd string formation
14074#	a1: ptr to PTENxx array/Unchanged
14075#	a2: ptr to FP_SCR1(a6)/Unchanged
14076#	fp0: int portion of Y/abs(YINT) adjusted
14077#	fp1: 10^ISCALE/Unchanged
14078#	fp2: x/10^LEN
14079#	F_SCR1:x/x
14080#	F_SCR2:Y with original exponent/Unchanged
14081#	L_SCR1:original USER_FPCR/Unchanged
14082#	L_SCR2:first word of X packed/Unchanged
14083
14084A13_st:
14085	swap		%d5		# put ICTR in lower word of d5
14086	tst.w		%d5		# check if ICTR = 0
14087	bne		not_zr		# if non-zero, go to second test
14088#
14089# Compute 10^(LEN-1)
14090#
14091	fmov.s		FONE(%pc),%fp2	# init fp2 to 1.0
14092	mov.l		%d4,%d0		# put LEN in d0
14093	subq.l		&1,%d0		# d0 = LEN -1
14094	clr.l		%d3		# clr table index
14095l_loop:
14096	lsr.l		&1,%d0		# shift next bit into carry
14097	bcc.b		l_next		# if zero, skip the mul
14098	fmul.x		(%a1,%d3),%fp2	# mul by 10**(d3_bit_no)
14099l_next:
14100	add.l		&12,%d3		# inc d3 to next pwrten table entry
14101	tst.l		%d0		# test if LEN is zero
14102	bne.b		l_loop		# if not, loop
14103#
14104# 10^LEN-1 is computed for this test and A14.  If the input was
14105# denormalized, check only the case in which YINT > 10^LEN.
14106#
14107	tst.b		BINDEC_FLG(%a6)	# check if input was norm
14108	beq.b		A13_con		# if norm, continue with checking
14109	fabs.x		%fp0		# take abs of YINT
14110	bra		test_2
14111#
14112# Compare abs(YINT) to 10^(LEN-1) and 10^LEN
14113#
14114A13_con:
14115	fabs.x		%fp0		# take abs of YINT
14116	fcmp.x		%fp0,%fp2	# compare abs(YINT) with 10^(LEN-1)
14117	fbge.w		test_2		# if greater, do next test
14118	subq.l		&1,%d6		# subtract 1 from ILOG
14119	mov.w		&1,%d5		# set ICTR
14120	fmov.l		&rm_mode*0x10,%fpcr	# set rmode to RM
14121	fmul.s		FTEN(%pc),%fp2	# compute 10^LEN
14122	bra.w		A6_str		# return to A6 and recompute YINT
14123test_2:
14124	fmul.s		FTEN(%pc),%fp2	# compute 10^LEN
14125	fcmp.x		%fp0,%fp2	# compare abs(YINT) with 10^LEN
14126	fblt.w		A14_st		# if less, all is ok, go to A14
14127	fbgt.w		fix_ex		# if greater, fix and redo
14128	fdiv.s		FTEN(%pc),%fp0	# if equal, divide by 10
14129	addq.l		&1,%d6		# and inc ILOG
14130	bra.b		A14_st		# and continue elsewhere
14131fix_ex:
14132	addq.l		&1,%d6		# increment ILOG by 1
14133	mov.w		&1,%d5		# set ICTR
14134	fmov.l		&rm_mode*0x10,%fpcr	# set rmode to RM
14135	bra.w		A6_str		# return to A6 and recompute YINT
14136#
14137# Since ICTR <> 0, we have already been through one adjustment,
14138# and shouldn't have another; this is to check if abs(YINT) = 10^LEN
14139# 10^LEN is again computed using whatever table is in a1 since the
14140# value calculated cannot be inexact.
14141#
14142not_zr:
14143	fmov.s		FONE(%pc),%fp2	# init fp2 to 1.0
14144	mov.l		%d4,%d0		# put LEN in d0
14145	clr.l		%d3		# clr table index
14146z_loop:
14147	lsr.l		&1,%d0		# shift next bit into carry
14148	bcc.b		z_next		# if zero, skip the mul
14149	fmul.x		(%a1,%d3),%fp2	# mul by 10**(d3_bit_no)
14150z_next:
14151	add.l		&12,%d3		# inc d3 to next pwrten table entry
14152	tst.l		%d0		# test if LEN is zero
14153	bne.b		z_loop		# if not, loop
14154	fabs.x		%fp0		# get abs(YINT)
14155	fcmp.x		%fp0,%fp2	# check if abs(YINT) = 10^LEN
14156	fbneq.w		A14_st		# if not, skip this
14157	fdiv.s		FTEN(%pc),%fp0	# divide abs(YINT) by 10
14158	addq.l		&1,%d6		# and inc ILOG by 1
14159	addq.l		&1,%d4		# and inc LEN
14160	fmul.s		FTEN(%pc),%fp2	# if LEN++, the get 10^^LEN
14161
14162# A14. Convert the mantissa to bcd.
14163#      The binstr routine is used to convert the LEN digit
14164#      mantissa to bcd in memory.  The input to binstr is
14165#      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
14166#      such that the decimal point is to the left of bit 63.
14167#      The bcd digits are stored in the correct position in
14168#      the final string area in memory.
14169#
14170#
14171# Register usage:
14172#	Input/Output
14173#	d0: x/LEN call to binstr - final is 0
14174#	d1: x/0
14175#	d2: x/ms 32-bits of mant of abs(YINT)
14176#	d3: x/ls 32-bits of mant of abs(YINT)
14177#	d4: LEN/Unchanged
14178#	d5: ICTR:LAMBDA/LAMBDA:ICTR
14179#	d6: ILOG
14180#	d7: k-factor/Unchanged
14181#	a0: pointer into memory for packed bcd string formation
14182#	    /ptr to first mantissa byte in result string
14183#	a1: ptr to PTENxx array/Unchanged
14184#	a2: ptr to FP_SCR1(a6)/Unchanged
14185#	fp0: int portion of Y/abs(YINT) adjusted
14186#	fp1: 10^ISCALE/Unchanged
14187#	fp2: 10^LEN/Unchanged
14188#	F_SCR1:x/Work area for final result
14189#	F_SCR2:Y with original exponent/Unchanged
14190#	L_SCR1:original USER_FPCR/Unchanged
14191#	L_SCR2:first word of X packed/Unchanged
14192
14193A14_st:
14194	fmov.l		&rz_mode*0x10,%fpcr	# force rz for conversion
14195	fdiv.x		%fp2,%fp0	# divide abs(YINT) by 10^LEN
14196	lea.l		FP_SCR0(%a6),%a0
14197	fmov.x		%fp0,(%a0)	# move abs(YINT)/10^LEN to memory
14198	mov.l		4(%a0),%d2	# move 2nd word of FP_RES to d2
14199	mov.l		8(%a0),%d3	# move 3rd word of FP_RES to d3
14200	clr.l		4(%a0)		# zero word 2 of FP_RES
14201	clr.l		8(%a0)		# zero word 3 of FP_RES
14202	mov.l		(%a0),%d0	# move exponent to d0
14203	swap		%d0		# put exponent in lower word
14204	beq.b		no_sft		# if zero, don't shift
14205	sub.l		&0x3ffd,%d0	# sub bias less 2 to make fract
14206	tst.l		%d0		# check if > 1
14207	bgt.b		no_sft		# if so, don't shift
14208	neg.l		%d0		# make exp positive
14209m_loop:
14210	lsr.l		&1,%d2		# shift d2:d3 right, add 0s
14211	roxr.l		&1,%d3		# the number of places
14212	dbf.w		%d0,m_loop	# given in d0
14213no_sft:
14214	tst.l		%d2		# check for mantissa of zero
14215	bne.b		no_zr		# if not, go on
14216	tst.l		%d3		# continue zero check
14217	beq.b		zer_m		# if zero, go directly to binstr
14218no_zr:
14219	clr.l		%d1		# put zero in d1 for addx
14220	add.l		&0x00000080,%d3	# inc at bit 7
14221	addx.l		%d1,%d2		# continue inc
14222	and.l		&0xffffff80,%d3	# strip off lsb not used by 882
14223zer_m:
14224	mov.l		%d4,%d0		# put LEN in d0 for binstr call
14225	addq.l		&3,%a0		# a0 points to M16 byte in result
14226	bsr		binstr		# call binstr to convert mant
14227
14228
14229# A15. Convert the exponent to bcd.
14230#      As in A14 above, the exp is converted to bcd and the
14231#      digits are stored in the final string.
14232#
14233#      Digits are stored in L_SCR1(a6) on return from BINDEC as:
14234#
14235#	 32               16 15                0
14236#	-----------------------------------------
14237#	|  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
14238#	-----------------------------------------
14239#
14240# And are moved into their proper places in FP_SCR0.  If digit e4
14241# is non-zero, OPERR is signaled.  In all cases, all 4 digits are
14242# written as specified in the 881/882 manual for packed decimal.
14243#
14244# Register usage:
14245#	Input/Output
14246#	d0: x/LEN call to binstr - final is 0
14247#	d1: x/scratch (0);shift count for final exponent packing
14248#	d2: x/ms 32-bits of exp fraction/scratch
14249#	d3: x/ls 32-bits of exp fraction
14250#	d4: LEN/Unchanged
14251#	d5: ICTR:LAMBDA/LAMBDA:ICTR
14252#	d6: ILOG
14253#	d7: k-factor/Unchanged
14254#	a0: ptr to result string/ptr to L_SCR1(a6)
14255#	a1: ptr to PTENxx array/Unchanged
14256#	a2: ptr to FP_SCR1(a6)/Unchanged
14257#	fp0: abs(YINT) adjusted/float(ILOG)
14258#	fp1: 10^ISCALE/Unchanged
14259#	fp2: 10^LEN/Unchanged
14260#	F_SCR1:Work area for final result/BCD result
14261#	F_SCR2:Y with original exponent/ILOG/10^4
14262#	L_SCR1:original USER_FPCR/Exponent digits on return from binstr
14263#	L_SCR2:first word of X packed/Unchanged
14264
14265A15_st:
14266	tst.b		BINDEC_FLG(%a6)	# check for denorm
14267	beq.b		not_denorm
14268	ftest.x		%fp0		# test for zero
14269	fbeq.w		den_zero	# if zero, use k-factor or 4933
14270	fmov.l		%d6,%fp0	# float ILOG
14271	fabs.x		%fp0		# get abs of ILOG
14272	bra.b		convrt
14273den_zero:
14274	tst.l		%d7		# check sign of the k-factor
14275	blt.b		use_ilog	# if negative, use ILOG
14276	fmov.s		F4933(%pc),%fp0	# force exponent to 4933
14277	bra.b		convrt		# do it
14278use_ilog:
14279	fmov.l		%d6,%fp0	# float ILOG
14280	fabs.x		%fp0		# get abs of ILOG
14281	bra.b		convrt
14282not_denorm:
14283	ftest.x		%fp0		# test for zero
14284	fbneq.w		not_zero	# if zero, force exponent
14285	fmov.s		FONE(%pc),%fp0	# force exponent to 1
14286	bra.b		convrt		# do it
14287not_zero:
14288	fmov.l		%d6,%fp0	# float ILOG
14289	fabs.x		%fp0		# get abs of ILOG
14290convrt:
14291	fdiv.x		24(%a1),%fp0	# compute ILOG/10^4
14292	fmov.x		%fp0,FP_SCR1(%a6)	# store fp0 in memory
14293	mov.l		4(%a2),%d2	# move word 2 to d2
14294	mov.l		8(%a2),%d3	# move word 3 to d3
14295	mov.w		(%a2),%d0	# move exp to d0
14296	beq.b		x_loop_fin	# if zero, skip the shift
14297	sub.w		&0x3ffd,%d0	# subtract off bias
14298	neg.w		%d0		# make exp positive
14299x_loop:
14300	lsr.l		&1,%d2		# shift d2:d3 right
14301	roxr.l		&1,%d3		# the number of places
14302	dbf.w		%d0,x_loop	# given in d0
14303x_loop_fin:
14304	clr.l		%d1		# put zero in d1 for addx
14305	add.l		&0x00000080,%d3	# inc at bit 6
14306	addx.l		%d1,%d2		# continue inc
14307	and.l		&0xffffff80,%d3	# strip off lsb not used by 882
14308	mov.l		&4,%d0		# put 4 in d0 for binstr call
14309	lea.l		L_SCR1(%a6),%a0	# a0 is ptr to L_SCR1 for exp digits
14310	bsr		binstr		# call binstr to convert exp
14311	mov.l		L_SCR1(%a6),%d0	# load L_SCR1 lword to d0
14312	mov.l		&12,%d1		# use d1 for shift count
14313	lsr.l		%d1,%d0		# shift d0 right by 12
14314	bfins		%d0,FP_SCR0(%a6){&4:&12}	# put e3:e2:e1 in FP_SCR0
14315	lsr.l		%d1,%d0		# shift d0 right by 12
14316	bfins		%d0,FP_SCR0(%a6){&16:&4}	# put e4 in FP_SCR0
14317	tst.b		%d0		# check if e4 is zero
14318	beq.b		A16_st		# if zero, skip rest
14319	or.l		&opaop_mask,USER_FPSR(%a6)	# set OPERR & AIOP in USER_FPSR
14320
14321
14322# A16. Write sign bits to final string.
14323#	   Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
14324#
14325# Register usage:
14326#	Input/Output
14327#	d0: x/scratch - final is x
14328#	d2: x/x
14329#	d3: x/x
14330#	d4: LEN/Unchanged
14331#	d5: ICTR:LAMBDA/LAMBDA:ICTR
14332#	d6: ILOG/ILOG adjusted
14333#	d7: k-factor/Unchanged
14334#	a0: ptr to L_SCR1(a6)/Unchanged
14335#	a1: ptr to PTENxx array/Unchanged
14336#	a2: ptr to FP_SCR1(a6)/Unchanged
14337#	fp0: float(ILOG)/Unchanged
14338#	fp1: 10^ISCALE/Unchanged
14339#	fp2: 10^LEN/Unchanged
14340#	F_SCR1:BCD result with correct signs
14341#	F_SCR2:ILOG/10^4
14342#	L_SCR1:Exponent digits on return from binstr
14343#	L_SCR2:first word of X packed/Unchanged
14344
14345A16_st:
14346	clr.l		%d0		# clr d0 for collection of signs
14347	and.b		&0x0f,FP_SCR0(%a6)	# clear first nibble of FP_SCR0
14348	tst.l		L_SCR2(%a6)	# check sign of original mantissa
14349	bge.b		mant_p		# if pos, don't set SM
14350	mov.l		&2,%d0		# move 2 in to d0 for SM
14351mant_p:
14352	tst.l		%d6		# check sign of ILOG
14353	bge.b		wr_sgn		# if pos, don't set SE
14354	addq.l		&1,%d0		# set bit 0 in d0 for SE
14355wr_sgn:
14356	bfins		%d0,FP_SCR0(%a6){&0:&2}	# insert SM and SE into FP_SCR0
14357
14358# Clean up and restore all registers used.
14359
14360	fmov.l		&0,%fpsr	# clear possible inex2/ainex bits
14361	fmovm.x		(%sp)+,&0xe0	#  {%fp0-%fp2}
14362	movm.l		(%sp)+,&0x4fc	#  {%d2-%d7/%a2}
14363	rts
14364
14365	global		PTENRN
14366PTENRN:
14367	long		0x40020000,0xA0000000,0x00000000	# 10 ^ 1
14368	long		0x40050000,0xC8000000,0x00000000	# 10 ^ 2
14369	long		0x400C0000,0x9C400000,0x00000000	# 10 ^ 4
14370	long		0x40190000,0xBEBC2000,0x00000000	# 10 ^ 8
14371	long		0x40340000,0x8E1BC9BF,0x04000000	# 10 ^ 16
14372	long		0x40690000,0x9DC5ADA8,0x2B70B59E	# 10 ^ 32
14373	long		0x40D30000,0xC2781F49,0xFFCFA6D5	# 10 ^ 64
14374	long		0x41A80000,0x93BA47C9,0x80E98CE0	# 10 ^ 128
14375	long		0x43510000,0xAA7EEBFB,0x9DF9DE8E	# 10 ^ 256
14376	long		0x46A30000,0xE319A0AE,0xA60E91C7	# 10 ^ 512
14377	long		0x4D480000,0xC9767586,0x81750C17	# 10 ^ 1024
14378	long		0x5A920000,0x9E8B3B5D,0xC53D5DE5	# 10 ^ 2048
14379	long		0x75250000,0xC4605202,0x8A20979B	# 10 ^ 4096
14380
14381	global		PTENRP
14382PTENRP:
14383	long		0x40020000,0xA0000000,0x00000000	# 10 ^ 1
14384	long		0x40050000,0xC8000000,0x00000000	# 10 ^ 2
14385	long		0x400C0000,0x9C400000,0x00000000	# 10 ^ 4
14386	long		0x40190000,0xBEBC2000,0x00000000	# 10 ^ 8
14387	long		0x40340000,0x8E1BC9BF,0x04000000	# 10 ^ 16
14388	long		0x40690000,0x9DC5ADA8,0x2B70B59E	# 10 ^ 32
14389	long		0x40D30000,0xC2781F49,0xFFCFA6D6	# 10 ^ 64
14390	long		0x41A80000,0x93BA47C9,0x80E98CE0	# 10 ^ 128
14391	long		0x43510000,0xAA7EEBFB,0x9DF9DE8E	# 10 ^ 256
14392	long		0x46A30000,0xE319A0AE,0xA60E91C7	# 10 ^ 512
14393	long		0x4D480000,0xC9767586,0x81750C18	# 10 ^ 1024
14394	long		0x5A920000,0x9E8B3B5D,0xC53D5DE5	# 10 ^ 2048
14395	long		0x75250000,0xC4605202,0x8A20979B	# 10 ^ 4096
14396
14397	global		PTENRM
14398PTENRM:
14399	long		0x40020000,0xA0000000,0x00000000	# 10 ^ 1
14400	long		0x40050000,0xC8000000,0x00000000	# 10 ^ 2
14401	long		0x400C0000,0x9C400000,0x00000000	# 10 ^ 4
14402	long		0x40190000,0xBEBC2000,0x00000000	# 10 ^ 8
14403	long		0x40340000,0x8E1BC9BF,0x04000000	# 10 ^ 16
14404	long		0x40690000,0x9DC5ADA8,0x2B70B59D	# 10 ^ 32
14405	long		0x40D30000,0xC2781F49,0xFFCFA6D5	# 10 ^ 64
14406	long		0x41A80000,0x93BA47C9,0x80E98CDF	# 10 ^ 128
14407	long		0x43510000,0xAA7EEBFB,0x9DF9DE8D	# 10 ^ 256
14408	long		0x46A30000,0xE319A0AE,0xA60E91C6	# 10 ^ 512
14409	long		0x4D480000,0xC9767586,0x81750C17	# 10 ^ 1024
14410	long		0x5A920000,0x9E8B3B5D,0xC53D5DE4	# 10 ^ 2048
14411	long		0x75250000,0xC4605202,0x8A20979A	# 10 ^ 4096
14412
14413#########################################################################
14414# binstr(): Converts a 64-bit binary integer to bcd.			#
14415#									#
14416# INPUT *************************************************************** #
14417#	d2:d3 = 64-bit binary integer					#
14418#	d0    = desired length (LEN)					#
14419#	a0    = pointer to start in memory for bcd characters		#
14420#		(This pointer must point to byte 4 of the first		#
14421#		 lword of the packed decimal memory string.)		#
14422#									#
14423# OUTPUT ************************************************************** #
14424#	a0 = pointer to LEN bcd digits representing the 64-bit integer.	#
14425#									#
14426# ALGORITHM ***********************************************************	#
14427#	The 64-bit binary is assumed to have a decimal point before	#
14428#	bit 63.  The fraction is multiplied by 10 using a mul by 2	#
14429#	shift and a mul by 8 shift.  The bits shifted out of the	#
14430#	msb form a decimal digit.  This process is iterated until	#
14431#	LEN digits are formed.						#
14432#									#
14433# A1. Init d7 to 1.  D7 is the byte digit counter, and if 1, the	#
14434#     digit formed will be assumed the least significant.  This is	#
14435#     to force the first byte formed to have a 0 in the upper 4 bits.	#
14436#									#
14437# A2. Beginning of the loop:						#
14438#     Copy the fraction in d2:d3 to d4:d5.				#
14439#									#
14440# A3. Multiply the fraction in d2:d3 by 8 using bit-field		#
14441#     extracts and shifts.  The three msbs from d2 will go into d1.	#
14442#									#
14443# A4. Multiply the fraction in d4:d5 by 2 using shifts.  The msb	#
14444#     will be collected by the carry.					#
14445#									#
14446# A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5	#
14447#     into d2:d3.  D1 will contain the bcd digit formed.		#
14448#									#
14449# A6. Test d7.  If zero, the digit formed is the ms digit.  If non-	#
14450#     zero, it is the ls digit.  Put the digit in its place in the	#
14451#     upper word of d0.  If it is the ls digit, write the word		#
14452#     from d0 to memory.						#
14453#									#
14454# A7. Decrement d6 (LEN counter) and repeat the loop until zero.	#
14455#									#
14456#########################################################################
14457
14458#	Implementation Notes:
14459#
14460#	The registers are used as follows:
14461#
14462#		d0: LEN counter
14463#		d1: temp used to form the digit
14464#		d2: upper 32-bits of fraction for mul by 8
14465#		d3: lower 32-bits of fraction for mul by 8
14466#		d4: upper 32-bits of fraction for mul by 2
14467#		d5: lower 32-bits of fraction for mul by 2
14468#		d6: temp for bit-field extracts
14469#		d7: byte digit formation word;digit count {0,1}
14470#		a0: pointer into memory for packed bcd string formation
14471#
14472
14473	global		binstr
14474binstr:
14475	movm.l		&0xff00,-(%sp)	#  {%d0-%d7}
14476
14477#
14478# A1: Init d7
14479#
14480	mov.l		&1,%d7		# init d7 for second digit
14481	subq.l		&1,%d0		# for dbf d0 would have LEN+1 passes
14482#
14483# A2. Copy d2:d3 to d4:d5.  Start loop.
14484#
14485loop:
14486	mov.l		%d2,%d4		# copy the fraction before muls
14487	mov.l		%d3,%d5		# to d4:d5
14488#
14489# A3. Multiply d2:d3 by 8; extract msbs into d1.
14490#
14491	bfextu		%d2{&0:&3},%d1	# copy 3 msbs of d2 into d1
14492	asl.l		&3,%d2		# shift d2 left by 3 places
14493	bfextu		%d3{&0:&3},%d6	# copy 3 msbs of d3 into d6
14494	asl.l		&3,%d3		# shift d3 left by 3 places
14495	or.l		%d6,%d2		# or in msbs from d3 into d2
14496#
14497# A4. Multiply d4:d5 by 2; add carry out to d1.
14498#
14499	asl.l		&1,%d5		# mul d5 by 2
14500	roxl.l		&1,%d4		# mul d4 by 2
14501	swap		%d6		# put 0 in d6 lower word
14502	addx.w		%d6,%d1		# add in extend from mul by 2
14503#
14504# A5. Add mul by 8 to mul by 2.  D1 contains the digit formed.
14505#
14506	add.l		%d5,%d3		# add lower 32 bits
14507	nop				# ERRATA FIX #13 (Rev. 1.2 6/6/90)
14508	addx.l		%d4,%d2		# add with extend upper 32 bits
14509	nop				# ERRATA FIX #13 (Rev. 1.2 6/6/90)
14510	addx.w		%d6,%d1		# add in extend from add to d1
14511	swap		%d6		# with d6 = 0; put 0 in upper word
14512#
14513# A6. Test d7 and branch.
14514#
14515	tst.w		%d7		# if zero, store digit & to loop
14516	beq.b		first_d		# if non-zero, form byte & write
14517sec_d:
14518	swap		%d7		# bring first digit to word d7b
14519	asl.w		&4,%d7		# first digit in upper 4 bits d7b
14520	add.w		%d1,%d7		# add in ls digit to d7b
14521	mov.b		%d7,(%a0)+	# store d7b byte in memory
14522	swap		%d7		# put LEN counter in word d7a
14523	clr.w		%d7		# set d7a to signal no digits done
14524	dbf.w		%d0,loop	# do loop some more!
14525	bra.b		end_bstr	# finished, so exit
14526first_d:
14527	swap		%d7		# put digit word in d7b
14528	mov.w		%d1,%d7		# put new digit in d7b
14529	swap		%d7		# put LEN counter in word d7a
14530	addq.w		&1,%d7		# set d7a to signal first digit done
14531	dbf.w		%d0,loop	# do loop some more!
14532	swap		%d7		# put last digit in string
14533	lsl.w		&4,%d7		# move it to upper 4 bits
14534	mov.b		%d7,(%a0)+	# store it in memory string
14535#
14536# Clean up and return with result in fp0.
14537#
14538end_bstr:
14539	movm.l		(%sp)+,&0xff	#  {%d0-%d7}
14540	rts
14541
14542#########################################################################
14543# XDEF ****************************************************************	#
14544#	facc_in_b(): dmem_read_byte failed				#
14545#	facc_in_w(): dmem_read_word failed				#
14546#	facc_in_l(): dmem_read_long failed				#
14547#	facc_in_d(): dmem_read of dbl prec failed			#
14548#	facc_in_x(): dmem_read of ext prec failed			#
14549#									#
14550#	facc_out_b(): dmem_write_byte failed				#
14551#	facc_out_w(): dmem_write_word failed				#
14552#	facc_out_l(): dmem_write_long failed				#
14553#	facc_out_d(): dmem_write of dbl prec failed			#
14554#	facc_out_x(): dmem_write of ext prec failed			#
14555#									#
14556# XREF ****************************************************************	#
14557#	_real_access() - exit through access error handler		#
14558#									#
14559# INPUT ***************************************************************	#
14560#	None								#
14561#									#
14562# OUTPUT **************************************************************	#
14563#	None								#
14564#									#
14565# ALGORITHM ***********************************************************	#
14566#	Flow jumps here when an FP data fetch call gets an error	#
14567# result. This means the operating system wants an access error frame	#
14568# made out of the current exception stack frame.			#
14569#	So, we first call restore() which makes sure that any updated	#
14570# -(an)+ register gets returned to its pre-exception value and then	#
14571# we change the stack to an access error stack frame.			#
14572#									#
14573#########################################################################
14574
14575facc_in_b:
14576	movq.l		&0x1,%d0			# one byte
14577	bsr.w		restore				# fix An
14578
14579	mov.w		&0x0121,EXC_VOFF(%a6)		# set FSLW
14580	bra.w		facc_finish
14581
14582facc_in_w:
14583	movq.l		&0x2,%d0			# two bytes
14584	bsr.w		restore				# fix An
14585
14586	mov.w		&0x0141,EXC_VOFF(%a6)		# set FSLW
14587	bra.b		facc_finish
14588
14589facc_in_l:
14590	movq.l		&0x4,%d0			# four bytes
14591	bsr.w		restore				# fix An
14592
14593	mov.w		&0x0101,EXC_VOFF(%a6)		# set FSLW
14594	bra.b		facc_finish
14595
14596facc_in_d:
14597	movq.l		&0x8,%d0			# eight bytes
14598	bsr.w		restore				# fix An
14599
14600	mov.w		&0x0161,EXC_VOFF(%a6)		# set FSLW
14601	bra.b		facc_finish
14602
14603facc_in_x:
14604	movq.l		&0xc,%d0			# twelve bytes
14605	bsr.w		restore				# fix An
14606
14607	mov.w		&0x0161,EXC_VOFF(%a6)		# set FSLW
14608	bra.b		facc_finish
14609
14610################################################################
14611
14612facc_out_b:
14613	movq.l		&0x1,%d0			# one byte
14614	bsr.w		restore				# restore An
14615
14616	mov.w		&0x00a1,EXC_VOFF(%a6)		# set FSLW
14617	bra.b		facc_finish
14618
14619facc_out_w:
14620	movq.l		&0x2,%d0			# two bytes
14621	bsr.w		restore				# restore An
14622
14623	mov.w		&0x00c1,EXC_VOFF(%a6)		# set FSLW
14624	bra.b		facc_finish
14625
14626facc_out_l:
14627	movq.l		&0x4,%d0			# four bytes
14628	bsr.w		restore				# restore An
14629
14630	mov.w		&0x0081,EXC_VOFF(%a6)		# set FSLW
14631	bra.b		facc_finish
14632
14633facc_out_d:
14634	movq.l		&0x8,%d0			# eight bytes
14635	bsr.w		restore				# restore An
14636
14637	mov.w		&0x00e1,EXC_VOFF(%a6)		# set FSLW
14638	bra.b		facc_finish
14639
14640facc_out_x:
14641	mov.l		&0xc,%d0			# twelve bytes
14642	bsr.w		restore				# restore An
14643
14644	mov.w		&0x00e1,EXC_VOFF(%a6)		# set FSLW
14645
14646# here's where we actually create the access error frame from the
14647# current exception stack frame.
14648facc_finish:
14649	mov.l		USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
14650
14651	fmovm.x		EXC_FPREGS(%a6),&0xc0	# restore fp0-fp1
14652	fmovm.l		USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
14653	movm.l		EXC_DREGS(%a6),&0x0303	# restore d0-d1/a0-a1
14654
14655	unlk		%a6
14656
14657	mov.l		(%sp),-(%sp)		# store SR, hi(PC)
14658	mov.l		0x8(%sp),0x4(%sp)	# store lo(PC)
14659	mov.l		0xc(%sp),0x8(%sp)	# store EA
14660	mov.l		&0x00000001,0xc(%sp)	# store FSLW
14661	mov.w		0x6(%sp),0xc(%sp)	# fix FSLW (size)
14662	mov.w		&0x4008,0x6(%sp)	# store voff
14663
14664	btst		&0x5,(%sp)		# supervisor or user mode?
14665	beq.b		facc_out2		# user
14666	bset		&0x2,0xd(%sp)		# set supervisor TM bit
14667
14668facc_out2:
14669	bra.l		_real_access
14670
14671##################################################################
14672
14673# if the effective addressing mode was predecrement or postincrement,
14674# the emulation has already changed its value to the correct post-
14675# instruction value. but since we're exiting to the access error
14676# handler, then AN must be returned to its pre-instruction value.
14677# we do that here.
14678restore:
14679	mov.b		EXC_OPWORD+0x1(%a6),%d1
14680	andi.b		&0x38,%d1		# extract opmode
14681	cmpi.b		%d1,&0x18		# postinc?
14682	beq.w		rest_inc
14683	cmpi.b		%d1,&0x20		# predec?
14684	beq.w		rest_dec
14685	rts
14686
14687rest_inc:
14688	mov.b		EXC_OPWORD+0x1(%a6),%d1
14689	andi.w		&0x0007,%d1		# fetch An
14690
14691	mov.w		(tbl_rest_inc.b,%pc,%d1.w*2),%d1
14692	jmp		(tbl_rest_inc.b,%pc,%d1.w*1)
14693
14694tbl_rest_inc:
14695	short		ri_a0 - tbl_rest_inc
14696	short		ri_a1 - tbl_rest_inc
14697	short		ri_a2 - tbl_rest_inc
14698	short		ri_a3 - tbl_rest_inc
14699	short		ri_a4 - tbl_rest_inc
14700	short		ri_a5 - tbl_rest_inc
14701	short		ri_a6 - tbl_rest_inc
14702	short		ri_a7 - tbl_rest_inc
14703
14704ri_a0:
14705	sub.l		%d0,EXC_DREGS+0x8(%a6)	# fix stacked a0
14706	rts
14707ri_a1:
14708	sub.l		%d0,EXC_DREGS+0xc(%a6)	# fix stacked a1
14709	rts
14710ri_a2:
14711	sub.l		%d0,%a2			# fix a2
14712	rts
14713ri_a3:
14714	sub.l		%d0,%a3			# fix a3
14715	rts
14716ri_a4:
14717	sub.l		%d0,%a4			# fix a4
14718	rts
14719ri_a5:
14720	sub.l		%d0,%a5			# fix a5
14721	rts
14722ri_a6:
14723	sub.l		%d0,(%a6)		# fix stacked a6
14724	rts
14725# if it's a fmove out instruction, we don't have to fix a7
14726# because we hadn't changed it yet. if it's an opclass two
14727# instruction (data moved in) and the exception was in supervisor
14728# mode, then also also wasn't updated. if it was user mode, then
14729# restore the correct a7 which is in the USP currently.
14730ri_a7:
14731	cmpi.b		EXC_VOFF(%a6),&0x30	# move in or out?
14732	bne.b		ri_a7_done		# out
14733
14734	btst		&0x5,EXC_SR(%a6)	# user or supervisor?
14735	bne.b		ri_a7_done		# supervisor
14736	movc		%usp,%a0		# restore USP
14737	sub.l		%d0,%a0
14738	movc		%a0,%usp
14739ri_a7_done:
14740	rts
14741
14742# need to invert adjustment value if the <ea> was predec
14743rest_dec:
14744	neg.l		%d0
14745	bra.b		rest_inc
~/ Read-only file preview.