From 840bcbda4fa510554ea64cc943d33bd96e28b556 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Fri, 31 Jul 2026 04:04:37 +0200 Subject: Adds curses UI (WIP) --- ui/curses/ui.c | 440 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 ui/curses/ui.c (limited to 'ui/curses/ui.c') diff --git a/ui/curses/ui.c b/ui/curses/ui.c new file mode 100644 index 0000000..f1a3459 --- /dev/null +++ b/ui/curses/ui.c @@ -0,0 +1,440 @@ +// file : ui/curses/ui.c +// project : Salis-VM +// author : Paul Oliver + +// index: +// [section] includes +// [section] macros/enums +// [section] gfx globals +// [section] tui globals +// [section] gfx functions +// [section] tui functions +// [section] main + +// ---------------------------------------------------------------------------- +// [section] includes +// ---------------------------------------------------------------------------- +#include +#define NCURSES_WIDECHAR 1 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arch.h" +#include "arch_spec.h" +#include "compress.h" +#include "logger.h" +#include "salis.h" + +// ---------------------------------------------------------------------------- +// [section] macros/enums +// ---------------------------------------------------------------------------- +#define LOG_LINE_COUNT 0x400 + +#define NCURSES_CTRL(x) (x & 0x1f) + +#define PANE_WIDTH 27 +#define PANE_WIDTH_AND_MARGIN (PANE_WIDTH + 2) +#define PROC_FIELD_WIDTH 21 +#define PROC_PAGE_LINES 12 + +#define FPS_MIN 10 +#define FPS_MAX 20 + +enum UIPage { + PAGE_CORE, + PAGE_PROCESS, + PAGE_WORLD, + PAGE_IPC, + PAGE_LOG, + PAGE_COUNT, +}; + +enum UIColorPair { + PAIR_NORMAL, + PAIR_HEADER, + PAIR_LIVE_PROC, + PAIR_SELECTED_PROC, + PAIR_FREE_CELL, + PAIR_ALLOC_CELL, + PAIR_MEM_BLOCK_START, + PAIR_SELECTED_MB1, + PAIR_SELECTED_MB2, + PAIR_SELECTED_IP, + PAIR_SELECTED_SP, + PAIR_LOG_TRACE, + PAIR_LOG_INFO, + PAIR_LOG_ATTENTION, +}; + +enum UILogLevel { + TRACE, + INFO, + ATTENTION, +}; + +// ---------------------------------------------------------------------------- +// [section] gfx globals +// ---------------------------------------------------------------------------- +static uint64_t g_gfx_vsiz; +static uint64_t *g_gfx_inst; +static uint64_t *g_gfx_mall; +static uint64_t *g_gfx_mbst; +static uint64_t *g_gfx_mb0s; +static uint64_t *g_gfx_mb1s; +static uint64_t *g_gfx_ipas; +static uint64_t *g_gfx_spas; + +static const wchar_t *g_zoomed_symbols = ( + L"⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" + L"⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿" + L"⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" + L"⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" +); + +// ---------------------------------------------------------------------------- +// [section] tui globals +// ---------------------------------------------------------------------------- +static bool g_exit; +static bool g_running; +static unsigned g_core; +static unsigned g_page; +static char *g_line_buff; +static bool g_proc_genes; +static uint64_t g_proc_scroll; +static uint64_t g_proc_field_scroll; +static uint64_t g_proc_gene_scroll; +static uint64_t g_proc_selected; +static uint64_t g_wrld_pos; +static uint64_t g_wrld_zoom; +static bool g_wcursor_mode; +static int g_wcursor_x; +static int g_wcursor_y; +static uint64_t g_wcursor_pointed; +static uint64_t g_log_cnt; +static unsigned g_log_ptr; +static unsigned g_log_scroll; +static enum UILogLevel g_log_levels[LOG_LINE_COUNT]; +static char g_logs[LOG_LINE_COUNT][LOG_BUFFER_SIZE]; +static uint64_t g_vlin; +static uint64_t g_vsiz; +static uint64_t g_vlin_rng; +static uint64_t g_vsiz_rng; +static uint64_t g_ivpt_scroll; +static uint64_t g_step_block; +static float g_steps_per_sec; + +// ---------------------------------------------------------------------------- +// [section] gfx functions +// ---------------------------------------------------------------------------- +static void gfx_init(uint64_t vsiz) { + assert(vsiz); + + g_gfx_vsiz = vsiz; + g_gfx_inst = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mall = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mbst = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mb0s = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mb1s = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_ipas = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_spas = calloc(g_gfx_vsiz, sizeof(uint64_t)); + + assert(g_gfx_inst); + assert(g_gfx_mall); + assert(g_gfx_mbst); + assert(g_gfx_mb0s); + assert(g_gfx_mb1s); + assert(g_gfx_ipas); + assert(g_gfx_spas); +} + +static void gfx_free(void) { + if (g_gfx_vsiz == 0) { + return; + } + + assert(g_gfx_inst); + assert(g_gfx_mall); + assert(g_gfx_mbst); + assert(g_gfx_mb0s); + assert(g_gfx_mb1s); + assert(g_gfx_ipas); + assert(g_gfx_spas); + + g_gfx_vsiz = 0; + + free(g_gfx_inst); + free(g_gfx_mall); + free(g_gfx_mbst); + free(g_gfx_mb0s); + free(g_gfx_mb1s); + free(g_gfx_ipas); + free(g_gfx_spas); + + g_gfx_inst = NULL; + g_gfx_mall = NULL; + g_gfx_mbst = NULL; + g_gfx_mb0s = NULL; + g_gfx_mb1s = NULL; + g_gfx_ipas = NULL; + g_gfx_spas = NULL; +} + +static void gfx_resize(uint64_t vsiz) { + assert(vsiz); + gfx_free(); + gfx_init(vsiz); +} + +static void gfx_render_inst(const struct Core *core, uint64_t pos, uint64_t zoom) { + assert(core); + + for (uint64_t i = 0; i < g_gfx_vsiz; i++) { + g_gfx_inst[i] = 0; + g_gfx_mall[i] = 0; + + for (uint64_t j = 0; j < zoom; j++) { + uint64_t addr = pos + (i * zoom) + j; + g_gfx_inst[i] += mvec_get_byte(core, addr); + g_gfx_mall[i] += mvec_is_alloc(core, addr) ? 1 : 0; + } + } +} + +static void gfx_clear_array(uint64_t *arry) { + assert(arry); + memset(arry, 0, g_gfx_vsiz * sizeof(uint64_t)); +} + +#if defined(ARCH_SPEC_MVEC_LOOP) +static void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { + assert(arry); + uint64_t beg_mod = pos % MVEC_SIZE; + uint64_t end_mod = beg_mod + (g_gfx_vsiz * zoom); + uint64_t pix_mod = pixa % MVEC_SIZE; + +#if !defined(NDEBUG) + uint64_t inc_cnt = 0; +#endif + + while (pix_mod < end_mod) { + if (pix_mod >= beg_mod && pix_mod < end_mod) { + uint64_t pixi = (pix_mod - beg_mod) / zoom; + assert(pixi < g_gfx_vsiz); + arry[pixi]++; + +#if !defined(NDEBUG) + inc_cnt++; +#endif + } + + pix_mod += MVEC_SIZE; + } + +#if !defined(NDEBUG) + if (zoom != 1) { + assert(inc_cnt <= 2); + } +#endif +} +#else +static void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { + assert(arry); + uint64_t end = pos + (g_gfx_vsiz * zoom); + + if (pixa < pos || pixa >= end) { + return; + } + + uint64_t pixi = (pixa - pos) / zoom; + assert(pixi < g_gfx_vsiz); + arry[pixi]++; +} +#endif + +static void gfx_render_mbst(const struct Core *core, uint64_t pos, uint64_t zoom) { + assert(core); + gfx_clear_array(g_gfx_mbst); + + for (uint64_t pix = core->pfst; pix <= core->plst; pix++) { + uint64_t mb0a = arch_proc_get_mb0_addr(core, pix); + uint64_t mb1a = arch_proc_get_mb1_addr(core, pix); + gfx_accumulate_pixel(pos, zoom, mb0a, g_gfx_mbst); + + if (arch_proc_get_mb1_size(core, pix)) { + gfx_accumulate_pixel(pos, zoom, mb1a, g_gfx_mbst); + } + } +} + +static void gfx_render_mb0s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + gfx_clear_array(g_gfx_mb0s); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t mb0a = arch_proc_get_mb0_addr(core, psel); + uint64_t mb0s = arch_proc_get_mb0_size(core, psel); + + for (uint64_t i = 0; i < mb0s; i++) { + gfx_accumulate_pixel(pos, zoom, mb0a + i, g_gfx_mb0s); + } +} + +static void gfx_render_mb1s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + gfx_clear_array(g_gfx_mb1s); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t mb1a = arch_proc_get_mb1_addr(core, psel); + uint64_t mb1s = arch_proc_get_mb1_size(core, psel); + + for (uint64_t i = 0; i < mb1s; i++) { + gfx_accumulate_pixel(pos, zoom, mb1a + i, g_gfx_mb1s); + } +} + +static void gfx_render_ipas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + gfx_clear_array(g_gfx_ipas); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + gfx_accumulate_pixel(pos, zoom, arch_proc_get_ip_addr(core, psel), g_gfx_ipas); +} + +static void gfx_render_spas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + gfx_clear_array(g_gfx_spas); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + gfx_accumulate_pixel(pos, zoom, arch_proc_get_sp_addr(core, psel), g_gfx_spas); +} + +static void gfx_render(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + gfx_render_inst(core, pos, zoom); + gfx_render_mbst(core, pos, zoom); + gfx_render_mb0s(core, pos, zoom, psel); + gfx_render_mb1s(core, pos, zoom, psel); + gfx_render_ipas(core, pos, zoom, psel); + gfx_render_spas(core, pos, zoom, psel); +} + +// ---------------------------------------------------------------------------- +// [section] tui functions +// ---------------------------------------------------------------------------- +static void tui_line_buff_free(void) { + if (g_line_buff) { + free(g_line_buff); + } + + g_line_buff = NULL; +} + +static void tui_line_buff_resize(void) { + tui_line_buff_free(); + g_line_buff = calloc(COLS + 1, sizeof(char)); +} + +static void tui_line(bool clear, int line, int color, int attr, const char *format, ...) { + assert(line >= 0); + assert(format); + + if (line >= LINES) { + return; + } + + if (clear) { + move(line, 0); + clrtoeol(); + } + + va_list args; + va_start(args, format); + attron(COLOR_PAIR(color) | attr); + vsnprintf(g_line_buff, COLS, format, args); + mvprintw(line, 1, "%s", g_line_buff); + attroff(COLOR_PAIR(color) | attr); + va_end(args); +} + +static void tui_clear_line(int l) { + tui_line(true, l, PAIR_NORMAL, A_NORMAL, ""); +} + +static void tui_field(int line, int col, int color, int attr, const char *format, ...) { + assert(line >= 0); + assert(col >= 0); + assert(format); + + if (line >= LINES || col >= COLS) { + return; + } + + va_list args; + va_start(args, format); + attron(COLOR_PAIR(color) | attr); + vsnprintf(g_line_buff, COLS - col, format, args); + mvprintw(line, col, "%s", g_line_buff); + attroff(COLOR_PAIR(color) | attr); + va_end(args); +} + +static void tui_str_field(int l, const char *label, const char *value) { + assert(label); + assert(strlen(label) <= 4); + assert(value); + tui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %18s", label, value); +} + +static void tui_ulx_field(int l, const char *label, uint64_t value) { + assert(label); + assert(strlen(label) <= 4); + tui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %#18lx", label, value); +} + +static void tui_uld_field(int l, const char *label, uint64_t value) { + assert(label); + assert(strlen(label) <= 4); + tui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %#18ld", label, value); +} + +static void tui_print_core(int l) { + tui_line(false, ++l, PAIR_HEADER, A_BOLD, "CORE [%d]", g_core); + tui_ulx_field(++l, "cycl", g_cores[g_core].cycl); + tui_ulx_field(++l, "mall", g_cores[g_core].mall); + tui_ulx_field(++l, "mut0", g_cores[g_core].muta[0]); + tui_ulx_field(++l, "mut1", g_cores[g_core].muta[1]); + tui_ulx_field(++l, "mut2", g_cores[g_core].muta[2]); + tui_ulx_field(++l, "mut3", g_cores[g_core].muta[3]); + tui_ulx_field(++l, "pnum", g_cores[g_core].pnum); + tui_ulx_field(++l, "pcap", g_cores[g_core].pcap); + tui_ulx_field(++l, "pfst", g_cores[g_core].pfst); + tui_ulx_field(++l, "plst", g_cores[g_core].plst); + tui_ulx_field(++l, "pcur", g_cores[g_core].pcur); + tui_ulx_field(++l, "psli", g_cores[g_core].psli); + tui_ulx_field(++l, "ivpt", g_cores[g_core].ivpt); +} + +// ---------------------------------------------------------------------------- +// [section] main +// ---------------------------------------------------------------------------- +int main(void) { + return 0; +} -- cgit v1.3.1