1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - ThreadSafeTest - CP
3   File:     main.c
4 
5   Copyright 2007 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:: 2009-02-06#$
14   $Rev: 9986 $
15   $Author: yosizaki $
16  *---------------------------------------------------------------------------*/
17 
18 //---------------------------------------------------------------------------
19 // Thread-safe test for divider and square root arithmetic unit
20 // HOWTO:
21 // 1. The state of the divider and square root unit are switched when a thread is switched, so it is thread-safe without any special processing.
22 //
23 //
24 // 2. By calling the CP_SaveContext and CP_RestoreContext functions in an interrupt before and after (respectively) using the divider and square root unit, you can restore the state of these two units and use them safely.
25 //
26 //
27 //---------------------------------------------------------------------------
28 
29 #include <nitro.h>
30 
31 
32 /*---------------------------------------------------------------------------*
33     Prototype Declarations
34  *---------------------------------------------------------------------------*/
35 static void VBlankIntr(void);
36 void    proc1(void *arg);
37 void    proc2(void *arg);
38 
39 
40 /*---------------------------------------------------------------------------*
41     Constant Definitions
42  *---------------------------------------------------------------------------*/
43 #define A1  0x40F337
44 #define B1  0x197
45 #define A2  0x7843276F4561
46 #define B2  0x3208F1
47 
48 
49 #define     THREAD1_PRIO    10
50 #define     THREAD2_PRIO    11
51 
52 #define STACK_SIZE  1024
53 
54 
55 /*---------------------------------------------------------------------------*
56     Internal Variable Definitions
57  *---------------------------------------------------------------------------*/
58 u64     stack1[STACK_SIZE / sizeof(u64)];
59 u64     stack2[STACK_SIZE / sizeof(u64)];
60 
61 OSThread thread1;
62 OSThread thread2;
63 
64 
65 //---------------------------------------------------------------------------
66 // Main Loop
67 //---------------------------------------------------------------------------
NitroMain(void)68 void NitroMain(void)
69 {
70     u64     a;
71     u32     b;
72     u64     c;
73 
74     //---------------------------------------------------------------------------
75     //  Initialization
76     //---------------------------------------------------------------------------
77     OS_Init();
78     OS_InitThread();
79     FX_Init();
80 
81     GX_Init();
82     GX_SetPower(GX_POWER_ALL);
83 
84     GX_DispOn();
85 
86     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
87     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
88     (void)OS_EnableIrq();
89 
90     reg_GX_DISPSTAT = 8;
91 
92 
93     OS_Printf("Correct Answer: %x / %x = %x\n", A1, B1, A1 / B1);
94     OS_Printf("Correct Answer: %llx / %x = %llx\n\n", A2, B2, A2 / B2);
95 
96     a = A2;
97     b = B2;
98 
99 
100     // Wait for V-Blank in the middle of calculation
101     CP_SetDiv64_32(a, b);
102     OS_Printf("Main: Start %llx / %x ...\n", a, b);
103 
104     CP_WaitDiv();
105     OS_WaitVBlankIntr();               // Waiting for the end of the V-Blank interrupt
106 
107     c = (u64)CP_GetDivResult64();
108 
109     OS_Printf("Main: Get %llx / %x = %llx\n", a, b, c);
110 
111 
112     // Start thread
113     OS_Printf("----------------------------\n");
114     OS_Printf("Create Thread\n");
115 
116     OS_CreateThread(&thread1, proc1, (void *)0x111, stack1 + STACK_SIZE / sizeof(u64), STACK_SIZE,
117                     THREAD1_PRIO);
118     OS_CreateThread(&thread2, proc2, (void *)0x222, stack2 + STACK_SIZE / sizeof(u64), STACK_SIZE,
119                     THREAD2_PRIO);
120 
121     OS_WakeupThreadDirect(&thread1);
122     OS_WakeupThreadDirect(&thread2);
123 
124     OS_Printf("Idle\n");
125     OS_WakeupThreadDirect(&thread2);
126 
127 
128     // Quit
129     OS_Printf("==== Finish sample.\n");
130     OS_Terminate();
131 
132     while (1)
133     {
134 
135         OS_WaitVBlankIntr();           // Waiting for the end of the V-Blank interrupt
136 
137     }
138 }
139 
140 
141 //---------------------------------------------------------------------------
142 // V-Blank interrupt function:
143 //---------------------------------------------------------------------------
VBlankIntr(void)144 static void VBlankIntr(void)
145 {
146     u32     a, b, c;
147     CPContext context;
148 
149     // Save context of arithmetic unit
150     CP_SaveContext(&context);
151 
152     a = A1;
153     b = B1;
154 
155     CP_SetDiv32_32(a, b);
156     OS_Printf("VBlank: Start %x / %x ...\n", a, b);
157     CP_WaitDiv();
158     c = (u32)CP_GetDivResult32();
159 
160     OS_Printf("VBlank: Get %x / %x = %x\n", a, b, c);
161 
162     // Restore context of arithmetic unit
163     CP_RestoreContext(&context);
164 
165     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
166 
167 
168 }
169 
170 
171 //--------------------------------------------------------------------------------
172 //    proc1
173 //
proc1(void * arg)174 void proc1(void *arg)
175 {
176 #pragma unused(arg)
177     u64     a;
178     u32     b;
179     u64     c;
180 
181     while (1)
182     {
183         OS_Printf("Sleep Thread1\n");
184         OS_SleepThread(NULL);
185         OS_Printf("Wake Thread1 (Priority %d)\n", THREAD1_PRIO);
186 
187         a = A2;
188         b = B2;
189 
190         CP_SetDiv64_32(a, b);
191         OS_Printf("Thread1: Start %llx / %x ...\n", a, b);
192         CP_WaitDiv();
193         c = (u64)CP_GetDivResult64();
194 
195         OS_Printf("Thread1: Get %llx / %x = %x\n", a, b, c);
196     }
197 }
198 
199 //--------------------------------------------------------------------------------
200 //    proc2
201 //
proc2(void * arg)202 void proc2(void *arg)
203 {
204 #pragma unused(arg)
205     u32     a, b, c;
206 
207     while (1)
208     {
209         OS_Printf("Sleep Thread2\n");
210         OS_SleepThread(NULL);
211         OS_Printf("WakeThread2: (Priority %d)\n", THREAD2_PRIO);
212 
213         a = A1;
214         b = B1;
215 
216         CP_SetDiv32_32(a, b);
217         OS_Printf("Thread2: Start %x / %x ...\n", a, b);
218         CP_WaitDiv();
219 
220         // Call thread 1 in the middle of calculation
221         OS_WakeupThreadDirect(&thread1);
222         c = (u32)CP_GetDivResult32();
223         OS_Printf("Thread2: Get %x / %x = %x\n", a, b, c);
224     }
225 }
226