From 1e3fbcd95f4d09396cdd46abc91cc80a754a9b13 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Thu, 7 Nov 2019 19:26:58 -0800 Subject: [PATCH] Change HLL calling convention ...and add OutputLog.dll stubs. The calling convention no longer has HLL functions reaching into the stack. The previous implementation didn't even work since the return value could overwrite an argument that needed to be freed. --- ain.h | 4 +- hll/{math.c => Math.c} | 102 ++++++++++++++++++++++++----------------- hll/OutputLog.c | 40 ++++++++++++++++ hll/hll.h | 30 ++++++------ meson.build | 5 +- vm.c | 53 ++++++++++----------- vm.h | 3 +- 7 files changed, 145 insertions(+), 92 deletions(-) rename hll/{math.c => Math.c} (55%) create mode 100644 hll/OutputLog.c diff --git a/ain.h b/ain.h index 1c8543f..c4101fe 100644 --- a/ain.h +++ b/ain.h @@ -147,9 +147,11 @@ struct ain_hll_argument { int32_t data_type; }; +union vm_value; + struct ain_hll_function { char *name; - void (*fun)(void); + union vm_value (*fun)(union vm_value *args); int32_t data_type; int32_t nr_arguments; struct ain_hll_argument *arguments; diff --git a/hll/math.c b/hll/Math.c similarity index 55% rename from hll/math.c rename to hll/Math.c index 40e570d..d3dcb81 100644 --- a/hll/math.c +++ b/hll/Math.c @@ -1,6 +1,4 @@ /* Copyright (C) 2019 Nunuhara Cabbage - * - * Credit to SLC for reverse engineering AIN formats. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,86 +25,104 @@ static inline float deg2rad(float deg) return deg * (M_PI / 180.0); } -hll_defun(Cos) { - hll_return(cosf(deg2rad(hll_arg(0).f))); +hll_defun(Cos, args) +{ + hll_return(cosf(deg2rad(args[0].f))); } -hll_defun(Sin) { - hll_return(sinf(deg2rad(hll_arg(0).f))); +hll_defun(Sin, args) +{ + hll_return(sinf(deg2rad(args[0].f))); } -hll_defun(Sqrt) { - hll_return(sqrtf(hll_arg(0).f)); +hll_defun(Sqrt, args) +{ + hll_return(sqrtf(args[0].f)); } -hll_defun(Atan) { - hll_return(atanf(hll_arg(0).f)); +hll_defun(Atan, args) +{ + hll_return(atanf(args[0].f)); } -hll_defun(Atan2) { - hll_return(atan2f(hll_arg(0).f, hll_arg(1).f)); +hll_defun(Atan2, args) +{ + hll_return(atan2f(args[0].f, args[1].f)); } -hll_defun(Abs) { - hll_return(abs(hll_arg(0).i)); +hll_defun(Abs, args) +{ + hll_return(abs(args[0].i)); } -hll_defun(AbsF) { - hll_return(fabsf(hll_arg(0).f)); +hll_defun(AbsF, args) +{ + hll_return(fabsf(args[0].f)); } -hll_defun(Pow) { - hll_return(powf(hll_arg(0).f, hll_arg(1).f)); +hll_defun(Pow, args) +{ + hll_return(powf(args[0].f, args[1].f)); } -hll_defun(SetSeed) { - srand(hll_arg(0).i); +hll_defun(SetSeed, args) +{ + srand(args[0].i); hll_return(0); } -hll_unimplemented(SetRandMode) +hll_unimplemented(Math, SetRandMode) -hll_defun(Rand) { +hll_defun(Rand, args) +{ hll_return(rand()); } // TODO -hll_unimplemented(RandF) -hll_unimplemented(RandTableInit) -hll_unimplemented(RandTable) -hll_unimplemented(RandTable2Init) -hll_unimplemented(RandTable2) +hll_unimplemented(Math, RandF) +hll_unimplemented(Math, RandTableInit) +hll_unimplemented(Math, RandTable) +hll_unimplemented(Math, RandTable2Init) +hll_unimplemented(Math, RandTable2) -hll_defun(Min) { - int a = hll_arg(0).i, b = hll_arg(1).i; +hll_defun(Min, args) +{ + int a = args[0].i, b = args[1].i; hll_return(a < b ? a : b); } -hll_defun(MinF) { - float a = hll_arg(0).f, b = hll_arg(1).f; +hll_defun(MinF, args) +{ + float a = args[0].f, b = args[1].f; hll_return(a < b ? a : b); } -hll_defun(Max) { - int a = hll_arg(0).i, b = hll_arg(1).i; +hll_defun(Max, args) +{ + int a = args[0].i, b = args[1].i; hll_return(a > b ? a : b); } -hll_defun(MaxF) { - float a = hll_arg(0).f, b = hll_arg(1).f; +hll_defun(MaxF, args) +{ + float a = args[0].f, b = args[1].f; hll_return(a > b ? a : b); } -hll_defun(Swap) { - int tmp = *hll_arg(0).iref; - *hll_arg(0).iref = *hll_arg(1).iref; - *hll_arg(1).iref = tmp; +hll_defun(Swap, args) +{ + int tmp = *args[0].iref; + *args[0].iref = *args[1].iref; + *args[1].iref = tmp; + hll_return(0); } -hll_defun(SwapF) { - float tmp = *hll_arg(0).fref; - *hll_arg(0).fref = *hll_arg(1).fref; - *hll_arg(1).fref = tmp; +hll_defun(SwapF, args) +{ + float tmp = *args[0].fref; + *args[0].fref = *args[1].fref; + *args[1].fref = tmp; + hll_return(0); } hll_deflib(Math) { diff --git a/hll/OutputLog.c b/hll/OutputLog.c new file mode 100644 index 0000000..3381973 --- /dev/null +++ b/hll/OutputLog.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include "hll.h" + +hll_warn_unimplemented(OutputLog, Create) + +hll_defun(Output, args) { + printf("%s", heap[args[1].i].s->text); + hll_return(0); +} + +hll_warn_unimplemented(OutputLog, Clear) +hll_warn_unimplemented(OutputLog, Save) +hll_warn_unimplemented(OutputLog, EnableAutoSave) +hll_warn_unimplemented(OutputLog, DisableAutoSave) + +hll_deflib(OutputLog) { + hll_export(Create), + hll_export(Output), + hll_export(Clear), + hll_export(Save), + hll_export(EnableAutoSave), + hll_export(DisableAutoSave), + NULL +}; diff --git a/hll/hll.h b/hll/hll.h index 2d44d92..9a5aa86 100644 --- a/hll/hll.h +++ b/hll/hll.h @@ -1,6 +1,4 @@ /* Copyright (C) 2019 Nunuhara Cabbage - * - * Credit to SLC for reverse engineering AIN formats. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,23 +18,30 @@ #define SYSTEM4_HLL_H /* - * DSL for implementing for implementing libraries. + * DSL for implementing libraries. */ #include "../vm.h" #include "../page.h" +#include "../system4.h" -#define hll_defun(fname) \ - static void _hllfun_ ## fname(void); \ +#define hll_defun(fname, args) \ + static union vm_value _hllfun_ ## fname(unused union vm_value *args); \ static struct hll_function _hllstruct_ ## fname = { \ .name = #fname, \ .fun = _hllfun_ ## fname \ }; \ - static void _hllfun_ ## fname(void) + static union vm_value _hllfun_ ## fname(unused union vm_value *args) -#define hll_unimplemented(fname) \ - hll_defun(fname) { \ - ERROR("Unimplemented HLL function: " #fname); \ +#define hll_unimplemented(libname, fname) \ + hll_defun(fname, args) { \ + ERROR("Unimplemented HLL function: " #libname "." #fname); \ + } + +#define hll_warn_unimplemented(libname, fname) \ + hll_defun(fname, args) { \ + WARNING("Unimplemented HLL function: " #libname "." #fname); \ + hll_return(0); \ } #define hll_export(fname) &_hllstruct_ ## fname @@ -49,11 +54,6 @@ }; \ static struct hll_function *_lib_ ## lname[] = -#define hll_return(v) stack_push(vm_value_cast(v)) - -static inline union vm_value hll_arg(int n) -{ - return stack[stack_ptr + n]; -} +#define hll_return(v) return vm_value_cast(v) #endif /* SYSTEM4_HLL_H */ diff --git a/meson.build b/meson.build index b841ccc..9d414d3 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,8 @@ project('system4', 'c', default_options : ['c_std=c11']) -system4 = ['system4.c', 'ain.c', 'instructions.c', 'vm.c', 'string.c', 'page.c', 'utfsjis.c', 'hll/math.c'] +system4 = ['system4.c', 'ain.c', 'instructions.c', 'vm.c', 'string.c', 'page.c', 'utfsjis.c'] +hll_libs = ['hll/Math.c', 'hll/OutputLog.c'] zdep = dependency('zlib') mdep = meson.get_compiler('c').find_library('m', required: false) -executable('system4', system4, dependencies: [mdep, zdep]) +executable('system4', system4 + hll_libs, dependencies: [mdep, zdep]) diff --git a/vm.c b/vm.c index f565f7a..63bf7d1 100644 --- a/vm.c +++ b/vm.c @@ -29,6 +29,7 @@ #define INITIAL_STACK_SIZE 1024 #define INITIAL_HEAP_SIZE 4096 #define INITIAL_PAGES_SIZE 4096 +#define HLL_MAX_ARGS 64 // When the IP is set to VM_RETURN, the VM halts #define VM_RETURN 0xFFFFFFFF @@ -158,9 +159,9 @@ static union vm_value *local_page(void) return heap[local_page_slot()].page->values; } -static int32_t local_get(int varno) +static union vm_value local_get(int varno) { - return local_page()[varno].i; + return local_page()[varno]; } static void local_set(int varno, int32_t value) @@ -173,9 +174,9 @@ static union vm_value *local_ptr(int varno) return local_page() + varno; } -static int32_t global_get(int varno) +static union vm_value global_get(int varno) { - return heap[0].page->values[varno].i; + return heap[0].page->values[varno]; } static int32_t struct_page_slot(void) @@ -311,41 +312,29 @@ static void hll_call(int libno, int fno) if (!f->fun) EXECUTION_ERROR("Unimplemented HLL function: %s.%s", ain->libraries[libno].name, f->name); - // convert non-heap ref types to pointers + union vm_value args[HLL_MAX_ARGS]; for (int i = f->nr_arguments - 1; i >= 0; i--) { + int pageno, varno; switch(f->arguments[i].data_type) { case AIN_REF_INT: case AIN_REF_BOOL: case AIN_REF_FLOAT: stack_ptr -= 2; + pageno = stack[stack_ptr].i; + varno = stack[stack_ptr+1].i; + args[i].ref = &heap[pageno].page->values[varno]; break; default: stack_ptr--; + args[i] = stack[stack_ptr]; } } - for (int i = 0, src = 0; i < f->nr_arguments; i++, src++) { - int pageno, varno; - switch (f->arguments[i].data_type) { - case AIN_REF_INT: - case AIN_REF_BOOL: - pageno = stack[stack_ptr+src].i; - varno = stack[stack_ptr+src+1].i; - stack[stack_ptr+i].iref = &heap[pageno].page->values[varno].i; - src++; - break; - case AIN_REF_FLOAT: - pageno = stack[stack_ptr+src].i; - varno = stack[stack_ptr+src+1].i; - stack[stack_ptr+i].fref = &heap[pageno].page->values[varno].f; - src++; - break; - } - } - - f->fun(); + union vm_value r = f->fun(args); for (int i = 0; i < f->nr_arguments; i++) { variable_fini(stack[stack_ptr + i], f->arguments[i].data_type); } + if (f->data_type != AIN_VOID) + stack_push(r); } static void function_return(void) @@ -507,10 +496,10 @@ static void execute_instruction(int16_t opcode) stack_push(val); break; case SH_GLOBALREF: // VARNO - stack_push(global_get(get_argument(0))); + stack_push(global_get(get_argument(0)).i); break; case SH_LOCALREF: // VARNO - stack_push(local_get(get_argument(0))); + stack_push(local_get(get_argument(0)).i); break; case SH_STRUCTREF: // VARNO stack_push(struct_page()[get_argument(0)]); @@ -520,14 +509,14 @@ static void execute_instruction(int16_t opcode) break; case SH_LOCALINC: // VARNO varno = get_argument(0); - local_set(varno, local_get(varno)+1); + local_set(varno, local_get(varno).i+1); break; case SH_LOCALDEC: // VARNO varno = get_argument(0); - local_set(varno, local_get(varno)-1); + local_set(varno, local_get(varno).i-1); break; case SH_LOCALDELETE: - if ((slot = local_get(get_argument(0))) != -1) { + if ((slot = local_get(get_argument(0)).i) != -1) { heap_unref(slot); local_set(get_argument(0), -1); } @@ -1075,9 +1064,11 @@ static void vm_execute(void) } extern struct library lib_Math; +extern struct library lib_OutputLog; struct library *libraries[] = { &lib_Math, + &lib_OutputLog, NULL }; @@ -1094,6 +1085,8 @@ static void link_library(struct ain_library *ainlib, struct library *lib) } if (!linked) WARNING("Unimplemented library function: %s", ainlib->functions[i].name); + else if (ainlib->functions[i].nr_arguments >= HLL_MAX_ARGS) + ERROR("Too many arguments to library function: %s", ainlib->functions[i].name); } } diff --git a/vm.h b/vm.h index 0268578..54f59d1 100644 --- a/vm.h +++ b/vm.h @@ -26,6 +26,7 @@ union vm_value { int64_t i64; float f; // HLL only + void *ref; int *iref; float *fref; }; @@ -53,7 +54,7 @@ struct vm_pointer { struct hll_function { char *name; - void (*fun)(void); + union vm_value (*fun)(union vm_value *_args); }; struct library {