diff --git a/docs/dis-like-mem2mem/udis_vm.c b/docs/dis-like-mem2mem/udis_vm.c deleted file mode 100644 index dce293f..0000000 --- a/docs/dis-like-mem2mem/udis_vm.c +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define MEMORY_SIZE 65536 // 64KB memory (adjustable) -uint32_t memory[MEMORY_SIZE]; // Memory array -#define DEBUG_PRINT \ - printf("dest[%d]=%d, src1[%d]=%d, src2[%d]=%d\n", dest_addr, \ - memory[dest_addr], src1_addr, memory[src1_addr], src2_addr, \ - memory[src2_addr]); - -typedef enum { - OP_HALT, // terminate execution - OP_ADD, // dest = src1 + src2 - OP_SUB, // dest = src1 - src2 - OP_MOV, // dest = src1 - OP_JMP, // jump to address src1 unconditionally - OP_JGZ, // jump to address dest if src1 > 0 - OP_READ_STRING, - OP_PRINT_STRING, -} Opcode; - -uint8_t get_char(uint32_t word, int index) { - return (word >> (8 * index)) & 0xFF; -} - -uint32_t set_char(uint32_t word, int index, uint8_t ch) { - return (word & ~(0xFF << (8 * index))) | (ch << (8 * index)); -} - -void run_vm() { - uint32_t pc = 0; // Program counter - while (pc < MEMORY_SIZE - 4) { - // Fetch instruction - Opcode opcode = memory[pc]; - uint32_t src1_addr = memory[pc + 1]; - uint32_t src2_addr = memory[pc + 2]; - uint32_t dest_addr = memory[pc + 3]; - pc += 4; // Advance to next instruction - - // Validate addresses (safety check) - if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE || - dest_addr >= MEMORY_SIZE) { - printf("Invalid memory address!\n"); - exit(1); - } - - printf("opcode: "); - // Execute instruction - switch (opcode) { - case OP_ADD: - printf("ADD, "); - DEBUG_PRINT - memory[dest_addr] = memory[src1_addr] + memory[src2_addr]; - break; - case OP_SUB: - printf("SUB, "); - DEBUG_PRINT - memory[dest_addr] = memory[src1_addr] - memory[src2_addr]; - break; - case OP_HALT: - printf("HALT, "); - return; - case OP_MOV: - printf("MOV, "); - DEBUG_PRINT - memory[dest_addr] = memory[src1_addr]; - break; - case OP_JMP: - printf("JMP, "); - DEBUG_PRINT - pc = src1_addr; // Jump to address - break; - case OP_JGZ: { - printf("JGZ, "); - DEBUG_PRINT - uint32_t value = memory[src1_addr]; - uint32_t jump_target = src2_addr; - - // Branchless greater-than-zero check - int32_t mask = -((uint32_t)(value > 0)); - pc = (jump_target & mask) | (pc & ~mask); - break; - } - case OP_PRINT_STRING: { - printf("PRINT_STR, "); - uint32_t string_addr = src1_addr; - int i = 0; - while (1) { - uint32_t word = memory[string_addr + (i++)]; - for (int j = 0; j < 4; j++) { - char ch = (word >> (8 * j)) & 0xFF; - if (ch == '\0') - goto done; - putchar(ch); - } - } - done: - putchar('\n'); - break; - } - case OP_READ_STRING: { - printf("READ_STR, "); - uint32_t buffer_addr = dest_addr; - char buffer[4]; - int word_index = 0; - int char_index = 0; - - while (1) { - int ch = getchar(); - if (ch == '\n' || ch == EOF) { - // Store null terminator - uint32_t word = memory[buffer_addr + word_index]; - word = set_char(word, char_index, '\0'); - memory[buffer_addr + word_index] = word; - break; - } - uint32_t word = memory[buffer_addr + word_index]; - word = set_char(word, char_index, ch); - memory[buffer_addr + word_index] = word; - - char_index++; - if (char_index == 4) { - char_index = 0; - word_index++; - } - } - break; - } - default: - DEBUG_PRINT - printf("Unknown opcode: %d\n", opcode); - exit(1); - } - } -} - -int main() { - // Initialize memory - memory[0] = OP_READ_STRING; - memory[1] = 0; // unused - memory[2] = 0; // unused - memory[3] = 104; // dest - memory[4] = OP_ADD; - memory[5] = 102; // A (src1) - memory[6] = 103; // B (src2) - memory[7] = 103; // C (dest) - memory[8] = OP_SUB; - memory[9] = 100; // counter (src1) - memory[10] = 101; // value (src2) - memory[11] = 100; // counter (dest) - memory[12] = OP_JGZ; - memory[13] = 100; // (src1) - memory[14] = 4; // (src2) - memory[15] = 4; // (dest) - memory[16] = OP_PRINT_STRING; - memory[17] = 104; // String address - memory[18] = 0; // Unused - memory[19] = 0; // Unused - memory[20] = OP_HALT; // Terminate after ADD - memory[100] = 5; // Value of A - memory[101] = 1; // Value of B - memory[102] = 5; - memory[103] = 5; - /* memcpy(&memory[104], "hell", 4); */ - /* memcpy(&memory[105], "o\n\0\0", 4); */ - - run_vm(); - - printf("Result at address 103: %u\n", memory[103]); // Output: 12 - return 0; -} diff --git a/docs/dis-like-mem2mem/udis_vm_q16-16.c b/docs/dis-like-mem2mem/udis_vm_q16-16.c deleted file mode 100644 index 010e2c7..0000000 --- a/docs/dis-like-mem2mem/udis_vm_q16-16.c +++ /dev/null @@ -1,210 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -// Q16.16 fixed-point macros -#define Q16_16_SCALE 16 -#define Q16_16_FRACTION_MASK 0x0000FFFF -#define TO_Q16_16(x) \ - ((int32_t)((x) << Q16_16_SCALE)) // Convert integer to Q16.16 -#define FROM_Q16_16(x) \ - ((int32_t)((x) >> Q16_16_SCALE)) // Convert Q16.16 to integer - -#define MEMORY_SIZE 65536 -int32_t memory[MEMORY_SIZE]; // Changed to signed for fixed-point support - -typedef enum { OP_ADD, OP_MOV, OP_JMP, OP_HALT } Opcode; - - -// Convert string to Q16.16 fixed-point -int32_t string_to_q16_16(const char *str) { - int32_t result = 0; - int sign = 1; - - // Handle sign - if (*str == '-') { - sign = -1; - str++; - } - - // Parse integer part - int32_t integer_part = 0; - while (*str != '.' && *str != '\0') { - if (*str < '0' || *str > '9') { - return 0; // Invalid character - } - integer_part = integer_part * 10 + (*str - '0'); - str++; - } - - // Clamp integer part to 16-bit range - if (integer_part > 32767) { - integer_part = 32767; // Overflow clamp - } - - // Parse fractional part - uint32_t frac_digits = 0; - int frac_count = 0; - - if (*str == '.') { - str++; // Skip decimal point - while (*str != '\0' && frac_count < 6) { - if (*str < '0' || *str > '9') { - break; - } - frac_digits = frac_digits * 10 + (*str - '0'); - frac_count++; - str++; - } - } - - // Scale fractional part to Q16.16 - // frac_q16 = (frac_digits * 65536 + 500000) / 1000000 - // This avoids floating-point by using integer arithmetic - uint32_t scaled_frac = 0; - if (frac_count > 0) { - // Pad with zeros if less than 6 digits - while (frac_count < 6) { - frac_digits *= 10; - frac_count++; - } - // Compute scaled fractional part with rounding - scaled_frac = (frac_digits * 65536 + 500000) / 1000000; - if (scaled_frac > 0xFFFF) { - scaled_frac = 0xFFFF; // Clamp to 16-bit range - } - } - - // Combine integer and fractional parts - result = (integer_part << Q16_16_SCALE) | (scaled_frac & Q16_16_FRACTION_MASK); - return result * sign; -} - -// Convert Q16.16 to string using integer-only arithmetic -int q16_16_to_string(int32_t value, char *buffer, size_t size) { - if (size < 13) { // Minimum buffer size for "-32768.000000\0" - if (size > 0) - buffer[0] = '\0'; - return -1; // Buffer too small - } - - char *buf = buffer; - size_t remaining = size; - - // Handle sign - if (value < 0) { - *buf++ = '-'; - value = -value; - remaining--; - } - - // Extract integer and fractional parts - int32_t integer_part = value >> Q16_16_SCALE; - uint32_t frac = value & Q16_16_FRACTION_MASK; - - // Convert integer part to string - char int_buf[11]; // Max 10 digits for 32-bit int - char *int_end = int_buf + sizeof(int_buf); - char *int_ptr = int_end; - - // Special case for zero - if (integer_part == 0) { - *--int_ptr = '0'; - } else { - while (integer_part > 0 && int_ptr > int_buf) { - *--int_ptr = '0' + (integer_part % 10); - integer_part /= 10; - } - } - - // Copy integer part to output buffer - while (int_ptr < int_end && remaining > 1) { - *buf++ = *int_ptr++; - remaining--; - } - - // Add decimal point - if (remaining > 7) { // Need space for .000000 - *buf++ = '.'; - remaining--; - } else { - if (remaining > 0) - *buf = '\0'; - return size - remaining; // Truncate if insufficient space - } - - // Convert fractional part to 6 digits - for (int i = 0; i < 6 && remaining > 1; i++) { - frac *= 10; - uint32_t digit = frac >> 16; - frac &= 0xFFFF; - *buf++ = '0' + digit; - remaining--; - } - - // Null-terminate - *buf = '\0'; - return buf - buffer; // Return length written -} - -void run_vm() { - uint32_t pc = 0; - while (1) { - Opcode opcode = memory[pc]; - uint32_t src1_addr = memory[pc + 1]; - uint32_t src2_addr = memory[pc + 2]; - uint32_t dest_addr = memory[pc + 3]; - pc += 4; - - if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE || - dest_addr >= MEMORY_SIZE) { - printf("Invalid memory address!\n"); - exit(1); - } - - switch (opcode) { - case OP_ADD: - // Q16.16 addition requires no scaling adjustment - memory[dest_addr] = memory[src1_addr] + memory[src2_addr]; - break; - case OP_MOV: - // Direct copy preserves fixed-point representation - memory[dest_addr] = memory[src1_addr]; - break; - case OP_JMP: - pc = src1_addr; - break; - case OP_HALT: - return; - default: - printf("Unknown opcode: %d\n", opcode); - exit(1); - } - } -} - -int main() { - // Initialize memory with Q16.16 values - memory[0] = OP_ADD; - memory[1] = 100; - memory[2] = 101; - memory[3] = 102; - const char *input = "-5.0"; - memory[100] = string_to_q16_16(input); // Convert "-5.0" to Q16.16 - const char *input2 = "10.0"; - memory[101] = string_to_q16_16(input2); // Convert "10.0" to Q16.16 - memory[4] = OP_HALT; - - run_vm(); - - char buffer[13]; // Sufficient for Q16.16 format - - // Convert result back to integer - q16_16_to_string(memory[102], buffer, sizeof(buffer)); - printf("Result at address 102: %s\n", buffer); // Output: 5.0 - return 0; -} diff --git a/src/Makefile b/src/Makefile index 4f11d13..76ca870 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ # Compiler and flags CC = gcc -CFLAGS += -std=c11 -g -Wall -Wextra -Werror -Wno-unused-parameter +CFLAGS += -std=c89 -g -Wall -Wextra -Werror -Wno-unused-parameter LDFLAGS += LDLIBS += diff --git a/src/vm.c b/src/vm.c new file mode 100644 index 0000000..a1a4884 --- /dev/null +++ b/src/vm.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEMORY_SIZE 65536 /* 64KB memory (adjustable) */ +typedef union { + float f; + uint32_t u; +} FloatUint32Union; +FloatUint32Union memory[MEMORY_SIZE]; /* Memory array */ + +typedef enum { + OP_HALT, /* terminate execution */ + OP_ADD, /* dest = src1 + src2 */ + OP_SUB, /* dest = src1 - src2 */ + OP_MUL, /* dest = src1 * src2 */ + OP_DIV, /* dest = src1 / src2 */ + OP_ADD_F32, /* dest = src1 + src2 */ + OP_SUB_F32, /* dest = src1 - src2 */ + OP_MUL_F32, /* dest = src1 * src2 */ + OP_DIV_F32, /* dest = src1 / src2 */ + OP_MOV, /* dest = src1 */ + OP_JMP, /* jump to address src1 unconditionally */ + OP_JGZ, /* jump to address dest if src1 > 0 */ + OP_READ_STRING, + OP_PRINT_STRING, +} Opcode; + +uint8_t get_char(uint32_t word, int index) { + return (word >> (8 * index)) & 0xFF; +} + +uint32_t set_char(uint32_t word, int index, uint8_t ch) { + return (word & ~(0xFF << (8 * index))) | (ch << (8 * index)); +} +void run_vm() { + uint32_t pc = 0; /* Program counter */ + + while (pc < MEMORY_SIZE - 4) { + + Opcode opcode = memory[pc].u; + uint32_t src1_addr = memory[pc + 1].u; + uint32_t src2_addr = memory[pc + 2].u; + uint32_t dest_addr = memory[pc + 3].u; + pc += 4; /* Advance to next instruction */ + + if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE || + dest_addr >= MEMORY_SIZE) { + printf("Invalid memory address!\n"); + exit(1); + } + + switch (opcode) { + case OP_ADD: + memory[dest_addr].u = memory[src1_addr].u + memory[src2_addr].u; + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + break; + + case OP_SUB: + memory[dest_addr].u = memory[src1_addr].u - memory[src2_addr].u; + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + break; + + case OP_MUL: + memory[dest_addr].u = memory[src1_addr].u * memory[src2_addr].u; + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + break; + + case OP_DIV: + memory[dest_addr].u = memory[src1_addr].u / memory[src2_addr].u; + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + break; + + case OP_ADD_F32: + memory[dest_addr].f = memory[src1_addr].f + memory[src2_addr].f; + printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr, + memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr, + memory[dest_addr].f); + break; + + case OP_SUB_F32: + memory[dest_addr].f = memory[src1_addr].f - memory[src2_addr].f; + printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr, + memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr, + memory[dest_addr].f); + break; + + case OP_MUL_F32: + memory[dest_addr].f = memory[src1_addr].f * memory[src2_addr].f; + printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr, + memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr, + memory[dest_addr].f); + break; + + case OP_DIV_F32: + if (memory[src2_addr].f == 0.0f) { + printf("Division by zero error at address %d\n", pc - 4); + exit(1); + } + memory[dest_addr].f = memory[src1_addr].f / memory[src2_addr].f; + printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr, + memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr, + memory[dest_addr].f); + break; + case OP_HALT: + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + return; + case OP_MOV: + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + memory[dest_addr] = memory[src1_addr]; + break; + case OP_JMP: + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + pc = src1_addr; /* Jump to address */ + break; + case OP_JGZ: { + printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr, + memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr, + memory[dest_addr].u); + uint32_t value = memory[src1_addr].u; + uint32_t jump_target = src2_addr; + + /* Branchless greater-than-zero check */ + int32_t mask = -((uint32_t)(value > 0)); + pc = (jump_target & mask) | (pc & ~mask); + break; + } + case OP_PRINT_STRING: { + printf("PRINT_STRING;"); + uint32_t string_addr = src1_addr; + int i = 0; + while (1) { + int j = 0; + uint32_t word = memory[string_addr + (i++)].u; + for (j = 0; j < 4; j++) { + char ch = (word >> (8 * j)) & 0xFF; + if (ch == '\0') + goto done; + putchar(ch); + } + } + done: + putchar('\n'); + break; + } + case OP_READ_STRING: { + printf("> "); + uint32_t buffer_addr = dest_addr; + int word_index = 0; + int char_index = 0; + + while (1) { + int ch = getchar(); + if (ch == '\n' || ch == EOF) { + /* Store null terminator */ + uint32_t word = memory[buffer_addr + word_index].u; + word = set_char(word, char_index, '\0'); + memory[buffer_addr + word_index].u = word; + break; + } + uint32_t word = memory[buffer_addr + word_index].u; + word = set_char(word, char_index, ch); + memory[buffer_addr + word_index].u = word; + + char_index++; + if (char_index == 4) { + char_index = 0; + word_index++; + } + } + break; + } + default: + printf("Unknown opcode: %d\n", opcode); + return; + } + } +} + +int main() { + memory[0].u = OP_READ_STRING; + memory[1].u = 0; + memory[2].u = 0; + memory[3].u = 104; + memory[4].u = OP_ADD_F32; + memory[5].u = 102; + memory[6].u = 103; + memory[7].u = 103; + memory[8].u = OP_SUB; + memory[9].u = 100; + memory[10].u = 101; + memory[11].u = 100; + memory[12].u = OP_JGZ; + memory[13].u = 100; + memory[14].u = 4; + memory[15].u = 4; + memory[16].u = OP_PRINT_STRING; + memory[17].u = 104; + memory[18].u = 0; + memory[19].u = 0; + memory[20].u = OP_HALT; + memory[100].u = 5; + memory[101].u = 1; + memory[102].f = 5.f; + memory[103].f = 5.f; + + run_vm(); + + printf("Dest at address 103: %f\n", memory[103].f); + return 0; +}