diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ba7b92..43a523d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ set(SOURCES src/gint/bopti.c src/gint/cpumem.c src/gint/dma.c + src/gint/drivers.c src/gint/dsp.c src/gint/dsp.s src/gint/dump.c @@ -31,7 +32,6 @@ set(SOURCES src/gint/ram.c src/gint/rtc.c src/gint/spuram.c - src/gint/switch.c src/gint/timer.c src/gint/timer_callbacks.c src/gint/tlb.c @@ -70,6 +70,8 @@ set(ASSETS_fx assets-fx/img/opt_dump.png assets-fx/img/opt_gint_bopti.png assets-fx/img/opt_gint_cpumem.png + assets-fx/img/opt_gint_dma.png + assets-fx/img/opt_gint_drivers.png assets-fx/img/opt_gint_gray.png assets-fx/img/opt_gint_keyboard.png assets-fx/img/opt_gint_kmalloc.png @@ -84,10 +86,9 @@ set(ASSETS_fx assets-fx/img/opt_main.png assets-fx/img/opt_mem.png assets-fx/img/opt_perf_libprof.png + assets-fx/img/opt_perf_memory.png + assets-fx/img/opt_perf_memory_sh3.png assets-fx/img/opt_perf_render.png - assets-fx/img/opt_switch_ctx.png - assets-fx/img/opt_switch_ctx_sh3.png - assets-fx/img/opt_switch.png assets-fx/img/profile_gray_alpha.png assets-fx/img/profile_gray.png assets-fx/img/profile_mono_alpha.png diff --git a/assets-fx/img/opt_gint_dma.png b/assets-fx/img/opt_gint_dma.png new file mode 100644 index 0000000..0eb10dc Binary files /dev/null and b/assets-fx/img/opt_gint_dma.png differ diff --git a/assets-fx/img/opt_gint_drivers.png b/assets-fx/img/opt_gint_drivers.png new file mode 100644 index 0000000..0f7a23d Binary files /dev/null and b/assets-fx/img/opt_gint_drivers.png differ diff --git a/assets-fx/img/opt_perf_memory.png b/assets-fx/img/opt_perf_memory.png new file mode 100644 index 0000000..8c187ef Binary files /dev/null and b/assets-fx/img/opt_perf_memory.png differ diff --git a/assets-fx/img/opt_perf_memory_sh3.png b/assets-fx/img/opt_perf_memory_sh3.png new file mode 100644 index 0000000..59176a6 Binary files /dev/null and b/assets-fx/img/opt_perf_memory_sh3.png differ diff --git a/assets-fx/img/opt_switch.png b/assets-fx/img/opt_switch.png deleted file mode 100644 index 88d8b4d..0000000 Binary files a/assets-fx/img/opt_switch.png and /dev/null differ diff --git a/assets-fx/img/opt_switch_ctx.png b/assets-fx/img/opt_switch_ctx.png deleted file mode 100644 index ad1e606..0000000 Binary files a/assets-fx/img/opt_switch_ctx.png and /dev/null differ diff --git a/assets-fx/img/opt_switch_ctx_sh3.png b/assets-fx/img/opt_switch_ctx_sh3.png deleted file mode 100644 index c8c7c6f..0000000 Binary files a/assets-fx/img/opt_switch_ctx_sh3.png and /dev/null differ diff --git a/include/gintctl/assets.h b/include/gintctl/assets.h index 7490967..6d4b999 100644 --- a/include/gintctl/assets.h +++ b/include/gintctl/assets.h @@ -25,6 +25,7 @@ extern bopti_image_t img_opt_dump, img_opt_gint_bopti, img_opt_gint_cpumem, + img_opt_gint_drivers, img_opt_gint_gray, img_opt_gint_keyboard, img_opt_gint_kmalloc, @@ -39,10 +40,9 @@ extern bopti_image_t img_opt_main, img_opt_mem, img_opt_perf_libprof, + img_opt_perf_memory, + img_opt_perf_memory_sh3, img_opt_perf_render, - img_opt_switch_ctx, - img_opt_switch_ctx_sh3, - img_opt_switch, img_profile_gray_alpha, img_profile_gray, img_profile_mono_alpha, diff --git a/include/gintctl/gint.h b/include/gintctl/gint.h index 9c4263f..fc6c56f 100644 --- a/include/gintctl/gint.h +++ b/include/gintctl/gint.h @@ -20,8 +20,8 @@ void gintctl_gint_spuram(void); /* gintctl_gint_dump(): Dump memory to filesystem */ void gintctl_gint_dump(void); -/* gintctl_gint_switch(): Test the gint switch-in-out procedures */ -void gintctl_gint_switch(void); +/* gintctl_gint_drivers(): Test the gint driver logic and world switch */ +void gintctl_gint_drivers(void); /* gintctl_gint_tlb(): TLB miss handler and TLB management */ void gintctl_gint_tlb(void); @@ -35,6 +35,9 @@ void gintctl_gint_timer(void); /* gintctl_gint_timer_callbacks(): Stunts in the environment of callbacks */ void gintctl_gint_timer_callbacks(void); +/* gintctl_gint_dma(): Test the Direct Access Memory Controller */ +void gintctl_gint_dma(void); + /* gintctl_gint_rtc(): Configure RTC and check timer speed */ void gintctl_gint_rtc(void); @@ -50,13 +53,6 @@ void gintctl_gint_kmalloc(void); /* gintctl_gint_usb(): USB communication */ void gintctl_gint_usb(void); -#ifdef FXCG50 - -/* gintctl_gint_dma(): Test the Direct Access Memory Controller */ -void gintctl_gint_dma(void); - -#endif /* FXCG50 */ - #ifdef FX9860G /* gintctl_gint_gray(): Gray engine tuning */ diff --git a/src/gint/dma.c b/src/gint/dma.c index 7d6f2b4..8ad5e74 100644 --- a/src/gint/dma.c +++ b/src/gint/dma.c @@ -3,28 +3,26 @@ #include #include #include +#include #include #include -#ifdef FXCG50 - #define DMA SH7305_DMA #define dprint(x, y, ...) dprint(x, y, C_BLACK, __VA_ARGS__) -void show_dma(int x, int y, int channel, sh7305_dma_channel_t *dma) +void show_dma(int x, int y, GUNUSED int channel, sh7305_dma_channel_t *dma) { #ifdef FX9860G - dma->SAR = 0x12345678; - dma->DAR = 0x9abcdef0; - dma->TCR = 0x12481248; - int dx=60, dy=8; - dprint(x, y, "DMA%d:", channel); - dprint(x, y+1*dy, "%08X", (uint32_t)dma); + dprint(x, y, "SAR:"); + dprint(x, y+1*dy, "DAR:"); + dprint(x, y+2*dy, "TCR:"); + dprint(x, y+3*dy, "CHCR:"); + dprint(x+dx, y, "%08X", dma->SAR); dprint(x+dx, y+1*dy, "%08X", dma->DAR); - dprint(x, y+2*dy, "%08X", dma->TCR); - dprint(x+dx, y+2*dy, "%08X", dma->CHCR); + dprint(x+dx, y+2*dy, "%08X", dma->TCR); + dprint(x+dx, y+3*dy, "%08X", dma->CHCR); #endif #ifdef FXCG50 @@ -44,28 +42,30 @@ void show_dma(int x, int y, int channel, sh7305_dma_channel_t *dma) /* gintctl_gint_dma(): Test the Direct Access Memory Controller */ void gintctl_gint_dma(void) { - /* Here we'll display the DMA status at "full speed", only limited by - the dupdate() time. */ - int key = 0, timeout = 1; - - /* Test channel, interrupts, and source */ - int channel = 0, interrupts = 0, source = 0; - /* Number of successful attempts */ - int successes = 0; + /* We'll display the DMA status at "full speed", without sleeping. */ + int key=0, timeout=1; + /* Test channel, interrupts, and source; successful attempts */ + int channel=0, interrupts=0, source=0, successes=0; + /* Get the physical VRAM address */ + void *vram_address = gint_vram; #ifdef FX9860G - /* Currently visible channel */ - int view = 0; + uint32_t virt_page = (uint32_t)vram_address & 0xfffff000; + uint32_t phys_page = 0x80000000 + mmu_translate(virt_page, NULL); + vram_address = (void *)phys_page + (vram_address - (void *)virt_page); #endif + sh7305_dma_channel_t *addr[6] = { + &DMA.DMA0, &DMA.DMA1, &DMA.DMA2, &DMA.DMA3, &DMA.DMA4, &DMA.DMA5, + }; + while(key != KEY_EXIT) { dclear(C_WHITE); #ifdef FX9860G - show_dma(1, 1, view); - - dprint(1, 32, "Channel %d", channel); + show_dma(1, 0, channel, addr[channel]); + dprint(1, 32, "Channel DMA%d", channel); dprint(1, 40, "Interrupts %s", interrupts ? "Yes" : "No"); dprint(1, 48, "Source %s", source ? "IL" : "RAM"); dprint(103, 40, "%d", successes); @@ -75,11 +75,6 @@ void gintctl_gint_dma(void) #endif #ifdef FXCG50 - sh7305_dma_channel_t *addr[6] = { - &DMA.DMA0, &DMA.DMA1, &DMA.DMA2, - &DMA.DMA3, &DMA.DMA4, &DMA.DMA5, - }; - row_title("Direct Memory Access status"); show_dma(6, 24, 0, addr[0]); @@ -105,11 +100,11 @@ void gintctl_gint_dma(void) dupdate(); key = getkey_opt(GETKEY_DEFAULT, &timeout).key; - /* On F1, start a DMA transfer and see what happens */ + /* On F1, start a 1024-byte DMA transfer and see what happens */ if(key == KEY_F1) { void *src = (void *)(source ? 0xe5200000 : 0x88000000); - void *dst = gint_vram; + void *dst = vram_address; int blocks = 256; if(interrupts) @@ -124,16 +119,8 @@ void gintctl_gint_dma(void) successes++; } - #ifdef FX9860G - /* On F2, switch the visible channel */ - if(key == KEY_F2) view = (view + 1) % 6; - #endif - - /* On F4, F5 and F6, change parameters */ if(key == KEY_F4) channel = (channel + 1) % 6; if(key == KEY_F5) interrupts = !interrupts; if(key == KEY_F6) source = !source; } } - -#endif /* FXCG50 */ diff --git a/src/gint/drivers.c b/src/gint/drivers.c new file mode 100644 index 0000000..d5ed77d --- /dev/null +++ b/src/gint/drivers.c @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//--- +// Driver list and information +//--- + +static void draw_list(int offset, int maximum) +{ + #ifdef FXCG50 + row_print(1, 2, "Id"); + row_print(1, 5, "Name"); + row_print(1, 13, "Size"); + row_print(1, 18, "Flags"); + #endif + + font_t const *old_font = dfont(_(&font_mini, dfont_default())); + + for(int i=offset; i < (int)gint_driver_count() && i < offset+maximum; i++) + { + gint_driver_t *d = &gint_drivers[i]; + uint8_t flags = gint_driver_flags[i]; + int y = _(10+6*(i-offset), row_y(i-offset+2)); + + dprint(_( 2,row_x(2)), y, C_BLACK, "%d", i); + dprint(_(12,row_x(5)), y, C_BLACK, "%s", d->name); + dprint(_(36,row_x(13)), y, C_BLACK, "%d", d->state_size); + dprint(_(52,row_x(18)), y, C_BLACK, "%s%s%s", + (flags & GINT_DRV_CLEAN) ? "CLEAN " : "", + (flags & GINT_DRV_FOREIGN_POWERED) ? _("FP ","FOREIGN_POW. ") : "", + (flags & GINT_DRV_SHARED) ? "SHARED " : "" + ); + } + + dfont(old_font); + + if((int)gint_driver_count() > maximum) scrollbar_px(_(8,50), _(55,200), 0, + gint_driver_count(), offset, maximum); +} + +//--- +// State management +//--- + +static void draw_state(gint_world_t world, int i) +{ + font_t const *old_font = dfont(_(&font_mini, dfont_default())); + + if(i > 0) + dprint(_(86,10), _(57,row_y(1)), C_BLACK, "<"); + if(i < (int)gint_driver_count() - 1) + dprint(DWIDTH - _(4,16), _(57,row_y(1)), C_BLACK, ">"); + + dprint_opt(_(106, DWIDTH / 2), _(57, row_y(1)), C_BLACK, C_NONE, + DTEXT_CENTER, DTEXT_TOP, "%s", gint_drivers[i].name); + + if(gint_driver_flags[i] & GINT_DRV_SHARED) + { + dprint_opt(DWIDTH / 2, DHEIGHT / 2, C_BLACK, C_NONE, DTEXT_CENTER, + DTEXT_MIDDLE, "Device is shared"); + return; + } + if(world == gint_world_addin && (gint_driver_flags[i] & GINT_DRV_CLEAN)) + { + dprint_opt(DWIDTH / 2, DHEIGHT / 2, C_BLACK, C_NONE, DTEXT_CENTER, + DTEXT_MIDDLE, "Device is clean"); + return; + } + + if(!strcmp(gint_drivers[i].name, "CPG")) + { + cpg_state_t const *s = world[i]; + if(isSH3()) row_print(_(1,3), 1, "No state"); + else row_print(_(1,3), 1, "SSCGCR: %08X", s->SSCGCR); + } + else if(!strcmp(gint_drivers[i].name, "CPU")) + { + cpu_state_t const *s = world[i]; + row_print(_(1,3), 1, "SR: %08X", s->SR); + row_print(_(2,4), 1, "VBR: %08X", s->VBR); + row_print(_(3,5), 1, "CPUOPM: %08X", s->CPUOPM); + } + else if(!strcmp(gint_drivers[i].name, "DMA")) + { + dma_state_t const *s = world[i]; + + #ifdef FX9860G + for(int i = 0; i < 6; i++) { + dprint(1, 1+6*i, C_BLACK, "%d: %08X->%08X %08X", + i, s->ch[i].SAR, s->ch[i].DAR, s->ch[i].CHCR); + } + dprint(1, 43, C_BLACK, "OR: %08X", s->OR); + #endif + + #ifdef FXCG50 + for(int i = 0; i < 6; i++) { + int y=3+5*(i/3), x=1+16*(i%3); + row_print(y, x, "%d:", i); + row_print(y, x+2, "SAR"); + row_print(y, x+7, "%08X", s->ch[i].SAR); + row_print(y+1, x+2, "DAR"); + row_print(y+1, x+7, "%08X", s->ch[i].DAR); + row_print(y+2, x+2, "TCR"); + row_print(y+2, x+7, "%08X", s->ch[i].TCR); + row_print(y+3, x+2, "CHCR"); + row_print(y+3, x+7, "%08X", s->ch[i].CHCR); + } + row_print(13, 1, "OR: %08X\n", s->OR); + #endif + } + else if(!strcmp(gint_drivers[i].name, "INTC")) + { + intc_state_t const *s = world[i]; + + #ifdef FX9860G + for(int i = 0; i < 12; i++) { + dprint(1+32*(i%4),1+6*(i/4), C_BLACK, "%c:%04X", 'A'+i, s->IPR[i]); + } + for(int i = 0; i < 13; i++) { + dprint(1+32*(i%4),25+6*(i/4), C_BLACK, "%d:%02X", i, s->MSK[i]); + } + #endif + + #ifdef FXCG50 + for(int i = 0; i < 12; i++) { + row_print(3+i/4, 1+11*(i%4), "IPR%c:", 'A'+i); + row_print(3+i/4, 6+11*(i%4), "%04X", s->IPR[i]); + } + for(int i = 0; i < 13; i++) { + row_print(7+i/4, 1+11*(i%4), "IMR%d:", i); + row_print(7+i/4, 7+11*(i%4), "%02X", s->MSK[i]); + } + #endif + } + else if(!strcmp(gint_drivers[i].name, "KEYSC")) + { + row_print(_(1,3), 1, "No state"); + } + else if(!strcmp(gint_drivers[i].name, "MMU")) + { + mmu_state_t const *s = world[i]; + row_print(_(1,3), 1, "PASCR: %08X", s->PASCR); + row_print(_(2,4), 1, "IRMCR: %08X", s->IRMCR); + } + else if(!strcmp(gint_drivers[i].name, "R61524")) + { + r61524_state_t const *s = world[i]; + row_print(3, 1, "HSA..HEA: %d..%d", s->HSA, s->HEA); + row_print(4, 1, "VSA..VEA: %d..%d", s->VSA, s->VEA); + } + else if(!strcmp(gint_drivers[i].name, "RTC")) + { + rtc_state_t const *s = world[i]; + row_print(_(1,3), 1, "RCR1: %02X RCR2: %02X", s->RCR1, s->RCR2); + } + else if(!strcmp(gint_drivers[i].name, "SPU")) + { + spu_state_t const *s = world[i]; + + #ifdef FX9860G + dprint(1, 1, C_BLACK, "PBANKC0: %08X", s->PBANKC0); + dprint(1, 7, C_BLACK, "PBANKC1: %08X", s->PBANKC1); + dprint(1, 13, C_BLACK, "XBANKC0: %08X", s->XBANKC0); + dprint(1, 19, C_BLACK, "XBANKC1: %08X", s->XBANKC1); + #endif + + #ifdef FXCG50 + row_print(3,1, "PBANKC0: %08X PBANKC1: %08X", s->PBANKC0, s->PBANKC1); + row_print(4,1, "XBANKC0: %08X XBANKC1: %08X", s->XBANKC0, s->XBANKC1); + #endif + } + else if(!strcmp(gint_drivers[i].name, "T6K11")) + { + t6k11_state_t const *s = world[i]; + dprint(1, 1, C_BLACK, "STRD: %02X", s->STRD); + dprint(1, 7, C_BLACK, "RESET:%d", (s->STRD & 0x08) != 0); + dprint(1, 13, C_BLACK, "N/F:%d", (s->STRD & 0x04) != 0); + dprint(1, 19, C_BLACK, "X/Y:%d", (s->STRD & 0x02) != 0); + dprint(1, 25, C_BLACK, "U/D:%d", (s->STRD & 0x01) != 0); + } + else if(!strcmp(gint_drivers[i].name, "TMU")) + { + tmu_state_t const *s = world[i]; + + for(int k = 0; k < 9; k++) { + #ifdef FX9860G + if(k < 3) dprint(1, 6*k, C_BLACK, "TMU%d: CNT:%08X TCR:%04X %s", + k, s->t[k].TCNT, s->t[k].TCR, (s->TSTR & (1<t[k].TCNT, s->t[k].TCR, s->t[k].TSTR); + #endif + + #ifdef FXCG50 + row_print(k+3, 1, "%sTMU%d:", (k<3 ? "" : "E"), (k<3 ? k : k-3)); + if(k < 3) row_print(k+3, 8, "%08X/%08X TCR:%04X", + s->t[k].TCNT, s->t[k].TCOR, s->t[k].TCR); + else row_print(k+3, 8,"%08X/%08X TCR:%02X TSTR:%02X", + s->t[k].TCNT, s->t[k].TCOR, s->t[k].TCR, s->t[k].TSTR); + #endif + } + } + else if(!strcmp(gint_drivers[i].name, "USB")) + { + row_print(_(1,3), 1, "In USB test"); + } + + dfont(old_font); +} + +//--- +// Manual switches with performance statistics +//--- + +struct switch_stats { + /* Number of empty world switches */ + int world_switch_count; + /* Number of return-to-menu */ + int return_to_menu_count; + /* TODO: Performance statistics for each driver */ +}; + +static void draw_manual(struct switch_stats *stats) +{ + #ifdef FX9860G + row_print(2, 1, "World switches: %d", stats->world_switch_count); + row_print(3, 1, "Return-to-menu: %d", stats->return_to_menu_count); + // row_print(4, 1, "Switch time: %d µs", stats->world_switch_time); + row_print(5, 1, "[1]: World switch"); + row_print(6, 1, "[2]: Return-to-menu"); + row_print(7, 1, "[3]: Measure perf"); + #endif + + #ifdef FXCG50 + row_print(1, 1, "World switches performed: %d", + stats->world_switch_count); + row_print(2, 1, "Return-to-menu performed: %d", + stats->return_to_menu_count); + + row_print(11, 1, "[1]: Standard world switch"); + row_print(12, 1, "[2]: Return-to-menu with gint_osmenu()"); + row_print(13, 1, "[3]: World switch with shared libprof (TODO)"); + #endif +} + +//--- +// Main test +//--- + +/* gintctl_gint_drivers(): Test the gint driver logic and world switch */ +void gintctl_gint_drivers(void) +{ + int key=0, tab=0, list_scroll=0, list_max=_(7,12), selected_driver=0; + struct switch_stats stats = { 0 }; + + while(key != KEY_EXIT) + { + dclear(C_WHITE); + + #ifdef FX9860G + if(tab == 0 || tab == 3) row_print(1, 1, "Drivers and worlds"); + dimage(0, 56, &img_opt_gint_drivers); + #endif + + #ifdef FXCG50 + row_title("Drivers and world switches"); + fkey_menu(1, "DRIVERS"); + fkey_menu(2, "OS"); + fkey_menu(3, "ADDIN"); + fkey_menu(4, "MANUAL"); + #endif + + if(tab == 0) draw_list(list_scroll, list_max); + if(tab == 1) draw_state(gint_world_os, selected_driver); + if(tab == 2) draw_state(gint_world_addin, selected_driver); + if(tab == 3) draw_manual(&stats); + dupdate(); + + key = getkey().key; + if(key == KEY_F1) tab = 0; + if(key == KEY_F2) tab = 1; + if(key == KEY_F3) tab = 2; + if(key == KEY_F4) tab = 3; + + /* Action for list tab */ + if(tab == 0 && key == KEY_UP && list_scroll > 0) + list_scroll--; + if(tab == 0 && key == KEY_DOWN && list_scroll < + (int)gint_driver_count() - list_max) + list_scroll++; + + /* Actions for OS state tab */ + if((tab == 1 || tab == 2) && key == KEY_LEFT && selected_driver > 0) + selected_driver--; + if((tab == 1 || tab == 2) && key == KEY_RIGHT + && selected_driver < (int)gint_driver_count()-1) + selected_driver++; + + /* Actions for the manual tab */ + if(tab == 3 && key == KEY_1) + gint_world_switch(GINT_CALL_INC(&stats.world_switch_count)); + if(tab == 3 && key == KEY_2) + { + /* TODO: Should render next frame in advance for seamless return */ + stats.return_to_menu_count++; + dupdate(); + + gint_osmenu(); + /* Wait for KEY_2 to be released before calling next getkey() */ + while(keydown(KEY_2)) waitevent(NULL); + } + if(tab == 3 && key == KEY_3) + { + /* TODO: World switch with performance statistics */ + } + } +} diff --git a/src/gint/dump.c b/src/gint/dump.c index 297c2c9..188bc6e 100644 --- a/src/gint/dump.c +++ b/src/gint/dump.c @@ -15,13 +15,6 @@ struct region { int segment_count; }; -struct { - int region; - int segment; - char filename[30]; - int retcode; -} dump; - static struct region const regs[] = { #ifdef FX9860G { "ROM", 0x80000000, 0x807fffff, 8 }, @@ -36,15 +29,15 @@ static struct region const regs[] = { #endif }; -static void switch_dump(void) +static void switch_dump(int region, int segment, char *filename, int *retcode) { - uint32_t start = regs[dump.region].start; - int size = regs[dump.region].end + 1 - start; + uint32_t start = regs[region].start; + int size = regs[region].end + 1 - start; /* For segmented regions, use blocks of 1M */ - if(regs[dump.region].segment_count > 1) + if(regs[region].segment_count > 1) { - start += dump.segment << 20; + start += segment << 20; size = 1 << 20; } @@ -52,35 +45,34 @@ static void switch_dump(void) size &= ~1; uint16_t file[30] = { 0 }; - for(int i = 0; i < 30; i++) file[i] = dump.filename[i]; + for(int i = 0; i < 30; i++) file[i] = filename[i]; - dump.retcode = 1; + *retcode = 1; int x = BFile_Remove(file); - if(x < 0 && x != -1) { dump.retcode = x; return; } + if(x < 0 && x != -1) { *retcode = x; return; } x = BFile_Create(file, BFile_File, &size); - if(x < 0) { dump.retcode = x; return; } + if(x < 0) { *retcode = x; return; } int fd = BFile_Open(file, BFile_WriteOnly); - if(fd < 0) { dump.retcode = fd; return; } + if(fd < 0) { *retcode = fd; return; } x = BFile_Write(fd, (void *)start, size); - if(x < 0) { dump.retcode = x; return; } + if(x < 0) { *retcode = x; return; } BFile_Close(fd); } static int do_dump(int region, int segment) { - /* Pass around parameters through the global variable */ - dump.region = region; - dump.segment = segment; - sprintf(dump.filename, "\\\\fls0\\%s%02x.bin", regs[region].name, - segment); + char filename[30]; + int retcode = 0; - gint_switch(switch_dump); - return dump.retcode; + sprintf(filename, "\\\\fls0\\%s%02x.bin", regs[region].name, segment); + gint_world_switch(GINT_CALL(switch_dump,region,segment,filename,&retcode)); + + return retcode; } /* gintctl_gint_dump(): Dump memory to filesystem */ diff --git a/src/gint/switch.c b/src/gint/switch.c deleted file mode 100644 index d62074e..0000000 --- a/src/gint/switch.c +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int switches = 0; -static int menus = 0; - -static void switch_function(void) -{ - switches++; -} - -//--- -// Saved system context visualizer -//--- - -void *driver_ctx(char const *name) -{ - extern gint_driver_t bdrv, edrv; - for(gint_driver_t *drv = &bdrv; drv < &edrv; drv++) - { - if(!strcmp(drv->name, name)) return drv->sys_ctx; - } - return NULL; -} - -#ifdef FX9860G -static void ctx_tmu() -{ - tmu_t *t = driver_ctx("TMU"); - uint8_t *TSTR = (void *)t + 3 * sizeof(tmu_t) + 6 * sizeof(etmu_t); - - for(int i = 0; i < 3; i++, t++) - { - row_print(2*i+1, 1, "TMU%d=%d CNT:%08x", i, - (*TSTR & (1 << i)) != 0, t->TCNT); - row_print(2*i+2, 1, "TCR:%04x COR:%08x", t->TCR.word, t->TCOR); - } -} -static void ctx_dd() -{ - uint8_t *STRD = driver_ctx("T6K11"); - - row_print(1, 1, "STRD:%02x", *STRD); - row_print(2, 2, "RESET:%d", (*STRD & 0x08) != 0); - row_print(3, 2, "N/F:%d", (*STRD & 0x04) != 0); - row_print(4, 2, "X/Y:%d", (*STRD & 0x02) != 0); - row_print(5, 2, "U/D:%d", (*STRD & 0x01) != 0); -} -static void ctx_rtc() -{ - uint8_t *ctx = driver_ctx("RTC"); - if(!ctx) return; - - uint8_t RCR1=ctx[0], RCR2=ctx[1]; - row_print(1, 1, "RCR1:%02x", RCR1); - row_print(2, 1, "RCR2:%02x", RCR2); -} -static void show_etmu(int line, int id, etmu_t *t) -{ - row_print(line, 1, "ETMU%d=%-3dCNT:%08x", id, t->TSTR, t->TCNT); - row_print(line+1, 1, "TCR:%02x COR:%08x", t->TCR.byte, t->TCOR); -} -static void ctx_etmu(int start) -{ - etmu_t *t = driver_ctx("TMU") + 3 * sizeof(tmu_t); - int length = 3; - - if(isSH3()) length=1, start=0; - - t += start; - for(int i = 0; i < length; i++, t++) - { - show_etmu(2*i+1, i+start, t); - } -} -static void ctx_intc() -{ - uint16_t *IPR = driver_ctx("INTC"); - - if(isSH3()) - { - row_print(1,1, "A:%04x B:%04x C:%04x", IPR[0], IPR[1], IPR[2]); - row_print(2,1, "D:%04x E:%04x F:%04x", IPR[3], IPR[4], IPR[5]); - row_print(3,1, "G:%04x H:%04x", IPR[6], IPR[7]); - } - else - { - row_print(1,1, "A:%04x B:%04x C:%04x", IPR[0], IPR[1], IPR[2]); - row_print(2,1, "D:%04x E:%04x F:%04x", IPR[3], IPR[4], IPR[5]); - row_print(3,1, "G:%04x H:%04x I:%04x", IPR[6], IPR[7], IPR[8]); - row_print(4,1, "J:%04x K:%04x L:%04x", IPR[9],IPR[10],IPR[11]); - } -} -#endif /* FX9860G */ - -#ifdef FXCG50 -static void ctx_tmu() -{ - tmu_t *t = driver_ctx("TMU"); - etmu_t *e = (void *)(t + 3); - uint8_t *TSTR = (void *)(e + 6); - - int const x[] = { 6, 138, 270, 6, 138, 270, 6, 138, 270 }; - int const y[] = { 24, 24, 24, 84, 84, 84, 144, 144, 144 }; - - tmu_print(x[0], y[0], "TMU0", t+0, *TSTR & 0x1); - tmu_print(x[1], y[1], "TMU1", t+1, *TSTR & 0x2); - tmu_print(x[2], y[2], "TMU2", t+2, *TSTR & 0x4); - - etmu_print(x[3], y[3], "ETMU0", e+0); - etmu_print(x[4], y[4], "ETMU1", e+1); - etmu_print(x[5], y[5], "ETMU2", e+2); - - etmu_print(x[6], y[6], "ETMU3", e+3); - etmu_print(x[7], y[7], "ETMU4", e+4); - etmu_print(x[8], y[8], "ETMU5", e+5); -} -static void ctx_dd() -{ - uint16_t *win = driver_ctx("R61524"); - uint16_t HSA = win[0], HEA = win[1], VSA = win[2], VEA = win[3]; - - row_print(1, 1, "Horizontal range: %d..%d", HSA, HEA); - row_print(2, 1, "Vertical range: %d..%d", VSA, VEA); -} -static void ctx_rtc() -{ - uint8_t *ctx = driver_ctx("RTC"); - if(!ctx) return; - - uint8_t RCR1=ctx[0], RCR2=ctx[1]; - row_print(1, 1, "RCR1:%02x", RCR1); - row_print(2, 1, "RCR2:%02x", RCR2); -} -static void ctx_dma() -{ - sh7305_dma_channel_t *ch = driver_ctx("DMA0"); - int *clock = (void *)(ch + 6); - uint16_t *OR = (void *)(clock + 1); - - show_dma(6, 24, 0, ch+0); - show_dma(138, 24, 1, ch+1); - show_dma(270, 24, 2, ch+2); - - show_dma(6, 104, 3, ch+3); - show_dma(138, 104, 4, ch+4); - show_dma(270, 104, 5, ch+5); - - dprint(6, 184, C_BLACK, "DMAOR: %08X", *OR); - dprint(198, 184, C_BLACK, "Clock enabled: %s",(*clock ? "No" : "Yes")); -} -#endif /* FXCG50 */ - -static void system_contexts(void) -{ - int key=0, tab=0; - - while(key != KEY_EXIT) - { - dclear(C_WHITE); - - #ifdef FX9860G - extern bopti_image_t img_opt_switch_ctx_sh3; - extern bopti_image_t img_opt_switch_ctx; - - if(isSH3()) - dimage(0, 56, &img_opt_switch_ctx_sh3); - else - dimage(0, 56, &img_opt_switch_ctx); - #endif - - #ifdef FXCG50 - row_title("System context visualizer"); - fkey_button(1, "TMU"); - fkey_button(2, "R61524"); - fkey_button(3, "RTC"); - fkey_button(4, "DMA"); - #endif - - if(tab == 0) ctx_tmu(); - if(tab == 1) ctx_dd(); - if(tab == 2) ctx_rtc(); - - #ifdef FX9860G - if(tab == 3) ctx_etmu(0); - if(tab == 4) ctx_etmu(3); - if(tab == 5) ctx_intc(); - #endif - - #ifdef FXCG50 - if(tab == 3) ctx_dma(); - #endif - - dupdate(); - - key = getkey().key; - if(key == KEY_F1) tab = 0; - if(key == KEY_F2) tab = 1; - if(key == KEY_F3) tab = 2; - if(key == KEY_F4) tab = 3; - if(key == KEY_F6) tab = 5; - - #ifdef FX9860G - if(key == KEY_F5 && isSH3()) tab = 4; - #endif - } -} - -//--- -// Interactive in-out switching -//--- - -/* Render VRAM for this screen, used when returning to menu */ -void render(void) -{ - dclear(C_WHITE); - - #ifdef FX9860G - extern bopti_image_t img_opt_switch; - row_print(1, 1, "Switch to OS"); - row_print(3, 1, "Switches done: %d", switches); - row_print(4, 1, "Menus done: %d", menus); - - dimage(0, 56, &img_opt_switch); - #endif - - #ifdef FXCG50 - row_title("Hot switching between gint and OS"); - row_print(2, 1, "Switches done: %d", switches); - row_print(3, 1, "Menus done: %d", menus); - fkey_button(1, "SWITCH"); - fkey_button(2, "MENU"); - fkey_action(6, "SYSTEM"); - #endif -} - -/* gintctl_gint_switch(): Test the gint switch-in-out procedures */ -void gintctl_gint_switch(void) -{ - int key = 0; - - while(key != KEY_EXIT) - { - render(); - dupdate(); - - key = getkey().key; - if(key == KEY_F1) gint_switch(switch_function); - /* Wait for F2 to be released before calling next getkey() */ - if(key == KEY_F2) - { - /* Render next frame in advance. When we return from - the main menu, our VRAM will be displayed but - GetKeyWait() will not give control back until a key - is pressed. This will make it look like we render a - new frame right away. */ - menus++; - render(); - dupdate(); - - gint_osmenu(); - while(keydown(KEY_F2)) waitevent(NULL); - } - if(key == KEY_F6) system_contexts(); - } -} diff --git a/src/gint/usb.c b/src/gint/usb.c index 40b5acf..df9f5a7 100644 --- a/src/gint/usb.c +++ b/src/gint/usb.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,17 +20,6 @@ #define USB SH7305_USB -/* Copy of the context structure from the driver (edgy style but heck) */ -typedef struct -{ - uint16_t SYSCFG, DVSTCTR, TESTMODE, REG_C2; - uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL; - uint16_t INTENB0, BRDYENB, NRDYENB, BEMPENB, SOFCFG; - uint16_t DCPCFG, DCPMAXP, DCPCTR; - uint16_t PIPECFG[9], PIPEBUF[9], PIPEMAXP[9], PIPEPERI[9]; - uint16_t PIPEnCTR[9], PIPEnTRE[5], PIPEnTRN[5]; -} ctx_t; - /* USB log buffer */ #define LOG_SIZE _(1023, 16383) static char log_buffer[LOG_SIZE+1]; @@ -155,25 +146,28 @@ static void draw_registers(GUNUSED int scroll) static void draw_context(void) { - extern void *driver_ctx(char const *name); - ctx_t *ctx = driver_ctx("USB"); - GUNUSED int scroll = 0; + usb_state_t *s = NULL; + for(int i = 0; i < gint_driver_count(); i++) { + if(!strcmp(gint_drivers[i].name, "USB")) s = gint_world_os[i]; + } + if(!s) return; - val( 0, "SYSCFG", ctx->SYSCFG); - val( 1, "DVSTCTR", ctx->DVSTCTR); - val( 2, "TESTMODE", ctx->TESTMODE); - val( 3, "REG_C2", ctx->REG_C2); - val( 4, "CFIFOSEL", ctx->CFIFOSEL); - val( 5, "D0FIFOSEL", ctx->D0FIFOSEL); - val( 6, "D1FIFOSEL", ctx->D1FIFOSEL); - val( 7, "INTENB0", ctx->INTENB0); - val( 8, "BRDYENB", ctx->BRDYENB); - val( 9, "NRDYENB", ctx->NRDYENB); - val(10, "BEMPENB", ctx->BEMPENB); - val(11, "SOFCFG", ctx->SOFCFG); - val(12, "DCPCFG", ctx->DCPCFG); - val(13, "DCPMAXP", ctx->DCPMAXP); - val(14, "DCPCTR", ctx->DCPCTR); + GUNUSED int scroll = 0; + val( 0, "SYSCFG", s->SYSCFG); + val( 1, "DVSTCTR", s->DVSTCTR); + val( 2, "TESTMODE", s->TESTMODE); + val( 3, "REG_C2", s->REG_C2); + val( 4, "CFIFOSEL", s->CFIFOSEL); + val( 5, "D0FIFOSEL", s->D0FIFOSEL); + val( 6, "D1FIFOSEL", s->D1FIFOSEL); + val( 7, "INTENB0", s->INTENB0); + val( 8, "BRDYENB", s->BRDYENB); + val( 9, "NRDYENB", s->NRDYENB); + val(10, "BEMPENB", s->BEMPENB); + val(11, "SOFCFG", s->SOFCFG); + val(12, "DCPCFG", s->DCPCFG); + val(13, "DCPMAXP", s->DCPMAXP); + val(14, "DCPCTR", s->DCPCTR); // uint16_t PIPECFG[9], PIPEBUF[9], PIPEMAXP[9], PIPEPERI[9]; // uint16_t PIPEnCTR[9], PIPEnTRE[5], PIPEnTRN[5]; @@ -305,7 +299,8 @@ void gintctl_gint_usb(void) if(key == KEY_F3) tab = 2; if(key == KEY_F4) tab = 3; - if(tab == 2 && key == KEY_F5) gint_switch(save_logger); + if(tab == 2 && key == KEY_F5) + gint_world_switch(GINT_CALL(save_logger)); if(key == KEY_F6) { @@ -313,7 +308,7 @@ void gintctl_gint_usb(void) else { usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL }; - int rc = usb_open(interfaces, GINT_CB(open_callback)); + int rc = usb_open(interfaces, GINT_CALL(open_callback)); open = (rc == 0); } } diff --git a/src/gintctl.c b/src/gintctl.c index 72b2e05..9093823 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -27,29 +27,27 @@ struct menu menu_gint = { _("gint tests", "gint features and driver tests"), .entries = { - { "CPU and memory", gintctl_gint_cpumem, 0 }, - { "RAM discovery", gintctl_gint_ram, MENU_SH4_ONLY }, + { "CPU and memory", gintctl_gint_cpumem, 0 }, + { "RAM discovery", gintctl_gint_ram, MENU_SH4_ONLY }, #ifdef FXCG50 - { "DSP processors", gintctl_gint_dsp, 0 }, + { "DSP processors", gintctl_gint_dsp, 0 }, #endif - { "SPU memory", gintctl_gint_spuram, MENU_SH4_ONLY }, - { "Memory dump", gintctl_gint_dump, 0 }, - { "Switching to OS", gintctl_gint_switch, 0 }, - { "TLB management", gintctl_gint_tlb, 0 }, - { "Memory allocation",gintctl_gint_kmalloc, 0 }, - { "Keyboard", gintctl_gint_keyboard, 0 }, - { "Timers", gintctl_gint_timer, 0 }, - { "Timer callbacks", gintctl_gint_timer_callbacks, 0 }, - #ifdef FXCG50 - { "DMA control", gintctl_gint_dma, 0 }, - #endif - { "Real-time clock", gintctl_gint_rtc, 0 }, - { "USB communication",gintctl_gint_usb, MENU_SH4_ONLY }, - { "Image rendering", gintctl_gint_bopti, 0 }, - { "Text rendering", gintctl_gint_topti, 0 }, + { "SPU memory", gintctl_gint_spuram, MENU_SH4_ONLY }, + { "Memory dump", gintctl_gint_dump, 0 }, + { "Drivers and worlds", gintctl_gint_drivers, 0 }, + { "TLB management", gintctl_gint_tlb, 0 }, + { "Memory allocation", gintctl_gint_kmalloc, 0 }, + { "Keyboard", gintctl_gint_keyboard, 0 }, + { "Timers", gintctl_gint_timer, 0 }, + { "Timer callbacks", gintctl_gint_timer_callbacks, 0 }, + { "DMA control", gintctl_gint_dma, MENU_SH4_ONLY }, + { "Real-time clock", gintctl_gint_rtc, 0 }, + { "USB communication", gintctl_gint_usb, MENU_SH4_ONLY }, + { "Image rendering", gintctl_gint_bopti, 0 }, + { "Text rendering", gintctl_gint_topti, 0 }, #ifdef FX9860G - { "Gray engine", gintctl_gint_gray, 0 }, - { "Gray rendering", gintctl_gint_grayrender, 0 }, + { "Gray engine", gintctl_gint_gray, 0 }, + { "Gray rendering", gintctl_gint_grayrender, 0 }, #endif { NULL, NULL, 0 }, }}; @@ -61,9 +59,7 @@ struct menu menu_perf = { { "libprof basics", gintctl_perf_libprof, 0 }, { "CPU and cache", gintctl_perf_cpucache, 0 }, { "Interrupt stress", gintctl_perf_interrupts, 0 }, - #ifdef FXCG50 { "Memory access speed", gintctl_perf_memory, 0 }, - #endif { "Rendering functions", gintctl_perf_render, 0 }, /* TODO: Comparison with MonochromeLib */ diff --git a/src/perf/memory.c b/src/perf/memory.c index 7a660a9..a8af278 100644 --- a/src/perf/memory.c +++ b/src/perf/memory.c @@ -3,9 +3,11 @@ #include #include #include +#include #include #include +#include #include @@ -104,17 +106,13 @@ static void test(struct results *r, void *address, uint32_t size, int rounds) }); r->dma_memset_time = prof_exec({ - #ifdef FXCG50 for(int i = 0; i < rounds; i++) - dma_memset(address, 0, size); - #endif + if(isSH4()) dma_memset(address, 0, size); }); r->dma_memcpy_time = 2 * prof_exec({ - #ifdef FXCG50 for(int i = 0; i < rounds; i++) - dma_memcpy(address + size / 2, address, size / 2); - #endif + if(isSH4()) dma_memcpy(address + size / 2, address, size / 2); }); if(address == &xram_buffer) @@ -122,14 +120,14 @@ static void test(struct results *r, void *address, uint32_t size, int rounds) /* Since the buffers are small, repeat 16 times */ r->dsp_xram_memset_time = prof_exec({ for(int i = 0; i < rounds; i++) - memory_dsp_xram_memset(address, size); + if(isSH4()) memory_dsp_xram_memset(address, size); }); } if(address == &yram_buffer) { r->dsp_yram_memset_time = prof_exec({ for(int i = 0; i < rounds; i++) - memory_dsp_yram_memset(address, size); + if(isSH4()) memory_dsp_yram_memset(address, size); }); } if(address == &xram_buffer) @@ -140,7 +138,7 @@ static void test(struct results *r, void *address, uint32_t size, int rounds) /* Since the buffers are small, repeat 16 times */ r->dsp_xyram_memcpy_time = prof_exec({ for(int i = 0; i < rounds; i++) - memory_dsp_xyram_memcpy(y, x, size); + if(isSH4()) memory_dsp_xyram_memcpy(y, x, size); }); } if(address == &yram_buffer) @@ -150,7 +148,7 @@ static void test(struct results *r, void *address, uint32_t size, int rounds) r->dsp_xyram_memcpy_time = prof_exec({ for(int i = 0; i < rounds; i++) - memory_dsp_xyram_memcpy(x, y, size); + if(isSH4()) memory_dsp_xyram_memcpy(x, y, size); }); } @@ -171,25 +169,76 @@ static void test(struct results *r, void *address, uint32_t size, int rounds) static void results_line(int row, uint32_t time, uint32_t speed) { - dprint_opt(260, row_y(row), C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, + int y = _(8+6*row, row_y(row)); + dprint_opt(_(80,260), y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d us", time); - dprint_opt(370, row_y(row), C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, - "%3.3j MB/s", speed); + dprint_opt(_(125,370), y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, + _("%3.1j MB/s", "%3.3j MB/s"), _(speed/100, speed)); } /* gintctl_perf_memory(): Memory primitives and reading/writing speed */ void gintctl_perf_memory(void) { - /* TODO: Memory performance on SH3 */ - if(isSH3()) return; - int key = 0; struct results r = { 0 }; + /* Get the physical VRAM address */ + void *vram_address = gint_vram; + #ifdef FX9860G + uint32_t virt_page = (uint32_t)vram_address & 0xfffff000; + uint32_t phys_page = 0x80000000 + mmu_translate(virt_page, NULL); + vram_address = (void *)phys_page + (vram_address - (void *)virt_page); + #endif + while(key != KEY_EXIT) { dclear(C_WHITE); row_title("Memory access speed"); + font_t const *old_font = dfont(_(&font_mini, dfont_default())); + + #ifdef FX9860G + /* Due to less space, focus on the non-trivial methods */ + dprint(1, 14, C_BLACK, "gint memcpy:"); + dprint(1, 20, C_BLACK, "gint memset:"); + if(isSH4()) { + dprint(1, 26, C_BLACK, "dma_memcpy:"); + dprint(1, 32, C_BLACK, "dma_memset:"); + + if(r.address == &xram_buffer) + dprint(1, 38, C_BLACK, "DSP memset:"); + if(r.address == &yram_buffer) + dprint(1, 38, C_BLACK, "DSP memset:"); + if(r.address == &xram_buffer || r.address == &yram_buffer) + dprint(1, 44, C_BLACK, "DSP memcpy:"); + } + + if(!r.address) dprint(1, 8, C_BLACK, "No test yet"); + else + { + dprint(1, 8, C_BLACK, "Area: %08X (%d B, %d round%s)", + (uint32_t)r.address, r.size, r.rounds, (r.rounds>1)?"s":""); + results_line(1, r.memcpy_time, r.memcpy_speed); + results_line(2, r.memset_time, r.memset_speed); + if(isSH4()) { + results_line(3, r.dma_memcpy_time, r.dma_memcpy_speed); + results_line(4, r.dma_memset_time, r.dma_memset_speed); + if(r.address == &xram_buffer) + results_line(5, r.dsp_xram_memset_time, + r.dsp_xram_memset_speed); + if(r.address == &yram_buffer) + results_line(5, r.dsp_yram_memset_time, + r.dsp_yram_memset_speed); + if(r.address==&xram_buffer || r.address==&yram_buffer) + results_line(6, r.dsp_xyram_memcpy_time, + r.dsp_xyram_memcpy_speed); + } + } + + if(isSH3()) + dimage(0, 56, &img_opt_perf_memory_sh3); + else + dimage(0, 56, &img_opt_perf_memory); + #endif #ifdef FXCG50 row_print( 3, 1, "Naive C-loop u8 read:"); @@ -208,10 +257,7 @@ void gintctl_perf_memory(void) if(r.address == &xram_buffer || r.address == &yram_buffer) row_print(12, 1, "DSP XRAM->YRAM memcpy():"); - if(!r.address) - { - row_print(1, 1, "No test yet"); - } + if(!r.address) row_print(1, 1, "No test yet"); else { row_print(1, 1, "Results for area %08x (%d bytes, %d " @@ -227,20 +273,14 @@ void gintctl_perf_memory(void) results_line(10,r.dma_memset_time, r.dma_memset_speed); if(r.address == &xram_buffer) - { results_line(11, r.dsp_xram_memset_time, r.dsp_xram_memset_speed); - } if(r.address == &yram_buffer) - { results_line(11, r.dsp_yram_memset_time, r.dsp_yram_memset_speed); - } if(r.address==&xram_buffer || r.address==&yram_buffer) - { results_line(12, r.dsp_xyram_memcpy_time, r.dsp_xyram_memcpy_speed); - } } fkey_button(1, "RAM"); @@ -249,12 +289,15 @@ void gintctl_perf_memory(void) fkey_button(4, "YRAM"); #endif + dfont(old_font); dupdate(); key = getkey().key; - if(key == KEY_F1) test(&r, gint_vram, _(0x400,0x8000), 1); - if(key == KEY_F2) test(&r, &ilram_buffer, 0x800, 64); - if(key == KEY_F3) test(&r, &xram_buffer, 0x800, 64); - if(key == KEY_F4) test(&r, &yram_buffer, 0x800, 64); + if(key == KEY_F1) test(&r, vram_address, _(0x400,0x8000), _(32,1)); + if(isSH4()) { + if(key == KEY_F2) test(&r, &ilram_buffer, 0x800, 64); + if(key == KEY_F3) test(&r, &xram_buffer, 0x800, 64); + if(key == KEY_F4) test(&r, &yram_buffer, 0x800, 64); + } } } diff --git a/src/util.c b/src/util.c index 2ac8308..d86ac0c 100644 --- a/src/util.c +++ b/src/util.c @@ -218,9 +218,7 @@ void fkey_menu(int position, char const *text) // Screenshot saving //--- -static uint16_t const *path; - -void switch_screen_mono(void) +void switch_screen_mono(uint16_t const *path) { int size = 1024; @@ -235,6 +233,5 @@ void switch_screen_mono(void) /* screen_mono(): Take a screenshot of the mono VRAM */ void screen_mono(uint16_t const *filepath) { - path = filepath; - gint_switch(switch_screen_mono); + gint_world_switch(GINT_CALL(switch_screen_mono, filepath)); }