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:
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 = ®isters[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;
}