diff --git a/CMakeLists.txt b/CMakeLists.txt index c51e027..6c0e852 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(SOURCES ) set(ASSETS_fx assets-fx/fonts/hexa.png + assets-fx/fonts/mini.png assets-fx/fonts/uf5x7 assets-fx/img/bopti_1col.png assets-fx/img/bopti_2col.png diff --git a/assets-fx/fonts/fxconv-metadata.txt b/assets-fx/fonts/fxconv-metadata.txt index c0613ab..1ada7a3 100644 --- a/assets-fx/fonts/fxconv-metadata.txt +++ b/assets-fx/fonts/fxconv-metadata.txt @@ -5,6 +5,15 @@ hexa.png: grid.size: 3x5 grid.padding: 1 +mini.png: + type: font + name: font_mini + charset: ascii + proportional: true + height: 5 + grid.size: 5x6 + grid.padding: 1 + uf5x7: type: font name: font_uf5x7 diff --git a/assets-fx/fonts/mini.png b/assets-fx/fonts/mini.png new file mode 100644 index 0000000..a29757c Binary files /dev/null and b/assets-fx/fonts/mini.png differ diff --git a/assets-fx/img/opt_dump.png b/assets-fx/img/opt_dump.png index 67bd0f0..46a2212 100644 Binary files a/assets-fx/img/opt_dump.png and b/assets-fx/img/opt_dump.png differ diff --git a/assets-fx/img/opt_gint_bopti.png b/assets-fx/img/opt_gint_bopti.png index 8388216..7989bb0 100644 Binary files a/assets-fx/img/opt_gint_bopti.png and b/assets-fx/img/opt_gint_bopti.png differ diff --git a/assets-fx/img/opt_gint_gray.png b/assets-fx/img/opt_gint_gray.png index b3b8d77..12265c8 100644 Binary files a/assets-fx/img/opt_gint_gray.png and b/assets-fx/img/opt_gint_gray.png differ diff --git a/assets-fx/img/opt_gint_ram.png b/assets-fx/img/opt_gint_ram.png index 2c6b994..f246bd3 100644 Binary files a/assets-fx/img/opt_gint_ram.png and b/assets-fx/img/opt_gint_ram.png differ diff --git a/assets-fx/img/opt_gint_rtc.png b/assets-fx/img/opt_gint_rtc.png index 33006d3..74b727f 100644 Binary files a/assets-fx/img/opt_gint_rtc.png and b/assets-fx/img/opt_gint_rtc.png differ diff --git a/assets-fx/img/opt_gint_spuram.png b/assets-fx/img/opt_gint_spuram.png index 3878f43..9f38e26 100644 Binary files a/assets-fx/img/opt_gint_spuram.png and b/assets-fx/img/opt_gint_spuram.png differ diff --git a/assets-fx/img/opt_gint_timer_callbacks.png b/assets-fx/img/opt_gint_timer_callbacks.png index dce071c..1472987 100644 Binary files a/assets-fx/img/opt_gint_timer_callbacks.png and b/assets-fx/img/opt_gint_timer_callbacks.png differ diff --git a/assets-fx/img/opt_gint_timers.png b/assets-fx/img/opt_gint_timers.png index 00af5be..48b2d12 100644 Binary files a/assets-fx/img/opt_gint_timers.png and b/assets-fx/img/opt_gint_timers.png differ diff --git a/assets-fx/img/opt_gint_tlb.png b/assets-fx/img/opt_gint_tlb.png index af4fa76..b65f971 100644 Binary files a/assets-fx/img/opt_gint_tlb.png and b/assets-fx/img/opt_gint_tlb.png differ diff --git a/assets-fx/img/opt_main.png b/assets-fx/img/opt_main.png index 3083554..9ad426a 100644 Binary files a/assets-fx/img/opt_main.png and b/assets-fx/img/opt_main.png differ diff --git a/assets-fx/img/opt_mem.png b/assets-fx/img/opt_mem.png index 8079c10..44ba00b 100644 Binary files a/assets-fx/img/opt_mem.png and b/assets-fx/img/opt_mem.png differ diff --git a/assets-fx/img/opt_switch.png b/assets-fx/img/opt_switch.png index 8d4d0aa..88d8b4d 100644 Binary files a/assets-fx/img/opt_switch.png and b/assets-fx/img/opt_switch.png differ diff --git a/assets-fx/img/tlb_cells.png b/assets-fx/img/tlb_cells.png index db47e72..3fc180d 100644 Binary files a/assets-fx/img/tlb_cells.png and b/assets-fx/img/tlb_cells.png differ diff --git a/include/gintctl/menu.h b/include/gintctl/menu.h index f7d09e4..d9781c8 100644 --- a/include/gintctl/menu.h +++ b/include/gintctl/menu.h @@ -44,10 +44,11 @@ struct menu { void menu_init(struct menu *menu, int top, int bottom); /* menu_move(): Move the cursor in a menu - @menu Initialized list menu - @key Either KEY_UP, indicating up, or KEY_DOWN indicating down - @wrap Allow wrap-around */ -void menu_move(struct menu *menu, int key, int wrap); + @menu Initialized list menu + @key Either KEY_UP, indicating up, or KEY_DOWN indicating down + @quick Whether to quick-move to start or end + @wrap Allow wrap-around */ +void menu_move(struct menu *menu, int key, int quick, int wrap); /* menu_show(): Render a list menu */ void menu_show(struct menu const *menu); diff --git a/include/gintctl/util.h b/include/gintctl/util.h index 0734eb1..1d993d5 100644 --- a/include/gintctl/util.h +++ b/include/gintctl/util.h @@ -50,11 +50,23 @@ int row_x(int x); int row_y(int y); //--- -// General (x,y) printing +// General rendering //--- -/* print(): Formatted printing shorthand */ -void print(int x, int y, char const *format, ...); +/* scrollbar_px(): Pixel-based scrollbar + @view_top First pixel covered by scrollbar area + @view_bottom Pixel below last pixel covered by scrollbar area + @range_min Minimum value in the virtual range we're scrolling through + @range_max Maximum value in the virtual range + @range_pos Position within the virtual range + @range_view How much of the range is visible on-screen */ +void scrollbar_px(int view_top, int view_bottom, int range_min, int range_max, + int range_pos, int range_view); + +#define print_prefix(x, y, prefix, fmt, ...) { \ + dtext_opt(x-_(3,5), y, C_BLACK,C_NONE,DTEXT_RIGHT,DTEXT_TOP, prefix); \ + dprint(x+_(3,5), y, C_BLACK, fmt __VA_OPT__(,) __VA_ARGS__); \ +} //--- // F-key rendering diff --git a/src/gint/bopti.c b/src/gint/bopti.c index cf7fbc2..7f0c459 100644 --- a/src/gint/bopti.c +++ b/src/gint/bopti.c @@ -9,7 +9,6 @@ /* gintctl_gint_bopti(): Test image rendering */ void gintctl_gint_bopti(void) { - extern bopti_image_t img_swift; extern bopti_image_t img_swords; extern bopti_image_t img_potion_17x22, img_potion_18x22; extern bopti_image_t img_applejack_31x27, img_applejack_36x25; diff --git a/src/gint/cpumem.c b/src/gint/cpumem.c index d18c7f4..dfb254d 100644 --- a/src/gint/cpumem.c +++ b/src/gint/cpumem.c @@ -2,18 +2,23 @@ #include #include #include +#include #include #include -#define put(...) row_print(++(*row), 1, __VA_ARGS__) +/* TODO: Include */ +extern uint32_t cpu_getVBR(void); + +/* Some symbols from the linker script */ +extern uint32_t + brom, srom, /* Limits of ROM mappings */ + sdata, rdata, /* User's data section */ + sbss, rbss; /* User's BSS section */ +#ifdef FX9860G +extern uint32_t sgmapped; /* Permanently mapped functions */ +#endif -#define load_barrier(x) { \ - if(!((x) & HW_LOADED)) { \ - put(" (not loaded)"); \ - return; \ - } \ -} /* MPU type and processor version */ void show_mpucpu(void) @@ -35,8 +40,8 @@ void show_mpucpu(void) }; char const *calc_names[] = { "Unknown", - "SH3 fx-9860G*", - "SH4 fx-9860G*", + "fx-9860G-like", + "fx-9860G-like", "Graph 35+E II", "Prizm fx-CG 20", "fx-CG 50/Graph 90+E", @@ -46,69 +51,101 @@ void show_mpucpu(void) int mpu = gint[HWMPU]; int calc = gint[HWCALC]; - char const *str_calc = _("Model", "Calculator model"); - if(calc < 0 || calc > 6) - row_print(1, 1, "%s: ", str_calc, calc); - else - row_print(1, 1, "%s: %s", str_calc, calc_names[calc]); + /* Generate a default calc name if invalid values are found */ + char calc_default[16]; + sprintf(calc_default, "", calc); + char const *str_calc = calc_default; + if(calc >= 0 && calc < 7) str_calc = calc_names[calc]; - if(mpu < 0 || mpu > 4) - row_print(_(2,3), 1, "MPU: ", mpu); - else - row_print(_(2,3), 1, "MPU: %s", mpu_names[mpu]); + /* Generate a default MPU name if invalid values are found */ + char mpu_default[16]; + sprintf(mpu_default, "", mpu); + char const *str_mpu = mpu_default; + if(mpu >= 0 && mpu < 5) str_mpu = mpu_names[mpu]; volatile uint32_t *CPUOPM = (void *)0xff2f0000; - uint32_t SR; - __asm__("stc sr, %0" : "=r"(SR)); + uint32_t SR, r15; + __asm__("stc sr, %0" : "=r"(SR)); + __asm__("mov r15, %0" : "=r"(r15)); #ifdef FX9860G - if(isSH3()) - { - row_print(4, 1, " SR %08x", SR); - return; + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + + dprint(1, 10, C_BLACK, "Model: %s", str_calc); + dprint(1, 16, C_BLACK, "MPU: %s", str_mpu); + + print_prefix(29, 24, "SR", "%08X", SR); + dline(29, 24, 29, 46, C_BLACK); + if(isSH3()) { + print_prefix(29, 30, "PVR", ""); + print_prefix(29, 36, "PRR", ""); + print_prefix(29, 42, "CPUOPM", ""); } - row_print(4, 1, " SR %08x", SR); - row_print(5, 1, " PVR %08x", gint[HWCPUVR]); - row_print(6, 1, " PRR %08x", gint[HWCPUPR]); - row_print(7, 1, " CPUOPM %08x", *CPUOPM); + else { + print_prefix(29, 30, "PVR", "%08X", gint[HWCPUVR]); + print_prefix(29, 36, "PRR", "%08X", gint[HWCPUPR]); + print_prefix(29, 42, "CPUOPM", "%08X", *CPUOPM); + } + print_prefix(85, 24, "VBR", "%08X", cpu_getVBR()); + print_prefix(85, 30, "R15", "%08X", r15); + dline(85, 24, 85, 34, C_BLACK); + dfont(old_font); #endif #ifdef FXCG50 + row_print(1, 1, "Calculator model: %s", str_calc); + row_print(3, 1, "MPU: %s", str_mpu); row_print(4, 1, " Status Register: %08x", SR); row_print(5, 1, " Processor Version Register: %08x", gint[HWCPUVR]); row_print(6, 1, " Product Register: %08x", gint[HWCPUPR]); 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); #endif } /* Memory */ static void show_memory(void) { - uint32_t base_rom = 0x80000000; - uint32_t base_ram = 0x88000000; - uint32_t base_uram = (uint32_t)mmu_uram(); - - int rom = gint[HWROM]; - int ram = gint[HWRAM]; - int uram = mmu_uram_size(); - #ifdef FX9860G - row_title("Basic memory layout"); - row_print(3, 2, "%08x %4dk ROM", base_rom, rom >> 10); - row_print(4, 2, "%08x %4dk RAM", base_ram, ram >> 10); - row_print(5, 2, "%08x %4dk URAM", base_uram, uram >> 10); - row_print(6, 2, "Mapped %4dk", gint[HWURAM] >> 10); + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + print_prefix(28, 10, "brom", "%08X", &brom); + print_prefix(28, 16, "rdata", "%08X", &rdata); + print_prefix(28, 22, "rbss", "%08X", &rbss); + print_prefix(28, 28, "rreloc", "%08X", mmu_uram()); + + print_prefix(98, 10, "srom", "%06d", &srom); + print_prefix(98, 16, "sdata", "%06d", &sdata); + print_prefix(98, 22, "sbss", "%06d", &sbss); + print_prefix(98, 28, "sreloc", "%06d", &sgmapped); + + dprint(1, 38, C_BLACK, "ROM: %dk, RAM: %dk", + gint[HWROM] >> 10, gint[HWRAM] >> 10); + dprint(1, 45, C_BLACK, "User RAM: %08X (%dk, P0 %dk)", + mmu_uram(), mmu_uram_size() >> 10, gint[HWURAM] >> 10); + dfont(old_font); #endif #ifdef FXCG50 + uint32_t base_ram = 0x88000000; if(gint[HWCALC] == HWCALC_FXCG50) base_ram = 0x8c000000; - row_print(1, 1, "ROM: %dM", rom >> 20); - row_print(2, 2, "%08X ... %08X", 0x80000000, 0x80000000+rom-1); - row_print(3, 1, "RAM: %dM", ram >> 20); - row_print(4, 2, "%08X ... %08X", base_ram, base_ram+ram-1); - row_print(5, 1, "Userspace RAM: %dk blocked", uram >> 10); - row_print(6, 2, "%08X ... %08X", base_uram, base_uram+uram-1); - row_print(7, 1, "Total mapped RAM: %dk", gint[HWURAM] >> 10); + + row_print(1, 1, "RAM: %dM, RAM: %dM (starts at %08X)", + gint[HWROM] >> 20, gint[HWRAM] >> 20, base_ram); + row_print(2, 1, "Userspace RAM: %08X (%dk continuous block)", + mmu_uram(), mmu_uram_size() >> 10); + row_print(3, 1, "Total RAM mapped in P0: %dk", + gint[HWURAM] >> 10); + + print_prefix(80, row_y(5), "brom", "%08X", &brom); + print_prefix(80, row_y(6), "rdata", "%08X", &rdata); + print_prefix(80, row_y(7), "rbss", "%08X", &rbss); + + print_prefix(240, row_y(5), "srom", "%06d", &srom); + print_prefix(240, row_y(6), "sdata", "%06d", &sdata); + print_prefix(240, row_y(7), "sbss", "%06d", &sbss); #endif } @@ -164,6 +201,7 @@ void gintctl_gint_cpumem(void) if(tab == 1) show_memory(); #ifdef FX9860G + row_title("CPU and memory"); extern bopti_image_t img_opt_gint_cpumem; dimage(0, 56, &img_opt_gint_cpumem); #endif diff --git a/src/gint/ram.c b/src/gint/ram.c index 19fbdc2..d9105b3 100644 --- a/src/gint/ram.c +++ b/src/gint/ram.c @@ -127,31 +127,31 @@ static void show_region(int row, struct region *r) /* Out-of-bounds rows */ if(row < 1 || row > 9 || (row == 1 && r)) return; - extern font_t font_hexa; - font_t const *old_font = dfont(&font_hexa); - int y = (row - 1) * 6; + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + int y = (row - 1) * 6 + 2 * (row > 1); if(!r) { dprint( 1, y, C_BLACK, "Area"); - dprint(24, y, C_BLACK, "Address"); - dprint(60, y, C_BLACK, "Size"); - dprint(80, y, C_BLACK, "Reason"); + dprint(26, y, C_BLACK, "Address"); + dprint(62, y, C_BLACK, "Size"); + dprint(82, y, C_BLACK, "At end"); dfont(old_font); return; } - char const *reasons[] = { "", "Read-only", "Loops", "" }; + char const *reasons[] = { "Not tested", "Read-only", "Loops", "" }; dprint( 1, y, C_BLACK, "%s", r->name); - dprint(24, y, C_BLACK, "%08X", r->mem); + dprint(26, y, C_BLACK, "%08X", r->mem); if(r->reason != 0) - { - dprint(60, y, C_BLACK, "%dk", r->size >> 10); - dprint(80, y, C_BLACK, "%s", reasons[r->reason]); - } + dprint(62, y, C_BLACK, "%dk", r->size >> 10); + else + dprint(62, y, C_BLACK, "-"); + dprint(82, y, C_BLACK, "%s", reasons[r->reason]); dfont(old_font); } #endif @@ -172,7 +172,7 @@ static void show_region(int y, struct region *r) row_print(y, 9, "Address"); row_print(y, 18, "AS"); row_print(y, 22, "Size"); - row_print(y, 35, "Reason"); + row_print(y, 35, "At end"); return; } @@ -207,6 +207,7 @@ void gintctl_gint_ram(void) /* List scroll no fx-9860G */ GUNUSED int scroll = spu_zero(); + key_event_t ev; int key = 0; while(key != KEY_EXIT) { @@ -214,13 +215,13 @@ void gintctl_gint_ram(void) #ifdef FX9860G show_region(1, NULL); + dhline(6, C_BLACK); for(int i = 0; i < region_count; i++) { show_region(i+2-scroll, &r[i]); } - - if(scroll > 0) triangle_up(7); - if(scroll < region_count - 8) triangle_down(49); + scrollbar_px(/* view */ 8, 54, /* range */ 0, region_count, + /* visible */ scroll, 8); extern bopti_image_t img_opt_gint_ram; dimage(0, 56, &img_opt_gint_ram); @@ -242,7 +243,8 @@ void gintctl_gint_ram(void) dupdate(); - key = getkey().key; + ev = getkey(); + key = ev.key; if(key == KEY_F1) { explore_region(&r[0]); @@ -271,8 +273,17 @@ void gintctl_gint_ram(void) } #ifdef FX9860G - if(key == KEY_UP && scroll > 0) scroll--; - if(key == KEY_DOWN && scroll < region_count - 8) scroll++; + int scroll_max = region_count - 8; + if(key == KEY_UP) + { + if(ev.shift || keydown(KEY_SHIFT)) scroll=0; + else if(scroll > 0) scroll--; + } + if(key == KEY_DOWN) + { + if(ev.shift || keydown(KEY_SHIFT)) scroll=scroll_max; + else if(scroll < scroll_max) scroll++; + } #endif } } diff --git a/src/gint/spuram.c b/src/gint/spuram.c index 6a7a0d7..4a98fcf 100644 --- a/src/gint/spuram.c +++ b/src/gint/spuram.c @@ -41,7 +41,7 @@ static void restore(volatile uint32_t *area, uint32_t *save, int pages) } #ifdef FX9860G -static void render_header(int y, int bank_count) +static void render_header(int y, GUNUSED int bank_count) { y = 9 + 6*y; dtext( 1, 9, C_BLACK, "Area"); @@ -166,6 +166,8 @@ void gintctl_gint_spuram(void) int cur_bank = 0; int cur_page = 0; + int switch_key = _(KEY_F6, KEY_F1); + #ifdef FX9860G int tab = 0; #endif @@ -178,7 +180,7 @@ void gintctl_gint_spuram(void) row_title("SPU memory banking"); extern font_t font_hexa; - font_t *old_font = dfont(&font_hexa); + font_t const *old_font = dfont(&font_hexa); if(tab == 0) { @@ -204,7 +206,8 @@ void gintctl_gint_spuram(void) dfont(old_font); extern bopti_image_t img_opt_gint_spuram; - dimage(0, 56, &img_opt_gint_spuram); + dsubimage(0, 56, &img_opt_gint_spuram, 0, 0, + (tab == 1 ? 128 : 107), 8, DIMAGE_NONE); #endif #ifdef FXCG50 @@ -244,20 +247,20 @@ void gintctl_gint_spuram(void) if(key == KEY_DOWN && cur_bank == 0) cur_bank++; - if(key == KEY_F1 && cur_bank == 0 && _(tab == 1, 1)) + if(key == switch_key && cur_bank == 0 && _(tab == 1, 1)) { SPU.PBANKC0 ^= (1 << cur_page); SPU.PBANKC1 ^= (1 << cur_page); } - if(key == KEY_F1 && cur_bank == 1 && _(tab == 1, 1)) + if(key == switch_key && cur_bank == 1 && _(tab == 1, 1)) { SPU.XBANKC0 ^= (1 << cur_page); SPU.XBANKC1 ^= (1 << cur_page); } #ifdef FX9860G - if(key == KEY_F2) tab = 0; - if(key == KEY_F3) tab = 1; + if(key == KEY_F1) tab = 0; + if(key == KEY_F2) tab = 1; #endif } diff --git a/src/gint/switch.c b/src/gint/switch.c index 7300700..d62074e 100644 --- a/src/gint/switch.c +++ b/src/gint/switch.c @@ -12,7 +12,6 @@ #include static int switches = 0; -static int fast = 0; static int menus = 0; static void switch_function(void) @@ -230,8 +229,7 @@ void render(void) 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, "Fast done: %d", fast); - row_print(5, 1, "Menus done: %d", menus); + row_print(4, 1, "Menus done: %d", menus); dimage(0, 56, &img_opt_switch); #endif @@ -239,11 +237,9 @@ void render(void) #ifdef FXCG50 row_title("Hot switching between gint and OS"); row_print(2, 1, "Switches done: %d", switches); - row_print(3, 1, "Fast done: %d", fast); - row_print(4, 1, "Menus done: %d", menus); + row_print(3, 1, "Menus done: %d", menus); fkey_button(1, "SWITCH"); - fkey_button(2, "FAST"); - fkey_button(3, "MENU"); + fkey_button(2, "MENU"); fkey_action(6, "SYSTEM"); #endif } @@ -260,10 +256,8 @@ void gintctl_gint_switch(void) key = getkey().key; if(key == KEY_F1) gint_switch(switch_function); - /* TODO: Fast gint switch in gintctl */ - if(key == KEY_F2) {} - /* Wait for F3 to be released before calling next getkey() */ - if(key == KEY_F3) + /* 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 @@ -275,7 +269,7 @@ void gintctl_gint_switch(void) dupdate(); gint_osmenu(); - while(keydown(KEY_F3)) waitevent(NULL); + while(keydown(KEY_F2)) waitevent(NULL); } if(key == KEY_F6) system_contexts(); } diff --git a/src/gint/timer.c b/src/gint/timer.c index 8e7d90f..183e993 100644 --- a/src/gint/timer.c +++ b/src/gint/timer.c @@ -98,7 +98,6 @@ void gintctl_gint_timer(void) program to ~90 FPS.) */ int key=0, tid=0; GUNUSED int timeout=1; - volatile int flag = 0; #ifdef FX9860G int tab = 1; @@ -116,8 +115,11 @@ void gintctl_gint_timer(void) extern bopti_image_t img_opt_gint_timers; dimage(0, 56, &img_opt_gint_timers); - if(tid < 3) dprint(23, 56, C_BLACK, "TMU%d", tid); - else dprint(23, 56, C_BLACK, "ETMU%d", tid-3); + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + if(tid < 3) dprint(24, 57, C_BLACK, "\x01 TMU%d \x02", tid); + else dprint(24, 57, C_BLACK, "\x01 ETMU%d \x02", tid-3); + dfont(old_font); #endif #ifdef FXCG50 @@ -155,7 +157,9 @@ void gintctl_gint_timer(void) if(key == KEY_F6) tab = 3; #endif - if(key == KEY_UP) tid = (tid+timer_count()-1) % timer_count(); - if(key == KEY_DOWN) tid = (tid + 1) % timer_count(); + if(key == KEY_LEFT) + tid = (tid + timer_count() - 1) % timer_count(); + if(key == KEY_RIGHT) + tid = (tid + 1) % timer_count(); } } diff --git a/src/gint/tlb.c b/src/gint/tlb.c index 1c5e2a3..05d23a8 100644 --- a/src/gint/tlb.c +++ b/src/gint/tlb.c @@ -37,8 +37,8 @@ static void draw_rom_cell(int x, int y, int status) #ifdef FX9860G #define PAGE_COUNT 0x80 -#define SQUARE_WIDTH 4 -#define SQUARE_HEIGHT 4 +#define SQUARE_WIDTH 5 +#define SQUARE_HEIGHT 5 #define LINE_SIZE 16 #define TLB_VIEW 8 @@ -61,44 +61,6 @@ static int rom_cell_y(int page_number) return (page_number / LINE_SIZE) * SQUARE_HEIGHT; } -#ifdef FX9860G -void triangle_up(int y) -{ - int x=118; - dpixel(x+2, y, C_BLACK); - dline(x+1, y+1, x+3, y+1, C_BLACK); - dline(x, y+2, x+4, y+2, C_BLACK); -} -void triangle_down(int y) -{ - int x=118; - dline(x, y, x+4, y, C_BLACK); - dline(x+1, y+1, x+3, y+1, C_BLACK); - dpixel(x+2, y+2, C_BLACK); -} -#endif - -#ifdef FXCG50 -void triangle_up(int y) -{ - int x=370; - dpixel(x+3, y, C_BLACK); - dline(x+2, y+1, x+4, y+1, C_BLACK); - dline(x+1, y+2, x+5, y+2, C_BLACK); - dline(x, y+3, x+6, y+3, C_BLACK); - dline(x, y+4, x+6, y+4, C_BLACK); -} -void triangle_down(int y) -{ - int x=370; - dline(x, y, x+6, y, C_BLACK); - dline(x, y+1, x+6, y+1, C_BLACK); - dline(x+1, y+2, x+5, y+2, C_BLACK); - dline(x+2, y+3, x+4, y+3, C_BLACK); - dpixel(x+3, y+4, C_BLACK); -} -#endif - static void explore_pages(uint8_t *pages, uint32_t *next_miss) { extern uint32_t srom; @@ -177,44 +139,48 @@ void show_utlb(int row, int E) char const *access_str[] = { "K:r", "K:rw", "U:r", "U:rw" }; uint16_t fg = valid ? C_BLACK : C_RGB(24,24,24); - #define fg_ fg, C_NONE + #define fg_ fg, C_NONE, DTEXT_LEFT, DTEXT_TOP - row_print_color(row, 2, fg_, "%d", E); - row_print_color(row, 5, fg_, "%08X", src); - row_print_color(row, 14, fg_, "%08X", dst); - row_print_color(row, 23, fg_, "%s", size_str[size]); - row_print_color(row, 28, fg_, "%s", access_str[data.PR]); - row_print_color(row, 34, fg_, "%s", (data.SH ? "SH" : "-")); - row_print_color(row, 37, fg_, "%s", (data.WT ? "WT" : "CB")); - row_print_color(row, 40, fg_, "%s", (data.C ? "C" : "-")); - row_print_color(row, 42, fg_, "%s", (addr.D || data.D ? "D" : "-")); - row_print_color(row, 44, fg_, "%s", (addr.V && data.V ? "V" : "-")); + int y = row_y(row) + 2 * (row > 1); + + dprint_opt( 14, y, fg_, "%d", E); + dprint_opt( 38, y, fg_, "%08X", src); + dprint_opt(110, y, fg_, "%08X", dst); + dprint_opt(182, y, fg_, "%s", size_str[size]); + dprint_opt(222, y, fg_, "%s", access_str[data.PR]); + dprint_opt(270, y, fg_, "%s", (data.SH ? "SH" : "-")); + dprint_opt(294, y, fg_, "%s", (data.WT ? "WT" : "CB")); + dprint_opt(318, y, fg_, "%s", (data.C ? "C" : "-")); + dprint_opt(334, y, fg_, "%s", (addr.D || data.D ? "D" : "-")); + dprint_opt(350, y, fg_, "%s", (addr.V && data.V ? "V" : "-")); } #endif #ifdef FX9860G void show_utlb(int row, int E) { - extern font_t font_hexa; - font_t const *old_font = dfont(&font_hexa); - int y = (row - 1) * 6; + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + int y = (row - 1) * 6 + 2 * (row > 1); if(E == -1) { - dprint( 1, y, C_BLACK, "ID"); - dprint(12, y, C_BLACK, "Virtual"); - dprint(47, y, C_BLACK, "Physical"); - dprint(82, y, C_BLACK, "Len"); - dprint(98, y, C_BLACK, "Mode"); + dprint( 1, y, C_BLACK, "ID"); + dprint( 12, y, C_BLACK, "Virtual"); + dprint( 47, y, C_BLACK, "Physical"); + dprint( 82, y, C_BLACK, "Len"); + dprint( 97, y, C_BLACK, "Pr"); + dprint(115, y, C_BLACK, "CD"); dfont(old_font); return; } char const *size_str[] = { "1k", "4k", "64k", "1M" }; - char const *access_str[] = { "K:r", "K:rw", "U:r", "U:rw" }; + char const *access_str[] = { "Kr", "Krw", "Ur", "Urw" }; + char const *cd_str[] = { "--", "-D", "C-", "CD" }; uint32_t src, dst; - int valid, size, pr; + int valid, size, pr, cd; if(isSH3()) { @@ -232,6 +198,7 @@ void show_utlb(int row, int E) dst = data.PPN << 10; pr = data.PR; + cd = (data.C << 1) | data.D; } else { @@ -244,16 +211,18 @@ void show_utlb(int row, int E) valid = (addr.V != 0) && (data.V != 0); size = (data.SZ1 << 1) | data.SZ2; pr = data.PR; + cd = (data.C << 1) | data.D; } dprint( 1, y, C_BLACK, "%d", E); if(valid) { - dprint(12, y, C_BLACK, "%08X", src); - dprint(47, y, C_BLACK, "%08X", dst); - dprint(82, y, C_BLACK, "%s", size_str[size]); - dprint(98, y, C_BLACK, "%s", access_str[pr]); + dprint( 12, y, C_BLACK, "%08X", src); + dprint( 47, y, C_BLACK, "%08X", dst); + dprint( 82, y, C_BLACK, "%s", size_str[size]); + dprint( 97, y, C_BLACK, "%s", access_str[pr]); + dprint(115, y, C_BLACK, "%s", cd_str[cd]); } dfont(old_font); @@ -271,23 +240,29 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) #endif row_title(_("TLB management", "TLB miss handler and TLB management")); + #ifdef FX9860G + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); + #endif + if(tab == 0) { - row_print(_(2,1), 1, _("srom=%x (%d pages)", - "Size of ROM sections: %08X (%d pages of 4k)"), + #ifdef FXCG50 + row_print(1, 1, "Size of ROM sections: %08X (%d pages of 4k)", rom_size, rom_pages); + #endif - for(uint p=0, y=_(19,36); p < PAGE_COUNT; p += 2*LINE_SIZE) + for(uint p=0, y=_(12,36); p < PAGE_COUNT; p += 2*LINE_SIZE) { - dprint(_(4,18), y, C_BLACK, _("%06x","%08X"), + dprint(_(5,18), y, C_BLACK, "%08X", 0x00300000 + (p << 12)); y += 2*SQUARE_HEIGHT; } for(uint p = 0; p < PAGE_COUNT; p++) { - draw_rom_cell(_(44,88) + rom_cell_x(p), - _(20,36) + rom_cell_y(p), pages[p]); + draw_rom_cell(_(39,88) + rom_cell_x(p), + _(11,36) + rom_cell_y(p), pages[p]); } #ifdef FXCG50 @@ -308,18 +283,18 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) else if(tab == 1) { row_print(_(2,1), 1, "Legend:"); - draw_rom_cell(_(8,18), _(17,36), 0); - draw_rom_cell(_(64,200), _(17,36), 1); - draw_rom_cell(_(8,18), _(25,50), 2); - draw_rom_cell(_(64,200), _(25,50), 3); + draw_rom_cell(_(8,18), _(15,36), 0); + draw_rom_cell(_(64,200), _(15,36), 1); + draw_rom_cell(_(8,18), _(22,50), 2); + draw_rom_cell(_(64,200), _(22,50), 3); - dprint(_(16,30), _(16,36), C_BLACK, + dprint(_(16,30), _(15,36), C_BLACK, _("Unused", "Unused in add-in")); - dprint(_(72,212), _(16,36), C_BLACK, + dprint(_(72,212), _(15,36), C_BLACK, _("Unmapped", "Currently unmapped")); - dprint(_(16,30), _(24,50), C_BLACK, + dprint(_(16,30), _(22,50), C_BLACK, _("Data", "Data still mapped")); - dprint(_(72,212), _(24,50), C_BLACK, + dprint(_(72,212), _(22,50), C_BLACK, _("Mapped", "Currently mapped")); #ifdef FXCG50 @@ -327,7 +302,7 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) dprint(30, 64, C_BLACK, "Next page to load"); row_print(6, 1, - "The MISS key will load an unmapped page to TLB by"); + "The LOAD key will load an unmapped page to TLB by"); row_print(7, 1, "performing a TLB miss, which calls %%003 on fx9860g"); row_print(8, 1, @@ -341,12 +316,16 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) #endif #ifdef FX9860G + dprint(1, 30, C_BLACK, "Size of ROM text: %X (%d pages)", + rom_size, rom_pages); + if(next_miss != 0xffffffff) - row_print(5, 1, "Next load: %x", next_miss); + dprint(1, 36, C_BLACK, "Next load: %08x", next_miss); else - row_print(5, 1, "No page left to load!"); - row_print(6, 1, "MISS: TLB miss"); - row_print(7, 1, "TIMER: From timer"); + dprint(1, 36, C_BLACK, "No page left to load!"); + + dprint(1, 43, C_BLACK, "F5: Load a page by TLB miss"); + dprint(1, 49, C_BLACK, "F6: Do it from a timer callback"); #endif } @@ -356,11 +335,23 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) for(int i = 0; i < TLB_VIEW; i++) show_utlb(i+2, tlb_scroll+i); - if(tlb_scroll > 0) triangle_up(_(7,38)); - if(tlb_scroll < TLB_VIEW_MAX) triangle_down(_(49,192)); + #ifdef FX9860G + dhline(6, C_BLACK); + #endif + + #ifdef FXCG50 + dline(12, 34, 363, 34, C_BLACK); + #endif + + scrollbar_px( + /* view */ _(8,37), _(54,201), + /* range */ 0, TLB_VIEW_MAX + TLB_VIEW, + /* visible */ tlb_scroll, TLB_VIEW); } #ifdef FX9860G + dfont(old_font); + extern bopti_image_t img_opt_gint_tlb; dimage(0, 56, &img_opt_gint_tlb); #endif @@ -369,7 +360,7 @@ static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll) fkey_menu(1, "ROM"); fkey_menu(2, "INFO"); fkey_menu(3, "TLB"); - fkey_action(5, "MISS"); + fkey_action(5, "LOAD"); fkey_action(6, "TIMER"); #endif } @@ -408,13 +399,17 @@ void gintctl_gint_tlb(void) if(tab == 2 && key == KEY_UP) { - if(ev.shift) tlb_scroll = 0; - else if(tlb_scroll > 0) tlb_scroll--; + if(ev.shift || keydown(KEY_SHIFT)) + tlb_scroll = 0; + else if(tlb_scroll > 0) + tlb_scroll--; } if(tab == 2 && key == KEY_DOWN) { - if(ev.shift) tlb_scroll = TLB_VIEW_MAX; - else if (tlb_scroll < TLB_VIEW_MAX) tlb_scroll++; + if(ev.shift || keydown(KEY_SHIFT)) + tlb_scroll = TLB_VIEW_MAX; + else if (tlb_scroll < TLB_VIEW_MAX) + tlb_scroll++; } if(key == KEY_F5 && next_miss != 0xffffffff) diff --git a/src/gintctl.c b/src/gintctl.c index 393df3e..622589b 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -170,6 +170,7 @@ int main(GUNUSED int isappli, GUNUSED int optnum) dfont(&font_uf5x7); #endif + key_event_t ev; int key = 0; struct menu *menu = NULL; @@ -177,7 +178,9 @@ int main(GUNUSED int isappli, GUNUSED int optnum) { draw(menu); dupdate(); - key = getkey().key; + + ev = getkey(); + key = ev.key; if(key == KEY_F1) menu = NULL; @@ -195,7 +198,7 @@ int main(GUNUSED int isappli, GUNUSED int optnum) if(!menu) continue; if(key == KEY_UP || key == KEY_DOWN) - menu_move(menu, key, 0); + menu_move(menu, key, ev.shift || keydown(KEY_SHIFT),0); if(key == KEY_EXE) menu_exec(menu); } diff --git a/src/libs/openlibm.c b/src/libs/openlibm.c index bd92b14..8223e57 100644 --- a/src/libs/openlibm.c +++ b/src/libs/openlibm.c @@ -3,6 +3,7 @@ #include #include +#include #define __BSD_VISIBLE 1 #include diff --git a/src/libs/printf.c b/src/libs/printf.c index 7fb54dc..3cded69 100644 --- a/src/libs/printf.c +++ b/src/libs/printf.c @@ -12,7 +12,7 @@ #define NAN __builtin_nan("") #define INFINITY __builtin_inf() -#define SCROLL_HEIGHT _(8,12) +#define SCROLL_HEIGHT _(9,12) struct printf_test { char const *format; @@ -198,27 +198,26 @@ static void draw(struct printf_test const *tests, char answers[][16], dclear(C_WHITE); #ifdef FX9860G - extern font_t font_hexa; - font_t const *old_font = dfont(&font_hexa); + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); dprint( 1, 0, C_BLACK, "ID"); dprint(13, 0, C_BLACK, "Format"); dprint(43, 0, C_BLACK, "Output"); - dprint(91, 0, C_BLACK, "Valid"); + dprint(99, 0, C_BLACK, "%d/%d", total_passed, total); + dhline(6, C_BLACK); for(int i = 0; i < SCROLL_HEIGHT; i++) { struct printf_test const *t = &tests[offset+i]; - int y = (i+1) * 6; + int y = (i+1) * 6 + 2; dprint( 1, y, C_BLACK, "%d", offset+i+1); dprint(13, y, C_BLACK, "%s", t->format); dprint(43, y, C_BLACK, "%s", answers[offset+i][0] ? answers[offset+i] : ""); - dprint(91, y, C_BLACK, "%s", passed[offset+i]?"Ok":"Err"); + dprint(99, y, C_BLACK, "%s", passed[offset+i]?"Ok":"Err"); } - dfont(old_font); - row_print(8, 1, "Passed %d of %d.", total_passed, total); #endif #ifdef FXCG50 @@ -228,25 +227,28 @@ static void draw(struct printf_test const *tests, char answers[][16], row_print(1, 5, "Format"); row_print(1, 13, "Argument"); row_print(1, 29, "Answer"); + dline(12, 34, 355, 34, C_BLACK); for(int i = 0; i < SCROLL_HEIGHT; i++) { struct printf_test const *t = &tests[offset+i]; - row_print(i+2, 2, "%d", offset+i+1); - row_print(i+2, 5, "%s", t->format); - row_print(i+2, 13, "%s", t->argument_as_string); + int y = row_y(i+2) + 2; + dprint( 14, y, C_BLACK, "%d", offset+i+1); + dprint( 38, y, C_BLACK, "%s", t->format); + dprint(102, y, C_BLACK, "%s", t->argument_as_string); int fg = passed[offset+i] ? C_RGB(0,31,0) : C_RGB(31,0,0); - row_print_color(i+2, 29, fg, C_NONE, "%s", answers[offset+i][0] - ? answers[offset+i] : ""); + dprint_opt(230, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, "%s", + answers[offset+i][0] ? answers[offset+i] : ""); } row_print(14, 1, "Passed: %d/%d", total_passed, total); #endif - if(offset > 0) triangle_up(_(7,38)); - if(offset < total - SCROLL_HEIGHT) triangle_down(_(49,192)); - + scrollbar_px( + /* view */ _(8,37), _(60,201), + /* range */ 0, total, + /* visible */ offset, SCROLL_HEIGHT); dupdate(); } @@ -267,9 +269,16 @@ void gintctl_libs_printf(void) draw(tests, answers, passed, offset); key = (ev = getkey()).key; - if(key == KEY_UP && offset > 0) offset--; - if(key == KEY_UP && ev.shift) offset = 0; - if(key == KEY_DOWN && offset < total - SCROLL_HEIGHT) offset++; - if(key == KEY_DOWN && ev.shift) offset = total - SCROLL_HEIGHT; + int scroll_max = total - SCROLL_HEIGHT; + if(key == KEY_UP) + { + if(ev.shift || keydown(KEY_SHIFT)) offset = 0; + else if(offset > 0) offset--; + } + if(key == KEY_DOWN) + { + if(ev.shift || keydown(KEY_SHIFT)) offset = scroll_max; + else if(offset < scroll_max) offset++; + } } } diff --git a/src/mem/mem.c b/src/mem/mem.c index 5f3c5f6..e877909 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -53,7 +53,7 @@ int line(uint8_t *mem, char *header, char *bytes, char *ascii, int n) /* Read single bytes when possible, but longwords when in SPU memory */ for(int k = 0; k < n; k++) { - uint32_t addr = mem; + uint32_t addr = (uint32_t)mem; int c = 0x11; /* XRAM, YRAM, PRAM */ @@ -78,10 +78,23 @@ int line(uint8_t *mem, char *header, char *bytes, char *ascii, int n) return 0; } +void draw_input(int x, int y, char *text, int cursor_pos) +{ + int w, h; + int next = text[cursor_pos]; + text[cursor_pos] = 0; + dsize(text, NULL, &w, &h); + text[cursor_pos] = next; + + dtext(x, y, C_BLACK, text); + dline(x+w, y, x+w, y+h-1, C_BLACK); +} + /* gintctl_mem(): Memory browser */ void gintctl_mem(void) { uint32_t base = 0x88000000; + key_event_t ev; int key = 0; #ifdef FX9860G @@ -97,6 +110,16 @@ void gintctl_mem(void) int size = 8; int lines = _(9,14); + char input[9]; + int input_pos = -1; + int input_len = -1; + int input_keys[16] = { + KEY_0, KEY_1, KEY_2, KEY_3, + KEY_4, KEY_5, KEY_6, KEY_7, + KEY_8, KEY_9, KEY_XOT, KEY_LOG, + KEY_LN, KEY_SIN, KEY_COS, KEY_TAN, + }; + while(key != KEY_EXIT) { dclear(C_WHITE); @@ -129,36 +152,111 @@ void gintctl_mem(void) } #ifdef FX9860G - extern bopti_image_t img_opt_mem; - dsubimage(0, 56, &img_opt_mem, 0, 0, 128, 8, DIMAGE_NONE); + if(input_pos < 0) + { + extern bopti_image_t img_opt_mem; + dsubimage(0, 56, &img_opt_mem, 0, 0, 128, 8, + DIMAGE_NONE); + if(view_ascii) dsubimage(23, 56, &img_opt_mem, 23, 9, + 21, 8, DIMAGE_NONE); + } + else + { + extern font_t font_mini; + font_t const *old_font = dfont(&font_mini); - if(view_ascii) dsubimage(23, 56, &img_opt_mem, 23, 9, 21, 8, - DIMAGE_NONE); + dtext(1, 57, C_BLACK, "Go to:"); + draw_input(24, 57, input, input_pos); + + dfont(old_font); + } #endif #ifdef FXCG50 row_title("Memory browser"); - fkey_button(1, "JUMP"); - fkey_action(3, "ROM"); - fkey_action(4, "RAM"); - fkey_action(5, "ILRAM"); - fkey_action(6, "ADDIN"); + if(input_pos < 0) + { + fkey_button(1, "JUMP"); + fkey_action(3, "ROM"); + fkey_action(4, "RAM"); + fkey_action(5, "ILRAM"); + fkey_action(6, "ADDIN"); + } + else + { + dtext(4, 210, C_BLACK, "Go to:"); + draw_input(52, 210, input, input_pos); + } #endif dupdate(); - key = getkey().key; + ev = getkey(); + key = ev.key; - if(key == KEY_UP) base -= size * lines; - if(key == KEY_DOWN) base += size * lines; + int move_speed = 1; + if(ev.shift || keydown(KEY_SHIFT)) move_speed = 8; + + if(key == KEY_UP) base -= move_speed * size * lines; + if(key == KEY_DOWN) base += move_speed * size * lines; + + if(key == KEY_F1 && input_pos < 0) + { + input[0] = 0; + input_pos = 0; + input_len = 0; + } + if(key == KEY_EXIT && input_pos >= 0) + { + input_pos = -1; + input_len = -1; + /* Don't quit the memory viewer */ + key = 0; + } + if(key == KEY_EXE && input_pos >= 0) + { + /* Parse string into hexa */ + uint32_t target = 0; + for(int k = 0; k < input_len; k++) + { + target <<= 4; + if(input[k] <= '9') target += (input[k] - '0'); + else target += (input[k] - 'A' + 10); + + base = target & ~7; + } + + input_pos = -1; + input_len = -1; + } + + for(int i = 0; i < 16; i++) + if(key == input_keys[i] && input_pos >= 0 && input_len < 8) + { + /* Insert at input_pos, shift everything else right */ + for(int k = 8; k >= input_pos; k--) + input[k + 1] = input[k]; + input[input_pos++] = i + '0' + 7 * (i > 9); + input_len++; + } + if(key == KEY_DEL && input_pos > 0) + { + /* Shift everything after input_pos left one place */ + for(int k = input_pos - 1; k < 8; k++) + input[k] = input[k + 1]; + input_pos--; + input_len--; + } + if(key == KEY_LEFT && input_pos > 0) input_pos--; + if(key == KEY_RIGHT && input_pos < input_len) input_pos++; #ifdef FX9860G - if(key == KEY_F2) view_ascii = !view_ascii; + if(key == KEY_F2 && input_pos < 0) view_ascii = !view_ascii; #endif - if(key == KEY_F3) base = 0x80000000; - if(key == KEY_F4) base = 0x88000000; - if(key == KEY_F5) base = 0xe5200000; - if(key == KEY_F6) base = 0x00300000; + if(key == KEY_F3 && input_pos < 0) base = 0x80000000; + if(key == KEY_F4 && input_pos < 0) base = 0x88000000; + if(key == KEY_F5 && input_pos < 0) base = 0xe5200000; + if(key == KEY_F6 && input_pos < 0) base = 0x00300000; } #ifdef FX9860G diff --git a/src/menu.c b/src/menu.c index 8648f09..142694e 100644 --- a/src/menu.c +++ b/src/menu.c @@ -25,12 +25,24 @@ void menu_init(struct menu *menu, int top, int bottom) } /* menu_move(): Move the cursor in a menu */ -void menu_move(struct menu *menu, int key, int wrap) +void menu_move(struct menu *menu, int key, int quick, int wrap) { int visible = menu->bottom - menu->top; int max_offset = max(menu->len - visible, 0); - if(key == KEY_UP && menu->pos > 0) + /* Quick moves */ + if(key == KEY_UP && quick) + { + menu->pos = 0; + menu->offset = 0; + } + else if(key == KEY_DOWN && quick) + { + menu->pos = menu->len - 1; + menu->offset = max_offset; + } + /* Normal move up and wrapping move up */ + else if(key == KEY_UP && menu->pos > 0) { menu->pos--; menu->offset = min(menu->offset, menu->pos); @@ -40,8 +52,8 @@ void menu_move(struct menu *menu, int key, int wrap) menu->pos = menu->len - 1; menu->offset = max_offset; } - - if(key == KEY_DOWN && menu->pos + 1 < menu->len) + /* Normal move down and wrapping move down */ + else if(key == KEY_DOWN && menu->pos + 1 < menu->len) { menu->pos++; if(menu->pos > menu->offset + visible - 1 diff --git a/src/util.c b/src/util.c index 40e5248..2ac8308 100644 --- a/src/util.c +++ b/src/util.c @@ -134,6 +134,29 @@ int row_y(int y) return ROW_Y + ROW_H * (y - 1) + ROW_YPAD; } +//--- +// General rendering +//--- + +/* scrollbar_px(): Pixel-based scrollbar */ +void scrollbar_px(int view_top, int view_bottom, int range_min, int range_max, + int range_pos, int range_view) +{ + int view_x = _(127, 391); + int view_width = _(1, 2); + int view_height = view_bottom - view_top; + + /* Bring virtual range to 0..range_max */ + range_max -= range_min; + range_pos -= range_min; + + int bar_pos = (range_pos * view_height + range_max/2) / range_max; + int bar_height = (range_view * view_height + range_max/2) / range_max; + + drect(view_x, view_top + bar_pos, view_x + view_width - 1, + view_top + bar_pos + bar_height, C_BLACK); +} + //--- // Other drawing utilities //---