< [Back](chapter-1.md) | [Summary](table-of-contents.md) | [Next](chapter-3.md) > # **Prometeu Virtual Machine (PVM)** This chapter defines the execution model, value system, calling convention, memory model, and host interface of the Prometeu Virtual Machine. The PVM is a **deterministic, stack-based VM** designed for a 2D fantasy console environment. Its primary goal is to provide predictable performance, safe memory access, and a stable execution contract suitable for real-time games running at a fixed frame rate. fileciteturn2file0 --- ## 1 Core Design Principles The PVM is designed around the following constraints: 1. **Deterministic execution**: no hidden threads or asynchronous callbacks. 2. **Frame-based timing**: execution is bounded by frame time. 3. **Safe memory model**: all heap objects are accessed through handles. 4. **Simple compilation target**: stack-based bytecode with verified control flow. 5. **Stable ABI**: multi-value returns with fixed slot semantics. 6. **First-class functions**: functions can be passed, stored, and returned. --- ## 2 Execution Model The PVM executes bytecode in a **frame loop**. Each frame: 1. The firmware enters the VM. 2. The VM runs until: * the frame budget is consumed, or * a `FRAME_SYNC` instruction is reached. 3. At `FRAME_SYNC`: * events are delivered * input is sampled * optional GC may run 4. Control returns to the firmware. `FRAME_SYNC` is the **primary safepoint** in the system. --- ## 3 Value Types All runtime values are stored in VM slots as a `Value`. ### Primitive value types (stack values) | Type | Description | | ------- | --------------------- | | `int` | 64-bit signed integer | | `bool` | Boolean value | | `float` | 64-bit floating point | ### Built-in vector and graphics types (stack values) These are treated as VM primitives with dedicated opcodes: | Type | Description | | ------- | --------------------------------- | | `vec2` | 2D vector (x, y) | | `color` | Packed color value | | `pixel` | Combination of position and color | These types: * live entirely on the stack * are copied by value * never allocate on the heap ### Heap values All user-defined objects live on the heap and are accessed via **handles**. | Type | Description | | -------- | -------------------------- | | `handle` | Reference to a heap object | | `null` | Null handle | Handles may refer to: * user objects * arrays * strings * closures --- ## 4 Handles and Gate Table Heap objects are accessed through **handles**. A handle is a pair: ``` handle = { index, generation } ``` The VM maintains a **gate table**: ``` GateEntry { alive: bool generation: u32 base: usize slots: u32 type_id: u32 } ``` When an object is freed: * its gate entry is marked dead * its generation is incremented If a handle’s generation does not match the gate entry, the VM traps. This prevents use-after-free bugs. --- ## 5 Heap Model * All user objects live in the heap. * Objects are fixed-layout blocks of slots. * No inheritance at the memory level. * Traits/interfaces are resolved by the compiler or via vtables. Built-in types remain stack-only. Heap objects include: * user structs/classes * strings * arrays * closures --- ## 6 Tuples and Multi-Return ABI The PVM supports **multi-value returns**. ### Tuple rules * Tuples are **stack-only**. * Maximum tuple arity is **N = 6**. * Tuples are not heap objects by default. * To persist a tuple, it must be explicitly boxed. ### Call convention Each function declares a fixed `ret_slots` value. At call time: 1. Caller prepares arguments. 2. `CALL` transfers control. 3. Callee executes. 4. `RET` leaves exactly `ret_slots` values on the stack. The verifier ensures that: * all control paths produce the same `ret_slots` * stack depth is consistent. --- ## 7 Call Stack and Frames The VM uses a **call stack**. Each frame contains: ``` Frame { return_pc base_pointer ret_slots } ``` Execution uses only the following call instructions: | Opcode | Description | | ------ | ---------------------- | | `CALL` | Calls a function by id | | `RET` | Returns from function | There is no separate `PUSH_FRAME` or `POP_FRAME` instruction in the public ISA. --- ## 8 Closures and First-Class Functions Closures are heap objects and represent **function values**. The PVM treats functions as **first-class values**. This means: * Functions can be stored in variables. * Functions can be passed as arguments. * Functions can be returned from other functions. * All function values are represented as closures. Even functions without captures are represented as closures with an empty capture set. ### Closure layout ``` Closure { func_id captures[] } ``` Captures are stored as handles or value copies. All closure environments are part of the GC root set. ### Direct and indirect calls The PVM supports two forms of function invocation: | Opcode | Description | | -------------- | -------------------------------------- | | `CALL` | Direct call by function id | | `CALL_CLOSURE` | Indirect call through a closure handle | For `CALL_CLOSURE`: 1. The closure handle is read from the stack. 2. The VM extracts the `func_id` from the closure. 3. The function is invoked using the closure’s captures as its environment. The verifier ensures that: * The closure handle is valid. * The target function’s arity matches the call site. * The `ret_slots` contract is respected. --- ## 9 Coroutines (Deterministic) The PVM supports **cooperative coroutines**. Characteristics: * Coroutines are scheduled deterministically. * No preemption. * No parallel execution. * All scheduling happens at safepoints. Each coroutine contains: ``` Coroutine { call_stack operand_stack state } ``` ### Coroutine instructions | Opcode | Description | | ------- | -------------------------- | | `SPAWN` | Creates a coroutine | | `YIELD` | Suspends current coroutine | | `SLEEP` | Suspends for N frames | Scheduling is: * round-robin * deterministic * bounded by frame budget Coroutine stacks are part of the GC root set. --- ## 10 Garbage Collection The PVM uses a **mark-sweep collector**. ### GC rules * GC runs only at **safepoints**. * The primary safepoint is `FRAME_SYNC`. * GC is triggered by: * heap thresholds, or * allocation pressure. ### Root set The GC marks from: * operand stack * call stack frames * global variables * coroutine stacks * closure environments * host-held handles The collector: * does not compact memory (v1) * uses free lists for reuse --- ## 11 Event and Interrupt Model The PVM does not allow asynchronous callbacks. All events are: * queued by the firmware * delivered at `FRAME_SYNC` This ensures: * deterministic execution * predictable frame timing Coroutines are the only supported concurrency mechanism. --- ## 12 Host Interface (Syscalls) All hardware access occurs through syscalls. Syscalls are: * synchronous * deterministic * capability-checked They operate on the following subsystems: ### Graphics * tilebanks * layers * sprites * palette control * fade registers * frame present ### Audio * voice allocation * play/stop * volume/pan/pitch * steal policy ### Input * sampled once per frame * exposed as frame state ### Assets Asset banks are **host-owned memory**. The VM interacts through handles: | Syscall | Description | | -------------- | ---------------------------- | | `asset.load` | Request asset load into slot | | `asset.status` | Query load state | | `asset.commit` | Activate loaded asset | Asset memory: * is not part of the VM heap * is not scanned by GC ### Save Memory (MEMCARD) | Syscall | Description | | --------------- | --------------- | | `mem.read_all` | Read save data | | `mem.write_all` | Write save data | | `mem.commit` | Persist save | | `mem.size` | Query capacity | --- ## 13 Verifier Requirements Before execution, bytecode must pass the verifier. The verifier ensures: 1. Valid jump targets 2. Stack depth consistency 3. Correct `ret_slots` across all paths 4. Handle safety rules 5. Closure call safety 6. No invalid opcode sequences Invalid bytecode is rejected. --- ## 14 Summary The Prometeu VM is: * stack-based * deterministic * frame-synchronized * handle-based for heap access * multi-return capable * first-class function capable * coroutine-driven for concurrency This design balances: * ease of compilation * predictable performance * safety and debuggability * suitability for real-time 2D games. < [Back](chapter-1.md) | [Summary](table-of-contents.md) | [Next](chapter-3.md) >