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.
This commit is contained in:
Nunuhara Cabbage
2019-11-07 19:26:58 -08:00
parent 14dd027ef1
commit 1e3fbcd95f
7 changed files with 145 additions and 92 deletions
+3 -1
View File
@@ -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;
+59 -43
View File
@@ -1,6 +1,4 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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) {
+40
View File
@@ -0,0 +1,40 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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 <http://gnu.org/licenses/>.
*/
#include <stdio.h>
#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
};
+15 -15
View File
@@ -1,6 +1,4 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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 */
+3 -2
View File
@@ -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])
+23 -30
View File
@@ -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);
}
}
+2 -1
View File
@@ -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 {