use crate::*; pub struct HeadlessEmulator { pub br: BedrockEmulator, pub debug: DebugState, } impl HeadlessEmulator { pub fn new(config: &EmulatorConfig, debug: bool) -> Self { Self { br: BedrockEmulator::new(HeadlessDeviceBus::new(config)), debug: DebugState::new(debug, config.symbols_path.as_ref()), } } pub fn load_program(&mut self, bytecode: &[u8]) { self.br.core.mem.load_program(bytecode); } fn sleep(&mut self) { loop { if self.br.dev.wake() { break; } std::thread::sleep(TICK_DURATION); } } fn halt(&mut self) { self.br.dev.stream.flush(); info!("Program halted, exiting."); self.debug.debug_full(&self.br.core); std::process::exit(0); } pub fn run(&mut self) -> ! { loop { if let Some(signal) = self.br.evaluate(BATCH_SIZE, self.debug.enabled) { match signal { Signal::Fork | Signal::Reset => self.br.reset(), Signal::Sleep => self.sleep(), Signal::Halt => self.halt(), Signal::Debug(debug_signal) => match debug_signal { Debug::Debug1 => self.debug.debug_full(&self.br.core), Debug::Debug2 => self.debug.debug_timing(&self.br.core), _ => (), } _ => (), } } } } } pub struct HeadlessDeviceBus { pub system: SystemDevice, pub memory: MemoryDevice, pub math: MathDevice, pub clock: ClockDevice, pub stream: StreamDevice, pub file: FileDevice, pub wake_queue: WakeQueue, } impl HeadlessDeviceBus { pub fn new(config: &EmulatorConfig) -> Self { Self { system: SystemDevice::new(0b1111_0000_1100_0000), memory: MemoryDevice::new(), math: MathDevice::new(), clock: ClockDevice::new(), stream: StreamDevice::new(&config), file: FileDevice::new(), wake_queue: WakeQueue::new(), } } } impl DeviceBus for HeadlessDeviceBus { fn get_device(&mut self, slot: u8) -> Option<&mut dyn Device> { match slot { 0x0 => Some(&mut self.system), 0x1 => Some(&mut self.memory), 0x2 => Some(&mut self.math ), 0x3 => Some(&mut self.clock ), 0x8 => Some(&mut self.stream), 0x9 => Some(&mut self.file ), _ => None } } fn wake(&mut self) -> bool { for slot in self.wake_queue.iter(self.system.wake_mask) { if let Some(device) = self.get_device(slot) { if device.wake() { self.system.wake_slot = slot; self.system.asleep = false; self.wake_queue.wake(slot); return true; } } } return false; } }