[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Emulator Project Question



OneLouder wrote:

>> ==> It is my goal to translate 6502 instructions / opcodes into 80x86
>> instructions / opcodes without using functions nor emulation BEFORE
>written
>> C++ is programmed to point 80x86 memory location before emulation can be
>> executed.  It is how speed and preformance can increase!  Please state
>your
>> opinion what you think!
>
>Ah - so what you're attempting to build is in fact an 6502->x86 translator.
>One question, I guess, is whether you're doing this at runtime (ie
>"just-in-time") in order to speed up emulation, or in advance, basically
>translating a program in total then running it.
>
>A couple of issues:
>
>Translation generally works best if the source instruction set is very clear
>about intent - Java JITs work because the Java bytecodes are very well
>defined, are produced in recognizable patterns by compilers and generally
>have few side effects. The 6502 with the memory-mapped hardware, as has been
>mentioned, makes this very tough.

Yes, it would be much easier if the code could be caused to trap on
accesses to soft switch locations.  Usually such trapping cannot be
controlled at a sufficiently small granularity.  It might be necessary to
trap all references to $Cxxx and then interpret the intent.

Of course, references with absolute addresses could be easily translated.

>Having said that, translation in advance _is_ possible by mapping every 6502
>instruction to an x86 functional equivalent code fragment, though that may
>involve several instructions in order to get all of the flags correctly
>handled.  Of course, then the inter-branch distances will be wrong, so
>they'll have to change too.

One major optimization afforded by code translation is that condition
codes that are not referenced need not be computed.  Since a very large
fraction of instructions set conditions which are never tested, this is an
opportunity to do less work.

To be sure that the condition is redundant, we must have a good idea
of program flow.  If the analysis is being done at run time, there are
several good heuristics that will guess the best and recover if wrong.
If flow analysis is being done "dry", prior to run time, then it must
generate a trace (simulation of execution) to discover the most likely
case(s), and then use "guess the best and recover if wrong" techniques.

<snip>
>The trouble is, it's never quite that simple.  Screen memory is generally
>not accessed with absolute addressing modes.

Ah, but screen memory should simply be mapped as part of the
source machine's memory image.  Periodically (say, 30 times per
second) this screen image can be mapped to the host machine's
display memory, using appropriate color algorithms and optimizations
(such as comparing for changes before mapping).

<snip>
>
>Another example, tough to translate: the very common 6502-type jump table,
>wherein we see the 6502 quirkiness about loading the return address-1 on the
>stack in a JSR/RTS:
>
>TABLE DW SUB1-1
> DW SUB2-2
>...
>
>LDA INDEX
>ASL
>TAX
>LDA TABLE+1,X
>PHA
>LDA TABLE,X
>PHA
>RTS
>
>The translator really has no idea that the table contains addresses, and
>won't know the intent until the RTS instruction.

This is why doing translation in advance of execution is so hard--you have
to flow trace through thickets like this!  Bell Labs did it, so we know that
it can be done, but it takes a lot of "rules" to do most of it automatically,
and even then, you can never be sure that there isn't a trick that you haven't
seen yet.  ;-)

If translating at run time, you must keep an image of the source machine's
memory, so when a computed branch address arises, you can look and
see what is supposed to happen, even reverting to emulation if you think
that it will happen rarely.

The best run time translators I've seen start as pure emulators, but
keep count of how often they emulate a chunk of code, then translate
them when the count exceeds a threshold.  This saves a lot of useless
translation of code that is practically never executed (error handling
code) or executed only once (initialization and termination code).
Taken together, these kinds of code are a big chunk of most programs.

>Advanced translators usually are taught common patterns of instructions
>rather than individual ones, so simply looking up a 6502 instruction and
>replacing it with a similar x86 instruction is not likely to work well.

True.  And patterns of patterns--kind of like compilation.  ;-)


-michael

 Email:  mjmahon@aol.com
 Home page:  http://members.aol.com/MJMahon/