diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 745039a7..35e58d8e 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -52,6 +52,10 @@ graph.c: .text: [0x80405518, 0x80405EC8] .data: [0x8065ECA8, 0x8065ECB0] .bss: [0x812F31E8, 0x812F3560] +#irqmgr.c: +# .text: [0x80405EC8, 0x80406480] +# .data: [0x8065ECB0, 0x8065ECD0] +# .bss: [0x812F3560, 0x812F4CB0] lb_rtc.c: .text: [0x80406480, 0x8040752C] .rodata: [0x806436F8, 0x806437A0] diff --git a/include/dolphin/os/OSTimer.h b/include/dolphin/os/OSTimer.h index a45137ec..e1ec2433 100644 --- a/include/dolphin/os/OSTimer.h +++ b/include/dolphin/os/OSTimer.h @@ -5,6 +5,7 @@ #include "types.h" #include "dolphin/os/OSAlarm.h" +#include "dolphin/os/OSMessage.h" #ifdef __cplusplus extern "C" { diff --git a/include/irqmgr.h b/include/irqmgr.h index 92030758..d4ca499e 100644 --- a/include/irqmgr.h +++ b/include/irqmgr.h @@ -4,6 +4,7 @@ #include "types.h" #include "dolphin/os/OSTime.h" #include "dolphin/os/OSTimer.h" +#include "dolphin/os/OSMessage.h" #ifdef __cplusplus extern "C" { @@ -31,16 +32,33 @@ typedef struct { irqmgr_mesg_t msgDelayPreNMI; OSMessageQueue _msgQueue; OSMessage _msgBuf[IRQMGR_MESSAGES_MAX]; - OSThread thread; - irqmgr_client_t* clients; - u8 prenmi; + + union { + OSThread thread; + struct { + u8 unused[sizeof(OSThread) - 2 * sizeof(void*)]; + irqmgr_client_t* clients; + u8 prenmi; + }; + }; + OSTime prenmi_time; OSTimer timer; OSTime retraceTime; } irqmgr_t; +extern void irqmgr_AddClient(irqmgr_client_t* client, OSMessageQueue* msgqueue); +/* @unused extern void irqmgr_RemoveClient(irqmgr_client_t* client) */ +extern void CreateIRQManager(void* stack, size_t stack_size, int priority, u8 retracecount); + +/* probably declared in os_vi.h */ +extern void osViSetEvent(OSMessageQueue* mesgq, OSMessage msg, u32 retcount); + extern volatile int ResetStatus; extern volatile OSTime ResetTime; +extern volatile OSTime RetraceTime; +extern volatile int RetraceCount; +extern irqmgr_t irqmgr_class; #ifdef __cplusplus }; diff --git a/include/libultra/os_thread.h b/include/libultra/os_thread.h new file mode 100644 index 00000000..3c21805f --- /dev/null +++ b/include/libultra/os_thread.h @@ -0,0 +1,18 @@ +#ifndef LIBULTRA_OS_THREAD_H +#define LIBULTRA_OS_THREAD_H + +#include "types.h" +#include "dolphin/os/OSThread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void osCreateThread2(OSThread* t, int id, void(*entry)(void*), void* arg, void* stack_pointer, size_t stack_size, OSPriority priority); +extern void osStartThread(OSThread* t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/irqmgr.c b/rel/irqmgr.c new file mode 100644 index 00000000..17785fc2 --- /dev/null +++ b/rel/irqmgr.c @@ -0,0 +1,217 @@ +#include "irqmgr.h" +#include "libultra/os_thread.h" +#include "dolphin/os.h" +#include "dolphin/os/OSMessage.h" +#include "dolphin/os/OSTime.h" + +#define MSEC(x) OSMicrosecondsToTicks((x) * (OSTime)1000) + +volatile int ResetStatus; // 0x00 +volatile OSTime ResetTime; // 0x08 +volatile OSTime RetraceTime; // 0x10 +volatile int RetraceCount; // 0x18 +static irqmgr_t* this; // 0x1C +irqmgr_t irqmgr_class; + +#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 + +/** + * @brief Adds anew client to the IRQ manager with a callback message queue. + * + * @param client The new client to add + * @param msgqueue The callback message queue + **/ +extern void irqmgr_AddClient(irqmgr_client_t* client, OSMessageQueue* msgqueue) { + BOOL enable = OSDisableInterrupts(); + client->msgQueue = msgqueue; + client->next = this->clients; + this->clients = client; + OSRestoreInterrupts(enable); + + if (this->prenmi >= 1) { + osSendMesg(client->msgQueue, &this->msgPreNMI, 0); + } + if (this->prenmi >= 2) { + osSendMesg(client->msgQueue, &this->msgDelayPreNMI, 0); + } +} + +/* @unused extern void irqmgr_RemoveClient(irqmgr_client_t* client) */ + +/** + * @brief Sends a new message to all active IRQ clients. + * + * @param msg The message which will be sent + **/ +static void irqmgr_SendMesgForClient(irqmgr_mesg_t* msg) { + irqmgr_client_t* i; + OSMessageQueue* mesgq; + for (i = this->clients; i != NULL; i = i->next) { + mesgq = i->msgQueue; + if (mesgq->usedCount < mesgq->msgCount) { + osSendMesg(mesgq, msg, 0); + } + } +} + +/** + * @brief Sends a new message to all active IRQ clients. Duplicate of above. + * + * @param msg The message which will be sent + **/ +static void irqmgr_JamMesgForClient(irqmgr_mesg_t* msg) { + irqmgr_client_t* i; + OSMessageQueue* mesgq; + for (i = this->clients; i != NULL; i = i->next) { + mesgq = i->msgQueue; + if (mesgq->usedCount < mesgq->msgCount) { + osSendMesg(mesgq, msg, 0); + } + } +} + +#pragma pool_data on +/** + * @brief Handler function for pre-NMI message. + **/ +static void irqmgr_HandlePreNMI() { + ResetStatus = 1; + this->prenmi = 1; + ResetTime = this->prenmi_time = osGetTime(); + + osSetTimer(&this->timer, MSEC(400), 0, &this->_msgQueue, (OSMessage)IRQ_PRENMI450_MSG); + irqmgr_JamMesgForClient(&this->msgPreNMI); +} +#pragma pool_data reset + +/** + * @brief Handler for pre-NMI message (post 400ms). + **/ +static void irqmgr_HandlePreNMI450() { + ResetStatus = 2; + this->prenmi = 2; + osSetTimer(&this->timer, MSEC(50), 0, &this->_msgQueue, (OSMessage)IRQ_PRENMI480_MSG); + irqmgr_SendMesgForClient(&this->msgDelayPreNMI); +} + +/** + * @brief Handler for pre-NMI message (post 450ms). + **/ +static void irqmgr_HandlePreNMI480() { + osSetTimer(&this->timer, MSEC(50), 0, &this->_msgQueue, (OSMessage)IRQ_PRENMI500_MSG); +} + +/** + * @brief Handler for pre-NMI message (post 500ms). + **/ +static void irqmgr_HandlePreNMI500() {} + +#pragma pool_data on +/** + * @brief Handler for retrace message. + **/ +static void irqmgr_HandleRetrace() { + OSTime time; + if (RetraceTime == 0) { + if (this->retraceTime == 0) { + time = osGetTime(); + this->retraceTime = time; + } + else { + time = osGetTime(); + RetraceTime = time - this->retraceTime; + } + } + RetraceCount++; + irqmgr_SendMesgForClient(&this->msgRetrace); +} +#pragma pool_data reset + +/** + * @brief Main IRQ manager handler. + * + * @param arg unused OSThread func arg + **/ +static void irqmgr_Main(void* arg) { + OSMessage msg = (OSMessage)0; + + while (TRUE) { + osRecvMesg(&this->_msgQueue, &msg, 1); + switch ((u32)msg) { + case IRQ_RETRACE_MSG: + irqmgr_HandleRetrace(); + break; + case IRQ_PRENMI_MSG: + irqmgr_HandlePreNMI(); + break; + case IRQ_PRENMI450_MSG: + irqmgr_HandlePreNMI450(); + break; + case IRQ_PRENMI480_MSG: + irqmgr_HandlePreNMI480(); + break; + case IRQ_PRENMI500_MSG: + irqmgr_HandlePreNMI500(); + break; + default: + break; + } + } +} + +/** + * @brief Creates a new IRQ manager. + * + * @param stack The IRQ manager's stack + * @param stack_size The IRQ manager's stack size + * @param priority The thread's priority + * @param retracecount Taken by osViSetEvent, unused + **/ +extern void CreateIRQManager(void* stack, size_t stack_size, int priority, u8 retracecount) { + this = &irqmgr_class; + this->clients = NULL; + this->msgRetrace.type = 1; + this->msgPreNMI.type = 4; + this->msgDelayPreNMI.type = 3; + this->prenmi = 0; + this->prenmi_time = 0; + + osCreateMesgQueue(&this->_msgQueue, this->_msgBuf, 8); + osViSetEvent(&this->_msgQueue, (OSMessage)IRQ_RETRACE_MSG, retracecount); + osCreateThread2(&this->thread, 9, irqmgr_Main, NULL, stack, stack_size, priority); + osStartThread(&this->thread); +} + +/* these were probably written in a header directly and included here */ + +#define VI_STACK_SIZE 0x1000 + +static OSMessage vc_msg; +static OSMessageQueue* vc_msgq; +static u16 vc_retraceCount; +static u16 retrace; /* this probably belongs in one of the unused vi functions below */ +static u8 viThreadStack[VI_STACK_SIZE]; +static OSThread viThread; + +/* @unused ? viMgrMain(?) */ + +/* @unused ? osCreateViManager(?) */ + +#pragma pool_data on +/** + * @brief Sets the VI event info. Stubbed outside this functionality. + * + * @param msgq The OSMessageQueue which would be notified upon event invocation + * @param msg The OSMessage which would be sent upon event invocation + * @param retcount The retrace count before invoking the event + **/ +extern void osViSetEvent(OSMessageQueue* mesgq, OSMessage msg, u32 retcount) { + vc_msgq = mesgq; + vc_msg = msg; + vc_retraceCount = retcount; +} +#pragma pool_data reset