//--- // gint:core:setup - Installing and unloading the library //--- #include #include #include #include #include #include #include #include /* VBR address, from the linker script */ extern char gint_vbr[]; /* System's VBR address */ GBSS static uint32_t system_vbr; /* Size of exception and TLB handler */ extern char gint_exch_tlbh_size; /* Driver table */ extern gint_driver_t bdrv, edrv; //--- // Context system for gint's core //--- typedef struct { uint16_t iprs[12]; uint8_t masks[13]; } GPACKED(2) gint_core_ctx; /* gint_ctx_save() - save interrupt controller configuration @arg ctx gint core context object */ static void gint_ctx_save(gint_core_ctx *ctx) { if(isSH3()) { for(int i = 0; i < 8; i++) ctx->iprs[i] = *(SH7705_INTC.IPRS[i]); } else { for(int i = 0; i < 12; i++) ctx->iprs[i] = SH7305_INTC.IPRS[2 * i]; uint8_t *IMR = (void *)SH7305_INTC.MSK; for(int i = 0; i < 13; i++, IMR += 4) ctx->masks[i] = *IMR; } } /* gint_ctx_restore() - restore interrupt controller configuration @arg ctx gint core context object */ static void gint_ctx_restore(gint_core_ctx *ctx) { if(isSH3()) { for(int i = 0; i < 8; i++) *(SH7705_INTC.IPRS[i]) = ctx->iprs[i]; } else { for(int i = 0; i < 12; i++) SH7305_INTC.IPRS[2 * i] = ctx->iprs[i]; /* Setting masks it a bit more involved than reading them */ uint8_t *IMCR = (void *)SH7305_INTC.MSKCLR; uint8_t *IMR = (void *)SH7305_INTC.MSK; for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4) { *IMCR = 0xff; *IMR = ctx->masks[i]; } } } //--- // Initialization and unloading //--- /* System context */ GBSS static gint_core_ctx sys_ctx; /* lock() - lock interrupts to avoid receiving unsupported signals */ static void lock(void) { /* Just disable everything, drivers will enable what they support */ if(isSH3()) for(int i = 0; i < 8; i++) *(SH7705_INTC.IPRS[i]) = 0x0000; else for(int i = 0; i < 12; i++) SH7305_INTC.IPRS[2 * i] = 0x0000; } /* gint_install() - install and start gint */ void gint_install(void) { /* VBR address, provided by the linker script */ void *vbr = (void *)&gint_vbr; /* Event handler entry points */ void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305; /* Size of the exception and TLB handlers */ uint32_t exch_tlbh_size = (uint32_t)&gint_exch_tlbh_size; /* First save the hardware configuration. This step is crucial because we don't want the system to find out about us directly manipulating the peripheral modules */ gint_ctx_save(&sys_ctx); /* Load the event handler entry points into memory */ memcpy(vbr + 0x100, gint_exch_tlbh, exch_tlbh_size); memcpy(vbr + 0x400, gint_exch_tlbh, exch_tlbh_size); memcpy(vbr + 0x600, inth_entry, 64); /* Time to switch VBR and roll! */ system_vbr = gint_setvbr((uint32_t)vbr, lock); } /* unlock() - unlock interrupts, restoring system settings */ static void unlock(void) { /* Restore all driver settings, but do it in reverse order of loading to honor the dependency system */ for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;) { if(drv->unload) drv->unload(); if(drv->ctx_restore) drv->ctx_restore(drv->sys_ctx); } gint_ctx_restore(&sys_ctx); } /* gint_unload() - unload gint and give back control to the system */ void gint_unload(void) { gint_setvbr(system_vbr, unlock); } //--- // Hot switching to operating system //--- static gint_core_ctx gint_ctx; extern gint_driver_t bdrv, edrv; static void gint_switch_out(void) { /* Save all drivers in reverse order */ for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;) { if(!drv->ctx_save || !drv->ctx_restore) continue; drv->ctx_save(drv->gint_ctx); } gint_ctx_save(&gint_ctx); /* Restore the system context */ for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;) { if(!drv->ctx_save || !drv->ctx_restore) continue; drv->ctx_restore(drv->sys_ctx); } gint_ctx_restore(&sys_ctx); } static void gint_switch_in(void) { /* Save system state again */ for(gint_driver_t *drv = &bdrv; drv < &edrv; drv++) { if(!drv->ctx_save || !drv->ctx_restore) continue; drv->ctx_save(drv->sys_ctx); } gint_ctx_save(&sys_ctx); /* Restore all drivers to their gint state */ for(gint_driver_t *drv = &bdrv; drv < &edrv; drv++) { if(!drv->ctx_save || !drv->ctx_restore) continue; drv->ctx_restore(drv->gint_ctx); } gint_ctx_restore(&gint_ctx); } /* gint_switch() - temporarily switch out of gint */ void gint_switch(void (*function)(void)) { gint_setvbr(system_vbr, gint_switch_out); if(function) function(); gint_setvbr((uint32_t)&gint_vbr, gint_switch_in); } int __Timer_Install(int id, void (*handler)(void), int delay); int __Timer_Start(int id); int __Timer_Stop(int id); int __Timer_Deinstall(int id); int __PutKeyCode(short *matrixcode); int __GetKeyWait(int *col,int *row,int type,int time,int menu,uint16_t *key); void __ClearKeyBuffer(void); /* ? */ void *__GetVRAMAddress(void); static int __osmenu_id; static void __osmenu_handler(void) { short matrixcode = 0x0308; __PutKeyCode(&matrixcode); __Timer_Stop(__osmenu_id); __Timer_Deinstall(__osmenu_id); } static void __osmenu(void) { __ClearKeyBuffer(); memcpy(__GetVRAMAddress(), gint_vram, 1024); __osmenu_id = __Timer_Install(0, __osmenu_handler, 0 /* ms */); if(__osmenu_id <= 0) return; __Timer_Start(__osmenu_id); int column, row; unsigned short keycode; __GetKeyWait(&column, &row, 0, 0 /* s */, 0, &keycode); } /* gint_osmenu() - switch out of gint and call the calculator's main menu */ void gint_osmenu(void) { /* TODO: return to menu on fxcg50 */ #ifdef FX9860G gint_switch(__osmenu); #endif }