From b9e32ee2f5058b42631bbe376ee412cf31cf26e2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Jan 2022 11:38:21 +0900 Subject: [PATCH] [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. --- libs/gamecode/opcodes.py | 71 ++++++++++------------ libs/gamecode/pr_exec.c | 123 ++++++++++++++++++++++++++------------- 2 files changed, 116 insertions(+), 78 deletions(-) diff --git a/libs/gamecode/opcodes.py b/libs/gamecode/opcodes.py index 319859f1d..f7745c76c 100644 --- a/libs/gamecode/opcodes.py +++ b/libs/gamecode/opcodes.py @@ -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]) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 3d179c869..66b1f3818 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -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;