: "ir" (val), "m" (*ptr)); } while (0)
+#define R_DEBUG_BRAKE __asm__ ("int $3")
+#define ASSERT(__a__) do {if (!(__a__)) R_DEBUG_BRAKE; } while (0)
#ifndef NULL
#ifdef __cplusplus
$(OUTDIR)/rrefreg.o \
$(OUTDIR)/rvmcpu.o \
$(OUTDIR)/rvmoperator.o \
+ $(OUTDIR)/rvmoperatorcast.o \
$(OUTDIR)/rvmoperatorcat.o \
$(OUTDIR)/rvmoperatoradd.o \
$(OUTDIR)/rvmoperatorsub.o \
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include "rvmcpu.h"
+#include "rvmoperator.h"
+#include "rvmoperatorcast.h"
#include "rmem.h"
#include "rstring.h"
-#include "rvmcpu.h"
+#include "rvmreg.h"
static const char *stropcalls[] = {
"RVM_PUSHM",
"RVM_POPM",
"RVM_TST",
- "RVM_TEQ",
+ "RVM_TEQ",
+ "ERVM_CAST", /* Cast: op1 = (op3)op2 */
+ "ERVM_TYPE", /* Type: op1 = typeof(op2) */
+ "ERVM_MOV",
};
str += ret;
sz -= ret;
- if ((ret = rvm_snprintf(str, sz, "0x%lx ", (unsigned long)RVM_REG_GETU(&pi->data))) < 0)
+// if ((ret = rvm_snprintf(str, sz, "0x%lx ", (unsigned long)RVM_REG_GETU(&pi->data))) < 0)
+// return ret;
+ if ((ret = rvm_snprintf(str, sz, "0x%lx ", (unsigned long)pi->data)) < 0)
return ret;
+
+
str += ret;
sz -= ret;
}
+static void ervm_op_cast(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rvmreg_type_t type = (rvmreg_type_t)RVM_CPUREG_GETU(cpu, ins->op3);
+ rvmreg_t tmp;
+
+ RVM_REG_CLEAR(&tmp);
+ RVM_REG_SETTYPE(&tmp, type);
+ rvm_opmap_invoke_binary_handler(cpu->opmap, RVM_OPID_CAST, cpu, RVM_CPUREG_PTR(cpu, ins->op1), RVM_CPUREG_PTR(cpu, ins->op2), &tmp);
+}
+
+
+static void ervm_op_type(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rvmreg_type_t type = (rvmreg_type_t)RVM_CPUREG_GETTYPE(cpu, ins->op2);
+
+ RVM_CPUREG_CLEAR(cpu, ins->op1);
+ RVM_CPUREG_SETU(cpu, ins->op1, type);
+}
+
+
+static void ervm_op_mov(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rvm_op_mov(cpu, ins);
+}
+
+
+static void ervm_op_adc(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 + op3 + (RVM_STATUS_GETBIT(cpu, RVM_STATUS_C) ? 1 : 0);
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_C, res < op2 || res < op3);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_V, (op2 & RVM_SIGN_BIT) == (op3 & RVM_SIGN_BIT) &&
+ (res & RVM_SIGN_BIT) != (op2 & RVM_SIGN_BIT));
+}
+
+
+static void ervm_op_adds(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 + op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_C, res < op2 || res < op3);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_V, (op2 & RVM_SIGN_BIT) == (op3 & RVM_SIGN_BIT) &&
+ (res & RVM_SIGN_BIT) != (op2 & RVM_SIGN_BIT));
+}
+
+
+static void ervm_op_add(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rvmreg_type_t type;
+ rvmreg_t *r2 = rvm_reg_unshadow(RVM_CPUREG_PTR(cpu, ins->op2));
+ rvmreg_t *r3 = rvm_reg_unshadow(RVM_CPUREG_PTR(cpu, ins->op3));
+
+ type = RVM_REG_GETTYPE(r2);
+
+
+ if (type != RVM_REG_GETTYPE(r3))
+ RVM_ABORT(cpu, RVM_E_CAST);
+
+ switch (type) {
+ case RVM_DTYPE_UNSIGNED:
+ RVM_CPUREG_SETU(cpu, ins->op1, RVM_REG_GETU(r2) + RVM_REG_GETU(r2));
+ RVM_CPUREG_SETTYPE(cpu, ins->op1, RVM_DTYPE_NONE);
+ RVM_CPUREG_CLRFLAG(cpu, ins->op1, RVM_INFOBIT_ROBJECT);
+ break;
+ case RVM_DTYPE_LONG:
+ RVM_CPUREG_SETU(cpu, ins->op1, RVM_REG_GETL(r2) + RVM_REG_GETL(r2));
+ RVM_CPUREG_SETTYPE(cpu, ins->op1, RVM_DTYPE_LONG);
+ RVM_CPUREG_CLRFLAG(cpu, ins->op1, RVM_INFOBIT_ROBJECT);
+ break;
+ case RVM_DTYPE_DOUBLE:
+ RVM_CPUREG_SETD(cpu, ins->op1, RVM_REG_GETD(r2) + RVM_REG_GETD(r2));
+ RVM_CPUREG_SETTYPE(cpu, ins->op1, RVM_DTYPE_DOUBLE);
+ RVM_CPUREG_CLRFLAG(cpu, ins->op1, RVM_INFOBIT_ROBJECT);
+ break;
+ default:
+ RVM_ABORT(cpu, RVM_E_CAST);
+ };
+}
+
+
+static void ervm_op_and(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 & op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
+static void ervm_op_eor(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 ^ op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
+static void ervm_op_mls(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rsword res;
+ rsword op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = (rsword)(op2 * op3);
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ /* TBD: Not sure how to update the RVM_STATUS_C */
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
+static void ervm_op_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ RVM_CPUREG_SETU(cpu, ins->op1, RVM_CPUREG_GETU(cpu, ins->op2) * RVM_CPUREG_GETU(cpu, ins->op3));
+}
+
+
+static void ervm_op_muls(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 * op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_C, op2 && (res / op2) != op3);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
+static void ervm_op_sub(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ RVM_CPUREG_SETU(cpu, ins->op1, RVM_CPUREG_GETU(cpu, ins->op2) - RVM_CPUREG_GETU(cpu, ins->op3));
+}
+
+
+static void ervm_op_subs(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 - op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_C, !(res > op2)); /* borrow = !carry */
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_V, (op2 & RVM_SIGN_BIT) != (op3 & RVM_SIGN_BIT) &&
+ (res & RVM_SIGN_BIT) == (op2 & RVM_SIGN_BIT));
+}
+
+
+static void ervm_op_sbc(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ res = op2 - op3 + (RVM_STATUS_GETBIT(cpu, RVM_STATUS_C) ? 0 : -1);
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_C, !(res > op2)); /* borrow = !carry */
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_V, (op2 & RVM_SIGN_BIT) != (op3 & RVM_SIGN_BIT) &&
+ (res & RVM_SIGN_BIT) == (op2 & RVM_SIGN_BIT));
+}
+
+
+static void ervm_op_div(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ if (!RVM_CPUREG_GETU(cpu, ins->op3))
+ RVM_ABORT(cpu, RVM_E_DIVZERO);
+
+ RVM_CPUREG_SETU(cpu, ins->op1, RVM_CPUREG_GETU(cpu, ins->op2) / RVM_CPUREG_GETU(cpu, ins->op3));
+}
+
+
+static void ervm_op_divs(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rword res, op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ if (!op3)
+ RVM_ABORT(cpu, RVM_E_DIVZERO);
+ res = op2 / op3;
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
+static void ervm_op_dvs(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rsword res;
+ rsword op2 = RVM_CPUREG_GETU(cpu, ins->op2), op3 = RVM_CPUREG_GETU(cpu, ins->op3);
+
+ if (!op3)
+ RVM_ABORT(cpu, RVM_E_DIVZERO);
+ res = (rsword)(op2 / op3);
+ RVM_CPUREG_SETU(cpu, ins->op1, res);
+ RVM_STATUS_CLRALL(cpu);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !res);
+ RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, res & RVM_SIGN_BIT);
+}
+
+
static rvm_cpu_op ops[] = {
rvm_op_exit, // RVM_EXT
rvm_op_asr, // RVM_ASR
rvm_op_popm, // RVM_POPM
rvm_op_tst, // RVM_TST
rvm_op_teq, // RVM_TEQ
+
+/* Extended VM instructions */
+ ervm_op_cast, // ERVM_CAST
+ ervm_op_type, // ERVM_TYPE
+ ervm_op_mov, // ERVM_MOV
+ ervm_op_add, // ERVM_ADD
+ ervm_op_adds, // ERVM_ADDS
+ ervm_op_adc, // ERVM_ADC
+ ervm_op_and, // ERVM_AND
+ ervm_op_eor, // ERVM_EOR
+ ervm_op_sub, // ERVM_SUB
+ ervm_op_subs, // ERVM_SUBS
+ ervm_op_sbc, // ERVM_SBC
+ ervm_op_mul, // ERVM_MUL
+ ervm_op_mls, // ERVM_MLS
+ ervm_op_muls, // ERVM_MULS
+ ervm_op_div, // RVM_DIV
+ ervm_op_dvs, // RVM_DVS
+ ervm_op_divs, // RVM_DIVS
(void*) 0,
(void*) 0,
(void*) 0,
r_memset(cpu, 0, sizeof(*cpu));
cpu->switables = r_array_create(sizeof(rvm_switable_t*));
cpu->stack = r_array_create(sizeof(rvmreg_t));
+ cpu->opmap = rvm_opmap_create();
+ rvm_op_cast_init(cpu->opmap);
return cpu;
}
// rvm_free(cpu->stack);
r_array_destroy(cpu->switables);
r_array_destroy(cpu->stack);
+ rvm_opmap_destroy(cpu->opmap);
r_free(cpu);
}
cpu->error = 0;
do {
pi = RVM_CPUREG_GETIP(cpu, PC);
- cpu->r[DA] = pi->data;
+ RVM_CPUREG_SETU(cpu, DA, pi->data);
ops[pi->opcode](cpu, pi);
+#ifdef DEBUG
+ if (RVM_CPUREG_GETTYPE(cpu, DA) || RVM_CPUREG_TSTFLAG(cpu, DA, RVM_INFOBIT_ALL))
+ RVM_ABORT(cpu, RVM_E_ILLEGAL);
+#endif
if (cpu->abort)
return -1;
RVM_CPUREG_INCIP(cpu, PC, 1);
cpu->error = 0;
do {
pi = RVM_CPUREG_GETIP(cpu, PC);
- cpu->r[DA] = pi->data;
+ RVM_CPUREG_CLEAR(cpu, DA);
+ RVM_CPUREG_SETU(cpu, DA, pi->data);
ops[pi->opcode](cpu, pi);
+#ifdef DEBUG
+ if (RVM_CPUREG_GETTYPE(cpu, DA) || RVM_CPUREG_TSTFLAG(cpu, DA, RVM_INFOBIT_ALL))
+ RVM_ABORT(cpu, RVM_E_ILLEGAL);
+#endif
if (cpu->abort)
return -1;
rvm_cpu_dumpregs(pi, cpu);
}
-rvm_asmins_t rvm_asmd(rword opcode, rword op1, rword op2, rword op3, rdouble data)
-{
- rvm_asmins_t a;
-
- r_memset(&a, 0, sizeof(a));
- a.opcode = (unsigned char) opcode;
- a.op1 = (unsigned char)op1;
- a.op2 = (unsigned char)op2;
- a.op3 = (unsigned char)op3;
- RVM_REG_GETD(&a.data) = data;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_DOUBLE);
- return a;
-}
-
-
rvm_asmins_t rvm_asmp(rword opcode, rword op1, rword op2, rword op3, rpointer data)
{
rvm_asmins_t a;
a.op1 = (unsigned char)op1;
a.op2 = (unsigned char)op2;
a.op3 = (unsigned char)op3;
- RVM_REG_GETP(&a.data) = data;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_POINTER);
+ a.data = (rword)data;
+
+// RVM_REG_GETP(&a.data) = data;
+// RVM_REG_SETTYPE(&a.data, RVM_DTYPE_POINTER);
return a;
}
-rvm_asmins_t rvm_asmu(rword opcode, rword op1, rword op2, rword op3, rword data)
+rvm_asmins_t rvm_asm(rword opcode, rword op1, rword op2, rword op3, rword data)
{
rvm_asmins_t a;
a.op1 = (unsigned char)op1;
a.op2 = (unsigned char)op2;
a.op3 = (unsigned char)op3;
- RVM_REG_GETU(&a.data) = data;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_WORD);
+ a.data = (rword)data;
+
+// RVM_REG_GETU(&a.data) = data;
+// RVM_REG_SETTYPE(&a.data, RVM_DTYPE_WORD);
return a;
}
a.op1 = (unsigned char)op1;
a.op2 = (unsigned char)op2;
a.op3 = (unsigned char)op3;
- RVM_REG_GETL(&a.data) = (rword)data;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_LONG);
+ a.data = (rword)data;
+
+// RVM_REG_GETL(&a.data) = (rword)data;
+// RVM_REG_SETTYPE(&a.data, RVM_DTYPE_LONG);
return a;
}
-rvm_asmins_t rvm_asmi(rword opcode, rword op1, rword op2, rword op3, rint data)
-{
- return rvm_asml(opcode, op1, op2, op3, data);
-}
-
rvm_asmins_t rvm_asmr(rword opcode, rword op1, rword op2, rword op3, rpointer pReloc)
{
a.op1 = (unsigned char)op1;
a.op2 = (unsigned char)op2;
a.op3 = (unsigned char)op3;
- RVM_REG_GETP(&a.data) = pReloc;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_RELOCPTR);
+ a.data = (rword)pReloc;
+ a.flags = RVM_ASMINS_RELOC | RVM_ASMINS_RELOCPTR;
+
+// RVM_REG_GETP(&a.data) = pReloc;
+// RVM_REG_SETTYPE(&a.data, RVM_DTYPE_RELOCPTR);
return a;
}
a.op1 = (unsigned char)op1;
a.op2 = (unsigned char)op2;
a.op3 = (unsigned char)op3;
- RVM_REG_GETP(&a.data) = pReloc;
- RVM_REG_SETTYPE(&a.data, RVM_DTYPE_RELOCINDEX);
- return a;
-}
-
+ a.data = (rword)pReloc;
+ a.flags = RVM_ASMINS_RELOC;
-rvm_asmins_t rvm_asm(rword opcode, rword op1, rword op2, rword op3, rword data)
-{
- return rvm_asmu(opcode, op1, op2, op3, data);
+// RVM_REG_GETP(&a.data) = pReloc;
+// RVM_REG_SETTYPE(&a.data, RVM_DTYPE_RELOCINDEX);
+ return a;
}
rulong off;
for (off = 0; off < size; off++, code++) {
- if (RVM_REG_GETTYPE(&code->data) == RVM_DTYPE_RELOCPTR) {
- RVM_REG_SETTYPE(&code->data, RVM_DTYPE_NONE);
- reloc = *((rvm_asmins_t **)RVM_REG_GETP(&code->data));
- RVM_REG_GETU(&code->data) = reloc - code;
- } else if (RVM_REG_GETTYPE(&code->data) == RVM_DTYPE_RELOCINDEX) {
- RVM_REG_SETTYPE(&code->data, RVM_DTYPE_NONE);
- relocindex = *((rulong *)RVM_REG_GETP(&code->data));
- RVM_REG_GETU(&code->data) = relocindex - off;
+ if (code->flags & RVM_ASMINS_RELOC) {
+ if (code->flags & RVM_ASMINS_RELOCPTR) {
+ reloc = *((rvm_asmins_t **)code->data);
+ code->data = reloc - code;
+ } else {
+ relocindex = *((rulong *)code->data);
+ code->data = relocindex - off;
+ }
+ code->flags &= ~(RVM_ASMINS_RELOCPTR | RVM_ASMINS_RELOC);
}
}
}
+
RVM_POPM,
RVM_TST,
RVM_TEQ,
+
+/* Extended VM opcodes, */
+ ERVM_CAST, /* Cast: op1 = (op3)op2 */
+ ERVM_TYPE, /* Type: op1 = typeof(op2) */
+ ERVM_MOV,
+ ERVM_ADD,
+ ERVM_ADDS, /* Add: op1 = op2 + op3, update the status register */
+ ERVM_ADC, /* Add: op1 = op2 + op3 + C, update the status register */
+ ERVM_AND, /* Bitwise AND: op1 = op2 & op3, update status register */
+ ERVM_EOR, /* XOR: op1 = op2 ^ op3, update the status register */
+ ERVM_SUB,
+ ERVM_SUBS,
+ ERVM_SBC,
+ ERVM_MUL,
+ ERVM_MLS, /* Signed multiplication: op1 = op2 * op3 */
+ ERVM_MULS,
+ ERVM_DIV, /* Divide: op1 = op2 / op3 */
+ ERVM_DVS, /* Signed division: op1 = op2 / op3 */
+ ERVM_DIVS, /* Divide: op1 = op2 / op3, Update the status register */
};
#define RVM_DTYPE_NONE 0
#define RVM_DTYPE_WORD RVM_DTYPE_NONE
+#define RVM_DTYPE_UNSIGNED RVM_DTYPE_NONE
#define RVM_DTYPE_LONG 1
#define RVM_DTYPE_DOUBLE 2
#define RVM_DTYPE_BOOLEAN 3
#define SP R13
#define LR R14
#define PC R15
-#define DA 16
+#define DA 16 /* The DA register should never be modified manually, otherwise the result is undefined */
#define RLST 16
#define XX 255
#define RVM_STACK_CHUNK 256
-#define RVM_ABORT(__cpu__, __e__) do { __cpu__->error = (__e__); (__cpu__)->abort = 1; return; } while (0)
+#define RVM_ABORT(__cpu__, __e__) do { __cpu__->error = (__e__); (__cpu__)->abort = 1; ASSERT(0); return; } while (0)
#define BIT(__shiftby__) (1 << (__shiftby__))
#define RVM_CPUREG_PTR(__cpu__, __r__) (&(__cpu__)->r[(__r__)])
#define RVM_REG_GETTYPE(__r__) (__r__)->type
#define RVM_REG_SETTYPE(__r__, __val__) do { (__r__)->type = (__val__); } while(0);
-#define RVM_CPUREG_GETTYPE(__cpu__, __r__) RVM_CPUREG_GETTYPE(RVM_CPUREG_PTR(__cpu__, __r__))
+#define RVM_CPUREG_GETTYPE(__cpu__, __r__) RVM_REG_GETTYPE(RVM_CPUREG_PTR(__cpu__, __r__))
#define RVM_CPUREG_SETTYPE(__cpu__, __r__, __val__) RVM_REG_SETTYPE(RVM_CPUREG_PTR(__cpu__, __r__), __val__)
#define RVM_REG_TSTFLAG(__r__, __flag__) ((__r__)->flags & (__flag__)) ? TRUE : FALSE
#define RVM_REG_SETFLAG(__r__, __flag__) do { (__r__)->flags |= (__flag__); } while (0)
#define RVM_REG_CLRFLAG(__r__, __flag__) do { (__r__)->flags &= ~(__flag__); } while (0)
-#define RVM_CPUREG_GETFLAG(__cpu__, __r__, __flag__) RVM_REG_TSTFLAG(RVM_CPUREG_PTR(__cpu__, __r__), __flag__)
+#define RVM_CPUREG_TSTFLAG(__cpu__, __r__, __flag__) RVM_REG_TSTFLAG(RVM_CPUREG_PTR(__cpu__, __r__), __flag__)
#define RVM_CPUREG_SETFLAG(__cpu__, __r__, __flag__) RVM_REG_SETFLAG(RVM_CPUREG_PTR(__cpu__, __r__), __flag__)
#define RVM_CPUREG_CLRFLAG(__cpu__, __r__, __flag__) RVM_REG_CLRFLAG(RVM_CPUREG_PTR(__cpu__, __r__), __flag__)
//#define RVM_REG_REF(__r__) do { if (rvm_reg_gettype(__r__) == RVM_DTYPE_REFREG) r_ref_inc((rref_t*)RVM_REG_GETP(__r__));} while (0)
//#define RVM_REG_UNREF(__r__) do { if (rvm_reg_gettype(__r__) == RVM_DTYPE_REFREG) r_ref_dec((rref_t*)RVM_REG_GETP(__r__));} while (0)
#define RVM_REG_CLEAR(__r__) do { (__r__)->v.w = 0UL; (__r__)->type = 0; (__r__)->flags = 0; } while (0)
+#define RVM_CPUREG_CLEAR(__cpu__, __r__) RVM_REG_CLEAR(RVM_CPUREG_PTR(__cpu__, __r__))
+
#define RVM_SWI_TABLE(__op__) ((__op__) >> 16)
#define RVM_SWI_NUM(__op__) ((__op__) & ((1 << 16) - 1))
#define RVM_SWI_ID(__t__, __o__) ((((__t__) & ((1 << 16) - 1)) << 16) | ((__o__) & ((1 << 16) - 1)))
-#define RVM_E_DIVZERO (1)
-#define RVM_E_ILLEGAL (2)
-#define RVM_E_SWINUM (3)
-#define RVM_E_SWITABLE (4)
-
+#define RVM_E_DIVZERO (1)
+#define RVM_E_ILLEGAL (2)
+#define RVM_E_CAST (3)
+#define RVM_E_SWINUM (4)
+#define RVM_E_SWITABLE (5)
+#define RVM_E_ILLEGALDST (6)
typedef struct rvm_asmins_s rvm_asmins_t;
typedef struct rvmcpu_s rvmcpu_t;
} rvm_switable_t;
+typedef ruint16 rvmreg_type_t;
+typedef ruint16 rvmreg_flags_t;
+
typedef struct rvmreg_s {
union {
rword w;
rdouble d;
ruint8 c[RVM_MIN_REGSIZE];
} v;
- ruint16 type;
- ruint16 flags;
+ rvmreg_type_t type;
+ rvmreg_flags_t flags;
ruint32 size;
} rvmreg_t;
+#define RVM_ASMINS_RELOC (1 << 0)
+#define RVM_ASMINS_RELOCPTR (1 << 1)
struct rvm_asmins_s {
ruint8 opcode;
- ruint8 op1;
- ruint8 op2;
- ruint8 op3;
- rvmreg_t data;
+ ruint8 flags;
+ ruint16 op1:5;
+ ruint16 op2:5;
+ ruint16 op3:5;
+ rword data;
};
+struct rvm_opmap_s;
struct rvmcpu_s {
rvmreg_t r[DA + 1];
rword abort;
rarray_t *switables;
rarray_t *stack;
+ struct rvm_opmap_s *opmap;
void *userdata;
};
rint rvm_cpu_getswi(rvmcpu_t *cpu, const rchar *swiname);
void rvm_relocate(rvm_asmins_t *code, rsize_t size);
rvm_asmins_t rvm_asm(rword opcode, rword op1, rword op2, rword op3, rword data);
-rvm_asmins_t rvm_asmi(rword opcode, rword op1, rword op2, rword op3, rint data);
rvm_asmins_t rvm_asml(rword opcode, rword op1, rword op2, rword op3, rlong data);
-rvm_asmins_t rvm_asmu(rword opcode, rword op1, rword op2, rword op3, rword data);
rvm_asmins_t rvm_asmp(rword opcode, rword op1, rword op2, rword op3, rpointer data);
rvm_asmins_t rvm_asmr(rword opcode, rword op1, rword op2, rword op3, rpointer pReloc);
rvm_asmins_t rvm_asmx(rword opcode, rword op1, rword op2, rword op3, rpointer pReloc);
-rvm_asmins_t rvm_asmd(rword opcode, rword op1, rword op2, rword op3, rdouble data);
void rvm_asm_dump(rvm_asmins_t *pi, ruint count);
rint rvm_opmap_set_binary_handler(rvm_opmap_t *opmap, rushort opid, rvm_binaryop_handler func, ruchar firstType, ruchar secondType)
{
rvm_ophandler_t *h;
+ ruint index = RVM_OP_HANDLER(firstType, secondType);
rvm_opinfo_t *opinfo = ((rvm_opinfo_t*)r_array_slot(opmap->operators, opid));
if (!opinfo->handlers)
return -1;
- h = &opinfo->handlers[RVM_OP_HANDLER(firstType, secondType)];
+ h = &opinfo->handlers[index];
h->op = func;
return 0;
}
#define RVM_OPID_MUL 3
#define RVM_OPID_DIV 4
#define RVM_OPID_CAT 5
+#define RVM_OPID_CAST 6
/*
* Important: the res pointer might be the same as one of the arguments, the operator must
--- /dev/null
+#include "rvmoperatorcast.h"
+#include "rvmreg.h"
+
+
+void rvm_op_cast_static_static(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ *res = *arg1;
+}
+
+
+void rvm_op_cast_double_unsigned(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rword r = (rword)RVM_REG_GETD(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_UNSIGNED);
+ RVM_REG_SETL(res, r);
+}
+
+void rvm_op_cast_double_long(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rlong r = (rlong)RVM_REG_GETD(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_LONG);
+ RVM_REG_SETL(res, r);
+}
+
+
+void rvm_op_cast_long_unsigned(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rword r = (rword)RVM_REG_GETL(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_UNSIGNED);
+ RVM_REG_SETU(res, r);
+}
+
+
+void rvm_op_cast_long_double(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rdouble r = (rdouble)RVM_REG_GETL(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_DOUBLE);
+ RVM_REG_SETL(res, r);
+}
+
+
+void rvm_op_cast_unsigned_long(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rlong r = (rlong)RVM_REG_GETU(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_LONG);
+ RVM_REG_SETL(res, r);
+}
+
+
+void rvm_op_cast_unsigned_double(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ rdouble r = (rdouble)RVM_REG_GETU(arg1);
+
+ RVM_REG_CLEAR(res);
+ RVM_REG_SETTYPE(res, RVM_DTYPE_DOUBLE);
+ RVM_REG_SETD(res, r);
+}
+
+
+void rvm_op_cast_string_string(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ if (res == arg1)
+ RVM_ABORT(cpu, RVM_E_ILLEGALDST);
+ rvm_reg_setstring(res, r_string_copy(RVM_REG_GETP(arg1)));
+}
+
+
+void rvm_op_cast_refreg_string(rvmcpu_t *cpu, rvmreg_t *res, const rvmreg_t *arg1, const rvmreg_t *arg2)
+{
+ if (res == arg1)
+ RVM_ABORT(cpu, RVM_E_ILLEGALDST);
+ rvm_reg_refer(res, arg1);
+}
+
+
+void rvm_op_cast_init(rvm_opmap_t *opmap)
+{
+ rvm_opmap_add_binary_operator(opmap, RVM_OPID_CAST);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_static_static, RVM_DTYPE_DOUBLE, RVM_DTYPE_DOUBLE);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_static_static, RVM_DTYPE_LONG, RVM_DTYPE_LONG);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_long_double, RVM_DTYPE_LONG, RVM_DTYPE_DOUBLE);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_long_unsigned, RVM_DTYPE_LONG, RVM_DTYPE_UNSIGNED);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_double_long, RVM_DTYPE_DOUBLE, RVM_DTYPE_LONG);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_double_unsigned, RVM_DTYPE_DOUBLE, RVM_DTYPE_UNSIGNED);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_unsigned_long, RVM_DTYPE_UNSIGNED, RVM_DTYPE_LONG);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_unsigned_double, RVM_DTYPE_UNSIGNED, RVM_DTYPE_DOUBLE);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_refreg_string, RVM_DTYPE_REFREG, RVM_DTYPE_STRING);
+ rvm_opmap_set_binary_handler(opmap, RVM_OPID_CAST, rvm_op_cast_string_string, RVM_DTYPE_STRING, RVM_DTYPE_STRING);
+}
+
--- /dev/null
+#ifndef _RVMOPERATORCAST_H_
+#define _RVMOPERATORCAST_H_
+
+#include "rvmoperator.h"
+
+void rvm_op_cast_init(rvm_opmap_t *opmap);
+
+#endif
{
RVM_REG_SETL(r, l);
RVM_REG_SETTYPE(r, RVM_DTYPE_LONG);
- RVM_REG_CLRFLAG(r, RVM_INFOBIT_ALL);
+ RVM_REG_CLRFLAG(r, RVM_INFOBIT_ROBJECT);
}
{
RVM_REG_SETD(r, d);
RVM_REG_SETTYPE(r, RVM_DTYPE_DOUBLE);
- RVM_REG_CLRFLAG(r, RVM_INFOBIT_ALL);
+ RVM_REG_CLRFLAG(r, RVM_INFOBIT_ROBJECT);
}
RVM_REG_CLEAR(reg);
rvm_reg_setrefreg(reg, refreg);
}
+
+
+rvmreg_t *rvm_reg_unshadow(rvmreg_t *reg)
+{
+ if (rvm_reg_gettype(reg) != RVM_DTYPE_REFREG)
+ return reg;
+ return REFREG2REGPTR(RVM_REG_GETP(reg));
+}
void rvm_reg_setarray(rvmreg_t *r, rarray_t *ptr);
void rvm_reg_setharray(rvmreg_t *r, rharray_t *ptr);
void rvm_reg_convert_to_refreg(rvmreg_t *r);
+rvmreg_t *rvm_reg_unshadow(rvmreg_t *reg);
struct rrefreg_s;
void rvm_reg_setrefreg(rvmreg_t *r, struct rrefreg_s *ptr);
* R0 = R0 + R1 + R2
*/
l_add3 = &vmcode[off];
- vmcode[off++] = rvm_asmu(RVM_PUSHM,DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(LR));
- vmcode[off++] = rvm_asmi(RVM_PUSH, R2, XX, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_PUSHM,DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(LR));
+ vmcode[off++] = rvm_asm(RVM_PUSH, R2, XX, XX, 0);
vmcode[off++] = rvm_asmr(RVM_BL, DA, XX, XX, &l_add2);
- vmcode[off++] = rvm_asmi(RVM_POP, R1, XX, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_POP, R1, XX, XX, 0);
vmcode[off++] = rvm_asmr(RVM_BL, DA, XX, XX, &l_add2);
- vmcode[off++] = rvm_asmi(RVM_POPM, DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(LR));
- vmcode[off++] = rvm_asmi(RVM_RET, XX, XX, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_POPM, DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(LR));
+ vmcode[off++] = rvm_asm(RVM_RET, XX, XX, XX, 0);
/*
* We could directly restore the LR in the PC, so we will not need the RET instruction after POPM
*
- * vmcode[off++] = rvm_asmi(RVM_POPM, DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(PC));
+ * vmcode[off++] = rvm_asm(RVM_POPM, DA, XX, XX, BIT(R7)|BIT(R8)|BIT(SP)|BIT(PC));
*
*/
l_main = &vmcode[off];
- vmcode[off++] = rvm_asmi(RVM_MOV, R0, DA, XX, 1);
- vmcode[off++] = rvm_asmi(RVM_MOV, R1, DA, XX, 2);
+ vmcode[off++] = rvm_asm(RVM_MOV, R0, DA, XX, 1);
+ vmcode[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 2);
vmcode[off++] = rvm_asmr(RVM_BL, DA, XX, XX, &l_add2);
VMTEST_REG(vmcode, off, 0, 3, "BL/RET");
- vmcode[off++] = rvm_asmi(RVM_MOV, R0, DA, XX, 1);
- vmcode[off++] = rvm_asmi(RVM_MOV, R1, DA, XX, 2);
- vmcode[off++] = rvm_asmi(RVM_MOV, R2, DA, XX, 4);
+ vmcode[off++] = rvm_asm(RVM_MOV, R0, DA, XX, 1);
+ vmcode[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 2);
+ vmcode[off++] = rvm_asm(RVM_MOV, R2, DA, XX, 4);
vmcode[off++] = rvm_asmr(RVM_BL, DA, XX, XX, &l_add3);
VMTEST_REG(vmcode, off, 0, 7, "BL/RET");
- vmcode[off++] = rvm_asmi(RVM_EXT, R0, XX, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_EXT, R0, XX, XX, 0);
rvm_relocate(vmcode, off);
--- /dev/null
+#include <stdio.h>
+#include "rrefreg.h"
+#include "rvmcpu.h"
+#include "common.h"
+
+static void test_swi_print_r(rvmcpu_t *cpu, rvm_asmins_t *ins)
+{
+ rvmreg_t *r = RVM_CPUREG_PTR(cpu, ins->op2);
+
+ if (rvm_reg_gettype(r) == RVM_DTYPE_REFREG)
+ r = REFREG2REGPTR(RVM_REG_GETP(r));
+ if (rvm_reg_gettype(r) == RVM_DTYPE_WORD)
+ fprintf(stdout, "R%d = %ld\n", ins->op2, RVM_REG_GETL(r));
+ else if (rvm_reg_gettype(r) == RVM_DTYPE_LONG)
+ fprintf(stdout, "R%d = %ld\n", ins->op2, RVM_REG_GETL(r));
+ else if (rvm_reg_gettype(r) == RVM_DTYPE_DOUBLE)
+ fprintf(stdout, "R%d = %5.2f\n", ins->op2, RVM_REG_GETD(r));
+ else if (rvm_reg_gettype(r) == RVM_DTYPE_STRING)
+ fprintf(stdout, "R%d = %s\n", ins->op2, ((rstring_t*) RVM_REG_GETP(r))->s.str);
+ else
+ fprintf(stdout, "R%d = Unknown type\n", ins->op2);
+}
+
+
+static rvm_switable_t switable[] = {
+ {"print", test_swi_print_r},
+ {NULL, NULL},
+};
+
+
+int main(int argc, char *argv[])
+{
+ ruint ret = 0;
+ ruint off = 0;
+ rvmreg_t d1 = rvm_reg_create_double(1.0);
+ rvmreg_t d2 = rvm_reg_create_double(-1.0);
+ rvm_asmins_t vmcode[256];
+ rvmcpu_t *vm = rvm_cpu_create();
+
+ rvmcpu_switable_add(vm, common_calltable);
+ rvmcpu_switable_add(vm, switable);
+ vmcode[off++] = rvm_asmp(RVM_LDRR, R0, DA, XX, &d1);
+ vmcode[off++] = rvm_asm(ERVM_TYPE, R1, R0, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_SWI, DA, R1, XX, rvm_cpu_getswi(vm, "print"));
+ vmcode[off++] = rvm_asm(ERVM_CAST, R0, R0, DA, RVM_DTYPE_UNSIGNED);
+ vmcode[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 2);
+ vmcode[off++] = rvm_asm(RVM_ADD, R0, R1, R0, 0);
+ vmcode[off++] = rvm_asm(RVM_SWI, DA, R0, XX, rvm_cpu_getswi(vm, "print"));
+ VMTEST_REG(vmcode, off, 0, 3, "CAST");
+ VMTEST_STATUS(vmcode, off, 0, "CAST STATUS");
+
+ vmcode[off++] = rvm_asmp(RVM_LDRR, R0, DA, XX, &d2);
+ vmcode[off++] = rvm_asm(ERVM_TYPE, R1, R0, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_SWI, DA, R1, XX, rvm_cpu_getswi(vm, "print"));
+ vmcode[off++] = rvm_asm(ERVM_CAST, R0, R0, DA, RVM_DTYPE_LONG);
+ vmcode[off++] = rvm_asm(RVM_SWI, DA, R0, XX, rvm_cpu_getswi(vm, "print"));
+ vmcode[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 2);
+ vmcode[off++] = rvm_asm(RVM_ADD, R0, R1, R0, 0);
+ vmcode[off++] = rvm_asm(RVM_SWI, DA, R0, XX, rvm_cpu_getswi(vm, "print"));
+ VMTEST_REG(vmcode, off, 0, 1, "CAST");
+ VMTEST_STATUS(vmcode, off, 0, "CAST STATUS");
+
+
+ vmcode[off++] = rvm_asm(RVM_EXT, R0, XX, XX, 0);
+#ifdef EXECDEBUG
+ ret = rvm_cpu_exec_debug(vm, vmcode, 0);
+#else
+ ret = rvm_cpu_exec(vm, vmcode, 0);
+#endif
+ rvm_cpu_destroy(vm);
+ return 0;
+}
$(OUTDIR)/scope-test \
$(OUTDIR)/rhash-test \
$(OUTDIR)/rvm-test \
+ $(OUTDIR)/loop-test \
$(OUTDIR)/memalloc-test \
+ $(OUTDIR)/asm-cast \
$(OUTDIR)/asm-add \
$(OUTDIR)/asm-adds \
$(OUTDIR)/asm-b \
--- /dev/null
+#include <stdio.h>
+#include "common.h"
+
+
+
+int main(int argc, char *argv[])
+{
+ ruint ret = 0;
+ ruint off = 0;
+ rvm_asmins_t vmcode[256];
+ rvmcpu_t *vm = rvm_cpu_create();
+
+ rvmcpu_switable_add(vm, common_calltable);
+
+ vmcode[off++] = rvm_asm(RVM_MOV, R4, DA, XX, 0);
+ vmcode[off++] = rvm_asm(RVM_MOV, R5, DA, XX, 1000*1000 * 200);
+ vmcode[off++] = rvm_asm(RVM_ADD, R4, R4, DA, 1);
+ vmcode[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 1);
+ vmcode[off++] = rvm_asm(RVM_MOV, R2, DA, XX, 2);
+ vmcode[off++] = rvm_asm(RVM_ADD, R0, R1, R2, 0);
+ vmcode[off++] = rvm_asm(RVM_CMP, R4, R5, XX, 0);
+ vmcode[off++] = rvm_asml(RVM_BLES, DA, XX, XX, -5);
+ vmcode[off++] = rvm_asm(RVM_EXT, R0, XX, XX, 0);
+
+
+ rvm_relocate(vmcode, off);
+ ret = rvm_cpu_exec(vm, vmcode, 0);
+ fprintf(stdout, "R0 = %ld (%ld operations)\n", (unsigned long) RVM_CPUREG_GETU(vm, R0), (unsigned long)RVM_CPUREG_GETU(vm, R5));
+ rvm_cpu_destroy(vm);
+ return 0;
+}
rvm_opmap_set_binary_handler(opmap, RVM_OPID_DIV, rvm_op_div_long_long, RVM_DTYPE_LONG, RVM_DTYPE_LONG);
ntable = rvmcpu_switable_add(cpu, switable);
- code[off++] = rvm_asmd(RVM_MOV, R1, DA, XX, 1);
- code[off++] = rvm_asml(RVM_MOV, R2, DA, XX, 3.2);
+ code[off++] = rvm_asm(RVM_MOV, R1, DA, XX, 1);
+ code[off++] = rvm_asm(RVM_MOV, R2, DA, XX, 3);
// code[off++] = rvm_asm(RVM_SWI, DA, XX, XX, RVM_SWI_ID(ntable, 1)); // mul
code[off++] = rvm_asm(RVM_MOV, R0, DA, XX, rvm_cpu_getswi(cpu, "add")); // add
code[off++] = rvm_asm(RVM_SWI, R0, R1, R2, 0);