mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-01-22 19:52:05 +01:00
More minor fixes and renames
This commit is contained in:
parent
3534e99dca
commit
fad8aa11bc
@ -242,10 +242,11 @@
|
|||||||
"title": "{CART_ICON} Storage device checksums",
|
"title": "{CART_ICON} Storage device checksums",
|
||||||
"prompt": "{RIGHT_ARROW} Press {START_BUTTON} to go back.",
|
"prompt": "{RIGHT_ARROW} Press {START_BUTTON} to go back.",
|
||||||
|
|
||||||
"bios": "BIOS ROM (512 KB):\t\t\t\t%08X\n",
|
"bios": "BIOS ROM (512 KB):\t\t\t\t%08X\n",
|
||||||
"rtc": "RTC RAM (8184 bytes):\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",
|
"flash": "Internal flash (16 MB):\t\t\t%08X\n",
|
||||||
"pcmcia": "PCMCIA card in slot %d (first %d MB):\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": {
|
"ConfirmScreen": {
|
||||||
|
@ -190,6 +190,8 @@ enum IntelCommand : uint16_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum FlashIdentifier : uint16_t {
|
enum FlashIdentifier : uint16_t {
|
||||||
|
_ID_AM29F016 = 0x01 | (0xad << 8),
|
||||||
|
_ID_AM29F040 = 0x01 | (0xa4 << 8),
|
||||||
_ID_MBM29F016A = 0x04 | (0xad << 8),
|
_ID_MBM29F016A = 0x04 | (0xad << 8),
|
||||||
_ID_MBM29F017A = 0x04 | (0x3d << 8),
|
_ID_MBM29F017A = 0x04 | (0x3d << 8),
|
||||||
_ID_MBM29F040A = 0x04 | (0xa4 << 8),
|
_ID_MBM29F040A = 0x04 | (0xa4 << 8),
|
||||||
@ -233,13 +235,18 @@ uint32_t FlashRegion::getJEDECID(void) const {
|
|||||||
|
|
||||||
auto _ptr = reinterpret_cast<volatile uint16_t *>(ptr);
|
auto _ptr = reinterpret_cast<volatile uint16_t *>(ptr);
|
||||||
|
|
||||||
_ptr[0x000] = _INTEL_RESET;
|
_ptr[0x000] = _JEDEC_RESET;
|
||||||
_ptr[0x000] = _INTEL_RESET;
|
_ptr[0x000] = _INTEL_RESET;
|
||||||
_ptr[0x555] = _JEDEC_HANDSHAKE1;
|
_ptr[0x555] = _JEDEC_HANDSHAKE1;
|
||||||
_ptr[0x2aa] = _JEDEC_HANDSHAKE2;
|
_ptr[0x2aa] = _JEDEC_HANDSHAKE2;
|
||||||
_ptr[0x555] = _JEDEC_GET_ID; // Same as _INTEL_GET_ID
|
_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 {
|
Driver *FlashRegion::newDriver(void) const {
|
||||||
@ -256,15 +263,17 @@ Driver *FlashRegion::newDriver(void) const {
|
|||||||
if (low == high) {
|
if (low == high) {
|
||||||
// Two 8-bit chips for each bank
|
// Two 8-bit chips for each bank
|
||||||
switch (low) {
|
switch (low) {
|
||||||
|
case _ID_AM29F016:
|
||||||
case _ID_MBM29F016A:
|
case _ID_MBM29F016A:
|
||||||
case _ID_MBM29F017A:
|
case _ID_MBM29F017A:
|
||||||
// The MBM29F017A datasheet incorrectly lists the device ID as
|
// The MBM29F017A datasheet incorrectly lists the device ID as
|
||||||
// 0xad rather than 0x3d in some places. The chip behaves pretty
|
// 0xad rather than 0x3d in some places. The chip behaves pretty
|
||||||
// much identically to the MBM29F016A.
|
// much identically to the MBM29F016A.
|
||||||
return new MBM29F016ADriver(*this);
|
return new AM29F016Driver(*this);
|
||||||
|
|
||||||
|
case _ID_AM29F040:
|
||||||
case _ID_MBM29F040A:
|
case _ID_MBM29F040A:
|
||||||
return new MBM29F040ADriver(*this);
|
return new AM29F040Driver(*this);
|
||||||
|
|
||||||
case _ID_28F016S5:
|
case _ID_28F016S5:
|
||||||
// The chip used by Konami is actually the Sharp LH28F016S,
|
// The chip used by Konami is actually the Sharp LH28F016S,
|
||||||
@ -319,6 +328,11 @@ static const ChipSize _STANDARD_CHIP_SIZE{
|
|||||||
.eraseSectorLength = 2 * 0x10000
|
.eraseSectorLength = 2 * 0x10000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const ChipSize _ALT_CHIP_SIZE{
|
||||||
|
.chipLength = 2 * 0x80000,
|
||||||
|
.eraseSectorLength = 2 * 0x10000
|
||||||
|
};
|
||||||
|
|
||||||
const ChipSize &Driver::getChipSize(void) const {
|
const ChipSize &Driver::getChipSize(void) const {
|
||||||
return _DUMMY_CHIP_SIZE;
|
return _DUMMY_CHIP_SIZE;
|
||||||
}
|
}
|
||||||
@ -368,7 +382,7 @@ const ChipSize &RTCDriver::getChipSize(void) const {
|
|||||||
return _RTC_CHIP_SIZE;
|
return _RTC_CHIP_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fujitsu MBM29F016A/017A driver */
|
/* AMD AM29F016/017 (Fujitsu MBM29F016A/017A) driver */
|
||||||
|
|
||||||
enum FujitsuStatusFlag : uint16_t {
|
enum FujitsuStatusFlag : uint16_t {
|
||||||
_FUJITSU_STATUS_ERASE_TOGGLE = 1 << 2,
|
_FUJITSU_STATUS_ERASE_TOGGLE = 1 << 2,
|
||||||
@ -378,29 +392,27 @@ enum FujitsuStatusFlag : uint16_t {
|
|||||||
_FUJITSU_STATUS_POLL_BIT = 1 << 7
|
_FUJITSU_STATUS_POLL_BIT = 1 << 7
|
||||||
};
|
};
|
||||||
|
|
||||||
DriverError MBM29F016ADriver::_flush(
|
DriverError AM29F016Driver::_flush(
|
||||||
uint32_t offset, uint16_t value, int timeout
|
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;
|
int shift = (offset & 1) * 8;
|
||||||
uint8_t byte = (value >> shift) & 0xff;
|
uint8_t byte = (value >> shift) & 0xff;
|
||||||
|
|
||||||
for (; timeout > 0; timeout--) {
|
uint8_t status, diff;
|
||||||
uint8_t status = (*ptr >> shift) & 0xff;
|
|
||||||
|
|
||||||
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;
|
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) {
|
if (status & _FUJITSU_STATUS_ERROR) {
|
||||||
LOG("error @ 0x%08x, stat=0x%02x", offset, status);
|
LOG("error @ 0x%08x, stat=0x%02x", offset, status);
|
||||||
|
|
||||||
@ -411,13 +423,23 @@ DriverError MBM29F016ADriver::_flush(
|
|||||||
delayMicroseconds(10);
|
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;
|
*ptr = _JEDEC_RESET;
|
||||||
return CHIP_TIMEOUT;
|
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);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
||||||
|
|
||||||
@ -428,7 +450,7 @@ void MBM29F016ADriver::write(uint32_t offset, uint16_t value) {
|
|||||||
ptr[offset] = value;
|
ptr[offset] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MBM29F016ADriver::eraseSector(uint32_t offset) {
|
void AM29F016Driver::eraseSector(uint32_t offset) {
|
||||||
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
||||||
|
|
||||||
@ -441,7 +463,7 @@ void MBM29F016ADriver::eraseSector(uint32_t offset) {
|
|||||||
ptr[offset] = _JEDEC_ERASE_SECTOR;
|
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);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
|
|
||||||
ptr[0x000] = _JEDEC_RESET;
|
ptr[0x000] = _JEDEC_RESET;
|
||||||
@ -453,7 +475,7 @@ void MBM29F016ADriver::eraseChip(uint32_t offset) {
|
|||||||
ptr[0x555] = _JEDEC_ERASE_CHIP;
|
ptr[0x555] = _JEDEC_ERASE_CHIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
DriverError MBM29F016ADriver::flushWrite(
|
DriverError AM29F016Driver::flushWrite(
|
||||||
uint32_t offset, uint16_t value
|
uint32_t offset, uint16_t value
|
||||||
) {
|
) {
|
||||||
auto error = _flush(offset, value, _FLASH_WRITE_TIMEOUT);
|
auto error = _flush(offset, value, _FLASH_WRITE_TIMEOUT);
|
||||||
@ -464,7 +486,7 @@ DriverError MBM29F016ADriver::flushWrite(
|
|||||||
return _flush(offset + 1, value, _FLASH_WRITE_TIMEOUT);
|
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);
|
auto error = _flush(offset, 0xffff, _FLASH_ERASE_TIMEOUT);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
@ -473,16 +495,16 @@ DriverError MBM29F016ADriver::flushErase(uint32_t offset) {
|
|||||||
return _flush(offset + 1, 0xffff, _FLASH_ERASE_TIMEOUT);
|
return _flush(offset + 1, 0xffff, _FLASH_ERASE_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChipSize &MBM29F016ADriver::getChipSize(void) const {
|
const ChipSize &AM29F016Driver::getChipSize(void) const {
|
||||||
return _STANDARD_CHIP_SIZE;
|
return _STANDARD_CHIP_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fujitsu MBM29F040A driver */
|
/* AMD AM29F040 (Fujitsu MBM29F040A) driver */
|
||||||
|
|
||||||
// Konami's drivers handle this chip pretty much identically to the MBM29F016A,
|
// Konami's drivers handle this chip pretty much identically to the MBM29F016A,
|
||||||
// but using 0x5555/0x2aaa as command addresses instead of 0x555/0x2aa.
|
// 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);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
||||||
|
|
||||||
@ -493,7 +515,7 @@ void MBM29F040ADriver::write(uint32_t offset, uint16_t value) {
|
|||||||
ptr[offset] = value;
|
ptr[offset] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MBM29F040ADriver::eraseSector(uint32_t offset) {
|
void AM29F040Driver::eraseSector(uint32_t offset) {
|
||||||
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
offset = (offset % FLASH_BANK_LENGTH) / 2;
|
||||||
|
|
||||||
@ -506,7 +528,7 @@ void MBM29F040ADriver::eraseSector(uint32_t offset) {
|
|||||||
ptr[offset] = _JEDEC_ERASE_SECTOR;
|
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);
|
volatile uint16_t *ptr = _region.getRawPtr(offset, true);
|
||||||
|
|
||||||
ptr[0x0005] = _JEDEC_RESET;
|
ptr[0x0005] = _JEDEC_RESET;
|
||||||
@ -518,6 +540,10 @@ void MBM29F040ADriver::eraseChip(uint32_t offset) {
|
|||||||
ptr[0x5555] = _JEDEC_ERASE_CHIP;
|
ptr[0x5555] = _JEDEC_ERASE_CHIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ChipSize &AM29F040Driver::getChipSize(void) const {
|
||||||
|
return _ALT_CHIP_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Intel 28F016S5 (Sharp LH28F016S) driver */
|
/* Intel 28F016S5 (Sharp LH28F016S) driver */
|
||||||
|
|
||||||
enum IntelStatusFlag : uint16_t {
|
enum IntelStatusFlag : uint16_t {
|
||||||
@ -533,14 +559,15 @@ enum IntelStatusFlag : uint16_t {
|
|||||||
DriverError Intel28F016S5Driver::_flush(uint32_t offset, int timeout) {
|
DriverError Intel28F016S5Driver::_flush(uint32_t offset, int timeout) {
|
||||||
volatile uint16_t *ptr = _region.getRawPtr(offset & ~1);
|
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
|
// Not required as all write/erase commands already put the chip into status
|
||||||
// reading mode.
|
// reading mode.
|
||||||
//*ptr = _INTEL_GET_STATUS;
|
//*ptr = _INTEL_GET_STATUS;
|
||||||
|
|
||||||
for (; timeout > 0; timeout--) {
|
for (; timeout > 0; timeout -= 10) {
|
||||||
uint8_t status = (*ptr >> shift) & 0xff;
|
status = (*ptr >> shift) & 0xff;
|
||||||
|
|
||||||
if (status & (_INTEL_STATUS_DPS | _INTEL_STATUS_VPPS)) {
|
if (status & (_INTEL_STATUS_DPS | _INTEL_STATUS_VPPS)) {
|
||||||
LOG("locked @ 0x%08x, stat=0x%02x", offset, status);
|
LOG("locked @ 0x%08x, stat=0x%02x", offset, status);
|
||||||
@ -562,7 +589,7 @@ DriverError Intel28F016S5Driver::_flush(uint32_t offset, int timeout) {
|
|||||||
delayMicroseconds(10);
|
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;
|
*ptr = _INTEL_CLEAR_STATUS;
|
||||||
return CHIP_TIMEOUT;
|
return CHIP_TIMEOUT;
|
||||||
|
@ -128,12 +128,12 @@ public:
|
|||||||
const ChipSize &getChipSize(void) const;
|
const ChipSize &getChipSize(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MBM29F016ADriver : public Driver {
|
class AM29F016Driver : public Driver {
|
||||||
protected:
|
protected:
|
||||||
DriverError _flush(uint32_t offset, uint16_t value, int timeout);
|
DriverError _flush(uint32_t offset, uint16_t value, int timeout);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline MBM29F016ADriver(const FlashRegion ®ion)
|
inline AM29F016Driver(const FlashRegion ®ion)
|
||||||
: Driver(region) {}
|
: Driver(region) {}
|
||||||
|
|
||||||
virtual void write(uint32_t offset, uint16_t value);
|
virtual void write(uint32_t offset, uint16_t value);
|
||||||
@ -144,14 +144,15 @@ public:
|
|||||||
const ChipSize &getChipSize(void) const;
|
const ChipSize &getChipSize(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MBM29F040ADriver : public MBM29F016ADriver {
|
class AM29F040Driver : public AM29F016Driver {
|
||||||
public:
|
public:
|
||||||
inline MBM29F040ADriver(const FlashRegion ®ion)
|
inline AM29F040Driver(const FlashRegion ®ion)
|
||||||
: MBM29F016ADriver(region) {}
|
: AM29F016Driver(region) {}
|
||||||
|
|
||||||
void write(uint32_t offset, uint16_t value);
|
void write(uint32_t offset, uint16_t value);
|
||||||
void eraseSector(uint32_t offset);
|
void eraseSector(uint32_t offset);
|
||||||
void eraseChip(uint32_t offset);
|
void eraseChip(uint32_t offset);
|
||||||
|
const ChipSize &getChipSize(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Intel28F016S5Driver : public Driver {
|
class Intel28F016S5Driver : public Driver {
|
||||||
|
@ -58,6 +58,8 @@ void WorkerStatus::finish(void) {
|
|||||||
|
|
||||||
/* App class */
|
/* App class */
|
||||||
|
|
||||||
|
static constexpr size_t _WORKER_STACK_SIZE = 0x20000;
|
||||||
|
|
||||||
App::App(ui::Context &ctx, file::ZIPProvider &resourceProvider)
|
App::App(ui::Context &ctx, file::ZIPProvider &resourceProvider)
|
||||||
#ifdef ENABLE_LOG_BUFFER
|
#ifdef ENABLE_LOG_BUFFER
|
||||||
: _overlayLayer(_logBuffer),
|
: _overlayLayer(_logBuffer),
|
||||||
@ -65,9 +67,7 @@ App::App(ui::Context &ctx, file::ZIPProvider &resourceProvider)
|
|||||||
:
|
:
|
||||||
#endif
|
#endif
|
||||||
_ctx(ctx), _resourceProvider(resourceProvider), _resourceFile(nullptr),
|
_ctx(ctx), _resourceProvider(resourceProvider), _resourceFile(nullptr),
|
||||||
_cartDriver(nullptr), _cartParser(nullptr), _identified(nullptr) {
|
_cartDriver(nullptr), _cartParser(nullptr), _identified(nullptr) {}
|
||||||
_workerStack = new uint8_t[WORKER_STACK_SIZE];
|
|
||||||
}
|
|
||||||
|
|
||||||
App::~App(void) {
|
App::~App(void) {
|
||||||
_unloadCartData();
|
_unloadCartData();
|
||||||
@ -79,8 +79,6 @@ App::~App(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//_fileProvider.close();
|
//_fileProvider.close();
|
||||||
|
|
||||||
delete[] _workerStack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::_unloadCartData(void) {
|
void App::_unloadCartData(void) {
|
||||||
@ -93,10 +91,10 @@ void App::_unloadCartData(void) {
|
|||||||
_cartParser = nullptr;
|
_cartParser = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dump.chipType = cart::NONE;
|
_cartDump.chipType = cart::NONE;
|
||||||
_dump.flags = 0;
|
_cartDump.flags = 0;
|
||||||
_dump.clearIdentifiers();
|
_cartDump.clearIdentifiers();
|
||||||
_dump.clearData();
|
_cartDump.clearData();
|
||||||
|
|
||||||
_identified = nullptr;
|
_identified = nullptr;
|
||||||
//_selectedEntry = nullptr;
|
//_selectedEntry = nullptr;
|
||||||
@ -107,13 +105,16 @@ void App::_setupWorker(bool (App::*func)(void)) {
|
|||||||
|
|
||||||
auto enable = disableInterrupts();
|
auto enable = disableInterrupts();
|
||||||
|
|
||||||
|
_workerStack.allocate(_WORKER_STACK_SIZE);
|
||||||
_workerStatus.reset();
|
_workerStatus.reset();
|
||||||
_workerFunction = func;
|
|
||||||
|
_workerFunction = func;
|
||||||
|
auto stackBottom = _workerStack.as<uint8_t>();
|
||||||
|
|
||||||
initThread(
|
initThread(
|
||||||
// This is not how you implement delegates in C++.
|
// This is not how you implement delegates in C++.
|
||||||
&_workerThread, util::forcedCast<ArgFunction>(&App::_worker), this,
|
&_workerThread, util::forcedCast<ArgFunction>(&App::_worker), this,
|
||||||
&_workerStack[(WORKER_STACK_SIZE - 1) & ~7]
|
&stackBottom[(_WORKER_STACK_SIZE - 1) & ~7]
|
||||||
);
|
);
|
||||||
if (enable)
|
if (enable)
|
||||||
enableInterrupts();
|
enableInterrupts();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "common/file.hpp"
|
#include "common/file.hpp"
|
||||||
#include "main/app/cartactions.hpp"
|
#include "main/app/cartactions.hpp"
|
||||||
#include "main/app/cartunlock.hpp"
|
#include "main/app/cartunlock.hpp"
|
||||||
@ -50,8 +49,6 @@ public:
|
|||||||
|
|
||||||
/* App class */
|
/* App class */
|
||||||
|
|
||||||
static constexpr size_t WORKER_STACK_SIZE = 0x20000;
|
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
friend class WorkerStatusScreen;
|
friend class WorkerStatusScreen;
|
||||||
friend class MessageScreen;
|
friend class MessageScreen;
|
||||||
@ -110,13 +107,16 @@ private:
|
|||||||
file::FATProvider _fileProvider;
|
file::FATProvider _fileProvider;
|
||||||
file::StringTable _stringTable;
|
file::StringTable _stringTable;
|
||||||
|
|
||||||
cart::CartDump _dump;
|
cart::CartDump _cartDump;
|
||||||
cart::CartDB _db;
|
cart::ROMHeaderDump _romHeaderDump;
|
||||||
Thread _workerThread;
|
cart::CartDB _cartDB;
|
||||||
WorkerStatus _workerStatus;
|
cart::ROMHeaderDB _romHeaderDB;
|
||||||
bool (App::*_workerFunction)(void);
|
|
||||||
|
Thread _workerThread;
|
||||||
|
util::Data _workerStack;
|
||||||
|
WorkerStatus _workerStatus;
|
||||||
|
bool (App::*_workerFunction)(void);
|
||||||
|
|
||||||
uint8_t *_workerStack;
|
|
||||||
cart::Driver *_cartDriver;
|
cart::Driver *_cartDriver;
|
||||||
cart::CartParser *_cartParser;
|
cart::CartParser *_cartParser;
|
||||||
const cart::CartDBEntry *_identified, *_selectedEntry;
|
const cart::CartDBEntry *_identified, *_selectedEntry;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
|
|
||||||
#include "common/defs.hpp"
|
|
||||||
#include "common/util.hpp"
|
#include "common/util.hpp"
|
||||||
#include "main/app/cartactions.hpp"
|
#include "main/app/cartactions.hpp"
|
||||||
#include "main/app/app.hpp"
|
#include "main/app/app.hpp"
|
||||||
@ -139,12 +138,12 @@ void CartActionsScreen::resetSystemID(ui::Context &ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CartActionsScreen::matchSystemID(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(
|
APP->_confirmScreen.setMessage(
|
||||||
*this,
|
*this,
|
||||||
[](ui::Context &ctx) {
|
[](ui::Context &ctx) {
|
||||||
APP->_cartParser->getIdentifiers()->systemID.copyFrom(
|
APP->_cartParser->getIdentifiers()->systemID.copyFrom(
|
||||||
APP->_dump.systemID.data
|
APP->_cartDump.systemID.data
|
||||||
);
|
);
|
||||||
APP->_cartParser->flush();
|
APP->_cartParser->flush();
|
||||||
|
|
||||||
@ -238,12 +237,12 @@ void HexdumpScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_body = _bodyText;
|
_body = _bodyText;
|
||||||
_prompt = STR("HexdumpScreen.prompt");
|
_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)];
|
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
|
||||||
|
|
||||||
for (size_t i = 0; i < length; i += 16) {
|
for (size_t i = 0; i < length; i += 16) {
|
||||||
ptr += snprintf(ptr, end - ptr, "%04X: ", i);
|
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';
|
*(ptr++) = '\n';
|
||||||
}
|
}
|
||||||
@ -264,7 +263,7 @@ void HexdumpScreen::update(ui::Context &ctx) {
|
|||||||
const char *ReflashGameScreen::_getItemName(ui::Context &ctx, int index) const {
|
const char *ReflashGameScreen::_getItemName(ui::Context &ctx, int index) const {
|
||||||
static char name[96]; // TODO: get rid of this ugly crap
|
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;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +272,7 @@ void ReflashGameScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_prompt = STR("ReflashGameScreen.prompt");
|
_prompt = STR("ReflashGameScreen.prompt");
|
||||||
_itemPrompt = STR("ReflashGameScreen.itemPrompt");
|
_itemPrompt = STR("ReflashGameScreen.itemPrompt");
|
||||||
|
|
||||||
_listLength = APP->_db.getNumEntries();
|
_listLength = APP->_cartDB.getNumEntries();
|
||||||
|
|
||||||
ListScreen::show(ctx, goBack);
|
ListScreen::show(ctx, goBack);
|
||||||
}
|
}
|
||||||
@ -294,7 +293,7 @@ void ReflashGameScreen::update(ui::Context &ctx) {
|
|||||||
STR("CartActionsScreen.reflash.confirm")
|
STR("CartActionsScreen.reflash.confirm")
|
||||||
);
|
);
|
||||||
|
|
||||||
APP->_selectedEntry = APP->_db.get(_activeItem);
|
APP->_selectedEntry = APP->_cartDB.get(_activeItem);
|
||||||
ctx.show(APP->_confirmScreen, false, true);
|
ctx.show(APP->_confirmScreen, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_title = STR("CartInfoScreen.title");
|
_title = STR("CartInfoScreen.title");
|
||||||
_body = _bodyText;
|
_body = _bodyText;
|
||||||
|
|
||||||
auto &dump = APP->_dump;
|
auto &dump = APP->_cartDump;
|
||||||
|
|
||||||
char id1[32], id2[32], config[32];
|
char id1[32], id2[32], config[32];
|
||||||
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
|
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
|
||||||
@ -178,7 +178,7 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
} else if (
|
} else if (
|
||||||
dump.flags & (cart::DUMP_PUBLIC_DATA_OK | cart::DUMP_PRIVATE_DATA_OK)
|
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 {
|
} else {
|
||||||
state = UNKNOWN;
|
state = UNKNOWN;
|
||||||
}
|
}
|
||||||
@ -207,8 +207,8 @@ void CartInfoScreen::update(ui::Context &ctx) {
|
|||||||
if (ctx.buttons.pressed(ui::BTN_START)) {
|
if (ctx.buttons.pressed(ui::BTN_START)) {
|
||||||
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
|
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
|
||||||
ctx.show(APP->_mainMenuScreen, true, true);
|
ctx.show(APP->_mainMenuScreen, true, true);
|
||||||
} else if (APP->_dump.chipType) {
|
} else if (APP->_cartDump.chipType) {
|
||||||
if (APP->_dump.flags & cart::DUMP_PRIVATE_DATA_OK)
|
if (APP->_cartDump.flags & cart::DUMP_PRIVATE_DATA_OK)
|
||||||
ctx.show(APP->_cartActionsScreen, false, true);
|
ctx.show(APP->_cartActionsScreen, false, true);
|
||||||
else
|
else
|
||||||
ctx.show(APP->_unlockKeyScreen, false, true);
|
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
|
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;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnlockKeyScreen::autoUnlock(ui::Context &ctx) {
|
void UnlockKeyScreen::autoUnlock(ui::Context &ctx) {
|
||||||
__builtin_memcpy(
|
__builtin_memcpy(
|
||||||
APP->_dump.dataKey, APP->_identified->dataKey,
|
APP->_cartDump.dataKey, APP->_identified->dataKey,
|
||||||
sizeof(APP->_dump.dataKey)
|
sizeof(APP->_cartDump.dataKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
//APP->_selectedEntry = APP->_identified;
|
//APP->_selectedEntry = APP->_identified;
|
||||||
@ -282,7 +282,7 @@ void UnlockKeyScreen::useCustomKey(ui::Context &ctx) {
|
|||||||
|
|
||||||
void UnlockKeyScreen::use00Key(ui::Context &ctx) {
|
void UnlockKeyScreen::use00Key(ui::Context &ctx) {
|
||||||
__builtin_memset(
|
__builtin_memset(
|
||||||
APP->_dump.dataKey, 0x00, sizeof(APP->_dump.dataKey)
|
APP->_cartDump.dataKey, 0x00, sizeof(APP->_cartDump.dataKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
APP->_selectedEntry = nullptr;
|
APP->_selectedEntry = nullptr;
|
||||||
@ -291,7 +291,7 @@ void UnlockKeyScreen::use00Key(ui::Context &ctx) {
|
|||||||
|
|
||||||
void UnlockKeyScreen::useFFKey(ui::Context &ctx) {
|
void UnlockKeyScreen::useFFKey(ui::Context &ctx) {
|
||||||
__builtin_memset(
|
__builtin_memset(
|
||||||
APP->_dump.dataKey, 0xff, sizeof(APP->_dump.dataKey)
|
APP->_cartDump.dataKey, 0xff, sizeof(APP->_cartDump.dataKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
APP->_selectedEntry = nullptr;
|
APP->_selectedEntry = nullptr;
|
||||||
@ -303,7 +303,7 @@ void UnlockKeyScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_prompt = STR("UnlockKeyScreen.prompt");
|
_prompt = STR("UnlockKeyScreen.prompt");
|
||||||
_itemPrompt = STR("UnlockKeyScreen.itemPrompt");
|
_itemPrompt = STR("UnlockKeyScreen.itemPrompt");
|
||||||
|
|
||||||
_listLength = APP->_db.getNumEntries() - _getSpecialEntryOffset(ctx);
|
_listLength = APP->_cartDB.getNumEntries() - _getSpecialEntryOffset(ctx);
|
||||||
|
|
||||||
ListScreen::show(ctx, goBack);
|
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)) {
|
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
|
||||||
ctx.show(APP->_cartInfoScreen, true, true);
|
ctx.show(APP->_cartInfoScreen, true, true);
|
||||||
} else {
|
} else {
|
||||||
int index = _activeItem + _getSpecialEntryOffset(ctx);
|
auto &dump = APP->_cartDump;
|
||||||
|
int index = _activeItem + _getSpecialEntryOffset(ctx);
|
||||||
|
|
||||||
APP->_confirmScreen.setMessage(
|
APP->_confirmScreen.setMessage(
|
||||||
APP->_unlockKeyScreen,
|
APP->_unlockKeyScreen,
|
||||||
@ -323,18 +324,18 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
|
|||||||
APP->_setupWorker(&App::_cartUnlockWorker);
|
APP->_setupWorker(&App::_cartUnlockWorker);
|
||||||
ctx.show(APP->_workerStatusScreen, false, true);
|
ctx.show(APP->_workerStatusScreen, false, true);
|
||||||
},
|
},
|
||||||
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
|
STRH(_UNLOCK_WARNINGS[dump.chipType])
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
(this->*_SPECIAL_ENTRIES[-index].target)(ctx);
|
(this->*_SPECIAL_ENTRIES[-index].target)(ctx);
|
||||||
} else {
|
} else {
|
||||||
__builtin_memcpy(
|
__builtin_memcpy(
|
||||||
APP->_dump.dataKey, APP->_db.get(index)->dataKey,
|
dump.dataKey, APP->_cartDB.get(index)->dataKey,
|
||||||
sizeof(APP->_dump.dataKey)
|
sizeof(dump.dataKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
APP->_selectedEntry = APP->_db.get(index);
|
APP->_selectedEntry = APP->_cartDB.get(index);
|
||||||
ctx.show(APP->_confirmScreen, false, true);
|
ctx.show(APP->_confirmScreen, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,6 +364,8 @@ void KeyEntryScreen::update(ui::Context &ctx) {
|
|||||||
if (_activeButton == _buttonIndexOffset) {
|
if (_activeButton == _buttonIndexOffset) {
|
||||||
ctx.show(APP->_unlockKeyScreen, true, true);
|
ctx.show(APP->_unlockKeyScreen, true, true);
|
||||||
} else if (_activeButton == (_buttonIndexOffset + 1)) {
|
} else if (_activeButton == (_buttonIndexOffset + 1)) {
|
||||||
|
auto &dump = APP->_cartDump;
|
||||||
|
|
||||||
// TODO: deduplicate this code (it is the same as UnlockKeyScreen)
|
// TODO: deduplicate this code (it is the same as UnlockKeyScreen)
|
||||||
APP->_confirmScreen.setMessage(
|
APP->_confirmScreen.setMessage(
|
||||||
APP->_unlockKeyScreen,
|
APP->_unlockKeyScreen,
|
||||||
@ -370,12 +373,10 @@ void KeyEntryScreen::update(ui::Context &ctx) {
|
|||||||
APP->_setupWorker(&App::_cartUnlockWorker);
|
APP->_setupWorker(&App::_cartUnlockWorker);
|
||||||
ctx.show(APP->_workerStatusScreen, false, true);
|
ctx.show(APP->_workerStatusScreen, false, true);
|
||||||
},
|
},
|
||||||
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
|
STRH(_UNLOCK_WARNINGS[dump.chipType])
|
||||||
);
|
);
|
||||||
|
|
||||||
__builtin_memcpy(
|
__builtin_memcpy(dump.dataKey, _buffer, sizeof(dump.dataKey));
|
||||||
APP->_dump.dataKey, _buffer, sizeof(APP->_dump.dataKey)
|
|
||||||
);
|
|
||||||
ctx.show(APP->_confirmScreen, false, true);
|
ctx.show(APP->_confirmScreen, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,17 +31,17 @@ bool App::_cartDetectWorker(void) {
|
|||||||
|
|
||||||
if (cart::dummyDriverDump.chipType) {
|
if (cart::dummyDriverDump.chipType) {
|
||||||
LOG("using dummy cart driver");
|
LOG("using dummy cart driver");
|
||||||
_cartDriver = new cart::DummyDriver(_dump);
|
_cartDriver = new cart::DummyDriver(_cartDump);
|
||||||
_cartDriver->readSystemID();
|
_cartDriver->readSystemID();
|
||||||
} else {
|
} else {
|
||||||
_cartDriver = cart::newCartDriver(_dump);
|
_cartDriver = cart::newCartDriver(_cartDump);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
_cartDriver = cart::newCartDriver(_dump);
|
_cartDriver = cart::newCartDriver(_cartDump);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_dump.chipType) {
|
if (_cartDump.chipType) {
|
||||||
LOG("cart dump @ 0x%08x", &_dump);
|
LOG("cart dump @ 0x%08x", &_cartDump);
|
||||||
LOG("cart driver @ 0x%08x", _cartDriver);
|
LOG("cart driver @ 0x%08x", _cartDriver);
|
||||||
|
|
||||||
auto error = _cartDriver->readCartID();
|
auto error = _cartDriver->readCartID();
|
||||||
@ -53,17 +53,17 @@ bool App::_cartDetectWorker(void) {
|
|||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
LOG("read error [%s]", cart::getErrorString(error));
|
LOG("read error [%s]", cart::getErrorString(error));
|
||||||
else if (!_dump.isReadableDataEmpty())
|
else if (!_cartDump.isReadableDataEmpty())
|
||||||
_cartParser = cart::newCartParser(_dump);
|
_cartParser = cart::newCartParser(_cartDump);
|
||||||
|
|
||||||
LOG("cart parser @ 0x%08x", _cartParser);
|
LOG("cart parser @ 0x%08x", _cartParser);
|
||||||
_workerStatus.update(1, 3, WSTR("App.cartDetectWorker.identifyGame"));
|
_workerStatus.update(1, 3, WSTR("App.cartDetectWorker.identifyGame"));
|
||||||
|
|
||||||
if (!_db.ptr) {
|
if (!_cartDB.ptr) {
|
||||||
if (!_resourceProvider.loadData(
|
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;
|
goto _cartInitDone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ bool App::_cartDetectWorker(void) {
|
|||||||
if (!_cartParser)
|
if (!_cartParser)
|
||||||
goto _cartInitDone;
|
goto _cartInitDone;
|
||||||
if (_cartParser->getCode(code) && _cartParser->getRegion(region))
|
if (_cartParser->getCode(code) && _cartParser->getRegion(region))
|
||||||
_identified = _db.lookup(code, region);
|
_identified = _cartDB.lookup(code, region);
|
||||||
if (!_identified)
|
if (!_identified)
|
||||||
goto _cartInitDone;
|
goto _cartInitDone;
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ bool App::_cartDetectWorker(void) {
|
|||||||
// ambiguity between different formats).
|
// ambiguity between different formats).
|
||||||
delete _cartParser;
|
delete _cartParser;
|
||||||
_cartParser = cart::newCartParser(
|
_cartParser = cart::newCartParser(
|
||||||
_dump, _identified->formatType, _identified->flags
|
_cartDump, _identified->formatType, _identified->flags
|
||||||
);
|
);
|
||||||
|
|
||||||
LOG("new cart parser @ 0x%08x", _cartParser);
|
LOG("new cart parser @ 0x%08x", _cartParser);
|
||||||
@ -90,11 +90,12 @@ bool App::_cartDetectWorker(void) {
|
|||||||
_cartInitDone:
|
_cartInitDone:
|
||||||
_workerStatus.update(2, 3, WSTR("App.cartDetectWorker.readDigitalIO"));
|
_workerStatus.update(2, 3, WSTR("App.cartDetectWorker.readDigitalIO"));
|
||||||
|
|
||||||
|
if (
|
||||||
#ifdef ENABLE_DUMMY_DRIVER
|
#ifdef ENABLE_DUMMY_DRIVER
|
||||||
if (io::isDigitalIOPresent() && !(_dump.flags & cart::DUMP_SYSTEM_ID_OK)) {
|
!(_cartDump.flags & cart::DUMP_SYSTEM_ID_OK) &&
|
||||||
#else
|
|
||||||
if (io::isDigitalIOPresent()) {
|
|
||||||
#endif
|
#endif
|
||||||
|
io::isDigitalIOPresent()
|
||||||
|
) {
|
||||||
util::Data bitstream;
|
util::Data bitstream;
|
||||||
bool ready;
|
bool ready;
|
||||||
|
|
||||||
@ -141,7 +142,8 @@ bool App::_cartUnlockWorker(void) {
|
|||||||
if (error) {
|
if (error) {
|
||||||
_messageScreen.setMessage(
|
_messageScreen.setMessage(
|
||||||
MESSAGE_ERROR, _cartInfoScreen,
|
MESSAGE_ERROR, _cartInfoScreen,
|
||||||
WSTRH(_UNLOCK_ERRORS[_dump.chipType]), cart::getErrorString(error)
|
WSTRH(_UNLOCK_ERRORS[_cartDump.chipType]),
|
||||||
|
cart::getErrorString(error)
|
||||||
);
|
);
|
||||||
|
|
||||||
_workerStatus.setNextScreen(_messageScreen);
|
_workerStatus.setNextScreen(_messageScreen);
|
||||||
@ -151,7 +153,7 @@ bool App::_cartUnlockWorker(void) {
|
|||||||
if (_cartParser)
|
if (_cartParser)
|
||||||
delete _cartParser;
|
delete _cartParser;
|
||||||
|
|
||||||
_cartParser = cart::newCartParser(_dump);
|
_cartParser = cart::newCartParser(_cartDump);
|
||||||
|
|
||||||
if (!_cartParser)
|
if (!_cartParser)
|
||||||
return true;
|
return true;
|
||||||
@ -162,7 +164,7 @@ bool App::_cartUnlockWorker(void) {
|
|||||||
char code[8], region[8];
|
char code[8], region[8];
|
||||||
|
|
||||||
if (_cartParser->getCode(code) && _cartParser->getRegion(region))
|
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),
|
// If auto-identification failed (e.g. because the format has no game code),
|
||||||
// use the game whose unlocking key was selected as a hint.
|
// use the game whose unlocking key was selected as a hint.
|
||||||
@ -177,7 +179,7 @@ bool App::_cartUnlockWorker(void) {
|
|||||||
|
|
||||||
delete _cartParser;
|
delete _cartParser;
|
||||||
_cartParser = cart::newCartParser(
|
_cartParser = cart::newCartParser(
|
||||||
_dump, _identified->formatType, _identified->flags
|
_cartDump, _identified->formatType, _identified->flags
|
||||||
);
|
);
|
||||||
|
|
||||||
LOG("new cart parser @ 0x%08x", _cartParser);
|
LOG("new cart parser @ 0x%08x", _cartParser);
|
||||||
@ -189,7 +191,7 @@ bool App::_qrCodeWorker(void) {
|
|||||||
|
|
||||||
_workerStatus.setNextScreen(_qrCodeScreen);
|
_workerStatus.setNextScreen(_qrCodeScreen);
|
||||||
_workerStatus.update(0, 2, WSTR("App.qrCodeWorker.compress"));
|
_workerStatus.update(0, 2, WSTR("App.qrCodeWorker.compress"));
|
||||||
_dump.toQRString(qrString);
|
_cartDump.toQRString(qrString);
|
||||||
|
|
||||||
_workerStatus.update(1, 2, WSTR("App.qrCodeWorker.generate"));
|
_workerStatus.update(1, 2, WSTR("App.qrCodeWorker.generate"));
|
||||||
_qrCodeScreen.generateCode(qrString);
|
_qrCodeScreen.generateCode(qrString);
|
||||||
@ -213,7 +215,7 @@ bool App::_cartDumpWorker(void) {
|
|||||||
char code[8], region[8];
|
char code[8], region[8];
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
length = _dump.getDumpLength();
|
length = _cartDump.getDumpLength();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_identified && _cartParser->getCode(code) &&
|
_identified && _cartParser->getCode(code) &&
|
||||||
@ -235,7 +237,7 @@ bool App::_cartDumpWorker(void) {
|
|||||||
|
|
||||||
LOG("saving %s, length=%d", path, length);
|
LOG("saving %s, length=%d", path, length);
|
||||||
|
|
||||||
if (_fileProvider.saveData(&_dump, length, path) != length)
|
if (_fileProvider.saveData(&_cartDump, length, path) != length)
|
||||||
goto _error;
|
goto _error;
|
||||||
|
|
||||||
_messageScreen.setMessage(
|
_messageScreen.setMessage(
|
||||||
@ -273,7 +275,7 @@ bool App::_cartWriteWorker(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dump.copyKeyFrom(key);
|
_cartDump.copyKeyFrom(key);
|
||||||
return _cartUnlockWorker();
|
return _cartUnlockWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +303,7 @@ bool App::_cartRestoreWorker(void) {
|
|||||||
_file->close();
|
_file->close();
|
||||||
delete _file;
|
delete _file;
|
||||||
|
|
||||||
if (_dump.chipType != newDump.chipType) {
|
if (_cartDump.chipType != newDump.chipType) {
|
||||||
_messageScreen.setMessage(
|
_messageScreen.setMessage(
|
||||||
MESSAGE_ERROR, _filePickerScreen,
|
MESSAGE_ERROR, _filePickerScreen,
|
||||||
WSTR("App.cartRestoreWorker.typeError"), path
|
WSTR("App.cartRestoreWorker.typeError"), path
|
||||||
@ -321,9 +323,9 @@ bool App::_cartRestoreWorker(void) {
|
|||||||
if (newDump.flags & (
|
if (newDump.flags & (
|
||||||
cart::DUMP_PUBLIC_DATA_OK | cart::DUMP_PRIVATE_DATA_OK
|
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)
|
if (newDump.flags & cart::DUMP_CONFIG_OK)
|
||||||
_dump.copyConfigFrom(newDump.config);
|
_cartDump.copyConfigFrom(newDump.config);
|
||||||
|
|
||||||
_workerStatus.update(2, 3, WSTR("App.cartRestoreWorker.write"));
|
_workerStatus.update(2, 3, WSTR("App.cartRestoreWorker.write"));
|
||||||
error = _cartDriver->writeData();
|
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.
|
// Make sure a valid cart ID is present if required by the new data.
|
||||||
if (
|
if (
|
||||||
_selectedEntry->requiresCartID() &&
|
_selectedEntry->requiresCartID() &&
|
||||||
!(_dump.flags & cart::DUMP_CART_ID_OK)
|
!(_cartDump.flags & cart::DUMP_CART_ID_OK)
|
||||||
) {
|
) {
|
||||||
_messageScreen.setMessage(
|
_messageScreen.setMessage(
|
||||||
MESSAGE_ERROR, _cartInfoScreen,
|
MESSAGE_ERROR, _cartInfoScreen,
|
||||||
@ -382,21 +384,23 @@ bool App::_cartReflashWorker(void) {
|
|||||||
delete _cartParser;
|
delete _cartParser;
|
||||||
|
|
||||||
_cartParser = cart::newCartParser(
|
_cartParser = cart::newCartParser(
|
||||||
_dump, _selectedEntry->formatType, _selectedEntry->flags
|
_cartDump, _selectedEntry->formatType, _selectedEntry->flags
|
||||||
);
|
);
|
||||||
auto pri = _cartParser->getIdentifiers();
|
auto pri = _cartParser->getIdentifiers();
|
||||||
auto pub = _cartParser->getPublicIdentifiers();
|
auto pub = _cartParser->getPublicIdentifiers();
|
||||||
|
|
||||||
_dump.clearData();
|
_cartDump.clearData();
|
||||||
_dump.initConfig(9, _selectedEntry->flags & cart::DATA_HAS_PUBLIC_SECTION);
|
_cartDump.initConfig(
|
||||||
|
9, _selectedEntry->flags & cart::DATA_HAS_PUBLIC_SECTION
|
||||||
|
);
|
||||||
|
|
||||||
if (pri) {
|
if (pri) {
|
||||||
if (_selectedEntry->flags & cart::DATA_HAS_CART_ID)
|
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)
|
if (_selectedEntry->flags & cart::DATA_HAS_TRACE_ID)
|
||||||
pri->updateTraceID(
|
pri->updateTraceID(
|
||||||
_selectedEntry->traceIDType, _selectedEntry->traceIDParam,
|
_selectedEntry->traceIDType, _selectedEntry->traceIDParam,
|
||||||
&_dump.cartID
|
&_cartDump.cartID
|
||||||
);
|
);
|
||||||
if (_selectedEntry->flags & cart::DATA_HAS_INSTALL_ID) {
|
if (_selectedEntry->flags & cart::DATA_HAS_INSTALL_ID) {
|
||||||
// The private installation ID seems to be unused on carts with a
|
// The private installation ID seems to be unused on carts with a
|
||||||
|
@ -37,10 +37,14 @@ bool App::_startupWorker(void) {
|
|||||||
|
|
||||||
_workerStatus.update(2, 4, WSTR("App.startupWorker.initFAT"));
|
_workerStatus.update(2, 4, WSTR("App.startupWorker.initFAT"));
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Attempt to mount the secondary drive first, then in case of failure try
|
// Attempt to mount the secondary drive first, then in case of failure try
|
||||||
// mounting the primary drive instead.
|
// mounting the primary drive instead.
|
||||||
if (!_fileProvider.init("1:"))
|
if (!_fileProvider.init("1:"))
|
||||||
_fileProvider.init("0:");
|
_fileProvider.init("0:");
|
||||||
|
#else
|
||||||
|
_fileProvider.init("1:");
|
||||||
|
#endif
|
||||||
|
|
||||||
_workerStatus.update(3, 4, WSTR("App.startupWorker.loadResources"));
|
_workerStatus.update(3, 4, WSTR("App.startupWorker.loadResources"));
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ void StorageActionsScreen::update(ui::Context &ctx) {
|
|||||||
|
|
||||||
if (ctx.buttons.pressed(ui::BTN_START)) {
|
if (ctx.buttons.pressed(ui::BTN_START)) {
|
||||||
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
|
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 {
|
} else {
|
||||||
if (action.region.isPresent()) {
|
if (action.region.isPresent()) {
|
||||||
this->_selectedRegion = &(action.region);
|
this->_selectedRegion = &(action.region);
|
||||||
@ -322,9 +322,9 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
|
|
||||||
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
|
char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)];
|
||||||
|
|
||||||
_PRINT(STR("ChecksumScreen.bios"), biosCRC);
|
_PRINT(STR("ChecksumScreen.bios"), values.bios);
|
||||||
_PRINT(STR("ChecksumScreen.rtc"), rtcCRC);
|
_PRINT(STR("ChecksumScreen.rtc"), values.rtc);
|
||||||
_PRINT(STR("ChecksumScreen.flash"), flashCRC);
|
_PRINT(STR("ChecksumScreen.flash"), values.flash);
|
||||||
|
|
||||||
_PRINTLN();
|
_PRINTLN();
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto slot = i + 1;
|
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, 16, crc[0]);
|
||||||
_PRINT(STR("ChecksumScreen.pcmcia"), slot, 32, crc[1]);
|
_PRINT(STR("ChecksumScreen.pcmcia"), slot, 32, crc[1]);
|
||||||
@ -342,7 +342,9 @@ void ChecksumScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_PRINTLN();
|
_PRINTLN();
|
||||||
}
|
}
|
||||||
|
|
||||||
*(--ptr) = 0;
|
_PRINT(STR("ChecksumScreen.description"));
|
||||||
|
|
||||||
|
//*(--ptr) = 0;
|
||||||
LOG("remaining=%d", end - ptr);
|
LOG("remaining=%d", end - ptr);
|
||||||
|
|
||||||
TextScreen::show(ctx, goBack);
|
TextScreen::show(ctx, goBack);
|
||||||
|
@ -41,14 +41,21 @@ public:
|
|||||||
void update(ui::Context &ctx);
|
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 {
|
class ChecksumScreen : public ui::TextScreen {
|
||||||
private:
|
private:
|
||||||
char _bodyText[2048];
|
char _bodyText[2048];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool valid;
|
bool valid;
|
||||||
uint32_t biosCRC, rtcCRC, flashCRC;
|
ChecksumValues values;
|
||||||
uint32_t pcmciaCRC[2][4];
|
|
||||||
|
|
||||||
inline ChecksumScreen(void)
|
inline ChecksumScreen(void)
|
||||||
: valid(false) {}
|
: valid(false) {}
|
||||||
|
@ -23,31 +23,31 @@ static const RegionInfo _REGION_INFO[]{
|
|||||||
.crcPrompt = "App.romChecksumWorker.hashBIOS"_h,
|
.crcPrompt = "App.romChecksumWorker.hashBIOS"_h,
|
||||||
.path = "%s/bios.bin",
|
.path = "%s/bios.bin",
|
||||||
.region = rom::bios,
|
.region = rom::bios,
|
||||||
.crcOffset = offsetof(ChecksumScreen, biosCRC)
|
.crcOffset = offsetof(ChecksumValues, bios)
|
||||||
}, {
|
}, {
|
||||||
.dumpPrompt = "App.romDumpWorker.dumpRTC"_h,
|
.dumpPrompt = "App.romDumpWorker.dumpRTC"_h,
|
||||||
.crcPrompt = "App.romChecksumWorker.hashRTC"_h,
|
.crcPrompt = "App.romChecksumWorker.hashRTC"_h,
|
||||||
.path = "%s/rtc.bin",
|
.path = "%s/rtc.bin",
|
||||||
.region = rom::rtc,
|
.region = rom::rtc,
|
||||||
.crcOffset = offsetof(ChecksumScreen, rtcCRC)
|
.crcOffset = offsetof(ChecksumValues, rtc)
|
||||||
}, {
|
}, {
|
||||||
.dumpPrompt = "App.romDumpWorker.dumpFlash"_h,
|
.dumpPrompt = "App.romDumpWorker.dumpFlash"_h,
|
||||||
.crcPrompt = "App.romChecksumWorker.hashFlash"_h,
|
.crcPrompt = "App.romChecksumWorker.hashFlash"_h,
|
||||||
.path = "%s/flash.bin",
|
.path = "%s/flash.bin",
|
||||||
.region = rom::flash,
|
.region = rom::flash,
|
||||||
.crcOffset = offsetof(ChecksumScreen, flashCRC)
|
.crcOffset = offsetof(ChecksumValues, flash)
|
||||||
}, {
|
}, {
|
||||||
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA1"_h,
|
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA1"_h,
|
||||||
.crcPrompt = "App.romChecksumWorker.hashPCMCIA1"_h,
|
.crcPrompt = "App.romChecksumWorker.hashPCMCIA1"_h,
|
||||||
.path = "%s/pcmcia1.bin",
|
.path = "%s/pcmcia1.bin",
|
||||||
.region = rom::pcmcia[0],
|
.region = rom::pcmcia[0],
|
||||||
.crcOffset = offsetof(ChecksumScreen, pcmciaCRC[0])
|
.crcOffset = offsetof(ChecksumValues, pcmcia[0])
|
||||||
}, {
|
}, {
|
||||||
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA2"_h,
|
.dumpPrompt = "App.romDumpWorker.dumpPCMCIA2"_h,
|
||||||
.crcPrompt = "App.romChecksumWorker.hashPCMCIA2"_h,
|
.crcPrompt = "App.romChecksumWorker.hashPCMCIA2"_h,
|
||||||
.path = "%s/pcmcia2.bin",
|
.path = "%s/pcmcia2.bin",
|
||||||
.region = rom::pcmcia[1],
|
.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 offset = 0;
|
||||||
uint32_t crc = 0;
|
uint32_t crc = 0;
|
||||||
auto crcPtr = reinterpret_cast<uint32_t *>(
|
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
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,6 +709,6 @@ template<typename T> const T *DB<T>::lookup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template class DB<CartDBEntry>;
|
template class DB<CartDBEntry>;
|
||||||
template class DB<FlashDBEntry>;
|
template class DB<ROMHeaderDBEntry>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class [[gnu::packed]] FlashDBEntry {
|
class [[gnu::packed]] ROMHeaderDBEntry {
|
||||||
public:
|
public:
|
||||||
// TODO: define these flags
|
// TODO: define these flags
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -332,7 +332,7 @@ public:
|
|||||||
const T *lookup(const char *code, const char *region) const;
|
const T *lookup(const char *code, const char *region) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CartDB = DB<CartDBEntry>;
|
using CartDB = DB<CartDBEntry>;
|
||||||
using FlashDB = DB<FlashDBEntry>;
|
using ROMHeaderDB = DB<ROMHeaderDBEntry>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user