Implement irqmgr

This commit is contained in:
Cuyler36
2023-04-29 08:04:22 -04:00
parent 7581a5c5bd
commit aad0bc2f09
5 changed files with 261 additions and 3 deletions
+4
View File
@@ -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]
+1
View File
@@ -5,6 +5,7 @@
#include "types.h"
#include "dolphin/os/OSAlarm.h"
#include "dolphin/os/OSMessage.h"
#ifdef __cplusplus
extern "C" {
+21 -3
View File
@@ -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
};
+18
View File
@@ -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
+217
View File
@@ -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