From c5c1f68f7caca0554f8eba40ad7582763a4646f2 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 3 Feb 2026 16:51:28 +0000 Subject: [PATCH] pr 00.1 --- Cargo.lock | 9 ++ Cargo.toml | 1 + crates/prometeu-abi/Cargo.toml | 9 ++ crates/prometeu-abi/src/debugger_protocol.rs | 147 +++++++++++++++++ crates/prometeu-abi/src/lib.rs | 12 ++ crates/prometeu-abi/src/log/log_event.rs | 13 ++ crates/prometeu-abi/src/log/log_level.rs | 8 + crates/prometeu-abi/src/log/log_service.rs | 93 +++++++++++ crates/prometeu-abi/src/log/log_source.rs | 8 + crates/prometeu-abi/src/log/mod.rs | 9 ++ crates/prometeu-abi/src/model/asset.rs | 80 ++++++++++ crates/prometeu-abi/src/model/button.rs | 40 +++++ crates/prometeu-abi/src/model/cartridge.rs | 77 +++++++++ .../src/model/cartridge_loader.rs | 80 ++++++++++ crates/prometeu-abi/src/model/color.rs | 76 +++++++++ crates/prometeu-abi/src/model/mod.rs | 25 +++ crates/prometeu-abi/src/model/sample.rs | 27 ++++ crates/prometeu-abi/src/model/sound_bank.rs | 16 ++ crates/prometeu-abi/src/model/sprite.rs | 13 ++ crates/prometeu-abi/src/model/tile.rs | 7 + crates/prometeu-abi/src/model/tile_bank.rs | 75 +++++++++ crates/prometeu-abi/src/model/tile_layer.rs | 109 +++++++++++++ crates/prometeu-abi/src/model/window.rs | 21 +++ crates/prometeu-abi/src/telemetry.rs | 123 ++++++++++++++ .../prometeu-abi/src/virtual_machine/value.rs | 151 ++++++++++++++++++ crates/prometeu-core/Cargo.toml | 3 +- crates/prometeu-core/src/lib.rs | 11 +- .../prometeu-core/src/virtual_machine/mod.rs | 3 +- .../src/virtual_machine/virtual_machine.rs | 2 +- docs/specs/pbs/files/PRs para Junie.md | 32 ---- test-cartridges/canonical/golden/program.pbc | Bin 3727 -> 3727 bytes 31 files changed, 1240 insertions(+), 40 deletions(-) create mode 100644 crates/prometeu-abi/Cargo.toml create mode 100644 crates/prometeu-abi/src/debugger_protocol.rs create mode 100644 crates/prometeu-abi/src/lib.rs create mode 100644 crates/prometeu-abi/src/log/log_event.rs create mode 100644 crates/prometeu-abi/src/log/log_level.rs create mode 100644 crates/prometeu-abi/src/log/log_service.rs create mode 100644 crates/prometeu-abi/src/log/log_source.rs create mode 100644 crates/prometeu-abi/src/log/mod.rs create mode 100644 crates/prometeu-abi/src/model/asset.rs create mode 100644 crates/prometeu-abi/src/model/button.rs create mode 100644 crates/prometeu-abi/src/model/cartridge.rs create mode 100644 crates/prometeu-abi/src/model/cartridge_loader.rs create mode 100644 crates/prometeu-abi/src/model/color.rs create mode 100644 crates/prometeu-abi/src/model/mod.rs create mode 100644 crates/prometeu-abi/src/model/sample.rs create mode 100644 crates/prometeu-abi/src/model/sound_bank.rs create mode 100644 crates/prometeu-abi/src/model/sprite.rs create mode 100644 crates/prometeu-abi/src/model/tile.rs create mode 100644 crates/prometeu-abi/src/model/tile_bank.rs create mode 100644 crates/prometeu-abi/src/model/tile_layer.rs create mode 100644 crates/prometeu-abi/src/model/window.rs create mode 100644 crates/prometeu-abi/src/telemetry.rs create mode 100644 crates/prometeu-abi/src/virtual_machine/value.rs diff --git a/Cargo.lock b/Cargo.lock index 30794b1f..7f4f33f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2188,6 +2188,14 @@ dependencies = [ "prometeu-runtime-desktop", ] +[[package]] +name = "prometeu-abi" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "prometeu-analysis" version = "0.1.0" @@ -2226,6 +2234,7 @@ dependencies = [ name = "prometeu-core" version = "0.1.0" dependencies = [ + "prometeu-abi", "prometeu-bytecode", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index b7ad9103..55cad8cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "crates/prometeu-abi", "crates/prometeu-core", "crates/prometeu-runtime-desktop", "crates/prometeu", diff --git a/crates/prometeu-abi/Cargo.toml b/crates/prometeu-abi/Cargo.toml new file mode 100644 index 00000000..ed912f33 --- /dev/null +++ b/crates/prometeu-abi/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "prometeu-abi" +version = "0.1.0" +edition = "2024" +license.workspace = true + +[dependencies] +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" diff --git a/crates/prometeu-abi/src/debugger_protocol.rs b/crates/prometeu-abi/src/debugger_protocol.rs new file mode 100644 index 00000000..31bfbd58 --- /dev/null +++ b/crates/prometeu-abi/src/debugger_protocol.rs @@ -0,0 +1,147 @@ +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 super::*; + 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-abi/src/lib.rs b/crates/prometeu-abi/src/lib.rs new file mode 100644 index 00000000..12c506b2 --- /dev/null +++ b/crates/prometeu-abi/src/lib.rs @@ -0,0 +1,12 @@ +//! Prometeu ABI: tipos e contratos compartilhados entre os crates. + +pub mod model; +pub mod log; +pub mod telemetry; +pub mod debugger_protocol; + +// 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; +} diff --git a/crates/prometeu-abi/src/log/log_event.rs b/crates/prometeu-abi/src/log/log_event.rs new file mode 100644 index 00000000..a35382b9 --- /dev/null +++ b/crates/prometeu-abi/src/log/log_event.rs @@ -0,0 +1,13 @@ +use crate::log::LogLevel; +use crate::log::LogSource; + +#[derive(Debug, Clone)] +pub struct LogEvent { + pub seq: u64, + pub ts_ms: u64, + pub frame: u64, + pub level: LogLevel, + pub source: LogSource, + pub tag: u16, + pub msg: String, +} diff --git a/crates/prometeu-abi/src/log/log_level.rs b/crates/prometeu-abi/src/log/log_level.rs new file mode 100644 index 00000000..25d8072c --- /dev/null +++ b/crates/prometeu-abi/src/log/log_level.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, +} diff --git a/crates/prometeu-abi/src/log/log_service.rs b/crates/prometeu-abi/src/log/log_service.rs new file mode 100644 index 00000000..a1b607e4 --- /dev/null +++ b/crates/prometeu-abi/src/log/log_service.rs @@ -0,0 +1,93 @@ +use crate::log::{LogEvent, LogLevel, LogSource}; +use std::collections::VecDeque; + +pub struct LogService { + events: VecDeque, + capacity: usize, + next_seq: u64, +} + +impl LogService { + pub fn new(capacity: usize) -> Self { + Self { + events: VecDeque::with_capacity(capacity), + capacity, + next_seq: 0, + } + } + + pub fn log(&mut self, ts_ms: u64, frame: u64, level: LogLevel, source: LogSource, tag: u16, msg: String) { + if self.events.len() >= self.capacity { + self.events.pop_front(); + } + self.events.push_back(LogEvent { + seq: self.next_seq, + ts_ms, + frame, + level, + source, + tag, + msg, + }); + self.next_seq += 1; + } + + pub fn get_recent(&self, n: usize) -> Vec { + self.events.iter().rev().take(n).cloned().collect::>().into_iter().rev().collect() + } + + pub fn get_after(&self, seq: u64) -> Vec { + self.events.iter().filter(|e| e.seq > seq).cloned().collect() + } + + pub fn last_seq(&self) -> Option { + self.events.back().map(|e| e.seq) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ring_buffer_capacity() { + let mut service = LogService::new(3); + service.log(100, 1, LogLevel::Info, LogSource::Pos, 0, "Log 1".to_string()); + service.log(110, 1, LogLevel::Info, LogSource::Pos, 0, "Log 2".to_string()); + service.log(120, 1, LogLevel::Info, LogSource::Pos, 0, "Log 3".to_string()); + + assert_eq!(service.events.len(), 3); + assert_eq!(service.events[0].msg, "Log 1"); + + service.log(130, 1, LogLevel::Info, LogSource::Pos, 0, "Log 4".to_string()); + assert_eq!(service.events.len(), 3); + assert_eq!(service.events[0].msg, "Log 2"); + assert_eq!(service.events[2].msg, "Log 4"); + } + + #[test] + fn test_get_recent() { + let mut service = LogService::new(10); + for i in 0..5 { + service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i)); + } + + let recent = service.get_recent(2); + assert_eq!(recent.len(), 2); + assert_eq!(recent[0].msg, "Log 3"); + assert_eq!(recent[1].msg, "Log 4"); + } + + #[test] + fn test_get_after() { + let mut service = LogService::new(10); + for i in 0..5 { + service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i)); + } + + let after = service.get_after(2); // seqs are 0, 1, 2, 3, 4. Should return 3 and 4. + assert_eq!(after.len(), 2); + assert_eq!(after[0].msg, "Log 3"); + assert_eq!(after[1].msg, "Log 4"); + } +} diff --git a/crates/prometeu-abi/src/log/log_source.rs b/crates/prometeu-abi/src/log/log_source.rs new file mode 100644 index 00000000..a9ed33a4 --- /dev/null +++ b/crates/prometeu-abi/src/log/log_source.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LogSource { + Pos, + Hub, + Vm, + Fs, + App { app_id: u32 }, +} diff --git a/crates/prometeu-abi/src/log/mod.rs b/crates/prometeu-abi/src/log/mod.rs new file mode 100644 index 00000000..547faf77 --- /dev/null +++ b/crates/prometeu-abi/src/log/mod.rs @@ -0,0 +1,9 @@ +mod log_level; +mod log_source; +mod log_event; +mod log_service; + +pub use log_level::LogLevel; +pub use log_source::LogSource; +pub use log_event::LogEvent; +pub use log_service::LogService; diff --git a/crates/prometeu-abi/src/model/asset.rs b/crates/prometeu-abi/src/model/asset.rs new file mode 100644 index 00000000..195427f3 --- /dev/null +++ b/crates/prometeu-abi/src/model/asset.rs @@ -0,0 +1,80 @@ +use serde::{Deserialize, Serialize}; + +pub type HandleId = u32; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[allow(non_camel_case_types)] +pub enum BankType { + TILES, + SOUNDS, + // TILEMAPS, + // BLOBS, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct AssetEntry { + pub asset_id: u32, + pub asset_name: String, + pub bank_type: BankType, + pub offset: u64, + pub size: u64, + pub decoded_size: u64, + pub codec: String, // e.g., "RAW" + pub metadata: serde_json::Value, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PreloadEntry { + pub asset_name: String, + pub slot: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum LoadStatus { + PENDING, + LOADING, + READY, + COMMITTED, + CANCELED, + ERROR, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BankStats { + pub total_bytes: usize, + pub used_bytes: usize, + pub free_bytes: usize, + pub inflight_bytes: usize, + pub slot_count: usize, + pub slots_occupied: usize, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SlotStats { + pub asset_id: Option, + pub asset_name: Option, + pub generation: u32, + pub resident_bytes: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SlotRef { + pub asset_type: BankType, + pub index: usize, +} + +impl SlotRef { + pub fn gfx(index: usize) -> Self { + Self { + asset_type: BankType::TILES, + index, + } + } + + pub fn audio(index: usize) -> Self { + Self { + asset_type: BankType::SOUNDS, + index, + } + } +} diff --git a/crates/prometeu-abi/src/model/button.rs b/crates/prometeu-abi/src/model/button.rs new file mode 100644 index 00000000..de214d2a --- /dev/null +++ b/crates/prometeu-abi/src/model/button.rs @@ -0,0 +1,40 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum ButtonId { + Up = 0, + Down = 1, + Left = 2, + Right = 3, + A = 4, + B = 5, + X = 6, + Y = 7, + L = 8, + R = 9, + Start = 10, + Select = 11, +} + +#[derive(Default, Clone, Copy, Debug)] +pub struct Button { + pub pressed: bool, + pub released: bool, + pub down: bool, + pub hold_frames: u32, +} + +impl Button { + pub fn begin_frame(&mut self, is_down_now: bool) { + let was_down = self.down; + self.down = is_down_now.clone(); + + self.pressed = !was_down && self.down; + self.released = was_down && !self.down; + + if self.down { + self.hold_frames = self.hold_frames.saturating_add(1); + } else { + self.hold_frames = 0; + } + } +} diff --git a/crates/prometeu-abi/src/model/cartridge.rs b/crates/prometeu-abi/src/model/cartridge.rs new file mode 100644 index 00000000..6beadebc --- /dev/null +++ b/crates/prometeu-abi/src/model/cartridge.rs @@ -0,0 +1,77 @@ +use crate::model::asset::{AssetEntry, PreloadEntry}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +pub enum AppMode { + Game, + System, +} + +#[derive(Debug, Clone)] +pub struct Cartridge { + pub app_id: u32, + pub title: String, + pub app_version: String, + pub app_mode: AppMode, + pub entrypoint: String, + pub program: Vec, + pub assets: Vec, + pub asset_table: Vec, + pub preload: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CartridgeDTO { + pub app_id: u32, + pub title: String, + pub app_version: String, + pub app_mode: AppMode, + pub entrypoint: String, + pub program: Vec, + pub assets: Vec, + #[serde(default)] + pub asset_table: Vec, + #[serde(default)] + pub preload: Vec, +} + +impl From for Cartridge { + fn from(dto: CartridgeDTO) -> Self { + Self { + app_id: dto.app_id, + title: dto.title, + app_version: dto.app_version, + app_mode: dto.app_mode, + entrypoint: dto.entrypoint, + program: dto.program, + assets: dto.assets, + asset_table: dto.asset_table, + preload: dto.preload, + } + } +} + +#[derive(Debug)] +pub enum CartridgeError { + NotFound, + InvalidFormat, + InvalidManifest, + UnsupportedVersion, + MissingProgram, + IoError, +} + +#[derive(Deserialize)] +pub struct CartridgeManifest { + pub magic: String, + pub cartridge_version: u32, + pub app_id: u32, + pub title: String, + pub app_version: String, + pub app_mode: AppMode, + pub entrypoint: String, + #[serde(default)] + pub asset_table: Vec, + #[serde(default)] + pub preload: Vec, +} diff --git a/crates/prometeu-abi/src/model/cartridge_loader.rs b/crates/prometeu-abi/src/model/cartridge_loader.rs new file mode 100644 index 00000000..960e5f8c --- /dev/null +++ b/crates/prometeu-abi/src/model/cartridge_loader.rs @@ -0,0 +1,80 @@ +use crate::model::cartridge::{Cartridge, CartridgeDTO, CartridgeError, CartridgeManifest}; +use std::fs; +use std::path::Path; + +pub struct CartridgeLoader; + +impl CartridgeLoader { + pub fn load(path: impl AsRef) -> Result { + let path = path.as_ref(); + if !path.exists() { + return Err(CartridgeError::NotFound); + } + + if path.is_dir() { + DirectoryCartridgeLoader::load(path) + } else if path.extension().is_some_and(|ext| ext == "pmc") { + PackedCartridgeLoader::load(path) + } else { + Err(CartridgeError::InvalidFormat) + } + } +} + +pub struct DirectoryCartridgeLoader; + +impl DirectoryCartridgeLoader { + pub fn load(path: &Path) -> Result { + let manifest_path = path.join("manifest.json"); + if !manifest_path.exists() { + return Err(CartridgeError::InvalidManifest); + } + + let manifest_content = fs::read_to_string(manifest_path).map_err(|_| CartridgeError::IoError)?; + let manifest: CartridgeManifest = serde_json::from_str(&manifest_content).map_err(|_| CartridgeError::InvalidManifest)?; + + // Additional validation as per requirements + if manifest.magic != "PMTU" { + return Err(CartridgeError::InvalidManifest); + } + if manifest.cartridge_version != 1 { + return Err(CartridgeError::UnsupportedVersion); + } + + let program_path = path.join("program.pbc"); + if !program_path.exists() { + return Err(CartridgeError::MissingProgram); + } + + let program = fs::read(program_path).map_err(|_| CartridgeError::IoError)?; + + let assets_pa_path = path.join("assets.pa"); + let assets = if assets_pa_path.exists() { + fs::read(assets_pa_path).map_err(|_| CartridgeError::IoError)? + } else { + Vec::new() + }; + + let dto = CartridgeDTO { + app_id: manifest.app_id, + title: manifest.title, + app_version: manifest.app_version, + app_mode: manifest.app_mode, + entrypoint: manifest.entrypoint, + program, + assets, + asset_table: manifest.asset_table, + preload: manifest.preload, + }; + + Ok(Cartridge::from(dto)) + } +} + +pub struct PackedCartridgeLoader; + +impl PackedCartridgeLoader { + pub fn load(_path: &Path) -> Result { + Err(CartridgeError::InvalidFormat) + } +} diff --git a/crates/prometeu-abi/src/model/color.rs b/crates/prometeu-abi/src/model/color.rs new file mode 100644 index 00000000..4e0fcffc --- /dev/null +++ b/crates/prometeu-abi/src/model/color.rs @@ -0,0 +1,76 @@ +/// Represents a 16-bit color in the RGB565 format. +/// +/// The RGB565 format is a common high-color representation for embedded systems: +/// - **Red**: 5 bits (0..31) +/// - **Green**: 6 bits (0..63) +/// - **Blue**: 5 bits (0..31) +/// +/// Prometeu does not have a hardware alpha channel. Transparency is achieved +/// by using a specific color key (Magenta / 0xF81F) which the GFX engine +/// skips during rendering. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct Color(pub u16); + +impl Color { + pub const BLACK: Self = Self::rgb(0, 0, 0); // 0x0000 + pub const WHITE: Self = Self::rgb(255, 255, 255); // 0xFFFF + pub const RED: Self = Self::rgb(255, 0, 0); // 0xF800 + pub const GREEN: Self = Self::rgb(0, 255, 0); // 0x07E0 + pub const BLUE: Self = Self::rgb(0, 0, 255); // 0x001F + pub const YELLOW: Self = Self::rgb(255, 255, 0); // 0xFFE0 + pub const ORANGE: Self = Self::rgb(255, 128, 0); + pub const INDIGO: Self = Self::rgb(75, 0, 130); + pub const GRAY: Self = Self::rgb(128, 128, 128); + pub const CYAN: Self = Self::rgb(0, 255, 255); // 0x07FF + pub const MAGENTA: Self = Self::rgb(255, 0, 255); // 0xF81F + pub const COLOR_KEY: Self = Self::MAGENTA; + pub const TRANSPARENT: Self = Self::MAGENTA; + + /// Extracts channels in the native RGB565 range: + /// R: 0..31, G: 0..63, B: 0..31 + #[inline(always)] + pub const fn unpack_to_native(px: u16) -> (u8, u8, u8) { + let r = ((px >> 11) & 0x1F) as u8; + let g = ((px >> 5) & 0x3F) as u8; + let b = (px & 0x1F) as u8; + (r, g, b) + } + + /// Packs channels from the native RGB565 range into a pixel: + /// R: 0..31, G: 0..63, B: 0..31 + #[inline(always)] + pub const fn pack_from_native(r: u8, g: u8, b: u8) -> u16 { + ((r as u16 & 0x1F) << 11) | ((g as u16 & 0x3F) << 5) | (b as u16 & 0x1F) + } + + /// Creates an RGB565 color from 8-bit components (0..255). + pub const fn rgb(r: u8, g: u8, b: u8) -> Self { + let r5 = (r as u16 >> 3) & 0x1F; + let g6 = (g as u16 >> 2) & 0x3F; + let b5 = (b as u16 >> 3) & 0x1F; + + Self((r5 << 11) | (g6 << 5) | b5) + } + + pub const fn gray_scale(c: u8) -> Self { + Self::rgb(c, c, c) + } + + pub const fn from_raw(raw: u16) -> Self { + Self(raw) + } + + pub const fn raw(self) -> u16 { + self.0 + } + + pub const fn hex(self) -> i32 { + let (r5, g6, b5) = Self::unpack_to_native(self.0); + let r8 = ((r5 as u32) << 3) | ((r5 as u32) >> 2); + let g8 = ((g6 as u32) << 2) | ((g6 as u32) >> 4); + let b8 = ((b5 as u32) << 3) | ((b5 as u32) >> 2); + let hex = r8 << 16 | g8 << 8 | b8; + hex as i32 + } + +} diff --git a/crates/prometeu-abi/src/model/mod.rs b/crates/prometeu-abi/src/model/mod.rs new file mode 100644 index 00000000..ded41a56 --- /dev/null +++ b/crates/prometeu-abi/src/model/mod.rs @@ -0,0 +1,25 @@ +mod asset; +mod color; +mod button; +mod tile; +mod tile_layer; +mod tile_bank; +mod sound_bank; +mod sprite; +mod sample; +mod cartridge; +mod cartridge_loader; +mod window; + +pub use asset::{AssetEntry, BankStats, BankType, HandleId, LoadStatus, PreloadEntry, SlotRef, SlotStats}; +pub use button::{Button, ButtonId}; +pub use cartridge::{AppMode, Cartridge, CartridgeDTO, CartridgeError}; +pub use cartridge_loader::{CartridgeLoader, DirectoryCartridgeLoader, PackedCartridgeLoader}; +pub use color::Color; +pub use sample::Sample; +pub use sound_bank::SoundBank; +pub use sprite::Sprite; +pub use tile::Tile; +pub use tile_bank::{TileBank, TileSize}; +pub use tile_layer::{HudTileLayer, ScrollableTileLayer, TileMap}; +pub use window::{Rect, Window, WindowId}; diff --git a/crates/prometeu-abi/src/model/sample.rs b/crates/prometeu-abi/src/model/sample.rs new file mode 100644 index 00000000..5ced72bf --- /dev/null +++ b/crates/prometeu-abi/src/model/sample.rs @@ -0,0 +1,27 @@ +pub struct Sample { + pub sample_rate: u32, + pub data: Vec, + pub loop_start: Option, + pub loop_end: Option, +} + +impl Sample { + pub fn new(sample_rate: u32, data: Vec) -> Self { + Self { + sample_rate, + data, + loop_start: None, + loop_end: None, + } + } + + pub fn with_loop(mut self, start: u32, end: u32) -> Self { + self.loop_start = Some(start); + self.loop_end = Some(end); + self + } + + pub fn frames_len(&self) -> usize { + self.data.len() + } +} diff --git a/crates/prometeu-abi/src/model/sound_bank.rs b/crates/prometeu-abi/src/model/sound_bank.rs new file mode 100644 index 00000000..fbf70218 --- /dev/null +++ b/crates/prometeu-abi/src/model/sound_bank.rs @@ -0,0 +1,16 @@ +use crate::model::Sample; +use std::sync::Arc; + +/// A container for audio assets. +/// +/// A SoundBank stores multiple audio samples that can be played by the +/// audio subsystem. +pub struct SoundBank { + pub samples: Vec>, +} + +impl SoundBank { + pub fn new(samples: Vec>) -> Self { + Self { samples } + } +} diff --git a/crates/prometeu-abi/src/model/sprite.rs b/crates/prometeu-abi/src/model/sprite.rs new file mode 100644 index 00000000..39331ab6 --- /dev/null +++ b/crates/prometeu-abi/src/model/sprite.rs @@ -0,0 +1,13 @@ +use crate::model::Tile; + +#[derive(Clone, Copy, Debug, Default)] +pub struct Sprite { + pub tile: Tile, + pub x: i32, + pub y: i32, + pub bank_id: u8, + pub active: bool, + pub flip_x: bool, + pub flip_y: bool, + pub priority: u8, +} diff --git a/crates/prometeu-abi/src/model/tile.rs b/crates/prometeu-abi/src/model/tile.rs new file mode 100644 index 00000000..07216fc2 --- /dev/null +++ b/crates/prometeu-abi/src/model/tile.rs @@ -0,0 +1,7 @@ +#[derive(Clone, Copy, Debug, Default)] +pub struct Tile { + pub id: u16, + pub flip_x: bool, + pub flip_y: bool, + pub palette_id: u8, +} diff --git a/crates/prometeu-abi/src/model/tile_bank.rs b/crates/prometeu-abi/src/model/tile_bank.rs new file mode 100644 index 00000000..c7c8f380 --- /dev/null +++ b/crates/prometeu-abi/src/model/tile_bank.rs @@ -0,0 +1,75 @@ +use crate::model::Color; + +/// Standard sizes for square tiles. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TileSize { + /// 8x8 pixels. + Size8 = 8, + /// 16x16 pixels. + Size16 = 16, + /// 32x32 pixels. + Size32 = 32, +} + +/// A container for graphical assets. +/// +/// A TileBank stores both the raw pixel data (as palette indices) and the +/// color palettes themselves. This encapsulates all the information needed +/// to render a set of tiles. +pub struct TileBank { + /// Dimension of each individual tile in the bank. + pub tile_size: TileSize, + /// Width of the full bank sheet in pixels. + pub width: usize, + /// Height of the full bank sheet in pixels. + pub height: usize, + + /// Pixel data stored as 4-bit indices (packed into 8-bit values). + /// Index 0 is always reserved for transparency. + pub pixel_indices: Vec, + /// Table of 64 palettes, each containing 16 RGB565 colors, total of 1024 colors for a bank. + pub palettes: [[Color; 16]; 64], +} + +impl TileBank { + /// Creates an empty tile bank with the specified dimensions. + pub fn new(tile_size: TileSize, width: usize, height: usize) -> Self { + Self { + tile_size, + width, + height, + pixel_indices: vec![0; width * height], // Index 0 = Transparent + palettes: [[Color::BLACK; 16]; 64], + } + } + + /// Resolves a global tile ID and local pixel coordinates to a palette index. + /// tile_id: the tile index in the bank + /// local_x, local_y: the pixel position inside the tile (0 to tile_size-1) + pub fn get_pixel_index(&self, tile_id: u16, local_x: usize, local_y: usize) -> u8 { + let size = self.tile_size as usize; + let tiles_per_row = self.width / size; + let tile_x = (tile_id as usize % tiles_per_row) * size; + let tile_y = (tile_id as usize / tiles_per_row) * size; + + let pixel_x = tile_x + local_x; + let pixel_y = tile_y + local_y; + + if pixel_x < self.width && pixel_y < self.height { + self.pixel_indices[pixel_y * self.width + pixel_x] + } else { + 0 // Default to transparent if out of bounds + } + } + + /// Maps a 4-bit index to a real RGB565 Color using the specified palette. + pub fn resolve_color(&self, palette_id: u8, pixel_index: u8) -> Color { + // Hardware Rule: Index 0 is always transparent. + // We use Magenta as the 'transparent' signal color during composition. + if pixel_index == 0 { + return Color::COLOR_KEY; + } + + self.palettes[palette_id as usize][pixel_index as usize] + } +} diff --git a/crates/prometeu-abi/src/model/tile_layer.rs b/crates/prometeu-abi/src/model/tile_layer.rs new file mode 100644 index 00000000..cbf975f5 --- /dev/null +++ b/crates/prometeu-abi/src/model/tile_layer.rs @@ -0,0 +1,109 @@ +use crate::model::tile_bank::TileSize; +use crate::model::Tile; +use crate::model::TileSize::Size8; + +pub struct TileMap { + pub width: usize, + pub height: usize, + pub tiles: Vec, +} + +impl TileMap { + fn create(width: usize, height: usize) -> Self { + Self { + width, + height, + tiles: vec![Tile::default(); width * height], + } + } + + pub fn set_tile(&mut self, x: usize, y: usize, tile: Tile) { + if x < self.width && y < self.height { + self.tiles[y * self.width + x] = tile; + } + } +} + + +pub struct TileLayer { + pub bank_id: u8, + pub tile_size: TileSize, + pub map: TileMap, +} + +impl TileLayer { + fn create(width: usize, height: usize, tile_size: TileSize) -> Self { + Self { + bank_id: 0, + tile_size, + map: TileMap::create(width, height), + } + } +} + +impl std::ops::Deref for TileLayer { + type Target = TileMap; + fn deref(&self) -> &Self::Target { + &self.map + } +} + +impl std::ops::DerefMut for TileLayer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.map + } +} + +pub struct ScrollableTileLayer { + pub layer: TileLayer, + pub scroll_x: i32, + pub scroll_y: i32, +} + +impl ScrollableTileLayer { + pub fn new(width: usize, height: usize, tile_size: TileSize) -> Self { + Self { + layer: TileLayer::create(width, height, tile_size), + scroll_x: 0, + scroll_y: 0, + } + } +} + +impl std::ops::Deref for ScrollableTileLayer { + type Target = TileLayer; + fn deref(&self) -> &Self::Target { + &self.layer + } +} + +impl std::ops::DerefMut for ScrollableTileLayer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.layer + } +} + +pub struct HudTileLayer { + pub layer: TileLayer, +} + +impl HudTileLayer { + pub fn new(width: usize, height: usize) -> Self { + Self { + layer: TileLayer::create(width, height, Size8), + } + } +} + +impl std::ops::Deref for HudTileLayer { + type Target = TileLayer; + fn deref(&self) -> &Self::Target { + &self.layer + } +} + +impl std::ops::DerefMut for HudTileLayer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.layer + } +} diff --git a/crates/prometeu-abi/src/model/window.rs b/crates/prometeu-abi/src/model/window.rs new file mode 100644 index 00000000..8b4123c2 --- /dev/null +++ b/crates/prometeu-abi/src/model/window.rs @@ -0,0 +1,21 @@ +use crate::model::Color; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Rect { + pub x: i32, + pub y: i32, + pub w: i32, + pub h: i32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WindowId(pub u32); + +#[derive(Debug, Clone)] +pub struct Window { + pub id: WindowId, + pub viewport: Rect, + pub has_focus: bool, + pub title: String, + pub color: Color, +} diff --git a/crates/prometeu-abi/src/telemetry.rs b/crates/prometeu-abi/src/telemetry.rs new file mode 100644 index 00000000..2dbe4f31 --- /dev/null +++ b/crates/prometeu-abi/src/telemetry.rs @@ -0,0 +1,123 @@ +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-abi/src/virtual_machine/value.rs b/crates/prometeu-abi/src/virtual_machine/value.rs new file mode 100644 index 00000000..4f4f6e5d --- /dev/null +++ b/crates/prometeu-abi/src/virtual_machine/value.rs @@ -0,0 +1,151 @@ +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 { + 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 { + 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 { + 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 { + use super::*; + + #[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); + } +} diff --git a/crates/prometeu-core/Cargo.toml b/crates/prometeu-core/Cargo.toml index 7e4d77a5..47fc58dc 100644 --- a/crates/prometeu-core/Cargo.toml +++ b/crates/prometeu-core/Cargo.toml @@ -7,4 +7,5 @@ license.workspace = true [dependencies] serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" -prometeu-bytecode = { path = "../prometeu-bytecode" } \ No newline at end of file +prometeu-bytecode = { path = "../prometeu-bytecode" } +prometeu-abi = { path = "../prometeu-abi" } \ No newline at end of file diff --git a/crates/prometeu-core/src/lib.rs b/crates/prometeu-core/src/lib.rs index 2ffc9607..f428f7fe 100644 --- a/crates/prometeu-core/src/lib.rs +++ b/crates/prometeu-core/src/lib.rs @@ -16,14 +16,17 @@ //! The "Source of Truth" for the console's behavior lives here. pub mod hardware; -pub mod log; pub mod virtual_machine; -pub mod model; pub mod firmware; pub mod fs; -pub mod telemetry; -pub mod debugger_protocol; pub mod prometeu_os; mod prometeu_hub; +// Facade/reexports for ABI modules (temporary during PR-00.x) +pub use prometeu_abi as abi; +pub use prometeu_abi::model; +pub use prometeu_abi::log; +pub use prometeu_abi::telemetry; +pub use prometeu_abi::debugger_protocol; + pub use hardware::hardware::Hardware; diff --git a/crates/prometeu-core/src/virtual_machine/mod.rs b/crates/prometeu-core/src/virtual_machine/mod.rs index 10f53d88..593def8b 100644 --- a/crates/prometeu-core/src/virtual_machine/mod.rs +++ b/crates/prometeu-core/src/virtual_machine/mod.rs @@ -1,5 +1,4 @@ mod virtual_machine; -mod value; mod call_frame; mod scope_frame; mod program; @@ -12,7 +11,7 @@ use crate::hardware::HardwareBridge; pub use program::ProgramImage; pub use prometeu_bytecode::abi::TrapInfo; pub use prometeu_bytecode::opcode::OpCode; -pub use value::Value; +pub use prometeu_abi::virtual_machine::Value; pub use verifier::VerifierError; pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine}; diff --git a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs index 5cad31ac..8ac5a763 100644 --- a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs +++ b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs @@ -1,7 +1,7 @@ use crate::hardware::HardwareBridge; use crate::virtual_machine::call_frame::CallFrame; use crate::virtual_machine::scope_frame::ScopeFrame; -use crate::virtual_machine::value::Value; +use crate::virtual_machine::Value; use crate::virtual_machine::{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; diff --git a/docs/specs/pbs/files/PRs para Junie.md b/docs/specs/pbs/files/PRs para Junie.md index 03d71545..5e258e45 100644 --- a/docs/specs/pbs/files/PRs para Junie.md +++ b/docs/specs/pbs/files/PRs para Junie.md @@ -405,38 +405,6 @@ pub struct AnalysisDb { --- -## PR-00.1 — Introduzir `prometeu-abi` (renomear/diluir `prometeu-core`) - -**Branch:** `pr-00-1-prometeu-abi` - -### Objetivo - -Criar crate `prometeu-abi` contendo **somente tipos e contratos** (types+model+protocols), e manter `prometeu-core` temporariamente como facade/reexport para não quebrar consumidores. - -### Passos prescritivos - -1. Criar novo crate `crates/prometeu-abi/` com `src/lib.rs`. -2. Copiar para `prometeu-abi` (sem execução): - - * `model/*` - * `debugger_protocol.rs` - * `telemetry.rs` - * `log.rs` (somente tipos/config; se tiver runtime logger, deixar no core por enquanto) - * **traits/contratos** usados por outros crates (ex.: IDs, enums de eventos) -3. Atualizar dependências dos crates consumidores para apontar para `prometeu-abi` onde aplicável. -4. Manter `prometeu-core` compilando com: - - * `pub use prometeu_abi as abi;` - * reexports temporários de tipos que mudaram de path. - -### Critérios de aceite - -* Workspace compila. -* Nenhum comportamento muda. -* `prometeu-core` ainda existe (temporário). - ---- - ## PR-00.2 — Extrair `prometeu-vm` do `prometeu-core` **Branch:** `pr-00-2-prometeu-vm` diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index b06b91caaacaf4416129e782584fa51dc847ec21..666448e9c82fd9759bc1514ce6c916eaa9193fac 100644 GIT binary patch delta 25 ecmeB|?U&tadA