From 78fbe9e37995f2f7e6af4e800bd22e96ce22d797 Mon Sep 17 00:00:00 2001 From: sozud <122322823+sozud@users.noreply.github.com> Date: Sat, 25 Jan 2025 22:09:19 -0800 Subject: [PATCH] intr.c (#7) * intr.c * updates --- build.py | 1 + src/etc/etc.h | 65 ++++++++++++++++ src/etc/intr.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 src/etc/etc.h create mode 100644 src/etc/intr.c diff --git a/build.py b/build.py index 449e59a..85c5ad4 100644 --- a/build.py +++ b/build.py @@ -243,6 +243,7 @@ def build_35(): 'src/etc/intr_vb.c', 'src/etc/pad.c', 'src/etc/vmode.c', + 'src/etc/intr.c' ] add_lib_263(etc_srcs, "build/3.5/etc", "./psy-q/3.5/PSX/LIB/LIBETC.LIB", "-DVERSION=35", "3.5") diff --git a/src/etc/etc.h b/src/etc/etc.h new file mode 100644 index 0000000..01e35fc --- /dev/null +++ b/src/etc/etc.h @@ -0,0 +1,65 @@ +#ifndef LIBETC_H +#define LIBETC_H + +#define JB_PC 0 +#define JB_SP 1 +#define JB_FP 2 +#define JB_S0 3 +#define JB_S1 4 +#define JB_S2 5 +#define JB_S3 6 +#define JB_S4 7 +#define JB_S5 8 +#define JB_S6 9 +#define JB_S7 10 +#define JB_GP 11 +#define JB_SIZE 12 + +typedef int jmp_buf[JB_SIZE]; +typedef void (*Callback)(); +struct intrEnv_t { + u16 interruptsInitialized; // 2 + u16 inInterrupt; // 2 + Callback handlers[11]; // 44 + u16 enabledInterruptsMask; // 2 + u16 savedMask; // 2 + struct Temp { + int savedPcr; // 4 + jmp_buf buf; // 48 + s32 stack[1024]; + } temp; +}; + +struct Callbacks { + const char* rcsid; /* "$Id: intr.c,v 1.73 1995/11/10 05:29:40 suzu Exp $" */ + void* (*DMACallback)(int dma, void (*func)()); + Callback (*InterruptCallback)(int irq, Callback f); + void* (*ResetCallback)(void); + void* (*StopCallback)(void); + int (*VSyncCallbacks)(int ch, void (*f)()); + void* (*RestartCallback)(void); + void* D_8002C2B8; +}; + +extern struct Callbacks* D_8002D340; + +void VSyncCallback(void (*f)()); /* 13 */ + +extern void ChangeClearPAD(long); /* 28 */ + +int VSync(int mode); +int VSyncCallbacks(int ch, void (*f)()); + +void* DMACallback(int dma, void (*func)()); +void* ResetCallback(void); +void* StopCallback(void); +void* RestartCallback(void); +int CheckCallback(void); + +long SetVideoMode(long mode); + +void PadInit(int mode); +u_long PadRead(int id); +void PadStop(void); + +#endif diff --git a/src/etc/intr.c b/src/etc/intr.c new file mode 100644 index 0000000..e778c96 --- /dev/null +++ b/src/etc/intr.c @@ -0,0 +1,201 @@ +#include "../types.h" +#include "etc.h" + +typedef struct intrEnv_t intrEnv_t; +static Callback setIntr(s32 arg0, Callback arg1); +static void* startIntr(); +static void* stopIntr(); +static void* restartIntr(); +static void memclr(void* ptr, s32 size); +static void trapIntr(); +s32 setjmp(s32*); +void* startIntrVSync(); /* extern */ +long long startIntrDMA(); + +static struct intrEnv_t intrEnv = { + 0, // interruptsInitialized + 0, // inInterrupt + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, // handlers (explicit zeros for each element) + 0, // enabledInterruptsMask + 0, // savedMask + {0}, // temp +}; + +static struct Callbacks callbacks = { + "$Id: intr.c,v 1.73 1995/11/10 05:29:40 suzu Exp $", + 0, + setIntr, + startIntr, + stopIntr, + 0, + restartIntr, + &intrEnv}; + +static struct Callbacks* pCallbacks = &callbacks; + +void* ResetCallback(void) { return pCallbacks->ResetCallback(); } + +void InterruptCallback(int irq, void (*f)()) { + pCallbacks->InterruptCallback(irq, f); +} + +void* DMACallback(int dma, void (*func)()) { + return pCallbacks->DMACallback(dma, func); +} + +void VSyncCallback(void (*f)()) { pCallbacks->VSyncCallbacks(0, f); } + +int VSyncCallbacks(int ch, void (*f)()) { + return pCallbacks->VSyncCallbacks(ch, f); +} + +void* StopCallback(void) { return pCallbacks->StopCallback(); } + +void* RestartCallback(void) { return pCallbacks->RestartCallback(); } + +int CheckCallback(void) { return intrEnv.inInterrupt; } + +static volatile u16* i_mask = (u16*)0x1F801070; +static volatile u16* g_InterruptMask = (u16*)0x1F801074; +static volatile s32* d_pcr = (s32*)0x1F8010F0; + +u16 GetIntrMask(void) { return *g_InterruptMask; } + +u16 SetIntrMask(u16 arg0) { + u16 mask; + + mask = *g_InterruptMask; + *g_InterruptMask = arg0; + return mask; +} + +void* startIntr() { + if (intrEnv.interruptsInitialized != 0) { + return NULL; + } + *i_mask = *g_InterruptMask = 0; + *d_pcr = 0x33333333; + memclr(&intrEnv, sizeof(intrEnv) / sizeof(s32)); + if (setjmp(intrEnv.temp.buf) != 0) { + trapIntr(); + } + intrEnv.temp.buf[JB_SP] = (s32)&intrEnv.temp.stack[1004]; + HookEntryInt((u16*)intrEnv.temp.buf); + intrEnv.interruptsInitialized = 1; + pCallbacks->VSyncCallbacks = startIntrVSync(); + pCallbacks->DMACallback = startIntrDMA(); + _96_remove(); + ExitCriticalSection(); + return &intrEnv; +} + +static s32 D_8002D350 = 0; + +void trapIntr() { + s32 i; + u16 mask; + + if (intrEnv.interruptsInitialized == 0) { + printf("unexpected interrupt(%04x)\n", *i_mask); + ReturnFromException(); + } + intrEnv.inInterrupt = 1; + mask = (intrEnv.enabledInterruptsMask & *i_mask) & *g_InterruptMask; + while (mask != 0) { + for (i = 0; mask && i < 11; ++i, mask >>= 1) { + if (mask & 1) { + *i_mask = ~(1 << i); + if (intrEnv.handlers[i] != NULL) { + intrEnv.handlers[i](); + } + } + } + mask = (intrEnv.enabledInterruptsMask & *i_mask) & *g_InterruptMask; + } + if (*i_mask & *g_InterruptMask) { + if (D_8002D350++ > 0x800) { + printf("intr timeout(%04x:%04x)\n", *i_mask, *g_InterruptMask); + D_8002D350 = 0; + *i_mask = 0; + } + } else { + D_8002D350 = 0; + } + intrEnv.inInterrupt = 0; + ReturnFromException(); +} + +Callback setIntr(s32 arg0, Callback arg1) { + Callback temp_s4; + u16 temp_v1; + s32 var_s3; + + temp_s4 = intrEnv.handlers[arg0]; + if ((arg1 != temp_s4) && (intrEnv.interruptsInitialized != 0)) { + temp_v1 = *g_InterruptMask; + *g_InterruptMask = 0; + var_s3 = temp_v1 & 0xFFFF; + if (arg1 != 0) { + intrEnv.handlers[arg0] = arg1; + var_s3 = var_s3 | (1 << arg0); + intrEnv.enabledInterruptsMask |= (1 << arg0); + } else { + intrEnv.handlers[arg0] = 0; + var_s3 = var_s3 & ~(1 << arg0); + intrEnv.enabledInterruptsMask &= ~(1 << arg0); + } + if (arg0 == 0) { + ChangeClearPAD(arg1 == 0); + ChangeClearRCnt(3, arg1 == 0); + } + if (arg0 == 4) { + ChangeClearRCnt(0, arg1 == 0); + } + if (arg0 == 5) { + ChangeClearRCnt(1, arg1 == 0); + } + if (arg0 == 6) { + ChangeClearRCnt(2, arg1 == 0); + } + *g_InterruptMask = var_s3; + } + return temp_s4; +} + +void* stopIntr() { + if (intrEnv.interruptsInitialized == 0) { + return NULL; + } + EnterCriticalSection(); + intrEnv.savedMask = *g_InterruptMask; + intrEnv.temp.savedPcr = *d_pcr; + *i_mask = *g_InterruptMask = 0; + *d_pcr &= 0x77777777; + ResetEntryInt(); + intrEnv.interruptsInitialized = 0; + return &intrEnv; +} + +void* restartIntr() { + if (intrEnv.interruptsInitialized != 0) { + return 0; + } + + HookEntryInt((u16*)intrEnv.temp.buf); + intrEnv.interruptsInitialized = 1; + *g_InterruptMask = intrEnv.savedMask; + *d_pcr = intrEnv.temp.savedPcr; + ExitCriticalSection(); + return &intrEnv; +} + +void memclr(void* ptr, s32 size) { + s32 i; + s32* e = (s32*)ptr; + + for (i = size - 1; i != -1; i--) { + *e = 0; + e++; + } +}