Bump to 0.4.2, parallelize flash writing, minor tweaks

This commit is contained in:
spicyjpeg 2024-04-23 00:04:15 +02:00
parent d85582d9b5
commit 1e79613029
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
14 changed files with 237 additions and 165 deletions

View File

@ -6,7 +6,7 @@ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain.cmake")
project(
cart_tool_private
LANGUAGES C CXX ASM
VERSION 0.4.1
VERSION 0.4.2
DESCRIPTION "Konami System 573 security cartridge tool"
)

View File

@ -354,7 +354,7 @@ size_t Provider::saveVRAMBMP(gpu::RectWH &rect, const char *path) {
size_t length = _file->write(&header, sizeof(header));
util::Data buffer;
if (buffer.allocate(rect.w * 2 + 32)) {
if (buffer.allocate<uint16_t>(rect.w + 32)) {
// Read the image from VRAM one line at a time from the bottom up, as
// the BMP format stores lines in reversed order.
gpu::RectWH slice;

View File

@ -18,7 +18,7 @@ void init(void) {
| SYS573_MISC_OUT_ADC_MOSI
| SYS573_MISC_OUT_ADC_CS
| SYS573_MISC_OUT_ADC_SCK
| SYS573_MISC_OUT_JVS_STAT;
| SYS573_MISC_OUT_JVS_RESET;
BIU_DEV0_ADDR = DEV0_BASE & 0x1fffffff;
BIU_DEV0_CTRL = 0
@ -204,13 +204,15 @@ bool loadRawBitstream(const uint8_t *data, size_t length) {
for (int i = 3; i; i--) {
SYS573D_CPLD_UNK_RESET = 0;
SYS573D_CPLD_CTRL = SYS573D_CPLD_CTRL_UNK4;
SYS573D_CPLD_CTRL = SYS573D_CPLD_CTRL_UNK3 | SYS573D_CPLD_CTRL_UNK4;
SYS573D_CPLD_CTRL = SYS573D_CPLD_CTRL_UNKNOWN;
SYS573D_CPLD_CTRL = 0
| SYS573D_CPLD_CTRL_UNK1
| SYS573D_CPLD_CTRL_UNK2
| SYS573D_CPLD_CTRL_UNK3
| SYS573D_CPLD_CTRL_UNK4;
| SYS573D_CPLD_CTRL_PROGRAM
| SYS573D_CPLD_CTRL_UNKNOWN;
SYS573D_CPLD_CTRL = 0
| SYS573D_CPLD_CTRL_INIT
| SYS573D_CPLD_CTRL_DONE
| SYS573D_CPLD_CTRL_PROGRAM
| SYS573D_CPLD_CTRL_UNKNOWN;
delayMicroseconds(5000);
if (!(SYS573D_CPLD_STAT & SYS573D_CPLD_STAT_INIT))

View File

@ -141,11 +141,10 @@ static inline void setMiscOutput(MiscOutputPin pin, bool value) {
/* Digital I/O board driver */
// TODO: these do not seem to actually be LDC and HDC...
static inline bool isDigitalIOPresent(void) {
return (
(SYS573D_CPLD_STAT & (SYS573D_CPLD_STAT_LDC | SYS573D_CPLD_STAT_HDC))
== SYS573D_CPLD_STAT_HDC
(SYS573D_CPLD_STAT & (SYS573D_CPLD_STAT_ID1 | SYS573D_CPLD_STAT_ID2)) ==
SYS573D_CPLD_STAT_ID1
);
}

View File

@ -33,6 +33,26 @@ Hash hash(const uint8_t *data, size_t length) {
/* Date and time class */
bool Date::isValid(void) const {
if ((hour > 23) || (minute > 59) || (second > 59))
return false;
if ((month < 1) || (month > 12))
return false;
if ((day < 1) || (day > getMonthDayCount()))
return false;
return true;
}
bool Date::isLeapYear(void) const {
if (year % 4)
return false;
if (!(year % 100) && (year % 400))
return false;
return true;
}
int Date::getDayOfWeek(void) const {
// See https://datatracker.ietf.org/doc/html/rfc3339#appendix-B
int _year = year, _month = month - 2;

View File

@ -103,6 +103,9 @@ public:
template<typename T> inline const T *as(void) const {
return reinterpret_cast<const T *>(ptr);
}
template<typename T> inline T *allocate(size_t count = 1) {
return reinterpret_cast<T *>(allocate(sizeof(T) * count));
}
inline void *allocate(size_t _length) {
if (ptr)
@ -170,15 +173,8 @@ public:
uint8_t month, day;
uint8_t hour, minute, second;
inline bool isLeapYear(void) const {
if (year % 4)
return false;
if (!(year % 100) && (year % 400))
return false;
return true;
}
bool isValid(void) const;
bool isLeapYear(void) const;
int getDayOfWeek(void) const;
int getMonthDayCount(void) const;
uint32_t toDOSTime(void) const;

View File

@ -1,4 +1,6 @@
#include <stddef.h>
#include <stdio.h>
#include "common/defs.hpp"
#include "common/file.hpp"
#include "common/gpu.hpp"
@ -154,27 +156,47 @@ void App::_loadResources(void) {
_resourceProvider.loadVAG(_ctx.sounds[i], _UI_SOUND_PATHS[i]);
}
bool App::_takeScreenshot(void) {
bool App::_createDataDirectory(void) {
file::FileInfo info;
if (!_fileProvider.getFileInfo(info, EXTERNAL_DATA_DIR))
return _fileProvider.createDirectory(EXTERNAL_DATA_DIR);
if (info.attributes & file::DIRECTORY)
return true;
return false;
}
bool App::_getNumberedPath(char *output, size_t length, const char *path) {
file::FileInfo info;
char path[32];
int index = 0;
do {
index++;
snprintf(path, sizeof(path), EXTERNAL_DATA_DIR "/shot%04d.bmp", index);
} while (_fileProvider.getFileInfo(info, path));
if (++index > 9999)
return false;
snprintf(output, length, path, index);
} while (_fileProvider.getFileInfo(info, output));
return true;
}
bool App::_takeScreenshot(void) {
char path[32];
if (!_createDataDirectory())
return false;
if (!_getNumberedPath(path, sizeof(path), EXTERNAL_DATA_DIR "/shot%04d.bmp"))
return false;
gpu::RectWH clip;
_ctx.gpuCtx.getVRAMClipRect(clip);
if (_fileProvider.saveVRAMBMP(clip, path)) {
LOG("%s saved", path);
return true;
} else {
LOG("%s saving failed", path);
if (!_fileProvider.saveVRAMBMP(clip, path))
return false;
}
LOG("%s saved", path);
return true;
}
void App::_worker(void) {

View File

@ -1,6 +1,7 @@
#pragma once
#include <stddef.h>
#include "common/file.hpp"
#include "main/app/cartactions.hpp"
#include "main/app/cartunlock.hpp"
@ -131,6 +132,8 @@ private:
void _setupWorker(bool (App::*func)(void));
void _setupInterrupts(void);
void _loadResources(void);
bool _createDataDirectory(void);
bool _getNumberedPath(char *output, size_t length, const char *path);
bool _takeScreenshot(void);
// cartworkers.cpp

View File

@ -202,20 +202,11 @@ bool App::_qrCodeWorker(void) {
bool App::_cartDumpWorker(void) {
_workerStatus.update(0, 1, WSTR("App.cartDumpWorker.save"));
file::FileInfo info;
char path[32];
char path[32], code[8], region[8];
size_t length = _cartDump.getDumpLength();
__builtin_strcpy(path, EXTERNAL_DATA_DIR);
if (!_fileProvider.getFileInfo(info, path)) {
if (!_fileProvider.createDirectory(path))
goto _error;
}
char code[8], region[8];
size_t length;
length = _cartDump.getDumpLength();
if (!_createDataDirectory())
goto _error;
if (
_identified && _cartParser->getCode(code) &&
@ -225,14 +216,10 @@ bool App::_cartDumpWorker(void) {
path, sizeof(path), EXTERNAL_DATA_DIR "/%s%s.573", code, region
);
} else {
int index = 0;
do {
index++;
snprintf(
path, sizeof(path), EXTERNAL_DATA_DIR "/cart%04d.573", index
);
} while (_fileProvider.getFileInfo(info, path));
if (!_getNumberedPath(
path, sizeof(path), EXTERNAL_DATA_DIR "/cart%04d.573"
))
goto _error;
}
LOG("saving %s, length=%d", path, length);

View File

@ -34,7 +34,10 @@ void WarningScreen::update(ui::Context &ctx) {
if (_locked) {
time = (time / ctx.gpuCtx.refreshRate) + 1;
sprintf(_buttonText, STR("WarningScreen.cooldown"), time);
snprintf(
_buttonText, sizeof(_buttonText), STR("WarningScreen.cooldown"),
time
);
return;
}

View File

@ -217,13 +217,12 @@ int FilePickerScreen::loadDirectory(ui::Context &ctx, const char *path) {
LOG("path: %s", path);
LOG("files=%d, dirs=%d", _numFiles, _numDirectories);
if (_numFiles)
_files.allocate(sizeof(file::FileInfo) * _numFiles);
if (_numDirectories)
_directories.allocate(sizeof(file::FileInfo) * _numDirectories);
file::FileInfo *files, *directories;
auto files = _files.as<file::FileInfo>();
auto directories = _directories.as<file::FileInfo>();
if (_numFiles)
files = _files.allocate<file::FileInfo>(_numFiles);
if (_numDirectories)
directories = _directories.allocate<file::FileInfo>(_numDirectories);
// Iterate over all entries again to populate the newly allocated arrays.
directory = APP->_fileProvider.openDirectory(path);

View File

@ -326,10 +326,10 @@ void StorageActionsScreen::update(ui::Context &ctx) {
void CardSizeScreen::show(ui::Context &ctx, bool goBack) {
_title = STR("CardSizeScreen.title");
_body = STR("CardSizeScreen.body");
_buttons[0] = STR("CardSizeScreen.16");
_buttons[1] = STR("CardSizeScreen.32");
_buttons[2] = STR("CardSizeScreen.64");
_buttons[3] = STR("CardSizeScreen.cancel");
_buttons[0] = STR("CardSizeScreen.cancel");
_buttons[1] = STR("CardSizeScreen.16");
_buttons[2] = STR("CardSizeScreen.32");
_buttons[3] = STR("CardSizeScreen.64");
_numButtons = 4;
@ -340,11 +340,11 @@ void CardSizeScreen::update(ui::Context &ctx) {
MessageBoxScreen::update(ctx);
if (ctx.buttons.pressed(ui::BTN_START)) {
if (_activeButton == 3) {
ctx.show(APP->_storageActionsScreen, true, true);
} else {
selectedLength = 0x1000000 << _activeButton;
if (_activeButton) {
selectedLength = 0x800000 << _activeButton;
(APP->_storageActionsScreen.*callback)(ctx);
} else {
ctx.show(APP->_storageActionsScreen, true, true);
}
}
}

View File

@ -98,33 +98,21 @@ bool App::_romChecksumWorker(void) {
bool App::_romDumpWorker(void) {
_workerStatus.update(0, 1, WSTR("App.romDumpWorker.init"));
// Store all dumps in a subdirectory named "dumpN" within the main data
// Store all dumps in a subdirectory named "dumpNNNN" within the main data
// folder.
file::FileInfo info;
char dirPath[32];
__builtin_strcpy(dirPath, EXTERNAL_DATA_DIR);
if (!_fileProvider.getFileInfo(info, dirPath)) {
if (!_fileProvider.createDirectory(dirPath))
goto _initError;
}
int index;
char filePath[32];
index = 0;
do {
index++;
snprintf(dirPath, sizeof(dirPath), EXTERNAL_DATA_DIR "/dump%04d", index);
} while (_fileProvider.getFileInfo(info, dirPath));
LOG("saving dumps to %s", dirPath);
char dirPath[32], filePath[32];
if (!_createDataDirectory())
goto _initError;
if (!_getNumberedPath(
dirPath, sizeof(dirPath), EXTERNAL_DATA_DIR "/dump%04d"
))
goto _initError;
if (!_fileProvider.createDirectory(dirPath))
goto _initError;
LOG("saving dumps to %s", dirPath);
for (auto &entry : _REGION_INFO) {
if (!entry.region.isPresent())
continue;
@ -142,19 +130,19 @@ bool App::_romDumpWorker(void) {
if (!_file)
goto _fileError;
auto buffer = new uint8_t[chunkLength];
uint32_t offset = 0;
util::Data buffer;
uint32_t offset = 0;
//assert(buffer);
buffer.allocate(chunkLength);
for (size_t i = 0; i < numChunks; i++) {
_workerStatus.update(i, numChunks, WSTRH(entry.dumpPrompt));
entry.region.read(buffer, offset, chunkLength);
entry.region.read(buffer.ptr, offset, chunkLength);
if (_file->write(buffer, chunkLength) < chunkLength) {
if (_file->write(buffer.ptr, chunkLength) < chunkLength) {
buffer.destroy();
_file->close();
delete _file;
delete[] buffer;
delete _file;
goto _fileError;
}
@ -162,9 +150,9 @@ bool App::_romDumpWorker(void) {
offset += chunkLength;
}
buffer.destroy();
_file->close();
delete _file;
delete[] buffer;
delete _file;
LOG("%s saved", filePath);
}
@ -202,67 +190,117 @@ bool App::_romRestoreWorker(void) {
auto region = _storageActionsScreen.selectedRegion;
auto regionLength = _cardSizeScreen.selectedLength;
size_t bytesWritten = 0;
util::Data buffers, chunkLengths;
if (!_file)
goto _fileError;
if (!_romEraseWorker())
return false;
size_t fileLength, dataLength;
fileLength = size_t(_file->length);
dataLength = util::min(fileLength, regionLength);
rom::Driver *driver;
size_t sectorLength, numSectors;
size_t chipLength, numChips, maxChunkLength;
driver = region->newDriver();
sectorLength = driver->getChipSize().eraseSectorLength;
numSectors = (dataLength + sectorLength - 1) / sectorLength;
driver = region->newDriver();
chipLength = driver->getChipSize().chipLength;
numChips = (regionLength + chipLength - 1) / chipLength;
maxChunkLength = util::min(regionLength, _DUMP_CHUNK_LENGTH / numChips);
LOG("%d chips, buf=%d", numChips, maxChunkLength);
rom::DriverError error;
uint8_t *buffer;
uint32_t offset;
buffer = new uint8_t[sectorLength];
offset = 0;
buffers.allocate(maxChunkLength * numChips);
chunkLengths.allocate<size_t>(numChips);
//assert(buffer);
// Parallelize writing by buffering a chunk for each chip into RAM, then
// writing all chunks to the respective chips at the same time.
for (size_t i = 0; i < chipLength; i += maxChunkLength) {
_workerStatus.update(i, chipLength, WSTR("App.romRestoreWorker.write"));
for (size_t i = 0; i < numSectors; i++) {
_workerStatus.update(i, numSectors, WSTR("App.romRestoreWorker.write"));
auto bufferPtr = buffers.as<uint8_t>();
auto lengthPtr = chunkLengths.as<size_t>();
size_t offset = i;
size_t totalLength = 0;
auto length = _file->read(buffer, sectorLength);
auto ptr = reinterpret_cast<const uint16_t *>(buffer);
for (
size_t j = numChips; j > 0; j--, bufferPtr += maxChunkLength,
offset += chipLength
) {
_file->seek(offset);
auto length = _file->read(bufferPtr, maxChunkLength);
// Data is written 16 bits at a time, so the buffer must be padded to an
// even number of bytes.
if (length % 2)
buffer[length++] = 0xff;
// Data is written 16 bits at a time, so the chunk must be padded to
// an even number of bytes.
if (length % 2)
bufferPtr[length++] = 0xff;
for (uint32_t end = offset + length; offset < end; offset += 2) {
auto value = *(ptr++);
*(lengthPtr++) = length;
totalLength += length;
}
driver->write(offset, value);
error = driver->flushWrite(offset, value);
// Stop once there is no more data to write.
if (!totalLength)
break;
if (error)
goto _flashError;
bufferPtr = buffers.as<uint8_t>();
offset = i;
for (
size_t j = 0; j < maxChunkLength; j += 2, bufferPtr += 2,
offset += 2
) {
auto chunkOffset = offset;
auto chunkPtr = bufferPtr;
lengthPtr = chunkLengths.as<size_t>();
for (
size_t k = numChips; k > 0;
k--, chunkPtr += maxChunkLength, chunkOffset += chipLength
) {
if (j >= *(lengthPtr++))
continue;
auto value = *reinterpret_cast<const uint16_t *>(chunkPtr);
driver->write(chunkOffset, value);
}
chunkOffset = offset;
chunkPtr = bufferPtr;
lengthPtr = chunkLengths.as<size_t>();
for (
size_t k = numChips; k > 0; k--, chunkPtr += maxChunkLength,
chunkOffset += chipLength, bytesWritten += 2
) {
if (j >= *(lengthPtr++))
continue;
auto value = *reinterpret_cast<const uint16_t *>(chunkPtr);
error = driver->flushWrite(chunkOffset, value);
if (error)
goto _flashError;
}
}
}
_file->close();
delete _file;
delete[] buffer;
delete driver;
util::Hash message;
message = (fileLength > dataLength)
message = (_file->length > regionLength)
? "App.romRestoreWorker.overflow"_h
: "App.romRestoreWorker.success"_h;
buffers.destroy();
chunkLengths.destroy();
_file->close();
delete _file;
delete driver;
_messageScreen.setMessage(
MESSAGE_SUCCESS, _storageInfoScreen, WSTRH(message), offset
MESSAGE_SUCCESS, _storageInfoScreen, WSTRH(message), bytesWritten
);
_workerStatus.setNextScreen(_messageScreen);
return true;
@ -276,15 +314,16 @@ _fileError:
return false;
_flashError:
buffers.destroy();
chunkLengths.destroy();
_file->close();
delete _file;
delete[] buffer;
delete driver;
delete _file;
delete driver;
_messageScreen.setMessage(
MESSAGE_ERROR, _storageInfoScreen,
WSTR("App.romRestoreWorker.flashError"), rom::getErrorString(error),
offset
bytesWritten
);
_workerStatus.setNextScreen(_messageScreen);
return false;
@ -293,10 +332,12 @@ _flashError:
bool App::_romEraseWorker(void) {
auto region = _storageActionsScreen.selectedRegion;
auto regionLength = _cardSizeScreen.selectedLength;
auto driver = region->newDriver();
size_t chipLength = driver->getChipSize().chipLength;
size_t sectorLength = driver->getChipSize().eraseSectorLength;
auto driver = region->newDriver();
size_t chipLength = driver->getChipSize().chipLength;
size_t sectorLength = driver->getChipSize().eraseSectorLength;
//size_t numChips = (regionLength + chipLength - 1) / chipLength;
size_t sectorsErased = 0;
if (!chipLength)
@ -306,7 +347,8 @@ bool App::_romEraseWorker(void) {
_checksumScreen.valid = false;
// Erase one sector at a time on each chip.
// Parallelize erasing by sending the same sector erase command to all chips
// at the same time.
for (size_t i = 0; i < chipLength; i += sectorLength) {
_workerStatus.update(i, chipLength, WSTR("App.romEraseWorker.erase"));
@ -356,6 +398,8 @@ bool App::_flashHeaderWriteWorker(void) {
auto driver = rom::flash.newDriver();
size_t sectorLength = driver->getChipSize().eraseSectorLength;
util::Data buffer;
// This should never happen since the flash chips are soldered to the 573,
// but whatever.
if (!sectorLength)
@ -367,14 +411,10 @@ bool App::_flashHeaderWriteWorker(void) {
// The flash can only be erased with sector granularity, so all data in the
// first sector other than the header must be backed up and rewritten.
rom::DriverError error;
uint8_t *buffer;
const uint16_t *ptr;
buffer = new uint8_t[sectorLength];
//assert(buffer);
rom::flash.read(buffer, 0, sectorLength);
buffer.allocate(sectorLength);
rom::flash.read(buffer.ptr, 0, sectorLength);
driver->eraseSector(0);
error = driver->flushErase(0);
@ -403,7 +443,7 @@ bool App::_flashHeaderWriteWorker(void) {
}
// Restore the rest of the sector that was erased.
ptr = reinterpret_cast<const uint16_t *>(&buffer[rom::FLASH_CRC_OFFSET]);
ptr = &buffer.as<const uint16_t>()[rom::FLASH_CRC_OFFSET / 2];
for (
uint32_t offset = rom::FLASH_CRC_OFFSET; offset < sectorLength;
@ -418,15 +458,15 @@ bool App::_flashHeaderWriteWorker(void) {
goto _flashError;
}
delete[] buffer;
delete driver;
buffer.destroy();
delete driver;
_workerStatus.setNextScreen(_storageInfoScreen);
return true;
_flashError:
delete[] buffer;
delete driver;
buffer.destroy();
delete driver;
_messageScreen.setMessage(
MESSAGE_ERROR, _storageInfoScreen,

View File

@ -29,7 +29,7 @@ typedef enum {
SYS573_MISC_OUT_AMP_ENABLE = 1 << 5,
SYS573_MISC_OUT_CDDA_ENABLE = 1 << 6,
SYS573_MISC_OUT_SPU_ENABLE = 1 << 7,
SYS573_MISC_OUT_JVS_STAT = 1 << 8
SYS573_MISC_OUT_JVS_RESET = 1 << 8
} Sys573MiscOutputFlag;
typedef enum {
@ -37,10 +37,10 @@ typedef enum {
SYS573_MISC_IN_ADC_SARS = 1 << 1,
SYS573_MISC_IN_CART_SDA = 1 << 2,
SYS573_MISC_IN_JVS_SENSE = 1 << 3,
SYS573_MISC_IN_JVS_AVAIL = 1 << 4,
SYS573_MISC_IN_JVS_UNK = 1 << 5,
SYS573_MISC_IN_CART_ISIG = 1 << 6,
SYS573_MISC_IN_CART_DSIG = 1 << 7,
SYS573_MISC_IN_JVS_IRDY = 1 << 4,
SYS573_MISC_IN_JVS_DRDY = 1 << 5,
SYS573_MISC_IN_CART_IRDY = 1 << 6,
SYS573_MISC_IN_CART_DRDY = 1 << 7,
SYS573_MISC_IN_COIN1 = 1 << 8,
SYS573_MISC_IN_COIN2 = 1 << 9,
SYS573_MISC_IN_PCMCIA_CD1 = 1 << 10,
@ -126,17 +126,18 @@ typedef enum {
typedef enum {
SYS573D_CPLD_STAT_INIT = 1 << 12,
SYS573D_CPLD_STAT_DONE = 1 << 13,
SYS573D_CPLD_STAT_LDC = 1 << 14,
SYS573D_CPLD_STAT_HDC = 1 << 15
SYS573D_CPLD_STAT_ID1 = 1 << 14,
SYS573D_CPLD_STAT_ID2 = 1 << 15
} Sys573DCPLDStatusFlag;
typedef enum {
SYS573D_CPLD_CTRL_UNK1 = 1 << 12,
SYS573D_CPLD_CTRL_UNK2 = 1 << 13,
SYS573D_CPLD_CTRL_UNK3 = 1 << 14,
SYS573D_CPLD_CTRL_UNK4 = 1 << 15
SYS573D_CPLD_CTRL_INIT = 1 << 12,
SYS573D_CPLD_CTRL_DONE = 1 << 13,
SYS573D_CPLD_CTRL_PROGRAM = 1 << 14,
SYS573D_CPLD_CTRL_UNKNOWN = 1 << 15
} Sys573DCPLDControlFlag;
#define SYS573D_FPGA_MAGIC _MMIO16(DEV0_BASE | 0x640080)
#define SYS573D_FPGA_LIGHTS_A1 _MMIO16(DEV0_BASE | 0x6400e0)
#define SYS573D_FPGA_LIGHTS_A0 _MMIO16(DEV0_BASE | 0x6400e2)
#define SYS573D_FPGA_LIGHTS_B1 _MMIO16(DEV0_BASE | 0x6400e4)