fox32: Start implementing keyboard input support

This commit is contained in:
Ry 2022-03-18 21:36:44 -07:00
parent 22c7b26317
commit 1f89b59f83
5 changed files with 78 additions and 18 deletions

10
Cargo.lock generated
View File

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

View File

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

View File

@ -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<Mutex<Keyboard>>,
pub memory: Memory,
pub mouse: Arc<Mutex<Mouse>>,
pub overlays: Arc<Mutex<Vec<Overlay>>>,
@ -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"),
}

28
src/keyboard.rs Normal file
View File

@ -0,0 +1,28 @@
// keyboard.rs
use crate::warn;
use ringbuf::{Consumer, Producer, RingBuffer};
pub struct Keyboard {
consumer: Consumer<u32>,
producer: Producer<u32>,
}
impl Keyboard {
pub fn new() -> Self {
let buffer = RingBuffer::<u32>::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)
}
}

View File

@ -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;
}