1 /*---------------------------------------------------------------------------*
2 Project: floating point exception demo
3 File: fpe.c
4
5 Copyright 2002 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: fpe.c,v $
14 Revision 1.2 02/20/2006 04:13:11 mitu
15 changed include path from dolphin/ to revolution/.
16
17 Revision 1.1 01/13/2006 11:24:13 hiratsu
18 Initial check in.
19
20
21 6 9/02/02 9:04 Shiki
22 Modified not to use variables that are declared in SN <math.h>.
23
24 5 8/29/02 13:54 Shiki
25 Added #ifdef __MWERKS__ for __frsqrte().
26
27 4 8/26/02 22:31:00 Shiki
28 Added test using __OSFpscrEnableBits.
29
30 3 8/22/02 17:46:00 Shiki
31 Fixed Func().
32
33 2 8/20/02 09:32:00 Shiki
34 Clean up.
35
36 1 8/19/02 21:57 Shiki
37 Initial check-in.
38 $NoKeywords: $
39 *---------------------------------------------------------------------------*/
40
41 #include <math.h>
42 #include <revolution/os.h>
43 #include <revolution/base/PPCArch.h>
44
45 #define FPSCR_VOUZXE (FPSCR_XE | FPSCR_ZE | FPSCR_UE | FPSCR_OE | FPSCR_VE)
46 #define FPSCR_VXALL (FPSCR_VXCVI | FPSCR_VXSQRT | FPSCR_VXSOFT | \
47 FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | \
48 FPSCR_VXIDI | FPSCR_VXISI | FPSCR_VXSNAN)
49
50 #ifdef __MWERKS__
51 #pragma global_optimizer off
52 #endif
53
54 static OSThread ThreadA;
55 static u8 ThreadStackA[8192];
56 static OSThread ThreadB;
57 static u8 ThreadStackB[8192];
58
59 f32 Zero; // 0.0f;
60 f32 LargeNum; // 1.0e30f;
61 f32 SmallNum; // 1.0e-30f;
62 f32 Nan; // Zero / Zero;
63 f32 F; // 1.1f;
64 f32 Inf; // LargeNum * LargeNum;
65 f32 Neg; // -1.0f;
66 f32 Snan; // Signaling NaN
67
FloatingPointErrorHandler(OSError error,OSContext * context,u32 dsisr,u32 dar)68 static void FloatingPointErrorHandler(OSError error, OSContext* context, u32 dsisr, u32 dar)
69 {
70 #pragma unused(error, dsisr, dar)
71 u32 fpscr;
72
73 // Mask out FPSCR_*X bit of no interest
74 fpscr = context->fpscr;
75 fpscr &= ((fpscr & FPSCR_VOUZXE) << (FPSCR_VE_BIT - FPSCR_VX_BIT)) | FPSCR_VXALL;
76
77 if (fpscr & FPSCR_VX)
78 {
79 OSReport("FPE: Invalid operation: ");
80 if (fpscr & FPSCR_VXSNAN)
81 {
82 OSReport("SNaN\n");
83 }
84 if (fpscr & FPSCR_VXISI)
85 {
86 OSReport("Infinity - Infinity\n");
87 }
88 if (fpscr & FPSCR_VXIDI)
89 {
90 OSReport("Infinity / Infinity\n");
91 }
92 if (fpscr & FPSCR_VXZDZ)
93 {
94 OSReport("0 / 0\n");
95 }
96 if (fpscr & FPSCR_VXIMZ)
97 {
98 OSReport("Infinity * 0\n");
99 }
100 if (fpscr & FPSCR_VXVC)
101 {
102 OSReport("Invalid compare\n");
103 }
104 if (fpscr & FPSCR_VXSOFT)
105 {
106 OSReport("Software request\n");
107 }
108 if (fpscr & FPSCR_VXSQRT)
109 {
110 OSReport("Invalid square root\n");
111 }
112 if (fpscr & FPSCR_VXCVI)
113 {
114 OSReport("Invalid integer convert\n");
115 }
116 }
117 if (fpscr & FPSCR_OX)
118 {
119 OSReport("FPE: Overflow\n");
120 }
121 if (fpscr & FPSCR_UX)
122 {
123 OSReport("FPE: Underflow\n");
124 }
125 if (fpscr & FPSCR_ZX)
126 {
127 OSReport("FPE: Zero division\n");
128 }
129 if (fpscr & FPSCR_XX)
130 {
131 OSReport("FPE: Inexact result\n");
132 }
133
134 // Move on to the next instruction anyway upon return
135 context->srr0 += 4;
136 }
137
Func(void * param)138 static void* Func(void* param)
139 {
140 #pragma unused( param )
141
142 OSReport("l: %f\n", 1.0f / Zero); // Zero division
143 return 0;
144 }
145
Test(OSErrorHandler handler)146 static void Test(OSErrorHandler handler)
147 {
148 OSCreateThread(
149 &ThreadA, // pointer to the thread to initialize
150 Func, // pointer to the start routine
151 0, // parameter passed to the start routine
152 ThreadStackA + sizeof ThreadStackA, // initial stack address
153 sizeof ThreadStackA,
154 1, // scheduling priority
155 0); // joinable by default
156
157 OSSetErrorHandler(OS_ERROR_FPE, handler);
158
159 OSCreateThread(
160 &ThreadB, // pointer to the thread to initialize
161 Func, // pointer to the start routine
162 0, // parameter passed to the start routine
163 ThreadStackB + sizeof ThreadStackB, // initial stack address
164 sizeof ThreadStackB,
165 1, // scheduling priority
166 0); // joinable by default
167
168 OSReport("a: %f\n", LargeNum * LargeNum); // overflow
169 OSReport("b: %f\n", SmallNum * SmallNum); // underflow
170 OSReport("c: %f\n", F / Zero); // Zero division
171
172 OSReport("d: %f\n", Inf - Inf); // infinity - infinity
173 OSReport("e: %f\n", Inf / Inf); // infinity / infinity
174 OSReport("f: %f\n", Zero / Zero); // 0 / 0
175 OSReport("g: %f\n", Inf * Zero); // infinity * 0
176 OSReport("h: %f\n", Nan < 0); // invalid compare
177
178 OSReport("i: %f\n", Snan * Zero); // signaling NaN
179
180 #ifdef __MWERKS__
181 OSReport("j: %f\n", __frsqrte(Neg)); // sqrt
182 #else
183 OSReport("j: %f\n", sqrtf(Neg)); // sqrt
184 #endif
185 OSReport("k: %d\n", (int) LargeNum); // invalid cast
186
187 OSResumeThread(&ThreadA); // Zero division by thread A
188 OSResumeThread(&ThreadB); // Zero division by thread B
189 OSJoinThread(&ThreadA, NULL);
190 OSJoinThread(&ThreadB, NULL);
191 }
192
main(void)193 void main(void)
194 {
195 Zero = 0.0f;
196 LargeNum = 1.0e30f;
197 SmallNum = 1.0e-30f;
198 Nan = Zero / Zero;
199 F = 1.1f;
200 Inf = LargeNum * LargeNum;
201 Neg = -1.0f;
202 *(u32*) &Snan = 0xff800001;
203
204 // Run with floating-point error handler
205 Test((OSErrorHandler) FloatingPointErrorHandler);
206 OSReport("\n");
207
208 // Run without floating-point error handler
209 Test((OSErrorHandler) NULL);
210 OSReport("\n");
211
212 // Run with Zero division exception only
213 __OSFpscrEnableBits = FPSCR_ZE;
214 Test((OSErrorHandler) FloatingPointErrorHandler);
215 OSReport("\n");
216
217 OSReport("Done.\n");
218 }
219
220 #ifdef __MWERKS__
221 #pragma global_optimizer reset
222 #endif
223