moa/emulator/core/src/system.rs

206 lines
6.0 KiB
Rust

use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
use std::collections::HashMap;
use crate::memory::Bus;
use crate::debugger::Debugger;
use crate::signals::EdgeSignal;
use crate::error::{Error, ErrorType};
use crate::interrupts::InterruptController;
use crate::devices::{Clock, ClockElapsed, Address, TransmutableBox};
pub struct System {
pub clock: Clock,
pub devices: HashMap<String, TransmutableBox>,
pub event_queue: Vec<NextStep>,
pub debug_enabled: Cell<bool>,
pub debugger: RefCell<Debugger>,
pub bus: Rc<RefCell<Bus>>,
pub interrupt_controller: RefCell<InterruptController>,
pub break_signal: Option<EdgeSignal>,
}
impl Default for System {
fn default() -> Self {
Self {
clock: 0,
devices: HashMap::new(),
event_queue: vec![],
debug_enabled: Cell::new(false),
debugger: RefCell::new(Debugger::default()),
bus: Rc::new(RefCell::new(Bus::default())),
interrupt_controller: RefCell::new(InterruptController::default()),
break_signal: None,
}
}
}
impl System {
pub fn get_bus(&self) -> RefMut<'_, Bus> {
self.bus.borrow_mut()
}
pub fn get_interrupt_controller(&self) -> RefMut<'_, InterruptController> {
self.interrupt_controller.borrow_mut()
}
pub fn get_device(&self, name: &str) -> Result<TransmutableBox, Error> {
self.devices.get(name).cloned().ok_or_else(|| Error::new(&format!("system: no device named {}", name)))
}
pub fn add_device(&mut self, name: &str, device: TransmutableBox) -> Result<(), Error> {
self.try_queue_device(device.clone());
self.devices.insert(name.to_string(), device);
Ok(())
}
pub fn add_addressable_device(&mut self, addr: Address, device: TransmutableBox) -> Result<(), Error> {
self.add_peripheral(&format!("mem{:x}", addr), addr, device)
}
pub fn add_peripheral(&mut self, name: &str, addr: Address, device: TransmutableBox) -> Result<(), Error> {
self.bus.borrow_mut().insert(addr, device.clone());
self.try_queue_device(device.clone());
self.devices.insert(name.to_string(), device);
Ok(())
}
pub fn add_interruptable_device(&mut self, name: &str, device: TransmutableBox) -> Result<(), Error> {
self.interrupt_controller.borrow_mut().set_target(device.clone())?;
self.try_queue_device(device.clone());
self.devices.insert(name.to_string(), device);
Ok(())
}
pub fn enable_debugging(&self) {
self.debug_enabled.set(true);
self.devices.get("cpu").map(|result| result.try_borrow_mut().map(|mut borrow| borrow.as_debuggable().map(|debug| debug.set_debugging(true))));
self.debugger.borrow_mut().breakpoint_occurred();
}
pub fn disable_debugging(&self) {
self.debug_enabled.set(false);
}
fn process_one_event(&mut self) -> Result<(), Error> {
let mut event_device = self.event_queue.pop().unwrap();
self.clock = event_device.next_clock;
let result = match event_device.device.borrow_mut().as_steppable().unwrap().step(self) {
Ok(diff) => {
event_device.next_clock = self.clock + diff;
Ok(())
},
Err(err) => Err(err),
};
self.queue_device(event_device);
result
}
pub fn step(&mut self) -> Result<(), Error> {
self.check_debugger();
match self.process_one_event() {
Ok(()) => {
if self.get_bus().check_and_reset_watcher_modified() {
self.enable_debugging();
}
},
Err(err) if err.err == ErrorType::Breakpoint => {
println!("Breakpoint reached: {}", err.msg);
self.enable_debugging();
},
Err(err) => {
self.exit_error();
println!("{:?}", err);
return Err(err);
},
}
Ok(())
}
pub fn run_for(&mut self, elapsed: ClockElapsed) -> Result<(), Error> {
let target = self.clock + elapsed;
while self.clock < target {
self.step()?;
}
Ok(())
}
pub fn run_until_break(&mut self) -> Result<(), Error> {
let mut signal = match &self.break_signal {
Some(signal) => signal.clone(),
None => return Ok(()),
};
while !signal.get() {
self.step()?;
}
Ok(())
}
pub fn run_loop(&mut self) {
self.run_for(u64::MAX).unwrap();
}
pub fn exit_error(&mut self) {
for (_, dev) in self.devices.iter() {
match dev.borrow_mut().as_steppable() {
Some(dev) => dev.on_error(self),
None => { },
}
}
}
fn check_debugger(&mut self) {
if self.debug_enabled.get() {
let top = self.event_queue[self.event_queue.len() - 1].device.clone();
if top.borrow_mut().as_debuggable().map(|debug| debug.debugging_enabled()).unwrap_or(false) {
if let Err(err) = self.debugger.borrow_mut().run_debugger(self, top.clone()) {
println!("Error: {:?}", err);
}
}
}
}
fn try_queue_device(&mut self, device: TransmutableBox) {
if device.borrow_mut().as_steppable().is_some() {
self.queue_device(NextStep::new(device));
}
}
fn queue_device(&mut self, device_step: NextStep) {
for i in (0..self.event_queue.len()).rev() {
if self.event_queue[i].next_clock > device_step.next_clock {
self.event_queue.insert(i + 1, device_step);
return;
}
}
self.event_queue.insert(0, device_step);
}
}
pub struct NextStep {
pub next_clock: Clock,
pub device: TransmutableBox,
}
impl NextStep {
pub fn new(device: TransmutableBox) -> Self {
Self {
next_clock: 0,
device,
}
}
}