153 lines
6.6 KiB
Markdown
153 lines
6.6 KiB
Markdown
# 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);
|
|
}
|
|
```
|