tuxanci2-engine
Game engine for tuxanci2
Log | Files | Refs | README | LICENSE
commit 53d806fe393fdc5c74f04c40849cba97f6241959
parent 5569729cba729800db5460d25c74c8cbedd1e3c1
Author: Connor Thomson <connor@gnufault.org>
Date:   Tue, 10 Nov 2026 20:22:10 -0800

Update tab format and more

Diffstat:
Mengine.mk | 32+++++++++++++++++++++++++++++++-
Minclude/abi.h | 4++++
Ainclude/file.h | 15+++++++++++++++
Minclude/image.h | 2+-
Minclude/syscall.h | 2+-
Ainclude/tab.h | 22++++++++++++++++++++++
Minclude/text.h | 1+
Minclude/vm.h | 6+++++-
Asrc/file.c | 33+++++++++++++++++++++++++++++++++
Msrc/image.c | 16++++++++++------
Msrc/main.c | 8+++++++-
Msrc/scene.c | 1+
Msrc/syscall.c | 120++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Asrc/tab.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/text.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/title.c | 2+-
Msrc/vm.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
17 files changed, 476 insertions(+), 59 deletions(-)

diff --git a/engine.mk b/engine.mk @@ -30,7 +30,16 @@ asset_sym = $(shell printf '%s' 'ta_file_$(notdir $(basename $(1)))' | sed 's/[ ASSET_GEN_SRCS := $(foreach a,$(ASSETS),$(BUILD_DIR)/engine/assets/$(notdir $(basename $(a))).c) ASSET_OBJS := $(ASSET_GEN_SRCS:.c=.o) -ALL_ENGINE_OBJS := $(ENGINE_OBJS) $(ASSET_OBJS) +EMBED_GAME ?= 0 +GAME_TAB ?= $(BUILD_DIR)/game/tuxanci2.tab + +ifeq ($(EMBED_GAME),1) +GAME_EMBED_SRC := $(BUILD_DIR)/engine/embed/ta_game_tab.c +GAME_EMBED_OBJ := $(GAME_EMBED_SRC:.c=.o) +CFLAGS += -DTA_EMBED_GAME +endif + +ALL_ENGINE_OBJS := $(ENGINE_OBJS) $(ASSET_OBJS) $(GAME_EMBED_OBJ) ENGINE_LIB := $(BUILD_DIR)/engine/libtuxanci2-engine.a OUT ?= $(BUILD_DIR)/tuxanci2 @@ -46,6 +55,25 @@ $(BUILD_DIR)/engine/assets/$(notdir $(basename $(1))).c: $(1) endef $(foreach a,$(ASSETS),$(eval $(call ASSET_RULE,$(a)))) +EMBED_STAMP := $(BUILD_DIR)/engine/embed-$(EMBED_GAME).stamp + +$(EMBED_STAMP): + mkdir -p $(@D) + rm -f $(BUILD_DIR)/engine/embed-*.stamp + touch $@ + +$(BUILD_DIR)/engine/src/tab.o: $(EMBED_STAMP) + +ifeq ($(EMBED_GAME),1) +$(GAME_EMBED_SRC): $(GAME_TAB) + mkdir -p $(@D) + $(XXD) -i -n ta_game_tab $< $@ + +$(BUILD_DIR)/engine/embed/%.o: $(BUILD_DIR)/engine/embed/%.c $(CONFIG_HEADER) + mkdir -p $(@D) + $(CC) $(CFLAGS) -I$(ENGINE_DIR)/include -I$(BUILD_DIR)/engine/include -MMD -MP -c $< -o $@ +endif + $(CONFIG_HEADER): $(ENGINE_DIR)/include/config.h.in mkdir -p $(@D) sed 's/\$$BITS/$(BITS)/g' $< > $@ @@ -86,9 +114,11 @@ $(ENGINE_LIB): $(ALL_ENGINE_OBJS) rm -f $@ $(AR) rcs $@ $^ +ifneq ($(NO_DEFAULT_LINK),1) $(OUT): $(RUNTIME_OBJS) $(ENGINE_LIB) mkdir -p $(@D) $(CC) $(CFLAGS) $(RUNTIME_OBJS) $(ENGINE_LIB) $(LDFLAGS) $(LDLIBS) -o $@ +endif clean: rm -rf $(BUILD_DIR)/engine $(BUILD_DIR)/runtime $(OUT) diff --git a/include/abi.h b/include/abi.h @@ -26,5 +26,9 @@ #define TA_SYS_FT2_PLAY 22 #define TA_SYS_FT2_STOP 23 #define TA_SYS_FT2_IS_PLAYING 24 +#define TA_SYS_FILE_SIZE 25 +#define TA_SYS_FILE_READ 26 +#define TA_SYS_FILE_EXEC 27 +#define TA_SYS_TEXT_CHANGE_COLOR 28 #endif // TA_ABI_H diff --git a/include/file.h b/include/file.h @@ -0,0 +1,15 @@ +#ifndef TA_FILE_H +#define TA_FILE_H + +#include <stdint.h> + +typedef struct __attribute__((packed)) { + uint8_t file; + uint32_t size; + char data[]; +} ta_file; + +ta_file *ta_file_open(uint8_t file); +void ta_file_close(ta_file *file); + +#endif // TA_FILE_H diff --git a/include/image.h b/include/image.h @@ -7,7 +7,7 @@ bool ta_image_draw(const uint8_t *data, uint32_t length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, uint16_t frame); bool ta_image_render(const uint8_t *data, uint32_t length, uint16_t frame, uint32_t width, uint32_t height, uint32_t *pixels); bool ta_image_init(const uint8_t *data, uint32_t length); -bool ta_image_get_size(const uint8_t *data, uint32_t length, uint32_t *width, uint32_t *height); +bool ta_image_get_size(const uint8_t *data, uint32_t *width, uint32_t *height); void ta_image_release(void); #endif diff --git a/include/syscall.h b/include/syscall.h @@ -3,7 +3,7 @@ #include "vm.h" -ta_vm_status ta_syscall(ta_vm *vm); +ta_vm_status ta_syscall_handler(ta_vm *vm); void ta_syscall_reset(void); #endif // TA_SYSCALL_H diff --git a/include/tab.h b/include/tab.h @@ -0,0 +1,22 @@ +#ifndef TA_TAB_H +#define TA_TAB_H + +#include <stdint.h> +#include <stdbool.h> + +#define TA_TAB_MAGIC_0 'T' +#define TA_TAB_MAGIC_1 'A' +#define TA_TAB_MAGIC_2 'B' +#define TA_TAB_MAGIC_3 'F' +#define TA_TAB_VERSION 1 +#define TA_TAB_HEADER_SIZE 5 +#define TA_TAB_ENTRY_SIZE 9 +#define TA_TAB_MAX_FILES 255 +#define TA_TAB_END 0 +#define TA_TAB_MAIN_PROGRAM 1 + +bool ta_tab_load(const char *path); +void ta_tab_unload(void); +bool ta_tab_find(uint8_t file, const uint8_t **data, uint32_t *size); + +#endif // TA_TAB_H diff --git a/include/text.h b/include/text.h @@ -17,6 +17,7 @@ typedef struct { void ta_text_rasterize(ta_text *text); void ta_text_draw(ta_text *text); +bool ta_text_change_color(ta_text *text, uint32_t color); void ta_text_destroy(ta_text *text); #endif // TA_TEXT_H diff --git a/include/vm.h b/include/vm.h @@ -3,6 +3,7 @@ #include <stdint.h> #include <stdbool.h> +#include <stddef.h> typedef enum { TA_VM_RUNNING, @@ -58,7 +59,10 @@ const char *ta_vm_cstr(const ta_vm *vm, uint32_t addr); extern bool ta_vm_running; bool ta_vm_load(const uint8_t *binary, size_t size); -bool ta_vm_load_file(const char *path); +bool ta_vm_load_tab(const char *path); +void ta_vm_request_exec(uint8_t file); +bool ta_vm_exec_pending(void); +bool ta_vm_exec_apply(void); bool ta_vm_call(uint32_t function, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t *result); int32_t ta_vm_exit_code(void); void ta_vm_unload(void); diff --git a/src/file.c b/src/file.c @@ -0,0 +1,33 @@ +#include <stdint.h> +#include <stdlib.h> +#include <stddef.h> +#include "file.h" +#include "tab.h" + +ta_file *ta_file_open(uint8_t file) { + const uint8_t *data; + uint32_t size; + + if (!ta_tab_find(file, &data, &size)) { + return NULL; + } + + ta_file *opened = (ta_file *)malloc(sizeof(ta_file) + size); + + if (opened == NULL) { + return NULL; + } + + opened->file = file; + opened->size = size; + + for (uint32_t i = 0; i < size; i++) { + opened->data[i] = (char)data[i]; + } + + return opened; +} + +void ta_file_close(ta_file *file) { + free(file); +} diff --git a/src/image.c b/src/image.c @@ -243,9 +243,13 @@ static bool decode_next_frame(ta_image_cache *image) { return true; } -static ta_image_cache *find_image(const uint8_t *data, uint32_t length) { +static ta_image_cache *find_image(const uint8_t *data) { + if (data == 0) { + return 0; + } + for (ta_image_cache *image = image_cache; image != 0; image = image->next) { - if (image->data == data && image->length == length) { + if (image->data == data) { return image; } } @@ -254,7 +258,7 @@ static ta_image_cache *find_image(const uint8_t *data, uint32_t length) { } bool ta_image_init(const uint8_t *data, uint32_t length) { - if (find_image(data, length) != 0) { + if (find_image(data) != 0) { return true; } @@ -281,8 +285,8 @@ bool ta_image_init(const uint8_t *data, uint32_t length) { return true; } -bool ta_image_get_size(const uint8_t *data, uint32_t length, uint32_t *width, uint32_t *height) { - ta_image_cache *image = find_image(data, length); +bool ta_image_get_size(const uint8_t *data, uint32_t *width, uint32_t *height) { + ta_image_cache *image = find_image(data); if (image == 0 || width == 0 || height == 0) { return false; } @@ -298,7 +302,7 @@ static ta_image_cache *get_image(const uint8_t *data, uint32_t length, uint16_t return 0; } - ta_image_cache *image = find_image(data, length); + ta_image_cache *image = find_image(data); if (frame >= image->frame_count) { return 0; } diff --git a/src/main.c b/src/main.c @@ -5,6 +5,7 @@ #include "api.h" #include "screen.h" #include "vm.h" +#include "tab.h" void ta_main_destroy(void) { int32_t exit_code = ta_vm_exit_code(); @@ -12,6 +13,7 @@ void ta_main_destroy(void) { ta_ft2_destroy(); ta_screen_destroy(); ta_vm_unload(); + ta_tab_unload(); ta_display_deinit(); ta_exit(exit_code); @@ -22,6 +24,10 @@ bool ta_main_update(void) { bool drawn = ta_screen_update(); + if (ta_vm_exec_pending()) { + ta_vm_exec_apply(); + } + if (!ta_vm_running) { ta_main_destroy(); } @@ -42,7 +48,7 @@ void ta_main_init(void) { ta_screen_init(); - if (!ta_vm_load_file("game/tuxanci2.tab")) { + if (!ta_vm_load_tab("game/tuxanci2.tab")) { ta_exit(1); } } diff --git a/src/scene.c b/src/scene.c @@ -156,6 +156,7 @@ bool ta_scene_text(ta_text *text, uint32_t x, uint32_t y) { } op->text = text; + op->color = ((uint32_t)text->red << 16) | ((uint32_t)text->green << 8) | text->blue; op->x = x; op->y = y; diff --git a/src/syscall.c b/src/syscall.c @@ -7,21 +7,19 @@ #include "abi.h" #include "scene.h" #include "screen.h" +#include "shapes.h" #include "keyboard.h" #include "image.h" #include "ft2.h" #include "api.h" +#include "tab.h" -static bool get_data(const ta_vm *vm, uint32_t address, const uint8_t **data, uint32_t *length) { - *data = (const uint8_t *)ta_vm_translate_pointer(vm, address, 1); - - if (*data == NULL) { +static bool get_file(uint32_t file, const uint8_t **data, uint32_t *length) { + if (file > TA_TAB_MAX_FILES) { return false; } - *length = vm->mem_size - address; - - return true; + return ta_tab_find((uint8_t)file, data, length); } static ta_text **texts; @@ -99,7 +97,6 @@ static uint32_t text_create(const char *string, uint32_t size, uint32_t color, u if (!text->sprite) { free(text); - return 0; } @@ -124,18 +121,25 @@ static void text_destroy(uint32_t handle) { return; } - ta_scene_invalidate(); ta_text_destroy(text); free(text); texts[handle - 1] = NULL; } -ta_vm_status ta_syscall(ta_vm *vm) { +ta_vm_status ta_syscall_handler(ta_vm *vm) { uint32_t *registers = vm->regs; - uint32_t *args = &registers[TA_VM_REG_A0]; + uint32_t number = registers[TA_VM_REG_A7]; + uint32_t args[6] = { + registers[TA_VM_REG_A0], + registers[TA_VM_REG_A1], + registers[TA_VM_REG_A2], + registers[TA_VM_REG_A3], + registers[TA_VM_REG_A4], + registers[TA_VM_REG_A5] + }; uint32_t result = 0; - switch (registers[TA_VM_REG_A7]) { + switch (number) { case TA_SYS_DISPLAY_WIDTH: { result = ta_display->width; @@ -152,53 +156,52 @@ ta_vm_status ta_syscall(ta_vm *vm) { break; } case TA_SYS_KEYBOARD_IS_DOWN: { - result = args[0] < 256 && ta_keyboard_is_down((ta_keyboard_keys)args[0]) ? 1 : 0; + result = ta_keyboard_is_down((ta_keyboard_keys)args[0]) ? 1 : 0; break; } - case TA_SYS_IMAGE_INIT: { + case TA_SYS_IMAGE_DRAW: { const uint8_t *data; uint32_t length; - if (!get_data(vm, args[0], &data, &length)) { - return TA_VM_FAULT_MEMORY; + if (!get_file(args[0], &data, &length)) { + break; } - result = ta_image_init(data, length) ? 1 : 0; + result = ta_scene_image(data, length, (ta_fixed)args[1], (ta_fixed)args[2], (ta_fixed)args[3], (ta_fixed)args[4], (uint16_t)args[5]) ? 1 : 0; break; } - case TA_SYS_IMAGE_DRAW: { + case TA_SYS_IMAGE_INIT: { const uint8_t *data; uint32_t length; - if (!get_data(vm, args[0], &data, &length)) { - return TA_VM_FAULT_MEMORY; + if (!get_file(args[0], &data, &length)) { + break; } - result = ta_scene_image(data, length, args[1], args[2], args[3], args[4], (uint16_t)args[5]) ? 1 : 0; + result = ta_image_init(data, length) ? 1 : 0; break; } case TA_SYS_IMAGE_GET_SIZE: { const uint8_t *data; uint32_t length; - uint32_t width; - uint32_t height; + uint32_t *width; + uint32_t *height; - if (!get_data(vm, args[0], &data, &length)) { - return TA_VM_FAULT_MEMORY; - } - - if (!ta_image_get_size(data, length, &width, &height)) { + if (!get_file(args[0], &data, &length)) { break; } - if (!ta_vm_write32(vm, args[1], width) || !ta_vm_write32(vm, args[2], height)) { + width = (uint32_t *)ta_vm_translate_pointer(vm, args[1], sizeof(uint32_t)); + height = (uint32_t *)ta_vm_translate_pointer(vm, args[2], sizeof(uint32_t)); + + if (!width || !height) { return TA_VM_FAULT_MEMORY; } - result = 1; + result = ta_image_get_size(data, width, height) ? 1 : 0; break; } @@ -241,6 +244,11 @@ ta_vm_status ta_syscall(ta_vm *vm) { break; } + case TA_SYS_TEXT_CHANGE_COLOR: { + result = ta_text_change_color(text_get(args[0]), args[1]) ? 1 : 0; + + break; + } case TA_SYS_SCREEN_REGISTER: { result = ta_screen_register(args[0], args[1], args[2], args[3]) ? 1 : 0; @@ -272,8 +280,8 @@ ta_vm_status ta_syscall(ta_vm *vm) { const uint8_t *data; uint32_t length; - if (!get_data(vm, args[0], &data, &length)) { - return TA_VM_FAULT_MEMORY; + if (!get_file(args[0], &data, &length)) { + break; } result = ta_ft2_init(data, length) ? 1 : 0; @@ -295,6 +303,54 @@ ta_vm_status ta_syscall(ta_vm *vm) { break; } + case TA_SYS_FILE_SIZE: { + const uint8_t *data; + uint32_t length; + + result = get_file(args[0], &data, &length) ? length : 0xFFFFFFFFu; + + break; + } + case TA_SYS_FILE_READ: { + const uint8_t *data; + uint32_t length; + + if (!get_file(args[0], &data, &length)) { + break; + } + + if (length == 0) { + result = 1; + + break; + } + + uint8_t *destination = (uint8_t *)ta_vm_translate_pointer(vm, args[1], length); + + if (destination == NULL) { + return TA_VM_FAULT_MEMORY; + } + + for (uint32_t i = 0; i < length; i++) { + destination[i] = data[i]; + } + + result = 1; + + break; + } + case TA_SYS_FILE_EXEC: { + const uint8_t *data; + uint32_t length; + + if (!get_file(args[0], &data, &length) || length == 0) { + break; + } + + ta_vm_request_exec((uint8_t)args[0]); + + return TA_VM_YIELDED; + } default: { return TA_VM_FAULT_ILLEGAL; } diff --git a/src/tab.c b/src/tab.c @@ -0,0 +1,132 @@ +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include "tab.h" +#include "fs.h" +#include "api.h" + +typedef struct { + uint32_t offset; + uint32_t size; + bool present; +} ta_tab_entry; + +#ifdef TA_EMBED_GAME +extern unsigned char ta_game_tab[]; +extern unsigned int ta_game_tab_len; +#endif + +#ifdef TA_EMBED_GAME +extern unsigned char ta_game_tab[]; +extern unsigned int ta_game_tab_len; +#endif + +static ta_fs_file tab_file; +static bool embedded; +static ta_tab_entry entries[TA_TAB_MAX_FILES + 1]; +static bool loaded; + +static uint32_t read_le32(const uint8_t *data) { + return (uint32_t)data[0] | ((uint32_t)data[1] << 8) | ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); +} + +static bool parse(const uint8_t *data, size_t length) { + if (length < TA_TAB_HEADER_SIZE + TA_TAB_ENTRY_SIZE) { + return false; + } + + if (data[0] != TA_TAB_MAGIC_0 || data[1] != TA_TAB_MAGIC_1 || data[2] != TA_TAB_MAGIC_2 || data[3] != TA_TAB_MAGIC_3) { + return false; + } + + if (data[4] != TA_TAB_VERSION) { + return false; + } + + size_t position = TA_TAB_HEADER_SIZE; + + while (1) { + if (length - position < TA_TAB_ENTRY_SIZE) { + return false; + } + + uint8_t file = data[position]; + + if (file == TA_TAB_END) { + break; + } + + uint32_t size = read_le32(data + position + 1); + uint32_t offset = read_le32(data + position + 5); + + if (entries[file].present || offset > length || size > length - offset) { + return false; + } + + entries[file].offset = offset; + entries[file].size = size; + entries[file].present = true; + + position += TA_TAB_ENTRY_SIZE; + } + + return entries[TA_TAB_MAIN_PROGRAM].present; +} + +bool ta_tab_load(const char *path) { + ta_tab_unload(); + +#ifdef TA_EMBED_GAME + (void)path; + + tab_file.data = (char *)ta_game_tab; + tab_file.size = ta_game_tab_len; + embedded = true; +#else + tab_file = ta_read_file(path); +#endif + + if (tab_file.data == NULL) { + return false; + } + + if (!parse((const uint8_t *)tab_file.data, tab_file.size)) { + ta_tab_unload(); + + return false; + } + + loaded = true; + + return true; +} + +void ta_tab_unload(void) { + if (tab_file.data != NULL && !embedded) { + ta_close_file(&tab_file); + } + + embedded = false; + + tab_file.data = NULL; + tab_file.size = 0; + + for (uint32_t i = 0; i <= TA_TAB_MAX_FILES; i++) { + entries[i].offset = 0; + entries[i].size = 0; + entries[i].present = false; + } + + loaded = false; +} + +bool ta_tab_find(uint8_t file, const uint8_t **data, uint32_t *size) { + if (!loaded || file == TA_TAB_END || !entries[file].present) { + return false; + } + + *data = (const uint8_t *)tab_file.data + entries[file].offset; + *size = entries[file].size; + + return true; +} diff --git a/src/text.c b/src/text.c @@ -861,18 +861,41 @@ static void measure_units(const char *text, uint32_t *max_width, uint32_t *lines *lines = line_count; } +static uint32_t line_units(const char *text) { + uint32_t width = 0; + + for (; *text && *text != '\n'; text++) { + uint32_t character = (uint8_t)*text; + + if (printable(character)) { + width += advance_of(glyph_for(character)); + } + } + + return width; +} + +static int32_t line_offset(const char *text, uint32_t widest, int32_t scale) { + return (int32_t)(((int64_t)(widest - line_units(text)) * scale) >> 1); +} + static void draw_text_pass(const char *text, int32_t x, int32_t y, const ta_text_ctx *ctx) { int32_t scale = ctx->scale; int32_t ascent = (int32_t)((int64_t)font.ascent * scale); int32_t line_height = (int32_t)((int64_t)line_height_units() * scale); - int32_t pen_x = x * ONE; + uint32_t widest; + uint32_t lines; + + measure_units(text, &widest, &lines); + + int32_t pen_x = x * ONE + line_offset(text, widest, scale); int32_t baseline_y = y * ONE + ascent; for (; *text; text++) { uint32_t character = (uint8_t)*text; if (character == '\n') { - pen_x = x * ONE; + pen_x = x * ONE + line_offset(text + 1, widest, scale); baseline_y += line_height; if (baseline_y - ascent >= ctx->clip_y1 * ONE) { @@ -1058,6 +1081,41 @@ void ta_text_draw(ta_text *text) { } } +bool ta_text_change_color(ta_text *text, uint32_t color) { + if (!text || !text->sprite) { + return false; + } + + uint8_t red = (uint8_t)((color >> 16) & 255); + uint8_t green = (uint8_t)((color >> 8) & 255); + uint8_t blue = (uint8_t)(color & 255); + uint32_t old_rgb = ((uint32_t)text->red << 24) | ((uint32_t)text->green << 16) | ((uint32_t)text->blue << 8); + uint32_t new_rgb = ((uint32_t)red << 24) | ((uint32_t)green << 16) | ((uint32_t)blue << 8); + uint32_t *pixels = (uint32_t *)text->sprite->pixels; + size_t count = (size_t)text->sprite->width * (size_t)text->sprite->height; + bool bordered = text->border_width != 0; + + for (size_t i = 0; i < count; i++) { + uint32_t pixel = pixels[i]; + + if ((pixel & 255) == 0) { + continue; + } + + if (bordered && (pixel & 0xffffff00u) != old_rgb) { + continue; + } + + pixels[i] = new_rgb | (pixel & 255); + } + + text->red = red; + text->green = green; + text->blue = blue; + + return true; +} + void ta_text_destroy(ta_text *text) { if (!text) { return; diff --git a/src/title.c b/src/title.c @@ -1,3 +1,3 @@ #include "config.h" -const char *ta_title = "Tux�nci v" TA_VERSION; +const char *ta_title = "Tuxánci v" TA_VERSION; diff --git a/src/vm.c b/src/vm.c @@ -4,6 +4,9 @@ #include "syscall.h" #include "abi.h" #include "api.h" +#include "tab.h" +#include "screen.h" +#include "scene.h" #define OP_LOAD 0x03 #define OP_MISC_MEM 0x0F @@ -477,6 +480,8 @@ static uint32_t return_stub; static uint32_t call_result; static bool ready; static bool returned; +static bool exec_pending; +static uint8_t exec_file; bool ta_vm_running; static ta_vm_status guest_ecall(ta_vm *machine, void *user) { @@ -503,7 +508,7 @@ static ta_vm_status guest_ecall(ta_vm *machine, void *user) { return TA_VM_YIELDED; } default: { - return ta_syscall(machine); + return ta_syscall_handler(machine); } } } @@ -530,11 +535,6 @@ bool ta_vm_load(const uint8_t *binary, size_t size) { return false; } - if (binary[0] != 0x54 || binary[1] != 0x41 || - binary[2] != 0x42 || binary[3] != 0x43) { - return false; - } - ram = (uint8_t *)malloc(TA_VM_RAM_SIZE); if (!ram) { @@ -546,7 +546,7 @@ bool ta_vm_load(const uint8_t *binary, size_t size) { } ta_vm_init(&guest, ram, TA_VM_RAM_SIZE, guest_ecall, NULL); - guest.pc = 4; + guest.pc = 0; guest_status = TA_VM_RUNNING; exit_code = 0; ready = false; @@ -555,6 +555,12 @@ bool ta_vm_load(const uint8_t *binary, size_t size) { guest_status = ta_vm_run(&guest, TA_VM_STEPS_PER_CALL); + if (guest_status == TA_VM_YIELDED && exec_pending) { + finish_run(true); + + return true; + } + if (guest_status != TA_VM_YIELDED || !ready) { finish_run(false); ta_vm_unload(); @@ -567,18 +573,56 @@ bool ta_vm_load(const uint8_t *binary, size_t size) { return true; } -bool ta_vm_load_file(const char *path) { - ta_fs_file file = ta_read_file(path); +bool ta_vm_load_tab(const char *path) { + if (!ta_tab_load(path)) { + return false; + } + + const uint8_t *data; + uint32_t size; - if (!file.data) { + if (!ta_tab_find(TA_TAB_MAIN_PROGRAM, &data, &size)) { return false; } - bool ok = ta_vm_load((const uint8_t *)file.data, file.size); + return ta_vm_load(data, size); +} - ta_close_file(&file); +void ta_vm_request_exec(uint8_t file) { + exec_file = file; + exec_pending = true; +} - return ok; +bool ta_vm_exec_pending(void) { + return exec_pending; +} + +bool ta_vm_exec_apply(void) { + while (exec_pending) { + const uint8_t *data; + uint32_t size; + uint8_t file = exec_file; + + exec_pending = false; + + if (!ta_tab_find(file, &data, &size)) { + ta_vm_unload(); + exit_code = 1; + + return false; + } + + ta_screen_init(); + ta_scene_invalidate(); + + if (!ta_vm_load(data, size)) { + exit_code = 1; + + return false; + } + } + + return ta_vm_running; } bool ta_vm_call(uint32_t function, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t *result) { @@ -595,6 +639,12 @@ bool ta_vm_call(uint32_t function, uint32_t arg0, uint32_t arg1, uint32_t arg2, guest_status = ta_vm_run(&guest, TA_VM_STEPS_PER_CALL); + if (guest_status == TA_VM_YIELDED && exec_pending) { + finish_run(true); + + return false; + } + bool completed = guest_status == TA_VM_YIELDED && returned; finish_run(completed); @@ -620,6 +670,7 @@ void ta_vm_unload(void) { ready = false; returned = false; + exec_pending = false; guest_status = TA_VM_HALTED; ta_vm_running = false; }