When I was a kid experimenting with electronics my big dream was always to build my own computer. Today, after thirty years, I finally realized that dream:
This is my breadboard implementation of Grant Searle’s 6809 SBC. His basic design is just six chips and a handful of miscellaneous components. If you use a USB to TTL serial cable like I did then you can cut that down to just five chips.
This SBC is powered by a 6809 with 32K of RAM, 16K of ROM, and a 68B50 ACIA for the serial I/O. The ROM contains a modified version of Microsoft Extended BASIC as used by the Tandy Color Computer 2. All I/O is via the serial port at 115200 bps. Here’s me running some really simple BASIC commands in Minicom:
I was able put this together in an afternoon over 2-3 hours, and surprisingly, it almost worked on the first try! The only reason it didn’t work right away was because I forgot to tie a couple of MPU pins to Vcc. Once the missing wires were added it booted right up.
Grant also has designs for basically the same SBC but with a Z-80 or a 6502 as the CPU, and i plan to build all three eventually. I had actually wanted to start with the Z-80 version, but it uses an 8k ROM (a 27C64) and my burner seems to be having problems burning those; more on that later.
Now that I’ve gotten my feet wet I’m to start designing my own SBC. I’d like to build something around a 65816 but I will probably start with a 6502 or 65802 to keep the first design simple. Whatever I do I’m sure I’ll have fun building it!
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
./configure --disable-pulseaudio --disable-esd --disable-video-mir \
--disable-video-wayland --disable-video-opengl --disable-video-x11 \
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>
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.
Traditionally I’ve never been one to put a great deal of effort into Halloween. This year, however, I decided I wanted to go as Rick from “Rick & Morty”, and i wanted the centerpiece of my costume to be a fully-functional portal gun prop (it could be argued that the costume was just an excuse to build the gun). So, I set out to build the Rickest portal gun of them all: a fully 3-D printed replica containing a micro projector powered by a Raspberry Pi that could project fully animated portals with sound.
The first thing I did was some research. I immediately came across this project, which is very impressive, but it was rather limited due to the use of a projector with an SD card slot. He can’t control the projector without it popping up its OSD, so the animation is always looping, and he uses some clever hacks to only show it when he wants it to be visible. I knew I could do better.
My next step was to get an idea of the dimensions for the gun I was going to build. After checking out dozens of other projects on the web I settled on having the main body of the gun be roughly 6″ long, 4″ wide, and 2″ high. This made the gun look aesthetically pleasing, and would just barely fit inside my printer’s build volume.
Choosing the Hardware
With the dimensions chosen and some rough sketches made I set out to select the parts to go inside the gun. A Raspberry Pi Zero was the obvious choice for the controller, since it’s cheap, tiny, and has enough horsepower to run the animation I wanted to display. I also settled on a Quad Alphanumeric Display from Adafruit for displaying the selected destination universe. The display is controlled via I2C which is perfect for interfacing to the Pi. It is available in red (and several other colors), but red was out of stock at the time so i went with the white version and a red plastic filter.
For the projector I settled on an APEMAN Mini Projector from Amazon. It has a decent output brightness, built-in speakers, and a USB output that can power external devices from its internal battery, meaning I wouldn’t need to wedge in another power source for the Pi and LEDs. It also happens to be 4″ x 4″ square which perfectly fit with the dimensions I had decided on for the body of the gun. At $200 it was by far the most expensive piece of this project!
Finally, I picked up a simple rotary encoder for the control knob, and some DIY HDMI cable parts from Adafruit to build a short, flexible cable for connecting the Pi and the projector.
With my parts acquired I began building a prototype. I framed out a basic version of the body with cardboard so that I could test fit everything. I then hooked up everything the way it would be connected in the final product and did some testing to make sure everything played nice together.On the left is the projector, connected via an HDMI ribbon cable and a home built USB power cable to the Pi, which is in turn wired to the display and the rotary encoder. Near the top center you can see my cardboard prototype for the gun body.
With the hardware proof of concept built I set out to design the software. My plan was to write some code that talked OpenGL directly to the GPU on the Pi, bypassing the need to run an X server. I was hoping to write a fancy shader that would actually generate the portal directly, but settled for a simpler setup with a static image and a modified version of a swirl filter shader that would rotate the static image. It also scales the image to create the open & close effects. This actually took surprisingly little time to create; I went from no code to a working prototype in a couple of hours.
Here’s the image that is used for the portal:
Next I had to add sound effects. The projector has two internal speakers so all I had to do was redirect the Pi’s audio output over the HDMI. The problem came when I tried to find some good sound samples to use. I found a decent “portal opening” sound, but was unable to find a matching “portal closing” sound. In the end I used Audacity to copy a portion of the opening sound and reverse it.
Last up was the alphanumeric display. This was simply a matter of using Adafruit’s sample code for the Arduino and converting it to run on the Pi. I had originally programmed it to just count sequentially as the knob was turned, but I realized that for a “real” portal gun that would be a horrible user experience, so I implemented a “favorites list” of known destinations from the show and had the knob scroll between those.
Once the software was finished I created a “pg” user on the Pi and set it to auto-login and run the app as soon as the Pi boots.
In the end I spent the better part of a week writing and tweaking the software. It would have gone faster if I’d had a cross-compile environment set up, but I don’t, so I had to do all my compiles on the Pi. It is NOT a fast process!
Building the Gun Body
By far the most time-consuming part of the project was designing and printing the gun body. I pushed my FreeCAD skills to their limits designing all the pieces, and ended up going through several iterations before settling on a final design that worked.
When I started out designing the body I had planned to print it in four pieces. The main (rectangular) part of the body would be printed as a box and a lid, with a black front panel held in place by slots, and the handle would be separate and attached to the back via screws. This turned out to be a bad idea for a couple of reasons:
1, My original design for the box (minus lid) was going to be an 11+ hour print. Every time I wanted to tweak anything would mean yet another 11 hours, not to mention all the wasted plastic.
2. I kept running into problems when trying to design complicated designs in FreeCAD; I would want to go back and change something and it would end up destroying my entire design. This is probably just a skill-level problem on my part, but in the end it was faster for me to design multiple smaller pieces instead of a few large ones.
So after a lot of thought I decided to print the top, bottom, front, and side pieces individually and then connect them with M1.5 screws and a little glue for added strength. Here’s my first prototype for the bottom panel:
The four square posts are for holding the projector, which needs to be centered vertically in the gun so that the projector output is lined up with the center line on the front panel, and to make sure the projector’s air vents can get some circulation. The small circular posts are for holding the Pi, and the slot along the front will hold the front panel. The large circular hole is where I was originally going to put the power switch, and all the tiny holes are the screw holes.
Here is my first test fitting of the electronics on the base:
The projector fit perfectly, but the Pi was hanging over the back edge just a hair. In addition I decided I wanted the Pi farther back so that I had more room to attach the handle to the top and bottom plates. Keen observers will also notice the missing mounting post for the Pi; it broke off while I was trying to screw the Pi down.
After a couple more tries I had a winner:Here you can also see the right-angle micro-USB connector I found on Amazon. By pure luck it is exactly the right size so that it lines up with right edge of the gun, meaning I would be able to charge the projector without opening the gun.
It’s at this point that I hit my first snag. The HDMI ribbon cable was built with right-angle connectors, which was fine on my original design, but with the Pi partially underneath the projector the connector on the Pi end did not have enough room. So, back to Adafruit i went for a straight connector.
Next up were the side pieces. These would need to have small tabs to allow them to be screwed to the top and bottom plates, and would also need some carefully positioned access slots in them for the projector’s side controls and the micro USB charging connector. This was a bit tricky because the corners and edges of the projector are rounded just enough to make it difficult to get an accurate measurement with my digital caliper. I went through several iterations of the side panels before finally coming up with ones that fit; fortunately they are small and printed fast.
Here’s the partially-assembled gun with the side panels attached:
Next up was the top panel. This was actually the simplest piece to print because it only had two openings beside the screw holes, and the placement of those two openings was rather arbitrary:
And here’s the top with the display and the portal fluid cylinder mounted:
Perfect! In fact the display actually just snaps in place on its own; originally I had intended to drill some small holes and secure it with screws, but i broke my 1.1mm drill bit so I just left it as-is.
Last, but not least, I printed the front plate. I did this last because it’s black and I didn’t want to change the filament in the printer until I was done printing the white pieces. I also printed two domes out of translucent green filament and mounted those in the front panel. The domes have a hollow space inside that is just large enough for an LED. Note that there are three holes but only two are filled; the third hole is the output for the projector.
Finally here’s the body mostly assembled, minus the yet-to-be-printed handle. The top isn’t screwed down yet because I still need to fill the portal fluid cylinder and also do all of the LED wiring.
Going into this I knew what the handle should look like, but I had no idea how to design it. It took me the better part of a day to design this one piece, and it was the most frustrating day of the entire project. The handle, with its non-square angles and curves, was well beyond anything I had ever done in FreeCAD before.
I am not going to go into too much detail on the handle design because I was learning as I went and so what I did may not be the best way to do things (and I don’t even remember all the steps now!) But the simple version is that it consists of a half cylinder base with a hollow area for wiring, and then a cylinder set at an angle as the actual handle. Two angled cylindrical shafts, one from the top and one from the bottom, provide mounts for the control knob and power switch:
Unfortunately my measurements for those access shafts were a bit tight so I had to carefully drill them out to make room.
With the software done and all the pieces designed and printed it was time for final assembly.
I started with the portal fluid. For this I used some clear Aloe Vera gel to provide a cool bubble effect. I also drilled two small holes in the lid for the leads of an LED (after making sure the lid was non-conductive of course!). I mounted a super-bright green LED on the inside of the lid and secured it with more Loctite.
Next I glued LEDs in each of the green domes on the front panel, and then wired them all in parallel along with some 200 ohm current-limiting resistors. All connections are soldered and covered in heat-shrink tubing for strength. The whole LED circuit is then connected to 5V and GND on the Pi. As long as the Pi is powered on the LEDs will be lit.
Once the wiring for the LEDs was done I permanently attached the portal fluid cylinder to the top panel with some Loctite:
Next I connected the top display to the I2C and power pins on the Pi. The display requires two power connections; a 5V supply, and a supply line tied to the desired voltage level of the I2C pins, which in the case of the Pi is 3.3V.
After the display was connected I turned to the handle. First up was the rotary encoder. It requires five wires: three for sensing rotation and one for the pushbutton function. Two of these would go to ground and the rest to GPIO inputs. Once it was connected I carefully mounted it in its access shaft on the handle, taking care not to break the connections.
Next I cut the ends off of a USB-A to micro-USB cable and wired them together with the power switch in series, then plugged one end into the projector and the other into the Pi. I then mounted the switch inside the shaft I made for it on the bottom of the handle.
The final step was to assemble the remaining pieces and test the portal gun. I slotted the front panel in its mounting slots, and then screwed the lid down to the body. Then I carefully pushed the handle into place, taking care not to break any of the wiring coming from the controls on the handle, and screwed it to the top and bottom panels. Here is my first power on test:
As you can see there is one TINY thing missing, and that is the red filter over the display. I bought some red plastic sheets on Amazon and cut them to size, doubling them up to produce a deeper red. I also printed a simple black frame to go around the display, and carefully glued both in place with Loctite.
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).
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
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.
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.
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.
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.
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:
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:
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.
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.
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.
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.
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:
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.
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!