765 lines
20 KiB
C
765 lines
20 KiB
C
#include "vm.h"
|
|
#include "device.h"
|
|
#include "opcodes.h"
|
|
#include "str.h"
|
|
|
|
#define COMPARE_AND_JUMP(type, op) \
|
|
do { \
|
|
i32 cond; \
|
|
u32 mask, target; \
|
|
u8 src1, src2; \
|
|
type value; \
|
|
type value2; \
|
|
target = read_u32(vm, code, vm->pc); \
|
|
vm->pc += 4; \
|
|
src1 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
src2 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
value = (type)frame->registers[src1]; \
|
|
value2 = (type)frame->registers[src2]; \
|
|
cond = !!(value op value2); \
|
|
mask = -(u32)cond; \
|
|
vm->pc = (target & mask) | (vm->pc & ~mask); \
|
|
return true; \
|
|
} while (0)
|
|
|
|
#define MATH_OP(type, op) \
|
|
do { \
|
|
dest = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
src1 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
src2 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
frame->registers[dest] = \
|
|
(type)frame->registers[src1] op(type) frame->registers[src2]; \
|
|
return true; \
|
|
} while (0)
|
|
|
|
#define BIT_OP(op) \
|
|
do { \
|
|
dest = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
src1 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
src2 = read_u8(vm, code, vm->pc); \
|
|
vm->pc++; \
|
|
frame->registers[dest] = frame->registers[src1] op frame->registers[src2]; \
|
|
return true; \
|
|
} while (0)
|
|
|
|
u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length) {
|
|
u32 str_addr = vm->mp;
|
|
u32 i = 0;
|
|
vm->mp += 4;
|
|
while (i < length) {
|
|
vm->memory[vm->mp++] = str[i++];
|
|
}
|
|
vm->memory[vm->mp++] = '\0';
|
|
|
|
write_u32(vm, memory, str_addr, length);
|
|
frame->end = vm->mp;
|
|
return str_addr;
|
|
}
|
|
|
|
/**
|
|
* Step to the next opcode in the vm.
|
|
*/
|
|
bool step_vm(VM *vm) {
|
|
u16 opcode, dest, src1, src2;
|
|
u32 v, ptr;
|
|
i32 value;
|
|
Frame *frame;
|
|
|
|
/* Get current instruction & Advance to next instruction */
|
|
opcode = vm->code[vm->pc++];
|
|
frame = &vm->frames[vm->fp];
|
|
|
|
switch (opcode) {
|
|
case OP_HALT: {
|
|
return false;
|
|
}
|
|
case OP_CALL: {
|
|
u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */
|
|
vm->pc += 4;
|
|
vm->return_stack[vm->rp++] = vm->pc; /* set return address */
|
|
vm->fp++; /* increment to the next free frame */
|
|
vm->frames[vm->fp].start = vm->mp; /* set start of new memory block */
|
|
vm->pc = jmp;
|
|
return true;
|
|
}
|
|
case OP_RETURN: {
|
|
frame->rp = 0; /* reset register ptr */
|
|
vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */
|
|
vm->mp =
|
|
vm->frames[vm->fp--].start; /* reset memory pointer to start
|
|
of old slice, pop the frame */
|
|
return true;
|
|
}
|
|
case OP_MALLOC: {
|
|
u32 size;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = vm->mp;
|
|
size = frame->registers[src1];
|
|
write_u32(vm, memory, vm->mp, size);
|
|
vm->mp += (size + 4);
|
|
return true;
|
|
}
|
|
case OP_MEMSET_32: {
|
|
u32 i, start, end;
|
|
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
|
u8 value_reg = read_u8(vm, code, vm->pc++);
|
|
u8 count_reg = read_u8(vm, code, vm->pc++);
|
|
|
|
u32 dest = frame->registers[dest_reg];
|
|
u32 value = frame->registers[value_reg];
|
|
u32 count = frame->registers[count_reg];
|
|
|
|
if (count == 0) {
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
|
|
start = dest;
|
|
end = dest + count;
|
|
|
|
if (start >= vm->mp || count > vm->mp ||
|
|
end > vm->mp) {
|
|
vm->flag = 0;
|
|
return true;
|
|
}
|
|
|
|
for (i = start; i < end; i+=4) {
|
|
write_u32(vm, memory, i, value);
|
|
}
|
|
|
|
frame->registers[0] = dest;
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
case OP_MEMSET_16: {
|
|
u32 i, start, end;
|
|
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
|
u8 value_reg = read_u8(vm, code, vm->pc++);
|
|
u8 count_reg = read_u8(vm, code, vm->pc++);
|
|
|
|
u32 dest = frame->registers[dest_reg];
|
|
u16 value = (u16)(frame->registers[value_reg]);
|
|
u32 count = frame->registers[count_reg];
|
|
|
|
if (count == 0) {
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
|
|
start = dest;
|
|
end = dest + count;
|
|
|
|
if (start >= vm->mp || count > vm->mp ||
|
|
end > vm->mp) {
|
|
vm->flag = 0;
|
|
return true;
|
|
}
|
|
|
|
for (i = start; i < end; i+=2) {
|
|
write_u16(vm, memory, i, value);
|
|
}
|
|
|
|
frame->registers[0] = dest;
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
case OP_MEMSET_8: {
|
|
u32 i, start, end;
|
|
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
|
u8 value_reg = read_u8(vm, code, vm->pc++);
|
|
u8 count_reg = read_u8(vm, code, vm->pc++);
|
|
|
|
u32 dest = frame->registers[dest_reg];
|
|
u8 value = (u8)(frame->registers[value_reg]);
|
|
u32 count = frame->registers[count_reg];
|
|
|
|
if (count == 0) {
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
|
|
start = dest;
|
|
end = dest + count;
|
|
|
|
if (start >= vm->mp || count > vm->mp ||
|
|
end > vm->mp) {
|
|
vm->flag = 0;
|
|
return true;
|
|
}
|
|
|
|
for (i = start; i < end; i++) {
|
|
write_u8(vm, memory, i, value);
|
|
}
|
|
|
|
frame->registers[0] = dest;
|
|
vm->flag = 1;
|
|
return true;
|
|
}
|
|
case OP_LOAD_IMM: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = read_u32(vm, code, vm->pc);
|
|
vm->pc += 4;
|
|
frame->registers[dest] = v;
|
|
return true;
|
|
}
|
|
case OP_LOAD_32: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = read_u32(vm, code, vm->pc);
|
|
vm->pc += 4;
|
|
v = read_u32(vm, memory, ptr);
|
|
frame->registers[dest] = v;
|
|
return true;
|
|
}
|
|
case OP_LOAD_16: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = read_u32(vm, code, vm->pc);
|
|
vm->pc += 4;
|
|
v = read_u16(vm, memory, ptr);
|
|
frame->registers[dest] = v;
|
|
return true;
|
|
}
|
|
case OP_LOAD_8: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = read_u32(vm, code, vm->pc);
|
|
vm->pc += 4;
|
|
v = read_u8(vm, memory, ptr);
|
|
frame->registers[dest] = v;
|
|
return true;
|
|
}
|
|
case OP_GET_32: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
ptr = read_u32(vm, memory, v);
|
|
frame->registers[dest] = ptr;
|
|
return true;
|
|
}
|
|
case OP_GET_16: {
|
|
u16 v16;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
v16 = read_u16(vm, memory, v);
|
|
frame->registers[dest] = v16;
|
|
return true;
|
|
}
|
|
case OP_GET_8: {
|
|
u8 v8;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
v8 = read_u8(vm, memory, v);
|
|
frame->registers[dest] = v8;
|
|
return true;
|
|
}
|
|
case OP_STORE_32: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
ptr = frame->registers[dest];
|
|
write_u32(vm, memory, ptr, v);
|
|
return true;
|
|
}
|
|
case OP_STORE_16: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
ptr = frame->registers[dest];
|
|
write_u16(vm, memory, ptr, v);
|
|
return true;
|
|
}
|
|
case OP_STORE_8: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
v = frame->registers[src1];
|
|
ptr = frame->registers[dest];
|
|
write_u8(vm, memory, ptr, v);
|
|
return true;
|
|
}
|
|
case OP_PUT_32: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = frame->registers[dest];
|
|
v = frame->registers[src1];
|
|
write_u32(vm, memory, ptr, v);
|
|
return true;
|
|
}
|
|
case OP_PUT_16: {
|
|
u16 v16;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = frame->registers[dest];
|
|
v16 = frame->registers[src1];
|
|
write_u16(vm, memory, ptr, v16);
|
|
return true;
|
|
}
|
|
case OP_PUT_8: {
|
|
u8 v8;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
ptr = frame->registers[dest];
|
|
v8 = frame->registers[src1];
|
|
write_u8(vm, memory, ptr, v8);
|
|
return true;
|
|
}
|
|
case OP_PUSH: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
vm->stack[++vm->sp] = frame->registers[dest];
|
|
return true;
|
|
}
|
|
case OP_POP: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = vm->stack[vm->sp--];
|
|
return true;
|
|
}
|
|
case OP_REG_MOV: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = frame->registers[src1];
|
|
return true;
|
|
}
|
|
case OP_JMP: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
vm->pc = frame->registers[dest]; /* Jump to address */
|
|
return true;
|
|
}
|
|
case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */
|
|
u32 mask;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
mask = -(u32)(vm->flag == 0);
|
|
vm->pc = (dest & mask) | (vm->pc & ~mask);
|
|
return true;
|
|
}
|
|
case OP_SYSCALL: {
|
|
u32 syscall_id;
|
|
|
|
syscall_id = read_u32(vm, code, vm->pc);
|
|
vm->pc += 4;
|
|
|
|
switch (syscall_id) {
|
|
case SYSCALL_DEVICE_OPEN: {
|
|
Device *dev;
|
|
u32 path_ptr, mode;
|
|
u8 path_reg, mode_reg, dest_reg;
|
|
dest_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
path_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
mode_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
path_ptr = frame->registers[path_reg];
|
|
mode = frame->registers[mode_reg];
|
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
|
if (dev) {
|
|
if (dev->ops->open) {
|
|
vm->flag = dev->ops->open(dev->data, mode);
|
|
frame->registers[dest_reg] = dev->handle;
|
|
} else {
|
|
vm->flag = 1; /* success, no open needed */
|
|
}
|
|
} else {
|
|
vm->flag = 0; /* error */
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
case SYSCALL_DEVICE_READ: {
|
|
Device *dev;
|
|
u32 handle, buffer_ptr, size;
|
|
u16 handle_reg, buffer_reg, size_reg;
|
|
handle_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
buffer_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
size_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
handle = frame->registers[handle_reg]; /* path pointer */
|
|
size = frame->registers[size_reg]; /* size */
|
|
buffer_ptr = frame->registers[dest];
|
|
|
|
dev = &vm->devices[handle];
|
|
if (dev && dev->ops->read) {
|
|
vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
|
|
frame->registers[buffer_reg] = buffer_ptr;
|
|
} else {
|
|
vm->flag = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
case SYSCALL_DEVICE_WRITE: {
|
|
Device *dev;
|
|
u32 handle, buffer_ptr, size;
|
|
u16 handle_reg, buffer_reg, size_reg;
|
|
handle_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
buffer_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
size_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
handle = frame->registers[handle_reg]; /* R0: path pointer */
|
|
buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */
|
|
size = frame->registers[size_reg]; /* R2: size */
|
|
|
|
dev = &vm->devices[handle];
|
|
if (dev && dev->ops->write) {
|
|
vm->flag = dev->ops->write(
|
|
dev->data, (const u8 *)&vm->memory[buffer_ptr + 4], size);
|
|
} else {
|
|
vm->flag = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
case SYSCALL_DEVICE_CLOSE: {
|
|
Device *dev;
|
|
u32 handle;
|
|
u8 handle_reg;
|
|
handle_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
handle = frame->registers[handle_reg]; /* R0: path pointer */
|
|
|
|
dev = &vm->devices[handle];
|
|
if (dev && dev->ops->close) {
|
|
i32 result = dev->ops->close(dev->data);
|
|
vm->flag = result;
|
|
} else {
|
|
vm->flag = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
case SYSCALL_DEVICE_IOCTL: {
|
|
Device *dev;
|
|
u32 handle, args_ptr, cmd;
|
|
u8 handle_reg, cmd_reg, args_ptr_reg;
|
|
handle_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
cmd_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
args_ptr_reg = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
handle = frame->registers[handle_reg]; /* R0: device path */
|
|
cmd = frame->registers[cmd_reg]; /* R1: ioctl command */
|
|
args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */
|
|
|
|
dev = &vm->devices[handle];
|
|
if (dev && dev->ops && dev->ops->ioctl) {
|
|
i32 result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]);
|
|
vm->flag = result;
|
|
} else {
|
|
vm->flag = 0; /* error or no ioctl support */
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
case SYSCALL_EXIT: {
|
|
return false;
|
|
}
|
|
|
|
default: {
|
|
vm->flag = 0; /* unknown syscall */
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
case OP_SLL:
|
|
BIT_OP(<<);
|
|
case OP_SRL:
|
|
BIT_OP(>>);
|
|
case OP_SRE:
|
|
MATH_OP(i32, >>);
|
|
case OP_BAND:
|
|
BIT_OP(&);
|
|
case OP_BOR:
|
|
BIT_OP(|);
|
|
case OP_BXOR:
|
|
BIT_OP(^);
|
|
case OP_ADD_INT:
|
|
MATH_OP(i32, +);
|
|
case OP_SUB_INT:
|
|
MATH_OP(i32, -);
|
|
case OP_MUL_INT:
|
|
MATH_OP(i32, *);
|
|
case OP_DIV_INT:
|
|
MATH_OP(i32, /);
|
|
case OP_ADD_UINT:
|
|
MATH_OP(u32, +);
|
|
case OP_SUB_UINT:
|
|
MATH_OP(u32, -);
|
|
case OP_MUL_UINT:
|
|
MATH_OP(u32, *);
|
|
case OP_DIV_UINT:
|
|
MATH_OP(u32, /);
|
|
case OP_MUL_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src2 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] =
|
|
(frame->registers[src1] * frame->registers[src2]) >> 16;
|
|
return true;
|
|
}
|
|
|
|
case OP_DIV_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src2 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] =
|
|
(frame->registers[src1] << 16) / frame->registers[src2];
|
|
return true;
|
|
}
|
|
|
|
case OP_ADD_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src2 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = frame->registers[src1] + frame->registers[src2];
|
|
return true;
|
|
}
|
|
|
|
case OP_SUB_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src2 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = frame->registers[src1] - frame->registers[src2];
|
|
return true;
|
|
}
|
|
case OP_REAL_TO_INT: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
value = frame->registers[src1];
|
|
|
|
if (value >= 0) {
|
|
frame->registers[dest] = value >> 16;
|
|
} else {
|
|
frame->registers[dest] = -((-value) >> 16);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
case OP_INT_TO_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = (frame->registers[src1] << 16);
|
|
return true;
|
|
}
|
|
case OP_REAL_TO_UINT: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
value = frame->registers[src1];
|
|
if (value < 0) {
|
|
frame->registers[dest] = 0;
|
|
} else {
|
|
frame->registers[dest] = AS_UINT(value >> 16);
|
|
}
|
|
return true;
|
|
}
|
|
case OP_UINT_TO_REAL: {
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
frame->registers[dest] = AS_INT(frame->registers[src1] << 16);
|
|
return true;
|
|
}
|
|
case OP_JEQ_UINT: {
|
|
COMPARE_AND_JUMP(u32, ==);
|
|
}
|
|
case OP_JNEQ_UINT: {
|
|
COMPARE_AND_JUMP(u32, !=);
|
|
}
|
|
case OP_JGT_UINT: {
|
|
COMPARE_AND_JUMP(u32, >);
|
|
}
|
|
case OP_JLT_UINT: {
|
|
COMPARE_AND_JUMP(u32, <);
|
|
}
|
|
case OP_JLE_UINT: {
|
|
COMPARE_AND_JUMP(u32, <=);
|
|
}
|
|
case OP_JGE_UINT: {
|
|
COMPARE_AND_JUMP(u32, >=);
|
|
}
|
|
case OP_JEQ_INT: {
|
|
COMPARE_AND_JUMP(i32, ==);
|
|
}
|
|
case OP_JNEQ_INT: {
|
|
COMPARE_AND_JUMP(i32, !=);
|
|
}
|
|
case OP_JGT_INT: {
|
|
COMPARE_AND_JUMP(i32, >);
|
|
}
|
|
case OP_JLT_INT: {
|
|
COMPARE_AND_JUMP(i32, <);
|
|
}
|
|
case OP_JLE_INT: {
|
|
COMPARE_AND_JUMP(i32, <=);
|
|
}
|
|
case OP_JGE_INT: {
|
|
COMPARE_AND_JUMP(i32, >=);
|
|
}
|
|
case OP_JEQ_REAL: {
|
|
COMPARE_AND_JUMP(i32, ==);
|
|
}
|
|
case OP_JNEQ_REAL: {
|
|
COMPARE_AND_JUMP(i32, !=);
|
|
}
|
|
case OP_JGT_REAL: {
|
|
COMPARE_AND_JUMP(i32, >);
|
|
}
|
|
case OP_JLT_REAL: {
|
|
COMPARE_AND_JUMP(i32, <);
|
|
}
|
|
case OP_JGE_REAL: {
|
|
COMPARE_AND_JUMP(i32, >=);
|
|
}
|
|
case OP_JLE_REAL: {
|
|
COMPARE_AND_JUMP(i32, <=);
|
|
}
|
|
case OP_INT_TO_STRING: {
|
|
char buffer[32];
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
int_to_string(AS_INT(frame->registers[src1]), buffer);
|
|
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
|
frame->registers[dest] = ptr;
|
|
return true;
|
|
}
|
|
case OP_UINT_TO_STRING: {
|
|
char buffer[32];
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
uint_to_string(frame->registers[src1], buffer);
|
|
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
|
frame->registers[dest] = ptr;
|
|
return true;
|
|
}
|
|
case OP_REAL_TO_STRING: {
|
|
char buffer[32];
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
fixed_to_string(AS_INT(frame->registers[src1]), buffer);
|
|
ptr = str_alloc(vm, frame, buffer,
|
|
strlength(buffer)); /* copy buffer to dest */
|
|
frame->registers[dest] = ptr;
|
|
return true;
|
|
}
|
|
case OP_STRLEN: {
|
|
u32 ptr, length;
|
|
dest = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
src1 = read_u8(vm, code, vm->pc);
|
|
vm->pc++;
|
|
|
|
ptr = frame->registers[src1];
|
|
length = read_u32(vm, memory, ptr);
|
|
frame->registers[dest] = length;
|
|
return true;
|
|
}
|
|
case OP_STRCAT: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STR_GET_CHAR: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STR_FIND_CHAR: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STR_SLICE: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STRING_TO_INT: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STRING_TO_UINT: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
case OP_STRING_TO_REAL: {
|
|
/* not implemented yet */
|
|
return false;
|
|
}
|
|
}
|
|
return false; /* something bad happened */
|
|
}
|