[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Emulator Project Question
> > If you could clearly define which bytes were "code" and which were
"Data",
> > performing assembly conversion at runtime wouldn't be so difficult.
> >
> > The problem is that you cannot "translate as you go",
>
> Why not? Some Java interpreters do precisely that: they translate
> the J-code into native machine instructions as they go (it's called
> JIT compilation where JIT means "Just In Time"). With linear code
> this will of course yield no gain in execution speed at all, but if
> you enter a loop there'll be a tremendeous gain: the loop is
> translated once, and then the loop is executed in native code.
>
> So why can't this technique be applied to 6502 machine code as well?
> BTW it would probably be the only secure way to distinguish code
> from data: what's executed is, by definition, code.
>
> > and you have no guaranteed method of identifying which is code
> > and which is data.
>
> Yes you have - by "following the code" so to say. But it'll be tricky
> if some bytes are used for code *and* data, particularly if the "data"
> is changed, i.e. self-modifying code.
I have an old saying. If you give me a set of rules, I can code it. It
doesn't promise to be easy, efficient or reliable, but I can code it. :)
The problem is that in order to maintain branch integrity, you need to
"translate" the entire execution path ahead of time. Otherwise, you will
spend more time adjusting things than running machine code. And if you gain
100% speed by pre-translating code, and lose 100% due to the branch
adjustments and "dirty segment" checks, why bother?
When I was developing XGS/32, I made a few small adjustments to the CPU
core, which was nothing more than a large set of function pointers. I found
that the working set for the CPU core was very small, fast and had little
overhead. Most of the code sat in the L1 cache regardless, so translation of
the code would have been ineffective.
The *vast* majority of CPU time is spent emulating the operation of various
silicon-based devices. For instance, the video refresh subroutine routinely
has to perform a screen refresh 30 times per second. At 30fps, in 640x480,
16 bit color, that is BLT'ing 18MBps to an offscreen framebuffer, which
DirectX then handles.
Keep in mind that the process of BLT'ing isn't a single CPU instruction.
Beyond that, sound on the IIgs is another big issue. More time consuming
pre-processing. Disk emulation, mouse emulation, handling emulated
interrupts, etc etc etc.
None of this stuff involves the emulated CPU core.
With an apple II, if you wanted to JIT-C the code, you would need something
that looked like this.
1 - Look at instruction pointer
2 - Is instruction pointer "dirty (has either been written to since last
compile, or has never been compiled)"
3 - If so, re-translate code. Set dirty flag to false
** Lots of innane logic to fix-up branch dependencies
4 - If not, execute code...
The part between 3 and 4 is where things get tricky. 65x02/816 instructions
are not 1/1 compatible with x86. Both are CISC processorts, but instruction
size varies. LDA/STA instructions may translate easily, but some of the
indexed modes are quite complex and will result in non-alignment of expected
code boundaries. Therefore, as you JIT-C the code, all branches need to be
adjusted outward/inward depending on where they fall.
Like I said, it can be coded. But I would guess that it would propably bring
the emulator to a halt, and reduce reliability a great deal!
>
> > The fastest method so far has been a simple jump table. Define an
> > array of function pointers that is 255 bytes long.
>
> I think you mean 256, not 255: remember that the 1-byte opcode of the
> 6502 has 256 possible values.
Sorry, was thinking 0-(n-1)
>
> Also, I think you mean 256 entries rather than 256 bytes: a function
> pointer is certainly longer than 1 byte.
Absolutely. On a IIgs, a function pointer is 16bit. In windoze 9x->XP, a FP
is 32 bit.
In windows, a typical emulator jump table will be 1k long. Good enough to
fit in the 8k/32k working set of most x86 compatible.