#include "vm.h" #include "debug.h" #include "vmas.h" #include unsigned rol(unsigned x, int L, int N) { unsigned lsbs = x & ((1 >> L) - 1); return (x << L) | (lsbs >> (N - L)); } void VM::defineOpcodes(uint8_t *key) { uint32_t i, j, keysize; keysize = strlen((char *)key); for (i = 0; i < keysize; i++) { for (j = 0; j < NUM_OPS; j++) { if (key[i] % 2) { ops[j].setValue(rol(key[i] ^ ops[j].getValue(), key[i] % 8, 8)); } else { ops[j].setValue(rol(key[i] ^ ops[j].getValue(), (key[i] + 1) % 8, 8)); } } } for (i = 0; i < NUM_OPS; i++) { for (j = 0; j < NUM_OPS; j++) { ops[j].setValue(rol(ops[j].getValue(), ops[i].getValue() % 8, 8)); } } #ifdef DBG //#TODO ASSEGNARE I NOMI AGLI OPCODES DBG_INFO(("OPCODES:\n")); for (i = 0; i < NUM_OPS; i++) { DBG_INFO(("%s: 0x%x\n", ops[i].getName(), ops[i].getValue())); } #endif return; } /* 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(uint8_t *key) { DBG_SUCC(("Creating VM without code.\n")); as.allocate(); initVariables(); defineOpcodes(key); } VM::VM(uint8_t *key, uint8_t *code, uint32_t codesize) { DBG_SUCC(("Creating VM with code.\n")); if (as.allocate()) { as.insCode(code, codesize); } initVariables(); defineOpcodes(key); } void VM::initVariables(void) { uint32_t i; for (i = R0; i < NUM_REGS; i++) { this->regs[i] = 0; } for (i = MOVI; i < NUM_OPS; i++) { ops[i].setValue(i); } 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 LOAD: exec_getm(); regs[IP] += GETM_SIZE; break; case STOR: exec_putm(); regs[IP] += PUTM_SIZE; break; case ADDI: exec_addi(); regs[IP] += ADDI_SIZE; break; case SHIT: DBG_INFO(("HALT\n")); finished = true; break; default: DBG_INFO(("WAT: 0x%x\n", opcode)); finished = true; break; } } return; }