1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_ContinuationIterator.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. 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 $Rev: 46347 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nn/assert.h>
17 #include <nn/os/os_ContinuationIterator.h>
18
19 namespace nn { namespace os {
20
Initialize(void * pc,uptr sp)21 void Context::Initialize(void *pc, uptr sp)
22 {
23 m_Registers.regs[8] = sp;
24 m_Registers.regs[9] = reinterpret_cast<bit32>(pc);
25 }
26
SwitchImpl(bit32,Registers *,Registers *)27 asm bit32 Context::SwitchImpl(bit32 /* r0 */, Registers* /* from */, Registers* /* to */)
28 {
29 ARM
30
31 stmia r1, {r4-r11,sp,lr}
32 ldmia r2, {r4-r11,sp,pc}
33 }
34
SwitchImpl(bit32,bit32,Registers *,Registers *)35 asm bit32 Context::SwitchImpl(bit32 /* r0 */, bit32 /* r1 */, Registers* /* from */, Registers* /* to */)
36 {
37 ARM
38
39 stmia r2, {r4-r11,sp,lr}
40 ldmia r3, {r4-r11,sp,pc}
41 }
42
SwitchImpl(bit32,Registers *)43 asm void Context::SwitchImpl(bit32 /* r0 */, Registers* /* to */)
44 {
45 ARM
46
47 ldmia r1, {r4-r11,sp,pc}
48 }
49
CallOnOtherStackImpl(bit32,void *,Registers *,uptr)50 asm bit32 Context::CallOnOtherStackImpl(bit32 /* r0: arg0 */, void* /* r1: f */, Registers* /* r2: regs */, uptr /* r3: SP */)
51 {
52 PRESERVE8
53 ARM
54
55 stmia r2, {r4-r11,sp,lr}
56 mov sp, r3 // Move stack
57 mov r4, r2 // r4 = regs save
58 blx r1 // f(arg)
59 ldmia r4, {r4-r11,sp,pc}
60 }
61
Initialize(void * stackBottom)62 void ContinuationIteratorBase::Initialize(void *stackBottom)
63 {
64 bit32 sp = reinterpret_cast<uptr>(stackBottom);
65
66 // Save the context save region on the stack
67 // As a matter of fact, isn't necessary for the main context to be allocated for each task?
68 #define AllocateFromStack(T, sp) reinterpret_cast<T*>((sp) -= sizeof(T))
69 this->m_MainContext = AllocateFromStack(Context, sp);
70 this->m_IteratorContext = AllocateFromStack(Context, sp);
71 #undef AllocateFromStack
72
73 // Create iterator context
74 // Set to start from RunIterator
75 m_IteratorContext->Initialize(reinterpret_cast<void*>(&RunIterator), sp);
76 }
77
RunIterator(ContinuationIteratorBase * p)78 void ContinuationIteratorBase::RunIterator(ContinuationIteratorBase* p)
79 {
80 // Execute with the iterator context
81
82 // Execute user-defined function
83 p->m_Result = p->Run();
84
85 // After the user-defined function finishes executing, switches to the main context
86 // Since the iterator context is no longer necessary, call a function that does not save it
87 // In r0, enter false as the END mark
88 p->m_MainContext->Switch(false);
89
90 // Do not return here
91 NN_TPANIC_("No more element.");
92 }
93
Yield()94 Result ContinuationIteratorBase::Yield()
95 {
96 // Execute with the iterator context
97
98 // Switch to main context
99 // In r0, enter true to instruct to continue
100 // Save iterator context so that it can return
101 m_MainContext->SwitchFrom(true, *m_IteratorContext);
102
103 // Since the result is saved in m_Result with the main context, return this with the iterator context
104 //
105 return m_Result;
106 }
107
MoveNext(Result result)108 bool ContinuationIteratorBase::MoveNext(Result result)
109 {
110 // Save Result in m_Result
111 this->m_Result = result;
112
113 // Recover the iterator context with r0 as this
114 // ("this" is used only when passed to RunIterator when first starting)
115 if (m_IteratorContext->SwitchFrom(reinterpret_cast<bit32>(this), *m_MainContext))
116 {
117 // If true is returned, there is still more
118 if (result.IsFailure())
119 {
120 // Even though Failure was returned in the iterator context Yield, it is invalid to return to this context again
121 //
122 NN_TPANIC_("Iterator is already invalid.");
123 }
124 return true;
125 }
126 else
127 {
128 // End iterate
129 return false;
130 }
131 }
132
133 }}
134