diff --git a/Cargo.lock b/Cargo.lock index 5876ca92..e61a0629 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1919,6 +1919,7 @@ dependencies = [ "oxc_parser", "oxc_span", "prometeu-bytecode", + "prometeu-core", "serde", "serde_json", ] diff --git a/crates/prometeu-core/src/lib.rs b/crates/prometeu-core/src/lib.rs index fe373146..87c706c6 100644 --- a/crates/prometeu-core/src/lib.rs +++ b/crates/prometeu-core/src/lib.rs @@ -6,7 +6,7 @@ pub mod firmware; pub mod fs; pub mod telemetry; pub mod debugger_protocol; -mod prometeu_os; +pub mod prometeu_os; mod prometeu_hub; pub use hardware::hardware::Hardware; diff --git a/crates/prometeu-core/src/model/button.rs b/crates/prometeu-core/src/model/button.rs index 72ab2bdb..75812ff0 100644 --- a/crates/prometeu-core/src/model/button.rs +++ b/crates/prometeu-core/src/model/button.rs @@ -1,3 +1,20 @@ +#[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, diff --git a/crates/prometeu-core/src/model/mod.rs b/crates/prometeu-core/src/model/mod.rs index fc42885a..8eb4733b 100644 --- a/crates/prometeu-core/src/model/mod.rs +++ b/crates/prometeu-core/src/model/mod.rs @@ -9,7 +9,7 @@ mod cartridge; mod cartridge_loader; mod window; -pub use button::Button; +pub use button::{Button, ButtonId}; pub use cartridge::{AppMode, Cartridge, CartridgeDTO, CartridgeError}; pub use cartridge_loader::{CartridgeLoader, DirectoryCartridgeLoader, PackedCartridgeLoader}; pub use color::Color; diff --git a/crates/prometeu-core/src/prometeu_os/mod.rs b/crates/prometeu-core/src/prometeu_os/mod.rs index 64c645ec..87fcf170 100644 --- a/crates/prometeu-core/src/prometeu_os/mod.rs +++ b/crates/prometeu-core/src/prometeu_os/mod.rs @@ -1,4 +1,6 @@ mod prometeu_os; +pub mod syscalls; pub use prometeu_os::PrometeuOS; +pub use syscalls::Syscall; pub use crate::virtual_machine::native_interface::NativeInterface; \ No newline at end of file diff --git a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs index 04748f08..831b7342 100644 --- a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs +++ b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs @@ -2,7 +2,7 @@ use crate::fs::{FsBackend, FsState, VirtualFS}; use crate::hardware::{HardwareBridge, InputSignals}; use crate::log::{LogLevel, LogService, LogSource}; use crate::model::{Cartridge, Color, Sample}; -use crate::prometeu_os::NativeInterface; +use crate::prometeu_os::{NativeInterface, Syscall}; use crate::telemetry::{CertificationConfig, Certifier, TelemetryFrame}; use crate::virtual_machine::{Value, VirtualMachine}; use std::collections::HashMap; @@ -554,17 +554,18 @@ impl NativeInterface for PrometeuOS { /// Each syscall returns the number of virtual cycles it consumed. fn syscall(&mut self, id: u32, vm: &mut VirtualMachine, hw: &mut dyn HardwareBridge) -> Result { self.telemetry_current.syscalls += 1; - match id { + let syscall = Syscall::from_u32(id).ok_or_else(|| format!("Unknown syscall: 0x{:08X}", id))?; + match syscall { // --- System Syscalls --- // system.has_cart() -> bool - 0x0001 => { + Syscall::SystemHasCart => { // Returns true if a cartridge is available. vm.push(Value::Boolean(true)); // For now, assume true or check state Ok(10) } // system.run_cart() -> null - 0x0002 => { + Syscall::SystemRunCart => { // Triggers loading and execution of the current cartridge. vm.push(Value::Null); Ok(100) @@ -573,7 +574,7 @@ impl NativeInterface for PrometeuOS { // --- GFX Syscalls --- // gfx.clear(color_index) -> null - 0x1001 => { + Syscall::GfxClear => { let color_idx = vm.pop_integer()? as usize; let color = self.get_color(color_idx, hw); hw.gfx_mut().clear(color); @@ -581,7 +582,7 @@ impl NativeInterface for PrometeuOS { Ok(100) } // gfx.draw_rect(x, y, w, h, color_index) -> null - 0x1002 => { + Syscall::GfxFillRect => { let color_idx = vm.pop_integer()? as usize; let h = vm.pop_integer()? as i32; let w = vm.pop_integer()? as i32; @@ -593,7 +594,7 @@ impl NativeInterface for PrometeuOS { Ok(200) } // gfx.draw_line(x1, y1, x2, y2, color_index) -> null - 0x1003 => { + Syscall::GfxDrawLine => { let color_idx = vm.pop_integer()? as usize; let y2 = vm.pop_integer()? as i32; let x2 = vm.pop_integer()? as i32; @@ -605,7 +606,7 @@ impl NativeInterface for PrometeuOS { Ok(200) } // gfx.draw_circle(x, y, r, color_index) -> null - 0x1004 => { + Syscall::GfxDrawCircle => { let color_idx = vm.pop_integer()? as usize; let r = vm.pop_integer()? as i32; let y = vm.pop_integer()? as i32; @@ -616,7 +617,7 @@ impl NativeInterface for PrometeuOS { Ok(200) } // gfx.draw_disc(x, y, r, border_color_idx, fill_color_idx) -> null - 0x1005 => { + Syscall::GfxDrawDisc => { let fill_color_idx = vm.pop_integer()? as usize; let border_color_idx = vm.pop_integer()? as usize; let r = vm.pop_integer()? as i32; @@ -629,7 +630,7 @@ impl NativeInterface for PrometeuOS { Ok(300) } // gfx.draw_square(x, y, w, h, border_color_idx, fill_color_idx) -> null - 0x1006 => { + Syscall::GfxDrawSquare => { let fill_color_idx = vm.pop_integer()? as usize; let border_color_idx = vm.pop_integer()? as usize; let h = vm.pop_integer()? as i32; @@ -646,7 +647,7 @@ impl NativeInterface for PrometeuOS { // --- Input Syscalls --- // input.get_pad(button_id) -> bool - 0x2001 => { + Syscall::InputGetPad => { let button_id = vm.pop_integer()? as u32; let is_down = self.is_button_down(button_id, hw); vm.push(Value::Boolean(is_down)); @@ -656,7 +657,7 @@ impl NativeInterface for PrometeuOS { // --- Audio Syscalls --- // audio.play_sample(sample_id, voice_id, volume, pan, pitch) - 0x3001 => { + Syscall::AudioPlaySample => { let pitch = vm.pop_number()?; let pan = vm.pop_integer()? as u8; let volume = vm.pop_integer()? as u8; @@ -681,7 +682,7 @@ impl NativeInterface for PrometeuOS { // FS_OPEN(path) -> handle // Opens a file in the virtual sandbox and returns a numeric handle. - 0x4001 => { + Syscall::FsOpen => { let path = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string path".into()), @@ -697,7 +698,7 @@ impl NativeInterface for PrometeuOS { Ok(200) } // FS_READ(handle) -> content - 0x4002 => { + Syscall::FsRead => { let handle = vm.pop_integer()? as u32; let path = self.open_files.get(&handle).ok_or("Invalid handle")?; match self.fs.read_file(path) { @@ -713,7 +714,7 @@ impl NativeInterface for PrometeuOS { } } // FS_WRITE(handle, content) - 0x4003 => { + Syscall::FsWrite => { let content = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string content".into()), @@ -732,14 +733,14 @@ impl NativeInterface for PrometeuOS { } } // FS_CLOSE(handle) - 0x4004 => { + Syscall::FsClose => { let handle = vm.pop_integer()? as u32; self.open_files.remove(&handle); vm.push(Value::Null); Ok(100) } // FS_LISTDIR(path) - 0x4005 => { + Syscall::FsListDir => { let path = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string path".into()), @@ -758,7 +759,7 @@ impl NativeInterface for PrometeuOS { } } // FS_EXISTS(path) -> bool - 0x4006 => { + Syscall::FsExists => { let path = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string path".into()), @@ -767,7 +768,7 @@ impl NativeInterface for PrometeuOS { Ok(100) } // FS_DELETE(path) - 0x4007 => { + Syscall::FsDelete => { let path = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string path".into()), @@ -782,7 +783,7 @@ impl NativeInterface for PrometeuOS { // --- Log Syscalls (0x5000) --- // LOG_WRITE(level, msg) - 0x5001 => { + Syscall::LogWrite => { let msg = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string message".into()), @@ -791,7 +792,7 @@ impl NativeInterface for PrometeuOS { self.syscall_log_write(vm, level, 0, msg) } // LOG_WRITE_TAG(level, tag, msg) - 0x5002 => { + Syscall::LogWriteTag => { let msg = match vm.pop()? { Value::String(s) => s, _ => return Err("Expected string message".into()), @@ -800,8 +801,6 @@ impl NativeInterface for PrometeuOS { let level = vm.pop_integer()?; self.syscall_log_write(vm, level, tag, msg) } - - _ => Err(format!("Unknown syscall: 0x{:08X}", id)), } } } \ No newline at end of file diff --git a/crates/prometeu-core/src/prometeu_os/syscalls.rs b/crates/prometeu-core/src/prometeu_os/syscalls.rs new file mode 100644 index 00000000..f2aef4be --- /dev/null +++ b/crates/prometeu-core/src/prometeu_os/syscalls.rs @@ -0,0 +1,110 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum Syscall { + // System + SystemHasCart = 0x0001, + SystemRunCart = 0x0002, + + // GFX + GfxClear = 0x1001, + GfxFillRect = 0x1002, + GfxDrawLine = 0x1003, + GfxDrawCircle = 0x1004, + GfxDrawDisc = 0x1005, + GfxDrawSquare = 0x1006, + + // Input + InputGetPad = 0x2001, + + // Audio + AudioPlaySample = 0x3001, + + // FS + FsOpen = 0x4001, + FsRead = 0x4002, + FsWrite = 0x4003, + FsClose = 0x4004, + FsListDir = 0x4005, + FsExists = 0x4006, + FsDelete = 0x4007, + + // Log + LogWrite = 0x5001, + LogWriteTag = 0x5002, +} + +impl Syscall { + pub fn from_u32(id: u32) -> Option { + match id { + 0x0001 => Some(Self::SystemHasCart), + 0x0002 => Some(Self::SystemRunCart), + 0x1001 => Some(Self::GfxClear), + 0x1002 => Some(Self::GfxFillRect), + 0x1003 => Some(Self::GfxDrawLine), + 0x1004 => Some(Self::GfxDrawCircle), + 0x1005 => Some(Self::GfxDrawDisc), + 0x1006 => Some(Self::GfxDrawSquare), + 0x2001 => Some(Self::InputGetPad), + 0x3001 => Some(Self::AudioPlaySample), + 0x4001 => Some(Self::FsOpen), + 0x4002 => Some(Self::FsRead), + 0x4003 => Some(Self::FsWrite), + 0x4004 => Some(Self::FsClose), + 0x4005 => Some(Self::FsListDir), + 0x4006 => Some(Self::FsExists), + 0x4007 => Some(Self::FsDelete), + 0x5001 => Some(Self::LogWrite), + 0x5002 => Some(Self::LogWriteTag), + _ => None, + } + } + + pub fn as_str(&self) -> &'static str { + match self { + Self::SystemHasCart => "system.has_cart", + Self::SystemRunCart => "system.run_cart", + Self::GfxClear => "gfx.clear", + Self::GfxFillRect => "gfx.fillRect", + Self::GfxDrawLine => "gfx.drawLine", + Self::GfxDrawCircle => "gfx.drawCircle", + Self::GfxDrawDisc => "gfx.drawDisc", + Self::GfxDrawSquare => "gfx.drawSquare", + Self::InputGetPad => "input.get_pad", + Self::AudioPlaySample => "audio.playSample", + Self::FsOpen => "fs.open", + Self::FsRead => "fs.read", + Self::FsWrite => "fs.write", + Self::FsClose => "fs.close", + Self::FsListDir => "fs.listDir", + Self::FsExists => "fs.exists", + Self::FsDelete => "fs.delete", + Self::LogWrite => "log.write", + Self::LogWriteTag => "log.writeTag", + } + } + + pub fn from_name(name: &str) -> Option { + match name { + "system.has_cart" => Some(Self::SystemHasCart), + "system.run_cart" => Some(Self::SystemRunCart), + "gfx.clear" => Some(Self::GfxClear), + "gfx.fillRect" | "gfx.draw_rect" => Some(Self::GfxFillRect), + "gfx.drawLine" | "gfx.draw_line" => Some(Self::GfxDrawLine), + "gfx.drawCircle" | "gfx.draw_circle" => Some(Self::GfxDrawCircle), + "gfx.drawDisc" | "gfx.draw_disc" => Some(Self::GfxDrawDisc), + "gfx.drawSquare" | "gfx.draw_square" => Some(Self::GfxDrawSquare), + "input.get_pad" => Some(Self::InputGetPad), + "audio.playSample" | "audio.play_sample" => Some(Self::AudioPlaySample), + "fs.open" => Some(Self::FsOpen), + "fs.read" => Some(Self::FsRead), + "fs.write" => Some(Self::FsWrite), + "fs.close" => Some(Self::FsClose), + "fs.listDir" => Some(Self::FsListDir), + "fs.exists" => Some(Self::FsExists), + "fs.delete" => Some(Self::FsDelete), + "log.write" => Some(Self::LogWrite), + "log.writeTag" => Some(Self::LogWriteTag), + _ => None, + } + } +} diff --git a/crates/prometeuc/Cargo.toml b/crates/prometeuc/Cargo.toml index 50109ad2..539e6e3f 100644 --- a/crates/prometeuc/Cargo.toml +++ b/crates/prometeuc/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] prometeu-bytecode = { path = "../prometeu-bytecode" } +prometeu-core = { path = "../prometeu-core" } oxc_parser = "0.48.0" oxc_allocator = "0.48.0" oxc_ast = "0.48.0" diff --git a/crates/prometeuc/src/syscall_map.rs b/crates/prometeuc/src/syscall_map.rs index 768164a8..50ffae92 100644 --- a/crates/prometeuc/src/syscall_map.rs +++ b/crates/prometeuc/src/syscall_map.rs @@ -1,23 +1,27 @@ -pub const SYS_GFX_FILL_RECT: u32 = 0x1002; -pub const SYS_INPUT_GET_PAD: u32 = 0x2001; +use prometeu_core::prometeu_os::Syscall; +use prometeu_core::model::ButtonId; -pub const BTN_UP: u32 = 0; -pub const BTN_DOWN: u32 = 1; -pub const BTN_LEFT: u32 = 2; -pub const BTN_RIGHT: u32 = 3; -pub const BTN_A: u32 = 4; -pub const BTN_B: u32 = 5; -pub const BTN_X: u32 = 6; -pub const BTN_Y: u32 = 7; -pub const BTN_L: u32 = 8; -pub const BTN_R: u32 = 9; -pub const BTN_START: u32 = 10; -pub const BTN_SELECT: u32 = 11; +pub const BTN_UP: u32 = ButtonId::Up as u32; +pub const BTN_DOWN: u32 = ButtonId::Down as u32; +pub const BTN_LEFT: u32 = ButtonId::Left as u32; +pub const BTN_RIGHT: u32 = ButtonId::Right as u32; +pub const BTN_A: u32 = ButtonId::A as u32; +pub const BTN_B: u32 = ButtonId::B as u32; +pub const BTN_X: u32 = ButtonId::X as u32; +pub const BTN_Y: u32 = ButtonId::Y as u32; +pub const BTN_L: u32 = ButtonId::L as u32; +pub const BTN_R: u32 = ButtonId::R as u32; +pub const BTN_START: u32 = ButtonId::Start as u32; +pub const BTN_SELECT: u32 = ButtonId::Select as u32; pub fn map_syscall(name: &str) -> Option { + if let Some(syscall) = Syscall::from_name(name) { + return Some(syscall as u32); + } + + // Fallback para nomes especiais do compilador match name { - "gfx.fillRect" => Some(SYS_GFX_FILL_RECT), - "input.btnA" | "input.btnB" | "input.get_pad" => Some(SYS_INPUT_GET_PAD), + "input.btnA" | "input.btnB" => Some(Syscall::InputGetPad as u32), _ => None, } }