#include "vm.h" #include "debug.h" #include "vmas.h" #include /* DBG UTILS */ uint8_t *VM::reg_name(uint8_t regvalue) { uint8_t *buf = new uint8_t[2]; #ifdef DBG switch (regvalue) { case R0: memcpy(buf, "R0", 2); break; case R1: memcpy(buf, "R1", 2); break; case R2: memcpy(buf, "R2", 2); break; case R3: memcpy(buf, "R3", 2); break; case S0: memcpy(buf, "S0", 2); break; case S1: memcpy(buf, "S1", 2); break; case S2: memcpy(buf, "S2", 2); break; case S3: memcpy(buf, "S3", 2); break; case IP: memcpy(buf, "IP", 2); break; case BP: memcpy(buf, "BP", 2); break; case SP: memcpy(buf, "SP", 2); break; default: memcpy(buf, "??", 2); break; } #endif return buf; } void VM::status(void) { #ifdef DBG uint8_t i; DBG_SUCC(("VM Status:\n")); DBG_SUCC(("~~~~~~~~~~\n")); for (i = R0; i <= SP; i++) { switch (i) { case R0: DBG_INFO(("R0:\t0x%x\n", this->regs[i])); break; case R1: DBG_INFO(("R1:\t0x%x\n", this->regs[i])); break; case R2: DBG_INFO(("R2:\t0x%x\n", this->regs[i])); break; case R3: DBG_INFO(("R3:\t0x%x\n", this->regs[i])); break; case S0: DBG_INFO(("S0:\t0x%x\n", this->regs[i])); break; case S1: DBG_INFO(("S1:\t0x%x\n", this->regs[i])); break; case S2: DBG_INFO(("S2:\t0x%x\n", this->regs[i])); break; case S3: DBG_INFO(("S3:\t0x%x\n", this->regs[i])); break; case IP: DBG_INFO(("IP:\t0x%x\n", this->regs[i])); break; case BP: DBG_INFO(("BP:\t0x%x\n", this->regs[i])); break; case SP: DBG_INFO(("SP:\t0x%x\n", this->regs[i])); break; } } DBG_SUCC(("~~~~~~~~~~\n")); #endif return; } /* CONSTRUCTORS */ VM::VM() { DBG_SUCC(("Creating VM without code.\n")); as.allocate(); init_regs(); } VM::VM(uint8_t *code, uint32_t codesize) { DBG_SUCC(("Creating VM with code.\n")); if (as.allocate()) { as.insCode(code, codesize); } init_regs(); } void VM::init_regs(void) { uint8_t i; for (i = R0; i <= SP; i++) { this->regs[i] = 0; } return; } /* INSTRUCTIONS IMPLEMENTATIONS */ bool VM::exec_movi(void) { /* MOVI R0, 0x2400 | R0 = 0x2400 */ uint8_t dst; uint16_t imm; dst = as.code[regs[IP] + 1]; imm = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("MOVI %s, 0x%x\n", reg_name(dst), imm)); if (dst == IP) { DBG_ERROR(("Can't MOVI to IP!\n")); return false; } regs[dst] = imm; return true; } bool VM::exec_movr(void) { /* MOVR R1, R0 | R1 = R0 --------------------- R1, R0 = 0x10 <- DST / SRC are nibbles! */ uint8_t dst, src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("MOVR %s, %s\n", reg_name(dst), reg_name(src))); if (dst == IP || src == IP) { DBG_ERROR(("Can't MOVR IP!\n")); return false; } regs[dst] = regs[src]; return true; } bool VM::exec_getm(void) { /* GETM R0, 0x1000 | R0 = data[0x1000] */ uint8_t dst; uint16_t src; dst = as.code[regs[IP] + 1]; src = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("GETM %s, 0x%x\n", reg_name(dst), src)); regs[dst] = *((uint16_t *)&as.data[src]); return true; } bool VM::exec_putm(void) { /* PUTM 0x1000, R0 | data[0x1000] = R0 */ uint16_t dst; uint8_t src; dst = *((uint16_t *)&as.code[regs[IP] + 1]); src = as.code[regs[IP] + 3]; DBG_INFO(("PUTM 0x%x, %s\n", dst, reg_name(src))); *((uint16_t *)&as.data[dst]) = regs[src]; return true; } bool VM::exec_addi(void) { /* ADDI R0, 0x2 | R0 += 2 */ uint8_t dst; uint16_t src; dst = as.code[regs[IP] + 1]; src = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("ADDI %s, 0x%x\n", reg_name(dst), src)); regs[dst] += src; return true; } void VM::run(void) { uint8_t opcode; bool finished = false; while (!finished) { opcode = (uint8_t)as.code[regs[IP]]; switch (opcode) { case MOVI: exec_movi(); regs[IP] += MOVI_SIZE; break; case MOVR: exec_movr(); regs[IP] += MOVR_SIZE; break; case GETM: exec_getm(); regs[IP] += GETM_SIZE; break; case PUTM: exec_putm(); regs[IP] += PUTM_SIZE; break; case ADDI: exec_addi(); regs[IP] += ADDI_SIZE; break; case HALT: DBG_INFO(("HALT\n")); finished = true; break; default: DBG_INFO(("WAT: 0x%x\n", opcode)); finished = true; break; } } return; }