more WIP. ROM loading working, sorta. not loading saves or anything yet.

This commit is contained in:
Arisotura 2021-12-29 15:42:30 +01:00
parent aa443c6bce
commit 9529356062
10 changed files with 353 additions and 98 deletions

View File

@ -648,6 +648,9 @@ void Reset()
void Eject()
{
if (Cart) delete Cart;
Cart = nullptr;
if (CartROM) delete[] CartROM;
CartInserted = false;
@ -656,9 +659,6 @@ void Eject()
CartCRC = 0;
CartID = 0;
if (Cart) delete Cart;
Cart = nullptr;
Reset();
}

View File

@ -903,12 +903,12 @@ bool LoadCart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen)
if (savedata && savelen)
NDSCart::LoadSave(savedata, savelen);
//Running = true;
return true;
}
void EjectCart()
{
printf("TODO!!!!\n");
NDSCart::EjectCart();
}
bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen)

View File

@ -55,8 +55,6 @@ bool CartInserted;
u8* CartROM;
u32 CartROMSize;
u32 CartID;
bool CartIsHomebrew;
bool CartIsDSi;
NDSHeader Header;
NDSBanner Banner;
@ -1505,16 +1503,14 @@ void DeInit()
void Reset()
{
if (Cart) delete Cart;
Cart = nullptr;
CartInserted = false;
if (CartROM) delete[] CartROM;
CartROM = nullptr;
CartROMSize = 0;
CartID = 0;
CartIsHomebrew = false;
CartIsDSi = false;
if (Cart) delete Cart;
Cart = nullptr;
ResetCart();
}
@ -1624,7 +1620,8 @@ void DecryptSecureArea(u8* out)
//bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
bool LoadROM(const u8* romdata, u32 romlen)
{
//NDS::Reset();
if (CartInserted)
EjectCart();
CartROMSize = 0x200;
while (CartROMSize < romlen)
@ -1654,10 +1651,10 @@ bool LoadROM(const u8* romdata, u32 romlen)
(u32)Header.GameCode[0];
u8 unitcode = Header.UnitCode;
CartIsDSi = (unitcode & 0x02) != 0;
bool dsi = (unitcode & 0x02) != 0;
u32 arm9base = Header.ARM9ROMOffset;
CartIsHomebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
bool homebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
ROMListEntry romparams;
if (!ReadROMParams(gamecode, &romparams))
@ -1667,7 +1664,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
romparams.GameCode = gamecode;
romparams.ROMSize = CartROMSize;
if (CartIsHomebrew)
if (homebrew)
romparams.SaveMemType = 0; // no saveRAM for homebrew
else
romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME)
@ -1691,7 +1688,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
if (romparams.SaveMemType >= 8 && romparams.SaveMemType <= 10)
CartID |= 0x08000000; // NAND flag
if (CartIsDSi)
if (dsi)
CartID |= 0x40000000;
// cart ID for Jam with the Band
@ -1719,7 +1716,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
Key1_Encrypt((u32*)&CartROM[arm9base]);
}
}
printf("FAZIL");
CartInserted = true;
u32 irversion = 0;
@ -1731,7 +1728,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
irversion = 2; // Pokémon HG/SS, B/W, B2/W2
}
if (CartIsHomebrew)
if (homebrew)
Cart = new CartHomebrew(CartROM, CartROMSize, CartID);
else if (CartID & 0x08000000)
Cart = new CartRetailNAND(CartROM, CartROMSize, CartID);
@ -1741,7 +1738,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
Cart = new CartRetailBT(CartROM, CartROMSize, CartID);
else
Cart = new CartRetail(CartROM, CartROMSize, CartID);
printf("PFART\n");
if (Cart)
Cart->Reset();
/*{
@ -1762,14 +1759,14 @@ bool LoadROM(const u8* romdata, u32 romlen)
//if (Cart) Cart->LoadSave(sram, romparams.SaveMemType);
if (Cart && romparams.SaveMemType > 0)
Cart->SetupSave(romparams.SaveMemType);
printf("PROEUPRAOUTTE\n");
return true;
}
void LoadSave(const u8* savedata, u32 savelen)
{
{printf("CARTSAVE\n");
if (Cart)
Cart->LoadSave(savedata, savelen);
Cart->LoadSave(savedata, savelen);printf("SAVE FARTED\n");
}
/*bool LoadROM(const char* path, const char* sram, bool direct)
@ -1854,6 +1851,26 @@ int ImportSRAM(const u8* data, u32 length)
return 0;
}*/
void EjectCart()
{
if (!CartInserted) return;
// ejecting the cart triggers the gamecard IRQ
NDS::SetIRQ(0, NDS::IRQ_CartIREQMC);
NDS::SetIRQ(1, NDS::IRQ_CartIREQMC);
if (Cart) delete Cart;
Cart = nullptr;
CartInserted = false;
if (CartROM) delete[] CartROM;
CartROM = nullptr;
CartROMSize = 0;
CartID = 0;
// CHECKME: does an eject imply anything for the ROM/SPI transfer registers?
}
void ResetCart()
{
// CHECKME: what if there is a transfer in progress?

View File

@ -218,6 +218,8 @@ bool LoadROM(const u8* romdata, u32 romlen);
void LoadSave(const u8* savedata, u32 savelen);
void SetupDirectBoot(std::string romname);
void EjectCart();
//void FlushSRAMFile();
//void RelocateSave(const char* path, bool write);

View File

@ -116,7 +116,45 @@ QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteA
}
u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata)
u32 ExtractFileFromArchive(QString path, QString wantedFile, u8** filedata, u32* filesize)
{
struct archive *a = archive_read_new();
struct archive_entry *entry;
int r;
if (!filedata) return -1;
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
//r = archive_read_open_filename(a, path, 10240);
r = melon_archive_open(a, path, 10240);
if (r != ARCHIVE_OK)
{
return -1;
}
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
{
if (strcmp(wantedFile.toUtf8().constData(), archive_entry_pathname_utf8(entry)) == 0)
{
break;
}
}
size_t bytesToRead = archive_entry_size(entry);
if (filesize) *filesize = bytesToRead;
*filedata = new u8[bytesToRead];
ssize_t bytesRead = archive_read_data(a, *filedata, bytesToRead);
archive_read_close(a);
archive_read_free(a);
return (u32)bytesRead;
}
/*u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata)
{
QByteArray romBuffer;
QVector<QString> extractResult = ExtractFileFromArchive(path, wantedFile, &romBuffer);
@ -131,6 +169,6 @@ u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdat
memcpy(*romdata, romBuffer.data(), len);
return len;
}
}*/
}

View File

@ -36,7 +36,8 @@ namespace Archive
{
QVector<QString> ListArchive(QString path);
QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer);
u32 ExtractFileFromArchive(QString path, QString wantedFile, u8** filedata, u32* filesize);
//QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer);
//u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
}

View File

@ -51,7 +51,7 @@ ARCodeFile* CheatFile;
bool CheatsOn;
void Init_ROM()
/*void Init_ROM()
{
SavestateLoaded = false;
@ -73,55 +73,53 @@ void DeInit_ROM()
delete CheatFile;
CheatFile = nullptr;
}
}
}*/
// TODO: currently, when failing to load a ROM for whatever reason, we attempt
// to revert to the previous state and resume execution; this may not be a very
// good thing, depending on what state the core was left in.
// should we do a better state revert (via the savestate system)? completely stop?
void SetupSRAMPath(int slot)
/*void SetupSRAMPath(int slot)
{
SRAMPath[slot] = ROMPath[slot].substr(0, ROMPath[slot].length() - 3) + "sav";
}
}*/
int VerifyDSBIOS()
QString VerifyDSBIOS()
{
FILE* f;
long len;
if (!Config::ExternalBIOSEnable) return Load_OK;
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
if (!f) return Load_BIOS9Missing;
if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x1000)
{
fclose(f);
return Load_BIOS9Bad;
return "DS ARM9 BIOS is not a valid BIOS dump.";
}
fclose(f);
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
if (!f) return Load_BIOS7Missing;
if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x4000)
{
fclose(f);
return Load_BIOS7Bad;
return "DS ARM7 BIOS is not a valid BIOS dump.";
}
fclose(f);
return Load_OK;
return "";
}
int VerifyDSiBIOS()
QString VerifyDSiBIOS()
{
FILE* f;
long len;
@ -129,43 +127,41 @@ int VerifyDSiBIOS()
// TODO: check the first 32 bytes
f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb");
if (!f) return Load_DSiBIOS9Missing;
if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x10000)
{
fclose(f);
return Load_DSiBIOS9Bad;
return "DSi ARM9 BIOS is not a valid BIOS dump.";
}
fclose(f);
f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
if (!f) return Load_DSiBIOS7Missing;
if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x10000)
{
fclose(f);
return Load_DSiBIOS7Bad;
return "DSi ARM7 BIOS is not a valid BIOS dump.";
}
fclose(f);
return Load_OK;
return "";
}
int VerifyDSFirmware()
QString VerifyDSFirmware()
{
FILE* f;
long len;
if (!Config::ExternalBIOSEnable) return Load_FirmwareNotBootable;
f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
if (!f) return Load_FirmwareNotBootable;
if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
@ -173,26 +169,27 @@ int VerifyDSFirmware()
{
// 128KB firmware, not bootable
fclose(f);
return Load_FirmwareNotBootable;
// TODO report it somehow? detect in core?
return "";
}
else if (len != 0x40000 && len != 0x80000)
{
fclose(f);
return Load_FirmwareBad;
return "DS firmware is not a valid firmware dump.";
}
fclose(f);
return Load_OK;
return "";
}
int VerifyDSiFirmware()
QString VerifyDSiFirmware()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb");
if (!f) return Load_FirmwareMissing;
if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
@ -201,30 +198,132 @@ int VerifyDSiFirmware()
// not 128KB
// TODO: check whether those work
fclose(f);
return Load_FirmwareBad;
return "DSi firmware is not a valid firmware dump.";
}
fclose(f);
return Load_OK;
return "";
}
int SetupDSiNAND()
QString VerifyDSiNAND()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
if (!f) return Load_DSiNANDMissing;
if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings.";
// TODO: some basic checks
// check that it has the nocash footer, and all
DSi::SDMMCFile = f;
fclose(f);
return Load_OK;
return "";
}
QString VerifySetup()
{
QString res;
if (Config::ExternalBIOSEnable)
{
res = VerifyDSBIOS();
if (!res.isEmpty()) return res;
}
if (Config::ConsoleType == 1)
{
res = VerifyDSiBIOS();
if (!res.isEmpty()) return res;
if (Config::ExternalBIOSEnable)
{
res = VerifyDSiFirmware();
if (!res.isEmpty()) return res;
}
res = VerifyDSiNAND();
if (!res.isEmpty()) return res;
}
else
{
if (Config::ExternalBIOSEnable)
{
res = VerifyDSFirmware();
if (!res.isEmpty()) return res;
}
}
return "";
}
bool LoadROM(QStringList filepath, bool reset)
{
if (filepath.empty()) return false;
u8* filedata;
u32 filelen;
int num = filepath.count();
if (num == 1)
{
// regular file
FILE* f = Platform::OpenFile(filepath.at(0).toStdString(), "rb", true);
if (!f) return false;
fseek(f, 0, SEEK_END);
long len = ftell(f);
if (len > 0x40000000)
{
fclose(f);
return false;
}
fseek(f, 0, SEEK_SET);
filedata = new u8[len];
size_t nread = fread(filedata, (size_t)len, 1, f);
if (nread != 1)
{
fclose(f);
delete[] filedata;
return false;
}
fclose(f);
filelen = (u32)len;
}
#ifdef ARCHIVE_SUPPORT_ENABLED
else if (num == 2)
{
// file inside archive
u32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
if (lenread < 0) return false;
if (!filedata) return false;
if (lenread != filelen)
{
delete[] filedata;
return false;
}
}
#endif
else
return false;
if (reset)
{
NDS::Reset();
}
// TODO: SAVE
return NDS::LoadCart(filedata, filelen, nullptr, 0);
}
void LoadCheats()
{
if (CheatFile)
@ -251,7 +350,7 @@ void LoadCheats()
AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
}
int LoadBIOS()
/*int LoadBIOS()
{
DSi::CloseDSiNAND();
@ -363,7 +462,7 @@ int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
return Load_OK;
}
else*/
else*-/
{
ROMPath[slot] = oldpath;
SRAMPath[slot] = oldsram;
@ -443,13 +542,13 @@ int LoadROM(const char* file, int slot)
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
return Load_OK;
}
else*/
else*-/
{
ROMPath[slot] = oldpath;
SRAMPath[slot] = oldsram;
return Load_ROMLoadError;
}
}
}*/
void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef)
{
@ -535,7 +634,7 @@ void UnloadROM(int slot)
int Reset()
{
DSi::CloseDSiNAND();
/*DSi::CloseDSiNAND();
int res;
bool directboot = Config::DirectBoot != 0;
@ -611,7 +710,7 @@ int Reset()
bool ok = NDS::LoadROM(romdata, romlen, sramfilename, directboot);
delete romdata;
if (!ok)*/
if (!ok)*-/
return Load_ROMLoadError;
}
#endif
@ -650,13 +749,13 @@ int Reset()
bool ok = NDS::LoadGBAROM(romdata, romlen, romfilename, SRAMPath[ROMSlot_GBA]);
delete romdata;
if (!ok)*/
if (!ok)*-/
return Load_ROMLoadError;
}
#endif
}
LoadCheats();
LoadCheats();*/
return Load_OK;
}

View File

@ -27,6 +27,9 @@
namespace ROMLoader
{
QString VerifySetup();
bool LoadROM(QStringList filepath, bool reset);
enum
{
ROMSlot_NDS = 0,

View File

@ -81,6 +81,7 @@
#include "main_shaders.h"
#include "ROMLoader.h"
#include "ArchiveUtil.h"
// TODO: uniform variable spelling
@ -1792,7 +1793,7 @@ void MainWindow::dropEvent(QDropEvent* event)
QList<QUrl> urls = event->mimeData()->urls();
if (urls.count() > 1) return; // not handling more than one file at once
emuThread->emuPause();
/*emuThread->emuPause();
QString filename = urls.at(0).toLocalFile();
QString ext = filename.right(3).toLower();
@ -1852,7 +1853,7 @@ void MainWindow::dropEvent(QDropEvent* event)
else
{
emuThread->emuRun();
}
}*/
}
void MainWindow::onAppStateChanged(Qt::ApplicationState state)
@ -1912,7 +1913,7 @@ QString MainWindow::loadErrorStr(int error)
}
}
void MainWindow::loadROM(QByteArray *romData, QString archiveFileName, QString romFileName)
/*void MainWindow::loadROM(QByteArray *romData, QString archiveFileName, QString romFileName)
{
recentFileList.removeAll(archiveFileName);
recentFileList.prepend(archiveFileName);
@ -2006,13 +2007,60 @@ void MainWindow::loadROM(QString filename)
{
emuThread->emuRun();
}
}*/
bool MainWindow::verifySetup()
{
QString res = ROMLoader::VerifySetup();
if (!res.isEmpty())
{
QMessageBox::critical(this, "melonDS", res);
return false;
}
return true;
}
void MainWindow::pickAndLoadROM(bool gba)
QString MainWindow::pickFileFromArchive(QString archiveFileName)
{
QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName);
QString romFileName = ""; // file name inside archive
if (archiveROMList.size() > 2)
{
archiveROMList.removeFirst();
bool ok;
QString toLoad = QInputDialog::getItem(this, "melonDS",
"This archive contains multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false, &ok);
if (!ok) // User clicked on cancel
return QString();
romFileName = toLoad;
}
else if (archiveROMList.size() == 2)
{
romFileName = archiveROMList.at(1);
}
else if ((archiveROMList.size() == 1) && (archiveROMList[0] == QString("OK")))
{
QMessageBox::warning(this, "melonDS", "This archive is empty.");
}
else
{
QMessageBox::critical(this, "melonDS", "This archive could not be read. It may be corrupt or you don't have the permissions.");
}
return romFileName;
}
QStringList MainWindow::pickROM(bool gba)
{
QString console;
QStringList romexts;
QStringList arcexts{"*.zip", "*.7z", "*.rar", "*.tar", "*.gz", "*.xz", "*.bz2"};
QStringList arcexts{"*.zip", "*.7z", "*.rar", "*.tar", "*.tar.gz", "*.tar.xz", "*.tar.bz2"};
QStringList ret;
if (gba)
{
@ -2025,8 +2073,6 @@ void MainWindow::pickAndLoadROM(bool gba)
romexts.append({"*.nds", "*.dsi", "*.srl"});
}
emuThread->emuPause();
QString filter = romexts.join(' ') + " " + arcexts.join(' ');
filter = console + " ROMs (" + filter + ");;Any file (*.*)";
@ -2035,37 +2081,81 @@ void MainWindow::pickAndLoadROM(bool gba)
QString::fromStdString(Config::LastROMFolder),
filter);
if (filename.isEmpty())
{
emuThread->emuUnpause();
return;
}
return ret;
int pos = filename.length() - 1;
while (filename[pos] != '/' && filename[pos] != '\\' && pos > 0) pos--;
QString path_dir = filename.left(pos);
QString path_file = filename.mid(pos+1);
QString path_ext = path_file.mid(path_file.lastIndexOf('.')).toLower();
Config::LastROMFolder = path_dir.toStdString();
printf("LOADING ROM: %s\n", filename.toStdString().c_str());
printf("- %s\n", path_dir.toStdString().c_str());
printf("- %s\n", path_file.toStdString().c_str());
printf("- %s\n", path_ext.toStdString().c_str());
if (arcexts.contains("*"+path_ext))
bool isarc = false;
for (const auto& ext : arcexts)
{
QByteArray romBuffer;
QString arcfile = pickAndExtractFileFromArchive(filename, &romBuffer);
printf("ARCHIVE: %s\n", arcfile.toStdString().c_str());
printf("SIZE=%d\n", romBuffer.size());
int l = ext.length() - 1;
if (path_file.right(l).toLower() == ext.right(l))
{
isarc = true;
break;
}
}
if (isarc)
{
path_file = pickFileFromArchive(filename);
if (path_file.isEmpty())
return ret;
ret.append(filename);
ret.append(path_file);
}
else
{
ret.append(filename);
}
return ret;
}
void MainWindow::onOpenFile()
{
pickAndLoadROM(false);
emuThread->emuPause();
// stock path/archivepath in this module, alongside recent ROM list
// update them at the same time?
//
// 1. verify BIOS/firm/etc
// 2. pick ROM
// 3. set recent ROM, last folder, etc
// 4. reset system (if need be)
// 5. load ROM/SRAM into core
// 6. boot
if (!verifySetup())
{
emuThread->emuUnpause();
return;
}
QStringList file = pickROM(false);
if (file.isEmpty())
{
emuThread->emuUnpause();
return;
}
// TODO: add to recent ROM list
if (!ROMLoader::LoadROM(file, true))
{
// TODO: better error reporting?
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
emuThread->emuUnpause();
return;
}
printf("PROEUPRAON\n");
NDS::Start();printf("PROOT\n");
emuThread->emuRun();printf("ASSFAZIL\n");
}
void MainWindow::onOpenFileArchive()
@ -2090,7 +2180,7 @@ void MainWindow::onOpenFileArchive()
}*/
}
QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer)
/*QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer)
{
printf("Finding list of ROMs...\n");
QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName.toUtf8().constData());
@ -2142,7 +2232,7 @@ QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByte
}
return romFileName;
}
}*/
void MainWindow::onClearRecentFiles()
{
@ -2201,7 +2291,7 @@ void MainWindow::updateRecentFilesMenu()
void MainWindow::onClickRecentFile()
{
QAction *act = (QAction *)sender();
/*QAction *act = (QAction *)sender();
QString fileName = act->data().toString();
if (fileName.endsWith(".gba", Qt::CaseInsensitive) ||
@ -2223,7 +2313,7 @@ void MainWindow::onClickRecentFile()
emuThread->emuPause();
loadROM(&romBuffer, archiveFileName, romFileName);
}
}
}*/
}
void MainWindow::onBootFirmware()
@ -2868,7 +2958,8 @@ bool MelonApplication::event(QEvent *event)
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent*>(event);
emuThread->emuPause();
mainWindow->loadROM(openEvent->file());
//mainWindow->loadROM(openEvent->file());
printf("ASS EVENT???\n");
}
return QApplication::event(event);

View File

@ -292,13 +292,17 @@ private slots:
void onFullscreenToggled();
private:
QStringList currentROM;
QStringList currentGBAROM;
QList<QString> recentFileList;
QMenu *recentMenu;
void updateRecentFilesMenu();
QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer);
//QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer);
void pickAndLoadROM(bool gba);
bool verifySetup();
QString pickFileFromArchive(QString archiveFileName);
QStringList pickROM(bool gba);
void createScreenPanel();