#include #include #include #include #include #include #include #ifdef FX9860G #include #endif #include #include #include #include #include #include #include #include #include /* TODO: * Interrupt controller state? * Clock frequencies * F2 to save hardware data to file */ /* gint test menu */ 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 }, #ifdef FXCG50 { "DSP processors", gintctl_gint_dsp, 0 }, #endif { "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 }, #ifdef FXCG50 { "Overclocking", gintctl_gint_overclock, MENU_SH4_ONLY }, #endif { "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 }, #ifdef FXCG50 { "USB tracer", gintctl_gint_usbtrace, MENU_SH4_ONLY }, #endif { "Basic rendering", gintctl_gint_render, 0 }, { "Image rendering", gintctl_gint_image, 0 }, { "Text rendering", gintctl_gint_topti, 0 }, #ifdef FX9860G { "Gray engine", gintctl_gint_gray, 0 }, { "Gray rendering", gintctl_gint_grayrender, 0 }, #endif { NULL, NULL, 0 }, }}; /* Performance menu */ struct menu menu_perf = { _("Performance", "Performance benchmarks"), .entries = { { "libprof basics", gintctl_perf_libprof, 0 }, { "CPU and cache", gintctl_perf_cpucache, 0 }, { _("CPU parallelism", "Superscalar and pipeline parallelism"), gintctl_perf_cpu, 0 }, { "Interrupt stress", gintctl_perf_interrupts, 0 }, #ifdef FXCG50 { "Memory read/write speed", gintctl_perf_memory, 0 }, #endif { "Rendering functions", gintctl_perf_render, 0 }, /* TODO: Comparison with MonochromeLib */ { NULL, NULL, 0 }, }}; /* External libraries */ struct menu menu_libs = { _("Libraries", "External and standard libraries"), .entries = { { "libm: " _("OpenLibm", "OpenLibm floating-point functions"), gintctl_libs_openlibm, 0 }, { "JustUI widgets", gintctl_libs_justui, 0 }, { "BFile filesystem", gintctl_libs_bfile, 0 }, { NULL, NULL, 0 }, }}; //--- // Global shortcuts //--- /* Whether we're recording */ static bool getkey_recording = false; static void getkey_record_video_frame(int onscreen) { /* Auto stop when closing USB connection */ if(!usb_is_open()) { dupdate_set_hook(GINT_CALL_NULL); return; } #ifdef FX9860G if(dgray_enabled()) usb_fxlink_videocapture_gray(true); else usb_fxlink_videocapture(onscreen); #endif #ifdef FXCG50 usb_fxlink_videocapture(onscreen); #endif } static bool getkey_global_shortcuts(key_event_t e) { if(usb_is_open() && e.key == KEY_OPTN && !e.shift && !e.alpha) { #ifdef FX9860G if(dgray_enabled()) usb_fxlink_screenshot_gray(true); else usb_fxlink_screenshot(true); #endif #ifdef FXCG50 usb_fxlink_screenshot(true); #endif return true; } if(usb_is_open() && e.key == KEY_VARS && e.shift && !e.alpha) { if(!getkey_recording) { dupdate_set_hook(GINT_CALL(getkey_record_video_frame, (int)false)); getkey_record_video_frame(true); getkey_recording = true; } else { dupdate_set_hook(GINT_CALL_NULL); getkey_recording = false; } } if(e.shift && e.key == KEY_COMMA) { static int stage = 0; stage = (stage + 1) % 8; int border = stage * _(3, 13); struct dwindow win = { .left = border, .top = border, .right = DWIDTH - border, .bottom = DHEIGHT - border, }; dwindow_set((struct dwindow){ 0, 0, DWIDTH, DHEIGHT }); dclear(_(C_WHITE, 0x5555)); dwindow_set(win); } return false; } int volatile gintctl_interrupt = 0; static void gintctl_fxlink_notification(void) { /* Hack: use bit #31 to indicate an internal interrupt */ gintctl_interrupt |= (1 << 31); } key_event_t gintctl_getkey_opt(int options) { usb_fxlink_header_t header; while(1) { key_event_t ev = getkey_opt(options, &gintctl_interrupt); while(usb_fxlink_handle_messages(&header)) gintctl_handle_usb_command(&header); /* Keep waiting only if we were interrupted *and* the interrupt only set bit #31 */ if(ev.type != KEYEV_NONE || ((gintctl_interrupt << 1) != 0)) { gintctl_interrupt = 0; return ev; } } } key_event_t gintctl_getkey(void) { return gintctl_getkey_opt(GETKEY_DEFAULT); } //--- // Main application //--- /* gintctl_main(): Show the main tab */ void gintctl_main(void) { #ifdef FX9860G row_title("gint %s %07x", GINT_VERSION, GINT_HASH); row_print(3, 1, "F2:gint tests"); row_print(4, 1, "F3:Performance"); row_print(5, 1, "F4:Libraries"); row_print(6, 1, "F5:MPU registers"); row_print(7, 1, "F6:Memory map/dump"); #endif /* FX9860G */ #ifdef FXCG50 row_title("gint %s (@%07x) for fx-CG 50", GINT_VERSION, GINT_HASH); row_print(1,1, "F2: gint features and driver tests"); row_print(2,1, "F3: Performance benchmarks"); row_print(3,1, "F4: External libraries"); row_print(4,1, "F5: MPU register browser"); row_print(5,1, "F6: Hexadecimal memory browser"); row_print(7,1, "This add-in is running a unikernel called gint by"); row_print(8,1, "Lephe'. Information about the project is available"); row_print(9,1, "on planet-casio.com."); #endif /* FXCG50 */ } static void draw(struct menu *menu) { dclear(C_WHITE); if(menu) menu_show(menu); else gintctl_main(); #ifdef FX9860G dimage(0, 56, &img_opt_main); #endif #ifdef FXCG50 fkey_action(1, "INFO"); fkey_menu(2, "GINT"); fkey_menu(3, "PERF"); fkey_menu(4, "LIBS"); fkey_button(5, "REGS"); fkey_button(6, "MEMORY"); #endif } int main(GUNUSED int isappli, GUNUSED int optnum) { /* Initialize menu metadata */ int top = _(1, 0), bottom = 1; menu_init(&menu_gint, top, bottom); menu_init(&menu_perf, top, bottom); menu_init(&menu_libs, top, bottom); gint_setrestart(1); /* Enable global getkey() shortcuts */ getkey_set_feature_function(getkey_global_shortcuts); /* Start the profiling library */ prof_init(); /* Enable floating-point formatters */ __printf_enable_fp(); /* Enable fixed-point formatters */ __printf_enable_fixed(); #ifdef FX9860G /* Use the Unicode font uf5x7 on fx-9860G */ dfont(&font_uf5x7); #endif /* Get notified when fxlink messages arrive through USB */ usb_fxlink_set_notifier(gintctl_fxlink_notification); /* Enable keyboard options globally because we're going to interrupt getkey_opt() to answer USB requests synchronously */ keydev_transform_t tr = keydev_transform(keydev_std()); tr.enabled |= KEYDEV_TR_DELAYED_SHIFT | KEYDEV_TR_INSTANT_SHIFT; tr.enabled |= KEYDEV_TR_DELAYED_ALPHA | KEYDEV_TR_INSTANT_ALPHA; keydev_set_transform(keydev_std(), tr); key_event_t ev; int key = 0; struct menu *menu = NULL; while(key != KEY_EXIT) { draw(menu); dupdate(); ev = gintctl_getkey(); key = ev.key; if(key == KEY_F1) menu = NULL; if(key == KEY_F2) menu = &menu_gint; if(key == KEY_F3) menu = &menu_perf; if(key == KEY_F4) menu = &menu_libs; if(key == KEY_F5) gintctl_regs(); if(key == KEY_F6) gintctl_mem(); if(!menu) continue; if(key == KEY_UP || key == KEY_DOWN) menu_move(menu, key, ev.shift || keydown(KEY_SHIFT),0); if(key == KEY_EXE) menu_exec(menu); } /* Prepare a main menu frame to maintain the illusion when coming back after a restart */ draw(NULL); prof_quit(); return 0; }