diff --git a/doc/notes.org b/doc/notes.org new file mode 100644 index 0000000..b589102 --- /dev/null +++ b/doc/notes.org @@ -0,0 +1,58 @@ +#+TITLE: DMD 5620 Core Notes +#+AUTHOR: Seth Morabito +#+EMAIL: web@loomcom.com +#+DATE: <2021-04-23 Fri 12:33> +#+STARTUP: showall inlineimages +#+OPTIONS: toc:nil num:nil + +* About + + This document contains miscellaneous development notes taken while working + on devleopment. + +* Features + +** CPU Idle Loop Detection + + There are several interesting blocks that look like idle + loops. Ideally, we want to detect these loops and just idle the CPU + until the next interrupt is likely to occur. + +*** Idle Loop Example 1 + + This tight loop occurs early on before startup is complete, and only exits + via interrupt which sets some value in ~*$0x71a79c~. + + #+BEGIN_EXAMPLE + [0000678d] MOVH *$0x71a79c,%r0 + [00006795] CMPW %r1,%r0 + [00006798] BLB + #+END_EXAMPLE + +*** Idle Loop Example 2 + + This occurs later on after startup is complete. It continuously calls + the function at ~0x715c~. + + #+BEGIN_EXAMPLE + [0000068c] BITW %r0,$0x16 + [0000068f] BEB + [00000659] TSTB 0x6293186 + [0000065f] BNEB + [00000661] TSTW 64(%r9) + [00000664] BNEB + [0000715c] CALL (%r12),0x29020 + [0000715c] SAVE %r9 + [0000715e] MOVW $0x71c590,%r1 + [00007161] ADDW3 $0x71c590,0x1096,%r0 + [00007169] TSTH (%r0) + [0000716b] BLEB + [00007170] MOVW *$0x719024,%r0 + [00007177] MOVW (%r0),%r0 + [0000717a] TSTH 52(%r0) + [0000717d] BLEB + [00007182] MOVW %r1,%r0 + [00007185] RESTORE %r9 + [0000068c] RET + + #+END_EXAMPLE diff --git a/src/bus.rs b/src/bus.rs index d73535e..3cfa42a 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -5,8 +5,8 @@ use crate::err::BusError; use crate::mem::Mem; use crate::mouse::Mouse; use std::io::Write; -use std::{fmt, fs::File, ops::Range}; use std::{fmt::Debug, fs::OpenOptions}; +use std::{fs::File, ops::Range}; const NVRAM_SIZE: usize = 8192; @@ -108,8 +108,8 @@ impl Bus { } pub fn trace_on(&mut self, name: &str) -> std::io::Result<()> { - let mut out = OpenOptions::new().write(true).open(name)?; - write!(out, "TRACE START")?; + let mut out = OpenOptions::new().create(true).write(true).open(name)?; + writeln!(out, "TRACE START")?; self.trace_log = Some(out); Ok(()) } @@ -122,12 +122,9 @@ impl Bus { self.trace_log = None; } - pub fn trace(&mut self, step: u64, object: &T) - where - T: fmt::Display, - { + pub fn trace(&mut self, step: u64, line: &str) { if let Some(trace_log) = &mut self.trace_log { - let _ = writeln!(trace_log, "{:08}: {}", step, object); + let _ = writeln!(trace_log, "{:08}: {}", step, line); } } diff --git a/src/cpu.rs b/src/cpu.rs index 0189c93..6ce2d03 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -48,6 +48,14 @@ const IPL_TABLE: [u32; 64] = [ const WE32100_VERSION: u32 = 0x1a; const HALFWORD_MNEMONIC_COUNT: usize = 11; +macro_rules! trace { + ($bus:ident, $steps:expr, $msg:expr) => { + if ($bus.trace_enabled()) { + $bus.trace($steps, $msg) + } + }; +} + pub enum ExceptionType { ExternalMemory, } @@ -152,6 +160,15 @@ impl Operand { None => self.data_type, } } + + fn clear(&mut self) { + self.size = 0; + self.mode = AddrMode::None; + self.data_type = Data::None; + self.expanded_type = None; + self.register = None; + self.embedded = 0; + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -173,16 +190,59 @@ pub struct Instruction { impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.data_type { - Data::None => Ok(()), - Data::Byte | Data::SByte => { - write!(f, "0x{:02x}", self.data as u8) + match self.mode { + AddrMode::None => Ok(()), + AddrMode::Absolute => { + write!(f, "0x{}", self.data) } - Data::Half | Data::UHalf => { - write!(f, "0x{:04x}", self.data as u16) + AddrMode::AbsoluteDeferred => write!(f, "*$0x{:x}", self.data), + AddrMode::ByteDisplacement => { + write!(f, "{}(%r{})", self.data as i8, self.register.unwrap()) } - Data::Word | Data::UWord => { - write!(f, "0x{:08x}", self.data) + AddrMode::ByteDisplacementDeferred => { + write!(f, "*{}(%r{})", self.data as i8, self.register.unwrap()) + } + AddrMode::HalfwordDisplacement => { + write!(f, "0x{:x}(%r{})", self.data as i16, self.register.unwrap()) + } + AddrMode::HalfwordDisplacementDeferred => { + write!(f, "*0x{:x}(%r{})", self.data as i16, self.register.unwrap()) + } + AddrMode::WordDisplacement => { + write!(f, "0x{:x}(%r{})", self.data, self.register.unwrap()) + } + AddrMode::WordDisplacementDeferred => { + write!(f, "*0x{:x}(%r{})", self.data, self.register.unwrap()) + } + AddrMode::ApShortOffset => { + write!(f, "{}(%ap)", self.data as i8) + } + AddrMode::FpShortOffset => { + write!(f, "{}(%fp)", self.data as i8) + } + AddrMode::ByteImmediate => { + write!(f, "&{}", self.data as u8) + } + AddrMode::HalfwordImmediate => { + write!(f, "&0x{:x}", self.data as u16) + } + AddrMode::WordImmediate => { + write!(f, "&0x{:x}", self.data) + } + AddrMode::PositiveLiteral => { + write!(f, "$0x{:x}", self.data) + } + AddrMode::NegativeLiteral => { + write!(f, "-$0x{:x}", self.data) + } + AddrMode::Register => { + write!(f, "%r{}", self.register.unwrap()) + } + AddrMode::RegisterDeferred => { + write!(f, "(%r{})", self.register.unwrap()) + } + AddrMode::Expanded => { + write!(f, "{{???}}") } } } @@ -190,11 +250,23 @@ impl fmt::Display for Operand { impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{:5} {}{}{}{}", - self.name, self.operands[0], self.operands[1], self.operands[2], self.operands[3] - ) + let _ = write!(f, "{:8} ", self.name); + + for index in 0..=3 { + let op = &self.operands[index]; + + if op.mode == AddrMode::None { + break; + } + + if index == 0 { + let _ = write!(f, "{}", op); + } else { + let _ = write!(f, ",{}", op); + } + } + + Ok(()) } } @@ -948,6 +1020,11 @@ impl Cpu { if let Some(val) = bus.get_interrupts() { let cpu_ipl = (self.r[R_PSW]) >> 13 & 0xf; if cpu_ipl < IPL_TABLE[(val & 0x3f) as usize] { + trace!( + bus, + self.steps, + &format!("[{:08x}] INTERRUPT 0x{:x}", &self.r[R_PC], (!val) & 0x3f) + ); self.on_interrupt(bus, (!val) & 0x3f); } } @@ -955,8 +1032,6 @@ impl Cpu { self.decode_instruction(bus)?; let mut pc_increment: i32 = i32::from(self.ir.bytes); - bus.trace(self.steps, &self.ir); - match self.ir.opcode { NOP => { pc_increment = 1; @@ -1905,18 +1980,24 @@ impl Cpu { pub fn step(&mut self, bus: &mut Bus) { // TODO: On CPU Exception or Bus Error, handle each error with the appropriate exception handler routine match self.dispatch(bus) { - Ok(i) => self.r[R_PC] = (self.r[R_PC] as i32 + i) as u32, - Err(CpuError::Bus(BusError::Alignment)) => {} - Err(CpuError::Bus(BusError::Permission)) => {} + Ok(i) => { + // We should have the necessary information to trace after dispatch. + trace!(bus, self.steps, &format!("[{:08x}] {}", &self.r[R_PC], &self.ir)); + self.r[R_PC] = (self.r[R_PC] as i32 + i) as u32 + } Err(CpuError::Bus(BusError::NoDevice(_))) | Err(CpuError::Bus(BusError::Read(_))) | Err(CpuError::Bus(BusError::Write(_))) => { self.on_exception(bus, &ExceptionType::ExternalMemory).unwrap(); } - Err(CpuError::Exception(CpuException::IllegalOpcode)) => {} - Err(CpuError::Exception(CpuException::InvalidDescriptor)) => {} - Err(CpuError::Exception(CpuException::PrivilegedOpcode)) => {} - Err(_) => {} + // Err(CpuError::Bus(BusError::Alignment)) => {} + // Err(CpuError::Bus(BusError::Permission)) => {} + // Err(CpuError::Exception(CpuException::IllegalOpcode)) => {} + // Err(CpuError::Exception(CpuException::InvalidDescriptor)) => {} + // Err(CpuError::Exception(CpuException::PrivilegedOpcode)) => {} + Err(e) => { + panic!("Unexpected CPU Error: {}", e) + } } } @@ -2393,12 +2474,13 @@ impl Cpu { for (index, ot) in mn.ops.iter().enumerate() { if *ot == OpType::None { - break; + self.ir.operands[index].clear(); + } else { + // Push a decoded operand + self.decode_operand(bus, index, mn, *ot, etype, addr)?; + etype = self.ir.operands[index].expanded_type; + addr += self.ir.operands[index].size as usize; } - // Push a decoded operand - self.decode_operand(bus, index, mn, *ot, etype, addr)?; - etype = self.ir.operands[index].expanded_type; - addr += self.ir.operands[index].size as usize; } let total_bytes = addr - initial_addr; diff --git a/src/dmd.rs b/src/dmd.rs index bd492ce..046edc4 100644 --- a/src/dmd.rs +++ b/src/dmd.rs @@ -175,8 +175,14 @@ fn dmd_step() -> c_int { } } +/// # Safety +/// +/// Uses a raw pointer. +/// #[no_mangle] -fn dmd_trace_on(file_name: &CStr) -> c_int { +pub unsafe fn dmd_trace_on(file_name: *const c_char) -> c_int { + let file_name = CStr::from_ptr(file_name); + match DMD.lock() { Ok(mut dmd) => match file_name.to_str() { Ok(file_name) => match dmd.trace_on(file_name) {