extern crate clap; use std::fs; use std::io; use std::io::prelude::*; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use std::time::Duration; use std::rc::Rc; use std::cell::RefCell; mod cpu8051; mod bus; mod progmem; mod ram; use self::cpu8051::Cpu8051; use self::progmem::ProgramMemory; enum Control { Run(bool), } enum SimData {} struct BoundController { tx: Sender, _rx: Receiver, } struct BoundEmu { _tx: Sender, rx: Receiver, } fn new_bound_pair() -> (BoundEmu, BoundController) { let (tx_c, rx_c): (Sender, Receiver) = channel(); let (tx_d, rx_d): (Sender, Receiver) = channel(); ( BoundEmu { _tx: tx_d, rx: rx_c, }, BoundController { tx: tx_c, _rx: rx_d, }, ) } fn cli_controller(bound: BoundController) { let stdin = io::stdin(); for line in stdin.lock().lines() { let line = line.unwrap(); match line.as_ref() { "stop" => { println!("stop"); bound.tx.send(Control::Run(false)).unwrap(); } "start" => { println!("start"); bound.tx.send(Control::Run(true)).unwrap(); } _ => (), } } } fn ws_controller(_bound: BoundController) { // TODO implement println!("AAA"); } fn new_controller(name: &str) -> Result<&dyn Fn(BoundController), i32> { match name { "cli" => Ok(&cli_controller), "ws" => Ok(&ws_controller), _ => Err(1), } } fn emu_worker(mut cpu: Cpu8051, bound: BoundEmu) { let mut should_stop = false; loop { if should_stop { if let Ok(msg) = bound.rx.recv() { match msg { Control::Run(run) => should_stop = !run, } } } else { println!("0x{:08x}: {}", cpu.pc(), cpu.op()); cpu.step(); if let Ok(msg) = bound.rx.recv_timeout(Duration::from_millis(1000)) { match msg { Control::Run(run) => should_stop = !run, } } } } } fn main() { /* Parse args*/ let cli_args_matches = clap::App::new("x51emu") .version("0.1.0") .author("oxore") .about("MCS51 emulator") .arg( clap::Arg::with_name("file") .short("f") .long("file") .value_name("FILE") .help("Sets a file with program to load") .takes_value(true) .required(true), ) .arg( clap::Arg::with_name("interface") .short("i") .long("interface") .value_name("INTERFACE") .help("Sets a controlling and I/O interface") .takes_value(true) .default_value("cli") .possible_values(&["cli", "ws"]), ) .get_matches(); let filename = cli_args_matches .value_of("file") .expect("No file name provided"); /* Read program and instantiate a simulator */ let data = fs::read_to_string(filename).unwrap_or_else(|_| panic!("Unable to read file {}", filename)); let cpu = Cpu8051::new().rom(match ProgramMemory::from_hex(data) { Ok(value) => Rc::new(RefCell::new(value)), Err(err_string) => { println!("{}", err_string); return; } }); /* Run cpu worker and controller */ let (bound_core, bound_controller) = new_bound_pair(); emu_worker(cpu, bound_core); thread::spawn(move || { let controller = { let controller_type_name = cli_args_matches .value_of("interface") .expect("No interface type specified"); new_controller(controller_type_name) .unwrap_or_else(|_| panic!("Unknown controller type \"{}\"", controller_type_name)) }; controller(bound_controller); }); }