1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
#include "global.h"
#include "vt.h"
vu32 gIrqMgrResetStatus = 0;
volatile OSTime sIrqMgrResetTime = 0;
volatile OSTime gIrqMgrRetraceTime = 0;
u32 sIrqMgrRetraceCount = 0;
#define RETRACE_MSG 666
#define PRE_NMI_MSG 669
#define PRENMI450_MSG 671
#define PRENMI480_MSG 672
#define PRENMI500_MSG 673
#define STATUS_IDLE 0
#define STATUS_PRENMI 1
#define STATUS_NMI 2
void IrqMgr_AddClient(IrqMgr* this, IrqMgrClient* c, OSMesgQueue* msgQ) {
OSIntMask prevInt;
LOG_CHECK_NULL_POINTER("this", this);
LOG_CHECK_NULL_POINTER("c", c);
LOG_CHECK_NULL_POINTER("msgQ", msgQ);
prevInt = osSetIntMask(1);
c->queue = msgQ;
c->prev = this->clients;
this->clients = c;
osSetIntMask(prevInt);
if (this->resetStatus > STATUS_IDLE) {
osSendMesgPtr(c->queue, &this->prenmiMsg, OS_MESG_NOBLOCK);
}
if (this->resetStatus >= STATUS_NMI) {
osSendMesgPtr(c->queue, &this->nmiMsg, OS_MESG_NOBLOCK);
}
}
void IrqMgr_RemoveClient(IrqMgr* this, IrqMgrClient* c) {
IrqMgrClient* iter = this->clients;
IrqMgrClient* lastIter = NULL;
OSIntMask prevInt;
LOG_CHECK_NULL_POINTER("this", this);
LOG_CHECK_NULL_POINTER("c", c);
prevInt = osSetIntMask(1);
while (iter != NULL) {
if (iter == c) {
if (lastIter) {
lastIter->prev = c->prev;
} else {
this->clients = c->prev;
}
break;
}
lastIter = iter;
iter = iter->prev;
}
osSetIntMask(prevInt);
}
void IrqMgr_SendMesgForClient(IrqMgr* this, OSMesg msg) {
IrqMgrClient* iter = this->clients;
while (iter != NULL) {
if (iter->queue->validCount >= iter->queue->msgCount) {
// "irqmgr_SendMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
osSyncPrintf(
VT_COL(RED, WHITE) "irqmgr_SendMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
iter->queue, iter->queue->validCount);
} else {
osSendMesg(iter->queue, msg, OS_MESG_NOBLOCK);
}
iter = iter->prev;
}
}
void IrqMgr_JamMesgForClient(IrqMgr* this, OSMesg msg) {
IrqMgrClient* iter = this->clients;
while (iter != NULL) {
if (iter->queue->validCount >= iter->queue->msgCount) {
// "irqmgr_JamMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
osSyncPrintf(
VT_COL(RED, WHITE) "irqmgr_JamMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
iter->queue, iter->queue->validCount);
} else {
// mistake? the function's name suggests it would use osJamMesg
osSendMesg(iter->queue, msg, OS_MESG_NOBLOCK);
}
iter = iter->prev;
}
}
void IrqMgr_HandlePreNMI(IrqMgr* this) {
u64 temp = STATUS_PRENMI; // required to match
gIrqMgrResetStatus = temp;
this->resetStatus = STATUS_PRENMI;
sIrqMgrResetTime = this->resetTime = osGetTime();
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(450000), 0ull, &this->queue, OS_MESG_32(PRENMI450_MSG));
IrqMgr_JamMesgForClient(this, OS_MESG_PTR(&this->prenmiMsg));
}
void IrqMgr_CheckStack() {
osSyncPrintf("irqmgr.c: PRENMIから0.5秒経過\n"); // "0.5 seconds after PRENMI"
if (StackCheck_Check(NULL) == 0) {
osSyncPrintf("スタックは大丈夫みたいです\n"); // "The stack looks ok"
} else {
osSyncPrintf("%c", 7);
osSyncPrintf(VT_FGCOL(RED));
// "Stack overflow or dangerous"
osSyncPrintf("スタックがオーバーフローしたか危険な状態です\n");
// "Increase stack size early or don't consume stack"
osSyncPrintf("早々にスタックサイズを増やすか、スタックを消費しないようにしてください\n");
osSyncPrintf(VT_RST);
}
}
void IrqMgr_HandlePRENMI450(IrqMgr* this) {
u64 temp = STATUS_NMI; // required to match
gIrqMgrResetStatus = temp;
this->resetStatus = STATUS_NMI;
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(30000), 0ull, &this->queue, OS_MESG_32(PRENMI480_MSG));
IrqMgr_SendMesgForClient(this, OS_MESG_PTR(&this->nmiMsg));
}
void IrqMgr_HandlePRENMI480(IrqMgr* this) {
u32 ret;
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(20000), 0ull, &this->queue, OS_MESG_32(PRENMI500_MSG));
ret = osAfterPreNMI();
if (ret) {
// "osAfterPreNMI returned %d !?"
osSyncPrintf("osAfterPreNMIが %d を返しました!?\n", ret);
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(1000), 0ull, &this->queue, OS_MESG_32(PRENMI480_MSG));
}
}
void IrqMgr_HandlePRENMI500(IrqMgr* this) {
IrqMgr_CheckStack();
}
void IrqMgr_HandleRetrace(IrqMgr* this) {
if (gIrqMgrRetraceTime == 0ull) {
if (this->retraceTime == 0) {
this->retraceTime = osGetTime();
} else {
gIrqMgrRetraceTime = osGetTime() - this->retraceTime;
}
}
sIrqMgrRetraceCount++;
IrqMgr_SendMesgForClient(this, OS_MESG_PTR(&this->retraceMsg));
}
void IrqMgr_ThreadEntry(void* arg0) {
OSMesg msg;
IrqMgr* this = (IrqMgr*)arg0;
u8 exit;
msg.data32 = 0;
osSyncPrintf("IRQマネージャスレッド実行開始\n"); // "Start IRQ manager thread execution"
exit = false;
while (!exit) {
osRecvMesg(&this->queue, &msg, OS_MESG_BLOCK);
switch (msg.data32) {
case RETRACE_MSG:
IrqMgr_HandleRetrace(this);
break;
case PRE_NMI_MSG:
osSyncPrintf("PRE_NMI_MSG\n");
// "Scheduler: Receives PRE_NMI message"
osSyncPrintf("スケジューラ:PRE_NMIメッセージを受信\n");
IrqMgr_HandlePreNMI(this);
break;
case PRENMI450_MSG:
osSyncPrintf("PRENMI450_MSG\n");
// "Scheduler: Receives PRENMI450 message"
osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n");
IrqMgr_HandlePRENMI450(this);
break;
case PRENMI480_MSG:
osSyncPrintf("PRENMI480_MSG\n");
// "Scheduler: Receives PRENMI480 message"
osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n");
IrqMgr_HandlePRENMI480(this);
break;
case PRENMI500_MSG:
osSyncPrintf("PRENMI500_MSG\n");
// "Scheduler: Receives PRENMI500 message"
osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n");
exit = true;
IrqMgr_HandlePRENMI500(this);
break;
default:
// "Unexpected message received"
osSyncPrintf("irqmgr.c:予期しないメッセージを受け取りました(%08x)\n", msg);
break;
}
}
osSyncPrintf("IRQマネージャスレッド実行終了\n"); // "End of IRQ manager thread execution"
}
void IrqMgr_Init(IrqMgr* this, void* stack, OSPri pri, u8 retraceCount) {
LOG_CHECK_NULL_POINTER("this", this);
LOG_CHECK_NULL_POINTER("stack", stack);
this->clients = NULL;
this->retraceMsg.type = OS_SC_RETRACE_MSG;
this->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
this->nmiMsg.type = OS_SC_NMI_MSG;
this->resetStatus = STATUS_IDLE;
this->resetTime = 0;
osCreateMesgQueue(&this->queue, this->msgBuf, ARRAY_COUNT(this->msgBuf));
osSetEventMesg(OS_EVENT_PRENMI, &this->queue, OS_MESG_32(PRE_NMI_MSG));
osViSetEvent(&this->queue, OS_MESG_32(RETRACE_MSG), retraceCount);
osCreateThread(&this->thread, 0x13, IrqMgr_ThreadEntry, this, stack, pri);
osStartThread(&this->thread);
}
|