add boot loader
This commit is contained in:
parent
4a6def6aa0
commit
990e3ead2a
@ -4,6 +4,6 @@
|
|||||||
"app_id": 1234,
|
"app_id": 1234,
|
||||||
"title": "Cart de Teste",
|
"title": "Cart de Teste",
|
||||||
"app_version": "1.0.0",
|
"app_version": "1.0.0",
|
||||||
"app_mode": "Invalid",
|
"app_mode": "Game",
|
||||||
"entrypoint": "0"
|
"entrypoint": "0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ mod log_sink;
|
|||||||
|
|
||||||
use crate::prometeu_runner::PrometeuRunner;
|
use crate::prometeu_runner::PrometeuRunner;
|
||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
|
use prometeu_core::firmware::BootTarget;
|
||||||
use prometeu_core::telemetry::CertificationConfig;
|
use prometeu_core::telemetry::CertificationConfig;
|
||||||
|
|
||||||
fn load_cap_config(path: &str) -> Option<CertificationConfig> {
|
fn load_cap_config(path: &str) -> Option<CertificationConfig> {
|
||||||
@ -37,14 +38,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
let mut fs_root = None;
|
let mut fs_root = None;
|
||||||
let mut cap_config = None;
|
let mut cap_config = None;
|
||||||
let mut cartridge_path = None;
|
let mut boot_target = BootTarget::Hub;
|
||||||
|
|
||||||
let mut i = 1; // Pula o nome do executável
|
let mut i = 1; // Pula o nome do executável
|
||||||
while i < args.len() {
|
while i < args.len() {
|
||||||
match args[i].as_str() {
|
match args[i].as_str() {
|
||||||
"run" => {
|
"--run" => {
|
||||||
if i + 1 < args.len() {
|
if i + 1 < args.len() {
|
||||||
cartridge_path = Some(args[i + 1].clone());
|
boot_target = BootTarget::Cartridge {
|
||||||
|
path: args[i + 1].clone(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--debug" => {
|
||||||
|
if i + 1 < args.len() {
|
||||||
|
boot_target = BootTarget::Cartridge {
|
||||||
|
path: args[i + 1].clone(),
|
||||||
|
debug: true,
|
||||||
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,16 +81,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let event_loop = EventLoop::new()?;
|
let event_loop = EventLoop::new()?;
|
||||||
|
|
||||||
let mut runner = PrometeuRunner::new(fs_root, cap_config);
|
let mut runner = PrometeuRunner::new(fs_root, cap_config);
|
||||||
|
runner.set_boot_target(boot_target);
|
||||||
if let Some(path) = cartridge_path {
|
|
||||||
match runner.load_cartridge(&path) {
|
|
||||||
Ok(_) => println!("Cartridge loaded: {}", path),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Failed to load cartridge: {:?}", e);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_loop.run_app(&mut runner)?;
|
event_loop.run_app(&mut runner)?;
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::fs_desktop_backend::HostDirBackend;
|
|||||||
use crate::log_sink::HostConsoleSink;
|
use crate::log_sink::HostConsoleSink;
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
use prometeu_core::firmware::Firmware;
|
use prometeu_core::firmware::{BootTarget, Firmware};
|
||||||
use prometeu_core::hardware::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE};
|
use prometeu_core::hardware::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE};
|
||||||
use prometeu_core::Hardware;
|
use prometeu_core::Hardware;
|
||||||
use ringbuf::traits::{Consumer, Producer, Split};
|
use ringbuf::traits::{Consumer, Producer, Split};
|
||||||
@ -42,6 +42,8 @@ pub struct PrometeuRunner {
|
|||||||
|
|
||||||
overlay_enabled: bool,
|
overlay_enabled: bool,
|
||||||
|
|
||||||
|
debug_waiting_for_start: bool,
|
||||||
|
|
||||||
audio_load_accum_us: u64,
|
audio_load_accum_us: u64,
|
||||||
audio_load_samples: u64,
|
audio_load_samples: u64,
|
||||||
audio_perf_consumer: Option<ringbuf::wrap::CachingCons<Arc<HeapRb<u64>>>>,
|
audio_perf_consumer: Option<ringbuf::wrap::CachingCons<Arc<HeapRb<u64>>>>,
|
||||||
@ -51,6 +53,15 @@ pub struct PrometeuRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrometeuRunner {
|
impl PrometeuRunner {
|
||||||
|
pub(crate) fn set_boot_target(&mut self, boot_target: BootTarget) {
|
||||||
|
self.firmware.boot_target = boot_target.clone();
|
||||||
|
if let BootTarget::Cartridge { debug: true, .. } = boot_target {
|
||||||
|
self.debug_waiting_for_start = true;
|
||||||
|
println!("[Debugger] Waiting for start command...");
|
||||||
|
println!("[Debugger] (Stub: press D to start execution)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn load_cartridge(&mut self, path: &str) -> Result<(), CartridgeError> {
|
pub(crate) fn load_cartridge(&mut self, path: &str) -> Result<(), CartridgeError> {
|
||||||
let cartridge = CartridgeLoader::load(path)?;
|
let cartridge = CartridgeLoader::load(path)?;
|
||||||
self.firmware.load_cartridge(cartridge);
|
self.firmware.load_cartridge(cartridge);
|
||||||
@ -82,6 +93,7 @@ impl PrometeuRunner {
|
|||||||
frames_since_last_update: 0,
|
frames_since_last_update: 0,
|
||||||
current_fps: 0.0,
|
current_fps: 0.0,
|
||||||
overlay_enabled: false,
|
overlay_enabled: false,
|
||||||
|
debug_waiting_for_start: false,
|
||||||
audio_load_accum_us: 0,
|
audio_load_accum_us: 0,
|
||||||
audio_load_samples: 0,
|
audio_load_samples: 0,
|
||||||
audio_perf_consumer: None,
|
audio_perf_consumer: None,
|
||||||
@ -225,6 +237,12 @@ impl ApplicationHandler for PrometeuRunner {
|
|||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
if let PhysicalKey::Code(code) = event.physical_key {
|
if let PhysicalKey::Code(code) = event.physical_key {
|
||||||
let is_down = event.state == ElementState::Pressed;
|
let is_down = event.state == ElementState::Pressed;
|
||||||
|
|
||||||
|
if is_down && code == KeyCode::KeyD && self.debug_waiting_for_start {
|
||||||
|
self.debug_waiting_for_start = false;
|
||||||
|
println!("[Debugger] Execution started!");
|
||||||
|
}
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
KeyCode::ArrowUp => self.input_signals.up_signal = is_down,
|
KeyCode::ArrowUp => self.input_signals.up_signal = is_down,
|
||||||
KeyCode::ArrowDown => self.input_signals.down_signal = is_down,
|
KeyCode::ArrowDown => self.input_signals.down_signal = is_down,
|
||||||
@ -301,7 +319,9 @@ impl ApplicationHandler for PrometeuRunner {
|
|||||||
|
|
||||||
// 🔥 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.firmware.step_frame(&self.input_signals, &mut self.hardware);
|
if !self.debug_waiting_for_start {
|
||||||
|
self.firmware.step_frame(&self.input_signals, &mut self.hardware);
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
|||||||
11
crates/prometeu-core/src/firmware/boot_target.rs
Normal file
11
crates/prometeu-core/src/firmware/boot_target.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum BootTarget {
|
||||||
|
Hub,
|
||||||
|
Cartridge { path: String, debug: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BootTarget {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Hub
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::firmware::boot_target::BootTarget;
|
||||||
use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetStep};
|
use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetStep};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
use crate::hardware::{HardwareBridge, InputSignals};
|
use crate::hardware::{HardwareBridge, InputSignals};
|
||||||
@ -13,6 +14,7 @@ pub struct Firmware {
|
|||||||
pub os: PrometeuOS,
|
pub os: PrometeuOS,
|
||||||
pub hub: PrometeuHub,
|
pub hub: PrometeuHub,
|
||||||
pub state: FirmwareState,
|
pub state: FirmwareState,
|
||||||
|
pub boot_target: BootTarget,
|
||||||
state_initialized: bool,
|
state_initialized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ impl Firmware {
|
|||||||
os: PrometeuOS::new(cap_config),
|
os: PrometeuOS::new(cap_config),
|
||||||
hub: PrometeuHub::new(),
|
hub: PrometeuHub::new(),
|
||||||
state: FirmwareState::Reset(ResetStep),
|
state: FirmwareState::Reset(ResetStep),
|
||||||
|
boot_target: BootTarget::Hub,
|
||||||
state_initialized: false,
|
state_initialized: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,7 +44,7 @@ impl Firmware {
|
|||||||
self.change_state(next_state, signals, hw);
|
self.change_state(next_state, signals, hw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_state(&mut self, new_state: FirmwareState, signals: &InputSignals, hw: &mut dyn HardwareBridge) {
|
pub fn change_state(&mut self, new_state: FirmwareState, signals: &InputSignals, hw: &mut dyn HardwareBridge) {
|
||||||
self.on_exit(signals, hw);
|
self.on_exit(signals, hw);
|
||||||
self.state = new_state;
|
self.state = new_state;
|
||||||
@ -57,6 +60,7 @@ impl Firmware {
|
|||||||
vm: &mut self.vm,
|
vm: &mut self.vm,
|
||||||
os: &mut self.os,
|
os: &mut self.os,
|
||||||
hub: &mut self.hub,
|
hub: &mut self.hub,
|
||||||
|
boot_target: &self.boot_target,
|
||||||
signals,
|
signals,
|
||||||
hw,
|
hw,
|
||||||
};
|
};
|
||||||
@ -76,6 +80,7 @@ impl Firmware {
|
|||||||
vm: &mut self.vm,
|
vm: &mut self.vm,
|
||||||
os: &mut self.os,
|
os: &mut self.os,
|
||||||
hub: &mut self.hub,
|
hub: &mut self.hub,
|
||||||
|
boot_target: &self.boot_target,
|
||||||
signals,
|
signals,
|
||||||
hw,
|
hw,
|
||||||
};
|
};
|
||||||
@ -95,6 +100,7 @@ impl Firmware {
|
|||||||
vm: &mut self.vm,
|
vm: &mut self.vm,
|
||||||
os: &mut self.os,
|
os: &mut self.os,
|
||||||
hub: &mut self.hub,
|
hub: &mut self.hub,
|
||||||
|
boot_target: &self.boot_target,
|
||||||
signals,
|
signals,
|
||||||
hw,
|
hw,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
use crate::firmware::firmware_state::{FirmwareState, HubHomeStep};
|
use crate::firmware::boot_target::BootTarget;
|
||||||
|
use crate::firmware::firmware_state::{FirmwareState, HubHomeStep, LoadCartridgeStep};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
|
use crate::model::CartridgeLoader;
|
||||||
use crate::log::{LogLevel, LogSource};
|
use crate::log::{LogLevel, LogSource};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -11,7 +13,19 @@ impl LaunchHubStep {
|
|||||||
ctx.hub.init();
|
ctx.hub.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update(&mut self, _ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||||
|
if let BootTarget::Cartridge { path, debug } = ctx.boot_target {
|
||||||
|
match CartridgeLoader::load(path) {
|
||||||
|
Ok(cartridge) => {
|
||||||
|
// No caso de debug, aqui poderíamos pausar, mas o requisito diz
|
||||||
|
// para o Runtime abrir o socket e aguardar.
|
||||||
|
return Some(FirmwareState::LoadCartridge(LoadCartridgeStep { cartridge }));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
ctx.os.log(LogLevel::Error, LogSource::Pos, 0, format!("Failed to auto-load cartridge: {:?}", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(FirmwareState::HubHome(HubHomeStep))
|
Some(FirmwareState::HubHome(HubHomeStep))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,9 @@ impl LoadCartridgeStep {
|
|||||||
Color::WHITE
|
Color::WHITE
|
||||||
);
|
);
|
||||||
ctx.hub.window_manager.set_focus(id);
|
ctx.hub.window_manager.set_focus(id);
|
||||||
|
|
||||||
|
// Apps de sistema não mudam o estado do firmware para GameRunning.
|
||||||
|
// Eles rodam em background ou via janelas no Hub.
|
||||||
return Some(FirmwareState::HubHome(HubHomeStep));
|
return Some(FirmwareState::HubHome(HubHomeStep));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::firmware::firmware_state::{FirmwareState, SplashScreenStep};
|
use crate::firmware::boot_target::BootTarget;
|
||||||
|
use crate::firmware::firmware_state::{FirmwareState, LaunchHubStep, SplashScreenStep};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
use crate::log::{LogLevel, LogSource};
|
use crate::log::{LogLevel, LogSource};
|
||||||
|
|
||||||
@ -11,8 +12,11 @@ impl ResetStep {
|
|||||||
ctx.os.reset(ctx.vm);
|
ctx.os.reset(ctx.vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update(&mut self, _ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||||
Some(FirmwareState::SplashScreen(SplashScreenStep { frame: 0 }))
|
match ctx.boot_target {
|
||||||
|
BootTarget::Hub => Some(FirmwareState::SplashScreen(SplashScreenStep { frame: 0 })),
|
||||||
|
BootTarget::Cartridge { .. } => Some(FirmwareState::LaunchHub(LaunchHubStep)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
mod firmware;
|
mod firmware;
|
||||||
pub mod firmware_state;
|
pub mod firmware_state;
|
||||||
|
mod boot_target;
|
||||||
|
|
||||||
pub(crate) mod firmware_step_reset;
|
pub(crate) mod firmware_step_reset;
|
||||||
pub(crate) mod firmware_step_splash_screen;
|
pub(crate) mod firmware_step_splash_screen;
|
||||||
@ -13,3 +14,4 @@ mod prometeu_context;
|
|||||||
pub use firmware::Firmware;
|
pub use firmware::Firmware;
|
||||||
pub use firmware_state::FirmwareState;
|
pub use firmware_state::FirmwareState;
|
||||||
pub use prometeu_context::PrometeuContext;
|
pub use prometeu_context::PrometeuContext;
|
||||||
|
pub use boot_target::BootTarget;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::firmware::boot_target::BootTarget;
|
||||||
use crate::hardware::{HardwareBridge, InputSignals};
|
use crate::hardware::{HardwareBridge, InputSignals};
|
||||||
use crate::prometeu_hub::PrometeuHub;
|
use crate::prometeu_hub::PrometeuHub;
|
||||||
use crate::prometeu_os::PrometeuOS;
|
use crate::prometeu_os::PrometeuOS;
|
||||||
@ -7,6 +8,7 @@ pub struct PrometeuContext<'a> {
|
|||||||
pub vm: &'a mut VirtualMachine,
|
pub vm: &'a mut VirtualMachine,
|
||||||
pub os: &'a mut PrometeuOS,
|
pub os: &'a mut PrometeuOS,
|
||||||
pub hub: &'a mut PrometeuHub,
|
pub hub: &'a mut PrometeuHub,
|
||||||
|
pub boot_target: &'a BootTarget,
|
||||||
pub signals: &'a InputSignals,
|
pub signals: &'a InputSignals,
|
||||||
pub hw: &'a mut dyn HardwareBridge,
|
pub hw: &'a mut dyn HardwareBridge,
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user