Date : Mon, 18 Jul 1994 11:06:46 EST
From : Stephen Quan <quan@...>
Subject: Steve's emulators.
I don't know if anyone is following some of the things I have been
writing, but I am working on 2 emulators and am starting a third.
Why? Because they have completely different design architectures,
and I particularly like my 2nd emulator's internal design, which
holds my secret [now to be reveal] of *not* storing the Status
Register anywhere!
1st emulator -
This is my standard emulator with a few optimisations here and
there. Standard being, it was my first obvious C implementation.
I have started with
while (1)
{
switch (fetch_opcode)
{
case .....
}
}
2nd emulator -
Now, here's the big secret! What happens if you knew the carry was
cleared. You don't have it stored in a variable, you just knew it
was cleared??? BCC will be just a jump!
eg.
case BCC: branch(relative()); break;
case BCS: PC++; break;
Well what I did was I extend this idea to NVZC. I assumed that
they were all know quantities and wrote every combination into 16
different emulators all built into one. For instance
case CLC: goto emulator_with_carry_cleared; break;
case SEC: goto emulator_with_carry_set; break;
I never store, update or check the condition codes of NVZC. I just
do a lot of jumps!!!!!
To my dismay the overall performance has not been improved because
a few problems in representing this idea totally in C, and this
emulator only differs from my first emulator by a +/- 5 seconds
than my previous emulator running. I am having a few problems
which was indirectly related to my post on 256-branches. I know
this can be done in assembly, but if somehow I could do it in C,
I bet this emulator will get unrivalled speed!
Especially that 256^3 loop where have the instructions executed are
actually BNE instructions. BNE will be implemented the same way as
BCC above (based on we know whether Z is set or cleared).
3rd emulator -
At my dismay, I have no way of storing labels in a big array and
jumping to them. I have found that I can store procedure names
into an array and call them. So I can replace
switch (opcode)
{
case :
}
With
run_opcode[opcode]();
Ok, so now I am losing performance by making a function call, but
I do make a again that it calls exactly the right function without
bothering to have one big whopping switch loop. I have yet to
implement this and determine whether the gain in trashing switch
outways the loss in using procedures. I am hoping that my compiler
realises that my procedures require nothing more than pushing and
pulling the PC.
Also, this emulator I can further my pursuit in knowing NVZC before
jumping. How you may ask??? Ok, here comes my next secret!!! :-)
N0V0Z0C0_run_opcode[opcode]();
Of course this will be a 256 array of procedure names that know that
all the status registers are cleared and will run the appropriate
functions.
N1V0Z0C1_run_opcode[opcode]();
This one knows that N and C are set, and V and Z are cleared.
The actual C syntax on how I implement this, I am with-holding until
I have tried it out myself. :-) :-) If I have time to get a good
book on 386 programming I'd do it in assembly as well! :-) :-)
--
Stephen Quan (quan@... ), SysAdmin, Analyst/Programmer.
Centre for Spatial Information Studies, University of Tasmania, Hobart.
GPO BOX 252C, Australia, 7001. Local Tel: (002) 202898 Fax: (002) 240282
International Callers use +6102 instead of (002).