diff options
Diffstat (limited to 'src/emulators/headless_emulator.rs')
-rw-r--r-- | src/emulators/headless_emulator.rs | 164 |
1 files changed, 72 insertions, 92 deletions
diff --git a/src/emulators/headless_emulator.rs b/src/emulators/headless_emulator.rs index f215db3..770bae3 100644 --- a/src/emulators/headless_emulator.rs +++ b/src/emulators/headless_emulator.rs @@ -1,125 +1,105 @@ use crate::*; -use bedrock_core::*; -pub struct HeadlessDeviceBus { - pub sys: SystemDevice, - pub mem: MemoryDevice, - pub mat: MathDevice, - pub clk: ClockDevice, - pub loc: LocalDevice, - pub rem: RemoteDevice, - pub fs1: FileDevice, - pub fs2: FileDevice, +pub struct HeadlessEmulator { + pub br: BedrockEmulator<HeadlessDeviceBus>, + pub debug: DebugState, } -impl HeadlessDeviceBus { - pub fn new(config: &EmulatorConfig) -> Self { +impl HeadlessEmulator { + pub fn new(config: &EmulatorConfig, debug: bool) -> Self { Self { - sys: SystemDevice::new(), - mem: MemoryDevice::new(), - mat: MathDevice::new(), - clk: ClockDevice::new(), - loc: LocalDevice::new(config), - rem: RemoteDevice::new(), - fs1: FileDevice::new(), - fs2: FileDevice::new(), + br: BedrockEmulator::new(HeadlessDeviceBus::new(config)), + debug: DebugState::new(debug, config.symbols_path.as_ref()), } } -} -impl DeviceBus for HeadlessDeviceBus { - fn read(&mut self, port: u8) -> u8 { - match port & 0xf0 { - 0x00 => self.sys.read(port & 0x0f), - 0x10 => self.mem.read(port & 0x0f), - 0x20 => self.mat.read(port & 0x0f), - 0x30 => self.clk.read(port & 0x0f), - 0x80 => self.loc.read(port & 0x0f), - 0x90 => self.rem.read(port & 0x0f), - 0xa0 => self.fs1.read(port & 0x0f), - 0xb0 => self.fs2.read(port & 0x0f), - _ => 0 - } + pub fn load_program(&mut self, bytecode: &[u8]) { + self.br.core.mem.load_program(bytecode); } - fn write(&mut self, port: u8, value: u8) -> Option<Signal> { - match port & 0xf0 { - 0x00 => self.sys.write(port & 0x0f, value), - 0x10 => self.mem.write(port & 0x0f, value), - 0x20 => self.mat.write(port & 0x0f, value), - 0x30 => self.clk.write(port & 0x0f, value), - 0x80 => self.loc.write(port & 0x0f, value), - 0x90 => self.rem.write(port & 0x0f, value), - 0xa0 => self.fs1.write(port & 0x0f, value), - 0xb0 => self.fs2.write(port & 0x0f, value), - _ => None + fn sleep(&mut self) { + loop { + if self.br.dev.wake() { break; } + std::thread::sleep(TICK_DURATION); } } - fn wake(&mut self) -> bool { - macro_rules! rouse { - ($id:expr, $dev:ident) => { - if self.sys.can_wake($id) && self.$dev.wake() { - self.sys.wake_id = $id; - self.sys.asleep = false; - return true; + 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), + _ => (), + } + _ => (), } - }; + } } - rouse!(0xb, fs2); - rouse!(0xa, fs1); - rouse!(0x9, rem); - rouse!(0x8, loc); - rouse!(0x3, clk); - rouse!(0x2, mat); - rouse!(0x1, mem); - rouse!(0x0, sys); - return false; } } -pub struct HeadlessEmulator { - pub br: BedrockEmulator<HeadlessDeviceBus>, - pub debug: DebugState, +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 HeadlessEmulator { - pub fn new(config: &EmulatorConfig, debug: bool, verbose: bool) -> Self { +impl HeadlessDeviceBus { + pub fn new(config: &EmulatorConfig) -> Self { Self { - br: BedrockEmulator::new(HeadlessDeviceBus::new(config)), - debug: DebugState::new(debug, verbose, config.symbols_path.as_ref()), + system: SystemDevice::new(0b1111_0000_1100_0000), + memory: MemoryDevice::new(), + math: MathDevice::new(), + clock: ClockDevice::new(), + stream: StreamDevice::new(&config), + file: FileDevice::new(&config), + wake_queue: WakeQueue::new(), } } +} - pub fn load_program(&mut self, bytecode: &[u8]) { - self.br.core.mem.load_program(bytecode); +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 + } } - pub fn run(&mut self, debug: bool) -> EmulatorSignal { - loop { - match self.br.evaluate(BATCH_SIZE, self.debug.enabled) { - Some(Signal::Fork) => { - self.br.core.mem.pc = 0; - self.br.core.wst.sp = 0; - self.br.core.rst.sp = 0; - } - Some(Signal::Sleep) => loop { - if self.br.dev.wake() { break; } - std::thread::sleep(MIN_TICK_DURATION); - } - Some(Signal::Halt) => { - self.br.dev.loc.flush(); - self.debug.info("Program halted, exiting."); - self.debug.debug_summary(&self.br.core); - return EmulatorSignal::Halt; - } - Some(Signal::Debug1) => if debug { - self.debug.debug_summary(&self.br.core); + 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; } } |