diff --git a/include/functions.h b/include/functions.h index c50d8f4b8b..c4525ee7c6 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1792,18 +1792,6 @@ void func_800D3178(UnkRumbleStruct* arg0); void func_800D31A0(void); void func_800D31F0(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_Malloc(u32 size); void* DebugArena_MallocDebug(u32 size, const char* file, s32 line); diff --git a/include/irqmgr.h b/include/irqmgr.h index 0f26fc3ce7..6c5b72458a 100644 --- a/include/irqmgr.h +++ b/include/irqmgr.h @@ -3,6 +3,17 @@ #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 { /* 0x00 */ s16 type; /* 0x02 */ char misc[0x1E]; @@ -14,8 +25,8 @@ typedef struct IrqMgrClient { } IrqMgrClient; typedef struct { - /* 0x000 */ OSScMsg retraceMsg; // this apparently got moved from OSSched - /* 0x020 */ OSScMsg prenmiMsg; // this apparently got moved from OSSched + /* 0x000 */ OSScMsg retraceMsg; + /* 0x020 */ OSScMsg prenmiMsg; /* 0x040 */ OSScMsg nmiMsg; /* 0x060 */ OSMesgQueue queue; /* 0x078 */ OSMesg msgBuf[8]; @@ -27,4 +38,9 @@ typedef struct { /* 0x278 */ OSTime retraceTime; } 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 diff --git a/include/ultra64/convert.h b/include/ultra64/convert.h index 62409158c1..02024d17fa 100644 --- a/include/ultra64/convert.h +++ b/include/ultra64/convert.h @@ -15,6 +15,7 @@ #define OS_PHYSICAL_TO_K0(x) (void*)(((u32)(x)+0x80000000)) #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 diff --git a/include/ultra64/message.h b/include/ultra64/message.h index d463ec4c6d..6c6966a20b 100644 --- a/include/ultra64/message.h +++ b/include/ultra64/message.h @@ -36,4 +36,11 @@ typedef struct OSMesgQueue { /* 0x14 */ OSMesg* msg; } 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 diff --git a/include/vt.h b/include/vt.h index 4f7c73641e..61b95706ad 100644 --- a/include/vt.h +++ b/include/vt.h @@ -31,4 +31,7 @@ #define VT_RST VT_SGR("") #define VT_CLS VT_ED(2) +// ASCII BEL character, plays an alert tone +#define BEL '\a' + #endif diff --git a/include/z64.h b/include/z64.h index 7bc163a54f..658ca1476a 100644 --- a/include/z64.h +++ b/include/z64.h @@ -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_SP 0x0002 #define OS_SC_YIELD 0x0010 diff --git a/src/boot/z_std_dma.c b/src/boot/z_std_dma.c index 11e0392a06..d50807f4f8 100644 --- a/src/boot/z_std_dma.c +++ b/src/boot/z_std_dma.c @@ -170,7 +170,7 @@ void DmaMgr_Error(DmaRequest* req, const char* file, const char* errorName, cons char buff1[80]; char buff2[80]; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); osSyncPrintf(VT_FGCOL(RED)); osSyncPrintf("DMA致命的エラー(%s)\nROM:%X RAM:%X SIZE:%X %s\n", 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 ((sDmaMgrQueueFullLogged == 0) && (sDmaMgrMsgQueue.validCount >= sDmaMgrMsgQueue.msgCount)) { sDmaMgrQueueFullLogged++; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); osSyncPrintf(VT_FGCOL(RED)); osSyncPrintf("dmaEntryMsgQが一杯です。キューサイズの再検討をおすすめします。"); LOG_NUM("(sizeof(dmaEntryMsgBufs) / sizeof(dmaEntryMsgBufs[0]))", ARRAY_COUNT(sDmaMgrMsgs), diff --git a/src/code/game.c b/src/code/game.c index 785e04ca4e..11a68e4b4f 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -346,7 +346,7 @@ void GameState_Realloc(GameState* gameState, size_t size) { osSyncPrintf("ハイラル一時解放!!\n"); // "Hyrule temporarily released!!" SystemArena_GetSizes(&systemMaxFree, &systemFree, &systemAlloc); if ((systemMaxFree - 0x10) < size) { - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); osSyncPrintf(VT_FGCOL(RED)); // "Not enough memory. Change the hyral size to the largest possible value" diff --git a/src/code/graph.c b/src/code/graph.c index 9c988bbb04..97a7d37920 100644 --- a/src/code/graph.c +++ b/src/code/graph.c @@ -323,14 +323,14 @@ void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) { if (pool->headMagic != GFXPOOL_HEAD_MAGIC) { //! @bug (?) : "problem = true;" may be missing - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); // "Dynamic area head is destroyed" osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域先頭が破壊されています\n" VT_RST); Fault_AddHungupAndCrash("../graph.c", 1070); } if (pool->tailMagic != GFXPOOL_TAIL_MAGIC) { problem = true; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); // "Dynamic region tail is destroyed" osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域末尾が破壊されています\n" VT_RST); Fault_AddHungupAndCrash("../graph.c", 1076); @@ -339,19 +339,19 @@ void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) { if (THGA_IsCrash(&gfxCtx->polyOpa)) { problem = true; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); // "Zelda 0 is dead" osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ0は死んでしまった(graph_alloc is empty)\n" VT_RST); } if (THGA_IsCrash(&gfxCtx->polyXlu)) { problem = true; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); // "Zelda 1 is dead" osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ1は死んでしまった(graph_alloc is empty)\n" VT_RST); } if (THGA_IsCrash(&gfxCtx->overlay)) { problem = true; - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); // "Zelda 4 is dead" osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ4は死んでしまった(graph_alloc is empty)\n" VT_RST); } diff --git a/src/code/irqmgr.c b/src/code/irqmgr.c index 50ba2def95..9df7563d81 100644 --- a/src/code/irqmgr.c +++ b/src/code/irqmgr.c @@ -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 "vt.h" -vu32 gIrqMgrResetStatus = 0; +vu32 gIrqMgrResetStatus = IRQ_RESET_STATUS_IDLE; 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 +// Internal messages +#define IRQ_RETRACE_MSG 666 +#define IRQ_PRENMI_MSG 669 +#define IRQ_PRENMI450_MSG 671 +#define IRQ_PRENMI480_MSG 672 +#define IRQ_PRENMI500_MSG 673 -#define STATUS_IDLE 0 -#define STATUS_PRENMI 1 -#define STATUS_NMI 2 - -void IrqMgr_AddClient(IrqMgr* this, IrqMgrClient* c, OSMesgQueue* msgQ) { +/** + * Registers a client and an associated message queue with the IRQ manager. When an + * interrupt event is received by the IRQ manager, these clients will be notified of + * the event. + * + * @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; - LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 96); - LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 97); + LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 96); + LogUtils_CheckNullPointer("c", client, "../irqmgr.c", 97); LogUtils_CheckNullPointer("msgQ", msgQ, "../irqmgr.c", 98); prevInt = osSetIntMask(OS_IM_NONE); - c->queue = msgQ; - c->prev = this->clients; - this->clients = c; + client->queue = msgQ; + client->prev = irqMgr->clients; + irqMgr->clients = client; osSetIntMask(prevInt); - if (this->resetStatus > STATUS_IDLE) { - osSendMesg(c->queue, (OSMesg) & this->prenmiMsg, OS_MESG_NOBLOCK); + if (irqMgr->resetStatus >= IRQ_RESET_STATUS_PRENMI) { + osSendMesg(client->queue, (OSMesg)&irqMgr->prenmiMsg, OS_MESG_NOBLOCK); } - if (this->resetStatus >= STATUS_NMI) { - osSendMesg(c->queue, (OSMesg) & this->nmiMsg, OS_MESG_NOBLOCK); + if (irqMgr->resetStatus >= IRQ_RESET_STATUS_NMI) { + osSendMesg(client->queue, (OSMesg)&irqMgr->nmiMsg, OS_MESG_NOBLOCK); } } -void IrqMgr_RemoveClient(IrqMgr* this, IrqMgrClient* c) { - IrqMgrClient* iter = this->clients; - IrqMgrClient* lastIter = NULL; +void IrqMgr_RemoveClient(IrqMgr* irqMgr, IrqMgrClient* client) { + IrqMgrClient* iterClient = irqMgr->clients; + IrqMgrClient* lastClient = NULL; OSIntMask prevInt; - LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 129); - LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 130); + LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 129); + 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); - while (iter != NULL) { - if (iter == c) { - if (lastIter) { - lastIter->prev = c->prev; + // Remove the client + while (iterClient != NULL) { + if (iterClient == client) { + if (lastClient != NULL) { + lastClient->prev = client->prev; } else { - this->clients = c->prev; + irqMgr->clients = client->prev; } break; } - lastIter = iter; - iter = iter->prev; + lastClient = iterClient; + iterClient = iterClient->prev; } 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) { - if (iter->queue->validCount >= iter->queue->msgCount) { + for (client = irqMgr->clients; client != NULL; client = client->prev) { + if (MQ_IS_FULL(client->queue)) { // "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); + client->queue, MQ_GET_COUNT(client->queue)); } 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) { - if (iter->queue->validCount >= iter->queue->msgCount) { + for (client = irqMgr->clients; client != NULL; client = client->prev) { + if (MQ_IS_FULL(client->queue)) { // "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); + client->queue, MQ_GET_COUNT(client->queue)); } else { - // mistake? the function's name suggests it would use osJamMesg - osSendMesg(iter->queue, msg, OS_MESG_NOBLOCK); + //! @bug The function's name suggests this would use osJamMesg rather than osSendMesg, using the + //! 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; - this->resetStatus = STATUS_PRENMI; - sIrqMgrResetTime = this->resetTime = osGetTime(); + gIrqMgrResetStatus = preNmi; + irqMgr->resetStatus = IRQ_RESET_STATUS_PRENMI; + sIrqMgrResetTime = irqMgr->resetTime = osGetTime(); - osSetTimer(&this->timer, OS_USEC_TO_CYCLES(450000), 0ull, &this->queue, (OSMesg)PRENMI450_MSG); - IrqMgr_JamMesgForClient(this, (OSMesg) & this->prenmiMsg); + // Schedule a PRENMI450 message to be handled in 450ms + osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(450), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI450_MSG); + IrqMgr_JamMesgToClients(irqMgr, (OSMesg)&irqMgr->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" +void IrqMgr_CheckStacks(void) { + // "0.5 seconds after PRENMI" + osSyncPrintf("irqmgr.c: PRENMIから0.5秒経過\n"); + + if (StackCheck_Check(NULL) == STACK_STATUS_OK) { + // "The stack looks ok" + osSyncPrintf("スタックは大丈夫みたいです\n"); } else { - osSyncPrintf("%c", 7); + osSyncPrintf("%c", BEL); osSyncPrintf(VT_FGCOL(RED)); // "Stack overflow or dangerous" osSyncPrintf("スタックがオーバーフローしたか危険な状態です\n"); @@ -126,82 +183,94 @@ void IrqMgr_CheckStack() { } } -void IrqMgr_HandlePRENMI450(IrqMgr* this) { - u64 temp = STATUS_NMI; // required to match - gIrqMgrResetStatus = temp; - this->resetStatus = STATUS_NMI; +void IrqMgr_HandlePRENMI450(IrqMgr* irqMgr) { + u64 nmi = IRQ_RESET_STATUS_NMI; // required to match - osSetTimer(&this->timer, OS_USEC_TO_CYCLES(30000), 0ull, &this->queue, (OSMesg)PRENMI480_MSG); - IrqMgr_SendMesgForClient(this, (OSMesg) & this->nmiMsg); + gIrqMgrResetStatus = nmi; + 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) { - u32 ret; +void IrqMgr_HandlePRENMI480(IrqMgr* irqMgr) { + u32 result; - osSetTimer(&this->timer, OS_USEC_TO_CYCLES(20000), 0ull, &this->queue, (OSMesg)PRENMI500_MSG); - ret = osAfterPreNMI(); - if (ret) { + // Schedule a PRENMI500 message to be handled in 20ms + osSetTimer(&irqMgr->timer, OS_MSEC_TO_CYCLES(20), 0, &irqMgr->queue, (OSMesg)IRQ_PRENMI500_MSG); + + result = osAfterPreNMI(); + if (result != 0) { // "osAfterPreNMI returned %d !?" - osSyncPrintf("osAfterPreNMIが %d を返しました!?\n", ret); - osSetTimer(&this->timer, OS_USEC_TO_CYCLES(1000), 0ull, &this->queue, (OSMesg)PRENMI480_MSG); + osSyncPrintf("osAfterPreNMIが %d を返しました!?\n", result); + // 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) { - IrqMgr_CheckStack(); +void IrqMgr_HandlePRENMI500(IrqMgr* irqMgr) { + IrqMgr_CheckStacks(); } -void IrqMgr_HandleRetrace(IrqMgr* this) { - if (gIrqMgrRetraceTime == 0ull) { - if (this->retraceTime == 0) { - this->retraceTime = osGetTime(); +/** + * Runs on each VI retrace, measures the time elapsed between the first and second VI retrace + * and dispatches VI retrace messages to each registered Irq Client + */ +void IrqMgr_HandleRetrace(IrqMgr* irqMgr) { + if (gIrqMgrRetraceTime == 0) { + if (irqMgr->retraceTime == 0) { + irqMgr->retraceTime = osGetTime(); } else { - gIrqMgrRetraceTime = osGetTime() - this->retraceTime; + gIrqMgrRetraceTime = osGetTime() - irqMgr->retraceTime; } } sIrqMgrRetraceCount++; - IrqMgr_SendMesgForClient(this, (OSMesg) & this->retraceMsg); + IrqMgr_SendMesgToClients(irqMgr, (OSMesg)&irqMgr->retraceMsg); } -void IrqMgr_ThreadEntry(void* arg0) { - OSMesg msg; - IrqMgr* this = (IrqMgr*)arg0; +void IrqMgr_ThreadEntry(void* arg) { + u32 msg = 0; + IrqMgr* irqMgr = (IrqMgr*)arg; u8 exit; - msg = 0; - osSyncPrintf("IRQマネージャスレッド実行開始\n"); // "Start IRQ manager thread execution" + // "Start IRQ manager thread execution" + osSyncPrintf("IRQマネージャスレッド実行開始\n"); exit = false; while (!exit) { - osRecvMesg(&this->queue, &msg, OS_MESG_BLOCK); - switch ((u32)msg) { - case RETRACE_MSG: - IrqMgr_HandleRetrace(this); + osRecvMesg(&irqMgr->queue, (OSMesg*)&msg, OS_MESG_BLOCK); + switch (msg) { + case IRQ_RETRACE_MSG: + IrqMgr_HandleRetrace(irqMgr); break; - case PRE_NMI_MSG: + case IRQ_PRENMI_MSG: osSyncPrintf("PRE_NMI_MSG\n"); // "Scheduler: Receives PRE_NMI message" osSyncPrintf("スケジューラ:PRE_NMIメッセージを受信\n"); - IrqMgr_HandlePreNMI(this); + IrqMgr_HandlePreNMI(irqMgr); break; - case PRENMI450_MSG: + case IRQ_PRENMI450_MSG: osSyncPrintf("PRENMI450_MSG\n"); // "Scheduler: Receives PRENMI450 message" osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n"); - IrqMgr_HandlePRENMI450(this); + IrqMgr_HandlePRENMI450(irqMgr); break; - case PRENMI480_MSG: + case IRQ_PRENMI480_MSG: osSyncPrintf("PRENMI480_MSG\n"); // "Scheduler: Receives PRENMI480 message" osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n"); - IrqMgr_HandlePRENMI480(this); + IrqMgr_HandlePRENMI480(irqMgr); break; - case PRENMI500_MSG: + case IRQ_PRENMI500_MSG: osSyncPrintf("PRENMI500_MSG\n"); // "Scheduler: Receives PRENMI500 message" osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n"); exit = true; - IrqMgr_HandlePRENMI500(this); + IrqMgr_HandlePRENMI500(irqMgr); break; default: // "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) { - LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 346); +void IrqMgr_Init(IrqMgr* irqMgr, void* stack, OSPri pri, u8 retraceCount) { + LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 346); LogUtils_CheckNullPointer("stack", stack, "../irqmgr.c", 347); - 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; + irqMgr->clients = NULL; + // Messages to send to each client message queue on each interrupt event + irqMgr->retraceMsg.type = OS_SC_RETRACE_MSG; + irqMgr->prenmiMsg.type = OS_SC_PRE_NMI_MSG; + irqMgr->nmiMsg.type = OS_SC_NMI_MSG; + irqMgr->resetStatus = IRQ_RESET_STATUS_IDLE; + irqMgr->resetTime = 0; - osCreateMesgQueue(&this->queue, this->msgBuf, ARRAY_COUNT(this->msgBuf)); - osSetEventMesg(OS_EVENT_PRENMI, &this->queue, (OSMesg)PRE_NMI_MSG); - osViSetEvent(&this->queue, (OSMesg)RETRACE_MSG, retraceCount); - osCreateThread(&this->thread, 0x13, IrqMgr_ThreadEntry, this, stack, pri); - osStartThread(&this->thread); + osCreateMesgQueue(&irqMgr->queue, irqMgr->msgBuf, ARRAY_COUNT(irqMgr->msgBuf)); + osSetEventMesg(OS_EVENT_PRENMI, &irqMgr->queue, (OSMesg)IRQ_PRENMI_MSG); + osViSetEvent(&irqMgr->queue, (OSMesg)IRQ_RETRACE_MSG, retraceCount); + osCreateThread(&irqMgr->thread, 19, IrqMgr_ThreadEntry, irqMgr, stack, pri); + osStartThread(&irqMgr->thread); } diff --git a/src/code/main.c b/src/code/main.c index c3773b51d2..775ba3e723 100644 --- a/src/code/main.c +++ b/src/code/main.c @@ -37,9 +37,9 @@ void Main(void* arg) { IrqMgrClient irqClient; OSMesgQueue irqMgrMsgQ; OSMesg irqMgrMsgBuf[60]; - u32 sysHeap; + u32 systemHeapStart; u32 fb; - s32 debugHeap; + s32 debugHeapStart; s32 debugHeapSize; s16* msg; @@ -50,52 +50,52 @@ void Main(void* arg) { PreNmiBuff_Init(gAppNmiBufferPtr); Fault_Init(); SysCfb_Init(0); - sysHeap = (u32)gSystemHeap; + systemHeapStart = (u32)gSystemHeap; fb = SysCfb_GetFbPtr(0); - gSystemHeapSize = (fb - sysHeap); + gSystemHeapSize = fb - systemHeapStart; // "System heap initalization" - osSyncPrintf("システムヒープ初期化 %08x-%08x %08x\n", sysHeap, fb, gSystemHeapSize); - SystemHeap_Init(sysHeap, gSystemHeapSize); // initializes the system heap + osSyncPrintf("システムヒープ初期化 %08x-%08x %08x\n", systemHeapStart, fb, gSystemHeapSize); + SystemHeap_Init(systemHeapStart, gSystemHeapSize); // initializes the system heap if (osMemSize >= 0x800000) { - debugHeap = SysCfb_GetFbEnd(); - debugHeapSize = (s32)(0x80600000 - debugHeap); + debugHeapStart = SysCfb_GetFbEnd(); + debugHeapSize = PHYS_TO_K0(0x600000) - debugHeapStart; } else { debugHeapSize = 0x400; - debugHeap = SystemArena_MallocDebug(debugHeapSize, "../main.c", 565); + debugHeapStart = SystemArena_MallocDebug(debugHeapSize, "../main.c", 565); } - osSyncPrintf("debug_InitArena(%08x, %08x)\n", debugHeap, debugHeapSize); - DebugArena_Init(debugHeap, debugHeapSize); + osSyncPrintf("debug_InitArena(%08x, %08x)\n", debugHeapStart, debugHeapSize); + DebugArena_Init(debugHeapStart, debugHeapSize); func_800636C0(); R_ENABLE_ARENA_DBG = 0; - osCreateMesgQueue(&sSiIntMsgQ, sSiIntMsgBuf, 1); - osSetEventMesg(5, &sSiIntMsgQ, 0); + osCreateMesgQueue(&sSiIntMsgQ, sSiIntMsgBuf, ARRAY_COUNT(sSiIntMsgBuf)); + osSetEventMesg(OS_EVENT_SI, &sSiIntMsgQ, NULL); Main_LogSystemHeap(); - osCreateMesgQueue(&irqMgrMsgQ, irqMgrMsgBuf, 0x3C); + osCreateMesgQueue(&irqMgrMsgQ, irqMgrMsgBuf, ARRAY_COUNT(irqMgrMsgBuf)); 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" 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); 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"); - 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); StackCheck_Init(&sGraphStackInfo, sGraphStack, STACK_TOP(sGraphStack), 0, 0x100, "graph"); osCreateThread(&sGraphThread, 4, Graph_ThreadEntry, arg, STACK_TOP(sGraphStack), Z_PRIORITY_GRAPH); osStartThread(&sGraphThread); - osSetThreadPri(0, Z_PRIORITY_SCHED); + osSetThreadPri(NULL, 15); while (true) { msg = NULL; diff --git a/src/code/sched.c b/src/code/sched.c index cf8f6eced9..504ed4c710 100644 --- a/src/code/sched.c +++ b/src/code/sched.c @@ -59,7 +59,7 @@ void func_800C84E4(SchedContext* sc, CfbInfo* cfbInfo) { if (sc->unk_24C != 0) { sc->unk_24C = 0; - if (gIrqMgrResetStatus == 0) { + if (gIrqMgrResetStatus == IRQ_RESET_STATUS_IDLE) { ViConfig_UpdateVi(0); } } diff --git a/src/overlays/gamestates/ovl_select/z_select.c b/src/overlays/gamestates/ovl_select/z_select.c index fdfad58d3a..eb3fb25fe6 100644 --- a/src/overlays/gamestates/ovl_select/z_select.c +++ b/src/overlays/gamestates/ovl_select/z_select.c @@ -707,7 +707,7 @@ void Select_Main(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" osSyncPrintf("*** view_cleanupはハングアップするので、呼ばない ***\n"); }