use std::sync::mpsc::SyncSender; use armv4t_emu::Memory; pub struct Mem<'m> { pub inner: &'m mut [u8], pub tx: SyncSender, } impl<'m> Memory for Mem<'m> { fn r8(&mut self, addr: u32) -> u8 { self.special_addr(addr, false); self.inner[addr as usize] } fn r16(&mut self, addr: u32) -> u16 { self.special_addr(addr, false); u16::from_be_bytes([self.inner[addr as usize], self.inner[addr as usize + 1]]) } fn r32(&mut self, addr: u32) -> u32 { self.special_addr(addr, false); u32::from_be_bytes([ self.inner[addr as usize], self.inner[addr as usize + 1], self.inner[addr as usize + 2], self.inner[addr as usize + 3], ]) } fn w8(&mut self, addr: u32, val: u8) { self.special_addr(addr, true); self.inner[addr as usize] = val; } fn w16(&mut self, addr: u32, val: u16) { self.special_addr(addr, true); let bytes = val.to_be_bytes(); self.inner[addr as usize] = bytes[0]; self.inner[addr as usize + 1] = bytes[1]; } fn w32(&mut self, addr: u32, val: u32) { self.special_addr(addr, true); let bytes = val.to_be_bytes(); self.inner[addr as usize] = bytes[0]; self.inner[addr as usize + 1] = bytes[1]; self.inner[addr as usize + 2] = bytes[2]; self.inner[addr as usize + 3] = bytes[3]; } } impl<'m> Mem<'m> { const IO: u32 = 0x00020000; const IO_END: u32 = 0x000200FF; pub const CTSI_ASIC_WATCHDOG: usize = Self::IO as usize | 0x03; pub const CTSI_IRQ_LINES: usize = Self::IO as usize | 0x09; pub const CTSI_CLOCK_CONTROL: usize = Self::IO as usize | 0x0D; pub const CCONT_WRITE: usize = Self::IO as usize | 0x2C; pub const GENSIO_START_TRANSACTION: usize = Self::IO as usize | 0x2D; pub const UIF_CTRL_IO_2: usize = Self::IO as usize | 0x32; pub const CCONT_READ: usize = Self::IO as usize | 0x6C; pub const GENSIO_STATUS: usize = Self::IO as usize | 0x6D; pub const GENSIO_LCD_CTRL: usize = Self::IO as usize | 0x6E; pub fn set_gensio_status(&mut self, state: GensioState) { let byte = &mut self.inner[Self::GENSIO_STATUS]; match state { GensioState::DataWrite => *byte |= 1, GensioState::TransactionReady => *byte |= 2, GensioState::DataRead => *byte |= 5, } } pub fn gensio_status_clear(&mut self) { self.inner[Self::GENSIO_STATUS] = 0x00; } fn special_addr(&mut self, addr: u32, write: bool) { if (Self::IO..=Self::IO_END).contains(&addr) { self.special_io(addr, write) } } fn special_io(&mut self, addr: u32, write: bool) { let io_addr = addr ^ Self::IO; let meaning = match io_addr { // 00-3F 0x00 => "ASIC Version", 0x01 => "MCU reset control register", 0x02 => "DSP reset control register", 0x03 => { self.tx.send(Event::Ctsi(Ctsi::AsicWatchdog)).unwrap(); "CTSI ASIC Watchdog Write Register" } 0x0A => "CTSI FIQ lines mask", 0x0B => "CTSI IRQ lines mask ", 0x0D => { self.tx.send(Event::Ctsi(Ctsi::WriteClockControl)).unwrap(); "CTSI Clock Control Register" } 0x20 => "McuGenIO Signal Lines", 0x28 => "Keyboard ROW signal lines", 0x2A => "Keyboard COL signal lines", 0x2C => { self.tx.send(Event::GenSIO(GenSIO::CContWrite)).unwrap(); "CCont write" } 0x2D => { self.tx .send(Event::GenSIO(GenSIO::StartTransaction)) .unwrap(); "GENSIO start transaction" } 0x2E => "GENSIO LCD data write", 0x32 => { self.tx.send(Event::Uif(Uif::CtrlIo2)).unwrap(); "UIF CTRL IO 2" } addr if addr >= 0x36 && addr <= 0x3F => "SIM something [0x36 to 0x3F]", // 40-7F 0x6B => "Keyboard COL interrupt mask", 0x6C => "CCont read", 0x6D => { self.gensio_status(); "GENSIO status" } 0x6E => { self.tx.send(Event::GenSIO(GenSIO::LcdCtrl)).unwrap(); "GENSIO LCD Ctrl" } 0x6F => "GENSIO - 3/SELECT1", 0x70 => "CTRL I/O Direction 0,1", 0x71 => "CTRL I/O Direction 1,1", 0x72 => "CTRL I/O Direction 2,1", 0x73 => "CTRL I/O Direction 3,1", //80-BF 0xA8 => "Keyboard ROW I/O direction", 0xAD => "GENSIO - 1/SELECT2", 0xAE => "GENSIO - 2/SELECT2", 0xAF => "GENSIO - 3/SELECT2", 0xB0 => "CTRL I/O Direction 0,2", 0xB1 => "CTRL I/O Direction 1,2", 0xB2 => "CTRL I/O Direction 2,2", 0xB3 => "CTRL I/O Direction 3,2", //C0-FF 0xED => "GENSIO - 1/SELECT3", 0xEE => "GENSIO - 2/SELECT3", 0xEF => "GENSIO - 3/SELECT3", 0xF0 => "CTRL I/O Input 0", 0xF1 => "CTRL I/O Input 1", 0xF2 => "CTRL I/O Input 2", 0xF3 => "CTRL I/O Input 3", _ => "unknown IO", }; let read_write = if write { "w" } else { "r" }; log::info!("IO {read_write} [{io_addr:02X}] - {meaning}"); } fn gensio_status(&mut self) { let base = (Self::IO | 0x2D) as usize; let ctrl_io_dir_1 = self.inner[base]; log::info!("CTRL Start Transaction -- {:08b}", ctrl_io_dir_1); log::info!("GENSIO Status -- {:08b}", self.inner[Self::GENSIO_STATUS]); self.print_ctrl_io_direction_1(); self.print_ctrl_io_direction_2(); } fn print_ctrl_io_direction_1(&self) { let base = (Self::IO | 0x70) as usize; let ctrl_io_dir_1 = &self.inner[base..base + 4]; log::info!( "CTRL I/O Direction (1) -- {:08b} {:08b} {:08b} {:08b}", ctrl_io_dir_1[0], ctrl_io_dir_1[1], ctrl_io_dir_1[2], ctrl_io_dir_1[3] ); } fn print_ctrl_io_direction_2(&self) { let base = (Self::IO | 0xB0) as usize; let ctrl_io_dir_1 = &self.inner[base..base + 4]; log::info!( "CTRL I/O Direction (2) -- {:08b} {:08b} {:08b} {:08b}", ctrl_io_dir_1[0], ctrl_io_dir_1[1], ctrl_io_dir_1[2], ctrl_io_dir_1[3] ); } } pub enum GensioState { DataWrite, TransactionReady, DataRead, } pub enum Event { GenSIO(GenSIO), Ctsi(Ctsi), Uif(Uif), } pub enum GenSIO { StartTransaction, CContWrite, LcdCtrl, } pub enum Ctsi { AsicWatchdog, WriteClockControl, } pub enum Uif { CtrlIo2, }