summaryrefslogtreecommitdiff
path: root/src/graphics.c
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2024-02-29 02:39:32 +0100
committerPaul Oliver <contact@pauloliver.dev>2024-04-16 02:28:53 +0200
commit5daf52d92c472ebf2a675cb2d27ca3e3fbdf0034 (patch)
tree36f58b9fd17f38724ff5a5263ac9a326a857f76e /src/graphics.c
Initial
Diffstat (limited to 'src/graphics.c')
-rw-r--r--src/graphics.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/graphics.c b/src/graphics.c
new file mode 100644
index 0000000..8114f30
--- /dev/null
+++ b/src/graphics.c
@@ -0,0 +1,223 @@
+// Project: Salis
+// Author: Paul Oliver
+// Email: contact@pauloliver.dev
+
+/*
+ * This module renders the contents of the VM memory buffer into a 7 channel
+ * image. It supports zooming in and out, condensing the state of several
+ * bytes of memory into single pixels, when zoomed out. When zoomed in, each
+ * pixel represents a single byte in memory.
+ */
+
+u64 g_gfx_vsiz; // zoom level
+
+u64 *g_gfx_inst; // instruction channel
+u64 *g_gfx_mall; // allocated state channel
+u64 *g_gfx_mbst; // memory block start channel
+u64 *g_gfx_mb0s; // selected organism's memory block #1 channel
+u64 *g_gfx_mb1s; // selected organism's memory block #2 channel
+u64 *g_gfx_ipas; // selected organism's IP channel
+u64 *g_gfx_spas; // selected organism's SP channel
+
+void gfx_init(u64 vsiz) {
+ assert(vsiz);
+
+ g_gfx_vsiz = vsiz;
+
+ g_gfx_inst = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_mall = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_mbst = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_mb0s = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_mb1s = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_ipas = calloc(g_gfx_vsiz, sizeof(u64));
+ g_gfx_spas = calloc(g_gfx_vsiz, sizeof(u64));
+
+ 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);
+}
+
+void gfx_free() {
+ 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;
+}
+
+void gfx_resize(u64 vsiz) {
+ assert(vsiz);
+
+ gfx_free();
+ gfx_init(vsiz);
+}
+
+void gfx_render_inst(const Core *core, u64 pos, u64 zoom) {
+ assert(core);
+
+ for (u64 i = 0; i < g_gfx_vsiz; ++i) {
+ g_gfx_inst[i] = 0;
+ g_gfx_mall[i] = 0;
+
+ for (u64 j = 0; j < zoom; ++j) {
+ u64 addr = pos + (i * zoom) + j;
+ u8 byte = mvec_get_byte(core, addr);
+
+ g_gfx_inst[i] += byte;
+ g_gfx_mall[i] += (byte & MALL_FLAG) ? 1 : 0;
+ }
+ }
+}
+
+void gfx_clear_array(u64 *arry) {
+ assert(arry);
+ memset(arry, 0, g_gfx_vsiz * sizeof(u64));
+}
+
+void gfx_accumulate_pixel(u64 pos, u64 zoom, u64 pixa, u64 *arry) {
+ assert(arry);
+
+ u64 beg_mod = pos % MVEC_SIZE;
+ u64 end_mod = beg_mod + (g_gfx_vsiz * zoom);
+ u64 pix_mod = pixa % MVEC_SIZE;
+
+#ifndef NDEBUG
+ u64 inc_cnt = 0;
+#endif
+
+ while (pix_mod < end_mod) {
+ if (pix_mod >= beg_mod && pix_mod < end_mod) {
+ u64 pixi = (pix_mod - beg_mod) / zoom;
+ assert(pixi < g_gfx_vsiz);
+ arry[pixi]++;
+
+#ifndef NDEBUG
+ inc_cnt++;
+#endif
+ }
+
+ pix_mod += MVEC_SIZE;
+ }
+
+
+#ifndef NDEBUG
+ if (zoom != 1) {
+ assert(inc_cnt <= 2);
+ }
+#endif
+}
+
+void gfx_render_mbst(const Core *core, u64 pos, u64 zoom) {
+ assert(core);
+
+ gfx_clear_array(g_gfx_mbst);
+
+ for (u64 pix = core->pfst; pix <= core->plst; ++pix) {
+ u64 mb0a = arch_proc_mb0_addr(core, pix);
+ u64 mb1a = arch_proc_mb1_addr(core, pix);
+
+ gfx_accumulate_pixel(pos, zoom, mb0a, g_gfx_mbst);
+ gfx_accumulate_pixel(pos, zoom, mb1a, g_gfx_mbst);
+ }
+}
+
+void gfx_render_mb0s(const Core *core, u64 pos, u64 zoom, u64 psel) {
+ assert(core);
+
+ gfx_clear_array(g_gfx_mb0s);
+
+ if (psel < core->pfst || psel > core->plst) {
+ return;
+ }
+
+ u64 mb0a = arch_proc_mb0_addr(core, psel);
+ u64 mb0s = arch_proc_mb0_size(core, psel);
+
+ for (u64 i = 0; i < mb0s; ++i) {
+ gfx_accumulate_pixel(pos, zoom, mb0a + i, g_gfx_mb0s);
+ }
+}
+
+void gfx_render_mb1s(const Core *core, u64 pos, u64 zoom, u64 psel) {
+ assert(core);
+
+ gfx_clear_array(g_gfx_mb1s);
+
+ if (psel < core->pfst || psel > core->plst) {
+ return;
+ }
+
+ u64 mb1a = arch_proc_mb1_addr(core, psel);
+ u64 mb1s = arch_proc_mb1_size(core, psel);
+
+ for (u64 i = 0; i < mb1s; ++i) {
+ gfx_accumulate_pixel(pos, zoom, mb1a + i, g_gfx_mb1s);
+ }
+}
+
+void gfx_render_ipas(const Core *core, u64 pos, u64 zoom, u64 psel) {
+ assert(core);
+
+ gfx_clear_array(g_gfx_ipas);
+
+ if (psel < core->pfst || psel > core->plst) {
+ return;
+ }
+
+ u64 ipa = arch_proc_ip_addr(core, psel);
+
+ gfx_accumulate_pixel(pos, zoom, ipa, g_gfx_ipas);
+}
+
+void gfx_render_spas(const Core *core, u64 pos, u64 zoom, u64 psel) {
+ assert(core);
+
+ gfx_clear_array(g_gfx_spas);
+
+ if (psel < core->pfst || psel > core->plst) {
+ return;
+ }
+
+ u64 spa = arch_proc_sp_addr(core, psel);
+
+ gfx_accumulate_pixel(pos, zoom, spa, g_gfx_spas);
+}
+
+void gfx_render(const Core *core, u64 pos, u64 zoom, u64 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);
+}