dma.rsannotateddma.rssource487 lines · 16.3 KB · raw

SH-2 DMA controller (DMAC)

Has 2 DMA channels that can transfer data between memory regions in parallel to CPU execution

5use crate::Sh2;
6use crate::bus::{AccessContext, BusInterface};
7use bincode::{Decode, Encode};
8use jgenesis_common::num::GetBit;
9use std::array;
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}