Following on the last post, I’m keeping focus on the plan, which is to move SoapyBASIC from an interpreter written in Swift to a compiler written in Swift, tagging an Instruction Set Architecture (ISA) that I need to design, and of course the CPU to implement that ISA.
The ISA
Three weeks in to 2025 and I’m settled in an ISA that:
- RISC-inspired load/store architecture
- 32, 64-bit general purpose registers and 32, double precision floating point registers.
- Fixed size instructions (32-bit)
- Optional setting of condition flags on arithmetic and logic operations.
- Can work with different data sizes (64,32,16,8-bit integer and 64,32,16-bit floating point)
- Easy for humans to read and write in assembler/mnemonic form. GET/SET/COPY/ADD etc.
- CISC enough to be performant in a simulated CPU (let’s face it, this is never going to be silicon!)
- RISC enough so I don’t feel ill.
- Superuser / user protection, system calls
This design is just about done. Making a few tweaks here and there, but I want to stay focused and move on to implementation.
The CPU
My CPU is written in Swift but I’m looking to implement parts in C. Indeed I may write the majority of it in C as C is so much more expressive at the bit level.
Everything works on macOS (Apple Silicon) and Linux (x86_64).
Work done so far:
- Implementation of memory and addressing
- Instrument fetch and decode
- Partial implementation of the ISA (enough for arithmetic and looping)
- Debugging helpers.
Challenges
Challenges so far…
Documentation
Annoyingly, one of the main challenges I faces was deciding whether to document my ISA in MarkDown or in an Apple Pages document!
The latter looks better, and is easier to read, but harder to version control well.
I flip-flopped between the two a few times, but ended up with Pages.
But once I wrote a Swift enum for representing the instructions, I started moving the documentation there. At least this way, if I make changes, the documentation follows automatically.
Swift 6 language
Swift 6 language mode, along with its structure concurrency safety can be a right pain in the arse, and forces you to choose between unnatural architectural choices (for something that is inherently single-threaded) or label your code as crap (I think there’s a swift proposal to walk back on this).
I’ve decided to go for the unnatural choices, partly because it’s not really wrong, and partly because I’m going to have to mix in with C or unsafe Swift during this process.
Eg, Swift doesn’t have a fixed size array type ( https://github.com/swiftlang/swift-evolution/blob/main/proposals/0453-vector.md isn’t there yet ). Swift Array is too expensive, so I’m resorting to unsafe pointers to memory or structures. But at that point you might as well mix in some C code. And at that point you might as well do it all in C!
Next Steps
- Complete core CPU implementation and a validation suite of tests. This includes full arithmetic and logic instructions, integer and floating point.
- Implement handlers for system calls for writing data out to host stdout.
- A very simple assembler to make writing test code easier.
- An working program to emit the mandlebrot set in text (see below).
Mandelbrot test program
My SoapyBASIC interpreter runs a program to produce this:

The program is:

In SoapyBASIC interpreted, this takes about 50ms on my old M1 MacBookPro.
The “machine code” version on my synthetic CPU should be at least ten times faster, I think – it’s still interpreted after all.
Let’s see!
Leave a Reply