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

Re: Emulator Project Question



>
> Presumably you could handle this by keeping your caches of translated
> instructions in some sort of data structure that mimics the Apple II's
> memory banks.  Then, when you hit that "JMP $E000", you'll know the
> right destination in your trasnlated code.
>

Keeping a cache of "dirty" bytes would be really expensive, as you would
have to do it byte-by-byte. That would not only be very inefficient, but
time consuming.  Which is why I was noting that while it is feasible to
perform a code-translation to x86, it is propably going to be a
rube-goldberg algorithm!

> There seems little advantage in Java's JITC unless the compiled
> routine is likely to be executed more than once, regardless of any
> loops.  After all, the cost of translating the bytecodes, and saving
> the translated version, is approximately the cost of interpreting the
> bytecodes directly.  This is my impression at least, having just
> scanned the JVM architecture specs; the bytecodes represent very
> simple operations on a stack-based machine.  (True?)
>

The MS .Net CLR is similar in architecture to a java VM. It is essentially a
"rich cpu", where exception handling and standard types are built in, and
the instruction architecture is relatively limited and simple to port to
various environments.

> > > 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.
>
> I'll bet Steve is kicking himself over that typo.
>

Oh yes, I am :)


> > > Each element points to a function that handles that particular opcode.
> > > Simply do a array[opcodenumber]; and you can call the emulated CPU.
>
> Actually, I recommend using a dense "switch" statement, not a function
> pointer table.  A *dense* (all case values from 0 and N are present,
> even if some of them do nothing) and *large* (N is at least ten or so;
> 256 is certainly plenty) switch statement will be optimized into a
> relative branch using an inline lookup table, indexed by the switch
> expression.  Any C/C++ compiler with the sense that God gave a kitten
> will do this, and you can avoid the function call overhead that you
> are otherwise *very* likely to incur.
>

This makes *alot* of sense. A table of function pointers, while propably
retained in the data working set, still would have to make a long jump in
most cases, depending on how the code segments are linked. I suspect that
transition would be expensive!

A case statement, while not being pretty to look at (understatement) would
allow the compiler to perform heavy optimization and most likely retain the
vast majority of the code to benefit from the integral branch prediction on
the P3/P4/K7 processors.

I am gonna have to take a peek at XGS/32 ...time to dig it out of sourcesafe
:)

>
> Usually no one cares about all this, because in typical programs a
> function's overhead cost is negligible compared to the cost of the
> function's body.

Except when the function call occurance ratio hovers in the 90th percentile!
:)

> The gains are little; the headaches, enormous.
>

My sentiments exactly...