mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
Add a stack and push and pop instructions.
The stack is for data, not return addresses.
This commit is contained in:
parent
9501d30a8f
commit
364c2d2c2b
6 changed files with 785 additions and 21 deletions
|
@ -295,6 +295,66 @@ typedef enum {
|
|||
OP_RCALL8,
|
||||
|
||||
OP_RETURN_V,
|
||||
|
||||
OP_PUSH_S,
|
||||
OP_PUSH_F,
|
||||
OP_PUSH_V,
|
||||
OP_PUSH_ENT,
|
||||
OP_PUSH_FLD,
|
||||
OP_PUSH_FN,
|
||||
OP_PUSH_P,
|
||||
OP_PUSH_Q,
|
||||
OP_PUSH_I,
|
||||
|
||||
OP_PUSHB_S,
|
||||
OP_PUSHB_F,
|
||||
OP_PUSHB_V,
|
||||
OP_PUSHB_ENT,
|
||||
OP_PUSHB_FLD,
|
||||
OP_PUSHB_FN,
|
||||
OP_PUSHB_P,
|
||||
OP_PUSHB_Q,
|
||||
OP_PUSHB_I,
|
||||
|
||||
OP_PUSHBI_S,
|
||||
OP_PUSHBI_F,
|
||||
OP_PUSHBI_V,
|
||||
OP_PUSHBI_ENT,
|
||||
OP_PUSHBI_FLD,
|
||||
OP_PUSHBI_FN,
|
||||
OP_PUSHBI_P,
|
||||
OP_PUSHBI_Q,
|
||||
OP_PUSHBI_I,
|
||||
|
||||
OP_POP_S,
|
||||
OP_POP_F,
|
||||
OP_POP_V,
|
||||
OP_POP_ENT,
|
||||
OP_POP_FLD,
|
||||
OP_POP_FN,
|
||||
OP_POP_P,
|
||||
OP_POP_Q,
|
||||
OP_POP_I,
|
||||
|
||||
OP_POPB_S,
|
||||
OP_POPB_F,
|
||||
OP_POPB_V,
|
||||
OP_POPB_ENT,
|
||||
OP_POPB_FLD,
|
||||
OP_POPB_FN,
|
||||
OP_POPB_P,
|
||||
OP_POPB_Q,
|
||||
OP_POPB_I,
|
||||
|
||||
OP_POPBI_S,
|
||||
OP_POPBI_F,
|
||||
OP_POPBI_V,
|
||||
OP_POPBI_ENT,
|
||||
OP_POPBI_FLD,
|
||||
OP_POPBI_FN,
|
||||
OP_POPBI_P,
|
||||
OP_POPBI_Q,
|
||||
OP_POPBI_I,
|
||||
} pr_opcode_e;
|
||||
|
||||
typedef struct opcode_s {
|
||||
|
|
|
@ -1612,6 +1612,19 @@ struct progs_s {
|
|||
prstack_t pr_stack[MAX_STACK_DEPTH];
|
||||
int pr_depth;
|
||||
|
||||
/// \name progs visible stack
|
||||
/// Usable by the progs for any purpose. Will not be accessible unless
|
||||
/// a .stack global is found. Space is allocated from the top of the stack
|
||||
/// (as is common for hardware). The push and pop instructions will not
|
||||
/// be considered valid if there is no .stack global.
|
||||
/// \note The return address and saved locals will not ever be on this
|
||||
/// stack.
|
||||
//@{
|
||||
pr_type_t *stack;
|
||||
pointer_t stack_bottom;
|
||||
int stack_size; ///< set by user
|
||||
//@}
|
||||
|
||||
int localstack[LOCALSTACK_SIZE];
|
||||
int localstack_used;
|
||||
//@}
|
||||
|
@ -1656,6 +1669,7 @@ struct progs_s {
|
|||
struct {
|
||||
float *time; ///< required for OP_STATE
|
||||
pr_int_t *self; ///< required for OP_STATE
|
||||
pointer_t *stack; ///< required for OP_(PUSH|POP)*
|
||||
} globals;
|
||||
struct {
|
||||
pr_int_t nextthink; ///< required for OP_STATE
|
||||
|
|
|
@ -358,13 +358,24 @@ PR_CallFunction (progs_t *pr, func_t fnum)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_stack_pointer (progs_t *pr, pointer_t stack, int size)
|
||||
{
|
||||
if (stack < pr->stack_bottom) {
|
||||
PR_RunError (pr, "Progs stack overflow");
|
||||
}
|
||||
if (stack > pr->globals_size - size) {
|
||||
PR_RunError (pr, "Progs stack underflow");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
PR_ExecuteProgram
|
||||
|
||||
The interpretation main loop
|
||||
*/
|
||||
VISIBLE void
|
||||
PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
||||
PR_ExecuteProgram (progs_t *pr, func_t fnum)
|
||||
{
|
||||
int exitdepth, profile, startprofile;
|
||||
pr_uint_t pointer;
|
||||
|
@ -859,6 +870,318 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
|||
QuatCopy (OPA.quat_var, ptr->quat_var);
|
||||
break;
|
||||
|
||||
case OP_PUSH_F:
|
||||
case OP_PUSH_FLD:
|
||||
case OP_PUSH_ENT:
|
||||
case OP_PUSH_S:
|
||||
case OP_PUSH_FN:
|
||||
case OP_PUSH_I:
|
||||
case OP_PUSH_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 1;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
}
|
||||
stk->integer_var = OPA.integer_var;
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSH_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 3;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
}
|
||||
memcpy (stk, &OPA, 3 * sizeof (OPC));
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSH_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 4;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
}
|
||||
memcpy (stk, &OPA, 4 * sizeof (OPC));
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_PUSHB_F:
|
||||
case OP_PUSHB_S:
|
||||
case OP_PUSHB_ENT:
|
||||
case OP_PUSHB_FLD:
|
||||
case OP_PUSHB_FN:
|
||||
case OP_PUSHB_I:
|
||||
case OP_PUSHB_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 1;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
stk->integer_var = ptr->integer_var;
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSHB_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 3;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
VectorCopy (ptr->vector_var, stk->vector_var);
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSHB_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 4;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
PR_BoundsCheck (pr, pointer, ev_quat);
|
||||
}
|
||||
|
||||
QuatCopy (ptr->quat_var, stk->quat_var);
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_PUSHBI_F:
|
||||
case OP_PUSHBI_S:
|
||||
case OP_PUSHBI_ENT:
|
||||
case OP_PUSHBI_FLD:
|
||||
case OP_PUSHBI_FN:
|
||||
case OP_PUSHBI_I:
|
||||
case OP_PUSHBI_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 1;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
stk->integer_var = ptr->integer_var;
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSHBI_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 3;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
VectorCopy (ptr->vector_var, stk->vector_var);
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
case OP_PUSHBI_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack - 4;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
PR_BoundsCheck (pr, pointer, ev_quat);
|
||||
}
|
||||
|
||||
QuatCopy (ptr->quat_var, stk->quat_var);
|
||||
*pr->globals.stack = stack;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POP_F:
|
||||
case OP_POP_FLD:
|
||||
case OP_POP_ENT:
|
||||
case OP_POP_S:
|
||||
case OP_POP_FN:
|
||||
case OP_POP_I:
|
||||
case OP_POP_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
}
|
||||
stk->integer_var = OPA.integer_var;
|
||||
*pr->globals.stack = stack + 1;
|
||||
}
|
||||
break;
|
||||
case OP_POP_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
}
|
||||
memcpy (stk, &OPA, 3 * sizeof (OPC));
|
||||
*pr->globals.stack = stack + 3;
|
||||
}
|
||||
break;
|
||||
case OP_POP_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
}
|
||||
memcpy (stk, &OPA, 4 * sizeof (OPC));
|
||||
*pr->globals.stack = stack + 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POPB_F:
|
||||
case OP_POPB_S:
|
||||
case OP_POPB_ENT:
|
||||
case OP_POPB_FLD:
|
||||
case OP_POPB_FN:
|
||||
case OP_POPB_I:
|
||||
case OP_POPB_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
stk->integer_var = ptr->integer_var;
|
||||
*pr->globals.stack = stack + 1;
|
||||
}
|
||||
break;
|
||||
case OP_POPB_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
VectorCopy (ptr->vector_var, stk->vector_var);
|
||||
*pr->globals.stack = stack + 3;
|
||||
}
|
||||
break;
|
||||
case OP_POPB_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + OPB.integer_var;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
PR_BoundsCheck (pr, pointer, ev_quat);
|
||||
}
|
||||
|
||||
QuatCopy (ptr->quat_var, stk->quat_var);
|
||||
*pr->globals.stack = stack + 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POPBI_F:
|
||||
case OP_POPBI_S:
|
||||
case OP_POPBI_ENT:
|
||||
case OP_POPBI_FLD:
|
||||
case OP_POPBI_FN:
|
||||
case OP_POPBI_I:
|
||||
case OP_POPBI_P:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 1);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
stk->integer_var = ptr->integer_var;
|
||||
*pr->globals.stack = stack + 1;
|
||||
}
|
||||
break;
|
||||
case OP_POPBI_V:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 3);
|
||||
PR_BoundsCheck (pr, pointer, ev_integer);
|
||||
}
|
||||
|
||||
VectorCopy (ptr->vector_var, stk->vector_var);
|
||||
*pr->globals.stack = stack + 3;
|
||||
}
|
||||
break;
|
||||
case OP_POPBI_Q:
|
||||
{
|
||||
pointer_t stack = *pr->globals.stack;
|
||||
pr_type_t *stk = pr->pr_globals + stack;
|
||||
|
||||
pointer = OPA.integer_var + st->b;
|
||||
ptr = pr->pr_globals + pointer;
|
||||
|
||||
if (pr_boundscheck->int_val) {
|
||||
check_stack_pointer (pr, stack, 4);
|
||||
PR_BoundsCheck (pr, pointer, ev_quat);
|
||||
}
|
||||
|
||||
QuatCopy (ptr->quat_var, stk->quat_var);
|
||||
*pr->globals.stack = stack + 4;
|
||||
}
|
||||
break;
|
||||
|
||||
// ==================
|
||||
case OP_IFNOT:
|
||||
if (!OPA.integer_var) {
|
||||
|
|
|
@ -97,6 +97,17 @@ free_progs_mem (progs_t *pr, void *mem)
|
|||
{
|
||||
}
|
||||
|
||||
static int
|
||||
align_size (int size)
|
||||
{
|
||||
// round off to next highest whole word address (esp for Alpha)
|
||||
// this ensures that pointers in the engine data area are always
|
||||
// properly aligned
|
||||
size += sizeof (void*) - 1;
|
||||
size &= ~(sizeof (void*) - 1);
|
||||
return size;
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
|
||||
{
|
||||
|
@ -160,33 +171,27 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
|
|||
// size of progs themselves
|
||||
pr->progs_size = size + offset_tweak;
|
||||
Sys_MaskPrintf (SYS_DEV, "Programs occupy %iK.\n", size / 1024);
|
||||
// round off to next highest whole word address (esp for Alpha)
|
||||
// this ensures that pointers in the engine data area are always
|
||||
// properly aligned
|
||||
pr->progs_size += sizeof (void*) - 1;
|
||||
pr->progs_size &= ~(sizeof (void*) - 1);
|
||||
|
||||
// round off to next highest whole word address (esp for Alpha)
|
||||
// this ensures that pointers in the engine data area are always
|
||||
// properly aligned
|
||||
pr->zone_size += sizeof (void*) - 1;
|
||||
pr->zone_size &= ~(sizeof (void*) - 1);
|
||||
pr->progs_size = align_size (pr->progs_size);
|
||||
pr->zone_size = align_size (pr->zone_size);
|
||||
pr->stack_size = align_size (pr->stack_size);
|
||||
|
||||
// size of edict asked for by progs
|
||||
pr->pr_edict_size = max (1, progs.entityfields) * 4;
|
||||
// size of engine data
|
||||
pr->pr_edict_size += sizeof (edict_t);
|
||||
// round off to next highest whole word address (esp for Alpha)
|
||||
// this ensures that pointers in the engine data area are always
|
||||
// properly aligned
|
||||
pr->pr_edict_size += sizeof (void*) - 1;
|
||||
pr->pr_edict_size &= ~(sizeof (void*) - 1);
|
||||
pr->pr_edict_size = align_size (pr->progs_size);
|
||||
|
||||
pr->pr_edictareasize = pr->max_edicts * pr->pr_edict_size;
|
||||
|
||||
mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize;
|
||||
mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize
|
||||
+ pr->stack_size;
|
||||
// +1 for a nul terminator
|
||||
pr->progs = pr->allocate_progs_mem (pr, mem_size + 1);
|
||||
if (!pr->progs)
|
||||
return;
|
||||
// Place a nul at the end of progs memory to ensure any unterminated
|
||||
// strings within progs memory don't run off the end.
|
||||
((byte *) pr->progs)[mem_size] = 0;
|
||||
|
||||
memcpy (pr->progs, &progs, sizeof (progs));
|
||||
|
@ -195,8 +200,10 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
|
|||
CRC_ProcessBlock (base, &pr->crc, size - sizeof (progs));
|
||||
base -= sizeof (progs); // offsets are from file start
|
||||
|
||||
if (pr->edicts)
|
||||
if (pr->edicts) {
|
||||
*pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size);
|
||||
}
|
||||
|
||||
if (pr->zone_size) {
|
||||
//FIXME zone_size needs to be at least as big as memzone_t, but
|
||||
//memzone_t is opaque so its size is unknown
|
||||
|
@ -213,9 +220,11 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
|
|||
pr->pr_statements = (dstatement_t *) (base + pr->progs->ofs_statements);
|
||||
|
||||
pr->pr_globals = (pr_type_t *) (base + pr->progs->ofs_globals);
|
||||
|
||||
pr->globals_size = (pr_type_t*)((byte *) pr->zone + pr->zone_size)
|
||||
pr->stack = (pr_type_t *) ((byte *) pr->zone + pr->zone_size);
|
||||
pr->stack_bottom = pr->stack - pr->pr_globals;
|
||||
pr->globals_size = (pr_type_t *) ((byte *) pr->stack + pr->stack_size)
|
||||
- pr->pr_globals;
|
||||
|
||||
if (pr->zone) {
|
||||
PR_Zone_Init (pr);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include "QF/progs.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
hashtab_t *opcode_table;
|
||||
|
||||
VISIBLE int pr_type_size[ev_type_count] = {
|
||||
|
@ -1041,6 +1043,282 @@ VISIBLE opcode_t pr_opcodes[] = {
|
|||
"%Ga, %Gb, %Gc",
|
||||
},
|
||||
|
||||
{"<PUSH>", "push.s", OP_PUSH_S, false,
|
||||
ev_string, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.f", OP_PUSH_F, false,
|
||||
ev_float, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.v", OP_PUSH_V, false,
|
||||
ev_vector, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.ent", OP_PUSH_ENT, false,
|
||||
ev_entity, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.fld", OP_PUSH_FLD, false,
|
||||
ev_field, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.fn", OP_PUSH_FN, false,
|
||||
ev_func, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.p", OP_PUSH_P, false,
|
||||
ev_pointer, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.q", OP_PUSH_Q, false,
|
||||
ev_quat, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
{"<PUSH>", "push.i", OP_PUSH_I, false,
|
||||
ev_integer, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%Ga",
|
||||
},
|
||||
|
||||
{"<PUSH>", "pushb.s", OP_PUSHB_S, false,
|
||||
ev_pointer, ev_integer, ev_string,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.f", OP_PUSHB_F, false,
|
||||
ev_pointer, ev_integer, ev_float,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.v", OP_PUSHB_V, false,
|
||||
ev_pointer, ev_integer, ev_vector,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.ent", OP_PUSHB_ENT, false,
|
||||
ev_pointer, ev_integer, ev_entity,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.fld", OP_PUSHB_FLD, false,
|
||||
ev_pointer, ev_integer, ev_field,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.fn", OP_PUSHB_FN, false,
|
||||
ev_pointer, ev_integer, ev_func,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.p", OP_PUSHB_P, false,
|
||||
ev_pointer, ev_integer, ev_pointer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.q", OP_PUSHB_Q, false,
|
||||
ev_pointer, ev_integer, ev_quat,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<PUSH>", "pushb.i", OP_PUSHB_I, false,
|
||||
ev_pointer, ev_integer, ev_integer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
|
||||
{"<PUSH>", "pushbi.s", OP_PUSHBI_S, false,
|
||||
ev_pointer, ev_short, ev_string,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.f", OP_PUSHBI_F, false,
|
||||
ev_pointer, ev_short, ev_float,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.v", OP_PUSHBI_V, false,
|
||||
ev_pointer, ev_short, ev_vector,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.ent", OP_PUSHBI_ENT, false,
|
||||
ev_pointer, ev_short, ev_entity,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.fld", OP_PUSHBI_FLD, false,
|
||||
ev_pointer, ev_short, ev_field,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.fn", OP_PUSHBI_FN, false,
|
||||
ev_pointer, ev_short, ev_func,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.p", OP_PUSHBI_P, false,
|
||||
ev_pointer, ev_short, ev_pointer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.q", OP_PUSHBI_Q, false,
|
||||
ev_pointer, ev_short, ev_quat,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<PUSH>", "pushbi.i", OP_PUSHBI_I, false,
|
||||
ev_pointer, ev_short, ev_integer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
|
||||
{"<POP>", "pop.s", OP_POP_S, false,
|
||||
ev_string, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.f", OP_POP_F, false,
|
||||
ev_float, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.v", OP_POP_V, false,
|
||||
ev_vector, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.ent", OP_POP_ENT, false,
|
||||
ev_entity, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.fld", OP_POP_FLD, false,
|
||||
ev_field, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.fn", OP_POP_FN, false,
|
||||
ev_func, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.p", OP_POP_P, false,
|
||||
ev_pointer, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.q", OP_POP_Q, false,
|
||||
ev_quat, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
{"<POP>", "pop.i", OP_POP_I, false,
|
||||
ev_integer, ev_invalid, ev_invalid,
|
||||
PROG_VERSION,
|
||||
"%ga",
|
||||
},
|
||||
|
||||
{"<POP>", "popb.s", OP_POPB_S, false,
|
||||
ev_pointer, ev_integer, ev_string,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.f", OP_POPB_F, false,
|
||||
ev_pointer, ev_integer, ev_float,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.v", OP_POPB_V, false,
|
||||
ev_pointer, ev_integer, ev_vector,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.ent", OP_POPB_ENT, false,
|
||||
ev_pointer, ev_integer, ev_entity,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.fld", OP_POPB_FLD, false,
|
||||
ev_pointer, ev_integer, ev_field,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.fn", OP_POPB_FN, false,
|
||||
ev_pointer, ev_integer, ev_func,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.p", OP_POPB_P, false,
|
||||
ev_pointer, ev_integer, ev_pointer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.q", OP_POPB_Q, false,
|
||||
ev_pointer, ev_integer, ev_quat,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
{"<POP>", "popb.i", OP_POPB_I, false,
|
||||
ev_pointer, ev_integer, ev_integer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %Gb)",
|
||||
},
|
||||
|
||||
{"<POP>", "popbi.s", OP_POPBI_S, false,
|
||||
ev_pointer, ev_short, ev_string,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.f", OP_POPBI_F, false,
|
||||
ev_pointer, ev_short, ev_float,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.v", OP_POPBI_V, false,
|
||||
ev_pointer, ev_short, ev_vector,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.ent", OP_POPBI_ENT, false,
|
||||
ev_pointer, ev_short, ev_entity,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.fld", OP_POPBI_FLD, false,
|
||||
ev_pointer, ev_short, ev_field,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.fn", OP_POPBI_FN, false,
|
||||
ev_pointer, ev_short, ev_func,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.p", OP_POPBI_P, false,
|
||||
ev_pointer, ev_short, ev_pointer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.q", OP_POPBI_Q, false,
|
||||
ev_pointer, ev_short, ev_quat,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
{"<POP>", "popbi.i", OP_POPBI_I, false,
|
||||
ev_pointer, ev_short, ev_integer,
|
||||
PROG_VERSION,
|
||||
"*(%Ga + %sb)",
|
||||
},
|
||||
|
||||
// end of table
|
||||
{0},
|
||||
};
|
||||
|
@ -1192,11 +1470,16 @@ PR_Check_Opcodes (progs_t *pr)
|
|||
opcode_t *op;
|
||||
dstatement_t *st;
|
||||
int state_ok = 0;
|
||||
int pushpop_ok = 0;
|
||||
pr_uint_t i;
|
||||
|
||||
if (pr->globals.time && pr->globals.self && pr->fields.nextthink != -1
|
||||
&& pr->fields.think != -1 && pr->fields.frame != -1)
|
||||
&& pr->fields.think != -1 && pr->fields.frame != -1) {
|
||||
state_ok = 1;
|
||||
}
|
||||
if (pr->globals.stack) {
|
||||
pushpop_ok = 1;
|
||||
}
|
||||
|
||||
//FIXME need to decide if I really want to always do static bounds checking
|
||||
// the only problem is that it slows progs load a little, but it's the only
|
||||
|
@ -1214,6 +1497,11 @@ PR_Check_Opcodes (progs_t *pr)
|
|||
PR_Error (pr, "PR_Check_Opcodes: %s used with missing fields "
|
||||
"or globals", op->opname);
|
||||
}
|
||||
if ((strequal(op->name, "<PUSH>") || strequal(op->name, "<POP>"))
|
||||
&& !pushpop_ok) {
|
||||
PR_Error (pr, "PR_Check_Opcodes: %s used with missing .stack "
|
||||
"globals", op->opname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements;
|
||||
|
@ -1267,6 +1555,69 @@ PR_Check_Opcodes (progs_t *pr)
|
|||
check_global_size (pr, st, op, st->b, st->a);
|
||||
check_global_size (pr, st, op, st->b, st->c);
|
||||
break;
|
||||
case OP_PUSHB_F:
|
||||
case OP_PUSHB_S:
|
||||
case OP_PUSHB_ENT:
|
||||
case OP_PUSHB_FLD:
|
||||
case OP_PUSHB_FN:
|
||||
case OP_PUSHB_I:
|
||||
case OP_PUSHB_P:
|
||||
case OP_PUSHB_V:
|
||||
case OP_PUSHB_Q:
|
||||
case OP_PUSHBI_F:
|
||||
case OP_PUSHBI_S:
|
||||
case OP_PUSHBI_ENT:
|
||||
case OP_PUSHBI_FLD:
|
||||
case OP_PUSHBI_FN:
|
||||
case OP_PUSHBI_I:
|
||||
case OP_PUSHBI_P:
|
||||
case OP_PUSHBI_V:
|
||||
case OP_PUSHBI_Q:
|
||||
// op->type_c is used for selecting the operator during
|
||||
// compilation, but is invalid when running
|
||||
check_global (pr, st, op, op->type_a, st->a, 1);
|
||||
check_global (pr, st, op, op->type_b, st->b, 1);
|
||||
check_global (pr, st, op, ev_invalid, st->c, 1);
|
||||
break;
|
||||
case OP_POP_F:
|
||||
case OP_POP_FLD:
|
||||
case OP_POP_ENT:
|
||||
case OP_POP_S:
|
||||
case OP_POP_FN:
|
||||
case OP_POP_I:
|
||||
case OP_POP_P:
|
||||
case OP_POP_V:
|
||||
case OP_POP_Q:
|
||||
// don't want to check for denormal floats, otherwise
|
||||
// OP_POP_* could use the defualt rule
|
||||
check_global (pr, st, op, op->type_a, st->a, 0);
|
||||
check_global (pr, st, op, ev_invalid, st->b, 1);
|
||||
check_global (pr, st, op, ev_invalid, st->c, 1);
|
||||
break;
|
||||
case OP_POPB_F:
|
||||
case OP_POPB_S:
|
||||
case OP_POPB_ENT:
|
||||
case OP_POPB_FLD:
|
||||
case OP_POPB_FN:
|
||||
case OP_POPB_I:
|
||||
case OP_POPB_P:
|
||||
case OP_POPB_V:
|
||||
case OP_POPB_Q:
|
||||
case OP_POPBI_F:
|
||||
case OP_POPBI_S:
|
||||
case OP_POPBI_ENT:
|
||||
case OP_POPBI_FLD:
|
||||
case OP_POPBI_FN:
|
||||
case OP_POPBI_I:
|
||||
case OP_POPBI_P:
|
||||
case OP_POPBI_V:
|
||||
case OP_POPBI_Q:
|
||||
// op->type_c is used for selecting the operator during
|
||||
// compilation, but is invalid when running
|
||||
check_global (pr, st, op, op->type_a, st->a, 1);
|
||||
check_global (pr, st, op, op->type_b, st->b, 1);
|
||||
check_global (pr, st, op, ev_invalid, st->c, 1);
|
||||
break;
|
||||
default:
|
||||
check_global (pr, st, op, op->type_a, st->a, 1);
|
||||
check_global (pr, st, op, op->type_b, st->b,
|
||||
|
|
|
@ -149,6 +149,13 @@ PR_ResolveGlobals (progs_t *pr)
|
|||
|| (def = PR_FindGlobal (pr, "self")))
|
||||
pr->globals.self = &G_INT (pr, def->ofs);
|
||||
}
|
||||
if (!pr->globals.stack) {
|
||||
if ((def = PR_FindGlobal (pr, ".stack"))
|
||||
|| (def = PR_FindGlobal (pr, "stack")))
|
||||
pr->globals.stack = &G_POINTER (pr, def->ofs);
|
||||
// the stack is at the very end of the progs memory map
|
||||
*pr->globals.stack = pr->globals_size;
|
||||
}
|
||||
if (pr->fields.nextthink == -1)
|
||||
if ((def = PR_FindField (pr, "nextthink")))
|
||||
pr->fields.nextthink = def->ofs;
|
||||
|
|
Loading…
Reference in a new issue