From 77067f6e244a9cf4a6ef59df2e3d735b4f172c35 Mon Sep 17 00:00:00 2001
From: Ben Bridle <bridle.benjamin@gmail.com>
Date: Sun, 24 Dec 2023 22:19:11 +1300
Subject: First commit

---
 src/devices.rs | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 339 insertions(+)
 create mode 100644 src/devices.rs

(limited to 'src/devices.rs')

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;
+
+    }
+}
-- 
cgit v1.2.3-70-g09d2