diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index e74cb6f2..c1c93e4f 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -2,5 +2,6 @@ pub mod machine; pub mod peripherals; pub mod vm; mod model; +mod native_interface; pub use machine::Machine; diff --git a/crates/core/src/machine.rs b/crates/core/src/machine.rs index 0ee3743e..9bf6ca6e 100644 --- a/crates/core/src/machine.rs +++ b/crates/core/src/machine.rs @@ -1,6 +1,6 @@ -use crate::model::{Color, Sample, Cartridge}; -use crate::peripherals::{Gfx, InputSignals, Pad, Touch, Audio}; -use crate::vm::{VirtualMachine, NativeInterface, Value}; +use crate::model::{Cartridge, Color, Sample}; +use crate::peripherals::{Audio, Gfx, InputSignals, Pad, Touch}; +use crate::vm::VirtualMachine; use std::sync::Arc; /// PROMETEU "hardware lógico" (v0). @@ -21,123 +21,13 @@ pub struct Machine { pub sample_snare: Option>, } -impl NativeInterface for Machine { - fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result { - match id { - // system.has_cart() -> bool - 0x0001 => { - vm.push(Value::Boolean(self.cartridge.is_some())); - Ok(10) - } - // system.run_cart() - 0x0002 => { - if let Some(cart) = self.cartridge.as_ref() { - vm.rom = cart.rom.clone(); - vm.constant_pool = cart.constant_pool.clone(); - vm.pc = 0; - vm.operand_stack.clear(); - vm.call_stack.clear(); - vm.halted = false; - } else { - return Err("No cartridge inserted".into()); - } - Ok(100) - } - // gfx.clear(color_index) - 0x1001 => { - let color_idx = vm.pop_integer()? as usize; - let color = self.get_color(color_idx); - self.gfx.clear(color); - Ok(100) - } - // gfx.draw_rect(x, y, w, h, color_index) - 0x1002 => { - let color_idx = vm.pop_integer()? as usize; - let h = vm.pop_integer()? as i32; - let w = vm.pop_integer()? as i32; - let y = vm.pop_integer()? as i32; - let x = vm.pop_integer()? as i32; - let color = self.get_color(color_idx); - self.gfx.fill_rect(x, y, w, h, color); - Ok(200) - } - // input.get_pad(button_id) -> bool - 0x2001 => { - let button_id = vm.pop_integer()? as u32; - let is_down = self.is_button_down(button_id); - vm.push(Value::Boolean(is_down)); - Ok(50) - } - // audio.play_sample(sample_id, voice_id, volume, pan, pitch) - // sample_id: 0=square, 1=kick, 2=snare - 0x3001 => { - let pitch = vm.pop_number()?; - let pan = vm.pop_integer()? as u8; - let volume = vm.pop_integer()? as u8; - let voice_id = vm.pop_integer()? as usize; - let sample_id = vm.pop_integer()? as u32; - let sample = match sample_id { - 0 => self.sample_square.clone(), - 1 => self.sample_kick.clone(), - 2 => self.sample_snare.clone(), - _ => None, - }; - - if let Some(s) = sample { - self.audio.play(s, voice_id, volume, pan, pitch, 0, crate::peripherals::LoopMode::Off); - } - Ok(300) - } - _ => Err(format!("Unknown native call: 0x{:08X}", id)), - } - } -} impl Machine { pub const W: usize = 320; pub const H: usize = 180; pub const CYCLES_PER_FRAME: u64 = 100_000; // Exemplo de budget - fn get_color(&self, index: usize) -> Color { - // Implementação simplificada: se houver bancos, usa a paleta do banco 0 - // Caso contrário, usa cores básicas fixas - if let Some(bank) = self.gfx.banks[0].as_ref() { - bank.palettes[0][index % 16] - } else { - match index % 16 { - 0 => Color::BLACK, - 1 => Color::WHITE, - 2 => Color::RED, - 3 => Color::GREEN, - 4 => Color::BLUE, - 5 => Color::YELLOW, - 6 => Color::CYAN, - 7 => Color::INDIGO, - 8 => Color::GRAY, - _ => Color::BLACK, - } - } - } - - fn is_button_down(&self, id: u32) -> bool { - match id { - 0 => self.pad.up.down, - 1 => self.pad.down.down, - 2 => self.pad.left.down, - 3 => self.pad.right.down, - 4 => self.pad.a.down, - 5 => self.pad.b.down, - 6 => self.pad.x.down, - 7 => self.pad.y.down, - 8 => self.pad.l.down, - 9 => self.pad.r.down, - 10 => self.pad.start.down, - 11 => self.pad.select.down, - _ => false, - } - } - pub fn new() -> Self { let mut machine = Self { gfx: Gfx::new(Self::W, Self::H), @@ -159,6 +49,45 @@ impl Machine { machine } + pub fn get_color(&self, index: usize) -> Color { + // Implementação simplificada: se houver bancos, usa a paleta do banco 0 + // Caso contrário, usa cores básicas fixas + if let Some(bank) = self.gfx.banks[0].as_ref() { + bank.palettes[0][index % 16] + } else { + match index % 16 { + 0 => Color::BLACK, + 1 => Color::WHITE, + 2 => Color::RED, + 3 => Color::GREEN, + 4 => Color::BLUE, + 5 => Color::YELLOW, + 6 => Color::CYAN, + 7 => Color::INDIGO, + 8 => Color::GRAY, + _ => Color::BLACK, + } + } + } + + pub fn is_button_down(&self, id: u32) -> bool { + match id { + 0 => self.pad.up.down, + 1 => self.pad.down.down, + 2 => self.pad.left.down, + 3 => self.pad.right.down, + 4 => self.pad.a.down, + 5 => self.pad.b.down, + 6 => self.pad.x.down, + 7 => self.pad.y.down, + 8 => self.pad.l.down, + 9 => self.pad.r.down, + 10 => self.pad.start.down, + 11 => self.pad.select.down, + _ => false, + } + } + pub fn load_cartridge(&mut self, cart: Cartridge) { self.cartridge = Some(cart); } diff --git a/crates/core/src/native_interface.rs b/crates/core/src/native_interface.rs new file mode 100644 index 00000000..dfdd565b --- /dev/null +++ b/crates/core/src/native_interface.rs @@ -0,0 +1,75 @@ +use crate::Machine; +use crate::vm::{NativeInterface, Value, VirtualMachine}; + +impl NativeInterface for Machine { + fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result { + match id { + // system.has_cart() -> bool + 0x0001 => { + vm.push(Value::Boolean(self.cartridge.is_some())); + Ok(10) + } + // system.run_cart() + 0x0002 => { + if let Some(cart) = self.cartridge.as_ref() { + vm.rom = cart.rom.clone(); + vm.constant_pool = cart.constant_pool.clone(); + vm.pc = 0; + vm.operand_stack.clear(); + vm.call_stack.clear(); + vm.halted = false; + } else { + return Err("No cartridge inserted".into()); + } + Ok(100) + } + // gfx.clear(color_index) + 0x1001 => { + let color_idx = vm.pop_integer()? as usize; + let color = self.get_color(color_idx); + self.gfx.clear(color); + Ok(100) + } + // gfx.draw_rect(x, y, w, h, color_index) + 0x1002 => { + let color_idx = vm.pop_integer()? as usize; + let h = vm.pop_integer()? as i32; + let w = vm.pop_integer()? as i32; + let y = vm.pop_integer()? as i32; + let x = vm.pop_integer()? as i32; + let color = self.get_color(color_idx); + self.gfx.fill_rect(x, y, w, h, color); + Ok(200) + } + // input.get_pad(button_id) -> bool + 0x2001 => { + let button_id = vm.pop_integer()? as u32; + let is_down = self.is_button_down(button_id); + vm.push(Value::Boolean(is_down)); + Ok(50) + } + // audio.play_sample(sample_id, voice_id, volume, pan, pitch) + // sample_id: 0=square, 1=kick, 2=snare + 0x3001 => { + let pitch = vm.pop_number()?; + let pan = vm.pop_integer()? as u8; + let volume = vm.pop_integer()? as u8; + let voice_id = vm.pop_integer()? as usize; + let sample_id = vm.pop_integer()? as u32; + + let sample = match sample_id { + 0 => self.sample_square.clone(), + 1 => self.sample_kick.clone(), + 2 => self.sample_snare.clone(), + _ => None, + }; + + if let Some(s) = sample { + self.audio.play(s, voice_id, volume, pan, pitch, 0, crate::peripherals::LoopMode::Off); + } + Ok(300) + } + _ => Err(format!("Unknown native call: 0x{:08X}", id)), + } + } +} \ No newline at end of file