Soul of a tiny new machine. More thorough tests → More comprehensible and rewrite-friendly software → More resilient society.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Kartik K. Agaram bf82a57959 slack: update instructions for downloading images 4 hours ago
apps fix a regression from 3 commits and 12 days ago :/ 3 weeks ago
archive 6206 2 years ago
browse-slack slack: update instructions for downloading images 4 hours ago
editor rename grapheme to code-point-utf8 2 months ago
html . 1 month ago
linux obsolete argument 1 week ago
shell rename grapheme to code-point-utf8 2 months ago
tools . 2 months ago
tutorial . 2 months ago
.gitattributes 6690 1 year ago
.gitignore create .gitignore 7 months ago
101screen.subx helper to render fonts outside video RAM, take 2 7 months ago
102keyboard.subx . 8 months ago
103glyph.subx bugfix: rendering fake screens 3 months ago
104test.subx . 7 months ago
105string-equal.subx 7842 - new directory organization 11 months ago
106stream.subx 7842 - new directory organization 11 months ago
108write.subx periodic run of misc_checks 7 months ago
109stream-equal.subx snapshot 7 months ago
112read-byte.subx . 5 months ago
113write-stream.subx reading from streams 7 months ago
115write-byte.subx support backspace when reading line from keyboard 3 months ago
117write-int-hex.subx 7842 - new directory organization 11 months ago
118parse-hex-int.subx print call stack on all low-level errors 8 months ago
120allocate.subx debugging helper: heap remaining 5 months ago
121new-stream.subx print call stack on all low-level errors 8 months ago
123slice.subx print call stack on all low-level errors 8 months ago
124next-token.subx 7842 - new directory organization 11 months ago
126write-int-decimal.subx rename grapheme to code-point-utf8 2 months ago
127next-word.subx support non-line-oriented processing in next-word 6 months ago
301array-equal.subx 7842 - new directory organization 11 months ago
302stack_allocate.subx 7254 1 year ago
308allocate-array.subx 7254 1 year ago
309stream.subx . 6 months ago
310copy-bytes.subx reading from streams 7 months ago
311decimal-int.subx . 8 months ago
312copy.subx 7842 - new directory organization 11 months ago
313index-bounds-check.subx start double-buffering 8 months ago
314divide.subx 7290 1 year ago
315stack-debug.subx . 8 months ago
316colors.subx primitive: read r/g/b for color 9 months ago
317abort.subx fix bad terminology: grapheme -> code point 5 months ago
318debug-counter.subx . 7 months ago
319timer.subx more general timer interface 7 months ago
400.mu rename grapheme to code-point-utf8 2 months ago
403unicode.mu rename grapheme to code-point-utf8 2 months ago
408float.mu maintain aspect ratio when rendering images 6 months ago
411string.mu rename grapheme to code-point-utf8 2 months ago
412render-float-decimal.mu 7842 - new directory organization 11 months ago
500fake-screen.mu rename grapheme to code-point-utf8 2 months ago
501draw-text.mu rename grapheme to code-point-utf8 2 months ago
502test.mu . 3 months ago
503manhattan-line.mu 7842 - new directory organization 11 months ago
504test-screen.mu rename grapheme to code-point-utf8 2 months ago
505colors.mu . 6 months ago
506math.mu press '+' and '-' to zoom in and out respectively 8 months ago
507line.mu playing with Paul Batchelor's Trikufic tileset 1 month ago
508circle.mu reimplement Bresenham circle in Mu 8 months ago
509bezier.mu first bit of animation 8 months ago
510disk.mu more powerful load-sectors 6 months ago
511image.mu task: juggling function outputs between registers 3 months ago
512array.mu render functions in MRU order 6 months ago
513grapheme-stack.mu . 2 months ago
514gap-buffer.mu keep 'grapheme-stack' 2 months ago
515parse-float.mu parse float from text 3 months ago
516read-line.mu support backspace when reading line from keyboard 3 months ago
517random.mu fix a regression from 3 commits and 12 days ago :/ 3 weeks ago
LICENSE.txt 7489 - include GNU Unifont 1 year ago
README.md acknowledge current status 3 days ago
boot.subx start hacky experiment to support combining chars 5 months ago
cheatsheet.pdf 5485 - promote SubX to top-level 3 years ago
font.subx . 3 months ago
help make online help more obvious 10 months ago
misc_checks some hacky checks for common errors 10 months ago
misc_checks.subx some hacky checks for common errors 10 months ago
modrm.pdf 5485 - promote SubX to top-level 3 years ago
mu-init.subx . 6 months ago
mu.md rename grapheme to code-point-utf8 2 months ago
mu_instructions compute-offset: literal index 5 months ago
sib.pdf 5485 - promote SubX to top-level 3 years ago
signatures.mu keep 'grapheme-stack' 2 months ago
subx.md . 3 months ago
subx_bare.md . 10 months ago
subx_opcodes support checking overflow flag everywhere 8 months ago
translate start hacky experiment to support combining chars 5 months ago
translate_emulated Mac OS build broken since Aug 29 :/ 3 months ago
vimrc.vim . 5 months ago
vocabulary.md . 2 months ago

README.md

Mu: a human-scale computer

Mu is a minimal-dependency hobbyist computing stack (everything above the processor).

Mu is not designed to operate in large clusters providing services for millions of people. Mu is designed for you, to run one computer. (Or a few.) Running the code you want to run, and nothing else.

Here's the Mu computer running Conway's Game of Life.

git clone https://github.com/akkartik/mu
cd mu
./translate apps/life.mu  # emit a bootable code.img
qemu-system-i386 code.img
screenshot of Game of Life running on the Mu computer

(Colorized sources. This is memory-safe code, and most statements map to a single instruction of machine code.)

Rather than start from some syntax and introduce layers of translation to implement it, Mu starts from the processor's instruction set and tries to get to some safe and clear syntax with as few layers of translation as possible. The emphasis is on internal consistency at any point in time rather than compatibility with the past. (More details.)

Tests are a key mechanism here for creating a computer that others can make their own. I want to encourage a style of active and interactive reading with Mu. If something doesn't make sense, try changing it and see what tests break. Any breaking change should cause a failure in some well-named test somewhere.

Mu requires a 32-bit x86 processor. It supports a short list of generic hardware. There's no networking support yet. Development has slowed, but I still care about it. Feedback, bug reports and other forms of contribution continue to be appreciated.

Goals

In priority order:

  • Reward curiosity.
  • Safe.
    • Thorough test coverage. If you break something you should immediately see an error message.
    • Memory leaks over memory corruption.
  • Teach the computer bottom-up.

Thorough test coverage in particular deserves some elaboration. It implies that any manual test should be easy to turn into a reproducible automated test. Mu has some unconventional methods for providing this guarantee. It exposes testable interfaces for hardware using dependency injection so that tests can run on -- and make assertions against -- fake hardware. It also performs automated white-box testing which enables robust tests for performance, concurrency, fault-tolerance, etc.

Non-goals

  • Speed. Staying close to machine code should naturally keep Mu fast enough.
  • Efficiency. Controlling the number of abstractions should naturally keep Mu using far less than the gigabytes of memory modern computers have.
  • Portability. Mu will run on any computer as long as it's x86. I will enthusiastically contribute to support for other processors -- in separate forks. Readers shouldn't have to think about processors they don't have.
  • Compatibility. The goal is to get off mainstream stacks, not to perpetuate them. Sometimes the right long-term solution is to bump the major version number.
  • Syntax. Mu code is meant to be comprehended by running, not just reading. It will always be just a thin memory-safe veneer over machine code. I don't know how to make higher-level notations both fast and comprehensible, so they are likely to remain slow and comprehensible, useful for prototyping but invariably needing to be rewritten in statements that map 1:1 with machine code. The goal of a prototype should be a risk-free rewrite, thanks to tests that capture all the details of lessons learned.

Toolchain

The Mu stack consists of:

  • the Mu type-safe and memory-safe language;
  • SubX, an unsafe notation for a subset of x86 machine code; and
  • bare SubX, a more rudimentary form of SubX without certain syntax sugar.

All Mu programs get translated through these layers into tiny zero-dependency binaries that run natively. The translators for most levels are built out of lower levels. The translator from Mu to SubX is written in SubX, and the translator from SubX to bare SubX is built in bare SubX. There is also an emulator for Mu's supported subset of x86, that's useful for debugging SubX programs.

Mu programs build natively either on Linux or on Windows using WSL 2. For Macs and other Unix-like systems, use the (much slower) emulator:

./translate_emulated apps/ex2.mu  # 2-5 minutes to emit code.img

Mu programs can be written for two very different environments:

  • At the top-level, Mu programs emit a bootable image that runs without an OS (under emulation; I haven't tested on native hardware yet). There's rudimentary support for some core peripherals: a 1024x768 screen, a keyboard with some key-combinations, a PS/2 mouse that must be polled, a slow ATA disk drive. No hardware acceleration, no virtual memory, no process separation, no multi-tasking, no network. Boot always runs all tests, and only gets to main if all tests pass.

  • The top-level is built using tools created under the linux/ sub-directory. This sub-directory contains an entirely separate set of libraries intended for building programs that run with just a Linux kernel, reading from stdin and writing to stdout. The Mu compiler is such a program, at linux/mu.subx. Individual programs typically run tests if given a command-line argument called test.

The largest program built in Mu today is its prototyping environment for writing slow, interpreted programs in a Lisp-based high-level language.

screenshot of the Mu shell

(For more details, see the shell/ directory.)

While I currently focus on programs without an OS, the linux/ sub-directory is fairly ergonomic. There's a couple of dozen example programs to try out there. It is likely to be the option for a network stack in the foreseeable future; I have no idea how to interact on the network without Linux.

Syntax

The entire stack shares certain properties and conventions. Programs consist of functions and functions consist of statements, each performing a single operation. Operands to statements are always variables or constants. You can't perform a + b*c in a single statement; you have to break it up into two. Variables can live in memory or in registers. Registers must be explicitly specified. There are some shared lexical rules. Comments always start with '#'. Numbers are always written in hex. Many terms can have context-dependent metadata attached after '/'.

Here's an example program in Mu:

ex2.mu

More resources on Mu:

Here's an example program in SubX:

== code
Entry:
  # ebx = 1
  bb/copy-to-ebx  1/imm32
  # increment ebx
  43/increment-ebx
  # exit(ebx)
  e8/call  syscall_exit/disp32

More resources on SubX:

Mirrors and Forks

As of 2022-01, updates to Mu can be downloaded from the following mirrors:

Forks of Mu are encouraged. If you don't like something about this repo, feel free to make a fork. If you show it to me, I'll link to it here. I might even pull features upstream!

  • uCISC: a 16-bit processor being designed from scratch by Robert Butler and programmed with a SubX-like syntax.
  • subv: experimental SubX-like syntax by s-ol bekic for the RISC-V instruction set.
  • mu-x86_64: experimental fork for 64-bit x86 in collaboration with Max Bernstein. It's brought up a few concrete open problems that I don't have good solutions for yet.
  • mu-normie: with a more standard build system for the linux/bootstrap/ directory that organizes the repo by header files and compilation units. Stays in sync with this repo.

Desiderata

If you're still reading, here are some more things to check out:

Credits

Mu builds on many ideas that have come before, especially:

  • Peter Naur for articulating the paramount problem of programming: communicating a codebase to others;
  • Christopher Alexander and Richard Gabriel for the intellectual tools for reasoning about the higher order design of a codebase;
  • David Parnas and others for highlighting the value of separating concerns and stepwise refinement;
  • The folklore of debugging by print and the trace facility in many Lisp systems;
  • Automated tests for showing the value of developing programs inside an elaborate harness;

On a more tactical level, this project has made progress in a series of bursts as I discovered the following resources. In autobiographical order, with no claims of completeness: