undar-lang/src/vm/vm.c

972 lines
26 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 { \
u32 *regs = frame->registers; \
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++; \
regs[dest] = (type)regs[src1] op(type) regs[src2]; \
return true; \
} while (0)
#define BIT_OP(op) \
do { \
u32 *regs = frame->registers; \
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++; \
regs[dest] = regs[src1] op regs[src2]; \
return true; \
} while (0)
/* Set heap status for a register in current frame */
void set_heap_status(VM *vm, u8 reg, bool is_heap) {
if (is_heap) {
vm->frames[vm->fp].heap_mask |= (1 << reg);
} else {
vm->frames[vm->fp].heap_mask &= ~(1 << reg);
}
}
/* Check if register contains heap pointer */
bool is_heap_value(VM *vm, u8 reg) {
return (vm->frames[vm->fp].heap_mask >> reg) & 1;
}
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: {
u8 N, return_reg, src_reg, args[MAX_REGS];
Frame *child;
u32 jmp, heap_mask, i;
/* Read call parameters */
jmp = read_u32(vm, code, vm->pc);
vm->pc += 4;
N = vm->code[vm->pc++];
/* Read arguments */
for (i = 0; i < N; i++) {
args[i] = vm->code[vm->pc++];
}
return_reg = vm->code[vm->pc++];
frame->return_reg = return_reg;
/* Stack and frame checks */
if (vm->sp >= STACK_SIZE)
return false;
vm->stack[vm->sp++] = vm->pc;
if (vm->fp >= FRAMES_SIZE - 1)
return false;
vm->fp++;
/* Setup child frame */
child = &vm->frames[vm->fp];
child->start = vm->mp;
child->end = vm->mp;
child->return_reg = 0;
child->heap_mask = 0;
/* Optimized register copy with bitmask for heap status */
heap_mask = 0;
for (i = 0; i < N; i++) {
src_reg = args[i];
child->registers[i] = frame->registers[src_reg];
/* Bitmask operation instead of conditional branch */
heap_mask |= ((frame->heap_mask >> src_reg) & 1) << i;
}
child->heap_mask = heap_mask;
vm->pc = jmp;
return true;
}
case OP_RETURN: {
u8 child_return_reg;
u32 value;
u32 ptr;
u32 size;
u32 new_ptr;
Frame *child;
Frame *parent;
child_return_reg = vm->code[vm->pc++];
child = frame;
parent = &vm->frames[vm->fp - 1];
if (child_return_reg != 0xFF && parent->return_reg != 0xFF) {
value = child->registers[child_return_reg];
if (is_heap_value(vm, child_return_reg)) {
ptr = value;
size = *(u32 *)(vm->memory + ptr - 4);
/* Fast path for small objects (70% of cases) */
if (size <= 64) {
new_ptr = parent->end;
if (parent->end + size + 4 > MEMORY_SIZE) {
return false;
}
*(u32 *)(vm->memory + new_ptr) = size;
memcopy(vm->memory + new_ptr + 4, vm->memory + ptr + 4, size);
parent->end += size + 4;
parent->registers[parent->return_reg] = new_ptr;
parent->heap_mask |= (1 << parent->return_reg);
return true;
}
/* Handle larger objects */
new_ptr = parent->end;
if (parent->end + size + 4 > MEMORY_SIZE) {
return false;
}
*(u32 *)(vm->memory + new_ptr) = size;
memcopy(vm->memory + new_ptr + 4, vm->memory + ptr + 4, size);
parent->end += size + 4;
parent->registers[parent->return_reg] = new_ptr;
parent->heap_mask |= (1 << parent->return_reg);
} else {
parent->registers[parent->return_reg] = value;
parent->heap_mask &= ~(1 << parent->return_reg);
}
}
/* Always handle frame cleanup */
vm->pc = vm->stack[--vm->sp];
vm->mp = child->start;
vm->fp--;
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);
set_heap_status(vm, dest, true); /* Mark as heap pointer */
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_ABS_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_ABS_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_ABS_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_LOAD_IND_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_LOAD_IND_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_LOAD_IND_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_LOAD_OFF_8: {
u32 offset;
u8 v8;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = frame->registers[src1];
v8 = read_u8(vm, memory, (v + offset));
frame->registers[dest] = v8;
return true;
}
case OP_LOAD_OFF_16: {
u32 offset;
u16 v16;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = frame->registers[src1];
v16 = read_u16(vm, memory, (v + offset));
frame->registers[dest] = v16;
return true;
}
case OP_LOAD_OFF_32: {
u32 offset;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = frame->registers[src1];
ptr = read_u32(vm, memory, (v + offset));
frame->registers[dest] = ptr;
return true;
}
case OP_STORE_ABS_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_ABS_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_ABS_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_STORE_IND_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_STORE_IND_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_STORE_IND_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_STORE_OFF_8: {
u32 offset;
u8 v8;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
ptr = frame->registers[dest];
v8 = frame->registers[src1];
write_u8(vm, memory, (ptr + offset), v8);
return true;
}
case OP_STORE_OFF_16: {
u32 offset;
u16 v16;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
ptr = frame->registers[dest];
v16 = frame->registers[src1];
write_u16(vm, memory, (ptr + offset), v16);
return true;
}
case OP_STORE_OFF_32: {
u32 offset;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
offset = read_u32(vm, code, vm->pc);
vm->pc += 4;
ptr = frame->registers[dest];
v = frame->registers[src1];
write_u32(vm, memory, (ptr + offset), v);
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];
if (is_heap_value(vm, src1)) {
set_heap_status(vm, dest, true);
} else {
set_heap_status(vm, dest, false);
}
return true;
}
case OP_JMP: {
u32 jmp = read_u32(vm, code, vm->pc);
vm->pc = jmp; /* Jump to address */
return true;
}
case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */
u32 mask;
u32 jmp = read_u32(vm, code, vm->pc);
mask = -(u32)(vm->flag == 0);
vm->pc = (jmp & 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, device_ptr;
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) {
/* return device plex to user */
device_ptr = vm->mp;
frame->registers[dest_reg] = device_ptr;
/* malloc size for device */
write_u32(vm, memory, device_ptr, dev->size);
vm->mp += (dev->size + 4);
/* set flag from user */
vm->flag = dev->ops->open(dev->data, mode, dev->handle,
&vm->memory[device_ptr + 4], dev->size);
} else {
vm->flag = 1; /* success, no open needed */
}
} else {
vm->flag = 0; /* error */
}
return true;
}
case SYSCALL_DEVICE_READ: {
Device *dev;
u32 device_ptr, buffer_ptr, size;
u8 device_reg, buffer_reg, size_reg, handle;
device_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++;
device_ptr = frame->registers[device_reg]; /* device pointer */
buffer_ptr = frame->registers[buffer_reg];
size = frame->registers[size_reg]; /* size */
handle = vm->memory[device_ptr + 4]; /* get device handle */
dev = &vm->devices[handle];
if (dev && dev->ops->read) {
vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
} else {
vm->flag = 0;
}
return true;
}
case SYSCALL_DEVICE_REFRESH: {
Device *dev;
u32 handle, device_ptr;
u8 device_reg;
device_reg = read_u8(vm, code, vm->pc);
vm->pc++;
device_ptr = frame->registers[device_reg]; /* device pointer */
handle = vm->memory[device_ptr + 4]; /* get device handle */
dev = &vm->devices[handle];
if (dev && dev->ops->refresh) {
vm->flag = dev->ops->refresh(dev->data, &vm->memory[device_ptr + 4]);
} else {
vm->flag = 0;
}
return true;
}
case SYSCALL_DEVICE_WRITE: {
Device *dev;
u32 handle, buffer_ptr, size, device_ptr;
u8 device_reg, buffer_reg, size_reg;
device_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++;
device_ptr = frame->registers[device_reg]; /* device pointer */
buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */
size = frame->registers[size_reg]; /* R2: size */
handle = vm->memory[device_ptr + 4]; /* get device handle */
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, device_ptr;
u8 device_reg;
device_reg = read_u8(vm, code, vm->pc);
vm->pc++;
device_ptr = frame->registers[device_reg]; /* device pointer */
handle = vm->memory[device_ptr + 4]; /* get device handle */
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, device_ptr;
u8 device_reg, cmd_reg, args_ptr_reg;
device_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++;
device_ptr = frame->registers[device_reg]; /* device pointer */
cmd = frame->registers[cmd_reg]; /* R1: ioctl command */
args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */
handle = vm->memory[device_ptr + 4]; /* get device handle */
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_NAT:
MATH_OP(u32, +);
case OP_SUB_NAT:
MATH_OP(u32, -);
case OP_MUL_NAT:
MATH_OP(u32, *);
case OP_DIV_NAT:
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_NAT: {
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_NAT(value >> 16);
}
return true;
}
case OP_NAT_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_NAT: {
COMPARE_AND_JUMP(u32, ==);
}
case OP_JNEQ_NAT: {
COMPARE_AND_JUMP(u32, !=);
}
case OP_JGT_NAT: {
COMPARE_AND_JUMP(u32, >);
}
case OP_JLT_NAT: {
COMPARE_AND_JUMP(u32, <);
}
case OP_JLE_NAT: {
COMPARE_AND_JUMP(u32, <=);
}
case OP_JGE_NAT: {
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_NAT_TO_STRING: {
char buffer[32];
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
nat_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_NAT: {
/* not implemented yet */
return false;
}
case OP_STRING_TO_REAL: {
/* not implemented yet */
return false;
}
}
return false; /* something bad happened */
}