From 93c9307829f3955c17b371470348def88670519a Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 16 Oct 2021 16:11:50 -0700 Subject: [PATCH] Moved I/O to a separate thread but I'm not happy with it, and will likely change it in future, possibly to use two threads and two sets of channels to pass chars back and forth --- src/cpus/m68k/state.rs | 7 ++- src/main.rs | 1 + src/peripherals/mc68681.rs | 37 +++++---------- src/ttys.rs | 95 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 30 deletions(-) create mode 100644 src/ttys.rs diff --git a/src/cpus/m68k/state.rs b/src/cpus/m68k/state.rs index 8cb64bf..9bc7388 100644 --- a/src/cpus/m68k/state.rs +++ b/src/cpus/m68k/state.rs @@ -7,21 +7,19 @@ use super::decode::M68kDecoder; use super::debugger::M68kDebugger; +#[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum M68kType { - #[allow(dead_code)] MC68000, - #[allow(dead_code)] MC68010, - #[allow(dead_code)] MC68020, - #[allow(dead_code)] MC68030, } const FLAGS_ON_RESET: u16 = 0x2700; #[repr(u16)] +#[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum Flags { Carry = 0x0001, @@ -36,6 +34,7 @@ pub enum Flags { } #[repr(u8)] +#[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum Exceptions { BusError = 2, diff --git a/src/main.rs b/src/main.rs index ae25777..8f7036f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod error; mod memory; mod timers; mod devices; +mod ttys; mod interrupts; mod cpus; mod peripherals; diff --git a/src/peripherals/mc68681.rs b/src/peripherals/mc68681.rs index 6bd5ceb..aa2ef84 100644 --- a/src/peripherals/mc68681.rs +++ b/src/peripherals/mc68681.rs @@ -1,15 +1,9 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; - -use nix::fcntl::OFlag; -use nix::pty::{self, PtyMaster}; -use nix::fcntl::{fcntl, FcntlArg}; - use crate::error::Error; use crate::system::System; use crate::devices::{Clock, Steppable}; use crate::memory::{Address, Addressable, MAX_READ}; +use crate::ttys::{SimplePty, SharedSimplePty}; const REG_MR1A_MR2A: Address = 0x01; @@ -77,7 +71,7 @@ const ISR_CH_A_TX_READY: u8 = 0x01; const DEV_NAME: &'static str = "mc68681"; pub struct MC68681Port { - pub tty: Option, + pub tty: Option, pub status: u8, pub tx_enabled: bool, @@ -100,21 +94,15 @@ impl MC68681Port { } pub fn open(&mut self) -> Result { - let master = pty::posix_openpt(OFlag::O_RDWR).and_then(|master| { - pty::grantpt(&master)?; - pty::unlockpt(&master)?; - fcntl(master.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; - Ok(master) - }).map_err(|_| Error::new("Error opening new pseudoterminal"))?; - - let name = unsafe { pty::ptsname(&master).map_err(|_| Error::new("Unable to get pty name"))? }; + let pty = SimplePty::open()?; + let name = pty.lock().unwrap().name.clone(); println!("{}: opening pts {}", DEV_NAME, name); - self.tty = Some(master); + self.tty = Some(pty); Ok(name) } pub fn send_byte(&mut self, data: u8) { - self.tty.as_mut().map(|tty| tty.write_all(&[data])); + self.tty.as_mut().map(|tty| tty.lock().unwrap().write(data)); self.set_tx_status(false); } @@ -134,18 +122,15 @@ impl MC68681Port { pub fn check_rx(&mut self) -> Result { if self.rx_enabled && (self.status & SR_RX_READY) == 0 && self.tty.is_some() { - let mut buf = [0; 1]; let tty = self.tty.as_mut().unwrap(); - match tty.read(&mut buf) { - Ok(count) => { - self.input = buf[0]; + let result = tty.lock().unwrap().read(); + match result { + Some(input) => { + self.input = input; self.set_rx_status(true); return Ok(true); }, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { }, - Err(err) => { - println!("ERROR: {:?}", err); - } + None => { }, } } Ok(false) diff --git a/src/ttys.rs b/src/ttys.rs new file mode 100644 index 0000000..7b0b382 --- /dev/null +++ b/src/ttys.rs @@ -0,0 +1,95 @@ + +use std::thread; +use std::time::Duration; +use std::io::{Read, Write}; +use std::sync::{Arc, Mutex}; +use std::os::unix::io::AsRawFd; + +use nix::fcntl::OFlag; +use nix::pty::{self, PtyMaster}; +use nix::fcntl::{fcntl, FcntlArg}; + +use crate::error::Error; + + +pub struct SimplePty { + pub name: String, + input: Option, + output: Vec, +} + +pub type SharedSimplePty = Arc>; + +impl SimplePty { + pub fn new_shared(name: String) -> SharedSimplePty { + Arc::new(Mutex::new(SimplePty { + name, + input: None, + output: vec![], + })) + } + + pub fn open() -> Result { + let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| { + pty::grantpt(&pty)?; + pty::unlockpt(&pty)?; + fcntl(pty.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; + Ok(pty) + }).map_err(|_| Error::new("Error opening new pseudoterminal"))?; + + let name = unsafe { pty::ptsname(&pty).map_err(|_| Error::new("Unable to get pty name"))? }; + let shared = SimplePty::new_shared(name); + SimplePty::spawn_poller(pty, shared.clone()); + Ok(shared) + } + + pub fn read(&mut self) -> Option { + if self.input.is_some() { + let input = self.input; + self.input = None; + input + } else { + None + } + } + + pub fn write(&mut self, output: u8) -> bool { + self.output.push(output); + true + } + + fn spawn_poller(mut pty: PtyMaster, shared: SharedSimplePty) { + thread::spawn(move || { + println!("pty: spawned reader for {}", shared.lock().unwrap().name); + + let mut buf = [0; 1]; + loop { + { + let mut value = shared.lock().unwrap(); + if value.input.is_none() { + match pty.read(&mut buf) { + Ok(_) => { + (*value).input = Some(buf[0]); + }, + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { }, + Err(err) => { + println!("ERROR: {:?}", err); + } + } + } + + if !value.output.is_empty() { + match pty.write_all(value.output.as_slice()) { + Ok(()) => { }, + _ => panic!(""), + } + (*value).output.clear(); + } + } + + thread::sleep(Duration::from_millis(10)); + } + }); + } +} +