Files
nunuhara_xsystem4/include/system4/instructions.h
T
Nunuhara Cabbage dab8deca42 Add ainedit utility
The ainedit utility is a tool capable of modifying AIN files up to
version 12 (Rance X). As far as I know, this is the first publicly
released tool that can handle AIN files above version 7.

The basic mode of operation is as follows:

* dump the CODE section with aindump
* edit the disassembled bytecode
* assemble & insert the edited bytebode back into the original AIN file
  using ainedit

E.g.

    aindump -c -o out.jam /path/to/Rance10.ain
    $EDITOR out.jam
    ainedit -c out.jam -o out.ain /path/to/Rance10.ain
    mv /path/to/Rance10.ain /path/to/Rance10.ain.backup
    mv out.ain /path/to/Rance10.ain

ainedit is also capable of editing declarations (structures, functions,
etc.) using the JSON (-j) output from aindump.

There is currently one major deficiency in this tool: it does not
rebuild the AIN file's switch table (SWI0 section). This means that you
can't insert or delete instructions, as it would render the addresses
stored in the switch table invalid. I hope to fix this soon.

A number of changes have also been made to the aindump utility, since
these tools need to work together.
2020-02-07 19:49:39 -08:00

386 lines
11 KiB
C

/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* Credit to SLC for reverse engineering the opcodes.
*
* 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/>.
*/
#ifndef SYSTEM4_INSTRUCTIONS_H
#define SYSTEM4_INSTRUCTIONS_H
#include <stdbool.h>
#include <stdint.h>
#include "system4.h"
#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_GET_GAME_NAME = 0x0E,
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_RESUME_WRITE_COMMENT = 0x16,
SYS_RESUME_READ_COMMENT = 0x17,
SYS_GROUP_SAVE = 0x18,
SYS_GROUP_LOAD = 0x19,
SYS_DELETE_SAVE_FILE = 0x1A,
SYS_EXIST_FUNC = 0x1B,
SYS_COPY_SAVE_FILE = 0x1C,
NR_SYSCALLS
};
struct syscall {
const enum syscall_code code;
const char * const name;
const bool implemented;
};
const struct syscall syscalls[NR_SYSCALLS];
enum opcode
{
PUSH = 0x00,
POP = 0x01,
REF = 0x02,
REFREF = 0x03,
PUSHGLOBALPAGE = 0x04,
PUSHLOCALPAGE = 0x05,
INV = 0x06,
NOT = 0x07,
COMPL = 0x08,
ADD = 0x09,
SUB = 0x0a,
MUL = 0x0b,
DIV = 0x0c,
MOD = 0x0d,
AND = 0x0e,
OR = 0x0f,
XOR = 0x10,
LSHIFT = 0x11,
RSHIFT = 0x12,
LT = 0x13,
GT = 0x14,
LTE = 0x15,
GTE = 0x16,
NOTE = 0x17,
EQUALE = 0x18,
ASSIGN = 0x19,
PLUSA = 0x1a,
MINUSA = 0x1b,
MULA = 0x1c,
DIVA = 0x1d,
MODA = 0x1e,
ANDA = 0x1f,
ORA = 0x20,
XORA = 0x21,
LSHIFTA = 0x22,
RSHIFTA = 0x23,
F_ASSIGN = 0x24,
F_PLUSA = 0x25,
F_MINUSA = 0x26,
F_MULA = 0x27,
F_DIVA = 0x28,
DUP2 = 0x29,
DUP_X2 = 0x2a,
CMP = 0x2b,
JUMP = 0x2c,
IFZ = 0x2d,
IFNZ = 0x2e,
RETURN = 0x2f,
CALLFUNC = 0x30,
INC = 0x31,
DEC = 0x32,
FTOI = 0x33,
ITOF = 0x34,
F_INV = 0x35,
F_ADD = 0x36,
F_SUB = 0x37,
F_MUL = 0x38,
F_DIV = 0x39,
F_LT = 0x3a,
F_GT = 0x3b,
F_LTE = 0x3c,
F_GTE = 0x3D,
F_NOTE = 0x3E,
F_EQUALE = 0x3f,
F_PUSH = 0x40,
S_PUSH = 0x41,
S_POP = 0x42,
S_ADD = 0x43,
S_ASSIGN = 0x44,
S_PLUSA = 0x45,
S_REF = 0x46,
S_REFREF = 0x47,
S_NOTE = 0x48,
S_EQUALE = 0x49,
SF_CREATE = 0x4A,
SF_CREATEPIXEL = 0x4B,
SF_CREATEALPHA = 0x4C,
SR_POP = 0x4d,
SR_ASSIGN = 0x4e,
SR_REF = 0x4f,
SR_REFREF = 0x50,
A_ALLOC = 0x51,
A_REALLOC = 0x52,
A_FREE = 0x53,
A_NUMOF = 0x54,
A_COPY = 0x55,
A_FILL = 0x56,
C_REF = 0x57,
C_ASSIGN = 0x58,
MSG = 0x59,
CALLHLL = 0x5a,
PUSHSTRUCTPAGE = 0x5b,
CALLMETHOD = 0x5c,
SH_GLOBALREF = 0x5d,
SH_LOCALREF = 0x5e,
SWITCH = 0x5f,
STRSWITCH = 0x60,
FUNC = 0x61,
_EOF = 0x62,
CALLSYS = 0x63,
SJUMP = 0x64,
CALLONJUMP = 0x65,
SWAP = 0x66,
SH_STRUCTREF = 0x67,
S_LENGTH = 0x68,
S_LENGTHBYTE = 0x69,
I_STRING = 0x6a,
CALLFUNC2 = 0x6b,
DUP2_X1 = 0x6c,
R_ASSIGN = 0x6d,
FT_ASSIGNS = 0x6e,
ASSERT = 0x6f,
S_LT = 0x70,
S_GT = 0x71,
S_LTE = 0x72,
S_GTE = 0x73,
S_LENGTH2 = 0x74,
S_LENGTHBYTE2 = 0x75,
NEW = 0x76,
DELETE = 0x77,
CHECKUDO = 0x78,
A_REF = 0x79,
DUP = 0x7a,
DUP_U2 = 0x7b,
SP_INC = 0x7c,
SP_DEC = 0x7d,
ENDFUNC = 0x7e,
R_EQUALE = 0x7f,
R_NOTE = 0x80,
SH_LOCALCREATE = 0x81,
SH_LOCALDELETE = 0x82,
STOI = 0x83,
A_PUSHBACK = 0x84,
A_POPBACK = 0x85,
S_EMPTY = 0x86,
A_EMPTY = 0x87,
A_ERASE = 0x88,
A_INSERT = 0x89,
SH_LOCALINC = 0x8a,
SH_LOCALDEC = 0x8b,
SH_LOCALASSIGN = 0x8c,
ITOB = 0x8d,
S_FIND = 0x8e,
S_GETPART = 0x8f,
A_SORT = 0x90,
S_PUSHBACK = 0x91,
S_POPBACK = 0x92,
FTOS = 0x93,
S_MOD = 0x94,
S_PLUSA2 = 0x95,
OBJSWAP = 0x96,
S_ERASE = 0x97,
SR_REF2 = 0x98,
S_ERASE2 = 0x99,
S_PUSHBACK2 = 0x9A,
S_POPBACK2 = 0x9B,
ITOLI = 0x9c,
LI_ADD = 0x9d,
LI_SUB = 0x9e,
LI_MUL = 0x9f,
LI_DIV = 0xa0,
LI_MOD = 0xa1,
LI_ASSIGN = 0xa2,
LI_PLUSA = 0xa3,
LI_MINUSA = 0xa4,
LI_MULA = 0xa5,
LI_DIVA = 0xa6,
LI_MODA = 0xa7,
LI_ANDA = 0xa8,
LI_ORA = 0xa9,
LI_XORA = 0xaa,
LI_LSHIFTA = 0xab,
LI_RSHIFTA = 0xac,
LI_INC = 0xad,
LI_DEC = 0xae,
A_FIND = 0xaf,
A_REVERSE = 0xb0,
SH_SR_ASSIGN,
SH_MEM_ASSIGN_LOCAL,
A_NUMOF_GLOB_1,
A_NUMOF_STRUCT_1,
SH_MEM_ASSIGN_IMM,
SH_LOCALREFREF,
SH_LOCALASSIGN_SUB_IMM,
SH_IF_LOC_LT_IMM,
SH_IF_LOC_GE_IMM,
SH_LOCREF_ASSIGN_MEM,
PAGE_REF,
SH_GLOBAL_ASSIGN_LOCAL,
SH_STRUCTREF_GT_IMM,
SH_STRUCT_ASSIGN_LOCALREF_ITOB,
SH_LOCAL_ASSIGN_STRUCTREF,
SH_IF_STRUCTREF_NE_LOCALREF,
SH_IF_STRUCTREF_GT_IMM,
SH_STRUCTREF_CALLMETHOD_NO_PARAM,
SH_STRUCTREF2,
SH_REF_STRUCTREF2,
SH_STRUCTREF3,
SH_STRUCTREF2_CALLMETHOD_NO_PARAM,
SH_IF_STRUCTREF_Z,
SH_IF_STRUCT_A_NOT_EMPTY,
SH_IF_LOC_GT_IMM,
SH_IF_STRUCTREF_NE_IMM,
THISCALLMETHOD_NOPARAM,
SH_IF_LOC_NE_IMM,
SH_IF_STRUCTREF_EQ_IMM,
SH_GLOBAL_ASSIGN_IMM,
SH_LOCALSTRUCT_ASSIGN_IMM,
SH_STRUCT_A_PUSHBACK_LOCAL_STRUCT,
SH_GLOBAL_A_PUSHBACK_LOCAL_STRUCT,
SH_LOCAL_A_PUSHBACK_LOCAL_STRUCT,
SH_IF_SREF_NE_STR0,
SH_S_ASSIGN_REF,
SH_A_FIND_SREF,
SH_SREF_EMPTY,
SH_STRUCTSREF_EQ_LOCALSREF,
SH_LOCALSREF_EQ_STR0,
SH_STRUCTSREF_NE_LOCALSREF,
SH_LOCALSREF_NE_STR0,
SH_STRUCT_SR_REF,
SH_STRUCT_S_REF,
S_REF2,
SH_REF_LOCAL_ASSIGN_STRUCTREF2,
SH_GLOBAL_S_REF,
SH_LOCAL_S_REF,
SH_LOCALREF_SASSIGN_LOCALSREF,
SH_LOCAL_APUSHBACK_LOCALSREF,
SH_S_ASSIGN_CALLSYS19,
SH_S_ASSIGN_STR0,
SH_SASSIGN_LOCALSREF,
SH_STRUCTREF_SASSIGN_LOCALSREF,
SH_LOCALSREF_EMPTY,
SH_GLOBAL_APUSHBACK_LOCALSREF,
SH_STRUCT_APUSHBACK_LOCALSREF,
SH_STRUCTSREF_EMPTY,
SH_GLOBALSREF_EMPTY,
SH_SASSIGN_STRUCTSREF,
SH_SASSIGN_GLOBALSREF,
SH_STRUCTSREF_NE_STR0,
SH_GLOBALSREF_NE_STR0,
SH_LOC_LT_IMM_OR_LOC_GE_IMM,
// instruction names are known, exact order of them are guesses after this point
A_SORT_MEM,
DG_ADD,
DG_SET,
DG_CALL,
DG_NUMOF,
DG_EXIST,
DG_ERASE,
DG_CLEAR,
DG_COPY,
DG_ASSIGN,
DG_PLUSA,
DG_POP,
DG_NEW_FROM_METHOD,
DG_MINUSA,
DG_CALLBEGIN,
DG_NEW,
DG_STR_TO_METHOD,
OP_0X102 = 0x102,
OP_0X103 = 0x103,
OP_0X104 = 0x104,
OP_0X105 = 0x105,
NR_OPCODES
};
enum instruction_argtype {
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,
T_DLG,
};
// TODO: Need to know which class a method belongs to
// in order to use this. Should be replaced with
// "this.<member-name>" in disassembled output.
#define T_MEMB T_INT
// TODO: As above, but for member of a member, etc.
#define T_MEMB2 T_INT
#define T_MEMB3 T_INT
// TODO: Similar to above, but for member of local variable.
// Only used in one instruction--maybe special case?
#define T_LOCMEMB T_INT
struct instruction {
const enum opcode opcode; // the opcode
const char * const name; // assembler name
int nr_args; // number of arguments (???: always 1 or 0?)
const int ip_inc; // amount to increment instruction pointer after instruction
const bool implemented; // implemented in xsystem4
int args[INSTRUCTION_MAX_ARGS]; // argument data types
};
struct instruction instructions[NR_OPCODES];
static const_pure inline int32_t instruction_width(enum opcode opcode)
{
return 2 + instructions[opcode].nr_args * 4;
}
#endif /* SYSTEM4_INSTRUCTIONS_H */