lc3_ensemble/sim/device/
keyboard.rs

1use std::collections::VecDeque;
2use std::sync::{Arc, RwLock, RwLockWriteGuard, TryLockError};
3
4use super::{DevWrapper, ExternalDevice, Interrupt, KBDR, KBSR, KB_INTP, KB_INTV};
5
6/// Scaffolding needed to implement [`ExternalDevice`] for keyboard devices.
7trait KeyboardDevice: Send + Sync + 'static {
8    /// State of interrupt enabled.
9    fn interrupts_enabled(&self) -> bool;
10    /// Sets interrupt enabled.
11    fn set_interrupts_enabled(&mut self, value: bool);
12
13    /// Whether the keyboard has input to take.
14    fn ready(&self) -> bool;
15    /// Reads a character from the input (but does not take it).
16    fn get_input(&self) -> Option<u8>;
17    /// Reads and removes a character from the input.
18    fn pop_input(&mut self) -> Option<u8>;
19    /// Clears the input completely.
20    fn clear_input(&mut self);
21}
22
23impl<K: KeyboardDevice> ExternalDevice for DevWrapper<K, dyn KeyboardDevice> {
24    fn io_read(&mut self, addr: u16, effectful: bool) -> Option<u16> {
25        match addr {
26            KBSR => {
27                Some((u16::from(self.ready()) << 15) | (u16::from(self.interrupts_enabled()) << 14))
28            },
29            KBDR if effectful => self.pop_input().map(u16::from),
30            KBDR => self.get_input().map(u16::from),
31            _ => None
32        }
33    }
34
35    fn io_write(&mut self, addr: u16, data: u16) -> bool {
36        match addr {
37            KBSR => {
38                let ie = (data >> 14) & 1 != 0;
39                self.set_interrupts_enabled(ie);
40                true
41            },
42            _ => false
43        }
44    }
45    
46    fn io_reset(&mut self) {
47        self.clear_input();
48        self.set_interrupts_enabled(false);
49    }
50
51    fn poll_interrupt(&mut self) -> Option<Interrupt> {
52        match self.ready() && self.interrupts_enabled() {
53            true  => Some(Interrupt::vectored(KB_INTV, KB_INTP)),
54            false => None,
55        }
56    }
57}
58
59/// Keyboard that accesses input from a memory buffer.
60#[derive(Default, Clone)]
61pub struct BufferedKeyboard {
62    buffer: Arc<RwLock<VecDeque<u8>>>,
63    interrupts_enabled: bool
64}
65impl BufferedKeyboard {
66    /// Creates a new keyboard, wrapping it around a given buffer.
67    pub fn new(buffer: Arc<RwLock<VecDeque<u8>>>) -> Self {
68        Self { buffer, interrupts_enabled: false }
69    }
70
71    /// Gets a reference to the internal buffer of this keyboard.
72    pub fn get_buffer(&self) -> &Arc<RwLock<VecDeque<u8>>> {
73        &self.buffer
74    }
75    
76    fn try_input(&self) -> Option<RwLockWriteGuard<'_, VecDeque<u8>>> {
77        match self.buffer.try_write() {
78            Ok(g) => Some(g),
79            Err(TryLockError::Poisoned(e)) => Some(e.into_inner()),
80            Err(TryLockError::WouldBlock) => None,
81        }
82    }
83}
84impl KeyboardDevice for BufferedKeyboard {
85    fn interrupts_enabled(&self) -> bool {
86        self.interrupts_enabled
87    }
88
89    fn set_interrupts_enabled(&mut self, value: bool) {
90        self.interrupts_enabled = value;
91    }
92
93    fn ready(&self) -> bool {
94        self.try_input().is_some_and(|buf| !buf.is_empty())
95    }
96
97    fn get_input(&self) -> Option<u8> {
98        self.try_input()?.front().copied()
99    }
100
101    fn pop_input(&mut self) -> Option<u8> {
102        self.try_input()?.pop_front()
103    }
104    
105    fn clear_input(&mut self) {
106        if let Some(mut inp) = self.try_input() {
107            inp.clear();
108        }
109    }
110}
111impl ExternalDevice for BufferedKeyboard {
112    fn io_read(&mut self, addr: u16, effectful: bool) -> Option<u16> {
113        DevWrapper::wrap(self).io_read(addr, effectful)
114    }
115
116    fn io_write(&mut self, addr: u16, data: u16) -> bool {
117        DevWrapper::wrap(self).io_write(addr, data)
118    }
119
120    fn io_reset(&mut self) {
121        DevWrapper::wrap(self).io_reset()
122    }
123    
124    fn poll_interrupt(&mut self) -> Option<Interrupt> {
125        DevWrapper::wrap(self).poll_interrupt()
126    }
127    
128    fn _to_sim_device(self, _: super::internals::ToSimDeviceToken) -> super::internals::SimDevice
129        where Self: Sized
130    {
131        super::internals::SimDevice::Keyboard(self)
132    }
133}