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; const int FLAG_Z = 1, FLAG_N = 2, FLAG_VM = 4, FLAG_SYS = 8; int specreg[16]; const int SPECREG_PDBR = 1, SPECREG_INTVEC = 2, SPECREG_SYSSP = 3, ....; 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; } const int VALID = 1, SYSTEM = 2; int vm_translate(unsigned int addr) { int table = addr >> 22; int page = (addr >> 11) & 0x7FF; int offset = addr & 0x7FF; int pdbr = specreg[SPECREG_PDBR]; if (pdbr == 0) { cause_interrupt(INT_PAGE_FAULT, addr); return 0; } int pt = read_phys_mem(pdbr + table); if (interrupting) return 0; if ((pt & VALID) == 0) { cause_interrupt(INT_PAGE_FAULT, addr); return 0; } pt &= ~ VALID; int base = read_phys_mem(pt + page); if (interrupting) return 0; if ((base & VALID) == 0) { cause_interrupt(INT_PAGE_FAULT, addr); return 0; } if ((base & SYSTEM) && (getflag(FLAG_SYS) == 0)) { cause_interrupt(INT_PAGE_FAULT, addr); return 0; } base &= ~ (VALID | SYSTEM); return base + offset; } int read_mem(int addr) { if (getflag(FLAG_VM)) addr = vm_translate(addr); return read_phys_mem(addr); } void write_mem(int addr, int val) { if (getflag(FLAG_VM)) addr = vm_translate(add); write_phys_mem(addr, val); } void init() { reg[REG_PC] = 0; reg[REG_SP] = 0x80000000; specreg[SPECREG_SYSSP] = 0x80000000; specreg[SPECREG_FLAGS] = FLAG_SYS; ... } int getreg(int n) { if (n == REG_SP) if (getflag(FLAG_SYS)) return specreg[SPECREG_SYSSP]; else return reg[REG_SP]; if (n == REG_FP) if (getflag(FLAG_SYS)) return specreg[SPECREG_SYSFP]; else return reg[REG_FP]; return reg[n]; } void setreg(int n, int value) similar int get_operand() { int op = numeric; if (secreg != 0) op += getreg(secreg); if (accessmem) op = read_mem(op); return op; } void put_operand(int value) { if (numeric != 0 && ! accessmem) { cause_interrupt(INT_UNWR_OP, getreg(REG_PC)-1); return; } if (! accessmem) { setreg(secreg, value); return; } int addr = numeric; if (secreg != 0) addr += getreg(secreg); write_mem(addr, value); } int getflag(int f) { if (specreg[SPECREG_FLAGS] & f) return 1; else return 0; } void setflag(int f, int v) { if (v) specreg[SPECREG_FLAGS] |= f; else specreg[SPECREG_FLAGS] &= ~f; } int interrupting = 0, int_detail = 0; void cause_interrupt(int i, int d) { interrupting = i; int_detail = d; } // instruction format = OOOOOOO M PPPP SSSS NNNNNNNNNNNNNNNN while (running) { int instruction; int opcode, accessmem, reg, secreg, numeric; if (interrupting) { int iv = specreg[SPECREG_INTVEC]; if (iv == 0) break; setreg(REG_PC, read_phys_mem(iv + interrupting); setflag(FLAG_SYS, 1); int sp = getreg(REG_SP); write_mem(sp-1, getreg(0)); write_mem(sp-2, getreg(1)); ... write_mem(sp-13, getreg(REG_FP)); write_mem(sp-14, getreg(REG_SP)); write_mem(sp-15, getreg(REG_PC)); write_mem(sp-16, int_detail); write_mem(sp-17, specreg[SPECREG_FLAGS]); setreg(REG_SP, sp-17); interrupting = 0; } instruction = read_mem(getreg[REG_PC]); if (interrupting) continue; setreg(REG_PC, getreg(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, ....; switch (opcode) { case OP_HALT: if (getflag(FLAG_SYS) != 1) { cause_interrupt(INT_ILLEGAL_OP, 0); break; } running = false; break; case OP_LOAD: int opd = get_operand(); if (interrupting) break; setreg(mainreg, opd); break; case OP_STORE: put_operand(getreg(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 int opd = get_operand(); if (interrupting) break; setreg(mainreg, getreg(mainreg) & 0xFFFF) | (opd << 16)); break; case OP_ADD: int opd = get_operand(); if (interrupting) break; setreg(mainreg, getreg(mainreg) + opd); break; case OP_DIV: val = get_operand(); if (interrupting) break; if (val == 0) cause_interrupt(INT_DIV_ZERO, 0); else setreg(mainreg, getreg(mainreg) / val); break; case OP_COMP: val1 = getreg(mainreg); val2 = get_operand(); if (interrupting) break; setflag(FLAG_Z, val1 == val2); setflag(FLAG_N, val1 < val2); break; case OP_JUMP: int opd = get_operand(); if (interrupting) break; setreg(REG_PC, opd); break; case OP_JCOND: int opd = get_operand(); if (interrupting) break; if (mainreg == COND_LSS) { if (getflag(FLAG_N) && ! getflag(FLAG_Z)) setreg(REG_PC, opd); } else (mainreg == COND_EQL) { if (getflag(FLAG_Z)) setreg(REG_PC, opd); } etc etc etc; case OP_PUSH: int opd = get_operand(); if (interrupting) break; setreg(REG_SP, getreg(REG_SP) - 1); write_mem(getreg(REG_SP), opd); break; case OP_POP: set_operand(read_mem(getreg(REG_SP])); if (interrupting) break; setreg(REG_SP, getreg(REG_SP) + 1); break; case OP_CALL: int opd = get_operand(); if (interrupting) break; setreg(REG_SP, getreg(REG_SP) - 1); write_mem(getreg(REG_SP), getreg(REG_PC)); setreg(REG_PC, opd); break; case OP_RET: int val = read_mem(getreg(REG_SP)); if (interrupting) break; setreg(REG_PC, val); setreg(REG_SP, getreg(REG_SP) + 1); break; case OP_FADD: val = get_operand(); if (interrupting) break; float fv2 = *(float *)(& val) int iv2 = getreg(mainreg); float fv1 = *(float *)(& iv2); float ans = fv1 + fv2; setreg(mainreg, *(int *)(& ans)); break; case OP_INCH: set_operand(getchar()); break; case OP_TYPE: int opd = get_operand(); if (interrupting) break; putchar((char)opd); break; case OP_GETSR: int index = get_operand(); if (interrupting) break; if (index < 0 || index > MAX_SPECREG) { cause_interrupt(INT_BAP_OPD, index); break; } setreg(mainreg, specreg[index]); break; case OP_SETSR: similar case OP_IRET: int sp = getreg(REG_SP); int flags = read_mem(sp); if (interrupting) break; setreg(REG_PC, read_mem(sp+2)); if (interrupting) break; setreg(REG_SC, read_mem(sp+3)); if (interrupting) break; setreg(REG_FC, read_mem(sp+4)); if (interrupting) break; ... setreg(0, read_mem(sp+18)); if (interrupting) break; setreg(REG_SP, sp+18); if (getflag(FLAG_SYS) == 0 && (flags & FLAG_SYS)) { cause_interrupt(INT_ILLEGAL_OP, 0); break; } specreg[SRECREG_FLAGS] = flags; break; case OP_MOVE: if (getreg(0) <= 0) break; int val = read_mem(getreg(secreg)); if (interrupting) break; write_mem(getreg(mainreg), val); if (interrupting) break; setreg(0, getreg(0) - 1); setreg(mainreg, getreg(mainreg) + 1); setreg(secreg, getreg(secreg) + 1); setreg(REG_PC, getreg(REG_PC) - 1); break; case OP_ATAS: int opd = get_operand(); if (interrupting) break; setreg(mainreg, opd); set_operand(1); break;