1//! SH-2 DMA controller (DMAC) 2//! 3//! Has 2 DMA channels that can transfer data between memory regions in parallel to CPU execution 4 5use crate::Sh2; 6use crate::bus::{AccessContext, BusInterface}; 7use bincode::{Decode, Encode}; 8use jgenesis_common::num::GetBit; 9use std::array; 10 11const EXTERNAL_ADDRESS_MASK: u32 = super::EXTERNAL_ADDRESS_MASK; 12 13#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 14pub enum DmaAddressMode { 15 #[default] 16 Fixed = 0, 17 AutoIncrement = 1, 18 AutoDecrement = 2, 19 Invalid = 3, 20} 21 22impl DmaAddressMode { 23 fn from_value(value: u32) -> Self { 24 match value & 3 { 25 0 => Self::Fixed, 26 1 => Self::AutoIncrement, 27 2 => Self::AutoDecrement, 28 3 => Self::Invalid, 29 _ => unreachable!(), 30 } 31 } 32} 33 34#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 35pub enum DmaTransferUnit { 36 #[default] 37 Byte = 0, 38 Word = 1, 39 Longword = 2, 40 SixteenByte = 3, 41} 42 43impl DmaTransferUnit { 44 fn from_value(value: u32) -> Self { 45 match value & 3 { 46 0 => Self::Byte, 47 1 => Self::Word, 48 2 => Self::Longword, 49 3 => Self::SixteenByte, 50 _ => unreachable!(), 51 } 52 } 53} 54 55#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 56pub enum DmaAckMode { 57 #[default] 58 Read = 0, 59 Write = 1, 60} 61 62impl DmaAckMode { 63 fn from_bit(bit: bool) -> Self { 64 if bit { Self::Write } else { Self::Read } 65 } 66} 67 68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 69pub enum DreqDetectionMode { 70 #[default] 71 Level = 0, 72 Edge = 1, 73} 74 75impl DreqDetectionMode { 76 fn from_bit(bit: bool) -> Self { 77 if bit { Self::Edge } else { Self::Level } 78 } 79} 80 81#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 82pub enum DmaBusMode { 83 #[default] 84 CycleStealing = 0, 85 Burst = 1, 86} 87 88impl DmaBusMode { 89 fn from_bit(bit: bool) -> Self { 90 if bit { Self::Burst } else { Self::CycleStealing } 91 } 92} 93 94#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 95pub enum DmaTransferAddressMode { 96 #[default] 97 Dual = 0, 98 Single = 1, 99} 100 101impl DmaTransferAddressMode { 102 fn from_bit(bit: bool) -> Self { 103 if bit { Self::Single } else { Self::Dual } 104 } 105} 106 107#[derive(Debug, Clone, Default, Encode, Decode)] 108pub struct DmaChannelControl { 109 pub source_address_mode: DmaAddressMode, 110 pub destination_address_mode: DmaAddressMode, 111 pub transfer_size: DmaTransferUnit, 112 pub auto_request: bool, 113 pub ack_mode: DmaAckMode, 114 pub ack_level: bool, 115 pub dreq_select: DreqDetectionMode, 116 pub dreq_level: bool, 117 pub bus_mode: DmaBusMode, 118 pub transfer_address_mode: DmaTransferAddressMode, 119 pub interrupt_enabled: bool, 120 pub dma_complete: bool, 121 pub dma_enabled: bool, 122} 123 124impl DmaChannelControl { 125 fn to_register_value(&self) -> u32 { 126 ((self.destination_address_mode as u32) << 14) 127 | ((self.source_address_mode as u32) << 12) 128 | ((self.transfer_size as u32) << 10) 129 | (u32::from(self.auto_request) << 9) 130 | ((self.ack_mode as u32) << 8) 131 | (u32::from(self.ack_level) << 7) 132 | ((self.dreq_select as u32) << 6) 133 | (u32::from(self.dreq_level) << 5) 134 | ((self.bus_mode as u32) << 4) 135 | ((self.transfer_address_mode as u32) << 3) 136 | (u32::from(self.interrupt_enabled) << 2) 137 | (u32::from(self.dma_complete) << 1) 138 | u32::from(self.dma_enabled) 139 } 140 141 fn write(&mut self, value: u32) { 142 self.destination_address_mode = DmaAddressMode::from_value(value >> 14); 143 self.source_address_mode = DmaAddressMode::from_value(value >> 12); 144 self.transfer_size = DmaTransferUnit::from_value(value >> 10); 145 self.auto_request = value.bit(9); 146 self.ack_mode = DmaAckMode::from_bit(value.bit(8)); 147 self.ack_level = value.bit(7); 148 self.dreq_select = DreqDetectionMode::from_bit(value.bit(6)); 149 self.dreq_level = value.bit(5); 150 self.bus_mode = DmaBusMode::from_bit(value.bit(4)); 151 self.transfer_address_mode = DmaTransferAddressMode::from_bit(value.bit(3)); 152 self.interrupt_enabled = value.bit(2); 153 // DMA complete flag can only be cleared by writes, not set 154 self.dma_complete &= value.bit(1); 155 self.dma_enabled = value.bit(0); 156 } 157 158 pub(crate) fn interrupt_pending(&self) -> bool { 159 self.interrupt_enabled && self.dma_complete && self.dma_enabled 160 } 161} 162 163#[derive(Debug, Clone, Encode, Decode)] 164pub struct DmaChannel { 165 pub source_address: u32, 166 pub destination_address: u32, 167 pub transfer_count: u32, 168 pub control: DmaChannelControl, 169 pub just_ran: bool, 170} 171 172impl DmaChannel { 173 fn new() -> Self { 174 Self { 175 source_address: 0, 176 destination_address: 0, 177 transfer_count: 0, 178 control: DmaChannelControl::default(), 179 just_ran: false, 180 } 181 } 182} 183 184#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 185pub enum DmaPriorityMode { 186 #[default] 187 Fixed = 0, 188 RoundRobin = 1, 189} 190 191impl DmaPriorityMode { 192 fn from_bit(bit: bool) -> Self { 193 if bit { Self::RoundRobin } else { Self::Fixed } 194 } 195} 196 197#[derive(Debug, Clone, Default, Encode, Decode)] 198pub struct DmaOperation { 199 pub priority: DmaPriorityMode, 200 pub address_error: bool, 201 pub dma_master_enabled: bool, 202} 203 204impl DmaOperation { 205 pub fn read(&self) -> u32 { 206 // TODO Bit 1 (NMI flag) hardcoded to 0 207 ((self.priority as u32) << 3) 208 | (u32::from(self.address_error) << 2) 209 | u32::from(self.dma_master_enabled) 210 } 211 212 pub fn write(&mut self, value: u32) { 213 self.priority = DmaPriorityMode::from_bit(value.bit(3)); 214 self.address_error &= value.bit(2); 215 self.dma_master_enabled = value.bit(0); 216 } 217} 218 219#[derive(Debug, Clone, Encode, Decode)] 220pub struct DmaController { 221 pub channels: [DmaChannel; 2], 222 pub operation: DmaOperation, 223} 224 225impl DmaController { 226 pub fn new() -> Self { 227 Self { channels: array::from_fn(|_| DmaChannel::new()), operation: DmaOperation::default() } 228 } 229 230 pub fn read_register(&self, address: u32) -> u32 { 231 match address { 232 0xFFFFFF80 => self.channels[0].source_address, 233 0xFFFFFF84 => self.channels[0].destination_address, 234 0xFFFFFF88 => self.channels[0].transfer_count, 235 0xFFFFFF8C => self.channels[0].control.to_register_value(), 236 0xFFFFFF90 => self.channels[1].source_address, 237 0xFFFFFF94 => self.channels[1].destination_address, 238 0xFFFFFF98 => self.channels[1].transfer_count, 239 0xFFFFFF9C => self.channels[1].control.to_register_value(), 240 0xFFFFFFB0 => self.operation.read(), 241 _ => panic!("Invalid DMAC register address: {address:08X}"), 242 } 243 } 244 245 pub fn write_register(&mut self, address: u32, value: u32) { 246 match address { 247 0xFFFFFF80 => { 248 self.channels[0].source_address = value; 249 log::trace!("DMAC channel 0 source address (SAR0): {value:08X}"); 250 } 251 0xFFFFFF84 => { 252 self.channels[0].destination_address = value; 253 log::trace!("DMAC channel 0 destination address (DAR0): {value:08X}"); 254 } 255 0xFFFFFF88 => { 256 self.channels[0].transfer_count = value & 0xFFFFFF; 257 log::trace!( 258 "DMAC channel 0 transfer count (TCR0): {:06X}", 259 self.channels[0].transfer_count 260 ); 261 } 262 0xFFFFFF8C => { 263 self.channels[0].control.write(value); 264 log::trace!("DMAC channel 0 control write (CHCR0): {value:08X}"); 265 log::trace!(" {:?}", self.channels[0].control); 266 } 267 0xFFFFFF90 => { 268 self.channels[1].source_address = value; 269 log::trace!("DMAC channel 1 source address (SAR1): {value:08X}"); 270 } 271 0xFFFFFF94 => { 272 self.channels[1].destination_address = value; 273 log::trace!("DMAC channel 1 destination address (DAR1): {value:08X}"); 274 } 275 0xFFFFFF98 => { 276 self.channels[1].transfer_count = value & 0xFFFFFF; 277 log::trace!( 278 "DMAC channel 1 transfer count (TCR1): {:06X}", 279 self.channels[1].transfer_count 280 ); 281 } 282 0xFFFFFF9C => { 283 self.channels[1].control.write(value); 284 log::trace!("DMAC channel 1 control write (CHCR1): {value:08X}"); 285 log::trace!(" {:?}", self.channels[1].control); 286 } 287 0xFFFFFFB0 => { 288 self.operation.write(value); 289 log::trace!("DMAOR write: {value:08X}"); 290 log::trace!(" {:?}", self.operation); 291 } 292 _ => panic!("Invalid DMA register write: {address:08X} {value:08X}"), 293 } 294 } 295 296 pub fn channel_ready<B: BusInterface>(&mut self, bus: &mut B) -> Option<usize> { 297 if !self.operation.dma_master_enabled || self.operation.address_error { 298 return None; 299 } 300 301 // TODO respect priority 302 303 let mut idx_can_run: Option<usize> = None; 304 305 for (idx, channel) in self.channels.iter_mut().enumerate() { 306 if !channel.control.dma_enabled || channel.control.dma_complete { 307 continue; 308 } 309 310 let can_run = channel.control.auto_request 311 || (idx == 0 && bus.dma_request_0()) 312 || (idx == 1 && bus.dma_request_1()); 313 314 if channel.control.bus_mode == DmaBusMode::CycleStealing && channel.just_ran { 315 channel.just_ran = false; 316 if can_run && idx_can_run.is_none() { 317 idx_can_run = Some(idx); 318 } 319 continue; 320 } 321 322 if can_run { 323 channel.just_ran = true; 324 return Some(idx); 325 } 326 } 327 328 if let Some(idx) = idx_can_run { 329 self.channels[idx].just_ran = true; 330 return Some(idx); 331 } 332 333 None 334 } 335} 336 337impl Sh2 { 338 // TODO better timing? DMA memory accesses should only impact CPU speed if the CPU accesses memory simultaneously 339 pub(super) fn try_tick_dma(&mut self, bus: &mut impl BusInterface) -> bool { 340 let Some(channel) = self.dmac.channel_ready(bus) else { return false }; 341 342 log::debug!( 343 "[{}] Progressing DMA{channel}: src={:08X}, dest={:08X}, unit={:?}, size={:06X}", 344 self.name, 345 self.dmac.channels[channel].source_address, 346 self.dmac.channels[channel].destination_address, 347 self.dmac.channels[channel].control.transfer_size, 348 self.dmac.channels[channel].transfer_count 349 ); 350 351 // TODO handle single address mode? seems to never be used 352 assert_eq!( 353 self.dmac.channels[channel].control.transfer_address_mode, 354 DmaTransferAddressMode::Dual 355 ); 356 357 match self.dmac.channels[channel].control.transfer_size { 358 DmaTransferUnit::Byte => { 359 let source_addr = self.dmac.channels[channel].source_address; 360 let byte = bus 361 .read_byte(source_addr & EXTERNAL_ADDRESS_MASK, AccessContext::Dma { channel }); 362 363 apply_dma_source_address_mode(&mut self.dmac.channels[channel], 1); 364 365 let dest_addr = self.dmac.channels[channel].destination_address; 366 bus.write_byte( 367 dest_addr & EXTERNAL_ADDRESS_MASK, 368 byte, 369 AccessContext::Dma { channel }, 370 ); 371 372 apply_dma_destination_address_mode(&mut self.dmac.channels[channel], 1); 373 374 self.dmac.channels[channel].transfer_count = 375 self.dmac.channels[channel].transfer_count.wrapping_sub(1); 376 } 377 DmaTransferUnit::Word => { 378 let source_addr = self.dmac.channels[channel].source_address; 379 let word = bus 380 .read_word(source_addr & EXTERNAL_ADDRESS_MASK, AccessContext::Dma { channel }); 381 382 apply_dma_source_address_mode(&mut self.dmac.channels[channel], 2); 383 384 let dest_addr = self.dmac.channels[channel].destination_address; 385 bus.write_word( 386 dest_addr & EXTERNAL_ADDRESS_MASK, 387 word, 388 AccessContext::Dma { channel }, 389 ); 390 391 apply_dma_destination_address_mode(&mut self.dmac.channels[channel], 2); 392 393 self.dmac.channels[channel].transfer_count = 394 self.dmac.channels[channel].transfer_count.wrapping_sub(1); 395 } 396 DmaTransferUnit::Longword => { 397 let source_addr = self.dmac.channels[channel].source_address; 398 let longword = bus.read_longword( 399 source_addr & EXTERNAL_ADDRESS_MASK, 400 AccessContext::Dma { channel }, 401 ); 402 403 apply_dma_source_address_mode(&mut self.dmac.channels[channel], 4); 404 405 let dest_addr = self.dmac.channels[channel].destination_address; 406 bus.write_longword( 407 dest_addr & EXTERNAL_ADDRESS_MASK, 408 longword, 409 AccessContext::Dma { channel }, 410 ); 411 412 apply_dma_destination_address_mode(&mut self.dmac.channels[channel], 4); 413 414 self.dmac.channels[channel].transfer_count = 415 self.dmac.channels[channel].transfer_count.wrapping_sub(1); 416 } 417 DmaTransferUnit::SixteenByte => { 418 // TODO timing will be wrong when DMAing from 32X SDRAM 419 for _ in 0..4 { 420 let source_addr = self.dmac.channels[channel].source_address; 421 let longword = bus.read_longword( 422 source_addr & EXTERNAL_ADDRESS_MASK, 423 AccessContext::Dma { channel }, 424 ); 425 426 // Source address mode is ignored for 16-byte transfers 427 self.dmac.channels[channel].source_address = 428 self.dmac.channels[channel].source_address.wrapping_add(4); 429 430 let dest_addr = self.dmac.channels[channel].destination_address; 431 bus.write_longword( 432 dest_addr & EXTERNAL_ADDRESS_MASK, 433 longword, 434 AccessContext::Dma { channel }, 435 ); 436 437 apply_dma_destination_address_mode(&mut self.dmac.channels[channel], 4); 438 439 self.dmac.channels[channel].transfer_count = 440 self.dmac.channels[channel].transfer_count.wrapping_sub(1); 441 if self.dmac.channels[channel].transfer_count == 0 { 442 break; 443 } 444 } 445 } 446 } 447 448 let transfer_complete = self.dmac.channels[channel].transfer_count == 0; 449 self.dmac.channels[channel].control.dma_complete = transfer_complete; 450 451 self.update_internal_interrupt_level(); 452 453 if channel == 1 { 454 bus.acknowledge_dreq_1(); 455 } 456 457 if log::log_enabled!(log::Level::Debug) && transfer_complete { 458 log::debug!("[{}] DMA{channel} complete", self.name); 459 } 460 461 true 462 } 463} 464 465fn apply_dma_source_address_mode(channel: &mut DmaChannel, size: u32) { 466 match channel.control.source_address_mode { 467 DmaAddressMode::AutoIncrement => { 468 channel.source_address = channel.source_address.wrapping_add(size); 469 } 470 DmaAddressMode::AutoDecrement => { 471 channel.source_address = channel.source_address.wrapping_sub(size); 472 } 473 DmaAddressMode::Fixed | DmaAddressMode::Invalid => {} 474 } 475} 476 477fn apply_dma_destination_address_mode(channel: &mut DmaChannel, size: u32) { 478 match channel.control.destination_address_mode { 479 DmaAddressMode::AutoIncrement => { 480 channel.destination_address = channel.destination_address.wrapping_add(size); 481 } 482 DmaAddressMode::AutoDecrement => { 483 channel.destination_address = channel.destination_address.wrapping_sub(size); 484 } 485 DmaAddressMode::Fixed | DmaAddressMode::Invalid => {} 486 } 487}