JIT may work, but it'll be slower & need more ram.
Slower and need more RAM than what? The alternative is to not run the application at all, or run it under emulation. For stuff you have source to, recompiling it is the better alternative.
In terms of RAM, unless the code is self-modifying, you can get away with only very minor amounts for cases like m68k to CF, in order to patch in emulation of instructions that are not supported and that can't be replaced in-line with code of the same size.
You only need to maintain two copies of the code *if* you need to deal with self modifying code. A simple solution is to not deal with it in ordinary cases, and possibly not at all (frankly, given the small, finite amount of legacy code relying on self modifying code, it's probably better to spend the time patching the few programs that do).
Code accessed through jump tables are also difficult to find until you actually get to it.
Exactly, and that's the reason to do a tracing JIT instead of static translator.
With a tracing JIT it's easy, as you'll always hit a breakpoint when the branch should happen until all paths have been completely traced. A major point of a tracing JIT as opposed to a method based JIT is exactly to make it trivial to handle control flow.
There is a difference between writing a JITing for a language that was designed for it & one that isn't.
Yes, but in this case it's vastly *easier*, as the mapping function for the vast majority of instructions is simply the identity function (that is, nothing is done other than to skip to the next instruction).
The existence of JIT's that JIT m68k to i386 or PPC demonstrates a worst case bound where all instructions need to be JIT'd. Yet there are decently performing JIT's that do that. For m68k to Coldfire the case is far simpler.