While playing Day of the Tentacle on SCUMM-VM (Dos no worky on Xp) , I realized how the games seem to run normal while actually being emulated.
1) When created a machine, you can stick to real opcodes or virtual opcodes.
Real opcodes are more like mov, add, etc.
Virtual opcodes are more like: drawpixel, hidemouse
An opcode is a single instruction which can make a bigger instruction.
Emulating a bunch of real opcodes to draw a pixel will be naturally time consuming. Virtual opcodes are faster and simpler.
2)To Intrepret or Recompile?
This mostly matters on what you picked on question 1.
Recompiling runs fast, but takes too long (At load times). Also, if the program jumps to a variable, the recompiler doesn't know what to convert that variable to. That is why you need to recompile everytime a byte in the program's execution path is changed. The solution may be to disable programs writing to themselves. That is a nono mostly. Recompiling is great if you are using real opcodes.
Intrepreting real opcodes IS SLOOOOOOOWWWWW, but it is less buggy. Intrepreting virtual opcodes is faster, but you have to use asm to do it correctly.
3)Better Intrepretation core:
(A made up language to prevent people from copy-pasting. Make em do something ;D )
word offset;
byte program[10];
....
//Load program
....
jump(0x100040+program[offset] *3) //Jump instruction is 3 bytes (I think :/ )
//Means, get current opcode, multiply it by 10, and jump there
0x100040:
jmp executeop0;
0x100043:
jmp executeop1;
This way is fast. If you used an if/switch, it would waste instructions using compare.
System core solutions
Re:System core solutions
//Modified version: (Error checked)
While playing Day of the Tentacle on SCUMM-VM (DOS no worky on XP), I realized how the game seemed to run normal while actually being emulated.
1) When creating a core, you can stick to real opcodes or virtual opcodes.
Real opcodes are more like: mov, add, etc.
Virtual opcodes are more like: drawpixel, hidemouse
An opcode is a single instruction which can make a bigger instruction.
Emulating a bunch of real opcodes to draw a pixel will be naturally time consuming. Virtual opcodes are faster and simpler for the programmer to use.
2) To Interpret or Recompile?
This mostly matters on what you picked on item one.
Recompiling executes fast, but takes too long (At load times). Also, if the program jumps to a variable, the recompiler doesn't know what opcode to convert the variable to. That is why you need to recompile every time a byte/word/etc. in the program's execution path is changed. The solution may be to disable programs writing to themselves. That is mostly a NONO! Recompiling is great if you are using real opcodes, recompiling virtual opcodes makes a big offset in the difference of programs.
Interpreting real opcodes IS SLOOOOOOOWWWWW, but it is less buggy. Interpreting virtual opcodes is faster.
3)Better Interpretation Core:
(A made up language to prevent people from copy-pasting. Make ?EM? do something!)
word offset;
byte program[10];
....
//Load program
offset=0;
....
jmp start;
exe:
offset++;
start:
jmp 0x100040+program[offset] *3; //Jump instruction is 3 bytes (I think :/ )
//Means, get current opcode, multiply it by 3, and jump there
0x100040:
jmp executeop0;
0x100043:
jmp executeop1;
?
executeop0:
//Do blah
jmp exe;
executeop1:
//Do blah
jmp exe;
This way is fast. If you used an if/switch, it would waste instructions using compare.
While playing Day of the Tentacle on SCUMM-VM (DOS no worky on XP), I realized how the game seemed to run normal while actually being emulated.
1) When creating a core, you can stick to real opcodes or virtual opcodes.
Real opcodes are more like: mov, add, etc.
Virtual opcodes are more like: drawpixel, hidemouse
An opcode is a single instruction which can make a bigger instruction.
Emulating a bunch of real opcodes to draw a pixel will be naturally time consuming. Virtual opcodes are faster and simpler for the programmer to use.
2) To Interpret or Recompile?
This mostly matters on what you picked on item one.
Recompiling executes fast, but takes too long (At load times). Also, if the program jumps to a variable, the recompiler doesn't know what opcode to convert the variable to. That is why you need to recompile every time a byte/word/etc. in the program's execution path is changed. The solution may be to disable programs writing to themselves. That is mostly a NONO! Recompiling is great if you are using real opcodes, recompiling virtual opcodes makes a big offset in the difference of programs.
Interpreting real opcodes IS SLOOOOOOOWWWWW, but it is less buggy. Interpreting virtual opcodes is faster.
3)Better Interpretation Core:
(A made up language to prevent people from copy-pasting. Make ?EM? do something!)
word offset;
byte program[10];
....
//Load program
offset=0;
....
jmp start;
exe:
offset++;
start:
jmp 0x100040+program[offset] *3; //Jump instruction is 3 bytes (I think :/ )
//Means, get current opcode, multiply it by 3, and jump there
0x100040:
jmp executeop0;
0x100043:
jmp executeop1;
?
executeop0:
//Do blah
jmp exe;
executeop1:
//Do blah
jmp exe;
This way is fast. If you used an if/switch, it would waste instructions using compare.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:System core solutions
what you'd probably love to learn about is High-Level Emulation (HLE) that is now used in N64 and PlayStation emulators (and possibly other recent gaming platforms).
The idea is that the emulator will be able to interprete long blocks of code rather than single opcodes. For instance, it could detect a code sequence that correspond to the programming of one triangle rasterization and make it correspond to one single OpenGL call, or detect that a code chunk programs a sample on the Sound chip and program the same sample on DirectSound ...
now, the less registers the CPU has, the more complex HLE becomes, because the same "logical" operation will have a lot of different variants encoding, while the encoding will often look similar on a RISC machine that has plenty of registers to store intermediate results and very few addressing modes (imho
The idea is that the emulator will be able to interprete long blocks of code rather than single opcodes. For instance, it could detect a code sequence that correspond to the programming of one triangle rasterization and make it correspond to one single OpenGL call, or detect that a code chunk programs a sample on the Sound chip and program the same sample on DirectSound ...
now, the less registers the CPU has, the more complex HLE becomes, because the same "logical" operation will have a lot of different variants encoding, while the encoding will often look similar on a RISC machine that has plenty of registers to store intermediate results and very few addressing modes (imho
Re:System core solutions
Hmm, that's interesting. I knew of HLE, but never exactly knew what it did. But isn't that a little bit painstaking to identify what each pattern of opcodes will be converted to? I am gonna use virtual opcodes with the faster in. method for now.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:System core solutions
for sure, if you're the one who define opcodes :p