From 8598be727f5ae455ecf68fc1630df3e773bb0bdf Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Fri, 12 Dec 2025 14:22:42 +0000 Subject: [PATCH] Provide a framebuffer 320x200 (RGBA8888) on render(addr,len) syscall, copy from that VM memory location to framebuffer. --- hosts/host-sdl/Makefile | 2 +- hosts/host-sdl/host-sdl.c | 137 +++++++++++++++++++++++++------------- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/hosts/host-sdl/Makefile b/hosts/host-sdl/Makefile index ff36649..8c424df 100644 --- a/hosts/host-sdl/Makefile +++ b/hosts/host-sdl/Makefile @@ -11,7 +11,7 @@ endif #CFLAGS += -Wall -Werror CFLAGS += -pedantic -std=c99 -O3 -CFLAGS += -DUVM32_MEMORY_SIZE=65536 +CFLAGS += -DUVM32_MEMORY_SIZE=$(shell echo "1024 * 1024 * 8" | bc) all: gcc ${CFLAGS} -I${TOPDIR}/uvm32 -I${TOPDIR}/common -o host-sdl ${TOPDIR}/uvm32/uvm32.c host-sdl.c ${LIBS} diff --git a/hosts/host-sdl/host-sdl.c b/hosts/host-sdl/host-sdl.c index 81ac485..03ed768 100644 --- a/hosts/host-sdl/host-sdl.c +++ b/hosts/host-sdl/host-sdl.c @@ -16,8 +16,16 @@ #include "../common/uvm32_common_custom.h" -#define WIDTH 800 -#define HEIGHT 600 +#define WIDTH 320 +#define HEIGHT 200 + +#define WINDOW_WIDTH WIDTH*2 +#define WINDOW_HEIGHT HEIGHT*2 + +// TBD replace with queue of keypresses +uint16_t last_keyscancode; +bool last_keyvalid = false; +bool last_keypressed = false; static uint8_t *read_file(const char* filename, int *len) { FILE* f = fopen(filename, "rb"); @@ -72,18 +80,18 @@ void usage(const char *name) { printf("Options:\n"); printf(" -h show help\n"); printf(" -i max instrs before requiring a syscall\n"); + printf(" -e numbers of bytes for extram\n"); exit(1); } int main(int argc, char *argv[]) { - uvm32_state_t vmst; + uvm32_state_t *vmst = NULL; uint32_t max_instrs_per_run = 500000; - clock_t start_time = clock() / (CLOCKS_PER_SEC / 1000); char c; const char *rom_filename = NULL; - uint32_t extram_len = WIDTH * HEIGHT * 4; + uint32_t extram_len = 0; uint32_t *extram_buf = NULL; uvm32_evt_t evt; bool isrunning = true; @@ -95,9 +103,17 @@ int main(int argc, char *argv[]) { SDL_Event event; SDL_Surface *surface = NULL; SDL_Texture *tex = NULL; + SDL_Texture *render_target = NULL; + + // memory for vmst is very large, so allocate + vmst = (uvm32_state_t *)malloc(sizeof(uvm32_state_t)); + if (vmst == NULL) { + printf("Out of memory\n"); + return 1; + } // parse commandline args - while ((c = getopt(argc, argv, "hi:")) != -1) { + while ((c = getopt(argc, argv, "hi:e:")) != -1) { switch(c) { case 'h': usage(argv[0]); @@ -108,6 +124,9 @@ int main(int argc, char *argv[]) { usage(argv[0]); } break; + case 'e': + extram_len = strtoll(optarg, NULL, 10); + break; } } if (optind < argc) { @@ -122,9 +141,9 @@ int main(int argc, char *argv[]) { return 1; } - uvm32_init(&vmst); + uvm32_init(vmst); - if (!uvm32_load(&vmst, rom, romlen)) { + if (!uvm32_load(vmst, rom, romlen)) { printf("load failed!\n"); return 1; } @@ -136,7 +155,7 @@ int main(int argc, char *argv[]) { return 1; } memset(extram_buf, 0x00, extram_len); - uvm32_extram(&vmst, extram_buf, extram_len); + uvm32_extram(vmst, extram_buf, extram_len); } SDL_SetMainReady(); @@ -145,10 +164,7 @@ int main(int argc, char *argv[]) { return 1; } - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16); - - screen = SDL_CreateWindow("sdl-host", WIDTH, HEIGHT, SDL_WINDOW_OPENGL); + screen = SDL_CreateWindow("sdl-host", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL); if (NULL == screen) { printf("SDL CreateWindow failed\n"); return 1; @@ -159,32 +175,33 @@ int main(int argc, char *argv[]) { return 1; } - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - - surface = SDL_CreateSurfaceFrom(WIDTH, HEIGHT, SDL_PIXELFORMAT_RGBA8888, extram_buf, 4 * WIDTH); - if (NULL == surface) { - printf("Failed to create SDL surface\n"); - return 1; - } - + render_target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); + SDL_SetTextureScaleMode(render_target, SDL_SCALEMODE_NEAREST); while (isrunning) { SDL_PollEvent(&event); switch(event.type) { case SDL_EVENT_QUIT: - exit(0); + isrunning = false; + break; + case SDL_EVENT_KEY_DOWN: + if (!event.key.repeat) { + last_keyscancode = event.key.scancode; + last_keypressed = true; + last_keyvalid = true; + } + break; + case SDL_EVENT_KEY_UP: + if (!event.key.repeat) { + last_keyscancode = event.key.scancode; + last_keypressed = false; + last_keyvalid = true; + } break; } - if (uvm32_extramDirty(&vmst)) { - tex = SDL_CreateTextureFromSurface(renderer, surface); - SDL_RenderTexture(renderer, tex, NULL, NULL); - SDL_DestroyTexture(tex); - SDL_RenderPresent(renderer); - } - - total_instrs += uvm32_run(&vmst, &evt, max_instrs_per_run); // num instructions before vm considered hung + total_instrs += uvm32_run(vmst, &evt, max_instrs_per_run); // num instructions before vm considered hung num_syscalls++; switch(evt.typ) { @@ -196,11 +213,11 @@ int main(int argc, char *argv[]) { printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode); if (evt.data.err.errcode == UVM32_ERR_HUNG) { printf("VM may have hung, increase max_instrs_per_run\n"); - uvm32_clearError(&vmst); // allow to continue + uvm32_clearError(vmst); // allow to continue } else { isrunning = false; - memdump("host-ram.dump", vmst.memory, UVM32_MEMORY_SIZE); - printf("memory dumped to host-ram.dump, pc=0x%08x\n", vmst.core.pc); + memdump("host-ram.dump", vmst->memory, UVM32_MEMORY_SIZE); + printf("memory dumped to host-ram.dump, pc=0x%08x\n", vmst->core.pc); if (extram_buf != NULL) { memdump("host-extram.dump", (uint8_t *)extram_buf, extram_len); printf("extram dumped to host-extram.dump\n"); @@ -210,40 +227,70 @@ int main(int argc, char *argv[]) { case UVM32_EVT_SYSCALL: switch(evt.data.syscall.code) { case UVM32_SYSCALL_PRINTBUF: { - uvm32_evt_syscall_buf_t buf = uvm32_getbuf(&vmst, &evt, ARG0, ARG1); + uvm32_evt_syscall_buf_t buf = uvm32_getbuf(vmst, &evt, ARG0, ARG1); while(buf.len--) { printf("%02x", *buf.ptr++); } } break; case UVM32_SYSCALL_YIELD: { - // uint32_t yield_typ = uvm32_getval(&vmst, &evt, ARG0); + // uint32_t yield_typ = uvm32_getval(vmst, &evt, ARG0); // printf("YIELD type=%d\n", yield_typ); - // uvm32_setval(&vmst, &evt, RET, 123); + // uvm32_setval(vmst, &evt, RET, 123); } break; case UVM32_SYSCALL_PRINT: { - const char *str = uvm32_getcstr(&vmst, &evt, ARG0); + const char *str = uvm32_getcstr(vmst, &evt, ARG0); printf("%s", str); } break; case UVM32_SYSCALL_PRINTLN: { - const char *str = uvm32_getcstr(&vmst, &evt, ARG0); + const char *str = uvm32_getcstr(vmst, &evt, ARG0); printf("%s\n", str); } break; case UVM32_SYSCALL_PRINTDEC: - printf("%d", uvm32_getval(&vmst, &evt, ARG0)); + printf("%d", uvm32_getval(vmst, &evt, ARG0)); break; case UVM32_SYSCALL_PUTC: - printf("%c", uvm32_getval(&vmst, &evt, ARG0)); + printf("%c", uvm32_getval(vmst, &evt, ARG0)); break; case UVM32_SYSCALL_PRINTHEX: - printf("%08x", uvm32_getval(&vmst, &evt, ARG0)); + printf("%08x", uvm32_getval(vmst, &evt, ARG0)); break; case UVM32_SYSCALL_MILLIS: { - clock_t now = clock() / (CLOCKS_PER_SEC / 1000); - uvm32_setval(&vmst, &evt, RET, now - start_time); + uvm32_setval(vmst, &evt, RET, SDL_GetTicks()); } break; case UVM32_SYSCALL_GETC: { - uvm32_setval(&vmst, &evt, RET, 0xFFFFFFFF); + uvm32_setval(vmst, &evt, RET, 0xFFFFFFFF); } break; + case UVM32_SYSCALL_RENDER: { + uvm32_evt_syscall_buf_t buf = uvm32_getbuf(vmst, &evt, ARG0, ARG1); + + void* dst; + const unsigned char* src = buf.ptr; + int src_pitch = WIDTH * 4; + int dst_pitch; + if (SDL_LockTexture(render_target, NULL, &dst, &dst_pitch)) { + for (int y = 0; y < HEIGHT; y++) { + memcpy(dst, src, src_pitch); + dst = (unsigned char*)dst + dst_pitch; + src += src_pitch; + } + SDL_UnlockTexture(render_target); + } + + // stretch to window + SDL_FRect src_rect = {0, 0, WIDTH, HEIGHT }; + SDL_FRect dst_rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + SDL_RenderTexture(renderer, render_target, &src_rect, &dst_rect); + SDL_RenderPresent(renderer); + } break; + case UVM32_SYSCALL_GETKEY: + if (last_keyvalid) { + uint32_t code = (last_keypressed ? 0x80000000 : 0) | last_keyscancode; + uvm32_setval(vmst, &evt, RET, code); + } else { + uvm32_setval(vmst, &evt, RET, 0xFFFFFFFF); + } + last_keyvalid = false; + break; default: printf("Unhandled syscall 0x%08x\n", evt.data.syscall.code); break; @@ -257,7 +304,7 @@ int main(int argc, char *argv[]) { fflush(stdout); } - printf("Executed total of %d instructions and %d syscalls\n", (int)total_instrs, (int)num_syscalls); + printf("Executed total of %lu instructions and %lu syscalls\n", (unsigned long)total_instrs, (unsigned long)num_syscalls); free(rom); if (extram_buf != NULL) {