More minor fixes and renames

This commit is contained in:
spicyjpeg 2024-04-17 15:59:36 +02:00
parent 3534e99dca
commit fad8aa11bc
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
14 changed files with 192 additions and 143 deletions

View File

@ -242,10 +242,11 @@
"title": "{CART_ICON} Storage device checksums",
"prompt": "{RIGHT_ARROW} Press {START_BUTTON} to go back.",
"bios": "BIOS ROM (512 KB):\t\t\t\t%08X\n",
"rtc": "RTC RAM (8184 bytes):\t\t\t%08X\n",
"flash": "Internal flash (16 MB):\t\t\t%08X\n",
"pcmcia": "PCMCIA card in slot %d (first %d MB):\t%08X\n"
"bios": "BIOS ROM (512 KB):\t\t\t\t%08X\n",
"rtc": "RTC RAM (8184 bytes):\t\t\t%08X\n",
"flash": "Internal flash (16 MB):\t\t\t%08X\n",
"pcmcia": "PCMCIA card in slot %d (first %d MB):\t%08X\n",
"description": "All checksums are computed using the standard CRC32 algorithm and parameters (polynomial 04C11DB7, initial value FFFFFFFF, input and output reflected, output bits negated)."
},
"ConfirmScreen": {

View File

@ -190,6 +190,8 @@ enum IntelCommand : uint16_t {
};
enum FlashIdentifier : uint16_t {
_ID_AM29F016 = 0x01 | (0xad << 8),
_ID_AM29F040 = 0x01 | (0xa4 << 8),
_ID_MBM29F016A = 0x04 | (0xad << 8),
_ID_MBM29F017A = 0x04 | (0x3d << 8),
_ID_MBM29F040A = 0x04 | (0xa4 << 8),
@ -233,13 +235,18 @@ uint32_t FlashRegion::getJEDECID(void) const {
auto _ptr = reinterpret_cast<volatile uint16_t *>(ptr);
_ptr[0x000] = _INTEL_RESET;
_ptr[0x000] = _JEDEC_RESET;
_ptr[0x000] = _INTEL_RESET;
_ptr[0x555] = _JEDEC_HANDSHAKE1;
_ptr[0x2aa] = _JEDEC_HANDSHAKE2;
_ptr[0x555] = _JEDEC_GET_ID; // Same as _INTEL_GET_ID
return _ptr[0] | (_ptr[1] << 16);
uint32_t id = _ptr[0] | (_ptr[1] << 16);
_ptr[0x000] = _JEDEC_RESET;
_ptr[0x000] = _INTEL_RESET;
return id;
}
Driver *FlashRegion::newDriver(void) const {
@ -256,15 +263,17 @@ Driver *FlashRegion::newDriver(void) const {
if (low == high) {
// Two 8-bit chips for each bank
switch (low) {
case _ID_AM29F016:
case _ID_MBM29F016A:
case _ID_MBM29F017A:
// The MBM29F017A datasheet incorrectly lists the device ID as
// 0xad rather than 0x3d in some places. The chip behaves pretty
// much identically to the MBM29F016A.
return new MBM29F016ADriver(*this);
return new AM29F016Driver(*this);
case _ID_AM29F040:
case _ID_MBM29F040A:
return new MBM29F040ADriver(*this);
return new AM29F040Driver(*this);
case _ID_28F016S5:
// The chip used by Konami is actually the Sharp LH28F016S,
@ -319,6 +328,11 @@ static const ChipSize _STANDARD_CHIP_SIZE{
.eraseSectorLength = 2 * 0x10000
};
static const ChipSize _ALT_CHIP_SIZE{
.chipLength = 2 * 0x80000,
.eraseSectorLength = 2 * 0x10000
};
const ChipSize &Driver::getChipSize(void) const {
return _DUMMY_CHIP_SIZE;
}
@ -368,7 +382,7 @@ const ChipSize &RTCDriver::getChipSize(void) const {
return _RTC_CHIP_SIZE;
}
/* Fujitsu MBM29F016A/017A driver */
/* AMD AM29F016/017 (Fujitsu MBM29F016A/017A) driver */
enum FujitsuStatusFlag : uint16_t {
_FUJITSU_STATUS_ERASE_TOGGLE = 1 << 2,
@ -378,29 +392,27 @@ enum FujitsuStatusFlag : uint16_t {
_FUJITSU_STATUS_POLL_BIT = 1 << 7
};
DriverError MBM29F016ADriver::_flush(
DriverError AM29F016Driver::_flush(
uint32_t offset, uint16_t value, int timeout
) {
volatile uint16_t *ptr = _region.getRawPtr(offset & ~1);
volatile uint16_t *ptr = _region.getRawPtr(offset & ~1);
int shift = (offset & 1) * 8;
uint8_t byte = (value >> shift) & 0xff;
for (; timeout > 0; timeout--) {
uint8_t status = (*ptr >> shift) & 0xff;
uint8_t status, diff;
if (status == byte)
for (; timeout > 0; timeout -= 10) {
status = (*ptr >> shift) & 0xff;
diff = status ^ byte;
// Some chips seem to flip the poll bit slightly before returning the
// newly written byte.
if (!diff)
return NO_ERROR;
if (!(diff & _FUJITSU_STATUS_POLL_BIT))
continue;
if (!((status ^ byte) & _FUJITSU_STATUS_POLL_BIT)) {
LOG(
"mismatch @ 0x%08x, exp=0x%02x, got=0x%02x", offset, byte,
status
);
*ptr = _JEDEC_RESET;
return VERIFY_MISMATCH;
}
if (status & _FUJITSU_STATUS_ERROR) {
LOG("error @ 0x%08x, stat=0x%02x", offset, status);
@ -411,13 +423,23 @@ DriverError MBM29F016ADriver::_flush(
delayMicroseconds(10);
}
LOG("timeout @ 0x%08x, stat=0x%02x", offset, (*ptr >> shift) & 0xff);
if (diff & _FUJITSU_STATUS_POLL_BIT) {
LOG("timeout @ 0x%08x, stat=0x%02x", offset, status);
*ptr = _JEDEC_RESET;
return CHIP_TIMEOUT;
*ptr = _JEDEC_RESET;
return CHIP_TIMEOUT;
} else {
LOG(
"mismatch @ 0x%08x, exp=0x%02x, got=0x%02x", offset, byte,
status
);
*ptr = _JEDEC_RESET;
return VERIFY_MISMATCH;
}
}
void MBM29F016ADriver::write(uint32_t offset, uint16_t value) {
void AM29F016Driver::write(uint32_t offset, uint16_t value) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
offset = (offset % FLASH_BANK_LENGTH) / 2;
@ -428,7 +450,7 @@ void MBM29F016ADriver::write(uint32_t offset, uint16_t value) {
ptr[offset] = value;
}
void MBM29F016ADriver::eraseSector(uint32_t offset) {
void AM29F016Driver::eraseSector(uint32_t offset) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
offset = (offset % FLASH_BANK_LENGTH) / 2;
@ -441,7 +463,7 @@ void MBM29F016ADriver::eraseSector(uint32_t offset) {
ptr[offset] = _JEDEC_ERASE_SECTOR;
}
void MBM29F016ADriver::eraseChip(uint32_t offset) {
void AM29F016Driver::eraseChip(uint32_t offset) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
ptr[0x000] = _JEDEC_RESET;
@ -453,7 +475,7 @@ void MBM29F016ADriver::eraseChip(uint32_t offset) {
ptr[0x555] = _JEDEC_ERASE_CHIP;
}
DriverError MBM29F016ADriver::flushWrite(
DriverError AM29F016Driver::flushWrite(
uint32_t offset, uint16_t value
) {
auto error = _flush(offset, value, _FLASH_WRITE_TIMEOUT);
@ -464,7 +486,7 @@ DriverError MBM29F016ADriver::flushWrite(
return _flush(offset + 1, value, _FLASH_WRITE_TIMEOUT);
}
DriverError MBM29F016ADriver::flushErase(uint32_t offset) {
DriverError AM29F016Driver::flushErase(uint32_t offset) {
auto error = _flush(offset, 0xffff, _FLASH_ERASE_TIMEOUT);
if (error)
@ -473,16 +495,16 @@ DriverError MBM29F016ADriver::flushErase(uint32_t offset) {
return _flush(offset + 1, 0xffff, _FLASH_ERASE_TIMEOUT);
}
const ChipSize &MBM29F016ADriver::getChipSize(void) const {
const ChipSize &AM29F016Driver::getChipSize(void) const {
return _STANDARD_CHIP_SIZE;
}
/* Fujitsu MBM29F040A driver */
/* AMD AM29F040 (Fujitsu MBM29F040A) driver */
// Konami's drivers handle this chip pretty much identically to the MBM29F016A,
// but using 0x5555/0x2aaa as command addresses instead of 0x555/0x2aa.
void MBM29F040ADriver::write(uint32_t offset, uint16_t value) {
void AM29F040Driver::write(uint32_t offset, uint16_t value) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
offset = (offset % FLASH_BANK_LENGTH) / 2;
@ -493,7 +515,7 @@ void MBM29F040ADriver::write(uint32_t offset, uint16_t value) {
ptr[offset] = value;
}
void MBM29F040ADriver::eraseSector(uint32_t offset) {
void AM29F040Driver::eraseSector(uint32_t offset) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
offset = (offset % FLASH_BANK_LENGTH) / 2;
@ -506,7 +528,7 @@ void MBM29F040ADriver::eraseSector(uint32_t offset) {
ptr[offset] = _JEDEC_ERASE_SECTOR;
}
void MBM29F040ADriver::eraseChip(uint32_t offset) {
void AM29F040Driver::eraseChip(uint32_t offset) {
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
ptr[0x0005] = _JEDEC_RESET;
@ -518,6 +540,10 @@ void MBM29F040ADriver::eraseChip(uint32_t offset) {
ptr[0x5555] = _JEDEC_ERASE_CHIP;
}
const ChipSize &AM29F040Driver::getChipSize(void) const {
return _ALT_CHIP_SIZE;
}
/* Intel 28F016S5 (Sharp LH28F016S) driver */
enum IntelStatusFlag : uint16_t {
@ -533,14 +559,15 @@ enum IntelStatusFlag : uint16_t {
DriverError Intel28F016S5Driver::_flush(uint32_t offset, int timeout) {
volatile uint16_t *ptr = _region.getRawPtr(offset & ~1);
int shift = (offset & 1) * 8;
int shift = (offset & 1) * 8;
uint8_t status;
// Not required as all write/erase commands already put the chip into status
// reading mode.
//*ptr = _INTEL_GET_STATUS;
for (; timeout > 0; timeout--) {
uint8_t status = (*ptr >> shift) & 0xff;
for (; timeout > 0; timeout -= 10) {
status = (*ptr >> shift) & 0xff;
if (status & (_INTEL_STATUS_DPS | _INTEL_STATUS_VPPS)) {
LOG("locked @ 0x%08x, stat=0x%02x", offset, status);
@ -562,7 +589,7 @@ DriverError Intel28F016S5Driver::_flush(uint32_t offset, int timeout) {
delayMicroseconds(10);
}
LOG("timeout @ 0x%08x, stat=0x%02x", offset, (*ptr >> shift) & 0xff);
LOG("timeout @ 0x%08x, stat=0x%02x", offset, status);
*ptr = _INTEL_CLEAR_STATUS;
return CHIP_TIMEOUT;

View File

@ -128,12 +128,12 @@ public:
const ChipSize &getChipSize(void) const;
};
class MBM29F016ADriver : public Driver {
class AM29F016Driver : public Driver {
protected:
DriverError _flush(uint32_t offset, uint16_t value, int timeout);
public:
inline MBM29F016ADriver(const FlashRegion &region)
inline AM29F016Driver(const FlashRegion &region)
: Driver(region) {}
virtual void write(uint32_t offset, uint16_t value);
@ -144,14 +144,15 @@ public:
const ChipSize &getChipSize(void) const;
};
class MBM29F040ADriver : public MBM29F016ADriver {
class AM29F040Driver : public AM29F016Driver {
public:
inline MBM29F040ADriver(const FlashRegion &region)
: MBM29F016ADriver(region) {}
inline AM29F040Driver(const FlashRegion &region)
: AM29F016Driver(region) {}
void write(uint32_t offset, uint16_t value);
void eraseSector(uint32_t offset);
void eraseChip(uint32_t offset);
const ChipSize &getChipSize(void) const;
};
class Intel28F016S5Driver : public Driver {

View File

@ -58,6 +58,8 @@ void WorkerStatus::finish(void) {
/* App class */
static constexpr size_t _WORKER_STACK_SIZE = 0x20000;
App::App(ui::Context &ctx, file::ZIPProvider &resourceProvider)
#ifdef ENABLE_LOG_BUFFER
: _overlayLayer(_logBuffer),
@ -65,9 +67,7 @@ App::App(ui::Context &ctx, file::ZIPProvider &resourceProvider)
:
#endif
_ctx(ctx), _resourceProvider(resourceProvider), _resourceFile(nullptr),
_cartDriver(nullptr), _cartParser(nullptr), _identified(nullptr) {
_workerStack = new uint8_t[WORKER_STACK_SIZE];
}
_cartDriver(nullptr), _cartParser(nullptr), _identified(nullptr) {}
App::~App(void) {
_unloadCartData();
@ -79,8 +79,6 @@ App::~App(void) {
}
//_fileProvider.close();
delete[] _workerStack;
}
void App::_unloadCartData(void) {
@ -93,10 +91,10 @@ void App::_unloadCartData(void) {
_cartParser = nullptr;
}
_dump.chipType = cart::NONE;
_dump.flags = 0;
_dump.clearIdentifiers();
_dump.clearData();
_cartDump.chipType = cart::NONE;
_cartDump.flags = 0;
_cartDump.clearIdentifiers();
_cartDump.clearData();
_identified = nullptr;
//_selectedEntry = nullptr;
@ -107,13 +105,16 @@ void App::_setupWorker(bool (App::*func)(void)) {
auto enable = disableInterrupts();
_workerStack.allocate(_WORKER_STACK_SIZE);
_workerStatus.reset();
_workerFunction = func;
_workerFunction = func;
auto stackBottom = _workerStack.as<uint8_t>();
initThread(
// This is not how you implement delegates in C++.
&_workerThread, util::forcedCast<ArgFunction>(&App::_worker), this,
&_workerStack[(WORKER_STACK_SIZE - 1) & ~7]
&stackBottom[(_WORKER_STACK_SIZE - 1) & ~7]
);
if (enable)
enableInterrupts();

View File

@ -1,7 +1,6 @@
#pragma once
#include <stdint.h>
#include "common/file.hpp"
#include "main/app/cartactions.hpp"
#include "main/app/cartunlock.hpp"
@ -50,8 +49,6 @@ public:
/* App class */
static constexpr size_t WORKER_STACK_SIZE = 0x20000;
class App {
friend class WorkerStatusScreen;
friend class MessageScreen;
@ -110,13 +107,16 @@ private:
file::FATProvider _fileProvider;
file::StringTable _stringTable;
cart::CartDump _dump;
cart::CartDB _db;
Thread _workerThread;
WorkerStatus _workerStatus;
bool (App::*_workerFunction)(void);
cart::CartDump _cartDump;
cart::ROMHeaderDump _romHeaderDump;
cart::CartDB _cartDB;
cart::ROMHeaderDB _romHeaderDB;
Thread _workerThread;
util::Data _workerStack;
WorkerStatus _workerStatus;
bool (App::*_workerFunction)(void);
uint8_t *_workerStack;
cart::Driver *_cartDriver;
cart::CartParser *_cartParser;
const cart::CartDBEntry *_identified, *_selectedEntry;

View File

@ -1,5 +1,4 @@
#include "common/defs.hpp"
#include "common/util.hpp"
#include "main/app/cartactions.hpp"
#include "main/app/app.hpp"
@ -139,12 +138,12 @@ void CartActionsScreen::resetSystemID(ui::Context &ctx) {
}
void CartActionsScreen::matchSystemID(ui::Context &ctx) {
if (APP->_dump.flags & cart::DUMP_SYSTEM_ID_OK) {
if (APP->_cartDump.flags & cart::DUMP_SYSTEM_ID_OK) {
APP->_confirmScreen.setMessage(
*this,
[](ui::Context &ctx) {
APP->_cartParser->getIdentifiers()->systemID.copyFrom(
APP->_dump.systemID.data
APP->_cartDump.systemID.data
);
APP->_cartParser->flush();
@ -238,12 +237,12 @@ void HexdumpScreen::show(ui::Context &ctx, bool goBack) {
_body = _bodyText;
_prompt = STR("HexdumpScreen.prompt");
size_t length = APP->_dump.getChipSize().dataLength;
size_t length = APP->_cartDump.getChipSize().dataLength;
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
for (size_t i = 0; i < length; i += 16) {
ptr += snprintf(ptr, end - ptr, "%04X: ", i);
ptr += util::hexToString(ptr, &APP->_dump.data[i], 16, ' ');
ptr += util::hexToString(ptr, &APP->_cartDump.data[i], 16, ' ');
*(ptr++) = '\n';
}
@ -264,7 +263,7 @@ void HexdumpScreen::update(ui::Context &ctx) {
const char *ReflashGameScreen::_getItemName(ui::Context &ctx, int index) const {
static char name[96]; // TODO: get rid of this ugly crap
APP->_db.get(index)->getDisplayName(name, sizeof(name));
APP->_cartDB.get(index)->getDisplayName(name, sizeof(name));
return name;
}
@ -273,7 +272,7 @@ void ReflashGameScreen::show(ui::Context &ctx, bool goBack) {
_prompt = STR("ReflashGameScreen.prompt");
_itemPrompt = STR("ReflashGameScreen.itemPrompt");
_listLength = APP->_db.getNumEntries();
_listLength = APP->_cartDB.getNumEntries();
ListScreen::show(ctx, goBack);
}
@ -294,7 +293,7 @@ void ReflashGameScreen::update(ui::Context &ctx) {
STR("CartActionsScreen.reflash.confirm")
);
APP->_selectedEntry = APP->_db.get(_activeItem);
APP->_selectedEntry = APP->_cartDB.get(_activeItem);
ctx.show(APP->_confirmScreen, false, true);
}
}

View File

@ -40,7 +40,7 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
_title = STR("CartInfoScreen.title");
_body = _bodyText;
auto &dump = APP->_dump;
auto &dump = APP->_cartDump;
char id1[32], id2[32], config[32];
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
@ -178,7 +178,7 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
} else if (
dump.flags & (cart::DUMP_PUBLIC_DATA_OK | cart::DUMP_PRIVATE_DATA_OK)
) {
state = APP->_dump.isReadableDataEmpty() ? BLANK_CART : UNIDENTIFIED;
state = dump.isReadableDataEmpty() ? BLANK_CART : UNIDENTIFIED;
} else {
state = UNKNOWN;
}
@ -207,8 +207,8 @@ void CartInfoScreen::update(ui::Context &ctx) {
if (ctx.buttons.pressed(ui::BTN_START)) {
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_mainMenuScreen, true, true);
} else if (APP->_dump.chipType) {
if (APP->_dump.flags & cart::DUMP_PRIVATE_DATA_OK)
} else if (APP->_cartDump.chipType) {
if (APP->_cartDump.flags & cart::DUMP_PRIVATE_DATA_OK)
ctx.show(APP->_cartActionsScreen, false, true);
else
ctx.show(APP->_unlockKeyScreen, false, true);
@ -260,14 +260,14 @@ const char *UnlockKeyScreen::_getItemName(ui::Context &ctx, int index) const {
static char name[96]; // TODO: get rid of this ugly crap
APP->_db.get(index)->getDisplayName(name, sizeof(name));
APP->_cartDB.get(index)->getDisplayName(name, sizeof(name));
return name;
}
void UnlockKeyScreen::autoUnlock(ui::Context &ctx) {
__builtin_memcpy(
APP->_dump.dataKey, APP->_identified->dataKey,
sizeof(APP->_dump.dataKey)
APP->_cartDump.dataKey, APP->_identified->dataKey,
sizeof(APP->_cartDump.dataKey)
);
//APP->_selectedEntry = APP->_identified;
@ -282,7 +282,7 @@ void UnlockKeyScreen::useCustomKey(ui::Context &ctx) {
void UnlockKeyScreen::use00Key(ui::Context &ctx) {
__builtin_memset(
APP->_dump.dataKey, 0x00, sizeof(APP->_dump.dataKey)
APP->_cartDump.dataKey, 0x00, sizeof(APP->_cartDump.dataKey)
);
APP->_selectedEntry = nullptr;
@ -291,7 +291,7 @@ void UnlockKeyScreen::use00Key(ui::Context &ctx) {
void UnlockKeyScreen::useFFKey(ui::Context &ctx) {
__builtin_memset(
APP->_dump.dataKey, 0xff, sizeof(APP->_dump.dataKey)
APP->_cartDump.dataKey, 0xff, sizeof(APP->_cartDump.dataKey)
);
APP->_selectedEntry = nullptr;
@ -303,7 +303,7 @@ void UnlockKeyScreen::show(ui::Context &ctx, bool goBack) {
_prompt = STR("UnlockKeyScreen.prompt");
_itemPrompt = STR("UnlockKeyScreen.itemPrompt");
_listLength = APP->_db.getNumEntries() - _getSpecialEntryOffset(ctx);
_listLength = APP->_cartDB.getNumEntries() - _getSpecialEntryOffset(ctx);
ListScreen::show(ctx, goBack);
}
@ -315,7 +315,8 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_cartInfoScreen, true, true);
} else {
int index = _activeItem + _getSpecialEntryOffset(ctx);
auto &dump = APP->_cartDump;
int index = _activeItem + _getSpecialEntryOffset(ctx);
APP->_confirmScreen.setMessage(
APP->_unlockKeyScreen,
@ -323,18 +324,18 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
STRH(_UNLOCK_WARNINGS[dump.chipType])
);
if (index < 0) {
(this->*_SPECIAL_ENTRIES[-index].target)(ctx);
} else {
__builtin_memcpy(
APP->_dump.dataKey, APP->_db.get(index)->dataKey,
sizeof(APP->_dump.dataKey)
dump.dataKey, APP->_cartDB.get(index)->dataKey,
sizeof(dump.dataKey)
);
APP->_selectedEntry = APP->_db.get(index);
APP->_selectedEntry = APP->_cartDB.get(index);
ctx.show(APP->_confirmScreen, false, true);
}
}
@ -363,6 +364,8 @@ void KeyEntryScreen::update(ui::Context &ctx) {
if (_activeButton == _buttonIndexOffset) {
ctx.show(APP->_unlockKeyScreen, true, true);
} else if (_activeButton == (_buttonIndexOffset + 1)) {
auto &dump = APP->_cartDump;
// TODO: deduplicate this code (it is the same as UnlockKeyScreen)
APP->_confirmScreen.setMessage(
APP->_unlockKeyScreen,
@ -370,12 +373,10 @@ void KeyEntryScreen::update(ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
STRH(_UNLOCK_WARNINGS[dump.chipType])
);
__builtin_memcpy(
APP->_dump.dataKey, _buffer, sizeof(APP->_dump.dataKey)
);
__builtin_memcpy(dump.dataKey, _buffer, sizeof(dump.dataKey));
ctx.show(APP->_confirmScreen, false, true);
}
}

View File

@ -31,17 +31,17 @@ bool App::_cartDetectWorker(void) {
if (cart::dummyDriverDump.chipType) {
LOG("using dummy cart driver");
_cartDriver = new cart::DummyDriver(_dump);
_cartDriver = new cart::DummyDriver(_cartDump);
_cartDriver->readSystemID();
} else {
_cartDriver = cart::newCartDriver(_dump);
_cartDriver = cart::newCartDriver(_cartDump);
}
#else
_cartDriver = cart::newCartDriver(_dump);
_cartDriver = cart::newCartDriver(_cartDump);
#endif
if (_dump.chipType) {
LOG("cart dump @ 0x%08x", &_dump);
if (_cartDump.chipType) {
LOG("cart dump @ 0x%08x", &_cartDump);
LOG("cart driver @ 0x%08x", _cartDriver);
auto error = _cartDriver->readCartID();
@ -53,17 +53,17 @@ bool App::_cartDetectWorker(void) {
if (error)
LOG("read error [%s]", cart::getErrorString(error));
else if (!_dump.isReadableDataEmpty())
_cartParser = cart::newCartParser(_dump);
else if (!_cartDump.isReadableDataEmpty())
_cartParser = cart::newCartParser(_cartDump);
LOG("cart parser @ 0x%08x", _cartParser);
_workerStatus.update(1, 3, WSTR("App.cartDetectWorker.identifyGame"));
if (!_db.ptr) {
if (!_cartDB.ptr) {
if (!_resourceProvider.loadData(
_db, _CARTDB_PATHS[_dump.chipType])
_cartDB, _CARTDB_PATHS[_cartDump.chipType])
) {
LOG("%s not found", _CARTDB_PATHS[_dump.chipType]);
LOG("%s not found", _CARTDB_PATHS[_cartDump.chipType]);
goto _cartInitDone;
}
}
@ -73,7 +73,7 @@ bool App::_cartDetectWorker(void) {
if (!_cartParser)
goto _cartInitDone;
if (_cartParser->getCode(code) && _cartParser->getRegion(region))
_identified = _db.lookup(code, region);
_identified = _cartDB.lookup(code, region);
if (!_identified)
goto _cartInitDone;
@ -81,7 +81,7 @@ bool App::_cartDetectWorker(void) {
// ambiguity between different formats).
delete _cartParser;
_cartParser = cart::newCartParser(
_dump, _identified->formatType, _identified->flags
_cartDump, _identified->formatType, _identified->flags
);
LOG("new cart parser @ 0x%08x", _cartParser);
@ -90,11 +90,12 @@ bool App::_cartDetectWorker(void) {
_cartInitDone:
_workerStatus.update(2, 3, WSTR("App.cartDetectWorker.readDigitalIO"));
if (
#ifdef ENABLE_DUMMY_DRIVER
if (io::isDigitalIOPresent() && !(_dump.flags & cart::DUMP_SYSTEM_ID_OK)) {
#else
if (io::isDigitalIOPresent()) {
!(_cartDump.flags & cart::DUMP_SYSTEM_ID_OK) &&
#endif
io::isDigitalIOPresent()
) {
util::Data bitstream;
bool ready;
@ -141,7 +142,8 @@ bool App::_cartUnlockWorker(void) {
if (error) {
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen,
WSTRH(_UNLOCK_ERRORS[_dump.chipType]), cart::getErrorString(error)
WSTRH(_UNLOCK_ERRORS[_cartDump.chipType]),
cart::getErrorString(error)
);
_workerStatus.setNextScreen(_messageScreen);
@ -151,7 +153,7 @@ bool App::_cartUnlockWorker(void) {
if (_cartParser)
delete _cartParser;
_cartParser = cart::newCartParser(_dump);
_cartParser = cart::newCartParser(_cartDump);
if (!_cartParser)
return true;
@ -162,7 +164,7 @@ bool App::_cartUnlockWorker(void) {
char code[8], region[8];
if (_cartParser->getCode(code) && _cartParser->getRegion(region))
_identified = _db.lookup(code, region);
_identified = _cartDB.lookup(code, region);
// If auto-identification failed (e.g. because the format has no game code),
// use the game whose unlocking key was selected as a hint.
@ -177,7 +179,7 @@ bool App::_cartUnlockWorker(void) {
delete _cartParser;
_cartParser = cart::newCartParser(
_dump, _identified->formatType, _identified->flags
_cartDump, _identified->formatType, _identified->flags
);
LOG("new cart parser @ 0x%08x", _cartParser);
@ -189,7 +191,7 @@ bool App::_qrCodeWorker(void) {
_workerStatus.setNextScreen(_qrCodeScreen);
_workerStatus.update(0, 2, WSTR("App.qrCodeWorker.compress"));
_dump.toQRString(qrString);
_cartDump.toQRString(qrString);
_workerStatus.update(1, 2, WSTR("App.qrCodeWorker.generate"));
_qrCodeScreen.generateCode(qrString);
@ -213,7 +215,7 @@ bool App::_cartDumpWorker(void) {
char code[8], region[8];
size_t length;
length = _dump.getDumpLength();
length = _cartDump.getDumpLength();
if (
_identified && _cartParser->getCode(code) &&
@ -235,7 +237,7 @@ bool App::_cartDumpWorker(void) {
LOG("saving %s, length=%d", path, length);
if (_fileProvider.saveData(&_dump, length, path) != length)
if (_fileProvider.saveData(&_cartDump, length, path) != length)
goto _error;
_messageScreen.setMessage(
@ -273,7 +275,7 @@ bool App::_cartWriteWorker(void) {
return false;
}
_dump.copyKeyFrom(key);
_cartDump.copyKeyFrom(key);
return _cartUnlockWorker();
}
@ -301,7 +303,7 @@ bool App::_cartRestoreWorker(void) {
_file->close();
delete _file;
if (_dump.chipType != newDump.chipType) {
if (_cartDump.chipType != newDump.chipType) {
_messageScreen.setMessage(
MESSAGE_ERROR, _filePickerScreen,
WSTR("App.cartRestoreWorker.typeError"), path
@ -321,9 +323,9 @@ bool App::_cartRestoreWorker(void) {
if (newDump.flags & (
cart::DUMP_PUBLIC_DATA_OK | cart::DUMP_PRIVATE_DATA_OK
))
_dump.copyDataFrom(newDump.data);
_cartDump.copyDataFrom(newDump.data);
if (newDump.flags & cart::DUMP_CONFIG_OK)
_dump.copyConfigFrom(newDump.config);
_cartDump.copyConfigFrom(newDump.config);
_workerStatus.update(2, 3, WSTR("App.cartRestoreWorker.write"));
error = _cartDriver->writeData();
@ -360,7 +362,7 @@ bool App::_cartReflashWorker(void) {
// Make sure a valid cart ID is present if required by the new data.
if (
_selectedEntry->requiresCartID() &&
!(_dump.flags & cart::DUMP_CART_ID_OK)
!(_cartDump.flags & cart::DUMP_CART_ID_OK)
) {
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen,
@ -382,21 +384,23 @@ bool App::_cartReflashWorker(void) {
delete _cartParser;
_cartParser = cart::newCartParser(
_dump, _selectedEntry->formatType, _selectedEntry->flags
_cartDump, _selectedEntry->formatType, _selectedEntry->flags
);
auto pri = _cartParser->getIdentifiers();
auto pub = _cartParser->getPublicIdentifiers();
_dump.clearData();
_dump.initConfig(9, _selectedEntry->flags & cart::DATA_HAS_PUBLIC_SECTION);
_cartDump.clearData();
_cartDump.initConfig(
9, _selectedEntry->flags & cart::DATA_HAS_PUBLIC_SECTION
);
if (pri) {
if (_selectedEntry->flags & cart::DATA_HAS_CART_ID)
pri->cartID.copyFrom(_dump.cartID.data);
pri->cartID.copyFrom(_cartDump.cartID.data);
if (_selectedEntry->flags & cart::DATA_HAS_TRACE_ID)
pri->updateTraceID(
_selectedEntry->traceIDType, _selectedEntry->traceIDParam,
&_dump.cartID
&_cartDump.cartID
);
if (_selectedEntry->flags & cart::DATA_HAS_INSTALL_ID) {
// The private installation ID seems to be unused on carts with a

View File

@ -37,10 +37,14 @@ bool App::_startupWorker(void) {
_workerStatus.update(2, 4, WSTR("App.startupWorker.initFAT"));
#if 0
// Attempt to mount the secondary drive first, then in case of failure try
// mounting the primary drive instead.
if (!_fileProvider.init("1:"))
_fileProvider.init("0:");
#else
_fileProvider.init("1:");
#endif
_workerStatus.update(3, 4, WSTR("App.startupWorker.loadResources"));

View File

@ -299,7 +299,7 @@ void StorageActionsScreen::update(ui::Context &ctx) {
if (ctx.buttons.pressed(ui::BTN_START)) {
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_mainMenuScreen, true, true);
ctx.show(APP->_storageInfoScreen, true, true);
} else {
if (action.region.isPresent()) {
this->_selectedRegion = &(action.region);
@ -322,9 +322,9 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
_PRINT(STR("ChecksumScreen.bios"), biosCRC);
_PRINT(STR("ChecksumScreen.rtc"), rtcCRC);
_PRINT(STR("ChecksumScreen.flash"), flashCRC);
_PRINT(STR("ChecksumScreen.bios"), values.bios);
_PRINT(STR("ChecksumScreen.rtc"), values.rtc);
_PRINT(STR("ChecksumScreen.flash"), values.flash);
_PRINTLN();
@ -333,7 +333,7 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
continue;
auto slot = i + 1;
auto crc = pcmciaCRC[i];
auto crc = values.pcmcia[i];
_PRINT(STR("ChecksumScreen.pcmcia"), slot, 16, crc[0]);
_PRINT(STR("ChecksumScreen.pcmcia"), slot, 32, crc[1]);
@ -342,7 +342,9 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
_PRINTLN();
}
*(--ptr) = 0;
_PRINT(STR("ChecksumScreen.description"));
//*(--ptr) = 0;
LOG("remaining=%d", end - ptr);
TextScreen::show(ctx, goBack);

View File

@ -41,14 +41,21 @@ public:
void update(ui::Context &ctx);
};
// The CRCs have to be wrapped into their own structure in order to allow usage
// of offsetof().
struct ChecksumValues {
public:
uint32_t bios, rtc, flash;
uint32_t pcmcia[2][4];
};
class ChecksumScreen : public ui::TextScreen {
private:
char _bodyText[2048];
public:
bool valid;
uint32_t biosCRC, rtcCRC, flashCRC;
uint32_t pcmciaCRC[2][4];
bool valid;
ChecksumValues values;
inline ChecksumScreen(void)
: valid(false) {}

View File

@ -23,31 +23,31 @@ static const RegionInfo _REGION_INFO[]{
.crcPrompt = "App.romChecksumWorker.hashBIOS"_h,
.path = "%s/bios.bin",
.region = rom::bios,
.crcOffset = offsetof(ChecksumScreen, biosCRC)
.crcOffset = offsetof(ChecksumValues, bios)
}, {
.dumpPrompt = "App.romDumpWorker.dumpRTC"_h,
.crcPrompt = "App.romChecksumWorker.hashRTC"_h,
.path = "%s/rtc.bin",
.region = rom::rtc,
.crcOffset = offsetof(ChecksumScreen, rtcCRC)
.crcOffset = offsetof(ChecksumValues, rtc)
}, {
.dumpPrompt = "App.romDumpWorker.dumpFlash"_h,
.crcPrompt = "App.romChecksumWorker.hashFlash"_h,
.path = "%s/flash.bin",
.region = rom::flash,
.crcOffset = offsetof(ChecksumScreen, flashCRC)
.crcOffset = offsetof(ChecksumValues, flash)
}, {
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA1"_h,
.crcPrompt = "App.romChecksumWorker.hashPCMCIA1"_h,
.path = "%s/pcmcia1.bin",
.region = rom::pcmcia[0],
.crcOffset = offsetof(ChecksumScreen, pcmciaCRC[0])
.crcOffset = offsetof(ChecksumValues, pcmcia[0])
}, {
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA2"_h,
.crcPrompt = "App.romChecksumWorker.hashPCMCIA2"_h,
.path = "%s/pcmcia2.bin",
.region = rom::pcmcia[1],
.crcOffset = offsetof(ChecksumScreen, pcmciaCRC[1])
.crcOffset = offsetof(ChecksumValues, pcmcia[1])
}
};
@ -71,7 +71,8 @@ bool App::_romChecksumWorker(void) {
uint32_t offset = 0;
uint32_t crc = 0;
auto crcPtr = reinterpret_cast<uint32_t *>(
reinterpret_cast<uintptr_t>(&_checksumScreen) + entry.crcOffset
reinterpret_cast<uintptr_t>(&_checksumScreen.values) +
entry.crcOffset
);
// Flash cards can be 16, 32 or 64 MB, so copies of the current CRC are
@ -90,6 +91,7 @@ bool App::_romChecksumWorker(void) {
}
}
_checksumScreen.valid = true;
return true;
}

View File

@ -709,6 +709,6 @@ template<typename T> const T *DB<T>::lookup(
}
template class DB<CartDBEntry>;
template class DB<FlashDBEntry>;
template class DB<ROMHeaderDBEntry>;
}

View File

@ -295,7 +295,7 @@ public:
}
};
class [[gnu::packed]] FlashDBEntry {
class [[gnu::packed]] ROMHeaderDBEntry {
public:
// TODO: define these flags
uint8_t flags;
@ -332,7 +332,7 @@ public:
const T *lookup(const char *code, const char *region) const;
};
using CartDB = DB<CartDBEntry>;
using FlashDB = DB<FlashDBEntry>;
using CartDB = DB<CartDBEntry>;
using ROMHeaderDB = DB<ROMHeaderDBEntry>;
}