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 E-UAE. Show all posts
Showing posts with label E-UAE. Show all posts

Friday, January 2, 2015

Release 1.0.0 (Waiting for Marty edition)

Happy new year Earthlings! 
(...and Ufonauts, in case any of you is reading this post.)

I have an awesome news, the most awesome that have been landed for this project so far:

It is done!

Yes, finished, version 1.0.0 is completed. The final round was about some bug fixes and tiny improvements.

There are still minor outstanding issues and features I dreamed of while I was busy with bug fixing, these are postponed to v1.1 release for now.

This was a long run, I agree. My original estimation was 1 year for completing the project. What I haven't considered that I have a life, unlike back in the uni days... Finally, it took almost 4 years to complete the project.

But on the other hand, what I was planning to do for the bounty was surpassed by a magnitude thanks to all the helping hands and my constant desire to improve things. So, it took some time, but it all worth the wait, I believe.

You, who followed the project closely enough know already that the last half year was spent on polishing the release rather than actual development. All the features were ready a year ago, but it needed some more love (and mostly testing).

About the future

Speaking of Marty, I invite you to have a quick look at the tickets for the upcoming release. Just like any good open source software project: there is always room for improvements.

When will it be finished - sorry, I couldn't tell. And I don't want to fall into the same mistake again, of course. ;)

If you had found any bugs, please do report. I intend to fix any issues which was discovered in the meanwhile.

Further dreams

This project was set up specifically to implement JIT compiling for PowerPC processors, due to the current state of AmigaOS4 and MorphOS. Since the JIT compiling was already available for x86 it was never a goal for me to come up with a generic solution which supports multiple architectures.

But more than 4 years passed since I started to think about it and lots of things have changed. Nowadays smart phones are standing tall, probably even more important than desktop computers. These are mostly running on ARM compatible processors, so PPC or x86 JIT implementations are completely useless for these devices.
When I had a few email rounds with Toni Wilen, maintainer of WinUAE, he complained about the x86 implementation and mentioned that it is completely outdated in the era of x64 architecture. Unfortunately, the ancient x86 implementation is so complicated and messy that nobody is brave enough to touch it. (This is why I started my own implementation instead of porting the x86 version.)
AmigaOS4 is running on PowerPCs, but let's be realistic: PowerPC is dead. (Or is it? Yes, it is at desktop computing.) Sooner or later AmigaOS4 will migrate to a new architecture probably.

So, what is the bottom line of my ramblings? This JIT implementation was made for PowerPC, but it can be changed to support multiple processor architectures. I don't think that it would be too complicated, the majority of the code can be reused, it just needs some restructuring.

Am I going to do that? Errr... no? I don't know. Sounds challenging enough, but I have spent enough time on JIT compiling already in my life to look for something new instead.

Big Thanks

Finally, I would like to mention a few folks around the globe who helped me in any way while I have been working on the E-UAE JIT. (Let me know if I mistyped anybody's name...)

Thank you for your great help!

First special thanks:

Robert Trevor Dickinson - special thanks for making me do the JIT, you have talked me into it, so this is all your fault now! ;)

Stephen Fellner - thanks for lending me the µAmigaOne I am still using after my AmigaOne-XE did not survive the moving to New Zealand. Without this machine I wouldn't be able to do any development at all.

Michael Trebilcock (MickJT) - you have helped me a lot with the scattered around source code of E-UAE, building, testing, AmigaOne X1000 support and plenty of other things. Without your contribution this project wouldn't be in this good shape at all.

Tobias Netzel - thanks for picking up the G5 support, Tobias. I had no opportunity implementing the required changes, your handiwork made plenty of MacOSX, MorphOS and AmigaOne X1000 user smiling ear-to-ear.

Mike Blackburn Heltne - great work on improving the build script and Linux support! I always neglected the Linux support, I was too lazy to deal with it, but you picked it up. Also merging fixes from other UAE derivatives helped a lot. (And finally, I have written down your full name. :)

Chris Handley - thanks for all your help in testing and for maintaining RunInUAE, which brings the obscure art of E-UAE configuration closer to the average user.

kas1e, Luigi Burdo, Samir Hawamdeh, Thunder - thanks for all the beta testing results and useful comments you have sent to me. Without testing software is always buggy and I don't have the energy for running hundreds of apps under the emulation.

Fabien Coeurjoly (Fab) - thanks for MorphOS-related help and for your time you are investing into proper MorphOS builds. I am an AmigaOS4 fan, so what do I know about MorphOS... :)

And thanks to everybody who helped me directly or indirectly:
Allan Ullmann;
Andreas Loong;
Davide Palombo; Douglas McLaughlin;
Frank Wille;
Fredrik Wikstrom;
hostcove;
itix;
Massimiliano Tretene (Soft3);

Michael C. Battilana and Cloanto;
Noel Fuller;
Philippe Ferrucci;

Sebastian Bauer;
Sven Ottemann;
Timothy De Groote;
Tommysammy;
Troels Ersking and all the staff at AmigaBounty.net;
Zerohero.


I would like to thank the donations to all who supported the project on AmigaBounty.net.

Please visit the E-UAE JIT bounty page for the complete list.

I would like to mention the main donors here, just to commemorate their significant contribution:

William Morris and Robert Trevor Dickinson.

Thank you for supporting this project with your hard-earned money.


Am I missing something?

I have almost forgotten, here is the release... ;)


See you soon.

Monday, July 28, 2014

PPCJITBETA04b (Hundreds and XThousands)

There is something new each day, I haven't done this before: a Fast Follow to the previous beta release.

Let me sprinkle the life of the suffering Amiga X1000 owners, here is a


After I had done some investigation, it turned out that MickJT was right for a long time. We don't need unique changes for Amiga X1000 (for the P.A. Semi PA6T processor), because it is similar to the already supported G5 (PowerPC 970) processor.

So, I have decided that we must not delay the beta for Amiga X1000 any longer. This new build is exactly the same Beta #4 release feature-wise; which was done for the other platforms already. Except that it is compiled for AmigaOS4 with the same minor changes which increase the performance on G5 significantly.

Since the code base is the same I kept the same beta version tag with a postfix. For the first and the last time... Úttörő becsület szavamra! :)

Caveat emptor

This build is not fully optimized for PA6T processor, since there is no support for that processor target in the AmigaOS4 SDK yet. It is still running much better than the previous generic builds.
Hopefully the PA6T support will be resolved sooner or later in the SDK and then I will add any necessary changes to the E-UAE build too.

In the meanwhile the binary for this build target will be added to the upcoming releases.

Credz

Actually, the credit goes to the following good people:
  • Tobias Netzel - who implemented the G5 support and helped MickJT with advices;
  • MickJT - who was experimenting with the build for a long time already and pushed me to do this release;
  • Sven Ottemann & Sebastian Bauer - who helped me with the documentation for PA6T;
  • Tommysammy - who was kindly doing the testing.
Thanks guys!

Feedback

This was a blindfolded build again: I have no access to an Amiga X1000, so I couldn't test the build by myself.

I would like to invite all Amiga X1000 owner to give me some feedback regarding the performance or any issues what turns up with this special build.

You can find my email address at the end of the README file.

Sunday, July 20, 2014

PPCJITBETA04 (FourFOurfOurfoUR!)


Four is a nice, round number. Power of 2, not too many, not too less. You know, four is referring to many good things, like: the Fantastic Four, 4th of July, AmigaOS4, The Magnificent Four... Err.. Maybe not that, scratch that last one.

Therefore, without further ado, here is Beta #4:


I had an irresistible urge to RickRoll you guys with the link, but that video has been blocked recently on YouTube in many countries, so maybe next time.

Tickets please

I had my sweet time with a very weird bug related to Quake, which is not resolved yet and probably related to the failure to implement the soft cache flushing. These two tickets are pushed back to Beta #5 for now. Previously I had no intention to do one more beta release before the first Release Candidate, but as it seems I need one more round of testing period.

I had to shuffle around some tickets while I was rethinking the upcoming Release Candidate. You know, changing priorities, agile development, whatnot. What is listed in the milestones now is the plan, although it is not set in (mile)stone... Heheh... (Huh, that was a really lame pun. You should do better than that!)

The idea is: I am going to fix every issue which is known and give you guys some time to test before the final release (candidate).

SAM440

After a few rounds of pushing and pulling some SAM440/Flex related codes hopefully we have sorted out all the various problems related to those machines. If you were still experiencing issues then please let me know.

G5 again

Thanks to Tobias Netzel, the flag extraction on G5 is fixed, this will resolve a number of problems with various programs.

The compiling for G5 is still not resolved for MorphOS, no G5-optimized binary again, sorry guys. If you could tell me how can I (easily) compile the files for G5 on my iBook then I give it a go, I promise.

What's next

As you can see: Beta #5 is coming, there are already a handful things lined up for it.

Please do test Beta #4 and please do report bugs you have found. It is important to sort out as many problems as I could. It is equally important to help me reproducing the bug. So, please read the instructions. Thanks a bunch!

Best Boys

I would like to give a big thanks to Luigi Burdo. He helped me with a great deal of things, reported lots of bugs and he is so enthusiastic that he inspired me to keep walking on the road. Thanks a lot, Luigi! Keep up the good spirit!

And, of course, my dearest sidekicks, who just couldn't stay away from the project:
MickJT and Tobias Netzel. Cheers!

Also would like to thank the helps, bug reports and overall support to:
Samir Hawamdeh, Kicko, Chris Handley, Allan Ullmann.

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.

Monday, November 4, 2013

On a collision course

So, where are we at with the recent update? 349 out of 387: no, it is not 100% yet, but a nice, fat 90.1%!

Quickly, what was done this time and let's jump to conclusions right after that:
  • Implementation of BFINS Dx,Da{y,z}, BFFFO Dx{y,z},Da, BFEXTS Dx{y,z},Da, BFEXTU Dx{y,z},Da, BFCLR Dx{y,z}, BFTST Dx{y,z}, BFSET Dx{y,z}, BFCHG Dx{y,z}, ROXR.x Dy,Dz, ROXR.W mem, ROXR.x #imm,Dy, ROXL.x Dy,Dz, ROXL.W mem, ROXL.x #imm,Dy, ASR.W mem, ASL.W mem, LSR.W mem, LSL.W mem, ROR.W mem, ROL.W mem instructions.
  • Opcode compiler fucntions for different operation sizes are unified, unnecessary helper functions were removed.
  • Macroblock protos are generated from the opcode table file rather than used the manually prepared file.
  • Fixed wrong function name for the CNTLZW PowerPC instruction emitter.
  • Fixed missing input register in C and X flag extraction macroblock which is used in some shift instructions.
  • Fixed register dependency in ASR.x Dy,Dz and LSR.x Dy,Dz instructions.
(Slightly unrelated: I have found a bug in the original E-UAE code for BFINS and flags, if I will have enough patience I will fix that. And another one in Petunia, that will be fixed too...)

Now, we are getting dangerously close to the beta stage. It is really hard not to give you guys any promises what I cannot keep later on... (Summer is coming, you know... ;)

Anyway, my plans for the near future (read: when it is done) are:
  1. After I have finished with the implementation of all instructions which were anticipated earlier I am going to stabilize the emulator a bit and clean up the code if needed.
  2. I will try to release a compiled beta version and put together some documentation for using/testing it.
  3. There are some outstanding issues, one of the most critical one is fixing the problems with the macroblock optimizer.
So much for the crystal ball and now...

Something completely different

I have to admit that my posts were not that interesting to read recently. Earlier I invested more effort into the posts and it was probably more fun to read, especially to the developers.
I would like to bring back that tradition, so for this update I came up with a few interesting thoughts on:

How to avoid the decisions

I know that many developers love to procrastinate anything, including (but not limited to) decisions. But what I am about to write is not how lazy my fellow developers are, but rather how to get around a situation when it is not ideal to do a comparison and branch according to the result.

Why would that be important at all?
There are a number of reasons why it is better to avoid branching, this article lists many examples for that and also explains the reasons. It basically boils down to the following reasons:
In our case none of these reasons apply, but unfortunately branching is not really possible due to the static flow analysis on the macroblock list.

To put it simply: each macroblock is depending on the results of the previously executed macroblocks, if we skip ahead then it is impossible to tell whether those required macroblocks were executed or not before the dependent macroblocks.

Why does this cause any trouble? Because sometimes it is pretty hard to avoid conditions inside the instruction implementations.

I already faced this issue earlier, when I started to work on the conditional branching and setting instructions (Bcc and Scc). There was no possible way to avoid the conditional branching for these instructions due to its very nature of the instructions.
I ended up creating a very specific macroblock which embeds the condition checking and branching, so the "inter-macroblock" flow analysis remains intact.

In the recent update you can find many bit field instructions which were complicated enough already and then the very same issue came up again:

For bit field instructions 0 (zero) bit field width means 32 bit actually. This doesn't sound that bad, however sometimes the bit field width is coming from an emulated data register instead of a statically encoded constant. In this case the decision must be done in the emulated code instead of in compiling time.

Not in every case, but quite often it is possible to calculate the result instead of making a comparison and branching.

For the bit field instructions the solution was (written in C code, just because it is easier to understand):

temp = width - 1;
width = width | (temp & 32);

(There is one condition, though: the width must be between 0 (zero) and 31 before this operation starts.)

Now, think about it a little bit and figure out on your own why does it work. I am not going to explain it. :)

See you soon.

Wednesday, October 2, 2013

Back on track

Finally, I am back on track with the development after the house move. There were two updates since the last post; one was a follow-up to the previous code refactoring; the other was a massive list of improvements:
  • Implementation of NEGX.x mem, NEGX.x Dy, SUBX.x -(Ay),-(Az), ADDX.x -(Ay),-(Az),  MOVE CCR,mem, MOVE CCR,Dx, EOR #imm,CCR, OR #imm,CCR, AND #imm,CCR, RTR, MOVE mem,CCR, MOVE Dx,CCR, MOVE #imm,CCR, ASR.x Dy,Dz, RTD, MULU.W mem,Dx, MULU.W #imm,Dx, MULS.W mem,Dx, MULS.W #imm,Dx, SUBX.x Dy,Dz, ADDX.x Dy,Dz, MOVEM.x regs,mem, MOVEM.x mem,regs, MOVEM.x (Ay)+,regs, CMPM.x (Ax)+,(Ay)+ instructions.
  • Added dependency tracking for non-volatile PowerPC registers.
  • Fixed X flag handling in register-based shifting instructions, previously the X flag was cleared together with the C flag if the shift steps were zero.
  • Removed RTM from the list of the potentially supported opcodes.
  • Added RTR back to the list of the potentially supported opcodes.
  • Optimized temporary register usage in MULU.W Dx,Dy and MULS.W Dx,Dy instructions.
  • Introduced tracking of the extension words after the instructions, it is needed for adjusting the PC before certain addressing modes are processed.
  • Fixed register dependency and order of register storage for MOVEM.x regs,-(Ay) when direct memory access is enabled.
  • Implemented stack-like concept for register saving into the context.
  • Code cleanup: removed unused reference, fixed some warnings regarding misformatted and unused code lines.
So, things are getting together slowly. The number of the implemented instructions went up to 321 out of the planned 387! That is roughly 82%... Getting closer and closer... :)

Recently I faced an interesting problem, I am not quite sure how can I solve: division by zero. My beloved math teacher already told me: who is trying to divide by zero is an idiot. (Well, that is not quite right, as we know it.) Yet, some programs might try it.
Why is that a problem? Because it triggers an exception inside a compiled block. It also needs branching (skip the exception triggering if the divisor is not null, for a change) which contradicts the macroblock register flow tracking. Well, here is the challenge, but I am pretty sure I will solve it somehow.

'Til then the usual: watch this space.

Sunday, June 30, 2013

The Hot and the Cold

I just realized the last update was more than a month ago. Time flies, especially when we have fun, right? :)
Well, we had some fun at least: a short holiday in the (unusually) hot Hungarian summer. 38 degrees Celsius, it was almost unbearable for us after we got used to the cooler kiwi climate.
Then we came back to the (unusually) cold New Zealand Winter. 8 degrees Celsius, almost unbearable for us now. Hard to please, you might say. ;)

Anyway, back to business: since I was barely here this month the update is less impressive than the last time. Yet, I managed to implement some more missing instructions:
  • Implementation of ASL.x Dy,Dz, LSR.x Dy,Dz, LSL.x Dy,Dz, ROR.x Dy,Dz, ROL.x Dy,Dz, SUBA.x mem,Ay, SUB.x mem,Dy, SUBQ.x #imm,mem, SUB.x #imm,mem, SUB.x Dy,mem, SUBQ.x #imm,Ay, SUBQ.x #imm,Dy, SUB.x #imm,Dy instructions.
  • Removed not required TODO from ROL/ROR.x #imm, Dy instruction.
So, nothing much to see, move along.

Sunday, July 1, 2012

Lies, Damned Lies, Statistics and Benchmarks

Another nice batch of instructions implemented in the recent update. This is an important milestone: most of the instructions are JIT compiled now, that are used in the Mandelbrot test. Why is it important?

Because finally we can do some benchmarking!

Source: http://wumocomicstrip.com/2012/04/16

 

The update


So, the changes in this update are:
  • Implementation of
    ADD.x #imm,Dy,
    ADD.x regy,Dz,
    ADDA.x regy,Az,
    ADDI.x #immq,Dy,
    AND.x #imm,Dy,
    ANDI.x #immq,Dy,
    ASL.x #imm,Dy,
    ASR.x #imm,Dy,
    BTST.L #imm,Dx,
    CMP.x #imm,Dy/Ay,
    CMPA.W #imm,Ay,
    CMPI.x #immq,Dy,
    EOR.x #imm,Dy,
    EORI.x #immq,Dy,
    LSR.x #imm,Dy,
    MULS.W Dx,Dy,
    MULU.W Dx,Dy,
    ORI.x #immq,Dy,
    ROL.x #imm,Dy,
    SUB.x regy,Dz,
    TST.x reg instructions.
  • Fixed OR.x reg,reg flag dependency.
  • Recycling of mapped temporary registers is implemented.
  • Added the possibility of inverting C flag after extracting.
  • CMP.L #imm,Ax and CMP.W #imm,Ax were removed from the table, there are no such instructions.

Phew, that was a nice long list.

Recycling of the temporary registers

While I was running amok on implementing the selected instructions for the Mandelbrot test, I had to face the inevitable: the shortage of the temporary registers. When I implemented the register allocation subsystem I tried to postpone the fix for this problem, but since a lot more instructions are implemented the consistent translated chunks are getting longer. Suddenly, I got the error message that I wrote a couple months ago:

“Error: JIT compiler ran out of free temporary registers”

Probably this error needs some explanation. Let’s start with how the registers are handled in the JIT engine:

In Petunia the emulated 68k registers are statically mapped to PowerPC registers. This approach has its benefits, like constructing the code that handles the emulated registers is much more easy. But also has some major issues, especially because all registers must be up-to-date at anytime. Whenever the execution is leaving the compiled code all registers must be saved and restored to the previous state. Needless to say how long that takes: more than 20 registers must be saved.

In E-UAE this would be a no-go. The compiled code consists of smaller contiguous chunks and the support functions from the environment must be called quite often. The rest of the emulator was written in C and it expects a certain state of the registers at a time (which is described in details in the PowerPC SysV ABI document).

How to overcome of these issues? First, I realized that there is no point in keeping all the contents of the emulated registers in real registers all the time. The usage of certain emulated registers are localized in a certain range of the code that consists of closely tied instructions mostly.

Then I figured out from the SysV ABI that I can safely use a range of registers that needs no saving/restoring and also I can make use of the non-volatile registers that must be restored, because other called functions must restore that too.

I ended up implementing a dynamically allocated register serving system that can handle the needs of the compiling.

There are two types of registers: the temporary registers that are used in one instruction only for a specific role and the mapped 68k registers that are loaded once and kept until the registers must be released because the execution leaves the compiled code.

Back to the error message: eventually the free registers are running out because the compiler keeps the mapped 68k registers between instructions. I had to figure out some solution for enforcing releasing a previously mapped register when there are no more free registers left. Also, I had to make sure that I wouldn’t release the register that was allocated just recently and needed for the actual instruction compiling (or for the following instructions that might depend on the same 68k register).

This issue was resolved by some simple locking mechanism for the mapped registers: when a register is mapped then in the same time it is locked for the actual instruction. At the end of an instruction all mapped 68k registers are unlocked but not released.
On enforced releasing of the registers I look for an unlocked mapped register and release it.
But I start searching for the next unlocked register in a round-robin manner, to make sure I won’t release-allocate-release the same register all the time.

This system looks robust enough to handle the needs of the compiling.

Back to the lies… errr… benchmarks

As I already mentioned: in the implementation I reached the point when almost all instructions are implemented that are needed by the Mandelbrot test. So let’s see how the compiled code performs.

The test system consists of a Micro AmigaOne (G3/800 MHz), a slightly outdated AmigaOS4 version and my beloved Galaxy S2 who acts as a stopwatch. (Yes, I measure the time by using stopwatch. I didn’t want to spend too much effort on figuring out how to measure the time more precisely.)

Running the Mandelbrot test, I got the following results:
 
Interpretive: ~6 seconds,
JIT compiled: ~3 seconds.


Not too precise, but as it seems the JIT compiler is doing nice, the compiled code finished twice as fast as the interpretive.

To confirm the results I created a new version of the Mandelbrot test that needs lot more processor power to complete. You can find it among the test kickstarts, it is called: mandel_though_hw.kick. The code is essentially the same as the previous Mandelbrot test, but I tweaked the parameters a bit: zoomed in and adjusted the drop out threshold, so the picture is more detailed.

Honey! The Mandelbrot is almost done in the oven!
The results are:

Interpretive: 108 seconds,
JIT compiled: 52 seconds.


Yay! It is indeed twice as fast! Rejoice!

Disclaimer

Why we must not jump to any conclusions just yet regarding the speed...

First of all, not all instructions are implemented yet. This most likely means more speed increase, because the JIT instructions are always faster or at least as fast as the interpretive implementation. When the emulation hits an not implemented instruction then it has to call the interpretive implementation, which means essentially storing all the emulated registers in the memory and restart the register mapping.

Also, the register flow optimization is not implemented yet, that will be certainly a big boost on the speed, it will eliminate lots of instructions from the compiled code.

On the other hand, this test relies more on the rather simple, mostly processing-demanding instructions. When the test code is doing much more memory accessing then the difference between the interpretive and the JIT compiled will be almost certainly much smaller.

Anyway, I hope I assured all of you that we are heading to the right direction.

Full speed ahead! (Don’t mind the mines.)

Sunday, February 26, 2012

Test Kickstarts are kickin'

Finally, I managed to publish the fully working build environment for creating Kickstart files, you can find it in the project's SourceForge Subversion repository.

If you are looking for the binaries for these tests then check out the downloads.

Please make sure that if you would like to fool around with these files then you read the post about them here and the README files in the folders.

Some more tests are coming as soon as I have time to clean up the sources.

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, October 2, 2011

Let It Rip

I had spent lot of time on understanding and reshaping the x86 JIT compiling, and fit the PPC code emitter into it. No, no and no. The source code is so deeply convoluted, riddled with residue from debugging, useless functions and scary/cryptic workarounds that I had to give it up.
So, I finally decided: I will rip the x86 part out of the recent E-UAE sources. The PPC code emitter will come as a brand new part, won't depend on the x86 counterpart.

PS. I would like to thank Douglas McLaughlin for the Synergy client for OS4. Great work, it helps much.

Sunday, September 11, 2011

The Big X on the Map

Just a very quick update: things are slowly evolving, so DON'T PANIC.

Some more words about what has happened recently: I had some trouble with my Amiga, turned out as a PSU problem. Luckily it is already fixed with a "new" case for the poor girl.

I am fighting with the rather chaotic E-UAE sources, so I made a few steps to make it easier to edit the whole project: I managed to put together a cross-compiling environment from Windows. *booo-booo*
Compiling is much faster on the muscle x86 processor (*booo-booo*) and there are some advanced tools to do some heavy lifting when it comes to source code editing. I must also admit that since I use source version control at work, I barely can go on without it.

With the help of Cygwin, Eclipse CDT, TortoiseSVN, VisualSVN Server, FileZilla Server and a simple script on the Amiga side I was able to assemble a semi-automatic build and test deployment environment.

Thanks to Zerohero for the detailed cross-compiling setup description.

Friday, July 1, 2011

...beep...

Sorry for being silent for long time, at the moment I am struggling with my personal life, but will be back shortly. (I had to find a new place and move in, wasn't that simple actually, but finally we are over it. All I need now is a desk to put my computers on it...)

In the meantime I had stolen a few hours to dig deep into the E-UAE JIT implementation. As it seems I can reuse the already implemented bits and pieces. The "only" part that needs to be implemented is the actual PowerPC code translator.

So, stay tuned. (Or you can lay back, if you prefer.)

Sunday, March 27, 2011

Rainy Day with Copper-rendered Rainbows

The sky is cloudy, sometimes sudden showers are soaking the insanely green grass and I am forced into the shabby unit we rented half a year ago. Time to move - popping into my mind quite often these days, but that is a completely different matter.
There are only a few things distracting me from working on E-UAE, I tried to concentrate working on it with a great strength. (Apage Satanas: Facebook! I clearly miss the times when I was developing Flamingo. I was sitting in my curtained flat all day, no internet, no phone, no tv: the best environment for creating your own little pet creature and take over the world, MUHAHAH...)

I was trying to compile E-UAE since my last post, but I am clearly not really fond of the multi-platform environment. Configure script is a bad dog: never behaves. (Linux developers must have an insane amount of time and patience.)
Finally, after running into the never-ending circle of deleting all, copy back, adjusting, configuring and do the make for the hundredth time: I was able to compile E-UAE sources, and the binary is even working. YAY! \o/

I am happy that I can start on tinkering with the JIT implementation, but I have to admit that my Amiga developer skills became a bit rusty in the last three years, since I hardly had time to spend on development.
I fought big time with the path of include files, still getting flooded with complaints about missing prototypes for the AOS functions, but at least that is only a warning. (Not that I can live with compile-time warnings for my code, but I really don't have enough strength to find what minor thing needs fine tuning in the compiling to get rid of these warnings safely.)
It took me an hour today to find out that TimeDelay function is part of the (obsolete) libamiga and this is why the linking failed every time. There was an easy fix for that: just remove the check for AOS4 from the sources and let it fall back to the DOS/Delay() function. Not a proper solution, because Delay() is badly inaccurate, but at least I was able to compile and fire it up.

The compiling on the uA1 is awesomely slow and eating up all the memory, so I had to turn on the swapping. I seriously considering the cross-compiling from my windows laptop, and let the A1 do the testing functionality only. It was a very long time since I tried cross-compiling for the OS kernel, back in the days when it was impossible to compile it on AOS4. It was painful, I had to use Cygwin and a number of tricks to get it working. Then copied the compiled binary to my Amiga 4000 on a floppy disk for testing... *Sigh* I was soo patient, I am amazed now. ;)
Speaking of which: I still need net connection for the uA1, that would be essential for the cross-compiling.

Anyway, let's go back to experimenting. The first test will be implementing a very-very simple form of the poor-man's JIT, which will do nothing more than "compiling" the executed code into series of calls to the interpretive instruction implementation functions. The outcome will be an environment, where I still have all the already implemented instructions, but I can replace them one-by-one with the real JIT instructions. Something what I needed when developed Petunia, but there was no interpretive emulator to back up the missing instructions.

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… :)