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]; } 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 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; }