diff --git a/.vscode/settings.json b/.vscode/settings.json index 72c31cd1..eda91655 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -45,7 +45,8 @@ "trees.h": "c", "musyx.h": "c", "dsp_import.h": "c", - "osinterrupt.h": "c" + "osinterrupt.h": "c", + "osmodule.h": "c" }, "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, diff --git a/asm/Dolphin/os/OSError.s b/asm/Dolphin/os/OSError.s index 58c026e9..6af16c4c 100644 --- a/asm/Dolphin/os/OSError.s +++ b/asm/Dolphin/os/OSError.s @@ -529,12 +529,12 @@ lbl_8037FFD8: /* 8038001C 0037CF7C 38 7F 02 88 */ addi r3, r31, 0x288 /* 80380020 0037CF80 4B FF F9 8D */ bl OSReport lbl_80380024: -/* 80380024 0037CF84 A8 8D AD 18 */ lha r4, lbl_805A98D8@sda21(r13) +/* 80380024 0037CF84 A8 8D AD 18 */ lha r4, __OSLastInterrupt@sda21(r13) /* 80380028 0037CF88 38 7F 02 A4 */ addi r3, r31, 0x2a4 /* 8038002C 0037CF8C 4C C6 31 82 */ crclr 6 -/* 80380030 0037CF90 80 AD AD 14 */ lwz r5, lbl_805A98D4@sda21(r13) -/* 80380034 0037CF94 80 ED AD 20 */ lwz r7, lbl_805A98E0@sda21(r13) -/* 80380038 0037CF98 81 0D AD 24 */ lwz r8, lbl_805A98E4@sda21(r13) +/* 80380030 0037CF90 80 AD AD 14 */ lwz r5, __OSLastInterruptSrr0@sda21(r13) +/* 80380034 0037CF94 80 ED AD 20 */ lwz r7, __OSLastInterruptTime@sda21(r13) +/* 80380038 0037CF98 81 0D AD 24 */ lwz r8, __OSLastInterruptTime+4@sda21(r13) /* 8038003C 0037CF9C 4B FF F9 71 */ bl OSReport /* 80380040 0037CFA0 4B FE F7 D5 */ bl PPCHalt /* 80380044 0037CFA4 BA C1 00 18 */ lmw r22, 0x18(r1) diff --git a/asm/Dolphin/os/OSInterrupt.s b/asm/Dolphin/os/OSInterrupt.s index d0d04d2a..b08eacc1 100644 --- a/asm/Dolphin/os/OSInterrupt.s +++ b/asm/Dolphin/os/OSInterrupt.s @@ -2,26 +2,24 @@ .section .sbss .balign 8 -.global lbl_805A98D0 -lbl_805A98D0: +.global InterruptHandlerTable +InterruptHandlerTable: .skip 0x4 -.global lbl_805A98D4 -lbl_805A98D4: +.global __OSLastInterruptSrr0 +__OSLastInterruptSrr0: .skip 0x4 -.global lbl_805A98D8 -lbl_805A98D8: +.global __OSLastInterrupt +__OSLastInterrupt: + .skip 0x2 + .skip 6 +.global __OSLastInterruptTime +__OSLastInterruptTime: .skip 0x8 -.global lbl_805A98E0 -lbl_805A98E0: - .skip 0x4 -.global lbl_805A98E4 -lbl_805A98E4: - .skip 0x4 .section .data .balign 8 -.global lbl_803F2260 -lbl_803F2260: +.global InterruptPrioTable +InterruptPrioTable: .4byte 0x00000100 .4byte 0x00000040 .4byte 0xF8000000 @@ -74,7 +72,7 @@ lbl_803816A0: .global __OSSetInterruptHandler __OSSetInterruptHandler: /* 803816AC 0037E60C 7C 60 07 34 */ extsh r0, r3 -/* 803816B0 0037E610 80 6D AD 10 */ lwz r3, lbl_805A98D0@sda21(r13) +/* 803816B0 0037E610 80 6D AD 10 */ lwz r3, InterruptHandlerTable@sda21(r13) /* 803816B4 0037E614 54 00 10 3A */ slwi r0, r0, 2 /* 803816B8 0037E618 7C A3 02 14 */ add r5, r3, r0 /* 803816BC 0037E61C 80 65 00 00 */ lwz r3, 0(r5) @@ -84,7 +82,7 @@ __OSSetInterruptHandler: .global __OSGetInterruptHandler __OSGetInterruptHandler: /* 803816C8 0037E628 7C 60 07 34 */ extsh r0, r3 -/* 803816CC 0037E62C 80 6D AD 10 */ lwz r3, lbl_805A98D0@sda21(r13) +/* 803816CC 0037E62C 80 6D AD 10 */ lwz r3, InterruptHandlerTable@sda21(r13) /* 803816D0 0037E630 54 00 10 3A */ slwi r0, r0, 2 /* 803816D4 0037E634 7C 63 00 2E */ lwzx r3, r3, r0 /* 803816D8 0037E638 4E 80 00 20 */ blr @@ -97,10 +95,10 @@ __OSInterruptInit: /* 803816E8 0037E648 93 E1 00 0C */ stw r31, 0xc(r1) /* 803816EC 0037E64C 3F E0 80 00 */ lis r31, 0x80003040@ha /* 803816F0 0037E650 38 1F 30 40 */ addi r0, r31, 0x80003040@l -/* 803816F4 0037E654 90 0D AD 10 */ stw r0, lbl_805A98D0@sda21(r13) +/* 803816F4 0037E654 90 0D AD 10 */ stw r0, InterruptHandlerTable@sda21(r13) /* 803816F8 0037E658 38 80 00 00 */ li r4, 0 /* 803816FC 0037E65C 38 A0 00 80 */ li r5, 0x80 -/* 80381700 0037E660 80 6D AD 10 */ lwz r3, lbl_805A98D0@sda21(r13) +/* 80381700 0037E660 80 6D AD 10 */ lwz r3, InterruptHandlerTable@sda21(r13) /* 80381704 0037E664 4B C8 1C A5 */ bl memset /* 80381708 0037E668 38 00 00 00 */ li r0, 0 /* 8038170C 0037E66C 90 1F 00 C4 */ stw r0, 0xc4(r31) @@ -619,8 +617,8 @@ lbl_80381DA8: /* 80381DB8 0037ED18 7C 04 18 78 */ andc r4, r0, r3 /* 80381DBC 0037ED1C 28 04 00 00 */ cmplwi r4, 0 /* 80381DC0 0037ED20 41 82 00 98 */ beq lbl_80381E58 -/* 80381DC4 0037ED24 3C 60 80 3F */ lis r3, lbl_803F2260@ha -/* 80381DC8 0037ED28 38 03 22 60 */ addi r0, r3, lbl_803F2260@l +/* 80381DC4 0037ED24 3C 60 80 3F */ lis r3, InterruptPrioTable@ha +/* 80381DC8 0037ED28 38 03 22 60 */ addi r0, r3, InterruptPrioTable@l /* 80381DCC 0037ED2C 7C 03 03 78 */ mr r3, r0 /* 80381DD0 0037ED30 48 00 00 04 */ b lbl_80381DD4 lbl_80381DD4: @@ -637,19 +635,19 @@ lbl_80381DF4: /* 80381DF4 0037ED54 38 63 00 04 */ addi r3, r3, 4 /* 80381DF8 0037ED58 4B FF FF E0 */ b lbl_80381DD8 lbl_80381DFC: -/* 80381DFC 0037ED5C 80 6D AD 10 */ lwz r3, lbl_805A98D0@sda21(r13) +/* 80381DFC 0037ED5C 80 6D AD 10 */ lwz r3, InterruptHandlerTable@sda21(r13) /* 80381E00 0037ED60 57 A0 10 3A */ slwi r0, r29, 2 /* 80381E04 0037ED64 7F E3 00 2E */ lwzx r31, r3, r0 /* 80381E08 0037ED68 28 1F 00 00 */ cmplwi r31, 0 /* 80381E0C 0037ED6C 41 82 00 4C */ beq lbl_80381E58 /* 80381E10 0037ED70 2C 1D 00 04 */ cmpwi r29, 4 /* 80381E14 0037ED74 40 81 00 1C */ ble lbl_80381E30 -/* 80381E18 0037ED78 B3 AD AD 18 */ sth r29, lbl_805A98D8@sda21(r13) +/* 80381E18 0037ED78 B3 AD AD 18 */ sth r29, __OSLastInterrupt@sda21(r13) /* 80381E1C 0037ED7C 48 00 35 8D */ bl OSGetTime -/* 80381E20 0037ED80 90 8D AD 24 */ stw r4, lbl_805A98E4@sda21(r13) -/* 80381E24 0037ED84 90 6D AD 20 */ stw r3, lbl_805A98E0@sda21(r13) +/* 80381E20 0037ED80 90 8D AD 24 */ stw r4, __OSLastInterruptTime+4@sda21(r13) +/* 80381E24 0037ED84 90 6D AD 20 */ stw r3, __OSLastInterruptTime@sda21(r13) /* 80381E28 0037ED88 80 1E 01 98 */ lwz r0, 0x198(r30) -/* 80381E2C 0037ED8C 90 0D AD 14 */ stw r0, lbl_805A98D4@sda21(r13) +/* 80381E2C 0037ED8C 90 0D AD 14 */ stw r0, __OSLastInterruptSrr0@sda21(r13) lbl_80381E30: /* 80381E30 0037ED90 48 00 27 B1 */ bl OSDisableScheduler /* 80381E34 0037ED94 7F A3 EB 78 */ mr r3, r29 @@ -694,4 +692,3 @@ ExternalInterruptHandler: /* 80381EC0 0037EE20 90 04 01 C0 */ stw r0, 0x1c0(r4) /* 80381EC4 0037EE24 94 21 FF F8 */ stwu r1, -8(r1) /* 80381EC8 0037EE28 4B FF FC 70 */ b __OSDispatchInterrupt - diff --git a/configure.py b/configure.py index f738fc35..2b825375 100755 --- a/configure.py +++ b/configure.py @@ -813,7 +813,7 @@ LIBS = [ "Dolphin/os/OSError", "Dolphin/os/OSFatal", "Dolphin/os/OSFont", - "Dolphin/os/OSInterrupt", + ["Dolphin/os/OSInterrupt", True], ["Dolphin/os/OSLink", True], "Dolphin/os/OSMemory", ["Dolphin/os/OSMutex", True], diff --git a/src/Dolphin/os/OSInterrupt.c b/src/Dolphin/os/OSInterrupt.c new file mode 100644 index 00000000..30b6e813 --- /dev/null +++ b/src/Dolphin/os/OSInterrupt.c @@ -0,0 +1,433 @@ +#include + +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context); + +// TODO: Move these to a more appropriate location +vu32 __PIRegs[12] : 0xCC003000; +vu32 __EXIRegs[16] : 0xCC006800; +vu16 __MEMRegs[64] : 0xCC004000; +vu16 __DSPRegs[32] : 0xCC005000; +vu32 __AIRegs[8] : 0xCC006C00; + +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +static __OSInterruptHandler* InterruptHandlerTable; + +static OSInterruptMask InterruptPrioTable[] = { + OS_INTERRUPTMASK_PI_ERROR, + OS_INTERRUPTMASK_PI_DEBUG, + OS_INTERRUPTMASK_MEM, + OS_INTERRUPTMASK_PI_RSW, + OS_INTERRUPTMASK_PI_VI, + OS_INTERRUPTMASK_PI_PE, + OS_INTERRUPTMASK_PI_HSP, + OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP | OS_INTERRUPTMASK_AI | + OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI, + OS_INTERRUPTMASK_DSP_AI, + OS_INTERRUPTMASK_PI_CP, + 0xFFFFFFFF, +}; + +asm BOOL OSDisableInterrupts(void) { + // clang-format off + nofralloc +entry __RAS_OSDisableInterrupts_begin + mfmsr r3 + rlwinm r4, r3, 0, 17, 15 + mtmsr r4 +entry __RAS_OSDisableInterrupts_end + rlwinm r3, r3, 17, 31, 31 + blr + // clang-format on +} +asm BOOL OSEnableInterrupts(void) { + // clang-format off + nofralloc + + mfmsr r3 + ori r4, r3, 0x8000 + mtmsr r4 + rlwinm r3, r3, 17, 31, 31 + blr + // clang-format on +} + +asm BOOL OSRestoreInterrupts(register BOOL level){ + // clang-format off + + nofralloc + + cmpwi level, 0 + mfmsr r4 + beq _disable + ori r5, r4, 0x8000 + b _restore +_disable: + rlwinm r5, r4, 0, 17, 15 +_restore: + mtmsr r5 + rlwinm r3, r4, 17, 31, 31 + blr + // clang-format on +} + +__OSInterruptHandler + __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler) { + __OSInterruptHandler oldHandler; + + oldHandler = InterruptHandlerTable[interrupt]; + InterruptHandlerTable[interrupt] = handler; + return oldHandler; +} + +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt) { + return InterruptHandlerTable[interrupt]; +} + +void __OSInterruptInit(void) { + InterruptHandlerTable = OSPhysicalToCached(0x3040); + memset(InterruptHandlerTable, 0, __OS_INTERRUPT_MAX * sizeof(__OSInterruptHandler)); + + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = 0; + + *(OSInterruptMask*)OSPhysicalToCached(0x00C8) = 0; + + __PIRegs[1] = 0xf0; + + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI | + OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI); + + __OSSetExceptionHandler(4, ExternalInterruptHandler); +} + +u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) { + u32 reg; + + switch (__cntlzw(mask)) { + case __OS_INTERRUPT_MEM_0: + case __OS_INTERRUPT_MEM_1: + case __OS_INTERRUPT_MEM_2: + case __OS_INTERRUPT_MEM_3: + case __OS_INTERRUPT_MEM_ADDRESS: + reg = 0; + if (!(current & OS_INTERRUPTMASK_MEM_0)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_MEM_1)) + reg |= 0x2; + if (!(current & OS_INTERRUPTMASK_MEM_2)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_MEM_3)) + reg |= 0x8; + if (!(current & OS_INTERRUPTMASK_MEM_ADDRESS)) + reg |= 0x10; + __MEMRegs[0x0000000e] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_MEM; + break; + case __OS_INTERRUPT_DSP_AI: + case __OS_INTERRUPT_DSP_ARAM: + case __OS_INTERRUPT_DSP_DSP: + reg = __DSPRegs[0x00000005]; + reg &= ~0x1F8; + if (!(current & OS_INTERRUPTMASK_DSP_AI)) + reg |= 0x10; + if (!(current & OS_INTERRUPTMASK_DSP_ARAM)) + reg |= 0x40; + if (!(current & OS_INTERRUPTMASK_DSP_DSP)) + reg |= 0x100; + __DSPRegs[0x00000005] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_DSP; + break; + case __OS_INTERRUPT_AI_AI: + reg = __AIRegs[0]; + reg &= ~0x2C; + if (!(current & OS_INTERRUPTMASK_AI_AI)) + reg |= 0x4; + __AIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_AI; + break; + case __OS_INTERRUPT_EXI_0_EXI: + case __OS_INTERRUPT_EXI_0_TC: + case __OS_INTERRUPT_EXI_0_EXT: + reg = __EXIRegs[0]; + reg &= ~0x2C0F; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_0_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXT)) + reg |= 0x400; + __EXIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_0; + break; + case __OS_INTERRUPT_EXI_1_EXI: + case __OS_INTERRUPT_EXI_1_TC: + case __OS_INTERRUPT_EXI_1_EXT: + reg = __EXIRegs[5]; + reg &= ~0xC0F; + + if (!(current & OS_INTERRUPTMASK_EXI_1_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_1_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_1_EXT)) + reg |= 0x400; + __EXIRegs[5] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_1; + break; + case __OS_INTERRUPT_EXI_2_EXI: + case __OS_INTERRUPT_EXI_2_TC: + reg = __EXIRegs[10]; + reg &= ~0xF; + if (!(current & OS_INTERRUPTMASK_EXI_2_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_2_TC)) + reg |= 0x4; + + __EXIRegs[10] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_2; + break; + case __OS_INTERRUPT_PI_CP: + case __OS_INTERRUPT_PI_SI: + case __OS_INTERRUPT_PI_DI: + case __OS_INTERRUPT_PI_RSW: + case __OS_INTERRUPT_PI_ERROR: + case __OS_INTERRUPT_PI_VI: + case __OS_INTERRUPT_PI_DEBUG: + case __OS_INTERRUPT_PI_PE_TOKEN: + case __OS_INTERRUPT_PI_PE_FINISH: + case __OS_INTERRUPT_PI_HSP: + reg = 0xF0; + + if (!(current & OS_INTERRUPTMASK_PI_CP)) { + reg |= 0x800; + } + if (!(current & OS_INTERRUPTMASK_PI_SI)) { + reg |= 0x8; + } + if (!(current & OS_INTERRUPTMASK_PI_DI)) { + reg |= 0x4; + } + if (!(current & OS_INTERRUPTMASK_PI_RSW)) { + reg |= 0x2; + } + if (!(current & OS_INTERRUPTMASK_PI_ERROR)) { + reg |= 0x1; + } + if (!(current & OS_INTERRUPTMASK_PI_VI)) { + reg |= 0x100; + } + if (!(current & OS_INTERRUPTMASK_PI_DEBUG)) { + reg |= 0x1000; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_TOKEN)) { + reg |= 0x200; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_FINISH)) { + reg |= 0x400; + } + if (!(current & OS_INTERRUPTMASK_PI_HSP)) { + reg |= 0x2000; + } + __PIRegs[1] = reg; + mask &= ~OS_INTERRUPTMASK_PI; + break; + default: + break; + } + return mask; +} + +OSInterruptMask OSGetInterruptMask(void) { return *(OSInterruptMask*)OSPhysicalToCached(0x00C8); } + +OSInterruptMask OSSetInterruptMask(OSInterruptMask local) { + BOOL enabled; + OSInterruptMask global; + OSInterruptMask prev; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + global = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = (global | prev) ^ local; + *(OSInterruptMask*)OSPhysicalToCached(0x00C8) = local; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +OSInterruptMask __OSMaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = ~(prev | local) & global; + global |= prev; + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = (prev | local) & global; + global = prev & ~global; + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +volatile OSTime __OSLastInterruptTime; +volatile __OSInterrupt __OSLastInterrupt; +volatile u32 __OSLastInterruptSrr0; + +void __OSDispatchInterrupt(__OSException exception, OSContext* context) { + u32 intsr; + u32 reg; + OSInterruptMask cause; + OSInterruptMask unmasked; + OSInterruptMask* prio; + __OSInterrupt interrupt; + __OSInterruptHandler handler; + intsr = __PIRegs[0]; + intsr &= ~0x00010000; + + if (intsr == 0 || (intsr & __PIRegs[1]) == 0) { + OSLoadContext(context); + } + + cause = 0; + + if (intsr & 0x00000080) { + reg = __MEMRegs[15]; + if (reg & 0x1) + cause |= OS_INTERRUPTMASK_MEM_0; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_MEM_1; + if (reg & 0x4) + cause |= OS_INTERRUPTMASK_MEM_2; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_MEM_3; + if (reg & 0x10) + cause |= OS_INTERRUPTMASK_MEM_ADDRESS; + } + + if (intsr & 0x00000040) { + reg = __DSPRegs[5]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_DSP_AI; + if (reg & 0x20) + cause |= OS_INTERRUPTMASK_DSP_ARAM; + if (reg & 0x80) + cause |= OS_INTERRUPTMASK_DSP_DSP; + } + + if (intsr & 0x00000020) { + reg = __AIRegs[0]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_AI_AI; + } + + if (intsr & 0x00000010) { + reg = __EXIRegs[0]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_0_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_0_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_0_EXT; + reg = __EXIRegs[5]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_1_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_1_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_1_EXT; + reg = __EXIRegs[10]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_2_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_2_TC; + } + + if (intsr & 0x00002000) + cause |= OS_INTERRUPTMASK_PI_HSP; + if (intsr & 0x00001000) + cause |= OS_INTERRUPTMASK_PI_DEBUG; + if (intsr & 0x00000400) + cause |= OS_INTERRUPTMASK_PI_PE_FINISH; + if (intsr & 0x00000200) + cause |= OS_INTERRUPTMASK_PI_PE_TOKEN; + if (intsr & 0x00000100) + cause |= OS_INTERRUPTMASK_PI_VI; + if (intsr & 0x00000008) + cause |= OS_INTERRUPTMASK_PI_SI; + if (intsr & 0x00000004) + cause |= OS_INTERRUPTMASK_PI_DI; + if (intsr & 0x00000002) + cause |= OS_INTERRUPTMASK_PI_RSW; + if (intsr & 0x00000800) + cause |= OS_INTERRUPTMASK_PI_CP; + if (intsr & 0x00000001) + cause |= OS_INTERRUPTMASK_PI_ERROR; + + unmasked = cause & ~(*(OSInterruptMask*)OSPhysicalToCached(0x00C4) | + *(OSInterruptMask*)OSPhysicalToCached(0x00C8)); + if (unmasked) { + for (prio = InterruptPrioTable;; ++prio) { + if (unmasked & *prio) { + interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio); + break; + } + } + + handler = __OSGetInterruptHandler(interrupt); + if (handler) { + if (__OS_INTERRUPT_MEM_ADDRESS < interrupt) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + OSLoadContext(context); +} + +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context) { +#pragma unused(exception) + // clang-format off + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + + stwu r1, -8(r1) + b __OSDispatchInterrupt + // clang-format on +}