PageRenderTime 327ms CodeModel.GetById 22ms app.highlight 225ms RepoModel.GetById 1ms app.codeStats 3ms

/arch/m68k/ifpsp060/src/pfpsp.S

https://bitbucket.org/evzijst/gittest
Assembly | 14745 lines | 13552 code | 1193 blank | 0 comment | 323 complexity | 175cf69aa2f13a5f5a79a01ab9b41c33 MD5 | raw file
    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# undeflow 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 threshhold	#
 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