#include #include #include #include #include #include #include #include #include #include void __Reset(void); #define dprint(x, y, ...) dprint(x, y, C_BLACK, __VA_ARGS__) #define dtext(x, y, str) dtext (x, y, C_BLACK, str) /* Weak implementation of driver functions, which are used if the keyboard and display drivers are not linked in. This allows add-ins to not link in these drivers (which is useful for low-level debugging). */ GWEAK void _WEAK_dupdate(void) { return; } GWEAK keydev_t *_WEAK_keydev_std(void) { return NULL; } GWEAK bool _WEAK_keydev_keydown(GUNUSED keydev_t *d, GUNUSED int key) { return false; } GWEAK key_event_t _WEAK_keydev_unqueue_event(GUNUSED keydev_t *d) { return (key_event_t){ .type = KEYEV_NONE }; } /* gint_panic_default(): Default panic handler */ GNORETURN static void gint_default_panic(GUNUSED uint32_t code) { uint32_t TEA, TRA; keydev_t *kd = _WEAK_keydev_std(); if(isSH3()) { TEA = *(volatile uint32_t *)0xfffffffc; TRA = *(volatile uint32_t *)0xffffffd0 >> 2; } else { TEA = *(volatile uint32_t *)0xff00000c; TRA = *(volatile uint32_t *)0xff000020 >> 2; } uint32_t PC; __asm__("stc spc, %0" : "=r"(PC)); uint32_t SGR = 0xffffffff; if(isSH4()) __asm__("stc sgr, %0" : "=r"(SGR)); dfont(NULL); #ifdef FX9860G memset(gint_vram, 0, 1024); dtext(1, 0, "Exception! (SysERROR)"); for(int i = 0; i < 32; i++) gint_vram[i] = ~gint_vram[i]; char const *name = ""; if(code == 0x040) name = "TLB miss read"; if(code == 0x060) name = "TLB miss write"; if(code == 0x0e0) name = "Read address error"; if(code == 0x100) name = "Write address error"; if(code == 0x160) name = "Unconditional trap"; if(code == 0x180) name = "Illegal instruction"; if(code == 0x1a0) name = "Illegal delay slot"; /* Custom gint codes for convenience */ if(code == 0x1020) name = "DMA address error"; if(code == 0x1040) name = "Add-in too large"; if(code == 0x1060) name = "Memory init failed"; if(code == 0x1080) name = "Stack overflow"; if(name[0]) dtext(1, 9, name); else dprint(1, 9, "%03x", code); dprint(1, 17, " PC:%08x TRA:%d", PC, TRA); dprint(1, 25, "TEA:%08x", TEA); dtext(1, 33, "The add-in crashed."); if(kd == NULL) { dtext(1, 41, "Please reset the calc"); } else { dtext(1, 41, "[EXIT]:Quit add-in"); dtext(1, 49, "[MENU]:Main menu"); dtext(1, 57, "[F1]+[F6]: RESET calc"); } #endif #ifdef FXCG50 /* Don't require the DMA driver just for a clear */ memset(gint_vram, 0xff, DWIDTH*DHEIGHT*2); dtext(6, 3, "An exception occured! (System ERROR)"); uint32_t *long_vram = (void *)gint_vram; for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i]; char const *name = ""; if(code == 0x040) name = "TLB miss (nonexisting address) on read"; if(code == 0x060) name = "TLB miss (nonexisting address) on write"; if(code == 0x0e0) name = "Read address error (probably alignment)"; if(code == 0x100) name = "Write address error (probably alignment)"; if(code == 0x160) name = "Unconditional trap"; if(code == 0x180) name = "Illegal instruction"; if(code == 0x1a0) name = "Illegal delay slot instruction"; /* Custom gint codes for convenience */ if(code == 0x1020) name = "DMA address error"; if(code == 0x1040) name = "Add-in not fully mapped (too large)"; if(code == 0x1060) name = "Memory initialization failed (heap)"; if(code == 0x1080) name = "Stack overflow during world switch"; dprint(6, 25, "%03x %s", code, name); dtext(6, 45, "PC"); dprint(38, 45, "= %08x", PC); dtext(261, 45, "(Error location)"); dtext(6, 60, "TEA"); dprint(38, 60, "= %08x", TEA); dtext(234, 60, "(Offending address)"); dtext(6, 75, "TRA"); dprint(38, 75, "= %#x", TRA); dtext(281, 75, "(Trap number)"); dtext(6, 95, "The add-in crashed!"); if(kd == NULL) { dtext(6, 108, "Please press the RESET button to restart the"); dtext(6, 121, "calculator."); } else { dtext(6, 121, "[EXIT]: Exit the program with abort()"); dtext(6, 134, "[MENU]: Leave to main menu"); dtext(6, 147, "[F1]+[F6]: RESET the calculator"); } /* DMA address error handler */ if(code == 0x1020) { #define DMA SH7305_DMA dprint(6, 167, "SAR0: %08x DAR0: %08x TCR0: %08x", DMA.DMA0.SAR, DMA.DMA0.DAR, DMA.DMA0.TCR); dprint(6, 180, "CHCR0: %08x", DMA.DMA0.CHCR); dprint(6, 193, "SAR1: %08x DAR1: %08x TCR1: %08x", DMA.DMA1.SAR, DMA.DMA1.DAR, DMA.DMA1.TCR); dprint(6, 206, "CHCR1: %08x DMAOR:%04x", DMA.DMA1.CHCR, DMA.OR); #undef DMA } /* Illegal instruction handler */ if(code == 0x180) { uint16_t *opcodes = (void *)PC; dprint(6, 160, "Opcodes: %04x %04x [%04x] %04x", opcodes[-2], opcodes[-1], opcodes[0], opcodes[1]); } #endif _WEAK_dupdate(); /* Make sure relevant keys are released before taking in events; we don't want the user to RESET through this screen by holding a key */ bool has_released = false; while(1) { while(_WEAK_keydev_unqueue_event(kd).type != KEYEV_NONE) {} bool exit = _WEAK_keydev_keydown(kd, KEY_EXIT); bool menu = _WEAK_keydev_keydown(kd, KEY_MENU); bool f1 = _WEAK_keydev_keydown(kd, KEY_F1); bool f6 = _WEAK_keydev_keydown(kd, KEY_F6); if(has_released && exit) abort(); if(has_released && menu) gint_osmenu(); if(has_released && f1 && f6) __Reset(); if(!exit && !menu && !f1 && !f6) has_released = true; sleep(); } } /* Panic handler */ GNORETURN void (*gint_exc_panic)(uint32_t code) = gint_default_panic; /* Exception catcher */ int (*gint_exc_catcher)(uint32_t code) = NULL; /* gint_panic(): Panic handler function */ void gint_panic(uint32_t code) { gint_exc_panic(code); } /* gint_panic_set(): Change the panic handler function */ void gint_panic_set(GNORETURN void (*panic)(uint32_t code)) { gint_exc_panic = panic ? panic : gint_default_panic; } /* gint_exc_catch(): Set a function to catch exceptions */ void gint_exc_catch(int (*handler)(uint32_t code)) { gint_exc_catcher = handler; } /* gint_exc_skip(): Skip pending exception instructions */ void gint_exc_skip(int instructions) { uint32_t spc; /* Increase SPC by 2 bytes per instruction */ __asm__("stc spc, %0" : "=r"(spc)); spc += 2 * instructions; __asm__("ldc %0, spc" :: "r"(spc)); }