From ba2344e324a6f8a961c2d20d104ab6ee4bef3f2a Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 3 Feb 2026 20:58:16 +0000 Subject: [PATCH] pr 00.1 decouple more code from vm and hardware --- Cargo.lock | 4 + compilation_errors.txt | 604 ------------------ compilation_errors_2.txt | 69 -- crates/prometeu-abi/Cargo.toml | 1 + crates/prometeu-abi/src/lib.rs | 6 +- .../prometeu-abi/src/virtual_machine/mod.rs | 12 + .../src/virtual_machine/vm_init_error.rs | 8 + crates/prometeu-core/Cargo.toml | 1 + crates/prometeu-core/src/debugger_protocol.rs | 146 ----- crates/prometeu-core/src/hardware/asset.rs | 2 +- crates/prometeu-core/src/hardware/audio.rs | 23 +- crates/prometeu-core/src/hardware/gfx.rs | 4 +- crates/prometeu-core/src/hardware/mod.rs | 33 +- crates/prometeu-core/src/hardware/pad.rs | 4 +- crates/prometeu-core/src/hardware/touch.rs | 4 +- .../src/prometeu_os/prometeu_os.rs | 3 +- crates/prometeu-core/src/telemetry.rs | 123 ---- .../prometeu-core/src/virtual_machine/mod.rs | 93 +-- .../src/virtual_machine/virtual_machine.rs | 3 +- crates/prometeu-hardware-contract/Cargo.toml | 2 + .../prometeu-hardware-contract/src/asset.rs | 21 + .../prometeu-hardware-contract/src/audio.rs | 38 ++ crates/prometeu-hardware-contract/src/gfx.rs | 51 ++ .../src/hardware.rs | 22 + .../src}/host_context.rs | 9 +- .../src/host_return.rs | 33 + .../src/input_signals.rs | 23 + crates/prometeu-hardware-contract/src/lib.rs | 23 + .../src/native_helpers.rs | 25 + .../src/native_interface.rs | 14 + crates/prometeu-hardware-contract/src/pad.rs | 20 + .../prometeu-hardware-contract/src/touch.rs | 9 + test-cartridges/canonical/golden/program.pbc | Bin 3727 -> 3727 bytes test-cartridges/test01/cartridge/program.pbc | Bin 3727 -> 3727 bytes 34 files changed, 345 insertions(+), 1088 deletions(-) delete mode 100644 compilation_errors.txt delete mode 100644 compilation_errors_2.txt create mode 100644 crates/prometeu-abi/src/virtual_machine/mod.rs create mode 100644 crates/prometeu-abi/src/virtual_machine/vm_init_error.rs delete mode 100644 crates/prometeu-core/src/debugger_protocol.rs delete mode 100644 crates/prometeu-core/src/telemetry.rs create mode 100644 crates/prometeu-hardware-contract/src/asset.rs create mode 100644 crates/prometeu-hardware-contract/src/audio.rs create mode 100644 crates/prometeu-hardware-contract/src/gfx.rs create mode 100644 crates/prometeu-hardware-contract/src/hardware.rs rename crates/{prometeu-core/src/virtual_machine => prometeu-hardware-contract/src}/host_context.rs (73%) create mode 100644 crates/prometeu-hardware-contract/src/host_return.rs create mode 100644 crates/prometeu-hardware-contract/src/input_signals.rs create mode 100644 crates/prometeu-hardware-contract/src/native_helpers.rs create mode 100644 crates/prometeu-hardware-contract/src/native_interface.rs create mode 100644 crates/prometeu-hardware-contract/src/pad.rs create mode 100644 crates/prometeu-hardware-contract/src/touch.rs diff --git a/Cargo.lock b/Cargo.lock index af27ed27..30605014 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,6 +2192,7 @@ dependencies = [ name = "prometeu-abi" version = "0.1.0" dependencies = [ + "prometeu-bytecode", "serde", "serde_json", ] @@ -2236,6 +2237,7 @@ version = "0.1.0" dependencies = [ "prometeu-abi", "prometeu-bytecode", + "prometeu-hardware-contract", "serde", "serde_json", "url", @@ -2245,6 +2247,8 @@ dependencies = [ name = "prometeu-hardware-contract" version = "0.1.0" dependencies = [ + "prometeu-abi", + "prometeu-bytecode", "serde", "serde_json", ] diff --git a/compilation_errors.txt b/compilation_errors.txt deleted file mode 100644 index abb3282d..00000000 --- a/compilation_errors.txt +++ /dev/null @@ -1,604 +0,0 @@ - Checking prometeu-core v0.1.0 (/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/prometeu-core) -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/firmware/firmware_step_hub_home.rs:20:29 - | -20 | if ctx.hw.pad().start.down { - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -20 | if ctx.hw.pad().start().down { - | ++ - -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/firmware/firmware_step_crash_screen.rs:27:25 - | -27 | if ctx.hw.pad().start.down { - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -27 | if ctx.hw.pad().start().down { - | ++ - -error[E0615]: attempted to take value of method `up` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:380:28 - | -380 | 0 => Some(&pad.up), - | ^^ method, not a field - | -help: use parentheses to call the method - | -380 | 0 => Some(&pad.up()), - | ++ - -error[E0615]: attempted to take value of method `down` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:381:28 - | -381 | 1 => Some(&pad.down), - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -381 | 1 => Some(&pad.down()), - | ++ - -error[E0615]: attempted to take value of method `left` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:382:28 - | -382 | 2 => Some(&pad.left), - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -382 | 2 => Some(&pad.left()), - | ++ - -error[E0615]: attempted to take value of method `right` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:383:28 - | -383 | 3 => Some(&pad.right), - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -383 | 3 => Some(&pad.right()), - | ++ - -error[E0615]: attempted to take value of method `a` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:384:28 - | -384 | 4 => Some(&pad.a), - | ^ method, not a field - | -help: use parentheses to call the method - | -384 | 4 => Some(&pad.a()), - | ++ - -error[E0615]: attempted to take value of method `b` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:385:28 - | -385 | 5 => Some(&pad.b), - | ^ method, not a field - | -help: use parentheses to call the method - | -385 | 5 => Some(&pad.b()), - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:386:28 - | -386 | 6 => Some(&pad.x), - | ^ method, not a field - | -help: use parentheses to call the method - | -386 | 6 => Some(&pad.x()), - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:387:28 - | -387 | 7 => Some(&pad.y), - | ^ method, not a field - | -help: use parentheses to call the method - | -387 | 7 => Some(&pad.y()), - | ++ - -error[E0615]: attempted to take value of method `l` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:388:28 - | -388 | 8 => Some(&pad.l), - | ^ method, not a field - | -help: use parentheses to call the method - | -388 | 8 => Some(&pad.l()), - | ++ - -error[E0615]: attempted to take value of method `r` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:389:28 - | -389 | 9 => Some(&pad.r), - | ^ method, not a field - | -help: use parentheses to call the method - | -389 | 9 => Some(&pad.r()), - | ++ - -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:390:29 - | -390 | 10 => Some(&pad.start), - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -390 | 10 => Some(&pad.start()), - | ++ - -error[E0615]: attempted to take value of method `select` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:391:29 - | -391 | 11 => Some(&pad.select), - | ^^^^^^ method, not a field - | -help: use parentheses to call the method - | -391 | 11 => Some(&pad.select()), - | ++ - -error[E0615]: attempted to take value of method `up` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:398:27 - | -398 | 0 => hw.pad().up.down, - | ^^ method, not a field - | -help: use parentheses to call the method - | -398 | 0 => hw.pad().up().down, - | ++ - -error[E0615]: attempted to take value of method `down` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:399:27 - | -399 | 1 => hw.pad().down.down, - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -399 | 1 => hw.pad().down().down, - | ++ - -error[E0615]: attempted to take value of method `left` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:400:27 - | -400 | 2 => hw.pad().left.down, - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -400 | 2 => hw.pad().left().down, - | ++ - -error[E0615]: attempted to take value of method `right` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:401:27 - | -401 | 3 => hw.pad().right.down, - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -401 | 3 => hw.pad().right().down, - | ++ - -error[E0615]: attempted to take value of method `a` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:402:27 - | -402 | 4 => hw.pad().a.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -402 | 4 => hw.pad().a().down, - | ++ - -error[E0615]: attempted to take value of method `b` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:403:27 - | -403 | 5 => hw.pad().b.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -403 | 5 => hw.pad().b().down, - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:404:27 - | -404 | 6 => hw.pad().x.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -404 | 6 => hw.pad().x().down, - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:405:27 - | -405 | 7 => hw.pad().y.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -405 | 7 => hw.pad().y().down, - | ++ - -error[E0615]: attempted to take value of method `l` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:406:27 - | -406 | 8 => hw.pad().l.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -406 | 8 => hw.pad().l().down, - | ++ - -error[E0615]: attempted to take value of method `r` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:407:27 - | -407 | 9 => hw.pad().r.down, - | ^ method, not a field - | -help: use parentheses to call the method - | -407 | 9 => hw.pad().r().down, - | ++ - -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:408:28 - | -408 | 10 => hw.pad().start.down, - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -408 | 10 => hw.pad().start().down, - | ++ - -error[E0615]: attempted to take value of method `select` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:409:28 - | -409 | 11 => hw.pad().select.down, - | ^^^^^^ method, not a field - | -help: use parentheses to call the method - | -409 | 11 => hw.pad().select().down, - | ++ - -error[E0609]: no field `sprites` on type `&mut dyn GfxBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:963:34 - | -963 | hw.gfx_mut().sprites[index] = crate::model::Sprite { - | ^^^^^^^ unknown field - -error[E0615]: attempted to take value of method `x` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1031:41 - | -1031 | ret.push_int(hw.touch().x as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1031 | ret.push_int(hw.touch().x() as i64); - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1035:41 - | -1035 | ret.push_int(hw.touch().y as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1035 | ret.push_int(hw.touch().y() as i64); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1039:42 - | -1039 | ret.push_bool(hw.touch().f.down); - | ^ method, not a field - | -help: use parentheses to call the method - | -1039 | ret.push_bool(hw.touch().f().down); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1043:42 - | -1043 | ret.push_bool(hw.touch().f.pressed); - | ^ method, not a field - | -help: use parentheses to call the method - | -1043 | ret.push_bool(hw.touch().f().pressed); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1047:42 - | -1047 | ret.push_bool(hw.touch().f.released); - | ^ method, not a field - | -help: use parentheses to call the method - | -1047 | ret.push_bool(hw.touch().f().released); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1051:41 - | -1051 | ret.push_int(hw.touch().f.hold_frames as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1051 | ret.push_int(hw.touch().f().hold_frames as i64); - | ++ - -error[E0615]: attempted to take value of method `up` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1057:26 - | -1057 | &pad.up, &pad.down, &pad.left, &pad.right, - | ^^ method, not a field - | -help: use parentheses to call the method - | -1057 | &pad.up(), &pad.down, &pad.left, &pad.right, - | ++ - -error[E0615]: attempted to take value of method `down` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1057:35 - | -1057 | &pad.up, &pad.down, &pad.left, &pad.right, - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -1057 | &pad.up, &pad.down(), &pad.left, &pad.right, - | ++ - -error[E0615]: attempted to take value of method `left` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1057:46 - | -1057 | &pad.up, &pad.down, &pad.left, &pad.right, - | ^^^^ method, not a field - | -help: use parentheses to call the method - | -1057 | &pad.up, &pad.down, &pad.left(), &pad.right, - | ++ - -error[E0615]: attempted to take value of method `right` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1057:57 - | -1057 | &pad.up, &pad.down, &pad.left, &pad.right, - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -1057 | &pad.up, &pad.down, &pad.left, &pad.right(), - | ++ - -error[E0615]: attempted to take value of method `a` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1058:26 - | -1058 | &pad.a, &pad.b, &pad.x, &pad.y, - | ^ method, not a field - | -help: use parentheses to call the method - | -1058 | &pad.a(), &pad.b, &pad.x, &pad.y, - | ++ - -error[E0615]: attempted to take value of method `b` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1058:34 - | -1058 | &pad.a, &pad.b, &pad.x, &pad.y, - | ^ method, not a field - | -help: use parentheses to call the method - | -1058 | &pad.a, &pad.b(), &pad.x, &pad.y, - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1058:42 - | -1058 | &pad.a, &pad.b, &pad.x, &pad.y, - | ^ method, not a field - | -help: use parentheses to call the method - | -1058 | &pad.a, &pad.b, &pad.x(), &pad.y, - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1058:50 - | -1058 | &pad.a, &pad.b, &pad.x, &pad.y, - | ^ method, not a field - | -help: use parentheses to call the method - | -1058 | &pad.a, &pad.b, &pad.x, &pad.y(), - | ++ - -error[E0615]: attempted to take value of method `l` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1059:26 - | -1059 | &pad.l, &pad.r, &pad.start, &pad.select, - | ^ method, not a field - | -help: use parentheses to call the method - | -1059 | &pad.l(), &pad.r, &pad.start, &pad.select, - | ++ - -error[E0615]: attempted to take value of method `r` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1059:34 - | -1059 | &pad.l, &pad.r, &pad.start, &pad.select, - | ^ method, not a field - | -help: use parentheses to call the method - | -1059 | &pad.l, &pad.r(), &pad.start, &pad.select, - | ++ - -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1059:42 - | -1059 | &pad.l, &pad.r, &pad.start, &pad.select, - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -1059 | &pad.l, &pad.r, &pad.start(), &pad.select, - | ++ - -error[E0615]: attempted to take value of method `select` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1059:54 - | -1059 | &pad.l, &pad.r, &pad.start, &pad.select, - | ^^^^^^ method, not a field - | -help: use parentheses to call the method - | -1059 | &pad.l, &pad.r, &pad.start, &pad.select(), - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1070:37 - | -1070 | ret.push_bool(touch.f.pressed); - | ^ method, not a field - | -help: use parentheses to call the method - | -1070 | ret.push_bool(touch.f().pressed); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1071:37 - | -1071 | ret.push_bool(touch.f.released); - | ^ method, not a field - | -help: use parentheses to call the method - | -1071 | ret.push_bool(touch.f().released); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1072:37 - | -1072 | ret.push_bool(touch.f.down); - | ^ method, not a field - | -help: use parentheses to call the method - | -1072 | ret.push_bool(touch.f().down); - | ++ - -error[E0615]: attempted to take value of method `f` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1073:36 - | -1073 | ret.push_int(touch.f.hold_frames as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1073 | ret.push_int(touch.f().hold_frames as i64); - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1074:36 - | -1074 | ret.push_int(touch.x as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1074 | ret.push_int(touch.x() as i64); - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn TouchBridge` - --> crates/prometeu-core/src/prometeu_os/prometeu_os.rs:1075:36 - | -1075 | ret.push_int(touch.y as i64); - | ^ method, not a field - | -help: use parentheses to call the method - | -1075 | ret.push_int(touch.y() as i64); - | ++ - -error[E0615]: attempted to take value of method `a` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:28:21 - | -28 | if hw.pad().a.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -28 | if hw.pad().a().pressed { - | ++ - -error[E0615]: attempted to take value of method `b` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:31:28 - | -31 | } else if hw.pad().b.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -31 | } else if hw.pad().b().pressed { - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:34:28 - | -34 | } else if hw.pad().x.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -34 | } else if hw.pad().x().pressed { - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:37:28 - | -37 | } else if hw.pad().y.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -37 | } else if hw.pad().y().pressed { - | ++ - -Some errors have detailed explanations: E0609, E0615. -For more information about an error, try `rustc --explain E0609`. -error: could not compile `prometeu-core` (lib) due to 55 previous errors diff --git a/compilation_errors_2.txt b/compilation_errors_2.txt deleted file mode 100644 index a7ecabc9..00000000 --- a/compilation_errors_2.txt +++ /dev/null @@ -1,69 +0,0 @@ - Checking prometeu-core v0.1.0 (/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/prometeu-core) -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/firmware/firmware_step_hub_home.rs:20:29 - | -20 | if ctx.hw.pad().start.down { - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -20 | if ctx.hw.pad().start().down { - | ++ - -error[E0615]: attempted to take value of method `start` on type `&dyn PadBridge` - --> crates/prometeu-core/src/firmware/firmware_step_crash_screen.rs:27:25 - | -27 | if ctx.hw.pad().start.down { - | ^^^^^ method, not a field - | -help: use parentheses to call the method - | -27 | if ctx.hw.pad().start().down { - | ++ - -error[E0615]: attempted to take value of method `a` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:28:21 - | -28 | if hw.pad().a.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -28 | if hw.pad().a().pressed { - | ++ - -error[E0615]: attempted to take value of method `b` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:31:28 - | -31 | } else if hw.pad().b.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -31 | } else if hw.pad().b().pressed { - | ++ - -error[E0615]: attempted to take value of method `x` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:34:28 - | -34 | } else if hw.pad().x.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -34 | } else if hw.pad().x().pressed { - | ++ - -error[E0615]: attempted to take value of method `y` on type `&dyn PadBridge` - --> crates/prometeu-core/src/prometeu_hub/prometeu_hub.rs:37:28 - | -37 | } else if hw.pad().y.pressed { - | ^ method, not a field - | -help: use parentheses to call the method - | -37 | } else if hw.pad().y().pressed { - | ++ - -For more information about this error, try `rustc --explain E0615`. -error: could not compile `prometeu-core` (lib) due to 6 previous errors diff --git a/crates/prometeu-abi/Cargo.toml b/crates/prometeu-abi/Cargo.toml index ed912f33..0fda9a3d 100644 --- a/crates/prometeu-abi/Cargo.toml +++ b/crates/prometeu-abi/Cargo.toml @@ -7,3 +7,4 @@ license.workspace = true [dependencies] serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" +prometeu-bytecode = { path = "../prometeu-bytecode" } diff --git a/crates/prometeu-abi/src/lib.rs b/crates/prometeu-abi/src/lib.rs index 1fe2775e..1005fce9 100644 --- a/crates/prometeu-abi/src/lib.rs +++ b/crates/prometeu-abi/src/lib.rs @@ -6,8 +6,4 @@ pub mod telemetry; pub mod debugger_protocol; pub mod syscalls; -// Tipos da VM que fazem parte do contrato (ex.: inspeção de pilha pelo debugger) -pub mod virtual_machine { - mod value; - pub use value::Value; -} +pub mod virtual_machine; diff --git a/crates/prometeu-abi/src/virtual_machine/mod.rs b/crates/prometeu-abi/src/virtual_machine/mod.rs new file mode 100644 index 00000000..4a914605 --- /dev/null +++ b/crates/prometeu-abi/src/virtual_machine/mod.rs @@ -0,0 +1,12 @@ +mod value; +mod vm_init_error; + +pub use value::Value; +pub use vm_init_error::VmInitError; + +#[derive(Debug, PartialEq, Clone)] +pub enum VmFault { + Trap(u32, String), + Panic(String), + Unavailable, +} diff --git a/crates/prometeu-abi/src/virtual_machine/vm_init_error.rs b/crates/prometeu-abi/src/virtual_machine/vm_init_error.rs new file mode 100644 index 00000000..30b3bf04 --- /dev/null +++ b/crates/prometeu-abi/src/virtual_machine/vm_init_error.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum VmInitError { + InvalidFormat, + UnsupportedFormat, + PbsV0LoadFailed(prometeu_bytecode::LoadError), + EntrypointNotFound, + VerificationFailed(E), +} diff --git a/crates/prometeu-core/Cargo.toml b/crates/prometeu-core/Cargo.toml index 1c4ef217..bd3ba407 100644 --- a/crates/prometeu-core/Cargo.toml +++ b/crates/prometeu-core/Cargo.toml @@ -9,4 +9,5 @@ serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" prometeu-bytecode = { path = "../prometeu-bytecode" } prometeu-abi = { path = "../prometeu-abi" } +prometeu-hardware-contract = { path = "../prometeu-hardware-contract" } url = "2.5.8" \ No newline at end of file diff --git a/crates/prometeu-core/src/debugger_protocol.rs b/crates/prometeu-core/src/debugger_protocol.rs deleted file mode 100644 index c977e67c..00000000 --- a/crates/prometeu-core/src/debugger_protocol.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::model::AppMode; -use serde::{Deserialize, Serialize}; - -use crate::virtual_machine::Value; - -pub const DEVTOOLS_PROTOCOL_VERSION: u32 = 1; - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum DebugCommand { - #[serde(rename = "ok")] - Ok, - #[serde(rename = "start")] - Start, - #[serde(rename = "pause")] - Pause, - #[serde(rename = "resume")] - Resume, - #[serde(rename = "step")] - Step, - #[serde(rename = "stepFrame")] - StepFrame, - #[serde(rename = "getState")] - GetState, - #[serde(rename = "setBreakpoint")] - SetBreakpoint { pc: usize }, - #[serde(rename = "listBreakpoints")] - ListBreakpoints, - #[serde(rename = "clearBreakpoint")] - ClearBreakpoint { pc: usize }, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum DebugResponse { - #[serde(rename = "handshake")] - Handshake { - protocol_version: u32, - runtime_version: String, - cartridge: HandshakeCartridge, - }, - #[serde(rename = "getState")] - GetState { - pc: usize, - stack_top: Vec, - frame_index: u64, - app_id: u32, - }, - #[serde(rename = "breakpoints")] - Breakpoints { - pcs: Vec, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct HandshakeCartridge { - pub app_id: u32, - pub title: String, - pub app_version: String, - pub app_mode: AppMode, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "event")] -pub enum DebugEvent { - #[serde(rename = "breakpointHit")] - BreakpointHit { - pc: usize, - frame_index: u64, - }, - #[serde(rename = "log")] - Log { - level: String, - source: String, - msg: String, - }, - #[serde(rename = "telemetry")] - Telemetry { - frame_index: u64, - vm_steps: u32, - syscalls: u32, - cycles: u64, - cycles_budget: u64, - host_cpu_time_us: u64, - violations: u32, - gfx_used_bytes: usize, - gfx_inflight_bytes: usize, - gfx_slots_occupied: u32, - audio_used_bytes: usize, - audio_inflight_bytes: usize, - audio_slots_occupied: u32, - }, - #[serde(rename = "cert")] - Cert { - rule: String, - used: u64, - limit: u64, - frame_index: u64, - }, -} - -#[cfg(test)] -mod tests { - use crate::virtual_machine::Value; - - #[test] - fn test_telemetry_event_serialization() { - let event = DebugEvent::Telemetry { - frame_index: 10, - vm_steps: 100, - syscalls: 5, - cycles: 5000, - cycles_budget: 10000, - host_cpu_time_us: 1200, - violations: 0, - gfx_used_bytes: 1024, - gfx_inflight_bytes: 0, - gfx_slots_occupied: 1, - audio_used_bytes: 2048, - audio_inflight_bytes: 0, - audio_slots_occupied: 2, - }; - - let json = serde_json::to_string(&event).unwrap(); - assert!(json.contains("\"event\":\"telemetry\"")); - assert!(json.contains("\"cycles\":5000")); - assert!(json.contains("\"cycles_budget\":10000")); - } - - #[test] - fn test_get_state_serialization() { - let resp = DebugResponse::GetState { - pc: 42, - stack_top: vec![Value::Int64(10), Value::String("test".into()), Value::Boolean(true)], - frame_index: 5, - app_id: 1, - }; - - let json = serde_json::to_string(&resp).unwrap(); - assert!(json.contains("\"type\":\"getState\"")); - assert!(json.contains("\"pc\":42")); - assert!(json.contains("\"stack_top\":[10,\"test\",true]")); - assert!(json.contains("\"frame_index\":5")); - assert!(json.contains("\"app_id\":1")); - } -} diff --git a/crates/prometeu-core/src/hardware/asset.rs b/crates/prometeu-core/src/hardware/asset.rs index dec4b314..0db35d52 100644 --- a/crates/prometeu-core/src/hardware/asset.rs +++ b/crates/prometeu-core/src/hardware/asset.rs @@ -136,7 +136,7 @@ struct LoadHandleInfo { status: LoadStatus, } -impl AssetBridge for AssetManager { +impl prometeu_hardware_contract::AssetBridge for AssetManager { fn initialize_for_cartridge(&self, assets: Vec, preload: Vec, assets_data: Vec) { self.initialize_for_cartridge(assets, preload, assets_data) } fn load(&self, asset_name: &str, slot: SlotRef) -> Result { self.load(asset_name, slot) } fn status(&self, handle: HandleId) -> LoadStatus { self.status(handle) } diff --git a/crates/prometeu-core/src/hardware/audio.rs b/crates/prometeu-core/src/hardware/audio.rs index ca95395b..43c5bc95 100644 --- a/crates/prometeu-core/src/hardware/audio.rs +++ b/crates/prometeu-core/src/hardware/audio.rs @@ -7,15 +7,8 @@ pub const MAX_CHANNELS: usize = 16; /// Standard sample rate for the final audio output. pub const OUTPUT_SAMPLE_RATE: u32 = 48000; -/// Defines if a sample should stop at the end or repeat indefinitely. -#[derive(Clone, Copy, Debug, PartialEq, Default)] -pub enum LoopMode { - /// Play once and stop. - #[default] - Off, - /// Return to the start (or loop_start) when reaching the end. - On, -} +/// Looping mode for samples (re-exported from the hardware contract). +pub use prometeu_hardware_contract::LoopMode; /// State of a single playback voice (channel). /// @@ -130,9 +123,15 @@ pub struct Audio { pub sound_banks: Arc, } -impl AudioBridge for Audio { - fn play(&mut self, bank_id: u8, sample_id: u16, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) { self.play(bank_id, sample_id, voice_id, volume, pan, pitch, priority, loop_mode) } - fn play_sample(&mut self, sample: Arc, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) { self.play_sample(sample, voice_id, volume, pan, pitch, priority, loop_mode) } +impl prometeu_hardware_contract::AudioBridge for Audio { + fn play(&mut self, bank_id: u8, sample_id: u16, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: prometeu_hardware_contract::LoopMode) { + let lm = match loop_mode { prometeu_hardware_contract::LoopMode::Off => LoopMode::Off, prometeu_hardware_contract::LoopMode::On => LoopMode::On }; + self.play(bank_id, sample_id, voice_id, volume, pan, pitch, priority, lm) + } + fn play_sample(&mut self, sample: Arc, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: prometeu_hardware_contract::LoopMode) { + let lm = match loop_mode { prometeu_hardware_contract::LoopMode::Off => LoopMode::Off, prometeu_hardware_contract::LoopMode::On => LoopMode::On }; + self.play_sample(sample, voice_id, volume, pan, pitch, priority, lm) + } fn stop(&mut self, voice_id: usize) { self.stop(voice_id) } fn set_volume(&mut self, voice_id: usize, volume: u8) { self.set_volume(voice_id, volume) } fn set_pan(&mut self, voice_id: usize, pan: u8) { self.set_pan(voice_id, pan) } diff --git a/crates/prometeu-core/src/hardware/gfx.rs b/crates/prometeu-core/src/hardware/gfx.rs index 20654701..bd80da0d 100644 --- a/crates/prometeu-core/src/hardware/gfx.rs +++ b/crates/prometeu-core/src/hardware/gfx.rs @@ -114,11 +114,11 @@ pub struct Gfx { priority_buckets: [Vec; 5], } -impl GfxBridge for Gfx { +impl prometeu_hardware_contract::GfxBridge for Gfx { fn size(&self) -> (usize, usize) { self.size() } fn front_buffer(&self) -> &[u16] { self.front_buffer() } fn clear(&mut self, color: Color) { self.clear(color) } - fn fill_rect_blend(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color, mode: BlendMode) { self.fill_rect_blend(x, y, w, h, color, mode) } + fn fill_rect_blend(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color, mode: prometeu_hardware_contract::BlendMode) { let m = match mode { prometeu_hardware_contract::BlendMode::None => BlendMode::None, prometeu_hardware_contract::BlendMode::Half => BlendMode::Half, prometeu_hardware_contract::BlendMode::HalfPlus => BlendMode::HalfPlus, prometeu_hardware_contract::BlendMode::HalfMinus => BlendMode::HalfMinus, prometeu_hardware_contract::BlendMode::Full => BlendMode::Full }; self.fill_rect_blend(x, y, w, h, color, m) } fn fill_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color) { self.fill_rect(x, y, w, h, color) } fn draw_pixel(&mut self, x: i32, y: i32, color: Color) { self.draw_pixel(x, y, color) } fn draw_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) { self.draw_line(x0, y0, x1, y1, color) } diff --git a/crates/prometeu-core/src/hardware/mod.rs b/crates/prometeu-core/src/hardware/mod.rs index afa4b506..db9fa69c 100644 --- a/crates/prometeu-core/src/hardware/mod.rs +++ b/crates/prometeu-core/src/hardware/mod.rs @@ -2,34 +2,19 @@ mod asset; mod gfx; mod pad; mod touch; -mod input_signal; mod audio; mod memory_banks; pub mod hardware; pub use crate::model::HandleId; -pub use asset::{AssetBridge, AssetManager}; -pub use audio::{Audio, AudioBridge, AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; -pub use gfx::BlendMode; -pub use gfx::{Gfx, GfxBridge}; -pub use input_signal::InputSignals; +pub use asset::AssetManager; +pub use audio::{Audio, AudioCommand, Channel, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; +pub use gfx::Gfx; pub use memory_banks::MemoryBanks; -pub use pad::{Pad, PadBridge}; -pub use touch::{Touch, TouchBridge}; +pub use pad::Pad; +pub use touch::Touch; -pub trait HardwareBridge { - fn gfx(&self) -> &dyn GfxBridge; - fn gfx_mut(&mut self) -> &mut dyn GfxBridge; - - fn audio(&self) -> &dyn AudioBridge; - fn audio_mut(&mut self) -> &mut dyn AudioBridge; - - fn pad(&self) -> &dyn PadBridge; - fn pad_mut(&mut self) -> &mut dyn PadBridge; - - fn touch(&self) -> &dyn TouchBridge; - fn touch_mut(&mut self) -> &mut dyn TouchBridge; - - fn assets(&self) -> &dyn AssetBridge; - fn assets_mut(&mut self) -> &mut dyn AssetBridge; -} +pub use prometeu_hardware_contract::{ + AssetBridge, AudioBridge, BlendMode, GfxBridge, HardwareBridge, InputSignals, LoopMode, + PadBridge, TouchBridge, +}; diff --git a/crates/prometeu-core/src/hardware/pad.rs b/crates/prometeu-core/src/hardware/pad.rs index 0552eb6e..9eb78515 100644 --- a/crates/prometeu-core/src/hardware/pad.rs +++ b/crates/prometeu-core/src/hardware/pad.rs @@ -1,4 +1,4 @@ -use crate::hardware::input_signal::InputSignals; +use crate::hardware::InputSignals; use crate::model::Button; pub trait PadBridge { @@ -37,7 +37,7 @@ pub struct Pad { pub select: Button, } -impl PadBridge for Pad { +impl prometeu_hardware_contract::PadBridge for Pad { fn begin_frame(&mut self, signals: &InputSignals) { self.begin_frame(signals) } fn any(&self) -> bool { self.any() } diff --git a/crates/prometeu-core/src/hardware/touch.rs b/crates/prometeu-core/src/hardware/touch.rs index c760f3eb..a3f490e0 100644 --- a/crates/prometeu-core/src/hardware/touch.rs +++ b/crates/prometeu-core/src/hardware/touch.rs @@ -1,4 +1,4 @@ -use crate::hardware::input_signal::InputSignals; +use crate::hardware::InputSignals; use crate::model::Button; pub trait TouchBridge { @@ -15,7 +15,7 @@ pub struct Touch { pub y: i32, } -impl TouchBridge for Touch { +impl prometeu_hardware_contract::TouchBridge for Touch { fn begin_frame(&mut self, signals: &InputSignals) { self.begin_frame(signals) } fn f(&self) -> &Button { &self.f } fn x(&self) -> i32 { self.x } diff --git a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs index 63599110..6492408c 100644 --- a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs +++ b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs @@ -5,9 +5,10 @@ use crate::log::{LogLevel, LogService, LogSource}; use crate::model::{BankType, Cartridge, Color}; use crate::prometeu_os::NativeInterface; use crate::telemetry::{CertificationConfig, Certifier, TelemetryFrame}; -use crate::virtual_machine::{expect_bool, expect_int, HostContext, HostReturn, SyscallId, Value, VirtualMachine, VmFault}; +use crate::virtual_machine::{HostContext, HostReturn, SyscallId, Value, VirtualMachine, VmFault}; use std::collections::HashMap; use std::time::Instant; +use prometeu_hardware_contract::{expect_bool, expect_int}; /// PrometeuOS (POS): The central system firmware and resource manager. /// diff --git a/crates/prometeu-core/src/telemetry.rs b/crates/prometeu-core/src/telemetry.rs deleted file mode 100644 index 2dbe4f31..00000000 --- a/crates/prometeu-core/src/telemetry.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::log::{LogLevel, LogService, LogSource}; - -#[derive(Debug, Clone, Copy, Default)] -pub struct TelemetryFrame { - pub frame_index: u64, - pub vm_steps: u32, - pub cycles_used: u64, - pub cycles_budget: u64, - pub syscalls: u32, - pub host_cpu_time_us: u64, - pub violations: u32, - - // GFX Banks - pub gfx_used_bytes: usize, - pub gfx_inflight_bytes: usize, - pub gfx_slots_occupied: u32, - - // Audio Banks - pub audio_used_bytes: usize, - pub audio_inflight_bytes: usize, - pub audio_slots_occupied: u32, -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct CertificationConfig { - pub enabled: bool, - pub cycles_budget_per_frame: Option, - pub max_syscalls_per_frame: Option, - pub max_host_cpu_us_per_frame: Option, -} - -pub struct Certifier { - pub config: CertificationConfig, -} - -impl Certifier { - pub fn new(config: CertificationConfig) -> Self { - Self { config } - } - - pub fn evaluate(&self, telemetry: &TelemetryFrame, log_service: &mut LogService, ts_ms: u64) -> usize { - if !self.config.enabled { - return 0; - } - - let mut violations = 0; - - if let Some(budget) = self.config.cycles_budget_per_frame { - if telemetry.cycles_used > budget { - log_service.log( - ts_ms, - telemetry.frame_index, - LogLevel::Warn, - LogSource::Pos, - 0xCA01, - format!("Cert: cycles_used exceeded budget ({} > {})", telemetry.cycles_used, budget), - ); - violations += 1; - } - } - - if let Some(limit) = self.config.max_syscalls_per_frame { - if telemetry.syscalls > limit { - log_service.log( - ts_ms, - telemetry.frame_index, - LogLevel::Warn, - LogSource::Pos, - 0xCA02, - format!("Cert: syscalls per frame exceeded limit ({} > {})", telemetry.syscalls, limit), - ); - violations += 1; - } - } - - if let Some(limit) = self.config.max_host_cpu_us_per_frame { - if telemetry.host_cpu_time_us > limit { - log_service.log( - ts_ms, - telemetry.frame_index, - LogLevel::Warn, - LogSource::Pos, - 0xCA03, - format!("Cert: host_cpu_time_us exceeded limit ({} > {})", telemetry.host_cpu_time_us, limit), - ); - violations += 1; - } - } - - violations - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::log::LogService; - - #[test] - fn test_certifier_violations() { - let config = CertificationConfig { - enabled: true, - cycles_budget_per_frame: Some(100), - max_syscalls_per_frame: Some(5), - max_host_cpu_us_per_frame: Some(1000), - }; - let cert = Certifier::new(config); - let mut ls = LogService::new(10); - - let mut tel = TelemetryFrame::default(); - tel.cycles_used = 150; - tel.syscalls = 10; - tel.host_cpu_time_us = 500; - - let violations = cert.evaluate(&tel, &mut ls, 1000); - assert_eq!(violations, 2); - - let logs = ls.get_recent(10); - assert_eq!(logs.len(), 2); - assert!(logs[0].msg.contains("cycles_used")); - assert!(logs[1].msg.contains("syscalls")); - } -} diff --git a/crates/prometeu-core/src/virtual_machine/mod.rs b/crates/prometeu-core/src/virtual_machine/mod.rs index 8e9dba46..f7e0049a 100644 --- a/crates/prometeu-core/src/virtual_machine/mod.rs +++ b/crates/prometeu-core/src/virtual_machine/mod.rs @@ -2,101 +2,18 @@ mod virtual_machine; mod call_frame; mod scope_frame; mod program; -pub mod host_context; pub mod local_addressing; pub mod opcode_spec; pub mod bytecode; pub mod verifier; -pub use host_context::{HostContext, HostContextProvider}; pub use program::ProgramImage; -pub use prometeu_abi::virtual_machine::Value; +pub use prometeu_abi::virtual_machine::{Value, VmFault}; pub use prometeu_bytecode::abi::TrapInfo; pub use prometeu_bytecode::opcode::OpCode; +pub use prometeu_hardware_contract::{ + HostContext, HostReturn, NativeInterface, SyscallId, +}; +pub type VmInitError = prometeu_abi::virtual_machine::VmInitError; pub use verifier::VerifierError; pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine}; - -pub type SyscallId = u32; - -#[derive(Debug, PartialEq, Clone)] -pub enum VmFault { - Trap(u32, String), - Panic(String), - Unavailable, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VmInitError { - InvalidFormat, - UnsupportedFormat, - PbsV0LoadFailed(prometeu_bytecode::LoadError), - EntrypointNotFound, - VerificationFailed(VerifierError), -} - -pub struct HostReturn<'a> { - stack: &'a mut Vec -} - -impl<'a> HostReturn<'a> { - pub fn new(stack: &'a mut Vec) -> Self { - Self { stack } - } - pub fn push_bool(&mut self, v: bool) { - self.stack.push(Value::Boolean(v)); - } - pub fn push_int(&mut self, v: i64) { - self.stack.push(Value::Int64(v)); - } - pub fn push_bounded(&mut self, v: u32) -> Result<(), VmFault> { - if v > 0xFFFF { - return Err(VmFault::Trap(prometeu_bytecode::abi::TRAP_OOB, format!( - "bounded overflow: {}", v - ))); - } - self.stack.push(Value::Bounded(v)); - Ok(()) - } - pub fn push_null(&mut self) { - self.stack.push(Value::Null); - } - pub fn push_gate(&mut self, g: usize) { - self.stack.push(Value::Gate(g)); - } - pub fn push_string(&mut self, s: String) { - self.stack.push(Value::String(s)); - } -} - -pub trait NativeInterface { - /// Dispatches a syscall from the Virtual Machine to the native implementation. - /// - /// ABI Rule: Arguments for the syscall are passed in `args`. - /// - /// Returns are written via `ret`. - fn syscall(&mut self, id: SyscallId, args: &[Value], ret: &mut HostReturn, ctx: &mut HostContext) -> Result<(), VmFault>; -} - -pub fn expect_bounded(args: &[Value], idx: usize) -> Result { - args.get(idx) - .and_then(|v| match v { - Value::Bounded(b) => Some(*b), - _ => None, - }) - .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected bounded at index {}", idx))) -} - -pub fn expect_int(args: &[Value], idx: usize) -> Result { - args.get(idx) - .and_then(|v| v.as_integer()) - .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected integer at index {}", idx))) -} - -pub fn expect_bool(args: &[Value], idx: usize) -> Result { - args.get(idx) - .and_then(|v| match v { - Value::Boolean(b) => Some(*b), - _ => None, - }) - .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected boolean at index {}", idx))) -} diff --git a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs index 52c07f45..440df371 100644 --- a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs +++ b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs @@ -931,9 +931,10 @@ mod tests { }]); vm } - use crate::virtual_machine::{expect_int, HostReturn, Value, VmFault}; + use crate::virtual_machine::{HostReturn, Value, VmFault}; use prometeu_bytecode::abi::SourceSpan; use prometeu_bytecode::FunctionMeta; + use prometeu_hardware_contract::expect_int; struct MockNative; impl NativeInterface for MockNative { diff --git a/crates/prometeu-hardware-contract/Cargo.toml b/crates/prometeu-hardware-contract/Cargo.toml index 2958dcd5..2c5f8354 100644 --- a/crates/prometeu-hardware-contract/Cargo.toml +++ b/crates/prometeu-hardware-contract/Cargo.toml @@ -5,5 +5,7 @@ edition = "2024" license.workspace = true [dependencies] +prometeu-abi = { path = "../prometeu-abi" } +prometeu-bytecode = { path = "../prometeu-bytecode" } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" \ No newline at end of file diff --git a/crates/prometeu-hardware-contract/src/asset.rs b/crates/prometeu-hardware-contract/src/asset.rs new file mode 100644 index 00000000..623e3ce5 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/asset.rs @@ -0,0 +1,21 @@ +use prometeu_abi::model::{ + AssetEntry, BankStats, BankType, HandleId, LoadStatus, PreloadEntry, SlotRef, SlotStats, +}; + +pub trait AssetBridge { + fn initialize_for_cartridge( + &self, + assets: Vec, + preload: Vec, + assets_data: Vec, + ); + fn load(&self, asset_name: &str, slot: SlotRef) -> Result; + fn status(&self, handle: HandleId) -> LoadStatus; + fn commit(&self, handle: HandleId); + fn cancel(&self, handle: HandleId); + fn apply_commits(&self); + fn bank_info(&self, kind: BankType) -> BankStats; + fn slot_info(&self, slot: SlotRef) -> SlotStats; + fn find_slot_by_name(&self, asset_name: &str, kind: BankType) -> Option; + fn shutdown(&self); +} diff --git a/crates/prometeu-hardware-contract/src/audio.rs b/crates/prometeu-hardware-contract/src/audio.rs new file mode 100644 index 00000000..0e1df473 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/audio.rs @@ -0,0 +1,38 @@ +use prometeu_abi::model::Sample; +use std::sync::Arc; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LoopMode { + Off, + On, +} + +pub trait AudioBridge { + fn play( + &mut self, + bank_id: u8, + sample_id: u16, + voice_id: usize, + volume: u8, + pan: u8, + pitch: f64, + priority: u8, + loop_mode: LoopMode, + ); + fn play_sample( + &mut self, + sample: Arc, + voice_id: usize, + volume: u8, + pan: u8, + pitch: f64, + priority: u8, + loop_mode: LoopMode, + ); + fn stop(&mut self, voice_id: usize); + fn set_volume(&mut self, voice_id: usize, volume: u8); + fn set_pan(&mut self, voice_id: usize, pan: u8); + fn set_pitch(&mut self, voice_id: usize, pitch: f64); + fn is_playing(&self, voice_id: usize) -> bool; + fn clear_commands(&mut self); +} diff --git a/crates/prometeu-hardware-contract/src/gfx.rs b/crates/prometeu-hardware-contract/src/gfx.rs new file mode 100644 index 00000000..a10b5a84 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/gfx.rs @@ -0,0 +1,51 @@ +use prometeu_abi::model::{Color, HudTileLayer, ScrollableTileLayer, Sprite}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BlendMode { + None, + Half, + HalfPlus, + HalfMinus, + Full, +} + +pub trait GfxBridge { + fn size(&self) -> (usize, usize); + fn front_buffer(&self) -> &[u16]; + fn clear(&mut self, color: Color); + fn fill_rect_blend(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color, mode: BlendMode); + fn fill_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color); + fn draw_pixel(&mut self, x: i32, y: i32, color: Color); + fn draw_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color); + fn draw_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color); + fn draw_circle_points(&mut self, xc: i32, yc: i32, x: i32, y: i32, color: Color); + fn fill_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color); + fn draw_circle_lines(&mut self, xc: i32, yc: i32, x: i32, y: i32, color: Color); + fn draw_disc(&mut self, x: i32, y: i32, r: i32, border_color: Color, fill_color: Color); + fn draw_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color); + fn draw_square(&mut self, x: i32, y: i32, w: i32, h: i32, border_color: Color, fill_color: Color); + fn draw_horizontal_line(&mut self, x0: i32, x1: i32, y: i32, color: Color); + fn draw_vertical_line(&mut self, x: i32, y0: i32, y1: i32, color: Color); + fn present(&mut self); + fn render_all(&mut self); + fn render_layer(&mut self, layer_idx: usize); + fn render_hud(&mut self); + fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color); + fn draw_char(&mut self, x: i32, y: i32, c: char, color: Color); + + fn layer(&self, index: usize) -> &ScrollableTileLayer; + fn layer_mut(&mut self, index: usize) -> &mut ScrollableTileLayer; + fn hud(&self) -> &HudTileLayer; + fn hud_mut(&mut self) -> &mut HudTileLayer; + fn sprite(&self, index: usize) -> &Sprite; + fn sprite_mut(&mut self, index: usize) -> &mut Sprite; + + fn scene_fade_level(&self) -> u8; + fn set_scene_fade_level(&mut self, level: u8); + fn scene_fade_color(&self) -> Color; + fn set_scene_fade_color(&mut self, color: Color); + fn hud_fade_level(&self) -> u8; + fn set_hud_fade_level(&mut self, level: u8); + fn hud_fade_color(&self) -> Color; + fn set_hud_fade_color(&mut self, color: Color); +} diff --git a/crates/prometeu-hardware-contract/src/hardware.rs b/crates/prometeu-hardware-contract/src/hardware.rs new file mode 100644 index 00000000..878ef08d --- /dev/null +++ b/crates/prometeu-hardware-contract/src/hardware.rs @@ -0,0 +1,22 @@ +use crate::asset::AssetBridge; +use crate::audio::AudioBridge; +use crate::gfx::GfxBridge; +use crate::pad::PadBridge; +use crate::touch::TouchBridge; + +pub trait HardwareBridge { + fn gfx(&self) -> &dyn GfxBridge; + fn gfx_mut(&mut self) -> &mut dyn GfxBridge; + + fn audio(&self) -> &dyn AudioBridge; + fn audio_mut(&mut self) -> &mut dyn AudioBridge; + + fn pad(&self) -> &dyn PadBridge; + fn pad_mut(&mut self) -> &mut dyn PadBridge; + + fn touch(&self) -> &dyn TouchBridge; + fn touch_mut(&mut self) -> &mut dyn TouchBridge; + + fn assets(&self) -> &dyn AssetBridge; + fn assets_mut(&mut self) -> &mut dyn AssetBridge; +} diff --git a/crates/prometeu-core/src/virtual_machine/host_context.rs b/crates/prometeu-hardware-contract/src/host_context.rs similarity index 73% rename from crates/prometeu-core/src/virtual_machine/host_context.rs rename to crates/prometeu-hardware-contract/src/host_context.rs index 0689bbcd..2395682a 100644 --- a/crates/prometeu-core/src/virtual_machine/host_context.rs +++ b/crates/prometeu-hardware-contract/src/host_context.rs @@ -1,5 +1,5 @@ use crate::hardware::HardwareBridge; -use crate::virtual_machine::VmFault; +use prometeu_abi::virtual_machine::VmFault; pub struct HostContext<'a> { pub hw: Option<&'a mut dyn HardwareBridge>, @@ -22,10 +22,3 @@ impl<'a> HostContext<'a> { pub trait HostContextProvider { fn make_ctx(&'_ mut self) -> HostContext<'_>; } - -impl HostContextProvider for T { - #[inline] - fn make_ctx(&'_ mut self) -> HostContext { - HostContext::new(Some(self)) - } -} diff --git a/crates/prometeu-hardware-contract/src/host_return.rs b/crates/prometeu-hardware-contract/src/host_return.rs new file mode 100644 index 00000000..fa2b5161 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/host_return.rs @@ -0,0 +1,33 @@ +use prometeu_abi::virtual_machine::Value; + +pub struct HostReturn<'a> { + stack: &'a mut Vec +} + +impl<'a> HostReturn<'a> { + pub fn new(stack: &'a mut Vec) -> Self { + Self { stack } + } + pub fn push_bool(&mut self, v: bool) { + self.stack.push(Value::Boolean(v)); + } + pub fn push_int(&mut self, v: i64) { + self.stack.push(Value::Int64(v)); + } + pub fn push_bounded(&mut self, v: u32) -> Result<(), prometeu_abi::virtual_machine::VmFault> { + if v > 0xFFFF { + return Err(prometeu_abi::virtual_machine::VmFault::Trap(prometeu_bytecode::abi::TRAP_OOB, "Bounded value overflow".into())); + } + self.stack.push(Value::Bounded(v)); + Ok(()) + } + pub fn push_null(&mut self) { + self.stack.push(Value::Null); + } + pub fn push_gate(&mut self, g: usize) { + self.stack.push(Value::Gate(g)); + } + pub fn push_string(&mut self, s: String) { + self.stack.push(Value::String(s)); + } +} diff --git a/crates/prometeu-hardware-contract/src/input_signals.rs b/crates/prometeu-hardware-contract/src/input_signals.rs new file mode 100644 index 00000000..86bb9caa --- /dev/null +++ b/crates/prometeu-hardware-contract/src/input_signals.rs @@ -0,0 +1,23 @@ +#[derive(Default, Clone, Copy, Debug)] +pub struct InputSignals { + // PAD + pub up_signal: bool, + pub down_signal: bool, + pub left_signal: bool, + pub right_signal: bool, + + pub a_signal: bool, + pub b_signal: bool, + pub x_signal: bool, + pub y_signal: bool, + pub l_signal: bool, + pub r_signal: bool, + + pub start_signal: bool, + pub select_signal: bool, + + // TOUCH + pub f_signal: bool, + pub x_pos: i32, + pub y_pos: i32, +} diff --git a/crates/prometeu-hardware-contract/src/lib.rs b/crates/prometeu-hardware-contract/src/lib.rs index e69de29b..59e8b9f1 100644 --- a/crates/prometeu-hardware-contract/src/lib.rs +++ b/crates/prometeu-hardware-contract/src/lib.rs @@ -0,0 +1,23 @@ +pub mod asset; +pub mod audio; +pub mod gfx; +pub mod hardware; +pub mod host_context; +pub mod host_return; +pub mod input_signals; +pub mod native_interface; +pub mod pad; +pub mod touch; +pub mod native_helpers; + +pub use asset::AssetBridge; +pub use audio::{AudioBridge, LoopMode}; +pub use gfx::{BlendMode, GfxBridge}; +pub use hardware::HardwareBridge; +pub use host_context::{HostContext, HostContextProvider}; +pub use host_return::HostReturn; +pub use input_signals::InputSignals; +pub use native_interface::{NativeInterface, SyscallId}; +pub use pad::PadBridge; +pub use touch::TouchBridge; +pub use native_helpers::{expect_bool, expect_bounded, expect_int}; \ No newline at end of file diff --git a/crates/prometeu-hardware-contract/src/native_helpers.rs b/crates/prometeu-hardware-contract/src/native_helpers.rs new file mode 100644 index 00000000..97c3ee2f --- /dev/null +++ b/crates/prometeu-hardware-contract/src/native_helpers.rs @@ -0,0 +1,25 @@ +use prometeu_abi::virtual_machine::{Value, VmFault}; + +pub fn expect_bounded(args: &[Value], idx: usize) -> Result { + args.get(idx) + .and_then(|v| match v { + Value::Bounded(b) => Some(*b), + _ => None, + }) + .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected bounded at index {}", idx))) +} + +pub fn expect_int(args: &[Value], idx: usize) -> Result { + args.get(idx) + .and_then(|v| v.as_integer()) + .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected integer at index {}", idx))) +} + +pub fn expect_bool(args: &[Value], idx: usize) -> Result { + args.get(idx) + .and_then(|v| match v { + Value::Boolean(b) => Some(*b), + _ => None, + }) + .ok_or_else(|| VmFault::Trap(prometeu_bytecode::abi::TRAP_TYPE, format!("Expected boolean at index {}", idx))) +} diff --git a/crates/prometeu-hardware-contract/src/native_interface.rs b/crates/prometeu-hardware-contract/src/native_interface.rs new file mode 100644 index 00000000..cb382fd2 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/native_interface.rs @@ -0,0 +1,14 @@ +use prometeu_abi::virtual_machine::{Value, VmFault}; +use crate::host_context::HostContext; +use crate::host_return::HostReturn; + +pub type SyscallId = u32; + +pub trait NativeInterface { + /// Dispatches a syscall from the Virtual Machine to the native implementation. + /// + /// ABI Rule: Arguments for the syscall are passed in `args`. + /// + /// Returns are written via `ret`. + fn syscall(&mut self, id: SyscallId, args: &[Value], ret: &mut HostReturn, ctx: &mut HostContext) -> Result<(), VmFault>; +} diff --git a/crates/prometeu-hardware-contract/src/pad.rs b/crates/prometeu-hardware-contract/src/pad.rs new file mode 100644 index 00000000..57bf1e7d --- /dev/null +++ b/crates/prometeu-hardware-contract/src/pad.rs @@ -0,0 +1,20 @@ +use crate::input_signals::InputSignals; +use prometeu_abi::model::Button; + +pub trait PadBridge { + fn begin_frame(&mut self, signals: &InputSignals); + fn any(&self) -> bool; + + fn up(&self) -> &Button; + fn down(&self) -> &Button; + fn left(&self) -> &Button; + fn right(&self) -> &Button; + fn a(&self) -> &Button; + fn b(&self) -> &Button; + fn x(&self) -> &Button; + fn y(&self) -> &Button; + fn l(&self) -> &Button; + fn r(&self) -> &Button; + fn start(&self) -> &Button; + fn select(&self) -> &Button; +} diff --git a/crates/prometeu-hardware-contract/src/touch.rs b/crates/prometeu-hardware-contract/src/touch.rs new file mode 100644 index 00000000..e84fb8d8 --- /dev/null +++ b/crates/prometeu-hardware-contract/src/touch.rs @@ -0,0 +1,9 @@ +use crate::input_signals::InputSignals; +use prometeu_abi::model::Button; + +pub trait TouchBridge { + fn begin_frame(&mut self, signals: &InputSignals); + fn f(&self) -> &Button; + fn x(&self) -> i32; + fn y(&self) -> i32; +} diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index 666448e9c82fd9759bc1514ce6c916eaa9193fac..b06b91caaacaf4416129e782584fa51dc847ec21 100644 GIT binary patch delta 47 wcmeB|?U&tadAadA