diff options
Diffstat (limited to 'src/devices.rs')
-rw-r--r-- | src/devices.rs | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/src/devices.rs b/src/devices.rs new file mode 100644 index 0000000..562b664 --- /dev/null +++ b/src/devices.rs @@ -0,0 +1,339 @@ +use bedrock_core::*; + +mod math; +mod clock; +mod input; +mod screen; +mod scratch; +mod stream; +mod file; + +pub use math::*; +pub use clock::*; +pub use input::*; +pub use screen::*; +pub use scratch::*; +pub use stream::*; +pub use file::*; + +pub struct StandardDevices { + pub math: MathDevice, + pub clock: ClockDevice, + pub input: InputDevice, + pub screen: ScreenDevice, + pub scratch: ScratchDevice, + pub stream: StreamDevice, + pub file: FileDevice, + + pub wake_mask: u16, + pub wake_device: u8, +} + +impl StandardDevices { + pub fn new() -> Self { + let mut screen = ScreenDevice::new(); + screen.resize(ScreenDimensions::new(256, 192)); + + Self { + math: MathDevice::new(), + clock: ClockDevice::new(), + input: InputDevice::new(), + screen, + scratch: ScratchDevice::new(), + stream: StreamDevice::new(), + file: FileDevice::new(), + + wake_mask: 0x0000, + wake_device: 0x00, + } + } + + pub fn can_wake(&mut self) -> bool { + macro_rules! test_wake { + ($flag:expr, $mask:expr, $index:expr) => { + if $flag && self.wake_mask & $mask != 0 { + $flag = false; self.wake_device = $index; return true; + } + }; + } + self.clock.update_timer_1(); + self.clock.update_timer_2(); + self.clock.update_timer_3(); + self.clock.update_timer_4(); + test_wake!(self.clock.wake_flag, 0x1000, 0x03); + test_wake!(self.input.wake_flag, 0x0800, 0x04); + test_wake!(self.screen.wake_flag, 0x0400, 0x05); + test_wake!(self.stream.wake_flag, 0x0040, 0x09); + return false; + } +} + +impl DeviceBus for StandardDevices { + fn read_u8(&mut self, port: u8) -> u8 { + macro_rules! read_hh { ($v:expr) => { ($v>>24) as u8 }; } + macro_rules! read_hl { ($v:expr) => { ($v>>16) as u8 }; } + macro_rules! read_lh { ($v:expr) => { ($v>>8) as u8 }; } + macro_rules! read_ll { ($v:expr) => { $v as u8 }; } + macro_rules! read_h { ($v:expr) => { ($v>>8) as u8 }; } + macro_rules! read_l { ($v:expr) => { $v as u8 }; } + macro_rules! read_b { ($b:expr) => { if $b { 0xff } else { 0x00 } }; } + + macro_rules! no_read { () => { 0x00 }; } + + match port { + // System + 0x00 => no_read!(), + 0x01 => no_read!(), + 0x02 => self.wake_device, + 0x03 => no_read!(), + 0x04 => no_read!(), + 0x05 => no_read!(), + 0x06 => no_read!(), + 0x07 => no_read!(), + 0x08 => 0xFF, + 0x09 => 0xFF, + 0x0A => 0xFF, + 0x0B => 0xFF, + 0x0C => 0xBC, + 0x0D => 0x80, + 0x0E => 0xBC, + 0x0F => 0x80, + // Math + 0x20 => no_read!(), + 0x21 => no_read!(), + 0x22 => no_read!(), + 0x23 => no_read!(), + 0x24 => no_read!(), + 0x25 => no_read!(), + 0x26 => no_read!(), + 0x27 => no_read!(), + 0x28 => { self.math.multiply(); read_h!(self.math.product_high) }, + 0x29 => { self.math.multiply(); read_l!(self.math.product_high) }, + 0x2A => { self.math.multiply(); read_h!(self.math.product_low) }, + 0x2B => { self.math.multiply(); read_l!(self.math.product_low) }, + 0x2C => { self.math.divide(); read_h!(self.math.quotient) }, + 0x2D => { self.math.divide(); read_l!(self.math.quotient) }, + 0x2E => { self.math.modulo(); read_h!(self.math.remainder) }, + 0x2F => { self.math.modulo(); read_l!(self.math.remainder) }, + // Clock + 0x30 => self.clock.year(), + 0x31 => self.clock.month(), + 0x32 => self.clock.day(), + 0x33 => self.clock.hour(), + 0x34 => self.clock.minute(), + 0x35 => self.clock.second(), + 0x36 => { self.clock.update_cumulative_seconds(); read_h!(self.clock.cumulative_seconds) }, + 0x37 => read_l!(self.clock.cumulative_seconds), + 0x38 => { self.clock.update_timer_1(); read_h!(self.clock.timer_1) } + 0x39 => read_l!(self.clock.timer_1), + 0x3A => { self.clock.update_timer_2(); read_h!(self.clock.timer_2) } + 0x3B => read_l!(self.clock.timer_2), + 0x3C => { self.clock.update_timer_3(); read_h!(self.clock.timer_3) } + 0x3D => read_l!(self.clock.timer_3), + 0x3E => { self.clock.update_timer_4(); read_h!(self.clock.timer_4) } + 0x3F => read_l!(self.clock.timer_4), + // Input + 0x40 => read_h!(self.input.mouse_position.x), + 0x41 => read_l!(self.input.mouse_position.x), + 0x42 => read_h!(self.input.mouse_position.y), + 0x43 => read_l!(self.input.mouse_position.y), + 0x44 => read_h!(self.input.horizontal_scroll_value), + 0x45 => read_l!(self.input.horizontal_scroll_value), + 0x46 => read_h!(self.input.vertical_scroll_value), + 0x47 => read_l!(self.input.vertical_scroll_value), + 0x48 => self.input.character_queue.pop_front().unwrap_or(0), + 0x49 => self.input.modifier_state, + 0x4A => self.input.mouse_button_state, + 0x4B => self.input.navigation_state, + // Screen + 0x50 => read_h!(self.screen.dimensions.width), + 0x51 => read_l!(self.screen.dimensions.width), + 0x52 => read_h!(self.screen.dimensions.height), + 0x53 => read_l!(self.screen.dimensions.height), + 0x54 => read_h!(self.screen.cursor.x), + 0x55 => read_l!(self.screen.cursor.x), + 0x56 => read_h!(self.screen.cursor.y), + 0x57 => read_l!(self.screen.cursor.y), + 0x58 => no_read!(), + 0x59 => no_read!(), + 0x5A => no_read!(), + 0x5B => no_read!(), + 0x5C => no_read!(), + 0x5D => no_read!(), + 0x5E => no_read!(), + 0x5F => no_read!(), + // Scratch + 0x80 => no_read!(), + 0x81 => no_read!(), + 0x82 => no_read!(), + 0x83 => no_read!(), + 0x84 => no_read!(), + 0x85 => no_read!(), + 0x86 => no_read!(), + 0x87 => no_read!(), + 0x88 => self.scratch.read_head_1(), + 0x89 => self.scratch.read_head_1(), + 0x8A => self.scratch.read_head_2(), + 0x8B => self.scratch.read_head_2(), + 0x8C => read_hh!(self.scratch.max_capacity), + 0x8D => read_hl!(self.scratch.max_capacity), + 0x8E => read_lh!(self.scratch.max_capacity), + 0x8F => read_ll!(self.scratch.max_capacity), + // Stream + // File + 0xA0 => read_b!(self.file.file.is_some()), + 0xA1 => read_b!(self.file.operation_state), + 0xA2 => no_read!(), + 0xA3 => no_read!(), + 0xA4 => read_hh!(self.file.pointer), + 0xA5 => read_hl!(self.file.pointer), + 0xA6 => read_lh!(self.file.pointer), + 0xA7 => read_ll!(self.file.pointer), + 0xA8 => self.file.read(), + 0xA9 => self.file.read(), + 0xAA => no_read!(), + 0xAB => no_read!(), + 0xAC => read_hh!(self.file.file_size), + 0xAD => read_hl!(self.file.file_size), + 0xAE => read_lh!(self.file.file_size), + 0xAF => read_ll!(self.file.file_size), + + _ => unimplemented!("Reading from device port 0x{port:02x}"), + } + } + + fn write_u8(&mut self, val: u8, port: u8) -> Option<Signal> { + + macro_rules! write_hh { ($v:expr) => { $v = $v & 0x00ffffff | ((val as u32) << 24) }; } + macro_rules! write_hl { ($v:expr) => { $v = $v & 0xff00ffff | ((val as u32) << 16) }; } + macro_rules! write_lh { ($v:expr) => { $v = $v & 0x00ff | ((val as u32) << 8) }; } + macro_rules! write_ll { ($v:expr) => { $v = $v & 0xff00 | (val as u32) }; } + macro_rules! write_h { ($v:expr) => { $v = $v & 0x00ff | ((val as u16) << 8) }; } + macro_rules! write_l { ($v:expr) => { $v = $v & 0xff00 | (val as u16) }; } + + macro_rules! no_write { () => { () }; } + + match port { + // System + 0x00 => write_h!(self.wake_mask), + 0x01 => { write_l!(self.wake_mask); return Some(Signal::Pause) }, + 0x02 => no_write!(), + 0x03 => no_write!(), + 0x04 => no_write!(), + 0x05 => no_write!(), + 0x06 => no_write!(), + 0x07 => no_write!(), + 0x08 => no_write!(), + 0x09 => no_write!(), + 0x0A => no_write!(), + 0x0B => no_write!(), + 0x0C => no_write!(), + 0x0D => no_write!(), + 0x0E => no_write!(), + 0x0F => no_write!(), + // Math + 0x20 => write_h!(self.math.operand_1), + 0x21 => write_l!(self.math.operand_1), + 0x22 => write_h!(self.math.operand_2), + 0x23 => write_l!(self.math.operand_2), + 0x24 => no_write!(), + 0x25 => no_write!(), + 0x26 => no_write!(), + 0x27 => no_write!(), + 0x28 => no_write!(), + 0x29 => no_write!(), + 0x2A => no_write!(), + 0x2B => no_write!(), + 0x2C => no_write!(), + 0x2D => no_write!(), + 0x2E => no_write!(), + 0x2F => no_write!(), + // Clock + 0x38 => write_h!(self.clock.timer_1), + 0x39 => { write_l!(self.clock.timer_1); self.clock.set_timer_1() }, + 0x3A => write_h!(self.clock.timer_2), + 0x3B => { write_l!(self.clock.timer_2); self.clock.set_timer_2() }, + 0x3C => write_h!(self.clock.timer_3), + 0x3D => { write_l!(self.clock.timer_3); self.clock.set_timer_3() }, + 0x3E => write_h!(self.clock.timer_4), + 0x3F => { write_l!(self.clock.timer_4); self.clock.set_timer_4() }, + // Input + 0x40 => no_write!(), + 0x41 => no_write!(), + 0x42 => no_write!(), + 0x43 => no_write!(), + 0x44 => no_write!(), + 0x45 => no_write!(), + 0x46 => no_write!(), + 0x47 => no_write!(), + 0x48 => self.input.character_queue.clear(), + 0x49 => no_write!(), + 0x4A => no_write!(), + 0x4B => no_write!(), + 0x4C => no_write!(), + 0x4D => no_write!(), + 0x4E => no_write!(), + 0x4F => no_write!(), + // Screen + 0x50 => write_h!(self.screen.dimensions.width), + 0x51 => { write_l!(self.screen.dimensions.width); self.screen.set_size(self.screen.dimensions) }, + 0x52 => write_h!(self.screen.dimensions.height), + 0x53 => { write_l!(self.screen.dimensions.height); self.screen.set_size(self.screen.dimensions) }, + 0x54 => write_h!(self.screen.cursor.x), + 0x55 => write_l!(self.screen.cursor.x), + 0x56 => write_h!(self.screen.cursor.y), + 0x57 => write_l!(self.screen.cursor.y), + 0x58 => self.screen.draw(val), + 0x59 => self.screen.shunt(val), + 0x5A => self.screen.sprite_data.push(val), + 0x5B => self.screen.sprite_data.push(val), + 0x5C => self.screen.set_palette_high(val), + 0x5D => self.screen.set_palette_low(val), + 0x5E => self.screen.set_sprite_colour_high(val), + 0x5F => self.screen.set_sprite_colour_low(val), + // Scratch + 0x80 => write_hh!(self.scratch.pointer_1), + 0x81 => write_hl!(self.scratch.pointer_1), + 0x82 => write_lh!(self.scratch.pointer_1), + 0x83 => write_ll!(self.scratch.pointer_1), + 0x84 => write_hh!(self.scratch.pointer_2), + 0x85 => write_hl!(self.scratch.pointer_2), + 0x86 => write_lh!(self.scratch.pointer_2), + 0x87 => write_ll!(self.scratch.pointer_2), + 0x88 => self.scratch.write_head_1(val), + 0x89 => self.scratch.write_head_1(val), + 0x8A => self.scratch.write_head_2(val), + 0x8B => self.scratch.write_head_2(val), + 0x8C => no_write!(), + 0x8D => no_write!(), + 0x8E => no_write!(), + 0x8F => no_write!(), + // File + 0xA0 => self.file.push_name_byte(val), + 0xA1 => no_write!(), + 0xA2 => no_write!(), + 0xA3 => no_write!(), + 0xA4 => write_hh!(self.file.pointer), + 0xA5 => write_hl!(self.file.pointer), + 0xA6 => write_lh!(self.file.pointer), + 0xA7 => write_ll!(self.file.pointer), + 0xA8 => no_write!(), + 0xA9 => no_write!(), + 0xAA => no_write!(), + 0xAB => no_write!(), + 0xAC => write_hh!(self.file.file_size), + 0xAD => write_hl!(self.file.file_size), + 0xAE => write_lh!(self.file.file_size), + 0xAF => { write_ll!(self.file.file_size); self.file.set_file_size() }, + + // Bytestreams + 0x96 => self.stream.write_stdout(val), + 0x97 => self.stream.write_stdout(val), + + _ => unimplemented!("Writing to device port 0x{port:02x}"), + }; + + return None; + + } +} |