2021-11-07 04:46:17 +00:00
|
|
|
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
2023-04-23 22:46:47 +00:00
|
|
|
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn};
|
2022-10-01 19:12:25 +00:00
|
|
|
use moa_core::host::gfx::{Frame, FrameQueue};
|
2022-10-03 03:39:02 +00:00
|
|
|
use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent};
|
2021-11-07 04:46:17 +00:00
|
|
|
|
|
|
|
use super::keymap;
|
|
|
|
use super::charset::CharacterGenerator;
|
|
|
|
|
|
|
|
|
2023-03-06 04:19:49 +00:00
|
|
|
const DEV_NAME: &str = "model1";
|
2022-10-01 19:12:25 +00:00
|
|
|
const SCREEN_SIZE: (u32, u32) = (384, 128);
|
2021-11-07 04:46:17 +00:00
|
|
|
|
|
|
|
pub struct Model1Peripherals {
|
2022-10-01 19:12:25 +00:00
|
|
|
frame_queue: FrameQueue,
|
2021-12-13 20:00:24 +00:00
|
|
|
keyboard_mem: Arc<Mutex<[u8; 8]>>,
|
|
|
|
video_mem: [u8; 1024],
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Model1Peripherals {
|
|
|
|
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
|
2022-10-01 19:12:25 +00:00
|
|
|
let frame_queue = FrameQueue::new(SCREEN_SIZE.0, SCREEN_SIZE.1);
|
2021-11-07 04:46:17 +00:00
|
|
|
let keyboard_mem = Arc::new(Mutex::new([0; 8]));
|
|
|
|
|
2022-10-01 19:12:25 +00:00
|
|
|
host.add_window(Box::new(frame_queue.clone()))?;
|
2021-11-07 04:46:17 +00:00
|
|
|
host.register_keyboard(Box::new(Model1KeyboardUpdater(keyboard_mem.clone())))?;
|
|
|
|
|
|
|
|
Ok(Self {
|
2022-10-01 19:12:25 +00:00
|
|
|
frame_queue,
|
2021-11-07 04:46:17 +00:00
|
|
|
keyboard_mem,
|
2023-04-23 22:46:47 +00:00
|
|
|
video_mem: [0x20; 1024],
|
2021-11-07 04:46:17 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Model1KeyboardUpdater(Arc<Mutex<[u8; 8]>>);
|
|
|
|
|
|
|
|
impl KeyboardUpdater for Model1KeyboardUpdater {
|
2022-10-03 03:39:02 +00:00
|
|
|
fn update_keyboard(&mut self, event: KeyEvent) {
|
|
|
|
println!(">>> {:?}", event.key);
|
|
|
|
keymap::record_key_press(&mut self.0.lock().unwrap(), event.key, event.state);
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Steppable for Model1Peripherals {
|
2023-04-23 22:46:47 +00:00
|
|
|
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
2023-03-25 17:51:46 +00:00
|
|
|
let mut frame = Frame::new(SCREEN_SIZE.0, SCREEN_SIZE.1, self.frame_queue.encoding());
|
2021-11-07 04:46:17 +00:00
|
|
|
for y in 0..16 {
|
|
|
|
for x in 0..64 {
|
|
|
|
let ch = self.video_mem[x + (y * 64)];
|
2023-04-23 22:46:47 +00:00
|
|
|
let iter = CharacterGenerator::new(ch.saturating_sub(0x20) % 64);
|
2021-12-08 21:52:11 +00:00
|
|
|
frame.blit((x * 6) as u32, (y * 8) as u32, iter, 6, 8);
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-01 19:12:25 +00:00
|
|
|
self.frame_queue.add(system.clock, frame);
|
2021-11-07 04:46:17 +00:00
|
|
|
|
2023-04-23 22:46:47 +00:00
|
|
|
Ok(ClockDuration::from_micros(16_630))
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Addressable for Model1Peripherals {
|
|
|
|
fn len(&self) -> usize {
|
|
|
|
0x820
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
2023-03-06 04:19:49 +00:00
|
|
|
if (0x20..=0xA0).contains(&addr) {
|
2021-11-07 04:46:17 +00:00
|
|
|
let offset = addr - 0x20;
|
|
|
|
data[0] = 0;
|
|
|
|
if (offset & 0x01) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[0]; }
|
|
|
|
if (offset & 0x02) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[1]; }
|
|
|
|
if (offset & 0x04) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[2]; }
|
|
|
|
if (offset & 0x08) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[3]; }
|
|
|
|
if (offset & 0x10) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[4]; }
|
|
|
|
if (offset & 0x20) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[5]; }
|
|
|
|
if (offset & 0x40) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[6]; }
|
|
|
|
if (offset & 0x80) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[7]; }
|
|
|
|
//info!("{}: read from keyboard {:x} of {:?}", DEV_NAME, addr, data);
|
2023-03-06 04:19:49 +00:00
|
|
|
} else if (0x420..=0x820).contains(&addr) {
|
2021-11-07 04:46:17 +00:00
|
|
|
data[0] = self.video_mem[addr as usize - 0x420];
|
|
|
|
} else {
|
2022-10-09 16:40:20 +00:00
|
|
|
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
2021-11-08 06:44:40 +00:00
|
|
|
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
2023-03-06 04:19:49 +00:00
|
|
|
if (0x420..0x820).contains(&addr) {
|
2021-11-07 04:46:17 +00:00
|
|
|
self.video_mem[addr as usize - 0x420] = data[0];
|
|
|
|
} else {
|
2022-10-09 16:40:20 +00:00
|
|
|
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
2021-11-07 04:46:17 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Transmutable for Model1Peripherals {
|
|
|
|
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
|
|
|
|
Some(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
|
|
|
Some(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|