309 lines
10 KiB
C
309 lines
10 KiB
C
|
#ifndef INTERPRETER_H
|
||
|
#define INTERPRETER_H
|
||
|
|
||
|
#include <setjmp.h>
|
||
|
|
||
|
// The maximum number of opcodes.
|
||
|
#define OPCODE_MAX_COUNT (342)
|
||
|
|
||
|
typedef enum Opcode {
|
||
|
OPCODE_NOOP = 0x8000,
|
||
|
OPCODE_PUSH = 0x8001,
|
||
|
OPCODE_ENTER_CRITICAL_SECTION = 0x8002,
|
||
|
OPCODE_LEAVE_CRITICAL_SECTION = 0x8003,
|
||
|
OPCODE_JUMP = 0x8004,
|
||
|
OPCODE_CALL = 0x8005,
|
||
|
OPCODE_CALL_AT = 0x8006,
|
||
|
OPCODE_CALL_WHEN = 0x8007,
|
||
|
OPCODE_CALLSTART = 0x8008,
|
||
|
OPCODE_EXEC = 0x8009,
|
||
|
OPCODE_SPAWN = 0x800A,
|
||
|
OPCODE_FORK = 0x800B,
|
||
|
OPCODE_A_TO_D = 0x800C,
|
||
|
OPCODE_D_TO_A = 0x800D,
|
||
|
OPCODE_EXIT = 0x800E,
|
||
|
OPCODE_DETACH = 0x800F,
|
||
|
OPCODE_EXIT_PROGRAM = 0x8010,
|
||
|
OPCODE_STOP_PROGRAM = 0x8011,
|
||
|
OPCODE_FETCH_GLOBAL = 0x8012,
|
||
|
OPCODE_STORE_GLOBAL = 0x8013,
|
||
|
OPCODE_FETCH_EXTERNAL = 0x8014,
|
||
|
OPCODE_STORE_EXTERNAL = 0x8015,
|
||
|
OPCODE_EXPORT_VARIABLE = 0x8016,
|
||
|
OPCODE_EXPORT_PROCEDURE = 0x8017,
|
||
|
OPCODE_SWAP = 0x8018,
|
||
|
OPCODE_SWAPA = 0x8019,
|
||
|
OPCODE_POP = 0x801A,
|
||
|
OPCODE_DUP = 0x801B,
|
||
|
OPCODE_POP_RETURN = 0x801C,
|
||
|
OPCODE_POP_EXIT = 0x801D,
|
||
|
OPCODE_POP_ADDRESS = 0x801E,
|
||
|
OPCODE_POP_FLAGS = 0x801F,
|
||
|
OPCODE_POP_FLAGS_RETURN = 0x8020,
|
||
|
OPCODE_POP_FLAGS_EXIT = 0x8021,
|
||
|
OPCODE_POP_FLAGS_RETURN_EXTERN = 0x8022,
|
||
|
OPCODE_POP_FLAGS_EXIT_EXTERN = 0x8023,
|
||
|
OPCODE_POP_FLAGS_RETURN_VAL_EXTERN = 0x8024,
|
||
|
OPCODE_POP_FLAGS_RETURN_VAL_EXIT = 0x8025,
|
||
|
OPCODE_POP_FLAGS_RETURN_VAL_EXIT_EXTERN = 0x8026,
|
||
|
OPCODE_CHECK_PROCEDURE_ARGUMENT_COUNT = 0x8027,
|
||
|
OPCODE_LOOKUP_PROCEDURE_BY_NAME = 0x8028,
|
||
|
OPCODE_POP_BASE = 0x8029,
|
||
|
OPCODE_POP_TO_BASE = 0x802A,
|
||
|
OPCODE_PUSH_BASE = 0x802B,
|
||
|
OPCODE_SET_GLOBAL = 0x802C,
|
||
|
OPCODE_FETCH_PROCEDURE_ADDRESS = 0x802D,
|
||
|
OPCODE_DUMP = 0x802E,
|
||
|
OPCODE_IF = 0x802F,
|
||
|
OPCODE_WHILE = 0x8030,
|
||
|
OPCODE_STORE = 0x8031,
|
||
|
OPCODE_FETCH = 0x8032,
|
||
|
OPCODE_EQUAL = 0x8033,
|
||
|
OPCODE_NOT_EQUAL = 0x8034,
|
||
|
OPCODE_LESS_THAN_EQUAL = 0x8035,
|
||
|
OPCODE_GREATER_THAN_EQUAL = 0x8036,
|
||
|
OPCODE_LESS_THAN = 0x8037,
|
||
|
OPCODE_GREATER_THAN = 0x8038,
|
||
|
OPCODE_ADD = 0x8039,
|
||
|
OPCODE_SUB = 0x803A,
|
||
|
OPCODE_MUL = 0x803B,
|
||
|
OPCODE_DIV = 0x803C,
|
||
|
OPCODE_MOD = 0x803D,
|
||
|
OPCODE_AND = 0x803E,
|
||
|
OPCODE_OR = 0x803F,
|
||
|
OPCODE_BITWISE_AND = 0x8040,
|
||
|
OPCODE_BITWISE_OR = 0x8041,
|
||
|
OPCODE_BITWISE_XOR = 0x8042,
|
||
|
OPCODE_BITWISE_NOT = 0x8043,
|
||
|
OPCODE_FLOOR = 0x8044,
|
||
|
OPCODE_NOT = 0x8045,
|
||
|
OPCODE_NEGATE = 0x8046,
|
||
|
OPCODE_WAIT = 0x8047,
|
||
|
OPCODE_CANCEL = 0x8048,
|
||
|
OPCODE_CANCEL_ALL = 0x8049,
|
||
|
OPCODE_START_CRITICAL = 0x804A,
|
||
|
OPCODE_END_CRITICAL = 0x804B,
|
||
|
} Opcode;
|
||
|
|
||
|
typedef enum ProcedureFlags {
|
||
|
PROCEDURE_FLAG_TIMED = 0x01,
|
||
|
PROCEDURE_FLAG_CONDITIONAL = 0x02,
|
||
|
PROCEDURE_FLAG_IMPORTED = 0x04,
|
||
|
PROCEDURE_FLAG_EXPORTED = 0x08,
|
||
|
PROCEDURE_FLAG_CRITICAL = 0x10,
|
||
|
} ProcedureFlags;
|
||
|
|
||
|
typedef enum ProgramFlags {
|
||
|
PROGRAM_FLAG_EXITED = 0x01,
|
||
|
PROGRAM_FLAG_0x02 = 0x02,
|
||
|
PROGRAM_FLAG_0x04 = 0x04,
|
||
|
PROGRAM_FLAG_STOPPED = 0x08,
|
||
|
PROGRAM_FLAG_0x10 = 0x10,
|
||
|
PROGRAM_FLAG_0x20 = 0x20,
|
||
|
PROGRAM_FLAG_0x40 = 0x40,
|
||
|
PROGRAM_FLAG_CRITICAL_SECTION = 0x80,
|
||
|
PROGRAM_FLAG_0x0100 = 0x0100,
|
||
|
} ProgramFlags;
|
||
|
|
||
|
enum RawValueType {
|
||
|
RAW_VALUE_TYPE_OPCODE = 0x8000,
|
||
|
RAW_VALUE_TYPE_INT = 0x4000,
|
||
|
RAW_VALUE_TYPE_FLOAT = 0x2000,
|
||
|
RAW_VALUE_TYPE_STATIC_STRING = 0x1000,
|
||
|
RAW_VALUE_TYPE_DYNAMIC_STRING = 0x0800,
|
||
|
};
|
||
|
|
||
|
#define VALUE_TYPE_MASK 0xF7FF
|
||
|
|
||
|
#define VALUE_TYPE_INT 0xC001
|
||
|
#define VALUE_TYPE_FLOAT 0xA001
|
||
|
#define VALUE_TYPE_STRING 0x9001
|
||
|
#define VALUE_TYPE_DYNAMIC_STRING 0x9801
|
||
|
|
||
|
typedef unsigned short opcode_t;
|
||
|
|
||
|
typedef struct Procedure {
|
||
|
int field_0;
|
||
|
int field_4;
|
||
|
int field_8;
|
||
|
int field_C;
|
||
|
int field_10;
|
||
|
int field_14;
|
||
|
} Procedure;
|
||
|
|
||
|
// It's size in original code is 144 (0x8C) bytes due to the different
|
||
|
// size of `jmp_buf`.
|
||
|
typedef struct Program {
|
||
|
char* name;
|
||
|
unsigned char* data;
|
||
|
struct Program* parent;
|
||
|
struct Program* child;
|
||
|
int instructionPointer; // current pos in data
|
||
|
int framePointer; // saved stack 1 pos - probably beginning of local variables - probably called base
|
||
|
int basePointer; // saved stack 1 pos - probably beginning of global variables
|
||
|
unsigned char* stack; // stack 1 (4096 bytes)
|
||
|
unsigned char* returnStack; // stack 2 (4096 bytes)
|
||
|
int stackPointer; // stack pointer 1
|
||
|
int returnStackPointer; // stack pointer 2
|
||
|
unsigned char* staticStrings; // static strings table
|
||
|
unsigned char* dynamicStrings; // dynamic strings table
|
||
|
unsigned char* identifiers;
|
||
|
unsigned char* procedures;
|
||
|
jmp_buf env;
|
||
|
int field_70; // end time of timer (field_74 + wait time)
|
||
|
int field_74; // time when wait was called
|
||
|
int field_78; // time when program begin execution (for the first time)?, -1 - program never executed
|
||
|
int (*field_7C)(struct Program* s); // proc to check timer
|
||
|
int flags; // flags
|
||
|
int field_84;
|
||
|
bool exited;
|
||
|
} Program;
|
||
|
|
||
|
typedef void OpcodeHandler(Program* program);
|
||
|
|
||
|
typedef struct ProgramListNode {
|
||
|
Program* program;
|
||
|
struct ProgramListNode* next; // next
|
||
|
struct ProgramListNode* prev; // prev
|
||
|
} ProgramListNode;
|
||
|
|
||
|
extern int _TimeOut;
|
||
|
extern int _Enabled;
|
||
|
extern int (*_timerFunc)();
|
||
|
extern int _timerTick;
|
||
|
extern char* (*_filenameFunc)(char*);
|
||
|
extern int (*_outputFunc)(char*);
|
||
|
extern int _cpuBurstSize;
|
||
|
|
||
|
extern OpcodeHandler* gInterpreterOpcodeHandlers[OPCODE_MAX_COUNT];
|
||
|
extern Program* gInterpreterCurrentProgram;
|
||
|
extern ProgramListNode* gInterpreterProgramListHead;
|
||
|
extern int _suspendEvents;
|
||
|
extern int _busy;
|
||
|
|
||
|
int _defaultTimerFunc();
|
||
|
char* _defaultFilename_(char* s);
|
||
|
char* _interpretMangleName(char* s);
|
||
|
int _outputStr(char* a1);
|
||
|
int _checkWait(Program* program);
|
||
|
void _interpretOutputFunc(int (*func)(char*));
|
||
|
int _interpretOutput(const char* format, ...);
|
||
|
char* programGetCurrentProcedureName(Program* s);
|
||
|
__declspec(noreturn) void programFatalError(const char* str, ...);
|
||
|
opcode_t stackReadInt16(unsigned char* data, int pos);
|
||
|
int stackReadInt32(unsigned char* a1, int a2);
|
||
|
void stackWriteInt16(int value, unsigned char* a2, int a3);
|
||
|
void stackWriteInt32(int value, unsigned char* stack, int pos);
|
||
|
void stackPushInt16(unsigned char* a1, int* a2, int value);
|
||
|
void stackPushInt32(unsigned char* a1, int* a2, int value);
|
||
|
int stackPopInt32(unsigned char* a1, int* a2);
|
||
|
opcode_t stackPopInt16(unsigned char* a1, int* a2);
|
||
|
void programPopString(Program* program, opcode_t a2, int a3);
|
||
|
void programStackPushInt16(Program* program, int value);
|
||
|
void programStackPushInt32(Program* program, int value);
|
||
|
opcode_t programStackPopInt16(Program* program);
|
||
|
int programStackPopInt32(Program* program);
|
||
|
void programReturnStackPushInt16(Program* program, int value);
|
||
|
opcode_t programReturnStackPopInt16(Program* program);
|
||
|
int programReturnStackPopInt32(Program* program);
|
||
|
void _detachProgram(Program* program);
|
||
|
void _purgeProgram(Program* program);
|
||
|
void programFree(Program* program);
|
||
|
Program* programCreateByPath(const char* path);
|
||
|
char* programGetString(Program* program, opcode_t opcode, int offset);
|
||
|
char* programGetIdentifier(Program* program, int offset);
|
||
|
void programMarkHeap(Program* program);
|
||
|
int programPushString(Program* program, char* string);
|
||
|
void opNoop(Program* program);
|
||
|
void opPush(Program* program);
|
||
|
void opPushBase(Program* program);
|
||
|
void opPopBase(Program* program);
|
||
|
void opPopToBase(Program* program);
|
||
|
void op802C(Program* program);
|
||
|
void opDump(Program* program);
|
||
|
void opDelayedCall(Program* program);
|
||
|
void opConditionalCall(Program* program);
|
||
|
void opWait(Program* program);
|
||
|
void opCancel(Program* program);
|
||
|
void opCancelAll(Program* program);
|
||
|
void opIf(Program* program);
|
||
|
void opWhile(Program* program);
|
||
|
void opStore(Program* program);
|
||
|
void opFetch(Program* program);
|
||
|
void opConditionalOperatorNotEqual(Program* program);
|
||
|
void opConditionalOperatorEqual(Program* program);
|
||
|
void opConditionalOperatorLessThanEquals(Program* program);
|
||
|
void opConditionalOperatorGreaterThanEquals(Program* program);
|
||
|
void opConditionalOperatorLessThan(Program* program);
|
||
|
void opConditionalOperatorGreaterThan(Program* program);
|
||
|
void opAdd(Program* program);
|
||
|
void opSubtract(Program* program);
|
||
|
void opMultiply(Program* program);
|
||
|
void opDivide(Program* program);
|
||
|
void opModulo(Program* program);
|
||
|
void opLogicalOperatorAnd(Program* program);
|
||
|
void opLogicalOperatorOr(Program* program);
|
||
|
void opLogicalOperatorNot(Program* program);
|
||
|
void opUnaryMinus(Program* program);
|
||
|
void opBitwiseOperatorNot(Program* program);
|
||
|
void opFloor(Program* program);
|
||
|
void opBitwiseOperatorAnd(Program* program);
|
||
|
void opBitwiseOperatorOr(Program* program);
|
||
|
void opBitwiseOperatorXor(Program* program);
|
||
|
void opSwapReturnStack(Program* program);
|
||
|
void opLeaveCriticalSection(Program* program);
|
||
|
void opEnterCriticalSection(Program* program);
|
||
|
void opJump(Program* program);
|
||
|
void opCall(Program* program);
|
||
|
void op801F(Program* program);
|
||
|
void op801C(Program* program);
|
||
|
void op801D(Program* program);
|
||
|
void op8020(Program* program);
|
||
|
void op8021(Program* program);
|
||
|
void op8025(Program* program);
|
||
|
void op8026(Program* program);
|
||
|
void op8022(Program* program);
|
||
|
void op8023(Program* program);
|
||
|
void op8024(Program* program);
|
||
|
void op801E(Program* program);
|
||
|
void opAtoD(Program* program);
|
||
|
void opDtoA(Program* program);
|
||
|
void opExitProgram(Program* program);
|
||
|
void opStopProgram(Program* program);
|
||
|
void opFetchGlobalVariable(Program* program);
|
||
|
void opStoreGlobalVariable(Program* program);
|
||
|
void opSwapStack(Program* program);
|
||
|
void opFetchProcedureAddress(Program* program);
|
||
|
void opPop(Program* program);
|
||
|
void opDuplicate(Program* program);
|
||
|
void opStoreExternalVariable(Program* program);
|
||
|
void opFetchExternalVariable(Program* program);
|
||
|
void opExportProcedure(Program* program);
|
||
|
void opExportVariable(Program* program);
|
||
|
void opExit(Program* program);
|
||
|
void opDetach(Program* program);
|
||
|
void opCallStart(Program* program);
|
||
|
void opSpawn(Program* program);
|
||
|
Program* forkProgram(Program* program);
|
||
|
void opFork(Program* program);
|
||
|
void opExec(Program* program);
|
||
|
void opCheckProcedureArgumentCount(Program* program);
|
||
|
void opLookupStringProc(Program* program);
|
||
|
void interpreterRegisterOpcodeHandlers();
|
||
|
void _interpretClose();
|
||
|
void _interpret(Program* program, int a2);
|
||
|
void _setupCallWithReturnVal(Program* program, int address, int a3);
|
||
|
void _setupExternalCallWithReturnVal(Program* program1, Program* program2, int address, int a4);
|
||
|
void _executeProc(Program* program, int procedure_index);
|
||
|
int programFindProcedure(Program* prg, const char* name);
|
||
|
void _executeProcedure(Program* program, int procedure_index);
|
||
|
void _doEvents();
|
||
|
void programListNodeFree(ProgramListNode* programListNode);
|
||
|
void programListNodeCreate(Program* program);
|
||
|
void _updatePrograms();
|
||
|
void programListFree();
|
||
|
void interpreterRegisterOpcode(int opcode, OpcodeHandler* handler);
|
||
|
void interpreterPrintStats();
|
||
|
|
||
|
#endif /* INTERPRETER_H */
|