Files
bsnes/higan/gba/cpu/cpu.hpp
Tim Allen d4876a831f Update to v103r07 release.
byuu says:

Changelog:

  - gba/cpu: massive code cleanup effort
  - gba/cpu: DMA can run in between active instructions¹
  - gba/cpu: added two-cycle startup delay between DMA activation and
    DMA transfers²
  - processor/spc700: BBC, BBC, CBNE cycle 4 is an idle cycle
  - processor/spc700: ADDW, SUBW, MOVW (read) cycle 4 is an idle cycle

¹: unfortunately, this causes yet another performance penalty for the
poor GBA core =( Also, I think I may have missed disabling DMAs while
the CPU is stopped. I'll fix that in the next WIP.

²: I put the waiting counter decrement at the wrong place, so this
doesn't actually work. Needs to be more like
this:

    auto CPU::step(uint clocks) -> void {
      for(auto _ : range(clocks)) {
        for(auto& timer : this->timer) timer.run();
        for(auto& dma : this->dma) if(dma.active && dma.waiting) dma.waiting--;
        context.clock++;
      }
      ...

    auto CPU::DMA::run() -> bool {
      if(cpu.stopped() || !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;
    }

Of course, the real fix will be restructuring how DMA works, so that
it's always running in parallel with the CPU instead of this weird
design where it tries to run all channels in some kind of loop until no
channels are active anymore whenever one channel is activated.

Not really sure how to design that yet, however.
2017-07-05 15:29:27 +10:00

209 lines
4.1 KiB
C++

struct CPU : Processor::ARM, Thread, IO {
using ARM::read;
using ARM::write;
struct Interrupt { enum : uint {
VBlank = 0x0001,
HBlank = 0x0002,
VCoincidence = 0x0004,
Timer0 = 0x0008,
Timer1 = 0x0010,
Timer2 = 0x0020,
Timer3 = 0x0040,
Serial = 0x0080,
DMA0 = 0x0100,
DMA1 = 0x0200,
DMA2 = 0x0400,
DMA3 = 0x0800,
Keypad = 0x1000,
Cartridge = 0x2000,
};};
inline auto clock() const -> uint { return context.clock; }
inline auto halted() const -> bool { return context.halted; }
inline auto stopped() const -> bool { return context.stopped; }
//cpu.cpp
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void override;
auto power() -> void;
//prefetch.cpp
auto prefetchSync(uint32 addr) -> void;
auto prefetchStep(uint clocks) -> void;
auto prefetchWait() -> void;
auto prefetchRead() -> uint16;
//bus.cpp
auto _idle() -> void override;
auto _read(uint mode, uint32 addr) -> uint32 override;
auto _write(uint mode, uint32 addr, uint32 word) -> void override;
auto _wait(uint mode, uint32 addr) -> uint;
//io.cpp
auto readIO(uint32 addr) -> uint8;
auto writeIO(uint32 addr, uint8 byte) -> void;
auto readIWRAM(uint mode, uint32 addr) -> uint32;
auto writeIWRAM(uint mode, uint32 addr, uint32 word) -> void;
auto readEWRAM(uint mode, uint32 addr) -> uint32;
auto writeEWRAM(uint mode, uint32 addr, uint32 word) -> void;
//dma.cpp
auto dmaVblank() -> void;
auto dmaHblank() -> void;
auto dmaHDMA() -> void;
//timer.cpp
auto runFIFO(uint n) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 iwram[ 32 * 1024];
uint8 ewram[256 * 1024];
//private:
struct DMA {
//dma.cpp
auto run() -> bool;
auto transfer() -> void;
uint2 id;
boolean active;
natural waiting;
uint2 targetMode;
uint2 sourceMode;
uint1 repeat;
uint1 size;
uint1 drq;
uint2 timingMode;
uint1 irq;
uint1 enable;
VariadicNatural source;
VariadicNatural target;
VariadicNatural length;
uint32 data;
struct Latch {
VariadicNatural target;
VariadicNatural source;
VariadicNatural length;
} latch;
} dma[4];
struct Timer {
//timer.cpp
auto run() -> void;
auto step() -> void;
uint2 id;
boolean pending;
uint16 period;
uint16 reload;
uint2 frequency;
uint1 cascade;
uint1 irq;
uint1 enable;
} timer[4];
struct Serial {
uint1 shiftClockSelect;
uint1 shiftClockFrequency;
uint1 transferEnableReceive;
uint1 transferEnableSend;
uint1 startBit;
uint1 transferLength;
uint1 irqEnable;
uint16 data[4];
uint8 data8;
} serial;
struct Keypad {
//auto keypad.cpp
auto run() -> void;
uint1 enable;
uint1 condition;
uint1 flag[10];
} keypad;
struct Joybus {
uint1 sc;
uint1 sd;
uint1 si;
uint1 so;
uint1 scMode;
uint1 sdMode;
uint1 siMode;
uint1 soMode;
uint1 siIRQEnable;
uint2 mode;
uint1 resetSignal;
uint1 receiveComplete;
uint1 sendComplete;
uint1 resetIRQEnable;
uint32 receive;
uint32 transmit;
uint1 receiveFlag;
uint1 sendFlag;
uint2 generalFlag;
} joybus;
struct IRQ {
uint1 ime;
uint16 enable;
uint16 flag;
} irq;
struct Wait {
uint2 nwait[4];
uint1 swait[4];
uint2 phi;
uint1 prefetch;
uint1 gameType;
} wait;
struct Memory {
uint1 disable;
uint3 unknown1;
uint1 ewram = 1;
uint4 ewramWait = 13;
uint4 unknown2;
} memory;
struct {
uint16 slot[8];
uint32 addr; //read location of slot buffer
uint32 load; //write location of slot buffer
integer wait = 1; //number of clocks before next slot load
auto empty() const { return addr == load; }
auto full() const { return load - addr == 16; }
} prefetch;
struct Context {
natural clock;
boolean halted;
boolean stopped;
boolean booted; //set to true by the GBA BIOS
boolean dmaActive;
} context;
};
extern CPU cpu;