A bare-metal port of SimCoupe (SAM Coupé emulator) running on Raspberry Pi 2B/3B/4B/400 using the Circle C++ framework.
SimCoupe emulates the SAM Coupé — a British Z80-based home computer released in 1989 by Miles Gordon Technology. This version brings SimCoupe to Raspberry Pi as a bare-metal application, eliminating the need for a full operating system.
This port is based on SimCoupe by Simon Owen, adapted to run on Circle, a C++ bare-metal programming environment for Raspberry Pi.
- Bare-metal execution — No Linux required; runs directly on Raspberry Pi hardware
- Multicore architecture:
- Core 0: USB host, scheduler, input handling, VCHIQ audio transport
- Core 1: Z80 CPU emulation and video rendering
- Core 2: Audio synthesis (SAA1099, SID, DAC)
- USB input — Keyboard, mouse and gamepads (up to 2)
- VCHIQ audio — HDMI or headphone jack output via GPU audio service
- FAT filesystem — Load ROMs and disk images from SD card
- Framebuffer video — 800x600, 8-bit palette (Pi 2/3) or 32-bit ARGB (Pi 4/400)
| Raspberry Pi | Kernel File | CPU | Audio Default | Video |
|---|---|---|---|---|
| Pi 2B | kernel7.img |
Cortex-A7 | Headphones | 8-bit palette |
| Pi 3B | kernel8-32.img |
Cortex-A53 | Headphones | 8-bit palette |
| Pi 4B | kernel7l.img |
Cortex-A72 | HDMI | 32-bit ARGB |
| Pi 400 | kernel7l.img |
Cortex-A72 | HDMI | 32-bit ARGB |
Pi 400 notes: Must use HDMI0 port (closest to USB-C power). No headphone jack.
All audio goes through VCHIQ (VideoCore Host Interface Queue), routed to HDMI or headphone jack:
- Sample rate: 44100 Hz stereo (matching upstream SimCoupe)
- Auto-detection: Pi 4/400 defaults to HDMI, Pi 2/3 to headphones
- Override: Set
sounddev=hdmiorsounddev=headphonesincmdline.txt - Ring buffer: Core 2 generates audio, Core 0 transports to GPU via VCHIQ
- Flow control: GPU callback reports buffered bytes, poll rate-limited
Core 2 (emulator) Ring Buffer Core 0 (poll) GPU
Sound::FrameUpdate() --> s_ring[] ---------> circle_audio_poll() --> VCHIQ --> speaker
SAA1099 + DAC + SID ~1s stereo 1 frame per poll HDMI/jack
44100 Hz stereo 176K s16 via WriteSamples()
- Toolchain:
arm-none-eabi-gcc(ARM cross-compiler) - Build tools: CMake 3.16+, GNU Make
- SD Card: FAT32 formatted, 512MB+ recommended
- SAM Coupé ROM:
samcoupe.rom(included insimcoupe/Resource/)
macOS:
brew install --cask gcc-arm-embedded
brew install cmakeLinux (Debian/Ubuntu):
sudo apt install gcc-arm-none-eabi cmake make# Build for a specific platform
./build.sh pi2 # Raspberry Pi 2B
./build.sh pi3 # Raspberry Pi 3B (default)
./build.sh pi4 # Raspberry Pi 4B / 400
# Build all platforms
./build.sh all
# Create release ZIP
./build.sh release
# Clean everything
./build.sh cleanFormat your SD card as FAT32 and copy all of the following files to the root. Without the firmware files the Pi will not boot.
| File | Source | Required |
|---|---|---|
bootcode.bin |
circle/boot/ |
Pi 2B/3B |
start.elf |
circle/boot/ |
Pi 2B/3B |
start4.elf |
circle/boot/ |
Pi 4B/400 |
fixup.dat |
circle/boot/ |
Pi 2B/3B |
fixup4.dat |
circle/boot/ |
Pi 4B/400 |
armstub7-rpi4.bin |
circle/boot/ |
Pi 4B/400 |
bcm2711-rpi-4-b.dtb |
circle/boot/ |
Pi 4B |
bcm2711-rpi-400.dtb |
circle/boot/ |
Pi 400 |
config.txt |
simcoupe/sdcard/ |
All |
cmdline.txt |
simcoupe/sdcard/ |
Optional |
kernel7.img |
simcoupe/ |
Pi 2B |
kernel8-32.img |
simcoupe/ |
Pi 3B |
kernel7l.img |
simcoupe/ |
Pi 4B/400 |
simcoupe/samcoupe.rom |
simcoupe/Resource/ |
All |
simcoupe/atom.rom |
simcoupe/Resource/ |
Optional |
simcoupe/atomlite.rom |
simcoupe/Resource/ |
Optional |
simcoupe/sp0256-al2.bin |
simcoupe/Resource/ |
Optional |
simcoupe/*.dsk |
your collection | Optional |
The Pi firmware auto-selects the correct kernel based on the board. You can place all three kernel files on the same SD card.
The easiest way to set up the SD card is to use ./build.sh release which creates a ready-to-use ZIP file.
The included config.txt supports all Pi models with conditional sections:
arm_64bit=0
initial_turbo=0
dtparam=audio=on
[pi4]
kernel=kernel7l.img
armstub=armstub7-rpi4.bin
max_framebuffers=2Optional kernel parameters:
sounddev=hdmi # Force HDMI audio (auto-detected on Pi 4/400)
sounddev=headphones # Force headphone jack (auto-detected on Pi 2/3)
If cmdline.txt is empty or absent, audio destination is auto-detected.
| Input | Function |
|---|---|
| USB Keyboard | SAM Coupé keyboard |
| USB Mouse | SAM Coupé mouse |
| USB Gamepad | Joystick 1/2 |
| Key | Function |
|---|---|
| F1 | Insert disk (drive 1) |
| Shift+F1 | Eject disk (drive 1) |
| Alt+F1 | New disk (drive 1) |
| F2 | Insert disk (drive 2) |
| Shift+F2 | Eject disk (drive 2) |
| Alt+F2 | New disk (drive 2) |
| F3 | Tape browser |
| Shift+F3 | Eject tape |
| F4 | Import data |
| Shift+F4 | Export data |
| Alt+F4 | Exit (halt) |
| F5 | Toggle TV aspect ratio |
| F6 | Toggle smoothing |
| Shift+F6 | Toggle motion blur |
| F8 | Toggle fullscreen |
| F9 | Debugger |
| Shift+F9 | Save screenshot (PNG) |
| F10 | Options menu |
| F11 | NMI |
| F12 | Reset |
| Ctrl+F12 | Exit (halt) |
| Numpad 9 | Boot from drive 1 |
+-----------------------------------------------------------+
| Raspberry Pi |
+------------------+------------------+---------------------+
| Core 0 | Core 1 | Core 2 |
| | | |
| USB HCI | Z80 Emulation | Audio Synthesis |
| Scheduler | Video Rendering | SAA1099 + DAC +SID |
| KB/Mouse/Gamepad| Frame Update | Sound::FrameUpdate |
| VCHIQ Audio Poll| | Ring Buffer Write |
+------------------+------------------+---------------------+
| Circle Framework + Multicore-safe Linux Compat Layer |
| |
| VCHIQSound CScreenDevice CEMMCDevice CUSBHCIDevice |
| (Audio) (Pi4 Video) (SD Card) (USB) |
+-----------------------------------------------------------+
| Hardware |
| HDMI/Jack Audio | HDMI Video | SD Card | USB |
+-----------------------------------------------------------+
- Video: Pi 2/3 use
CBcmFrameBuffer(8-bit palette, GPU converts). Pi 4/400 useCScreenDevice(32-bit ARGB, software palette LUT) because VCHIQ init disrupts raw framebuffers on BCM2711 - Audio: Push-based VCHIQ (adapted from BMC64). Ring buffer decouples emulator (Core 2) from VCHIQ transport (Core 0). Re-START mechanism recovers from GPU pipeline drain
- Multicore locks:
linux_multicore_fix.cppprovides atomic rwlock, mutex, semaphore and completion overrides for Circle's Linux compat layer (originals assert Core 0 only)
- Simon Owen — SimCoupe emulator (https://github.com/simonowen/simcoupe)
- Allan Skillman — Original SimCoupe 0.72
- Dave Laundon — CPU contention and sound enhancements
- Dave Hooper — Phillips SAA 1099 chip emulator
- Rene Stange — Circle bare-metal C++ environment (https://github.com/rsta2/circle)
- RQ Radionics & Rodolfo Guerra
This project is licensed under the GNU General Public License v2.0. See simcoupe/License.txt for details.