diff --git a/CMakeLists.txt b/CMakeLists.txt index b6cbc9a..5ba7b92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ find_package(LibProf 2.1 REQUIRED) find_package(LibImg 2.1 REQUIRED) find_package(JustUI 1.0 REQUIRED) +set_property(GLOBAL PROPERTY RULE_MESSAGES OFF) + set(SOURCES src/gintctl.c src/menu.c @@ -34,6 +36,7 @@ set(SOURCES src/gint/timer_callbacks.c src/gint/tlb.c src/gint/topti.c + src/gint/usb.c src/libs/justui.c src/libs/libimg.c src/libs/memory.c @@ -76,6 +79,7 @@ set(ASSETS_fx assets-fx/img/opt_gint_timer_callbacks.png assets-fx/img/opt_gint_timers.png assets-fx/img/opt_gint_tlb.png + assets-fx/img/opt_gint_usb.png assets-fx/img/opt_libs_jui.png assets-fx/img/opt_main.png assets-fx/img/opt_mem.png diff --git a/assets-fx/img/opt_gint_usb.png b/assets-fx/img/opt_gint_usb.png new file mode 100644 index 0000000..63f43e4 Binary files /dev/null and b/assets-fx/img/opt_gint_usb.png differ diff --git a/include/gintctl/assets.h b/include/gintctl/assets.h index 98466ab..7490967 100644 --- a/include/gintctl/assets.h +++ b/include/gintctl/assets.h @@ -34,6 +34,7 @@ extern bopti_image_t img_opt_gint_timer_callbacks, img_opt_gint_timers, img_opt_gint_tlb, + img_opt_gint_usb, img_opt_libs_jui, img_opt_main, img_opt_mem, diff --git a/include/gintctl/gint.h b/include/gintctl/gint.h index 99c80b1..9c4263f 100644 --- a/include/gintctl/gint.h +++ b/include/gintctl/gint.h @@ -47,6 +47,9 @@ void gintctl_gint_topti(void); /* gintctl_gint_kmalloc(): Dynamic memory allocator */ 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 */ diff --git a/include/gintctl/menu.h b/include/gintctl/menu.h index d9781c8..d4f85ab 100644 --- a/include/gintctl/menu.h +++ b/include/gintctl/menu.h @@ -25,11 +25,11 @@ enum { struct menu { char const *name; - int len; - int offset; - int pos; - int top; - int bottom; + int8_t len; + int8_t offset; + int8_t pos; + int8_t top; + int8_t bottom; struct menuentry entries[]; }; diff --git a/src/gint/usb.c b/src/gint/usb.c new file mode 100644 index 0000000..40b5acf --- /dev/null +++ b/src/gint/usb.c @@ -0,0 +1,329 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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]; +static int log_pos; +static int volatile log_interrupt = 0; + +static void reset_logger(void) +{ + memset(log_buffer, 0, LOG_SIZE+1); + 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; +} + +static void save_logger(void) +{ + uint16_t const *file = u"\\\\fls0\\usb-log.txt"; + int size = log_pos; + + BFile_Remove(file); + BFile_Create(file, BFile_File, &size); + + int fd = BFile_Open(file, BFile_WriteOnly); + if(fd < 0) return; + + BFile_Write(fd, log_buffer, log_pos); + BFile_Close(fd); +} + +//--- +// Rendering functions +//--- + +static void val(int order, char const *name, uint32_t value,GUNUSED int scroll) +{ + #ifdef FX9860G + order -= 2 * scroll; + if(order < 0 || order > 15) return; + int y = 6 * (order / 2) + 8; + int x = 3 + 64 * (order % 2); + #endif + + #ifdef FXCG50 + int y = 12 * (order / 3) + 20; + int x = 6 + 128 * (order % 3); + #endif + + dprint(x, y, C_BLACK, "%s", name); + dprint(x+_(40,88), y, C_BLACK, "%04X", value); +} + +/* Automatically insert ".word" for most registers */ +#define reg(order, name, value) val(order, name, value.word) +/* Force casts to uint32_t for pointers */ +#define val(order, name, value) val(order, name, (uint32_t)value, scroll) + +static void draw_registers(GUNUSED int scroll) +{ + uint16_t volatile *MSELCRA = (void *)0xa4050180; + uint16_t volatile *MSELCRB = (void *)0xa4050182; + + reg( 0, "SYSCFG", USB.SYSCFG); + reg( 1, "BUSWAIT", USB.BUSWAIT); + reg( 2, "SYSSTS", USB.SYSSTS); + reg( 3, "DVSTCTR", USB.DVSTCTR); + reg( 4, "TESTMODE", USB.TESTMODE); + reg( 5, "CFIFOSEL", USB.CFIFOSEL); + reg( 6, "CFIFOCTR", USB.CFIFOCTR); + reg( 7, "D0FIFOSEL", USB.D0FIFOSEL); + reg( 8, "D0FIFOCTR", USB.D0FIFOCTR); + reg( 9, "D1FIFOSEL", USB.D1FIFOSEL); + reg(10, "D1FIFOCTR", USB.D1FIFOCTR); + reg(11, "INTENB0", USB.INTENB0); + reg(12, "BRDYENB", USB.BRDYENB); + reg(13, "NRDYENB", USB.NRDYENB); + reg(14, "BEMPENB", USB.BEMPENB); + reg(15, "SOFCFG", USB.SOFCFG); + reg(16, "INTSTS0", USB.INTSTS0); + reg(17, "BRDYSTS", USB.BRDYSTS); + reg(18, "NRDYSTS", USB.NRDYSTS); + reg(19, "BEMPSTS", USB.BEMPSTS); + reg(20, "FRMNUM", USB.FRMNUM); + reg(21, "UFRMNUM", USB.UFRMNUM); + reg(22, "USBADDR", USB.USBADDR); + reg(23, "USBREQ", USB.USBREQ); + reg(24, "USBVAL", USB.USBVAL); + reg(25, "USBINDX", USB.USBINDX); + reg(26, "USBLENG", USB.USBLENG); + reg(27, "DCPCFG", USB.DCPCFG); + reg(28, "DCPMAXP", USB.DCPMAXP); + reg(29, "DCPCTR", USB.DCPCTR); + reg(30, "PIPESEL", USB.PIPESEL); + reg(31, "PIPECFG", USB.PIPECFG); + reg(32, "PIPEBUF", USB.PIPEBUF); + reg(33, "PIPEMAXP", USB.PIPEMAXP); + reg(34, "PIPEPERI", USB.PIPEPERI); + reg(35, "PIPE1CTR", USB.PIPECTR[0]); + reg(36, "PIPE1TRE", USB.PIPE1TRE); + reg(37, "PIPE1TRN", USB.PIPE1TRN); + reg(38, "UPONCR", SH7305_USB_UPONCR); + val(39, "REG_C2", USB.REG_C2); + val(40, "MSELCRA", *MSELCRA); + val(41, "MSELCRB", *MSELCRB); + + #ifdef FX9860G + if(scroll >= 14) dprint(3, 50 - 6 * (scroll - 14), C_BLACK, + "USBCLKCR:%08X", SH7305_CPG.USBCLKCR.lword); + if(scroll >= 15) dprint(3, 50 - 6 * (scroll - 15), C_BLACK, + "MSTPCR2: %08X", SH7305_POWER.MSTPCR2.lword); + #endif + + #ifdef FXCG50 + dprint(row_x(1), 188, C_BLACK, "USBCLKCR: %08X MSTPCR2: %08X", + SH7305_CPG.USBCLKCR.lword, SH7305_POWER.MSTPCR2.lword); + #endif +} + +static void draw_context(void) +{ + extern void *driver_ctx(char const *name); + ctx_t *ctx = driver_ctx("USB"); + GUNUSED int scroll = 0; + + 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); + + // uint16_t PIPECFG[9], PIPEBUF[9], PIPEMAXP[9], PIPEPERI[9]; + // uint16_t PIPEnCTR[9], PIPEnTRE[5], PIPEnTRN[5]; +} + +static int draw_log(int offset) +{ + int const y0=_(8,20), dy=_(6,12), lines=_(8,15); + int const x=_(2,6), w=DWIDTH-_(9,15); + + /* Split log into lines */ + char const *log = log_buffer; + int y = y0 - offset*dy; + int line = 0; + + while(log < log_buffer + log_pos) + { + char const *endscreen = drsize(log, NULL, w, NULL); + char const *endline = strchrnul(log, '\n'); + int end = 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); + y += dy; + line++; + log += end + (log[end] == '\n'); + } + + if(line > lines) + { + scrollbar_px(y0, y0 + lines*dy, 0, line, offset, lines); + return line - lines; + } + + return 0; +} + +static void draw_pipes(void) +{ +#ifdef FXCG50 + char const *PID[4] = { "NAK", "BUF", "STALL0", "STALL1" }; + char const *BSTS[2] = { "Disabled", "Enabled" }; + char const *FRDY[2] = { "NotReady", "Ready" }; + char const *PBUSY[2] = { "Idle", "Busy" }; + + row_print(1, 1, "CFIFOSEL:"); + row_print(1, 11, "%04x", USB.CFIFOSEL.word); + row_print(1, 16, "CFIFOCTR:"); + row_print(1, 26, "%04x %s", USB.CFIFOCTR.word, + FRDY[USB.CFIFOCTR.FRDY]); + row_print(2, 1, "DCPCTR:"); + row_print(2, 11, "%04x %s %s %s %d", USB.DCPCTR.word, + BSTS[USB.DCPCTR.BSTS], PBUSY[USB.DCPCTR.PBUSY], PID[USB.DCPCTR.PID], + USB.DCPCTR.CCPL); + + row_print(3, 1, "D0FIFOCTR:"); + row_print(3, 11, "%04x", USB.D0FIFOCTR.word); + row_print(3, 16, "D0FIFOSEL:"); + row_print(3, 26, "%04x", USB.D0FIFOSEL.word); + + row_print(4, 1, "D1FIFOCTR:"); + row_print(4, 11, "%04x", USB.D1FIFOCTR.word); + row_print(4, 16, "D1FIFOSEL:"); + row_print(4, 26, "%04x", USB.D1FIFOSEL.word); + + for(int i = 0; i < 9; i++) + { + row_print(i+5, 1, "PIPE%dCTR:", i+1); + row_print(i+5, 10, "%04x", USB.PIPECTR[i].word); + } +#endif +} + +static void open_callback(void) +{ + usb_log("Open callback, doing test!\n"); + extern void usb_tests(void); + usb_tests(); +} + +/* gintctl_gint_usb(): USB communication */ +void gintctl_gint_usb(void) +{ + int key=0, tab=0; + bool open=false; + GUNUSED int scroll0=0, scroll2=0, maxscroll2=0; + + reset_logger(); + usb_set_log(usb_logger); + + while(key != KEY_EXIT) + { + dclear(C_WHITE); + + #ifdef FX9860G + row_title("USB 2.0 communication"); + dsubimage(0, 56, &img_opt_gint_usb, 0, open * 9, 128, 9, DIMAGE_NONE); + if(tab == 0) scrollbar_px(8, 52, 0, 22, scroll0, 8); + #endif + + font_t const *old_font = dfont(_(&font_mini, dfont_default())); + + if(tab == 0) draw_registers(scroll0); + if(tab == 1) draw_context(); + if(tab == 2) maxscroll2 = draw_log(scroll2); + if(tab == 3) draw_pipes(); + + #ifdef FXCG50 + row_title("USB 2.0 function module and communication"); + fkey_menu(1, "REGS"); + fkey_menu(2, "CTX"); + fkey_menu(3, "LOG"); + fkey_menu(4, "PIPES"); + if(tab == 2) fkey_button(5, "FILE"); + fkey_action(6, open ? "CLOSE" : "OPEN"); + #endif + +// dprint_opt(DWIDTH - 8, DHEIGHT - 6, C_BLACK, C_NONE, DTEXT_RIGHT, +// DTEXT_BOTTOM, "Interrupts: %d", usb_interrupt_count); + + dfont(old_font); + dupdate(); + + key = getkey_opt(GETKEY_DEFAULT, &log_interrupt).key; + log_interrupt = 0; + + 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(tab == 2 && key == KEY_F5) gint_switch(save_logger); + + if(key == KEY_F6) + { + if(open) usb_close(), open = false; + else + { + usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL }; + int rc = usb_open(interfaces, GINT_CB(open_callback)); + open = (rc == 0); + } + } + + #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++; + } +} diff --git a/src/gintctl.c b/src/gintctl.c index 47eceeb..72b2e05 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -44,6 +44,7 @@ struct menu menu_gint = { { "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 }, #ifdef FX9860G