diff options
Diffstat (limited to 'sources')
-rw-r--r-- | sources/iui.c | 300 | ||||
-rw-r--r-- | sources/main.c | 306 | ||||
-rw-r--r-- | sources/mem.c | 139 | ||||
-rw-r--r-- | sources/meta/exec.c | 7 | ||||
-rw-r--r-- | sources/plat.c | 24 | ||||
-rw-r--r-- | sources/x11.c | 8 |
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 |