1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - GX -
3   File:     fx_cp.c
4 
5   Copyright 2003-2008 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   $Date:: 2008-09-18#$
14   $Rev: 8573 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro/fx/fx_cp.h>
19 #include <nitro/cp/divider.h>
20 #include <nitro/cp/sqrt.h>
21 
22 #define FX_DIV_SHIFT (32 - FX32_SHIFT) // 20
23 #define FX_DIV_1_2   (1 << (FX_DIV_SHIFT - 1))
24 
25 #define FX_SQRT_SHIFT ((32 + FX32_SHIFT) / 2 - FX32_SHIFT)      // 10
26 #define FX_SQRT_1_2   (1 << (FX_SQRT_SHIFT - 1))
27 
28 #define FX_INVSQRT_SHIFT \
29     (FX64C_SHIFT + ((32 + FX32_SHIFT) / 2 - FX32_SHIFT))        // 42
30 #define FX_INVSQRT_1_2   (1LL << (FX_INVSQRT_SHIFT - 1))
31 
32 
33 /*---------------------------------------------------------------------------*
34   Name:         FX_Div
35 
36   Description:  Divides 'numer' by 'denom', and returns the result in fx32
37                 format. This uses the divider.
38 
39   Arguments:    numer        a value in fx32 format
40                 denom        a value in fx32 format
41 
42   Returns:      result in fx32 format
43  *---------------------------------------------------------------------------*/
FX_Div(fx32 numer,fx32 denom)44 fx32 FX_Div(fx32 numer, fx32 denom)
45 {
46     FX_DivAsync(numer, denom);
47     return FX_GetDivResult();
48 }
49 
50 
51 /*---------------------------------------------------------------------------*
52   Name:         FX_DivFx64c
53 
54   Description:  Divides 'numer' by 'denom', and returns the result in fx64c
55                 format. This uses the divider.
56 
57   Arguments:    numer        a value in fx32 format
58                 denom        a value in fx32 format
59 
60   Returns:      result in fx64c format
61  *---------------------------------------------------------------------------*/
FX_DivFx64c(fx32 numer,fx32 denom)62 fx64c FX_DivFx64c(fx32 numer, fx32 denom)
63 {
64     FX_DivAsync(numer, denom);
65     return (fx64c)CP_GetDivResult64();
66 }
67 
68 /*---------------------------------------------------------------------------*
69   Name:         FX_Inv
70 
71   Description:  Returns an inverse number of 'denom'. This uses the divider.
72 
73   Arguments:    denom        a value in fx32 format
74 
75   Returns:      result in fx32 format
76  *---------------------------------------------------------------------------*/
FX_Inv(fx32 denom)77 fx32 FX_Inv(fx32 denom)
78 {
79     FX_InvAsync(denom);
80     return FX_GetDivResult();
81 }
82 
83 
84 /*---------------------------------------------------------------------------*
85   Name:         FX_InvFx64c
86 
87   Description:  Returns an inverse number of 'denom'. This uses the divider.
88 
89   Arguments:    denom        a value in fx32 format
90 
91   Returns:      result in fx64c format
92  *---------------------------------------------------------------------------*/
FX_InvFx64c(fx32 denom)93 fx64c FX_InvFx64c(fx32 denom)
94 {
95     FX_InvAsync(denom);
96     return (fx64c)CP_GetDivResult64();
97 }
98 
99 
100 /*---------------------------------------------------------------------------*
101   Name:         FX_Sqrt
102 
103   Description:  Returns a square root of 'x'. This uses the sqrt unit.
104 
105   Arguments:    x            a value in fx32 format
106 
107   Returns:      result in fx32 format
108  *---------------------------------------------------------------------------*/
FX_Sqrt(fx32 x)109 fx32 FX_Sqrt(fx32 x)
110 {
111     SDK_ASSERT(!CP_IsSqrtBusy());
112     if (x > 0)
113     {
114         CP_SetSqrt64((u64)x << 32);
115         return FX_GetSqrtResult();
116     }
117     else
118     {
119         return 0;
120     }
121 }
122 
123 
124 /*---------------------------------------------------------------------------*
125   Name:         FX_InvSqrt
126 
127   Description:  Returns an inverse of a square root of 'x'. This uses
128                 the divider and the sqrt unit.
129 
130   Arguments:    x            a value in fx32 format
131 
132   Returns:      result in fx32 format
133  *---------------------------------------------------------------------------*/
FX_InvSqrt(fx32 x)134 fx32 FX_InvSqrt(fx32 x)
135 {
136     if (x > 0)
137     {
138         fx64c   inv_x;
139         s64     sqrt_x;
140         s64     tmp;
141 
142         FX_InvAsync(x);
143         FX_SqrtAsync(x);
144 
145         inv_x = FX_GetInvResultFx64c();
146         sqrt_x = CP_GetSqrtResult32();
147         tmp = inv_x * sqrt_x;
148         return (fx32)((tmp + FX_INVSQRT_1_2) >> FX_INVSQRT_SHIFT);
149     }
150     else
151     {
152         return 0;
153     }
154 }
155 
156 
157 /*---------------------------------------------------------------------------*
158   Name:         FX_GetDivResultFx64c
159 
160   Description:  Get the result of division in fx64c format.
161                 This function must be called after FX_DivAsync/FX_DivAsyncImm is executed.
162 
163   Arguments:    none
164 
165   Returns:      the result of division in fx64c format
166  *---------------------------------------------------------------------------*/
FX_GetDivResultFx64c(void)167 fx64c FX_GetDivResultFx64c(void)
168 {
169     return (fx64c)CP_GetDivResult64();
170 }
171 
172 
173 /*---------------------------------------------------------------------------*
174   Name:         FX_GetDivResult
175 
176   Description:  Get the result of division in fx32 format.
177                 This function must be called after FX_DivAsync/FX_DivAsyncImm is executed.
178 
179   Arguments:    none
180 
181   Returns:      the result of division in fx32 format
182  *---------------------------------------------------------------------------*/
FX_GetDivResult(void)183 fx32 FX_GetDivResult(void)
184 {
185     return (fx32)((CP_GetDivResult64() + FX_DIV_1_2) >> FX_DIV_SHIFT);
186 }
187 
188 /*---------------------------------------------------------------------------*
189   Name:         FX_InvAsync
190 
191   Description:  Just the same as FX_DivAsync(FX32_ONE, denom).
192                 This function sets numer and denom onto the divider.
193                 It also sets up the divider DIVMODE 01(64/32)
194 
195   Arguments:    denom     in fx32 format
196 
197   Returns:      none
198  *---------------------------------------------------------------------------*/
FX_InvAsync(fx32 denom)199 void FX_InvAsync(fx32 denom)
200 {
201     SDK_ASSERT(!CP_IsDivBusy());
202     FX_DIVISION_BY_ZERO(FX32_ONE, denom);
203 
204     CP_SetDiv64_32((u64)FX32_ONE << 32, (u32)denom);
205 }
206 
207 
208 // Sqrt
209 /*---------------------------------------------------------------------------*
210   Name:         FX_SqrtAsync
211 
212   Description:  Use a sqrt calculator asynchronously.
213                 This function sets numer onto the calculator.
214                 It also sets up the calculator SQRTMODE 01(64).
215 
216   Arguments:    numer     in fx32 format
217 
218   Returns:      none
219  *---------------------------------------------------------------------------*/
FX_SqrtAsync(fx32 x)220 void FX_SqrtAsync(fx32 x)
221 {
222     SDK_ASSERT(!CP_IsSqrtBusy());
223     if (x > 0)
224     {
225         CP_SetSqrt64((u64)x << 32);
226     }
227     else
228     {
229         CP_SetSqrt64(0);
230     }
231 }
232 
233 
234 /*---------------------------------------------------------------------------*
235   Name:         FX_SqrtAsyncImm
236 
237   Description:  Use a sqrt calculator asynchronously.
238                 This function sets numer onto the calculator.
239                 It assumes that the calculator is in SQRTMODE 01(64).
240 
241   Arguments:    numer     in fx32 format
242 
243   Returns:      none
244  *---------------------------------------------------------------------------*/
FX_SqrtAsyncImm(fx32 x)245 void FX_SqrtAsyncImm(fx32 x)
246 {
247     SDK_ASSERT(!CP_IsSqrtBusy());
248     if (x > 0)
249     {
250         CP_SetSqrtImm64((u64)x << 32);
251     }
252     else
253     {
254         CP_SetSqrtImm64(0);
255     }
256 }
257 
258 
259 /*---------------------------------------------------------------------------*
260   Name:         FX_GetSqrtResult
261 
262   Description:  Get the result of sqrt in fx32 format.
263                 This function must be called after FX_SqrtAsync/FX_SqrtAsyncImm is executed.
264 
265   Arguments:    none
266 
267   Returns:      the result of sqrt in fx32 format
268  *---------------------------------------------------------------------------*/
FX_GetSqrtResult(void)269 fx32 FX_GetSqrtResult(void)
270 {
271     return (fx32)((CP_GetSqrtResult32() + FX_SQRT_1_2) >> FX_SQRT_SHIFT);
272 }
273 
274 
275 // Div
276 /*---------------------------------------------------------------------------*
277   Name:         FX_DivAsync
278 
279   Description:  Use a divider asynchronously.
280                 This function sets numer and denom onto the divider.
281                 It also sets up the divider DIVMODE 01(64/32)
282 
283   Arguments:    numer     in fx32 format
284                 denom     in fx32 format
285 
286   Returns:      none
287  *---------------------------------------------------------------------------*/
FX_DivAsync(fx32 numer,fx32 denom)288 void FX_DivAsync(fx32 numer, fx32 denom)
289 {
290     SDK_ASSERT(!CP_IsDivBusy());
291     FX_DIVISION_BY_ZERO(numer, denom);
292 
293     CP_SetDiv64_32((u64)numer << 32, (u32)denom);
294 }
295 
296 
297 
298 
299 /*---------------------------------------------------------------------------*
300   Name:         FX_DivS32
301 
302   Description:  Divides an integer by an integer, and returns the result
303                 in integer. This uses the divider. Faster than software emulation.
304 
305   Arguments:    numer        a value in s32 format
306                 denom        a value in s32 format
307 
308   Returns:      result in s32 format
309  *---------------------------------------------------------------------------*/
FX_DivS32(s32 a,s32 b)310 s32 FX_DivS32(s32 a, s32 b)
311 {
312     SDK_ASSERT(!CP_IsDivBusy());
313     FX_DIVISION_BY_ZERO(a, b);
314     CP_SetDiv32_32((u32)a, (u32)b);
315     return CP_GetDivResult32();
316 }
317 
318 
319 /*---------------------------------------------------------------------------*
320   Name:         FX_ModS32
321 
322   Description:  Divides an integer by an integer, and returns the remainder
323                 in integer. This uses the divider. Faster than software emulation.
324 
325   Arguments:    numer        a value in s32 format
326                 denom        a value in s32 format
327 
328   Returns:      result in s32 format
329  *---------------------------------------------------------------------------*/
FX_ModS32(s32 a,s32 b)330 s32 FX_ModS32(s32 a, s32 b)
331 {
332     SDK_ASSERT(!CP_IsDivBusy());
333     FX_DIVISION_BY_ZERO(a, b);
334     CP_SetDiv32_32((u32)a, (u32)b);
335     return CP_GetDivRemainder32();
336 }
337