crustacean_6502_emulator/src/handler.rs

114 lines
3.6 KiB
Rust

use crate::emulator::{CpuError, System};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
static TEST_CODE: &'static [u8; 0x10000] = include_bytes!("color.hex");
/* #region Commands */
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Cmd {
Step,
Run,
Stop,
Get(GetType),
Reset,
}
impl std::convert::From<&str> for Cmd {
fn from(text: &str) -> Self {
match text {
"Step" => Self::Step,
"Run" => Self::Run,
"Stop" => Self::Stop,
"Reset" => Self::Reset,
_ => panic!("???"),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GetType {
Range(usize, usize),
Value(usize),
Flags,
}
/* #endregion */
pub struct ThreadedEmulator {
pub tcmd: mpsc::Sender<Cmd>,
pub rdata: glib::Receiver<Vec<u8>>,
pub system: Arc<Mutex<System>>,
pub thread: thread::JoinHandle<Result<(), CpuError>>,
}
impl ThreadedEmulator {
pub fn new() -> Self {
let (tcmd, rcmd) = mpsc::channel::<Cmd>();
let (tdata, rdata) = glib::MainContext::channel(glib::source::Priority::default());
let system = Arc::from(Mutex::from(System::new()));
let thread = {
let system = system.clone();
thread::spawn(move || Self::thread(rcmd, tdata, system))
};
Self {
tcmd,
rdata,
system,
thread,
}
}
fn thread(
rcmd: mpsc::Receiver<Cmd>,
tdata: glib::Sender<Vec<u8>>,
system: Arc<Mutex<System>>,
) -> Result<(), CpuError> {
loop {
if let Ok(cmd) = rcmd.recv() {
let mut system = system.lock().unwrap_or_else(|e| {
panic!("Error acquiring lock for the system. Error: {}", e)
});
println!("Cmd: {:?}", cmd);
match cmd {
Cmd::Step => {
system.step()?;
let page_02 = Vec::from(&(*system.ram)[0x200..0x300]);
tdata.send(page_02);
}
Cmd::Reset => {
system.restart();
system.ram.load(*TEST_CODE);
}
Cmd::Run => loop {
if let Err(e) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
if e == std::sync::mpsc::RecvTimeoutError::Timeout {
system.step()?;
let page_02 = Vec::from(&(*system.ram)[0x200..0x300]);
tdata.send(page_02);
} else {
panic!("Controller mpsc disconnected: {}", e)
}
} else {
break;
}
},
Cmd::Get(what) => match what {
GetType::Flags => {}
GetType::Range(start, end) => {
let data = &(*system.ram)[start..end];
tdata
.send(Vec::from(data))
.expect("Couldn't send requested value");
}
GetType::Value(addr) => {
tdata
.send(vec![(*system.ram)[addr]])
.expect("Couldn't send requested value");
}
},
_ => {}
};
}
}
}
}