add native_interface

This commit is contained in:
Nilton Constantino 2026-01-15 15:32:16 +00:00
parent 760189929a
commit cbb9b93ce1
No known key found for this signature in database
3 changed files with 118 additions and 113 deletions

View File

@ -2,5 +2,6 @@ pub mod machine;
pub mod peripherals;
pub mod vm;
mod model;
mod native_interface;
pub use machine::Machine;

View File

@ -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<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 {
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);
}

View 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)),
}
}
}