Add a stack and push and pop instructions.

The stack is for data, not return addresses.
This commit is contained in:
Bill Currie 2018-10-11 13:24:03 +09:00
parent 9501d30a8f
commit 364c2d2c2b
6 changed files with 785 additions and 21 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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) {

View file

@ -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);
}

View file

@ -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,

View file

@ -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;