#include "vm.h" #include "debug.h" #include "opcodes.h" #include "vmas.h" #include #include void VM::encryptOpcodes(uint8_t *key) { uint8_t arr[256]; uint32_t i, j, tmp, keysize; keysize = strlen((char *)key); /* RC4 KSA! :-D */ for (i = 0; i < 256; i++) { arr[i] = i; } j = 0; for (i = 0; i < 256; i++) { j = (j + arr[i] + key[i % keysize]) % 256; tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } for (i = 0; i < NUM_OPS; i++) { OPS[i] = arr[i]; } #ifdef DBG //#TODO ASSEGNARE I NOMI AGLI OPCODES DBG_INFO(("~~~~~~~~~~\nOPCODES:\n")); for (i = 0; i < NUM_OPS; i++) { DBG_INFO(("0x%x: 0x%x\n", i, OPS[i])); } DBG_INFO(("~~~~~~~~~~\n")); #endif return; } /* DBG UTILS */ uint8_t *VM::getRegName(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 RP: memcpy(buf, "RP", 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++) { DBG_INFO(("%s:\t0x%04x\n", getRegName(i), regs[i])); } DBG_INFO(("Flags: ZF = %d, CF = %d\n", flags.ZF, flags.CF)); DBG_SUCC(("~~~~~~~~~~\n")); #endif return; } /* CONSTRUCTORS */ VM::VM(uint8_t *key) { DBG_SUCC(("Creating VM without code.\n")); as.allocate(); initVariables(); encryptOpcodes(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(); encryptOpcodes(key); } void VM::initVariables(void) { uint32_t i; for (i = R0; i < NUM_REGS; i++) { this->regs[i] = 0; } for (i = 0; i < NUM_OPS; i++) { OPS[i] = i; } return; } /* INSTRUCTIONS IMPLEMENTATIONS */ bool VM::execMOVI(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", getRegName(dst), imm)); if (dst == IP) { DBG_ERROR(("Can't MOVI to IP!\n")); return false; } regs[dst] = imm; return true; } bool VM::execMOVR(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", getRegName(dst), getRegName(src))); if (dst == IP || src == IP) { DBG_ERROR(("Can't MOVR IP!\n")); return false; } regs[dst] = regs[src]; return true; } bool VM::execLODI(void) { /* LODI 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(("LODI %s, 0x%x\n", getRegName(dst), src)); regs[dst] = *((uint16_t *)&as.data[src]); return true; } bool VM::execLODR(void) { /* LODR R1, R0 -> R1 = data[R0] */ uint16_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("LODR %s, %s\n", getRegName(dst), getRegName(src))); regs[dst] = *((uint16_t *)&as.data[regs[src]]); return true; } bool VM::execSTRI(void) { /* STRI 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(("STRI 0x%x, %s\n", dst, getRegName(src))); *((uint16_t *)&as.data[dst]) = regs[src]; return true; } bool VM::execSTRR(void) { /* STRR R1, R0 -> data[R1] = R0 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("STRR %s, %s\n", getRegName(dst), getRegName(src))); *((uint16_t *)&as.data[regs[dst]]) = regs[src]; return true; } bool VM::execADDI(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", getRegName(dst), src)); regs[dst] += src; return true; } bool VM::execADDR(void) { /* ADDR R0, R1 -> R0 += R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("ADDR %s, 0x%x\n", getRegName(dst), src)); regs[dst] += regs[src]; return true; } bool VM::execSUBI(void) { /* SUBI 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(("SUBI %s, 0x%x\n", getRegName(dst), src)); regs[dst] -= src; return true; } bool VM::execSUBR(void) { /* SUBR R0, R1 -> R0 -= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("SUBR %s, 0x%x\n", getRegName(dst), src)); regs[dst] -= regs[src]; return true; } bool VM::execANDB(void) { /* ANDB R0, 0x2 -> R0 &= 0x02 or R0 &= [BYTE] 0x02 (low byte) */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1]; src = as.code[regs[IP] + 2]; DBG_INFO(("ANDB %s, 0x%x\n", getRegName(dst), src)); regs[dst] &= src; return true; } bool VM::execANDW(void) { /* ANDW R0, 0x2 -> R0 &= 0x0002 or R0, ^= [WORD] 0x2 */ uint8_t dst; uint16_t src; dst = as.code[regs[IP] + 1]; src = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src)); regs[dst] &= src; return true; } bool VM::execANDR(void) { /* ANDR R0, R1 -> R0 ^= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("ANDR %s, 0x%x\n", getRegName(dst), src)); regs[dst] &= regs[src]; return true; } bool VM::execYORB(void) { /* YORB R0, 0x2 -> R0 |= 0x02 or R0 |= [BYTE] 0x02 (low byte) */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1]; src = as.code[regs[IP] + 2]; DBG_INFO(("YORB %s, 0x%x\n", getRegName(dst), src)); regs[dst] |= src; return true; } bool VM::execYORW(void) { /* YORW R0, 0x2 -> R0 |= 0x0002 or R0, |= [WORD] 0x2 */ uint8_t dst; uint16_t src; dst = as.code[regs[IP] + 1]; src = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src)); regs[dst] |= src; return true; } bool VM::execYORR(void) { /* YORR R0, R1 -> R0 |= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("XORR %s, 0x%x\n", getRegName(dst), src)); regs[dst] |= regs[src]; return true; } bool VM::execXORB(void) { /* XORB R0, 0x2 -> R0 ^= 0x02 or R0 ^= [BYTE] 0x02 (low byte) */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1]; src = as.code[regs[IP] + 2]; DBG_INFO(("XORB %s, 0x%x\n", getRegName(dst), src)); regs[dst] ^= src; return true; } bool VM::execXORW(void) { /* XORW R0, 0x2 -> R0 ^= 0x0002 or R0, ^= [WORD] 0x2 */ uint8_t dst; uint16_t src; dst = as.code[regs[IP] + 1]; src = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src)); regs[dst] ^= src; return true; } bool VM::execXORR(void) { /* XORR R0, R1 -> R0 ^= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("XORR %s, 0x%x\n", getRegName(dst), src)); regs[dst] ^= regs[src]; return true; } bool VM::execNOTR(void) { /* NOTR R0, R1 -> R0 = ~R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("NOTR %s, 0x%x\n", getRegName(dst), src)); regs[dst] = ~regs[src]; return true; } bool VM::execMULI(void) { /* MULI 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(("SUBI %s, 0x%x\n", getRegName(dst), src)); regs[dst] *= src; return true; } bool VM::execMULR(void) { /* MULR R0, R1 -> R0 *= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("MULR %s, 0x%x\n", getRegName(dst), src)); regs[dst] *= regs[src]; return true; } bool VM::execDIVI(void) { /* DIVI 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(("DIVI %s, 0x%x\n", getRegName(dst), src)); regs[dst] /= src; return true; } bool VM::execDIVR(void) { /* DIVR R0, R1 -> R0 /= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("DIVR %s, 0x%x\n", getRegName(dst), src)); regs[dst] /= regs[src]; return true; } bool VM::execSHLI(void) { /* DIVI 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(("SHLI %s, 0x%x\n", getRegName(dst), src)); regs[dst] = regs[dst] << src; return true; } bool VM::execSHLR(void) { /* SHLR R0, R1 -> R0 /= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("SHLR %s, 0x%x\n", getRegName(dst), src)); regs[dst] = regs[dst] << regs[src]; return true; } bool VM::execSHRI(void) { /* SHRI 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(("SHRI %s, 0x%x\n", getRegName(dst), src)); regs[dst] = regs[dst] >> src; return true; } bool VM::execSHRR(void) { /* SHRR R0, R1 -> R0 /= R1 */ uint8_t dst; uint8_t src; dst = as.code[regs[IP] + 1] >> 4; src = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("SHRR %s, 0x%x\n", getRegName(dst), src)); regs[dst] = regs[dst] >> regs[src]; return true; } bool VM::execPUSH(void) { // TODO: STACK < 0 uint8_t src; src = as.code[regs[IP] + 1]; DBG_INFO(("PUSH %s\n", getRegName(src))); memcpy(&as.stack[regs[SP]], ®s[src], sizeof(uint16_t)); regs[SP] += sizeof(uint16_t); return true; } bool VM::execPOOP(void) { // TODO: STACK < 0 uint8_t dst; dst = as.code[regs[IP] + 1]; DBG_INFO(("POOP %s\n", getRegName(dst))); regs[SP] -= sizeof(uint16_t); memcpy(®s[dst], &as.stack[regs[SP]], sizeof(uint16_t)); return true; } bool VM::execCMPB(void) { /* CMPB R0, 0x2 -> Compare immediate with lower half (BYTE) register */ uint8_t reg; uint8_t imm; reg = as.code[regs[IP] + 1]; imm = as.code[regs[IP] + 2]; DBG_INFO(("CMPB %s, 0x%x\n", getRegName(reg), imm)); if (*((uint8_t *)®s[reg]) == imm) { flags.ZF = 1; } else { flags.ZF = 0; } if (*((uint8_t *)®s[reg]) > imm) { flags.CF = 0; } else { flags.CF = 1; } return true; } bool VM::execCMPW(void) { /* CMPW R0, 0x2 -> Compare immediate with whole (WORD) register */ uint8_t reg; uint16_t imm; reg = as.code[regs[IP] + 1]; imm = *((uint16_t *)&as.code[regs[IP] + 2]); DBG_INFO(("CMPW %s, 0x%x\n", getRegName(reg), imm)); if (regs[reg] == imm) { flags.ZF = 1; } else { flags.ZF = 0; } if (regs[reg] > imm) { flags.CF = 0; } else { flags.CF = 1; } return true; } bool VM::execCMPR(void) { /* CMPR R0, R1 -> Compares 2 registers */ uint8_t r1; uint8_t r2; r1 = as.code[regs[IP] + 1] >> 4; r2 = as.code[regs[IP] + 1] & 0b00001111; DBG_INFO(("CMPR %s, %s\n", getRegName(r1), getRegName(r2))); if (regs[r1] == regs[r2]) { flags.ZF = 1; } else { flags.ZF = 0; } if (regs[r1] > regs[r2]) { flags.CF = 0; } else { flags.CF = 1; } return true; } bool VM::execJMPI(void) { /* JMPI 0x2000 -> IP = 0x2000 */ uint16_t imm; imm = *(uint16_t *)&as.code[regs[IP] + 1]; DBG_INFO(("JMPI 0x%x\n", imm)); regs[IP] = imm; return true; } bool VM::execJMPR(void) { /* JMPR R0 -> IP = R0 */ uint8_t reg; reg = as.code[regs[IP] + 1]; DBG_INFO(("JMPR %s = 0x%x\n", getRegName(reg), regs[reg])); regs[IP] = regs[reg]; return true; } bool VM::execJPAI(void) { /* JPAI 0x2000 -> Jump to 0x2000 if above */ uint16_t imm; imm = *(uint16_t *)&as.code[regs[IP] + 1]; DBG_INFO(("JPAI 0x%x\n", imm)); if (flags.CF == 0 && flags.ZF == 0) { regs[IP] = imm; return true; } return false; } bool VM::execJPAR(void) { /* JPAR R0 -> Jump to [R0] if above */ uint8_t reg; reg = as.code[regs[IP] + 1]; DBG_INFO(("JPAR %s = 0x%x\n", getRegName(reg), regs[reg])); if (flags.CF == 0 && flags.ZF == 0) { regs[IP] = reg; return true; } return false; } bool VM::execJPBI(void) { /* JPBI 0x2000 -> Jump to 0x2000 if below */ uint16_t imm; imm = *(uint16_t *)&as.code[regs[IP] + 1]; DBG_INFO(("JPBI 0x%x\n", imm)); if (flags.CF == 1) { regs[IP] = imm; return true; } return false; } bool VM::execJPBR(void) { /* JPBR R0 -> Jump to [R0] if below */ uint8_t reg; reg = as.code[regs[IP] + 1]; DBG_INFO(("JPBR %s = 0x%x\n", getRegName(reg), regs[reg])); if (flags.CF == 1) { regs[IP] = reg; return true; } return false; } bool VM::execJPEI(void) { /* JPEI 0x2000 -> Jump to 0x2000 if equal */ uint16_t imm; imm = *(uint16_t *)&as.code[regs[IP] + 1]; DBG_INFO(("JPEI 0x%x\n", imm)); if (flags.ZF == 1) { regs[IP] = imm; return true; } return false; } bool VM::execJPER(void) { /* JPNR R0 -> Jump to [R0] if equal */ uint8_t reg; reg = as.code[regs[IP] + 1]; DBG_INFO(("JPER %s = 0x%x\n", getRegName(reg), regs[reg])); if (flags.ZF == 1) { regs[IP] = reg; return true; } return false; } bool VM::execJPNI(void) { /* JPEI 0x2000 -> Jump to 0x2000 if not equal */ uint16_t imm; imm = *(uint16_t *)&as.code[regs[IP] + 1]; DBG_INFO(("JPNI 0x%x\n", imm)); if (flags.ZF == 0) { regs[IP] = imm; return true; } return false; } bool VM::execJPNR(void) { /* JPER R0 -> Jump to [R0] if not equal */ uint8_t reg; reg = as.code[regs[IP] + 1]; DBG_INFO(("JPNR %s = 0x%x\n", getRegName(reg), regs[reg])); if (flags.ZF == 0) { regs[IP] = reg; return true; } return false; } bool VM::execCALL(void) { /* CALL 0x1000 -> Jump to data[0x1000] and saves the RP onto the stack */ uint16_t dst; dst = *((uint16_t *)&as.code[regs[IP] + 1]); DBG_INFO(("CALL 0x%x\n", dst)); *((uint16_t *)&as.stack[regs[SP]]) = regs[IP] + 3; regs[SP] += sizeof(uint16_t); regs[IP] = dst; return false; } bool VM::execRETN(void) { /* RETN -> IP = RP , restores saved return IP */ regs[SP] -= sizeof(uint16_t); regs[RP] = *((uint16_t *)&as.stack[regs[SP]]); DBG_INFO(("RETN 0x%x\n", regs[RP])); regs[IP] = regs[RP]; return true; } bool VM::execGRMN(void) { uint8_t i; for (i = 0; i < NUM_REGS; i++) { if (i != IP && i != RP) { regs[i] = 0x4747; } } return true; } void VM::run(void) { uint8_t opcode; bool finished = false; while (!finished) { opcode = (uint8_t)as.code[regs[IP]]; if (opcode == OPS[MOVI]) { execMOVI(); regs[IP] += MOVI_SIZE; } else if (opcode == OPS[MOVR]) { execMOVR(); regs[IP] += MOVR_SIZE; } else if (opcode == OPS[LODI]) { execLODI(); regs[IP] += LODI_SIZE; } else if (opcode == OPS[LODR]) { execLODR(); regs[IP] += LODR_SIZE; } else if (opcode == OPS[STRI]) { execSTRI(); regs[IP] += STRI_SIZE; } else if (opcode == OPS[STRR]) { execSTRR(); regs[IP] += STRR_SIZE; } else if (opcode == OPS[ADDI]) { execADDI(); regs[IP] += ADDI_SIZE; } else if (opcode == OPS[ADDR]) { execADDR(); regs[IP] += ADDR_SIZE; } else if (opcode == OPS[SUBI]) { execSUBI(); regs[IP] += SUBI_SIZE; } else if (opcode == OPS[SUBR]) { execSUBR(); regs[IP] += SUBR_SIZE; } else if (opcode == OPS[ANDB]) { execANDB(); regs[IP] += ANDB_SIZE; } else if (opcode == OPS[ANDW]) { execANDW(); regs[IP] += ANDW_SIZE; } else if (opcode == OPS[ANDR]) { execANDR(); regs[IP] += ANDR_SIZE; } else if (opcode == OPS[YORB]) { execYORB(); regs[IP] += YORB_SIZE; } else if (opcode == OPS[YORW]) { execYORW(); regs[IP] += YORW_SIZE; } else if (opcode == OPS[YORR]) { execYORR(); regs[IP] += YORR_SIZE; } else if (opcode == OPS[XORB]) { execXORB(); regs[IP] += XORB_SIZE; } else if (opcode == OPS[XORW]) { execXORW(); regs[IP] += XORW_SIZE; } else if (opcode == OPS[XORR]) { execXORR(); regs[IP] += XORR_SIZE; } else if (opcode == OPS[NOTR]) { execNOTR(); regs[IP] += NOTR_SIZE; } else if (opcode == OPS[MULI]) { execMULI(); regs[IP] += MULI_SIZE; } else if (opcode == OPS[MULR]) { execMULR(); regs[IP] += MULR_SIZE; } else if (opcode == OPS[DIVI]) { execDIVI(); regs[IP] += DIVI_SIZE; } else if (opcode == OPS[DIVR]) { execDIVR(); regs[IP] += DIVR_SIZE; } else if (opcode == OPS[SHLI]) { execSHLI(); regs[IP] += SHLI_SIZE; } else if (opcode == OPS[SHLR]) { execSHLR(); regs[IP] += SHLR_SIZE; } else if (opcode == OPS[SHRI]) { execSHRI(); regs[IP] += SHRI_SIZE; } else if (opcode == OPS[SHRR]) { execSHRR(); regs[IP] += SHRR_SIZE; } else if (opcode == OPS[PUSH]) { execPUSH(); regs[IP] += PUSH_SIZE; } else if (opcode == OPS[POOP]) { execPOOP(); regs[IP] += POOP_SIZE; } else if (opcode == OPS[CMPB]) { execCMPB(); regs[IP] += CMPB_SIZE; } else if (opcode == OPS[CMPW]) { execCMPW(); regs[IP] += CMPW_SIZE; } else if (opcode == OPS[CMPR]) { execCMPR(); regs[IP] += CMPR_SIZE; } else if (opcode == OPS[JMPI]) { execJMPI(); } else if (opcode == OPS[JMPR]) { execJMPR(); } else if (opcode == OPS[JPAI]) { if (!execJPAI()) { regs[IP] += JPAI_SIZE; } } else if (opcode == OPS[JPAR]) { if (!execJPAR()) { regs[IP] += JPAR_SIZE; } } else if (opcode == OPS[JPBI]) { if (!execJPBI()) { regs[IP] += JPBI_SIZE; } } else if (opcode == OPS[JPBR]) { if (!execJPBR()) { regs[IP] += JPBR_SIZE; } } else if (opcode == OPS[JPEI]) { if (!execJPEI()) { regs[IP] += JPEI_SIZE; } } else if (opcode == OPS[JPER]) { if (!execJPER()) { regs[IP] += JPER_SIZE; } } else if (opcode == OPS[JPNI]) { if (!execJPNI()) { regs[IP] += JPNI_SIZE; } } else if (opcode == OPS[JPNR]) { if (!execJPNR()) { regs[IP] += JPNR_SIZE; } } else if (opcode == OPS[CALL]) { execCALL(); } else if (opcode == OPS[RETN]) { execRETN(); regs[IP] = regs[RP]; } else if (opcode == OPS[GRMN]) { execGRMN(); regs[IP] += GRMN_SIZE; } else if (opcode == OPS[SHIT]) { DBG_INFO(("Halting.\n")); finished = true; } else if (opcode == OPS[NOPE]) { regs[IP] += NOPE_SIZE; } #ifdef DBG else if (opcode == OPS[DEBG]) { status(); regs[IP] += DEBG_SIZE; } #endif else { DBG_ERROR(("WAT: 0x%x\n", as.code[regs[IP]])); finished = true; } } return; }