tl;dr: Infinite Mac can now run early Mac OS X, with 10.1 and 10.3 being the best supported versions. It’s not particularly snappy, but as someone who lived through that period, I can tell you that it wasn’t much better on real hardware. Infinite HD has also been rebuilt to have some notable indie software from that era.
Porting PearPC
I’ve been tracking DingusPPC progress since my initial port and making the occasional contribution myself, with the hope of using it to run Mac OS X in Infinite Mac. While it has continued to improve, I reached a plateau last summer; my attempts would result in either kernel panics or graphical corruption. I tried to reduce the problem a bit via a deterministic execution mode, but it wasn’t really clear where to go next. I decided to take a break from this emulator and explore alternate paths of getting Mac OS X to run.
PearPC was the obvious choice – it was created with the express purpose of emulating Mac OS X on x86 Windows and Linux machines in the early 2000s. By all accounts, it did this successfully for a few years, until interest waned after the Intel switch. I had earlier dismissed it as a “dead” codebase, but I decided that the satisfaction of getting something working compensated for dealing with legacy C++ (complete with its own string class, sprintf implementation, and GIF decoder). An encouraging discovery was that kanjitalk755 (the de-facto Basilisk II and SheepShaver maintainer) had somewhat recently set up an experimental branch of PearPC that built and ran on modern macOS. I was able to replicate their work without too much trouble, and with that existence proof I started on my sixth port of an emulator to WebAssembly/Emscripten and the Infinite Mac runtime.
In some ways PearPC not being actively developed made things easier – I didn’t have to worry about merging in changes from upstream, or agonize over how to structure my modifications to make them easier to contribute back. It was also helpful that PearPC was already a multi-platform codebase and thus had the right layers of abstraction to make adding another target pretty easy. As a bonus, it didn’t make pervasive use of threads or other harder-to-port concepts. Over the course of a few days, I was able to get it to build, output video, load disk images, and get mouse and keyboard input hooked up. It was pretty satisfying to have Mac OS X 10.2 running in a browser more reliably than it previously had.
Performance
While PearPC ran 10.2 more reliably, it felt slower than DingusPCC. I had spent some time last year making some optimizations to the latter, partly inspired by the TinyPPC emulator in this SheepShaver fork (aren’t all these names fun?). I ported DingusPPC’s benchmark harness and then set about replicating the performance work in PearPC (both emulators are pure interpreters driven by a lookup table, so the process was relatively straightforward). I was able to shave off about 15 seconds from the 10.2 boot time – it helps from a saving lives perspective, but is still not enough given that it takes almost 2 minutes to be fully operational. In the end, I copped out and added a UI disclaimer that Mac OS X can be slow to boot. I also got flashbacks to the “is it snappy yet?” discussions from the early days of Mac OS X – it was indeed slow, but not this slow.
Performance is still not as good as DingusPPC’s – the biggest bottleneck is the lack of any kind of caching in the MMU, so all loads and stores are expensive since they involve complex address computations. DingusPPC has a much more mature tiered cache that appears to be quite effective. More generally, while PearPC may be more stable than DingusPPC at running 10.2-10.4, it’s a much less principled codebase (I came across many mystery commits) and it “cheats” in many ways (it has a custom firmware and video driver, and only the subset of PowerPC instructions that are needed for Mac OS X are implemented). I’m still holding out hope for DingusPPC to be the fast, stable, and correct choice for the long term.
A Side Quest
I implemented the “unified decoding table” approach in PearPC’s interpreter one opcode family at a time. When I got to the floating point operations, I assumed it was going to be another mechanical change. I was instead surprised to see that behavior regressed – I got some rendering glitches in the Dock, and the Finder windows would not open at all. After some debugging, I noticed that the dispatching for opcode groups 59 and 63 didn’t just do a basic lookup on the relevant instruction bits. It first checked the FP bit of the Machine State Register (MSR), and if it was not set it would throw a “floating point unavailable” exception.
... continue reading