The OS also includes the zRAM memory compression tool which makes it run faster on older machines. There's also a special ‘Lite Upgrade’ utility. Despite its name, this distro isn't the least. Make sure you downloaded the Mac OS version of the game! (Some people have downloaded the Windows dev-build version by accident) It should be a.zip file called 'BBE0.2.1Mac.zip' which you need to extract. Inside the extracted folder is the BBE app it should be as simple as running it at that point. Let me know if you have any issues!
Game Overview: Songbird Symphony
A heart-warming journey of discovery, as orphaned chick ‘Birb’ sets off to find his true origins. Follow this cheerful little bouncing bird who revels in singing, and guide him through this magical journey of stunning pixel art and gorgeous animation that shapes itself to your musical interactions! Chirp to activate platforms, and sing to the residents of the forest, learning new notes to aid you in captivating rhythm battles against the creatures of this sprawling, enchanting world.
In this journey of self-discovery, Birb will come across dozens of cheery denizens with joyful and bubbly animations. Fly your way across areas rendered in beautiful pixel graphics as you learn more about the tales of the forest. Come to the aid of the creatures of the forest to find hidden musical notes scattered across the levels. Your good deeds will release extra layers of beats that will blend harmoniously with the soundtrack, bringing further the atmosphere of the world to life. Learn new notes as you engage in catchy musical segments that will challenge your rhythmic skills. Join the choir and press notes in synchronization with the music to sing along! Lead Birb across interconnected levels bursting with life and hidden areas to uncover. Pick up feathers along your way and find their owner to discover myriad of secrets and the lore of this magical world. ScreenshotsMinimum system requirements
Windows
Mac OS
© 2018 JoySteak Studios. All rights reserved. Published by PQube Ltd.
It’s April 1, and that means it’s both April Fools’ Day and the anniversary of the founding of Apple Inc. While this year is a sober one due to current events, I think a lot of people still appreciate what people are creating and sharing to keep spirits up, whether that be music or art or…impractical programming projects. And while pranks on April Fools’ seem less and less fun1, obvious jokes and whimsy, not at anyone’s expense, are still something I believe in…and even better if they actually work.
Last year I implemented the world’s best code visualizer. This year I decided to seriously attempt something that I’d thought about in the past: getting a Swift program to run on Mac OS 9.
What’s a Mac OS 9?
Twenty (!) years ago, before the macOS2 we know today, there was another operating system known as “Mac OS”.3 It was one of the first OSs to use a GUI at all, something that we pretty much take for granted these days. It also dates from the days when only one program could run at a time; because of that, even the latest version uses cooperative multitasking to run multiple programs—that is, a program has to yield its time to let others run.4 If a program crashed or overwrote memory it wasn’t supposed to, there was a good chance you’d have to restart the whole system.
Mac OS 9 ran on PowerPC processors, which were also used in the GameCube, PS3, and Xbox 360; earlier versions of the OS had started on Motorola’s 68k CPU series. Its successor Mac OS X5 also ran on PowerPC when it first launched; it wasn’t until 10.4 that Apple began to switch to Intel processors instead, and 10.6 when PowerPC was finally dropped.
Mac OS X was a huge step forward from Mac OS 9 in a number of ways, including preemptive multitasking so that you could actually run multiple things at once. But Apple didn’t want to just leave OS 9 programs behind, so they did two things:
Classic ended with the switch to Intel processors back in the 2000s, but Carbon worked all the way up to last year, macOS Mojave. Apple never released a 64-bit version of Carbon, presumably to encourage developers to move to Cocoa, and with last year’s macOS Catalina, support for 32-bit apps was dropped
What’s the goal?
Since I learned to program on Classic Mac OS, and years later spent a good chunk of my career working on Swift, I’ve had the tantalizing thought that I’d like to write a program in Swift and run it on Mac OS 9. That is,
Is this useful? No! Absolutely not! But neither was ROSE-8, and yet I still learned a lot doing it.
As you probably guessed, I managed to accomplish this, or I wouldn’t be writing this blog post. So, without further ado, here’s a picture of a Swift Toolbox app running on Mac OS 9.2, on my friend Nadine’s Power Mac G4. (Check out that blazing fast 400MHz processor!)
I assume a good number of people reading this would like to know how to do it too!
I’d like to hear about anything you make with these tools! Meanwhile, if you’d like to hear how I made this work, read on.
Gathering materials
The last time I was building Classic Mac OS apps, I was using CodeWarrior. Actually, calling that “building Classic Mac OS apps” was a stretch; I was learning C and using CodeWarrior’s terminal I/O library to get a stdin/stdout interface that Classic Mac OS didn’t have natively. (Remember, no command line!) I could try to get some version of CodeWarrior running again, but that didn’t seem like the most convenient thing. I didn’t think I’d be able to get the Swift compiler running on Classic, so I’d be shuttling object files back and forth between OSs to get anything done.
Fortunately for me, I’m not the only one interested in building Classic apps on modern macOS. At some point I found about the
mpw project: an emulator specifically for running Apple’s Macintosh Programmer’s Workshop tools. And I knew it was going to work, too, because Steve Troughton-Smith, (in)famous in the Apple community for finding undocumented and prerelease features in Apple’s OSs, had written up his experiences building an app with mpw that ran on System 1 all the way up to modern Mac OS X, just by building with the appropriate compiler and against the appropriate libraries.
If you’re interested in all this, I highly recommend checking out his blog post. Not only was this the reference I used to get started, but the app you see running in the above picture, BitPaint, is Troughton-Smith’s test app, ported to Swift. (I did ask him ahead of time if it was okay to use his app for a hobbyist project.) Longtime Mac developer Gwynne Raskind also gave a two-part high-level tour of the Toolbox APIs on Mike Ash’s blog several years ago (part 1 | part 2); fortunately, Carbon takes care of a fair amount for us even on Mac OS 9.
So okay. What does MPW give us?
That’s pretty good; as Troughton-Smith’s blog post shows, it’s enough to build an entire app that’ll run on Classic. My idea was to take object files produced by a modern compiler and feed them to the PowerPC linker, which means I’ll additionally need:
And, well, that should be it! So, off we go.
Modern compiler, classic linker
To make things more manageable, I set an intermediate goal: build an app using Clang, the modern C compiler that ships with Xcode. Clang uses the same LLVM infrastructure as the Swift compiler, so I figured I could deal with all the object format and workflow issues in Clang, and then move on to the Swift-specific parts.
The first thing I did was try to figure out what the file format was for PowerPC object files. It turns out it’s a format called XCOFF; searching for modern documentation on this turned up an IBM reference doc. Pretty much no one else uses this format, which was not encouraging. The first time I started looking into this project, I was worried I’d have to have my compiler write out assembly code and then send that through the MPW PowerPC assembler…after fixing it up to account for the differences in how LLVM and MPW print PowerPC assembly.
However, when I checked to see if LLVM supported XCOFF, I was in for a stroke of luck. It turns out IBM has started adding support for XCOFF to LLVM just last year, as part of adding support for their AIX OS…which runs on PowerPC. So I could ask Clang to generate XCOFF files for AIX, which means it should only be a short step to making it generate XCOFF files for Classic Mac OS.
At this point I remembered a bit of trivia. Apple and IBM used to have a close partnership, along with Motorola. They’d even made some common standards that were used across platforms and CPUs, though perhaps with less impact than they’d hoped. Was it possible that AIX and Classic Mac OS used the same calling conventions for their procedures, and they could just interoperate without any extra work?
I got lucky: the answer is (nearly) yes. The AIX register conventions and stack conventions match up with the ones in the Mac OS Runtime Architectures guide. That meant I could feed object files produced by Clang directly into MPW’s
PPCLink and get a working Classic Mac OS binary out.
Smol Birb Mac Os X
I’m pretty sure my mouth fell open when I first saw this work.
That should work with just top-of-master-branch LLVM/Clang (and a very simple test.c). I did end up needing to change LLVM in a few ways in the end, but it’s really fairly minimal, so much thanks to the IBM folks for doing the hard part of the work for me!
Now do Swift
Being able to compile a simple test program was a great milestone, but I had to do a fair bit of work before I could get swiftc to compile a whole BitPaint. Here are some of the highlights:
You can check out all the changes in the swift and llvm-project repos, if you’re curious. Very few are appropriate for upstreaming to their respective projects, but I’ll try to get the ones that are relevant upstreamed at some point.
A week of mysterious failures
Having made all the changes above, I had an app that worked! In Swift!
…except, it only worked some of the time. I’d change something arbitrary and suddenly events wouldn’t register any more. It got so bad that I added a counter: after any ten events, exit the app. Without that, I’d get trapped, unable to even quit without restarting the (virtual) machine. Even in a seemingly working version, my friend Nadine reported that trying to use the Reset command caused the app to crash. What was going on?
I decided I had to get to the bottom of something strange I’d seen earlier: even the Clang version of the program didn’t work correctly when I turned on optimizations. It’s possible that that was a bug in IBM’s newly-added AIX support, or 32-bit PowerPC support since it’s not such a common platform, or even LLVM’s optimizations. It could be that AIX and Classic Mac OS really weren’t as similar as I thought they were, and so my code wasn’t agreeing with the system code on how things were supposed to work. And it could be that the optimized code was using an instruction that SheepShaver didn’t support, though that didn’t really seem to match the symptoms.
Smol Birb Mac Os Download
And the symptoms were weird. Some local variables were getting corrupted, but others weren’t. So I started testing everything I could think of:
Without being able to rely on logging, I made the simplest textual debug output facility I could: modifying the title of a menu. (It later turned out that writing to stdout in Mac OS 9 automatically results in a file being created, so I could have used that instead.) I wrote C functions that tracked the current stack pointer to make sure it was getting restored properly; I made good use of the
DumpXCOFF and DumpPEF tools that came with MPW; I learned how PEF “pidata” (“pattern-initialized data”) worked and tried to step through CFM relocations by hand (again, see the Mac OS Runtime Architectures guide). I even started trying to decompile some of the actual system libraries to see if they were doing anything suspicious, even though a bug in the actual Mac OS 9 seemed incredibly unlikely. This led all the way to learning about the “toolbox ROM”, which isn’t actually ROM at all: it’s a boot script and a compressed set of system libraries. (It’s called that because it’s content that used to be in ROM.) Fortunately SheepShaver already knows how to load it, which meant that I could do the same decompression and then manually split out the individual libraries.
Smol Birb Mac Os 11
Yeah, I got way off in the weeds. I learned a lot, though!
Finally, I looked at the decompiled optimized code—the C version, not the Swift version. I observed that the variable getting corrupted was in general-purpose register 13. That’s supposed to be an okay place to put data in Classic Mac OS (and in 32-bit AIX, and in 32-bit Mac OS X), but I decided I didn’t trust that, particularly because that register had been used to track thread-local storage in 64-bit AIX. So I marked r13 as reserved…
…and the problems went away. Optimized, non-optimized, even with
-fstack-protector-all on. And Swift.
(Debugging this took about a week, unfortunately, which led to this project being a little less ambitious than I originally wanted.)
Smol Birb Mac Os Catalina“Future directions”
What didn’t I get to? An awful lot, actually.
Maybe I’ll follow up on some of these, but I’ve been putting a lot of effort into making sure I could finish this by April 1, so I should probably get to some of the things I’ve been neglecting in favor of this project instead.
Summary
This project took a lot of time, even though I (1) know a lot about compilers and (2) hacked my way to success instead of being careful and maintaining proper software development practices. But I learned a lot, and I accomplished a goal I’ve had in the back of my mind for a long time.
If you made it all the way to the end of the article, here’s a reward: BitPaint running under Classic on Mac OS X 10.2 (also courtesy of Nadine).
Stay safe, everyone, and help the people around you when you can. And if anybody makes something with this project, I want to hear about it!
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
December 2021
Categories |