mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-11 08:48:16 +03:00
aindump: improve disassembler output
Replace many instruction arguments with names/values (strings/messages, local/global variables, structs, functions, etc.) and add labels to jump targets.
This commit is contained in:
@@ -208,6 +208,7 @@ struct ain {
|
||||
int32_t msgf;
|
||||
int32_t nr_libraries;
|
||||
struct ain_library *libraries;
|
||||
int32_t nr_switches;
|
||||
struct ain_switch *switches;
|
||||
int32_t game_version;
|
||||
int32_t nr_strings;
|
||||
@@ -217,6 +218,7 @@ struct ain {
|
||||
int32_t ojmp;
|
||||
int nr_function_types;
|
||||
struct ain_function_type *function_types;
|
||||
int nr_delegates;
|
||||
struct ain_function_type *delegates;
|
||||
int32_t nr_global_groups;
|
||||
char **global_group_names;
|
||||
|
||||
@@ -24,6 +24,35 @@
|
||||
|
||||
#define INSTRUCTION_MAX_ARGS 4 // FIXME: determine the real maximum
|
||||
|
||||
enum syscall_code {
|
||||
SYS_EXIT = 0x00,
|
||||
SYS_GLOBAL_SAVE = 0x01,
|
||||
SYS_GLOBAL_LOAD = 0x02,
|
||||
SYS_LOCK_PEEK = 0x03,
|
||||
SYS_UNLOCK_PEEK = 0x04,
|
||||
SYS_RESET = 0x05,
|
||||
SYS_OUTPUT = 0x06,
|
||||
SYS_MSGBOX = 0x07,
|
||||
SYS_RESUME_SAVE = 0x08,
|
||||
SYS_RESUME_LOAD = 0x09,
|
||||
SYS_EXISTS_FILE = 0x0A,
|
||||
SYS_OPEN_WEB = 0x0B,
|
||||
SYS_GET_SAVE_FOLDER_NAME = 0x0C,
|
||||
SYS_GET_TIME = 0x0D,
|
||||
SYS_ERROR = 0x0F,
|
||||
SYS_EXISTS_SAVE_FILE = 0x10,
|
||||
SYS_IS_DEBUG_MODE = 0x11,
|
||||
SYS_MSGBOX_OK_CANCEL = 0x12,
|
||||
SYS_GET_FUNC_STACK_NAME = 0x13,
|
||||
SYS_PEEK = 0x14,
|
||||
SYS_SLEEP = 0x15,
|
||||
SYS_GROUP_SAVE = 0x18,
|
||||
SYS_GROUP_LOAD = 0x19,
|
||||
NR_SYSCALLS
|
||||
};
|
||||
|
||||
const char * const syscalls[NR_SYSCALLS];
|
||||
|
||||
enum opcode
|
||||
{
|
||||
PUSH = 0x00,
|
||||
@@ -290,12 +319,19 @@ enum opcode
|
||||
};
|
||||
|
||||
enum instruction_argtype {
|
||||
INSTR_INT = 0,
|
||||
INSTR_FLO,
|
||||
INSTR_PTR,
|
||||
INSTR_FUN,
|
||||
INSTR_STR,
|
||||
INSTR_FILE
|
||||
T_INT,
|
||||
T_FLOAT,
|
||||
T_ADDR,
|
||||
T_FUNC,
|
||||
T_STRING,
|
||||
T_MSG,
|
||||
T_LOCAL,
|
||||
T_GLOBAL,
|
||||
T_STRUCT,
|
||||
T_SYSCALL,
|
||||
T_HLL,
|
||||
T_HLLFUNC,
|
||||
T_FILE,
|
||||
};
|
||||
|
||||
struct instruction {
|
||||
|
||||
@@ -475,8 +475,8 @@ static bool read_tag(struct ain_reader *r, struct ain *ain)
|
||||
ain->nr_libraries = read_int32(r);
|
||||
ain->libraries = read_libraries(r, ain->nr_libraries);
|
||||
} else if (TAG_EQ("SWI0")) {
|
||||
int32_t count = read_int32(r);
|
||||
ain->switches = read_switches(r, count);
|
||||
ain->nr_switches = read_int32(r);
|
||||
ain->switches = read_switches(r, ain->nr_switches);
|
||||
} else if (TAG_EQ("GVER")) {
|
||||
ain->game_version = read_int32(r);
|
||||
} else if (TAG_EQ("STR0")) {
|
||||
@@ -493,8 +493,8 @@ static bool read_tag(struct ain_reader *r, struct ain *ain)
|
||||
ain->function_types = read_function_types(r, ain->nr_function_types, ain);
|
||||
} else if (TAG_EQ("DELG")) {
|
||||
read_int32(r); // ???
|
||||
int32_t count = read_int32(r);
|
||||
ain->delegates = read_function_types(r, count, ain);
|
||||
ain->nr_delegates = read_int32(r);
|
||||
ain->delegates = read_function_types(r, ain->nr_delegates, ain);
|
||||
} else if (TAG_EQ("OBJG")) {
|
||||
ain->nr_global_groups = read_int32(r);
|
||||
ain->global_group_names = read_strings(r, ain->nr_global_groups);
|
||||
@@ -655,7 +655,96 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ain_free_variables(struct ain_variable *vars, int nr_vars)
|
||||
{
|
||||
for (int i = 0; i < nr_vars; i++) {
|
||||
free(vars[i].name);
|
||||
free(vars[i].name2);
|
||||
}
|
||||
free(vars);
|
||||
}
|
||||
|
||||
static void ain_free_function_types(struct ain_function_type *funs, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(funs[i].name);
|
||||
ain_free_variables(funs[i].variables, funs[i].nr_variables);
|
||||
}
|
||||
free(funs);
|
||||
}
|
||||
|
||||
static void ain_free_strings(struct string **strings, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
free_string(strings[i]);
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
static void ain_free_cstrings(char **strings, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(strings[i]);
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
void ain_free(struct ain *ain)
|
||||
{
|
||||
free(ain->code);
|
||||
|
||||
for (int f = 0; f < ain->nr_functions; f++) {
|
||||
free(ain->functions[f].name);
|
||||
ain_free_variables(ain->functions[f].vars, ain->functions[f].nr_vars);
|
||||
}
|
||||
free(ain->functions);
|
||||
|
||||
for (int i = 0; i < ain->nr_globals; i++) {
|
||||
free(ain->globals[i].name);
|
||||
free(ain->globals[i].name2);
|
||||
}
|
||||
free(ain->globals);
|
||||
|
||||
for (int i = 0; i < ain->nr_initvals; i++) {
|
||||
if (ain->global_initvals[i].data_type != AIN_STRING)
|
||||
continue;
|
||||
free(ain->global_initvals[i].string_value);
|
||||
}
|
||||
free(ain->global_initvals);
|
||||
|
||||
for (int s = 0; s < ain->nr_structures; s++) {
|
||||
free(ain->structures[s].name);
|
||||
ain_free_variables(ain->structures[s].members, ain->structures[s].nr_members);
|
||||
}
|
||||
free(ain->structures);
|
||||
|
||||
for (int lib = 0; lib < ain->nr_libraries; lib++) {
|
||||
free(ain->libraries[lib].name);
|
||||
for (int f = 0; f < ain->libraries[lib].nr_functions; f++) {
|
||||
free(ain->libraries[lib].functions[f].name);
|
||||
for (int a = 0; a < ain->libraries[lib].functions[f].nr_arguments; a++) {
|
||||
free(ain->libraries[lib].functions[f].arguments[a].name);
|
||||
}
|
||||
free(ain->libraries[lib].functions[f].arguments);
|
||||
}
|
||||
free(ain->libraries[lib].functions);
|
||||
}
|
||||
free(ain->libraries);
|
||||
|
||||
for (int i = 0; i < ain->nr_switches; i++) {
|
||||
free(ain->switches[i].cases);
|
||||
}
|
||||
free(ain->switches);
|
||||
|
||||
ain_free_function_types(ain->function_types, ain->nr_function_types);
|
||||
ain_free_function_types(ain->delegates, ain->nr_delegates);
|
||||
|
||||
ain_free_strings(ain->strings, ain->nr_strings);
|
||||
ain_free_strings(ain->messages, ain->nr_messages);
|
||||
|
||||
ain_free_cstrings(ain->filenames, ain->nr_filenames);
|
||||
ain_free_cstrings(ain->global_group_names, ain->nr_global_groups);
|
||||
ain_free_cstrings(ain->enums, ain->nr_enums);
|
||||
|
||||
free(ain);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
|
||||
void disassemble_ain(struct ain *ain, FILE *out);
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
puts("Usage: aindump <options> <ainfile>");
|
||||
@@ -56,20 +58,6 @@ static void ain_dump_version(struct ain *ain)
|
||||
printf("AIN VERSION %d\n", ain->version);
|
||||
}
|
||||
|
||||
static void ain_dump_code(struct ain *ain)
|
||||
{
|
||||
for (size_t i = 0; i < ain->code_size;) {
|
||||
uint16_t opcode = LittleEndian_getW(ain->code, i);
|
||||
const struct instruction *instr = &instructions[opcode];
|
||||
printf("%s", instr->name);
|
||||
for (int j = 0; j < instr->nr_args; j++) {
|
||||
printf(" 0x%x", LittleEndian_getDW(ain->code, i + 2 + j*4));
|
||||
}
|
||||
putchar('\n');
|
||||
i += instruction_width(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_arglist(struct ain *ain, struct ain_variable *args, int nr_args)
|
||||
{
|
||||
if (!nr_args) {
|
||||
@@ -342,5 +330,7 @@ int main(int argc, char *argv[])
|
||||
if (dump_enums)
|
||||
ain_dump_enums(ain);
|
||||
if (dump_code)
|
||||
ain_dump_code(ain);
|
||||
disassemble_ain(ain, stdout);
|
||||
|
||||
ain_free(ain);
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/* 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 <string.h>
|
||||
#include "little_endian.h"
|
||||
#include "system4/ain.h"
|
||||
#include "system4/instructions.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
|
||||
#define DASM_ERROR(dasm, fmt, ...) ERROR("At 0x%x: " fmt, dasm->addr, ##__VA_ARGS__)
|
||||
|
||||
struct dasm_state {
|
||||
struct ain *ain;
|
||||
FILE *out;
|
||||
size_t addr;
|
||||
int func;
|
||||
};
|
||||
|
||||
#define NR_LABEL_BUCKETS 128
|
||||
|
||||
struct label {
|
||||
char *name;
|
||||
size_t addr;
|
||||
};
|
||||
|
||||
struct label_bucket {
|
||||
int nr_labels;
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
struct label_bucket label_table[NR_LABEL_BUCKETS];
|
||||
|
||||
static struct label_bucket *get_bucket(size_t addr)
|
||||
{
|
||||
return &label_table[(addr>>4) % NR_LABEL_BUCKETS];
|
||||
}
|
||||
|
||||
static char *get_label(size_t addr)
|
||||
{
|
||||
struct label_bucket *bucket = get_bucket(addr);
|
||||
for (int i = 0; i < bucket->nr_labels; i++) {
|
||||
if (bucket->labels[i].addr == addr)
|
||||
return bucket->labels[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_label(char *name, size_t addr)
|
||||
{
|
||||
// NOTE: first registered label takes precedence
|
||||
if (get_label(addr)) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
struct label_bucket *bucket = get_bucket(addr);
|
||||
int n = bucket->nr_labels;
|
||||
|
||||
bucket->labels = xrealloc(bucket->labels, sizeof(struct label) * (n + 1));
|
||||
bucket->nr_labels = n+1;
|
||||
|
||||
bucket->labels[n].name = name;
|
||||
bucket->labels[n].addr = addr;
|
||||
}
|
||||
|
||||
union float_cast {
|
||||
int32_t i;
|
||||
float f;
|
||||
};
|
||||
|
||||
static float arg_to_float(int32_t arg)
|
||||
{
|
||||
union float_cast v;
|
||||
v.i = arg;
|
||||
return v.f;
|
||||
}
|
||||
|
||||
static void print_sjis(struct dasm_state *dasm, const char *s)
|
||||
{
|
||||
char *u = sjis2utf(s, strlen(s));
|
||||
fprintf(dasm->out, "%s", u);
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void print_string(struct dasm_state *dasm, struct string *s)
|
||||
{
|
||||
int i, escapes = 0;
|
||||
char *u = sjis2utf(s->text, s->size);
|
||||
|
||||
// check for characters that need escaping
|
||||
for (i = 0; u[i]; i++) {
|
||||
if (u[i] == '"' || u[i] == '\n') {
|
||||
escapes++;
|
||||
}
|
||||
}
|
||||
|
||||
// add backslash escapes
|
||||
if (escapes > 0) {
|
||||
int j = 0;
|
||||
char *tmp = xmalloc(i + escapes + 1);
|
||||
for (int i = 0; u[i];) {
|
||||
if (u[i] == '"') {
|
||||
tmp[j++] = '\\';
|
||||
tmp[j++] = u[i++];
|
||||
} else if (u[i] == '\n') {
|
||||
tmp[j++] = '\\';
|
||||
tmp[j++] = 'n';
|
||||
i++;
|
||||
} else {
|
||||
tmp[j++] = u[i++];
|
||||
}
|
||||
}
|
||||
tmp[i+escapes] = '\0';
|
||||
free(u);
|
||||
u = tmp;
|
||||
}
|
||||
|
||||
fprintf(dasm->out, "\"%s\"", u);
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void print_argument(struct dasm_state *dasm, int32_t arg, enum instruction_argtype type)
|
||||
{
|
||||
char *label;
|
||||
struct ain *ain = dasm->ain;
|
||||
switch (type) {
|
||||
case T_INT:
|
||||
fprintf(dasm->out, "0x%x", arg);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
fprintf(dasm->out, "%f", arg_to_float(arg));
|
||||
break;
|
||||
case T_ADDR:
|
||||
label = get_label(arg);
|
||||
if (!label) {
|
||||
WARNING("No label generated for address: 0x%x", arg);
|
||||
fprintf(dasm->out, "0x%x", arg);
|
||||
} else {
|
||||
fprintf(dasm->out, "%s", label);
|
||||
}
|
||||
break;
|
||||
case T_FUNC:
|
||||
if (arg < 0 || arg >= ain->nr_functions)
|
||||
DASM_ERROR(dasm, "Invalid function number: %d", arg);
|
||||
print_sjis(dasm, ain->functions[arg].name);
|
||||
break;
|
||||
case T_STRING:
|
||||
if (arg < 0 || arg >= ain->nr_strings)
|
||||
DASM_ERROR(dasm, "Invalid string number: %d", arg);
|
||||
print_string(dasm, ain->strings[arg]);
|
||||
break;
|
||||
case T_MSG:
|
||||
if (arg < 0 || arg >= ain->nr_messages)
|
||||
DASM_ERROR(dasm, "Invalid message number: %d", arg);
|
||||
print_string(dasm, ain->messages[arg]);
|
||||
break;
|
||||
case T_LOCAL:
|
||||
if (dasm->func < 0)
|
||||
DASM_ERROR(dasm, "Attempt to access local variable outside of function");
|
||||
if (arg < 0 || arg >= ain->functions[dasm->func].nr_vars)
|
||||
DASM_ERROR(dasm, "Invalid variable number: %d", arg);
|
||||
print_sjis(dasm, ain->functions[dasm->func].vars[arg].name);
|
||||
break;
|
||||
case T_GLOBAL:
|
||||
if (arg < 0 || arg >= ain->nr_globals)
|
||||
DASM_ERROR(dasm, "Invalid global number: %d", arg);
|
||||
print_sjis(dasm, ain->globals[arg].name);
|
||||
break;
|
||||
case T_STRUCT:
|
||||
if (arg < 0 || arg >= ain->nr_structures)
|
||||
DASM_ERROR(dasm, "Invalid struct number: %d", arg);
|
||||
print_sjis(dasm, ain->structures[arg].name);
|
||||
break;
|
||||
case T_SYSCALL:
|
||||
if (arg < 0 || arg >= NR_SYSCALLS || !syscalls[arg])
|
||||
DASM_ERROR(dasm, "Invalid/unknown syscall number: %d", arg);
|
||||
fprintf(dasm->out, "%s", syscalls[arg]);
|
||||
break;
|
||||
case T_HLL:
|
||||
if (arg < 0 || arg >= ain->nr_libraries)
|
||||
DASM_ERROR(dasm, "Invalid HLL library number: %d", arg);
|
||||
print_sjis(dasm, ain->libraries[arg].name);
|
||||
break;
|
||||
case T_HLLFUNC:
|
||||
fprintf(dasm->out, "0x%x", arg);
|
||||
break;
|
||||
case T_FILE:
|
||||
if (arg < 0 || arg >= ain->nr_filenames)
|
||||
DASM_ERROR(dasm, "Invalid file number: %d", arg);
|
||||
print_sjis(dasm, ain->filenames[arg]);
|
||||
break;
|
||||
default:
|
||||
fprintf(dasm->out, "<UNKNOWN ARG TYPE?>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_arguments(struct dasm_state *dasm, const struct instruction *instr)
|
||||
{
|
||||
if (instr->opcode == CALLHLL) {
|
||||
int32_t lib = LittleEndian_getDW(dasm->ain->code, dasm->addr + 2);
|
||||
int32_t fun = LittleEndian_getDW(dasm->ain->code, dasm->addr + 6);
|
||||
fprintf(dasm->out, " %s.%s", dasm->ain->libraries[lib].name, dasm->ain->libraries[lib].functions[fun].name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < instr->nr_args; i++) {
|
||||
fputc(' ', dasm->out);
|
||||
print_argument(dasm, LittleEndian_getDW(dasm->ain->code, dasm->addr + 2 + i*4), instr->args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_instruction(struct dasm_state *dasm, const struct instruction *instr)
|
||||
{
|
||||
switch (instr->opcode) {
|
||||
case FUNC:
|
||||
dasm->func = LittleEndian_getDW(dasm->ain->code, dasm->addr + 2);
|
||||
if (dasm->func < 0 || dasm->func >= dasm->ain->nr_functions)
|
||||
DASM_ERROR(dasm, "Invalid function number: %d", dasm->func);
|
||||
break;
|
||||
case ENDFUNC:
|
||||
dasm->func = -1;
|
||||
break;
|
||||
case _EOF:
|
||||
break;
|
||||
default:
|
||||
fputc('\t', dasm->out);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(dasm->out, "%s", instr->name);
|
||||
print_arguments(dasm, instr);
|
||||
fputc('\n', dasm->out);
|
||||
}
|
||||
|
||||
static const struct instruction *get_instruction(struct dasm_state *dasm)
|
||||
{
|
||||
uint16_t opcode = LittleEndian_getW(dasm->ain->code, dasm->addr);
|
||||
const struct instruction *instr = &instructions[opcode];
|
||||
if (opcode >= NR_OPCODES)
|
||||
DASM_ERROR(dasm, "Unknown/invalid opcode: %u", opcode);
|
||||
if (dasm->addr + instr->nr_args * 4 >= dasm->ain->code_size)
|
||||
DASM_ERROR(dasm, "CODE section truncated?");
|
||||
return instr;
|
||||
}
|
||||
|
||||
static char *genlabel(size_t addr)
|
||||
{
|
||||
char name[64];
|
||||
snprintf(name, 64, "0x%lx", addr);
|
||||
return strdup(name);
|
||||
}
|
||||
|
||||
void disassemble_ain(struct ain *ain, FILE *out)
|
||||
{
|
||||
struct dasm_state dasm = {
|
||||
.ain = ain,
|
||||
.out = out,
|
||||
.addr = 0,
|
||||
.func = -1
|
||||
};
|
||||
|
||||
// first pass to generate labels
|
||||
for (dasm.addr = 0; dasm.addr < dasm.ain->code_size;) {
|
||||
const struct instruction *instr = get_instruction(&dasm);
|
||||
switch (instr->opcode) {
|
||||
case JUMP:
|
||||
case IFZ:
|
||||
case IFNZ: {
|
||||
int32_t arg = LittleEndian_getDW(dasm.ain->code, dasm.addr + 2);
|
||||
add_label(genlabel(arg), arg);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
dasm.addr += instruction_width(instr->opcode);
|
||||
}
|
||||
|
||||
for (dasm.addr = 0; dasm.addr < dasm.ain->code_size;) {
|
||||
const struct instruction *instr = get_instruction(&dasm);
|
||||
char *label = get_label(dasm.addr);
|
||||
if (label)
|
||||
fprintf(dasm.out, "%s:\n", label);
|
||||
print_instruction(&dasm, instr);
|
||||
dasm.addr += instruction_width(instr->opcode);
|
||||
}
|
||||
fflush(dasm.out);
|
||||
|
||||
for (int i = 0; i < NR_LABEL_BUCKETS; i++) {
|
||||
for (int j = 0; j < label_table[i].nr_labels; j++) {
|
||||
free(label_table[i].labels[j].name);
|
||||
}
|
||||
free(label_table[i].labels);
|
||||
}
|
||||
}
|
||||
+51
-25
@@ -21,6 +21,32 @@
|
||||
#include "system4.h"
|
||||
#include "system4/instructions.h"
|
||||
|
||||
const char * const syscalls[NR_SYSCALLS] = {
|
||||
[SYS_EXIT] = "system.Exit",
|
||||
[SYS_GLOBAL_SAVE] = "system.GlobalSave",
|
||||
[SYS_GLOBAL_LOAD] = "system.GlobalLoad",
|
||||
[SYS_LOCK_PEEK] = "system.LockPeek",
|
||||
[SYS_UNLOCK_PEEK] = "system.UnlockPeek",
|
||||
[SYS_RESET] = "system.Reset",
|
||||
[SYS_OUTPUT] = "system.Output",
|
||||
[SYS_MSGBOX] = "system.MsgBox",
|
||||
[SYS_RESUME_SAVE] = "system.ResumeSave",
|
||||
[SYS_RESUME_LOAD] = "system.ResumeLoad",
|
||||
[SYS_EXISTS_FILE] = "system.ExistsFile",
|
||||
[SYS_OPEN_WEB] = "system.OpenWeb",
|
||||
[SYS_GET_SAVE_FOLDER_NAME] = "system.GetSaveFolderName",
|
||||
[SYS_GET_TIME] = "system.GetTime",
|
||||
[SYS_ERROR] = "system.Error",
|
||||
[SYS_EXISTS_SAVE_FILE] = "system.ExistsSaveFile",
|
||||
[SYS_IS_DEBUG_MODE] = "system.IsDebugMode",
|
||||
[SYS_MSGBOX_OK_CANCEL] = "system.MsgBoxOkCancel",
|
||||
[SYS_GET_FUNC_STACK_NAME] = "system.GetFuncStackName",
|
||||
[SYS_PEEK] = "system.Peek",
|
||||
[SYS_SLEEP] = "system.Sleep",
|
||||
[SYS_GROUP_SAVE] = "system.GroupSave",
|
||||
[SYS_GROUP_LOAD] = "system.GroupLoad"
|
||||
};
|
||||
|
||||
// JMP = instruction that modifies the instruction pointer
|
||||
// OP = everything else
|
||||
#define OP(code, nargs, ...) \
|
||||
@@ -41,7 +67,7 @@
|
||||
}
|
||||
|
||||
const struct instruction instructions[NR_OPCODES] = {
|
||||
OP(PUSH, 1, INSTR_INT),
|
||||
OP(PUSH, 1, T_INT),
|
||||
OP(POP, 0),
|
||||
OP(REF, 0),
|
||||
OP(REFREF, 0),
|
||||
@@ -89,11 +115,11 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
|
||||
OP(CMP, 0), // TODO
|
||||
|
||||
JMP(JUMP, 1, INSTR_PTR),
|
||||
JMP(IFZ, 1, INSTR_PTR),
|
||||
JMP(IFNZ, 1, INSTR_PTR),
|
||||
JMP(JUMP, 1, T_ADDR),
|
||||
JMP(IFZ, 1, T_ADDR),
|
||||
JMP(IFNZ, 1, T_ADDR),
|
||||
JMP(RETURN, 0),
|
||||
JMP(CALLFUNC, 1, INSTR_FUN),
|
||||
JMP(CALLFUNC, 1, T_FUNC),
|
||||
OP(INC, 0),
|
||||
OP(DEC, 0),
|
||||
OP(FTOI, 0),
|
||||
@@ -109,8 +135,8 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
OP(F_GTE, 0),
|
||||
OP(F_NOTE, 0),
|
||||
OP(F_EQUALE, 0),
|
||||
OP(F_PUSH, 1, INSTR_FLO),
|
||||
OP(S_PUSH, 1, INSTR_STR),
|
||||
OP(F_PUSH, 1, T_FLOAT),
|
||||
OP(S_PUSH, 1, T_STRING),
|
||||
OP(S_POP, 0),
|
||||
OP(S_ADD, 0),
|
||||
OP(S_ASSIGN, 0),
|
||||
@@ -125,7 +151,7 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
|
||||
OP(SR_POP, 0),
|
||||
OP(SR_ASSIGN, 0),
|
||||
OP(SR_REF, 1, INSTR_INT),
|
||||
OP(SR_REF, 1, T_STRUCT),
|
||||
OP(SR_REFREF, 0), // TODO
|
||||
OP(A_ALLOC, 0),
|
||||
OP(A_REALLOC, 0),
|
||||
@@ -135,21 +161,21 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
OP(A_FILL, 0),
|
||||
OP(C_REF, 0),
|
||||
OP(C_ASSIGN, 0),
|
||||
JMP(MSG, 1, INSTR_INT),
|
||||
OP(CALLHLL, 2, INSTR_INT, INSTR_INT),
|
||||
JMP(MSG, 1, T_MSG),
|
||||
OP(CALLHLL, 2, T_HLL, T_HLLFUNC),
|
||||
OP(PUSHSTRUCTPAGE, 0),
|
||||
JMP(CALLMETHOD, 1, INSTR_FUN),
|
||||
OP(SH_GLOBALREF, 1, INSTR_INT),
|
||||
OP(SH_LOCALREF, 1, INSTR_INT),
|
||||
JMP(SWITCH, 1),
|
||||
JMP(STRSWITCH, 1),
|
||||
OP(FUNC, 1, INSTR_FUN),
|
||||
OP(_EOF, 1, INSTR_FILE),
|
||||
OP(CALLSYS, 1, INSTR_INT),
|
||||
JMP(CALLMETHOD, 1, T_FUNC),
|
||||
OP(SH_GLOBALREF, 1, T_GLOBAL),
|
||||
OP(SH_LOCALREF, 1, T_LOCAL),
|
||||
JMP(SWITCH, 1, T_INT),
|
||||
JMP(STRSWITCH, 1, T_INT),
|
||||
OP(FUNC, 1, T_FUNC),
|
||||
OP(_EOF, 1, T_FILE),
|
||||
OP(CALLSYS, 1, T_SYSCALL),
|
||||
JMP(SJUMP, 0),
|
||||
OP(CALLONJUMP, 0),
|
||||
OP(SWAP, 0),
|
||||
OP(SH_STRUCTREF, 1, INSTR_INT),
|
||||
OP(SH_STRUCTREF, 1, T_INT),
|
||||
OP(S_LENGTH, 0),
|
||||
OP(S_LENGTHBYTE, 0),
|
||||
OP(I_STRING, 0),
|
||||
@@ -172,11 +198,11 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
OP(DUP_U2, 0),
|
||||
OP(SP_INC, 0),
|
||||
OP(SP_DEC, 0), // TODO
|
||||
OP(ENDFUNC, 1, INSTR_FUN),
|
||||
OP(ENDFUNC, 1, T_FUNC),
|
||||
OP(R_EQUALE, 0), // TODO
|
||||
OP(R_NOTE, 0), // TODO
|
||||
OP(SH_LOCALCREATE, 2),
|
||||
OP(SH_LOCALDELETE, 1),
|
||||
OP(SH_LOCALCREATE, 2, T_LOCAL, T_STRUCT),
|
||||
OP(SH_LOCALDELETE, 1, T_LOCAL),
|
||||
OP(STOI, 0), // TODO
|
||||
OP(A_PUSHBACK, 0),
|
||||
OP(A_POPBACK, 0),
|
||||
@@ -184,9 +210,9 @@ const struct instruction instructions[NR_OPCODES] = {
|
||||
OP(A_EMPTY, 0),
|
||||
OP(A_ERASE, 0),
|
||||
OP(A_INSERT, 0),
|
||||
OP(SH_LOCALINC, 1, INSTR_INT),
|
||||
OP(SH_LOCALDEC, 1, INSTR_INT),
|
||||
OP(SH_LOCALASSIGN, 2, INSTR_INT, INSTR_INT),
|
||||
OP(SH_LOCALINC, 1, T_LOCAL),
|
||||
OP(SH_LOCALDEC, 1, T_LOCAL),
|
||||
OP(SH_LOCALASSIGN, 2, T_LOCAL, T_INT),
|
||||
OP(ITOB, 0),
|
||||
OP(S_FIND, 0),
|
||||
OP(S_GETPART, 0),
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ executable('xsystem4', xsystem4,
|
||||
include_directories : incdir,
|
||||
link_with : libsys4)
|
||||
|
||||
executable('aindump', ['aindump.c'],
|
||||
executable('aindump', ['aindump/aindump.c', 'aindump/dasm.c'],
|
||||
dependencies : [libm, zlib],
|
||||
include_directories : incdir,
|
||||
link_with : libsys4)
|
||||
|
||||
@@ -354,30 +354,7 @@ static void function_return(void)
|
||||
call_stack_ptr--;
|
||||
}
|
||||
|
||||
enum syscall_code {
|
||||
SYS_EXIT = 0x00,
|
||||
SYS_GLOBAL_SAVE = 0x01,
|
||||
SYS_GLOBAL_LOAD = 0x02,
|
||||
SYS_LOCK_PEEK = 0x03,
|
||||
SYS_UNLOCK_PEEK = 0x04,
|
||||
SYS_OUTPUT = 0x06,
|
||||
SYS_MSGBOX = 0x07,
|
||||
SYS_RESUME_SAVE = 0x08,
|
||||
SYS_RESUME_LOAD = 0x09,
|
||||
SYS_EXISTS_FILE = 0x0A,
|
||||
SYS_GET_SAVE_FOLDER_NAME = 0x0C,
|
||||
SYS_GET_TIME = 0x0D,
|
||||
SYS_ERROR = 0x0F,
|
||||
SYS_EXISTS_SAVE_FILE = 0x10,
|
||||
SYS_IS_DEBUG_MODE = 0x11,
|
||||
SYS_GET_FUNC_STACK_NAME = 0x13,
|
||||
SYS_PEEK = 0x14,
|
||||
SYS_SLEEP = 0x15,
|
||||
SYS_GROUP_SAVE = 0x18,
|
||||
SYS_GROUP_LOAD = 0x19
|
||||
};
|
||||
|
||||
static void system_call(int32_t code)
|
||||
static void system_call(enum syscall_code code)
|
||||
{
|
||||
switch (code) {
|
||||
case SYS_EXIT: {// system.Exit(int nResult)
|
||||
|
||||
Reference in New Issue
Block a user