bsnes/higan/gba/cpu/dma.cpp
Tim Allen ba384a7c48 Update to v104 release.
byuu says:

Changelog:

  - emulator/interface: removed unused Region struct
  - gba/cpu: optimized CPU::step() as much as I could for a slight
    speedup¹
  - gba/cpu: synchronize the APU better during FIFO updates
  - higan/md, icarus: add automatic region detection; make it the
    default option [hex\_usr]
      - picks NTSC-J if there's more than one match ... eventually, this
        will be a setting
  - higan/md, icarus: support all three combinations of SRAM (8-bit low,
    8-bit high, 16-bit)
  - processor/arm7tdmi: fix bug when changing to THUMB mode via MSR
    [MerryMage]
  - tomoko: redesigned crash detector to only occur once for all three
    ruby drivers
      - this will reduce disk thrashing since the configuration file
        only needs to be written out one extra time
      - technically, it's twice ... but we should've always been writing
        one out on first run in case it crashes then
  - tomoko: defaulted back to the safest ruby drivers, given the optimal
    drivers have some stability concerns

¹: minor errata: spotted a typo saying `synchronize(cpu)` when the CPU
is stopped, instead of `synchronize(ppu)`. This will be fixed in the v104
official 7zip archives.

I'm kind of rushing here but, it's really good timing for me to push out
a new official release. The blocking issues are resolved or close to it,
and we need lots of testing of the new major changes.

I'm going to consider this a semi-stable testing release and leave links
to v103 just in case.
2017-08-12 20:53:13 +10:00

77 lines
1.8 KiB
C++

auto CPU::DMA::run() -> bool {
if(!active || waiting) return false;
transfer();
if(irq) cpu.irq.flag |= CPU::Interrupt::DMA0 << id;
if(drq && id == 3) cpu.irq.flag |= CPU::Interrupt::Cartridge;
return true;
}
auto CPU::DMA::transfer() -> void {
uint seek = size ? 4 : 2;
uint mode = size ? Word : Half;
mode |= latch.length == length ? Nonsequential : Sequential;
if(mode & Nonsequential) {
if((source & 0x0800'0000) && (target & 0x0800'0000)) {
//ROM -> ROM transfer
} else {
cpu.idle();
cpu.idle();
}
}
if(latch.source < 0x0200'0000) {
cpu.idle(); //cannot access BIOS
} else {
uint32 addr = latch.source;
if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1;
data = cpu.get(mode, addr);
}
if(latch.target < 0x0200'0000) {
cpu.idle(); //cannot access BIOS
} else {
uint32 addr = latch.target;
if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1;
cpu.set(mode, addr, data);
}
switch(sourceMode) {
case 0: latch.source += seek; break;
case 1: latch.source -= seek; break;
}
switch(targetMode) {
case 0: latch.target += seek; break;
case 1: latch.target -= seek; break;
case 3: latch.target += seek; break;
}
if(--latch.length == 0) {
active = false;
if(targetMode == 3) latch.target = target;
if(repeat == 1) latch.length = length;
if(repeat == 0) enable = false;
}
}
auto CPU::dmaVblank() -> void {
for(auto& dma : this->dma) {
if(dma.enable && dma.timingMode == 1) dma.active = true;
}
}
auto CPU::dmaHblank() -> void {
for(auto& dma : this->dma) {
if(dma.enable && dma.timingMode == 2) dma.active = true;
}
}
auto CPU::dmaHDMA() -> void {
auto& dma = this->dma[3];
if(dma.enable && dma.timingMode == 3) dma.active = true;
}