Emulacja jest w pewnym sensie najbardziej bezpośrednim podejściem do problemu udostępniania abstrakcyjnych, wirtualnych zasobów. Jej zasadnicza idea polega na przechowywaniu stanu emulowanego urządzenia (na ogół będą to takie rzeczy jak: zawartość pamięci RAM, innych nośników, np. dysków, stanu rejestrów, flag) i zmienianiu ich w zależności od wykonywanego kodu.
Tak więc typowy kod emulatora wygląda mniej więcej tak:
for (;;) {
if (cycles >= eventTrigger) do_some_timed_event();
opcode = mem[Reg_PC++];
cycles = cycles + 1;
switch (opcode) {
case TFRregreg:
operand = mem[Reg_PC++];
cycles = cycles + 1;
firstreg = operand>>4;
secondreg = operand&15;
*Reg[firstreg] = *Reg[secondreg];
break;
case ADDimmediate:
operand = mem[Reg_PC++];
cycles = cycles + 1;
temp = Reg_A + operand + Flag_Carry;
Flag_Carry = temp >> 8;
Flag_Overflow = (Reg_A ^ operand ^ (Flag_Carry<<7))>>7;
Reg_A = temp & 0xff;
Flag_Negative = Reg_A >> 7;
Flag_Zero = (Reg_A == 0 ? 1 : 0);
break;
case MULdirect:
... similar code for all the available opcodes ...
}
}