Add JEDEC ID reading, FAT info, fix warnings/bugs

This commit is contained in:
spicyjpeg 2023-12-30 15:41:23 +01:00
parent f38a96621a
commit 6c86494fe1
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
19 changed files with 329 additions and 132 deletions

View File

@ -17,26 +17,29 @@
},
"cartEraseWorker": {
"erase": "Erasing cartridge...\nDo not turn off the 573.",
"error": "An error occurred while erasing the cartridge's EEPROM. The unlocking key may or may not have been successfully changed.\n\nPress the Test button to view debug logs."
"error": "An error occurred while erasing the cartridge's EEPROM. The unlocking key may or may not have been successfully changed.\n\nError code: %s\nPress the Test button to view debug logs."
},
"cartReflashWorker": {
"setDataKey": "Setting new unlocking key...\nDo not turn off the 573.",
"write": "Writing new data to cartridge...\nDo not turn off the 573.",
"idError": "The selected game is not compatible with the currently inserted cartridge, as it requires one with a valid DS2401 identifier.",
"writeError": "An error occurred while reflashing the cartridge. The unlocking key may or may not have been successfully changed.\n\nPress the Test button to view debug logs."
"writeError": "An error occurred while reflashing the cartridge. The unlocking key may or may not have been successfully changed.\n\nError code: %s\nPress the Test button to view debug logs."
},
"cartUnlockWorker": {
"read": "Dumping cartridge...\nDo not turn off the 573.",
"identifyGame": "Attempting to identify game..."
"identifyGame": "Attempting to identify game...",
"x76f041Error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the maximum allowed number of failed unlocking attempts may have been exceeded (and thus the cartridge may have been bricked).\n\nError code: %s\nPress the Test button to view debug logs.",
"x76f100Error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the cartridge may have self-erased and reset the key to a null key due to too many failed unlocking attempts.\n\nError code: %s\nPress the Test button to view debug logs.",
"zs01Error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the cartridge may have self-erased and reset the key to a null key due to too many failed unlocking attempts.\n\nError code: %s\nPress the Test button to view debug logs."
},
"cartWriteWorker": {
"write": "Writing new data to cartridge...\nDo not turn off the 573.",
"error": "An error occurred while writing to the cartridge's EEPROM.\n\nPress the Test button to view debug logs."
"error": "An error occurred while writing to the cartridge's EEPROM.\n\nError code: %s\nPress the Test button to view debug logs."
},
"cartDumpWorker": {
"save": "Saving cartridge dump...\nDo not turn off the 573.",
"success": "A dump of the cartridge and all its identifiers has been saved as %s in the root of the drive. The dump can be decoded and viewed using the decodeDump.py script provided with this tool.",
"error": "An error occurred while saving the dump to the hard drive. Turn off the system and make sure the drive is connected to the IDE bus properly, set as secondary and formatted with a single FAT16, FAT32 or exFAT partition.\n\nPress the Test button to view debug logs."
"error": "An error occurred while saving the dump (%s). Turn off the system and make sure the drive is connected to the IDE bus properly, set as secondary and formatted with a single FAT16, FAT32 or exFAT partition.\n\nPress the Test button to view debug logs."
},
"qrCodeWorker": {
"compress": "Compressing cartridge dump...",
@ -64,7 +67,7 @@
"eject": "Sending eject command...",
"success": "The drive's tray has been opened.\n\nYou may safely remove or replace the disc and close the tray. All data has been loaded into RAM and the tool will keep running until the 573 is turned off.",
"atapiError": "The drive currently configured as primary on the IDE bus is not an ATAPI CD-ROM drive and does not support ejecting.\n\nPress the Test button to view debug logs.",
"ejectError": "Failed to open the drive's tray. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs."
"ejectError": "Failed to open the drive's tray. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nError code: %s\nPress the Test button to view debug logs."
},
"rebootWorker": {
"reboot": "Rebooting system..."
@ -141,7 +144,7 @@
"cart": {
"header": "Security cartridge:\n",
"x76f041Info": " Chip type:\t\t{CHIP_ICON} Xicor X76F041\n Unlock status:\t%s\n DS2401 ID:\t\t%s\n Configuration:\t%s\n",
"x76f100Info": " Chip type:\t\t{CHIP_ICON} Xicor X76F041\n Unlock status:\t%s\n DS2401 ID:\t\t%s\n",
"x76f100Info": " Chip type:\t\t{CHIP_ICON} Xicor X76F100\n Unlock status:\t%s\n DS2401 ID:\t\t%s\n",
"zs01Info": " Chip type:\t\t{CHIP_ICON} Konami ZS01 (PIC16CE625)\n Unlock status:\t%s\n DS2401 ID:\t\t%s\n ZS01 ID:\t\t%s\n Configuration:\t%s\n"
},
"unlockStatus": {
@ -182,17 +185,10 @@
"error": "{RIGHT_ARROW} Hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back."
},
"x76f041": {
"warning": "X76F041 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, they will lock out any further access and thus become PERMANENTLY BRICKED, with no way to restore access.\n\nAre you sure the key is correct?",
"error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the maximum allowed number of failed unlocking attempts may have been exceeded (and thus the cartridge may have been bricked).\n\nPress the Test button to view debug logs."
},
"x76f100": {
"warning": "X76F100 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, the cartridge will self-erase and will have to be reinitialized to factory data and paired to the system again if the game requires it.\n\nAre you sure the key is correct?",
"error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the cartridge may have self-erased and reset the key to a null key due to too many failed unlocking attempts.\n\nPress the Test button to view debug logs."
},
"zs01": {
"warning": "ZS01 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, the cartridge will self-erase and will have to be reinitialized to factory data and paired to the system again if the game requires it.\n\nAre you sure the key is correct?",
"error": "An error occurred while attempting to unlock the cartridge; the key is probably incorrect. If you are sure you selected the proper key, the cartridge may have self-erased and reset the key to a null key due to too many failed unlocking attempts.\n\nPress the Test button to view debug logs."
"unlockWarning": {
"x76f041": "X76F041 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, they will lock out any further access and thus become PERMANENTLY BRICKED, with no way to restore access.\n\nAre you sure the key is correct?",
"x76f100": "X76F100 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, the cartridge will self-erase and will have to be reinitialized to factory data and paired to the system again if the game requires it.\n\nAre you sure the key is correct?",
"zs01": "ZS01 cartridges keep track of how many times a wrong key has been used. If too many unlock attempts fail, the cartridge will self-erase and will have to be reinitialized to factory data and paired to the system again if the game requires it.\n\nAre you sure the key is correct?"
}
},
@ -323,6 +319,11 @@
"hasFlush": " Supports cache flushing\n",
"error": " No drive present or initialization failed\n"
},
"fat": {
"header": "FAT file system:\n",
"info": " Type:\t\t%s\n Volume label:\t%s\n Serial number:\t%08X\n Formatted:\t\t%llu MB\n Free space:\t%llu MB\n",
"error": " No file system mounted\n"
},
"bios": {
"header": "BIOS ROM:\n",
"commonInfo": " CRC32:\t\t%08X\n",
@ -339,17 +340,17 @@
},
"rtc": {
"header": "RTC:\n",
"info": " CRC32:\t\t%08X\n",
"info": " CRC32:\t\t%08X (excl. clock registers)\n",
"batteryLow": " Battery voltage is below 2.5V\n"
},
"flash": {
"header": "Internal flash memory:\n",
"info": " JEDEC ID:\t\t%02X, %02X\n CRC32:\t\t%08X\n",
"info": " JEDEC ID:\t\tmanufacturer %02X, device %02X\n CRC32:\t\t%08X\n",
"bootable": " Valid boot executable present\n"
},
"pcmcia": {
"header": "PCMCIA card in slot %d:\n",
"info": " JEDEC ID:\t\t%02X, %02X\n CRC32 (16 MB):\t%08X\n CRC32 (32 MB):\t%08X\n CRC32 (64 MB):\t%08X\n",
"info": " JEDEC ID:\t\tmanufacturer %02X, device %02X\n CRC32 (16 MB):\t%08X\n CRC32 (32 MB):\t%08X\n CRC32 (64 MB):\t%08X\n",
"bootable": " Valid boot executable present\n",
"noCard": " No card inserted\n"
}

View File

@ -49,14 +49,14 @@ public:
/* System information buffer */
enum FlashRegionInfoFlag : uint8_t {
enum FlashRegionInfoFlag : uint16_t {
FLASH_REGION_INFO_PRESENT = 1 << 0,
FLASH_REGION_INFO_BOOTABLE = 1 << 1
};
class FlashRegionInfo {
public:
uint8_t flags, manufacturerID, deviceID;
uint16_t flags, jedecID;
uint32_t crc[4];
inline void clearFlags(void) {

View File

@ -162,6 +162,13 @@ _cartInitDone:
return true;
}
static const util::Hash _UNLOCK_ERRORS[cart::NUM_CHIP_TYPES]{
0,
"App.cartUnlockWorker.x76f041Error"_h,
"App.cartUnlockWorker.x76f100Error"_h,
"App.cartUnlockWorker.zs01Error"_h
};
bool App::_cartUnlockWorker(void) {
_workerStatus.setNextScreen(_cartInfoScreen, true);
_workerStatus.update(0, 2, WSTR("App.cartUnlockWorker.read"));
@ -169,11 +176,11 @@ bool App::_cartUnlockWorker(void) {
auto error = _driver->readPrivateData();
if (error) {
LOG("read error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen,
WSTRH(_UNLOCK_ERRORS[_dump.chipType]), util::getErrorString(error)
);
/*_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartUnlockWorker.error")
);*/
_workerStatus.setNextScreen(_messageScreen);
return false;
}
@ -259,7 +266,7 @@ bool App::_cartDumpWorker(void) {
_error:
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartDumpWorker.error")
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartDumpWorker.error"), path
);
_workerStatus.setNextScreen(_messageScreen);
return false;
@ -277,10 +284,9 @@ bool App::_cartWriteWorker(void) {
_cartDetectWorker();
if (error) {
LOG("write error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartWriteWorker.error")
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartWriteWorker.error"),
util::getErrorString(error)
);
_workerStatus.setNextScreen(_messageScreen);
return false;
@ -358,11 +364,10 @@ bool App::_cartReflashWorker(void) {
_cartDetectWorker();
if (error) {
LOG("write error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen,
WSTR("App.cartReflashWorker.writeError")
WSTR("App.cartReflashWorker.writeError"),
util::getErrorString(error)
);
_workerStatus.setNextScreen(_messageScreen);
return false;
@ -378,10 +383,9 @@ bool App::_cartEraseWorker(void) {
_cartDetectWorker();
if (error) {
LOG("erase error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartEraseWorker.error")
MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartEraseWorker.error"),
util::getErrorString(error)
);
_workerStatus.setNextScreen(_messageScreen);
return false;
@ -578,31 +582,28 @@ bool App::_systemInfoWorker(void) {
}
}
_systemInfo.flags = SYSTEM_INFO_VALID;
_systemInfo.flash.flags = FLASH_REGION_INFO_PRESENT;
_systemInfo.shell = rom::getShellInfo();
_systemInfo.flags = SYSTEM_INFO_VALID;
_systemInfo.shell = rom::getShellInfo();
if (io::isRTCBatteryLow())
_systemInfo.flags |= SYSTEM_INFO_RTC_BATTERY_LOW;
_systemInfo.flash.jedecID = rom::flash.getJEDECID();
_systemInfo.flash.flags = FLASH_REGION_INFO_PRESENT;
if (rom::flash.hasBootExecutable())
_systemInfo.flash.flags |= FLASH_REGION_INFO_BOOTABLE;
// TODO: actually read the JEDEC IDs
_systemInfo.flash.manufacturerID = 0;
_systemInfo.flash.deviceID = 0;
for (int i = 0; i < 2; i++) {
auto &region = rom::pcmcia[i];
auto &card = _systemInfo.pcmcia[i];
if (region.isPresent()) {
card.flags |= FLASH_REGION_INFO_PRESENT;
card.jedecID = region.getJEDECID();
card.flags = FLASH_REGION_INFO_PRESENT;
if (region.hasBootExecutable())
card.flags |= FLASH_REGION_INFO_BOOTABLE;
card.manufacturerID = 0;
card.deviceID = 0;
}
}
@ -629,11 +630,9 @@ bool App::_atapiEjectWorker(void) {
auto error = ide::devices[0].atapiPacket(packet);
if (error) {
LOG("eject error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _mainMenuScreen,
WSTR("App.atapiEjectWorker.ejectError")
WSTR("App.atapiEjectWorker.ejectError"), util::getErrorString(error)
);
_workerStatus.setNextScreen(_messageScreen);
return false;

View File

@ -1,35 +1,18 @@
#include <stdio.h>
#include <string.h>
#include "app/app.hpp"
#include "app/cartunlock.hpp"
#include "cartdata.hpp"
#include "cartio.hpp"
#include "defs.hpp"
#include "uibase.hpp"
#include "util.hpp"
/* Pre-unlock cartridge screens */
struct CartType {
public:
util::Hash warning, error;
};
static const CartType _CART_TYPES[cart::NUM_CHIP_TYPES]{
{
.warning = 0,
.error = 0
}, {
.warning = "CartInfoScreen.x76f041.warning"_h,
.error = "CartInfoScreen.x76f041.error"_h
}, {
.warning = "CartInfoScreen.x76f100.warning"_h,
.error = "CartInfoScreen.x76f100.error"_h
}, {
.warning = "CartInfoScreen.zs01.warning"_h,
.error = "CartInfoScreen.zs01.error"_h
}
static const util::Hash _UNLOCK_WARNINGS[cart::NUM_CHIP_TYPES]{
0,
"CartInfoScreen.unlockWarning.x76f041"_h,
"CartInfoScreen.unlockWarning.x76f100"_h,
"CartInfoScreen.unlockWarning.zs01"_h
};
enum IdentifyState {
@ -340,12 +323,7 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_CART_TYPES[APP->_dump.chipType].warning)
);
APP->_messageScreen.setMessage(
MESSAGE_ERROR, APP->_cartInfoScreen,
STRH(_CART_TYPES[APP->_dump.chipType].error)
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
);
if (index < 0) {
@ -392,12 +370,7 @@ void KeyEntryScreen::update(ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_CART_TYPES[APP->_dump.chipType].warning)
);
APP->_messageScreen.setMessage(
MESSAGE_ERROR, APP->_cartInfoScreen,
STRH(_CART_TYPES[APP->_dump.chipType].error)
STRH(_UNLOCK_WARNINGS[APP->_dump.chipType])
);
__builtin_memcpy(

View File

@ -8,7 +8,7 @@
class CartInfoScreen : public ui::TextScreen {
private:
char _bodyText[1024];
char _bodyText[2048];
public:
void show(ui::Context &ctx, bool goBack = false);

View File

@ -25,6 +25,7 @@ void WarningScreen::show(ui::Context &ctx, bool goBack) {
MessageBoxScreen::show(ctx, goBack);
ctx.buttons.buttonMap = ui::MAP_SINGLE_BUTTON;
ctx.buttons.reset();
}
void WarningScreen::update(ui::Context &ctx) {
@ -68,6 +69,7 @@ void ButtonMappingScreen::show(ui::Context &ctx, bool goBack) {
ListScreen::show(ctx, goBack);
ctx.buttons.buttonMap = ui::MAP_SINGLE_BUTTON;
ctx.buttons.reset();
}
void ButtonMappingScreen::update(ui::Context &ctx) {
@ -75,6 +77,8 @@ void ButtonMappingScreen::update(ui::Context &ctx) {
if (ctx.buttons.pressed(ui::BTN_START)) {
ctx.buttons.buttonMap = ui::ButtonMap(_activeItem);
ctx.buttons.reset();
ctx.show(APP->_mainMenuScreen, false, true);
}
}
@ -217,6 +221,14 @@ static const util::Hash _SYSTEM_INFO_IDE_HEADERS[]{
"SystemInfoScreen.ide.header.secondary"_h
};
static const char *const _FILE_SYSTEM_TYPES[]{
nullptr,
"FAT12",
"FAT16",
"FAT32",
"exFAT"
};
#define _PRINT(...) (ptr += snprintf(ptr, end - ptr, __VA_ARGS__))
#define _PRINTLN() (*(ptr++) = '\n')
@ -282,6 +294,27 @@ void SystemInfoScreen::show(ui::Context &ctx, bool goBack) {
_PRINTLN();
}
// FAT file system
auto &fs = APP->_fileProvider;
auto fsType = fs.getFileSystemType();
_PRINT(STR("SystemInfoScreen.fat.header"));
if (fsType) {
char label[32];
fs.getVolumeLabel(label, sizeof(label));
_PRINT(
STR("SystemInfoScreen.fat.info"), _FILE_SYSTEM_TYPES[fsType], label,
fs.getSerialNumber(), fs.getCapacity() / 0x100000,
fs.getFreeSpace() / 0x100000
);
} else {
_PRINT(STR("SystemInfoScreen.fat.error"));
}
_PRINTLN();
// BIOS ROM
auto &info = APP->_systemInfo;
@ -298,7 +331,6 @@ void SystemInfoScreen::show(ui::Context &ctx, bool goBack) {
char buildID[64];
rom::openBIOSHeader.getBuildID(buildID);
_PRINT(STR("SystemInfoScreen.bios.kernelInfo.openbios"), buildID);
} else {
_PRINT(STR("SystemInfoScreen.bios.kernelInfo.unknown"));
@ -326,8 +358,8 @@ void SystemInfoScreen::show(ui::Context &ctx, bool goBack) {
// Flash
_PRINT(STR("SystemInfoScreen.flash.header"));
_PRINT(
STR("SystemInfoScreen.flash.info"), info.flash.manufacturerID,
info.flash.deviceID, info.flash.crc[0]
STR("SystemInfoScreen.flash.info"), info.flash.jedecID & 0xff,
info.flash.jedecID >> 8, info.flash.crc[0]
);
if (info.flash.flags & FLASH_REGION_INFO_BOOTABLE)
@ -343,8 +375,8 @@ void SystemInfoScreen::show(ui::Context &ctx, bool goBack) {
if (card.flags & FLASH_REGION_INFO_PRESENT) {
_PRINT(
STR("SystemInfoScreen.pcmcia.info"), card.manufacturerID,
card.deviceID, card.crc[0], card.crc[1], card.crc[3]
STR("SystemInfoScreen.pcmcia.info"), card.jedecID & 0xff,
card.jedecID >> 8, card.crc[0], card.crc[1], card.crc[3]
);
if (card.flags & FLASH_REGION_INFO_BOOTABLE)

View File

@ -64,8 +64,8 @@ void BasicParser::setCode(const char *input) {
auto header = _getHeader();
header->region[2] = input[0];
header->region[3] = input[1];
header->codePrefix[0] = input[0];
header->codePrefix[1] = input[1];
}
size_t BasicParser::getRegion(char *output) const {

View File

@ -258,6 +258,10 @@ bool HostProvider::init(void) {
return true;
}
FileSystemType HostProvider::getFileSystemType(void) {
return HOST;
}
bool HostProvider::createDirectory(const char *path) {
int fd = pcdrvCreate(path, DIRECTORY);
@ -311,14 +315,78 @@ bool FATProvider::init(const char *drive) {
void FATProvider::close(void) {
auto error = f_unmount(_drive);
if (error)
if (error) {
LOG("%s, drive=%s", util::getErrorString(error), _drive);
else
LOG("FAT unmount ok, drive=%s", _drive);
return;
}
LOG("FAT unmount ok, drive=%s", _drive);
}
FileSystemType FATProvider::getFileSystemType(void) {
return FileSystemType(_fs.fs_type);
}
uint64_t FATProvider::getCapacity(void) {
if (!_fs.fs_type)
return 0;
size_t clusterSize = size_t(_fs.csize) * size_t(_fs.ssize);
return uint64_t(_fs.n_fatent - 2) * uint64_t(clusterSize);
}
uint64_t FATProvider::getFreeSpace(void) {
if (!_fs.fs_type)
return 0;
uint32_t count;
FATFS *dummy;
auto error = f_getfree(_drive, &count, &dummy);
if (error) {
LOG("%s, drive=%s", util::getErrorString(error), _drive);
return 0;
}
size_t clusterSize = size_t(_fs.csize) * size_t(_fs.ssize);
return uint64_t(count) * uint64_t(clusterSize);
}
size_t FATProvider::getVolumeLabel(char *output, size_t length) {
//assert(length >= 23);
if (!_fs.fs_type)
return 0;
auto error = f_getlabel(_drive, output, nullptr);
if (error) {
LOG("%s, drive=%s", util::getErrorString(error), _drive);
return 0;
}
return __builtin_strlen(output);
}
uint32_t FATProvider::getSerialNumber(void) {
if (!_fs.fs_type)
return 0;
uint32_t serial;
auto error = f_getlabel(_drive, nullptr, &serial);
if (error) {
LOG("%s, drive=%s", util::getErrorString(error), _drive);
return 0;
}
return serial;
}
bool FATProvider::_selectDrive(void) {
if (!_drive[0])
if (!_fs.fs_type)
return false;
return !f_chdrive(_drive);
@ -449,6 +517,17 @@ void ZIPProvider::close(void) {
}
}
FileSystemType ZIPProvider::getFileSystemType(void) {
if (!_zip.m_zip_mode)
return NONE;
return _file ? ZIP_FILE : ZIP_MEMORY;
}
uint64_t ZIPProvider::getCapacity(void) {
return _zip.m_archive_size;
}
bool ZIPProvider::getFileInfo(FileInfo &output, const char *path) {
mz_zip_archive_file_stat info;

View File

@ -3,7 +3,6 @@
#include <stddef.h>
#include <stdint.h>
#include "file.hpp"
#include "vendor/ff.h"
#include "vendor/miniz.h"
#include "gpu.hpp"
@ -16,6 +15,17 @@ namespace file {
static constexpr size_t MAX_PATH_LENGTH = 256;
// The first 4 of these map to the FS_* enum used by FatFs.
enum FileSystemType {
NONE = 0,
FAT12 = 1,
FAT16 = 2,
FAT32 = 3,
HOST = 4,
ZIP_MEMORY = 5,
ZIP_FILE = 6
};
// These are functionally equivalent to the FA_* flags used by FatFs.
enum FileModeFlag {
READ = 1 << 0,
@ -123,6 +133,10 @@ public:
virtual void close(void) {}
virtual FileSystemType getFileSystemType(void) { return NONE; }
virtual uint64_t getCapacity(void) { return 0; }
virtual uint64_t getFreeSpace(void) { return 0; }
virtual bool getFileInfo(FileInfo &output, const char *path) { return false; }
virtual Directory *openDirectory(const char *path) { return nullptr; }
virtual bool createDirectory(const char *path) { return false; }
@ -139,6 +153,8 @@ class HostProvider : public Provider {
public:
bool init(void);
FileSystemType getFileSystemType(void);
bool createDirectory(const char *path);
File *openFile(const char *path, uint32_t flags);
@ -153,12 +169,19 @@ private:
public:
inline FATProvider(void) {
_drive[0] = 0;
_fs.fs_type = 0;
_drive[0] = 0;
}
bool init(const char *drive);
void close(void);
FileSystemType getFileSystemType(void);
uint64_t getCapacity(void);
uint64_t getFreeSpace(void);
size_t getVolumeLabel(char *output, size_t length);
uint32_t getSerialNumber(void);
bool getFileInfo(FileInfo &output, const char *path);
Directory *openDirectory(const char *path);
bool createDirectory(const char *path);
@ -177,6 +200,9 @@ public:
bool init(const void *zipData, size_t length);
void close(void);
FileSystemType getFileSystemType(void);
uint64_t getCapacity(void);
bool getFileInfo(FileInfo &output, const char *path);
size_t loadData(util::Data &output, const char *path);

View File

@ -8,9 +8,9 @@
/* FatFs library API glue */
extern "C" DSTATUS disk_initialize(uint8_t drive) {
#if 0
auto &dev = ide::devices[drive];
#if 0
if (!(dev.flags & ide::DEVICE_READY)) {
if (dev.enumerate())
return RES_NOTRDY;

View File

@ -4,7 +4,6 @@
#include "ps1/registers.h"
#include "ps1/system.h"
#include "io.hpp"
#include "util.hpp"
namespace io {

View File

@ -128,7 +128,9 @@ _resourceInitDone:
io::setMiscOutput(io::MISC_SPU_ENABLE, true);
app->run();
delete app, uiCtx, gpuCtx;
delete app;
delete uiCtx;
delete gpuCtx;
uninstallExceptionHandler();
return 0;

View File

@ -107,6 +107,8 @@ void FlashRegion::read(void *data, uint32_t offset, size_t length) const {
uint32_t FlashRegion::zipCRC32(
uint32_t offset, size_t length, uint32_t crc
) const {
// FIXME: this implementation will not handle reads that cross bank
// boundaries properly
int bankOffset = offset / _FLASH_BANK_LENGTH;
int ptrOffset = offset % _FLASH_BANK_LENGTH;
@ -133,6 +135,8 @@ uint32_t FlashRegion::zipCRC32(
}
bool FlashRegion::hasBootExecutable(void) const {
// FIXME: this implementation will not detect executables that cross bank
// boundaries (but it shouldn't matter as executables must be <4 MB anyway)
auto data = reinterpret_cast<const uint8_t *>(ptr + _FLASH_EXE_OFFSET);
auto crcPtr = reinterpret_cast<const uint32_t *>(ptr + _FLASH_CRC_OFFSET);
auto table = reinterpret_cast<const uint32_t *>(CACHE_BASE);
@ -146,8 +150,10 @@ bool FlashRegion::hasBootExecutable(void) const {
// The integrity of the executable is verified by calculating the CRC32 of
// its bytes whose offsets are powers of 2 (i.e. the bytes at indices 0, 1,
// 2, 4, 8 and so on).
size_t length = header.textLength + 2048;
// 2, 4, 8 and so on). Note that the actual size of the executable is
// header.textLength + 2048, as the CRC is also calculated on the header,
// but Konami's shell ignores the last 2048 bytes due to a bug.
size_t length = header.textLength;
uint32_t crc = ~0;
crc = (crc >> 8) ^ table[(crc ^ *data) & 0xff];
@ -158,6 +164,27 @@ bool FlashRegion::hasBootExecutable(void) const {
return (~crc == *crcPtr);
}
uint16_t FlashRegion::getJEDECID(void) const {
auto flash = reinterpret_cast<volatile uint16_t *>(ptr);
io::setFlashBank(bank);
flash[0x000] = SHARP_RESET;
flash[0x000] = SHARP_RESET;
flash[0x555] = FUJITSU_HANDSHAKE1;
flash[0x2aa] = FUJITSU_HANDSHAKE2;
flash[0x555] = FUJITSU_GET_JEDEC_ID;
uint16_t id = (flash[0] & 0xff) | ((flash[1] & 0xff) << 8);
if (id == ID_SHARP_LH28F016S)
flash[0x000] = SHARP_RESET;
else
flash[0x000] = FUJITSU_RESET;
return id;
}
const BIOSRegion bios;
const RTCRegion rtc;
const FlashRegion flash(SYS573_BANK_FLASH, 0x1000000);

View File

@ -53,12 +53,47 @@ public:
uint32_t zipCRC32(uint32_t offset, size_t length, uint32_t crc = 0) const;
bool hasBootExecutable(void) const;
uint16_t getJEDECID(void) const;
};
extern const BIOSRegion bios;
extern const RTCRegion rtc;
extern const FlashRegion flash, pcmcia[2];
/* Flash memory driver */
enum FlashManufacturer : uint8_t {
MANUF_FUJITSU = 0x04,
MANUF_SHARP = 0x89
};
enum FlashJEDECID : uint16_t {
ID_FUJITSU_MBM29F016A = MANUF_FUJITSU | (0xad << 8),
ID_FUJITSU_MBM29F016A_ALT = MANUF_FUJITSU | (0x3d << 8),
ID_FUJITSU_UNKNOWN = MANUF_FUJITSU | (0xa4 << 8),
ID_SHARP_LH28F016S = MANUF_SHARP | (0xaa << 8)
};
enum FlashCommand : uint16_t {
SHARP_ERASE_SECTOR = 0x2020,
SHARP_WRITE = 0x4040,
SHARP_CLEAR_STATUS = 0x5050,
SHARP_GET_STATUS = 0x7070,
SHARP_GET_JEDEC_ID = 0x9090,
SHARP_SUSPEND = 0xb0b0,
SHARP_RESUME = 0xd0d0,
SHARP_RESET = 0xffff,
FUJITSU_ERASE_CHIP = 0x1010,
FUJITSU_ERASE_SECTOR = 0x3030,
FUJITSU_HANDSHAKE2 = 0x5555,
FUJITSU_ERASE = 0x8080,
FUJITSU_GET_JEDEC_ID = 0x9090,
FUJITSU_WRITE = 0xa0a0,
FUJITSU_HANDSHAKE1 = 0xaaaa,
FUJITSU_RESET = 0xf0f0
};
/* BIOS ROM headers */
struct [[gnu::packed]] SonyKernelHeader {

View File

@ -51,24 +51,16 @@ static const uint32_t _BUTTON_MAPPINGS[NUM_BUTTON_MAPS][NUM_BUTTONS]{
};
ButtonState::ButtonState(void)
: _held(0), _repeatTimer(0), buttonMap(MAP_JOYSTICK) {}
void ButtonState::update(void) {
_prevHeld = _held;
_held = 0;
: _held(0), _prevHeld(0), _pressed(0), _released(0), _repeating(0),
_repeatTimer(0), buttonMap(MAP_JOYSTICK) {}
uint8_t ButtonState::_getHeld(void) const {
uint32_t inputs = io::getJAMMAInputs();
uint8_t held = 0;
auto map = _BUTTON_MAPPINGS[buttonMap];
for (int i = 0; i < NUM_BUTTONS; i++) {
if (inputs & map[i])
_held |= 1 << i;
}
#ifdef ENABLE_PS1_CONTROLLER
if (pad::ports[0].pollPad() || pad::ports[1].pollPad()) {
_held = 0; // Ignore JAMMA inputs
for (int i = 1; i >= 0; i--) {
auto &port = pad::ports[i];
@ -80,17 +72,41 @@ void ButtonState::update(void) {
continue;
if (port.buttons & (pad::BTN_LEFT | pad::BTN_UP))
_held |= 1 << BTN_LEFT;
held |= 1 << BTN_LEFT;
if (port.buttons & (pad::BTN_RIGHT | pad::BTN_DOWN))
_held |= 1 << BTN_RIGHT;
held |= 1 << BTN_RIGHT;
if (port.buttons & (pad::BTN_CIRCLE | pad::BTN_CROSS))
_held |= 1 << BTN_START;
held |= 1 << BTN_START;
if (port.buttons & pad::BTN_SELECT)
_held |= 1 << BTN_DEBUG;
held |= 1 << BTN_DEBUG;
}
return held; // Ignore JAMMA inputs
}
#endif
for (int i = 0; i < NUM_BUTTONS; i++) {
if (inputs & map[i])
held |= 1 << i;
}
return held;
}
void ButtonState::reset(void) {
_held = _getHeld();
_prevHeld = _held;
_pressed = 0;
_released = 0;
_repeating = 0;
_repeatTimer = 0;
}
void ButtonState::update(void) {
_prevHeld = _held;
_held = _getHeld();
uint32_t changed = _prevHeld ^ _held;
if (buttonMap == MAP_SINGLE_BUTTON) {

View File

@ -107,6 +107,8 @@ private:
int _repeatTimer;
uint8_t _getHeld(void) const;
public:
ButtonMap buttonMap;
@ -127,6 +129,7 @@ public:
}
ButtonState(void);
void reset(void);
void update(void);
};

2
src/vendor/miniz.h vendored
View File

@ -987,7 +987,7 @@ enum
{
/* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */
MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 128,
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512
};

View File

@ -786,8 +786,9 @@ bool qrcodegen_getModule(const uint32_t qrcode[], int x, int y) {
// Returns the color of the module at the given coordinates, which must be in bounds.
testable bool getModuleBounded(const uint32_t qrcode[], int x, int y) {
int qrsize = qrcode[0] & 0xFFFF, stride = qrcode[0] >> 16;
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
//int qrsize = qrcode[0] & 0xFFFF;
int stride = qrcode[0] >> 16;
//assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
x += qrcodegen_MARGIN_X;
y += qrcodegen_MARGIN_Y;
int bitIndex = (x % 8) * 4;
@ -798,8 +799,9 @@ testable bool getModuleBounded(const uint32_t qrcode[], int x, int y) {
// Sets the color of the module at the given coordinates, which must be in bounds.
testable void setModuleBounded(uint32_t qrcode[], int x, int y, bool isDark) {
int qrsize = qrcode[0] & 0xFFFF, stride = qrcode[0] >> 16;
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
//int qrsize = qrcode[0] & 0xFFFF;
int stride = qrcode[0] >> 16;
//assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
x += qrcodegen_MARGIN_X;
y += qrcodegen_MARGIN_Y;
int bitIndex = (x % 8) * 4;

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__version__ = "0.3.4"
__version__ = "0.3.5"
__author__ = "spicyjpeg"
import sys
@ -77,16 +77,19 @@ def parseDumpString(data: str) -> Dump:
def printDumpInfo(dump: Dump, output: TextIO):
if dump.flags & DumpFlag.DUMP_SYSTEM_ID_OK:
output.write(f"Digital I/O ID: {dump.systemID.hex('-')}\n")
output.write(f"Digital I/O SN: {serialNumberToString(dump.systemID)}\n\n")
output.write("Digital I/O board:\n")
output.write(f" DS2401 ID: {dump.systemID.hex('-')}\n")
output.write(f" Serial number: {serialNumberToString(dump.systemID)}\n\n")
output.write("Security cartridge:\n")
output.write(f" Chip type: {_CHIP_NAMES[dump.chipType]}\n")
output.write(f"Cartridge type: {_CHIP_NAMES[dump.chipType]}\n")
if dump.flags & DumpFlag.DUMP_CART_ID_OK:
output.write(f"DS2401 identifier: {dump.cartID.hex('-')}\n")
output.write(f" DS2401 ID: {dump.cartID.hex('-')}\n")
if dump.flags & DumpFlag.DUMP_ZS_ID_OK:
output.write(f"ZS01 identifier: {dump.zsID.hex('-')}\n")
output.write(f" ZS01 ID: {dump.zsID.hex('-')}\n")
if dump.flags & DumpFlag.DUMP_CONFIG_OK:
output.write(f"Configuration: {dump.config.hex('-')}\n")
output.write(f" Configuration: {dump.config.hex('-')}\n")
output.write("\nEEPROM dump:\n")
hexdump(dump.data, output)