fpu_test64.s revision 6491:448e02e63395
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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29! Usage of %ncc
30!
31! When the branch instructions were modified from Bicc to BPcc format,
32! the pseudo-op %ncc was used. This will be converted by the assembler
33! to %icc or %xcc depending on whether the compilation is being done
34! for 32-bit or 64-bit platforms.
35
36
37#include<sys/asm_linkage.h>
38
39
40!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41! Name:	        datap_add()
42! Function:	This routine test the data path of the adder for single
43!		precision.
44! Calling:	i0 = value
45! Returns:
46! Convention:
47!--------------------------------------------------------------------------
48!
49!		f0 = value
50!		f1 = 0
51!	add =   f2 = value
52!
53	.section	".data"
54	.align	4
55
56.Ldadd:
57	.skip	4
58.Ldadd1:
59	.skip   4
60
61ENTRY_NP(datap_add)
62	save    %sp, -SA(MINFRAME), %sp	! save the stack frame
63	setn	.Ldadd,%l6,%l0	! get a memory address
64	setn    .Ldadd1,%l6,%l1 ! .. one for the result
65	mov     %g0,%l3         ! .. get a zero
66	st      %l3, [%l1]      ! .... and store it in memory
67	st	%i0, [%l0]	! .... store the value passed
68	ld	[%l0], %f0	! .... put the passed value into f0
69	ld	[%l1], %f1	! .... put value 0 into reg f1
70	fadds   %f0, %f1, %f2   ! ...... add zero and value into f2
71	fcmps	%fcc0, %f0, %f2	! .... check the value passed and added value
72	fbe,a	%fcc0, datap_ok	! .. if they are equal
73	nop			! .... delay
74
75	st	%f2, [%l1]	! return the result on error
76
77datap_ok:
78	ld	[%l1], %i0	! then return a zero
79	ret			! .... delay
80	restore
81SET_SIZE(datap_add)
82
83
84!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
85! Name:
86! Function:
87! Calling:
88! Returns:
89! Convention:
90!--------------------------------------------------------------------------
91!
92! This routine test the data path of multiplier for single precision
93!              f0 = value
94!              f1 = 1
95!      mult =  f2 = f0 * f1
96!
97        .section        ".data"
98        .align  4
99
100.Ldtmlt:
101	.skip	4
102.Ldtmlt1:
103	.skip	4
104
105ENTRY_NP(datap_mult)
106	save    %sp, -SA(MINFRAME), %sp
107        setn    .Ldtmlt,%l6,%l0
108        setn    .Ldtmlt1,%l6,%l1
109        setn    0x3F800000,%l6,%l3      ! put value 1 into memory
110	st      %l3, [%l1]
111        st      %i0, [%l0]      ! store the value passed into memory location
112        ld      [%l0], %f0      ! put the passed value into f0
113        ld      [%l1], %f1      ! put value 1 into reg f1
114        fmuls   %f0, %f1, %f2	! multiply value with 1 , it has to be same
115	fcmps   %fcc0, %f0, %f2
116
117	fbne,a	%fcc0, datap_mult_done
118	st	%f2, [%l1]	! executed only when the conditional
119				! branch is taken as annul bit is set.
120				! This branch will be taken under
121				! an error condition (%f0 != %f2).
122				! Then we need to return the result.
123
124	mov	%g0,%l3
125	st	%l3, [%l1]
126
127datap_mult_done :
128	ld	[%l1], %i0
129	ret
130	restore
131SET_SIZE(datap_mult)
132
133
134!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
135! Name:
136! Function:
137! Calling:
138! Returns:
139! Convention:
140!--------------------------------------------------------------------------
141!
142!	This routine tests the data path of the weitek multiplier for
143!	double precision. Single-precision load and store are being
144!       used as the input double-precision value is taken as two SP
145!       arguments
146!
147!               f0 = msw value
148!		f1 = lsw value
149!		f2 = 0
150!		f3 = 0
151!	add =   f4 = f0 + f2
152!
153        .section        ".data"
154        .align  8
155
156.Ldtadddp:
157	.skip	8
158.Ldtadddp1:
159	.skip	8
160.Ldtadddp2:
161	.skip	8
162.Lamsw:
163	.skip	8
164.Lalsw:
165	.skip	8
166
167ENTRY_NP(datap_add_dp)
168	save    %sp, -SA(MINFRAME), %sp
169        setn    .Ldtadddp,%l6,%l0
170        setn    .Ldtadddp1,%l6,%l1
171	setn	.Ldtadddp2,%l6,%l2
172	setn	.Lamsw,%l6,%l4
173	setn	.Lalsw,%l6,%l5
174	mov	%g0,%l3	! put value 0 into memory
175        st      %l3, [%l1]
176	st	%i0, [%l0]	! msw of value
177        st	%i1, [%l2]	! lsw of value
178	ld	[%l0], %f0	! put the msw into f0
179	ld	[%l2], %f1	! put the lsw into f1
180	ld	[%l1], %f2	! put 0 into f2
181	ld	[%l1], %f3	! put 0 into f3
182	faddd   %f0, %f2, %f4	! add value + 0 into f4
183	fcmpd   %fcc0, %f0, %f4	! now compare the result
184
185	fbe,a	%fcc0, datap_add_dp_ok	! good
186	nop
187
188	mov	0x1,%l3
189	st	%l3, [%l1]
190
191datap_add_dp_ok :
192	ld	[%l1], %i0
193	ret
194	restore
195
196SET_SIZE(datap_add_dp)
197
198!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
199! Name:
200! Function:
201! Calling:
202! Returns:
203! Convention:
204!--------------------------------------------------------------------------
205!
206!  This routine tests the data path of the weitek multiplier for
207!  double precision. Single-precision load and store are being
208!  used as the input double-precision value is taken as two SP
209!  arguments.
210!
211!              f0 = msw value
212!              f1 = lsw value
213!              f2 = 0
214!              f3 = 0
215!	mult = f4 = f0 * f2
216!
217        .section        ".data"
218        .align  8
219
220.Ldtmdp:
221	.skip	8
222.Ldtmdp1:
223	.skip	8
224.Ldtmdp2:
225	.skip	8
226.Lmmsw:
227	.skip	8
228.Lmlsw:
229	.skip	8
230
231ENTRY_NP(datap_mult_dp)
232	save    %sp, -SA(MINFRAME), %sp
233        setn    .Ldtmdp,%l6,%l0
234        setn    .Ldtmdp1,%l6,%l1
235        setn    .Ldtmdp2,%l6,%l2
236        setn    .Lmmsw,%l6,%l4
237	setn	.Lmlsw,%l6,%l5
238        setn    0x3FF00000,%l6,%l3 ! put msw value  of DP 1  into memory
239        st      %l3, [%l1]
240        st      %i0, [%l0]      ! msw of value
241        st      %i1, [%l2]      ! lsw of value
242        ld      [%l0], %f0      ! put the msw into f0
243        ld      [%l2], %f1      ! put the lsw into f1
244        ld      [%l1], %f2      ! put msw of DP 1 into f2
245	mov	%g0,%l3
246	st	%l3, [%l1]
247        ld      [%l1], %f3	! put 0 into f3, i.e f2|f3 = 0x3ff0000000000000 (dp 1)
248	fmuld	%f0, %f2, %f4   ! mult value * 1 into f4
249	fcmpd   %fcc0, %f0, %f4	! now compare the result
250
251        fbe,a     %fcc0, datap_mult_dp_ok        ! good
252	nop
253
254        mov     0x1,%l3
255        st      %l3, [%l1]
256
257datap_mult_dp_ok :
258	ld	[%l1], %i0
259	ret
260	restore
261
262SET_SIZE(datap_mult_dp)
263
264!
265! for add routine all the f registers from 0 - 19 will be filled with numbers
266! and the result should be 10.
267!
268
269        .section        ".data"
270        .align  4
271
272.Ltmasp:
273	.skip	4
274.Ltmasp1:
275	.skip	4
276.Ltmasp2:
277	.skip	4
278
279ENTRY_NP(timing_add_sp)
280	save    %sp, -SA(MINFRAME), %sp		! save the registers, stacck
281        setn    .Ltmasp,%l6,%l0
282	setn	.Ltmasp1,%l6,%l1
283	setn	.Ltmasp2,%l6,%l2
284	mov	%g0,%l3
285	setn    0x3f800000,%l6,%l4 	! put value 1
286	setn	0x41200000,%l6,%l5		! put value 10 into local 5
287	st	%l5, [%l0]
288	st	%l4, [%l1]
289	st	%l3, [%l2]
290	ld	[%l0], %f31		! register 31 has 10
291	ld	[%l1], %f30		! register 30 has 1
292
293	ld	[%l2], %f0		! reg 0 has 0
294	fmovs   %f31, %f1		! reg1 has 10
295	fsubs   %f31, %f30, %f18	! reg 18 has 9
296	fmovs   %f18, %f3		! reg 3 has 9
297	fmovs   %f30, %f2		! reg 2 has 1
298	fmovs   %f30, %f19		! reg 19 has 1
299	fsubs   %f18, %f19, %f16	! reg 16 has 8
300	fmovs   %f16, %f5		! reg 5 has 8
301	fsubs   %f31, %f16, %f17	! reg 17 has 2
302	fmovs	%f17, %f4		! reg 4 has 2
303	fsubs   %f16, %f30, %f14	! reg 14 has 7
304	fmovs   %f14, %f7		! reg 7 has 7
305	fsubs   %f31, %f14, %f15	! reg 15 has 3
306	fmovs	%f15, %f6		! reg 6 has 3
307	fsubs   %f14, %f30, %f12	! reg 12 has 6
308	fmovs	%f12, %f9		! reg 9 has 6
309	fsubs   %f31, %f12, %f13	! reg 13 has 4
310	fmovs	%f13, %f8		! reg 8 has 4
311	fsubs   %f12, %f30, %f10	! reg 10 has 5
312	fmovs	%f10, %f11		! reg 11 has 5
313
314	fadds	%f0, %f1, %f20		! reg 0 + reg 1 = reg 20 = 10
315	fadds   %f2, %f3, %f21		! reg 2 + reg 3 = reg 21 = 10
316	fadds   %f4, %f5, %f22		! reg 4 + reg 5 = reg 22 = 10
317	fadds   %f6, %f7, %f23		! reg 6 + reg 7 = reg 23 = 10
318	fadds   %f8, %f9, %f24		! reg 8 + reg 9 = reg 24 = 10
319	fadds   %f10, %f11, %f25	! reg 10 + reg 11 = reg 25 = 10
320	fadds   %f12, %f13, %f26	! reg 12 + reg 13 = reg 26 = 10
321	fadds   %f14, %f15, %f27	! reg 14 + reg 15 = reg 27 = 10
322	fadds   %f16, %f17, %f28	! reg 16 + reg 17 = reg 28 = 10
323	fadds   %f18, %f19, %f29	! reg 18 + reg 19 = reg 29 = 10
324
325	!  Now additions are done check it out
326	fcmps	%fcc0, %f31, %f20
327	fbne,a,pn	%fcc0, done_t_add_sp	! If not equal, go to the end.
328	st	%f20, [%l2] 	! Executed only when the conditional
329				! branch is taken as annul bit is set.
330				! This branch will be taken under
331				! an error condition.
332
333	! No errors. Move on to the next register
334
335	fcmps	%fcc0, %f31, %f21
336	fbne,a,pn	%fcc0, done_t_add_sp
337	st	%f21, [%l2]
338
339
340	fcmps   %fcc0, %f31, %f22
341	fbne,a,pn	%fcc0, done_t_add_sp
342	st	%f22, [%l2]
343
344
345	fcmps	%fcc0, %f31, %f23
346	fbne,a,pn	%fcc0, done_t_add_sp
347        st      %f23, [%l2]
348
349
350        fcmps   %fcc0, %f31, %f24
351        fbne,a,pn	%fcc0, done_t_add_sp
352        st      %f24, [%l2]
353
354
355        fcmps   %fcc0, %f31, %f25
356        fbne,a,pn	%fcc0, done_t_add_sp
357        st      %f25, [%l2]
358
359
360        fcmps   %fcc0, %f31, %f26
361        fbne,a,pn	%fcc0, done_t_add_sp
362        st      %f26, [%l2]
363
364
365        fcmps   %fcc0, %f31, %f27
366        fbne,a,pn	%fcc0, done_t_add_sp
367        st      %f27, [%l2]
368
369
370        fcmps   %fcc0, %f31, %f28
371        fbne,a,pn	%fcc0, done_t_add_sp
372        st      %f28, [%l2]
373
374
375	! Though this is the last set of compare instructions
376	! we cannot fall through as the store needs to be done
377	! only when the registers are not equal. That is why
378	! we need the unconditional branch with the annul bit set.
379        fcmps   %fcc0, %f31, %f29
380        fbne,a,pn	%fcc0, done_t_add_sp
381	st	%f29, [%l2]
382
383done_t_add_sp:
384	ld	[%l2], %i0
385	ret
386        restore
387SET_SIZE(timing_add_sp)
388
389!
390!	for mult routine all the f registers from 0 - 19 will be filled
391!	with numbers and the result should be the number.
392!
393        .section        ".data"
394        .align  4
395
396.Ltmmsp:
397	.skip	4
398.Ltmmsp1:
399	.skip	4
400.Ltmmsp2:
401	.skip	4
402
403ENTRY_NP(timing_mult_sp)
404	save    %sp, -SA(MINFRAME), %sp           ! save the registers, stacck
405        setn    .Ltmmsp,%l6, %l0
406        setn    .Ltmmsp1,%l6, %l1
407        setn    .Ltmmsp2,%l6, %l2
408        mov     %g0, %l3
409	setn	0x3f800000,%l6, %l4         ! put value 1
410        setn    0x41200000,%l6, %l5         ! put value 10 into local 5
411        st      %l5, [%l0]
412        st      %l4, [%l1]
413        st      %l3, [%l2]
414        ld      [%l0], %f31             ! register 31 has 10
415        ld      [%l1], %f1              ! register 1 has 1
416	fmovs   %f1, %f3
417	fmovs   %f1, %f5
418	fmovs   %f1, %f7
419	fmovs   %f1, %f9
420	fmovs   %f1, %f11	! register 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
421	fmovs   %f1, %f13	! has a value of 1
422	fmovs   %f1, %f15
423	fmovs   %f1, %f17
424	fmovs   %f1, %f19	!
425	fmovs	%f1, %f0
426	fmovs   %f31, %f18	! reg 18 has 10
427	fsubs	%f31, %f0, %f16		! reg 16  has 9
428	fsubs   %f16, %f0, %f14		! reg 14 has 8
429	fsubs   %f14, %f0, %f12		! reg 12 has 7
430	fsubs   %f12, %f0, %f10		! reg 10 has 6
431	fsubs   %f10, %f0, %f8		! reg 8 has 5
432	fsubs   %f8, %f0, %f6		! reg 6 has 4
433	fsubs   %f6, %f0, %f4		! reg 4 has 3
434	fsubs   %f4, %f0, %f2		! reg 2 has 2
435
436	fmuls   %f0, %f1, %f20          ! reg 0 * reg 1 = reg 20 = 1
437        fmuls   %f2, %f3, %f21          ! reg 2 * reg 3 = reg 21 = 2
438        fmuls   %f4, %f5, %f22          ! reg 4 * reg 5 = reg 22 = 3
439        fmuls   %f6, %f7, %f23          ! reg 6 * reg 7 = reg 23 = 4
440        fmuls   %f8, %f9, %f24          ! reg 8 * reg 9 = reg 24 = 5
441        fmuls   %f10, %f11, %f25        ! reg 10 * reg 11 = reg 25 = 6
442        fmuls   %f12, %f13, %f26        ! reg 12 * reg 13 = reg 26 = 7
443        fmuls   %f14, %f15, %f27        ! reg 14 * reg 15 = reg 27 = 8
444        fmuls   %f16, %f17, %f28        ! reg 16 * reg 17 = reg 28 = 9
445        fmuls   %f18, %f19, %f29        ! reg 18 * reg 19 = reg 29 = 10
446
447	fcmps	%fcc0, %f0, %f20
448	fbne,a,pn	%fcc0, done_t_mult_sp
449	st	%f20, [%l2] 	! Executed only when the conditional
450				! branch is taken as annul bit is set.
451				! This branch will be taken under
452				! an error condition.
453
454	! No errors. Move on to the next register
455
456	fcmps	%fcc0, %f2, %f21
457	fbne,a,pn	%fcc0, done_t_mult_sp
458	st	%f21, [%l2]
459
460
461	fcmps   %fcc0, %f4, %f22
462	fbne,a,pn 	%fcc0, done_t_mult_sp
463	st	%f22, [%l2]
464
465
466	fcmps	%fcc0, %f6, %f23
467	fbne,a,pn	%fcc0, done_t_mult_sp
468        st      %f23, [%l2]
469
470
471	fcmps	%fcc0, %f8, %f24
472	fbne,a,pn	%fcc0, done_t_mult_sp
473        st      %f24, [%l2]
474
475
476	fcmps	%fcc0, %f10, %f25
477	fbne,a,pn	%fcc0, done_t_mult_sp
478        st      %f25, [%l2]
479
480
481	fcmps	%fcc0, %f12, %f26
482	fbne,a,pn	%fcc0, done_t_mult_sp
483        st      %f26, [%l2]
484
485
486	fcmps	%fcc0, %f14, %f27
487	fbne,a,pn	%fcc0, done_t_mult_sp
488        st      %f27, [%l2]
489
490
491	fcmps	%fcc0, %f16, %f28
492	fbne,a,pn	%fcc0, done_t_mult_sp
493        st      %f28, [%l2]
494
495
496	! Though this is the last set of compare instructions
497	! we cannot fall through as the store needs to be done
498	! only when the registers are not equal. That is why
499	! we need the unconditional branch with the annul bit set.
500	fcmps	%fcc0, %f18, %f29
501	fbne,a,pn	%fcc0, done_t_mult_sp
502	st	%f29, [%l2]
503
504
505done_t_mult_sp:
506	ld	[%l2], %i0
507	ret
508        restore
509SET_SIZE(timing_mult_sp)
510
511!
512!	same thing for double precision
513!
514        .section        ".data"
515        .align  8
516
517.Ltmadp:
518	.skip	8
519.Ltmadp1:
520	.skip	8
521.Ltmadp2:
522	.skip	8
523
524ENTRY_NP(timing_add_dp)
525	save    %sp, -SA(MINFRAME), %sp           ! save the registers, stacck
526        setn    .Ltmadp,%l6, %l0
527        setn    .Ltmadp1,%l6, %l1
528        setn    .Ltmadp2,%l6, %l2
529        mov     %g0, %l3
530	setn	0x3ff0000000000000,%l6, %l4         ! put value 1
531        setn    0x4024000000000000,%l6, %l5         ! put value 10 into local 5
532        stx     %l5, [%l0]
533        stx     %l4, [%l1]
534        stx     %l3, [%l2]
535	ldd	[%l0], %f30             ! register 30 has 10
536	fmovd   %f30, %f2		! reg 2 has 10
537	ldd	[%l2], %f0		! reg 0 has 0
538	ldd	[%l1], %f4		! reg 4 has 1
539	fsubd	%f30, %f4, %f6		! reg 6 has 9
540	fsubd	%f6, %f4, %f10		! reg 10 has 8
541	fsubd   %f30, %f10, %f8		! reg 8 has 2
542	fsubd	%f10, %f4, %f14		! reg 14 has 7
543	fsubd   %f30, %f14, %f12	! reg 12 has 3
544	fsubd	%f14, %f4, %f18		! reg 18 has 6
545	fsubd	%f30, %f18, %f16	! reg 16 has 4
546!
547	faddd	%f0, %f2, %f20		! reg 20 has 10
548	faddd   %f4, %f6, %f22		! reg 22 has 10
549	faddd   %f8, %f10, %f24		! reg 24 has 10
550	faddd   %f12, %f14, %f26	! reg 26 has 10
551	faddd   %f16, %f18, %f28	! reg 28 has 10
552!
553	fcmpd	%fcc0, %f30, %f20
554	fbne,a,pn	%fcc0, done_t_add_dp
555	std	%f20, [%l2]
556
557	fcmpd	%fcc0, %f30, %f22
558	fbne,a,pn	%fcc0, done_t_add_dp
559	std	%f22, [%l2]
560
561	fcmpd   %fcc0, %f30, %f24
562        fbne,a,pn     %fcc0, done_t_add_dp
563        std      %f24, [%l2]
564
565        fcmpd   %fcc0, %f30, %f26
566        fbne,a,pn     %fcc0, done_t_add_dp
567        std      %f26, [%l2]
568
569	! Though this is the last set of compare instructions
570	! we cannot fall through as the store needs to be done
571	! only when the registers are not equal. That is why
572	! we need the unconditional branch with the annul bit set.
573	fcmpd	%fcc0, %f30, %f28
574	fbne,a	%fcc0, done_t_add_dp
575	std	%f28, [%l2]
576
577done_t_add_dp:
578	ldx	[%l2], %i0
579
580	ret
581	restore
582SET_SIZE(timing_add_dp)
583
584
585!	Now for mult
586!
587        .section        ".data"
588        .align  8
589
590.Ltmmdp:
591	.skip	8
592.Ltmmdp1:
593	.skip	8
594.Ltmmdp2:
595	.skip	8
596
597ENTRY_NP(timing_mult_dp)
598	save    %sp, -SA(MINFRAME), %sp           ! save the registers, stacck
599        setn    .Ltmmdp,%l6, %l0
600        setn    .Ltmmdp1,%l6, %l1
601        setn    .Ltmmdp2,%l6, %l2
602        mov     %g0, %l3
603        setn    0x3ff0000000000000,%l6, %l4         ! put value 1
604        setn    0x4034000000000000,%l6, %l5         ! put value 20 into local 5
605        stx      %l5, [%l0]
606        stx      %l4, [%l1]
607        stx      %l3, [%l2]
608	ldd      [%l0], %f30             ! register 30 has 20
609	ldd	[%l1], %f2		! register  2 has 1
610	fmovd   %f30, %f0		! register  0 has 20
611	faddd	%f2, %f2, %f10		! register 10 has 2
612	fmovd   %f10, %f16		! register 16 has 2
613	faddd	%f10, %f16, %f4		! register 4 has 4
614	faddd   %f4, %f2, %f6		! register 6 has 5
615	fmovd	%f6, %f12		! reg. 12 has 5
616	fmovd	%f4, %f14		! reg 14 has 4
617	faddd	%f12, %f6, %f18		! reg 18 has 10
618	fmovd	%f18, %f8		! reg 8 has 10
619!
620! 	now everything is set
621!
622	fmuld   %f0, %f2, %f20          ! reg 20 has 20
623	fmuld	%f4, %f6, %f22          ! reg 22 has 20
624	fmuld	%f8, %f10, %f24         ! reg 24 has 20
625	fmuld	%f12, %f14, %f26        ! reg 26 has 20
626	fmuld	%f16, %f18, %f28        ! reg 28 has 20
627!
628	fcmpd   %fcc0, %f30, %f20
629	fbne,a,pn	%fcc0, done_t_mult_dp
630        std      %f20, [%l2]
631
632	fcmpd   %fcc0, %f30, %f22
633        fbne,a,pn     %fcc0, done_t_mult_dp
634        std      %f22, [%l2]
635
636	fcmpd   %fcc0, %f30, %f24
637        fbne,a,pn     %fcc0, done_t_mult_dp
638        std      %f24, [%l2]
639
640        fcmpd   %fcc0, %f30, %f26
641        fbne,a,pn     %fcc0, done_t_mult_dp
642        std      %f26, [%l2]
643
644	! Though this is the last set of compare instructions
645	! we cannot fall through as the store needs to be done
646	! only when the registers are not equal. That is why
647	! we need the unconditional branch with the annul bit set.
648        fcmpd   %fcc0, %f30, %f28
649        fbne,a     %fcc0, done_t_mult_dp
650        std      %f28, [%l2]
651
652done_t_mult_dp:
653	ldx	[%l2], %i0
654
655	ret
656	restore
657SET_SIZE(timing_mult_dp)
658
659
660!--------------------------------------------------------------------------
661! The following routines are for testing the IEEE754 exception fields
662! of the FSR (cexc, aexc)
663!	The input is : i0 = amsw
664!		       i1 = bmsw or alsw (for double precision)
665!	  	       i2 = bmsw (for dp)
666!		       i3 = blsw (for dp)
667!
668!	The output is  i0 = value of FSR register
669!
670
671        .section        ".data"
672        .align  8
673
674.Lwadds:
675	.word 	0
676.Lwadds1:
677	.word 	0
678.Lwadds2:
679	.xword	0    ! For the FSR contents
680
681
682ENTRY_NP(wadd_sp)
683	save    %sp, -SA(MINFRAME), %sp
684        setn    .Lwadds,%l6, %l0
685        setn    .Lwadds1,%l6, %l1
686	setn	.Lwadds2,%l6, %l2
687
688	st	%i0, [%l0]		! get the first value
689	st	%i1, [%l1]		! get the second value
690	ld	[%l0], %f0		! f0 has the first value
691	ld 	[%l1], %f2		! f2 has the second value
692
693	fadds   %f0, %f2, %f3		! now do the instruction
694	stx	%fsr, [%l2]		! get the fsr value
695
696	ldx     [%l2], %i0
697	ret
698	restore
699SET_SIZE(wadd_sp)
700
701
702!
703!	same thing for add double precision
704!
705        .section        ".data"
706        .align  8
707
708.Ladddp:
709	.word	0
710.Ladddp1:
711	.word	0
712.Ladddp2:
713	.xword	0    ! For the FSR contents
714
715ENTRY_NP(wadd_dp)
716	save    %sp, -SA(MINFRAME), %sp
717        setn    .Ladddp,%l6, %l0
718        setn    .Ladddp1,%l6, %l1
719        setn    .Ladddp2,%l6, %l2
720
721	st	%i0, [%l0]              ! get the first value
722        st      %i1, [%l1]              ! get the lsw of first value
723	ld	[%l0], %f0
724	ld	[%l1], %f1
725	st      %i2, [%l0]              ! get the second value
726	st      %i3, [%l1]              ! get the lsw of second value
727	ld	[%l0], %f2
728	ld	[%l1], %f3
729
730	faddd	%f0, %f2, %f4		! now do the instruction
731        stx      %fsr, [%l2]             ! get the fsr value
732
733	ldx     [%l2], %i0
734	ret
735	restore
736
737SET_SIZE(wadd_dp)
738
739
740!
741!
742!	for divide single precision
743!
744        .section        ".data"
745        .align  8
746
747.Ldvsp:
748	.word	0
749.Ldvsp1:
750	.word	0
751.Ldvsp2:
752	.xword	0    ! For the FSR contents
753
754ENTRY_NP(wdiv_sp)
755	save    %sp, -SA(MINFRAME), %sp
756        setn    .Ldvsp,%l6, %l0
757        setn    .Ldvsp1,%l6, %l1
758        setn    .Ldvsp2,%l6, %l2
759
760        st      %i0, [%l0]              ! get the first value
761        st      %i1, [%l1]              ! get the second value
762        ld      [%l0], %f0              ! f0 has the first value
763        ld      [%l1], %f2              ! f2 has the second value
764
765        fdivs	%f0, %f2, %f3           ! now do the instruction
766        stx      %fsr, [%l2]             ! get the fsr value
767
768	ldx     [%l2], %i0
769	ret
770	restore
771
772SET_SIZE(wdiv_sp)
773
774
775!
776!
777!	for divide double precision
778!
779        .section        ".data"
780        .align  8
781
782.Ldvdp:
783	.word	0
784.Ldvdp1:
785	.word	0
786.Ldvdp2:
787	.xword	0    ! For the FSR contents
788
789ENTRY_NP(wdiv_dp)
790	save    %sp, -SA(MINFRAME), %sp
791        setn    .Ldvdp,%l6, %l0
792        setn    .Ldvdp1,%l6, %l1
793        setn    .Ldvdp2,%l6, %l2
794
795        st      %i0, [%l0]              ! get the first value
796        st      %i1, [%l1]              ! get the lsw of first value
797        ld      [%l0], %f0
798        ld      [%l1], %f1
799        st      %i2, [%l0]              ! get the second value
800        st      %i3, [%l1]              ! get the lsw of second value
801        ld      [%l0], %f2
802        ld      [%l1], %f3
803
804        fdivd	%f0, %f2, %f4           ! now do the instruction
805        stx      %fsr, [%l2]             ! get the fsr value
806
807	ldx     [%l2], %i0
808	ret
809	restore
810
811SET_SIZE(wdiv_dp)
812
813
814!
815!
816!       for multiply single precision
817!
818        .section        ".data"
819        .align  8
820
821.Lmltsp:
822	.word	0
823.Lmltsp1:
824	.word	0
825.Lmltsp2:
826	.xword	0    ! For the FSR contents
827
828ENTRY_NP(wmult_sp)
829	save    %sp, -SA(MINFRAME), %sp
830        setn    .Lmltsp,%l6, %l0
831        setn    .Lmltsp1,%l6, %l1
832        setn    .Lmltsp2,%l6, %l2
833
834        st      %i0, [%l0]              ! get the first value
835        st      %i1, [%l1]              ! get the second value
836        ld      [%l0], %f0              ! f0 has the first value
837        ld      [%l1], %f2              ! f2 has the second value
838
839        fmuls   %f0, %f2, %f3           ! now do the instruction
840        stx      %fsr, [%l2]             ! get the fsr value
841
842	ldx     [%l2], %i0
843	ret
844	restore
845
846SET_SIZE(wmult_sp)
847
848
849!
850!
851!       for multiply double precision
852!
853        .section        ".data"
854        .align  8
855
856.Lmltdp:
857	.word	0
858.Lmltdp1:
859	.word	0
860.Lmltdp2:
861	.xword	0    ! For the FSR contents
862
863ENTRY_NP(wmult_dp)
864        save    %sp, -SA(MINFRAME), %sp
865        setn    .Lmltdp,%l6, %l0
866        setn    .Lmltdp1,%l6, %l1
867        setn    .Lmltdp2,%l6, %l2
868
869        st      %i0, [%l0]		! get the first value
870        st      %i1, [%l1]		! get the lsw of first value
871        ld      [%l0], %f0
872        ld      [%l1], %f1
873        st      %i2, [%l0]		! get the second value
874        st      %i3, [%l1]		! get the lsw of second value
875        ld      [%l0], %f2
876        ld      [%l1], %f3
877
878        fmuld	 %f0, %f2, %f4		! now do the instruction
879        stx      %fsr, [%l2]		! get the fsr value
880
881	ldx     [%l2], %i0
882	ret
883	restore
884
885SET_SIZE(wmult_dp)
886
887
888!
889!
890!       for square-root single precision
891!
892        .section        ".data"
893        .align  4
894.Lsqsp_opr:
895		.word	0
896
897        .align  8
898.Lsqsp_fsr:
899		.xword	0	! For the FSR contents
900
901ENTRY_NP(wsqrt_sp)
902	save	%sp, -SA(MINFRAME), %sp	! save the registers, stack
903	setn	.Lsqsp_opr,%l6,%l0	! .. get the address of temp2
904	setn	.Lsqsp_fsr,%l6,%l2	! .. and temp
905
906	st	%i0, [%l0]	! .. get the callers value
907	ld	[%l0], %f0	! .. into the float register
908
909	fsqrts  %f0, %f2	! .... have the fpu perform the operation
910        stx     %fsr, [%l2]		! get the fsr value
911
912	ldx     [%l2], %i0
913	ret
914	restore
915
916SET_SIZE(wsqrt_sp)
917
918
919!
920!
921!       for square-root double precision
922!
923        .section        ".data"
924        .align  8
925.Lsqdp_opr:
926		.xword	0
927.Lsqdp_fsr:
928		.xword	0	! For the FSR contents
929
930ENTRY_NP(wsqrt_dp)
931	save	%sp, -SA(MINFRAME), %sp	! save the registers, stack
932	setn	.Lsqdp_opr,%l6,%l0 	! .. get the address of temp2
933	setn	.Lsqdp_fsr,%l6,%l2 	! .. and temp
934
935	stx	%i0, [%l0] 	! .. get the callers value
936	ldd	[%l0], %f0 	! .. into a float register
937
938	fsqrtd  %f0, %f2	! .... have the fpu perform the operation
939        stx     %fsr, [%l2]	! get the fsr value
940
941	ldx     [%l2], %i0
942	ret
943	restore
944
945SET_SIZE(wsqrt_dp)
946
947
948!
949!
950!	Chaining test.
951!
952        .section        ".data"
953        .align  8
954
955.Lchsp:
956	.word	0
957.Lchsp1:
958	.word	0
959
960ENTRY_NP(chain_sp)
961	save    %sp, -SA(MINFRAME), %sp
962        setn    .Lchsp,%l6, %l0
963        setn    .Lchsp1,%l6, %l1
964	st	%i0, [%l0]	! store the value
965	ld	[%l0], %f0
966	fitos   %f0, %f2	! convert integer into single
967	fmovs   %f2, %f0	! f0 has the same value  x
968	fadds	%f0, %f2, %f4   ! f4 will have 2x
969	fsubs   %f4, %f0, %f6   ! f6 will have x
970	fmuls   %f6, %f4, %f8   ! f8 will have (2x * x)
971	fdivs   %f8, %f4, %f10  ! f10 will have (2x * x) / 2x = x
972	fstoi	%f10, %f12
973
974	st	%f12, [%l1]
975	ld	[%l1], %i0
976
977	ret
978        restore
979SET_SIZE(chain_sp)
980
981
982!
983!
984        .section        ".data"
985        .align  8
986
987.Lchdp:
988	.word	0
989.Lchdp1:
990	.word	0
991
992ENTRY_NP(chain_dp)
993	save    %sp, -SA(MINFRAME), %sp
994        setn    .Lchdp,%l6, %l0
995        setn    .Lchdp1,%l6, %l1
996        st      %i0, [%l0]      ! store the value
997        ld      [%l0], %f0
998        fitod   %f0, %f2        ! convert integer into double
999	fmovs   %f2, %f0        ! f0 has the same value  x
1000        faddd   %f0, %f2, %f4   ! f4 will have 2x
1001        fsubd   %f4, %f0, %f6   ! f6 will have x
1002        fmuld   %f6, %f4, %f8   ! f8 will have (2x * x)
1003        fdivd   %f8, %f4, %f10  ! f10 will have (2x * x) / 2x = x
1004        fdtoi   %f10, %f12
1005
1006	st	%f12, [%l1]
1007	ld	[%l1], %i0
1008
1009	ret
1010        restore
1011SET_SIZE(chain_dp)
1012
1013
1014!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1015! Name:		Initialize all SP Registers
1016! Function:	Loads the callers value into all SP floating point registers.
1017! Calling:	in0 = Value
1018! Returns:	All float register = Value
1019! Convention:	init_regs(val);
1020! Method:	Copys the user value into each fp reg in sequence.
1021!--------------------------------------------------------------------------
1022        .section        ".data"
1023        .align  8
1024
1025.Lclrg:
1026	.skip	8
1027
1028ENTRY_NP(init_regs)
1029	save    %sp, -SA(MINFRAME), %sp	! save the registers, stack
1030        setn    .Lclrg,%l6,%l0	! load the address of temp2 in local0
1031	st	%i0, [%l0]	! load the value in temp2 via local0
1032	ld	[%l0], %f0	! .. load the value
1033	ld	[%l0], %f1	! .. load the value
1034        ld      [%l0], %f2	! .. load the value
1035        ld      [%l0], %f3	! .. load the value
1036        ld      [%l0], %f4	! .. load the value
1037	ld	[%l0], %f5	! .. load the value
1038        ld      [%l0], %f6 	! .. load the value
1039        ld      [%l0], %f7 	! .. load the value
1040        ld      [%l0], %f8 	! .. load the value
1041        ld      [%l0], %f9 	! .. load the value
1042        ld      [%l0], %f10 	! .. load the value
1043        ld      [%l0], %f11 	! .. load the value
1044        ld      [%l0], %f12 	! .. load the value
1045        ld      [%l0], %f13 	! .. load the value
1046        ld      [%l0], %f14 	! .. load the value
1047        ld      [%l0], %f15 	! .. load the value
1048        ld      [%l0], %f16 	! .. load the value
1049        ld      [%l0], %f17 	! .. load the value
1050        ld      [%l0], %f18 	! .. load the value
1051        ld      [%l0], %f19 	! .. load the value
1052        ld      [%l0], %f20 	! .. load the value
1053        ld      [%l0], %f21 	! .. load the value
1054        ld      [%l0], %f22 	! .. load the value
1055        ld      [%l0], %f23 	! .. load the value
1056        ld      [%l0], %f24 	! .. load the value
1057        ld      [%l0], %f25 	! .. load the value
1058        ld      [%l0], %f26 	! .. load the value
1059        ld      [%l0], %f27 	! .. load the value
1060        ld      [%l0], %f28 	! .. load the value
1061        ld      [%l0], %f29 	! .. load the value
1062        ld      [%l0], %f30 	! .. load the value
1063        ld      [%l0], %f31	! .. load the value
1064	ret
1065        restore
1066SET_SIZE(init_regs)
1067
1068
1069
1070!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1071! Name:		Initialize all double precision Registers
1072! Function:	Loads the callers value into all floating point registers.
1073! Calling:	in0 = Value
1074! Returns:	All float register = Value
1075! Convention:	init_regs_dp(val);
1076! Method:	Copys the user value into each fp reg in sequence.
1077!--------------------------------------------------------------------------
1078        .section        ".data"
1079        .align  8
1080
1081.Lclrg_dp:
1082	.skip	16
1083
1084ENTRY_NP(init_regs_dp)
1085	save    %sp, -SA(MINFRAME), %sp
1086								! save the registers, stack
1087        setx    .Lclrg_dp,%l6,%l0	! load the address of temp2 in local0
1088	stx	%i0, [%l0]		! load the value in temp2 via local0
1089	ldd	[%l0], %f0		! .. load the value
1090	ldd	[%l0], %f2		! .. load the value
1091        ldd     [%l0], %f4		! .. load the value
1092        ldd     [%l0], %f6		! .. load the value
1093        ldd     [%l0], %f8		! .. load the value
1094	ldd	[%l0], %f10		! .. load the value
1095        ldd     [%l0], %f12		! .. load the value
1096        ldd     [%l0], %f14		! .. load the value
1097        ldd     [%l0], %f16		! .. load the value
1098        ldd     [%l0], %f18		! .. load the value
1099        ldd     [%l0], %f20 	! .. load the value
1100        ldd     [%l0], %f22 	! .. load the value
1101        ldd     [%l0], %f24 	! .. load the value
1102        ldd     [%l0], %f26 	! .. load the value
1103        ldd     [%l0], %f28 	! .. load the value
1104        ldd     [%l0], %f30 	! .. load the value
1105        ldd     [%l0], %f32 	! .. load the value
1106        ldd     [%l0], %f34 	! .. load the value
1107        ldd     [%l0], %f36 	! .. load the value
1108        ldd     [%l0], %f38 	! .. load the value
1109        ldd     [%l0], %f40 	! .. load the value
1110        ldd     [%l0], %f42 	! .. load the value
1111        ldd     [%l0], %f44 	! .. load the value
1112        ldd     [%l0], %f46 	! .. load the value
1113        ldd     [%l0], %f48 	! .. load the value
1114        ldd     [%l0], %f50 	! .. load the value
1115        ldd     [%l0], %f52 	! .. load the value
1116        ldd     [%l0], %f54 	! .. load the value
1117        ldd     [%l0], %f56 	! .. load the value
1118        ldd     [%l0], %f58 	! .. load the value
1119        ldd     [%l0], %f60 	! .. load the value
1120        ldd     [%l0], %f62		! .. load the value
1121	ret
1122        restore
1123SET_SIZE(init_regs_dp)
1124
1125
1126
1127!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1128! Name:
1129! Function:
1130! Calling:
1131! Returns:
1132! Convention:
1133!--------------------------------------------------------------------------
1134
1135        .section        ".data"
1136        .align  4
1137
1138.Lrgtst1:
1139	.skip	4
1140.Lrgtst2:
1141	.skip	4
1142
1143ENTRY_NP(register_test)
1144	save    %sp, -SA(MINFRAME), %sp
1145
1146	setn	.Lrgtst1,%l6,%l1
1147	setn	.Lrgtst2,%l6,%l2
1148
1149
1150	setn	regTable, %l6, %o0
1151	mulx	%i0, 12, %o1		! Table entries are 12 bytes each.
1152
1153	! Jump to the appropriate set of instructions
1154	jmp	%o0+%o1
1155	st	%i1,  [%l1]		! save the pattern to be written
1156
1157
1158! If the number of instructions in this macro are changed,
1159! please ensure that the second operand for the mulx above
1160! is also updated. We can calculate this during run-time but
1161! that will mean extra instructions and time.
1162#define	TEST_REG(reg_num)		\
1163	ld	[%l1], %f/**/reg_num;	\
1164	ba	%ncc, reg_done;		\
1165	st	%f/**/reg_num, [%l2]
1166
1167regTable :
1168
1169	TEST_REG(0)
1170	TEST_REG(1)
1171	TEST_REG(2)
1172	TEST_REG(3)
1173	TEST_REG(4)
1174	TEST_REG(5)
1175	TEST_REG(6)
1176	TEST_REG(7)
1177	TEST_REG(8)
1178	TEST_REG(9)
1179	TEST_REG(10)
1180	TEST_REG(11)
1181	TEST_REG(12)
1182	TEST_REG(13)
1183	TEST_REG(14)
1184	TEST_REG(15)
1185	TEST_REG(16)
1186	TEST_REG(17)
1187	TEST_REG(18)
1188	TEST_REG(19)
1189	TEST_REG(20)
1190	TEST_REG(21)
1191	TEST_REG(22)
1192	TEST_REG(23)
1193	TEST_REG(24)
1194	TEST_REG(25)
1195	TEST_REG(26)
1196	TEST_REG(27)
1197	TEST_REG(28)
1198	TEST_REG(29)
1199	TEST_REG(30)
1200
1201	! No need for a branch here as this the last entry in
1202	! the table and the label is will be reached by falling
1203	! through.
1204	ld	[%l1], %f31
1205	st	%f31, [%l2]
1206
1207reg_done:
1208	ld	[%l2], %i0
1209
1210	ret
1211	restore
1212SET_SIZE(register_test)
1213
1214
1215!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1216! Name:
1217! Function:
1218! Calling:
1219! Returns:
1220! Convention:
1221!--------------------------------------------------------------------------
1222    	.section        ".data"
1223	.align  8
1224
1225.Lrgtst1_dp:
1226	.skip	8
1227.Lrgtst2_dp:
1228	.skip	8
1229
1230ENTRY_NP(register_test_dp)
1231	save    %sp, -SA(MINFRAME), %sp
1232
1233	setx	.Lrgtst1_dp,%l6,%l1
1234	setx	.Lrgtst2_dp,%l6,%l2
1235
1236	setn	regTable_dp, %l6, %o0
1237	mulx	%i0, 6, %o1	! Registers are 64-bit and hence the
1238				! register numbers given will be even.
1239				! Each table entry is 12 bytes.
1240				! Multiplying the even register number
1241				! by 6 will give the correct offset.
1242
1243
1244	! Jump to the appropriate set of instructions
1245	jmp	%o0+%o1
1246	stx	%i1,  [%l1]		!save the pattern to be written
1247
1248! If the number of instructions in this macro are changed,
1249! please ensure that the second operand for the mulx above
1250! is also updated. We can calculate this during run-time but
1251! that will mean extra instructions and time.
1252#define TEST_REG_DP(reg_num)		\
1253	ldd	[%l1], %f/**/reg_num;	\
1254	ba	%ncc, reg_done_dp;	\
1255	std	%f/**/reg_num, [%l2]
1256
1257regTable_dp :
1258
1259	TEST_REG_DP(0)
1260	TEST_REG_DP(2)
1261	TEST_REG_DP(4)
1262	TEST_REG_DP(6)
1263	TEST_REG_DP(8)
1264	TEST_REG_DP(10)
1265	TEST_REG_DP(12)
1266	TEST_REG_DP(14)
1267	TEST_REG_DP(16)
1268	TEST_REG_DP(18)
1269	TEST_REG_DP(20)
1270	TEST_REG_DP(22)
1271	TEST_REG_DP(24)
1272	TEST_REG_DP(26)
1273	TEST_REG_DP(28)
1274	TEST_REG_DP(30)
1275	TEST_REG_DP(32)
1276	TEST_REG_DP(34)
1277	TEST_REG_DP(36)
1278	TEST_REG_DP(38)
1279	TEST_REG_DP(40)
1280	TEST_REG_DP(42)
1281	TEST_REG_DP(44)
1282	TEST_REG_DP(46)
1283	TEST_REG_DP(48)
1284	TEST_REG_DP(50)
1285	TEST_REG_DP(52)
1286	TEST_REG_DP(54)
1287	TEST_REG_DP(56)
1288	TEST_REG_DP(58)
1289	TEST_REG_DP(60)
1290
1291	! No need for a branch here as this the last entry in
1292	! the table and the label is will be reached by falling
1293	! through.
1294	ldd	[%l1], %f62
1295	std	%f62, [%l2]
1296
1297reg_done_dp:
1298	ldx	[%l2], %i0
1299
1300	ret
1301	restore
1302SET_SIZE(register_test_dp)
1303
1304
1305
1306!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1307! Name:		Move Registers
1308! Function:	Move a value thru the float registers
1309! Calling:	in0 = value
1310! Returns:	in0 = result
1311! Convention:	if (result != move_regs(value))
1312!                   error(result-value);
1313!--------------------------------------------------------------------------
1314        .section        ".data"
1315        .align  4
1316
1317.Lmvrg:
1318	.skip	4
1319.Lmvrg1:
1320	.skip 	4
1321
1322ENTRY_NP(move_regs)
1323	save    %sp, -SA(MINFRAME), %sp	! save the registers, stack
1324        setn    .Lmvrg1,%l6,%l0	! get the address to temp2
1325        setn    .Lmvrg,%l6,%l1	! .. and temp
1326        st      %i0, [%l0]	! get the callers value
1327        ld      [%l0], %f0	! .. into a float register
1328	fmovs   %f0, %f1	! copy from 1 register to the next
1329	fmovs   %f1, %f2	! .. to the next
1330	fmovs   %f2, %f3	! .. to the next
1331	fmovs   %f3, %f4	! .. to the next
1332	fmovs   %f4, %f5	! .. to the next
1333	fmovs   %f5, %f6	! .. to the next
1334	fmovs   %f6, %f7	! .. to the next
1335	fmovs   %f7, %f8	! .. to the next
1336	fmovs   %f8, %f9	! .. to the next
1337	fmovs   %f9, %f10	! .. to the next
1338	fmovs   %f10, %f11	! .. to the next
1339	fmovs   %f11, %f12	! .. to the next
1340	fmovs   %f12, %f13	! .. to the next
1341	fmovs   %f13, %f14	! .. to the next
1342	fmovs   %f14, %f15	! .. to the next
1343	fmovs   %f15, %f16	! .. to the next
1344	fmovs   %f16, %f17	! .. to the next
1345	fmovs   %f17, %f18	! .. to the next
1346	fmovs   %f18, %f19	! .. to the next
1347	fmovs   %f19, %f20	! .. to the next
1348	fmovs   %f20, %f21	! .. to the next
1349	fmovs   %f21, %f22	! .. to the next
1350	fmovs   %f22, %f23	! .. to the next
1351	fmovs   %f23, %f24	! .. to the next
1352	fmovs   %f24, %f25	! .. to the next
1353	fmovs   %f25, %f26	! .. to the next
1354	fmovs   %f26, %f27	! .. to the next
1355	fmovs   %f27, %f28	! .. to the next
1356	fmovs   %f28, %f29	! .. to the next
1357	fmovs   %f29, %f30	! .. to the next
1358	fmovs   %f30, %f31	! .. to the next
1359	st	%f31, [%l1]	! .... save the result
1360	ld	[%l1], %i0	! .. and return it to the caller
1361	ret
1362        restore
1363SET_SIZE(move_regs)
1364
1365
1366
1367!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1368! Name:		Move Registers Double Precision
1369! Function:	Move a value thru the float registers
1370! Calling:	in0 = value
1371! Returns:	in0 = result
1372! Convention:	if (result != move_regs_dp(value))
1373!                   error(result-value);
1374!--------------------------------------------------------------------------
1375        .section        ".data"
1376        .align  8
1377
1378.Lmvrg_dp:
1379	.skip	8
1380.Lmvrg1_dp:
1381	.skip 	8
1382
1383ENTRY_NP(move_regs_dp)
1384    	save    %sp, -SA(MINFRAME), %sp	! save the registers, stack
1385    	setx    .Lmvrg1_dp,%l6,%l0	! get the address to temp2
1386    	setx    .Lmvrg_dp,%l6,%l1	! .. and temp
1387    	stx     %i0, [%l0]	! get the callers value
1388    	ldd     [%l0], %f0	! .. into a float register
1389    	fmovd   %f0, %f2	! copy from 1 register to the next
1390	fmovd   %f2, %f4	! .. to the next
1391	fmovd   %f4, %f6	! .. to the next
1392	fmovd   %f6, %f8	! .. to the next
1393	fmovd   %f8, %f10	! .. to the next
1394	fmovd   %f10, %f12	! .. to the next
1395	fmovd   %f12, %f14	! .. to the next
1396	fmovd   %f14, %f16	! .. to the next
1397	fmovd   %f16, %f18	! .. to the next
1398	fmovd   %f18, %f20	! .. to the next
1399	fmovd   %f20, %f22	! .. to the next
1400	fmovd   %f22, %f24	! .. to the next
1401	fmovd   %f24, %f26	! .. to the next
1402	fmovd   %f26, %f28	! .. to the next
1403	fmovd   %f28, %f30	! .. to the next
1404	fmovd   %f30, %f32	! .. to the next
1405	fmovd   %f32, %f34	! .. to the next
1406	fmovd   %f34, %f36	! .. to the next
1407	fmovd   %f36, %f38	! .. to the next
1408	fmovd   %f38, %f40	! .. to the next
1409	fmovd   %f40, %f42	! .. to the next
1410	fmovd   %f42, %f44	! .. to the next
1411	fmovd   %f44, %f46	! .. to the next
1412	fmovd   %f46, %f48	! .. to the next
1413	fmovd   %f48, %f50	! .. to the next
1414	fmovd   %f50, %f52	! .. to the next
1415	fmovd   %f52, %f54	! .. to the next
1416	fmovd   %f54, %f56	! .. to the next
1417	fmovd   %f56, %f58	! .. to the next
1418	fmovd   %f58, %f60	! .. to the next
1419	fmovd   %f60, %f62	! .. to the next
1420	std		%f62, [%l1]	! .... save the result
1421	ldx		[%l1], %i0	! .. and return it to the caller
1422	ret
1423    restore
1424SET_SIZE(move_regs_dp)
1425
1426
1427
1428!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1429! Name:
1430! Function:
1431! Calling:
1432! Returns:
1433! Convention:
1434!--------------------------------------------------------------------------
1435!
1436! 	The following routine checks the branching is done accordingly
1437!	to the ficc bits.
1438!	input	%i0 = 0 = branch unordered
1439!		      1 = branch greater
1440!		      2 = branch unordered or greater
1441!		      3 = branch less
1442!		      4 = branch unordered or less
1443!		      5 = branch less or greater
1444!		      6 = branch not equal
1445!		      7 = branch equal
1446!		      8 = branch unordered or equal
1447!		    . 9 = branch greater or equal
1448!		     10 = branch branch unordered or greater or equal
1449!		     11 = branch less or equal
1450!		     12 = branch unordered or or less or equal
1451!		     13 = branch ordered
1452!		     14 = branch always
1453!		     15 = branch never
1454!
1455!	ouput : %i0 = 0 = good
1456!		    = 1 = error
1457!
1458
1459        .section        ".data"
1460        .align  8
1461
1462.Lbr:
1463	.skip	8
1464.Lbr1:
1465	.skip	8
1466
1467ENTRY_NP(branches)
1468	save    %sp, -SA(MINFRAME), %sp           ! save the registers, stacck
1469        setn    .Lbr1,%l6,%l1
1470        setn    .Lbr,%l6,%l2
1471        st      %i1, [%l1]
1472	st	%i2, [%l2]
1473	ld      [%l1], %f0
1474        ld      [%l2], %f2
1475
1476	setn	brn_0, %l6, %o0
1477	mulx	%i0, 12, %o1
1478
1479
1480	jmp	%o0+%o1
1481	fcmps	%fcc0, %f0, %f2		! compare the values  to get ficc
1482!
1483!				branch unordered
1484brn_0:
1485	fbu,a	%fcc0, br_good
1486	nop
1487	ba,a	%ncc, br_error
1488
1489!				branch greater
1490brn_1:
1491	fbg,a	%fcc0, br_good
1492	nop
1493	ba,a	%ncc, br_error
1494
1495!				branch unordered or greater
1496brn_2:
1497	fbug,a	%fcc0, br_good
1498	nop
1499	ba,a	%ncc, br_error
1500
1501!				branch less
1502brn_3:
1503	fbl,a	%fcc0, br_good
1504	nop
1505	ba,a	%ncc, br_error
1506
1507!				branch unorderd or less
1508brn_4:
1509	fbul,a	%fcc0, br_good
1510	nop
1511	ba,a	%ncc, br_error
1512
1513!				branch less or greater
1514brn_5:
1515	fblg,a	%fcc0, br_good
1516	nop
1517	ba,a	%ncc, br_error
1518
1519!				branch not equal
1520brn_6:
1521	fbne,a	%fcc0, br_good
1522	nop
1523	ba,a	%ncc, br_error
1524
1525!                               branch equal
1526brn_7:
1527	fbe,a	%fcc0, br_good
1528        nop
1529	ba,a	%ncc, br_error
1530
1531!                               branch unordered or equal
1532brn_8:
1533	fbue,a	%fcc0, br_good
1534        nop
1535	ba,a	%ncc, br_error
1536
1537!                               branch greater or equal
1538brn_9:
1539	fbge,a	%fcc0, br_good
1540        nop
1541	ba,a	%ncc, br_error
1542
1543!                               branch unordered or greater or equal
1544brn_10:
1545	fbuge,a	%fcc0, br_good
1546        nop
1547	ba,a	%ncc, br_error
1548
1549!                               branch less or equal
1550brn_11:
1551	fble,a	%fcc0, br_good
1552        nop
1553	ba,a	%ncc, br_error
1554
1555!                               branch unordered or less or equal
1556brn_12:
1557	fbule,a	%fcc0, br_good
1558        nop
1559	ba,a	%ncc, br_error
1560
1561!                               branch ordered
1562brn_13:
1563	fbo,a	%fcc0, br_good
1564	nop
1565	ba,a	%ncc, br_error
1566
1567!				branch always
1568brn_14:
1569	fba,a	%fcc0, br_good
1570	nop
1571	ba,a	%ncc, br_error
1572
1573!				branch never
1574brn_15:
1575	fbn,a	%fcc0, br_error
1576	nop
1577
1578br_good:
1579	mov	%g0, %i0	! Branch worked as expected
1580
1581	ret
1582	restore
1583
1584br_error:
1585	mov	0xff, %i0	! set the flag that it is error
1586
1587        ret
1588        restore
1589SET_SIZE(branches)
1590
1591
1592!void read_fpreg(pf, n)
1593!       FPU_REGS_TYPE   *pf;    /* Old freg value. */
1594!       unsigned        n;      /* Want to read register n. */
1595!
1596!{
1597!       *pf = %f[n];
1598!}
1599
1600ENTRY_NP(read_fpreg)
1601	save    %sp, -SA(MINFRAME), %sp
1602        mulx    %i1, 12, %i1            ! Table entries are 12 bytes each.
1603        setn    stable, %l1, %g1        ! g1 gets base of table.
1604        jmp     %g1 + %i1               ! Jump into table
1605        nop                             ! Can't follow CTI by CTI.
1606
1607#define STOREFP(n) st %f/**/n, [%i0]; ret; restore
1608
1609stable:
1610	STOREFP(0)
1611	STOREFP(1)
1612	STOREFP(2)
1613	STOREFP(3)
1614	STOREFP(4)
1615	STOREFP(5)
1616	STOREFP(6)
1617	STOREFP(7)
1618	STOREFP(8)
1619	STOREFP(9)
1620	STOREFP(10)
1621	STOREFP(11)
1622	STOREFP(12)
1623	STOREFP(13)
1624	STOREFP(14)
1625	STOREFP(15)
1626	STOREFP(16)
1627	STOREFP(17)
1628	STOREFP(18)
1629	STOREFP(19)
1630	STOREFP(20)
1631	STOREFP(21)
1632	STOREFP(22)
1633	STOREFP(23)
1634	STOREFP(24)
1635	STOREFP(25)
1636	STOREFP(26)
1637	STOREFP(27)
1638	STOREFP(28)
1639	STOREFP(29)
1640	STOREFP(30)
1641	STOREFP(31)
1642SET_SIZE(read_fpreg)
1643
1644
1645ENTRY_NP(read_fpreg_dp)
1646	save    %sp, -SA(MINFRAME), %sp
1647        mulx    %i1, 6, %i1             ! Table entries are 12 bytes each.
1648										! But o1 will have even numbered
1649										! index
1650        setn    stable_dp, %l0, %g1			! g1 gets base of table.
1651        jmp     %g1 + %i1               ! Jump into table
1652        nop                             ! Can't follow CTI by CTI.
1653
1654#define STOREFP_DP(n) std %f/**/n, [%i0]; ret; restore
1655
1656stable_dp:
1657	STOREFP_DP(0)
1658	STOREFP_DP(2)
1659	STOREFP_DP(4)
1660	STOREFP_DP(6)
1661	STOREFP_DP(8)
1662	STOREFP_DP(10)
1663	STOREFP_DP(12)
1664	STOREFP_DP(14)
1665	STOREFP_DP(16)
1666	STOREFP_DP(18)
1667	STOREFP_DP(20)
1668	STOREFP_DP(22)
1669	STOREFP_DP(24)
1670	STOREFP_DP(26)
1671	STOREFP_DP(28)
1672	STOREFP_DP(30)
1673	STOREFP_DP(32)
1674	STOREFP_DP(34)
1675	STOREFP_DP(36)
1676	STOREFP_DP(38)
1677	STOREFP_DP(40)
1678	STOREFP_DP(42)
1679	STOREFP_DP(44)
1680	STOREFP_DP(46)
1681	STOREFP_DP(48)
1682	STOREFP_DP(50)
1683	STOREFP_DP(52)
1684	STOREFP_DP(54)
1685	STOREFP_DP(56)
1686	STOREFP_DP(58)
1687	STOREFP_DP(60)
1688	STOREFP_DP(62)
1689
1690SET_SIZE(read_fpreg_dp)
1691
1692!
1693!void
1694!write_fpreg(pf, n)
1695!       FPU_REGS_TYPE   *pf;    /* New freg value. */
1696!       unsigned        n;      /* Want to read register n. */
1697!
1698!{
1699!       %f[n] = *pf;
1700!}
1701
1702ENTRY_NP(write_fpreg)
1703        sll     %o1, 3, %o1             ! Table entries are 8 bytes each.
1704        setn     ltable, %l0,  %g1       ! g1 gets base of table.
1705        jmp     %g1 + %o1               ! Jump into table
1706        nop                             ! Can't follow CTI by CTI.
1707
1708
1709#define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n
1710
1711ltable:
1712	LOADFP(0)
1713	LOADFP(1)
1714	LOADFP(2)
1715	LOADFP(3)
1716	LOADFP(4)
1717	LOADFP(5)
1718	LOADFP(6)
1719	LOADFP(7)
1720	LOADFP(8)
1721	LOADFP(9)
1722	LOADFP(10)
1723	LOADFP(11)
1724	LOADFP(12)
1725	LOADFP(13)
1726	LOADFP(14)
1727	LOADFP(15)
1728	LOADFP(16)
1729	LOADFP(17)
1730	LOADFP(18)
1731	LOADFP(19)
1732	LOADFP(20)
1733	LOADFP(21)
1734	LOADFP(22)
1735	LOADFP(23)
1736	LOADFP(24)
1737	LOADFP(25)
1738	LOADFP(26)
1739	LOADFP(27)
1740	LOADFP(28)
1741	LOADFP(29)
1742	LOADFP(30)
1743	LOADFP(31)
1744SET_SIZE(write_fpreg)
1745