mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-21 11:11:37 +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 0010 mmss push
|
||||||
0 0011 mmss pop
|
0 0011 mmss pop
|
||||||
0 010c ccmm branch
|
0 010c ccmm branch
|
||||||
0 0110 0nnn rcall 1-8 (0 0100 11mm with 0 params for [r]call0)
|
|
||||||
0 0110 10ss return
|
# while call and return are part of the branch block, they have different
|
||||||
0 0110 1100 returnv
|
# 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 1101 with (mode in st->a, value in st->b, reg in st->c)
|
||||||
0 0110 111t state
|
0 0110 111t state
|
||||||
0 0111 tooo vecops
|
0 0111 tooo vecops
|
||||||
|
@ -115,7 +119,7 @@ branch_formats = {
|
||||||
"args": {
|
"args": {
|
||||||
"op_mode": "ABCD",
|
"op_mode": "ABCD",
|
||||||
"op_cond": ["ifz", "ifb", "ifa", "jump",
|
"op_cond": ["ifz", "ifb", "ifa", "jump",
|
||||||
"ifnz", "ifae", "ifbe", "call"],
|
"ifnz", "ifae", "ifbe", None], #call and return seprate
|
||||||
"branch_fmt": branch_fmt,
|
"branch_fmt": branch_fmt,
|
||||||
"cond_fmt": ["%Gc ", "%Gc ", "%Gc ", "", "%Gc ", "%Gc ", "%Gc ", ""],
|
"cond_fmt": ["%Gc ", "%Gc ", "%Gc ", "", "%Gc ", "%Gc ", "%Gc ", ""],
|
||||||
"cond_widths": [
|
"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 = {
|
compare_formats = {
|
||||||
"opcode": "OP_{op_cmp[ccc].upper()}_{cmp_type[tt]}_{ss+1}",
|
"opcode": "OP_{op_cmp[ccc].upper()}_{cmp_type[tt]}_{ss+1}",
|
||||||
"mnemonic": "{op_cmp[ccc]}.{cmp_type[tt]}",
|
"mnemonic": "{op_cmp[ccc]}.{cmp_type[tt]}",
|
||||||
|
@ -411,41 +432,13 @@ swizzle_formats = {
|
||||||
"swizzle_types": float_t,
|
"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 = {
|
return_formats = {
|
||||||
"opcode": "OP_RETURN_{ss+1}",
|
"opcode": "OP_RETURN",
|
||||||
"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",
|
|
||||||
"mnemonic": "return",
|
"mnemonic": "return",
|
||||||
"opname": "return",
|
"opname": "return",
|
||||||
"widths": "0, 0, 0",
|
"widths": "0, 0, 0", # width specified by st->c
|
||||||
"format": None,
|
"format": "FIXME",
|
||||||
"types": "ev_invalid, ev_invalid, ev_invalid",
|
"types": "ev_void, ev_void, ev_void",
|
||||||
}
|
}
|
||||||
vecops_formats = {
|
vecops_formats = {
|
||||||
"opcode": "OP_{op_vop[ooo].upper()}_{vop_type[t]}",
|
"opcode": "OP_{op_vop[ooo].upper()}_{vop_type[t]}",
|
||||||
|
@ -497,6 +490,7 @@ group_map = {
|
||||||
"bitops": bitops_formats,
|
"bitops": bitops_formats,
|
||||||
"boolops": boolops_formats,
|
"boolops": boolops_formats,
|
||||||
"branch": branch_formats,
|
"branch": branch_formats,
|
||||||
|
"call": call_formats,
|
||||||
"compare": compare_formats,
|
"compare": compare_formats,
|
||||||
"compare2": compare2_formats,
|
"compare2": compare2_formats,
|
||||||
"convert": convert_formats,
|
"convert": convert_formats,
|
||||||
|
@ -518,9 +512,7 @@ group_map = {
|
||||||
"store": store_formats,
|
"store": store_formats,
|
||||||
"string": string_formats,
|
"string": string_formats,
|
||||||
"swizzle": swizzle_formats,
|
"swizzle": swizzle_formats,
|
||||||
"rcall": rcall_formats,
|
|
||||||
"return": return_formats,
|
"return": return_formats,
|
||||||
"returnv": returnv_formats,
|
|
||||||
"vecops": vecops_formats,
|
"vecops": vecops_formats,
|
||||||
"vecops2": vecops2_formats,
|
"vecops2": vecops2_formats,
|
||||||
"with": with_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')
|
lines = bitmap_txt.split('\n')
|
||||||
for l in lines:
|
for l in lines:
|
||||||
if not l:
|
l = l.strip()
|
||||||
|
if not l or l[0] == '#':
|
||||||
continue
|
continue
|
||||||
c = l.split(' ')
|
c = l.split(' ')
|
||||||
bits = "".join(c[0:3])
|
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;
|
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))
|
static pr_pointer_t __attribute__((pure))
|
||||||
pr_jump_mode (progs_t *pr, const dstatement_t *st)
|
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;
|
st = pr->pr_statements + pr->pr_xstatement;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_CALL_A:
|
case OP_RETURN:
|
||||||
case OP_CALL_B:
|
int ret_size = st->c & 0x1f; // up to 32 words
|
||||||
case OP_CALL_C:
|
if (ret_size) {
|
||||||
case OP_CALL_D:
|
mm = pr_return_mode (pr, st, (st->c >> 5) & 7);
|
||||||
mm = pr_address_mode (pr, st, 0);
|
memcpy (&R_INT (pr), mm, ret_size * sizeof (*op_a));
|
||||||
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:
|
|
||||||
pr->pr_xfunction->profile += profile - startprofile;
|
pr->pr_xfunction->profile += profile - startprofile;
|
||||||
startprofile = profile;
|
startprofile = profile;
|
||||||
PR_LeaveFunction (pr, pr->pr_depth == exitdepth);
|
PR_LeaveFunction (pr, pr->pr_depth == exitdepth);
|
||||||
|
@ -2930,6 +2959,22 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
|
||||||
goto exit_program;
|
goto exit_program;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case OP_WITH:
|
||||||
pr->pr_bases[st->c & 3] = pr_with (pr, st);
|
pr->pr_bases[st->c & 3] = pr_with (pr, st);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue