MUXLEQ
_____ ______ ___ ___ ___ ___ ___ _______ ________
|\ _ \ _ \|\ \|\ \ |\ \ / /|\ \ |\ ___ \ |\ __ \
\ \ \\\__\ \ \ \ \\\ \ \ \ \/ / \ \ \ \ \ __/ \ \ \|\ \
\ \ \\|__| \ \ \ \\\ \ \ \ / / \ \ \ \ \ \ _\ \ \\\ \
\ \ \ \ \ \ \ \\\ \ / \/ \ \ \____\ \ \_|\ \ \ \\\ \
\ \__\ \ \__\ \_______\/ /\ \ \ \_______\ \_______\ \_____ \
\|__| \|__|\|_______/__/ /\ __\ \|_______|\|_______|\|___| \__\
|__|/ \|__| \|__|
MUXLEQ is a minimalist esoteric machine. Its core is two instructions: the
classic SUBLEQ plus a multiplexing (MUX) operation that adds single-instruction
data movement and boolean logic. A small, disciplined set of native primitives is
layered on top by encoding them in otherwise-unused operand values; today that is
a single right-shift op. The result runs faster and in fewer cells than pure
SUBLEQ, and this project ships a complete, self-hosting development environment
for it.
MUXLEQ is a 32-bit-cell, cell-addressed VM. With no argument it runs the
self-hosting eForth image; given a FILE it loads and runs that standalone
MUXLEQ image instead: ./build/muxleq image.dec.
Introduction
This repository contains a full toolchain for the MUXLEQ architecture, including:
- An assembler for the MUXLEQ instruction set.
- A virtual machine built upon the assembler.
- A cross-compiler that targets the VM with a version of the eForth programming language.
rvopt, a standalone RV32I-to-MUXLEQ compiler for wide native MUXLEQ images.
The system is self-hosted, meaning the eForth environment can compile new versions of itself from source, allowing for seamless modification and extension.
SUBLEQ is a Turing-complete One-Instruction Set Computer (OISC). While esoteric, its ability to run a high-level language like Forth is a powerful demonstration of computational minimalism. This project serves as an experimental platform for exploring the execution of high-level languages on a minimal hardware-like foundation.
Getting Started
This project requires a C compiler, Gforth, and GNU Make.
- macOS:
brew install gforth - Ubuntu/Debian:
sudo apt-get install gforth build-essential
Build the VM and start the eForth interpreter:
$ make run
An example session:
words
21 21 + . cr
: hello ." Hello, World!" cr ;
hello
bye
In Forth, executable commands are called "words."
The words command lists all defined functions in the dictionary.
Forth uses Reverse Polish Notation (RPN), so 21 21 + . cr pushes 21,
then 21, adds them, prints the result, and adds a carriage return.
New words are defined with : <name> <definition> ;.
Once defined, the word hello can be executed by typing its name.
Testing, benchmarking, and internals
make checkruns the pre-commit gate: byte-exact 32-bit golden-output tests, the PTY editor golden, 32-bit eForth smokes, and the self-hosting bootstrap.make check-allrunsmake checkplus wide native-image fuzz, loader rejection, and ASan/UBSan validation.rvoptis a standalone ahead-of-time compiler that lowers an RV32I ELF32/flat binary to a native MUXLEQ image running on the two ops directly, with no interpreter layer:rvopt mux prog > prog.decthen./build/muxleq prog.dec. Seedocs/rvopt-native-muxleq.md.- RV32I test programs: freestanding RISC-V demos, benchmarks, and the official
rv32ui conformance suite live in
tests/rv32i/.make rv32icross-builds the demo, unopt, and DureMark programs intobuild/rv32i;make rv32i-checkadditionally lowers the demo and unopt programs withrvopt mux, runs them on the VM, and runs the rv32ui conformance suite (DureMark is build-checked only, since it uses computed jumpsrvoptcannot lower). Both need a bare-metalriscv-none-elf-*toolchain, such as the xPack GNU RISC-V toolchain. CI builds and runs everything with the xPack toolchain on every push. On the default branch it also packsbuild/rv32iinto a compressed archive and publishes it as a rollingrv32i-latestpre-release, replaced on every push; every run additionally uploads the same tree as therv32i-binariesworkflow artifact. Either lets you download prebuilt images without a cross toolchain installed. docs/manual.mdis the reference manual: the instruction set, memory image and self-modifying-operand rules, the build/bootstrap pipeline, the interpreter, and the eForth environment.
MUXLEQ Architecture
The MUXLEQ architecture extends the classic SUBLEQ OISC with a second instruction to improve performance without significantly increasing implementation complexity. Existing SUBLEQ programs are generally compatible with MUXLEQ.
The SUBLEQ Foundation
A SUBLEQ instruction consists of three operands, a, b, and c,
which are addresses pointing to memory locations.
a b c
The instruction performs the following operation:
# Pseudo-code for a single SUBLEQ instruction
Mem[b] = Mem[b] - Mem[a]
if Mem[b] <= 0:
pc = c
Special operand values trigger I/O or halt the machine:
- Input: If
ais -1, a byte is read from input and stored at the addressb. - Output: If
bis -1, the byte at addressais sent to the output. - Halt: a taken branch to a negative address halts the machine: the program
counter itself goes negative. By convention the halt target is -1 (
Z, Z, -1).
The MUX Enhancement
MUXLEQ adds a multiplexing (MUX) instruction by encoding it into the c operand.
If c has its high bit set but is not -1 (0xffffffff, which stays the
halt/branch target), the MUX operation is performed instead of a branch.
This avoids needing a separate opcode, preserving the simple a b c instruction format.
The core MUXLEQ logic is as follows (one reserved mask value is additionally dispatched as a native shift; see "Native primitives and their limits" below):
# Pseudo-code for the MUXLEQ virtual machine; cells are unsigned 32-bit
while not (pc & 0x80000000): # run until the PC's high bit is set (halt)
# every Mem[] index below is masked into the bounded host arena
a = Mem[pc + 0]
b = Mem[pc + 1]
c = Mem[pc + 2]
pc += 3
if a == 0xFFFFFFFF: # -1: input
Mem[b] = get_byte()
elif b == 0xFFFFFFFF: # -1: output
put_byte(Mem[a])
elif (c & 0x80000000) and c != 0xFFFFFFFF: # high bit set: MUX or a native escape
mask_addr = c & 0x7FFFFFFF # low 31 bits address the mask cell
if mask_addr == 0x7FFFFFFE: # reserved: native shift-right-by-1
Mem[b] = Mem[a] >> 1
else:
mask = Mem[mask_addr] # cell 6 is the zero register: a zero mask is a MOVE
Mem[b] = (Mem[a] & ~mask) | (Mem[b] & mask) # Multiplex
else: # SUBLEQ
Mem[b] = Mem[b] - Mem[a]
if Mem[b] == 0 or (Mem[b] & 0x80000000): # result <= 0 (signed)
pc = c # Branch
MUX with constants 0 and -1 can implement any boolean function:
- AND: Use selector = second operand
- OR: Use selector = ~first operand
- XOR: Combine multiple MUX operations
- NOT: MUX with swapped true/false values
The above are expensive in pure SUBLEQ (requiring dozens of instructions).
Setting the mask to 0 makes a single-instruction MOVE, replacing SUBLEQ's multi-instruction copy sequence. Boolean masking through MUX likewise collapses bit-twiddling that pure SUBLEQ would build from many subtract-and-branch steps. Because MUX is a same-lane selector, though, it cannot move a bit between positions (it cannot shift). That gap is what the native-primitive mechanism below fills.
Native primitives and their limits
Further instructions are encoded in otherwise-unused operand values: a MUX whose
mask address is a reserved, out-of-range value is dispatched as a native op
instead. The machine reserves exactly one such value today, a right shift
(Mem[b] = Mem[a] >> 1), which the eForth shift word uses in place of a
bit-serial loop.
That one op is not arbitrary; it marks the boundary of what belongs in the ISA.
The core is cheap at same-lane logic (MUX), arithmetic and branching (SUBLEQ), and
upward bit movement (a left shift is just x + x, since a carry propagates low
to high). Moving a bit the other way, downward, it can do only through a
bit-serial loop, so a right shift is the single primitive that turns that loop
into one step. Everything else is a composition of it: a variable shift is a loop
of right shifts (a barrel shift does the same in one step but adds no new
capability), multiply is shift-and-add, divide is shift-and-subtract, all in
software. Native byte load/store are deliberately excluded too: on a cell-addressed
machine they would bake a byte-packing convention into the VM. (A comparison op would not
qualify either: SUBLEQ already subtracts and branches, so it is no gap.) The one
further candidate that does fit the rule is a bit-reversal, genuinely
cross-lane, which the core cannot do, and per "Subleq: An Area-Efficient
Two-Instruction-Set Computer" an
efficient route to arithmetic shifts, were a workload ever to justify it.
eForth and Meta-Compilation
The Forth environment provided is a variant of eForth, designed by Bill Muench and C.H. Ting for portability and efficiency. It is implemented with a small set of assembly primitives, making it ideal for unconventional targets like MUXLEQ.
The cross-compiler source lives in the numbered forth/*.fth modules, which
concatenate in order into the generated build/muxleq.fth, a Forth program
that translates eForth source into a MUXLEQ memory image. Edit the modules, not
the generated file. The cross-compilation proceeds in four stages:
- Assembler: define the MUXLEQ machine-code primitives.
- Virtual machine: build a VM layer over the assembler for high-level Forth.
- Forth dictionary: define the core words.
- Image generation: write the final memory image to standard output.
Bootstrap and Validation
The system's correctness is validated through a self-hosting build process, often called "meta-compilation" in the Forth community. If a compiled system can recompile itself and produce a byte-for-byte identical output, the compiler is considered correct.
This validation can be run with a single command:
$ make bootstrap
This command performs the following steps, all under build/:
- Concatenate the
forth/*.fthmodules intobuild/muxleq.fthand run it through Gforth to produce the first image,build/stage0.dec. - Compile the VM (
cc -Ibuild -o build/muxleq muxleq.c), which#includes the generatedbuild/stage0.c. - Run
build/muxleqonbuild/muxleq.fthto produce a second image,build/stage1.dec. - Compare the two images.
If build/stage0.dec and build/stage1.dec are byte-for-byte identical, the
bootstrap succeeds.
License
MUXLEQ is available under a permissive
MIT-style license.
Use of this source code is governed by a MIT license that can be found
in the LICENSE file.
It was originally written by Richard James Howe.