1mod debug; 2 3use crate::WhichCpu; 4use crate::vdp::Vdp; 5use bincode::{Decode, Encode}; 6use jgenesis_common::define_bit_enum; 7use jgenesis_common::num::{GetBit, U16Ext, U24Ext}; 8use std::array; 9use std::fmt::{Display, Formatter}; 10 11define_bit_enum!(Access, [M68k, Sh2]); 12 13impl Display for Access { 14 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 15 match self { 16 Self::M68k => write!(f, "68000"), 17 Self::Sh2 => write!(f, "SH-2"), 18 } 19 } 20} 21 22#[derive(Debug, Clone, Default, Encode, Decode)] 23pub struct Sh2Interrupts { 24 pub reset_pending: bool, 25 pub v_pending: bool, 26 pub v_enabled: bool, 27 pub h_pending: bool, 28 pub h_enabled: bool, 29 pub command_pending: bool, 30 pub command_enabled: bool, 31 pub pwm_pending: bool, 32 pub pwm_enabled: bool, 33 pub current_interrupt_level: u8, 34} 35 36impl Sh2Interrupts { 37 fn mask_bits(&self) -> u16 { 38 (u16::from(self.v_enabled) << 3) 39 | (u16::from(self.h_enabled) << 2) 40 | (u16::from(self.command_enabled) << 1) 41 | u16::from(self.pwm_enabled) 42 } 43 44 fn write_mask_bits(&mut self, value: u16) { 45 self.v_enabled = value.bit(3); 46 self.h_enabled = value.bit(2); 47 self.command_enabled = value.bit(1); 48 self.pwm_enabled = value.bit(0); 49 50 self.update_interrupt_level(); 51 } 52 53 fn clear_reset(&mut self) { 54 self.reset_pending = false; 55 self.update_interrupt_level(); 56 } 57 58 fn clear_v(&mut self) { 59 // Clear pending flag only if VINTs are enabled (verified on hardware) 60 // TODO do the other interrupt types also work this way? 61 self.v_pending &= !self.v_enabled; 62 self.update_interrupt_level(); 63 } 64 65 fn clear_h(&mut self) { 66 self.h_pending = false; 67 self.update_interrupt_level(); 68 } 69 70 fn clear_command(&mut self) { 71 self.command_pending = false; 72 self.update_interrupt_level(); 73 } 74 75 fn clear_pwm(&mut self) { 76 self.pwm_pending = false; 77 self.update_interrupt_level(); 78 } 79 80 fn update_interrupt_level(&mut self) { 81 self.current_interrupt_level = if self.reset_pending { 82 14 83 } else if self.v_pending && self.v_enabled { 84 12 85 } else if self.h_pending { 86 10 87 } else if self.command_pending && self.command_enabled { 88 8 89 } else if self.pwm_pending { 90 6 91 } else { 92 0 93 }; 94 } 95} 96 97const DMA_FIFO_LEN: usize = 4; 98 99#[derive(Debug, Clone, Default, Encode, Decode)] 100pub struct DmaFifo { 101 blocks: [[u16; 4]; 2], 102 ready: [bool; 2], 103 m68k_block: usize, 104 m68k_idx: usize, 105 sh2_block: usize, 106 sh2_idx: usize, 107} 108 109impl DmaFifo { 110 pub fn push(&mut self, value: u16) { 111 log::trace!("DMA FIFO push: {value:04X}"); 112 113 self.blocks[self.m68k_block][self.m68k_idx] = value; 114 self.m68k_idx += 1; 115 116 if self.m68k_idx == DMA_FIFO_LEN { 117 self.ready[self.m68k_block] = true; 118 self.m68k_block ^= 1; 119 self.m68k_idx = 0; 120 } 121 } 122 123 pub fn pop(&mut self) -> u16 { 124 let value = self.blocks[self.sh2_block][self.sh2_idx]; 125 self.sh2_idx += 1; 126 127 if self.sh2_idx == DMA_FIFO_LEN { 128 self.ready[self.sh2_block] = false; 129 self.sh2_block ^= 1; 130 self.sh2_idx = 0; 131 } 132 133 log::trace!("DMA FIFO pop: {value:04X}"); 134 135 value 136 } 137 138 pub fn sh2_is_empty(&self) -> bool { 139 !self.ready[self.sh2_block] 140 } 141 142 pub fn is_full(&self) -> bool { 143 self.ready[self.m68k_block] 144 } 145 146 pub fn clear(&mut self) { 147 self.ready.fill(false); 148 } 149} 150 151#[derive(Debug, Clone, Encode, Decode)] 152pub struct DmaRegisters { 153 pub rom_to_vram: bool, 154 // TODO not sure what this does 155 pub bit_1: bool, 156 pub active: bool, 157 pub source_address: u32, 158 pub destination_address: u32, 159 pub length: u16, 160 pub fifo: DmaFifo, 161} 162 163impl Default for DmaRegisters { 164 fn default() -> Self { 165 Self { 166 rom_to_vram: false, 167 bit_1: false, 168 active: false, 169 source_address: 0, 170 destination_address: 0, 171 length: 0xFFFF, 172 fifo: DmaFifo::default(), 173 } 174 } 175} 176 177#[derive(Debug, Clone, Encode, Decode)] 178pub struct SystemRegisters { 179 pub adapter_enabled: bool, 180 pub reset_sh2: bool, 181 pub vdp_access: Access, 182 pub m68k_rom_bank: u8, 183 pub communication_ports: [u16; 8], 184 pub master_interrupts: Sh2Interrupts, 185 pub slave_interrupts: Sh2Interrupts, 186 pub dma: DmaRegisters, 187 pub cartridge_present: bool, 188 // Functionality not emulated, only bits 0 and 8 being R/W 189 pub sega_tv_bits: u16, 190} 191 192impl SystemRegisters { 193 pub fn new(cartridge_present: bool) -> Self { 194 Self { 195 adapter_enabled: false, 196 reset_sh2: false, 197 vdp_access: Access::M68k, 198 m68k_rom_bank: 0, 199 communication_ports: array::from_fn(|_| 0), 200 master_interrupts: Sh2Interrupts::default(), 201 slave_interrupts: Sh2Interrupts::default(), 202 dma: DmaRegisters::default(), 203 cartridge_present, 204 sega_tv_bits: 0, 205 } 206 } 207 208 pub fn notify_vblank_start(&mut self) { 209 self.master_interrupts.v_pending = true; 210 self.slave_interrupts.v_pending = true; 211 212 self.master_interrupts.update_interrupt_level(); 213 self.slave_interrupts.update_interrupt_level(); 214 } 215 216 pub fn notify_vblank_end(&mut self) { 217 self.master_interrupts.v_pending = false; 218 self.slave_interrupts.v_pending = false; 219 220 self.master_interrupts.update_interrupt_level(); 221 self.slave_interrupts.update_interrupt_level(); 222 } 223 224 pub fn notify_h_interrupt(&mut self) { 225 self.master_interrupts.h_pending |= self.master_interrupts.h_enabled; 226 self.slave_interrupts.h_pending |= self.slave_interrupts.h_enabled; 227 228 self.master_interrupts.update_interrupt_level(); 229 self.slave_interrupts.update_interrupt_level(); 230 } 231 232 pub fn either_h_interrupt_enabled(&self) -> bool { 233 self.master_interrupts.h_enabled || self.slave_interrupts.h_enabled 234 } 235 236 pub fn notify_pwm_timer(&mut self) { 237 self.master_interrupts.pwm_pending |= self.master_interrupts.pwm_enabled; 238 self.slave_interrupts.pwm_pending |= self.slave_interrupts.pwm_enabled; 239 240 self.master_interrupts.update_interrupt_level(); 241 self.slave_interrupts.update_interrupt_level(); 242 } 243 244 pub fn reset(&mut self) { 245 self.master_interrupts.reset_pending = true; 246 self.slave_interrupts.reset_pending = true; 247 248 self.master_interrupts.update_interrupt_level(); 249 self.slave_interrupts.update_interrupt_level(); 250 251 self.adapter_enabled = false; 252 } 253 254 pub fn m68k_read(&mut self, address: u32) -> u16 { 255 match address { 256 0xA15100 => self.read_adapter_control(), 257 0xA15102 => self.read_interrupt_control(), 258 0xA15104 => self.read_68k_rom_bank(), 259 0xA15106 => self.m68k_read_dreq_control(), 260 0xA15108 => self.read_dreq_source_high(), 261 0xA1510A => self.read_dreq_source_low(), 262 0xA1510C => self.read_dreq_destination_high(), 263 0xA1510E => self.read_dreq_destination_low(), 264 0xA15110 => self.dma.length, 265 0xA1511A => self.sega_tv_bits, 266 0xA15120..=0xA1512F => self.read_communication_port(address), 267 _ => { 268 log::warn!("M68K invalid register read: {address:06X}"); 269 0 270 } 271 } 272 } 273 274 pub fn m68k_write_byte(&mut self, address: u32, value: u8) { 275 let mut word = self.m68k_read(address & !1); 276 if !address.bit(0) { 277 word.set_msb(value); 278 } else { 279 word.set_lsb(value); 280 } 281 self.m68k_write(address & !1, word); 282 } 283 284 pub fn m68k_write(&mut self, address: u32, value: u16) { 285 match address { 286 0xA15100 => self.write_adapter_control(value), 287 0xA15102 => self.write_interrupt_control(value), 288 0xA15104 => self.write_68k_rom_bank(value), 289 0xA15106 => self.write_dreq_control(value), 290 0xA15108 => self.write_dreq_source_high(value), 291 0xA1510A => self.write_dreq_source_low(value), 292 0xA1510C => self.write_dreq_destination_high(value), 293 0xA1510E => self.write_dreq_destination_low(value), 294 0xA15110 => self.write_dreq_length(value), 295 0xA15112 => self.write_dreq_fifo(value), 296 0xA1511A => { 297 // Only bits 0 and 8 are writable per testpico 298 // TODO is this actually a single bit mirrored? 299 self.sega_tv_bits = value & 0x0101; 300 } 301 0xA15120..=0xA1512F => self.write_communication_port(address, value), 302 _ => log::warn!("M68K invalid register write: {address:06X} {value:04X}"), 303 } 304 } 305 306 pub fn sh2_read(&mut self, address: u32, which: WhichCpu, vdp: &Vdp) -> u16 { 307 match address { 308 0x4000 => self.read_interrupt_mask(which, vdp), 309 0x4004 => vdp.h_interrupt_interval(), 310 0x4006 => self.sh2_read_dreq_control(), 311 0x4008 => self.read_dreq_source_high(), 312 0x400A => self.read_dreq_source_low(), 313 0x400C => self.read_dreq_destination_high(), 314 0x400E => self.read_dreq_destination_low(), 315 0x4010 => self.dma.length, 316 0x4012 => self.read_dreq_fifo(), 317 // TODO these registers shouldn't be readable? (interrupt clear) 318 0x4014 | 0x4016 | 0x4018 | 0x401A | 0x401C => 0, 319 0x4020..=0x402F => self.read_communication_port(address), 320 _ => { 321 log::warn!("SH-2 invalid register read: {address:08X} {which:?}"); 322 0 323 } 324 } 325 } 326 327 pub fn sh2_write(&mut self, address: u32, value: u16, which: WhichCpu, vdp: &mut Vdp) { 328 match address { 329 0x4000 => self.write_interrupt_mask(value, which, vdp), 330 0x4002 => { 331 // The master SH-2 writes to this register when it resets while the 32X adapter is 332 // not enabled, after which it executes a SLEEP instruction and waits for a reset 333 log::debug!("SH-2 {which:?} wrote to standby register $4002"); 334 } 335 0x4004 => vdp.write_h_interrupt_interval(value), 336 0x4014 => self.clear_reset_interrupt(which), 337 0x4016 => self.clear_v_interrupt(which), 338 0x4018 => self.clear_h_interrupt(which), 339 0x401A => self.clear_command_interrupt(which), 340 0x401C => self.clear_pwm_interrupt(which), 341 0x4020..=0x402F => self.write_communication_port(address, value), 342 _ => log::warn!("SH-2 invalid register write: {address:08X} {value:04X} {which:?}"), 343 } 344 } 345 346 // 68000: $A15100 347 fn read_adapter_control(&self) -> u16 { 348 // TODO bit 7? (REN / reset enabled) 349 ((self.vdp_access as u16) << 15) 350 | (1 << 7) 351 | (u16::from(!self.reset_sh2) << 1) 352 | u16::from(self.adapter_enabled) 353 } 354 355 // 68000: $A15100 356 fn write_adapter_control(&mut self, value: u16) { 357 self.adapter_enabled = value.bit(0); 358 self.reset_sh2 = !value.bit(1); 359 self.vdp_access = Access::from_bit(value.bit(15)); 360 361 log::trace!("Adapter control write: {value:04X}"); 362 log::trace!(" 32X adapter enabled: {}", self.adapter_enabled); 363 log::trace!(" Reset SH-2: {}", self.reset_sh2); 364 log::trace!(" 32X VDP access: {}", self.vdp_access); 365 } 366 367 // 68000: $A15102 368 fn read_interrupt_control(&self) -> u16 { 369 (u16::from(self.slave_interrupts.command_pending) << 1) 370 | u16::from(self.master_interrupts.command_pending) 371 } 372 373 // 68000: $A15102 374 fn write_interrupt_control(&mut self, value: u16) { 375 self.master_interrupts.command_pending = value.bit(0); 376 self.slave_interrupts.command_pending = value.bit(1); 377 378 self.master_interrupts.update_interrupt_level(); 379 self.slave_interrupts.update_interrupt_level(); 380 381 log::trace!("Interrupt control write: {value:04X}"); 382 log::trace!(" Master command interrupt: {}", self.master_interrupts.command_pending); 383 log::trace!(" Slave command interrupt: {}", self.slave_interrupts.command_pending); 384 } 385 386 // 68000: $A15104 387 fn read_68k_rom_bank(&self) -> u16 { 388 self.m68k_rom_bank.into() 389 } 390 391 // 68000: $A15104 392 fn write_68k_rom_bank(&mut self, value: u16) { 393 self.m68k_rom_bank = (value & 0x03) as u8; 394 log::trace!("68000 ROM bank: {}", self.m68k_rom_bank); 395 } 396 397 // 68000: $A15106 398 fn m68k_read_dreq_control(&self) -> u16 { 399 (u16::from(self.dma.fifo.is_full()) << 7) 400 | (u16::from(self.dma.active) << 2) 401 | (u16::from(self.dma.bit_1) << 1) 402 | u16::from(self.dma.rom_to_vram) 403 } 404 405 // SH-2: $4006 406 fn sh2_read_dreq_control(&self) -> u16 { 407 (u16::from(self.dma.fifo.is_full()) << 15) 408 | (u16::from(self.dma.fifo.sh2_is_empty()) << 14) 409 | (u16::from(self.dma.active) << 2) 410 | (u16::from(self.dma.bit_1) << 1) 411 | u16::from(self.dma.rom_to_vram) 412 } 413 414 // 68000: $A15106 415 fn write_dreq_control(&mut self, value: u16) { 416 self.dma.rom_to_vram = value.bit(0); 417 self.dma.bit_1 = value.bit(1); 418 self.dma.active = value.bit(2); 419 420 if !self.dma.active { 421 self.dma.fifo.clear(); 422 } 423 424 log::trace!("DREQ control write: {value:04X}"); 425 log::trace!(" ROM-to-VRAM DMA active: {}", self.dma.rom_to_vram); 426 log::trace!(" DMA active: {}", self.dma.active); 427 } 428 429 // 68000: $A15108 430 // SH-2: $4008 431 fn read_dreq_source_high(&self) -> u16 { 432 (self.dma.source_address >> 16) as u16 433 } 434 435 // 68000: $A1510A 436 // SH-2: $400A 437 fn read_dreq_source_low(&self) -> u16 { 438 self.dma.source_address as u16 439 } 440 441 // 68000: $A15108 442 fn write_dreq_source_high(&mut self, value: u16) { 443 self.dma.source_address.set_high_byte(value as u8); 444 445 log::trace!("DREQ source address high write: {value:04X}"); 446 log::trace!(" New address: {:06X}", self.dma.source_address); 447 } 448 449 // 68000: $A1510A 450 fn write_dreq_source_low(&mut self, value: u16) { 451 self.dma.source_address = (self.dma.source_address & 0xFFFF0000) | u32::from(value & !1); 452 453 log::trace!("DREQ source address low write: {value:04X}"); 454 log::trace!(" New address: {:06X}", self.dma.source_address); 455 } 456 457 // 68000: $A1510C 458 // SH-2: $410C 459 fn read_dreq_destination_high(&self) -> u16 { 460 (self.dma.destination_address >> 16) as u16 461 } 462 463 // 68000: $A1510E 464 // SH-2: $410E 465 fn read_dreq_destination_low(&self) -> u16 { 466 self.dma.destination_address as u16 467 } 468 469 // 68000: $A1510C 470 fn write_dreq_destination_high(&mut self, value: u16) { 471 self.dma.destination_address.set_high_byte(value as u8); 472 473 log::trace!("DREQ destination address high write: {value:04X}"); 474 log::trace!(" New address: {:06X}", self.dma.destination_address); 475 } 476 477 // 68000: $A1510E 478 fn write_dreq_destination_low(&mut self, value: u16) { 479 self.dma.destination_address = 480 (self.dma.destination_address & 0xFFFF0000) | u32::from(value); 481 482 log::trace!("DREQ destination address low write: {value:04X}"); 483 log::trace!(" New address: {:06X}", self.dma.destination_address); 484 } 485 486 // 68000: $A15110 487 fn write_dreq_length(&mut self, value: u16) { 488 // Lowest 2 bits are forced to 0 489 self.dma.length = value & !3; 490 log::trace!("DREQ length: {:04X}", self.dma.length); 491 } 492 493 // SH-2: $4012 494 fn read_dreq_fifo(&mut self) -> u16 { 495 self.dma.length = self.dma.length.wrapping_sub(1); 496 if self.dma.length == 0 { 497 self.dma.active = false; 498 } 499 500 self.dma.fifo.pop() 501 } 502 503 // 68000: $A15112 504 fn write_dreq_fifo(&mut self, value: u16) { 505 // Only push to the DMA FIFO if 68000-to-32X DMA is currently active. Virtua Racing Deluxe 506 // depends on this or else it will crash after the title screen. 507 // It does 68000-to-32X DMAs of length 64 while consistently pushing 65 words into the FIFO 508 // for each DMA, and it depends on the 65th word never getting transferred. 509 if self.dma.active { 510 self.dma.fifo.push(value); 511 } 512 } 513 514 // SH-2: $4000 515 fn read_interrupt_mask(&self, which: WhichCpu, vdp: &Vdp) -> u16 { 516 let mask_bits: u16 = match which { 517 WhichCpu::Master => self.master_interrupts.mask_bits(), 518 WhichCpu::Slave => self.slave_interrupts.mask_bits(), 519 }; 520 521 ((self.vdp_access as u16) << 15) 522 | (u16::from(self.adapter_enabled) << 9) 523 | (u16::from(!self.cartridge_present) << 8) 524 | (u16::from(vdp.hen_bit()) << 7) 525 | mask_bits 526 } 527 528 // SH-2: $4000 529 pub fn write_interrupt_mask(&mut self, value: u16, which: WhichCpu, vdp: &mut Vdp) { 530 self.vdp_access = Access::from_bit(value.bit(15)); 531 532 vdp.write_hen_bit(value.bit(7)); 533 534 match which { 535 WhichCpu::Master => self.master_interrupts.write_mask_bits(value), 536 WhichCpu::Slave => self.slave_interrupts.write_mask_bits(value), 537 } 538 539 log::trace!("Interrupt mask write ({which:?}): {value:04X}"); 540 log::trace!(" VDP access: {:?}", self.vdp_access); 541 log::trace!(" HINT during VBlank: {}", vdp.hen_bit()); 542 543 if log::log_enabled!(log::Level::Trace) { 544 let interrupts = match which { 545 WhichCpu::Master => &self.master_interrupts, 546 WhichCpu::Slave => &self.slave_interrupts, 547 }; 548 549 log::trace!(" V interrupt enabled: {}", interrupts.v_enabled); 550 log::trace!(" H interrupt enabled: {}", interrupts.h_enabled); 551 log::trace!(" Command interrupt enabled: {}", interrupts.command_enabled); 552 log::trace!(" PWM interrupt enabled: {}", interrupts.pwm_enabled); 553 } 554 } 555 556 // SH-2: $4014 557 fn clear_reset_interrupt(&mut self, which: WhichCpu) { 558 match which { 559 WhichCpu::Master => self.master_interrupts.clear_reset(), 560 WhichCpu::Slave => self.slave_interrupts.clear_reset(), 561 } 562 log::trace!("VRESINT cleared"); 563 } 564 565 // SH-2: $4016 566 fn clear_v_interrupt(&mut self, which: WhichCpu) { 567 match which { 568 WhichCpu::Master => self.master_interrupts.clear_v(), 569 WhichCpu::Slave => self.slave_interrupts.clear_v(), 570 } 571 log::trace!("VINT cleared"); 572 } 573 574 // SH-2: $4018 575 fn clear_h_interrupt(&mut self, which: WhichCpu) { 576 match which { 577 WhichCpu::Master => self.master_interrupts.clear_h(), 578 WhichCpu::Slave => self.slave_interrupts.clear_h(), 579 } 580 } 581 582 // SH-2: $401A 583 fn clear_command_interrupt(&mut self, which: WhichCpu) { 584 match which { 585 WhichCpu::Master => self.master_interrupts.clear_command(), 586 WhichCpu::Slave => self.slave_interrupts.clear_command(), 587 } 588 log::trace!("CMDINT cleared"); 589 } 590 591 // SH-2: $401C 592 fn clear_pwm_interrupt(&mut self, which: WhichCpu) { 593 match which { 594 WhichCpu::Master => self.master_interrupts.clear_pwm(), 595 WhichCpu::Slave => self.slave_interrupts.clear_pwm(), 596 } 597 log::trace!("PWMINT cleared"); 598 } 599 600 // 68000: $A15120-$A1512F 601 // SH-2: $4020-$402F 602 fn read_communication_port(&self, address: u32) -> u16 { 603 let idx = (address >> 1) & 0x7; 604 self.communication_ports[idx as usize] 605 } 606 607 // 68000: $A15120-$A1512F 608 // SH-2: $4020-$402F 609 fn write_communication_port(&mut self, address: u32, value: u16) { 610 let idx = (address >> 1) & 0x7; 611 self.communication_ports[idx as usize] = value; 612 } 613}