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