use std::sync::{ Arc, atomic::{AtomicBool, AtomicU8, Ordering}, }; use crate::{ io::{IoAccess, IoDevice}, processor::interrupts::Interrupt, }; pub struct DisplayDevice { buffer: Arc>, dirty: Arc, } impl DisplayDevice { pub fn new(width: usize, height: usize) -> (Self, DisplayHandle) { let buffer = Arc::new( (0..width * height) .map(|_| AtomicU8::new(0)) .collect::>() .into_boxed_slice(), ); let dirty = Arc::new(AtomicBool::new(false)); let handle = DisplayHandle { buffer: Arc::clone(&buffer), dirty: Arc::clone(&dirty), }; (Self { buffer, dirty }, handle) } } impl IoDevice for DisplayDevice { fn size(&self) -> u32 { (self.buffer.len()) as u32 } fn access(&self) -> IoAccess { IoAccess::WRITE } fn id(&self) -> super::DeviceId { super::DeviceId::Display } fn write_word(&mut self, offset: u32, val: u32) -> Result<(), Interrupt> { let bytes = val.to_le_bytes(); self.buffer[offset as usize].store(bytes[0], Ordering::Relaxed); self.buffer[offset as usize + 1].store(bytes[1], Ordering::Relaxed); self.buffer[offset as usize + 2].store(bytes[2], Ordering::Relaxed); self.buffer[offset as usize + 3].store(bytes[3], Ordering::Relaxed); self.dirty.store(true, Ordering::Relaxed); Ok(()) } fn write_byte(&mut self, offset: u32, val: u8) -> Result<(), Interrupt> { self.buffer[offset as usize].store(val, Ordering::Relaxed); self.dirty.store(true, Ordering::Relaxed); Ok(()) } } pub struct DisplayHandle { pub buffer: Arc>, pub dirty: Arc, } impl DisplayHandle { pub fn is_dirty(&self) -> bool { self.dirty.swap(false, Ordering::Relaxed) } pub fn read_all(&self) -> Vec { self.buffer .iter() .map(|b| b.load(Ordering::Relaxed)) .collect() } }