mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
[gamecode] Rework call and return instructions
The call1-8 instructions have been removed as they are really not needed (they were put in when I had plans of simple translation of v6p progs to ruamoko, but they joined the dinosaurs). The call instruction lost mode A (that is now return) and its mode B is just the regular function access. The important thing is op_c (with support for with-bases) specifies the location of the return def. The return instruction packs both its addressing mode and return value size into st->c as a 3.5 value: 3 bits for the mode (it supports all five addressing modes with entity.field being mode 4) and 5 for the size, limiting return sizes to 32 words, which is enough for one 4x4 double matrix. This, especially with the following convert patch, frees up a lot of instructions.
This commit is contained in:
parent
ba29be3f82
commit
b9e32ee2f5
2 changed files with 116 additions and 78 deletions
|
@ -4,9 +4,13 @@ bitmap_txt = """
|
|||
0 0010 mmss push
|
||||
0 0011 mmss pop
|
||||
0 010c ccmm branch
|
||||
0 0110 0nnn rcall 1-8 (0 0100 11mm with 0 params for [r]call0)
|
||||
0 0110 10ss return
|
||||
0 0110 1100 returnv
|
||||
|
||||
# while call and return are part of the branch block, they have different
|
||||
# handling for addressing and formatting
|
||||
0 0101 11mm call (return specified st->c)
|
||||
0 0101 1100 return (size in st->c)
|
||||
|
||||
0 0110 0nnn
|
||||
0 0110 1101 with (mode in st->a, value in st->b, reg in st->c)
|
||||
0 0110 111t state
|
||||
0 0111 tooo vecops
|
||||
|
@ -115,7 +119,7 @@ branch_formats = {
|
|||
"args": {
|
||||
"op_mode": "ABCD",
|
||||
"op_cond": ["ifz", "ifb", "ifa", "jump",
|
||||
"ifnz", "ifae", "ifbe", "call"],
|
||||
"ifnz", "ifae", "ifbe", None], #call and return seprate
|
||||
"branch_fmt": branch_fmt,
|
||||
"cond_fmt": ["%Gc ", "%Gc ", "%Gc ", "", "%Gc ", "%Gc ", "%Gc ", ""],
|
||||
"cond_widths": [
|
||||
|
@ -130,6 +134,23 @@ branch_formats = {
|
|||
],
|
||||
},
|
||||
}
|
||||
call_formats = {
|
||||
"opcode": "OP_CALL_{op_mode[mm]}",
|
||||
"mnemonic": "call",
|
||||
"opname": "call",
|
||||
"format": "{call_fmt[mm]}",
|
||||
"widths": "0, 0, 0",
|
||||
"types": "ev_void, ev_void, ev_void",
|
||||
"args": {
|
||||
"op_mode": ".BCD",
|
||||
"call_fmt": [
|
||||
None, # return handled seprately
|
||||
"%Ga, %gc",
|
||||
"%Ga[%sb], %gc",
|
||||
"%Ga[%Gb], %gc",
|
||||
],
|
||||
},
|
||||
}
|
||||
compare_formats = {
|
||||
"opcode": "OP_{op_cmp[ccc].upper()}_{cmp_type[tt]}_{ss+1}",
|
||||
"mnemonic": "{op_cmp[ccc]}.{cmp_type[tt]}",
|
||||
|
@ -411,41 +432,13 @@ swizzle_formats = {
|
|||
"swizzle_types": float_t,
|
||||
},
|
||||
}
|
||||
rcall_formats = {
|
||||
"opcode": "OP_CALL_{nnn+1}",
|
||||
"mnemonic": "rcall{nnn+1}",
|
||||
"opname": "rcall{nnn+1}",
|
||||
"format": "{rcall_fmt[nnn]}",
|
||||
"widths": "0, 0, 0",
|
||||
"types": "ev_func, ev_void, ev_void",
|
||||
"args": {
|
||||
"rcall_fmt": [
|
||||
"%Fa (%P0b)",
|
||||
"%Fa (%P0b, %P1c)",
|
||||
"%Fa (%P0b, %P1c, %P2x)",
|
||||
"%Fa (%P0b, %P1c, %P2x, %P3x)",
|
||||
"%Fa (%P0b, %P1c, %P2x, %P3x, %P4x)",
|
||||
"%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x)",
|
||||
"%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x, %P6x)",
|
||||
"%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x, %P6x, %P7x)",
|
||||
],
|
||||
},
|
||||
}
|
||||
return_formats = {
|
||||
"opcode": "OP_RETURN_{ss+1}",
|
||||
"mnemonic": "return{ss+1}",
|
||||
"opname": "return",
|
||||
"widths": "0, 0, 0",
|
||||
"format": "%Ra",
|
||||
"types": "ev_void, ev_invalid, ev_invalid",
|
||||
}
|
||||
returnv_formats = {
|
||||
"opcode": "OP_RETURN_0",
|
||||
"opcode": "OP_RETURN",
|
||||
"mnemonic": "return",
|
||||
"opname": "return",
|
||||
"widths": "0, 0, 0",
|
||||
"format": None,
|
||||
"types": "ev_invalid, ev_invalid, ev_invalid",
|
||||
"widths": "0, 0, 0", # width specified by st->c
|
||||
"format": "FIXME",
|
||||
"types": "ev_void, ev_void, ev_void",
|
||||
}
|
||||
vecops_formats = {
|
||||
"opcode": "OP_{op_vop[ooo].upper()}_{vop_type[t]}",
|
||||
|
@ -497,6 +490,7 @@ group_map = {
|
|||
"bitops": bitops_formats,
|
||||
"boolops": boolops_formats,
|
||||
"branch": branch_formats,
|
||||
"call": call_formats,
|
||||
"compare": compare_formats,
|
||||
"compare2": compare2_formats,
|
||||
"convert": convert_formats,
|
||||
|
@ -518,9 +512,7 @@ group_map = {
|
|||
"store": store_formats,
|
||||
"string": string_formats,
|
||||
"swizzle": swizzle_formats,
|
||||
"rcall": rcall_formats,
|
||||
"return": return_formats,
|
||||
"returnv": returnv_formats,
|
||||
"vecops": vecops_formats,
|
||||
"vecops2": vecops2_formats,
|
||||
"with": with_formats,
|
||||
|
@ -601,7 +593,8 @@ if len (sys.argv) < 2 or sys.argv[1] not in ["enum", "table"]:
|
|||
|
||||
lines = bitmap_txt.split('\n')
|
||||
for l in lines:
|
||||
if not l:
|
||||
l = l.strip()
|
||||
if not l or l[0] == '#':
|
||||
continue
|
||||
c = l.split(' ')
|
||||
bits = "".join(c[0:3])
|
||||
|
|
|
@ -1793,6 +1793,68 @@ pr_address_mode (progs_t *pr, const dstatement_t *st, int shift)
|
|||
return pr->pr_globals + mm_offs;
|
||||
}
|
||||
|
||||
static pr_type_t *
|
||||
pr_return_mode (progs_t *pr, const dstatement_t *st, int mm_ind)
|
||||
{
|
||||
pr_type_t *op_a = pr->pr_globals + st->a + PR_BASE (pr, st, A);
|
||||
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, B);
|
||||
pointer_t mm_offs = 0;
|
||||
|
||||
switch (mm_ind) {
|
||||
case 0:
|
||||
// regular global access
|
||||
mm_offs = op_a - pr->pr_globals;
|
||||
break;
|
||||
case 1:
|
||||
// simple pointer dereference: *a
|
||||
mm_offs = OPA(uint);
|
||||
break;
|
||||
case 2:
|
||||
// constant indexed pointer: *a + b (supports -ve offset)
|
||||
mm_offs = OPA(uint) + (short) st->b;
|
||||
break;
|
||||
case 3:
|
||||
// variable indexed pointer: *a + *b (supports -ve offset)
|
||||
mm_offs = OPA(uint) + OPB(int);
|
||||
break;
|
||||
case 4:
|
||||
// entity.field (equivalent to OP_LOAD_t_v6p)
|
||||
pointer_t edict_area = pr->pr_edict_area - pr->pr_globals;
|
||||
mm_offs = edict_area + OPA(uint) + OPB(uint);
|
||||
break;
|
||||
}
|
||||
return pr->pr_globals + mm_offs;
|
||||
}
|
||||
|
||||
static pr_type_t *
|
||||
pr_call_mode (progs_t *pr, const dstatement_t *st, int mm_ind)
|
||||
{
|
||||
pr_type_t *op_a = pr->pr_globals + st->a + PR_BASE (pr, st, A);
|
||||
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, B);
|
||||
pointer_t mm_offs = 0;
|
||||
|
||||
switch (mm_ind) {
|
||||
case 1:
|
||||
// regular global access
|
||||
mm_offs = op_a - pr->pr_globals;
|
||||
break;
|
||||
case 2:
|
||||
// constant indexed pointer: *a + b (supports -ve offset)
|
||||
mm_offs = OPA(uint) + (short) st->b;
|
||||
break;
|
||||
case 3:
|
||||
// variable indexed pointer: *a + *b (supports -ve offset)
|
||||
mm_offs = OPA(uint) + OPB(int);
|
||||
break;
|
||||
case 4:
|
||||
// entity.field (equivalent to OP_LOAD_t_v6p)
|
||||
pointer_t edict_area = pr->pr_edict_area - pr->pr_globals;
|
||||
mm_offs = edict_area + OPA(uint) + OPB(uint);
|
||||
break;
|
||||
}
|
||||
return pr->pr_globals + mm_offs;
|
||||
}
|
||||
|
||||
static pr_pointer_t __attribute__((pure))
|
||||
pr_jump_mode (progs_t *pr, const dstatement_t *st)
|
||||
{
|
||||
|
@ -2880,45 +2942,12 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
|
|||
st = pr->pr_statements + pr->pr_xstatement;
|
||||
}
|
||||
break;
|
||||
case OP_CALL_A:
|
||||
case OP_CALL_B:
|
||||
case OP_CALL_C:
|
||||
case OP_CALL_D:
|
||||
mm = pr_address_mode (pr, st, 0);
|
||||
function = mm->func_var;
|
||||
pr->pr_argc = 0;
|
||||
op_call:
|
||||
pr->pr_xfunction->profile += profile - startprofile;
|
||||
startprofile = profile;
|
||||
PR_CallFunction (pr, function);
|
||||
st = pr->pr_statements + pr->pr_xstatement;
|
||||
break;
|
||||
// 0 0101
|
||||
case OP_CALL_2: case OP_CALL_3: case OP_CALL_4:
|
||||
case OP_CALL_5: case OP_CALL_6: case OP_CALL_7: case OP_CALL_8:
|
||||
pr->pr_params[1] = op_c;
|
||||
goto op_call_n;
|
||||
case OP_CALL_1:
|
||||
pr->pr_params[1] = pr->pr_real_params[1];
|
||||
op_call_n:
|
||||
pr->pr_params[0] = op_b;
|
||||
function = op_a->func_var;
|
||||
pr->pr_argc = st->op - OP_CALL_1 + 1;
|
||||
goto op_call;
|
||||
case OP_RETURN_4:
|
||||
memcpy (&R_INT (pr), op_a, 4 * sizeof (*op_a));
|
||||
goto op_return;
|
||||
case OP_RETURN_3:
|
||||
memcpy (&R_INT (pr), op_a, 3 * sizeof (*op_a));
|
||||
goto op_return;
|
||||
case OP_RETURN_2:
|
||||
memcpy (&R_INT (pr), op_a, 2 * sizeof (*op_a));
|
||||
goto op_return;
|
||||
case OP_RETURN_1:
|
||||
memcpy (&R_INT (pr), op_a, 1 * sizeof (*op_a));
|
||||
goto op_return;
|
||||
case OP_RETURN_0:
|
||||
op_return:
|
||||
case OP_RETURN:
|
||||
int ret_size = st->c & 0x1f; // up to 32 words
|
||||
if (ret_size) {
|
||||
mm = pr_return_mode (pr, st, (st->c >> 5) & 7);
|
||||
memcpy (&R_INT (pr), mm, ret_size * sizeof (*op_a));
|
||||
}
|
||||
pr->pr_xfunction->profile += profile - startprofile;
|
||||
startprofile = profile;
|
||||
PR_LeaveFunction (pr, pr->pr_depth == exitdepth);
|
||||
|
@ -2930,6 +2959,22 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
|
|||
goto exit_program;
|
||||
}
|
||||
break;
|
||||
case OP_CALL_B:
|
||||
case OP_CALL_C:
|
||||
case OP_CALL_D:
|
||||
mm = pr_call_mode (pr, st, st->c & 3);
|
||||
function = mm->func_var;
|
||||
pr->pr_argc = 0;
|
||||
// op_c specifies the location for the return value if any
|
||||
pr->pr_return = op_c;
|
||||
pr->pr_xfunction->profile += profile - startprofile;
|
||||
startprofile = profile;
|
||||
PR_CallFunction (pr, function);
|
||||
st = pr->pr_statements + pr->pr_xstatement;
|
||||
break;
|
||||
// 0 0101
|
||||
// nnn spare
|
||||
//OP_CONV
|
||||
case OP_WITH:
|
||||
pr->pr_bases[st->c & 3] = pr_with (pr, st);
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue