summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authordweller <dweller@cabin.digital>2025-04-04 00:00:52 +0300
committerdweller <dweller@cabin.digital>2025-04-04 00:00:52 +0300
commit0533b005901b976e3e6d11d7ec5078118bbe5a2f (patch)
treea74846c72ca4f30bff5a3bae03bfffcac7bbac29 /sources
parent9c2842629f2e5f17c6949b5ff37c972f7dd62d4a (diff)
fix DRW instruction, add arena to iui so I don't need to manage label buffersHEADmaster
Diffstat (limited to 'sources')
-rw-r--r--sources/iui.c300
-rw-r--r--sources/main.c306
-rw-r--r--sources/mem.c139
-rw-r--r--sources/meta/exec.c7
-rw-r--r--sources/plat.c24
-rw-r--r--sources/x11.c8
6 files changed, 543 insertions, 241 deletions
diff --git a/sources/iui.c b/sources/iui.c
new file mode 100644
index 0000000..6f82ad1
--- /dev/null
+++ b/sources/iui.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2025 dwlr <dweller@cabin.digital>
+ *
+ * BSD 3-Clause License (BSD-3-Clause)
+ * See LICENSE for details
+ */
+
+
+#define IUI_TXT_CENTER bit(0)
+#define IUI_CLIP_CLEAR bit(0)
+
+typedef struct
+{
+ enum
+ {
+ IUI_ILL,
+ IUI_BOX,
+ IUI_FILL,
+ IUI_LINE,
+ IUI_TEXT,
+ IUI_CLIP,
+
+ } type;
+
+ u32 color;
+ u16 x, y, w, h;
+ u16 size;
+ u16 flags;
+ char* text;
+
+} iui_cmd;
+
+#define IUI_CMDBUF_LEN 512
+typedef struct
+{
+ arena* ar;
+ void* usr;
+
+ usize hot;
+ usize active;
+ usize kbdfocus;
+
+ /* mouse */
+ u16 x;
+ u16 y;
+
+ u8 pbtns;
+ u8 btns;
+
+ /* TODO: event pump */
+
+ usize ncmds;
+ iui_cmd cmds[IUI_CMDBUF_LEN]; /* TODO: arena? */
+
+} iui;
+
+
+void iui_init(iui* ui, arena* ar, void* usr)
+{
+ if(!ui)
+ {
+ report(WARN, "iui: iui_init() ui == NULL!\n");
+ return;
+ }
+
+ ui->ar = ar;
+ ui->usr = usr;
+}
+
+void iui_start(iui* ui)
+{
+ assert(ui);
+ ui->hot = 0;
+
+ ar_clear(ui->ar);
+}
+
+void iui_end(iui* ui)
+{
+ assert(ui);
+
+ if(!ui->btns) ui->active = 0;
+ else if(!ui->active) ui->kbdfocus = 0;
+
+ ui->pbtns = ui->btns;
+}
+
+bool iui_mouse_inside(iui* ui, u16 x, u16 y, u16 w, u16 h)
+{
+ return !(ui->x < x || ui->y < y || ui->x >= x + w || ui->y >= y + h);
+}
+
+int iui_button(iui* ui, u16 x, u16 y, int w, int h, char* label)
+{
+ xctx* x11 = (xctx*)ui->usr;
+ usize id = (usize)label;
+ bool imhot, imactive;
+
+ if(iui_mouse_inside(ui, x, y, w, h))
+ {
+ bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1));
+ if(!ui->active && click) ui->active = id;
+ ui->hot = id;
+ }
+
+ imhot = ui->hot == id;
+ imactive = ui->active == id;
+
+ {
+ iui_cmd cmd = {0};
+ cmd.type = IUI_FILL;
+
+ cmd.x = x;
+ cmd.y = y;
+ cmd.w = w;
+ cmd.h = h;
+
+ if(imhot) cmd.size = 2;
+ else cmd.size = 1;
+
+ if(imactive) cmd.color = x11->cols.as.fg;
+ else cmd.color = x11->cols.as.bg;
+
+ ui->cmds[ui->ncmds++] = cmd;
+
+ cmd.type = IUI_BOX;
+ cmd.color = x11->cols.as.fg;
+ ui->cmds[ui->ncmds++] = cmd;
+
+ cmd.type = IUI_TEXT;
+ cmd.size = 14;
+ cmd.text = label;
+ cmd.flags = IUI_TXT_CENTER;
+
+ if(imactive) cmd.color = x11->cols.as.bg;
+ else cmd.color = x11->cols.as.fg;
+
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+
+ return imhot && imactive && !(ui->btns & bit(1));
+}
+
+void iui_label(iui* ui, u16 x, u16 y, int w, int h, char* fmt, ...)
+{
+ int len = 0;
+ char* buf = NULL;
+ va_list ap = {0};
+ xctx* x11 = (xctx*)ui->usr;
+
+ buf = ar_push(ui->ar, 512);
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, 511, fmt, ap);
+ va_end(ap);
+
+ {
+ iui_cmd cmd = {0};
+ cmd.type = IUI_FILL;
+
+ cmd.x = x;
+ cmd.y = y;
+ cmd.w = w;
+ cmd.h = h;
+
+ {
+ iui_cmd clip = cmd;
+ clip.type = IUI_CLIP;
+ clip.flags = 0;
+ clip.x++;
+ clip.y++;
+ clip.w--;
+ clip.h--;
+
+ ui->cmds[ui->ncmds++] = clip;
+ }
+
+ {
+ cmd.type = IUI_TEXT;
+ cmd.size = 14;
+ cmd.text = buf;
+ cmd.flags = 0;
+
+ cmd.x = x + 6;
+ cmd.y = y;
+ cmd.w = w;
+ cmd.h = h;
+
+ cmd.color = x11->cols.as.fg;
+
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+
+ cmd.type = IUI_CLIP;
+ cmd.flags = IUI_CLIP_CLEAR;
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+}
+
+int iui_editbox(iui* ui, u16 x, u16 y, int w, int h, char* buf, usize buflen)
+{
+ xctx* x11 = (xctx*)ui->usr;
+ usize id = (usize)buf;
+ bool imhot, imactive;
+ usize len;
+
+ len = strlen(buf);
+
+ if(iui_mouse_inside(ui, x, y, w, h))
+ {
+ bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1));
+ if(!ui->active && click) ui->active = id;
+ ui->hot = id;
+ }
+
+ imhot = ui->hot == id;
+ imactive = ui->active == id;
+
+ {
+ iui_cmd cmd = {0};
+ cmd.type = IUI_FILL;
+
+ cmd.x = x;
+ cmd.y = y;
+ cmd.w = w;
+ cmd.h = h;
+
+ if(imhot) cmd.size = 2;
+ else cmd.size = 1;
+
+ cmd.color = x11->cols.as.bg;
+ ui->cmds[ui->ncmds++] = cmd;
+
+ cmd.type = IUI_BOX;
+ cmd.color = x11->cols.as.fg;
+ ui->cmds[ui->ncmds++] = cmd;
+
+ {
+ iui_cmd clip = cmd;
+ clip.type = IUI_CLIP;
+ clip.flags = 0;
+ clip.x++;
+ clip.y++;
+ clip.w--;
+ clip.h--;
+
+ ui->cmds[ui->ncmds++] = clip;
+ }
+
+ if(imactive) ui->kbdfocus = id;
+ if(ui->kbdfocus == id)
+ {
+ cmd.type = IUI_FILL;
+ cmd.x = x + 6 + 6 * len;
+ cmd.y = y + 6;
+ cmd.w = 10;
+ cmd.h = h - 12;
+ cmd.color = x11->cols.as.fg;
+
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+ else
+ {
+ cmd.type = IUI_BOX;
+ cmd.x = x + 6 + 6 * len;
+ cmd.y = y + 6;
+ cmd.w = 9;
+ cmd.h = h - 13;
+ cmd.color = x11->cols.as.fg;
+ cmd.size = 1;
+
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+
+ {
+ cmd.type = IUI_TEXT;
+ cmd.size = 14;
+ cmd.text = buf;
+ cmd.flags = 0;
+
+ cmd.x = x + 6;
+ cmd.y = y;
+ cmd.w = w;
+ cmd.h = h;
+
+ cmd.color = x11->cols.as.fg;
+
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+
+ cmd.type = IUI_CLIP;
+ cmd.flags = IUI_CLIP_CLEAR;
+ ui->cmds[ui->ncmds++] = cmd;
+ }
+
+ return imhot && imactive && !(ui->btns & bit(1));
+}
+
+
+void iui_draw(iui* ui);
diff --git a/sources/main.c b/sources/main.c
index 4bc972c..7027451 100644
--- a/sources/main.c
+++ b/sources/main.c
@@ -21,6 +21,8 @@
#include <sys/stat.h>
#include <fcntl.h>
+#include <pthread.h>
+
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
@@ -28,238 +30,17 @@
#include "bits.c"
#include "log.c"
+#include "plat.c"
+#include "mem.c"
#include "tga.c"
#include "x11.c"
+#include "iui.c"
#include "chip8.c"
#include "meta/disasm.c"
#include "meta/exec.c"
-#define IUI_TXT_CENTER bit(0)
-#define IUI_CLIP_CLEAR bit(0)
-
-typedef struct
-{
- enum
- {
- IUI_ILL,
- IUI_BOX,
- IUI_FILL,
- IUI_LINE,
- IUI_TEXT,
- IUI_CLIP,
-
- } type;
-
- u32 color;
- u16 x, y, w, h;
- u16 size;
- u16 flags;
- char* text;
-
-} iui_cmd;
-
-#define IUI_CMDBUF_LEN 512
-typedef struct
-{
- void* usr;
-
- usize hot;
- usize active;
- usize kbdfocus;
-
- /* mouse */
- u16 x;
- u16 y;
-
- u8 pbtns;
- u8 btns;
-
- /* TODO: event pump */
-
- usize ncmds;
- iui_cmd cmds[IUI_CMDBUF_LEN]; /* TODO: arena? */
-
-} iui;
-
-
-void iui_start(iui* ui, void* usr)
-{
- assert(ui);
-
- ui->usr = usr;
- ui->hot = 0;
-}
-
-void iui_end(iui* ui)
-{
- assert(ui);
-
- if(!ui->btns) ui->active = 0;
- else
- {
- if(!ui->active) ui->kbdfocus = 0;
- }
-
- ui->pbtns = ui->btns;
-}
-
-bool iui_mouse_inside(iui* ui, u16 x, u16 y, u16 w, u16 h)
-{
- return !(ui->x < x || ui->y < y || ui->x >= x + w || ui->y >= y + h);
-}
-
-int iui_button(iui* ui, u16 x, u16 y, int w, int h, char* label)
-{
- xctx* x11 = (xctx*)ui->usr;
- usize id = (usize)label;
- bool imhot, imactive;
-
- if(iui_mouse_inside(ui, x, y, w, h))
- {
- bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1));
- if(!ui->active && click) ui->active = id;
- ui->hot = id;
- }
-
- imhot = ui->hot == id;
- imactive = ui->active == id;
-
- {
- iui_cmd cmd = {0};
- cmd.type = IUI_FILL;
-
- cmd.x = x;
- cmd.y = y;
- cmd.w = w;
- cmd.h = h;
-
- if(imhot) cmd.size = 2;
- else cmd.size = 1;
-
- if(imactive) cmd.color = x11->cols.as.fg;
- else cmd.color = x11->cols.as.bg;
-
- ui->cmds[ui->ncmds++] = cmd;
-
- cmd.type = IUI_BOX;
- cmd.color = x11->cols.as.fg;
- ui->cmds[ui->ncmds++] = cmd;
-
- cmd.type = IUI_TEXT;
- cmd.size = 14;
- cmd.text = label;
- cmd.flags = IUI_TXT_CENTER;
-
- if(imactive) cmd.color = x11->cols.as.bg;
- else cmd.color = x11->cols.as.fg;
-
- ui->cmds[ui->ncmds++] = cmd;
- }
-
- return imhot && imactive && !(ui->btns & bit(1));
-}
-
-int iui_textbox(iui* ui, u16 x, u16 y, int w, int h, char* buf, usize buflen)
-{
- xctx* x11 = (xctx*)ui->usr;
- usize id = (usize)buf;
- bool imhot, imactive;
- usize len;
-
- len = strlen(buf);
-
- if(iui_mouse_inside(ui, x, y, w, h))
- {
- bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1));
- if(!ui->active && click) ui->active = id;
- ui->hot = id;
- }
-
- imhot = ui->hot == id;
- imactive = ui->active == id;
-
- {
- iui_cmd cmd = {0};
- cmd.type = IUI_FILL;
-
- cmd.x = x;
- cmd.y = y;
- cmd.w = w;
- cmd.h = h;
-
- if(imhot) cmd.size = 2;
- else cmd.size = 1;
-
- cmd.color = x11->cols.as.bg;
- ui->cmds[ui->ncmds++] = cmd;
-
- cmd.type = IUI_BOX;
- cmd.color = x11->cols.as.fg;
- ui->cmds[ui->ncmds++] = cmd;
-
- {
- iui_cmd clip = cmd;
- clip.type = IUI_CLIP;
- clip.flags = 0;
- clip.x++;
- clip.y++;
- clip.w--;
- clip.h--;
-
- ui->cmds[ui->ncmds++] = clip;
- }
-
- if(imactive) ui->kbdfocus = id;
- if(ui->kbdfocus == id)
- {
- cmd.type = IUI_FILL;
- cmd.x = x + 6 + 6 * len;
- cmd.y = y + 6;
- cmd.w = 10;
- cmd.h = h - 12;
- cmd.color = x11->cols.as.fg;
-
- ui->cmds[ui->ncmds++] = cmd;
- }
- else
- {
- cmd.type = IUI_BOX;
- cmd.x = x + 6 + 6 * len;
- cmd.y = y + 6;
- cmd.w = 9;
- cmd.h = h - 13;
- cmd.color = x11->cols.as.fg;
- cmd.size = 1;
-
- ui->cmds[ui->ncmds++] = cmd;
- }
-
- {
- cmd.type = IUI_TEXT;
- cmd.size = 14;
- cmd.text = buf;
- cmd.flags = 0;
-
- cmd.x = x + 6;
- cmd.y = y;
- cmd.w = w;
- cmd.h = h;
-
- cmd.color = x11->cols.as.fg;
-
- ui->cmds[ui->ncmds++] = cmd;
- }
-
- cmd.type = IUI_CLIP;
- cmd.flags = IUI_CLIP_CLEAR;
- ui->cmds[ui->ncmds++] = cmd;
- }
-
- return imhot && imactive && !(ui->btns & bit(1));
-}
-
void iui_draw(iui* ui)
{
usize i;
@@ -348,13 +129,53 @@ void iui_draw(iui* ui)
ui->ncmds = 0;
}
+void c8_dump_state_iui(chip8* c8, bool stack, iui* ui, u16 x, u16 y)
+{
+ int i = 0;
+
+ u16 dx = x, dy = y;
+ u16 w = 80, h = 10, p = 5;
+
+ for(i = 0; i < (int)sizeof(c8->V); i += 4)
+ {
+ iui_label(ui, dx, dy, w, h, "V%x: %02X (%3d)", i+0, c8->V[i+0], c8->V[i+0]);
+ dx += w + p;
+
+ iui_label(ui, dx, dy, w, h, "V%x: %02X (%3d)", i+1, c8->V[i+1], c8->V[i+1]);
+ dx += w + p;
+
+ iui_label(ui, dx, dy, w, h, "V%x: %02X (%3d)", i+2, c8->V[i+2], c8->V[i+2]);
+ dx += w + p;
+
+ iui_label(ui, dx, dy, w, h, "V%x: %02X (%3d)", i+3, c8->V[i+3], c8->V[i+3]);
+
+ dx = x;
+ dy += h + p;
+ }
+
+ iui_label(ui, dx, dy, 1000, h, "I:%04X SP: %02X DT: %02X ST: %02X CYCLES: %llu KEYS: %X",
+ c8->i, c8->sp, c8->dt, c8->st, c8->cycles, c8->keys);
+#if 0
+ if(stack)
+ {
+ iui_label(ui, "stack:\n");
+ for(i = 0; i < (int)sizeof(c8->STACK); i += 2)
+ {
+ iui_label(ui, " %-2d: %04X ", i+0, c8->STACK[i+0]);
+ iui_label(ui, "%-2d: %04X\n", i+1, c8->STACK[i+1]);
+ }
+ }
+#endif
+}
+
int main(int argc, char** argv)
{
chip8 c8 = {0};
xctx x11 = {0};
+ arena ar = {0};
iui ui = {0};
- bool run = true, cycle = false;;
+ bool run = true;
u64 sz = 0;
FILE* f = NULL;
@@ -404,7 +225,10 @@ int main(int argc, char** argv)
}
x11_init(800, 600, "xip-8", argc, argv, &x11);
+ ar_create(4*MB, true, &ar);
+ iui_init(&ui, &ar, &x11);
c8_reset(&c8);
+ c8.running = false;
while(run)
{
@@ -520,6 +344,12 @@ int main(int argc, char** argv)
}
}
+ if(c8.running)
+ {
+ c8_disasm(c8.RAM, c8.pc, buf);
+ c8_exec(c8.RAM, c8.pc, &c8);
+ }
+
{
int len = 0;
char buf[512] = {0};
@@ -539,8 +369,6 @@ int main(int argc, char** argv)
len = snprintf(buf, lengthof(buf), "cur: %dx%d", ui.x, ui.y);
XDrawString(x11.disp, x11.wnd, x11.gc, 650, 65, buf, len);
- iui_draw(&ui);
-
len = snprintf(buf, lengthof(buf), "btn: %d%d%d",
ui.btns & bit(1) ? 1 : 0,
ui.btns & bit(2) ? 2 : 0,
@@ -555,22 +383,22 @@ int main(int argc, char** argv)
len = snprintf(buf, lengthof(buf), "kbd: %p", (void*)ui.kbdfocus);
XDrawString(x11.disp, x11.wnd, x11.gc, 650, 125, buf, len);
- }
-
- iui_start(&ui, &x11);
- if(iui_button(&ui, 25, 25, 100, 35, "Cycle")) cycle = !cycle;
- iui_textbox(&ui, 25, 75, 225, 35, buf, lengthof(buf));
- iui_end(&ui);
+ len = snprintf(buf, lengthof(buf), "ar: %lu bytes", ar.cursor - ar.base);
+ XDrawString(x11.disp, x11.wnd, x11.gc, 650, 145, buf, len);
- if(cycle)
- {
- c8_disasm(c8.RAM, c8.pc, buf);
- c8_exec(c8.RAM, c8.pc, &c8);
+ iui_draw(&ui);
}
+ iui_start(&ui);
+ c8_dump_state_iui(&c8, false, &ui, 25, 25);
+ iui_editbox(&ui, 25, 600 - 45, 225, 35, buf, lengthof(buf));
+ if(!c8.running && iui_button(&ui, 270, 600 - 45, 100, 35, "Go")) c8.running = true;
+ else if(c8.running && iui_button(&ui, 270, 600 - 45, 100, 35, "Stop")) c8.running = false;
+ iui_end(&ui);
+
{
- usize x, y, s = 4;
+ usize x, y, s = 12;
XSetForeground(x11.disp, x11.gc, x11.cols.as.fg);
XSetBackground(x11.disp, x11.gc, x11.cols.as.bg);
@@ -581,7 +409,7 @@ int main(int argc, char** argv)
XFillRectangle(x11.disp, x11.wnd, x11.gc, 25 + x*s, 128 + y*s, s, s);
}
- usleep(10000);
+ usleep(100);
}
x11_cleanup(&x11);
diff --git a/sources/mem.c b/sources/mem.c
new file mode 100644
index 0000000..3b111f7
--- /dev/null
+++ b/sources/mem.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2025 dwlr <dweller@cabin.digital>
+ *
+ * BSD 3-Clause License (BSD-3-Clause)
+ * See LICENSE for details
+ */
+
+
+typedef struct
+{
+ u8* base;
+ u8* cursor;
+ usize size;
+
+} arena;
+
+
+typedef struct
+{
+ u8* base;
+ ssize pages;
+
+} do_pagefault_args;
+void* do_pagefault(void* arg)
+{
+ ssize i = 0;
+ ssize p = mm_pagesize();
+ do_pagefault_args* args = (do_pagefault_args*)arg;
+ if(!args)
+ {
+ report(ERR, "do_pagefault() with NULL args!\n");
+ return NULL;
+ }
+
+ for(i = 0; i < args->pages; i++) args->base[p * i] = 0;
+
+ return NULL;
+}
+
+bool ar_create(usize size, bool prefault, arena* ar)
+{
+ ssize p = mm_pagesize();
+
+ if(!ar) return false;
+ if(size <= 0) return false;
+
+ size += (size % p) ? (p - (size % p)) : 0;
+
+ ar->base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if(ar->base == MAP_FAILED) return false;
+ ar->size = size;
+ ar->cursor = ar->base;
+
+ if(prefault)
+ {
+ ssize i = 0;
+ ssize cpus = cpu_count();
+ pthread_t* t = NULL;
+ do_pagefault_args* args = NULL;
+
+ t = calloc(cpus, sizeof(t[0]));
+ if(!t) report(FATAL, "ar_create()/prefault/calloc(t) failed!\n");
+ else
+ {
+ args = calloc(cpus, sizeof(args[0]));
+ if(!args)
+ {
+ free(t);
+ report(FATAL, "ar_create()/prefault/calloc(args) failed!\n");
+ }
+ }
+
+ for(i = 1; i < cpus; i++)
+ {
+ args[i].base = ar->base + ((size / cpus) * i);
+ args[i].pages = ((size / p) / cpus);
+ pthread_create(&t[i], NULL, do_pagefault, &args[i]);
+ }
+
+ args[0].base = ar->base;
+ args[0].pages = ((size / p) / cpus);
+ do_pagefault(&args[0]);
+
+ for(i = 1; i < cpus; i++) pthread_join(t[i], NULL);
+
+ free(args);
+ free(t);
+ }
+
+ return true;
+}
+
+#define ar_push(ar, sz) ar_pusha((ar), (sz), sizeof(int), true)
+void* ar_pusha(arena* ar, usize size, usize alignment, bool zero)
+{
+ usize cur, ovfl;
+
+ if(!ar) return NULL;
+ else
+ {
+ cur = align((usize)ar->cursor, alignment);
+ ovfl = (cur + size);
+ if(ovfl < cur) return NULL;
+
+ if(ovfl <= (usize)(ar->base + ar->size))
+ {
+ ar->cursor = (u8*)ovfl;
+
+ if(zero) memset((u8*)cur, 0, size);
+ return (u8*)cur;
+ }
+ else
+ {
+ report(ERR, "arena(%P): overflow @ %P x %llu\n", ar, cur, size);
+ return NULL;
+ }
+ }
+}
+
+void ar_pop(arena* ar, usize size)
+{
+ if(!ar) return;
+ else ar->cursor = min(ar->base, ar->cursor - size);
+}
+
+void ar_clear(arena* ar)
+{
+ if(ar) ar->cursor = ar->base;
+}
+
+void ar_destroy(arena* ar)
+{
+ if(!ar) return;
+
+ munmap(ar->base, ar->size);
+ ar->base = ar->cursor = NULL;
+ ar->size = 0;
+}
+
diff --git a/sources/meta/exec.c b/sources/meta/exec.c
index 4f34d1b..663a2ae 100644
--- a/sources/meta/exec.c
+++ b/sources/meta/exec.c
@@ -237,7 +237,6 @@ BEGIN \
if(c8->V[x] != c8->V[y]) c8->pc += 2; \
END
-/* FIXME: correct wrapping, test */
#define X_C8_DRW \
BEGIN \
u8 l; \
@@ -245,7 +244,11 @@ BEGIN \
u8 cy = c8->V[y]; \
\
for(l = 0; l < n; l++) \
- c8->DISPLAY[(cy + l) % 32] ^= ((u64)c8->RAM[c8->i + l]) << (64 - cx); \
+ { \
+ u64 pix = (u64)c8->RAM[c8->i + l]; \
+ pix = (pix << (64 - cx)) | (pix >> cx); \
+ c8->DISPLAY[(cy + l) % 32] ^= pix; \
+ } \
END
c8_decode_generate(exec)
diff --git a/sources/plat.c b/sources/plat.c
new file mode 100644
index 0000000..afa0f21
--- /dev/null
+++ b/sources/plat.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2025 dwlr <dweller@cabin.digital>
+ *
+ * BSD 3-Clause License (BSD-3-Clause)
+ * See LICENSE for details
+ */
+
+
+ssize cpu_count(void)
+{
+ static ssize cpus = 0;
+ if(!cpus) cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ return cpus;
+}
+
+ssize mm_pagesize(void)
+{
+ static ssize page_size = 0;
+ if(!page_size) page_size = sysconf(_SC_PAGE_SIZE);
+
+ return page_size;
+}
+
diff --git a/sources/x11.c b/sources/x11.c
index b9f27b3..7d353cb 100644
--- a/sources/x11.c
+++ b/sources/x11.c
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2025 dwlr <dweller@cabin.digital>
+ *
+ * BSD 3-Clause License (BSD-3-Clause)
+ * See LICENSE for details
+ */
+
+
#if true != True
#error "true != Xlib's True"
#endif