From 118eb789ee143eec0f82a4139f67759063a4be5d Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Mon, 17 May 2021 15:09:23 +0200 Subject: [PATCH] my commit is magnificent, and fierce, and eh- kinda huge * Set minimum CMake version to 3.15 * Update icon because come on the previous one was bad * Show sleep block level counter in CPU details * Add global shortcut to make screenshots, and update some tests to use getkey()-based methods to support these screenshots * Fix the USB log freezing because my brain was gone when I made it * Implement actually useful stuff in the USB test --- CMakeLists.txt | 2 +- assets-cg/icon-sel.png | Bin 3005 -> 16859 bytes assets-cg/icon-uns.png | Bin 1426 -> 12025 bytes src/gint/cpumem.c | 6 +- src/gint/gray.c | 6 +- src/gint/usb.c | 163 +++++++++++++++++++++++++++++++++-------- src/gintctl.c | 32 ++++++++ 7 files changed, 176 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a499c4..8cd3216 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # gintctl: gint's control application -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.15) project(gintctl VERSION 2.2.1 LANGUAGES C ASM) include(GenerateG1A) diff --git a/assets-cg/icon-sel.png b/assets-cg/icon-sel.png index f31c66462ba16db886709b65ddba1d865b454c7d..67fba416c5591615473f25910603631748df65fc 100644 GIT binary patch literal 16859 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 Xu?nxH;+OR;00000NkvXXu0mjfXp`4% delta 1408 zcmV-`1%LYaU6KosBYyx1a7bBm000XU000XU0RWnu7ytkO2XskIMF-*p5D+T`DE&*| z000FsNklEo0+tpCwbUZECjLvj&=_Nk#&|HEy>cNY#)Jep zdFBKpCWH$Y6T^k0CyggeFeJTb{1cTJf+$c@Ds3&ixBuSrFn?w8F}pkS&F;Rk``9_n z?wkE)<~P6jeZM!mBmI6Kn(}C|8VDLt8c-TgN-R$D*4<9{^U_+_w=UmYS3DVqq0N}6 z#9^rJDTpH1aYQAEB6a&XjBMtJN*wCi_jj%X4rtzaVc5FL}V{OZc?e5Ey z?a8+H(cy#7K0T(|K41O0^6T>b#ia)dM8pvBh+WT90Fgwb<+)|W7Z6}X9NSidvV1?d zd}H;8TWc48`bVQFmu}o!>hyx1%Djm2@e%V&#bS#2bALqmrGhM`@x}Z(BK(p<7C-LY z+6cb>nj@@VN4{pG;RuCFfJ6n(Blh&2wW(9S@)xB%WI`&AF+UV&ujT2X^NIF z^!S1xSW_r`DLEw*_k60#DmaomzLBO33KZg=$7G>sO78fknquHnjA$aptsQjN4}SmT zO=9r*vwz>2#^-PdT#A5FvZknMGSK*`nzD6F!IZ{(K5OVW-2lMMiSq#9x-1A%Oz`zn zN2QL`{F*)eE#5L%Q*uLN<>p8ZpR)Os%K#u1kyK3~a-_PNqUOuyI_#a@iE>bu;)?kE za{sY&0C4m3kEOa=Q}Xd;t9^OLiRjw_-m)%7U= z@cd_A0KnCgM}$woegyj$e1HG3bBr;5XYAmMB7Q1IYUWdt%0g_(7z-bsat`7=<+1q` z&VP~71M@;zIbV3eY9etb@cq{GTr0t*@X^CyZ|cx6_!QIl_-2@WJYIF5lFT@-p1&e| z3OD$i7g$GleG|dyIV@fxzTm~M`4qaQ5II;UpMo>aL+;2vg)<^qPyY8I9=kmeKBeG) zpUU|ZoMkv`_}<}~vT6AdJJjbU3h3+YQ-83gP|j1Nm8iE*;k>|w`;?aFjskT3Ksrys zc?V}-{#TG!tUWUnzSPpE(BJ!DMCiV@x;|y}z`WwHHhJbISN?qRj zSVd?8iFdtJ z_U-uar77vBk>nTGcRS&QZ!Ud*WpVNLx)$s>ifqS;qlma&!zgBs9Y)kWZyKNY6(9h- zF*E-9!r>$DzoY*Uuqn`dM_b6zo_{%Y1^|wqI6h?a=kt=L<~-h^R1;`x5EI68RwI(U zEWJB*NnH}B$iqbn4_FY9t(YkAGtAN;2?eP^>b5fKE~~N8p0%WQ5HyD+Z^4Ao0Q-hq2-Thr!=~e0_A_(;eF-FMwA5r O0000", calc); @@ -89,7 +91,8 @@ void show_mpucpu(void) } print_prefix(85, 24, "VBR", "%08X", cpu_getVBR()); print_prefix(85, 30, "R15", "%08X", r15); - dline(85, 24, 85, 34, C_BLACK); + print_prefix(85, 36, "sbc", "%d", cpu_sleep_block_counter); + dline(85, 24, 85, 40, C_BLACK); dfont(old_font); #endif @@ -102,6 +105,7 @@ void show_mpucpu(void) row_print(7, 1, " CPU Operation Mode: %08x", *CPUOPM); row_print(8, 1, " Current VBR: %08x", cpu_getVBR()); row_print(9, 1, " Current stack pointer: %08x", r15); + row_print(10, 1, " CPU sleep block level: %d", cpu_sleep_block_counter); #endif } diff --git a/src/gint/gray.c b/src/gint/gray.c index d293caf..c87ce39 100644 --- a/src/gint/gray.c +++ b/src/gint/gray.c @@ -86,6 +86,7 @@ void gintctl_gint_gray(void) void gintctl_gint_grayrender(void) { int x, y; + int key = 0; dgray(DGRAY_ON); dclear(C_WHITE); @@ -144,7 +145,10 @@ void gintctl_gint_grayrender(void) dimage(x + 56, y + 2, &img_profile_gray_alpha); dupdate(); - getkey(); + + while(key != KEY_EXIT) { + key = getkey().key; + } dgray(DGRAY_OFF); } diff --git a/src/gint/usb.c b/src/gint/usb.c index 8eaea3b..cd9b213 100644 --- a/src/gint/usb.c +++ b/src/gint/usb.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -18,27 +19,33 @@ #include #include +#include + #define USB SH7305_USB /* USB log buffer */ -#define LOG_SIZE _(1023, 16383) -static char log_buffer[LOG_SIZE+1]; +#define LOG_SIZE _(1024, 4096) +static char log_buffer[LOG_SIZE]; static int log_pos; +static int const log_lines = _(8,15); static int volatile log_interrupt = 0; static void reset_logger(void) { - memset(log_buffer, 0, LOG_SIZE+1); + memset(log_buffer, 0, LOG_SIZE); log_pos = 0; } static void usb_logger(char const *format, va_list args) { - if(log_pos >= LOG_SIZE) return; - int length = vsnprintf(log_buffer+log_pos, LOG_SIZE-log_pos, format, args); - log_pos = min(log_pos + length, LOG_SIZE); /* Interrupt getkey() so that the log can be printed */ log_interrupt = 1; + if(log_pos >= LOG_SIZE) return; + + cpu_atomic_start(); + int length = vsnprintf(log_buffer+log_pos, LOG_SIZE-log_pos, format, args); + log_pos += min(length, LOG_SIZE - 1 - log_pos); + cpu_atomic_end(); } static void save_logger(void) @@ -139,8 +146,8 @@ static void draw_registers(GUNUSED int scroll) #endif #ifdef FXCG50 - dprint(row_x(1), 188, C_BLACK, "USBCLKCR: %08X MSTPCR2: %08X", - SH7305_CPG.USBCLKCR.lword, SH7305_POWER.MSTPCR2.lword); + dprint(row_x(1), 188, C_BLACK, "USBCLKCR:%08X MSTPCR2:%08X %d", + SH7305_CPG.USBCLKCR.lword, SH7305_POWER.MSTPCR2.lword, log_pos); #endif } @@ -175,7 +182,7 @@ static void draw_context(void) static int draw_log(int offset) { - int const y0=_(8,20), dy=_(6,12), lines=_(8,15); + int const y0=_(8,20), dy=_(6,12); int const x=_(2,6), w=DWIDTH-_(9,15); /* Split log into lines */ @@ -185,21 +192,28 @@ static int draw_log(int offset) while(log < log_buffer + log_pos) { + if(log[0] == '\n') { + y += dy; + line++; + log++; + continue; + } + char const *endscreen = drsize(log, NULL, w, NULL); char const *endline = strchrnul(log, '\n'); - int end = min(endscreen-log, endline-log); + int len = min(endscreen-log, endline-log); - if(y >= y0 && y < y0 + lines * dy) - dtext_opt(x, y, C_BLACK, C_NONE, DTEXT_LEFT, DTEXT_TOP, log, end); + if(y >= y0 && y < y0 + log_lines * dy) + dtext_opt(x, y, C_BLACK, C_NONE, DTEXT_LEFT, DTEXT_TOP, log, len); y += dy; line++; - log += end + (log[end] == '\n'); + log += len + (log[len] == '\n'); } - if(line > lines) + if(line > log_lines) { - scrollbar_px(y0, y0 + lines*dy, 0, line, offset, lines); - return line - lines; + scrollbar_px(y0, y0 + log_lines*dy, 0, line, offset, log_lines); + return line - log_lines; } return 0; @@ -241,21 +255,68 @@ static void draw_pipes(void) #endif } -static void open_callback(void) +static void draw_tests(void) { - usb_log("Open callback, doing test!\n"); - - int pipe = 5; - usb_write_async(pipe, gint_vram, _(1024, 396*224*2), 4, false, - GINT_CALL_NULL); - usb_commit_async(pipe, GINT_CALL_NULL); +#ifdef FXCG50 + row_print(1, 1, "[1]: Take screenshot (fxlink API)"); + row_print(2, 1, "[2]: Take screenshot (asynchronous)"); + row_print(3, 1, "[3]: Send some text (fxlink API)"); + row_print(4, 1, "[4]: Send some logs (fxlink API)"); +#endif } +//--- +// Tests +//--- + +static prof_t screenshot_async_prof; + +static void screenshot_async_4(void) +{ + prof_leave(screenshot_async_prof); + usb_log("Async DMA screenshot: %d us\n", prof_time(screenshot_async_prof)); +} +static void screenshot_async_3(void) +{ + int pipe = usb_ff_bulk_output(); + int rc = usb_commit_async(pipe, GINT_CALL(screenshot_async_4)); + usb_log("commit_async: %d\n", rc); +} +static void screenshot_async_2(void) +{ + int pipe = usb_ff_bulk_output(); + int rc = usb_write_async(pipe, gint_vram, _(1024, 396*224*2), 4, true, + GINT_CALL(screenshot_async_3)); + usb_log("write_async 2: %d\n", rc); +} +static void screenshot_async(void) +{ + usb_log("\n"); + int pipe = usb_ff_bulk_output(); + + int data_size = _(1024, 396*224*2); + + screenshot_async_prof = prof_make(); + prof_enter(screenshot_async_prof); + + usb_fxlink_header_t header; + if(!usb_fxlink_fill_header(&header, "gintctl", "asyncscreen", data_size)) + return; + + int rc = usb_write_async(pipe, &header, sizeof header, 4, false, + GINT_CALL(screenshot_async_2)); + usb_log("write_async 1: %d\n", rc); +} + +//--- +// Main function +//--- + /* gintctl_gint_usb(): USB communication */ void gintctl_gint_usb(void) { int key=0, tab=0; - bool open=false; + int open = usb_is_open(); GUNUSED int scroll0=0, scroll2=0, maxscroll2=0; reset_logger(); @@ -277,6 +338,7 @@ void gintctl_gint_usb(void) if(tab == 1) draw_context(); if(tab == 2) maxscroll2 = draw_log(scroll2); if(tab == 3) draw_pipes(); + if(tab == 4) draw_tests(); #ifdef FXCG50 row_title("USB 2.0 function module and communication"); @@ -284,7 +346,7 @@ void gintctl_gint_usb(void) fkey_menu(2, "CTX"); fkey_menu(3, "LOG"); fkey_menu(4, "PIPES"); - if(tab == 2) fkey_button(5, "FILE"); + fkey_menu(5, "TESTS"); fkey_action(6, open ? "CLOSE" : "OPEN"); #endif @@ -295,6 +357,11 @@ void gintctl_gint_usb(void) dupdate(); key = getkey_opt(GETKEY_DEFAULT, &log_interrupt).key; + + /* Scroll down log automatically at the cost of a redraw */ + if(log_interrupt == 1 && tab == 2) + scroll2 = draw_log(0); + log_interrupt = 0; if(key == KEY_F1) tab = 0; @@ -307,21 +374,57 @@ void gintctl_gint_usb(void) if(key == KEY_F6) { - if(open) usb_close(), open = false; + if(open) usb_close(), open = 0; else { usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL }; - int rc = usb_open(interfaces, GINT_CALL(open_callback)); - open = (rc == 0); + usb_open(interfaces, GINT_CALL_SET(&open)); } } + int scroll_speed = 1; + if(keydown(KEY_SHIFT)) scroll_speed = 4; + if(keydown(KEY_ALPHA)) scroll_speed = 16; + #ifdef FX9860G if(tab == 0 && key == KEY_UP && scroll0 > 0) scroll0--; if(tab == 0 && key == KEY_DOWN && scroll0 < 15) scroll0++; #endif - if(tab == 2 && key == KEY_UP && scroll2 > 0) scroll2--; - if(tab == 2 && key == KEY_DOWN && scroll2 < maxscroll2) scroll2++; + if(tab == 2 && key == KEY_UP) + scroll2 = max(scroll2 - scroll_speed, 0); + if(tab == 2 && key == KEY_DOWN) + scroll2 = min(scroll2 + scroll_speed, maxscroll2); + + if(key == KEY_1 && usb_is_open()) { +// extern prof_t usb_cpu_write_prof; +// usb_cpu_write_prof = prof_make(); + +// uint32_t time = prof_exec({ + usb_fxlink_screenshot(true); +// }); + +// usb_log("Screenshot: %d us\n", time); +// usb_log("Spent CPU writing: %d us\n", prof_time(usb_cpu_write_prof)); + } + if(key == KEY_2 && usb_is_open()) screenshot_async(); + if(key == KEY_3 && usb_is_open()) { + GALIGNED(4) char str[] = "Hi! This is gintctl!"; + usb_fxlink_text(str, 0); + } + if(key == KEY_4 && usb_is_open()) { + uint32_t time = prof_exec({ + int pipe = usb_ff_bulk_output(); + int data_size = _(1024, 396*224*2); + usb_fxlink_header_t header; + usb_fxlink_fill_header(&header, "gintctl", "dmascreen", data_size); + + usb_write_sync(pipe, &header, sizeof header, 4, false); +// usb_write_sync(pipe, (void *)0xfe200000, _(1024, 396*224*2), 4, true); + usb_write_sync(pipe, gint_vram, _(1024, 396*224*2), 4, true); + usb_commit_sync(pipe); + }); + usb_log("DMA screenshot: %d us\n", time); + } } } diff --git a/src/gintctl.c b/src/gintctl.c index 6ab4621..438d571 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -6,6 +6,12 @@ #include #include #include +#include +#include + +#ifdef FX9860G +#include +#endif #include #include @@ -88,6 +94,29 @@ struct menu menu_libs = { { NULL, NULL, 0 }, }}; +//--- +// Global shortcuts +//--- + +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; + } + return false; +} + //--- // Main application //--- @@ -152,6 +181,9 @@ int main(GUNUSED int isappli, GUNUSED int optnum) gint_setrestart(1); #endif + /* Enable global getkey() shortcuts */ + getkey_set_feature_function(getkey_global_shortcuts); + /* Start the profiling library */ prof_init();