9.5 KiB
⚙️ ** PVM (PROMETEU VM) — Instruction Set**
1. Overview
The PROMETEU VM is a mandatory virtual machine always present in the logical hardware:
- stack-based
- deterministic
- cycle-oriented
- designed for teaching and inspection
It exists to:
- map high-level language concepts
- make computational cost visible
- allow execution analysis
- serve as the foundation of the PROMETEU cartridge
The PROMETEU VM is simple by choice. Simplicity is a pedagogical tool.
2. Execution Model
2.1 Main Components
The VM has:
- PC (Program Counter) — next instruction
- Operand Stack — value stack
- Call Stack — stores execution frames for function calls
- Scope Stack — stores frames for blocks within a function
- Heap — dynamic memory
- Globals — global variables
- Constant Pool — literals and references
- ROM — cartridge bytecode
- RAM — mutable data
2.2 Execution Cycle
Each instruction executes:
FETCH → DECODE → EXECUTE → ADVANCE PC
Properties:
- every instruction has a fixed cost in cycles
- there is no invisible implicit work
- execution is fully deterministic
3. Fundamental Types
| Type | Description |
|---|---|
integer |
64-bit signed integer |
float |
64-bit floating point |
boolean |
true/false |
string |
immutable UTF-8 |
null |
absence of value |
ref |
heap reference |
Do not exist:
- magic coercions
- implicit casts
- silent overflows
4. Stack Conventions
- Operations use the top of the stack
- Results always return to the stack
- Last pushed = first consumed
Example:
PUSH_CONST 3
PUSH_CONST 4
ADD
State:
[3]
[3, 4]
[7]
5. Instruction Categories
- Flow control
- Stack
- Arithmetic and logic
- Variables
- Functions
- Heap and structures
- Peripherals (syscalls)
- System
6. Instructions — VM Set 1
6.1 Execution Control
| Instruction | Cycles | Description |
|---|---|---|
NOP |
1 | Does nothing |
HALT |
1 | Terminates execution |
JMP addr |
2 | Unconditional jump |
JMP_IF_FALSE addr |
3 | Jumps if top is false |
6.2 Stack
| Instruction | Cycles | Description |
|---|---|---|
PUSH_CONST k |
2 | Pushes constant |
POP |
1 | Removes top |
DUP |
1 | Duplicates top |
SWAP |
1 | Swaps two tops |
6.3 Arithmetic
| Instruction | Cycles |
|---|---|
ADD |
2 |
SUB |
2 |
MUL |
4 |
DIV |
6 |
6.4 Comparison and Logic
| Instruction | Cycles |
|---|---|
EQ |
2 |
NEQ |
2 |
LT |
2 |
GT |
2 |
AND |
2 |
OR |
2 |
NOT |
1 |
6.5 Variables
| Instruction | Cycles | Description |
|---|---|---|
GET_GLOBAL i |
3 | Reads global |
SET_GLOBAL i |
3 | Writes global |
GET_LOCAL i |
2 | Reads local |
SET_LOCAL i |
2 | Writes local |
6.6 Functions
| Instruction | Cycles | Description |
|---|---|---|
CALL addr |
5 | Saves PC and creates a new call frame |
RET |
4 | Returns from function, restoring PC |
PUSH_SCOPE |
3 | Creates a scope within the current function |
POP_SCOPE |
3 | Removes current scope and its local variables |
ABI Rules for Functions:
- Mandatory Return Value: Every function MUST leave exactly one value on the stack before
RET. If the function logic doesn't return a value, it must pushnull. - Stack Cleanup:
RETautomatically clears all local variables (based onstack_base) and re-pushes the return value.
6.7 Heap
| Instruction | Cycles | Description |
|---|---|---|
ALLOC size |
10 | Allocates on heap |
LOAD_REF off |
3 | Reads field |
STORE_REF off |
3 | Writes field |
Heap is:
- finite
- monitored
- accounted for in the CAP
6.8 Peripherals (Syscalls)
| Instruction | Cycles | Description |
|---|---|---|
SYSCALL id |
variable | Call to hardware |
ABI Rules for Syscalls:
- Argument Order: Arguments must be pushed in the order they appear in the call (LIFO stack behavior).
- Example:
gfx.draw_rect(x, y, w, h, color)means:PUSH xPUSH yPUSH wPUSH hPUSH colorSYSCALL 0x1002
- Example:
- Consumption: The native function MUST pop all its arguments from the stack.
- Return Value: If the syscall returns a value, it will be pushed onto the stack by the native implementation. If not, the stack state for the caller remains as it was before pushing arguments.
Implemented Syscalls (v0.1)
| ID | Name | Arguments (Stack) | Return |
|---|---|---|---|
0x0001 |
system.has_cart |
- | bool |
0x0002 |
system.run_cart |
- | - |
0x1001 |
gfx.clear |
color_idx |
- |
0x1002 |
gfx.draw_rect |
x, y, w, h, color_idx |
- |
0x1003 |
gfx.draw_line |
x1, y1, x2, y2, color_idx |
- |
0x1004 |
gfx.draw_circle |
xc, yc, r, color_idx |
- |
0x1005 |
gfx.draw_disc |
xc, yc, r, b_col, f_col |
- |
0x1006 |
gfx.draw_square |
x, y, w, h, b_col, f_col |
- |
0x2001 |
input.get_pad |
button_id |
bool |
0x3001 |
audio.play |
s_id, v_id, vol, pan, pitch |
- |
Button IDs:
0: Up,1: Down,2: Left,3: Right4: A,5: B,6: X,7: Y8: L,9: R10: Start,11: Select
7. Execution Errors
Errors are:
- explicit
- fatal
- never silent
Types:
- stack underflow
- invalid type
- invalid heap
- invalid frame
Generate:
- clear message
- state dump
- stack trace
8. Determinism
Guarantees:
- same input → same result
- same sequence → same cycles
- no speculative execution
- no invisible optimizations
If you see the instruction, you pay for it.
9. Relationship with Languages
Java, TypeScript, Lua etc:
- are source languages
- compiled to this bytecode
- never executed directly
All run on the same VM.
10. Example
Source:
x = 3 + 4;
Bytecode:
PUSH_CONST 3
PUSH_CONST 4
ADD
SET_GLOBAL 0
Cost:
2 + 2 + 2 + 3 = 9 cycles
11. Execution per Tick
The VM does not run infinitely.
It executes:
- until consuming the logical frame budget
- or until
HALT
The budget is defined by the PROMETEU logical hardware (e.g., CYCLES_PER_FRAME).
Example:
vm.step_budget(10_000)
This feeds:
- CAP
- profiling
- certification
12. Logical Frame and FRAME_SYNC
PROMETEU defines logical frame as the minimum unit of consistent game update.
- Input is latched per logical frame (does not change until the logical frame is completed).
- The cycle budget is applied to the logical frame.
- A new logical frame only starts when the current frame ends.
12.1 System Instruction: FRAME_SYNC
The FRAME_SYNC instruction marks the end of the logical frame.
| Instruction | Cycles | Description |
|---|---|---|
FRAME_SYNC |
1 | Finalizes the current logical frame |
Properties:
FRAME_SYNCis a system instruction.- It should not be exposed as a "manual" API to the user.
- Tooling/compiler can inject
FRAME_SYNCautomatically at the end of the main loop.
12.2 Semantics (what happens when it executes)
When executing FRAME_SYNC, the core:
- Finalizes the current logical frame.
- Presents the frame (
gfx.present()orgfx.compose_and_present()depending on the GFX model). - Releases the input latch.
- Resets the budget for the next logical frame.
12.3 Overbudget (when the frame doesn't finish on time)
If the logical frame budget runs out before the VM reaches FRAME_SYNC:
- the VM pauses (PC and stacks remain at the exact point)
- there is no present
- the input latch is maintained
- on the next host tick, the VM continues from where it left off, still in the same logical frame
Practical effect:
- if the code needs 2 budgets to reach
FRAME_SYNC, the game updates at ~30 FPS (logical frame takes 2 ticks) - this is deterministic and reportable in the CAP
15. Extensibility
The Instruction Set is versioned.
Future:
- DMA
- streaming
- vectors
- fictitious coprocessors
No existing instruction changes its meaning.
16. Summary
- stack-based VM
- explicit cost
- deterministic execution
- integrated with CAP
- foundation of every PROMETEU cartridge