From ab84ad75629b0a4124221023ca91411d2cd62a32 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Tue, 25 Mar 2025 12:46:49 +1300 Subject: Restructure program This commit also includes changes to devices according to the latest devices specification, in particular the math and system devices. --- src/devices/local_device.rs | 227 -------------------------------------------- 1 file changed, 227 deletions(-) delete mode 100644 src/devices/local_device.rs (limited to 'src/devices/local_device.rs') diff --git a/src/devices/local_device.rs b/src/devices/local_device.rs deleted file mode 100644 index c6456de..0000000 --- a/src/devices/local_device.rs +++ /dev/null @@ -1,227 +0,0 @@ -use crate::*; - -use bedrock_core::*; - -use std::collections::VecDeque; -use std::io::{BufRead, Stdout, Write}; -use std::sync::mpsc::{self, TryRecvError}; - - -pub struct LocalDevice { - wake: bool, - - stdin_connected: bool, - stdin_control: bool, - stdin_rx: mpsc::Receiver>, - stdin_queue: VecDeque, - stdin_excess: VecDeque, - stdout: Stdout, - - stdout_connected: bool, - - decode_stdin: bool, - encode_stdout: bool, - decode_buffer: Option, -} - -impl LocalDevice { - pub fn new(config: &EmulatorConfig) -> Self { - // Fill input queue with initial transmission. - let mut stdin_queue = VecDeque::new(); - if let Some(bytes) = &config.initial_transmission { - for byte in bytes { stdin_queue.push_front(*byte) } - } - // Spawn a thread to enable non-blocking reads of stdin. - let (stdin_tx, stdin_rx) = std::sync::mpsc::channel(); - std::thread::spawn(move || loop { - let mut stdin = std::io::stdin().lock(); - match stdin.fill_buf() { - Ok(buf) if !buf.is_empty() => { - let length = buf.len(); - stdin_tx.send(buf.to_vec()).unwrap(); - stdin.consume(length); - } - _ => break, - }; - }); - - Self { - wake: true, - - stdin_connected: true, - stdin_control: false, - stdin_rx, - stdin_queue, - stdin_excess: VecDeque::new(), - stdout: std::io::stdout(), - - stdout_connected: true, - - decode_stdin: config.decode_stdin, - encode_stdout: config.encode_stdout, - decode_buffer: None, - } - } - - pub fn stdin_length(&mut self) -> u8 { - self.fetch_stdin_data(); - self.stdin_queue.len().try_into().unwrap_or(u8::MAX) - } - - pub fn stdin_enable(&mut self) { - self.stdin_control = true; - } - - pub fn stdin_read(&mut self) -> u8 { - self.fetch_stdin_data(); - self.stdin_queue.pop_front().unwrap_or(0) - } - - pub fn stdout_write(&mut self, value: u8) { - macro_rules! hex { - ($value:expr) => { match $value { - 0x0..=0x9 => $value + b'0', - 0xa..=0xf => $value - 0x0a + b'a', - _ => unreachable!("Cannot encode value as hex digit: 0x{:02x}", $value), - } }; - } - if self.encode_stdout { - let encoded = [hex!(value >> 4), hex!(value & 0xf), b' ']; - self.stdout_write_raw(&encoded); - } else { - self.stdout_write_raw(&[value]); - }; - } - - fn stdout_write_raw(&mut self, bytes: &[u8]) { - if let Err(_) = self.stdout.write_all(bytes) { - if self.stdout_connected { - self.stdout_connected = false; - self.wake = true; // wake because stdout was disconnected. - } - } - } - - pub fn stdout_disable(&mut self) { - if self.encode_stdout { - self.stdout_write_raw(&[b'\n']); - } - } - - pub fn fetch_stdin_data(&mut self) { - while self.stdin_control { - match self.stdin_excess.pop_front() { - Some(byte) => self.fetch_byte(byte), - None => break, - } - } - match self.stdin_rx.try_recv() { - Ok(tx) => { - for byte in tx { - match self.stdin_control { - true => self.fetch_byte(byte), - false => self.stdin_excess.push_back(byte), - } - } - } - Err(TryRecvError::Empty) => (), - Err(TryRecvError::Disconnected) => { - self.stdin_control = false; - if self.stdin_connected { - self.stdin_connected = false; - self.wake = true; // wake because stdin was disconnected. - } - } - } - } - - fn fetch_byte(&mut self, byte: u8) { - if self.decode_stdin { - let decoded = match byte { - b'0'..=b'9' => byte - b'0', - b'a'..=b'f' => byte - b'a' + 0x0a, - b'A'..=b'F' => byte - b'A' + 0x0a, - b'\n' => { - self.decode_buffer = None; - self.stdin_control = false; - self.wake = true; // wake because a transmission ended. - return; - }, - _ => return, - }; - if let Some(high) = std::mem::take(&mut self.decode_buffer) { - self.stdin_queue.push_back((high << 4) | decoded); - self.wake = true; // wake because a byte was received. - } else { - self.decode_buffer = Some(decoded); - } - } else { - self.stdin_queue.push_back(byte); - self.wake = true; // wake because a byte was received. - } - } - - pub fn flush(&mut self) { - let _ = self.stdout.flush(); - } -} - - -impl Drop for LocalDevice { - fn drop(&mut self) { - self.flush(); - } -} - - -impl Device for LocalDevice { - fn read(&mut self, port: u8) -> u8 { - match port { - 0x0 => read_b!(self.stdin_connected), - 0x1 => 0xff, - 0x2 => read_b!(self.stdin_control), - 0x3 => 0xff, - 0x4 => self.stdin_length(), - 0x5 => 0xff, - 0x6 => self.stdin_read(), - 0x7 => self.stdin_read(), - 0x8 => todo!(), - 0x9 => todo!(), - 0xa => todo!(), - 0xb => todo!(), - 0xc => todo!(), - 0xd => todo!(), - 0xe => todo!(), - 0xf => todo!(), - _ => unreachable!(), - } - } - - fn write(&mut self, port: u8, value: u8) -> Option { - match port { - 0x0 => (), - 0x1 => (), - 0x2 => self.stdin_enable(), - 0x3 => self.stdout_disable(), - 0x4 => self.stdin_queue.clear(), - 0x5 => (), - 0x6 => self.stdout_write(value), - 0x7 => self.stdout_write(value), - 0x8 => todo!(), - 0x9 => todo!(), - 0xa => todo!(), - 0xb => todo!(), - 0xc => todo!(), - 0xd => todo!(), - 0xe => todo!(), - 0xf => todo!(), - _ => unreachable!(), - }; - return None; - } - - fn wake(&mut self) -> bool { - self.fetch_stdin_data(); - std::mem::take(&mut self.wake) - } -} -- cgit v1.2.3-70-g09d2