From ad9f55ba93663c0ae92c0f8c0698c053e9568a19 Mon Sep 17 00:00:00 2001 From: Ravi Nanavati Date: Thu, 6 Apr 2023 12:19:11 -0700 Subject: [PATCH] Change the dummy terminal to a "raw" terminal that attempts to pass on input. --- cli/src/dummy_terminal.rs | 44 -------------------------- cli/src/main.rs | 16 +++++----- cli/src/raw_terminal.rs | 66 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 52 deletions(-) delete mode 100644 cli/src/dummy_terminal.rs create mode 100644 cli/src/raw_terminal.rs diff --git a/cli/src/dummy_terminal.rs b/cli/src/dummy_terminal.rs deleted file mode 100644 index fa5c13a..0000000 --- a/cli/src/dummy_terminal.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::str; -use std::io::{stdout, Write}; - -use riscv_emu_rust::terminal::Terminal; - -/// Dummy `Terminal`. Output will be displayed in command line -/// and input will not be handled. -pub struct DummyTerminal { -} - -impl DummyTerminal { - pub fn new() -> Self { - DummyTerminal { - } - } -} - -impl Terminal for DummyTerminal { - fn put_byte(&mut self, value: u8) { - let str = vec![value]; - match str::from_utf8(&str) { - Ok(s) => { - print!("{}", s); - }, - Err(_e) => {} - }; - match stdout().flush() { - _ => {} // Ignoring error so far - }; - } - - fn get_input(&mut self) -> u8 { - 0 - } - - // Wasm specific methods. No use. - - fn put_input(&mut self, _value: u8) { - } - - fn get_output(&mut self) -> u8 { - 0 - } -} diff --git a/cli/src/main.rs b/cli/src/main.rs index f263362..081122f 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -2,13 +2,13 @@ extern crate getopts; extern crate riscv_emu_rust; mod popup_terminal; -mod dummy_terminal; +mod raw_terminal; use riscv_emu_rust::Emulator; use riscv_emu_rust::cpu::Xlen; use riscv_emu_rust::terminal::Terminal; use popup_terminal::PopupTerminal; -use dummy_terminal::DummyTerminal; +use raw_terminal::RawTerminal; use std::env; use std::fs::File; @@ -18,7 +18,7 @@ use getopts::Options; enum TerminalType { PopupTerminal, - DummyTerminal + RawTerminal, } fn print_usage(program: &str, opts: Options) { @@ -29,7 +29,7 @@ fn print_usage(program: &str, opts: Options) { fn get_terminal(terminal_type: TerminalType) -> Box { match terminal_type { TerminalType::PopupTerminal => Box::new(PopupTerminal::new()), - TerminalType::DummyTerminal => Box::new(DummyTerminal::new()), + TerminalType::RawTerminal => Box::new(RawTerminal::new()), } } @@ -41,7 +41,7 @@ fn main () -> std::io::Result<()> { opts.optopt("x", "xlen", "Set bit mode. Default is auto detect from elf file", "32|64"); opts.optopt("f", "fs", "File system image file", "xv6/fs.img"); opts.optopt("d", "dtb", "Device tree file", "linux/dtb"); - opts.optflag("n", "no_terminal", "No popup terminal"); + opts.optflag("r", "raw_terminal", "Use a raw terminal"); opts.optflag("h", "help", "Show this help menu"); opts.optflag("p", "page_cache", "Enable experimental page cache optimization"); @@ -93,10 +93,10 @@ fn main () -> std::io::Result<()> { let mut elf_contents = vec![]; elf_file.read_to_end(&mut elf_contents)?; - let terminal_type = match matches.opt_present("n") { + let terminal_type = match matches.opt_present("r") { true => { - println!("No popup terminal mode. Output will be flushed on your terminal but you can not input."); - TerminalType::DummyTerminal + println!("Raw terminal mode."); + TerminalType::RawTerminal }, false => TerminalType::PopupTerminal }; diff --git a/cli/src/raw_terminal.rs b/cli/src/raw_terminal.rs new file mode 100644 index 0000000..b0532f8 --- /dev/null +++ b/cli/src/raw_terminal.rs @@ -0,0 +1,66 @@ +use std::str; +use std::io::{stdin, stdout, Read, Write}; +use std::sync::mpsc; +use std::sync::mpsc::Receiver; +use std::thread; + +use riscv_emu_rust::terminal::Terminal; + +/// Raw `Terminal`. Output will be displayed in command line +/// and input will be read character-by-character from stdin +/// in a separate thread. +pub struct RawTerminal { + rx_input: Receiver, +} + +impl RawTerminal { + pub fn new() -> Self { + let (tx_input, rx_input) = mpsc::channel::(); + thread::spawn(move || loop { + let mut buf = [0; 1]; + if let Ok(n) = stdin().read(&mut buf) { + if n > 1 { + panic!("Read {} characters into a 1 byte buffer", n); + } + if n == 1 { + tx_input.send(buf[0]).unwrap(); + } + // Nothing needs to be sent for n == 0 + } + }); + RawTerminal { + rx_input, + } + } +} + +impl Terminal for RawTerminal { + fn put_byte(&mut self, value: u8) { + let str = vec![value]; + match str::from_utf8(&str) { + Ok(s) => { + print!("{}", s); + }, + Err(_e) => {} + }; + match stdout().flush() { + _ => {} // Ignoring error so far + }; + } + + fn get_input(&mut self) -> u8 { + match self.rx_input.try_recv() { + Ok(c) => return c, + _ => return 0, + } + } + + // Wasm specific methods. No use. + + fn put_input(&mut self, _value: u8) { + } + + fn get_output(&mut self) -> u8 { + 0 + } +}