vihaco / virtual ISA & machine framework
Author’s guide
  1. Start here
  2. The mental model
  3. Your first machine
  4. Essential concepts
  5. Dialects and instructions
  6. Writing components
  7. Preparing messages
  8. Stack inputs and outputs
  9. Writing composites
  10. Executing one instruction
  11. Handling effects
  12. Running programs
  13. Images and Loadables
  14. Parsing source
  15. Loading SST programs
  16. Emitting SST from a compiler
  17. Binary formats
  18. Patterns for larger machines
  19. Testing and extending
  20. Pattern parser reference

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

ChapterWhat you’ll learn
The mental modelMeet the pieces and see how a program moves through them
Your first machineWrite a component and run it in a complete program
Essential conceptsThe minimum needed to define instructions, implement components, and wire a VM
Dialects and instructionsDefine the operations your components will implement
Writing componentsGive a device state and implement Execute
Preparing messagesSupply runtime input with BuildMessage
Stack inputs and outputsMove typed operands into and out of a component
Writing compositesConnect devices, including nested ones, and route instructions
Executing one instructionFollow Dispatch, Step, BuildMessage, Execute, and Apply
Handling effectsDecide what happens to a component’s results
Running programsWork with frames, control flow, entry, and recovery
Images and LoadablesOwn programs, replace images, and reset execution
Parsing sourceGive instructions a source spelling
Loading SST programsRead sections, prepare metadata, and resolve symbols
Emitting SST from a compilerProduce the file structure, instruction syntax, and metadata a loader expects
Binary formatsEncode programs and plan for compatibility
Larger machinesShare message preparation and steps, and swap backends
Testing and extendingCheck 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 implement Execute<I> for each operation. Choose its runtime message, effect, and error types. See writing components.
  • Wire a VM: put devices in a #[composite] and supply Step implementations 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, where Machine is 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.

On this page
  1. Read the guide
  2. The bare bones: instructions, components, and a VM
  3. Find your starting point