diff --git a/Cargo.lock b/Cargo.lock index bed9eae..1a27790 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -739,6 +739,7 @@ dependencies = [ "log", "pixels", "rfd", + "ringbuf", "vergen", "winit", "winit_input_helper", @@ -1963,6 +1964,15 @@ dependencies = [ "windows", ] +[[package]] +name = "ringbuf" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3064490f4a0c5bc127544803fbc2bb5f77ec5170f0208f2d7b605a4f396d44" +dependencies = [ + "cache-padded", +] + [[package]] name = "rustc-hash" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 0e860c5..a80c11e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ image = "0.24" log = "0.4" pixels = "0.9.0" rfd = "0.7.0" +ringbuf = "0.2" winit = "0.26" winit_input_helper = "0.11" diff --git a/src/bus.rs b/src/bus.rs index a842165..81c4aab 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,12 +1,13 @@ // bus.rs -use crate::{DiskController, Memory, Mouse, Overlay}; +use crate::{DiskController, Keyboard, Memory, Mouse, Overlay}; use std::io::{stdout, Write}; use std::sync::{Arc, Mutex}; pub struct Bus { pub disk_controller: DiskController, + pub keyboard: Arc>, pub memory: Memory, pub mouse: Arc>, pub overlays: Arc>>, @@ -72,17 +73,21 @@ impl Bus { _ => panic!("invalid mouse control port"), } } - 0x80001000..=0x80002200 => { // disk controller port - let address_or_id = (port & 0x00000FFF) as usize; + 0x80000500 => { // keyboard port + let mut keyboard_lock = self.keyboard.lock().expect("failed to lock the keyboard mutex"); + keyboard_lock.pop() as u32 + } + 0x80001000..=0x80002003 => { // disk controller port + let id = port as u8; let operation = (port & 0x0000F000) >> 8; match operation { 0x10 => { // we're reading the current insert state of the specified disk id - if address_or_id > 3 { + if id > 3 { panic!("invalid disk ID"); } - match &self.disk_controller.disk[address_or_id] { + match &self.disk_controller.disk[id as usize] { Some(disk) => disk.size as u32, // return size if this disk is inserted None => 0, // return 0 if this disk is not inserted } @@ -154,19 +159,19 @@ impl Bus { _ => panic!("invalid mouse control port"), } } - 0x80001000..=0x80004200 => { // disk controller port - let address_or_id = (port & 0x00000FFF) as usize; + 0x80001000..=0x80004003 => { // disk controller port + let id = port as u8; let operation = (port & 0x0000F000) >> 8; match operation { 0x10 => { // we're requesting a disk to be inserted to the specified disk id - if address_or_id > 3 { + if id > 3 { panic!("invalid disk ID"); } let file = self.disk_controller.select_file(); match file { - Some(file) => self.disk_controller.insert(file, address_or_id as u8), + Some(file) => self.disk_controller.insert(file, id), None => {}, }; } @@ -176,19 +181,19 @@ impl Bus { } 0x30 => { // we're reading the specified sector of the specified disk id into the memory sector buffer - if address_or_id > 3 { + if id > 3 { panic!("invalid disk ID"); } - self.disk_controller.set_current_sector(address_or_id as u8, word); - self.disk_controller.read_into_memory(address_or_id as u8, self.memory.ram()); + self.disk_controller.set_current_sector(id, word); + self.disk_controller.read_into_memory(id, self.memory.ram()); } 0x40 => { // we're writing the specified sector to the specified disk id from the memory sector buffer - if address_or_id > 3 { + if id > 3 { panic!("invalid disk ID"); } - self.disk_controller.set_current_sector(address_or_id as u8, word); - self.disk_controller.write_from_memory(address_or_id as u8, self.memory.ram()); + self.disk_controller.set_current_sector(id, word); + self.disk_controller.write_from_memory(id, self.memory.ram()); } _ => panic!("invalid disk controller port"), } diff --git a/src/keyboard.rs b/src/keyboard.rs new file mode 100644 index 0000000..f2af456 --- /dev/null +++ b/src/keyboard.rs @@ -0,0 +1,28 @@ +// keyboard.rs + +use crate::warn; + +use ringbuf::{Consumer, Producer, RingBuffer}; + +pub struct Keyboard { + consumer: Consumer, + producer: Producer, +} + +impl Keyboard { + pub fn new() -> Self { + let buffer = RingBuffer::::new(32); + let (producer, consumer) = buffer.split(); + Keyboard { consumer, producer } + } + + pub fn push(&mut self, scancode: u32) { + self.producer.push(scancode).unwrap_or_else(|_| { + warn("keyboard buffer full!"); + }); + } + + pub fn pop(&mut self) -> u32 { + self.consumer.pop().unwrap_or_else(|| 0) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 311368f..bb5a5eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,13 @@ pub mod bus; pub mod cpu; pub mod disk; +pub mod keyboard; pub mod memory; pub mod mouse; use bus::Bus; use cpu::{Cpu, Interrupt}; use disk::DiskController; +use keyboard::Keyboard; use memory::{MEMORY_RAM_START, MEMORY_ROM_START, Memory, MemoryRam}; use mouse::Mouse; @@ -21,7 +23,7 @@ use image; use log::error; use pixels::{Pixels, SurfaceTexture}; use winit::dpi::LogicalSize; -use winit::event::{Event, VirtualKeyCode}; +use winit::event::{ElementState, Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::{WindowBuilder, Icon}; use winit_input_helper::WinitInputHelper; @@ -73,6 +75,7 @@ fn main() { }*/ let mut display = Display::new(); + let keyboard = Arc::new(Mutex::new(Keyboard::new())); let mouse = Arc::new(Mutex::new(Mouse::new())); let memory = Memory::new(read_rom().as_slice()); @@ -90,10 +93,11 @@ fn main() { let rom_top_address = rom_bottom_address + rom_size - 1; println!("ROM: {:.2} KiB mapped at {:#010X}-{:#010X}", rom_size / 1024, rom_bottom_address, rom_top_address); + let bus_keyboard = Arc::clone(&keyboard); let bus_mouse = Arc::clone(&mouse); let bus_overlays = Arc::clone(&display.overlays); let disk_controller = DiskController::new(); - let bus = Bus { disk_controller, memory: memory_cpu, mouse: bus_mouse, overlays: bus_overlays }; + let bus = Bus { disk_controller, keyboard: bus_keyboard, memory: memory_cpu, mouse: bus_mouse, overlays: bus_overlays }; Cpu::new(bus) }; @@ -180,9 +184,21 @@ fn main() { } // handle input events + if let Event::WindowEvent { ref event, .. } = event { + if let WindowEvent::KeyboardInput { input, .. } = event { + let mut keyboard_lock = keyboard.lock().unwrap(); + let mut scancode = input.scancode; + if input.state == ElementState::Released { + scancode |= 0x80; // "break" scancode + } + println!("scancode: {:x}", scancode); + keyboard_lock.push(scancode); + } + } + if input.update(&event) { // close events - if input.key_pressed(VirtualKeyCode::Escape) || input.quit() { + if input.quit() { *control_flow = ControlFlow::Exit; return; }