diff --git a/CorgiDS/CorgiDS.pro b/CorgiDS/CorgiDS.pro index a148e45..cc6063d 100644 --- a/CorgiDS/CorgiDS.pro +++ b/CorgiDS/CorgiDS.pro @@ -46,7 +46,9 @@ SOURCES += \ ../src/bios.cpp \ ../src/qt/audiodevice.cpp \ ../src/disasm_thumb.cpp \ - ../src/debugger.cpp + ../src/debugger.cpp \ + ../src/slot2.cpp \ + ../src/gba/gbarw.cpp DEFINES += QT_DEPRECATED_WARNINGS DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 @@ -80,7 +82,8 @@ HEADERS += \ ../src/qt/emuthread.hpp \ ../src/bios.hpp \ ../src/qt/audiodevice.hpp \ - ../src/debugger.hpp + ../src/debugger.hpp \ + ../src/slot2.hpp FORMS += \ ../src/qt/configwindow.ui \ diff --git a/src/arm7rw.cpp b/src/arm7rw.cpp index 80ce025..ceff9de 100644 --- a/src/arm7rw.cpp +++ b/src/arm7rw.cpp @@ -8,6 +8,9 @@ uint32_t Emulator::arm7_read_word(uint32_t address) { + //TODO: bad hack. + if (gba_mode) + return gba_read_word(address); if (address >= MAIN_RAM_START && address < SHARED_WRAM_START) return *(uint32_t*)&main_RAM[address & MAIN_RAM_MASK]; if (address >= ARM7_WRAM_START && address < IO_REGS_START) @@ -77,8 +80,8 @@ uint32_t Emulator::arm7_read_word(uint32_t address) } if (address >= 0x06000000 && address < 0x07000000) return gpu.read_ARM7(address); - if (address >= GBA_ROM_START) - return 0xFFFFFFFF; + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); printf("\n(7) Unrecognized word read from $%08X", address); //exit(2); return 0; @@ -86,6 +89,9 @@ uint32_t Emulator::arm7_read_word(uint32_t address) uint16_t Emulator::arm7_read_halfword(uint32_t address) { + //TODO: bad hack. + if (gba_mode) + return gba_read_halfword(address); if (address < 0x4000) { if (arm7.get_PC() > 0x4000) @@ -193,8 +199,8 @@ uint16_t Emulator::arm7_read_halfword(uint32_t address) return wifi.read(address); if (address >= 0x06000000 && address < 0x07000000) return gpu.read_ARM7(address); - if (address >= GBA_ROM_START) - return 0xFFFF; + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); printf("\n(7) Unrecognized halfword read from $%08X", address); //exit(2); return 0; @@ -202,6 +208,9 @@ uint16_t Emulator::arm7_read_halfword(uint32_t address) uint8_t Emulator::arm7_read_byte(uint32_t address) { + //TODO: bad hack. + if (gba_mode) + return gba_read_byte(address); if (address >= MAIN_RAM_START && address < SHARED_WRAM_START) return main_RAM[address & MAIN_RAM_MASK]; if (address >= ARM7_WRAM_START && address < IO_REGS_START) @@ -253,6 +262,8 @@ uint8_t Emulator::arm7_read_byte(uint32_t address) } if (address >= 0x04000400 && address < 0x04000500) return spu.read_channel_byte(address); + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); printf("\n(7) Unrecognized byte read from $%08X", address); //exit(2); return 0; @@ -260,10 +271,11 @@ uint8_t Emulator::arm7_read_byte(uint32_t address) void Emulator::arm7_write_word(uint32_t address, uint32_t word) { - if (address == 0x027E0014) + //TODO: bad hack. + if (gba_mode) { - printf("\n(7) Write of $%08X to $%08X", word, address); - //exit(0); + gba_write_word(address, word); + return; } if (address >= MAIN_RAM_START && address < SHARED_WRAM_START) { @@ -413,6 +425,12 @@ void Emulator::arm7_write_word(uint32_t address, uint32_t word) void Emulator::arm7_write_halfword(uint32_t address, uint16_t halfword) { + //TODO: bad hack. + if (gba_mode) + { + gba_write_halfword(address, halfword); + return; + } if (address >= MAIN_RAM_START && address < SHARED_WRAM_START) { *(uint16_t*)&main_RAM[address & MAIN_RAM_MASK] = halfword; @@ -581,6 +599,12 @@ void Emulator::arm7_write_halfword(uint32_t address, uint16_t halfword) void Emulator::arm7_write_byte(uint32_t address, uint8_t byte) { + //TODO: bad hack. + if (gba_mode) + { + gba_write_byte(address, byte); + return; + } if (address >= MAIN_RAM_START && address < SHARED_WRAM_START) { main_RAM[address & MAIN_RAM_MASK] = byte; @@ -639,6 +663,9 @@ void Emulator::arm7_write_byte(uint32_t address, uint8_t byte) case 0x04000301: switch (byte) { + case 0x40: + start_gba_mode(true); + break; case 0x80: arm7.halt(); /*printf("\nHalted ARM7"); diff --git a/src/arm9rw.cpp b/src/arm9rw.cpp index 623758b..ceee055 100644 --- a/src/arm9rw.cpp +++ b/src/arm9rw.cpp @@ -154,8 +154,8 @@ uint32_t Emulator::arm9_read_word(uint32_t address) return gpu.read_lcdc(address); if (address >= OAM_START && address < GBA_ROM_START) return gpu.read_OAM(address); - if (address >= GBA_ROM_START) - return 0xFFFFFFFF; + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); //Ignore reads from NULL printf("\n(9) Unrecognized word read from $%08X", address); //exit(1); @@ -321,8 +321,8 @@ uint16_t Emulator::arm9_read_halfword(uint32_t address) return gpu.read_objb(address); if (address >= VRAM_LCDC_A && address < VRAM_LCDC_END) return gpu.read_lcdc(address); - if (address >= GBA_ROM_START) - return 0xFFFF; + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); printf("\n(9) Unrecognized halfword read from $%08X", address); return 0; //exit(1); @@ -398,8 +398,8 @@ uint8_t Emulator::arm9_read_byte(uint32_t address) return gpu.read_lcdc(address); if (address >= OAM_START && address < GBA_ROM_START) return gpu.read_OAM(address); - if (address >= GBA_ROM_START) - return 0xFF; + if (address >= GBA_ROM_START && address < GBA_RAM_START) + return slot2.read(address); printf("\n(9) Unrecognized byte read from $%08X", address); //exit(1); return 0; diff --git a/src/config.cpp b/src/config.cpp index 6a054e7..9dccf6c 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -12,7 +12,9 @@ namespace Config std::string arm9_bios_path; std::string firmware_path; std::string savelist_path; + std::string gba_bios_path; bool direct_boot_enabled; + bool gba_direct_boot; bool pause_when_unfocused; bool bg_enable[4]; diff --git a/src/config.hpp b/src/config.hpp index eb5c96f..ea6809c 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -14,7 +14,9 @@ namespace Config extern std::string arm9_bios_path; extern std::string firmware_path; extern std::string savelist_path; + extern std::string gba_bios_path; extern bool direct_boot_enabled; + extern bool gba_direct_boot; extern bool pause_when_unfocused; extern bool bg_enable[4]; diff --git a/src/emulator.cpp b/src/emulator.cpp index de433c0..0028a7d 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -75,6 +75,7 @@ void Emulator::power_on() { for (int i = 0; i < 4; i++) Config::bg_enable[i] = true; + gba_mode = false; cycle_count = 0; arm9.power_on(); arm7.power_on(); @@ -161,12 +162,22 @@ int Emulator::load_ROM(string ROM_file_name) void Emulator::load_bios7(uint8_t *bios) { - memcpy(arm7_bios, bios, 16384 * sizeof(uint8_t)); + memcpy(arm7_bios, bios, BIOS7_SIZE); } void Emulator::load_bios9(uint8_t *bios) { - memcpy(arm9_bios, bios, 4096 * sizeof(uint8_t)); + memcpy(arm9_bios, bios, BIOS9_SIZE); +} + +void Emulator::load_bios_gba(uint8_t *bios) +{ + memcpy(gba_bios, bios, BIOS_GBA_SIZE); +} + +void Emulator::load_slot2(uint8_t *data, uint64_t size) +{ + slot2.load_data(data, size); } void Emulator::load_firmware(uint8_t *firmware) @@ -184,7 +195,7 @@ int Emulator::load_firmware() return 1; } - arm9_bios_file.read((char*)arm9_bios, 4096 * sizeof(uint8_t)); + arm9_bios_file.read((char*)arm9_bios, BIOS9_SIZE); printf("ARM9 BIOS loaded successfully.\n"); arm9_bios_file.close(); @@ -197,11 +208,23 @@ int Emulator::load_firmware() return 1; } - arm7_bios_file.read((char*)arm7_bios, 16384 * sizeof(uint8_t)); + arm7_bios_file.read((char*)arm7_bios, BIOS7_SIZE); printf("ARM7 BIOS loaded successfully.\n"); arm7_bios_file.close(); + ifstream gba_bios_file(Config::gba_bios_path, ios::in | ios::binary); + if (!gba_bios_file.is_open()) + { + printf("Warning: failed to load GBA BIOS\n"); + } + else + { + gba_bios_file.read((char*)gba_bios, BIOS_GBA_SIZE); + gba_bios_file.close(); + printf("GBA BIOS loaded successfully.\n"); + } + return spi.init(Config::firmware_path); } @@ -312,6 +335,36 @@ void Emulator::run() cart.save_check(); } +void Emulator::run_gba() +{ + gpu.start_frame(); + while (!gpu.is_frame_complete()) + { + arm7.execute(); + } +} + +bool Emulator::is_gba() +{ + return gba_mode; +} + +//Only use throw_exception when emulation has started +void Emulator::start_gba_mode(bool throw_exception) +{ + gba_mode = true; + arm7.jp(0, true); + debug(); + //Allocate VRAM C and D as 256 KB work RAM + gpu.set_VRAMCNT_C(0x82); + gpu.set_VRAMCNT_D(0x86); + if (throw_exception) + { + //Signal to the emulation thread that emulation has switched from NDS to GBA + throw "!"; + } +} + uint64_t Emulator::get_timestamp() { return system_timestamp; diff --git a/src/emulator.hpp b/src/emulator.hpp index 112a8b4..9308b43 100644 --- a/src/emulator.hpp +++ b/src/emulator.hpp @@ -15,6 +15,7 @@ #include "interrupts.hpp" #include "ipc.hpp" #include "rtc.hpp" +#include "slot2.hpp" #include "spi.hpp" #include "spu.hpp" #include "timers.hpp" @@ -75,16 +76,20 @@ class Emulator NDS_DMA dma; GPU gpu; RealTimeClock rtc; + Slot2Device slot2; SPI_Bus spi; SPU spu; NDS_Timing timers; WiFi wifi; + + bool gba_mode; uint8_t main_RAM[1024 * 1024 * 4]; //4 MB uint8_t shared_WRAM[1024 * 32]; //32 KB uint8_t arm7_WRAM[1024 * 64]; //64 KB uint8_t arm9_bios[BIOS9_SIZE]; uint8_t arm7_bios[BIOS7_SIZE]; + uint8_t gba_bios[BIOS_GBA_SIZE]; //Scheduling uint64_t system_timestamp; @@ -136,9 +141,11 @@ class Emulator Emulator(); int init(); int load_firmware(); + void load_bios_gba(uint8_t* bios); void load_bios7(uint8_t* bios); void load_bios9(uint8_t* bios); void load_firmware(uint8_t* firmware); + void load_slot2(uint8_t* data, uint64_t size); void load_save_database(std::string name); int load_ROM(std::string ROM_name); @@ -149,8 +156,12 @@ class Emulator void direct_boot(); void debug(); void run(); + void run_gba(); bool requesting_interrupt(int cpu_id); + bool is_gba(); + void start_gba_mode(bool throw_exception); + uint64_t get_timestamp(); void get_upper_frame(uint32_t* buffer); @@ -188,6 +199,13 @@ class Emulator void arm7_write_word(uint32_t address, uint32_t word); void arm7_write_halfword(uint32_t address, uint16_t halfword); void arm7_write_byte(uint32_t address, uint8_t byte); + + uint32_t gba_read_word(uint32_t address); + uint16_t gba_read_halfword(uint32_t address); + uint8_t gba_read_byte(uint32_t address); + void gba_write_word(uint32_t address, uint32_t word); + void gba_write_halfword(uint32_t address, uint16_t halfword); + void gba_write_byte(uint32_t address, uint8_t byte); void cart_copy_keybuffer(uint8_t* buffer); void cart_write_header(uint32_t address, uint16_t halfword); diff --git a/src/gba/gbarw.cpp b/src/gba/gbarw.cpp new file mode 100644 index 0000000..4c648b0 --- /dev/null +++ b/src/gba/gbarw.cpp @@ -0,0 +1,108 @@ +#include "../emulator.hpp" + +uint32_t Emulator::gba_read_word(uint32_t address) +{ + if (address < 0x4000) + return *(uint32_t*)&gba_bios[address]; + if (address >= 0x02000000 && address < 0x02040000) + return gpu.read_ARM7(address); + if (address >= 0x03000000 && address < 0x03008000) + return *(uint32_t*)&shared_WRAM[address & 0x7FFF]; + if (address >= 0x08000000 && address < 0x0A000000) + return slot2.read(address); + printf("\nUnrecognized read32 $%08X", address); + return 0; + //throw "[GBA_MEM] Unrecognized read32"; +} + +uint16_t Emulator::gba_read_halfword(uint32_t address) +{ + if (address < 0x4000) + return *(uint16_t*)&gba_bios[address]; + if (address >= 0x02000000 && address < 0x02040000) + return gpu.read_ARM7(address); + if (address >= 0x03000000 && address < 0x03008000) + return *(uint16_t*)&shared_WRAM[address & 0x7FFF]; + if (address >= 0x08000000 && address < 0x0A000000) + return slot2.read(address); + printf("\nUnrecognized read16 $%08X", address); + return 0; + //throw "[GBA_MEM] Unrecognized read16"; +} + +uint8_t Emulator::gba_read_byte(uint32_t address) +{ + if (address < 0x4000) + return gba_bios[address]; + if (address >= 0x02000000 && address < 0x02040000) + return gpu.read_ARM7(address); + if (address >= 0x03000000 && address < 0x03008000) + return shared_WRAM[address & 0x7FFF]; + if (address >= 0x08000000 && address < 0x0A000000) + return slot2.read(address); + switch (address) + { + case 0x04000300: + return POSTFLG7; + } + printf("\nUnrecognized read8 $%08X", address); + return 0; + //throw "[GBA_MEM] Unrecognized read8"; +} + +void Emulator::gba_write_word(uint32_t address, uint32_t word) +{ + if (address >= 0x02000000 && address < 0x02040000) + { + gpu.write_ARM7(address + 0x04000000, word); + return; + } + if (address >= 0x03000000 && address < 0x03008000) + { + *(uint32_t*)&shared_WRAM[address & 0x7FFF] = word; + return; + } + printf("\nUnrecognized write32 $%08X $%08X", address, word); + //throw "[GBA_MEM] Unrecognized write32"; +} + +void Emulator::gba_write_halfword(uint32_t address, uint16_t halfword) +{ + if (address >= 0x02000000 && address < 0x02040000) + { + gpu.write_ARM7(address + 0x04000000, halfword); + return; + } + if (address >= 0x03000000 && address < 0x03008000) + { + *(uint16_t*)&shared_WRAM[address & 0x7FFF] = halfword; + return; + } + printf("\nUnrecognized write16 $%08X $%04X", address, halfword); + //throw "[GBA_MEM] Unrecognized write16"; +} + +void Emulator::gba_write_byte(uint32_t address, uint8_t byte) +{ + if (address >= 0x02000000 && address < 0x02040000) + { + gpu.write_ARM7(address + 0x04000000, byte); + return; + } + if (address >= 0x03000000 && address < 0x03008000) + { + shared_WRAM[address & 0x7FFF] = byte; + return; + } + switch (address) + { + case 0x04000208: + int7_reg.IME = byte & 0x1; + return; + case 0x04000300: + POSTFLG7 = byte & 0x1; + return; + } + printf("\nUnrecognized write8 $%08X $%02X", address, byte); + //throw "[GBA_MEM] Unrecognized write8"; +} diff --git a/src/memconsts.h b/src/memconsts.h index 4ca5b91..14b282f 100644 --- a/src/memconsts.h +++ b/src/memconsts.h @@ -49,6 +49,7 @@ #define VRAM_I_SIZE 1024 * 16 #define BIOS9_SIZE 1024 * 4 #define BIOS7_SIZE 1024 * 16 +#define BIOS_GBA_SIZE 1024 * 16 //Masks #define ITCM_MASK 0x7FFF diff --git a/src/qt/configwindow.cpp b/src/qt/configwindow.cpp index 27fc456..13b2de5 100644 --- a/src/qt/configwindow.cpp +++ b/src/qt/configwindow.cpp @@ -19,6 +19,7 @@ ConfigWindow::ConfigWindow(QWidget *parent) : ui->arm9_BIOS_name->setReadOnly(true); ui->firmware_name->setReadOnly(true); ui->savelist_name->setReadOnly(true); + ui->gba_BIOS_name->setReadOnly(true); setWindowTitle("Emulator Configuration"); @@ -26,10 +27,14 @@ ConfigWindow::ConfigWindow(QWidget *parent) : Config::arm9_bios_path = cfg.value("boot/bios9path").toString().toStdString(); Config::firmware_path = cfg.value("boot/firmwarepath").toString().toStdString(); Config::savelist_path = cfg.value("saves/savelistpath").toString().toStdString(); + Config::gba_bios_path = cfg.value("boot/gbapath").toString().toStdString(); Config::direct_boot_enabled = cfg.value("boot/directboot").toBool(); ui->toggle_direct_boot->setChecked(Config::direct_boot_enabled); + Config::gba_direct_boot = cfg.value("boot/gbadirectboot").toBool(); + ui->toggle_gba_boot->setChecked(Config::gba_direct_boot); + Config::pause_when_unfocused = false; update_ui(); @@ -84,7 +89,11 @@ void ConfigWindow::update_ui() QString save_path(Config::savelist_path.c_str()); ui->savelist_name->setText(QFileInfo(save_path).fileName()); + QString gba_path(Config::gba_bios_path.c_str()); + ui->gba_BIOS_name->setText(QFileInfo(gba_path).fileName()); + ui->toggle_direct_boot->setChecked(Config::direct_boot_enabled); + ui->toggle_gba_boot->setChecked(Config::gba_direct_boot); } void ConfigWindow::on_find_savelist_clicked() @@ -94,3 +103,17 @@ void ConfigWindow::on_find_savelist_clicked() cfg.setValue("saves/savelistpath", path); update_ui(); } + +void ConfigWindow::on_find_gba_BIOS_clicked() +{ + QString path = QFileDialog::getOpenFileName(this, tr("Load GBA BIOS"), "", "GBA BIOS (*.bin *.rom)"); + Config::gba_bios_path = path.toStdString(); + cfg.setValue("boot/gbapath", path); + update_ui(); +} + +void ConfigWindow::on_toggle_gba_boot_clicked(bool checked) +{ + Config::gba_direct_boot = checked; + cfg.setValue("boot/gbadirectboot", checked); +} diff --git a/src/qt/configwindow.hpp b/src/qt/configwindow.hpp index 7db4a72..719edd2 100644 --- a/src/qt/configwindow.hpp +++ b/src/qt/configwindow.hpp @@ -33,6 +33,10 @@ class ConfigWindow : public QWidget void on_find_savelist_clicked(); + void on_find_gba_BIOS_clicked(); + + void on_toggle_gba_boot_clicked(bool checked); + private: QSettings cfg; Ui::ConfigWindow *ui; diff --git a/src/qt/configwindow.ui b/src/qt/configwindow.ui index 5eda1e1..8d588ad 100644 --- a/src/qt/configwindow.ui +++ b/src/qt/configwindow.ui @@ -7,7 +7,7 @@ 0 0 360 - 210 + 274 @@ -17,57 +17,73 @@ 10 - 170 - 291 + 210 + 331 20 - Directly boot game ROM + Directly boot NDS games (skip boot-up) - + 10 - 0 - 341 - 161 + 240 + 331 + 20 + + + + Autoboot GBA games (starts upon loading ROM) + + + + + + 10 + 10 + 330 + 191 - - + + ARM7 BIOS file: - - - - true + + + + + + + Browse... - - - - - + + - Savelist file: + ARM9 BIOS file: - - + + + + + - ARM9 BIOS file: + Browse... - + Firmware file: @@ -75,34 +91,52 @@ - - - - + - - + + Browse... - - + + - Browse... + Savelist file: + + + + + + + true - + Browse... + + + + GBA BIOS file: + + + + + + + true + + + - + Browse... diff --git a/src/qt/emuthread.cpp b/src/qt/emuthread.cpp index ae45306..f6875da 100644 --- a/src/qt/emuthread.cpp +++ b/src/qt/emuthread.cpp @@ -44,6 +44,19 @@ int EmuThread::load_game(QString ROM_name) return error; } +void EmuThread::load_slot2(uint8_t* data, uint64_t size) +{ + load_mutex.lock(); + e.load_slot2(data, size); + if (Config::gba_direct_boot) + { + e.power_on(); + e.start_gba_mode(false); + unpause(GAME_NOT_STARTED); + } + load_mutex.unlock(); +} + Emulator* EmuThread::get_emulator() { return &e; @@ -75,12 +88,18 @@ void EmuThread::run() auto last_update = chrono::system_clock::now(); try { - e.run(); + if (e.is_gba()) + e.run_gba(); + else + e.run(); } catch (const char* error) { - pause(GAME_NOT_STARTED); - emit emulation_error(error); + if (error[0] != '!') + { + pause(GAME_NOT_STARTED); + emit emulation_error(error); + } } frames++; e.get_upper_frame(upper_buffer); diff --git a/src/qt/emuthread.hpp b/src/qt/emuthread.hpp index 330bcea..576f17e 100644 --- a/src/qt/emuthread.hpp +++ b/src/qt/emuthread.hpp @@ -49,6 +49,7 @@ class EmuThread : public QThread int init(); int load_firmware(); void load_save_database(); + void load_slot2(uint8_t* data, uint64_t size); int load_game(QString ROM_file); Emulator* get_emulator(); diff --git a/src/qt/emuwindow.cpp b/src/qt/emuwindow.cpp index d384f7b..64087db 100644 --- a/src/qt/emuwindow.cpp +++ b/src/qt/emuwindow.cpp @@ -4,6 +4,8 @@ See LICENSE.txt for details */ +#include + #include #include #include @@ -14,6 +16,8 @@ #include "../config.hpp" #include "emuwindow.hpp" +using namespace std; + EmuWindow::EmuWindow(QWidget *parent) : QMainWindow(parent) { @@ -21,6 +25,7 @@ EmuWindow::EmuWindow(QWidget *parent) : QMainWindow(parent) int EmuWindow::initialize() { + e = emuthread.get_emulator(); if (emuthread.init()) return 1; @@ -32,12 +37,16 @@ int EmuWindow::initialize() load_ROM_act->setShortcuts(QKeySequence::Open); connect(load_ROM_act, &QAction::triggered, this, &EmuWindow::load_ROM); + //load_GBA_ROM_act = new QAction(tr("&Load GBA ROM..."), this); + //connect(load_GBA_ROM_act, &QAction::triggered, this, &EmuWindow::load_GBA_ROM); + screenshot_act = new QAction(tr("&Save Screenshot As..."), this); screenshot_act->setShortcut(Qt::Key_F2); connect(screenshot_act, &QAction::triggered, this, &EmuWindow::screenshot); file_menu = menuBar()->addMenu(tr("&File")); file_menu->addAction(load_ROM_act); + //file_menu->addAction(load_GBA_ROM_act); file_menu->addAction(screenshot_act); config_act = new QAction(tr("&Config"), this); @@ -63,7 +72,7 @@ int EmuWindow::initialize() setWindowTitle("CorgiDS"); show(); - spu_audio.set_SPU(emuthread.get_emulator()->get_SPU()); + spu_audio.set_SPU(e->get_SPU()); spu_audio.open(QIODevice::ReadOnly); //Initialize audio @@ -296,7 +305,7 @@ void EmuWindow::load_ROM() { audio->stop(); emuthread.pause(PAUSE_EVENT::LOADING_ROM); - if (emuthread.load_firmware()) + if (e->load_firmware()) { QMessageBox::critical(this, "Error", "Please load the BIOS and firmware images before " "loading a game ROM."); @@ -323,6 +332,44 @@ void EmuWindow::load_ROM() audio->start(&spu_audio); } +void EmuWindow::load_GBA_ROM() +{ + audio->stop(); + emuthread.pause(PAUSE_EVENT::LOADING_ROM); + //Load BIOS + ifstream bios_file(Config::gba_bios_path, ios::binary); + if (!bios_file.is_open()) + { + QMessageBox::critical(this, "Error", "Please load the GBA BIOS image before " + "loading a GBA ROM."); + emuthread.unpause(PAUSE_EVENT::LOADING_ROM); + return; + } + uint8_t* BIOS = new uint8_t[BIOS_GBA_SIZE]; + bios_file.read((char*)BIOS, BIOS_GBA_SIZE); + bios_file.close(); + e->load_bios_gba(BIOS); + delete[] BIOS; + QString name = QFileDialog::getOpenFileName(this, tr("Load GBA ROM"), "", "GBA ROMs (*.gba)"); + if (name.length()) + { + ifstream file(name.toStdString(), ios::binary | ios::ate); + if (file.is_open()) + { + uint64_t ROM_size = file.tellg(); + file.seekg(0, ios::beg); + uint8_t* data = new uint8_t[ROM_size]; + file.read((char*)data, ROM_size); + file.close(); + emuthread.load_slot2(data, ROM_size); + delete[] data; + printf("Slot 2 successfully loaded."); + } + } + audio->start(&spu_audio); + emuthread.unpause(PAUSE_EVENT::LOADING_ROM); +} + void EmuWindow::about() { QMessageBox::about(this, "CorgiDS v0.1", "Created by PSISP."); diff --git a/src/qt/emuwindow.hpp b/src/qt/emuwindow.hpp index 38c4db9..51f9501 100644 --- a/src/qt/emuwindow.hpp +++ b/src/qt/emuwindow.hpp @@ -24,6 +24,7 @@ class EmuWindow : public QMainWindow { Q_OBJECT private: + Emulator* e; EmuThread emuthread; AudioDevice spu_audio; @@ -35,6 +36,7 @@ class EmuWindow : public QMainWindow QString ROM_file_name; QMenu* file_menu; QAction* load_ROM_act; + QAction* load_GBA_ROM_act; QAction* screenshot_act; QMenu* emulation_menu; @@ -74,6 +76,7 @@ class EmuWindow : public QMainWindow private slots: void about(); void load_ROM(); + void load_GBA_ROM(); void preferences(); void screenshot(); void handle_audio_state(QAudio::State); diff --git a/src/slot2.cpp b/src/slot2.cpp new file mode 100644 index 0000000..6d8089d --- /dev/null +++ b/src/slot2.cpp @@ -0,0 +1,25 @@ +#include +#include "slot2.hpp" + +Slot2Device::Slot2Device() : memory(nullptr), mem_size(0) +{ + +} + +Slot2Device::~Slot2Device() +{ + if (memory) + delete[] memory; +} + +void Slot2Device::load_data(uint8_t *data, uint64_t size) +{ + if (size) + { + if (memory) + delete[] memory; + memory = new uint8_t[size]; + memcpy(memory, data, size); + mem_size = size; + } +} diff --git a/src/slot2.hpp b/src/slot2.hpp new file mode 100644 index 0000000..c4b353a --- /dev/null +++ b/src/slot2.hpp @@ -0,0 +1,30 @@ +#ifndef SLOT2_HPP +#define SLOT2_HPP +#include + +class Slot2Device +{ + private: + uint8_t* memory; + uint64_t mem_size; + public: + Slot2Device(); + ~Slot2Device(); + + void load_data(uint8_t* data, uint64_t size); + template T read(uint32_t address); + //template void write(uint32_t address, T value); +}; + +template +T Slot2Device::read(uint32_t address) +{ + address &= 0x1FFFFFF; + if (address < mem_size) + { + return *(T*)&memory[address]; + } + return (T)0xFFFFFFFF; +} + +#endif // SLOT2_HPP