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 {