//======================================================================= // Copyright XashXT Group 2007 © // vprogs.h - virtual machine export //======================================================================= #ifndef VPROGS_H #define VPROGS_H #include #include "launch_api.h" #include "qfiles_ref.h" #include "vprogs_api.h" #include "pr_local.h" extern stdlib_api_t com; extern vprogs_exp_t vm; extern cvar_t *prvm_traceqc; extern cvar_t *prvm_boundscheck; extern cvar_t *prvm_statementprofiling; extern int prvm_developer; #define Host_Error com.error #define PRVM_MAX_STACK_DEPTH 1024 #define PRVM_LOCALSTACK_SIZE 16384 #define PRVM_MAX_OPENFILES 256 #define PRVM_MAX_OPENSEARCHES 128 enum op_state { OP_DONE, // 0 OP_MUL_F, OP_MUL_V, OP_MUL_FV, // (vec3_t) * (float) OP_MUL_VF, // (float) * (vec3_t) OP_DIV_F, OP_ADD_F, OP_ADD_V, OP_SUB_F, OP_SUB_V, OP_EQ_F, // 10 OP_EQ_V, OP_EQ_S, OP_EQ_E, OP_EQ_FNC, OP_NE_F, OP_NE_V, OP_NE_S, OP_NE_E, OP_NE_FNC, OP_LE, // = (float) <= (float); OP_GE, // = (float) >= (float); OP_LT, // = (float) < (float); OP_GT, // = (float) > (float); OP_LOAD_F, OP_LOAD_V, OP_LOAD_S, OP_LOAD_ENT, OP_LOAD_FLD, OP_LOAD_FNC, OP_ADDRESS, // 30 OP_STORE_F, OP_STORE_V, OP_STORE_S, OP_STORE_ENT, OP_STORE_FLD, OP_STORE_FNC, OP_STOREP_F, OP_STOREP_V, OP_STOREP_S, OP_STOREP_ENT, // 40 OP_STOREP_FLD, OP_STOREP_FNC, OP_RETURN, OP_NOT_F, OP_NOT_V, OP_NOT_S, OP_NOT_ENT, OP_NOT_FNC, OP_NOT_BITI, OP_NOT_BITF, OP_IF, OP_IFNOT, // 50 OP_CALL0, OP_CALL1, OP_CALL2, OP_CALL3, OP_CALL4, OP_CALL5, OP_CALL6, OP_CALL7, OP_CALL8, OP_CALL9, OP_STATE, // 60 OP_GOTO, OP_AND, OP_OR, OP_BITAND, // = (float) & (float); // of cource converting into integer in real code OP_BITOR, OP_MULSTORE_F, // f *= f OP_MULSTORE_V, // v *= f OP_MULSTOREP_F, // e.f *= f OP_MULSTOREP_V, // e.v *= f OP_DIVSTORE_F, // f /= f OP_DIVSTOREP_F, // e.f /= f OP_ADDSTORE_F, // f += f OP_ADDSTORE_V, // v += v OP_ADDSTOREP_F, // e.f += f OP_ADDSTOREP_V, // e.v += v OP_SUBSTORE_F, // f -= f OP_SUBSTORE_V, // v -= v OP_SUBSTOREP_F, // e.f -= f OP_SUBSTOREP_V, // e.v -= v OP_FETCH_GBL_F, // 80 OP_FETCH_GBL_V, OP_FETCH_GBL_S, OP_FETCH_GBL_E, OP_FETCH_G_FNC, OP_CSTATE, OP_CWSTATE, OP_THINKTIME, OP_BITSET, // b (+) a OP_BITSETP, // .b (+) a OP_BITCLR, // b (-) a OP_BITCLRP, // .b (-) a OP_RAND0, OP_RAND1, OP_RAND2, OP_RANDV0, OP_RANDV1, OP_RANDV2, OP_SWITCH_F, // switches OP_SWITCH_V, OP_SWITCH_S, // 100 OP_SWITCH_E, OP_SWITCH_FNC, OP_CASE, OP_CASERANGE, OP_STORE_I, OP_STORE_IF, OP_STORE_FI, OP_ADD_I, OP_ADD_FI, OP_ADD_IF, // 110 OP_SUB_I, OP_SUB_FI, OP_SUB_IF, OP_CONV_ITOF, OP_CONV_FTOI, OP_CP_ITOF, OP_CP_FTOI, OP_LOAD_I, OP_STOREP_I, OP_STOREP_IF, // 120 OP_STOREP_FI, OP_BITAND_I, OP_BITOR_I, OP_MUL_I, OP_DIV_I, OP_EQ_I, OP_NE_I, OP_IFNOTS, OP_IFS, OP_NOT_I, // 130 OP_DIV_VF, OP_POWER_I, OP_RSHIFT_I, OP_LSHIFT_I, OP_RSHIFT_F, OP_LSHIFT_F, OP_MODULO_I, // (int)c = (int)a % (int)b OP_MODULO_F, // (float)c = fmod( (float)a, (float)b ) OP_GLOBAL_ADD, OP_POINTER_ADD, // pointer to 32 bit (remember to *3 for vectors) OP_LOADA_F, OP_LOADA_V, OP_LOADA_S, OP_LOADA_ENT, // 140 OP_LOADA_FLD, OP_LOADA_FNC, OP_LOADA_I, OP_STORE_P, OP_LOAD_P, OP_LOADP_F, OP_LOADP_V, OP_LOADP_S, OP_LOADP_ENT, OP_LOADP_FLD, // 150 OP_LOADP_FNC, OP_LOADP_I, OP_LE_I, // (int)c = (int)a <= (int)b; OP_GE_I, // (int)c = (int)a >= (int)b; OP_LT_I, // (int)c = (int)a < (int)b; OP_GT_I, // (int)c = (int)a > (int)b; OP_LE_IF, // (float)c = (int)a <= (float)b; OP_GE_IF, // (float)c = (int)a >= (float)b; OP_LT_IF, // (float)c = (int)a < (float)b; OP_GT_IF, // (float)c = (int)a > (float)b; OP_LE_FI, // (float)c = (float)a <= (int)b; OP_GE_FI, // (float)c = (float)a >= (int)b; OP_LT_FI, // (float)c = (float)a < (int)b; OP_GT_FI, // (float)c = (float)a > (int)b; OP_EQ_IF, OP_EQ_FI, OP_ADD_SF, // (char*)c = (char*)a + (float)b OP_SUB_S, // (float)c = (char*)a - (char*)b OP_STOREP_C, // (float)c = *(char*)b = (float)a OP_LOADP_C, // (float)c = *(char*) // 170 OP_MUL_IF, OP_MUL_FI, OP_MUL_VI, OP_MUL_IV, OP_DIV_IF, OP_DIV_FI, OP_BITAND_IF, OP_BITOR_IF, OP_BITAND_FI, OP_BITOR_FI, // 180 OP_AND_I, OP_OR_I, OP_AND_IF, OP_OR_IF, OP_AND_FI, OP_OR_FI, OP_NE_IF, OP_NE_FI, OP_GSTOREP_I, OP_GSTOREP_F, // 190 OP_GSTOREP_ENT, OP_GSTOREP_FLD, // integers OP_GSTOREP_S, OP_GSTOREP_FNC, // pointers OP_GSTOREP_V, OP_GADDRESS, OP_GLOAD_I, OP_GLOAD_F, OP_GLOAD_FLD, OP_GLOAD_ENT, // 200 OP_GLOAD_S, OP_GLOAD_FNC, OP_GLOAD_V, OP_BOUNDCHECK, OP_STOREP_P, // back to ones that we do use. OP_PUSH, OP_POP, OP_NUMOPS, }; #define PRVM_EDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (prvm_eval_t *)((byte *)ed->progs.vp + fieldoffset) : NULL) #define PRVM_GLOBALFIELDVALUE(fieldoffset) (fieldoffset ? (prvm_eval_t *)((byte *)vm.prog->globals.gp + fieldoffset) : NULL) extern prvm_prog_t prvm_prog_list[PRVM_MAXPROGS]; //============================================================================ // prvm_cmds part extern prvm_builtin_t vm_sv_builtins[]; extern prvm_builtin_t vm_cl_builtins[]; extern prvm_builtin_t vm_m_builtins[]; extern const int vm_sv_numbuiltins; extern const int vm_cl_numbuiltins; extern const int vm_m_numbuiltins; extern char *vm_sv_extensions; extern char *vm_cl_extensions; extern char *vm_m_extensions; void VM_SV_Cmd_Init(void); void VM_SV_Cmd_Reset(void); void VM_CL_Cmd_Init(void); void VM_CL_Cmd_Reset(void); void VM_M_Cmd_Init(void); void VM_M_Cmd_Reset(void); void VM_Cmd_Init(void); void VM_Cmd_Reset(void); //============================================================================ // console commands void PRVM_ED_PrintEdicts_f( void ); void PRVM_ED_PrintEdict_f( void ); void PRVM_ED_EdictSet_f( void ); void PRVM_GlobalSet_f( void ); void PRVM_Decompile_f( void ); void PRVM_ED_Count_f( void ); void PRVM_Globals_f( void ); void PRVM_Compile_f( void ); void PRVM_Global_f( void ); void PRVM_Fields_f( void ); void PRVM_ExecuteProgram( func_t fnum, const char *name, const char *file, const int line ); #define PRVM_Alloc(buffersize) _PRVM_Alloc(buffersize, __FILE__, __LINE__) #define PRVM_Free(buffer) _PRVM_Free(buffer, __FILE__, __LINE__) #define PRVM_FreeAll() _PRVM_FreeAll(__FILE__, __LINE__) void *_PRVM_Alloc (size_t buffersize, const char *filename, int fileline); void _PRVM_Free (void *buffer, const char *filename, int fileline); void _PRVM_FreeAll (const char *filename, int fileline); void PRVM_Profile (int maxfunctions, int mininstructions); void PRVM_Profile_f (void); void PRVM_PrintFunction_f (void); void PRVM_PrintState(void); void PRVM_CrashAll (void); void PRVM_Crash (void); int PRVM_ED_FindFieldOffset(const char *field); int PRVM_ED_FindGlobalOffset(const char *global); ddef_t *PRVM_ED_FindField (const char *name); ddef_t *PRVM_ED_FindGlobal (const char *name); mfunction_t *PRVM_ED_FindFunction (const char *name); func_t PRVM_ED_FindFunctionOffset(const char *function); void PRVM_MEM_IncreaseEdicts(void); pr_edict_t *PRVM_ED_Alloc (void); void PRVM_ED_Free (pr_edict_t *ed); void PRVM_ED_ClearEdict (pr_edict_t *e); ddef_t *PRVM_ED_GlobalAtOfs( int ofs ); void PRVM_PrintFunctionStatements (const char *name); void PRVM_ED_Print(pr_edict_t *ed); void PRVM_ED_Write( pr_edict_t *ed, void *buffer, void *ptr, setpair_t callback ); void PRVM_ED_Read( int s_table, int ednum, dkeyvalue_t *fields, int numpairs ); const char *PRVM_ED_ParseEdict (const char *data, pr_edict_t *ent); char *PRVM_ValueString( etype_t type, prvm_eval_t *val ); void PRVM_ED_WriteGlobals( void *buffer, void *ptr, setpair_t callback ); void PRVM_ED_ReadGlobals( int s_table, dkeyvalue_t *globals, int numpairs ); void PRVM_ED_LoadFromFile( const char *data ); pr_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline); #define PRVM_EDICT_NUM(n) (((n) >= 0 && (n) < vm.prog->max_edicts) ? vm.prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) #define PRVM_EDICT_NUM_UNSIGNED(n) (((n) < vm.prog->max_edicts) ? vm.prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) #define PRVM_NUM_FOR_EDICT(e) ((int)((pr_edict_t *)(e) - vm.prog->edicts)) #define PRVM_NEXT_EDICT(e) ((e) + 1) #define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e)) #define PRVM_PROG_TO_EDICT(n) (PRVM_EDICT_NUM(n)) #define PRVM_ED_POINTER(p) (prvm_eval_t *)((byte *)vm.prog->edictsfields + p->_int) #define PRVM_EM_POINTER(p) (prvm_eval_t *)((byte *)vm.prog->edictsfields + (p)) #define PRVM_EV_POINTER(p) (prvm_eval_t *)(((byte *)vm.prog->edicts) + p->_int) // this is correct ??? #define PRVM_CHECK_PTR(p, size) if(prvm_boundscheck->value && (p->_int < 0 || p->_int + size > vm.prog->edictareasize))\ {\ vm.prog->xfunction->profile += (st - startst);\ vm.prog->xstatement = st - vm.prog->statements;\ PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, p->_int);\ return;\ } #define PRVM_CHECK_INFINITE() if (++jumpcount == 10000000)\ {\ vm.prog->xstatement = st - vm.prog->statements;\ PRVM_Profile(1<<30, 1000000);\ PRVM_ERROR("runaway loop counter hit limit of %d jumps\n", jumpcount, PRVM_NAME);\ } //============================================================================ // get arguments from progs #define PRVM_G_FLOAT(o) (vm.prog->globals.gp[o]) #define PRVM_G_INT(o) (*(int *)&vm.prog->globals.gp[o]) #define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(uint *)&vm.prog->globals.gp[o])) #define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o)) #define PRVM_G_VECTOR(o) (&vm.prog->globals.gp[o]) #define PRVM_G_STRING(o) (PRVM_GetString(*(string_t *)&vm.prog->globals.gp[o])) #define PRVM_G_FUNCTION(o) (*(func_t *)&vm.prog->globals.gp[o]) // FIXME: make these go away? #define PRVM_E_FLOAT(e,o) (((float*)e->progs.vp)[o]) #define PRVM_E_INT(e,o) (((int*)e->progs.vp)[o]) //#define PRVM_E_VECTOR(e,o) (&((float*)e->progs.vp)[o]) #define PRVM_E_STRING(e,o) (PRVM_GetString(*(string_t *)&((float*)e->progs.vp)[o])) extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to // make the new vm mostly independent from the old one, thus if it's necessary, I copy everything void PRVM_Init_Exec(void); void PRVM_StackTrace (void); void PRVM_ED_PrintEdicts_f (void); void PRVM_ED_PrintNum (int ent); const char *PRVM_GetString(int num); int PRVM_SetEngineString(const char *s); int PRVM_SetTempString( const char *s ); int PRVM_AllocString(size_t bufferlength, char **pointer); void PRVM_FreeString(int num); //============================================================================ #define PRVM_NAME (vm.prog->name ? vm.prog->name : "unnamed.dat") // helper macro to make function pointer calls easier #define PRVM_GCALL(func) if(vm.prog->func) vm.prog->func #define PRVM_ERROR if(vm.prog) vm.prog->error_cmd // other prog handling functions bool PRVM_SetProgFromString(const char *str); void PRVM_SetProg(int prognr); /* Initializing a vm: Call InitProg with the num Set up the fields marked with [INIT] in the prog struct Load a program with LoadProgs */ void PRVM_InitProg(int prognr); // LoadProgs expects to be called right after InitProg void PRVM_LoadProgs( const char *filename ); void PRVM_ResetProg( void ); bool PRVM_ProgLoaded(int prognr); int PRVM_GetProgNr(void); void VM_Warning(const char *fmt, ...); void VM_Error(const char *fmt, ...); // TODO: fill in the params //void PRVM_Create(); //============================================================================ // nice helper macros #endif//VPROGS_H