1pub mod bus; 2mod instructions; 3 4use crate::bus::{BusInterface, MemoryCycle}; 5use crate::instructions::{ArmOpTable, ThumbOpTable}; 6use bincode::{Decode, Encode}; 7use jgenesis_common::num::GetBit; 8 9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 10pub enum CpuState { 11 // 32-bit opcodes, full instruction set 12 #[default] 13 Arm = 0, 14 // 16-bit opcodes, limited instruction set 15 Thumb = 1, 16} 17 18impl CpuState { 19 fn from_bit(bit: bool) -> Self { 20 if bit { Self::Thumb } else { Self::Arm } 21 } 22} 23 24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 25pub enum CpuMode { 26 #[default] 27 User = 0x10, 28 Fiq = 0x11, 29 Irq = 0x12, 30 Supervisor = 0x13, 31 Abort = 0x17, 32 Undefined = 0x1B, 33 // Arbitrary unused mode value 34 Illegal = 0x1E, 35 System = 0x1F, 36} 37 38impl CpuMode { 39 fn from_bits(bits: u32) -> Self { 40 // Only lowest 4 bits are checked on mode writes; highest bit is forced to 1 41 // (alyosha-tas/gba-tests PSR tests) 42 match bits & 0xF { 43 0x0 => Self::User, 44 0x1 => Self::Fiq, 45 0x2 => Self::Irq, 46 0x3 => Self::Supervisor, 47 0x7 => Self::Abort, 48 0xB => Self::Undefined, 49 0xF => Self::System, 50 _ => Self::Illegal, 51 } 52 } 53 54 fn spsr(self, registers: &mut Registers) -> Option<&mut StatusRegister> { 55 match self { 56 Self::Irq => Some(&mut registers.spsr_irq), 57 Self::Fiq => Some(&mut registers.spsr_fiq), 58 Self::Supervisor => Some(&mut registers.spsr_svc), 59 Self::Undefined => Some(&mut registers.spsr_und), 60 Self::Abort => Some(&mut registers.spsr_abt), 61 Self::User | Self::System | Self::Illegal => None, 62 } 63 } 64} 65 66#[derive(Debug, Clone, Copy, Default, Encode, Decode)] 67struct StatusRegister { 68 sign: bool, 69 zero: bool, 70 carry: bool, 71 overflow: bool, 72 irq_disabled: bool, 73 fiq_disabled: bool, 74 state: CpuState, 75 mode: CpuMode, 76} 77 78impl From<StatusRegister> for u32 { 79 fn from(value: StatusRegister) -> Self { 80 (u32::from(value.sign) << 31) 81 | (u32::from(value.zero) << 30) 82 | (u32::from(value.carry) << 29) 83 | (u32::from(value.overflow) << 28) 84 | (u32::from(value.irq_disabled) << 7) 85 | (u32::from(value.fiq_disabled) << 6) 86 | ((value.state as u32) << 5) 87 | (value.mode as u32) 88 } 89} 90 91impl From<u32> for StatusRegister { 92 fn from(value: u32) -> Self { 93 Self { 94 sign: value.bit(31), 95 zero: value.bit(30), 96 carry: value.bit(29), 97 overflow: value.bit(28), 98 irq_disabled: value.bit(7), 99 fiq_disabled: value.bit(6), 100 state: CpuState::from_bit(value.bit(5)), 101 mode: CpuMode::from_bits(value & 0x1F), 102 } 103 } 104} 105 106#[derive(Debug, Clone, Default, Encode, Decode)] 107struct Registers { 108 // "General-purpose" registers; R15 is the program counter 109 r: [u32; 16], 110 // R13 and R14 are banked by mode 111 r13_usr: u32, 112 r14_usr: u32, 113 r13_svc: u32, 114 r14_svc: u32, 115 r13_irq: u32, 116 r14_irq: u32, 117 r13_und: u32, 118 r14_und: u32, 119 r13_abt: u32, 120 r14_abt: u32, 121 r13_fiq: u32, 122 r14_fiq: u32, 123 // R8-R12 are banked only for FIQ vs. non-FIQ 124 fiq_r_8_12: [u32; 5], 125 other_r_8_12: [u32; 5], 126 // Condition codes and control register 127 cpsr: StatusRegister, 128 // Previous condition codes and control registers, banked by CPU mode (excluding usr) 129 spsr_svc: StatusRegister, 130 spsr_irq: StatusRegister, 131 spsr_und: StatusRegister, 132 spsr_abt: StatusRegister, 133 spsr_fiq: StatusRegister, 134} 135 136#[derive(Debug, Clone, Copy, PartialEq, Eq)] 137enum Exception { 138 Reset, 139 UndefinedInstruction, 140 SoftwareInterrupt, 141 Irq, 142} 143 144impl Exception { 145 const fn vector_address(self) -> u32 { 146 match self { 147 Self::Reset => 0x00, 148 Self::UndefinedInstruction => 0x04, 149 Self::SoftwareInterrupt => 0x08, 150 Self::Irq => 0x18, 151 } 152 } 153 154 const fn new_mode(self) -> CpuMode { 155 match self { 156 Self::Reset | Self::SoftwareInterrupt => CpuMode::Supervisor, 157 Self::UndefinedInstruction => CpuMode::Undefined, 158 Self::Irq => CpuMode::Irq, 159 } 160 } 161 162 #[allow(clippy::match_same_arms)] 163 fn return_address(self, state: CpuState, r15: u32) -> u32 { 164 // R15 is PC+8 for ARM and PC+4 for Thumb 165 match (state, self) { 166 // ARM R14 is always PC+4 except for Data abort, which is not emulated 167 (CpuState::Arm, _) => r15.wrapping_sub(4), 168 // Thumb R14 is PC+2 for SWI and Undefined 169 (CpuState::Thumb, Self::UndefinedInstruction | Self::SoftwareInterrupt) => { 170 r15.wrapping_sub(2) 171 } 172 // Thumb R14 is PC+4 for IRQ (and FIQ and Data abort, which are not emulated) 173 (CpuState::Thumb, Self::Irq) => r15, 174 // Reset value doesn't matter because return address is not written when handling Reset 175 (CpuState::Thumb, Self::Reset) => r15, 176 } 177 } 178} 179 180#[derive(Debug, Clone, Encode, Decode)] 181pub struct Arm7Tdmi<Bus: BusInterface> { 182 registers: Registers, 183 prefetch: [u32; 2], 184 fetch_cycle: MemoryCycle, 185 prev_r15: u32, 186 irq_disabled_latch: bool, 187 arm_op_table: ArmOpTable<Bus>, 188 thumb_op_table: ThumbOpTable<Bus>, 189} 190 191impl<Bus: BusInterface> Default for Arm7Tdmi<Bus> { 192 fn default() -> Self { 193 Self::new() 194 } 195} 196 197pub struct Arm7TdmiResetArgs { 198 pub pc: u32, 199 pub sp_usr: u32, 200 pub sp_svc: u32, 201 pub sp_irq: u32, 202 pub sp_fiq: u32, 203 pub mode: CpuMode, 204} 205 206impl<Bus: BusInterface> Arm7Tdmi<Bus> { 207 #[must_use] 208 pub fn new() -> Self { 209 Self { 210 registers: Registers::default(), 211 prefetch: [0, 0], 212 fetch_cycle: MemoryCycle::N, 213 prev_r15: 0, 214 irq_disabled_latch: false, 215 arm_op_table: ArmOpTable::default(), 216 thumb_op_table: ThumbOpTable::default(), 217 } 218 } 219 220 pub fn reset(&mut self, bus: &mut Bus) { 221 self.handle_exception(Exception::Reset, bus); 222 } 223 224 pub fn manual_reset(&mut self, args: Arm7TdmiResetArgs, bus: &mut Bus) { 225 self.registers = Registers::default(); 226 self.registers.r[..13].fill(0); 227 self.registers.r[14] = args.pc; 228 self.registers.r[15] = args.pc; 229 self.registers.r[13] = args.sp_usr; 230 self.registers.r13_svc = args.sp_svc; 231 self.registers.r13_irq = args.sp_irq; 232 self.registers.r13_fiq = args.sp_fiq; 233 self.registers.cpsr = StatusRegister { 234 sign: false, 235 zero: false, 236 carry: false, 237 overflow: false, 238 irq_disabled: false, 239 fiq_disabled: false, 240 state: CpuState::Arm, 241 mode: args.mode, 242 }; 243 self.registers.spsr_svc = 0_u32.into(); 244 self.registers.spsr_irq = 0_u32.into(); 245 246 self.refill_prefetch(bus); 247 } 248 249 #[inline] 250 pub fn execute_instruction(&mut self, bus: &mut Bus) { 251 let irq = !self.irq_disabled_latch && bus.irq(); 252 let opcode = self.prefetch[0]; 253 self.fetch_opcode(bus); 254 255 if irq { 256 return self.handle_exception(Exception::Irq, bus); 257 } 258 259 match self.registers.cpsr.state { 260 CpuState::Arm => self.execute_arm_opcode(opcode, bus), 261 CpuState::Thumb => self.execute_thumb_opcode(opcode as u16, bus), 262 } 263 } 264 265 fn refill_prefetch(&mut self, bus: &mut Bus) { 266 self.fetch_cycle = MemoryCycle::N; 267 268 match self.registers.cpsr.state { 269 CpuState::Arm => { 270 self.registers.r[15] &= !3; 271 272 self.fetch_opcode_state::<true>(bus); 273 self.fetch_opcode_state::<true>(bus); 274 } 275 CpuState::Thumb => { 276 self.registers.r[15] &= !1; 277 278 self.fetch_opcode_state::<false>(bus); 279 self.fetch_opcode_state::<false>(bus); 280 } 281 } 282 } 283 284 fn fetch_opcode(&mut self, bus: &mut Bus) { 285 match self.registers.cpsr.state { 286 CpuState::Arm => self.fetch_opcode_state::<true>(bus), 287 CpuState::Thumb => self.fetch_opcode_state::<false>(bus), 288 } 289 } 290 291 fn fetch_opcode_state<const ARM: bool>(&mut self, bus: &mut Bus) { 292 self.irq_disabled_latch = self.registers.cpsr.irq_disabled; 293 294 let fetch_cycle = self.fetch_cycle; 295 self.fetch_cycle = MemoryCycle::S; 296 self.prev_r15 = self.registers.r[15]; 297 298 self.prefetch[0] = self.prefetch[1]; 299 if ARM { 300 self.prefetch[1] = bus.fetch_opcode_word(self.registers.r[15], fetch_cycle); 301 self.registers.r[15] = self.registers.r[15].wrapping_add(4); 302 303 log::trace!( 304 "Fetched ARM opcode {:08X} from {:08X}", 305 self.prefetch[1], 306 self.registers.r[15].wrapping_sub(4) 307 ); 308 } else { 309 // Thumb 310 self.prefetch[1] = bus.fetch_opcode_halfword(self.registers.r[15], fetch_cycle).into(); 311 self.registers.r[15] = self.registers.r[15].wrapping_add(2); 312 313 log::trace!( 314 "Fetched Thumb opcode {:04X} from {:08X}", 315 self.prefetch[1], 316 self.registers.r[15].wrapping_sub(2) 317 ); 318 } 319 } 320 321 fn write_cpsr(&mut self, value: u32) { 322 log::trace!("CPSR write: {value:08X}"); 323 324 if self.registers.cpsr.mode != CpuMode::User { 325 let new_mode = CpuMode::from_bits(value); 326 self.change_mode(new_mode); 327 328 self.registers.cpsr = value.into(); 329 } else { 330 // Cannot modify control bits in user mode 331 self.registers.cpsr = StatusRegister { 332 mode: self.registers.cpsr.mode, 333 state: self.registers.cpsr.state, 334 fiq_disabled: self.registers.cpsr.fiq_disabled, 335 irq_disabled: self.registers.cpsr.irq_disabled, 336 ..StatusRegister::from(value) 337 }; 338 } 339 } 340 341 fn spsr_to_cpsr(&mut self) { 342 let spsr = match self.registers.cpsr.mode.spsr(&mut self.registers) { 343 Some(spsr) => *spsr, 344 None => { 345 log::warn!("Attempted to read SPSR in mode {:?}", self.registers.cpsr.mode); 346 return; 347 } 348 }; 349 350 self.change_mode(spsr.mode); 351 self.registers.cpsr = spsr; 352 } 353 354 fn change_mode(&mut self, new_mode: CpuMode) { 355 if new_mode == self.registers.cpsr.mode { 356 return; 357 } 358 359 log::trace!("Changing CPU mode to {new_mode:?} from {:?}", self.registers.cpsr.mode); 360 361 // Bank R13 and R14, as well as R8-12 if changing out of FIQ mode 362 match self.registers.cpsr.mode { 363 CpuMode::User | CpuMode::System => { 364 self.registers.r13_usr = self.registers.r[13]; 365 self.registers.r14_usr = self.registers.r[14]; 366 } 367 CpuMode::Supervisor => { 368 self.registers.r13_svc = self.registers.r[13]; 369 self.registers.r14_svc = self.registers.r[14]; 370 } 371 CpuMode::Irq => { 372 self.registers.r13_irq = self.registers.r[13]; 373 self.registers.r14_irq = self.registers.r[14]; 374 } 375 CpuMode::Undefined => { 376 self.registers.r13_und = self.registers.r[13]; 377 self.registers.r14_und = self.registers.r[14]; 378 } 379 CpuMode::Abort => { 380 self.registers.r13_abt = self.registers.r[13]; 381 self.registers.r14_abt = self.registers.r[14]; 382 } 383 CpuMode::Fiq => { 384 self.registers.r13_fiq = self.registers.r[13]; 385 self.registers.r14_fiq = self.registers.r[14]; 386 387 // Bank and update R8-12 if switching out of FIQ mode 388 self.registers.fiq_r_8_12.copy_from_slice(&self.registers.r[8..13]); 389 self.registers.r[8..13].copy_from_slice(&self.registers.other_r_8_12); 390 } 391 CpuMode::Illegal => { 392 log::warn!( 393 "Exiting unusual CPU mode {:?}, changing to mode {new_mode:?}", 394 self.registers.cpsr.mode 395 ); 396 } 397 } 398 399 // Update R13 and R14 to banked values, as well as R8-12 if switching into FIQ mode 400 match new_mode { 401 CpuMode::User | CpuMode::System => { 402 self.registers.r[13] = self.registers.r13_usr; 403 self.registers.r[14] = self.registers.r14_usr; 404 } 405 CpuMode::Supervisor => { 406 self.registers.r[13] = self.registers.r13_svc; 407 self.registers.r[14] = self.registers.r14_svc; 408 } 409 CpuMode::Irq => { 410 self.registers.r[13] = self.registers.r13_irq; 411 self.registers.r[14] = self.registers.r14_irq; 412 } 413 CpuMode::Undefined => { 414 self.registers.r[13] = self.registers.r13_und; 415 self.registers.r[14] = self.registers.r14_und; 416 } 417 CpuMode::Abort => { 418 self.registers.r[13] = self.registers.r13_abt; 419 self.registers.r[14] = self.registers.r14_abt; 420 } 421 CpuMode::Fiq => { 422 // Bank and update R8-12 if switching into FIQ mode 423 self.registers.other_r_8_12.copy_from_slice(&self.registers.r[8..13]); 424 self.registers.r[8..13].copy_from_slice(&self.registers.fiq_r_8_12); 425 426 self.registers.r[13] = self.registers.r13_fiq; 427 self.registers.r[14] = self.registers.r14_fiq; 428 } 429 CpuMode::Illegal => { 430 log::warn!( 431 "Entering unusual CPU mode {new_mode:?}, changing from mode {:?}", 432 self.registers.cpsr.mode 433 ); 434 } 435 } 436 437 self.registers.cpsr.mode = new_mode; 438 } 439 440 fn handle_exception(&mut self, exception: Exception, bus: &mut Bus) { 441 log::trace!("Handling exception of type {exception:?}"); 442 443 let mode = exception.new_mode(); 444 match exception { 445 Exception::Reset => { 446 self.registers.cpsr.mode = mode; 447 } 448 _ => { 449 let old_cpsr = self.registers.cpsr; 450 451 self.change_mode(mode); 452 if let Some(spsr) = mode.spsr(&mut self.registers) { 453 *spsr = old_cpsr; 454 } 455 456 self.registers.r[14] = 457 exception.return_address(self.registers.cpsr.state, self.prev_r15); 458 } 459 } 460 461 self.registers.cpsr.state = CpuState::Arm; 462 self.registers.cpsr.irq_disabled = true; 463 if exception == Exception::Reset { 464 self.registers.cpsr.fiq_disabled = true; 465 } 466 467 self.registers.r[15] = exception.vector_address(); 468 self.refill_prefetch(bus); 469 } 470 471 fn read_register(&self, r: u32) -> u32 { 472 if r == 15 { 473 // Return R15 from before the opcode fetch 474 self.prev_r15 475 } else { 476 self.registers.r[r as usize] 477 } 478 } 479}