XGS

A Long Overdue Update

It’s been about 14 months since I last posted an update, and I want to check in here and let everyone know the the blog isn’t dead; I’ve just been incredibly busy.

Early in 2023 I started to realize that my job of ten years was just not a good fit for me anymore. I was stuck maintaining and extending old code and subject to the whims of what features the clients wanted. So, in the spring, I decided to jump ship, and took a position at a new startup called Positron AI. Like most startups the work hours are longer and so I haven’t had as much energy for personal projects. But,it’s also much more rewarding work and I don’t regret the decision one bit.

JRC-1

First and foremost, the name of the OS for this project was changed last year from JR/OS to jrcOS. The OS itself is not entirely “retro” anymore, being a Unix clone, so the new name is more fitting. I did have a brief blog post about this last year, but the rest of the post was so bad I ended up deleting it.

Though my new job has more or less destroyed my original jrcOS schedule, I have continued to work on it, albeit in small bursts. In fact, about three months ago I made a major decision — I decided to do the thing I said I wouldn’t do and start writing non-critical jrcOS code in C, using the Calypsi 65816 C compiler.

I thought about decision this long and hard, especially because I felt like I was giving up on my self-imposed challenge, and it’s the right decision. In the end, it wasn’t that doing everything in assembly was beyond my ability, but rather I just don’t have the patience for it (I’m rather neurodivergent). I’ve also had more time to look at the code Calypsi generates, and I’m decently happy with it. Changing over to C is going to let me meet my goals much faster and with less hassle.

Look for more jrcOS updates between now and spring.

XGS

This project, unfortunately, is now on the far back burner. I hesitate to call it officially dead, because I do have plans for the code base, but I’m not actively working on it at the moment. Tentative plans for some future date include a port that runs on a bare metal Raspberry Pi, with a native ARM CPU emulation.

Home Automation

“Wait,” you are probably now saying, “when did you ever blog about home automation?” The answer is I haven’t…yet.

Over the last year I’ve largely rebuilt my entire home network, with the goal of being more fault-tolerant of both power fluctuations and Internet outages. This is quite a bit harder than it sounds with so many products these days being cloud-based.

As part of my revamp I also wanted to delve more into home automation. I’ve dabbled in it before in the form of Phillips Hue light bulbs, but I wanted to start automating even more. I also wanted to add a voice assistant like Alexa, but without relying on a cloud connection.

At this point I’ve achieved my initial goals, thanks to Home Assistant and its large ecosystem of compatible hardware and open source projects. Even my voice assistant, Wintermute (IYKYK), runs on local hardware.

Throughout 2024 I’m hoping to start blogging more about the progress I’ve made and my future plans, including some of the products I’ve found that work with HA.

Closing Thoughts

I have some other, smaller projects mulling around in my brain that I may or may not get to this year. Anything I do I will try to remember to document here. Stay tuned.

XGS on the Raspberry Pi 400

About a week and half ago I became the owner of Raspberry Pi 400, a small computer built around a Raspberry Pi 4. The kit I purchased came with a USB-C power adapter and a basic USB mouse; all I needed to supply was a monitor.

Naturally, the first thing I did after setting it up was get XGS running on it:

This was not quite as simple compiling XGS and running it, so let’s go over what changed, why it changed, and how to build XGS on the Pi after the changes.

Open GL Support on the Raspberry Pi

On older Pi models (1, 2, 3, and the Zero) the OpenGL support was provided through a proprietary firmware blob, and exposed through a set of custom GL libraries in /opt/vc/lib. Since 2017 XGS supported use of these libraries by specifying -DBCMHOST=true when running cmake.

As of the Pi 4 (and, by extension, the Pi 400) this proprietary firmware driver is no longer supported. Instead, there are now open source drivers supporting the Pi 3 and 4. They are fully integrated into Mesa now, so it is no longer necessary to link against proprietary libraries.

As a result of these changes I have decided to remove the BCMHOST option in XGS. Instead, XGS relies on SDL to pick the right driver; this will be KMSDRM when running from the console, or X11 when running from the desktop.

Note that this change has probably broken support for the Pi 1 or 2. Those models are sufficiently outdated now that I don’t feel the need to continue supporting them.

Building XGS

As of this writing Raspberry Pi OS does not ship a version of SDL with the KMSDRM driver enabled. So, before building XGS, you’ll need to build and install your own build of SDL. Fortunately this is very easy:

sudo apt-get remove -y --force-yes libsdl2-dev
sudo apt-get install libgbm-dev libdrm-dev
tar -xzvf SDL2-2.0.12.tar.gz
cd SDL2-2.0.12
./configure --host=arm-raspberry-linux-gnueabihf \
--disable-pulseaudio \
--disable-esd \
--disable-video-rpi \
--enable-video-kmsdrm
make -j4
sudo make install

You should also run raspi-config, navigate to Advanced Options -> GL Driver, and make sure you have the KMS driver selected. You’ll need to reboot after making this change.

With SDL built and the KMS driver enabled you can now build XGS:

cd xgs
mkdir build
cd build
cmake ..
make -j4

The resulting binary can be run from the desktop or direct from the console. It will open in a window when run from the desktop, and full-screen when run from the console.

The only problem I have noticed is that the video is a bit choppy when running from the console. It’s most noticeable when watching the sliding apple on the “Check startup device” screen. It does not happen when running from the desktop, so it is somehow related to the KMSDRM driver.

Raspberry Pi & the Future of XGS

XGS has certainly had a fragmented development history. I originally started it in 1996, but by 1997 development had already stalled. Five years later, in 2002, I briefly resumed work on it, but I also started a small business around that time and XGS ended up on a (virtual) shelf for nearly 15 years.

Fast forward to 2016, when I got the XGS itch again. I rewrote the code in C++ to make it easier to understand, removed non-SDL graphics support, and added a basic GUI.

By 2017 I had moved away from the project again despite making good progress. I briefly considered creating a retro emulated GS based around the Raspberry Pi (think of the C64 Mini) but that project never really got off of the ground, and by that point I was already spending the bulk of my time on other projects.

And so here we are in 2020. I’m currently between hardware projects (well sort of; more on that in another post) and I’m feeling the need to spend at least some of my free time on a software project. So, I am jumping back into XGS, with the intent of improving the Raspberry Pi support. My first task will be to create an ARM-optimized version of the M65816 emulation core. I’ve been wanting to learn ARM assembly, and this will be a great way to do that.

Stay tuned!

XGS gets a GUI, Raspberry Pi support, and 3.5″ drives

I’ve pushed up some more XGS changes today! Actually some of this stuff has been in since late spring but I’ve been a bit lax on my updates…sorry about that.

Video and GUI Updates

The video output in XGS is now done via OpenGL ES. SDL is still used to create the window and OpenGL context, but beyond that all video output is done via OpenGL. The reason for this change was to make it possible to integrate ImGui, which has become my GUI toolkit of choice for XGS.

Currently the GUI consists of a bottom bar that lists the current CPU speed and drive activity lights for slots 5 and 6, and a speed control you can toggle by pressing F1. The speed control lets you set the speed that the emulator runs when in “fast mode” to something other than the base 2.8 MHz.

Raspberry Pi Support

Early on I said that I wanted XGS to run an acceptable speed on a Raspberry Pi 2, and as of this update that’s now possible. By activating a compile-time feature it is now possible for XGS to run in “raw hardware” mode on the Pi. In this mode XGS will run full-screen, talking OpenGL ES direct to the GPU without requiring X11 to be running. Keyboard, mouse, and joystick events will be captured (via SDL) directly from the Linux input event interface.

To run in the special Raspberry Pi mode you will need (for the moment) a custom build of SDL2. As of this writing the build of SDL2 included with Raspbian does not appear to have the “rpi” driver enabled, or at least, I couldn’t get it working. Fortunately it’s very easy to build your own SDL2. Here’s what I did:

sudo apt-get remove -y --force-yes libsdl2-dev
tar -xzvf SDL2-2.0.7.tar.gz
cd SDL2-2.0.7
./configure --disable-pulseaudio --disable-esd --disable-video-mir \
--disable-video-wayland --disable-video-opengl --disable-video-x11 \
--host=arm-raspberry-linux-gnueabihf
make -j4
sudo make install

This will install the custom SDL2 libraries and include files under /usr/local. You can then just tell XGS to enable the RPI mode:

cmake -DCMAKE_BUILD_TYPE=Debug -DBCMHOST=yes <path to XGS source tree>
make -j4

On my Pi 2 I’ve found I can get a little over 3 MHz, which is not great, but it’s at least on par with a real GS. I’m sure I can speed that up down the road with some optimization.

3.5″ Drive Emulation

Finally, there is finally an implementation of the 3.5″ drive emulation again, albeit in read-only mode. This means you can now boot from slot 5, although you will still need to issue a manual “PR#5” for the moment because something about the emulated slot 7 Smartport is breaking boot scanning.

Weird Bug of the Week

While testing out my latest batch of changes I found an interesting bug. If I try to launch synthLAB from an image mounted on a Smartport device it will crash on startup, but it works fine if I mount the image on a 3.5″ drive. I’m a bit stumped here; the Smartport emulation seems to have no problem booting the OS so I’m not sure why it causes synthLAB to crash.

 

XGS progress marches on

The blog may be quiet lately, but that doesn’t mean I’ve stopped making progress! The big reason for the silence since January is that work has kept me busier than expected, and XGS development was stalled while I was hunting down a very subtle bug in the CPU emulation. I finally squashed that bug yesterday, resulting in me finding and fixing even more bugs in a marathon session last night. The end result is that I think the new XGS is pretty close to being at parity with XGS 0.54 when it come to compatibility.

Here’s a run-down of what’s changed since my last update:

CPU Emulation Improvements

A bug was fixed in which the final address calculation was not crossing bank boundaries in some of the indexed addressing modes. This single bug took me two months to track down because the effects were subtle, usually resulting in cases where pieces of GS/OS applications did not get moved into the right spot in memory and leading to jumps into blank memory.

A bug with interrupt handling was also fixed, in which the status register value pushed onto the stack in emulation mode included the M and X bits (both forced to 1), which made the interrupt handler think the (B)reak bit was set and treat the interrupt as a BRK.

The IRQ emulation is now level-triggered signal like the real hardware, and not edge-triggered. Logic has been added to the System class to allow multiple interrupt sources to raise and lower their virtual interrupt lines, which are then presented as a single IRQ level to the actual CPU emulation.

General Emulation Fixes

I discovered a minor bug that skipped a single page of memory remapping (page 3, specifically) which caused some 8-bit programs that use AUXRD/AUXWR to crash.

A bug that did not properly turn off the emulated 5.25″ drive motor was fixed. The bug caused GS/OS to hang indefinitely waiting for the motor to turn off.

The VBL interrupt now works properly (and can be cleared again).

Input Handling

The input handling has been much improved; there is no longer any lag or missing key presses, and I’ve added all the missing mappings for shifted keys so you can now type pretty much anything into the emulation and have it come out as the proper key press.

I’ve added in most of the old special keys, and remapped some others:

  • The input grab toggle is now Right-Control (formerly F5) to match things like VirtualBox and VMware.
  • F11 toggles full screen mode
  • Pause toggle trace mode (if the debugger is compiled in)
  • Control-Home resets the emulator
  • SysReq sends an NMI

Debugger

The trace output now shows the CPU register state as it is after the instruction, not before, which just makes more sense when you’re reading trace output.

The MVP instruction now actually shows up as MVP in trace outputs. Formerly it showed up as MVN.

Video

The video emulation no longer renders whole frames; instead, each line is rendered at the time it should be rendered during the emulation. I’ve also remove the code that renders each line twice; instead I rely on SDL to stretch the frame to the proper aspect ratio. On most modern systems this means that the aspect ratio correction moves from software to hardware.

Virtual Disks

All eight SmartPort virtual disks can now be set from the command line using the –hd1 through –hd8 options. Note that the numbering now starts with “1” so the former –hd0 option is gone.

Next Steps

I’m now working on implementing some sort of GUI, both for the emulator itself and for the built-in debugger. Originally I had planned to use some sort of SDL GUI toolkit, but I can’t find one I really like, so I think I’m going to just implement the GUI as a separate window that can be toggled between visible and hidden. The choice now is between GTK+ and Qt; currently I am leaning towards the latter.

 

Boot crash fix, CPU updates, and a new debugger

Lots of changes have been pushed into the XGS repository since my last post.

Boot crash fixed

The bug causing the emulation to crash into the system monitor at startup has been fixed. It was not, as I had originally suspected, a CPU emulation bug. Instead it was a bug in the Mega2::buildLanguageCard() method, and a fairly obvious one in retrospect. Turns out it was mapping all sixteen $DnXX logical pages to the same physical page; needless to say this resulted in severe memory corruption!

CPU emulation updates

The latest code makes two major changes to the CPU emulation, though not in any way visible outside the code.

First, there is now a LogicEngineBase class that defines the executeOpcode() method as a virtual method. The LogicEngine template class inherits from this, and so now the emulator just stores a pointer to the current logic engine and calls it directly, instead of using a large set of nested if statements to pick it manually for every opcode. This actually turned out to be just as fast as my original “no virtual functions” implementation, and the code is cleaner too.

Second, the cpuRead and cpuWrite methods now take an extra parameter of type mem_access_t (defined in the M65816/types.h file). This tells the rest of the emulator exactly what a particular memory access is for:

  • Instruction fetches
  • Opcode fetches
  • Stack operations
  • Generic data

This was done to facilitate the new debugger, which has been decoupled from the CPU emulation and moved to its own module.

The new debugger

As I mentioned above, the debugger is has been moved out of the M65816 emulation and into its own module. In the new implementation the debugger monitors all calls to cpuRead and cpuWrite, and using the memory access type provided by the CPU it can decode instructions as well as monitor (or even modify!) other memory accesses. I made this change for a couple of reasons:

  1. Some of the things i want the debugger to eventually do would have required putting a lot of hooks inside M65816. The new debugger design hooks into exactly two places, and since it’s sitting “above” the CPU emulation it has a lot more control.
  2. I want a graphical UI for the debugger, but I don’t want to make M65816 depend on any GUI libraries.

At the moment the debugger only implements the instruction disassembly from the old version. Additional features will get added once I implement the GUI.

 

 

A new year and a new XGS

Well, it took a lot longer than I thought, but I’ve finally managed to roll out my first alpha prerelease of the XGS rewrite. At the moment only text mode is implemented, and the boot sequence does not yet complete properly, but it dos start up. Since this is at such an early stage of development I am not making this available as a tarball release. Those interested in playing with it can download it directly from the GitHub page.

 

Changes in this Version

The entire code base has been converted from C to C++, and heavily refactored so that the individual code modules correspond more closely to the individual pieces of the IIGS’s hardware.

All of the platform-specific drivers have been removed; instead, the code uses SDL2 for most platform-specific functions.

The emulation timing has been rewritten to use Linux timer FDs. This is currently the dependency that makes the code non-portable.

The CPU emulation has been completely rewritten. The new version is significantly easier to understand and debug than the old version, as all of the cryptic and convoluted C macros are gone. The opcode execution logic is now implemented in a C++ template which is used to generates individual classes optimized for specific combinations of memory and index width.

What’s Next

At the moment all of my energy is focused on fixing whatever issue or issues are causing the boot sequence to crash. This involves running both old and new XGS in debug mode and comparing the resulting execution traces.

Once the boot issue is fixed the keyboard handling needs a lot of love. The current implementation is only partially usable, especially since it fails to properly handle applying modifiers (shift & control) to key presses before putting them into the input buffer. As a result you can’t even type many characters, making it difficult to investigate problems and run tests within the emulation.

 

XGS Lives

Believe it or not, XGS is now 20 years old! The project was started way back in 1996, when my fastest PC was still a 66 MHz Pentium. Sadly, for various reasons, development pretty much stalled in 1997. I briefly started tinkering with it again in 2002, but I got busy, and nothing came of it. The last released version is still from 1997…but that’s about to change.

Lately I’ve found myself in need of a good personal project to sink my teeth into, and so I’ve circled back around to XGS.  I have two goals in mind for the future of XGS:

  1. Finishing what I started 20 years ago.  I want to find and fix the bugs that keep some high-profile software from running (hi Diversi-Tune!), improve the emulation (3200-color support anyone?), and apply some spit and polish in the form of an actual GUI.
  2. Create a version of XGS that is geared towards running on a Raspberry Pi to create a teeny-tiny Apple IIGS. Part of this project would involve some actual hardware hacking to create interfaces to authentic Apple hardware. I for sure would like to implement ADB, so that a real IIGS keyboard and mouse can be used. I’m also considering trying to drive an actual 3.5″ 800k drive, which would be great if there’s anyone out there with some stuff on old IIGS disks.

With those goals mind, the first decision I’ve made is that I’m no longer going to go out of my way to make the code portable beyond Linux. I certainly won’t object if anyone wants to resurrect any of the other ports, and I will try to not make things hard on anyone who wants to do so, but if I can do something cleaner and/or easier by targeting just Linux that is the way I will go. Case in point: the current code base is using the Linux timerfd interface for timing, because it just works way better for me than straight POSIX timers (I did try them!)

Next, I’ve mostly finished up some work I started back in 2002 to replace all the individual video and audio drivers with a single set. Currently that’s SDL for video and PulseAudio for audio. I wanted to use SDL for both, but I so far I’ve been unable to get SDL audio that doesn’t have lots of skips and crackles. SDL does have the benefit of being multi-platform so at least here I hopefully made things easier for any would-be port maintainers.

I’m also looking at ways to simplify the code by removing some roundabout ways of doing things that were originally implemented to make the emulator actually usable on 1996-vintage PCs. The new low-end for acceptable performance is going to be a Raspberry Pi 2.

And finally, I’m considering changing the code base from C to C++ and implementing the various hardware chips as their own classes. This isn’t fundamentally different than what is there now, but the resulting code will be much cleaner, and the interfaces between the various emulated hardware bits will be well-defined. It will also aid in my long-term Raspberry Pi goals, because I’m going to need to be able to plug in different bits cleanly (e.g remove ADB emulation and replace with an interface to my yet-to-be-designed ADB hardware).

I’m really excited about all this, and I’m hoping to start pushing out some new development snapshots this month. Stay tuned!