rename Machine -> LogicalHardware
This commit is contained in:
parent
d1c87ef6e7
commit
85a5f2d63f
@ -1,8 +1,8 @@
|
|||||||
pub mod machine;
|
pub mod logical_hardware;
|
||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
mod model;
|
mod model;
|
||||||
mod native_interface;
|
mod native_interface;
|
||||||
mod utilz;
|
mod utilz;
|
||||||
|
|
||||||
pub use machine::Machine;
|
pub use logical_hardware::LogicalHardware;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
/// PROMETEU "hardware lógico" (v0).
|
/// PROMETEU "hardware lógico" (v0).
|
||||||
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
|
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
|
||||||
pub struct Machine {
|
pub struct LogicalHardware {
|
||||||
pub gfx: Gfx,
|
pub gfx: Gfx,
|
||||||
pub audio: Audio,
|
pub audio: Audio,
|
||||||
pub pad: Pad,
|
pub pad: Pad,
|
||||||
@ -23,13 +23,13 @@ pub struct Machine {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Machine {
|
impl LogicalHardware {
|
||||||
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
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut machine = Self {
|
let mut logical_hardware = Self {
|
||||||
gfx: Gfx::new(Self::W, Self::H),
|
gfx: Gfx::new(Self::W, Self::H),
|
||||||
audio: Audio::new(),
|
audio: Audio::new(),
|
||||||
pad: Pad::default(),
|
pad: Pad::default(),
|
||||||
@ -44,9 +44,9 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Inicializa samples básicos
|
// Inicializa samples básicos
|
||||||
machine.sample_square = Some(Arc::new(Self::create_square_sample(440.0, 0.1)));
|
logical_hardware.sample_square = Some(Arc::new(Self::create_square_sample(440.0, 0.1)));
|
||||||
|
|
||||||
machine
|
logical_hardware
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_color(&self, index: usize) -> Color {
|
pub fn get_color(&self, index: usize) -> Color {
|
||||||
@ -116,7 +116,7 @@ impl Machine {
|
|||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
self.begin_frame(signals);
|
self.begin_frame(signals);
|
||||||
|
|
||||||
// Retira a VM temporariamente para executar run_budget passando self (Machine) como NativeInterface.
|
// Retira a VM temporariamente para executar run_budget passando self (Logical Hardware) como NativeInterface.
|
||||||
// Como VirtualMachine implementa Default, usamos std::mem::take.
|
// Como VirtualMachine implementa Default, usamos std::mem::take.
|
||||||
let mut vm = std::mem::take(&mut self.vm);
|
let mut vm = std::mem::take(&mut self.vm);
|
||||||
let _result = vm.run_budget(Self::CYCLES_PER_FRAME, self);
|
let _result = vm.run_budget(Self::CYCLES_PER_FRAME, self);
|
||||||
@ -1,11 +1,11 @@
|
|||||||
use crate::vm::{Value, VirtualMachine};
|
use crate::vm::{Value, VirtualMachine};
|
||||||
use crate::Machine;
|
use crate::LogicalHardware;
|
||||||
|
|
||||||
pub trait NativeInterface {
|
pub trait NativeInterface {
|
||||||
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String>;
|
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NativeInterface for Machine {
|
impl NativeInterface for LogicalHardware {
|
||||||
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
||||||
match id {
|
match id {
|
||||||
// system.has_cart() -> bool
|
// system.has_cart() -> bool
|
||||||
|
|||||||
@ -726,10 +726,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_run_cart() {
|
fn test_system_run_cart() {
|
||||||
use crate::Machine;
|
use crate::LogicalHardware;
|
||||||
use crate::model::Cartridge;
|
use crate::model::Cartridge;
|
||||||
|
|
||||||
let mut machine = Machine::new();
|
let mut logical_hardware = LogicalHardware::new();
|
||||||
|
|
||||||
// 1. Verifica que não tem cartucho inicialmente
|
// 1. Verifica que não tem cartucho inicialmente
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
@ -738,12 +738,12 @@ mod tests {
|
|||||||
utilz::emit_u32(&mut rom, 0x0001);
|
utilz::emit_u32(&mut rom, 0x0001);
|
||||||
utilz::emit_op(&mut rom, OpCode::Halt);
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
machine.vm = VirtualMachine::new(rom, vec![]);
|
logical_hardware.vm = VirtualMachine::new(rom, vec![]);
|
||||||
let mut vm = std::mem::take(&mut machine.vm);
|
let mut vm = std::mem::take(&mut logical_hardware.vm);
|
||||||
vm.run_budget(100, &mut machine).unwrap();
|
vm.run_budget(100, &mut logical_hardware).unwrap();
|
||||||
machine.vm = vm;
|
logical_hardware.vm = vm;
|
||||||
|
|
||||||
assert_eq!(machine.vm.pop().unwrap(), Value::Boolean(false));
|
assert_eq!(logical_hardware.vm.pop().unwrap(), Value::Boolean(false));
|
||||||
|
|
||||||
// 2. Adiciona um cartucho e roda
|
// 2. Adiciona um cartucho e roda
|
||||||
let mut cart_rom = Vec::new();
|
let mut cart_rom = Vec::new();
|
||||||
@ -754,7 +754,7 @@ mod tests {
|
|||||||
let cart_pool = vec![Value::Integer(42)];
|
let cart_pool = vec![Value::Integer(42)];
|
||||||
|
|
||||||
let cart = Cartridge::new(Program::new(cart_rom, cart_pool));
|
let cart = Cartridge::new(Program::new(cart_rom, cart_pool));
|
||||||
machine.load_cartridge(cart);
|
logical_hardware.load_cartridge(cart);
|
||||||
|
|
||||||
// Código para rodar o cartucho
|
// Código para rodar o cartucho
|
||||||
let mut boot_rom = Vec::new();
|
let mut boot_rom = Vec::new();
|
||||||
@ -762,14 +762,14 @@ mod tests {
|
|||||||
utilz::emit_op(&mut boot_rom, OpCode::Syscall);
|
utilz::emit_op(&mut boot_rom, OpCode::Syscall);
|
||||||
utilz::emit_u32(&mut boot_rom, 0x0002);
|
utilz::emit_u32(&mut boot_rom, 0x0002);
|
||||||
|
|
||||||
machine.vm = VirtualMachine::new(boot_rom, vec![]);
|
logical_hardware.vm = VirtualMachine::new(boot_rom, vec![]);
|
||||||
let mut vm = std::mem::take(&mut machine.vm);
|
let mut vm = std::mem::take(&mut logical_hardware.vm);
|
||||||
vm.run_budget(1000, &mut machine).unwrap();
|
vm.run_budget(1000, &mut logical_hardware).unwrap();
|
||||||
machine.vm = vm;
|
logical_hardware.vm = vm;
|
||||||
|
|
||||||
// Após o run_budget, a VM deve ter executado o cartucho
|
// Após o run_budget, a VM deve ter executado o cartucho
|
||||||
assert_eq!(machine.vm.operand_stack.last(), Some(&Value::Integer(42)));
|
assert_eq!(logical_hardware.vm.operand_stack.last(), Some(&Value::Integer(42)));
|
||||||
assert!(machine.vm.halted);
|
assert!(logical_hardware.vm.halted);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -6,7 +6,7 @@ mod audio_mixer;
|
|||||||
use audio_mixer::AudioMixer;
|
use audio_mixer::AudioMixer;
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use prometeu_core::peripherals::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE};
|
use prometeu_core::peripherals::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE};
|
||||||
use prometeu_core::Machine;
|
use prometeu_core::LogicalHardware;
|
||||||
use ringbuf::traits::{Consumer, Producer, Split};
|
use ringbuf::traits::{Consumer, Producer, Split};
|
||||||
use ringbuf::HeapRb;
|
use ringbuf::HeapRb;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -32,7 +32,7 @@ struct PrometeuApp {
|
|||||||
window: Option<&'static Window>,
|
window: Option<&'static Window>,
|
||||||
pixels: Option<Pixels<'static>>,
|
pixels: Option<Pixels<'static>>,
|
||||||
|
|
||||||
machine: Machine,
|
logical_hardware: LogicalHardware,
|
||||||
|
|
||||||
input_signals: InputSignals,
|
input_signals: InputSignals,
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ impl PrometeuApp {
|
|||||||
window: None,
|
window: None,
|
||||||
pixels: None,
|
pixels: None,
|
||||||
|
|
||||||
machine: Machine::new(),
|
logical_hardware: LogicalHardware::new(),
|
||||||
|
|
||||||
input_signals: InputSignals::default(),
|
input_signals: InputSignals::default(),
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
let surface_texture = SurfaceTexture::new(size.width, size.height, window);
|
let surface_texture = SurfaceTexture::new(size.width, size.height, window);
|
||||||
|
|
||||||
let mut pixels = Pixels::new(Machine::W as u32, Machine::H as u32, surface_texture)
|
let mut pixels = Pixels::new(LogicalHardware::W as u32, LogicalHardware::H as u32, surface_texture)
|
||||||
.expect("failed to create Pixels");
|
.expect("failed to create Pixels");
|
||||||
|
|
||||||
pixels.frame_mut().fill(0);
|
pixels.frame_mut().fill(0);
|
||||||
@ -195,7 +195,7 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
let frame = pixels.frame_mut();
|
let frame = pixels.frame_mut();
|
||||||
|
|
||||||
// Borrow imutável do core (campo diferente, ok)
|
// Borrow imutável do core (campo diferente, ok)
|
||||||
let src = self.machine.gfx.front_buffer();
|
let src = self.logical_hardware.gfx.front_buffer();
|
||||||
|
|
||||||
draw_rgb565_to_rgba8(src, frame);
|
draw_rgb565_to_rgba8(src, frame);
|
||||||
} // <- frame borrow termina aqui
|
} // <- frame borrow termina aqui
|
||||||
@ -268,11 +268,11 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
|
|
||||||
// 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz
|
// 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz
|
||||||
while self.accumulator >= self.frame_target_dt {
|
while self.accumulator >= self.frame_target_dt {
|
||||||
self.machine.step_frame(&self.input_signals);
|
self.logical_hardware.step_frame(&self.input_signals);
|
||||||
|
|
||||||
// Envia comandos de áudio gerados neste frame para a thread de áudio
|
// Envia comandos de áudio gerados neste frame para a thread de áudio
|
||||||
if let Some(producer) = &mut self.audio_producer {
|
if let Some(producer) = &mut self.audio_producer {
|
||||||
for cmd in self.machine.audio.commands.drain(..) {
|
for cmd in self.logical_hardware.audio.commands.drain(..) {
|
||||||
let _ = producer.try_push(cmd);
|
let _ = producer.try_push(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,10 +294,11 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
if stats_elapsed >= Duration::from_secs(1) {
|
if stats_elapsed >= Duration::from_secs(1) {
|
||||||
if let Some(window) = self.window {
|
if let Some(window) = self.window {
|
||||||
let fps = self.frames_since_last_update as f64 / stats_elapsed.as_secs_f64();
|
let fps = self.frames_since_last_update as f64 / stats_elapsed.as_secs_f64();
|
||||||
let kb = self.machine.gfx.memory_usage_bytes() as f64 / 1024.0;
|
let kb = self.logical_hardware.gfx.memory_usage_bytes() as f64 / 1024.0;
|
||||||
|
|
||||||
|
// comparação fixa sempre contra 60Hz, manter mesmo quando fazer teste de stress na CPU
|
||||||
let frame_budget_us = 16666.0;
|
let frame_budget_us = 16666.0;
|
||||||
let cpu_load_core = (self.machine.last_frame_cpu_time_us as f64 / frame_budget_us) * 100.0;
|
let cpu_load_core = (self.logical_hardware.last_frame_cpu_time_us as f64 / frame_budget_us) * 100.0;
|
||||||
|
|
||||||
let cpu_load_audio = if self.audio_load_samples > 0 {
|
let cpu_load_audio = if self.audio_load_samples > 0 {
|
||||||
// O load real é (tempo total processando) / (tempo total de parede).
|
// O load real é (tempo total processando) / (tempo total de parede).
|
||||||
@ -308,7 +309,7 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
|
|
||||||
let title = format!(
|
let title = format!(
|
||||||
"PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% (C) + {:.1}% (A) | Frame: {}",
|
"PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% (C) + {:.1}% (A) | Frame: {}",
|
||||||
kb, fps, cpu_load_core, cpu_load_audio, self.machine.frame_index
|
kb, fps, cpu_load_core, cpu_load_audio, self.logical_hardware.frame_index
|
||||||
);
|
);
|
||||||
window.set_title(&title);
|
window.set_title(&title);
|
||||||
}
|
}
|
||||||
@ -327,13 +328,13 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
/// Depois podemos fazer letterbox/aspect-ratio correto.
|
/// Depois podemos fazer letterbox/aspect-ratio correto.
|
||||||
fn window_to_fb(wx: f32, wy: f32, window: &Window) -> (i32, i32) {
|
fn window_to_fb(wx: f32, wy: f32, window: &Window) -> (i32, i32) {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
let fb_w = Machine::W as f32;
|
let fb_w = LogicalHardware::W as f32;
|
||||||
let fb_h = Machine::H as f32;
|
let fb_h = LogicalHardware::H as f32;
|
||||||
|
|
||||||
let x = (wx * fb_w / size.width as f32).floor() as i32;
|
let x = (wx * fb_w / size.width as f32).floor() as i32;
|
||||||
let y = (wy * fb_h / size.height as f32).floor() as i32;
|
let y = (wy * fb_h / size.height as f32).floor() as i32;
|
||||||
|
|
||||||
(x.clamp(0, Machine::W as i32 - 1), y.clamp(0, Machine::H as i32 - 1))
|
(x.clamp(0, LogicalHardware::W as i32 - 1), y.clamp(0, LogicalHardware::H as i32 - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copia RGB565 (u16) -> RGBA8888 (u8[4]) para o frame do pixels.
|
/// Copia RGB565 (u16) -> RGBA8888 (u8[4]) para o frame do pixels.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user