/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:fpglue.s 12.1$ */
/* $ACIS:fpglue.s 12.1$ */
/* $Source: /ibm/acis/usr/sys/ca/RCS/fpglue.s,v $ */

	.data
/* note: fpglue is added to rcsid to avoid name duplication in kernel */
#if !defined(NO_RCS_HDRS)
rcsidfpglue:	.asciz	"$Header:fpglue.s 12.1$"
#endif
	.text

/*
 * NOTE:
 *
 * this source file exists in both libc (/usr/src/lib/libc/ca/csu/fpglue.s)
 * and the kernel (/usr/sys/ca/fpglue.s), make sure that modifications
 * are reflected in BOTH versions.
 */

#include <syscall.h>

#define MAJOR_VERSION	3
#define MINOR_VERSION	1

	.globl	FPGLUE
	.globl  fpglue
#if defined(KERNEL) || defined(PROFILE)
	.globl	_.fpgen			# necessary to call fpgen() directly
	.globl	_fpgen			# necessary to call fpgen() directly
#endif KERNEL
	.globl	.oVncs
	.set	.oVncs,0

#ifdef PROFILE
	.data
	.align	2
.fpglue:
	.long	fpglue
	.long	0			# mcount counter
#endif PROFILE

	.text
	.align	2
#ifdef KERNEL
fpglue:	.set	FPGLUE,fpglue-real0+NFL_INSTN /* bala fpget */
#else
fpglue:	.set	FPGLUE,fpglue+0x8a000000 /* bala fpget */
#endif
/*
 * fpglue is called from a RTFL block via:
 *		mr	r0,r15
 *		bala	r15,fpglue
 * At entrance, r0 = ultimate return address (in text segment),
 *		r15 = beginning of current RTFL block + 6
 */
	stm	r0,-100(sp)		# save ALL regs across call
	st	r0,-40(sp)		# change return address by  
					# override the stored r15
	cal	sp,-100(sp)		# move stack pointer
#ifdef PROFILE
	mr	r12,r15			# remember where RTFL block starts
	get	r14,$.fpglue
	bali	r15,mcount
	mr	r15,r12
#endif PROFILE
#ifndef KERNEL
 	get	r2,$fp_State		# see if state of FPA is known  
 	ls	r2,0(r2)
 	o	r2,r2			# If state of FPA is known,
 	jne	1f			# then go call FPA code generator,
					# else, get all state info:
	mr	r12,r15			# remember where RTFL block starts
	get	r2,$fpa_env		# name of fpa envir. variable
	get	r0,$_getenv		# data area for getenv
	bali	r15,_.getenv		# call getenv function
	get	r4,$fp_FPA		# pointer to FPA string
	sts	r2,0(r4)		# store pointer

	get	r2,$prec_env		# name of precision envir. variable
	get	r0,$_getenv		# data area for getenv
	bali	r15,_.getenv		# call getenv function
	get	r4,$fp_Precision	# pointer to FP_PRECISION string
	sts	r2,0(r4)		# store pointer
	mr	r15,r12			# restore r15

 	get	r2,$fp_State		# first argument for getfloatstate
 	get	r3,$fp_StateSize	# second argument
 	svc	SYS_getfloatstate(r0)	# issue svc to get state of FPA

	lis	r2,MAJOR_VERSION
	get	r3,$fp_FirstTime
	sts	r2,0(r3)
	lis	r2,MINOR_VERSION
	get	r3,$fp_MachRegs
	sts	r2,0(r3)
1:
#endif KERNEL
	cal	r2,-6(r15)		# 1st arg = beginning of RTFL block
	get	r3,$fp_State		# second argument for fp code gen.
	mr	r4,sp			# next argument is addr. of usr's gprs
	cal	r5,64(sp)		# last argument is addr. of emul cstat

#if defined(KERNEL) && defined(DEBUG)
	mfs	scr_ics,r6		# trap if priority < 6
	nilz	r6,r6,0x7
	ti	4,r6,6			# tlti r6,6
#endif

#if defined(KERNEL) || defined(PROFILE)
	get	r6,$fp_genaddr		# calling fpgen() directly
#else
 	get	r6,$fp_CodeGen		# addr of ptr to fpgen()
#endif KERNEL
 	get	r6,0(r6)		# get ptr to data of fpgen()
	mr	r0,r6
 	get	r6,0(r6)		# get text entry point of fpgen()
	balrx	r15,r6			# call fpgen()
	st	r2,0(sp)		# overwritten r0 on the stack with
					# the returned addr (the begining of
					# RTFL block)

	cis	r2,0			# code gen returns:
					# 1 - if no code generated (i.e. emul)
					# 0 - if code generated (fp hardware)
 	jne	2f
	cal	sp,100(sp)		# replace stack pointer
	lm	r0,-100(r1)		# restore regs after call
	br	r0			# return (to generated code)
2:
	load  	r2,64(sp)               # get condition code from save area
	mts     r15,r2	 		# store in RT's condition status reg.
	cal	sp,100(sp)		# replace stack pointer
	lm	r0,-100(r1)		# restore regs after call
	br	r15			# return (to caller no code generated)
	.short	0xdf07			# trace table
	.short	0xdf08			# first register saved is 0
	.short	0x0119			# npars=0, frame=r1, lcl_offset=100

#ifndef KERNEL
/*
 * Hideaway codes to handle CMPT with NAN for the mc881.
 *
 * Entry conditions:
 *
 * Original caller's r13,14,15 are stored at fp_r1X_holder
 * and their content have been re-loaded with:
 *
 * r13	= What f881_FPSR should be (with IOP bits set).
 * r14	= Scratch
 * r15	= Return address if IOP trap is disable.
 */
	.text
	.align	2
f881_cmp_NAN:
	get	r14,$f881_scr_holder	# write mc881 status
	sts	r13,0(r14)
	cau	r13,0xfc02(r0)
	st	r14,0x2001(r13)		# 0xfc022001 = FMOVE to FPSR

	cau	r13,0xfc3f(r0)		# read mc881 trap enable
	st	r14,0xc001(r13)		# 0xfc3ec001 = FMOVE from FPCR
	setsb	r15,8			# sync
	ls	r13,0(r14)

	nilz	r13,r13,0x2000		# is IOP trap enabled?
	berx	r15			# NO, restore r13-15 while
	lm	r13,8(r14)		#	returning to the caller

	get	r0,$_getpid		# YES, kill current process with
	get	r15,$_.getpid		#	floating point exception
	balr	r15,r15			#	signal.
	lis	r3,8			# SIGFPE = 8
	get	r0,$_kill
	get	r15,$_.kill
	br	r15
#endif !KERNEL


	.data
	.align	2
#if defined(KERNEL) || defined(PROFILE)
fp_genaddr:	.long	_fpgen		# for calling fpgen() directly
#endif KERNEL

 # the size of the floating point state structure
fp_StateSize:   .long	fp_StateEnd -fp_State

 # the following must match exactly to that of fp_state in fpgen.h
 # changes should be reflected in FirstTime value and in VERSION in fpgen.h
 #
 # fp_FirstTime, major version number, it is used to rule out a corrupted
 #	fpglue().
 # fp_MachRegs, minor version number, tell fpgen() what features supported
 #	in this a.out.  The minor version number is needed to support
 #	old a.out's running on new kernel.
 # After the first fp operation, fp_FirstTime += (fp_MachRegs + 1).
 #
 # ???-??-88	TQH	Change minor version number from 0-->1.  Added
 #			support for MC881 cmp with NAN's.  Also handle
 #			single precision correctly for the MC881.
 # Jun-13-88	TQH	Change minor version number from 1-->2.  Added
 #			support for unsigned int type in fpgen().
 # Sep-13-88	TQH	Change minor version back from 2-->1.  The support
 #			is done for mc881 but need more work for AFPA
 #			and emul.

 # the floating point state structure (see struct floatstate in #include
 # <machine/float.h>)
fp_State:	      		       
	.globl  __fp_HardwareState
	# init to 0, set by getfloatstate() system call.
	# Make __fp_HardwareState global so that user program can reset
	# it to 0.  This will force fpglue() to call getfloatstate()
	# again and hence update the fp_State structure.  It is rarely
	# used.
#ifdef KERNEL
__fp_HardwareState:	.long	FLOAT_EMUL	# hardware state
fp_PrState:   	.long	FLOAT_EMUL		# process state
#else
__fp_HardwareState:	.long	0	# hardware state
fp_PrState:   	.long	0		# process state
#endif
fp_EmulAddr:	.long	0		# address of pointer to fp emulator
fp_CodeGen:	.long	0		# address of pointer to code generator
fp_RegSet:	.long	0		# fp register set
fp_StateEnd:             		# end of FPA State structure

fp_FirstTime:	.long	MAJOR_VERSION	# version #: after first time, set to
					# fp_FirstTime + fp_MachRegs + 1
					# must match VERSION in fpgen.h
fp_MachRegs:	.long	MINOR_VERSION	# minor version number.  After first
					# time, address of emulator fp machine
fp_FpType:	.long	0		# type of "hardware" picked
fp_FPA:		.long	0		# address of fpa envir. variable string
fp_Precision:	.long	0		# address of precision envir. variable 
fp_Compat:	.long	__compat	# addr of compat value
#ifdef KERNEL
fp_calloc:	.long	_calloc		# dp for calloc()
fp_abort:	.long	_panic		# dp for panic(), called if errors
fp_block:	.long	_panic		# should never be called
fp_setfloatstate:	.long	_panic	# should never be called
f881_scr_holder:	.long	0
f881_cmp_NAN_code:	.long	_panic
#else
fp_Malloc:	.long	_malloc		# dp for malloc()
fp_abort:	.long	_fpabort	# dp for fpabort(), called if errors
fp_block:	.long	_sigsetmask	# dp for sigsetmask()
fp_setfloatstate:	.long	_setfloatstate	# dp for setfloatstate()
f881_scr_holder:	.long	0
f881_cmp_NAN_code:	.long	f881_cmp_NAN
#endif
fp_r13_holder:		.long	0
fp_r14_holder:		.long	0
fp_r15_holder:		.long	0
fp_hi_2to31:		.long	0x41e00000	# to support unsigned int
fp_lo_2to31:		.long	0		# to support unsigned int
fp_f_2to31:		.long	0x4f000000	# to support unsigned int
fp_scratch_1:		.long	0
fp_scratch_2:		.long	0
fp_scratch_3:		.long	0
fp_scratch_4:		.long	0
		.fill	25,4,0		# reserve 32-7 words for expansion.

		.comm	__compat,4
fpa_env:	.ascii	"FPA\0"		# name of fpa envir. variable
prec_env:	.ascii	"FP_PRECISION\0" #name of fp_precision envir. variable

