// bus.rs use crate::{Memory, Audio, DiskController, Keyboard, Mouse, Overlay}; use std::sync::{Arc, Mutex}; use std::io::{Write, stdout}; pub struct Bus { pub memory: Memory, pub disk_controller: DiskController, pub audio: Arc>, pub keyboard: Arc>, pub mouse: Arc>, pub overlays: Arc>>, } impl Bus { pub fn read_io(&mut self, port: u32) -> u32 { match port { 0x80000000..=0x8000031F => { // overlay port let overlay_lock = self.overlays.lock().unwrap(); let overlay_number = (port & 0x000000FF) as usize; let setting = (port & 0x0000FF00) >> 8; match setting { 0x00 => { // we're reading the position of this overlay let x = overlay_lock[overlay_number].x as u32; let y = overlay_lock[overlay_number].y as u32; (y << 16) | x } 0x01 => { // we're reading the size of this overlay let width = overlay_lock[overlay_number].width as u32; let height = overlay_lock[overlay_number].height as u32; (height << 16) | width } 0x02 => { // we're reading the framebuffer pointer of this overlay overlay_lock[overlay_number].framebuffer_pointer } 0x03 => { // we're reading the enable status of this overlay overlay_lock[overlay_number].enabled as u32 } _ => panic!("invalid overlay control port"), } } 0x80000400..=0x80000401 => { // mouse port let setting = (port & 0x000000FF) as u8; match setting { 0x00 => { // we're reading the button states let mut byte: u8 = 0x00; let mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); if mouse_lock.clicked { byte |= 0b001; } if mouse_lock.released { byte |= 0b010; } if mouse_lock.held { byte |= 0b100; } else { byte &= !0b100; } byte as u32 } 0x01 => { // we're reading the position let mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); let x = mouse_lock.x as u32; let y = mouse_lock.y as u32; (y << 16) | x } _ => panic!("invalid mouse control port"), } } 0x80000500 => { // keyboard port let mut keyboard_lock = self.keyboard.lock().expect("failed to lock the keyboard mutex"); keyboard_lock.pop() as u32 } 0x80000600 => { // audio port let audio_lock = self.audio.lock().unwrap(); audio_lock.playing 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 id > 3 { panic!("invalid disk ID"); } match &self.disk_controller.disk[id as usize] { Some(_) => self.disk_controller.get_size(id) as u32, // return size if this disk is inserted None => 0, // return 0 if this disk is not inserted } } 0x20 => { // we're getting the location of the memory sector buffer self.disk_controller.buffer_pointer as u32 } _ => panic!("invalid disk controller port"), } } _ => 0, } } pub fn write_io(&mut self, port: u32, word: u32) { match port { 0x00000000 => { // terminal output port print!("{}", word as u8 as char); stdout().flush().expect("could not flush stdout"); } 0x80000000..=0x8000031F => { // overlay port let mut overlay_lock = self.overlays.lock().unwrap(); let overlay_number = (port & 0x000000FF) as usize; let setting = (port & 0x0000FF00) >> 8; match setting { 0x00 => { // we're setting the position of this overlay let x = (word & 0x0000FFFF) as usize; let y = ((word & 0xFFFF0000) >> 16) as usize; overlay_lock[overlay_number].x = x; overlay_lock[overlay_number].y = y; } 0x01 => { // we're setting the size of this overlay let width = (word & 0x0000FFFF) as usize; let height = ((word & 0xFFFF0000) >> 16) as usize; overlay_lock[overlay_number].width = width; overlay_lock[overlay_number].height = height; } 0x02 => { // we're setting the framebuffer pointer of this overlay overlay_lock[overlay_number].framebuffer_pointer = word; } 0x03 => { // we're setting the enable status of this overlay overlay_lock[overlay_number].enabled = word != 0; } _ => panic!("invalid overlay control port"), } } 0x80000400..=0x80000401 => { // mouse port let setting = (port & 0x000000FF) as u8; match setting { 0x00 => { // we're setting the button states let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); mouse_lock.clicked = word & (1 << 0) != 0; mouse_lock.released = word & (1 << 1) != 0; mouse_lock.held = word & (1 << 2) != 0; } 0x01 => { // we're setting the position let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); let x = (word & 0x0000FFFF) as u16; let y = ((word & 0xFFFF0000) >> 16) as u16; mouse_lock.x = x; mouse_lock.y = y; } _ => panic!("invalid mouse control port"), } } 0x80000600 => { // audio port let mut audio_lock = self.audio.lock().unwrap(); audio_lock.playing = word != 0; audio_lock.current_buffer_is_0 = false; // the first buffer refill interrupt will invert this to true } 0x80001000..=0x80005003 => { // 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 id > 3 { panic!("invalid disk ID"); } let file = self.disk_controller.select_file(); match file { Some(file) => self.disk_controller.insert(file, id), None => {}, }; } 0x20 => { // we're setting the location of the memory sector buffer self.disk_controller.buffer_pointer = word as usize; } 0x30 => { // we're reading the specified sector of the specified disk id into the memory sector buffer if id > 3 { panic!("invalid disk ID"); } 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 id > 3 { panic!("invalid disk ID"); } self.disk_controller.set_current_sector(id, word); self.disk_controller.write_from_memory(id, self.memory.ram()); } 0x50 => { // we're requesting a disk to be removed from the specified disk id if id > 3 { panic!("invalid disk ID"); } self.disk_controller.remove(id); } _ => panic!("invalid disk controller port"), } } _ => return, } } }