xref: /onnv-gate/usr/src/uts/sparc/v9/ml/float.s (revision 1614:6743605c1475)
10Sstevel@tonic-gate/*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*1614Sjb145095 * Common Development and Distribution License (the "License").
6*1614Sjb145095 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate/*
22*1614Sjb145095 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate#ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate#include <sys/asm_linkage.h>
290Sstevel@tonic-gate#include <sys/trap.h>
300Sstevel@tonic-gate#include <sys/machpcb.h>
31*1614Sjb145095#include <sys/machtrap.h>
32*1614Sjb145095#include <sys/machsig.h>
33*1614Sjb145095#include <sys/machthread.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate#if !defined(lint) && !defined(__lint)
360Sstevel@tonic-gate#include "assym.h"
370Sstevel@tonic-gate#endif	/* lint */
380Sstevel@tonic-gate
390Sstevel@tonic-gate/*
400Sstevel@tonic-gate * Floating point trap handling.
410Sstevel@tonic-gate *
420Sstevel@tonic-gate *	The FPU is always in a V9 current configuration.
430Sstevel@tonic-gate *
440Sstevel@tonic-gate *	When a user process is first started via exec,
450Sstevel@tonic-gate *	floating point operations will be disabled by default.
460Sstevel@tonic-gate *	Upon execution of the first floating point instruction,
470Sstevel@tonic-gate *	a fp_disabled trap will be generated; then a word in
480Sstevel@tonic-gate *	the uarea is written signifying use of the floating point
490Sstevel@tonic-gate *	registers so that subsequent context switches will save
500Sstevel@tonic-gate *	and restore the floating point them. The trapped instruction
510Sstevel@tonic-gate *	will be restarted and processing will continue as normal.
520Sstevel@tonic-gate *
530Sstevel@tonic-gate *	When a operation occurs that the hardware cannot properly
540Sstevel@tonic-gate *	handle, an unfinshed fp_op exception will be generated.
550Sstevel@tonic-gate *	Software routines in the kernel will be	executed to
560Sstevel@tonic-gate *	simulate proper handling of such conditions.
570Sstevel@tonic-gate *
580Sstevel@tonic-gate *	Exception handling will emulate all instructions
590Sstevel@tonic-gate *	in the floating point address queue. Note that there
600Sstevel@tonic-gate *	is no %fq in sun4u, because it has precise FP traps.
610Sstevel@tonic-gate *
620Sstevel@tonic-gate *	Floating point queues are now machine dependent, and std %fq
630Sstevel@tonic-gate *	is an illegal V9 instruction. The fp_exception code has been
640Sstevel@tonic-gate *	moved to sun4u/ml/machfloat.s.
650Sstevel@tonic-gate *
660Sstevel@tonic-gate *	NOTE: This code DOES NOT SUPPORT KERNEL (DEVICE DRIVER)
670Sstevel@tonic-gate *		USE OF THE FPU
680Sstevel@tonic-gate *
690Sstevel@tonic-gate *	Instructions for running without the hardware fpu:
700Sstevel@tonic-gate *	1. Setting fpu_exists to 0 now only works on a DEBUG kernel.
710Sstevel@tonic-gate *	2. adb -w unix and set fpu_exists, use_hw_bcopy, use_hw_copyio, and
720Sstevel@tonic-gate *		use_hw_bzero to 0 and rename libc_psr.so.1 in
730Sstevel@tonic-gate *		/usr/platform/sun4u/lib so that it will not get used by
740Sstevel@tonic-gate *		the libc bcopy routines. Then reboot the system and you
750Sstevel@tonic-gate *		should see the bootup message "FPU not in use".
760Sstevel@tonic-gate *	3. To run kaos, you must comment out the code which sets the
770Sstevel@tonic-gate *		version number of the fsr to 7, in fldst: stfsr/stxfsr
780Sstevel@tonic-gate *		(unless you are running against a comparison system that
790Sstevel@tonic-gate *		has the same fsr version number).
800Sstevel@tonic-gate *	4. The stqf{a}/ldqf{a} instructions cause kaos errors, for reasons
810Sstevel@tonic-gate *		that appear to be a kaos bug, so don't use them!
820Sstevel@tonic-gate */
830Sstevel@tonic-gate
840Sstevel@tonic-gate#if defined(lint) || defined(__lint)
850Sstevel@tonic-gate
860Sstevel@tonic-gate#ifdef FP_DISABLED
870Sstevel@tonic-gateint fpu_exists = 0;
880Sstevel@tonic-gate#else
890Sstevel@tonic-gateint fpu_exists = 1;
900Sstevel@tonic-gate#endif
910Sstevel@tonic-gate
920Sstevel@tonic-gate#else	/* lint */
930Sstevel@tonic-gate
940Sstevel@tonic-gate	.section ".data"
950Sstevel@tonic-gate	.align	8
960Sstevel@tonic-gatefsrholder:
970Sstevel@tonic-gate	.word	0			! dummy place to write fsr
980Sstevel@tonic-gate	.word	0
990Sstevel@tonic-gate
1000Sstevel@tonic-gate	DGDEF(fpu_exists)		! always exists for V9
1010Sstevel@tonic-gate#ifdef FP_DISABLED
1020Sstevel@tonic-gate	.word	0
1030Sstevel@tonic-gate#else
1040Sstevel@tonic-gate	.word	1			! sundiag (gack) uses this variable
1050Sstevel@tonic-gate#endif
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate	DGDEF(fpu_version)
1080Sstevel@tonic-gate	.word	-1
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate#endif	/* lint */
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate/*
1130Sstevel@tonic-gate * FPU probe - read the %fsr and get fpu_version.
1140Sstevel@tonic-gate * Called from autoconf. If a %fq is created for
1150Sstevel@tonic-gate * future cpu versions, a fq_exists variable
1160Sstevel@tonic-gate * could be created by this function.
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate#if defined(lint) || defined(__lint)
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate/*ARGSUSED*/
1220Sstevel@tonic-gatevoid
1230Sstevel@tonic-gatefpu_probe(void)
1240Sstevel@tonic-gate{}
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate#else	/* lint */
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate	ENTRY_NP(fpu_probe)
1290Sstevel@tonic-gate	wr	%g0, FPRS_FEF, %fprs	! enable fpu in fprs
1300Sstevel@tonic-gate	rdpr	%pstate, %g2		! read pstate, save value in %g2
1310Sstevel@tonic-gate	or	%g2, PSTATE_PEF, %g1	! new pstate with fpu enabled
1320Sstevel@tonic-gate	wrpr	%g1, %g0, %pstate	! write pstate
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate	sethi	%hi(fsrholder), %g2
1350Sstevel@tonic-gate	stx	%fsr, [%g2 + %lo(fsrholder)]
1360Sstevel@tonic-gate	ldx	[%g2 + %lo(fsrholder)], %g2	! snarf the FSR
1370Sstevel@tonic-gate	set	FSR_VER, %g1
1380Sstevel@tonic-gate	and	%g2, %g1, %g2			! get version
1390Sstevel@tonic-gate	srl	%g2, FSR_VER_SHIFT, %g2		! and shift it down
1400Sstevel@tonic-gate	sethi	%hi(fpu_version), %g3		! save the FPU version
1410Sstevel@tonic-gate	st	%g2, [%g3 + %lo(fpu_version)]
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate	ba	fp_kstat_init		! initialize the fpu_kstat
1440Sstevel@tonic-gate	wr	%g0, %g0, %fprs		! disable fpu and clear fprs
1450Sstevel@tonic-gate	SET_SIZE(fpu_probe)
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate#endif	/* lint */
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate/*
1500Sstevel@tonic-gate * fp_clearregs(fp)
1510Sstevel@tonic-gate *	struct v9_fpu *fp;
1520Sstevel@tonic-gate *
1530Sstevel@tonic-gate * Initialization for the hardware fpu.
1540Sstevel@tonic-gate * Clear the fsr and initialize registers to NaN (-1)
1550Sstevel@tonic-gate * The caller (fp_disabled) is supposed to update the fprs
1560Sstevel@tonic-gate * so when the return to userland is made, the fpu is enabled.
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate#if defined(lint) || defined(__lint)
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate/*ARGSUSED*/
1620Sstevel@tonic-gatevoid
1630Sstevel@tonic-gatefp_clearregs(kfpu_t *fp)
1640Sstevel@tonic-gate{}
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate#else	/* lint */
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate	ENTRY_NP(fp_clearregs)
1690Sstevel@tonic-gate	ldx	[%o0 + FPU_FSR], %fsr		! load fsr
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate	mov	-1, %g2				! -1 is NaN
1720Sstevel@tonic-gate	stx	%g2, [%o0]			! initialize %f0
1730Sstevel@tonic-gate	ldd	[%o0], %d0
1740Sstevel@tonic-gate	ldd	[%o0], %d2
1750Sstevel@tonic-gate	ldd	[%o0], %d4
1760Sstevel@tonic-gate	ldd	[%o0], %d6
1770Sstevel@tonic-gate	ldd	[%o0], %d8
1780Sstevel@tonic-gate	ldd	[%o0], %d10
1790Sstevel@tonic-gate	ldd	[%o0], %d12
1800Sstevel@tonic-gate	ldd	[%o0], %d14
1810Sstevel@tonic-gate	ldd	[%o0], %d16
1820Sstevel@tonic-gate	ldd	[%o0], %d18
1830Sstevel@tonic-gate	ldd	[%o0], %d20
1840Sstevel@tonic-gate	ldd	[%o0], %d22
1850Sstevel@tonic-gate	ldd	[%o0], %d24
1860Sstevel@tonic-gate	ldd	[%o0], %d26
1870Sstevel@tonic-gate	ldd	[%o0], %d28
1880Sstevel@tonic-gate	ldd	[%o0], %d30
1890Sstevel@tonic-gate	ldd	[%o0], %d32
1900Sstevel@tonic-gate	ldd	[%o0], %d34
1910Sstevel@tonic-gate	ldd	[%o0], %d36
1920Sstevel@tonic-gate	ldd	[%o0], %d38
1930Sstevel@tonic-gate	ldd	[%o0], %d40
1940Sstevel@tonic-gate	ldd	[%o0], %d42
1950Sstevel@tonic-gate	ldd	[%o0], %d44
1960Sstevel@tonic-gate	ldd	[%o0], %d46
1970Sstevel@tonic-gate	ldd	[%o0], %d48
1980Sstevel@tonic-gate	ldd	[%o0], %d50
1990Sstevel@tonic-gate	ldd	[%o0], %d52
2000Sstevel@tonic-gate	ldd	[%o0], %d54
2010Sstevel@tonic-gate	ldd	[%o0], %d56
2020Sstevel@tonic-gate	ldd	[%o0], %d58
2030Sstevel@tonic-gate	ldd	[%o0], %d60
2040Sstevel@tonic-gate	retl
2050Sstevel@tonic-gate	ldd	[%o0], %d62
2060Sstevel@tonic-gate	SET_SIZE(fp_clearregs)
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate#endif	/* lint */
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate/*
2110Sstevel@tonic-gate * void _fp_read_pfreg(pf, n)
2120Sstevel@tonic-gate *	uint32_t	*pf;	Old freg value.
2130Sstevel@tonic-gate *	unsigned	n;	Want to read register n
2140Sstevel@tonic-gate *
2150Sstevel@tonic-gate * {
2160Sstevel@tonic-gate *	*pf = %f[n];
2170Sstevel@tonic-gate * }
2180Sstevel@tonic-gate *
2190Sstevel@tonic-gate * void
2200Sstevel@tonic-gate * _fp_write_pfreg(pf, n)
2210Sstevel@tonic-gate *	uint32_t	*pf;	New freg value.
2220Sstevel@tonic-gate *	unsigned	n;	Want to write register n.
2230Sstevel@tonic-gate *
2240Sstevel@tonic-gate * {
2250Sstevel@tonic-gate *	%f[n] = *pf;
2260Sstevel@tonic-gate * }
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate#if defined(lint) || defined(__lint)
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate/*ARGSUSED*/
2320Sstevel@tonic-gatevoid
2330Sstevel@tonic-gate_fp_read_pfreg(uint32_t *pf, u_int n)
2340Sstevel@tonic-gate{}
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate/*ARGSUSED*/
2370Sstevel@tonic-gatevoid
2380Sstevel@tonic-gate_fp_write_pfreg(uint32_t *pf, u_int n)
2390Sstevel@tonic-gate{}
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate#else	/* lint */
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate	ENTRY_NP(_fp_read_pfreg)
2440Sstevel@tonic-gate	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
2450Sstevel@tonic-gate	set	.stable, %g1		! g1 gets base of table.
2460Sstevel@tonic-gate	jmp	%g1 + %o1		! Jump into table
2470Sstevel@tonic-gate	nop				! Can't follow CTI by CTI.
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate	ENTRY_NP(_fp_write_pfreg)
2500Sstevel@tonic-gate	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
2510Sstevel@tonic-gate	set	.ltable, %g1		! g1 gets base of table.
2520Sstevel@tonic-gate	jmp	%g1 + %o1		! Jump into table
2530Sstevel@tonic-gate	nop				! Can't follow CTI by CTI.
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate#define STOREFP(n) jmp %o7+8 ; st %f/**/n, [%o0]
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate.stable:
2580Sstevel@tonic-gate	STOREFP(0)
2590Sstevel@tonic-gate	STOREFP(1)
2600Sstevel@tonic-gate	STOREFP(2)
2610Sstevel@tonic-gate	STOREFP(3)
2620Sstevel@tonic-gate	STOREFP(4)
2630Sstevel@tonic-gate	STOREFP(5)
2640Sstevel@tonic-gate	STOREFP(6)
2650Sstevel@tonic-gate	STOREFP(7)
2660Sstevel@tonic-gate	STOREFP(8)
2670Sstevel@tonic-gate	STOREFP(9)
2680Sstevel@tonic-gate	STOREFP(10)
2690Sstevel@tonic-gate	STOREFP(11)
2700Sstevel@tonic-gate	STOREFP(12)
2710Sstevel@tonic-gate	STOREFP(13)
2720Sstevel@tonic-gate	STOREFP(14)
2730Sstevel@tonic-gate	STOREFP(15)
2740Sstevel@tonic-gate	STOREFP(16)
2750Sstevel@tonic-gate	STOREFP(17)
2760Sstevel@tonic-gate	STOREFP(18)
2770Sstevel@tonic-gate	STOREFP(19)
2780Sstevel@tonic-gate	STOREFP(20)
2790Sstevel@tonic-gate	STOREFP(21)
2800Sstevel@tonic-gate	STOREFP(22)
2810Sstevel@tonic-gate	STOREFP(23)
2820Sstevel@tonic-gate	STOREFP(24)
2830Sstevel@tonic-gate	STOREFP(25)
2840Sstevel@tonic-gate	STOREFP(26)
2850Sstevel@tonic-gate	STOREFP(27)
2860Sstevel@tonic-gate	STOREFP(28)
2870Sstevel@tonic-gate	STOREFP(29)
2880Sstevel@tonic-gate	STOREFP(30)
2890Sstevel@tonic-gate	STOREFP(31)
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate#define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate.ltable:
2940Sstevel@tonic-gate	LOADFP(0)
2950Sstevel@tonic-gate	LOADFP(1)
2960Sstevel@tonic-gate	LOADFP(2)
2970Sstevel@tonic-gate	LOADFP(3)
2980Sstevel@tonic-gate	LOADFP(4)
2990Sstevel@tonic-gate	LOADFP(5)
3000Sstevel@tonic-gate	LOADFP(6)
3010Sstevel@tonic-gate	LOADFP(7)
3020Sstevel@tonic-gate	LOADFP(8)
3030Sstevel@tonic-gate	LOADFP(9)
3040Sstevel@tonic-gate	LOADFP(10)
3050Sstevel@tonic-gate	LOADFP(11)
3060Sstevel@tonic-gate	LOADFP(12)
3070Sstevel@tonic-gate	LOADFP(13)
3080Sstevel@tonic-gate	LOADFP(14)
3090Sstevel@tonic-gate	LOADFP(15)
3100Sstevel@tonic-gate	LOADFP(16)
3110Sstevel@tonic-gate	LOADFP(17)
3120Sstevel@tonic-gate	LOADFP(18)
3130Sstevel@tonic-gate	LOADFP(19)
3140Sstevel@tonic-gate	LOADFP(20)
3150Sstevel@tonic-gate	LOADFP(21)
3160Sstevel@tonic-gate	LOADFP(22)
3170Sstevel@tonic-gate	LOADFP(23)
3180Sstevel@tonic-gate	LOADFP(24)
3190Sstevel@tonic-gate	LOADFP(25)
3200Sstevel@tonic-gate	LOADFP(26)
3210Sstevel@tonic-gate	LOADFP(27)
3220Sstevel@tonic-gate	LOADFP(28)
3230Sstevel@tonic-gate	LOADFP(29)
3240Sstevel@tonic-gate	LOADFP(30)
3250Sstevel@tonic-gate	LOADFP(31)
3260Sstevel@tonic-gate	SET_SIZE(_fp_read_pfreg)
3270Sstevel@tonic-gate	SET_SIZE(_fp_write_pfreg)
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate#endif	/* lint */
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate/*
3320Sstevel@tonic-gate * void _fp_read_pdreg(
3330Sstevel@tonic-gate *	uint64_t	*pd,	Old dreg value.
3340Sstevel@tonic-gate *	u_int	n)		Want to read register n
3350Sstevel@tonic-gate *
3360Sstevel@tonic-gate * {
3370Sstevel@tonic-gate *	*pd = %d[n];
3380Sstevel@tonic-gate * }
3390Sstevel@tonic-gate *
3400Sstevel@tonic-gate * void
3410Sstevel@tonic-gate * _fp_write_pdreg(
3420Sstevel@tonic-gate *	uint64_t	*pd,	New dreg value.
3430Sstevel@tonic-gate *	u_int	n)		Want to write register n.
3440Sstevel@tonic-gate *
3450Sstevel@tonic-gate * {
3460Sstevel@tonic-gate *	%d[n] = *pd;
3470Sstevel@tonic-gate * }
3480Sstevel@tonic-gate */
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate#if defined(lint) || defined(__lint)
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate/*ARGSUSED*/
3530Sstevel@tonic-gatevoid
3540Sstevel@tonic-gate_fp_read_pdreg(uint64_t *pd, u_int n)
3550Sstevel@tonic-gate{}
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate/*ARGSUSED*/
3580Sstevel@tonic-gatevoid
3590Sstevel@tonic-gate_fp_write_pdreg(uint64_t *pd, u_int n)
3600Sstevel@tonic-gate{}
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate#else	/* lint */
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate	ENTRY_NP(_fp_read_pdreg)
3650Sstevel@tonic-gate	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
3660Sstevel@tonic-gate	set	.dstable, %g1		! g1 gets base of table.
3670Sstevel@tonic-gate	jmp	%g1 + %o1		! Jump into table
3680Sstevel@tonic-gate	nop				! Can't follow CTI by CTI.
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate	ENTRY_NP(_fp_write_pdreg)
3710Sstevel@tonic-gate	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
3720Sstevel@tonic-gate	set	.dltable, %g1		! g1 gets base of table.
3730Sstevel@tonic-gate	jmp	%g1 + %o1		! Jump into table
3740Sstevel@tonic-gate	nop				! Can't follow CTI by CTI.
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate#define STOREDP(n) jmp %o7+8 ; std %d/**/n, [%o0]
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate.dstable:
3790Sstevel@tonic-gate	STOREDP(0)
3800Sstevel@tonic-gate	STOREDP(2)
3810Sstevel@tonic-gate	STOREDP(4)
3820Sstevel@tonic-gate	STOREDP(6)
3830Sstevel@tonic-gate	STOREDP(8)
3840Sstevel@tonic-gate	STOREDP(10)
3850Sstevel@tonic-gate	STOREDP(12)
3860Sstevel@tonic-gate	STOREDP(14)
3870Sstevel@tonic-gate	STOREDP(16)
3880Sstevel@tonic-gate	STOREDP(18)
3890Sstevel@tonic-gate	STOREDP(20)
3900Sstevel@tonic-gate	STOREDP(22)
3910Sstevel@tonic-gate	STOREDP(24)
3920Sstevel@tonic-gate	STOREDP(26)
3930Sstevel@tonic-gate	STOREDP(28)
3940Sstevel@tonic-gate	STOREDP(30)
3950Sstevel@tonic-gate	STOREDP(32)
3960Sstevel@tonic-gate	STOREDP(34)
3970Sstevel@tonic-gate	STOREDP(36)
3980Sstevel@tonic-gate	STOREDP(38)
3990Sstevel@tonic-gate	STOREDP(40)
4000Sstevel@tonic-gate	STOREDP(42)
4010Sstevel@tonic-gate	STOREDP(44)
4020Sstevel@tonic-gate	STOREDP(46)
4030Sstevel@tonic-gate	STOREDP(48)
4040Sstevel@tonic-gate	STOREDP(50)
4050Sstevel@tonic-gate	STOREDP(52)
4060Sstevel@tonic-gate	STOREDP(54)
4070Sstevel@tonic-gate	STOREDP(56)
4080Sstevel@tonic-gate	STOREDP(58)
4090Sstevel@tonic-gate	STOREDP(60)
4100Sstevel@tonic-gate	STOREDP(62)
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate#define LOADDP(n) jmp %o7+8 ; ldd [%o0],%d/**/n
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate.dltable:
4150Sstevel@tonic-gate	LOADDP(0)
4160Sstevel@tonic-gate	LOADDP(2)
4170Sstevel@tonic-gate	LOADDP(4)
4180Sstevel@tonic-gate	LOADDP(6)
4190Sstevel@tonic-gate	LOADDP(8)
4200Sstevel@tonic-gate	LOADDP(10)
4210Sstevel@tonic-gate	LOADDP(12)
4220Sstevel@tonic-gate	LOADDP(14)
4230Sstevel@tonic-gate	LOADDP(16)
4240Sstevel@tonic-gate	LOADDP(18)
4250Sstevel@tonic-gate	LOADDP(20)
4260Sstevel@tonic-gate	LOADDP(22)
4270Sstevel@tonic-gate	LOADDP(24)
4280Sstevel@tonic-gate	LOADDP(26)
4290Sstevel@tonic-gate	LOADDP(28)
4300Sstevel@tonic-gate	LOADDP(30)
4310Sstevel@tonic-gate	LOADDP(32)
4320Sstevel@tonic-gate	LOADDP(34)
4330Sstevel@tonic-gate	LOADDP(36)
4340Sstevel@tonic-gate	LOADDP(38)
4350Sstevel@tonic-gate	LOADDP(40)
4360Sstevel@tonic-gate	LOADDP(42)
4370Sstevel@tonic-gate	LOADDP(44)
4380Sstevel@tonic-gate	LOADDP(46)
4390Sstevel@tonic-gate	LOADDP(48)
4400Sstevel@tonic-gate	LOADDP(50)
4410Sstevel@tonic-gate	LOADDP(52)
4420Sstevel@tonic-gate	LOADDP(54)
4430Sstevel@tonic-gate	LOADDP(56)
4440Sstevel@tonic-gate	LOADDP(58)
4450Sstevel@tonic-gate	LOADDP(60)
4460Sstevel@tonic-gate	LOADDP(62)
4470Sstevel@tonic-gate	SET_SIZE(_fp_read_pdreg)
4480Sstevel@tonic-gate	SET_SIZE(_fp_write_pdreg)
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate#endif	/* lint */
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate#if defined(lint) || defined(__lint)
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate/*ARGSUSED*/
4550Sstevel@tonic-gatevoid
4560Sstevel@tonic-gate_fp_write_pfsr(uint64_t *fsr)
4570Sstevel@tonic-gate{}
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate#else	/* lint */
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate	ENTRY_NP(_fp_write_pfsr)
4620Sstevel@tonic-gate	retl
4630Sstevel@tonic-gate	ldx	[%o0], %fsr
4640Sstevel@tonic-gate	SET_SIZE(_fp_write_pfsr)
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate#endif	/* lint */
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate#if defined(lint) || defined(__lint)
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate/*ARGSUSED*/
4710Sstevel@tonic-gatevoid
4720Sstevel@tonic-gate_fp_read_pfsr(uint64_t *fsr)
4730Sstevel@tonic-gate{}
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate#else	/* lint */
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate	ENTRY_NP(_fp_read_pfsr)
4780Sstevel@tonic-gate	retl
4790Sstevel@tonic-gate	stx	%fsr, [%o0]
4800Sstevel@tonic-gate	SET_SIZE(_fp_read_pfsr)
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate#endif	/* lint */
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate#if defined(lint) || defined(__lint)
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate/*ARGSUSED*/
4870Sstevel@tonic-gatevoid
4880Sstevel@tonic-gate_fp_write_fprs(u_int fprs_val)
4890Sstevel@tonic-gate{}
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate#else	/* lint */
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate	ENTRY_NP(_fp_write_fprs)
4940Sstevel@tonic-gate	retl
4950Sstevel@tonic-gate	wr	%o0, %g0, %fprs			! write fprs
4960Sstevel@tonic-gate	SET_SIZE(_fp_write_fprs)
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate#endif	/* lint */
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate#if defined(lint) || defined(__lint)
5010Sstevel@tonic-gate
5020Sstevel@tonic-gateunsigned
5030Sstevel@tonic-gate_fp_read_fprs(void)
5040Sstevel@tonic-gate{return 0;}
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate#else	/* lint */
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate	ENTRY_NP(_fp_read_fprs)
5090Sstevel@tonic-gate	retl
5100Sstevel@tonic-gate	rd	%fprs, %o0			! save fprs
5110Sstevel@tonic-gate	SET_SIZE(_fp_read_fprs)
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate#endif	/* lint */
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate#if defined(lint) || defined(__lint)
5160Sstevel@tonic-gate
5170Sstevel@tonic-gateunsigned
5180Sstevel@tonic-gate_fp_subcc_ccr(void)
5190Sstevel@tonic-gate{return 0;}
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate#else	/* lint */
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate	ENTRY_NP(_fp_subcc_ccr)
5240Sstevel@tonic-gate	subcc	%o0, %o1, %g0
5250Sstevel@tonic-gate	retl
5260Sstevel@tonic-gate	rd	%ccr, %o0			! save ccr
5270Sstevel@tonic-gate	SET_SIZE(_fp_subcc_ccr)
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate#endif	/* lint */
530*1614Sjb145095
531*1614Sjb145095/*
532*1614Sjb145095 * Floating Point Exceptions handled according to type:
533*1614Sjb145095 *	2) unfinished_fpop
534*1614Sjb145095 *		re-execute the faulty instruction(s) using
535*1614Sjb145095 *		software emulation (must do every instruction in FQ)
536*1614Sjb145095 *	3) unimplemented_fpop
537*1614Sjb145095 *		an unimplemented instruction, if it is legal,
538*1614Sjb145095 *		will cause emulation of the instruction (and all
539*1614Sjb145095 *		other instuctions in the FQ)
540*1614Sjb145095 *	4) sequence_error
541*1614Sjb145095 *		panic, this should not happen, and if it does it
542*1614Sjb145095 *		it is the result of a kernel bug
543*1614Sjb145095 *
544*1614Sjb145095 * This code assumes the trap preamble has set up the window environment
545*1614Sjb145095 * for execution of kernel code.
546*1614Sjb145095 * Note: this code could be changed to be part of the cpu-specific
547*1614Sjb145095 * (ie, Spitfire-specific) module code before final release.
548*1614Sjb145095 */
549*1614Sjb145095
550*1614Sjb145095#if defined(lint)
551*1614Sjb145095
552*1614Sjb145095/* ARGSUSED */
553*1614Sjb145095void
554*1614Sjb145095_fp_exception(struct regs *rp, uint64_t fsr)
555*1614Sjb145095{}
556*1614Sjb145095
557*1614Sjb145095#else	/* lint */
558*1614Sjb145095
559*1614Sjb145095	ENTRY_NP(_fp_exception)
560*1614Sjb145095	mov	%o7, %l0		! saved return address
561*1614Sjb145095	mov	%o0, %l1		! saved *rp
562*1614Sjb145095	set     FSR_FTT, %o4		! put FSR_FTT in %o4
563*1614Sjb145095	xor	%o4, 0xffffffffffffffff, %o3 ! xor FSR_FTT to get
564*1614Sjb145095	and     %o1, %o3, %o2		! an fsr with a zero'd ftt
565*1614Sjb145095	ldn	[THREAD_REG + T_LWP], %o3 ! get lwp
566*1614Sjb145095	ldn	[%o3 + LWP_FPU], %l3	! get lwp_fpu
567*1614Sjb145095	stx	%o2, [%l3 + FPU_FSR]	! save floating point status
568*1614Sjb145095	and	%o1, %o4, %g2		! get the ftt trap type
569*1614Sjb145095#ifdef  DEBUG
570*1614Sjb145095	brnz,a,pt %g2, fttok
571*1614Sjb145095	  nop
572*1614Sjb145095	set	.badfpfttmsg, %o0	! panic message
573*1614Sjb145095	call	panic			! %o1 has the fsr w/ftt value
574*1614Sjb145095	nop
575*1614Sjb145095fttok:
576*1614Sjb145095#endif  /* DEBUG */
577*1614Sjb145095	srl	%g2, FSR_FTT_SHIFT, %o4	! check ftt
578*1614Sjb145095	cmp	%o4, FTT_SEQ		! sanity check for bogus exceptions
579*1614Sjb145095	!
580*1614Sjb145095	! traps are already enabled to allow other
581*1614Sjb145095	! interrupts while emulating floating point instructions
582*1614Sjb145095	!
583*1614Sjb145095	blt,a,pt %xcc, fpeok
584*1614Sjb145095	nop
585*1614Sjb145095	!
586*1614Sjb145095	! Sequence error or unknown ftt exception.
587*1614Sjb145095	!
588*1614Sjb145095seq_error:
589*1614Sjb145095	set	.badfpexcpmsg, %o0	! panic if bad ftt
590*1614Sjb145095	call	panic
591*1614Sjb145095	sra	%o4, 0, %o1		! mov ftt to o1 for panic message
592*1614Sjb145095
593*1614Sjb145095fpeok:
594*1614Sjb145095	call	fp_kstat_update		! fp_kstat_update(ftt)
595*1614Sjb145095	mov	%o4, %o0		! ftt
596*1614Sjb145095	!
597*1614Sjb145095	! Get the floating point instruction, and run the floating
598*1614Sjb145095	! point simulator. There is no floating point queue, so we fake one.
599*1614Sjb145095	!
600*1614Sjb145095	call	fp_precise		! fp_precise(&regs)
601*1614Sjb145095	mov	%l1, %o0		! saved *rp
602*1614Sjb145095
603*1614Sjb145095fp_ret:
604*1614Sjb145095	rd	%fprs, %g1		! read fprs, save value in %g1
605*1614Sjb145095	st	%g1, [%l3 + FPU_FPRS]	! save fprs
606*1614Sjb145095	jmp	%l0 + 8			! jump to saved return address
607*1614Sjb145095	stx	%fsr, [%l3 + FPU_FSR]	! save fsr
608*1614Sjb145095	SET_SIZE(_fp_exception)
609*1614Sjb145095
610*1614Sjb145095.badfpexcpmsg:
611*1614Sjb145095	.asciz	"unexpected floating point exception %x"
612*1614Sjb145095
613*1614Sjb145095#ifdef	DEBUG
614*1614Sjb145095.badfpfttmsg:
615*1614Sjb145095	.asciz	"No floating point ftt, fsr %llx"
616*1614Sjb145095#endif	/* DEBUG */
617*1614Sjb145095
618*1614Sjb145095#endif	/* lint */
619*1614Sjb145095
620*1614Sjb145095/*
621*1614Sjb145095 * Floating Point Exceptions.
622*1614Sjb145095 * handled according to type:
623*1614Sjb145095 *	1) IEEE_exception
624*1614Sjb145095 *		re-execute the faulty instruction(s) using
625*1614Sjb145095 *		software emulation (must do every instruction in FQ)
626*1614Sjb145095 *
627*1614Sjb145095 * This code assumes the trap preamble has set up the window environment
628*1614Sjb145095 * for execution of kernel code.
629*1614Sjb145095 */
630*1614Sjb145095
631*1614Sjb145095#if defined(lint)
632*1614Sjb145095
633*1614Sjb145095/* ARGSUSED */
634*1614Sjb145095void
635*1614Sjb145095_fp_ieee_exception(struct regs *rp, uint64_t fsr)
636*1614Sjb145095{}
637*1614Sjb145095
638*1614Sjb145095#else	/* lint */
639*1614Sjb145095
640*1614Sjb145095	ENTRY_NP(_fp_ieee_exception)
641*1614Sjb145095	mov	%o7, %l0		! saved return address
642*1614Sjb145095	mov	%o0, %l1		! saved *rp
643*1614Sjb145095	mov	%o1, %l2		! saved fsr
644*1614Sjb145095	set	FSR_FTT, %o4		! put FSR_FTT in %o4
645*1614Sjb145095	xor	%o4, 0xffffffffffffffff, %o3 ! ! xor FSR_FTT to get
646*1614Sjb145095	and	%o1, %o3, %o2		! an fsr with a zero'd ftt
647*1614Sjb145095	ldn	[THREAD_REG + T_LWP], %o3 ! get lwp
648*1614Sjb145095	ldn	[%o3 + LWP_FPU], %l3	! get lwp_fpu
649*1614Sjb145095	stx	%o2, [%l3 + FPU_FSR]	! save floating point status
650*1614Sjb145095	stub	%g0, [%l3 + FPU_QCNT]	! clear fpu_qcnt
651*1614Sjb145095	and	%o1, %o4, %g2		! mask out trap type
652*1614Sjb145095#ifdef  DEBUG
653*1614Sjb145095	brnz,a,pt %g2, fttgd
654*1614Sjb145095	  nop
655*1614Sjb145095	set	.badfpfttmsg, %o0	! panic message
656*1614Sjb145095	call	panic			! %o1 has the fsr w/ftt value
657*1614Sjb145095	nop
658*1614Sjb145095fttgd:
659*1614Sjb145095#endif	/* DEBUG */
660*1614Sjb145095	srl	%g2, FSR_FTT_SHIFT, %o4	! check ftt
661*1614Sjb145095	cmp	%o4, FTT_SEQ		! sanity check for bogus exceptions
662*1614Sjb145095	!
663*1614Sjb145095	! traps are already enabled to allow other
664*1614Sjb145095	! interrupts while emulating floating point instructions
665*1614Sjb145095	!
666*1614Sjb145095	blt,a,pt %xcc, fpegd
667*1614Sjb145095	nop
668*1614Sjb145095	!
669*1614Sjb145095	! Sequence error or unknown ftt exception.
670*1614Sjb145095	!
671*1614Sjb145095seq_err:
672*1614Sjb145095	set	.badfpexcpmsg, %o0	! panic if bad ftt
673*1614Sjb145095	call	panic
674*1614Sjb145095	sra	%o4, 0, %o1		! mov ftt to o1 for panic message
675*1614Sjb145095
676*1614Sjb145095fpegd:
677*1614Sjb145095	call	fp_kstat_update		! fp_kstat_update(ftt)
678*1614Sjb145095	mov	%o4, %o0		! ftt
679*1614Sjb145095	!
680*1614Sjb145095	! Call fpu_trap directly, don't bother to run the fp simulator.
681*1614Sjb145095	! The *rp is already in %o0. Clear fpu_qcnt.
682*1614Sjb145095	!
683*1614Sjb145095	set	(T_FP_EXCEPTION_IEEE), %o2	! trap type
684*1614Sjb145095
685*1614Sjb145095	set	FSR_CEXC, %o3
686*1614Sjb145095	and	%l2, %o3, %g2		! mask out cexc
687*1614Sjb145095
688*1614Sjb145095	andcc	%g2, FSR_CEXC_NX, %g0	! check for inexact
689*1614Sjb145095	bnz,a,pt %xcc, fpok
690*1614Sjb145095	or	%g0, FPE_FLTRES, %o3	! fp inexact code
691*1614Sjb145095
692*1614Sjb145095	andcc	%g2, FSR_CEXC_DZ, %g0	! check for divide-by-zero
693*1614Sjb145095	bnz,a,pt %xcc, fpok
694*1614Sjb145095	or	%g0, FPE_FLTDIV, %o3	! fp divide by zero code
695*1614Sjb145095
696*1614Sjb145095	andcc	%g2, FSR_CEXC_UF, %g0	! check for underflow
697*1614Sjb145095	bnz,a,pt %xcc, fpok
698*1614Sjb145095	or	%g0, FPE_FLTUND, %o3	! fp underflow code
699*1614Sjb145095
700*1614Sjb145095	andcc	%g2, FSR_CEXC_OF, %g0	! check for overflow
701*1614Sjb145095	bnz,a,pt %xcc, fpok
702*1614Sjb145095	or	%g0, FPE_FLTOVF, %o3	! fp overflow code
703*1614Sjb145095
704*1614Sjb145095	andcc	%g2, FSR_CEXC_NV, %g0	! check for invalid
705*1614Sjb145095	bnz,a,pn %xcc, fpok
706*1614Sjb145095	or	%g0, FPE_FLTINV, %o3	! fp invalid code
707*1614Sjb145095
708*1614Sjb145095cexec_err:
709*1614Sjb145095	set	.badfpcexcmsg, %o0	! panic message
710*1614Sjb145095	call	panic			! panic if no cexc bit set
711*1614Sjb145095	mov	%g1, %o1
712*1614Sjb145095fpok:
713*1614Sjb145095	mov	%l1, %o0		! saved *rp
714*1614Sjb145095	call	fpu_trap		! fpu_trap(&regs, addr, type, code)
715*1614Sjb145095	ldn	[%o0 + PC_OFF], %o1 	! address of trapping instruction
716*1614Sjb145095
717*1614Sjb145095	rd	%fprs, %g1		! read fprs, save value in %g1
718*1614Sjb145095	st	%g1, [%l3 + FPU_FPRS]	! save fprs
719*1614Sjb145095	jmp	%l0 + 8			! jump to saved return address
720*1614Sjb145095	stx	%fsr, [%l3 + FPU_FSR]	! save fsr
721*1614Sjb145095	SET_SIZE(_fp_ieee_exception)
722*1614Sjb145095
723*1614Sjb145095.badfpcexcmsg:
724*1614Sjb145095	.asciz	"No floating point exception, fsr %llx"
725*1614Sjb145095
726*1614Sjb145095#endif	/* lint */
727