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

Testing and extending

Start by testing behavior where you define it. You can check a component’s computation without loading any source files. A loaded-program test can then check that the routing, metadata, and result handling all work together.

Test each boundary

BoundaryWhat to check
Component executionResults, state changes, and instruction-specific errors
Message preparationInput order, reference lookup, validation, and input consumed before an error
Step policyThe destination, effect application, and propagated errors
Program executionEntry arguments, calls/returns, branch targets, protected locals, and results
LoadingPreserved metadata, checked declarations, resolved symbols, and source ownership
Loadable lifecycleReset, replacement restrictions, and retained device state
Binary formatRound trips, malformed input rejection, and agreement with source execution

For a shared builder or step, check the behavior it promises rather than recreating its body in the test. Use different operand values for operations where order matters, so swapping them can’t pass unnoticed.

Add an instruction

Define the type in its dialect, give it a source spelling, and document its behavior and runtime inputs/results. Each component declaring the dialect needs an Execute<I> impl for it.

If syntax and runtime operands differ, add lowering. Then check whether your existing builders and steps cover the instruction. Add preparation or result handling where needed, and update any persistent codec and its compatibility policy separately.

Add a device or backend

Declare the device’s dialect support and implement execution. Give it a unique code in the composite, then provide steps for its routes. A backend that meets an existing wrapper contract can reuse the composite’s input and result handling.

Add an independently loaded program

Define its composite and context, build and validate its module, and pair its Image and machine in a Loadable owned by an outer runtime. Decide how the application starts it and handles its output. Keep invocation reset and device reset as separate choices.

Keep documentation executable

From a vihaco checkout, run the guide’s Rust blocks and examples with:

cargo test -p vihaco-doctests --features program-image-execution --all-targets
cargo test -p vihaco-doctests --features program-image-execution --doc

Make complete examples runnable. For a smaller excerpt, you can hide setup lines with rustdoc’s # prefix while still checking the whole example. Save ignore for deliberately illustrative fragments. Use the API reference when you need an exact trait or method signature.

On this page
  1. Test each boundary
  2. Add an instruction
  3. Add a device or backend
  4. Add an independently loaded program
  5. Keep documentation executable