The Roc machine
Each program on the page is a test from Cobblestone, an operating system written in Codex. In Cobblestone's own test runs these programs are compiled to x86 and run in QEMU or in codex-vm, Cobblestone's emulator. Here they run on a machine written in Roc instead, and this page describes that machine.
What runs, and what does not
rocemit turns each Codex program into Roc, one module for the test and one for each Codex chapter it uses; the page's Roc pane shows them. That Roc is built for WebAssembly together with the machine. Nothing here imitates x86 instructions. Cobblestone's lowest layer (booting, interrupts, the scheduler) is x86 code that Codex's compiler writes, not Codex, so the machine stands in for it.
One value holding every device
The machine is a single Roc record with a field for each device. Every Codex builtin that touches hardware, such as reading a disk sector, writing a byte to an I/O port or sending a network frame, becomes a function that takes the machine and hands back the machine as it is afterwards. The program passes the machine along from call to call, so a run is an ordinary Roc computation from the first machine to the last.
What "boot" means here
A run starts from the state that Cobblestone's x86 boot code leaves behind, and nothing more:
- a process table whose first entry is the running program;
- that program's capability word, the bits saying what it may do (use the console, the disk, the network), granted from the effects its Codex entry point declares;
- the network card found, and its hardware address copied into memory where the kernel keeps it;
- for a test that asks for a screen, the screen's width, height and row length in memory, written where codex-vm writes them.
The machine puts no files, programs or data anywhere. Whatever a program finds, it brought with it.
Where a program's inputs come from
A Cobblestone test is a .codex file with an .expected file beside it
holding the output it must print. It may also bring:
.diskand.disk2: disk image files, attached as the first and second drive;.keys: keystrokes typed while it runs;.vmargs: codex-vm command-line flags that choose device options, such as which network card is present.
fat16-list's files are on its disk image. fat16-list.disk is a 16 MB
image committed beside the test in Cobblestone's tree. It is partitioned like a boot disk, and its
partition holds a FAT16 volume with an EFI directory, EFI/BOOT/BOOTX64.EFI
and CODEX.CDX. The page fetches the image and loads it into drive 0 before the run; the
program's FAT16 code, which is Codex turned into Roc, reads the partition table, the file allocation
table and the directory sectors through the disk. fat16-write brings an image of its own, writes a
file into the page's copy of it, and the Disk pane shows the sectors that changed. Reloading the page
starts from the original image again.
The devices
| device | what the machine does |
|---|---|
| memory | Bytes addressed up to 236, stored sparsely, so a program can use the addresses Cobblestone's kernel uses. An address no device claims stops the run by name. |
| disk drives | The IDE channel, the classic PC disk interface: two drive positions, each an image or empty, answering the commands to read a sector, write a sector and identify the drive. On this page a drive is the page's copy of the image, read and written a sector at a time. |
| PCI configuration space | The table a driver scans to discover what hardware is plugged in, with the devices codex-vm lists. |
| NE2000 network card | The card's registers, its 32 KB of on-card memory and its receive ring, as codex-vm models them. |
| the network behind the card | A small stand-in for codex-vm's network address translation: it answers ARP (which hardware address has this IP address?) and DHCP (please give me an IP address) itself. Anything that would need the real internet, such as a DNS lookup or a TCP connection, stops the run with a message saying so. |
| Intel e1000 network card | The other card codex-vm offers, with its fault-injection options, for the tests that choose it. |
| timers | The PIT, the HPET and the local APIC timer, the PC's three timer chips, counting the machine's own clock rather than wall time. |
| keyboard | A queue of the keystrokes a test brings, delivered as the clock reaches them. |
| screen | codex-vm's framebuffer: a block of ordinary memory at a fixed address that a
program draws into, four bytes a pixel. A test's -gop flags choose its width, height and
how many pixels each row takes in memory. When the run ends, the page draws what the program left
there. |
| console | The lines a program prints, which is what its test checks. |
A program that reaches a device codex-vm has and this machine does not, such as the real-time clock or the Bochs graphics adapter, stops with a message naming that device rather than getting a made-up answer.
The machine's clock
Time on the machine is a counter: every access to a device register moves it forward 10 microseconds, and reading or writing plain memory does not. A run therefore takes the same machine time on every computer, which is what lets tests that measure time pass here.
What is hand-written
The machine is hand-written Roc, in roc-apps/machine/roc, one module per device. The programs are not: their Roc is exactly what rocemit wrote from the Codex source, apart from three lines connecting the program to the page.