Friday 28 November 2008

Running on Mac OS X

As I had a bit of time to kill this morning I thought I'd try running the speed test on my MacBook Pro.

At the moment I'm doing all of the development on my Windows XP box as that is my main machine at home and has a lovely 24" monitor attached to it. My Mac is my portable work machine and until I can afford a Mac Pro for home I have to use both XP and OS X.

Bear in mind that at the moment there are no "external" interrupts on the CPU as it's only executing the ROM code. There is no display, sound or DMA functionality at work here either, just the CPU reading and writing to memory and executing code.
Also bear in mind that this hasn't been optimised at all, other than removing the logging from the memory access code.

My Windows box is home built with an Intel Core 2 Quad @ 2.4Ghz and 3.5Gb RAM. It's running XP Pro SP3 and I'm using Java version 1.6.0_07 32-bit Client VM.

My Macbook is an Intel Core 2 Duo @ 2.5Ghz with 4Gb RAM. It's running OS X 10.5.5 with Java version 1.6.0_07 64-bit Server VM.

The Mac is running Miggy at a rather pleasing 85Mhz !

So, I think I'll carry on with the development for now and leave optimising until later as I think there's enough headroom there to emulate the other components. Time will tell.

Thursday 27 November 2008

Well that was quick!

I'm a little bit gob-smacked. I executed a preliminary profiler run against Miggy and noticed a lot of time was spent building Strings. I thought that was strange as I wasn't running the built-in debugger and so shouldn't be generating a lot of Strings.

And then the penny dropped. Despite turning off logging (I'm using the java.util.logging package), in each of the MemoryControllers I am building a String to pass to the Logger. What's more I'm doing this *every* time I access memory.

I thought I'd try commenting out the these calls in each of the memory access methods and ran my benchmarks again....

How about now averaging at 64.6Mhz. Even when running the profiler (hprof) it was still pulling 58.5Mhz averages.

Now that's changed my mood somewhat :D

First Speed Test

I was starting to get into writing some display code and the DMA controller when I realised I hadn't actually benchmarked the system as yet. So I thought now would be a good time to get an idea of the raw speed of the CPU and see whether there was any chance of this thing being fast enough.

I did the simple thing and wrapped the execution loop in calls to System.currentTimeMillis() counting the number of emulated CPU cycles performed each second. I'm running it against the Kickstart 1.3 ROM code as I know this just continually loops after executing several thousand instructions so gives it a bit of a chance to stretch it's legs.

To be honest, I was a bit disappointed with the result. I'm collecting the average over ten seconds and the system is running around 10.4Mhz over this period. I don't think this is going to be fast enough given all the custom chip, display and sound emulation that still needs to be added.

Now might be a rather good time to profile what I've got and optimise it before starting on the additional hardware emulation.

Monday 24 November 2008

Guru Meditation #00000008.00001968

I've spent a fair bit of time recently cleaning things up and simplifying a couple of the interfaces. The MemoryController I discussed in the last post has been cut down quite considerably and I have direct "debug" access to memory now too.

If you imagine a 68000 CPU wired to some RAM and an Amiga 1.3 Kickstart ROM, then that's about the current state of play with Miggy.

If I let the system "boot", my CPU code no longer ends up wandering randomly through memory after a few thousand cycles, which I take as a major positive. In fact what now happens is that the ROM code detects something is wrong and spits out a Guru Meditation and resets the machine. Pretty cool I think. I had a huge grin as I watched it stitch together the Guru message as I stepped through with the debugger. Shame there is no display code yet to show me the flashing red message.

For those that don't know, a Guru Meditation was the Amiga equivalent of a Windows Blue Screen of Death or a *nix kernel panic and usually resulted in a reboot.

Next on the agenda is to try and work out if the Guru Meditation is caused by a CPU emulation bug or the fact that the rest of the system isn't there, and something I don't yet know about isn't setting something in memory properly.

I suspect a combination of both.

Oh and have a gold star if you knew that the Guru Meditation in the title represents a Privilege Violation exception ;)

Thursday 20 November 2008

It's Refactor Time !

Well the debugger seems to be working great but I've become less happy about the structure of the code especially after strapping the GUI onto the emulation core and realising a short coming in the memory controller code. So, I'm taking stock and having a bit of a refactor before the project grows much larger.

What I'd missed in the memory controllers was the ability to bypass any side effects of reading or writing to a particular location. There are several places where custom chips react to a read or a write, and if I want to present the contents of memory through a debugger I have to be able to make these memory accesses transparent.

At the moment I manage memory by mapping the Amiga's memory to a simple array with 256 elements. I assign a specific "controller" instance to each "area" of memory. Using this method I can have separate classes that handle chip memory, CIA controllers, the custom chip set registers, reserved memory areas, ROM and so on. Each of the controllers implements a MemoryController interface that looks like this:


public interface MemoryController
{
void reset();
byte peekByte(int address);
short peekWord(int address);
int peekLong(int address);
void pokeByte(int address, byte value);
void pokeWord(int address, short value);
void pokeLong(int address, int value);
int peek(int address, DataSize size);
void poke(int address, int value, DataSize size);
}


As you can see though there is nothing that will let me access the memory in a transparent manner. I may need to add a few more methods such as debugPeekByte(...) or something similar to give me that functionality.

Memory accesses are handled by masking and shifting the requested address to give me an index into the memory map array and retrieving the appropriate controller. The request is then handed off to the controller to manage. This is all marshalled and encapsulated by a MemoryManager class which itself also implements the MemoryController interface. It's quite neat and is much nicer than a big switch statement or massive if/else if/else construct and no doubt a bit speedier too.

I'm also thinking I'm going to change my (not quite completed) breakpoint handling method with something simpler. At the moment I inject a special opcode at the address of the breakpoint and store the address in a map with the original opcode I replaced. The special Breakpoint instruction passes control to the CPU when invoked and also looks up the original code if disassembly is required. It's a bit ugly in it's implementation though and involves calling back and forth into several classes to determine the outcome, and of course it modifies code in memory. I think that it's waiting to bite me in the arse at a later point.

I think a better solution would be to handle the whole instruction execution cycle from a different method if we're running the debugger. This method could compare the current address to a list of breakpoints and handle them higher up the stack as it were. The overhead of doing this would only be while we were debugging. The "normal" execution loop wouldn't have the breakpoint checks in it.

Lots to do!

Monday 17 November 2008

Debugger Alpha

I thought I just make a quick post to show the GUI debugger I've been working on the last week or so. It's incomplete but working well enough to put a grin on my face while stepping through code.

A quick screenshot:



The disassembly syncs nicely with the Program Counter as you step through and registers are all editable in place too.
Still to do are breakpoints and the memory views alongside the registers.
Bananas all round to those who noticed that I've borrowed the layout from Devpac's MonAm debugger ;)

Friday 14 November 2008

Swings and Roundabouts

I've spent the last week trying to get a GUI interactive debugger together for Miggy and have ended up bouncing all over the place.

The big pain is trying to fit the disassembly output into a list of some description so that a user can view the code, interactively step through it and set breakpoints etc. Out of the box the JTable and JList are not going to do it for me without some serious hacking about I think.

These list type controls are backed by a model class that supplies the actual data and information such as the number of available entries to the list. This in turn controls the scrollbar range and response once the list is embedded in a JScrollPane.

My issue is that without disassembling the whole of the available emulator memory I won't know how many entries will be available for the list. Each instruction can be comprised of as little as 2 bytes or upwards of 8.

What I want to do is only disassemble enough rows to fill the visible area of the list and control the scrolling so that I can effectively create a sliding window view over the emulator's memory. Perhaps the best route would be to either have a separate JScrollBar which I use to update the sliding window, or provide my own "up and down" buttons to control the view.

Actually that sounds like a plan, I can control the number of rows in the list so that they equal the number visible rows on display, and use input from a separate scrollbar or other control to change the sliding view of memory.

Blimey, writing this entry has actually helped clear this up a lot in my mind. A bit like when you explain a problem to a colleague only to realise the solution mid-explanation. If only I'd done this a couple of days ago ;)

Thursday 6 November 2008

Hack n Slash

I'm still plodding on with writing the unit tests.  The end is in sight as I've nearly finished the instructions and I think I should be able to output tests a bit quicker when I haven't got to keep calculating opcodes by hand.

Unfortunately, last week I went an bought a copy of Fable II.  What a time sink that has been, and I would've finished the tests by now if it wasn't for that.  Cracking good game though.

Once the tests are complete the next step is to write a monitor/debugger application to wrap the CPU up in.  I want to be able to step through the emulated code and set breakpoints etc.  This will no doubt involve quite a bit of effort but is going to be crucial in keeping me sane as this project progresses.  Once I'm happy that I can accurately emulate the CPU and monitor the code running on it, I can start thinking about turning it into an Amiga.

Of course, I'm making a big assumption that the performance of my code is going to be adequate for the job, but that's a whole new kettle of fish that we'll have to wait for.  I'm just concentrating on developing a clean and robust model for now.