# prometeu-bytecode Official contract (ABI) of the PROMETEU ecosystem. This crate defines the Instruction Set Architecture (ISA), the `.pbc` file format (Prometeu ByteCode), and basic tools for assembly (Assembler) and disassembly (Disassembler). ## Design The PVM (Prometeu Virtual Machine) is a **stack-based** machine. Most instructions operate on values at the top of the operand stack. The default multi-byte data format in ROM is **Little-Endian**. ### Stack Notation Convention In the tables below, we use the following notation to represent the state of the stack: `[a, b] -> [c]` Means the instruction removes `a` and `b` from the stack (where `b` was at the top) and pushes `c` to the top. --- ## Instruction Set Architecture (ISA) ### 6.1 Execution Control | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `Nop` | `0x00` | - | `[] -> []` | No operation. | | `Halt` | `0x01` | - | `[] -> []` | Permanently halts VM execution. | | `Jmp` | `0x02` | `addr: u32` | `[] -> []` | Unconditional jump to absolute address `addr`. | | `JmpIfFalse`| `0x03` | `addr: u32` | `[bool] -> []` | Jumps to `addr` if the popped value is `false`. | | `JmpIfTrue` | `0x04` | `addr: u32` | `[bool] -> []` | Jumps to `addr` if the popped value is `true`. | | `Trap` | `0x05` | - | `[] -> []` | Debugger interruption (breakpoint). | ### 6.2 Stack Manipulation | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `PushConst` | `0x10` | `idx: u32` | `[] -> [val]` | Loads the constant at index `idx` from the Constant Pool. | | `Pop` | `0x11` | - | `[val] -> []` | Removes and discards the top value of the stack. | | `Dup` | `0x12` | - | `[val] -> [val, val]` | Duplicates the value at the top of the stack. | | `Swap` | `0x13` | - | `[a, b] -> [b, a]` | Swaps the positions of the two values at the top. | | `PushI64` | `0x14` | `val: i64` | `[] -> [i64]` | Pushes an immediate 64-bit integer. | | `PushF64` | `0x15` | `val: f64` | `[] -> [f64]` | Pushes an immediate 64-bit floating point. | | `PushBool` | `0x16` | `val: u8` | `[] -> [bool]` | Pushes a boolean (0=false, 1=true). | | `PushI32` | `0x17` | `val: i32` | `[] -> [i32]` | Pushes an immediate 32-bit integer. | | `PopN` | `0x18` | `n: u16` | `[...] -> [...]` | Removes `n` values from the stack at once. | ### 6.3 Arithmetic The VM performs automatic type promotion (e.g., `i32` + `f64` results in `f64`). | OpCode | Value | Stack | Description | | :--- | :--- | :--- | :--- | | `Add` | `0x20` | `[a, b] -> [a + b]` | Adds the two top values. | | `Sub` | `0x21` | `[a, b] -> [a - b]` | Subtracts `b` from `a`. | | `Mul` | `0x22` | `[a, b] -> [a * b]` | Multiplies the two top values. | | `Div` | `0x23` | `[a, b] -> [a / b]` | Divides `a` by `b`. Error if `b == 0`. | | `Neg` | `0x3E` | `[a] -> [-a]` | Negates the numeric sign. | ### 6.4 Logic and Comparison | OpCode | Value | Stack | Description | | :--- | :--- | :--- | :--- | | `Eq` | `0x30` | `[a, b] -> [bool]` | Tests equality. | | `Neq` | `0x31` | `[a, b] -> [bool]` | Tests inequality. | | `Lt` | `0x32` | `[a, b] -> [bool]` | `a < b` | | `Gt` | `0x33` | `[a, b] -> [bool]` | `a > b` | | `Lte` | `0x3C` | `[a, b] -> [bool]` | `a <= b` | | `Gte` | `0x3D` | `[a, b] -> [bool]` | `a >= b` | | `And` | `0x34` | `[a, b] -> [bool]` | Logical AND (boolean). | | `Or` | `0x35` | `[a, b] -> [bool]` | Logical OR (boolean). | | `Not` | `0x36` | `[a] -> [!a]` | Logical NOT. | | `BitAnd` | `0x37` | `[a, b] -> [int]` | Bitwise AND. | | `BitOr` | `0x38` | `[a, b] -> [int]` | Bitwise OR. | | `BitXor` | `0x39` | `[a, b] -> [int]` | Bitwise XOR. | | `Shl` | `0x3A` | `[a, b] -> [int]` | Shift Left: `a << b`. | | `Shr` | `0x3B` | `[a, b] -> [int]` | Shift Right: `a >> b`. | ### 6.5 Variables and Memory | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `GetGlobal`| `0x40` | `idx: u32` | `[] -> [val]` | Loads value from global `idx`. | | `SetGlobal`| `0x41` | `idx: u32` | `[val] -> []` | Stores top of stack in global `idx`. | | `GetLocal` | `0x42` | `idx: u32` | `[] -> [val]` | Loads local `idx` from the current frame. | | `SetLocal` | `0x43` | `idx: u32` | `[val] -> []` | Stores top of stack in local `idx` of the current frame. | ### 6.6 Functions and Scope | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `Call` | `0x50` | `addr: u32, args: u32` | `[a1, a2] -> [...]` | Calls `addr`. The `args` values at the top become locals of the new frame. | | `Ret` | `0x51` | - | `[val] -> [val]` | Returns from the current function, clearing the frame and returning the top value. | | `PushScope`| `0x52` | - | `[] -> []` | Starts a sub-scope (block) for temporary locals. | | `PopScope` | `0x53` | - | `[] -> []` | Ends sub-scope, removing locals created in it from the stack. | ### 6.7 Heap (Dynamic Memory) | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `Alloc` | `0x60` | `size: u32` | `[] -> [ref]` | Allocates `size` slots on the heap and returns a reference. | | `LoadRef` | `0x61` | `offset: u32`| `[ref] -> [val]` | Reads value from the heap at address `ref + offset`. | | `StoreRef`| `0x62` | `offset: u32`| `[ref, val] -> []` | Writes `val` to the heap at address `ref + offset`. | ### 6.8 System and Synchronization | OpCode | Value | Operands | Stack | Description | | :--- | :--- | :--- | :--- | :--- | | `Syscall` | `0x70` | `id: u32` | `[...] -> [...]` | Invokes a system/firmware function. The stack depends on the syscall. | | `FrameSync`| `0x80` | - | `[] -> []` | Marks the end of processing for the current logical frame (60 FPS). | --- ## PBC Structure (Prometeu ByteCode) PBC is the official binary format for Prometeu programs. ```rust // Example of how to load a PBC file let bytes = std::fs::read("game.pbc")?; let pbc = prometeu_bytecode::pbc::parse_pbc(&bytes)?; println!("ROM size: {} bytes", pbc.rom.len()); println!("Constants: {}", pbc.cp.len()); ``` --- ## Assembler and Disassembler This crate provides tools to facilitate code generation and inspection. ### Assembly (Assembler) ```rust use prometeu_bytecode::asm::{assemble, Asm, Operand}; use prometeu_bytecode::opcode::OpCode; let instructions = vec![ Asm::Op(OpCode::PushI32, vec![Operand::I32(10)]), Asm::Op(OpCode::PushI32, vec![Operand::I32(20)]), Asm::Op(OpCode::Add, vec![]), Asm::Op(OpCode::Halt, vec![]), ]; let rom_bytes = assemble(&instructions).unwrap(); ``` ### Disassembly (Disassembler) ```rust use prometeu_bytecode::disasm::disasm; let rom = vec![/* ... bytes ... */]; let code = disasm(&rom); for instr in code { println!("{:04X}: {:?} {:?}", instr.pc, instr.opcode, instr.operands); } ```