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
This commit is contained in:
transistor 2021-10-16 16:11:50 -07:00
parent 853626584e
commit 93c9307829
4 changed files with 110 additions and 30 deletions

View File

@ -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,

View File

@ -4,6 +4,7 @@ mod error;
mod memory;
mod timers;
mod devices;
mod ttys;
mod interrupts;
mod cpus;
mod peripherals;

View File

@ -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<PtyMaster>,
pub tty: Option<SharedSimplePty>,
pub status: u8,
pub tx_enabled: bool,
@ -100,21 +94,15 @@ impl MC68681Port {
}
pub fn open(&mut self) -> Result<String, Error> {
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<bool, Error> {
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)

95
src/ttys.rs Normal file
View File

@ -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<u8>,
output: Vec<u8>,
}
pub type SharedSimplePty = Arc<Mutex<SimplePty>>;
impl SimplePty {
pub fn new_shared(name: String) -> SharedSimplePty {
Arc::new(Mutex::new(SimplePty {
name,
input: None,
output: vec![],
}))
}
pub fn open() -> Result<SharedSimplePty, Error> {
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<u8> {
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));
}
});
}
}