pr 00.1 decouple more code from vm and hardware

This commit is contained in:
bQUARKz 2026-02-03 20:58:16 +00:00
parent 0cacf4fed8
commit ba2344e324
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
34 changed files with 345 additions and 1088 deletions

4
Cargo.lock generated
View File

@ -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",
]

View File

@ -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

View File

@ -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

View File

@ -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" }

View File

@ -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;

View File

@ -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,
}

View File

@ -0,0 +1,8 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VmInitError<E> {
InvalidFormat,
UnsupportedFormat,
PbsV0LoadFailed(prometeu_bytecode::LoadError),
EntrypointNotFound,
VerificationFailed(E),
}

View File

@ -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"

View File

@ -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<Value>,
frame_index: u64,
app_id: u32,
},
#[serde(rename = "breakpoints")]
Breakpoints {
pcs: Vec<usize>,
},
}
#[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"));
}
}

View File

@ -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<AssetEntry>, preload: Vec<PreloadEntry>, assets_data: Vec<u8>) { self.initialize_for_cartridge(assets, preload, assets_data) }
fn load(&self, asset_name: &str, slot: SlotRef) -> Result<HandleId, String> { self.load(asset_name, slot) }
fn status(&self, handle: HandleId) -> LoadStatus { self.status(handle) }

View File

@ -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<dyn SoundBankPoolAccess>,
}
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<Sample>, 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<Sample>, 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) }

View File

@ -114,11 +114,11 @@ pub struct Gfx {
priority_buckets: [Vec<usize>; 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) }

View File

@ -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,
};

View File

@ -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() }

View File

@ -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 }

View File

@ -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.
///

View File

@ -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<u64>,
pub max_syscalls_per_frame: Option<u32>,
pub max_host_cpu_us_per_frame: Option<u64>,
}
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"));
}
}

View File

@ -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<VerifierError>;
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<Value>
}
impl<'a> HostReturn<'a> {
pub fn new(stack: &'a mut Vec<Value>) -> 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<u32, VmFault> {
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<i64, VmFault> {
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<bool, VmFault> {
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)))
}

View File

@ -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 {

View File

@ -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"

View File

@ -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<AssetEntry>,
preload: Vec<PreloadEntry>,
assets_data: Vec<u8>,
);
fn load(&self, asset_name: &str, slot: SlotRef) -> Result<HandleId, String>;
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<u8>;
fn shutdown(&self);
}

View File

@ -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<Sample>,
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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<T: HardwareBridge> HostContextProvider for T {
#[inline]
fn make_ctx(&'_ mut self) -> HostContext {
HostContext::new(Some(self))
}
}

View File

@ -0,0 +1,33 @@
use prometeu_abi::virtual_machine::Value;
pub struct HostReturn<'a> {
stack: &'a mut Vec<Value>
}
impl<'a> HostReturn<'a> {
pub fn new(stack: &'a mut Vec<Value>) -> 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));
}
}

View File

@ -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,
}

View File

@ -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};

View File

@ -0,0 +1,25 @@
use prometeu_abi::virtual_machine::{Value, VmFault};
pub fn expect_bounded(args: &[Value], idx: usize) -> Result<u32, VmFault> {
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<i64, VmFault> {
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<bool, VmFault> {
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)))
}

View File

@ -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>;
}

View File

@ -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;
}

View File

@ -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;
}