[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:
Bill Currie 2022-01-10 11:38:21 +09:00
parent ba29be3f82
commit b9e32ee2f5
2 changed files with 116 additions and 78 deletions

View file

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

View file

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