mirror of https://github.com/bsnes-emu/bsnes.git
183 lines
5.0 KiB
C++
183 lines
5.0 KiB
C++
#include <gba/gba.hpp>
|
|
|
|
namespace GameBoyAdvance {
|
|
|
|
#include "prefetch.cpp"
|
|
#include "bus.cpp"
|
|
#include "io.cpp"
|
|
#include "memory.cpp"
|
|
#include "dma.cpp"
|
|
#include "timer.cpp"
|
|
#include "serialization.cpp"
|
|
CPU cpu;
|
|
|
|
CPU::CPU() {
|
|
iwram = new uint8[ 32 * 1024];
|
|
ewram = new uint8[256 * 1024];
|
|
|
|
regs.dma[0].source.resize(27); regs.dma[0].run.source.resize(27);
|
|
regs.dma[0].target.resize(27); regs.dma[0].run.target.resize(27);
|
|
regs.dma[0].length.resize(14); regs.dma[0].run.length.resize(14);
|
|
|
|
regs.dma[1].source.resize(28); regs.dma[1].run.source.resize(28);
|
|
regs.dma[1].target.resize(27); regs.dma[1].run.target.resize(27);
|
|
regs.dma[1].length.resize(14); regs.dma[1].run.length.resize(14);
|
|
|
|
regs.dma[2].source.resize(28); regs.dma[2].run.source.resize(28);
|
|
regs.dma[2].target.resize(27); regs.dma[2].run.target.resize(27);
|
|
regs.dma[2].length.resize(14); regs.dma[2].run.length.resize(14);
|
|
|
|
regs.dma[3].source.resize(28); regs.dma[3].run.source.resize(28);
|
|
regs.dma[3].target.resize(28); regs.dma[3].run.target.resize(28);
|
|
regs.dma[3].length.resize(16); regs.dma[3].run.length.resize(16);
|
|
}
|
|
|
|
CPU::~CPU() {
|
|
delete[] iwram;
|
|
delete[] ewram;
|
|
}
|
|
|
|
auto CPU::Enter() -> void {
|
|
while(true) scheduler.synchronize(), cpu.main();
|
|
}
|
|
|
|
auto CPU::main() -> void {
|
|
#if defined(DEBUG)
|
|
if(crash) {
|
|
print(cpsr().t ? disassemble_thumb_instruction(pipeline.execute.address)
|
|
: disassemble_arm_instruction(pipeline.execute.address), "\n");
|
|
print(disassemble_registers(), "\n");
|
|
print("Executed: ", instructions, "\n");
|
|
while(true) step(frequency);
|
|
}
|
|
#endif
|
|
|
|
processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag);
|
|
|
|
if(regs.mode == Registers::Mode::Stop) {
|
|
if(!(regs.irq.enable & regs.irq.flag & Interrupt::Keypad)) {
|
|
syncStep(16); //STOP does not advance timers
|
|
} else {
|
|
regs.mode = Registers::Mode::Normal;
|
|
}
|
|
return;
|
|
}
|
|
|
|
dmaRun();
|
|
|
|
if(regs.mode == Registers::Mode::Halt) {
|
|
if(!(regs.irq.enable & regs.irq.flag)) {
|
|
step(16);
|
|
} else {
|
|
regs.mode = Registers::Mode::Normal;
|
|
}
|
|
return;
|
|
}
|
|
|
|
exec();
|
|
}
|
|
|
|
auto CPU::step(uint clocks) -> void {
|
|
timerStep(clocks);
|
|
syncStep(clocks);
|
|
}
|
|
|
|
auto CPU::syncStep(uint clocks) -> void {
|
|
Thread::step(clocks);
|
|
synchronize(ppu);
|
|
synchronize(apu);
|
|
}
|
|
|
|
auto CPU::keypadRun() -> void {
|
|
//lookup table to convert button indexes to Emulator::Interface indexes
|
|
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1, 7, 6};
|
|
|
|
if(!regs.keypad.control.enable) return;
|
|
|
|
bool test = regs.keypad.control.condition; //0 = OR, 1 = AND
|
|
for(auto n : range(10)) {
|
|
if(!regs.keypad.control.flag[n]) continue;
|
|
bool input = platform->inputPoll(0, 0, lookup[n]);
|
|
if(regs.keypad.control.condition == 0) test |= input;
|
|
if(regs.keypad.control.condition == 1) test &= input;
|
|
}
|
|
if(test) regs.irq.flag |= Interrupt::Keypad;
|
|
}
|
|
|
|
auto CPU::power() -> void {
|
|
create(CPU::Enter, 16'777'216);
|
|
|
|
ARM::power();
|
|
for(auto n : range( 32 * 1024)) iwram[n] = 0;
|
|
for(auto n : range(256 * 1024)) ewram[n] = 0;
|
|
|
|
for(auto& dma : regs.dma) {
|
|
dma.source = 0;
|
|
dma.target = 0;
|
|
dma.length = 0;
|
|
dma.data = 0;
|
|
dma.control.targetmode = 0;
|
|
dma.control.sourcemode = 0;
|
|
dma.control.repeat = 0;
|
|
dma.control.size = 0;
|
|
dma.control.drq = 0;
|
|
dma.control.timingmode = 0;
|
|
dma.control.irq = 0;
|
|
dma.control.enable = 0;
|
|
dma.pending = 0;
|
|
dma.run.target = 0;
|
|
dma.run.source = 0;
|
|
dma.run.length = 0;
|
|
}
|
|
for(auto& timer : regs.timer) {
|
|
timer.period = 0;
|
|
timer.reload = 0;
|
|
timer.pending = false;
|
|
timer.control.frequency = 0;
|
|
timer.control.cascade = 0;
|
|
timer.control.irq = 0;
|
|
timer.control.enable = 0;
|
|
}
|
|
regs.serial = {};
|
|
for(auto& flag : regs.keypad.control.flag) flag = 0;
|
|
regs.keypad.control.enable = 0;
|
|
regs.keypad.control.condition = 0;
|
|
regs.joybus = {};
|
|
regs.ime = 0;
|
|
regs.irq.enable = 0;
|
|
regs.irq.flag = 0;
|
|
for(auto& nwait : regs.wait.control.nwait) nwait = 0;
|
|
for(auto& swait : regs.wait.control.swait) swait = 0;
|
|
regs.wait.control.phi = 0;
|
|
regs.wait.control.prefetch = 0;
|
|
regs.wait.control.gametype = 0; //0 = GBA, 1 = GBC
|
|
regs.memory.control.disable = 0;
|
|
regs.memory.control.unknown1 = 0;
|
|
regs.memory.control.ewram = 1;
|
|
regs.memory.control.ewramwait = 13;
|
|
regs.memory.control.unknown2 = 0;
|
|
regs.postboot = 0;
|
|
regs.mode = Registers::Mode::Normal;
|
|
regs.clock = 0;
|
|
|
|
prefetch = {};
|
|
prefetch.wait = 1;
|
|
|
|
pending.dma.vblank = 0;
|
|
pending.dma.hblank = 0;
|
|
pending.dma.hdma = 0;
|
|
|
|
active.dma = false;
|
|
|
|
for(uint n = 0x0b0; n <= 0x0df; n++) bus.io[n] = this; //DMA
|
|
for(uint n = 0x100; n <= 0x10f; n++) bus.io[n] = this; //Timers
|
|
for(uint n = 0x120; n <= 0x12b; n++) bus.io[n] = this; //Serial
|
|
for(uint n = 0x130; n <= 0x133; n++) bus.io[n] = this; //Keypad
|
|
for(uint n = 0x134; n <= 0x159; n++) bus.io[n] = this; //Serial
|
|
for(uint n = 0x200; n <= 0x209; n++) bus.io[n] = this; //System
|
|
for(uint n = 0x300; n <= 0x301; n++) bus.io[n] = this; //System
|
|
//0x080-0x083 mirrored via gba/memory/memory.cpp //System
|
|
}
|
|
|
|
}
|