Files
DSA/dsa/emulator/src/io/display.rs
T

81 lines
2.1 KiB
Rust

use std::sync::{
Arc,
atomic::{AtomicBool, AtomicU8, Ordering},
};
use crate::{
io::{IoAccess, IoDevice},
processor::interrupts::Interrupt,
};
pub struct DisplayDevice {
buffer: Arc<Box<[AtomicU8]>>,
dirty: Arc<AtomicBool>,
}
impl DisplayDevice {
pub fn new(width: usize, height: usize) -> (Self, DisplayHandle) {
let buffer = Arc::new(
(0..width * height)
.map(|_| AtomicU8::new(0))
.collect::<Vec<_>>()
.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<Box<[AtomicU8]>>,
pub dirty: Arc<AtomicBool>,
}
impl DisplayHandle {
pub fn is_dirty(&self) -> bool {
self.dirty.swap(false, Ordering::Relaxed)
}
pub fn read_all(&self) -> Vec<u8> {
self.buffer
.iter()
.map(|b| b.load(Ordering::Relaxed))
.collect()
}
}