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