Update to v087r04 release.
byuu says:
Changelog:
- gameboy/ -> gb/
- GameBoy -> GB
- basic memory map for GBA
- enough code to execute the first BIOS instruction (b 0x68)
I have the code resetting r(15) to 0 on an exception just as a test.
Since that flushes the pipeline, that means we're basically executing "b
0x68" at 8MHz, and nothing else.
... and I am getting __6 motherfucking FPS__ at 4.4GHz on an i7.
Something is seriously, horribly, unfuckingbelievably wrong here, and
I can't figure out what it is.
My *fully complete* ARM core on the ST018 is even less efficient and
runs at 21.47MHz, and yet I get 60fps even after emulating the SNES
CPU+PPU @ 10+MHz each as well.
... I'm stuck. I can't proceed until we figure out what in the holy fuck
is going on here. So ... if anyone can help, please do. If we can't fix
this, the GBA emulation is dead.
I was able to profile on Windows, and I've included that in this WIP
under out/log.txt.
But it looks normal to me. But yeah, there's NO. FUCKING. WAY. This code
should be running this slowly.
2012-03-18 12:35:53 +00:00
|
|
|
#include <gb/gb.hpp>
|
2010-12-28 01:53:15 +00:00
|
|
|
|
|
|
|
#define CPU_CPP
|
2012-04-26 10:51:13 +00:00
|
|
|
namespace GameBoy {
|
2010-12-28 01:53:15 +00:00
|
|
|
|
2012-04-26 10:51:13 +00:00
|
|
|
#include "mmio.cpp"
|
|
|
|
#include "memory.cpp"
|
|
|
|
#include "timing.cpp"
|
2011-01-07 11:11:56 +00:00
|
|
|
#include "serialization.cpp"
|
2010-12-28 01:53:15 +00:00
|
|
|
CPU cpu;
|
|
|
|
|
2010-12-28 06:03:02 +00:00
|
|
|
void CPU::Main() {
|
|
|
|
cpu.main();
|
|
|
|
}
|
|
|
|
|
2010-12-28 01:53:15 +00:00
|
|
|
void CPU::main() {
|
|
|
|
while(true) {
|
2011-01-07 11:11:56 +00:00
|
|
|
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
|
|
|
scheduler.sync = Scheduler::SynchronizeMode::All;
|
|
|
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
|
|
|
}
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
interrupt_test();
|
2012-04-26 10:51:13 +00:00
|
|
|
exec();
|
2010-12-28 01:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-02 04:46:54 +00:00
|
|
|
void CPU::interrupt_raise(CPU::Interrupt id) {
|
2011-01-22 08:15:49 +00:00
|
|
|
if(id == Interrupt::Vblank) {
|
|
|
|
status.interrupt_request_vblank = 1;
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.interrupt_enable_vblank) r.halt = false;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(id == Interrupt::Stat) {
|
|
|
|
status.interrupt_request_stat = 1;
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.interrupt_enable_stat) r.halt = false;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(id == Interrupt::Timer) {
|
|
|
|
status.interrupt_request_timer = 1;
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.interrupt_enable_timer) r.halt = false;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(id == Interrupt::Serial) {
|
|
|
|
status.interrupt_request_serial = 1;
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.interrupt_enable_serial) r.halt = false;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(id == Interrupt::Joypad) {
|
|
|
|
status.interrupt_request_joypad = 1;
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.interrupt_enable_joypad) r.halt = r.stop = false;
|
2011-01-02 04:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
void CPU::interrupt_test() {
|
2012-04-26 10:51:13 +00:00
|
|
|
if(r.ime) {
|
2010-12-30 07:18:47 +00:00
|
|
|
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
|
|
|
status.interrupt_request_vblank = 0;
|
|
|
|
return interrupt_exec(0x0040);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
|
|
|
|
status.interrupt_request_stat = 0;
|
|
|
|
return interrupt_exec(0x0048);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
|
|
|
|
status.interrupt_request_timer = 0;
|
|
|
|
return interrupt_exec(0x0050);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
|
|
|
|
status.interrupt_request_serial = 0;
|
|
|
|
return interrupt_exec(0x0058);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
|
|
|
|
status.interrupt_request_joypad = 0;
|
|
|
|
return interrupt_exec(0x0060);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPU::interrupt_exec(uint16 pc) {
|
2012-04-26 10:51:13 +00:00
|
|
|
r.ime = 0;
|
2010-12-30 07:18:47 +00:00
|
|
|
op_write(--r[SP], r[PC] >> 8);
|
|
|
|
op_write(--r[SP], r[PC] >> 0);
|
|
|
|
r[PC] = pc;
|
|
|
|
op_io();
|
2011-01-03 04:28:36 +00:00
|
|
|
op_io();
|
|
|
|
op_io();
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
Update to v088r08 release.
byuu says:
From this WIP, I'm starting on the impossible task of
a declarative-based GUI, which I'm calling Ethos.
base/ becomes emulator/, and we add emulator/interface.hpp, which is
a base API that all emulation cores must implement in full.
(Right now, it's kind of a hybrid to work with the old GUI and the new
GUI at the same time, of course.)
Unlike the old interfaces, the new base class also provides all general
usability hooks: loading and saving files and states, cheat codes, etc.
The new interface also contains information and vector structs to
describe all possible loading methods, controller bindings, etc; and
gives names for them all.
The actual GUI in fact should not include eg <gba/gba.hpp> anymore.
Should speed up GUI compilation.
So the idea going forward is that ethos will build a list of emulators
right when the application starts up.
Once you've appended an emulator to that list, you're done. No more GUI
changes are needed to support that system.
The GUI will have code to parse the emulator interfaces list, and build
all the requisite GUI options dynamically, declarative style.
Ultimately, once the project is finished, the new GUI should look ~99%
identical to the current GUI. But it'll probably be a whole lot smaller.
2012-04-29 06:29:54 +00:00
|
|
|
bool CPU::stop() {
|
2012-04-26 10:51:13 +00:00
|
|
|
if(status.speed_switch) {
|
|
|
|
status.speed_switch = 0;
|
|
|
|
status.speed_double ^= 1;
|
|
|
|
if(status.speed_double == 0) frequency = 4 * 1024 * 1024;
|
|
|
|
if(status.speed_double == 1) frequency = 8 * 1024 * 1024;
|
Update to v088r08 release.
byuu says:
From this WIP, I'm starting on the impossible task of
a declarative-based GUI, which I'm calling Ethos.
base/ becomes emulator/, and we add emulator/interface.hpp, which is
a base API that all emulation cores must implement in full.
(Right now, it's kind of a hybrid to work with the old GUI and the new
GUI at the same time, of course.)
Unlike the old interfaces, the new base class also provides all general
usability hooks: loading and saving files and states, cheat codes, etc.
The new interface also contains information and vector structs to
describe all possible loading methods, controller bindings, etc; and
gives names for them all.
The actual GUI in fact should not include eg <gba/gba.hpp> anymore.
Should speed up GUI compilation.
So the idea going forward is that ethos will build a list of emulators
right when the application starts up.
Once you've appended an emulator to that list, you're done. No more GUI
changes are needed to support that system.
The GUI will have code to parse the emulator interfaces list, and build
all the requisite GUI options dynamically, declarative style.
Ultimately, once the project is finished, the new GUI should look ~99%
identical to the current GUI. But it'll probably be a whole lot smaller.
2012-04-29 06:29:54 +00:00
|
|
|
return true;
|
2012-04-26 10:51:13 +00:00
|
|
|
}
|
Update to v088r08 release.
byuu says:
From this WIP, I'm starting on the impossible task of
a declarative-based GUI, which I'm calling Ethos.
base/ becomes emulator/, and we add emulator/interface.hpp, which is
a base API that all emulation cores must implement in full.
(Right now, it's kind of a hybrid to work with the old GUI and the new
GUI at the same time, of course.)
Unlike the old interfaces, the new base class also provides all general
usability hooks: loading and saving files and states, cheat codes, etc.
The new interface also contains information and vector structs to
describe all possible loading methods, controller bindings, etc; and
gives names for them all.
The actual GUI in fact should not include eg <gba/gba.hpp> anymore.
Should speed up GUI compilation.
So the idea going forward is that ethos will build a list of emulators
right when the application starts up.
Once you've appended an emulator to that list, you're done. No more GUI
changes are needed to support that system.
The GUI will have code to parse the emulator interfaces list, and build
all the requisite GUI options dynamically, declarative style.
Ultimately, once the project is finished, the new GUI should look ~99%
identical to the current GUI. But it'll probably be a whole lot smaller.
2012-04-29 06:29:54 +00:00
|
|
|
return false;
|
2012-04-26 10:51:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-28 01:53:15 +00:00
|
|
|
void CPU::power() {
|
2011-10-27 13:30:19 +00:00
|
|
|
create(Main, 4 * 1024 * 1024);
|
2012-04-26 10:51:13 +00:00
|
|
|
LR35902::power();
|
2011-01-03 04:28:36 +00:00
|
|
|
|
2010-12-29 11:03:42 +00:00
|
|
|
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
|
|
|
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
2011-10-27 00:00:17 +00:00
|
|
|
for(unsigned n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM
|
|
|
|
|
|
|
|
bus.mmio[0xff00] = this; //JOYP
|
|
|
|
bus.mmio[0xff01] = this; //SB
|
|
|
|
bus.mmio[0xff02] = this; //SC
|
|
|
|
bus.mmio[0xff04] = this; //DIV
|
|
|
|
bus.mmio[0xff05] = this; //TIMA
|
|
|
|
bus.mmio[0xff06] = this; //TMA
|
|
|
|
bus.mmio[0xff07] = this; //TAC
|
|
|
|
bus.mmio[0xff0f] = this; //IF
|
|
|
|
bus.mmio[0xff46] = this; //DMA
|
|
|
|
bus.mmio[0xffff] = this; //IE
|
|
|
|
|
|
|
|
if(system.cgb()) {
|
|
|
|
bus.mmio[0xff4d] = this; //KEY1
|
|
|
|
bus.mmio[0xff51] = this; //HDMA1
|
|
|
|
bus.mmio[0xff52] = this; //HDMA2
|
|
|
|
bus.mmio[0xff53] = this; //HDMA3
|
|
|
|
bus.mmio[0xff54] = this; //HDMA4
|
|
|
|
bus.mmio[0xff55] = this; //HDMA5
|
|
|
|
bus.mmio[0xff56] = this; //RP
|
|
|
|
bus.mmio[0xff6c] = this; //???
|
|
|
|
bus.mmio[0xff70] = this; //SVBK
|
|
|
|
bus.mmio[0xff72] = this; //???
|
|
|
|
bus.mmio[0xff73] = this; //???
|
|
|
|
bus.mmio[0xff74] = this; //???
|
|
|
|
bus.mmio[0xff75] = this; //???
|
|
|
|
bus.mmio[0xff76] = this; //???
|
|
|
|
bus.mmio[0xff77] = this; //???
|
|
|
|
}
|
2010-12-30 07:18:47 +00:00
|
|
|
|
2013-05-05 09:21:30 +00:00
|
|
|
for(auto& n : wram) n = 0x00;
|
|
|
|
for(auto& n : hram) n = 0x00;
|
2010-12-29 11:03:42 +00:00
|
|
|
|
2011-01-06 10:16:07 +00:00
|
|
|
r[PC] = 0x0000;
|
|
|
|
r[SP] = 0x0000;
|
|
|
|
r[AF] = 0x0000;
|
2010-12-28 06:03:02 +00:00
|
|
|
r[BC] = 0x0000;
|
|
|
|
r[DE] = 0x0000;
|
|
|
|
r[HL] = 0x0000;
|
|
|
|
|
2011-01-04 10:42:27 +00:00
|
|
|
status.clock = 0;
|
2010-12-30 07:18:47 +00:00
|
|
|
|
|
|
|
status.p15 = 0;
|
|
|
|
status.p14 = 0;
|
2010-12-31 05:43:47 +00:00
|
|
|
status.joyp = 0;
|
2011-01-06 10:16:07 +00:00
|
|
|
status.mlt_req = 0;
|
2010-12-30 07:18:47 +00:00
|
|
|
|
Update to v074r11 release.
byuu says:
Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
sprite; so that I could add uint8 oam[544]
- makes more sense anyway, OAM = object attribute memory, obj or
sprite are better names for Sprite rendering class
- more cleanup
2011-01-24 09:03:17 +00:00
|
|
|
status.serial_data = 0;
|
|
|
|
status.serial_bits = 0;
|
|
|
|
|
|
|
|
status.serial_transfer = 0;
|
|
|
|
status.serial_clock = 0;
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
status.div = 0;
|
|
|
|
|
|
|
|
status.tima = 0;
|
|
|
|
|
|
|
|
status.tma = 0;
|
|
|
|
|
|
|
|
status.timer_enable = 0;
|
|
|
|
status.timer_clock = 0;
|
|
|
|
|
|
|
|
status.interrupt_request_joypad = 0;
|
|
|
|
status.interrupt_request_serial = 0;
|
|
|
|
status.interrupt_request_timer = 0;
|
|
|
|
status.interrupt_request_stat = 0;
|
|
|
|
status.interrupt_request_vblank = 0;
|
|
|
|
|
2011-10-27 00:00:17 +00:00
|
|
|
status.speed_double = 0;
|
|
|
|
status.speed_switch = 0;
|
|
|
|
|
|
|
|
status.dma_source = 0;
|
|
|
|
status.dma_target = 0;
|
|
|
|
|
|
|
|
status.dma_mode = 0;
|
|
|
|
status.dma_length = 0;
|
2013-12-10 12:12:54 +00:00
|
|
|
status.dma_completed = true;
|
2011-10-27 00:00:17 +00:00
|
|
|
|
|
|
|
status.ff6c = 0;
|
|
|
|
status.ff72 = 0;
|
|
|
|
status.ff73 = 0;
|
|
|
|
status.ff74 = 0;
|
|
|
|
status.ff75 = 0;
|
|
|
|
|
|
|
|
status.wram_bank = 1;
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
status.interrupt_enable_joypad = 0;
|
|
|
|
status.interrupt_enable_serial = 0;
|
|
|
|
status.interrupt_enable_timer = 0;
|
|
|
|
status.interrupt_enable_stat = 0;
|
|
|
|
status.interrupt_enable_vblank = 0;
|
2013-12-14 06:25:12 +00:00
|
|
|
|
|
|
|
oamdma.active = false;
|
|
|
|
oamdma.bank = 0;
|
|
|
|
oamdma.offset = 0;
|
2010-12-28 06:03:02 +00:00
|
|
|
}
|
|
|
|
|
2010-12-28 01:53:15 +00:00
|
|
|
}
|