Vihaco Author’s Guide
This guide shows you how to build a virtual machine with vihaco. You’ll define its instructions, write the devices that execute them, and connect those devices into a machine. Then you’ll load a program and run it.
Version: these docs cover the new program-image protocols in the current vihaco source. Use the setup below for the examples, and keep all vihaco dependencies on the same revision.
[package]
name = "my-machine"
version = "0.1.0"
edition = "2024"
[dependencies]
vihaco = { git = "https://github.com/QuEraComputing/vihaco", features = ["program-image-execution"] }
vihaco-stdlib = { git = "https://github.com/QuEraComputing/vihaco", features = ["program-image-execution"] }
eyre = "0.6"
Most of the declarations and execution APIs you’ll use come from vihaco.
vihaco-stdlib provides the program dialect and loading examples. If you’d like
a ready-made computation device, add vihaco-cpu from the same revision.
You’ll also need a Rust toolchain that supports the workspace’s edition and
dependencies.
Read the guide
| Chapter | What you’ll learn |
|---|---|
| The mental model | Meet the pieces and see how a program moves through them |
| Your first machine | Write a component and run it in a complete program |
| Essential concepts | The minimum needed to define instructions, implement components, and wire a VM |
| Dialects and instructions | Define the operations your components will implement |
| Writing components | Give a device state and implement Execute |
| Preparing messages | Supply runtime input with BuildMessage |
| Stack inputs and outputs | Move typed operands into and out of a component |
| Writing composites | Connect devices, including nested ones, and route instructions |
| Executing one instruction | Follow Dispatch, Step, BuildMessage, Execute, and Apply |
| Handling effects | Decide what happens to a component’s results |
| Running programs | Work with frames, control flow, entry, and recovery |
| Images and Loadables | Own programs, replace images, and reset execution |
| Parsing source | Give instructions a source spelling |
| Loading SST programs | Read sections, prepare metadata, and resolve symbols |
| Emitting SST from a compiler | Produce the file structure, instruction syntax, and metadata a loader expects |
| Binary formats | Encode programs and plan for compatibility |
| Larger machines | Share message preparation and steps, and swap backends |
| Testing and extending | Check behavior and add new pieces |
The bare bones: instructions, components, and a VM
After your first machine, read the short essential concepts page. The three authoring tasks are:
- Define instructions: declare a
#[dialect]containing#[instruction]types for operations and their encoded operands. See dialects and instructions. - Define components: declare supported dialects with
#[component]and#[instructions { ... }], then implementExecute<I>for each operation. Choose its runtime message, effect, and error types. See writing components. - Wire a VM: put devices in a
#[composite]and supplyStepimplementations that prepare messages, execute operations, and handle effects. The macro lifts and flattens the devices’ instructions into a generated instruction set; you don’t manually define a machine instruction enum. Its executable type is<Machine as HasInstructionSet>::Runtime, whereMachineis your composite. See writing composites and executing one instruction.
Find your starting point
If you’re new to vihaco, start with the mental model and first machine. After that, you can follow the chapters in order or focus on the part you’re building.
For a component, read about dialects, execution, and the messages and effects that connect it to a machine. For a composite, keep going through routing, steps, and program ownership. If you’re writing a source or binary frontend, start with emitting SST from a compiler for the producer contract, or binary formats for encoded programs.
Keep the pattern reference nearby for parser grammar details. The API reference covers individual Rust types and methods.