add native_interface
This commit is contained in:
parent
a9d06aaf86
commit
f319d0dbaf
@ -2,5 +2,6 @@ pub mod machine;
|
|||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
mod model;
|
mod model;
|
||||||
|
mod native_interface;
|
||||||
|
|
||||||
pub use machine::Machine;
|
pub use machine::Machine;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::model::{Color, Sample, Cartridge};
|
use crate::model::{Cartridge, Color, Sample};
|
||||||
use crate::peripherals::{Gfx, InputSignals, Pad, Touch, Audio};
|
use crate::peripherals::{Audio, Gfx, InputSignals, Pad, Touch};
|
||||||
use crate::vm::{VirtualMachine, NativeInterface, Value};
|
use crate::vm::VirtualMachine;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// PROMETEU "hardware lógico" (v0).
|
/// PROMETEU "hardware lógico" (v0).
|
||||||
@ -21,123 +21,13 @@ pub struct Machine {
|
|||||||
pub sample_snare: Option<Arc<Sample>>,
|
pub sample_snare: Option<Arc<Sample>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NativeInterface for Machine {
|
|
||||||
fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
|
||||||
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 {
|
impl Machine {
|
||||||
pub const W: usize = 320;
|
pub const W: usize = 320;
|
||||||
pub const H: usize = 180;
|
pub const H: usize = 180;
|
||||||
pub const CYCLES_PER_FRAME: u64 = 100_000; // Exemplo de budget
|
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 {
|
pub fn new() -> Self {
|
||||||
let mut machine = Self {
|
let mut machine = Self {
|
||||||
gfx: Gfx::new(Self::W, Self::H),
|
gfx: Gfx::new(Self::W, Self::H),
|
||||||
@ -159,6 +49,45 @@ impl Machine {
|
|||||||
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) {
|
pub fn load_cartridge(&mut self, cart: Cartridge) {
|
||||||
self.cartridge = Some(cart);
|
self.cartridge = Some(cart);
|
||||||
}
|
}
|
||||||
|
|||||||
75
crates/core/src/native_interface.rs
Normal file
75
crates/core/src/native_interface.rs
Normal file
@ -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<u64, String> {
|
||||||
|
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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user