diff --git a/src/vm/libc.c b/src/vm/libc.c index 3a85ffe..f2afd6d 100644 --- a/src/vm/libc.c +++ b/src/vm/libc.c @@ -1,74 +1,16 @@ #include "libc.h" -void memcopy(u8 *dest, const u8 *src, u32 n) { - size_t i; - size_t words; - size_t bytes; - size_t unroll; - size_t remainder; - u32 *d32; - const u32 *s32; - u8 *d8; - const u8 *s8; +void memcopy(void *to, void *from, u32 length) { + u8 *src, *dest; + if (to == nil || from == nil) return; - /* Fast path for small copies (common case) */ - if (n <= 8) { - for (i = 0; i < n; i++) { - dest[i] = src[i]; - } - return; - } - - /* Check for word alignment (assuming 32-bit words) */ - if ((((size_t)dest) & 0x3) == 0 && (((size_t)src) & 0x3) == 0) { - /* Both pointers are 4-byte aligned - copy by words */ - d32 = (u32 *)dest; - s32 = (const u32 *)src; - words = n / 4; - bytes = n % 4; - - /* Loop unrolling - 4x unroll for better performance */ - unroll = words / 4; - remainder = words % 4; - - for (i = 0; i < unroll; i++) { - d32[0] = s32[0]; - d32[1] = s32[1]; - d32[2] = s32[2]; - d32[3] = s32[3]; - d32 += 4; - s32 += 4; - } - - /* Handle remaining words */ - for (i = 0; i < remainder; i++) { - *d32++ = *s32++; - } - - /* Handle trailing bytes */ - d8 = (u8 *)d32; - s8 = (const u8 *)s32; - for (i = 0; i < bytes; i++) { - d8[i] = s8[i]; - } - } else { - /* Unaligned copy - byte by byte but with loop unrolling */ - unroll = n / 4; - remainder = n % 4; - - for (i = 0; i < unroll; i++) { - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; - dest += 4; - src += 4; - } - - for (i = 0; i < remainder; i++) { - dest[i] = src[i]; - } + src = (u8 *)from; + dest = (u8 *)to; + + while (length-- > 0) { + *(dest++) = *(src++); } + return; } i32 strcopy(char *to, const char *from, u32 length) { @@ -128,129 +70,3 @@ u32 strnlength(const char *str, u32 max_len) { } return i; } - - -/* Static digit lookup table (0-9) */ -const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - -/* Writes decimal digits of 'value' backwards into 'buf_end' (inclusive), - stopping at 'buf_start'. Returns pointer to first written digit. */ -char *write_digits_backwards(u32 value, char *buf_end, char *buf_start) { - char *p = buf_end; - if (value == 0) { - *--p = '0'; - } else { - u32 num = value; - while (num && p > buf_start) { - *--p = digits[num % 10]; - num /= 10; - } - } - return p; -} - -void nat_to_string(u32 value, char *buffer) { - char temp[16]; - char *start; - char *end = temp + sizeof(temp) - 1; - *end = '\0'; - start = write_digits_backwards(value, end, temp); - strcopy(buffer, start, end - start + 1); /* +1 for null terminator */ -} - -void int_to_string(i32 value, char *buffer) { - char temp[17]; /* Extra space for '-' */ - i32 negative = 0; - u32 abs_value; - char *end = temp + sizeof(temp) - 1; - *end = '\0'; - - if (value == (-2147483647 - 1)) { /* INT32_MIN */ - strcopy(buffer, "-2147483648", 12); - return; - } - - if (value == 0) { - *--end = '0'; - } else { - if (value < 0) { - negative = 1; - abs_value = (u32)(-value); - } else { - abs_value = (u32)value; - } - - end = write_digits_backwards(abs_value, end, temp); - - if (negative) { - *--end = '-'; - } - } - - strcopy(buffer, end, temp + sizeof(temp) - end); -} - -void fixed_to_string(i32 value, char *buffer) { - char temp[32]; - i32 negative; - u32 int_part; - u32 frac_part, frac_digits, original_frac_digits; - char *end = temp + sizeof(temp) - 1; - char *frac_start; - *end = '\0'; - - negative = 0; - if (value < 0) { - negative = 1; - value = -value; - } - - int_part = AS_NAT(value >> 16); - frac_part = AS_NAT(value & 0xFFFF); - - /* Convert fractional part to 5 decimal digits */ - original_frac_digits = (frac_part * 100000U) / 65536U; - frac_digits = original_frac_digits; - - if (frac_digits > 0) { - /* Write fractional digits backwards */ - frac_start = write_digits_backwards(frac_digits, end, temp); - - /* Remove trailing zeros by moving the start pointer */ - while (*(end - 1) == '0' && end > frac_start) { - end--; - } - - /* If all fractional digits were zeros after removing trailing zeros, - we need to add back one zero to represent the .0 */ - if (end == frac_start) { - *--end = '0'; - } - - /* Add decimal point */ - *--end = '.'; - } else if (frac_part > 0) { - /* Handle case where original_frac_digits was rounded to 0 but frac_part was not 0 */ - /* This means we have a very small fractional part that should be represented as .0 */ - *--end = '0'; - *--end = '.'; - } else if (frac_part == 0) { - /* No fractional part - just add .0 if we have an integer part */ - if (int_part != 0) { - *--end = '0'; - *--end = '.'; - } - } - - if (int_part == 0 && frac_digits == 0 && frac_part == 0) { - *--end = '0'; - } else { - end = write_digits_backwards(int_part, end, temp); - } - - if (negative) { - *--end = '-'; - } - - strcopy(buffer, end, temp + sizeof(temp) - end); -} diff --git a/src/vm/libc.h b/src/vm/libc.h index 4479f9a..1ba9460 100644 --- a/src/vm/libc.h +++ b/src/vm/libc.h @@ -8,9 +8,6 @@ bool strleq(const char *s1, const char *s2, u32 length); i32 strcopy(char* to, const char *from, u32 length); u32 strlength(const char *str); u32 strnlength(const char *str, u32 max_len); -void memcopy(u8 *dest, const u8 *src, u32 n); -void nat_to_string(u32 value, char *buffer); -void int_to_string(i32 value, char *buffer); -void fixed_to_string(i32 value, char *buffer); +void memcopy(void *to, void *from, u32 length); #endif diff --git a/src/vm/vm.c b/src/vm/vm.c index 9ae7ac0..7d6c3bd 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -1,9 +1,13 @@ #include "vm.h" +#include "common.h" #include "device.h" #include "fixed.h" #include "libc.h" #include "opcodes.h" +#define MAX_LEN_INT32 11 +const char radix_set[11] = "0123456789"; + #define COMPARE_AND_JUMP(type, op) \ do { \ i32 cond; \ @@ -198,37 +202,6 @@ bool step_vm(VM *vm) { set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } - case OP_MEMSET_32: { - u32 i, start, end; - u8 value_reg = read_u8(vm, code, vm->pc++); - u8 count_reg = read_u8(vm, code, vm->pc++); - u8 dest_reg = read_u8(vm, code, vm->pc++); - - u32 dest = frame->locals[dest_reg]; - u32 value = frame->locals[value_reg]; - u32 count = frame->locals[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->locals[0] = dest; - vm->flag = 1; - return true; - } case OP_LOAD_ABS_32: { u32 v, ptr; u8 dest; @@ -465,6 +438,37 @@ bool step_vm(VM *vm) { write_u32(vm, memory, (ptr + offset), v); return true; } + case OP_MEMSET_32: { + u32 i, start, end; + u8 value_reg = read_u8(vm, code, vm->pc++); + u8 count_reg = read_u8(vm, code, vm->pc++); + u8 dest_reg = read_u8(vm, code, vm->pc++); + + u32 dest = frame->locals[dest_reg]; + u32 value = frame->locals[value_reg]; + u32 count = frame->locals[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->locals[0] = dest; + vm->flag = 1; + return true; + } case OP_MEMSET_16: { u32 i, start, end; u8 value_reg = read_u8(vm, code, vm->pc++); @@ -928,45 +932,103 @@ bool step_vm(VM *vm) { COMPARE_AND_JUMP(i32, <=); } case OP_INT_TO_STRING: { - u32 ptr; + char buffer[MAX_LEN_INT32]; + i32 v; + i32 n; + u32 i = MAX_LEN_INT32; u8 dest, src1; - char buffer[32]; + bool neg; src1 = read_u8(vm, code, vm->pc); vm->pc++; dest = read_u8(vm, code, vm->pc); vm->pc++; - int_to_string(AS_INT(frame->locals[src1]), buffer); - ptr = str_alloc(vm, frame, buffer, strlength(buffer)); - frame->locals[dest] = ptr; + v = AS_INT(frame->locals[src1]); + n = v; + neg = n < 0; + + if (neg) + n = -n; + + 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'; + + frame->locals[dest] = str_alloc(vm, frame, buffer + i, MAX_LEN_INT32 - i); set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } case OP_NAT_TO_STRING: { - u32 ptr; + char buffer[MAX_LEN_INT32]; + u32 v; + u32 n; + u32 i = MAX_LEN_INT32; u8 dest, src1; - char buffer[32]; src1 = read_u8(vm, code, vm->pc); vm->pc++; dest = read_u8(vm, code, vm->pc); vm->pc++; - nat_to_string(frame->locals[src1], buffer); - ptr = str_alloc(vm, frame, buffer, strlength(buffer)); - frame->locals[dest] = ptr; + v = AS_NAT(frame->locals[src1]); + n = v; + + 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'; + /* Copy from buffer[i] to buffer + MAX_LEN_INT32 */ + frame->locals[dest] = str_alloc(vm, frame, buffer + i, MAX_LEN_INT32 - i); set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } case OP_REAL_TO_STRING: { - u32 ptr; - u8 dest, src1; - char buffer[32]; + i32 q; + u8 dest, src1, int_part, frac_part; + u32 i = 0, j = 0; + char buffer[12]; src1 = read_u8(vm, code, vm->pc); vm->pc++; dest = read_u8(vm, code, vm->pc); vm->pc++; - fixed_to_string(AS_INT(frame->locals[src1]), buffer); - ptr = str_alloc(vm, frame, buffer, - strlength(buffer)); /* copy buffer to dest */ - frame->locals[dest] = ptr; + + q = (i32)frame->locals[src1]; + if (q < 0) { + buffer[i++] = '-'; + q = -q; + } + + int_part = q >> 16; + frac_part = q & 0xFFFF; + + if (int_part == 0) { + buffer[i++] = radix_set[0]; + } else { + char tmp[16]; + i32 tmp_i = 0; + while (int_part > 0) { + tmp[tmp_i++] = radix_set[int_part % 10]; + int_part /= 10; + } + while (tmp_i > 0) { + buffer[i++] = tmp[--tmp_i]; + } + } + + buffer[i++] = '.'; + for (j = 0; j < 6; j++) { + frac_part *= 10; + buffer[i++] = radix_set[frac_part >> 16]; + frac_part &= 0xFFFF; + } + + frame->locals[dest] = str_alloc(vm, frame, buffer + i, 12 - i); set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; }