Building a virtual machine class computer { int * memory[0x10000]; // all blocks 64K words long // initialise all to NULL; int reg[16]; const int REG_SP = 13, REG_FP = 14, REG_PC = 16; int sprecreg[6]; const int SPEC_PDBR = 1, SPEC_INTVEC = 2, .... ; int mem_quota = 0x100000, mem_used = 0; void phys_write_mem(unsigned int addr, int value) { int msh = addr >> 16; int lsh = addr & 0xFFFF; int * block = memory[msh]; if (block == NULL) { if (mem_used >= mem_quota) { cause_interrupt(INT_MEM_ERROR, addr); return; } else mem_used += 0x10000; block = new int[0x10000]; memory[msh] = block; } block[lsh] = value; } int phys_read_mem(unsigned int addr) { int msh = addr >> 16; int lsh = addr & 0xFFFF; int * block = memory[msh]; if (block == NULL) return 0; return block[lsh]; } unsigned int virt_to_phys_trans(unsigned int VA) { int page_table = VA >> 22; int page_number = (VA >> 11) & 0x7FF; int offset = VA & 0x7FF; unsigned int PDBR = specreg[spec_PDBR]; if (PDBR == 0) { cause_interrupt(INT_MEM_ERROR, VA); return 0; } unsigned int pt = phys_mem_read(PDBR + page_table); if ((pt & 1) == 0) // checking the valid bit { cause_interrupt(INT_PG_FLT, VA); return 0; } pt &= ~ 1; unsigned int page = phys_mem_read(pt+page_number); if (page & 2) { if (! flag_SYS) { cause_interrupt(INT_PG_FLT, VA); return 0; } } if ((page & 1) == 0) { cause_interrupt(INT_PG_FLT, VA); return 0; } pt &= ~ 1; return page | offset; } PDBR = 1800 VA = 150 page_table = 0, page_number = 0, offset = 150 pt = 2000 page = 7800 return 7950 instruction = load r1, [fp-1] vA = 7FFFF803 page_table = 511, page_number = 2047, offset = 003 pt = 2800 page = 5800 operand used = read_phys_mem(5803) = 1234; void cause_interrupt(int intcode, int detail) { interrupting = intcode; interruptvalue = detail; } void write_mem(unsigned int addr, int value) { if (FLAG_VM) addr = virt_to_phys_trans(addr); phys_write_mem(add, value); } int read_mem(unsigned int addr) { if (FLAG_VM) addr = virt_to_phys_trans(addr); return phys_read_mem(addr); } int instr; // instruction currently being executed // OOOOOOO M PPPP SSSS NNNNNNNNNNNNNNNN int opcode, accessmem, primaryreg, secreg, numeric; int get_operand() { int operand = numeric; if (secreg != 0) operand += reg[secreg]; if (accessmem) operand = read_mem(operand); return operand; } void set_operand(int value) { if (numeric != 0) { if (! accessmem) { cause_interrupt(INT_UNWR_OPND, instr); break; } if (! accessmem) { // STORE R1, R2 reg[secreg] = value; } else write_mem(reg[secreg] + numeric, value); void run() { while (flagRUN) { if (interrupting) { flagMODE = SYSTEM; int newpc = read_mem(specreg[specINTVEC] + inteerrupting); write_mem(reg[REG_SYSSP]-1, reg[REG0]); write_mem(reg[REG_SYSSP]-2, reg[REG1]); ... write_mem(reg[REG_SYSSP]-16, reg[REG_PC] - 1); write_mem(reg[REG_SYSSP]-17, interruptvalue); write_mem(reg[REG_SYSSP]-18, interrupting); write_mem(reg[REG_SYSSP]-19, makeflagsregister()); reg[reg_SYSSP] -= 19; reg[REG_PC] = newpc; flag_IP = 1; } execute_one_instruction(); } void execute_one_instr() { instr = read_mem(reg[REG_PC]); reg[REG_PC] += 1; opcode = (instr >> 25) & 0x7F; accessmem = (instr >> 24) & 1; .... numeric = instr & 0xFFFF; // 0000 0000 0000 0000 1111 1111 1111 1010 = decimal -6 in 16bits if (numeric & 0x8000) numeric |= 0xFFFF0000; switch (opcode) { case OP_LOAD: { // e.g. LOAD R1, [FP-2] operand = get_operand(); reg[primaryreg] = operand; break; } case OP_STORE { // e.g. STORE R1, [FP-2], not allowed: STORE R1, 123 put_operand(reg[primaryreg]); break; } case OP_LOADH: { // e.g. LOADH R1, 123 reg[primaryreg] = (reg[primaryreg] & 0xFFFF) | (get_operand() << 16); break; } // e.g. I wanted LOAD R1, 0x10237A36 // big and positive do instead LOAD R1, 0x7A36 LOADH R1, 0x1023 case OP_ADD: { e.g. ADD R1, [FP+3] reg[primaryreg] += get_operand(); break; } case OP_DIV: { e.g. ADD R1, [FP+3] int o = get_operand(); if (o == 0
 { cause_interrupt(INT_DIV_ZERO, instr); break; } reg[primaryreg] /= o; break; } case OP_CMP: { int c1 = reg[primaryreg]; int c2 = get_operand(); if (c1 == c2) FLAG_Z = 1; else FLAG_Z = 0; if (c1 < c2) FLAG_N = 1; else FLAG_N = 0; break; } case OP_JUMP: { reg[REG_PC] = get_operand(); break; } case OP_JCOND: { // e.g. JCOND LEQ, Label if (primaryreg == COND_LEQ) { if (FLAG_Z || FLAG_N) reg[REG_PC] = get_operand(); } else if (primaryreg == COND_NEQ) { if (! FLAG_Z) reg[REG_PC] = get_operand(); } else if (primaryreg == COND_GTR) { if (! FLAG_N && ! FLAG_Z) reg[REG_PC] = get_operand(); } ... break; } case OP_SETSR { // e.g. SETSR R1, $INTVEC if (numeric < 0 || numeric >= MAX_SPEC_REG) { cause_interrupt(INT_BAD_OPND, numeric); break; } specreg[numeric] = reg[primaryreg]; break; } case OP_GETSR { // e.g. GETSR R1, $INTVEC if (numeric < 0 || numeric >= MAX_SPEC_REG) { cause_interrupt(INT_BAD_OPND, numeric); break; } reg[primaryreg] = specreg[numeric]; break; } case OP_PUSH: { reg[REG_SP] -= 1; mem_write(reg[REG_SP], get_operand()); break; } case OP_PUSH: { put_operand(mem_read(reg[REG_SP])); if (interrupting) break; reg[REG_SP] += 1; break; }