CoreMach was born as a side effect of BareMach. When I tried to take BluMach’s machines to a Raspberry Pi with no operating system, lots of dependencies between its components came to light. Separating the emulation from everything else was so much work that it ended up as a project of its own: CoreMach, the portable engine.
What I wanted to separate
One thing is the computer I’m trying to reproduce: its processor, memory and devices. Another is the application I use it from: the windows, choosing files, or how the image is shown and the keys are received.
The idea behind CoreMach is to have the engine on one side and be able to use it from different places: a portable version of BluMach on the desktop, with its catalogue and configuration, and BareMach on the Raspberry Pi. Each one takes care of showing the image, reading the keyboard and accessing the disks.
Being “portable” doesn’t mean it works anywhere just by compiling it: each target has to be integrated and tested.
The test machines
To test it properly I needed a complete machine, and the first one was the PCS 86, the same one that ended up booting on the Pi.
Later came the work on the PCS 286 in CoreMach too. On 27 September, with its BIOS 1.42, it booted DOS 3.30a from floppy, and a file I copied from DOS was still there after closing and reopening the disk image. But the Customer Test still failed and ATA was pending. And it’s slow: in my tests, CoreMach’s 286 uses about seven times as much CPU time as BluMach’s and doesn’t reach real speed even on a current x86, so on the Raspberry Pi, for now, forget it. “PCS 286 finished” it is not, not yet.
Why I’m bringing it back now
I’m bringing this story back today because, in the end, this engine is going to have another use. BluMach carries an inherited limitation: it’s an x86 emulator and, because of the coupled way it’s built, it doesn’t support other platforms. That doesn’t mean it’s bad; it solves the problem it was designed for very well.
The problem is that for a long time x86 has claimed the term “personal computer” for itself, when in the seventies, eighties and nineties there were many machines that weren’t x86. And today x86’s dominance may be coming to an end.
BluMach and CoreMach, piece by piece
The PCS 86 shows the difference. Both diagrams have the same shape and the same pieces; what changes is how they connect. In BluMach, the interface and all the devices draw on the same global state, and touching one piece means dragging the others along:
In CoreMach, each layer only talks to the one next to it. The machine is a composition of components, each with its own state, and the interface can be swapped without touching the engine:
In short:
| Aspect | BluMach | CoreMach |
|---|---|---|
| Organisation | Inherited from PCem: CPU, devices, configuration and interface share code. | In layers: components, complete machines, engine and interface. |
| State | Lots of global state: the current CPU, the port map, the timers… | Each machine has its own CPU, devices, buses and time. That makes it easy to isolate and test. |
| Time | Tied to the CPU counters inherited from PCem. | One shared timeline; the CPU and each device run at their own frequency, stored as an exact fraction (the PIT runs at 14.31818 / 12 MHz). |
| Components | They hook in through PCem's global functions and tables. | Each component declares what it needs (memory, ports, interrupts, clock) and the machine wires it up. |
| Interface and platform | A single application, with all of 86Box's dependencies: Qt, sound, networking… | A C11 engine that can be built without Qt or windows. Qt is only used if you want a window. |
| Coverage | Almost all of 86Box's hardware, plus what BluMach added. | Much less: PCS 86, M15 and PCS 286, still being validated. The M10 is on its way. |
| Cost | Emulation runs on one thread; sound and networking use others. Its V30 also simulates the bus cycle by cycle. | The whole engine runs on a single thread. With the V30 and the 8088 it uses the same or less than BluMach; with the 286, about seven times as much. |
What I’ve learned
When you separate the engine, you have to decide things that used to be scattered all over the program: who advances emulated time, how devices talk to each other, and what happens when a machine is reset or a disk is changed.
Testing each component separately helps find bugs, but every piece working doesn’t mean the whole machine works. The good thing is that I can now test the complete machine easily, without dragging half the application along.
CoreMach is still in development. My plan was to throw it away, because I built it for the Raspberry Pi, but now I can see it’s going to be very useful for building machines with non-x86 architectures, from Olivetti and other brands. Olivetti alone has quite a few with good documentation: the M10, a portable with an 80C85; the M20, with a Zilog Z8000; or the Prodest PC128 and PC128S, which despite the name have nothing to do with each other: the first is a Thomson MO6 with a 6809, and the second a BBC Master Compact with a 6502 derivative. It gives an idea of what can be built.
Next: the M10, and BluMach with two engines
The next machine will be the Olivetti M10, a portable with an 80C85. It isn’t finished yet and will get its own post.
The M10 also brings an important change: BluMach will start using CoreMach. From then on, BluMach will have two emulation engines: the one inherited from 86Box for x86 PCs, and CoreMach for machines with other architectures. That, in the end, is the point of having decoupled the engine.
The code is on GitHub: CoreMach and BluMach. BareMach is still private; I’ll link it when I publish it.
Sources and licences
CoreMach doesn’t start from scratch. This is the origin of each part, as the repository itself records it in provenance/components.json:
- Base: CoreMach was extracted from BluMach, which is a modified version of 86Box, which in turn comes from PCem. Everything is distributed under GPL-2.0 or later, and each file keeps its copyright notices and original authors.
- 8088 and V30: a rewrite of the interpreter inherited from 86Box, which in turn is largely a port of XTCE, the emulator by Andrew Jenner (reenigne), with work by Miran Grča.
- 80286: mostly written anew from Intel’s documentation (references 210760-002 and 210498-005, and the 1987 80286/80287 programmer’s reference manual). Boot and reset derive from BluMach’s code. It’s checked against the SingleStepTests/80286 tests by Daniel Balsom (MIT licence).
- Peripherals: the 8237 DMA, 8259 PIC, 8253 PIT and PVGA1A video derive from BluMach and 86Box code, checked against Intel’s datasheets and the IBM PC AT technical reference manual. The XTA controller derives from a BluMach file under the BSD-3-Clause licence (Fred N. van Kempen).
- 8085 (for the M10, in development): it comes from the 8080 mode of CoreMach’s own V30, completed with OKI’s Microprocessor Data Book (1986).
- AI: much of this rewriting work I did with the help of AI.
- Diagrams and measurements: I made the diagrams from the code in both repositories. I measured the CPU usage comparisons by running the same synthetic loop in both emulators, on a current x86: they give an idea, they aren’t a complete benchmark.
No BIOS, ROM or disk image is distributed. Olivetti and the names of its machines are trademarks of their owners; this project isn’t affiliated with Olivetti or 86Box.