mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-10 19:20:13 +00:00
More documentation for IrqMgr (#1144)
* doc irqmgr * Fix * Format * Review suggestions * Fix * Some more review * Further changes
This commit is contained in:
parent
61b864a89c
commit
93096a45b6
13 changed files with 242 additions and 161 deletions
|
@ -1792,18 +1792,6 @@ void func_800D3178(UnkRumbleStruct* arg0);
|
||||||
void func_800D31A0(void);
|
void func_800D31A0(void);
|
||||||
void func_800D31F0(void);
|
void func_800D31F0(void);
|
||||||
void func_800D3210(void);
|
void func_800D3210(void);
|
||||||
void IrqMgr_AddClient(IrqMgr* this, IrqMgrClient* c, OSMesgQueue* msgQ);
|
|
||||||
void IrqMgr_RemoveClient(IrqMgr* this, IrqMgrClient* c);
|
|
||||||
void IrqMgr_SendMesgForClient(IrqMgr* this, OSMesg msg);
|
|
||||||
void IrqMgr_JamMesgForClient(IrqMgr* this, OSMesg msg);
|
|
||||||
void IrqMgr_HandlePreNMI(IrqMgr* this);
|
|
||||||
void IrqMgr_CheckStack();
|
|
||||||
void IrqMgr_HandlePRENMI450(IrqMgr* this);
|
|
||||||
void IrqMgr_HandlePRENMI480(IrqMgr* this);
|
|
||||||
void IrqMgr_HandlePRENMI500(IrqMgr* this);
|
|
||||||
void IrqMgr_HandleRetrace(IrqMgr* this);
|
|
||||||
void IrqMgr_ThreadEntry(void* arg0);
|
|
||||||
void IrqMgr_Init(IrqMgr* this, void* stack, OSPri pri, u8 retraceCount);
|
|
||||||
void DebugArena_CheckPointer(void* ptr, u32 size, const char* name, const char* action);
|
void DebugArena_CheckPointer(void* ptr, u32 size, const char* name, const char* action);
|
||||||
void* DebugArena_Malloc(u32 size);
|
void* DebugArena_Malloc(u32 size);
|
||||||
void* DebugArena_MallocDebug(u32 size, const char* file, s32 line);
|
void* DebugArena_MallocDebug(u32 size, const char* file, s32 line);
|
||||||
|
|
|
@ -3,6 +3,17 @@
|
||||||
|
|
||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
|
|
||||||
|
#define OS_SC_RETRACE_MSG 1
|
||||||
|
#define OS_SC_DONE_MSG 2
|
||||||
|
#define OS_SC_NMI_MSG 3 // name is made up, 3 is OS_SC_RDP_DONE_MSG in the original sched.c
|
||||||
|
#define OS_SC_PRE_NMI_MSG 4
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IRQ_RESET_STATUS_IDLE,
|
||||||
|
IRQ_RESET_STATUS_PRENMI,
|
||||||
|
IRQ_RESET_STATUS_NMI
|
||||||
|
} IrqResetStatus;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ s16 type;
|
/* 0x00 */ s16 type;
|
||||||
/* 0x02 */ char misc[0x1E];
|
/* 0x02 */ char misc[0x1E];
|
||||||
|
@ -14,8 +25,8 @@ typedef struct IrqMgrClient {
|
||||||
} IrqMgrClient;
|
} IrqMgrClient;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x000 */ OSScMsg retraceMsg; // this apparently got moved from OSSched
|
/* 0x000 */ OSScMsg retraceMsg;
|
||||||
/* 0x020 */ OSScMsg prenmiMsg; // this apparently got moved from OSSched
|
/* 0x020 */ OSScMsg prenmiMsg;
|
||||||
/* 0x040 */ OSScMsg nmiMsg;
|
/* 0x040 */ OSScMsg nmiMsg;
|
||||||
/* 0x060 */ OSMesgQueue queue;
|
/* 0x060 */ OSMesgQueue queue;
|
||||||
/* 0x078 */ OSMesg msgBuf[8];
|
/* 0x078 */ OSMesg msgBuf[8];
|
||||||
|
@ -27,4 +38,9 @@ typedef struct {
|
||||||
/* 0x278 */ OSTime retraceTime;
|
/* 0x278 */ OSTime retraceTime;
|
||||||
} IrqMgr; // size = 0x280
|
} IrqMgr; // size = 0x280
|
||||||
|
|
||||||
|
void IrqMgr_Init(IrqMgr* irqMgr, void* stack, OSPri pri, u8 retraceCount);
|
||||||
|
|
||||||
|
void IrqMgr_AddClient(IrqMgr* irqMgr, IrqMgrClient* client, OSMesgQueue* msgQ);
|
||||||
|
void IrqMgr_RemoveClient(IrqMgr* irqMgr, IrqMgrClient* client);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define OS_PHYSICAL_TO_K0(x) (void*)(((u32)(x)+0x80000000))
|
#define OS_PHYSICAL_TO_K0(x) (void*)(((u32)(x)+0x80000000))
|
||||||
#define OS_PHYSICAL_TO_K1(x) (void*)(((u32)(x)+0xA0000000))
|
#define OS_PHYSICAL_TO_K1(x) (void*)(((u32)(x)+0xA0000000))
|
||||||
|
|
||||||
#define OS_SEC_TO_CYCLES(n) OS_USEC_TO_CYCLES((n) * 1000 * 1000)
|
#define OS_MSEC_TO_CYCLES(n) OS_USEC_TO_CYCLES((n) * 1000)
|
||||||
|
#define OS_SEC_TO_CYCLES(n) OS_MSEC_TO_CYCLES((n) * 1000)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,4 +36,11 @@ typedef struct OSMesgQueue {
|
||||||
/* 0x14 */ OSMesg* msg;
|
/* 0x14 */ OSMesg* msg;
|
||||||
} OSMesgQueue; // size = 0x18
|
} OSMesgQueue; // size = 0x18
|
||||||
|
|
||||||
|
/* Get count of valid messages in queue */
|
||||||
|
#define MQ_GET_COUNT(mq) ((mq)->validCount)
|
||||||
|
|
||||||
|
/* Determine if message queue is empty or full */
|
||||||
|
#define MQ_IS_EMPTY(mq) (MQ_GET_COUNT(mq) == 0)
|
||||||
|
#define MQ_IS_FULL(mq) (MQ_GET_COUNT(mq) >= (mq)->msgCount)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,4 +31,7 @@
|
||||||
#define VT_RST VT_SGR("")
|
#define VT_RST VT_SGR("")
|
||||||
#define VT_CLS VT_ED(2)
|
#define VT_CLS VT_ED(2)
|
||||||
|
|
||||||
|
// ASCII BEL character, plays an alert tone
|
||||||
|
#define BEL '\a'
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1587,11 +1587,6 @@ typedef struct {
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
|
|
||||||
#define OS_SC_RETRACE_MSG 1
|
|
||||||
#define OS_SC_DONE_MSG 2
|
|
||||||
#define OS_SC_NMI_MSG 3 // name is made up, 3 is OS_SC_RDP_DONE_MSG in the original sched.c
|
|
||||||
#define OS_SC_PRE_NMI_MSG 4
|
|
||||||
|
|
||||||
#define OS_SC_DP 0x0001
|
#define OS_SC_DP 0x0001
|
||||||
#define OS_SC_SP 0x0002
|
#define OS_SC_SP 0x0002
|
||||||
#define OS_SC_YIELD 0x0010
|
#define OS_SC_YIELD 0x0010
|
||||||
|
|
|
@ -170,7 +170,7 @@ void DmaMgr_Error(DmaRequest* req, const char* file, const char* errorName, cons
|
||||||
char buff1[80];
|
char buff1[80];
|
||||||
char buff2[80];
|
char buff2[80];
|
||||||
|
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
osSyncPrintf("DMA致命的エラー(%s)\nROM:%X RAM:%X SIZE:%X %s\n",
|
osSyncPrintf("DMA致命的エラー(%s)\nROM:%X RAM:%X SIZE:%X %s\n",
|
||||||
errorDesc != NULL ? errorDesc : (errorName != NULL ? errorName : "???"), vrom, ram, size,
|
errorDesc != NULL ? errorDesc : (errorName != NULL ? errorName : "???"), vrom, ram, size,
|
||||||
|
@ -354,7 +354,7 @@ s32 DmaMgr_SendRequestImpl(DmaRequest* req, u32 ram, u32 vrom, u32 size, u32 unk
|
||||||
if (1) {
|
if (1) {
|
||||||
if ((sDmaMgrQueueFullLogged == 0) && (sDmaMgrMsgQueue.validCount >= sDmaMgrMsgQueue.msgCount)) {
|
if ((sDmaMgrQueueFullLogged == 0) && (sDmaMgrMsgQueue.validCount >= sDmaMgrMsgQueue.msgCount)) {
|
||||||
sDmaMgrQueueFullLogged++;
|
sDmaMgrQueueFullLogged++;
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
osSyncPrintf("dmaEntryMsgQが一杯です。キューサイズの再検討をおすすめします。");
|
osSyncPrintf("dmaEntryMsgQが一杯です。キューサイズの再検討をおすすめします。");
|
||||||
LOG_NUM("(sizeof(dmaEntryMsgBufs) / sizeof(dmaEntryMsgBufs[0]))", ARRAY_COUNT(sDmaMgrMsgs),
|
LOG_NUM("(sizeof(dmaEntryMsgBufs) / sizeof(dmaEntryMsgBufs[0]))", ARRAY_COUNT(sDmaMgrMsgs),
|
||||||
|
|
|
@ -346,7 +346,7 @@ void GameState_Realloc(GameState* gameState, size_t size) {
|
||||||
osSyncPrintf("ハイラル一時解放!!\n"); // "Hyrule temporarily released!!"
|
osSyncPrintf("ハイラル一時解放!!\n"); // "Hyrule temporarily released!!"
|
||||||
SystemArena_GetSizes(&systemMaxFree, &systemFree, &systemAlloc);
|
SystemArena_GetSizes(&systemMaxFree, &systemFree, &systemAlloc);
|
||||||
if ((systemMaxFree - 0x10) < size) {
|
if ((systemMaxFree - 0x10) < size) {
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
|
|
||||||
// "Not enough memory. Change the hyral size to the largest possible value"
|
// "Not enough memory. Change the hyral size to the largest possible value"
|
||||||
|
|
|
@ -323,14 +323,14 @@ void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) {
|
||||||
|
|
||||||
if (pool->headMagic != GFXPOOL_HEAD_MAGIC) {
|
if (pool->headMagic != GFXPOOL_HEAD_MAGIC) {
|
||||||
//! @bug (?) : "problem = true;" may be missing
|
//! @bug (?) : "problem = true;" may be missing
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
// "Dynamic area head is destroyed"
|
// "Dynamic area head is destroyed"
|
||||||
osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域先頭が破壊されています\n" VT_RST);
|
osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域先頭が破壊されています\n" VT_RST);
|
||||||
Fault_AddHungupAndCrash("../graph.c", 1070);
|
Fault_AddHungupAndCrash("../graph.c", 1070);
|
||||||
}
|
}
|
||||||
if (pool->tailMagic != GFXPOOL_TAIL_MAGIC) {
|
if (pool->tailMagic != GFXPOOL_TAIL_MAGIC) {
|
||||||
problem = true;
|
problem = true;
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
// "Dynamic region tail is destroyed"
|
// "Dynamic region tail is destroyed"
|
||||||
osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域末尾が破壊されています\n" VT_RST);
|
osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域末尾が破壊されています\n" VT_RST);
|
||||||
Fault_AddHungupAndCrash("../graph.c", 1076);
|
Fault_AddHungupAndCrash("../graph.c", 1076);
|
||||||
|
@ -339,19 +339,19 @@ void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) {
|
||||||
|
|
||||||
if (THGA_IsCrash(&gfxCtx->polyOpa)) {
|
if (THGA_IsCrash(&gfxCtx->polyOpa)) {
|
||||||
problem = true;
|
problem = true;
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
// "Zelda 0 is dead"
|
// "Zelda 0 is dead"
|
||||||
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ0は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ0は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
||||||
}
|
}
|
||||||
if (THGA_IsCrash(&gfxCtx->polyXlu)) {
|
if (THGA_IsCrash(&gfxCtx->polyXlu)) {
|
||||||
problem = true;
|
problem = true;
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
// "Zelda 1 is dead"
|
// "Zelda 1 is dead"
|
||||||
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ1は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ1は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
||||||
}
|
}
|
||||||
if (THGA_IsCrash(&gfxCtx->overlay)) {
|
if (THGA_IsCrash(&gfxCtx->overlay)) {
|
||||||
problem = true;
|
problem = true;
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
// "Zelda 4 is dead"
|
// "Zelda 4 is dead"
|
||||||
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ4は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ4は死んでしまった(graph_alloc is empty)\n" VT_RST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,122 +1,179 @@
|
||||||
|
/**
|
||||||
|
* @file irqmgr.c
|
||||||
|
*
|
||||||
|
* This file implements a manager for forwarding three key system interrupt events to
|
||||||
|
* registered clients. The architecture of this system appears to be derived in part from
|
||||||
|
* the libultra sched module.
|
||||||
|
*
|
||||||
|
* The interrupts the IRQ manager deals with are:
|
||||||
|
* - VI Retrace
|
||||||
|
* This event is sent to the IRQ manager by the OS VI manager which only supports
|
||||||
|
* the forwarding of VI events to a single message queue. The IRQ manager will
|
||||||
|
* forward these events to every registered client. VI retrace events are received
|
||||||
|
* when the Video Interface has reached the start of the vertical blanking interval,
|
||||||
|
* happening at approximately 60Hz on NTSC and 50Hz on PAL. Many threads sit idle
|
||||||
|
* until a VI Retrace event wakes them up, at which point they will perform their
|
||||||
|
* task and then return to idle to await the next retrace.
|
||||||
|
*
|
||||||
|
* - Pre-NMI
|
||||||
|
* This event is sent to the IRQ manager by the OS Interrupt Handler when the reset
|
||||||
|
* button on the N64 control deck is pressed. This event is forwarded to clients to
|
||||||
|
* inform them that a reset will occur in at least 0.5s / 500ms so they may begin any
|
||||||
|
* shutdown procedures.
|
||||||
|
*
|
||||||
|
* - NMI
|
||||||
|
* This event is sent at 450ms into the Pre-NMI phase, informing clients that the
|
||||||
|
* mandatory 0.5s of Pre-NMI is almost over and a reset may be imminent. This event
|
||||||
|
* is not to be confused with the hardware NMI interrupt signalled when the CPU is
|
||||||
|
* to fully reset, as by the time that interrupt is received there is no time left
|
||||||
|
* to do anything.
|
||||||
|
*/
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
|
||||||
vu32 gIrqMgrResetStatus = 0;
|
vu32 gIrqMgrResetStatus = IRQ_RESET_STATUS_IDLE;
|
||||||
volatile OSTime sIrqMgrResetTime = 0;
|
volatile OSTime sIrqMgrResetTime = 0;
|
||||||
volatile OSTime gIrqMgrRetraceTime = 0;
|
volatile OSTime gIrqMgrRetraceTime = 0;
|
||||||
u32 sIrqMgrRetraceCount = 0;
|
u32 sIrqMgrRetraceCount = 0;
|
||||||
|
|
||||||
#define RETRACE_MSG 666
|
// Internal messages
|
||||||
#define PRE_NMI_MSG 669
|
#define IRQ_RETRACE_MSG 666
|
||||||
#define PRENMI450_MSG 671
|
#define IRQ_PRENMI_MSG 669
|
||||||
#define PRENMI480_MSG 672
|
#define IRQ_PRENMI450_MSG 671
|
||||||
#define PRENMI500_MSG 673
|
#define IRQ_PRENMI480_MSG 672
|
||||||
|
#define IRQ_PRENMI500_MSG 673
|
||||||
|
|
||||||
#define STATUS_IDLE 0
|
/**
|
||||||
#define STATUS_PRENMI 1
|
* Registers a client and an associated message queue with the IRQ manager. When an
|
||||||
#define STATUS_NMI 2
|
* interrupt event is received by the IRQ manager, these clients will be notified of
|
||||||
|
* the event.
|
||||||
void IrqMgr_AddClient(IrqMgr* this, IrqMgrClient* c, OSMesgQueue* msgQ) {
|
*
|
||||||
|
* @param irqMgr the IrqMgr instance to register with.
|
||||||
|
* @param client client to register.
|
||||||
|
* @param msgQ message queue to send notifications of interrupts to, associated with the client.
|
||||||
|
*/
|
||||||
|
void IrqMgr_AddClient(IrqMgr* irqMgr, IrqMgrClient* client, OSMesgQueue* msgQ) {
|
||||||
OSIntMask prevInt;
|
OSIntMask prevInt;
|
||||||
|
|
||||||
LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 96);
|
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 96);
|
||||||
LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 97);
|
LogUtils_CheckNullPointer("c", client, "../irqmgr.c", 97);
|
||||||
LogUtils_CheckNullPointer("msgQ", msgQ, "../irqmgr.c", 98);
|
LogUtils_CheckNullPointer("msgQ", msgQ, "../irqmgr.c", 98);
|
||||||
|
|
||||||
prevInt = osSetIntMask(OS_IM_NONE);
|
prevInt = osSetIntMask(OS_IM_NONE);
|
||||||
|
|
||||||
c->queue = msgQ;
|
client->queue = msgQ;
|
||||||
c->prev = this->clients;
|
client->prev = irqMgr->clients;
|
||||||
this->clients = c;
|
irqMgr->clients = client;
|
||||||
|
|
||||||
osSetIntMask(prevInt);
|
osSetIntMask(prevInt);
|
||||||
|
|
||||||
if (this->resetStatus > STATUS_IDLE) {
|
if (irqMgr->resetStatus >= IRQ_RESET_STATUS_PRENMI) {
|
||||||
osSendMesg(c->queue, (OSMesg) & this->prenmiMsg, OS_MESG_NOBLOCK);
|
osSendMesg(client->queue, (OSMesg)&irqMgr->prenmiMsg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->resetStatus >= STATUS_NMI) {
|
if (irqMgr->resetStatus >= IRQ_RESET_STATUS_NMI) {
|
||||||
osSendMesg(c->queue, (OSMesg) & this->nmiMsg, OS_MESG_NOBLOCK);
|
osSendMesg(client->queue, (OSMesg)&irqMgr->nmiMsg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_RemoveClient(IrqMgr* this, IrqMgrClient* c) {
|
void IrqMgr_RemoveClient(IrqMgr* irqMgr, IrqMgrClient* client) {
|
||||||
IrqMgrClient* iter = this->clients;
|
IrqMgrClient* iterClient = irqMgr->clients;
|
||||||
IrqMgrClient* lastIter = NULL;
|
IrqMgrClient* lastClient = NULL;
|
||||||
OSIntMask prevInt;
|
OSIntMask prevInt;
|
||||||
|
|
||||||
LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 129);
|
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 129);
|
||||||
LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 130);
|
LogUtils_CheckNullPointer("c", client, "../irqmgr.c", 130);
|
||||||
|
|
||||||
|
// Disable interrupts to prevent a thread context switch while the linked list is modified
|
||||||
prevInt = osSetIntMask(OS_IM_NONE);
|
prevInt = osSetIntMask(OS_IM_NONE);
|
||||||
|
|
||||||
while (iter != NULL) {
|
// Remove the client
|
||||||
if (iter == c) {
|
while (iterClient != NULL) {
|
||||||
if (lastIter) {
|
if (iterClient == client) {
|
||||||
lastIter->prev = c->prev;
|
if (lastClient != NULL) {
|
||||||
|
lastClient->prev = client->prev;
|
||||||
} else {
|
} else {
|
||||||
this->clients = c->prev;
|
irqMgr->clients = client->prev;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lastIter = iter;
|
lastClient = iterClient;
|
||||||
iter = iter->prev;
|
iterClient = iterClient->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
osSetIntMask(prevInt);
|
osSetIntMask(prevInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_SendMesgForClient(IrqMgr* this, OSMesg msg) {
|
/**
|
||||||
IrqMgrClient* iter = this->clients;
|
* Send `msg` to every registered client if the message queue is not full. The message is
|
||||||
|
* appended to the back of the queue.
|
||||||
|
*/
|
||||||
|
void IrqMgr_SendMesgToClients(IrqMgr* irqMgr, OSMesg msg) {
|
||||||
|
IrqMgrClient* client;
|
||||||
|
|
||||||
while (iter != NULL) {
|
for (client = irqMgr->clients; client != NULL; client = client->prev) {
|
||||||
if (iter->queue->validCount >= iter->queue->msgCount) {
|
if (MQ_IS_FULL(client->queue)) {
|
||||||
// "irqmgr_SendMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
|
// "irqmgr_SendMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
|
||||||
osSyncPrintf(
|
osSyncPrintf(
|
||||||
VT_COL(RED, WHITE) "irqmgr_SendMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
|
VT_COL(RED, WHITE) "irqmgr_SendMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
|
||||||
iter->queue, iter->queue->validCount);
|
client->queue, MQ_GET_COUNT(client->queue));
|
||||||
} else {
|
} else {
|
||||||
osSendMesg(iter->queue, msg, OS_MESG_NOBLOCK);
|
osSendMesg(client->queue, msg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = iter->prev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_JamMesgForClient(IrqMgr* this, OSMesg msg) {
|
/**
|
||||||
IrqMgrClient* iter = this->clients;
|
* Send `msg` to every registered client if the message queue is not full. This appears to be for
|
||||||
|
* high-priority messages that should be jammed to the front of the queue, however a bug prevents
|
||||||
|
* this from working in this way and the message is appended to the back of the queue as in
|
||||||
|
* `IrqMgr_SendMesgToClients`.
|
||||||
|
*
|
||||||
|
* @see IrqMgr_SendMesgToClients
|
||||||
|
*/
|
||||||
|
void IrqMgr_JamMesgToClients(IrqMgr* irqMgr, OSMesg msg) {
|
||||||
|
IrqMgrClient* client;
|
||||||
|
|
||||||
while (iter != NULL) {
|
for (client = irqMgr->clients; client != NULL; client = client->prev) {
|
||||||
if (iter->queue->validCount >= iter->queue->msgCount) {
|
if (MQ_IS_FULL(client->queue)) {
|
||||||
// "irqmgr_JamMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
|
// "irqmgr_JamMesgForClient: Message queue is overflowing mq=%08x cnt=%d"
|
||||||
osSyncPrintf(
|
osSyncPrintf(
|
||||||
VT_COL(RED, WHITE) "irqmgr_JamMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
|
VT_COL(RED, WHITE) "irqmgr_JamMesgForClient:メッセージキューがあふれています mq=%08x cnt=%d\n" VT_RST,
|
||||||
iter->queue, iter->queue->validCount);
|
client->queue, MQ_GET_COUNT(client->queue));
|
||||||
} else {
|
} else {
|
||||||
// mistake? the function's name suggests it would use osJamMesg
|
//! @bug The function's name suggests this would use osJamMesg rather than osSendMesg, using the
|
||||||
osSendMesg(iter->queue, msg, OS_MESG_NOBLOCK);
|
//! latter makes this function no different than IrqMgr_SendMesgToClients.
|
||||||
|
osSendMesg(client->queue, msg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
iter = iter->prev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePreNMI(IrqMgr* this) {
|
/**
|
||||||
u64 temp = STATUS_PRENMI; // required to match
|
* Runs when the Pre-NMI OS Event is received. This indicates that the console will reset in at least
|
||||||
|
* 0.5s / 500ms. Updates the reset status and time before forwarding the Pre-NMI message to registered
|
||||||
|
* clients so they may begin shutting down in advance of the reset.
|
||||||
|
*/
|
||||||
|
void IrqMgr_HandlePreNMI(IrqMgr* irqMgr) {
|
||||||
|
u64 preNmi = IRQ_RESET_STATUS_PRENMI; // required to match
|
||||||
|
|
||||||
gIrqMgrResetStatus = temp;
|
gIrqMgrResetStatus = preNmi;
|
||||||
this->resetStatus = STATUS_PRENMI;
|
irqMgr->resetStatus = IRQ_RESET_STATUS_PRENMI;
|
||||||
sIrqMgrResetTime = this->resetTime = osGetTime();
|
sIrqMgrResetTime = irqMgr->resetTime = osGetTime();
|
||||||
|
|
||||||
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(450000), 0ull, &this->queue, (OSMesg)PRENMI450_MSG);
|
// Schedule a PRENMI450 message to be handled in 450ms
|
||||||
IrqMgr_JamMesgForClient(this, (OSMesg) & this->prenmiMsg);
|
osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(450), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI450_MSG);
|
||||||
|
IrqMgr_JamMesgToClients(irqMgr, (OSMesg)&irqMgr->prenmiMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_CheckStack() {
|
void IrqMgr_CheckStacks(void) {
|
||||||
osSyncPrintf("irqmgr.c: PRENMIから0.5秒経過\n"); // "0.5 seconds after PRENMI"
|
// "0.5 seconds after PRENMI"
|
||||||
if (StackCheck_Check(NULL) == 0) {
|
osSyncPrintf("irqmgr.c: PRENMIから0.5秒経過\n");
|
||||||
osSyncPrintf("スタックは大丈夫みたいです\n"); // "The stack looks ok"
|
|
||||||
|
if (StackCheck_Check(NULL) == STACK_STATUS_OK) {
|
||||||
|
// "The stack looks ok"
|
||||||
|
osSyncPrintf("スタックは大丈夫みたいです\n");
|
||||||
} else {
|
} else {
|
||||||
osSyncPrintf("%c", 7);
|
osSyncPrintf("%c", BEL);
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
// "Stack overflow or dangerous"
|
// "Stack overflow or dangerous"
|
||||||
osSyncPrintf("スタックがオーバーフローしたか危険な状態です\n");
|
osSyncPrintf("スタックがオーバーフローしたか危険な状態です\n");
|
||||||
|
@ -126,82 +183,94 @@ void IrqMgr_CheckStack() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI450(IrqMgr* this) {
|
void IrqMgr_HandlePRENMI450(IrqMgr* irqMgr) {
|
||||||
u64 temp = STATUS_NMI; // required to match
|
u64 nmi = IRQ_RESET_STATUS_NMI; // required to match
|
||||||
gIrqMgrResetStatus = temp;
|
|
||||||
this->resetStatus = STATUS_NMI;
|
|
||||||
|
|
||||||
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(30000), 0ull, &this->queue, (OSMesg)PRENMI480_MSG);
|
gIrqMgrResetStatus = nmi;
|
||||||
IrqMgr_SendMesgForClient(this, (OSMesg) & this->nmiMsg);
|
irqMgr->resetStatus = IRQ_RESET_STATUS_NMI;
|
||||||
|
|
||||||
|
// Schedule a PRENMI480 message to be handled in 30ms
|
||||||
|
osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(30), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI480_MSG);
|
||||||
|
// Send the NMI event to clients
|
||||||
|
IrqMgr_SendMesgToClients(irqMgr, (OSMesg)&irqMgr->nmiMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI480(IrqMgr* this) {
|
void IrqMgr_HandlePRENMI480(IrqMgr* irqMgr) {
|
||||||
u32 ret;
|
u32 result;
|
||||||
|
|
||||||
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(20000), 0ull, &this->queue, (OSMesg)PRENMI500_MSG);
|
// Schedule a PRENMI500 message to be handled in 20ms
|
||||||
ret = osAfterPreNMI();
|
osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(20), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI500_MSG);
|
||||||
if (ret) {
|
|
||||||
|
result = osAfterPreNMI();
|
||||||
|
if (result != 0) {
|
||||||
// "osAfterPreNMI returned %d !?"
|
// "osAfterPreNMI returned %d !?"
|
||||||
osSyncPrintf("osAfterPreNMIが %d を返しました!?\n", ret);
|
osSyncPrintf("osAfterPreNMIが %d を返しました!?\n", result);
|
||||||
osSetTimer(&this->timer, OS_USEC_TO_CYCLES(1000), 0ull, &this->queue, (OSMesg)PRENMI480_MSG);
|
// osAfterPreNMI failed, try again in 1ms
|
||||||
|
//! @bug setting the same timer for a second time without letting the first one complete breaks
|
||||||
|
//! the timer linked list
|
||||||
|
osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(1), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI480_MSG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI500(IrqMgr* this) {
|
void IrqMgr_HandlePRENMI500(IrqMgr* irqMgr) {
|
||||||
IrqMgr_CheckStack();
|
IrqMgr_CheckStacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandleRetrace(IrqMgr* this) {
|
/**
|
||||||
if (gIrqMgrRetraceTime == 0ull) {
|
* Runs on each VI retrace, measures the time elapsed between the first and second VI retrace
|
||||||
if (this->retraceTime == 0) {
|
* and dispatches VI retrace messages to each registered Irq Client
|
||||||
this->retraceTime = osGetTime();
|
*/
|
||||||
|
void IrqMgr_HandleRetrace(IrqMgr* irqMgr) {
|
||||||
|
if (gIrqMgrRetraceTime == 0) {
|
||||||
|
if (irqMgr->retraceTime == 0) {
|
||||||
|
irqMgr->retraceTime = osGetTime();
|
||||||
} else {
|
} else {
|
||||||
gIrqMgrRetraceTime = osGetTime() - this->retraceTime;
|
gIrqMgrRetraceTime = osGetTime() - irqMgr->retraceTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sIrqMgrRetraceCount++;
|
sIrqMgrRetraceCount++;
|
||||||
IrqMgr_SendMesgForClient(this, (OSMesg) & this->retraceMsg);
|
IrqMgr_SendMesgToClients(irqMgr, (OSMesg)&irqMgr->retraceMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_ThreadEntry(void* arg0) {
|
void IrqMgr_ThreadEntry(void* arg) {
|
||||||
OSMesg msg;
|
u32 msg = 0;
|
||||||
IrqMgr* this = (IrqMgr*)arg0;
|
IrqMgr* irqMgr = (IrqMgr*)arg;
|
||||||
u8 exit;
|
u8 exit;
|
||||||
|
|
||||||
msg = 0;
|
// "Start IRQ manager thread execution"
|
||||||
osSyncPrintf("IRQマネージャスレッド実行開始\n"); // "Start IRQ manager thread execution"
|
osSyncPrintf("IRQマネージャスレッド実行開始\n");
|
||||||
exit = false;
|
exit = false;
|
||||||
|
|
||||||
while (!exit) {
|
while (!exit) {
|
||||||
osRecvMesg(&this->queue, &msg, OS_MESG_BLOCK);
|
osRecvMesg(&irqMgr->queue, (OSMesg*)&msg, OS_MESG_BLOCK);
|
||||||
switch ((u32)msg) {
|
switch (msg) {
|
||||||
case RETRACE_MSG:
|
case IRQ_RETRACE_MSG:
|
||||||
IrqMgr_HandleRetrace(this);
|
IrqMgr_HandleRetrace(irqMgr);
|
||||||
break;
|
break;
|
||||||
case PRE_NMI_MSG:
|
case IRQ_PRENMI_MSG:
|
||||||
osSyncPrintf("PRE_NMI_MSG\n");
|
osSyncPrintf("PRE_NMI_MSG\n");
|
||||||
// "Scheduler: Receives PRE_NMI message"
|
// "Scheduler: Receives PRE_NMI message"
|
||||||
osSyncPrintf("スケジューラ:PRE_NMIメッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRE_NMIメッセージを受信\n");
|
||||||
IrqMgr_HandlePreNMI(this);
|
IrqMgr_HandlePreNMI(irqMgr);
|
||||||
break;
|
break;
|
||||||
case PRENMI450_MSG:
|
case IRQ_PRENMI450_MSG:
|
||||||
osSyncPrintf("PRENMI450_MSG\n");
|
osSyncPrintf("PRENMI450_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI450 message"
|
// "Scheduler: Receives PRENMI450 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n");
|
||||||
IrqMgr_HandlePRENMI450(this);
|
IrqMgr_HandlePRENMI450(irqMgr);
|
||||||
break;
|
break;
|
||||||
case PRENMI480_MSG:
|
case IRQ_PRENMI480_MSG:
|
||||||
osSyncPrintf("PRENMI480_MSG\n");
|
osSyncPrintf("PRENMI480_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI480 message"
|
// "Scheduler: Receives PRENMI480 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n");
|
||||||
IrqMgr_HandlePRENMI480(this);
|
IrqMgr_HandlePRENMI480(irqMgr);
|
||||||
break;
|
break;
|
||||||
case PRENMI500_MSG:
|
case IRQ_PRENMI500_MSG:
|
||||||
osSyncPrintf("PRENMI500_MSG\n");
|
osSyncPrintf("PRENMI500_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI500 message"
|
// "Scheduler: Receives PRENMI500 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n");
|
||||||
exit = true;
|
exit = true;
|
||||||
IrqMgr_HandlePRENMI500(this);
|
IrqMgr_HandlePRENMI500(irqMgr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// "Unexpected message received"
|
// "Unexpected message received"
|
||||||
|
@ -210,23 +279,25 @@ void IrqMgr_ThreadEntry(void* arg0) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osSyncPrintf("IRQマネージャスレッド実行終了\n"); // "End of IRQ manager thread execution"
|
// "End of IRQ manager thread execution"
|
||||||
|
osSyncPrintf("IRQマネージャスレッド実行終了\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_Init(IrqMgr* this, void* stack, OSPri pri, u8 retraceCount) {
|
void IrqMgr_Init(IrqMgr* irqMgr, void* stack, OSPri pri, u8 retraceCount) {
|
||||||
LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 346);
|
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 346);
|
||||||
LogUtils_CheckNullPointer("stack", stack, "../irqmgr.c", 347);
|
LogUtils_CheckNullPointer("stack", stack, "../irqmgr.c", 347);
|
||||||
|
|
||||||
this->clients = NULL;
|
irqMgr->clients = NULL;
|
||||||
this->retraceMsg.type = OS_SC_RETRACE_MSG;
|
// Messages to send to each client message queue on each interrupt event
|
||||||
this->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
|
irqMgr->retraceMsg.type = OS_SC_RETRACE_MSG;
|
||||||
this->nmiMsg.type = OS_SC_NMI_MSG;
|
irqMgr->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
|
||||||
this->resetStatus = STATUS_IDLE;
|
irqMgr->nmiMsg.type = OS_SC_NMI_MSG;
|
||||||
this->resetTime = 0;
|
irqMgr->resetStatus = IRQ_RESET_STATUS_IDLE;
|
||||||
|
irqMgr->resetTime = 0;
|
||||||
|
|
||||||
osCreateMesgQueue(&this->queue, this->msgBuf, ARRAY_COUNT(this->msgBuf));
|
osCreateMesgQueue(&irqMgr->queue, irqMgr->msgBuf, ARRAY_COUNT(irqMgr->msgBuf));
|
||||||
osSetEventMesg(OS_EVENT_PRENMI, &this->queue, (OSMesg)PRE_NMI_MSG);
|
osSetEventMesg(OS_EVENT_PRENMI, &irqMgr->queue, (OSMesg)IRQ_PRENMI_MSG);
|
||||||
osViSetEvent(&this->queue, (OSMesg)RETRACE_MSG, retraceCount);
|
osViSetEvent(&irqMgr->queue, (OSMesg)IRQ_RETRACE_MSG, retraceCount);
|
||||||
osCreateThread(&this->thread, 0x13, IrqMgr_ThreadEntry, this, stack, pri);
|
osCreateThread(&irqMgr->thread, 19, IrqMgr_ThreadEntry, irqMgr, stack, pri);
|
||||||
osStartThread(&this->thread);
|
osStartThread(&irqMgr->thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ void Main(void* arg) {
|
||||||
IrqMgrClient irqClient;
|
IrqMgrClient irqClient;
|
||||||
OSMesgQueue irqMgrMsgQ;
|
OSMesgQueue irqMgrMsgQ;
|
||||||
OSMesg irqMgrMsgBuf[60];
|
OSMesg irqMgrMsgBuf[60];
|
||||||
u32 sysHeap;
|
u32 systemHeapStart;
|
||||||
u32 fb;
|
u32 fb;
|
||||||
s32 debugHeap;
|
s32 debugHeapStart;
|
||||||
s32 debugHeapSize;
|
s32 debugHeapSize;
|
||||||
s16* msg;
|
s16* msg;
|
||||||
|
|
||||||
|
@ -50,52 +50,52 @@ void Main(void* arg) {
|
||||||
PreNmiBuff_Init(gAppNmiBufferPtr);
|
PreNmiBuff_Init(gAppNmiBufferPtr);
|
||||||
Fault_Init();
|
Fault_Init();
|
||||||
SysCfb_Init(0);
|
SysCfb_Init(0);
|
||||||
sysHeap = (u32)gSystemHeap;
|
systemHeapStart = (u32)gSystemHeap;
|
||||||
fb = SysCfb_GetFbPtr(0);
|
fb = SysCfb_GetFbPtr(0);
|
||||||
gSystemHeapSize = (fb - sysHeap);
|
gSystemHeapSize = fb - systemHeapStart;
|
||||||
// "System heap initalization"
|
// "System heap initalization"
|
||||||
osSyncPrintf("システムヒープ初期化 %08x-%08x %08x\n", sysHeap, fb, gSystemHeapSize);
|
osSyncPrintf("システムヒープ初期化 %08x-%08x %08x\n", systemHeapStart, fb, gSystemHeapSize);
|
||||||
SystemHeap_Init(sysHeap, gSystemHeapSize); // initializes the system heap
|
SystemHeap_Init(systemHeapStart, gSystemHeapSize); // initializes the system heap
|
||||||
if (osMemSize >= 0x800000) {
|
if (osMemSize >= 0x800000) {
|
||||||
debugHeap = SysCfb_GetFbEnd();
|
debugHeapStart = SysCfb_GetFbEnd();
|
||||||
debugHeapSize = (s32)(0x80600000 - debugHeap);
|
debugHeapSize = PHYS_TO_K0(0x600000) - debugHeapStart;
|
||||||
} else {
|
} else {
|
||||||
debugHeapSize = 0x400;
|
debugHeapSize = 0x400;
|
||||||
debugHeap = SystemArena_MallocDebug(debugHeapSize, "../main.c", 565);
|
debugHeapStart = SystemArena_MallocDebug(debugHeapSize, "../main.c", 565);
|
||||||
}
|
}
|
||||||
osSyncPrintf("debug_InitArena(%08x, %08x)\n", debugHeap, debugHeapSize);
|
osSyncPrintf("debug_InitArena(%08x, %08x)\n", debugHeapStart, debugHeapSize);
|
||||||
DebugArena_Init(debugHeap, debugHeapSize);
|
DebugArena_Init(debugHeapStart, debugHeapSize);
|
||||||
func_800636C0();
|
func_800636C0();
|
||||||
|
|
||||||
R_ENABLE_ARENA_DBG = 0;
|
R_ENABLE_ARENA_DBG = 0;
|
||||||
|
|
||||||
osCreateMesgQueue(&sSiIntMsgQ, sSiIntMsgBuf, 1);
|
osCreateMesgQueue(&sSiIntMsgQ, sSiIntMsgBuf, ARRAY_COUNT(sSiIntMsgBuf));
|
||||||
osSetEventMesg(5, &sSiIntMsgQ, 0);
|
osSetEventMesg(OS_EVENT_SI, &sSiIntMsgQ, NULL);
|
||||||
|
|
||||||
Main_LogSystemHeap();
|
Main_LogSystemHeap();
|
||||||
|
|
||||||
osCreateMesgQueue(&irqMgrMsgQ, irqMgrMsgBuf, 0x3C);
|
osCreateMesgQueue(&irqMgrMsgQ, irqMgrMsgBuf, ARRAY_COUNT(irqMgrMsgBuf));
|
||||||
StackCheck_Init(&sIrqMgrStackInfo, sIrqMgrStack, STACK_TOP(sIrqMgrStack), 0, 0x100, "irqmgr");
|
StackCheck_Init(&sIrqMgrStackInfo, sIrqMgrStack, STACK_TOP(sIrqMgrStack), 0, 0x100, "irqmgr");
|
||||||
IrqMgr_Init(&gIrqMgr, &sGraphStackInfo, Z_PRIORITY_IRQMGR, 1);
|
IrqMgr_Init(&gIrqMgr, STACK_TOP(sIrqMgrStack), Z_PRIORITY_IRQMGR, 1);
|
||||||
|
|
||||||
osSyncPrintf("タスクスケジューラの初期化\n"); // "Initialize the task scheduler"
|
osSyncPrintf("タスクスケジューラの初期化\n"); // "Initialize the task scheduler"
|
||||||
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
|
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
|
||||||
Sched_Init(&gSchedContext, &sAudioStack, Z_PRIORITY_SCHED, D_80013960, 1, &gIrqMgr);
|
Sched_Init(&gSchedContext, STACK_TOP(sSchedStack), Z_PRIORITY_SCHED, D_80013960, 1, &gIrqMgr);
|
||||||
|
|
||||||
IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQ);
|
IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQ);
|
||||||
|
|
||||||
StackCheck_Init(&sAudioStackInfo, sAudioStack, STACK_TOP(sAudioStack), 0, 0x100, "audio");
|
StackCheck_Init(&sAudioStackInfo, sAudioStack, STACK_TOP(sAudioStack), 0, 0x100, "audio");
|
||||||
AudioMgr_Init(&gAudioMgr, STACK_TOP(sAudioStack), Z_PRIORITY_AUDIOMGR, 0xA, &gSchedContext, &gIrqMgr);
|
AudioMgr_Init(&gAudioMgr, STACK_TOP(sAudioStack), Z_PRIORITY_AUDIOMGR, 10, &gSchedContext, &gIrqMgr);
|
||||||
|
|
||||||
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
|
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
|
||||||
PadMgr_Init(&gPadMgr, &sSiIntMsgQ, &gIrqMgr, 7, Z_PRIORITY_PADMGR, &sIrqMgrStack);
|
PadMgr_Init(&gPadMgr, &sSiIntMsgQ, &gIrqMgr, 7, Z_PRIORITY_PADMGR, STACK_TOP(sPadMgrStack));
|
||||||
|
|
||||||
AudioMgr_Unlock(&gAudioMgr);
|
AudioMgr_Unlock(&gAudioMgr);
|
||||||
|
|
||||||
StackCheck_Init(&sGraphStackInfo, sGraphStack, STACK_TOP(sGraphStack), 0, 0x100, "graph");
|
StackCheck_Init(&sGraphStackInfo, sGraphStack, STACK_TOP(sGraphStack), 0, 0x100, "graph");
|
||||||
osCreateThread(&sGraphThread, 4, Graph_ThreadEntry, arg, STACK_TOP(sGraphStack), Z_PRIORITY_GRAPH);
|
osCreateThread(&sGraphThread, 4, Graph_ThreadEntry, arg, STACK_TOP(sGraphStack), Z_PRIORITY_GRAPH);
|
||||||
osStartThread(&sGraphThread);
|
osStartThread(&sGraphThread);
|
||||||
osSetThreadPri(0, Z_PRIORITY_SCHED);
|
osSetThreadPri(NULL, 15);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
msg = NULL;
|
msg = NULL;
|
||||||
|
|
|
@ -59,7 +59,7 @@ void func_800C84E4(SchedContext* sc, CfbInfo* cfbInfo) {
|
||||||
if (sc->unk_24C != 0) {
|
if (sc->unk_24C != 0) {
|
||||||
sc->unk_24C = 0;
|
sc->unk_24C = 0;
|
||||||
|
|
||||||
if (gIrqMgrResetStatus == 0) {
|
if (gIrqMgrResetStatus == IRQ_RESET_STATUS_IDLE) {
|
||||||
ViConfig_UpdateVi(0);
|
ViConfig_UpdateVi(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -707,7 +707,7 @@ void Select_Main(GameState* thisx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Select_Destroy(GameState* thisx) {
|
void Select_Destroy(GameState* thisx) {
|
||||||
osSyncPrintf("%c", '\a'); // ASCII BEL character, plays an alert tone
|
osSyncPrintf("%c", BEL);
|
||||||
// "view_cleanup will hang, so it won't be called"
|
// "view_cleanup will hang, so it won't be called"
|
||||||
osSyncPrintf("*** view_cleanupはハングアップするので、呼ばない ***\n");
|
osSyncPrintf("*** view_cleanupはハングアップするので、呼ばない ***\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue