class computer { const int maxmem = 1000000; int memused = 0; int * memory[0x10000]; // init to all NULLs int reg[16]; const int REG_0 = 0, ...., REG_FP = 13, REG_SP = 14, REG_PC = 15; int FLAG_Z = 0, FLAG_N = 0, FLAG_VM = 0, FLAG_SYS = 1; int specreg[16]; const int SPECREG_PDBR = 1, SPECREG_INTVEC = 2, ....; int read_phys_mem(int addr) { int msp = (addr >> 16) & 0xFFFF; int lsp = addr & 0xFFFF; if (memory[msp] == NULL) return 0; return memory[msp][lsp]; } void write_phys_mem(int addr, int val) { int msp = (addr >> 16) & 0xFFFF; int lsp = addr & 0xFFFF; int * block = memory[msp]; if (block == NULL) { memused += 0x10000; if (memused > maxmem) { cause_interrupt(INT_MEM_QUOTA_EXC, 0); return; } memory[msp] = new int[0x10000]; block = memory[msp]; } block[lsp] = val; } int read_mem(int addr) { if (FLAG_VM) addr = vm_translate(addr); return read_phys_mem(addr); } void write_mem(int addr, int val) { if (FLAG_VM) addr = vm_translate(add); write_phys_mem(addr, val); } // instruction format = OOOOOOO M PPPP SSSS NNNNNNNNNNNNNNNN int instruction; int opcode, accessmem, reg, secreg, numeric; instruction = read_mem(reg[REG_PC]); reg[REG_PC] += 1; opcode = (instruction >> 25) & 0x7F; accessmem = (instruction >> 24) & 1; mainreg = (instruction >> 20) & 0xF; secreg = (instruction >> 16) & 0xF; numeric = instruction & 0xFFFF; if (numeric & 0x8000) numeric |= 0xFFFF0000; // e.g. 0000001 0 0001 0000 1111 1111 1111 1010 // decodes as LOAD R1, -6 const int OP_HALT = 0, OP_LOAD = 1, OP_STORE = 2, ....; void init() { reg[REG_PC] = 0; reg[REG_SP] = 0x80000000; ... } int get_operand() { int op = numeric; if (secreg != 0) op += reg[secreg]; if (accessmem) op = read_mem(op); return op; } void put_operand(int value) { if (numeric != 0 && ! accessmem) { cause_interrupt(INT_UNWR_OP, reg[REG_PC]-1); return; } if (! accessmem) { reg[secreg] = value; return; } int addr = numeric; if (secreg != 0) addr += reg[secreg]; write_mem(addr, value); } switch (opcode) { case OP_HALT: running = false; break; case OP_LOAD: reg[mainreg] = get_operand(); break; case OP_STORE: put_operand(reg[mainreg]); break; case OP_LOADH: // e.g. R2 = 0x12345678; // can't just use LOAD because numeric should be 32 bits // LOAD R2, 0x5678 // LOADH R2, 0x1234 reg[mainreg] = (reg[mainreg] & 0xFFFF) | (get_operand() << 16); break; case OP_ADD: reg[mainreg] += get_operand(); break; case OP_DIV: val = get_operand(); if (val == 0) cause_interrupt(INT_DIV_ZERO, 0); else reg[mainreg] /= val; break; case OP_COMP: val1 = reg[mainreg]; val2 = get_operand(); if (val1 == val2) FLAG_Z = 1; else FLAG_Z = 0; if (val1 < val2) FLAG_N = 1; else FLAG_N = 0; break; case OP_JUMP: reg[REG_PC] = get_operand(); break; case OP_JCOND: if (mainreg == COND_LSS) { if (FLAG_N && ! FLAG_Z) reg[REG_PC] = get_operand(); } else (mainreg == COND_EQL) { if (FLAG_Z) reg[REG_PC] = get_operand(); } etc etc etc; case OP_PUSH: reg[REG_SP] -= 1; write_mem(reg[REG_SP], get_operand()); break; case OP_POP: set_operand(read_mem(reg[REG_SP])); reg[REG_SP] += 1; break; case OP_CALL: reg[REG_SP] -= 1; write_mem(reg[REG_SP], reg[REG_PC]); reg[REG_PC] = get_operand(); break; case OP_RET: reg[REG_PC] = read_mem(reg[REG_SP]); reg[REG_SP] += 1; break; case OP_FADD: val = get_operand(); float fv2 = *(float *)(& val) float fv1 = *(float *)(& reg[mainreg]); float ans = fv1 + fv2; reg[mainreg] = *(int *)(& ans); break; case OP_INCH: set_operand(getchar()); break; case OP_TYPE: putchar((char)get_operand()); break;