#include "vm.h" #include #include /** * String copy in data memory. */ void mem_strcpy(Data *memory, const char *str, uint32_t length, uint32_t dest_addr) { memory[dest_addr].u = length; uint32_t buffer_addr = dest_addr + 1; uint32_t i = 0; while (i < length) { char ch = str[i]; if (ch == '\0') { break; } memory[buffer_addr + (i / 4)].c[i % 4] = ch; i++; } } void run_vm(Data *memory, uint32_t memory_size) { 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_HALT: return; case OP_ADD: memory[dest_addr].u = memory[src1_addr].u + memory[src2_addr].u; break; case OP_SUB: memory[dest_addr].u = memory[src1_addr].u - memory[src2_addr].u; break; case OP_MUL: memory[dest_addr].u = memory[src1_addr].u * memory[src2_addr].u; break; case OP_DIV: memory[dest_addr].u = memory[src1_addr].u / memory[src2_addr].u; break; case OP_ADD_REAL: memory[dest_addr].f = memory[src1_addr].f + memory[src2_addr].f; break; case OP_SUB_REAL: memory[dest_addr].f = memory[src1_addr].f - memory[src2_addr].f; break; case OP_MUL_REAL: memory[dest_addr].f = memory[src1_addr].f * memory[src2_addr].f; break; case OP_DIV_REAL: 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; break; case OP_REAL_TO_INT: { memory[dest_addr].u = (uint32_t)memory[src1_addr].f; break; } case OP_INT_TO_REAL: { memory[dest_addr].f = (float)memory[src1_addr].u; break; } case OP_MOV: memory[dest_addr] = memory[src1_addr]; break; case OP_JMP: pc = src1_addr; /* Jump to address */ break; case OP_JGT_INT: { uint32_t value = memory[src1_addr].u; uint32_t value2 = memory[src2_addr].u; uint32_t jump_target = dest_addr; pc = (value > value2) ? jump_target : pc; break; } case OP_JLT_INT: { uint32_t value = memory[src1_addr].u; uint32_t value2 = memory[src2_addr].u; uint32_t jump_target = dest_addr; pc = (value < value2) ? jump_target : pc; break; } case OP_JEQ_REAL: { float value = memory[src1_addr].f; float value2 = memory[src2_addr].f; uint32_t jump_target = dest_addr; pc = (value == value2) ? jump_target : pc; break; } case OP_JGT_REAL: { float value = memory[src1_addr].f; float value2 = memory[src2_addr].f; uint32_t jump_target = dest_addr; pc = (value > value2) ? jump_target : pc; break; } case OP_JLT_REAL: { float value = memory[src1_addr].f; float value2 = memory[src2_addr].f; uint32_t jump_target = dest_addr; pc = (value < value2) ? jump_target : pc; break; } case OP_JEQ_INT: { uint32_t value = memory[src1_addr].u; uint32_t value2 = memory[src2_addr].u; uint32_t jump_target = dest_addr; pc = (value == value2) ? jump_target : pc; break; } case OP_JGE_INT: { uint32_t value = memory[src1_addr].u; uint32_t value2 = memory[src2_addr].u; uint32_t jump_target = dest_addr; pc = (value >= value2) ? jump_target : pc; break; } case OP_JLE_INT: { uint32_t value = memory[src1_addr].u; uint32_t value2 = memory[src2_addr].u; uint32_t jump_target = dest_addr; pc = (value <= value2) ? jump_target : pc; break; } case OP_JGE_REAL: { float value = memory[src1_addr].f; float value2 = memory[src2_addr].f; uint32_t jump_target = dest_addr; pc = (value >= value2) ? jump_target : pc; break; } case OP_JLE_REAL: { float value = memory[src1_addr].f; float value2 = memory[src2_addr].f; uint32_t jump_target = dest_addr; pc = (value <= value2) ? jump_target : pc; break; } case OP_INT_TO_STRING: { int32_t a = (int32_t)memory[src1_addr].u; char buffer[32]; sprintf(buffer, "%d", a); mem_strcpy(memory, buffer, strlen(buffer), dest_addr); break; } case OP_REAL_TO_STRING: { float a = memory[src1_addr].f; char buffer[32]; sprintf(buffer, "%f", a); mem_strcpy(memory, buffer, strlen(buffer), dest_addr); break; } case OP_READ_STRING: { uint32_t buffer_addr = dest_addr + 1; uint32_t length = 0; while (1) { int ch = getchar(); if (ch == '\n' || ch == EOF) { memory[buffer_addr + (length / 4)].c[length % 4] = '\0'; break; } memory[buffer_addr + (length / 4)].c[length % 4] = ch; length++; } memory[dest_addr].u = length; break; } case OP_PRINT_STRING: { uint32_t string_addr = src1_addr; uint32_t length = memory[src1_addr - 1].u; uint32_t i; for (i = 0; i < length; i++) { uint8_t ch = memory[string_addr + (i / 4)].c[i % 4]; if (ch == '\0') break; putchar(ch); } putchar('\n'); break; } case OP_CMP_STRING: { uint32_t addr1 = src1_addr; uint32_t addr2 = src2_addr; uint32_t length1 = memory[src1_addr - 1].u; uint32_t length2 = memory[src2_addr - 1].u; uint32_t equal = 1; if (length1 != length2) { equal = 0; } else { uint32_t i = 0; while (i < length1) { uint32_t char1 = memory[addr1 + i].u; uint32_t char2 = memory[addr2 + i].u; if (char1 != char2) { equal = 0; break; } if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') break; } } memory[dest_addr].u = equal; break; } default: printf("Unknown opcode: %d\n", opcode); return; } } }