xref: /titanic_51/usr/src/uts/sparc/v9/ml/float.s (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/asm_linkage.h>
30#include <sys/trap.h>
31#include <sys/machpcb.h>
32
33#if !defined(lint) && !defined(__lint)
34#include "assym.h"
35#endif	/* lint */
36
37/*
38 * Floating point trap handling.
39 *
40 *	The FPU is always in a V9 current configuration.
41 *
42 *	When a user process is first started via exec,
43 *	floating point operations will be disabled by default.
44 *	Upon execution of the first floating point instruction,
45 *	a fp_disabled trap will be generated; then a word in
46 *	the uarea is written signifying use of the floating point
47 *	registers so that subsequent context switches will save
48 *	and restore the floating point them. The trapped instruction
49 *	will be restarted and processing will continue as normal.
50 *
51 *	When a operation occurs that the hardware cannot properly
52 *	handle, an unfinshed fp_op exception will be generated.
53 *	Software routines in the kernel will be	executed to
54 *	simulate proper handling of such conditions.
55 *
56 *	Exception handling will emulate all instructions
57 *	in the floating point address queue. Note that there
58 *	is no %fq in sun4u, because it has precise FP traps.
59 *
60 *	Floating point queues are now machine dependent, and std %fq
61 *	is an illegal V9 instruction. The fp_exception code has been
62 *	moved to sun4u/ml/machfloat.s.
63 *
64 *	NOTE: This code DOES NOT SUPPORT KERNEL (DEVICE DRIVER)
65 *		USE OF THE FPU
66 *
67 *	Instructions for running without the hardware fpu:
68 *	1. Setting fpu_exists to 0 now only works on a DEBUG kernel.
69 *	2. adb -w unix and set fpu_exists, use_hw_bcopy, use_hw_copyio, and
70 *		use_hw_bzero to 0 and rename libc_psr.so.1 in
71 *		/usr/platform/sun4u/lib so that it will not get used by
72 *		the libc bcopy routines. Then reboot the system and you
73 *		should see the bootup message "FPU not in use".
74 *	3. To run kaos, you must comment out the code which sets the
75 *		version number of the fsr to 7, in fldst: stfsr/stxfsr
76 *		(unless you are running against a comparison system that
77 *		has the same fsr version number).
78 *	4. The stqf{a}/ldqf{a} instructions cause kaos errors, for reasons
79 *		that appear to be a kaos bug, so don't use them!
80 */
81
82#if defined(lint) || defined(__lint)
83
84#ifdef FP_DISABLED
85int fpu_exists = 0;
86#else
87int fpu_exists = 1;
88#endif
89
90#else	/* lint */
91
92	.section ".data"
93	.align	8
94fsrholder:
95	.word	0			! dummy place to write fsr
96	.word	0
97
98	DGDEF(fpu_exists)		! always exists for V9
99#ifdef FP_DISABLED
100	.word	0
101#else
102	.word	1			! sundiag (gack) uses this variable
103#endif
104
105	DGDEF(fpu_version)
106	.word	-1
107
108#endif	/* lint */
109
110/*
111 * FPU probe - read the %fsr and get fpu_version.
112 * Called from autoconf. If a %fq is created for
113 * future cpu versions, a fq_exists variable
114 * could be created by this function.
115 */
116
117#if defined(lint) || defined(__lint)
118
119/*ARGSUSED*/
120void
121fpu_probe(void)
122{}
123
124#else	/* lint */
125
126	ENTRY_NP(fpu_probe)
127	wr	%g0, FPRS_FEF, %fprs	! enable fpu in fprs
128	rdpr	%pstate, %g2		! read pstate, save value in %g2
129	or	%g2, PSTATE_PEF, %g1	! new pstate with fpu enabled
130	wrpr	%g1, %g0, %pstate	! write pstate
131
132	sethi	%hi(fsrholder), %g2
133	stx	%fsr, [%g2 + %lo(fsrholder)]
134	ldx	[%g2 + %lo(fsrholder)], %g2	! snarf the FSR
135	set	FSR_VER, %g1
136	and	%g2, %g1, %g2			! get version
137	srl	%g2, FSR_VER_SHIFT, %g2		! and shift it down
138	sethi	%hi(fpu_version), %g3		! save the FPU version
139	st	%g2, [%g3 + %lo(fpu_version)]
140
141	ba	fp_kstat_init		! initialize the fpu_kstat
142	wr	%g0, %g0, %fprs		! disable fpu and clear fprs
143	SET_SIZE(fpu_probe)
144
145#endif	/* lint */
146
147/*
148 * fp_clearregs(fp)
149 *	struct v9_fpu *fp;
150 *
151 * Initialization for the hardware fpu.
152 * Clear the fsr and initialize registers to NaN (-1)
153 * The caller (fp_disabled) is supposed to update the fprs
154 * so when the return to userland is made, the fpu is enabled.
155 */
156
157#if defined(lint) || defined(__lint)
158
159/*ARGSUSED*/
160void
161fp_clearregs(kfpu_t *fp)
162{}
163
164#else	/* lint */
165
166	ENTRY_NP(fp_clearregs)
167	ldx	[%o0 + FPU_FSR], %fsr		! load fsr
168
169	mov	-1, %g2				! -1 is NaN
170	stx	%g2, [%o0]			! initialize %f0
171	ldd	[%o0], %d0
172	ldd	[%o0], %d2
173	ldd	[%o0], %d4
174	ldd	[%o0], %d6
175	ldd	[%o0], %d8
176	ldd	[%o0], %d10
177	ldd	[%o0], %d12
178	ldd	[%o0], %d14
179	ldd	[%o0], %d16
180	ldd	[%o0], %d18
181	ldd	[%o0], %d20
182	ldd	[%o0], %d22
183	ldd	[%o0], %d24
184	ldd	[%o0], %d26
185	ldd	[%o0], %d28
186	ldd	[%o0], %d30
187	ldd	[%o0], %d32
188	ldd	[%o0], %d34
189	ldd	[%o0], %d36
190	ldd	[%o0], %d38
191	ldd	[%o0], %d40
192	ldd	[%o0], %d42
193	ldd	[%o0], %d44
194	ldd	[%o0], %d46
195	ldd	[%o0], %d48
196	ldd	[%o0], %d50
197	ldd	[%o0], %d52
198	ldd	[%o0], %d54
199	ldd	[%o0], %d56
200	ldd	[%o0], %d58
201	ldd	[%o0], %d60
202	retl
203	ldd	[%o0], %d62
204	SET_SIZE(fp_clearregs)
205
206#endif	/* lint */
207
208/*
209 * void _fp_read_pfreg(pf, n)
210 *	uint32_t	*pf;	Old freg value.
211 *	unsigned	n;	Want to read register n
212 *
213 * {
214 *	*pf = %f[n];
215 * }
216 *
217 * void
218 * _fp_write_pfreg(pf, n)
219 *	uint32_t	*pf;	New freg value.
220 *	unsigned	n;	Want to write register n.
221 *
222 * {
223 *	%f[n] = *pf;
224 * }
225 */
226
227#if defined(lint) || defined(__lint)
228
229/*ARGSUSED*/
230void
231_fp_read_pfreg(uint32_t *pf, u_int n)
232{}
233
234/*ARGSUSED*/
235void
236_fp_write_pfreg(uint32_t *pf, u_int n)
237{}
238
239#else	/* lint */
240
241	ENTRY_NP(_fp_read_pfreg)
242	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
243	set	.stable, %g1		! g1 gets base of table.
244	jmp	%g1 + %o1		! Jump into table
245	nop				! Can't follow CTI by CTI.
246
247	ENTRY_NP(_fp_write_pfreg)
248	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
249	set	.ltable, %g1		! g1 gets base of table.
250	jmp	%g1 + %o1		! Jump into table
251	nop				! Can't follow CTI by CTI.
252
253#define STOREFP(n) jmp %o7+8 ; st %f/**/n, [%o0]
254
255.stable:
256	STOREFP(0)
257	STOREFP(1)
258	STOREFP(2)
259	STOREFP(3)
260	STOREFP(4)
261	STOREFP(5)
262	STOREFP(6)
263	STOREFP(7)
264	STOREFP(8)
265	STOREFP(9)
266	STOREFP(10)
267	STOREFP(11)
268	STOREFP(12)
269	STOREFP(13)
270	STOREFP(14)
271	STOREFP(15)
272	STOREFP(16)
273	STOREFP(17)
274	STOREFP(18)
275	STOREFP(19)
276	STOREFP(20)
277	STOREFP(21)
278	STOREFP(22)
279	STOREFP(23)
280	STOREFP(24)
281	STOREFP(25)
282	STOREFP(26)
283	STOREFP(27)
284	STOREFP(28)
285	STOREFP(29)
286	STOREFP(30)
287	STOREFP(31)
288
289#define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n
290
291.ltable:
292	LOADFP(0)
293	LOADFP(1)
294	LOADFP(2)
295	LOADFP(3)
296	LOADFP(4)
297	LOADFP(5)
298	LOADFP(6)
299	LOADFP(7)
300	LOADFP(8)
301	LOADFP(9)
302	LOADFP(10)
303	LOADFP(11)
304	LOADFP(12)
305	LOADFP(13)
306	LOADFP(14)
307	LOADFP(15)
308	LOADFP(16)
309	LOADFP(17)
310	LOADFP(18)
311	LOADFP(19)
312	LOADFP(20)
313	LOADFP(21)
314	LOADFP(22)
315	LOADFP(23)
316	LOADFP(24)
317	LOADFP(25)
318	LOADFP(26)
319	LOADFP(27)
320	LOADFP(28)
321	LOADFP(29)
322	LOADFP(30)
323	LOADFP(31)
324	SET_SIZE(_fp_read_pfreg)
325	SET_SIZE(_fp_write_pfreg)
326
327#endif	/* lint */
328
329/*
330 * void _fp_read_pdreg(
331 *	uint64_t	*pd,	Old dreg value.
332 *	u_int	n)		Want to read register n
333 *
334 * {
335 *	*pd = %d[n];
336 * }
337 *
338 * void
339 * _fp_write_pdreg(
340 *	uint64_t	*pd,	New dreg value.
341 *	u_int	n)		Want to write register n.
342 *
343 * {
344 *	%d[n] = *pd;
345 * }
346 */
347
348#if defined(lint) || defined(__lint)
349
350/*ARGSUSED*/
351void
352_fp_read_pdreg(uint64_t *pd, u_int n)
353{}
354
355/*ARGSUSED*/
356void
357_fp_write_pdreg(uint64_t *pd, u_int n)
358{}
359
360#else	/* lint */
361
362	ENTRY_NP(_fp_read_pdreg)
363	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
364	set	.dstable, %g1		! g1 gets base of table.
365	jmp	%g1 + %o1		! Jump into table
366	nop				! Can't follow CTI by CTI.
367
368	ENTRY_NP(_fp_write_pdreg)
369	sll	%o1, 3, %o1		! Table entries are 8 bytes each.
370	set	.dltable, %g1		! g1 gets base of table.
371	jmp	%g1 + %o1		! Jump into table
372	nop				! Can't follow CTI by CTI.
373
374#define STOREDP(n) jmp %o7+8 ; std %d/**/n, [%o0]
375
376.dstable:
377	STOREDP(0)
378	STOREDP(2)
379	STOREDP(4)
380	STOREDP(6)
381	STOREDP(8)
382	STOREDP(10)
383	STOREDP(12)
384	STOREDP(14)
385	STOREDP(16)
386	STOREDP(18)
387	STOREDP(20)
388	STOREDP(22)
389	STOREDP(24)
390	STOREDP(26)
391	STOREDP(28)
392	STOREDP(30)
393	STOREDP(32)
394	STOREDP(34)
395	STOREDP(36)
396	STOREDP(38)
397	STOREDP(40)
398	STOREDP(42)
399	STOREDP(44)
400	STOREDP(46)
401	STOREDP(48)
402	STOREDP(50)
403	STOREDP(52)
404	STOREDP(54)
405	STOREDP(56)
406	STOREDP(58)
407	STOREDP(60)
408	STOREDP(62)
409
410#define LOADDP(n) jmp %o7+8 ; ldd [%o0],%d/**/n
411
412.dltable:
413	LOADDP(0)
414	LOADDP(2)
415	LOADDP(4)
416	LOADDP(6)
417	LOADDP(8)
418	LOADDP(10)
419	LOADDP(12)
420	LOADDP(14)
421	LOADDP(16)
422	LOADDP(18)
423	LOADDP(20)
424	LOADDP(22)
425	LOADDP(24)
426	LOADDP(26)
427	LOADDP(28)
428	LOADDP(30)
429	LOADDP(32)
430	LOADDP(34)
431	LOADDP(36)
432	LOADDP(38)
433	LOADDP(40)
434	LOADDP(42)
435	LOADDP(44)
436	LOADDP(46)
437	LOADDP(48)
438	LOADDP(50)
439	LOADDP(52)
440	LOADDP(54)
441	LOADDP(56)
442	LOADDP(58)
443	LOADDP(60)
444	LOADDP(62)
445	SET_SIZE(_fp_read_pdreg)
446	SET_SIZE(_fp_write_pdreg)
447
448#endif	/* lint */
449
450#if defined(lint) || defined(__lint)
451
452/*ARGSUSED*/
453void
454_fp_write_pfsr(uint64_t *fsr)
455{}
456
457#else	/* lint */
458
459	ENTRY_NP(_fp_write_pfsr)
460	retl
461	ldx	[%o0], %fsr
462	SET_SIZE(_fp_write_pfsr)
463
464#endif	/* lint */
465
466#if defined(lint) || defined(__lint)
467
468/*ARGSUSED*/
469void
470_fp_read_pfsr(uint64_t *fsr)
471{}
472
473#else	/* lint */
474
475	ENTRY_NP(_fp_read_pfsr)
476	retl
477	stx	%fsr, [%o0]
478	SET_SIZE(_fp_read_pfsr)
479
480#endif	/* lint */
481
482#if defined(lint) || defined(__lint)
483
484/*ARGSUSED*/
485void
486_fp_write_fprs(u_int fprs_val)
487{}
488
489#else	/* lint */
490
491	ENTRY_NP(_fp_write_fprs)
492	retl
493	wr	%o0, %g0, %fprs			! write fprs
494	SET_SIZE(_fp_write_fprs)
495
496#endif	/* lint */
497
498#if defined(lint) || defined(__lint)
499
500unsigned
501_fp_read_fprs(void)
502{return 0;}
503
504#else	/* lint */
505
506	ENTRY_NP(_fp_read_fprs)
507	retl
508	rd	%fprs, %o0			! save fprs
509	SET_SIZE(_fp_read_fprs)
510
511#endif	/* lint */
512
513#if defined(lint) || defined(__lint)
514
515unsigned
516_fp_subcc_ccr(void)
517{return 0;}
518
519#else	/* lint */
520
521	ENTRY_NP(_fp_subcc_ccr)
522	subcc	%o0, %o1, %g0
523	retl
524	rd	%ccr, %o0			! save ccr
525	SET_SIZE(_fp_subcc_ccr)
526
527#endif	/* lint */
528