#include "ovm.h" #include #undef CMPEPS // #define 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); } if (0 != len % 12) { fprintf (stderr, "file size of %s not a multiple of frame size\n", filename); exit(1); } len /= 12; 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])) { #ifdef 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: #ifdef 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 \n" "\n" "typedef union { gdouble d; guint64 i; } double_int;\n" "\n" "static gboolean ovm_status;\n" "\n" )); #ifdef 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); }