From 557766c22a17d42ac58bd39cda9889f1f6b7f5bc Mon Sep 17 00:00:00 2001 From: gennyble Date: Wed, 5 Mar 2025 05:48:04 -0600 Subject: inititty comitty --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 4 + .rustfmt.toml | 1 + Cargo.lock | 325 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ My 3310 NR1 v5.79.fls | Bin 0 -> 2097152 bytes README.md | 2 + src/currentcontroller.rs | 207 ++++++++++++++++++++++++++++++ src/main.rs | 199 +++++++++++++++++++++++++++++ src/mem.rs | 244 +++++++++++++++++++++++++++++++++++ 10 files changed, 994 insertions(+) create mode 100755 .DS_Store create mode 100755 .gitignore create mode 100755 .rustfmt.toml create mode 100755 Cargo.lock create mode 100755 Cargo.toml create mode 100755 My 3310 NR1 v5.79.fls create mode 100644 README.md create mode 100755 src/currentcontroller.rs create mode 100755 src/main.rs create mode 100755 src/mem.rs diff --git a/.DS_Store b/.DS_Store new file mode 100755 index 0000000..5707b56 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..7fa6f53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +*.log +FuBu3310 v6.39 (PPM B).fls +mapped_rom.dump \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100755 index 0000000..218e203 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/Cargo.lock b/Cargo.lock new file mode 100755 index 0000000..9e550ba --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,325 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "armv4t_emu" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "041e88e25b5fd858fc0091f44a8981aed83d4c29141820b46c9f56f94e42e816" +dependencies = [ + "log", +] + +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "nokia3310emu" +version = "0.1.0" +dependencies = [ + "armv4t_emu", + "log", + "simple_logger", + "time", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simple_logger" +version = "4.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7e46c8c90251d47d08b28b8a419ffb4aede0f87c2eea95e17d1d5bacbf3ef1" +dependencies = [ + "colored", + "log", + "time", + "windows-sys 0.48.0", +] + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..d1a5e75 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "nokia3310emu" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +armv4t_emu = "0.1.0" +log = "0.4.20" +simple_logger = "4.3.3" +time = "0.3.31" diff --git a/My 3310 NR1 v5.79.fls b/My 3310 NR1 v5.79.fls new file mode 100755 index 0000000..ccc7627 Binary files /dev/null and b/My 3310 NR1 v5.79.fls differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..de7ba18 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +"Vintage Firmware Modding Nokia DCT3 Phones" +https://www.youtube.com/watch?v=_7tkjJ-F95U \ No newline at end of file diff --git a/src/currentcontroller.rs b/src/currentcontroller.rs new file mode 100755 index 0000000..7a39770 --- /dev/null +++ b/src/currentcontroller.rs @@ -0,0 +1,207 @@ +use std::time::SystemTime; + +use time::OffsetDateTime; + +use crate::mem::{GensioState, Mem}; + +pub struct CurrentController { + pub reg: Option, + pub control_reg: u8, + //TODO: make enum + pub charging_mode: u8, + pub tenbit_adc: u16, + pub head_hook_detection: u8, + //TODO: make enum + pub watchdog_setting: u8, + pub rtc_enable: u8, + //TODO: track time in struct + pub alarm_minute: u8, + pub alarm_hour: u8, + pub rtc_calibration: u8, + /// Bit 0 - RTC bat present + /// Bit 3/3 - CContINT 3-7 + pub irq: u8, + /// True(1)/False(0) + pub irq_mask: u8, +} + +impl CurrentController { + pub fn new() -> Self { + Self { + reg: None, + control_reg: 0, + charging_mode: 0, + tenbit_adc: 0, + head_hook_detection: 0, + watchdog_setting: 0, + rtc_enable: 0, + alarm_minute: 0, + alarm_hour: 12, + rtc_calibration: 0, + irq: 0, + irq_mask: 0, + } + } + + pub fn event(&mut self, mem: &mut Mem) { + log::trace!("CCont value={:02X}", mem.inner[Mem::CCONT_WRITE]); + log::trace!( + "CCont write >> 3 value={:02X}", + mem.inner[Mem::CCONT_WRITE] >> 3 + ); + log::trace!( + "CCont read ^ 4 >> 3 value={:02X}", + (mem.inner[Mem::CCONT_WRITE] ^ 0x04) >> 3 + ); + + let and_four = mem.inner[Mem::CCONT_WRITE] & 0x04; + + match self.reg { + None => { + if and_four > 0 { + self.read(mem.inner[Mem::CCONT_WRITE], mem); + } else { + self.reg = Some(mem.inner[Mem::CCONT_WRITE]) + } + } + Some(reg) => { + self.write(reg, mem); + self.reg = None; + } + } + } + + pub fn read(&mut self, addr: u8, mem: &mut Mem) { + log::trace!("ccont::read()"); + let reg = (addr ^ 0x04) >> 3; + + match reg { + 0x02 => { + log::trace!("CCont A/D 0-7 Read"); + let adc = self.tenbit_adc.to_be_bytes(); + mem.inner[Mem::CCONT_READ] = adc[0]; + } + 0x03 => { + log::trace!("CCont Headset/Hooked flag?"); + mem.inner[Mem::CCONT_READ] = self.head_hook_detection; + } + 0x04 => { + log::trace!("CCont A/D 8-9 Read & test bits"); + let adc = self.tenbit_adc.to_be_bytes(); + mem.inner[Mem::CCONT_READ] = ((adc[1] >> 6) & 3) | 0b101100_00; + } + 0x09 => { + log::trace!("CCont RTC Second"); + let time = OffsetDateTime::now_local().unwrap(); + mem.inner[Mem::CCONT_READ] = time.second(); + } + 0x0A => { + log::trace!("CCont RTC Minute"); + let time = OffsetDateTime::now_local().unwrap(); + mem.inner[Mem::CCONT_READ] = time.minute(); + } + 0x0B => { + log::trace!("CCont RTC Hour"); + let time = OffsetDateTime::now_local().unwrap(); + mem.inner[Mem::CCONT_READ] = time.hour(); + } + 0x0C => { + log::trace!("CCont RTC Day"); + let time = OffsetDateTime::now_local().unwrap(); + mem.inner[Mem::CCONT_READ] = time.day(); + } + 0x0D => { + log::trace!("CCont RTC Alarm Minute"); + mem.inner[Mem::CCONT_READ] = self.alarm_minute; + } + 0x0E => { + log::trace!("CCont RTC Alarm Hour"); + mem.inner[Mem::CCONT_READ] = self.alarm_hour; + } + 0x0F => { + log::trace!("CCont RTC Calibration"); + mem.inner[Mem::CCONT_READ] = self.rtc_calibration; + } + 0x10 => { + log::trace!("CCont RTC Interrupt Controller"); + mem.inner[Mem::CCONT_READ] = self.irq; + } + 0x11 => { + log::trace!("CCont RTC IRQ Mask"); + mem.inner[Mem::CCONT_READ] = self.irq_mask; + } + reg => { + log::trace!("CCont !!! {reg:02X} unknown read!"); + panic!() + } + } + + //mem.gensio_status_clear(); + mem.set_gensio_status(GensioState::DataRead); + //mem.set_gensio_status(GensioState::TransactionReady); + } + + pub fn write(&mut self, addr: u8, mem: &mut Mem) { + log::trace!("ccont::write()"); + let reg = addr >> 3; + let val = mem.inner[Mem::CCONT_WRITE]; + + match reg { + 0x00 => { + log::trace!("CCont control register"); + self.control_reg = val; + } + 0x01 => { + log::trace!("CCont PWM (charger)"); + self.charging_mode = val; + } + 0x03 => { + log::trace!("CCont A/D Read 0-7 (why call write?)"); + log::info!("Not writing to AD due to confusion on how that works"); + } + 0x05 => { + log::trace!("CCont Headset/Hooked flag?"); + self.head_hook_detection = val; + } + 0x06 => { + log::trace!("CCont Set Watchdog"); + self.watchdog_setting = val; + } + 0x07 => { + log::trace!("CCont RTC Enable"); + self.rtc_enable = val; + } + 0x08 => { + log::trace!("CCont RTC Second"); + log::info!("Ignoring RTC Second write due to current RTC implementation") + } + 0x0C => { + log::trace!("CCont RTC Day"); + log::info!("Ignoring RTC Day write due to current RTC implementation") + } + 0x0D => { + log::trace!("CCont RTC Alarm Minute"); + self.alarm_minute = val; + } + 0x0E => { + log::trace!("CCont RTC Alarm Hour"); + self.alarm_hour = val; + } + 0x0F => { + log::trace!("CCont RTC Callibration"); + self.rtc_calibration = val; + } + 0x10 => { + log::trace!("CCont RTC Interrupt Controller"); + self.irq = val; + } + 0x11 => { + log::trace!("CCont RTC IRQ Mask"); + self.irq_mask = val; + } + reg => { + log::trace!("CCont !!! {reg:02X} unknown register") + } + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100755 index 0000000..1279ceb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,199 @@ +#![allow(clippy::new_without_default)] +#![allow(clippy::unusual_byte_groupings)] +use std::{ + collections::HashMap, + sync::mpsc::TryRecvError, + time::{Duration, Instant}, +}; + +use armv4t_emu::{reg, Cpu, Exception, Memory, Mode}; + +use crate::mem::{Ctsi, Event, GenSIO, GensioState, Mem, Uif}; + +mod currentcontroller; +mod mem; + +use currentcontroller::CurrentController; + +fn main() { + simple_logger::SimpleLogger::new() + .with_level(log::LevelFilter::Info) + .with_module_level("nokia3310emu::currentcontroller", log::LevelFilter::Trace) + //.with_module_level("pc_all", log::LevelFilter::Trace) + .with_module_level("eec46_jmp", log::LevelFilter::Trace) + .with_module_level("armv4t_emu", log::LevelFilter::Info) + .env() + .with_colors(true) + .init() + .unwrap(); + + // Channel so the memory controller can tell us when memory mapped + // IO is activated + let (mut tx, mut rx) = std::sync::mpsc::sync_channel::(10); + + // Setup Memory + let mut memory_array = vec![0; 0x800000]; + let file = std::fs::read("My 3310 NR1 v5.79.fls").unwrap(); + //let file = std::fs::read("FuBu3310 v6.39 (PPM B).fls").unwrap(); + + memory_array[0x00200000..0x003FFFFF + 1].copy_from_slice(&file); + + let mut mem = Mem { + inner: &mut memory_array, + tx, + }; + + // Current Controller (CCont) + let mut ccont = CurrentController::new(); + + // Setup CPU + let mut cpu = Cpu::new(); + // We don't have a bootloader. Hope everything is okay and jump straight + // to where the bootloader does + cpu.reg_set(Mode::User, reg::PC, 0x200040); + + let mut hit_eec46 = false; + // Main loop + let mut last_pc = 0x0; + let mut print_all_pc = false; + let mut jump_counter = JumpCounter::default(); + + let known_jumps = vec![ + 0x002ef9e6, // Delay_r0_loop + ]; + + let start = Instant::now(); + let run_duration = Duration::from_millis(5000); + + 'cpustep: while cpu.step(&mut mem) { + // Log jumps to make debugging easier. We can look at these + // addresses in Ghidra + let pc = cpu.reg_get(Mode::User, reg::PC); + if print_all_pc { + log::trace!(target: "pc_all", "[{}] {pc:08x}", pc as isize - last_pc as isize); + } + + if (pc as isize - last_pc as isize).abs() > 4 { + log::trace!("jump detect - {last_pc:08X} => {pc:08X}",); + let count = jump_counter.jump(last_pc, pc); + + if count >= 100 && count % 100 == 0 && !known_jumps.contains(&pc) { + log::trace!(target: "eec46_jmp", "[{count:<6}] {last_pc:08x} => {pc:08x}"); + } + } + + if pc == 0x002eebec && last_pc != 0x002eebec { + log::info!("Entered eebec loop!"); + } + + if pc == 0x002eec44 { + //let r5 = cpu.reg_get(Mode::User, 5); + // We set R5 here because the next two instructions are as follows: + // [MainLoop?] eec46: cmp r5, 0x1 + // eec48: bne [MainLoop?] + // So if we do not set r5 to 0x1, we'll loop back to eec46 forever + log::warn!("hit eec44... setting register 5!"); + cpu.reg_set(Mode::User, 5, 0x1); + } + + if pc == 0x002eec46 && !hit_eec46 { + hit_eec46 = true; + print_all_pc = true; + log::info!("hit eec46!"); + } else if pc != 0x002eec48 && pc != 0x002eec46 && hit_eec46 { + hit_eec46 = false; + print_all_pc = true; + log::warn!("broke from eec46! (pc = {pc:x})"); + } + last_pc = pc; + + if pc == 0x002eec52 { + log::info!("hit eec52!"); + } + + match rx.try_recv() { + Err(TryRecvError::Empty) => (), + Err(TryRecvError::Disconnected) => panic!("event sender disconnected"), + Ok(event) => match event { + Event::GenSIO(GenSIO::StartTransaction) => { + let start_byte = mem.inner[Mem::GENSIO_START_TRANSACTION]; + if start_byte == 0x25 { + mem.gensio_status_clear(); + mem.set_gensio_status(GensioState::DataWrite); + mem.set_gensio_status(GensioState::TransactionReady); + } + } + + Event::GenSIO(GenSIO::CContWrite) => ccont.event(&mut mem), + + Event::GenSIO(GenSIO::LcdCtrl) => { + let dog = mem.inner[Mem::GENSIO_LCD_CTRL]; + log::info!("GENSIO LCD Mystery {dog:02X} -- {dog:08b}"); + //mem.inner[Mem::UIF_CTRL_IO_2] = 0b0010_0000; + } + + Event::Ctsi(Ctsi::AsicWatchdog) => { + let dog = mem.inner[Mem::CTSI_ASIC_WATCHDOG]; + log::info!("CTSI Clock ={dog}"); + } + + Event::Ctsi(Ctsi::WriteClockControl) => { + let clock = mem.inner[Mem::CTSI_CLOCK_CONTROL]; + log::info!("CTSI Clock {clock:08b}"); + } + + Event::Uif(Uif::CtrlIo2) => { + let ctrl = mem.inner[Mem::UIF_CTRL_IO_2]; + log::info!("CTSI Clock {ctrl:08b}"); + } + }, + } + + if start.elapsed() >= run_duration { + log::error!("hit run_duration max runtime. breaking from cpustep loop"); + break 'cpustep; + } + + // Run slow + std::thread::sleep(Duration::from_micros(10)); + } + + println!("cpu halted"); +} + +#[derive(Debug, Default)] +pub struct JumpCounter { + jmps: Vec, +} + +impl JumpCounter { + pub fn jump(&mut self, from: u32, to: u32) -> usize { + match self.jmps.iter_mut().find(|j| j.from == from && j.to == to) { + None => { + self.jmps.push(Jump::new(from, to)); + 1 + } + Some(jmp) => { + jmp.count += 1; + jmp.count + } + } + } +} + +#[derive(Debug)] +pub struct Jump { + from: u32, + to: u32, + count: usize, +} + +impl Jump { + pub fn new(from: u32, to: u32) -> Self { + Self { from, to, count: 1 } + } +} + +pub struct Lcd { + pub data: [u8; 44 * 84], +} diff --git a/src/mem.rs b/src/mem.rs new file mode 100755 index 0000000..34d16c6 --- /dev/null +++ b/src/mem.rs @@ -0,0 +1,244 @@ +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, +} -- cgit 1.4.1-3-g733a5