summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-07-31 04:04:37 +0200
committerPaul Oliver <contact@pauloliver.dev>2026-08-01 04:25:46 +0200
commit840bcbda4fa510554ea64cc943d33bd96e28b556 (patch)
treebb01d90b004b8a9550d3c3eaa57ac8c4cc727e35
parent8a4563d6d0c9e81fdaa42f6f760cae2b49cad431 (diff)
Adds curses UI (WIP)HEADmaster
-rw-r--r--arch/null/arch_inst.c2
-rw-r--r--arch/null/arch_spec.h1
-rw-r--r--core/logger.c69
-rw-r--r--core/logger.h16
-rw-r--r--core/salis.c12
-rwxr-xr-xsalis.py6
-rw-r--r--ui/curses/links.json1
-rw-r--r--ui/curses/ui.c440
8 files changed, 518 insertions, 29 deletions
diff --git a/arch/null/arch_inst.c b/arch/null/arch_inst.c
index 43f5d0c..140fa7c 100644
--- a/arch/null/arch_inst.c
+++ b/arch/null/arch_inst.c
@@ -34,7 +34,7 @@
// ----------------------------------------------------------------------------
// [section] globals
// ----------------------------------------------------------------------------
-wchar_t *g_arch_inst_symbols = (
+static const wchar_t *g_arch_inst_symbols = (
L"⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟"
L"⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿"
L"⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟"
diff --git a/arch/null/arch_spec.h b/arch/null/arch_spec.h
index eeb6d44..41f31e1 100644
--- a/arch/null/arch_spec.h
+++ b/arch/null/arch_spec.h
@@ -4,7 +4,6 @@
#pragma once
-//#define ARCH_SPEC_MVEC_LOOP
#define ARCH_SPEC_CORE_FIELDS
#define ARCH_SPEC_PROC_FIELDS \
diff --git a/core/logger.c b/core/logger.c
index 47182ce..015b84f 100644
--- a/core/logger.c
+++ b/core/logger.c
@@ -5,6 +5,7 @@
// index:
// [section] includes
// [section] macros
+// [section] extern globals
// [section] definitions
// ----------------------------------------------------------------------------
@@ -21,8 +22,6 @@
// ----------------------------------------------------------------------------
// [section] macros
// ----------------------------------------------------------------------------
-#define LOG_BUFFER_SIZE 0x800
-
#define COLOR_CLEAR "\033[0m"
#define COLOR_TRACE "\033[1;34m"
#define COLOR_INFO "\033[1;32m"
@@ -33,13 +32,19 @@
#define LEVEL_ATTENTION "ATTENTION"
// ----------------------------------------------------------------------------
+// [section] extern globals
+// ----------------------------------------------------------------------------
+void (*log_trace)(const char *format, ...) = log_trace_to_stdout;
+void (*log_info)(const char *format, ...) = log_info_to_stdout;
+void (*log_attention)(const char *format, ...) = log_attention_to_stdout;
+
+// ----------------------------------------------------------------------------
// [section] definitions
// ----------------------------------------------------------------------------
-static void log_default(const char *color_code, const char *level, const char *format, va_list args) {
+static void log_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *color_code, const char *level, const char *format, va_list args) {
assert(level);
assert(format);
- char log_buffer[LOG_BUFFER_SIZE];
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
int msec = (int)(ts.tv_nsec / 1000000l);
@@ -47,7 +52,7 @@ static void log_default(const char *color_code, const char *level, const char *f
pid_t pid = getpid();
int rem = snprintf(
- log_buffer,
+ buffer,
LOG_BUFFER_SIZE,
"\r%s%d-%02d-%02d %02d:%02d:%02d.%03d %07d [%s]%s ",
color_code ? color_code : "",
@@ -63,36 +68,70 @@ static void log_default(const char *color_code, const char *level, const char *f
color_code ? COLOR_CLEAR : ""
);
- vsnprintf(log_buffer + rem, LOG_BUFFER_SIZE - rem, format, args);
- printf("%s\n", log_buffer);
- fflush(stdout);
+ vsnprintf(buffer + rem, LOG_BUFFER_SIZE - rem, format, args);
}
-void log_trace(const char *format, ...) {
+void log_trace_to_stdout(const char *format, ...) {
assert(format);
+ (void)format;
#if defined(LOG_TRACE)
va_list args;
va_start(args, format);
- log_default(COLOR_TRACE, LEVEL_TRACE, format, args);
+ char buffer[LOG_BUFFER_SIZE];
+ log_to_buffer(buffer, COLOR_TRACE, LEVEL_TRACE, format, args);
+ printf("%s\n", buffer);
+ fflush(stdout);
+ va_end(args);
+#endif
+}
+
+void log_info_to_stdout(const char *format, ...) {
+ assert(format);
+ va_list args;
+ va_start(args, format);
+ char buffer[LOG_BUFFER_SIZE];
+ log_to_buffer(buffer, COLOR_INFO, LEVEL_INFO, format, args);
+ printf("%s\n", buffer);
+ fflush(stdout);
+ va_end(args);
+}
+
+void log_attention_to_stdout(const char *format, ...) {
+ assert(format);
+ va_list args;
+ va_start(args, format);
+ char buffer[LOG_BUFFER_SIZE];
+ log_to_buffer(buffer, COLOR_ATTENTION, LEVEL_ATTENTION, format, args);
+ printf("%s\n", buffer);
+ fflush(stdout);
va_end(args);
-#else
+}
+
+void log_trace_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...) {
+ assert(format);
(void)format;
+
+#if defined(LOG_TRACE)
+ va_list args;
+ va_start(args, format);
+ log_to_buffer(buffer, NULL, LEVEL_TRACE, format, args);
+ va_end(args);
#endif
}
-void log_info(const char *format, ...) {
+void log_info_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...) {
assert(format);
va_list args;
va_start(args, format);
- log_default(COLOR_INFO, LEVEL_INFO, format, args);
+ log_to_buffer(buffer, NULL, LEVEL_INFO, format, args);
va_end(args);
}
-void log_attention(const char *format, ...) {
+void log_attention_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...) {
assert(format);
va_list args;
va_start(args, format);
- log_default(COLOR_ATTENTION, LEVEL_ATTENTION, format, args);
+ log_to_buffer(buffer, NULL, LEVEL_ATTENTION, format, args);
va_end(args);
}
diff --git a/core/logger.h b/core/logger.h
index e0da38b..8774164 100644
--- a/core/logger.h
+++ b/core/logger.h
@@ -4,6 +4,16 @@
#pragma once
-void log_trace(const char *format, ...);
-void log_info(const char *format, ...);
-void log_attention(const char *format, ...);
+#define LOG_BUFFER_SIZE 0x800
+
+extern void (*log_trace)(const char *format, ...);
+extern void (*log_info)(const char *format, ...);
+extern void (*log_attention)(const char *format, ...);
+
+void log_trace_to_stdout(const char *format, ...);
+void log_info_to_stdout(const char *format, ...);
+void log_attention_to_stdout(const char *format, ...);
+
+void log_trace_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...);
+void log_info_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...);
+void log_attention_to_buffer(char buffer[LOG_BUFFER_SIZE], const char *format, ...);
diff --git a/core/salis.c b/core/salis.c
index 6cc0725..295467b 100644
--- a/core/salis.c
+++ b/core/salis.c
@@ -49,14 +49,14 @@
// ----------------------------------------------------------------------------
struct Core g_cores[CORES];
uint64_t g_step;
-uint64_t g_sync;
-const struct Proc g_null_proc;
+static uint64_t g_sync;
+static const struct Proc g_null_proc;
-char g_asav_pbuf[AUTOSAVE_NAME_LEN];
-char g_evas_pbuf[EVA_SAVE_NAME_LEN];
+static char g_asav_pbuf[AUTOSAVE_NAME_LEN];
+static char g_evas_pbuf[EVA_SAVE_NAME_LEN];
-atomic_bool g_running;
-thrd_t g_thrd;
+static atomic_bool g_running;
+static thrd_t g_thrd;
// ----------------------------------------------------------------------------
// [section] memory vector functions
diff --git a/salis.py b/salis.py
index 0497ee4..9e81480 100755
--- a/salis.py
+++ b/salis.py
@@ -175,9 +175,9 @@ logger_dll = ctypes.CDLL(logger_shared.binfile)
# Pull in logging functions from C
# This way there's just a single logging system to care about
log = SimpleNamespace()
-log.trace = lambda msg: logger_dll.log_trace(msg.encode())
-log.info = lambda msg: logger_dll.log_info(msg.encode())
-log.attention = lambda msg: logger_dll.log_attention(msg.encode())
+log.trace = lambda msg: logger_dll.log_trace_to_stdout(msg.encode())
+log.info = lambda msg: logger_dll.log_info_to_stdout(msg.encode())
+log.attention = lambda msg: logger_dll.log_attention_to_stdout(msg.encode())
logger_shared.log(log)
# ------------------------------------------------------------------------------
diff --git a/ui/curses/links.json b/ui/curses/links.json
new file mode 100644
index 0000000..0cfb567
--- /dev/null
+++ b/ui/curses/links.json
@@ -0,0 +1 @@
+["-lncurses"]
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 <contact@pauloliver.dev>
+
+// index:
+// [section] includes
+// [section] macros/enums
+// [section] gfx globals
+// [section] tui globals
+// [section] gfx functions
+// [section] tui functions
+// [section] main
+
+// ----------------------------------------------------------------------------
+// [section] includes
+// ----------------------------------------------------------------------------
+#include <assert.h>
+#define NCURSES_WIDECHAR 1
+#include <curses.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+#include <zlib.h>
+
+#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;
+}