[gamecode] Implement the conversion instructions

Not all possibilities are supported because converting between int and
uint, and long and ulong is essentially a no-op. However, thanks to
Deek's suggestion, not only are all reasonable conversions available,
conversions for all widths are available, so vector conversions are
supported.

The code for the conversions is generated.
This commit is contained in:
Bill Currie 2022-01-10 17:01:14 +09:00
parent f7181a09b4
commit 3587b13a40
3 changed files with 95 additions and 12 deletions

View file

@ -31,7 +31,10 @@ pr_opcode_src = \
${pr_opcode_hinc}
libs/gamecode/pr_opcode.lo: libs/gamecode/pr_opcode.c ${pr_opcode_src}
BUILT_SOURCES += $(pr_opcode_cinc) $(pr_opcode_hinc)
convert_py = $(srcdir)/libs/gamecode/convert.py
pr_convert_cinc = $(top_builddir)/libs/gamecode/pr_convert.cinc
BUILT_SOURCES += $(pr_opcode_cinc) $(pr_opcode_hinc) $(pr_convert_cinc)
$(pr_opcode_cinc): $(opcodes_py)
$(V_PY)$(PYTHON) $(opcodes_py) table > $(pr_opcode_cinc).t && \
@ -41,3 +44,7 @@ $(pr_opcode_hinc): $(opcodes_py)
$(V_PY) mkdir -p `dirname $(pr_opcode_hinc)` &&\
$(PYTHON) $(opcodes_py) enum > $(pr_opcode_hinc).t && \
$(am__mv) $(pr_opcode_hinc).t $(pr_opcode_hinc)
$(pr_convert_cinc): $(convert_py)
$(V_PY)$(PYTHON) $(convert_py) table > $(pr_convert_cinc).t && \
$(am__mv) $(pr_convert_cinc).t $(pr_convert_cinc)

66
libs/gamecode/convert.py Normal file
View file

@ -0,0 +1,66 @@
print("""// types are encoded as ubf where:
// u = 0: signed, u = 1: unsigned
// b = 0: 32-bit, b = 1: 64-bit
// f = 0: int, f = 1: float/double
// width is ww where:
// ww = 00: 1 component
// ww = 01: 2 components
// ww = 10: 3 components
// ww = 11: 4 components
// full conversion code is wwsssddd where:
// ww = width
// sss = src type
// ddd = dst type
// case values are in octal
""")
types = [
"int",
"float",
"long",
"double",
"uint",
None, # no such thing as unsigned float
"ulong",
None, # no such thing as unsigned double
]
#does not include size (2 or 4, 3 is special)
vec_types = [
"ivec",
"vec",
"lvec",
"dvec",
"uivec",
None, # no such thing as unsigned float
"ulvec",
None, # no such thing as unsigned double
]
skip_matrix = [
#i f l d ui X ul X
[1, 0, 0, 0, 1, 1, 0, 1], # i
[0, 1, 0, 0, 0, 1, 0, 1], # f
[0, 0, 1, 0, 0, 1, 1, 1], # l
[0, 0, 0, 1, 0, 1, 0, 1], # d
[1, 0, 0, 0, 1, 1, 0, 1], # ui
[1, 1, 1, 1, 1, 1, 1, 1], # X
[0, 0, 1, 0, 0, 1, 1, 1], # ul
[1, 1, 1, 1, 1, 1, 1, 1], # X
]
for width in range(4):
for src_type in range(8):
for dst_type in range(8):
if skip_matrix[src_type][dst_type]:
continue
case = (width << 6) | (src_type << 3) | (dst_type)
if width == 0:
print(f"case {case:04o}: OPC({types[dst_type]}) = (pr_{types[dst_type]}_t) OPA({types[src_type]}); break;")
elif width == 2:
print(f"case {case:04o}: VectorCompUop(&OPC({types[dst_type]}), (pr_{types[dst_type]}_t), &OPA({types[src_type]})); break;")
else:
if (src_type & 2) == (dst_type & 2):
print(f"case {case:04o}: OPC({vec_types[dst_type]}{width+1}) = (pr_{vec_types[dst_type]}{width+1}_t) OPA({vec_types[src_type]}{width+1}); break;")
else:
print(f"case {case:04o}:")
for i in range(width + 1):
print(f"\t(&OPC({types[dst_type]}))[{i}] = (pr_{types[dst_type]}_t) (&OPA({types[src_type]}))[{i}];")
print(f"\tbreak;")

View file

@ -2915,6 +2915,7 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
break;
// 0 0101
case OP_IFNZ_A:
case OP_IFNZ_B:
case OP_IFNZ_C:
@ -2972,9 +2973,17 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
PR_CallFunction (pr, function);
st = pr->pr_statements + pr->pr_xstatement;
break;
// 0 0101
// nnn spare
//OP_CONV
// 0 0110
// 0nnn spare
// 10nn spare
case OP_CONV:
switch (st->b) {
#include "libs/gamecode/pr_convert.cinc"
default:
PR_RunError (pr, "invalid conversion code: %04o",
st->b);
}
break;
case OP_WITH:
pr->pr_bases[st->c & 3] = pr_with (pr, st);
break;
@ -3002,7 +3011,6 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
pr->pr_edict_area[think].func_var = op_b->func_var;
}
break;
// 0 0110
// 0 0111
case OP_CROSS_F:
{
@ -3121,14 +3129,16 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
// 0 1010
OP_cmp(GT, >);
// 0 1011
// spare
// 0 1100
OP_cmp(NE, !=);
// 0 1101
OP_cmp(GE, >=);
// 0 1110
OP_cmp(LE, <=);
// 0 1011
//FIXME conversion 2
// 0 1111
// spare
#define OP_op_1(OP, T, t, op) \
case OP_##OP##_##T##_1: \
@ -3311,9 +3321,9 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
//FIXME scale ops
// 1 1010
OP_cmp_T (GT, u, int, ivec2, ivec4, >, uint, uivec2, uivec4);
//FIXME conversion ops
// spare
OP_cmp_T (GT, U, long, lvec2, lvec4, >, ulong, ulvec2, ulvec4);
//FIXME conversion ops
// spare
// 1 1011
case OP_LEA_A:
case OP_LEA_B:
@ -3447,14 +3457,14 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
case OP_V4QMUL_F:
OPC(vec4) = vqmulf (OPA(vec4), OPB(vec4));
break;
// spare
OP_cmp_T (LE, U, long, lvec2, lvec4, <=, ulong, ulvec2, ulvec4);
case OP_V4QMUL_D:
OPC(dvec4) = vqmuld (OPA(dvec4), OPB(dvec4));
break;
// spare
// 1 1111
// spare
default:
PR_RunError (pr, "Bad opcode o%03o", st->op & OP_MASK);
}