219 lines
6.2 KiB
C
219 lines
6.2 KiB
C
|
|
#include "ovm.h"
|
|
#include <glib/gstdio.h>
|
|
|
|
#undef CMPEPS
|
|
|
|
void ovm_free(ovm_t *ovm) {
|
|
if (!ovm) return;
|
|
g_slice_free1(ovm->limit * sizeof(instruction_t), ovm->instructions);
|
|
g_slice_free1(ovm->limit * sizeof(gdouble), ovm->values);
|
|
g_slice_free(ovm_t, ovm);
|
|
}
|
|
|
|
ovm_t* ovm_load(const gchar *filename) {
|
|
GError *err = NULL;
|
|
gchar *buf = NULL, *cur;
|
|
gsize len = 0, i;
|
|
instruction_t *oi;
|
|
gdouble *vi;
|
|
|
|
ovm_t *ovm = g_slice_new(ovm_t);
|
|
ovm->limit = 0x4000;
|
|
|
|
ovm->instructions = g_slice_alloc0(ovm->limit * sizeof(instruction_t));
|
|
ovm->values = g_slice_alloc0(ovm->limit * sizeof(gdouble));
|
|
|
|
if (!g_file_get_contents(filename, &buf, &len, &err)) {
|
|
fprintf (stderr, "Unable to read file %s: %s\n", filename, err->message);
|
|
g_error_free (err);
|
|
exit(1);
|
|
}
|
|
|
|
oi = ovm->instructions;
|
|
vi = ovm->values;
|
|
for (cur = buf, i = 0; i < len; i++) {
|
|
*vi++ = *(gdouble*)buf;
|
|
buf += sizeof(gdouble);
|
|
*oi++ = *(guint32*)buf;
|
|
buf += sizeof(guint32);
|
|
if (++i < len) {
|
|
*oi++ = *(guint32*)buf;
|
|
buf += sizeof(guint32);
|
|
*vi++ = *(gdouble*)buf;
|
|
buf += sizeof(gdouble);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
ovm->used = i;
|
|
|
|
return ovm;
|
|
}
|
|
|
|
void ovm_print_c(ovm_t *ovm, const gchar *filename) {
|
|
guint i, max_in=0, max_out=0;
|
|
instruction_t *oi = ovm->instructions;
|
|
gdouble *vi = ovm->values;
|
|
guint64 *uvi = (guint64*) ovm->values;
|
|
guchar *usedv = g_slice_alloc0(ovm->used*sizeof(guchar));
|
|
GString *str = g_string_sized_new(0), *buf = g_string_sized_new(0);
|
|
int f = g_open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
|
|
|
|
if (-1 == f) {
|
|
fprintf(stderr, "Couldn't open file %s: %s\n", filename, g_strerror(errno));
|
|
exit(2);
|
|
}
|
|
|
|
g_string_append_len(buf, CONST_STR_LEN(
|
|
"void ovm_step(guint scenario, gdouble *in, gdouble *out) {\n"
|
|
));
|
|
#define USED(i) (usedv[i] = TRUE, i)
|
|
#define USED_IN(i) (max_in = max_in > i ? max_in : i, i)
|
|
#define USED_OUT(i) (max_out = max_out > i ? max_out : i, i)
|
|
for (i = 0; i < ovm->used; i++) {
|
|
g_string_printf(str, "\t/* Invalid command: 0x%X */\n", (guint) oi[i]);
|
|
switch (instr_dop(oi[i])) {
|
|
case OP_STYPE:
|
|
switch (instr_sop(oi[i])) {
|
|
case SOP_NOOP:
|
|
g_string_printf(str, "/* NOOP */\n");
|
|
g_string_truncate(str, 0);
|
|
break;
|
|
case SOP_CMPZ:
|
|
switch (instr_sop_cmp(oi[i])) {
|
|
#if CMPEPS /* cmp with eps */
|
|
case CMP_LTZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d < -eps);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_LEZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d <= eps);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_EQZ:
|
|
g_string_printf(str, "\tovm_status = (fabs(v%u.d) <= eps);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_GEZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d >= -eps);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_GTZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d > eps);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
#else
|
|
case CMP_LTZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d < 0);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_LEZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d <= 0);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_EQZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d == 0);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_GEZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d >= 0);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case CMP_GTZ:
|
|
g_string_printf(str, "\tovm_status = (v%u.d > 0);\n", USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
#endif
|
|
}
|
|
break;
|
|
case SOP_SQRT:
|
|
g_string_printf(str, "\tv%u.d = sqrt(v%u.d);\n", USED(i), USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case SOP_COPY:
|
|
g_string_printf(str, "\tv%u.d = v%u.d;\n", USED(i), USED(instr_sop_r1(oi[i])));
|
|
break;
|
|
case SOP_IN:
|
|
if (0x3e80 == instr_sop_r1(oi[i])) {
|
|
g_string_printf(str, "\tv%u.d = scenario;\n", USED(i));
|
|
} else {
|
|
g_string_printf(str, "\tv%u.d = in[%u];\n", USED(i), USED_IN(instr_sop_r1(oi[i])));
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case OP_ADD:
|
|
g_string_printf(str, "\tv%u.d = v%u.d + v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
|
|
break;
|
|
case OP_SUB:
|
|
g_string_printf(str, "\tv%u.d = v%u.d - v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
|
|
break;
|
|
case OP_MULT:
|
|
g_string_printf(str, "\tv%u.d = v%u.d * v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
|
|
break;
|
|
case OP_DIV:
|
|
#if CMPEPS
|
|
g_string_printf(str, "\tv%u.d = (fabs(v%u.d) < eps) ? 0.0 : v%u.d / v%u.d;\n", USED(i), USED(instr_dop_r2(oi[i])), USED(instr_dop_r1(oi[i])), instr_dop_r2(oi[i]));
|
|
#else
|
|
g_string_printf(str, "\tv%u.d = (v%u.d == 0) ? 0.0 : v%u.d / v%u.d;\n", USED(i), USED(instr_dop_r2(oi[i])), USED(instr_dop_r1(oi[i])), instr_dop_r2(oi[i]));
|
|
#endif
|
|
break;
|
|
case OP_OUT:
|
|
g_string_printf(str, "\tout[%u] = v%u.d;\n", USED_OUT(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
|
|
break;
|
|
case OP_PHI:
|
|
g_string_printf(str, "\tv%u.d = ovm_status ? v%u.d : v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
|
|
break;
|
|
}
|
|
g_string_append_len(buf, GSTR_LEN(str));
|
|
}
|
|
#undef USED
|
|
|
|
g_string_append_len(buf, CONST_STR_LEN(
|
|
"}\n"
|
|
"\n"
|
|
));
|
|
|
|
write(f, CONST_STR_LEN(
|
|
"#include \"task.h\"\n"
|
|
"#include <math.h>\n"
|
|
"\n"
|
|
"typedef union { gdouble d; guint64 i; } double_int;\n"
|
|
"\n"
|
|
"static gboolean ovm_status;\n"
|
|
"\n"
|
|
));
|
|
#if CMPEPS
|
|
write(f, CONST_STR_LEN(
|
|
"static const gdouble eps = 1e-300;\n"
|
|
"\n"
|
|
));
|
|
#endif
|
|
g_string_printf(str, "const guint ovm_outs = %u, ovm_ins = %u;\n", max_out+1, max_in+1);
|
|
write(f, GSTR_LEN(str));
|
|
write(f, CONST_STR_LEN(
|
|
"\n"
|
|
"static double_int v0"
|
|
));
|
|
for (i = 1; i < ovm->used; i++) {
|
|
if (!usedv[i]) continue;
|
|
g_string_printf(str, ", v%u", i);
|
|
write(f, GSTR_LEN(str));
|
|
}
|
|
write(f, CONST_STR_LEN(
|
|
";\n"
|
|
"\n"
|
|
"void ovm_init() {\n"
|
|
"\tovm_status = FALSE;\n"
|
|
"\n"
|
|
));
|
|
for (i = 0; i < ovm->used; i++) {
|
|
if (!usedv[i]) continue;
|
|
/* g_string_printf(str, "\tv%u.d = %f;\n", i, vi[i]); */
|
|
g_string_printf(str, "\tv%u.i = G_GUINT64_CONSTANT(%" G_GUINT64_FORMAT "); /* %f */ \n", i, uvi[i], vi[i]);
|
|
write(f, GSTR_LEN(str));
|
|
}
|
|
|
|
write(f, CONST_STR_LEN(
|
|
"}\n"
|
|
"\n"
|
|
));
|
|
|
|
write(f, GSTR_LEN(buf));
|
|
|
|
close(f);
|
|
|
|
g_string_free(str, TRUE);
|
|
g_string_free(buf, TRUE);
|
|
}
|