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

The mental model

When you build a vihaco machine, you choose some instructions and write devices that know how to execute them. You can give the same instructions to different devices, or reuse a device in machines that supply its inputs and handle its outputs differently.

Addition is a small example. An addition instruction can have no encoded fields at all: its component receives two numbers in a message and returns their sum as an effect. The surrounding machine decides to take the numbers from the current invocation’s stack and put the result back there. The component just works with the numbers.

The building blocks

These names come up throughout the guide:

ConceptWhat it does
DialectDefines a vocabulary of named instructions and what they mean
InstructionDescribes an operation and any operands encoded in the program
ComponentOwns device state and implements instructions through Execute<I>
MessageSupplies input when an instruction runs
EffectCarries a successful execution result back to the caller
CompositeOwns devices and connects their execution through steps you write
ModuleHolds code and tables such as functions, strings, and labels
ImageOwns a module as program data
ExecutionStateHolds one invocation’s operands, locals, frames, and control state
LoadablePairs an image with the composite that executes it

From source to program data

Before a program can run, its source becomes an image:

source text
    → parsed syntax instructions and header declarations
    → validated metadata and symbolic lowering
    → LocalModule containing runtime instructions and metadata
    → Image

Parsing checks how instructions are spelled. Lowering turns source operands, such as function names and quoted strings, into the operands execution needs. Metadata describes the functions’ signatures, reserved locals, instruction ranges, and which function to enter. Your loader prepares all of this before execution starts.

From instruction to state change

Once the image is ready, the runner borrows its instructions and sends them through the machine:

runner borrows an instruction from the image
    → Dispatch selects a device route
    → authored Step prepares input, executes, and handles the result
        → BuildMessage prepares the component's message
        → Execute mutates the component and returns its effect
        → Apply or custom handling continues the effect

You write the steps and decide what happens to their results. A step can use BuildMessage to prepare input, or construct the message itself. It might put a result on the stack, collect a record, configure another device, or perform another action. Vihaco doesn’t generate a step or choose an effect-delivery policy for you.

Ownership makes the pieces fit

The image lives beside the mutable machine. That lets execution borrow code and metadata while changing components, without cloning instructions. Loadable<Image<Instruction>, Machine> is a typical way to own the pair.

Inside the machine, ExecutionState owns invocation storage and control flow. A CPU component computes with the values you give it; the program counter and operand stack live in execution state. Other components keep their own device state too. Resetting an invocation and resetting a device are separate operations.

Your first machine puts these pieces together.

On this page
  1. The building blocks
  2. From source to program data
  3. From instruction to state change
  4. Ownership makes the pieces fit