#include "vm.h" #include "debug.h" #include "vmas.h" #include /* CONSTRUCTORS */ VM::VM() { DBG_INFO(("Creating VM without code.\n")); as.allocate(); init_regs(); } VM::VM(uint8_t *code, uint32_t codesize) { DBG_INFO(("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; } void VM::status(void) { uint8_t i; DBG_INFO(("VM Status:\n")); DBG_INFO(("~~~~~~~~~~\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_INFO(("~~~~~~~~~~\n")); return; } /* INSTRUCTIONS IMPLEMENTATIONS */ void 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 0x%x 0x%x\n", dst, imm)); regs[dst] = imm; return; } void 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 0x%x 0x%x\n", dst, src)); regs[dst] = regs[src]; return; } void 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 0x%x 0x%x\n", dst, src)); regs[dst] = *((uint16_t *)&as.data[src]); return; } void 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 0x%x\n", dst, src)); *((uint16_t *)&as.data[dst]) = regs[src]; return; } void 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 0x%x 0x%x\n", dst, src)); regs[dst] += src; return; } 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; }