This commit is contained in:
bQUARKz 2026-02-04 01:47:43 +00:00
parent e52a426f02
commit d6bbef06a5
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
27 changed files with 166 additions and 690 deletions

432
Cargo.lock generated
View File

@ -86,7 +86,7 @@ dependencies = [
"ndk-context",
"ndk-sys 0.6.0+11769913",
"num_enum",
"thiserror 1.0.69",
"thiserror",
]
[[package]]
@ -310,7 +310,7 @@ dependencies = [
"polling",
"rustix 0.38.44",
"slab",
"thiserror 1.0.69",
"thiserror",
]
[[package]]
@ -325,15 +325,6 @@ dependencies = [
"wayland-client",
]
[[package]]
name = "castaway"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.2.52"
@ -437,7 +428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width 0.1.14",
"unicode-width",
]
[[package]]
@ -487,20 +478,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "compact_str"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"rustversion",
"ryu",
"static_assertions",
]
[[package]]
name = "concurrent-queue"
version = "2.5.0"
@ -570,12 +547,6 @@ dependencies = [
"bindgen",
]
[[package]]
name = "cow-utils"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79"
[[package]]
name = "cpal"
version = "0.15.3"
@ -679,12 +650,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
[[package]]
name = "dragonbox_ecma"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5577f010d4e1bb3f3c4d6081e05718eb6992cf20119cab4d3abadff198b5ae"
[[package]]
name = "either"
version = "1.15.0"
@ -919,7 +884,7 @@ checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
dependencies = [
"log",
"presser",
"thiserror 1.0.69",
"thiserror",
"winapi",
"windows 0.52.0",
]
@ -959,9 +924,6 @@ name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"allocator-api2",
]
[[package]]
name = "hassle-rs"
@ -973,7 +935,7 @@ dependencies = [
"com",
"libc",
"libloading 0.8.9",
"thiserror 1.0.69",
"thiserror",
"widestring",
"winapi",
]
@ -1146,7 +1108,7 @@ dependencies = [
"combine",
"jni-sys",
"log",
"thiserror 1.0.69",
"thiserror",
"walkdir",
"windows-sys 0.45.0",
]
@ -1358,7 +1320,7 @@ dependencies = [
"rustc-hash 1.1.0",
"spirv",
"termcolor",
"thiserror 1.0.69",
"thiserror",
"unicode-xid",
]
@ -1373,7 +1335,7 @@ dependencies = [
"log",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum",
"thiserror 1.0.69",
"thiserror",
]
[[package]]
@ -1388,7 +1350,7 @@ dependencies = [
"ndk-sys 0.6.0+11769913",
"num_enum",
"raw-window-handle",
"thiserror 1.0.69",
"thiserror",
]
[[package]]
@ -1425,22 +1387,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nonmax"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51"
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-derive"
version = "0.4.2"
@ -1452,15 +1398,6 @@ dependencies = [
"syn 2.0.114",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -1768,212 +1705,6 @@ dependencies = [
"ttf-parser",
]
[[package]]
name = "owo-colors"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
[[package]]
name = "oxc-miette"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a7ba54c704edefead1f44e9ef09c43e5cfae666bdc33516b066011f0e6ebf7"
dependencies = [
"cfg-if",
"owo-colors",
"oxc-miette-derive",
"textwrap",
"thiserror 2.0.18",
"unicode-segmentation",
"unicode-width 0.2.2",
]
[[package]]
name = "oxc-miette-derive"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4faecb54d0971f948fbc1918df69b26007e6f279a204793669542e1e8b75eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "oxc_allocator"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2174c7c8f77137b1bd1c653d7a5a531ae41f3b8fec1dd0251c801689784e7a2e"
dependencies = [
"allocator-api2",
"hashbrown 0.16.1",
"oxc_data_structures",
"rustc-hash 2.1.1",
]
[[package]]
name = "oxc_ast"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f1902f97a5cac8767b76a1d8a1b3124e9db80c176ebbc98f75143dcc124a15"
dependencies = [
"bitflags 2.10.0",
"oxc_allocator",
"oxc_ast_macros",
"oxc_data_structures",
"oxc_diagnostics",
"oxc_estree",
"oxc_regular_expression",
"oxc_span",
"oxc_syntax",
]
[[package]]
name = "oxc_ast_macros"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5a31bd55516a98a35b2d99fa5813a3d3a5b798bad3262c819dfe7344bc6f390"
dependencies = [
"phf",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "oxc_ast_visit"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2c520a488c04ba5267223edd0bb245fb7f10e2358e8955802a5d962bb95b50a"
dependencies = [
"oxc_allocator",
"oxc_ast",
"oxc_span",
"oxc_syntax",
]
[[package]]
name = "oxc_data_structures"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a42840ce8d83a08a92823dda6189e4d97359feca24a4fa732f3256c4614bb5a4"
[[package]]
name = "oxc_diagnostics"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f7b09c1563a67ede53af131f717b31ba89a992959ebad188b5158c21d4dc0a"
dependencies = [
"cow-utils",
"oxc-miette",
"percent-encoding",
]
[[package]]
name = "oxc_ecmascript"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4813b352bd5b0b05badf0c9e6c5ec7ea58a6a7ab49bec8d18ead262624c6ef8d"
dependencies = [
"cow-utils",
"num-bigint",
"num-traits",
"oxc_allocator",
"oxc_ast",
"oxc_regular_expression",
"oxc_span",
"oxc_syntax",
]
[[package]]
name = "oxc_estree"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54fb3effe995e6538d68070bf0a450b5ffd11dd41b62f11a4d01efa1f40e278"
[[package]]
name = "oxc_index"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3e6120999627ec9703025eab7c9f410ebb7e95557632a8902ca48210416c2b"
dependencies = [
"nonmax",
"serde",
]
[[package]]
name = "oxc_parser"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5592bf8b64743944eb46528f9eabdde2b2435c8293cd502f5c183f9dff644e16"
dependencies = [
"bitflags 2.10.0",
"cow-utils",
"memchr",
"num-bigint",
"num-traits",
"oxc_allocator",
"oxc_ast",
"oxc_data_structures",
"oxc_diagnostics",
"oxc_ecmascript",
"oxc_regular_expression",
"oxc_span",
"oxc_syntax",
"rustc-hash 2.1.1",
"seq-macro",
]
[[package]]
name = "oxc_regular_expression"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09de7f7e0fb82f54750e3a95346a828fd354b9aeac00f131719008733e66a18d"
dependencies = [
"bitflags 2.10.0",
"oxc_allocator",
"oxc_ast_macros",
"oxc_diagnostics",
"oxc_span",
"phf",
"rustc-hash 2.1.1",
"unicode-id-start",
]
[[package]]
name = "oxc_span"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a42c0759b745eca0fe776890af46ce12e79e61796995e51a8eb9dcdf5516ab0"
dependencies = [
"compact_str",
"oxc-miette",
"oxc_allocator",
"oxc_ast_macros",
"oxc_estree",
]
[[package]]
name = "oxc_syntax"
version = "0.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63eac2e04a75a10c5714aeb753cdfa06b1abc66bbaa748b7994700f52c9b184"
dependencies = [
"bitflags 2.10.0",
"cow-utils",
"dragonbox_ecma",
"nonmax",
"oxc_allocator",
"oxc_ast_macros",
"oxc_data_structures",
"oxc_estree",
"oxc_index",
"oxc_span",
"phf",
"unicode-id-start",
]
[[package]]
name = "parking_lot"
version = "0.12.5"
@ -2009,49 +1740,6 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "phf"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
dependencies = [
"phf_macros",
"phf_shared",
"serde",
]
[[package]]
name = "phf_generator"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
dependencies = [
"fastrand",
"phf_shared",
]
[[package]]
name = "phf_macros"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "phf_shared"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.1.10"
@ -2093,7 +1781,7 @@ dependencies = [
"bytemuck",
"pollster",
"raw-window-handle",
"thiserror 1.0.69",
"thiserror",
"ultraviolet",
"wgpu",
]
@ -2218,14 +1906,8 @@ version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"oxc_allocator",
"oxc_ast",
"oxc_ast_visit",
"oxc_parser",
"oxc_span",
"oxc_syntax",
"prometeu-abi",
"prometeu-bytecode",
"prometeu-core",
"serde",
"serde_json",
"tempfile",
@ -2238,6 +1920,7 @@ dependencies = [
"prometeu-abi",
"prometeu-bytecode",
"prometeu-hardware-contract",
"prometeu-vm",
"serde",
"serde_json",
"url",
@ -2276,6 +1959,16 @@ dependencies = [
"winit",
]
[[package]]
name = "prometeu-vm"
version = "0.1.0"
dependencies = [
"prometeu-abi",
"prometeu-bytecode",
"prometeu-hardware-contract",
"serde",
]
[[package]]
name = "quick-xml"
version = "0.38.4"
@ -2429,12 +2122,6 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
[[package]]
name = "safe_arch"
version = "0.7.4"
@ -2478,12 +2165,6 @@ dependencies = [
"tiny-skia",
]
[[package]]
name = "seq-macro"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
[[package]]
name = "serde"
version = "1.0.228"
@ -2554,12 +2235,6 @@ dependencies = [
"libc",
]
[[package]]
name = "siphasher"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
version = "0.4.11"
@ -2581,12 +2256,6 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "smawk"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "smithay-client-toolkit"
version = "0.19.2"
@ -2601,7 +2270,7 @@ dependencies = [
"log",
"memmap2",
"rustix 0.38.44",
"thiserror 1.0.69",
"thiserror",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
@ -2719,33 +2388,13 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width 0.2.2",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl 2.0.18",
"thiserror-impl",
]
[[package]]
@ -2759,17 +2408,6 @@ dependencies = [
"syn 2.0.114",
]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "tiny-skia"
version = "0.11.4"
@ -2982,24 +2620,12 @@ dependencies = [
"wide",
]
[[package]]
name = "unicode-id-start"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007"
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
@ -3012,12 +2638,6 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
@ -3311,7 +2931,7 @@ dependencies = [
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
"thiserror 1.0.69",
"thiserror",
"web-sys",
"wgpu-hal",
"wgpu-types",
@ -3355,7 +2975,7 @@ dependencies = [
"renderdoc-sys",
"rustc-hash 1.1.0",
"smallvec",
"thiserror 1.0.69",
"thiserror",
"wasm-bindgen",
"web-sys",
"wgpu-types",

View File

@ -1,6 +1,7 @@
[workspace]
members = [
"crates/prometeu-abi",
"crates/prometeu-vm",
"crates/prometeu-core",
"crates/prometeu-runtime-desktop",
"crates/prometeu",

View File

@ -1,6 +1,8 @@
mod value;
mod vm_init_error;
pub mod program;
pub use program::ProgramImage;
pub use value::Value;
pub use vm_init_error::VmInitError;

View File

@ -15,13 +15,7 @@ include = ["../../VERSION.txt"]
[dependencies]
prometeu-bytecode = { path = "../prometeu-bytecode" }
prometeu-core = { path = "../prometeu-core" }
oxc_parser = "0.110.0"
oxc_allocator = "0.110.0"
oxc_ast = "0.110.0"
oxc_ast_visit = "0.110.0"
oxc_syntax = "0.110.0"
oxc_span = "0.110.0"
prometeu-abi = { path = "../prometeu-abi" }
clap = { version = "4.5.54", features = ["derive"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"

View File

@ -2,8 +2,8 @@ use crate::building::output::CompiledModule;
use crate::building::plan::BuildStep;
use prometeu_bytecode::opcode::OpCode;
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo};
use prometeu_core::virtual_machine::{ProgramImage, Value};
use std::collections::HashMap;
use prometeu_abi::virtual_machine::{ProgramImage, Value};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LinkError {

View File

@ -3,8 +3,8 @@ use crate::building::output::{compile_project, CompileError};
use crate::building::plan::{BuildPlan, BuildTarget};
use crate::common::files::FileManager;
use crate::deps::resolver::ResolvedGraph;
use prometeu_core::virtual_machine::ProgramImage;
use std::collections::HashMap;
use prometeu_abi::virtual_machine::ProgramImage;
#[derive(Debug)]
pub enum BuildError {

View File

@ -1,83 +1,83 @@
use prometeu_compiler::compiler::compile;
use prometeu_core::hardware::{AssetBridge, AssetManager, Audio, AudioBridge, Gfx, GfxBridge, HardwareBridge, MemoryBanks, Pad, PadBridge, Touch, TouchBridge};
use prometeu_core::virtual_machine::{HostContext, HostReturn, LogicalFrameEndingReason, NativeInterface, Value, VirtualMachine, VmFault};
use std::path::PathBuf;
use std::sync::Arc;
struct SimpleNative;
impl NativeInterface for SimpleNative {
fn syscall(&mut self, _id: u32, _args: &[Value], _ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), VmFault> {
Ok(())
}
}
struct SimpleHardware {
gfx: Gfx,
audio: Audio,
pad: Pad,
touch: Touch,
assets: AssetManager,
}
impl SimpleHardware {
fn new() -> Self {
let banks = Arc::new(MemoryBanks::new());
Self {
gfx: Gfx::new(320, 240, banks.clone()),
audio: Audio::new(banks.clone()),
pad: Pad::default(),
touch: Touch::default(),
assets: AssetManager::new(vec![], vec![], banks.clone(), banks.clone()),
}
}
}
impl HardwareBridge for SimpleHardware {
fn gfx(&self) -> &dyn GfxBridge { &self.gfx }
fn gfx_mut(&mut self) -> &mut dyn GfxBridge { &mut self.gfx }
fn audio(&self) -> &dyn AudioBridge { &self.audio }
fn audio_mut(&mut self) -> &mut dyn AudioBridge { &mut self.audio }
fn pad(&self) -> &dyn PadBridge { &self.pad }
fn pad_mut(&mut self) -> &mut dyn PadBridge { &mut self.pad }
fn touch(&self) -> &dyn TouchBridge { &self.touch }
fn touch_mut(&mut self) -> &mut dyn TouchBridge { &mut self.touch }
fn assets(&self) -> &dyn AssetBridge { &self.assets }
fn assets_mut(&mut self) -> &mut dyn AssetBridge { &mut self.assets }
}
#[test]
fn test_integration_test01_link() {
let project_dir = PathBuf::from("../../test-cartridges/test01");
// Since the test runs from crates/prometeu-compiler, we need to adjust path if necessary.
// Actually, usually tests run from the workspace root if using cargo test --workspace,
// but if running from the crate dir, it's different.
// Let's try absolute path or relative to project root.
let mut root_dir = std::env::current_dir().unwrap();
while !root_dir.join("test-cartridges").exists() {
if let Some(parent) = root_dir.parent() {
root_dir = parent.to_path_buf();
} else {
break;
}
}
let _project_dir = root_dir.join("test-cartridges/test01");
let unit = compile(&project_dir).expect("Failed to compile and link");
let mut vm = VirtualMachine::default();
// Use initialize to load the ROM; entrypoint must be numeric or empty (defaults to 0)
vm.initialize(unit.rom, "frame").expect("Failed to initialize VM");
let mut native = SimpleNative;
let mut hw = SimpleHardware::new();
let mut ctx = HostContext::new(Some(&mut hw));
// Run for a bit
let report = vm.run_budget(1000, &mut native, &mut ctx).expect("VM execution failed");
// It should not trap. test01 might loop or return.
if let LogicalFrameEndingReason::Trap(t) = report.reason {
panic!("VM trapped: {:?}", t);
}
}
// use prometeu_compiler::compiler::compile;
// use std::path::PathBuf;
// use std::sync::Arc;
// use prometeu_compiler::ir_vm::Value;
// use prometeu_hardware_contract::{AssetBridge, AudioBridge, GfxBridge, HardwareBridge, HostContext, HostReturn, NativeInterface, PadBridge, TouchBridge};
//
// struct SimpleNative;
// impl NativeInterface for SimpleNative {
// fn syscall(&mut self, _id: u32, _args: &[Value], _ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), VmFault> {
// Ok(())
// }
// }
//
// struct SimpleHardware {
// gfx: Gfx,
// audio: Audio,
// pad: Pad,
// touch: Touch,
// assets: AssetManager,
// }
//
// impl SimpleHardware {
// fn new() -> Self {
// let banks = Arc::new(MemoryBanks::new());
// Self {
// gfx: Gfx::new(320, 240, banks.clone()),
// audio: Audio::new(banks.clone()),
// pad: Pad::default(),
// touch: Touch::default(),
// assets: AssetManager::new(vec![], vec![], banks.clone(), banks.clone()),
// }
// }
// }
//
// impl HardwareBridge for SimpleHardware {
// fn gfx(&self) -> &dyn GfxBridge { &self.gfx }
// fn gfx_mut(&mut self) -> &mut dyn GfxBridge { &mut self.gfx }
// fn audio(&self) -> &dyn AudioBridge { &self.audio }
// fn audio_mut(&mut self) -> &mut dyn AudioBridge { &mut self.audio }
// fn pad(&self) -> &dyn PadBridge { &self.pad }
// fn pad_mut(&mut self) -> &mut dyn PadBridge { &mut self.pad }
// fn touch(&self) -> &dyn TouchBridge { &self.touch }
// fn touch_mut(&mut self) -> &mut dyn TouchBridge { &mut self.touch }
// fn assets(&self) -> &dyn AssetBridge { &self.assets }
// fn assets_mut(&mut self) -> &mut dyn AssetBridge { &mut self.assets }
// }
//
// #[test]
// fn test_integration_test01_link() {
// let project_dir = PathBuf::from("../../test-cartridges/test01");
// // Since the test runs from crates/prometeu-compiler, we need to adjust path if necessary.
// // Actually, usually tests run from the workspace root if using cargo test --workspace,
// // but if running from the crate dir, it's different.
//
// // Let's try absolute path or relative to project root.
// let mut root_dir = std::env::current_dir().unwrap();
// while !root_dir.join("test-cartridges").exists() {
// if let Some(parent) = root_dir.parent() {
// root_dir = parent.to_path_buf();
// } else {
// break;
// }
// }
// let _project_dir = root_dir.join("test-cartridges/test01");
//
// let unit = compile(&project_dir).expect("Failed to compile and link");
//
// let mut vm = VirtualMachine::default();
// // Use initialize to load the ROM; entrypoint must be numeric or empty (defaults to 0)
// vm.initialize(unit.rom, "frame").expect("Failed to initialize VM");
//
// let mut native = SimpleNative;
// let mut hw = SimpleHardware::new();
// let mut ctx = HostContext::new(Some(&mut hw));
//
// // Run for a bit
// let report = vm.run_budget(1000, &mut native, &mut ctx).expect("VM execution failed");
//
// // It should not trap. test01 might loop or return.
// if let LogicalFrameEndingReason::Trap(t) = report.reason {
// panic!("VM trapped: {:?}", t);
// }
// }

View File

@ -7,6 +7,7 @@ license.workspace = true
[dependencies]
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
prometeu-vm = { path = "../prometeu-vm" }
prometeu-bytecode = { path = "../prometeu-bytecode" }
prometeu-abi = { path = "../prometeu-abi" }
prometeu-hardware-contract = { path = "../prometeu-hardware-contract" }

View File

@ -1,3 +1,4 @@
use prometeu_vm::VirtualMachine;
use crate::firmware::boot_target::BootTarget;
use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetStep};
use crate::firmware::prometeu_context::PrometeuContext;
@ -5,7 +6,6 @@ use crate::hardware::{HardwareBridge, InputSignals};
use crate::model::Cartridge;
use crate::prometeu_hub::PrometeuHub;
use crate::prometeu_os::PrometeuOS;
use crate::virtual_machine::VirtualMachine;
use crate::telemetry::CertificationConfig;

View File

@ -1,8 +1,8 @@
use prometeu_vm::VirtualMachine;
use crate::firmware::boot_target::BootTarget;
use crate::hardware::{HardwareBridge, InputSignals};
use crate::prometeu_hub::PrometeuHub;
use crate::prometeu_os::PrometeuOS;
use crate::virtual_machine::VirtualMachine;
pub struct PrometeuContext<'a> {
pub vm: &'a mut VirtualMachine,

View File

@ -16,7 +16,6 @@
//! The "Source of Truth" for the console's behavior lives here.
pub mod hardware;
pub mod virtual_machine;
pub mod firmware;
pub mod fs;
pub mod prometeu_os;

View File

@ -1,4 +1,3 @@
mod prometeu_os;
use crate::virtual_machine::NativeInterface;
pub use prometeu_os::PrometeuOS;

View File

@ -3,12 +3,12 @@ use crate::fs::{FsBackend, FsState, VirtualFS};
use crate::hardware::{HardwareBridge, InputSignals};
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::{HostContext, HostReturn, SyscallId, Value, VirtualMachine, VmFault};
use std::collections::HashMap;
use std::time::Instant;
use prometeu_hardware_contract::{expect_bool, expect_int};
use prometeu_abi::virtual_machine::{Value, VmFault};
use prometeu_hardware_contract::{expect_bool, expect_int, HostContext, HostReturn, NativeInterface, SyscallId};
use prometeu_vm::{LogicalFrameEndingReason, VirtualMachine};
/// PrometeuOS (POS): The central system firmware and resource manager.
///
@ -251,22 +251,22 @@ impl PrometeuOS {
self.telemetry_current.vm_steps += run.steps_executed;
// Handle Breakpoints
if run.reason == crate::virtual_machine::LogicalFrameEndingReason::Breakpoint {
if run.reason == LogicalFrameEndingReason::Breakpoint {
self.paused = true;
self.debug_step_request = false;
self.log(LogLevel::Info, LogSource::Vm, 0xDEB1, format!("Breakpoint hit at PC 0x{:X}", vm.pc));
}
// Handle Panics
if let crate::virtual_machine::LogicalFrameEndingReason::Panic(err) = run.reason {
if let LogicalFrameEndingReason::Panic(err) = run.reason {
let err_msg = format!("PVM Fault: \"{}\"", err);
self.log(LogLevel::Error, LogSource::Vm, 0, err_msg.clone());
return Some(err_msg);
}
// 4. Frame Finalization (FRAME_SYNC reached or Entrypoint returned)
if run.reason == crate::virtual_machine::LogicalFrameEndingReason::FrameSync ||
run.reason == crate::virtual_machine::LogicalFrameEndingReason::EndOfRom {
if run.reason == LogicalFrameEndingReason::FrameSync ||
run.reason == LogicalFrameEndingReason::EndOfRom {
// All drawing commands for this frame are now complete.
// Finalize the framebuffer.
hw.gfx_mut().render_all();
@ -415,10 +415,11 @@ impl PrometeuOS {
#[cfg(test)]
mod tests {
use prometeu_abi::virtual_machine::Value;
use prometeu_hardware_contract::HostReturn;
use super::*;
use crate::hardware::InputSignals;
use crate::model::{AppMode, Cartridge};
use crate::virtual_machine::{Value, VirtualMachine};
use crate::Hardware;
fn call_syscall(os: &mut PrometeuOS, id: u32, vm: &mut VirtualMachine, hw: &mut dyn HardwareBridge) -> Result<(), VmFault> {
@ -768,7 +769,7 @@ mod tests {
#[test]
fn test_gfx_clear565_syscall() {
let mut hw = crate::Hardware::new();
let mut hw = Hardware::new();
let mut os = PrometeuOS::new(None);
let mut stack = Vec::new();
@ -795,7 +796,7 @@ mod tests {
#[test]
fn test_input_snapshots_syscalls() {
let mut hw = crate::Hardware::new();
let mut hw = Hardware::new();
let mut os = PrometeuOS::new(None);
// Pad snapshot

View File

@ -1,149 +0,0 @@
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
/// Represents any piece of data that can be stored on the VM stack or in globals.
///
/// The PVM is "dynamically typed" at the bytecode level, meaning a single
/// `Value` enum can hold different primitive types. The VM performs
/// automatic type promotion (e.g., adding an Int32 to a Float64 results
/// in a Float64) to ensure mathematical correctness.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
/// 32-bit signed integer. Used for most loop counters and indices.
Int32(i32),
/// 64-bit signed integer. Used for large numbers and timestamps.
Int64(i64),
/// 64-bit double precision float. Used for physics and complex math.
Float(f64),
/// Boolean value (true/false).
Boolean(bool),
/// UTF-8 string. Strings are immutable and usually come from the Constant Pool.
String(String),
/// Bounded 16-bit-ish integer.
Bounded(u32),
/// A pointer to an object on the heap.
Gate(usize),
/// Represents the absence of a value (equivalent to `null` or `undefined`).
Null,
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Int32(a), Value::Int32(b)) => a == b,
(Value::Int64(a), Value::Int64(b)) => a == b,
(Value::Int32(a), Value::Int64(b)) => *a as i64 == *b,
(Value::Int64(a), Value::Int32(b)) => *a == *b as i64,
(Value::Float(a), Value::Float(b)) => a == b,
(Value::Int32(a), Value::Float(b)) => *a as f64 == *b,
(Value::Float(a), Value::Int32(b)) => *a == *b as f64,
(Value::Int64(a), Value::Float(b)) => *a as f64 == *b,
(Value::Float(a), Value::Int64(b)) => *a == *b as f64,
(Value::Boolean(a), Value::Boolean(b)) => a == b,
(Value::String(a), Value::String(b)) => a == b,
(Value::Bounded(a), Value::Bounded(b)) => a == b,
(Value::Gate(a), Value::Gate(b)) => a == b,
(Value::Null, Value::Null) => true,
_ => false,
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(Value::Int32(a), Value::Int32(b)) => a.partial_cmp(b),
(Value::Int64(a), Value::Int64(b)) => a.partial_cmp(b),
(Value::Int32(a), Value::Int64(b)) => (*a as i64).partial_cmp(b),
(Value::Int64(a), Value::Int32(b)) => a.partial_cmp(&(*b as i64)),
(Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
(Value::Bounded(a), Value::Bounded(b)) => a.partial_cmp(b),
(Value::Int32(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
(Value::Float(a), Value::Int32(b)) => a.partial_cmp(&(*b as f64)),
(Value::Int64(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
(Value::Float(a), Value::Int64(b)) => a.partial_cmp(&(*b as f64)),
(Value::Boolean(a), Value::Boolean(b)) => a.partial_cmp(b),
(Value::String(a), Value::String(b)) => a.partial_cmp(b),
_ => None,
}
}
}
impl Value {
pub fn as_float(&self) -> Option<f64> {
match self {
Value::Int32(i) => Some(*i as f64),
Value::Int64(i) => Some(*i as f64),
Value::Float(f) => Some(*f),
Value::Bounded(b) => Some(*b as f64),
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
Value::Int32(i) => Some(*i as i64),
Value::Int64(i) => Some(*i),
Value::Float(f) => Some(*f as i64),
Value::Bounded(b) => Some(*b as i64),
_ => None,
}
}
pub fn to_string(&self) -> String {
match self {
Value::Int32(i) => i.to_string(),
Value::Int64(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Bounded(b) => format!("{}b", b),
Value::Boolean(b) => b.to_string(),
Value::String(s) => s.clone(),
Value::Gate(r) => format!("[Gate {}]", r),
Value::Null => "null".to_string(),
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_value_equality() {
assert_eq!(Value::Int32(10), Value::Int32(10));
assert_eq!(Value::Int64(10), Value::Int64(10));
assert_eq!(Value::Int32(10), Value::Int64(10));
assert_eq!(Value::Int64(10), Value::Int32(10));
assert_eq!(Value::Float(10.5), Value::Float(10.5));
assert_eq!(Value::Int32(10), Value::Float(10.0));
assert_eq!(Value::Float(10.0), Value::Int32(10));
assert_eq!(Value::Int64(10), Value::Float(10.0));
assert_eq!(Value::Float(10.0), Value::Int64(10));
assert_ne!(Value::Int32(10), Value::Int32(11));
assert_ne!(Value::Int64(10), Value::Int64(11));
assert_ne!(Value::Int32(10), Value::Int64(11));
assert_ne!(Value::Int32(10), Value::Float(10.1));
assert_eq!(Value::Boolean(true), Value::Boolean(true));
assert_ne!(Value::Boolean(true), Value::Boolean(false));
assert_eq!(Value::String("oi".into()), Value::String("oi".into()));
assert_eq!(Value::Null, Value::Null);
}
#[test]
fn test_value_conversions() {
let v_int32 = Value::Int32(42);
assert_eq!(v_int32.as_float(), Some(42.0));
assert_eq!(v_int32.as_integer(), Some(42));
let v_int64 = Value::Int64(42);
assert_eq!(v_int64.as_float(), Some(42.0));
assert_eq!(v_int64.as_integer(), Some(42));
let v_float = Value::Float(42.7);
assert_eq!(v_float.as_float(), Some(42.7));
assert_eq!(v_float.as_integer(), Some(42));
let v_bool = Value::Boolean(true);
assert_eq!(v_bool.as_float(), None);
assert_eq!(v_bool.as_integer(), None);
}
}

View File

@ -1,14 +1,13 @@
use prometeu_core::virtual_machine::HostReturn;
use prometeu_core::virtual_machine::NativeInterface;
use prometeu_core::virtual_machine::Value;
use prometeu_core::virtual_machine::{HostContext, LogicalFrameEndingReason, VirtualMachine};
use prometeu_core::Hardware;
use std::fs;
use std::path::Path;
use prometeu_abi::virtual_machine::{Value, VmFault};
use prometeu_hardware_contract::{HostContext, HostReturn, NativeInterface};
use prometeu_vm::{LogicalFrameEndingReason, VirtualMachine};
struct MockNative;
impl NativeInterface for MockNative {
fn syscall(&mut self, id: u32, _args: &[Value], ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), prometeu_core::virtual_machine::VmFault> {
fn syscall(&mut self, id: u32, _args: &[Value], ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), VmFault> {
if id == 0x2010 { // InputPadSnapshot
for _ in 0..48 {
ret.push_bool(false);

View File

@ -0,0 +1,11 @@
[package]
name = "prometeu-vm"
version = "0.1.0"
edition = "2024"
license.workspace = true
[dependencies]
serde = { version = "1.0.228", features = ["derive"] }
prometeu-bytecode = { path = "../prometeu-bytecode" }
prometeu-abi = { path = "../prometeu-abi" }
prometeu-hardware-contract = { path = "../prometeu-hardware-contract" }

View File

@ -1,4 +1,4 @@
use crate::virtual_machine::opcode_spec::{OpCodeSpecExt, OpcodeSpec};
use crate::opcode_spec::{OpCodeSpecExt, OpcodeSpec};
use prometeu_bytecode::opcode::OpCode;
#[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -1,13 +1,12 @@
mod virtual_machine;
mod call_frame;
mod scope_frame;
mod program;
pub mod local_addressing;
pub mod opcode_spec;
pub mod bytecode;
pub mod verifier;
pub use program::ProgramImage;
pub use prometeu_abi::virtual_machine::program::ProgramImage;
pub use prometeu_abi::virtual_machine::{Value, VmFault};
pub use prometeu_bytecode::abi::TrapInfo;
pub use prometeu_bytecode::opcode::OpCode;

View File

@ -1,4 +1,4 @@
use crate::virtual_machine::call_frame::CallFrame;
use crate::call_frame::CallFrame;
use prometeu_bytecode::abi::{TrapInfo, TRAP_INVALID_LOCAL};
use prometeu_bytecode::FunctionMeta;

View File

@ -1,5 +1,5 @@
use crate::abi::syscalls::Syscall;
use crate::virtual_machine::bytecode::decoder::{decode_at, DecodeError};
use prometeu_abi::syscalls::Syscall;
use crate::bytecode::decoder::{decode_at, DecodeError};
use prometeu_bytecode::opcode::OpCode;
use prometeu_bytecode::FunctionMeta;
use std::collections::{HashMap, HashSet, VecDeque};

View File

@ -1,7 +1,7 @@
use crate::virtual_machine::call_frame::CallFrame;
use crate::virtual_machine::scope_frame::ScopeFrame;
use crate::virtual_machine::Value;
use crate::virtual_machine::{HostContext, NativeInterface, ProgramImage, VmInitError};
use crate::call_frame::CallFrame;
use crate::scope_frame::ScopeFrame;
use crate::Value;
use crate::{HostContext, NativeInterface, ProgramImage, VmInitError};
use prometeu_bytecode::abi::{TrapInfo, TRAP_BAD_RET_SLOTS, TRAP_DIV_ZERO, TRAP_INVALID_FUNC, TRAP_OOB, TRAP_TYPE};
use prometeu_bytecode::opcode::OpCode;
@ -125,7 +125,7 @@ impl VirtualMachine {
match prometeu_bytecode::BytecodeLoader::load(&program_bytes) {
Ok(module) => {
// Run verifier on the module
let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&module.code, &module.functions)
let max_stacks = crate::verifier::Verifier::verify(&module.code, &module.functions)
.map_err(VmInitError::VerificationFailed)?;
let mut program = ProgramImage::from(module);
@ -342,7 +342,7 @@ impl VirtualMachine {
let start_pc = self.pc;
// Fetch & Decode
let instr = crate::virtual_machine::bytecode::decoder::decode_at(&self.program.rom, self.pc)
let instr = crate::bytecode::decoder::decode_at(&self.program.rom, self.pc)
.map_err(|e| LogicalFrameEndingReason::Panic(format!("{:?}", e)))?;
let opcode = instr.opcode;
@ -699,10 +699,10 @@ impl VirtualMachine {
let frame = self.call_stack.last().ok_or_else(|| LogicalFrameEndingReason::Panic("No active call frame".into()))?;
let func = &self.program.functions[frame.func_idx];
crate::virtual_machine::local_addressing::check_local_slot(func, slot, opcode as u16, start_pc as u32)
crate::local_addressing::check_local_slot(func, slot, opcode as u16, start_pc as u32)
.map_err(|trap_info| self.trap(trap_info.code, trap_info.opcode, trap_info.message, trap_info.pc))?;
let stack_idx = crate::virtual_machine::local_addressing::local_index(frame, slot);
let stack_idx = crate::local_addressing::local_index(frame, slot);
let val = self.operand_stack.get(stack_idx).cloned().ok_or_else(|| LogicalFrameEndingReason::Panic("Internal error: validated local slot not found in stack".into()))?;
self.push(val);
}
@ -712,10 +712,10 @@ impl VirtualMachine {
let frame = self.call_stack.last().ok_or_else(|| LogicalFrameEndingReason::Panic("No active call frame".into()))?;
let func = &self.program.functions[frame.func_idx];
crate::virtual_machine::local_addressing::check_local_slot(func, slot, opcode as u16, start_pc as u32)
crate::local_addressing::check_local_slot(func, slot, opcode as u16, start_pc as u32)
.map_err(|trap_info| self.trap(trap_info.code, trap_info.opcode, trap_info.message, trap_info.pc))?;
let stack_idx = crate::virtual_machine::local_addressing::local_index(frame, slot);
let stack_idx = crate::local_addressing::local_index(frame, slot);
self.operand_stack[stack_idx] = val;
}
OpCode::Call => {
@ -828,8 +828,7 @@ impl VirtualMachine {
let pc_at_syscall = start_pc as u32;
let id = u32::from_le_bytes(instr.imm[0..4].try_into().unwrap());
let syscall = crate::abi::syscalls::Syscall::from_u32(id).ok_or_else(|| {
let syscall = prometeu_abi::syscalls::Syscall::from_u32(id).ok_or_else(|| {
self.trap(prometeu_bytecode::abi::TRAP_INVALID_SYSCALL, OpCode::Syscall as u16, format!("Unknown syscall: 0x{:08X}", id), pc_at_syscall)
})?;
@ -845,11 +844,11 @@ impl VirtualMachine {
args.reverse();
let stack_height_before = self.operand_stack.len();
let mut ret = crate::virtual_machine::HostReturn::new(&mut self.operand_stack);
let mut ret = crate::HostReturn::new(&mut self.operand_stack);
native.syscall(id, &args, &mut ret, ctx).map_err(|fault| match fault {
crate::virtual_machine::VmFault::Trap(code, msg) => self.trap(code, OpCode::Syscall as u16, msg, pc_at_syscall),
crate::virtual_machine::VmFault::Panic(msg) => LogicalFrameEndingReason::Panic(msg),
crate::virtual_machine::VmFault::Unavailable => LogicalFrameEndingReason::Panic("Host feature unavailable".into()),
crate::VmFault::Trap(code, msg) => self.trap(code, OpCode::Syscall as u16, msg, pc_at_syscall),
crate::VmFault::Panic(msg) => LogicalFrameEndingReason::Panic(msg),
crate::VmFault::Unavailable => LogicalFrameEndingReason::Panic("Host feature unavailable".into()),
})?;
let stack_height_after = self.operand_stack.len();
@ -931,7 +930,7 @@ mod tests {
}]);
vm
}
use crate::virtual_machine::{HostReturn, Value, VmFault};
use crate::{HostReturn, Value, VmFault};
use prometeu_bytecode::abi::SourceSpan;
use prometeu_bytecode::FunctionMeta;
use prometeu_hardware_contract::expect_int;
@ -1845,7 +1844,7 @@ mod tests {
let res = ret.push_bounded(65536);
assert!(res.is_err());
match res.err().unwrap() {
crate::virtual_machine::VmFault::Trap(code, _) => {
crate::VmFault::Trap(code, _) => {
assert_eq!(code, prometeu_bytecode::abi::TRAP_OOB);
}
_ => panic!("Expected Trap"),