On and off during the last month or so, I’ve worked toward finishing a project I wrote about last year. It’s an Amstrad CPC Emulator, written in C# using the Microsoft XNA library. I’ve written plenty about the background and motivation in the previous blog post. This post is just here to announce the finished product, and touch a little on the things I’ve worked on recently.
The picture above is from Hewson’s “Nebulus”. Now that the emulator has a pretty complete feature set; games like these are very playable now. It makes a world of difference having the audio fully working now, for example. It also is great to finally be able to play at the original, full frame rate on Xbox 360. Surprisingly the 360 had trouble emulating this seemingly primitive machine!
Anyway, after the jump is a video showing the emulator in action on the 360…
XNACPC In Action
Here you go! This video shows a number of games running on the emulator. It’s taken with a point-and-shoot camera, in a poorly lit room. So the quality isn’t too great, unfortunately. Some games have pretty washed out colors and bad contrast; some look fine though.
I guess I could have captured it from my PC, but the whole point of the emulator was to get it running on the Xbox 360. The fun part is showing it off on the real thing. 🙂
CRTC – Good Timing and Accurate Video
My first pass at XNACPC last year, used the same technique which I employed when I wrote my CPC emulator back in the 90’s. I used a pretty naive approach, that had surprisingly good results for the early crop of launch games for the CPC.
I fudged the interrupts simply so that they occurred at 300Hz, which they’d be at on a real CPC. I wasn’t emulating the HSYNC correctly, nor the counters which are based off the HSYNC and generate interrupts. I also had to fudge the VSYNC signal which is read from one of the PPI ports. Whilst it was a primitive approach, it worked pretty well. Even ‘Sorcery’; a split-screen game, looked and played like the original.
Fixing the CRTC to behave properly was at the top of my list. I was pleased that I managed it. The best reference I found for it was probably here:
So I threw away my old video implementation and did it the proper way. Many games which previously didn’t work, now played just fine. I also used to draw the entire screen at the end of the frame. When I switched to drawing it line-by-line after each HSYNC, it eliminated flickering artifacts in many games. “Monty on the Run” for instance, looked awful in many places when I was updating the whole screen at once.
“Monty On The Run” – Fullscreen vs. Line-by-line
Audio – Silence Isn’t Golden
I actually traded off the audio work with the CRTC work. I’d switch between them when I hit a wall, to keep things interesting. When I first worked on the emulator last year it actually wasn’t possible to implement emulated audio at all. That only became possible when XNA 4.0 was released, with the addition of DynamicSoundEffectInstance.
The audio on a CPC is pretty simple in it’s concept, but it did take me a little while to get the timing correct. It’s essentially based on square waves, where the audio signal is either on or off. The signal does have volume control, so it’s possible to produce pretty decent sounding music with it.
AY8912 Audio Square Waves
There’s three main parts to the AY audio chip used in the CPC:
- Three channels of tone generators. Producing square waves at given independent periods.
- A single noise generator. It generates random noise, which can be used by any combination of channels instead of the tone generator output.
- A single envelope generator. This allows any combination of channels to progressively change the volume over time, in a manner that doesn’t need any CPU assistance.
Of the three channels; two of them represent the left and right speakers, and the other one is mixed between each speaker.
That’s the gist of it. The audio was pretty satisfying to implement; since I’d never tried to get it working, back in the emulator I developed in the 90’s. Unfortunately the addition of the audio was taxing enough for the Xbox to drop under the 50fps that a CPC runs at. This meant I had to refactor the audio code somewhat, from a nice C#-style to a more brute-force C-style.
Z80, PPI and Other Hardware Bugs
There was a fun little period after I had the CRTC emulation all working correctly. With the last big hurdle overcome, I now had to fix bugs in my hardware implementation. This was the period where suddenly lots of other dead non-working games would spring to life.
Coming back to the source code after over a year was fine for the most part, but I did forget about a number of functions which I stubbed out. The PPI was a big one, I just did the basics to get the most primitive games running. So there I had to go back to the hardware documents and fill in the more obscure parts of the implementation. After doing that, a bunch more games would run.
One other key fix I remember was to the Z80 emulation. The HALT instruction was broken. I took the Z80 CPU emulator originally from an older C# Spectrum emulator. I’d made a number of modifications to get it to play nice with the CPC; mostly around timing and interrupts. When I noticed a couple of games dying on the HALT instruction, I went back to the Z80 documentation and implemented HALT correctly. As well as getting some games to run, it also amusingly fixed the broken ‘pelvic thrust’ animation in the intro to ‘Rocky Horror Picture Show’. 🙂
“The Rocky Horror Picture Show” – Intro
CRT Shader – A Bit of Polish
Once I finally had the majority of the games looking pretty much perfect, I had an inkling to go a little further. I’m not much of a graphics programmer, by today’s standards. I used to be really into graphics programming back in the mid to late 90’s. Michael Abrash’s “Zen of Graphics Programming” was one of my favorite books. I also remember fondly working through the ‘Asphixia VGA Trainers’. It’s about the last time I think I wrote more than just a handful of lines of assembly code at once. 🙂
It’d been a few years since I last experimented with shaders, so I decided to try writing a simple shader to give the emulator a ‘CRT effect’. I only spent a small amount of time on it; it’s nothing fancy. The gist of my effect works as follows:
- Each CPC pixel is exactly three ‘XNA pixels’ high. My shader uses modf() to modolo based on this, so I can do something different for each of the three rows of pixels.
- Row One: I leave the color alone. Sample goes straight through.
- Row Two: 90% of the color I take from original sampled value. 5% I actually sample from the next CPC pixel scanline. Then, 5% left out to make it darker.
- Row Three: 75% of the color I take from original sampled value. 15% I sample from the next scanline. Then, 10% left out to make it darker.
Sampling a little of the next scanline down, introduces a little color bleeding; which seems to work well. It’s pretty decent-looking considering how simple my shader was. Here’s a zoomed picture, below. It looks it’s best though at 1:1 resolution, as you can see from the “Nebulus” shot at the very top of this blog post.
“Ikari Warriors” – 2x Zoomed Shot of my CRT Shader Effect
Xbox 360 – Compact Framework Creaking Under Pressure
Getting the emulator running at the full frame rate of the original CPC, wasn’t much fun. On PC it was fine, no problems there. I think Task Manager shows ~2% CPU usage on my PC when it’s running. When I turned the frame-rate limiting off, I think it ran at >300fps. I’m talking specifically here about emulation of the CPC, not just drawing and updating the screen. So when I run it with the frame-limiter off, the machine runs so fast that any game is essentially unplayable.
Now, the Xbox 360. Some of you with experience with C# and the 360, will likely think I’ll mention garbage collection? Actually this wasn’t an issue for me. For any emulation runtime code, I made sure I wasn’t doing anything bad there. I generate absolutely no garbage when the game runs. I do allow for garbage in my “Pause Menu” code, however. But that’s really nice and easy to handle, just perform a full collection when unpausing. I like that approach for being able to write quick-and-dirty UI code, and keep the actual game clean.
So, not garbage? Nah, it’s just a raw CPU throughput problem. I hear someone shouting “JIT”…? Indeed; it does help a lot. The version of the emulator I’ve uploaded today runs at about half the speed of a CPC, when I have the debugger attached to the Xbox. So yeah: Release Build. No debugger attached. No garbage collection. This is as good as it gets.
I did a few things to drag the emulator kicking and screaming, to meet the 50fps that the CPC runs at:
- General optimizations which seem to benefit 360: Lookup tables seem to win over a handful of computational instructions. A general mistrust of the optimizer/JIT works well too. Cache variables yourself when doing multiple lookups from other classes, for example.
- Changed the routine which writes screen memory out to the XNA texture, to use unsafe code.
- Refactored my audio code to have the tone, noise and envelope generators as structs instead of classes (no vcalls). Ripped out my nice methods and just let my audio code access public members instead.
- The biggest win by far was hand-unrolling a simple for loop. It was an inner loop inside my graphics rendering code. It was walking over eight pixels for each byte of CPC memory. Instead of looping, I copy and pasted the line over eight times. My frame rate jumped from ~40fps to ~50fps.
Anyway. This was a bit of an eye-opener. I’m used to writing native code on 360, and I’m sure the thing wouldn’t break a sweat with a C++ version of my emulator. It’s odd to think that when I first worked on my emulator back in 1998, in C++; it was on a Pentium 120. That P120 ran the emulation fine, taxing the CPU at around 50% if I recall. Compare that to the ~95% I’m shipping XNACPC on the Xbox with. 🙂
So, the Compact Framework on 360 isn’t too hot. To be honest though, I’d have no qualms with developing something like this in C# if I was targeting PC. The full .NET Framework seems to be a good performer. Of course, straight-game code is going to be a whole different kettle of fish; compared to something as ridiculous as I’ve coded here. I don’t mean to slag off the Compact Framework; I’d imagine other XNA devs don’t see the huge disparity that I did, when they’re coding their games.
In an ideal world I’d be able to release it on the XBLIG channel. But given both copyright (and moral) issues with distributing games that other people have worked on, it’s not a possibility. This is a shame for people interested in playing with it though, since it means your only option requires a ‘Creators Club’ subscription. This costs $99 a year!
That said, I’d likely expect the few of you that actually read this blog (and the fewer that read this far down!) might be XNA coders. I’ve a zip file setup which contains the solution and project files, with the emulator ready to deploy to your Xbox. You can download it here:
If you just want to browse the code online, I’ve put it up here at Google Code too:
If you’re interested in taking XNACPC and releasing something (legal and authorized) on XBL Indie Games, or Windows Phone 7. Please contact me about it, I’d love to work on the project!
The PC version is playable without any sort of coding experience, nor requiring paying any money to Microsoft. You can download it here:
Just unzip it somewhere, and run ‘XNACPC.exe’. That’s it. There’s a number of games in the package, all setup ready to play. You may also need to download the XNA Runtime, if the app complains about missing something when you run it.
Well, I really don’t plan to do any more work on XNACPC. There’s plenty of other CPC emulators which are more complete. They emulate more features, and run pretty much any game you can throw at them. The intention wasn’t to compete with those emulators, it was just to prove it’s possible to do the same in C# with XNA. I think I’ve done that, so there’s no real motivation to continue with the project.
It’s been fun; but I’ve been tinkering with CPC emulators in various forms since 1998. Right now I’m happy to close the door on this, and keep working on ‘new’ stuff instead of having one eye on the past. 🙂
Hope you enjoy poking around the source code!