/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Usage of %ncc * * When the branch instructions were modified from Bicc to BPcc format, * the pseudo-op %ncc was used. This will be converted by the assembler * to %icc or %xcc depending on whether the compilation is being done * for 32-bit or 64-bit platforms. */ #include /* * ------------------------------------------------------------------------ * Name: datap_add() * Function: This routine test the data path of the adder for single * precision. * Calling: i0 = value * Returns: * Convention: * -------------------------------------------------------------------------- * * f0 = value * f1 = 0 * add = f2 = value */ #ifdef __lint /*ARGSUSED*/ unsigned long datap_add(unsigned long arg1) { return (0); } #else .section ".data" .align 4 .Ldadd: .skip 4 .Ldadd1: .skip 4 ENTRY_NP(datap_add) save %sp, -SA(MINFRAME), %sp ! save the stack frame setn .Ldadd,%l6,%l0 ! get a memory address setn .Ldadd1,%l6,%l1 ! .. one for the result mov %g0,%l3 ! .. get a zero st %l3, [%l1] ! .... and store it in memory st %i0, [%l0] ! .... store the value passed ld [%l0], %f0 ! .... put the passed value into f0 ld [%l1], %f1 ! .... put value 0 into reg f1 fadds %f0, %f1, %f2 ! ...... add zero and value into f2 fcmps %fcc0, %f0, %f2 ! .... check the value passed and added value fbe,a %fcc0, datap_ok ! .. if they are equal nop ! .... delay st %f2, [%l1] ! return the result on error datap_ok: ld [%l1], %i0 ! then return a zero ret ! .... delay restore SET_SIZE(datap_add) #endif /* * ------------------------------------------------------------------------ * Name: * Function: * Calling: * Returns: * Convention: * -------------------------------------------------------------------------- * * This routine test the data path of multiplier for single precision * f0 = value * f1 = 1 * mult = f2 = f0 * f1 */ #ifdef __lint /*ARGSUSED*/ unsigned long datap_mult(unsigned long arg1) { return (0); } #else .section ".data" .align 4 .Ldtmlt: .skip 4 .Ldtmlt1: .skip 4 ENTRY_NP(datap_mult) save %sp, -SA(MINFRAME), %sp setn .Ldtmlt,%l6,%l0 setn .Ldtmlt1,%l6,%l1 setn 0x3F800000,%l6,%l3 ! put value 1 into memory st %l3, [%l1] st %i0, [%l0] ! store the value passed into memory location ld [%l0], %f0 ! put the passed value into f0 ld [%l1], %f1 ! put value 1 into reg f1 fmuls %f0, %f1, %f2 ! multiply value with 1 , it has to be same fcmps %fcc0, %f0, %f2 fbne,a %fcc0, datap_mult_done st %f2, [%l1] ! executed only when the conditional ! branch is taken as annul bit is set. ! This branch will be taken under ! an error condition (%f0 != %f2). ! Then we need to return the result. mov %g0,%l3 st %l3, [%l1] datap_mult_done : ld [%l1], %i0 ret restore SET_SIZE(datap_mult) #endif /* * ------------------------------------------------------------------------ * Name: * Function: * Calling: * Returns: * Convention: * -------------------------------------------------------------------------- * * This routine tests the data path of the weitek multiplier for * double precision. Single-precision load and store are being * used as the input double-precision value is taken as two SP * arguments * * f0 = msw value * f1 = lsw value * * f2 = 0 * f3 = 0 * add = f4 = f0 + f2 */ #ifdef __lint /*ARGSUSED*/ unsigned long datap_add_dp(unsigned long arg1, unsigned long arg2) { return (0); } #else .section ".data" .align 8 .Ldtadddp: .skip 8 .Ldtadddp1: .skip 8 .Ldtadddp2: .skip 8 .Lamsw: .skip 8 .Lalsw: .skip 8 ENTRY_NP(datap_add_dp) save %sp, -SA(MINFRAME), %sp setn .Ldtadddp,%l6,%l0 setn .Ldtadddp1,%l6,%l1 setn .Ldtadddp2,%l6,%l2 setn .Lamsw,%l6,%l4 setn .Lalsw,%l6,%l5 mov %g0,%l3 ! put value 0 into memory st %l3, [%l1] st %i0, [%l0] ! msw of value st %i1, [%l2] ! lsw of value ld [%l0], %f0 ! put the msw into f0 ld [%l2], %f1 ! put the lsw into f1 ld [%l1], %f2 ! put 0 into f2 ld [%l1], %f3 ! put 0 into f3 faddd %f0, %f2, %f4 ! add value + 0 into f4 fcmpd %fcc0, %f0, %f4 ! now compare the result fbe,a %fcc0, datap_add_dp_ok ! good nop mov 0x1,%l3 st %l3, [%l1] datap_add_dp_ok : ld [%l1], %i0 ret restore SET_SIZE(datap_add_dp) #endif /* * ------------------------------------------------------------------------ * Name: * Function: * Calling: * Returns: * Convention: * * This routine tests the data path of the weitek multiplier for * double precision. Single-precision load and store are being * used as the input double-precision value is taken as two SP * arguments. * * f0 = msw value * f1 = lsw value * f2 = 0 * f3 = 0 * mult = f4 = f0 * f2 * ------------------------------------------------------------------------ */ #ifdef __lint /*ARGSUSED*/ unsigned long datap_mult_dp(unsigned long arg1, unsigned long arg2) { return (0); } #else .section ".data" .align 8 .Ldtmdp: .skip 8 .Ldtmdp1: .skip 8 .Ldtmdp2: .skip 8 .Lmmsw: .skip 8 .Lmlsw: .skip 8 ENTRY_NP(datap_mult_dp) save %sp, -SA(MINFRAME), %sp setn .Ldtmdp,%l6,%l0 setn .Ldtmdp1,%l6,%l1 setn .Ldtmdp2,%l6,%l2 setn .Lmmsw,%l6,%l4 setn .Lmlsw,%l6,%l5 setn 0x3FF00000,%l6,%l3 ! put msw value of DP 1 into memory st %l3, [%l1] st %i0, [%l0] ! msw of value st %i1, [%l2] ! lsw of value ld [%l0], %f0 ! put the msw into f0 ld [%l2], %f1 ! put the lsw into f1 ld [%l1], %f2 ! put msw of DP 1 into f2 mov %g0,%l3 st %l3, [%l1] ld [%l1], %f3 ! put 0 into f3, i.e f2|f3 = 0x3ff0000000000000 (dp 1) fmuld %f0, %f2, %f4 ! mult value * 1 into f4 fcmpd %fcc0, %f0, %f4 ! now compare the result fbe,a %fcc0, datap_mult_dp_ok ! good nop mov 0x1,%l3 st %l3, [%l1] datap_mult_dp_ok : ld [%l1], %i0 ret restore SET_SIZE(datap_mult_dp) #endif /* * ------------------------------------------------------------------------- * for add routine all the f registers from 0 - 19 will be filled with numbers * and the result should be 10. * ------------------------------------------------------------------------- */ #ifdef __lint unsigned long timing_add_sp() { return (0); } #else .section ".data" .align 4 .Ltmasp: .skip 4 .Ltmasp1: .skip 4 .Ltmasp2: .skip 4 ENTRY_NP(timing_add_sp) save %sp, -SA(MINFRAME), %sp ! save the registers, stacck setn .Ltmasp,%l6,%l0 setn .Ltmasp1,%l6,%l1 setn .Ltmasp2,%l6,%l2 mov %g0,%l3 setn 0x3f800000,%l6,%l4 ! put value 1 setn 0x41200000,%l6,%l5 ! put value 10 into local 5 st %l5, [%l0] st %l4, [%l1] st %l3, [%l2] ld [%l0], %f31 ! register 31 has 10 ld [%l1], %f30 ! register 30 has 1 ld [%l2], %f0 ! reg 0 has 0 fmovs %f31, %f1 ! reg1 has 10 fsubs %f31, %f30, %f18 ! reg 18 has 9 fmovs %f18, %f3 ! reg 3 has 9 fmovs %f30, %f2 ! reg 2 has 1 fmovs %f30, %f19 ! reg 19 has 1 fsubs %f18, %f19, %f16 ! reg 16 has 8 fmovs %f16, %f5 ! reg 5 has 8 fsubs %f31, %f16, %f17 ! reg 17 has 2 fmovs %f17, %f4 ! reg 4 has 2 fsubs %f16, %f30, %f14 ! reg 14 has 7 fmovs %f14, %f7 ! reg 7 has 7 fsubs %f31, %f14, %f15 ! reg 15 has 3 fmovs %f15, %f6 ! reg 6 has 3 fsubs %f14, %f30, %f12 ! reg 12 has 6 fmovs %f12, %f9 ! reg 9 has 6 fsubs %f31, %f12, %f13 ! reg 13 has 4 fmovs %f13, %f8 ! reg 8 has 4 fsubs %f12, %f30, %f10 ! reg 10 has 5 fmovs %f10, %f11 ! reg 11 has 5 fadds %f0, %f1, %f20 ! reg 0 + reg 1 = reg 20 = 10 fadds %f2, %f3, %f21 ! reg 2 + reg 3 = reg 21 = 10 fadds %f4, %f5, %f22 ! reg 4 + reg 5 = reg 22 = 10 fadds %f6, %f7, %f23 ! reg 6 + reg 7 = reg 23 = 10 fadds %f8, %f9, %f24 ! reg 8 + reg 9 = reg 24 = 10 fadds %f10, %f11, %f25 ! reg 10 + reg 11 = reg 25 = 10 fadds %f12, %f13, %f26 ! reg 12 + reg 13 = reg 26 = 10 fadds %f14, %f15, %f27 ! reg 14 + reg 15 = reg 27 = 10 fadds %f16, %f17, %f28 ! reg 16 + reg 17 = reg 28 = 10 fadds %f18, %f19, %f29 ! reg 18 + reg 19 = reg 29 = 10 ! Now additions are done check it out fcmps %fcc0, %f31, %f20 fbne,a,pn %fcc0, done_t_add_sp ! If not equal, go to the end. st %f20, [%l2] ! Executed only when the conditional ! branch is taken as annul bit is set. ! This branch will be taken under ! an error condition. ! No errors. Move on to the next register fcmps %fcc0, %f31, %f21 fbne,a,pn %fcc0, done_t_add_sp st %f21, [%l2] fcmps %fcc0, %f31, %f22 fbne,a,pn %fcc0, done_t_add_sp st %f22, [%l2] fcmps %fcc0, %f31, %f23 fbne,a,pn %fcc0, done_t_add_sp st %f23, [%l2] fcmps %fcc0, %f31, %f24 fbne,a,pn %fcc0, done_t_add_sp st %f24, [%l2] fcmps %fcc0, %f31, %f25 fbne,a,pn %fcc0, done_t_add_sp st %f25, [%l2] fcmps %fcc0, %f31, %f26 fbne,a,pn %fcc0, done_t_add_sp st %f26, [%l2] fcmps %fcc0, %f31, %f27 fbne,a,pn %fcc0, done_t_add_sp st %f27, [%l2] fcmps %fcc0, %f31, %f28 fbne,a,pn %fcc0, done_t_add_sp st %f28, [%l2] ! Though this is the last set of compare instructions ! we cannot fall through as the store needs to be done ! only when the registers are not equal. That is why ! we need the unconditional branch with the annul bit set. fcmps %fcc0, %f31, %f29 fbne,a,pn %fcc0, done_t_add_sp st %f29, [%l2] done_t_add_sp: ld [%l2], %i0 ret restore SET_SIZE(timing_add_sp) #endif /* * ---------------------------------------------------------------------- * for mult routine all the f registers from 0 - 19 will be filled * with numbers and the result should be the number. * ---------------------------------------------------------------------- */ #ifdef __lint unsigned long timing_mult_sp() { return (0); } #else .section ".data" .align 4 .Ltmmsp: .skip 4 .Ltmmsp1: .skip 4 .Ltmmsp2: .skip 4 ENTRY_NP(timing_mult_sp) save %sp, -SA(MINFRAME), %sp ! save the registers, stacck setn .Ltmmsp,%l6, %l0 setn .Ltmmsp1,%l6, %l1 setn .Ltmmsp2,%l6, %l2 mov %g0, %l3 setn 0x3f800000,%l6, %l4 ! put value 1 setn 0x41200000,%l6, %l5 ! put value 10 into local 5 st %l5, [%l0] st %l4, [%l1] st %l3, [%l2] ld [%l0], %f31 ! register 31 has 10 ld [%l1], %f1 ! register 1 has 1 fmovs %f1, %f3 fmovs %f1, %f5 fmovs %f1, %f7 fmovs %f1, %f9 fmovs %f1, %f11 ! register 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 fmovs %f1, %f13 ! has a value of 1 fmovs %f1, %f15 fmovs %f1, %f17 fmovs %f1, %f19 ! fmovs %f1, %f0 fmovs %f31, %f18 ! reg 18 has 10 fsubs %f31, %f0, %f16 ! reg 16 has 9 fsubs %f16, %f0, %f14 ! reg 14 has 8 fsubs %f14, %f0, %f12 ! reg 12 has 7 fsubs %f12, %f0, %f10 ! reg 10 has 6 fsubs %f10, %f0, %f8 ! reg 8 has 5 fsubs %f8, %f0, %f6 ! reg 6 has 4 fsubs %f6, %f0, %f4 ! reg 4 has 3 fsubs %f4, %f0, %f2 ! reg 2 has 2 fmuls %f0, %f1, %f20 ! reg 0 * reg 1 = reg 20 = 1 fmuls %f2, %f3, %f21 ! reg 2 * reg 3 = reg 21 = 2 fmuls %f4, %f5, %f22 ! reg 4 * reg 5 = reg 22 = 3 fmuls %f6, %f7, %f23 ! reg 6 * reg 7 = reg 23 = 4 fmuls %f8, %f9, %f24 ! reg 8 * reg 9 = reg 24 = 5 fmuls %f10, %f11, %f25 ! reg 10 * reg 11 = reg 25 = 6 fmuls %f12, %f13, %f26 ! reg 12 * reg 13 = reg 26 = 7 fmuls %f14, %f15, %f27 ! reg 14 * reg 15 = reg 27 = 8 fmuls %f16, %f17, %f28 ! reg 16 * reg 17 = reg 28 = 9 fmuls %f18, %f19, %f29 ! reg 18 * reg 19 = reg 29 = 10 fcmps %fcc0, %f0, %f20 fbne,a,pn %fcc0, done_t_mult_sp st %f20, [%l2] ! Executed only when the conditional ! branch is taken as annul bit is set. ! This branch will be taken under ! an error condition. ! No errors. Move on to the next register fcmps %fcc0, %f2, %f21 fbne,a,pn %fcc0, done_t_mult_sp st %f21, [%l2] fcmps %fcc0, %f4, %f22 fbne,a,pn %fcc0, done_t_mult_sp st %f22, [%l2] fcmps %fcc0, %f6, %f23 fbne,a,pn %fcc0, done_t_mult_sp st %f23, [%l2] fcmps %fcc0, %f8, %f24 fbne,a,pn %fcc0, done_t_mult_sp st %f24, [%l2] fcmps %fcc0, %f10, %f25 fbne,a,pn %fcc0, done_t_mult_sp st %f25, [%l2] fcmps %fcc0, %f12, %f26 fbne,a,pn %fcc0, done_t_mult_sp st %f26, [%l2] fcmps %fcc0, %f14, %f27 fbne,a,pn %fcc0, done_t_mult_sp st %f27, [%l2] fcmps %fcc0, %f16, %f28 fbne,a,pn %fcc0, done_t_mult_sp st %f28, [%l2] ! Though this is the last set of compare instructions ! we cannot fall through as the store needs to be done ! only when the registers are not equal. That is why ! we need the unconditional branch with the annul bit set. fcmps %fcc0, %f18, %f29 fbne,a,pn %fcc0, done_t_mult_sp st %f29, [%l2] done_t_mult_sp: ld [%l2], %i0 ret restore SET_SIZE(timing_mult_sp) #endif /* * ---------------------------------------------------------------- * same thing for double precision * ---------------------------------------------------------------- */ #ifdef __lint uint64_t timing_add_dp() { return (0); } #else .section ".data" .align 8 .Ltmadp: .skip 8 .Ltmadp1: .skip 8 .Ltmadp2: .skip 8 ENTRY_NP(timing_add_dp) save %sp, -SA(MINFRAME), %sp ! save the registers, stacck setn .Ltmadp,%l6, %l0 setn .Ltmadp1,%l6, %l1 setn .Ltmadp2,%l6, %l2 mov %g0, %l3 setn 0x3ff0000000000000,%l6, %l4 ! put value 1 setn 0x4024000000000000,%l6, %l5 ! put value 10 into local 5 stx %l5, [%l0] stx %l4, [%l1] stx %l3, [%l2] ldd [%l0], %f30 ! register 30 has 10 fmovd %f30, %f2 ! reg 2 has 10 ldd [%l2], %f0 ! reg 0 has 0 ldd [%l1], %f4 ! reg 4 has 1 fsubd %f30, %f4, %f6 ! reg 6 has 9 fsubd %f6, %f4, %f10 ! reg 10 has 8 fsubd %f30, %f10, %f8 ! reg 8 has 2 fsubd %f10, %f4, %f14 ! reg 14 has 7 fsubd %f30, %f14, %f12 ! reg 12 has 3 fsubd %f14, %f4, %f18 ! reg 18 has 6 fsubd %f30, %f18, %f16 ! reg 16 has 4 ! faddd %f0, %f2, %f20 ! reg 20 has 10 faddd %f4, %f6, %f22 ! reg 22 has 10 faddd %f8, %f10, %f24 ! reg 24 has 10 faddd %f12, %f14, %f26 ! reg 26 has 10 faddd %f16, %f18, %f28 ! reg 28 has 10 ! fcmpd %fcc0, %f30, %f20 fbne,a,pn %fcc0, done_t_add_dp std %f20, [%l2] fcmpd %fcc0, %f30, %f22 fbne,a,pn %fcc0, done_t_add_dp std %f22, [%l2] fcmpd %fcc0, %f30, %f24 fbne,a,pn %fcc0, done_t_add_dp std %f24, [%l2] fcmpd %fcc0, %f30, %f26 fbne,a,pn %fcc0, done_t_add_dp std %f26, [%l2] ! Though this is the last set of compare instructions ! we cannot fall through as the store needs to be done ! only when the registers are not equal. That is why ! we need the unconditional branch with the annul bit set. fcmpd %fcc0, %f30, %f28 fbne,a %fcc0, done_t_add_dp std %f28, [%l2] done_t_add_dp: ldx [%l2], %i0 ret restore SET_SIZE(timing_add_dp) #endif /* * ------------------------------------------------------------------- * Now for mult * ------------------------------------------------------------------- */ #ifdef __lint uint64_t timing_mult_dp() { return (0); } #else .section ".data" .align 8 .Ltmmdp: .skip 8 .Ltmmdp1: .skip 8 .Ltmmdp2: .skip 8 ENTRY_NP(timing_mult_dp) save %sp, -SA(MINFRAME), %sp ! save the registers, stacck setn .Ltmmdp,%l6, %l0 setn .Ltmmdp1,%l6, %l1 setn .Ltmmdp2,%l6, %l2 mov %g0, %l3 setn 0x3ff0000000000000,%l6, %l4 ! put value 1 setn 0x4034000000000000,%l6, %l5 ! put value 20 into local 5 stx %l5, [%l0] stx %l4, [%l1] stx %l3, [%l2] ldd [%l0], %f30 ! register 30 has 20 ldd [%l1], %f2 ! register 2 has 1 fmovd %f30, %f0 ! register 0 has 20 faddd %f2, %f2, %f10 ! register 10 has 2 fmovd %f10, %f16 ! register 16 has 2 faddd %f10, %f16, %f4 ! register 4 has 4 faddd %f4, %f2, %f6 ! register 6 has 5 fmovd %f6, %f12 ! reg. 12 has 5 fmovd %f4, %f14 ! reg 14 has 4 faddd %f12, %f6, %f18 ! reg 18 has 10 fmovd %f18, %f8 ! reg 8 has 10 ! ! now everything is set ! fmuld %f0, %f2, %f20 ! reg 20 has 20 fmuld %f4, %f6, %f22 ! reg 22 has 20 fmuld %f8, %f10, %f24 ! reg 24 has 20 fmuld %f12, %f14, %f26 ! reg 26 has 20 fmuld %f16, %f18, %f28 ! reg 28 has 20 ! fcmpd %fcc0, %f30, %f20 fbne,a,pn %fcc0, done_t_mult_dp std %f20, [%l2] fcmpd %fcc0, %f30, %f22 fbne,a,pn %fcc0, done_t_mult_dp std %f22, [%l2] fcmpd %fcc0, %f30, %f24 fbne,a,pn %fcc0, done_t_mult_dp std %f24, [%l2] fcmpd %fcc0, %f30, %f26 fbne,a,pn %fcc0, done_t_mult_dp std %f26, [%l2] ! Though this is the last set of compare instructions ! we cannot fall through as the store needs to be done ! only when the registers are not equal. That is why ! we need the unconditional branch with the annul bit set. fcmpd %fcc0, %f30, %f28 fbne,a %fcc0, done_t_mult_dp std %f28, [%l2] done_t_mult_dp: ldx [%l2], %i0 ret restore SET_SIZE(timing_mult_dp) #endif /* * -------------------------------------------------------------------------- * The following routines are for testing the IEEE754 exception fields * of the FSR (cexc, aexc) * The input is : i0 = amsw * i1 = bmsw or alsw (for double precision) * i2 = bmsw (for dp) * i3 = blsw (for dp) * * The output is i0 = value of FSR register * ------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wadd_sp(unsigned long arg1, unsigned long arg2) { return (0); } #else .section ".data" .align 8 .Lwadds: .word 0 .Lwadds1: .word 0 .Lwadds2: .xword 0 ! For the FSR contents ENTRY_NP(wadd_sp) save %sp, -SA(MINFRAME), %sp setn .Lwadds,%l6, %l0 setn .Lwadds1,%l6, %l1 setn .Lwadds2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the second value ld [%l0], %f0 ! f0 has the first value ld [%l1], %f2 ! f2 has the second value fadds %f0, %f2, %f3 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wadd_sp) #endif /* * ------------------------------------------------------------- * same thing for add double precision * ------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wadd_dp(unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { return (0); } #else .section ".data" .align 8 .Ladddp: .word 0 .Ladddp1: .word 0 .Ladddp2: .xword 0 ! For the FSR contents ENTRY_NP(wadd_dp) save %sp, -SA(MINFRAME), %sp setn .Ladddp,%l6, %l0 setn .Ladddp1,%l6, %l1 setn .Ladddp2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the lsw of first value ld [%l0], %f0 ld [%l1], %f1 st %i2, [%l0] ! get the second value st %i3, [%l1] ! get the lsw of second value ld [%l0], %f2 ld [%l1], %f3 faddd %f0, %f2, %f4 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wadd_dp) #endif /* * -------------------------------------------------------------- * for divide single precision * -------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wdiv_sp(unsigned long arg1, unsigned long arg2) { return (0); } #else .section ".data" .align 8 .Ldvsp: .word 0 .Ldvsp1: .word 0 .Ldvsp2: .xword 0 ! For the FSR contents ENTRY_NP(wdiv_sp) save %sp, -SA(MINFRAME), %sp setn .Ldvsp,%l6, %l0 setn .Ldvsp1,%l6, %l1 setn .Ldvsp2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the second value ld [%l0], %f0 ! f0 has the first value ld [%l1], %f2 ! f2 has the second value fdivs %f0, %f2, %f3 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wdiv_sp) #endif /* * ---------------------------------------------------------------- * for divide double precision * ---------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wdiv_dp(unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { return (0); } #else .section ".data" .align 8 .Ldvdp: .word 0 .Ldvdp1: .word 0 .Ldvdp2: .xword 0 ! For the FSR contents ENTRY_NP(wdiv_dp) save %sp, -SA(MINFRAME), %sp setn .Ldvdp,%l6, %l0 setn .Ldvdp1,%l6, %l1 setn .Ldvdp2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the lsw of first value ld [%l0], %f0 ld [%l1], %f1 st %i2, [%l0] ! get the second value st %i3, [%l1] ! get the lsw of second value ld [%l0], %f2 ld [%l1], %f3 fdivd %f0, %f2, %f4 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wdiv_dp) #endif /* * ------------------------------------------------------------------------ * for multiply single precision * ------------------------------------------------------------------------ */ #ifdef __lint /*ARGSUSED*/ uint64_t wmult_sp(unsigned long arg1, unsigned long arg2) { return (0); } #else .section ".data" .align 8 .Lmltsp: .word 0 .Lmltsp1: .word 0 .Lmltsp2: .xword 0 ! For the FSR contents ENTRY_NP(wmult_sp) save %sp, -SA(MINFRAME), %sp setn .Lmltsp,%l6, %l0 setn .Lmltsp1,%l6, %l1 setn .Lmltsp2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the second value ld [%l0], %f0 ! f0 has the first value ld [%l1], %f2 ! f2 has the second value fmuls %f0, %f2, %f3 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wmult_sp) #endif /* * --------------------------------------------------------------------- * for multiply double precision * --------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wmult_dp(unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { return (0); } #else .section ".data" .align 8 .Lmltdp: .word 0 .Lmltdp1: .word 0 .Lmltdp2: .xword 0 ! For the FSR contents ENTRY_NP(wmult_dp) save %sp, -SA(MINFRAME), %sp setn .Lmltdp,%l6, %l0 setn .Lmltdp1,%l6, %l1 setn .Lmltdp2,%l6, %l2 st %i0, [%l0] ! get the first value st %i1, [%l1] ! get the lsw of first value ld [%l0], %f0 ld [%l1], %f1 st %i2, [%l0] ! get the second value st %i3, [%l1] ! get the lsw of second value ld [%l0], %f2 ld [%l1], %f3 fmuld %f0, %f2, %f4 ! now do the instruction stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wmult_dp) #endif /* * ----------------------------------------------------------------- * for square-root single precision * ----------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wsqrt_sp(unsigned long arg1) { return (0); } #else .section ".data" .align 4 .Lsqsp_opr: .word 0 .align 8 .Lsqsp_fsr: .xword 0 ! For the FSR contents ENTRY_NP(wsqrt_sp) save %sp, -SA(MINFRAME), %sp ! save the registers, stack setn .Lsqsp_opr,%l6,%l0 ! .. get the address of temp2 setn .Lsqsp_fsr,%l6,%l2 ! .. and temp st %i0, [%l0] ! .. get the callers value ld [%l0], %f0 ! .. into the float register fsqrts %f0, %f2 ! .... have the fpu perform the operation stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wsqrt_sp) #endif /* * --------------------------------------------------------------------- * for square-root double precision * --------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t wsqrt_dp(uint64_t arg1) { return (0); } #else .section ".data" .align 8 .Lsqdp_opr: .xword 0 .Lsqdp_fsr: .xword 0 ! For the FSR contents ENTRY_NP(wsqrt_dp) save %sp, -SA(MINFRAME), %sp ! save the registers, stack setn .Lsqdp_opr,%l6,%l0 ! .. get the address of temp2 setn .Lsqdp_fsr,%l6,%l2 ! .. and temp stx %i0, [%l0] ! .. get the callers value ldd [%l0], %f0 ! .. into a float register fsqrtd %f0, %f2 ! .... have the fpu perform the operation stx %fsr, [%l2] ! get the fsr value ldx [%l2], %i0 ret restore SET_SIZE(wsqrt_dp) #endif /* * --------------------------------------------------------------------- * Chaining test. * --------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ unsigned long chain_sp(int arg1) { return (0); } #else .section ".data" .align 8 .Lchsp: .word 0 .Lchsp1: .word 0 ENTRY_NP(chain_sp) save %sp, -SA(MINFRAME), %sp setn .Lchsp,%l6, %l0 setn .Lchsp1,%l6, %l1 st %i0, [%l0] ! store the value ld [%l0], %f0 fitos %f0, %f2 ! convert integer into single fmovs %f2, %f0 ! f0 has the same value x fadds %f0, %f2, %f4 ! f4 will have 2x fsubs %f4, %f0, %f6 ! f6 will have x fmuls %f6, %f4, %f8 ! f8 will have (2x * x) fdivs %f8, %f4, %f10 ! f10 will have (2x * x) / 2x = x fstoi %f10, %f12 st %f12, [%l1] ld [%l1], %i0 ret restore SET_SIZE(chain_sp) #endif #ifdef __lint /*ARGSUSED*/ unsigned long chain_dp(int arg1) { return (0); } #else .section ".data" .align 8 .Lchdp: .word 0 .Lchdp1: .word 0 ENTRY_NP(chain_dp) save %sp, -SA(MINFRAME), %sp setn .Lchdp,%l6, %l0 setn .Lchdp1,%l6, %l1 st %i0, [%l0] ! store the value ld [%l0], %f0 fitod %f0, %f2 ! convert integer into double fmovs %f2, %f0 ! f0 has the same value x faddd %f0, %f2, %f4 ! f4 will have 2x fsubd %f4, %f0, %f6 ! f6 will have x fmuld %f6, %f4, %f8 ! f8 will have (2x * x) fdivd %f8, %f4, %f10 ! f10 will have (2x * x) / 2x = x fdtoi %f10, %f12 st %f12, [%l1] ld [%l1], %i0 ret restore SET_SIZE(chain_dp) #endif /* * -------------------------------------------------------------------------- * Name: Initialize all SP Registers * Function: Loads the callers value into all SP floating point registers. * Calling: in0 = Value * Returns: All float register = Value * Convention: init_regs(val); * Method: Copys the user value into each fp reg in sequence. * -------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ void init_regs(uint32_t arg1) { } #else .section ".data" .align 8 .Lclrg: .skip 8 ENTRY_NP(init_regs) save %sp, -SA(MINFRAME), %sp ! save the registers, stack setn .Lclrg,%l6,%l0 ! load the address of temp2 in local0 st %i0, [%l0] ! load the value in temp2 via local0 ld [%l0], %f0 ! .. load the value ld [%l0], %f1 ! .. load the value ld [%l0], %f2 ! .. load the value ld [%l0], %f3 ! .. load the value ld [%l0], %f4 ! .. load the value ld [%l0], %f5 ! .. load the value ld [%l0], %f6 ! .. load the value ld [%l0], %f7 ! .. load the value ld [%l0], %f8 ! .. load the value ld [%l0], %f9 ! .. load the value ld [%l0], %f10 ! .. load the value ld [%l0], %f11 ! .. load the value ld [%l0], %f12 ! .. load the value ld [%l0], %f13 ! .. load the value ld [%l0], %f14 ! .. load the value ld [%l0], %f15 ! .. load the value ld [%l0], %f16 ! .. load the value ld [%l0], %f17 ! .. load the value ld [%l0], %f18 ! .. load the value ld [%l0], %f19 ! .. load the value ld [%l0], %f20 ! .. load the value ld [%l0], %f21 ! .. load the value ld [%l0], %f22 ! .. load the value ld [%l0], %f23 ! .. load the value ld [%l0], %f24 ! .. load the value ld [%l0], %f25 ! .. load the value ld [%l0], %f26 ! .. load the value ld [%l0], %f27 ! .. load the value ld [%l0], %f28 ! .. load the value ld [%l0], %f29 ! .. load the value ld [%l0], %f30 ! .. load the value ld [%l0], %f31 ! .. load the value ret restore SET_SIZE(init_regs) #endif /* * Name: Initialize all double precision Registers * Function: Loads the callers value into all floating point registers. * Calling: in0 = Value * Returns: All float register = Value * Convention: init_regs_dp(val); * Method: Copys the user value into each fp reg in sequence. * -------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ void init_regs_dp(uint64_t arg1) { } #else .section ".data" .align 8 .Lclrg_dp: .skip 16 ENTRY_NP(init_regs_dp) save %sp, -SA(MINFRAME), %sp ! save the registers, stack setx .Lclrg_dp,%l6,%l0 ! load the address of temp2 in local0 stx %i0, [%l0] ! load the value in temp2 via local0 ldd [%l0], %f0 ! .. load the value ldd [%l0], %f2 ! .. load the value ldd [%l0], %f4 ! .. load the value ldd [%l0], %f6 ! .. load the value ldd [%l0], %f8 ! .. load the value ldd [%l0], %f10 ! .. load the value ldd [%l0], %f12 ! .. load the value ldd [%l0], %f14 ! .. load the value ldd [%l0], %f16 ! .. load the value ldd [%l0], %f18 ! .. load the value ldd [%l0], %f20 ! .. load the value ldd [%l0], %f22 ! .. load the value ldd [%l0], %f24 ! .. load the value ldd [%l0], %f26 ! .. load the value ldd [%l0], %f28 ! .. load the value ldd [%l0], %f30 ! .. load the value ldd [%l0], %f32 ! .. load the value ldd [%l0], %f34 ! .. load the value ldd [%l0], %f36 ! .. load the value ldd [%l0], %f38 ! .. load the value ldd [%l0], %f40 ! .. load the value ldd [%l0], %f42 ! .. load the value ldd [%l0], %f44 ! .. load the value ldd [%l0], %f46 ! .. load the value ldd [%l0], %f48 ! .. load the value ldd [%l0], %f50 ! .. load the value ldd [%l0], %f52 ! .. load the value ldd [%l0], %f54 ! .. load the value ldd [%l0], %f56 ! .. load the value ldd [%l0], %f58 ! .. load the value ldd [%l0], %f60 ! .. load the value ldd [%l0], %f62 ! .. load the value ret restore SET_SIZE(init_regs_dp) #endif /* * Name: * Function: * Calling: * Returns: * Convention: * -------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint32_t register_test(int arg1, uint32_t arg2) { return (0); } #else .section ".data" .align 4 .Lrgtst1: .skip 4 .Lrgtst2: .skip 4 ENTRY_NP(register_test) save %sp, -SA(MINFRAME), %sp setn .Lrgtst1,%l6,%l1 setn .Lrgtst2,%l6,%l2 setn regTable, %l6, %o0 mulx %i0, 12, %o1 ! Table entries are 12 bytes each. ! Jump to the appropriate set of instructions jmp %o0+%o1 st %i1, [%l1] ! save the pattern to be written ! If the number of instructions in this macro are changed, ! please ensure that the second operand for the mulx above ! is also updated. We can calculate this during run-time but ! that will mean extra instructions and time. #define TEST_REG(reg_num) \ ld [%l1], %f/**/reg_num; \ ba %ncc, reg_done; \ st %f/**/reg_num, [%l2] regTable : TEST_REG(0) TEST_REG(1) TEST_REG(2) TEST_REG(3) TEST_REG(4) TEST_REG(5) TEST_REG(6) TEST_REG(7) TEST_REG(8) TEST_REG(9) TEST_REG(10) TEST_REG(11) TEST_REG(12) TEST_REG(13) TEST_REG(14) TEST_REG(15) TEST_REG(16) TEST_REG(17) TEST_REG(18) TEST_REG(19) TEST_REG(20) TEST_REG(21) TEST_REG(22) TEST_REG(23) TEST_REG(24) TEST_REG(25) TEST_REG(26) TEST_REG(27) TEST_REG(28) TEST_REG(29) TEST_REG(30) ! No need for a branch here as this the last entry in ! the table and the label is will be reached by falling ! through. ld [%l1], %f31 st %f31, [%l2] reg_done: ld [%l2], %i0 ret restore SET_SIZE(register_test) #endif /* * Name: * Function: * Calling: * Returns: * Convention: * -------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ uint64_t register_test_dp(int arg1, uint64_t arg2) { return (0); } #else .section ".data" .align 8 .Lrgtst1_dp: .skip 8 .Lrgtst2_dp: .skip 8 ENTRY_NP(register_test_dp) save %sp, -SA(MINFRAME), %sp setx .Lrgtst1_dp,%l6,%l1 setx .Lrgtst2_dp,%l6,%l2 setn regTable_dp, %l6, %o0 mulx %i0, 6, %o1 ! Registers are 64-bit and hence the ! register numbers given will be even. ! Each table entry is 12 bytes. ! Multiplying the even register number ! by 6 will give the correct offset. ! Jump to the appropriate set of instructions jmp %o0+%o1 stx %i1, [%l1] !save the pattern to be written ! If the number of instructions in this macro are changed, ! please ensure that the second operand for the mulx above ! is also updated. We can calculate this during run-time but ! that will mean extra instructions and time. #define TEST_REG_DP(reg_num) \ ldd [%l1], %f/**/reg_num; \ ba %ncc, reg_done_dp; \ std %f/**/reg_num, [%l2] regTable_dp : TEST_REG_DP(0) TEST_REG_DP(2) TEST_REG_DP(4) TEST_REG_DP(6) TEST_REG_DP(8) TEST_REG_DP(10) TEST_REG_DP(12) TEST_REG_DP(14) TEST_REG_DP(16) TEST_REG_DP(18) TEST_REG_DP(20) TEST_REG_DP(22) TEST_REG_DP(24) TEST_REG_DP(26) TEST_REG_DP(28) TEST_REG_DP(30) TEST_REG_DP(32) TEST_REG_DP(34) TEST_REG_DP(36) TEST_REG_DP(38) TEST_REG_DP(40) TEST_REG_DP(42) TEST_REG_DP(44) TEST_REG_DP(46) TEST_REG_DP(48) TEST_REG_DP(50) TEST_REG_DP(52) TEST_REG_DP(54) TEST_REG_DP(56) TEST_REG_DP(58) TEST_REG_DP(60) ! No need for a branch here as this the last entry in ! the table and the label is will be reached by falling ! through. ldd [%l1], %f62 std %f62, [%l2] reg_done_dp: ldx [%l2], %i0 ret restore SET_SIZE(register_test_dp) #endif /* * ------------------------------------------------------------------------ * Name: Move Registers * Function: Move a value thru the float registers * Calling: in0 = value * Returns: in0 = result * Convention: if (result != move_regs(value)) * error(result-value); * -------------------------------------------------------------------------- */ #ifdef __lint /*ARGSUSED*/ unsigned long move_regs(unsigned long arg1) { return (0); } #else .section ".data" .align 4 .Lmvrg: .skip 4 .Lmvrg1: .skip 4 ENTRY_NP(move_regs) save %sp, -SA(MINFRAME), %sp ! save the registers, stack setn .Lmvrg1,%l6,%l0 ! get the address to temp2 setn .Lmvrg,%l6,%l1 ! .. and temp st %i0, [%l0] ! get the callers value ld [%l0], %f0 ! .. into a float register fmovs %f0, %f1 ! copy from 1 register to the next fmovs %f1, %f2 ! .. to the next fmovs %f2, %f3 ! .. to the next fmovs %f3, %f4 ! .. to the next fmovs %f4, %f5 ! .. to the next fmovs %f5, %f6 ! .. to the next fmovs %f6, %f7 ! .. to the next fmovs %f7, %f8 ! .. to the next fmovs %f8, %f9 ! .. to the next fmovs %f9, %f10 ! .. to the next fmovs %f10, %f11 ! .. to the next fmovs %f11, %f12 ! .. to the next fmovs %f12, %f13 ! .. to the next fmovs %f13, %f14 ! .. to the next fmovs %f14, %f15 ! .. to the next fmovs %f15, %f16 ! .. to the next fmovs %f16, %f17 ! .. to the next fmovs %f17, %f18 ! .. to the next fmovs %f18, %f19 ! .. to the next fmovs %f19, %f20 ! .. to the next fmovs %f20, %f21 ! .. to the next fmovs %f21, %f22 ! .. to the next fmovs %f22, %f23 ! .. to the next fmovs %f23, %f24 ! .. to the next fmovs %f24, %f25 ! .. to the next fmovs %f25, %f26 ! .. to the next fmovs %f26, %f27 ! .. to the next fmovs %f27, %f28 ! .. to the next fmovs %f28, %f29 ! .. to the next fmovs %f29, %f30 ! .. to the next fmovs %f30, %f31 ! .. to the next st %f31, [%l1] ! .... save the result ld [%l1], %i0 ! .. and return it to the caller ret restore SET_SIZE(move_regs) #endif /* * ------------------------------------------------------------------------ * Name: * Function: * Calling: * Returns: * Convention: * -------------------------------------------------------------------------- * * The following routine checks the branching is done accordingly * to the ficc bits. * input %i0 = 0 = branch unordered * 1 = branch greater * 2 = branch unordered or greater * 3 = branch less * 4 = branch unordered or less * 5 = branch less or greater * 6 = branch not equal * 7 = branch equal * 8 = branch unordered or equal * . 9 = branch greater or equal * 10 = branch branch unordered or greater or equal * 11 = branch less or equal * 12 = branch unordered or or less or equal * 13 = branch ordered * 14 = branch always * 15 = branch never * * ouput : %i0 = 0 = good * = 1 = error */ #ifdef __lint /*ARGSUSED*/ unsigned long branches(unsigned long arg1, unsigned long arg2, unsigned long arg3) { return (0); } #else .section ".data" .align 8 .Lbr: .skip 8 .Lbr1: .skip 8 ENTRY_NP(branches) save %sp, -SA(MINFRAME), %sp ! save the registers, stacck setn .Lbr1,%l6,%l1 setn .Lbr,%l6,%l2 st %i1, [%l1] st %i2, [%l2] ld [%l1], %f0 ld [%l2], %f2 setn brn_0, %l6, %o0 mulx %i0, 12, %o1 jmp %o0+%o1 fcmps %fcc0, %f0, %f2 ! compare the values to get ficc ! ! branch unordered brn_0: fbu,a %fcc0, br_good nop ba,a %ncc, br_error ! branch greater brn_1: fbg,a %fcc0, br_good nop ba,a %ncc, br_error ! branch unordered or greater brn_2: fbug,a %fcc0, br_good nop ba,a %ncc, br_error ! branch less brn_3: fbl,a %fcc0, br_good nop ba,a %ncc, br_error ! branch unorderd or less brn_4: fbul,a %fcc0, br_good nop ba,a %ncc, br_error ! branch less or greater brn_5: fblg,a %fcc0, br_good nop ba,a %ncc, br_error ! branch not equal brn_6: fbne,a %fcc0, br_good nop ba,a %ncc, br_error ! branch equal brn_7: fbe,a %fcc0, br_good nop ba,a %ncc, br_error ! branch unordered or equal brn_8: fbue,a %fcc0, br_good nop ba,a %ncc, br_error ! branch greater or equal brn_9: fbge,a %fcc0, br_good nop ba,a %ncc, br_error ! branch unordered or greater or equal brn_10: fbuge,a %fcc0, br_good nop ba,a %ncc, br_error ! branch less or equal brn_11: fble,a %fcc0, br_good nop ba,a %ncc, br_error ! branch unordered or less or equal brn_12: fbule,a %fcc0, br_good nop ba,a %ncc, br_error ! branch ordered brn_13: fbo,a %fcc0, br_good nop ba,a %ncc, br_error ! branch always brn_14: fba,a %fcc0, br_good nop ba,a %ncc, br_error ! branch never brn_15: fbn,a %fcc0, br_error nop br_good: mov %g0, %i0 ! Branch worked as expected ret restore br_error: mov 0xff, %i0 ! set the flag that it is error ret restore SET_SIZE(branches) #endif /* * void read_fpreg(pf, n) * FPU_REGS_TYPE *pf; Old freg value. * unsigned n; Want to read register n. * * { * *pf = %f[n]; * } */ #ifdef __lint /*ARGSUSED*/ void read_fpreg(unsigned int *arg1, int arg2) { } #else ENTRY_NP(read_fpreg) save %sp, -SA(MINFRAME), %sp mulx %i1, 12, %i1 ! Table entries are 12 bytes each. setn stable, %l1, %g1 ! g1 gets base of table. jmp %g1 + %i1 ! Jump into table nop ! Can't follow CTI by CTI. #define STOREFP(n) st %f/**/n, [%i0]; ret; restore stable: STOREFP(0) STOREFP(1) STOREFP(2) STOREFP(3) STOREFP(4) STOREFP(5) STOREFP(6) STOREFP(7) STOREFP(8) STOREFP(9) STOREFP(10) STOREFP(11) STOREFP(12) STOREFP(13) STOREFP(14) STOREFP(15) STOREFP(16) STOREFP(17) STOREFP(18) STOREFP(19) STOREFP(20) STOREFP(21) STOREFP(22) STOREFP(23) STOREFP(24) STOREFP(25) STOREFP(26) STOREFP(27) STOREFP(28) STOREFP(29) STOREFP(30) STOREFP(31) SET_SIZE(read_fpreg) #endif #ifdef __lint /*ARGSUSED*/ void read_fpreg_dp(unsigned long *arg1, int arg2) { return; } #else ENTRY_NP(read_fpreg_dp) save %sp, -SA(MINFRAME), %sp mulx %i1, 6, %i1 ! Table entries are 12 bytes each. ! But o1 will have even numbered ! index setn stable_dp, %l0, %g1 ! g1 gets base of table. jmp %g1 + %i1 ! Jump into table nop ! Can't follow CTI by CTI. #define STOREFP_DP(n) std %f/**/n, [%i0]; ret; restore stable_dp: STOREFP_DP(0) STOREFP_DP(2) STOREFP_DP(4) STOREFP_DP(6) STOREFP_DP(8) STOREFP_DP(10) STOREFP_DP(12) STOREFP_DP(14) STOREFP_DP(16) STOREFP_DP(18) STOREFP_DP(20) STOREFP_DP(22) STOREFP_DP(24) STOREFP_DP(26) STOREFP_DP(28) STOREFP_DP(30) STOREFP_DP(32) STOREFP_DP(34) STOREFP_DP(36) STOREFP_DP(38) STOREFP_DP(40) STOREFP_DP(42) STOREFP_DP(44) STOREFP_DP(46) STOREFP_DP(48) STOREFP_DP(50) STOREFP_DP(52) STOREFP_DP(54) STOREFP_DP(56) STOREFP_DP(58) STOREFP_DP(60) STOREFP_DP(62) SET_SIZE(read_fpreg_dp) #endif /* * void * write_fpreg(pf, n) * FPU_REGS_TYPE *pf; New freg value. * unsigned n; Want to read register n. * * { * %f[n] = *pf; * } */ #ifdef __lint #else ENTRY_NP(write_fpreg) sll %o1, 3, %o1 ! Table entries are 8 bytes each. setn ltable, %l0, %g1 ! g1 gets base of table. jmp %g1 + %o1 ! Jump into table nop ! Can't follow CTI by CTI. #define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n ltable: LOADFP(0) LOADFP(1) LOADFP(2) LOADFP(3) LOADFP(4) LOADFP(5) LOADFP(6) LOADFP(7) LOADFP(8) LOADFP(9) LOADFP(10) LOADFP(11) LOADFP(12) LOADFP(13) LOADFP(14) LOADFP(15) LOADFP(16) LOADFP(17) LOADFP(18) LOADFP(19) LOADFP(20) LOADFP(21) LOADFP(22) LOADFP(23) LOADFP(24) LOADFP(25) LOADFP(26) LOADFP(27) LOADFP(28) LOADFP(29) LOADFP(30) LOADFP(31) SET_SIZE(write_fpreg) #endif