add initial stuff, is very broken because of overflows
This commit is contained in:
parent
039aa7e9f9
commit
f476b74c3f
|
@ -2,6 +2,7 @@
|
|||
#define ZRL_OPCODES_H
|
||||
|
||||
#include "common.h"
|
||||
#include "fixed.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
|
@ -10,8 +11,8 @@ typedef enum {
|
|||
OP_GET_PC, /* pc : dest = current program counter */
|
||||
OP_CALL, /* call : creates a new frame */
|
||||
OP_RETURN, /* retn : returns from a frame to the parent frame */
|
||||
OP_LOAD, /* load : dest = &[next memory location] */
|
||||
OP_STORE, /* stor : next memory location = src1 as float */
|
||||
OP_LOAD, /* load : dest = &[next code location] */
|
||||
OP_STORE, /* stor : next code location = src1 as float */
|
||||
OP_PUSH, /* push : push str ref from register onto the stack and copy str */
|
||||
OP_POP, /* pop : pop int from stack onto the register */
|
||||
OP_REG_MOV, /* rmov : dest = src1 */
|
||||
|
@ -63,8 +64,8 @@ typedef enum {
|
|||
OP_STRING_TO_UINT,/* stou : dest = src1 as uint */
|
||||
OP_STRING_TO_REAL,/* stor : dest = src1 as real */
|
||||
/* to remove (replace with device), just for testing for now */
|
||||
OP_DBG_PRINT_STRING,
|
||||
OP_DBG_READ_STRING,
|
||||
OP_DBG_PRINT_STRING,/* puts : write src1 as str to stdout */
|
||||
OP_DBG_READ_STRING, /* gets : read to dest as str from stdin */
|
||||
} Opcode;
|
||||
|
||||
/* defines a uint32 opcode */
|
||||
|
@ -76,7 +77,7 @@ typedef enum {
|
|||
|
||||
typedef union value_u {
|
||||
int32_t i; /* Integers */
|
||||
float f; /* Float */
|
||||
fixed_t f; /* Fixed point */
|
||||
uint32_t u; /* Unsigned integers, also used for pointer address */
|
||||
char c[4]; /* 4 Byte char array for string packing */
|
||||
} Value;
|
||||
|
@ -123,7 +124,7 @@ typedef struct device_s {
|
|||
uint32_t flags; /* permissions, status, etc. */
|
||||
} Device;
|
||||
|
||||
#define MEMORY_SIZE (640 * 480 + 65536)
|
||||
#define MEMORY_SIZE ((640 * 480) + 65536)
|
||||
#define CODE_SIZE 8192
|
||||
#define FRAMES_SIZE 128
|
||||
#define STACK_SIZE 256
|
||||
|
|
277
src/vm.c
277
src/vm.c
|
@ -1,6 +1,8 @@
|
|||
#include "vm.h"
|
||||
#include "device.h"
|
||||
#include <string.h>
|
||||
#include "fixed.h"
|
||||
#include "opcodes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* no inline fn in ANSI C :( */
|
||||
#define COMPARE_AND_JUMP(type, accessor, op) \
|
||||
|
@ -12,17 +14,6 @@
|
|||
return true; \
|
||||
} while (0)
|
||||
|
||||
#define MATH_OP(accessor, op) \
|
||||
do { \
|
||||
vm->frames[vm->fp].registers[dest].accessor = \
|
||||
vm->frames[vm->fp] \
|
||||
.registers[src1] \
|
||||
.accessor op vm->frames[vm->fp] \
|
||||
.registers[src2] \
|
||||
.accessor; \
|
||||
return true; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Embeds a string into the VM
|
||||
*/
|
||||
|
@ -49,11 +40,17 @@ uint32_t str_alloc(VM *vm, const char *str, uint32_t length) {
|
|||
|
||||
vm->memory[str_addr].u = length;
|
||||
vm->frames[vm->fp].allocated.end = vm->mp;
|
||||
|
||||
return str_addr;
|
||||
}
|
||||
|
||||
uint32_t real_alloc(VM *vm, float v) {
|
||||
uint32_t float_as_real_alloc(VM *vm, float v) {
|
||||
uint32_t addr = vm->mp;
|
||||
vm->memory[vm->mp++].f = float_to_fixed(v);
|
||||
vm->frames[vm->fp].allocated.end++;
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint32_t real_alloc(VM *vm, fixed_t v) {
|
||||
uint32_t addr = vm->mp;
|
||||
vm->memory[vm->mp++].f = v;
|
||||
vm->frames[vm->fp].allocated.end++;
|
||||
|
@ -74,6 +71,94 @@ uint32_t int_alloc(VM *vm, int32_t v) {
|
|||
return addr;
|
||||
}
|
||||
|
||||
#define MAX_LEN_INT32 12 /* -2147483648 plus null terminator */
|
||||
#define MAX_LEN_UINT32 11 /* 4294967295 plus null terminator */
|
||||
#define MAX_LEN_FIXED 20 /* Enough for fixed-point representation */
|
||||
const char radix_set[11] = "0123456789";
|
||||
|
||||
/* Convert int32 to string */
|
||||
uint32_t int_to_string(VM *vm, int32_t v) {
|
||||
char buffer[MAX_LEN_INT32] = {0};
|
||||
int32_t n = v;
|
||||
bool neg = n < 0;
|
||||
if (neg)
|
||||
n = -n;
|
||||
int i = MAX_LEN_INT32;
|
||||
do {
|
||||
buffer[--i] = radix_set[n % 10];
|
||||
n /= 10;
|
||||
} while (n > 0);
|
||||
if (neg)
|
||||
buffer[--i] = '-';
|
||||
/* Ensure at least one digit is written for 0 */
|
||||
if (v == 0)
|
||||
buffer[--i] = '0';
|
||||
|
||||
uint32_t len = MAX_LEN_INT32 - i;
|
||||
return str_alloc(vm, buffer + i, len);
|
||||
}
|
||||
|
||||
/* Convert uint32 to string */
|
||||
uint32_t nat_to_string(VM *vm, uint32_t v) {
|
||||
char buffer[MAX_LEN_INT32] = {0};
|
||||
uint32_t n = v;
|
||||
int i = MAX_LEN_INT32;
|
||||
do {
|
||||
buffer[--i] = radix_set[n % 10];
|
||||
n /= 10;
|
||||
} while (n > 0);
|
||||
/* Ensure at least one digit is written for 0 */
|
||||
if (v == 0)
|
||||
buffer[--i] = '0';
|
||||
|
||||
uint32_t len = MAX_LEN_INT32 - i;
|
||||
return str_alloc(vm, buffer + i, len);
|
||||
}
|
||||
|
||||
/* Convert fixed-point to string */
|
||||
uint32_t real_to_string(VM *vm, fixed_t q) {
|
||||
char buffer[MAX_LEN_FIXED] = {0};
|
||||
|
||||
|
||||
/* Extract integer part (top 16 bits) */
|
||||
int32_t int_part = q >> 16;
|
||||
/* Extract fractional part (bottom 16 bits) */
|
||||
int32_t frac_part = q & 0xFFFF;
|
||||
|
||||
|
||||
int32_t n = frac_part;
|
||||
bool neg = n < 0;
|
||||
if (neg)
|
||||
n = -n;
|
||||
int i = MAX_LEN_FIXED;
|
||||
do {
|
||||
buffer[--i] = radix_set[n % 10];
|
||||
n /= 10;
|
||||
} while (n > 0);
|
||||
if (neg)
|
||||
buffer[--i] = '-';
|
||||
/* Ensure at least one digit is written for 0 */
|
||||
if (frac_part == 0)
|
||||
buffer[--i] = '0';
|
||||
|
||||
|
||||
/* Convert integer part to string (reverse order) */
|
||||
do {
|
||||
buffer[--i] = radix_set[int_part % 10];
|
||||
int_part /= 10;
|
||||
} while (int_part > 0);
|
||||
/* Ensure at least one digit is written for 0 */
|
||||
if (int_part == 0)
|
||||
buffer[--i] = '0';
|
||||
|
||||
/* Null-terminate */
|
||||
buffer[i] = '\0';
|
||||
|
||||
int32_t len = (MAX_LEN_INT32 - i);
|
||||
printf("i=%d, len=%d", i, len);
|
||||
return str_alloc(vm, buffer + i, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Step to the next opcode in the vm.
|
||||
*/
|
||||
|
@ -108,7 +193,9 @@ bool step_vm(VM *vm) {
|
|||
return true;
|
||||
}
|
||||
case OP_LOAD: {
|
||||
vm->frames[vm->fp].registers[dest].u = vm->code[vm->pc++].u;
|
||||
uint32_t ptr = vm->code[vm->pc++].u;
|
||||
Value v = vm->memory[ptr];
|
||||
vm->frames[vm->fp].registers[dest] = v;
|
||||
return true;
|
||||
}
|
||||
case OP_STORE: {
|
||||
|
@ -134,11 +221,13 @@ bool step_vm(VM *vm) {
|
|||
return true;
|
||||
}
|
||||
case OP_PUSH: {
|
||||
vm->stack[++vm->sp] = vm->frames[vm->fp].registers[dest];
|
||||
Value v = vm->frames[vm->fp].registers[dest];
|
||||
vm->stack[++vm->sp] = v;
|
||||
return true;
|
||||
}
|
||||
case OP_POP: {
|
||||
vm->frames[vm->fp].registers[dest] = vm->stack[vm->sp--];
|
||||
Value v = vm->stack[vm->sp--];
|
||||
vm->frames[vm->fp].registers[dest] = v;
|
||||
return true;
|
||||
}
|
||||
case OP_MEM_ALLOC: {
|
||||
|
@ -317,48 +406,98 @@ bool step_vm(VM *vm) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case OP_ADD_INT:
|
||||
MATH_OP(i, +);
|
||||
case OP_SUB_INT:
|
||||
MATH_OP(i, -);
|
||||
case OP_MUL_INT:
|
||||
MATH_OP(i, *);
|
||||
case OP_DIV_INT:
|
||||
MATH_OP(i, /);
|
||||
case OP_ADD_UINT:
|
||||
MATH_OP(u, +);
|
||||
case OP_SUB_UINT:
|
||||
MATH_OP(u, -);
|
||||
case OP_MUL_UINT:
|
||||
MATH_OP(u, *);
|
||||
case OP_DIV_UINT:
|
||||
MATH_OP(u, /);
|
||||
case OP_ADD_REAL:
|
||||
MATH_OP(f, +);
|
||||
case OP_SUB_REAL:
|
||||
MATH_OP(f, -);
|
||||
case OP_MUL_REAL:
|
||||
MATH_OP(f, *);
|
||||
case OP_DIV_REAL:
|
||||
MATH_OP(f, /);
|
||||
case OP_ADD_INT: {
|
||||
vm->frames[vm->fp].registers[dest].i =
|
||||
vm->frames[vm->fp].registers[src1].i +
|
||||
vm->frames[vm->fp].registers[src2].i;
|
||||
return true;
|
||||
}
|
||||
case OP_SUB_INT:{
|
||||
vm->frames[vm->fp].registers[dest].i =
|
||||
vm->frames[vm->fp].registers[src1].i -
|
||||
vm->frames[vm->fp].registers[src2].i;
|
||||
return true;
|
||||
}
|
||||
case OP_MUL_INT:{
|
||||
vm->frames[vm->fp].registers[dest].i =
|
||||
vm->frames[vm->fp].registers[src1].i *
|
||||
vm->frames[vm->fp].registers[src2].i;
|
||||
return true;
|
||||
}
|
||||
case OP_DIV_INT:{
|
||||
vm->frames[vm->fp].registers[dest].i =
|
||||
vm->frames[vm->fp].registers[src1].i /
|
||||
vm->frames[vm->fp].registers[src2].i;
|
||||
return true;
|
||||
}
|
||||
case OP_ADD_UINT:{
|
||||
vm->frames[vm->fp].registers[dest].u =
|
||||
vm->frames[vm->fp].registers[src1].u +
|
||||
vm->frames[vm->fp].registers[src2].u;
|
||||
return true;
|
||||
}
|
||||
case OP_SUB_UINT:{
|
||||
vm->frames[vm->fp].registers[dest].u =
|
||||
vm->frames[vm->fp].registers[src1].u -
|
||||
vm->frames[vm->fp].registers[src2].u;
|
||||
return true;
|
||||
}
|
||||
case OP_MUL_UINT:{
|
||||
vm->frames[vm->fp].registers[dest].u =
|
||||
vm->frames[vm->fp].registers[src1].u *
|
||||
vm->frames[vm->fp].registers[src2].u;
|
||||
return true;
|
||||
}
|
||||
case OP_DIV_UINT:{
|
||||
vm->frames[vm->fp].registers[dest].u =
|
||||
vm->frames[vm->fp].registers[src1].u /
|
||||
vm->frames[vm->fp].registers[src2].u;
|
||||
return true;
|
||||
}
|
||||
case OP_ADD_REAL:{
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
fixed_add(vm->frames[vm->fp].registers[src1].f,
|
||||
vm->frames[vm->fp].registers[src2].f);
|
||||
return true;
|
||||
}
|
||||
case OP_SUB_REAL:{
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
fixed_sub(vm->frames[vm->fp].registers[src1].f,
|
||||
vm->frames[vm->fp].registers[src2].f);
|
||||
return true;
|
||||
}
|
||||
case OP_MUL_REAL: {
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
fixed_mul(vm->frames[vm->fp].registers[src1].f,
|
||||
vm->frames[vm->fp].registers[src2].f);
|
||||
return true;
|
||||
}
|
||||
case OP_DIV_REAL: {
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
fixed_div(vm->frames[vm->fp].registers[src1].f,
|
||||
vm->frames[vm->fp].registers[src2].f);
|
||||
return true;
|
||||
}
|
||||
case OP_REAL_TO_INT: {
|
||||
vm->frames[vm->fp].registers[dest].i =
|
||||
(int32_t)(vm->frames[vm->fp].registers[src1].f);
|
||||
fixed_to_int(vm->frames[vm->fp].registers[src1].f);
|
||||
return true;
|
||||
}
|
||||
case OP_INT_TO_REAL: {
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
(float)(vm->frames[vm->fp].registers[src1].i);
|
||||
int_to_fixed(vm->frames[vm->fp].registers[src1].i);
|
||||
return true;
|
||||
}
|
||||
case OP_REAL_TO_UINT: {
|
||||
fixed_t f = vm->frames[vm->fp].registers[src1].f;
|
||||
int32_t i = fixed_to_int(f);
|
||||
vm->frames[vm->fp].registers[dest].u =
|
||||
(uint32_t)(vm->frames[vm->fp].registers[src1].f);
|
||||
(uint32_t)i;
|
||||
return true;
|
||||
}
|
||||
case OP_UINT_TO_REAL: {
|
||||
vm->frames[vm->fp].registers[dest].f =
|
||||
(float)(vm->frames[vm->fp].registers[src1].u);
|
||||
int_to_fixed(vm->frames[vm->fp].registers[src1].u);
|
||||
return true;
|
||||
}
|
||||
case OP_REG_SWAP: {
|
||||
|
@ -420,38 +559,48 @@ bool step_vm(VM *vm) {
|
|||
COMPARE_AND_JUMP(int32_t, i, ==);
|
||||
}
|
||||
case OP_JGT_REAL: {
|
||||
COMPARE_AND_JUMP(float, u, >);
|
||||
fixed_t value = vm->frames[vm->fp].registers[src1].f;
|
||||
fixed_t value2 = vm->frames[vm->fp].registers[src2].f;
|
||||
vm->pc =
|
||||
fixed_gt(value, value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc;
|
||||
return true;
|
||||
}
|
||||
case OP_JLT_REAL: {
|
||||
COMPARE_AND_JUMP(float, u, <);
|
||||
fixed_t value = vm->frames[vm->fp].registers[src1].f;
|
||||
fixed_t value2 = vm->frames[vm->fp].registers[src2].f;
|
||||
vm->pc =
|
||||
fixed_lt(value, value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc;
|
||||
return true;
|
||||
}
|
||||
case OP_JGE_REAL: {
|
||||
COMPARE_AND_JUMP(float, u, >=);
|
||||
fixed_t value = vm->frames[vm->fp].registers[src1].f;
|
||||
fixed_t value2 = vm->frames[vm->fp].registers[src2].f;
|
||||
vm->pc =
|
||||
fixed_ge(value, value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc;
|
||||
return true;
|
||||
}
|
||||
case OP_JLE_REAL: {
|
||||
COMPARE_AND_JUMP(float, u, <=);
|
||||
fixed_t value = vm->frames[vm->fp].registers[src1].f;
|
||||
fixed_t value2 = vm->frames[vm->fp].registers[src2].f;
|
||||
vm->pc =
|
||||
fixed_le(value, value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc;
|
||||
return true;
|
||||
}
|
||||
case OP_INT_TO_STRING: {
|
||||
int32_t a = (int32_t)vm->frames[vm->fp].registers[src1].i; /* get value */
|
||||
char buffer[32];
|
||||
int len = sprintf(buffer, "%d", a);
|
||||
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
|
||||
int32_t a = vm->frames[vm->fp].registers[src1].i;
|
||||
uint32_t ptr = int_to_string(vm, a);
|
||||
vm->frames[vm->fp].registers[dest].u = ptr;
|
||||
return true;
|
||||
}
|
||||
case OP_UINT_TO_STRING: {
|
||||
uint32_t a = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* get value */
|
||||
char buffer[32];
|
||||
int len = sprintf(buffer, "%d", a);
|
||||
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
|
||||
uint32_t a = vm->frames[vm->fp].registers[src1].u;
|
||||
uint32_t ptr = nat_to_string(vm, a);
|
||||
vm->frames[vm->fp].registers[dest].u = ptr;
|
||||
return true;
|
||||
}
|
||||
case OP_REAL_TO_STRING: {
|
||||
float a = (float)vm->frames[vm->fp].registers[src1].f; /* get value */
|
||||
char buffer[32];
|
||||
int len = sprintf(buffer, "%f", a);
|
||||
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
|
||||
fixed_t a = vm->frames[vm->fp].registers[src1].f;
|
||||
uint32_t ptr = real_to_string(vm, a);
|
||||
vm->frames[vm->fp].registers[dest].u = ptr;
|
||||
return true;
|
||||
}
|
||||
|
@ -484,7 +633,7 @@ bool step_vm(VM *vm) {
|
|||
return true;
|
||||
}
|
||||
case OP_DBG_PRINT_STRING: {
|
||||
uint32_t ptr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
|
||||
uint32_t ptr = vm->frames[vm->fp].registers[src1].u;
|
||||
uint32_t length = vm->memory[ptr].u;
|
||||
uint32_t str_src = ptr + 1;
|
||||
uint32_t i;
|
||||
|
@ -498,8 +647,8 @@ bool step_vm(VM *vm) {
|
|||
return true;
|
||||
}
|
||||
case OP_CMP_STRING: {
|
||||
uint32_t addr1 = (uint32_t)vm->frames[vm->fp].registers[src1].u;
|
||||
uint32_t addr2 = (uint32_t)vm->frames[vm->fp].registers[src2].u;
|
||||
uint32_t addr1 = vm->frames[vm->fp].registers[src1].u;
|
||||
uint32_t addr2 = vm->frames[vm->fp].registers[src2].u;
|
||||
uint32_t length1 = vm->memory[addr1 - 1].u;
|
||||
uint32_t length2 = vm->memory[addr2 - 1].u;
|
||||
uint32_t equal =
|
||||
|
|
3
src/vm.h
3
src/vm.h
|
@ -6,7 +6,8 @@
|
|||
VM* init_vm();
|
||||
bool step_vm(VM *vm);
|
||||
uint32_t str_alloc(VM *vm, const char *str, uint32_t length);
|
||||
uint32_t real_alloc(VM *vm, float v);
|
||||
uint32_t float_as_real_alloc(VM *vm, float v);
|
||||
uint32_t real_alloc(VM *vm, fixed_t v);
|
||||
uint32_t nat_alloc(VM *vm, uint32_t v);
|
||||
uint32_t int_alloc(VM *vm, int32_t v);
|
||||
|
||||
|
|
Loading…
Reference in New Issue