use serde::{Deserialize, Serialize}; use crate::{Emulator, RandomAccessMemory, processor::interrupts::Interrupt}; pub mod display; pub struct MappedDevice { pub base: u32, pub device: Box, } #[derive(Clone, Copy, Debug, PartialEq)] pub struct IoAccess(u8); impl IoAccess { pub const READ: Self = Self(0b01); pub const WRITE: Self = Self(0b10); /// Convenience alias for Read + Write. pub const READWRITE: Self = Self(Self::READ.0 | Self::WRITE.0); pub const NONE: Self = Self(0); /// Bitwise OR – returns a new `IoAccess` that contains all flags from both operands. #[inline] pub fn or(self, other: Self) -> Self { Self(self.0 | other.0) } /// Check if a flag is present. #[inline] pub fn contains(&self, flag: Self) -> bool { self.0 & flag.0 != 0 } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum DeviceId { Display, Serial, Random, Timer, } /// Trait representing an input/output device that can be mapped into a memory space. /// /// - Default methods return dummy data. pub trait IoDevice: Send { /// Return the size (in bytes) of the device's addressable region. fn size(&self) -> u32; /// Return the access permissions for the device. fn access(&self) -> IoAccess; /// Return the DeviceId fn id(&self) -> DeviceId; #[inline] /// Read a single byte from the specified address. /// /// By default, write‑only devices return `None`. All other devices /// return `Some(0)` as placeholder data. Implementations should override /// this method to provide actual read logic. fn read_byte(&self, offset: u32) -> Result { if self.access().contains(IoAccess::READ) { Ok(0) } else { Err(Interrupt::ReadFromWriteOnly) } } #[inline] /// Write a single byte to the specified address. /// /// By default, read‑only devices return `false` indicating failure. /// All other devices return `true`. Implementations should override /// this method to perform real write operations and return whether /// the operation succeeded. fn write_byte(&mut self, offset: u32, val: u8) -> Result<(), Interrupt> { if self.access().contains(IoAccess::WRITE) { Ok(()) } else { Err(Interrupt::WriteToReadOnly) } } /// Read a 32‑bit word from the specified address in little‑endian order. /// /// The default implementation composes four consecutive byte reads using /// `read_byte`. If any byte read fails, the whole operation returns `None`. /// Write‑only devices return `None` immediately. Override this method for /// more efficient word reads. #[inline] fn read_word(&self, offset: u32) -> Result { if self.access().contains(IoAccess::READ) { // default: compose from bytes let b0 = self.read_byte(offset)? as u32; let b1 = self.read_byte(offset + 1)? as u32; let b2 = self.read_byte(offset + 2)? as u32; let b3 = self.read_byte(offset + 3)? as u32; return Ok(b0 | b1 << 8 | b2 << 16 | b3 << 24); } Err(Interrupt::ReadFromWriteOnly) } /// Write a 32‑bit word to the specified address in little‑endian order. /// /// The default implementation splits the value into bytes and writes each /// using `write_byte`. Read‑only devices return `false`; otherwise returns /// `true` after attempting all byte writes. Override for more efficient /// word writes or to handle partial failures. fn write_word(&mut self, offset: u32, val: u32) -> Result<(), Interrupt> { if self.access().contains(IoAccess::WRITE) { let bytes = val.to_le_bytes(); self.write_byte(offset, bytes[0]); self.write_byte(offset + 1, bytes[1]); self.write_byte(offset + 2, bytes[2]); self.write_byte(offset + 3, bytes[3]); return Ok(()); } Err(Interrupt::WriteToReadOnly) } }