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.
// 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)
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)
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);
}