This project is dedicated to the memory of William Morris (aka Frags), who was the main contributor to the bounty but was unable to see the final result.

Showing posts with label instruction cache. Show all posts
Showing posts with label instruction cache. Show all posts

Monday, November 3, 2014

PPCJITBETA05 (Final Countdown)

Yes, yes, my dear friends: we are very close now! This is the final countdown indeed: the last beta before the final release of 1.0.

Are you excited? I bet you are. In the meanwhile download and enjoy the new beta:


To sum up what you will get with the new beta: mainly bugfixes. All the features are locked down for the release, the ticket list for release 1.0 is practically empty. I am waiting for any bugs you find before the release.

So, please do report bugs you find. But again: it is very important to try to verify the issue before you decide about reporting it. Please follow the steps which are documented in the README file.

Your efforts are greatly appreciated.

JIT compatibility diagnostics

I have rejected a few bugs due to the fact that these programs are not compatible with the current JIT compiling implementation. The reason is very simple: if the program is trying to modify itself without flushing the instruction cache properly then the modified code won't be recompiled and the program will misbehave. Like this program: Where Time Stood Still.

These programs might work on a real processor and still fail with the JIT compiling because the cache handling is not emulated exactly the same how it would behave on a real processor. (Namely: the number of cache lines are much larger than on a real processor, so more code is "cached".)

Although this is not ideal, but for now only a handful of programs are depending on the cache size, so it won't cause too much trouble.

How could you tell that the program is compatible with the JIT compiler?

That is a very valid question. And here is the answer: there is a option for that! (At least there is now.)
I have wasted so much time on chasing errors coming from this issue that finally I have decided I implement a diagnostic configuration option for it. It is called:
comp_test_consistency

Usual disclaimer: read the documentation and if you didn't understand what does it do then don't turn it on.

Actually, it is pretty simple: in addition to every compiled block of instructions the compiler also compiles a check which compares the original content of the memory which was used for the compiling to the current content. If it doesn't match then the emulation stops.

Basically, it can be used for verifying if the program misbehaves because it does not flush the instruction cache properly, or there is some other reason.

It is safe to keep it turned on, but it slows down the emulation (sometimes considerably), so use it only when it is needed.

X1000

As I already announced in the previous post (couple months ago): the Amiga X1000 optimized version is available in the package. Please use only that version on Amiga X1000, the generic build won't work properly.

060

Due to the "popular demand" (more than one request ;)  I have fixed the cache handling of the emulated 68060 processor type.
Please note: it is stated in the documentation from the original E-UAE that the 060 support is not implemented and all I had done was: fixed the cache bits to let the emulator turn on the caches, so the JIT can be activated. However, it is highly likely that there will be problems with some programs running on 060, since other important aspects of the 060 is not implemented (like proper stackframe).
So, watch your steps while using it. (And please don't report bugs for it. kthxbai)

RuninUAE

ChrisH kindly implemented the support for the betas in RuninUAE. You can turn on the JIT emulation from the menu now. (You guys are too spoiled!) Thanks Chris!

WinUAE PPC

In case you haven't heard: WinUAE is capable of emulating PowerPC hardware through QEmu on intel compatible processors and run PPC apps and even AmigaOS4.

The obvious question: how much better would it be running PowerPC programs on actual PowerPC processor under hardware emulation? :)
Probably it would be possible to make use of the native PowerPC processor and it would be fast. Very fast. 
Not to mention it would open the door for AmigaOS4 running on Macintosh iBooks for example.

Do I have plans implementing it? No, sorry. 
Thanks for asking.

Thanks

Finally, some thank-you's to the lovely people who helped me in this beta.

Big thanks goes to: MickJT, Mike Blackburn, Chris Handley, Luigi Burdo, Samir Hawamdeh, Raziel and Cass.

Some guys just can't stay away as it seems. :)

See you soon.

Wednesday, January 1, 2014

PPCJITBETA01 (Happy New Year 2014)

First of all:


I wish all of you guys an awesome happy new year for 2014!

We made it this far, there was no nuclear holocaust yet, which is an amazing achievement for the human race considering our lovely nature. Well done.

And now something completely different, but almost equally exciting (probably for much less human beings, can't speak for aliens)...

I woke up in the morning and had a look at the clock and it showed me:


BETA TIME!

Yes, it is unbelievable, I know. After this long-long waiting finally here it comes.
And it even comes with bugs! Lots of it!

Now seriously, if you are interested in testing the PowerPC JIT then go and get your binary release from the SourceForge page:


Tiny catch: at the moment only the AmigaOS4 version is available. See below.

You might also need a previous distribution which includes all the tools, like transrom, mousehack, make-hdf, etc. I tried to compile these, but somehow the cross-compiling failed and I ran out of patience.

What is included in beta01?

Before you fire up your favorite Amiga software in the emulator, please DO READ the README file! It will save you (and me) lots of wasted time, I guarantee.

The very first thing I have to mention is that although I had done my best I was not able to finish implementing all the planned instructions. We are very close, according to the statistics 95.09% of the instructions (368 out of 387) are done.
The reason is quite simple: the recently implemented instructions were the most complex ones. Well, you know this is exactly why you must not procrastinate the hardest part of the job just because it makes you nervous even simply thinking about it...
I have spent days on implementing BFINS and the exception handling for division by zero and I am still not convinced that it worth the effort. Anyway...
The following instructions are still emulated by the interpretive:
  • long versions of the division and multiplication instructions (DIVU.L/DIVS.L, MULU.L/MULS.L);
  • compare against bounds instructions (CMP2);
  • all the decimal data handling instructions (ABCD, SBCD, NBCD, PACK, UNPK).
The comparison and the decimal data handling is not that important, but the long division-multiplication are used quite often.
So that is sill a sore point, yet I have decided that I will release the beta without these instructions to get some feedback.
The missing instructions will be implemented soon, probably in the next beta release.

 

What is new in the sources?

 

Fixes and more

Since my last update I have managed to complete some more instructions and lots of bug fixes (thanks to Philippe Ferrucci and Davide Palombo, who insisted to demonstrate the JIT compiling at Alchimie and Pianeta Amiga shows, so I had to fix the most obvious bugs).
I don't want to bore you with the details regarding the current changes, have a look at this update if you are interested.

 

Source alignment

Another important change was: I have merged the final sources for E-UAE 0.8.29 over my changes.
Many thanks to Michael Trebilcock (MickJT) for driving my attention to the fact that I was using an outdated source version (0.8.29-WIP4) instead of the latest from the CVS (dated to 20/08/2008).
For the changes please have a look at these two updates: original source, fix for audio.

 

The LED (round#2)

Philippe Ferrucci pointed out that sometimes it is hard to tell whether the JIT is available and working or not, in spite of the already available JIT LED.
He suggested that the LED might also indicate other states of the JIT compiling, and I had found that a really useful idea.
Now, you can identify three distinct states of the JIT compiling from the LED colors:
1. Blinking green with "JIT" text on it: JIT compiling is active and the compiled code is executed.
The level of green shows you how active is the JIT compiled code compared to the interpretive-executed. (Same as before.)

2. Solid red with "JIT" text on it: the JIT compiling was set up, but the processor cache is turned off by the currently running software in the emulator, JIT compiling is not done while the cache is not turned on.

3. Solid black without "JIT" text on it: due to the emulator configuration the JIT compiling is not available.
Either no code cache was set up or specified processor type does not support the processor cache.



Some help needed

Unfortunately, I have no idea how to compile the sources for other platforms than AmigaOS4. If you feel like you know enough about how to compile these sources please get in touch with me. I am looking for MorphOS, MacOSX PPC, Linux PPC versions especially, but any other supported platforms are welcome. (Thunder? Tobias? Mike? :)

If you feel like there is a bug and you want to report it badly then please DO READ the How to report a bug section from the README before you jump on your mail client. Thanks.

Final words

It is a good start for a year, isn't it? I hope I can keep up and finally you can enjoy the benefits of the JIT compiling on your PowerPC machine.

Sunday, May 19, 2013

One small step for mankind, a giant leap for the project

I have no idea how did I manage to achieve this much in this update, but it is certainly a confident step forward. For this time the list is long and diversified:
  • Implementation of Bcc.x addr, BCHG.B Dx,mem, BCHG.L Dx,Dy, BCLR.B Dx,mem, BCLR.L Dx,Dy, BRA.x abs, BSET.B Dx,mem, BSET.L Dx,Dy, BSR.x abs, BTST.B #imm,mem, BTST.B Dx,#imm, BTST.B Dx,mem, BTST.L Dx,Dy, CMP.x #imm,mem, CMP.x mem,Dy, CMP.x reg,Dy, CMPA.L reg,Ax, CMPA.W reg,Ax, CMPA.x mem,Ay, DBF.W Dx,addr, EOR.x #imm,mem, JMP.L abs, JMP.L mem, JSR.L abs, JSR.L mem, NEG.x mem, NOT.x mem, RTS, TAS.B Dx, TAS.B mem instructions.
  • Cache invalidation fix for OSX 10.3.9 and below. (Thanks to Mike Blackburn again.)
  • Fixed mask handling in BCHG.B Dx,mem instruction.
  • Fixed missing register mapping in ASL.x #imm,Dy implementation.
  • Fixed input dependency overwriting in certain memory-related allocation functions.
  • Fixed dependency for destination memory pointer register in special memory reading.
  • Fixed post address handler for condition code addressing modes, previously it might crash or call some random handler from the other addressing modes.
  • Fixed instructions where temporary registers are allocated but not free'ed.
  • Optimized masking for register to register bit instruction.
  • Optimized the temporary register usage in helper_test_bit_register_register function.
  • Optimized flag extraction in several shifting operation.
  • Branch scheduling is more flexible: adding multiple interleaved branches is possible.
  • Comment on missing implementation for an exception on loading odd address into PC.

A few highlights

First of all, let me brag around a little bit about the number of freshly implemented instructions. Right now 237 instructions are implemented out of 388, a solid 61% is done. (Previously the ratio was ~46%.)

More MacOSX versions are supported now, Mike fixed up the cache flushing a little bit and added the pre-10.4 versions too. Please read the included README file regarding the compiling instructions.

While I was working on the instructions I discovered a few bugs and glitches, which are now fixed in this release thus improving the overall stability.

I have also managed to optimize the compiled code for some instructions. Together with the implementation of some yet missing instructions the results for the Mandelbrot test (mandel_though_hw.kick.gz among the test kick files) improved a bit compared to the previous results:

Interpretive: 108 seconds (no change there...);
JIT compiled without optimization: 44 seconds (previously it was 52 seconds);
JIT compiled with optimization: 27 seconds (previously it was 32 seconds).

That was the time for the self-polishing and now back to work...

Wednesday, April 24, 2013

Mac and cheese... err... Linux

Big thanks to Mike Blackburn for some fixes for the Macintosh support and for implementing the Linux PPC support! Well done, Mike.

After this (and this) update Mac OSX 10.4 is supported too: the instruction cache flush needed a different implementation.

Also Linux PPC users can benefit from the PowerPC JIT.

The more the merrier.

Wednesday, February 6, 2013

Can I haz time machine?

Another busy month passed, here comes the new update with lots of bug fixes and some freshly implemented instructions:
  • Implementation of
    • AND.x reg,reg;
    • EOR.x reg,reg;
    • EOR.x reg,mem;
    • SUBA.x reg,reg;
    • SUBA.x #imm,reg;
    • BSET.L #imm,reg;
    • BCLR.L #imm,reg;
    • EXG.L reg,reg and
    • NOP :) instruction.
  • Reorganized MOVE.x mem,mem instruction: memory reading and writing is separated out into independently callable functions to support the implementation of other similar instructions.
  • Implementation of OR.x reg,reg instruction was adapted to a more generic form.
  • Fixed flag checking for AND(I).(W|B) #imm,reg instructions.
  • Removed confusing OR immediate macroblock and replaced by the already available OR low immediate.
  • Falling back from addressing mode d16(ax) to (ax) if the offset is zero.
  • Fixed depenency flag handling in result check helper function.
  • Cleaned up opcode description table. Removed instructions from the table and from source code which won't be supported by the JIT compiler. Added missing RTM instruction.
  • Temporary register storage slots were moved from the stack frame to the Regs structure (context).
  • Removed useless debug log that flooded the output.
  • Temporarily disabled MOVE.x mem,mem and EOR.x reg,mem instructions to let the Kickstart run.

I have good news and not-so-good news

Which one should we start with? Okay, let me choose for you: not-so-good news first.
At the moment (beside the yet unimplemented instructions) there are two bugs that prevent the OS from running properly:
  1. For some unknown reason when an instruction reads and then writes the memory then the Kickstart goes back to the well-known reboot loop (actually it is a crash, sometimes you can even see the Guru message).
    At the moment I don't have the slightest idea why this happens. I traced it back to the normal MOVE instruction, when it copies data from one address to another. There is nothing wrong with the instruction implementation itself - as far as I can tell. So, this is some weird sh*t again. Lovely.
  2. When the optimize flag is turned on (comp_optimize = true in the config) then the Kickstart crashes very early.To tell you the truth, I am not surprised. When I tried to figure out the register dependency for each macroblock for each instruction then sometimes I mixed up stuff what I found later on. Due to the wrong register dependency settings for some macroblocks, these were accidentally removed, so some code is "optimized away". Most likely there are more mix-ups and missing dependencies in the code, it can be found just matter of time.
Good news:
As you can see in the last item for the update: I temporarily disabled the two already implemented instruction which tries to read and write the memory. The missing instructions are substituted by using the interpretive instructions.
Now, if you disable the optimize option in the configuration (comp_optimize=false) then the Kickstart seems working with some actual JIT compiled instructions! YAY! \o/ (I guess.)

Some more interesting problems

I have got some feedback about issues with running Kickstart 1.3 and some old Amiga500 games when the JIT is enabled. This is interesting indeed because if even if the JIT was turned on it did not emulate these old codes because the cache is never turned on (there was no cache in the Motorola 68000 processors when these programs were written).
As you can read it in the FAQ: the JIT compiling is depending on the cache emulation heavily. So, this is one more question mark. I haven't had much time to investigate it yet.

But most importantly: the Summer Sun is shining, let's go surfing! (Oh, wait. I don't do surfing. Last time when I jumped onto a bodyboard on the beach I bruised my ribs. Embarrassing and totally geeky. Let's just surf the net, shall we?)

Sunday, July 8, 2012

JIT Goes Blue

Although, it was just a small update, but highly important:
  • Thanks to Anonymous #1 Thore and Anonymous #2 itix (from the comments section for the previous post) MorphOS support for the JIT compiling is now implemented. (I had no possibility to test it, but fingers crossed...)
  • A bug is fixed in the memory read/write handling. It caused illegal memory access when the 3.x Kickstart was running, the stackframe was trashed due to a wrong offset calculation for the register saving.
    Unfortunately, this is not the fix what is needed for let the AmigaOS boot yet, but at least one more baby step toward that direction.
Enjoy!

P.S.: Anonymous MorphOS devs, don't you want to reveal yourselves? :)

Tuesday, May 1, 2012

Deep-diving into memory

Since I just bought a new SSD and I am about to reinstall my laptop, it is time to do another update on the project: another batch is uploaded to the SourceForge repository. (I hope I won’t lose the sources… ;)

So, what was made into this update? A quick list about what happened in the last two weeks:

  • Direct memory writing support
  • Detecting of special memory accesses per instruction and calling the chipset emulation on memory writes from the compiled code
  • Implementation of some instructions:
    • ADDQ.L;
    • MOVE.x register to memory;
    • MOVE.x register to register;
  • Implementation of some addressing modes:
    • immediate quick, like: ADDQ.L #x,reg;
    • indirect addressing with post increment, like: MOVE.x reg,(Ay)+;
  • Misc fixed stuff:
    • proper logging for JIT (with a new configuration item: comp_log);
    • slightly reworked temporary register handling;
    • better handling of reloading/saving of flags and the base register;
    • reloading of the emulated PC before leaving the compiled code is added (probably this was responsible for the reboot-loop at booting the OS, see below).

The most important change was the handling of the memory writes. When I started to plan the project this was one of the concerns: how to figure out which memory access requires special handling and which one can hit directly the emulated memory. By overcome of this issue all three problems are resolved:

  • memory accesses are emulated as it is needed;
  • self-modifying code is handled by using the processor cache;
  • translated code lookup is managed by simulating the cache lines.
Luckily, the x86 JIT implementation already solved this issue (too): every instruction is executed by the interpretive emulator first for a couple times to prevent unnecessary translation of the code pieces that won’t be executed often (like initialization/cleanup code). While it is doing that it collects some information about the executed code that can be reused for the translation. One of these is the memory access type. Very clever solution, I must admit.

I am still chasing the ghost-bug that prevents the OS from booting. The recent fixes for the PC register (program counter) reloading changed the behaviour. Instead of running around in a reboot-loop, the OS is waiting for something to happen, most likely some hardware to trigger something. So, it is still no good, but looks a bit better.

Where to go from here: more addressing modes and instructions will be implemented before I start working on the implementation of the optimizing routines. First, I want to make sure that most of the Mandelbrot test is executed using compiled code, thus it will be easier to test the optimization and finally we can see how better the JIT performs than the interpretive. Exciting!

You have probably noticed that the state of the project on SourceForge is still pre-alpha. I don’t want to change it while the OS cannot be run on the emulation, so this is the other important goal.

So much for today. While you are enjoying the sunny, warm summer, don’t forget about us who are suffering from the cold, rainy days: Winter is coming… :/

Monday, November 7, 2011

While you are waiting (FAQ)

I know you can hardly wait to fire up the JIT-crafted UAE; still I need to ask for more patience. Things are improving, yet it is not as mature as this admired audience would deserve, so there is no pre-relase just yet.

Some of you is more excited than the others and asked interesting questions that worth answering. Questions are repeated all over again quite often, so let me save some time and pondering: here are the answers for the...

Frequently Asked Questions

Last updated on 11 January 2014.


Q: How can I help?
A: You can always show your support by sending a small donation to this project on AmigaBounty. You can also spread the word to users of other platforms; maybe they would like to hear about it too.
In case you feel the urge, you can fiddle with the sources. See the Q/A below related to getting the current sources.

Q: Will this JIT translation work on AmigaOS3.x PPC/MorphOS/Macintosh/Linux/game consoles? The bounty is about AmigaOS4!
A: Absolutely, I have no intention to limit the implementation to AmigaOS4.
However, I cannot promise that I will release any other specific builds from E-UAE other than the one for AmigaOS4. (Simply because I have no experience, neither too much time/intention to dig deep into development for different platforms.)
The sources are released under GPL license; you can do your own build or merge it into your favorite UAE derivation.

Q: Will you fix the bug XYZ in E-UAE? Will you improve the chipset emulation?
A: No. I never promised anything else than PowerPC JIT translation and I still intend to stick to this. I have fixed some minor things in the original E-UAE implementation that was related to AmigaOS4, but don’t expect any subtle changes.

I am not going to take over the maintenance of the E-UAE source code base. Somebody else has to stand up and accept this task.

Q: Will this JIT thing improve the speed of the emulation of my favorite (OCS) game?
A: Possible, but I must point out that similarly to the x86 implementation the JIT translation will only work on processors that have instruction (CPU) cache built in and turned on (68020 and up). So, if your game cannot cope with these processors and the turned on processor cache, then I am sorry, but it won’t help much.


Q: I tried to run Kickstart 1.3 and it crashed with the JIT enabled!

Why? I tried to run <some ancient Amiga 500 game> and it crashed with the JIT enabled! Why?
A: Before Kickstart 2.05 the OS was not aware of the processor (CPU) cache, essentially these Kickstart versions wouldn't work with 68020 processors at all.
The processor cache is disabled when the processor resets and starts executing the ROM, but since the OS is not aware of the cache flags it turns on the cache when it fiddles with the processor control registers.
Why was it working with the interpretive emulator when 68020 processor was selected: the processor cache is not emulated in the interpretive emulator, so basically it doesn't matter at all if it was on or off.


Q: Why is the JIT depending on the processor (CPU) cache?
A: Because it is very hard to detect the self-modifying code, code overwriting and similar situations without the help from the OS or the running program itself. When the cache is flushed then the previously compiled code can be recompiled.
The JIT implementation is depending on the processor (CPU) cache emulation to overcome of the issue of the self-modifying and the generated/copied code. The JIT compiled code behaves quite similar to the actual 68020 execution, so if an OS version or a game does not work on 68020 (caches enabled) then it won't work with JIT either. (I had my sweet time with this issue while I was developing Petunia, back in the days. Still not resolved
completely there, but it is good enough for now.)

Q: Will this JIT thing improve the speed of the emulation of my favorite (OS-friendly) 68k application?
A: Most likely yes. No promises, though.


Q: When will it be ready?
A: When it’s done… ;) If everything went very well then it will be finished around when the bounty deadline comes: 02/21/2012. (Maybe I should start a countdown, but it would be too embarrassing when I miss the deadline. ;) Well, the deadline is missed, so, let's say: when it's done.


Q: Is the implementation derived from Petunia?
A: No, it is a completely different code. Neither any C or assembly source code from nor any dependency on the JIT implementation in AmigaOS4 is used.
(Actually, this is not entirely true: I was way too lazy to create an instruction description table file again and the parsing tool for it, so these two pieces were borrowed from Petunia. My original plan was using the present file and parsing, but it was so tuned to the interpretive emulation and my JIT implementation is significantly different than the x86 version, so I just skipped this.
But apart from that two files the emulation itself is completely different.)

Q: Will it be faster than Petunia?
A: I have no idea. It is more likely that some apps will run faster with Petunia, others will run faster with the E-UAE JIT. There are too many factors that might have effect the results. We will see when it will be finished.


Q: Where can I get the sources?
A: Check out the SourceForge project: https://sourceforge.net/projects/euaeppcjit 

Q: Where can I get the executable?
A: There is no final release yet, the project is in Beta stage.

Q: I want to try the emulation RIGHT NOW! How can I get it?
A: Go ahead and download the beta from the SourceForge project page:
https://sourceforge.net/projects/euaeppcjit/files
Please note: it is still Beta. You can give it a try, but be prepared that it might not work as you might expect it.

Q: But... but... I don't know how to set up the JIT compiling. What would you suggest?
A: There are some crucial settings for the JIT in the E-UAE configuration file. Without these settings the JIT compiling won't work properly. I suggest to add the following block into your E-UAE configuration file:

cpu_speed=max
cpu_type=68020
cpu_compatible=false
cpu_cycle_exact=false
blitter_cycle_exact=false
comp_optimize=no
cachesize=8192
comp_constjump=yes
comp_trustbyte=indirect
comp_trustword=indirect
comp_trustlong=indirect

ppc.use_tbc=false

These are the necessary settings for now, might (or most likely will) change in the future. 


Q: How can I be sure that the JIT is working while I am running the program?
A: There is a LED for it! Yes, if you turn on the LED on-screen-display (OSD) then you will see a LED that says "JIT". If this LED is green (read: not completely black) then the JIT is on. The more bright green means more executed JIT code.
If the LED is red then the JIT compiling is not working at the moment.
To turn the LEDs on put this into your configuration file:

show_leds=true

If you are interested in the details of how the JIT LED works have a look on this post: http://euaejit.blogspot.com/2013/02/watch-for-led.html
The LED behavior is slightly changed in Beta01, so have a look on this page too:
http://euaejit.blogspot.com/2014/01/ppcjitbeta01-happy-new-year-2014.html

(Bonus questions, asked almost every time… :)
Q: Do you like to live in New Zealand?
A: Very much so. :)


Q: Have you met the hobbits yet?
A: No, not yet, but I am looking forward to meet them. But we already visited the Hobbiton, that was fun!


Q: Have you met any sheep yet?
A: Yes, a lot.


I will add more questions and answers to this post as soon as I got more.
It seems pretty boring for now. Maybe I should post some naked ladi^H^H^H^H facts to this page.

Comments? :)

Sunday, March 6, 2011

Blueprints

It is time to celebrate: finally my Amiga configuration is complete. It took more than a half year after moving to the opposite side of the globe (from Hungary to New Zealand). I dragged my poor, old A1-XE with me in a suitcase; unfortunately it didn't survive the flight. :(
Stephen “Cobra” Fellner lent a uA1 to me in a compact case, I couldn't be grateful enough for it. (Not to mention the tons of helps they gave us to start our new life here from scratch...)
Piece-by-piece the machine was completed; the final item was an old Philips monitor from TradeMe.

It is also time to reorganize priorities in my (rather limited) free time. Cut back on beaches, bushwalks and especially on Facebook. :P
But enough from whining, this is a technical blog after all and the autumn is coming rapidly with lotsa rain...

Let's scheme!

A JIT compiler similar to a programming language compiler, the main difference is the source: while a programming language source is human readable text (or that would be the goal, at least), the source in this case is machine code from a different processor.
The upside is the machine code has very strict rules, easier to interpret. The downside is it must be precisely known in every minor detail and there are undocumented features and side-effects that have to be implemented correctly. (How to find out these: good question; usually with countless hours of debugging crashing applications.)

Why JIT called just-in-time compiling: the program code translated to natively executable code while it is emulated. It means every time the execution reaches a point in the program that wasn’t reached before then the compiler takes a chunk from the emulated code and translates it to native code then the execution flow goes on. (Some JIT compilers are able to translate the whole executable right after loading, but that is only possible in special cases.)
The compilation process can be either fairly simple or overly complicated, depending on the actual method. The final result must be directly executable on the host system; in other case it would be inefficient and probably useless. (It would require an interpreter to execute, rarely makes any sense.)
There are different approaches to the compilation process, which one is the best choice depends on multiple factors.

Poor man’s JIT

For example the most simplistic method produces a series of jump instructions for execution of source data fetching, operation execution, result store. Everything else is done by a library of functions in the emulation environment. This solution gets rid of the interpretation of every instruction code at every (re-)execution, but it is next to impossible to do any optimization which would involve the source- and destination handling together with the operation; not to mention a wider span of instructions.
Why anybody would try such an inefficient solution: if the interpreter is already implemented then requires significantly less work to turn it into a JIT compiler by this way. Also the translated code needs (lots of) memory, such implementation is lightweight on the memory usage.

Stamping Lil’ Roses and Rainbows

Slightly better approach is creating templates for certain addressing modes and operations that can be copied into the translated code (almost) directly. Not every instruction incarnation needs its own template; it is possible filling up some gaps regarding the specifics to the actual instruction, such as the involved registers.
This is the most common approach, flexible and efficient, if implemented properly. With some tweaking it is even possible to adjust the templates to handle special cases, such as optimizing arithmetic flag emulation away when consecutive instructions would overwrite it anyway. This is how Petunia works and as I found out recently, something similar that WinUAE implements.
However, templates are a bit rigid sometimes and still not to easy (or even impossible) to join together more, than two instructions in a specific optimization, which would make use of certain aspect of the target processor. Creating truly flexible templates could result a big mess in translation functions.

Big Planz I haz it

I had a couple years after finishing (the never-ever finished) Petunia playing around with scenarios in my mind where emulated code builds up this or that way. Finally, I came to the conclusion that there is a possible better way to implement JIT compiling, and that is similar to the microcode, that used often in CISC processors.
Microcode is for reducing the complexity of the machine code instruction by implementing it as a series of very simple “wired” instructions and an “interpreter” executes the simple instructions one-by-one at each clock cycle.
Combining this technique with the VLIW approach, when the simple instructions are executed out-of-order, or even can be eliminated completely the result might be lot more optimal on the generated code.
How do I intend to implement… Similarly to the templates, each emulated instruction will be prepared as a series of virtual instructions. The compiler in the first round collects the virtual instructions for each emulated instructions into a buffer for a defined chunk of the emulated code.
In the second round an optimizer runs trough the buffer while trying to apply modifications on the virtual instructions according to predefined rules. At this level the virtual instructions and the original (emulated) instructions have no connection at all anymore, each virtual instruction can be handled, reorganized, eliminated on its own.
The third round is the code emitter: turns the virtual instructions into natively executable code using actual code templates.

I am sure it wasn’t me who thought on this solution for the first time, but never read about similar approach before in the case of the JIT compiling. Programming language compilers do similar code translation to maintain the portability of the compiler between the different processor architectures. (Code emitter has to be adapted, the rest of the compiler needs no modification.)

Predicted Roadblocks

Once I heard: if you were not able to summarize the problem then you won't be able to find the solution either. Let's find out the possible problems with JIT compiling for the complete machine emulation then.

1. Memory access emulation
Unless the 68k emulation in OS4 the UAE is a complete machine emulation. While an application is running it reads and writes memory (no news to anybody, I guess). If the accessed memory is plain data then there is not much to do with it: the application can do whatever it was planned for.
Unfortunately there are two types of memory access that needs special care: accessing hardware registers and writing into the executed code area. For the latter see below at self-modifying code, the former is lot more easily to handle.
Solution: basically what needed is incorporate the functions from UAE that are called for each memory accesses into the translated code.

2. Self-modifying code
The 68k processors don't make difference between data and code, although the AmigaOS itself is able to recognize what part of the loaded executable contains actual code. The difference was never enforced to the developers with all of its up- and downsides, they found it out by the hard way what can of worms is hidden there, when the processors with cache (like 68020) appeared in Amigas. Several self-modifying game and demo fails running on the cached code memory, because the code cache and the data cache is separated.
In AmigaOS4 I was able to get information from DOS.library regarding the loaded and removed code segments. By using this information I could tell which memory areas are cleared, I simply dropped the translated code for those.
With UAE the situation is completely different: any byte in the memory is potential target for modifying. It means the translated code must be dropped and retranslated; otherwise it would conserve the previously translated state.
Solution: probably I must extend the memory access checking and drop the translated code when it gets modified. I have to revisit this topic later on; checking for translated code at every memory access might be too slow.

3. Translated code lookup
When the execution jumps, branches to a new memory address the emulator has to know whether there is an already translated code or the new address was never hit before, new translation is needed. The translated parts are sometimes following each other, but often the programs are wondering around in the memory with no logic to follow.
Solution: Petunia had the same problem, I created a two level look-up table for the translated code segments for each address in the address space; a bit memory-hungry, but very quick for finding the address of the translated code.

As Michael Jackson would say: This is it. These are the initial plans, more details must follow, but first thing first: let’s try to compile E-UAE… :)