Update ldscript, split off util.cpp into multiple files

This commit is contained in:
spicyjpeg 2024-07-29 14:15:27 +02:00
parent 661cba0e1a
commit 3f06ea5c50
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
63 changed files with 1556 additions and 1274 deletions

View File

@ -87,7 +87,7 @@ target_compile_definitions(
) )
link_libraries(common) link_libraries(common)
function(addExecutable name address stackTop) function(addPS1Executable name address stackTop)
add_executable(${name} ${ARGN}) add_executable(${name} ${ARGN})
target_link_options(${name} PRIVATE -Ttext=0x${address}) target_link_options(${name} PRIVATE -Ttext=0x${address})
@ -110,13 +110,18 @@ endfunction()
# IMPORTANT: these addresses assume the boot executable's size (including code, # IMPORTANT: these addresses assume the boot executable's size (including code,
# heap and stack allocations as well as the resource archive) is <576 KB # heap and stack allocations as well as the resource archive) is <576 KB
# (0x90000 bytes). # (0x90000 bytes).
addExecutable( addPS1Executable(
main 800a0000 801dfff0 main 800a0000 801dfff0
src/common/file/fat.cpp src/common/file/fat.cpp
src/common/file/file.cpp src/common/file/file.cpp
src/common/file/iso9660.cpp src/common/file/iso9660.cpp
src/common/file/misc.cpp src/common/file/misc.cpp
src/common/file/zip.cpp src/common/file/zip.cpp
src/common/util/hash.cpp
src/common/util/log.cpp
src/common/util/misc.cpp
src/common/util/string.cpp
src/common/util/tween.cpp
src/common/args.cpp src/common/args.cpp
src/common/gpu.cpp src/common/gpu.cpp
src/common/gpufont.cpp src/common/gpufont.cpp
@ -126,7 +131,6 @@ addExecutable(
src/common/rom.cpp src/common/rom.cpp
src/common/romdrivers.cpp src/common/romdrivers.cpp
src/common/spu.cpp src/common/spu.cpp
src/common/util.cpp
src/libc/crt0.c src/libc/crt0.c
src/main/app/app.cpp src/main/app/app.cpp
src/main/app/cartactions.cpp src/main/app/cartactions.cpp
@ -188,16 +192,18 @@ target_compile_definitions(
$<$<CONFIG:Debug>: $<$<CONFIG:Debug>:
#ENABLE_ARGV=1 #ENABLE_ARGV=1
#ENABLE_LOGGING=1 #ENABLE_LOGGING=1
NDEBUG=1
> >
) )
function(addLauncher address stackTop) function(addLauncher address stackTop)
addExecutable( addPS1Executable(
launcher${address} ${address} ${stackTop} launcher${address} ${address} ${stackTop}
src/common/util/hash.cpp
src/common/util/misc.cpp
src/common/args.cpp src/common/args.cpp
src/common/ide.cpp src/common/ide.cpp
src/common/io.cpp src/common/io.cpp
src/common/util.cpp
src/launcher/main.cpp src/launcher/main.cpp
src/libc/crt0.c src/libc/crt0.c
src/vendor/printf.c src/vendor/printf.c
@ -236,12 +242,13 @@ function(addBootStub name resourceName)
VERBATIM VERBATIM
) )
addExecutable( addPS1Executable(
${name} 80010000 0 ${name} 80010000 0
src/boot/crt0.s src/boot/crt0.s
src/boot/main.cpp src/boot/main.cpp
src/common/util/misc.cpp
src/common/util/string.cpp
src/common/io.cpp src/common/io.cpp
src/common/util.cpp
) )
addBinaryFile( addBinaryFile(
${name} _resourceArchive _resourceArchiveLength ${name} _resourceArchive _resourceArchiveLength

View File

@ -17,8 +17,7 @@
ENTRY(_start) ENTRY(_start)
MEMORY { MEMORY {
KERNEL_RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x010000 APP_RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x3f0000
APP_RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x7f0000
} }
SECTIONS { SECTIONS {
@ -108,7 +107,7 @@ SECTIONS {
} > APP_RAM } > APP_RAM
/DISCARD/ : { /DISCARD/ : {
*(.note.GNU-stack .gnu_debuglink .gnu.lto_*) *(.note.* .gnu_debuglink .gnu.lto_*)
*(.MIPS.abiflags) *(.MIPS.abiflags)
} }
} }

View File

@ -16,8 +16,10 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/misc.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "ps1/system.h" #include "ps1/system.h"
extern "C" const uint8_t _resourceArchive[]; extern "C" const uint8_t _resourceArchive[];

View File

@ -16,8 +16,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "common/args.hpp" #include "common/args.hpp"
#include "common/util.hpp"
namespace args { namespace args {

View File

@ -18,7 +18,7 @@
#include <stddef.h> #include <stddef.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util.hpp" #include "common/util/misc.hpp"
namespace args { namespace args {

View File

@ -18,9 +18,10 @@
#include <stdint.h> #include <stdint.h>
#include "common/file/fat.hpp" #include "common/file/fat.hpp"
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "ps1/system.h" #include "ps1/system.h"
#include "vendor/diskio.h" #include "vendor/diskio.h"
#include "vendor/ff.h" #include "vendor/ff.h"

View File

@ -19,8 +19,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/util.hpp"
namespace file { namespace file {

View File

@ -18,9 +18,10 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
namespace file { namespace file {

View File

@ -18,8 +18,10 @@
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/file/iso9660.hpp" #include "common/file/iso9660.hpp"
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/util.hpp"
namespace file { namespace file {

View File

@ -19,8 +19,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/util.hpp"
namespace file { namespace file {

View File

@ -18,7 +18,9 @@
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/file/misc.hpp" #include "common/file/misc.hpp"
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "ps1/pcdrv.h" #include "ps1/pcdrv.h"
namespace file { namespace file {

View File

@ -19,7 +19,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "ps1/pcdrv.h" #include "ps1/pcdrv.h"
namespace file { namespace file {

View File

@ -18,7 +18,8 @@
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/file/zip.hpp" #include "common/file/zip.hpp"
#include "common/util.hpp" #include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "vendor/miniz.h" #include "vendor/miniz.h"
namespace file { namespace file {

View File

@ -17,8 +17,9 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/util.hpp"
#include "ps1/gpucmd.h" #include "ps1/gpucmd.h"
#include "ps1/registers.h" #include "ps1/registers.h"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -16,10 +16,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/idedefs.hpp" #include "common/idedefs.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "ps1/registers573.h" #include "ps1/registers573.h"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -18,8 +18,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/templates.hpp"
#include "common/idedefs.hpp" #include "common/idedefs.hpp"
#include "common/util.hpp"
#include "ps1/registers573.h" #include "ps1/registers573.h"
namespace ide { namespace ide {

View File

@ -16,8 +16,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/misc.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "ps1/registers.h" #include "ps1/registers.h"
#include "ps1/registers573.h" #include "ps1/registers573.h"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -19,7 +19,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/util.hpp" #include "common/util/misc.hpp"
#include "ps1/registers.h" #include "ps1/registers.h"
#include "ps1/registers573.h" #include "ps1/registers573.h"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -16,10 +16,12 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/romdrivers.hpp" #include "common/romdrivers.hpp"
#include "common/util.hpp"
#include "ps1/registers.h" #include "ps1/registers.h"
#include "ps1/registers573.h" #include "ps1/registers573.h"

View File

@ -18,7 +18,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/misc.hpp"
#include "common/util/string.hpp"
#include "ps1/registers.h" #include "ps1/registers.h"
namespace rom { namespace rom {

View File

@ -16,6 +16,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/romdrivers.hpp" #include "common/romdrivers.hpp"

View File

@ -16,8 +16,9 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "ps1/registers.h" #include "ps1/registers.h"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -1,701 +0,0 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "common/util.hpp"
#include "ps1/registers.h"
#include "ps1/system.h"
namespace util {
/* String hashing */
Hash hash(const char *str, char terminator) {
auto _str = reinterpret_cast<const uint8_t *>(str);
Hash value = 0;
while (*_str && (*_str != terminator))
value = Hash(*(_str++)) + (value << 6) + (value << 16) - value;
return value;
}
Hash hash(const uint8_t *data, size_t length) {
Hash value = 0;
for (; length; length--)
value = Hash(*(data++)) + (value << 6) + (value << 16) - value;
return value;
}
/* 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;
if (_month <= 0) {
_month += 12;
_year--;
}
int century = _year / 100;
_year %= 100;
int weekday = 0
+ day
+ (_month * 26 - 2) / 10
+ _year
+ _year / 4
+ century / 4
+ century * 5;
return weekday % 7;
}
int Date::getMonthDayCount(void) const {
switch (month) {
case 2:
return isLeapYear() ? 29 : 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
uint32_t Date::toDOSTime(void) const {
int _year = year - 1980;
if (!isValid())
return 0;
if ((_year < 0) || (_year > 127))
return 0;
return 0
| (_year << 25)
| (month << 21)
| (day << 16)
| (hour << 11)
| (minute << 5)
| (second >> 1);
}
size_t Date::toString(char *output) const {
if (!isValid()) {
*output = 0;
return 0;
}
return sprintf(
output, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute,
second
);
}
/* Tween/animation classes */
template<typename T, typename E> void Tween<T, E>::setValue(
int time, T start, T target, int duration
) {
//assert(duration <= 0x800);
_base = start;
_delta = target - start;
_endTime = time + duration;
_timeScale = TWEEN_UNIT / duration;
}
template<typename T, typename E> void Tween<T, E>::setValue(T target) {
_base = target;
_delta = static_cast<T>(0);
_endTime = 0;
}
template<typename T, typename E> T Tween<T, E>::getValue(int time) const {
int remaining = time - _endTime;
if (remaining >= 0)
return _base + _delta;
return _base + (
_delta * E::apply(remaining * _timeScale + TWEEN_UNIT)
) / TWEEN_UNIT;
}
template class Tween<int, LinearEasing>;
template class Tween<int, QuadInEasing>;
template class Tween<int, QuadOutEasing>;
template class Tween<uint16_t, LinearEasing>;
template class Tween<uint16_t, QuadInEasing>;
template class Tween<uint16_t, QuadOutEasing>;
template class Tween<uint32_t, LinearEasing>;
template class Tween<uint32_t, QuadInEasing>;
template class Tween<uint32_t, QuadOutEasing>;
/* Logging framework */
// Global state, I know, but it's a necessary evil.
Logger logger;
void LogBuffer::clear(void) {
for (auto line : _lines)
line[0] = 0;
}
char *LogBuffer::allocateLine(void) {
size_t tail = _tail;
_tail = (tail + 1) % MAX_LOG_LINES;
return _lines[tail];
}
void Logger::setLogBuffer(LogBuffer *buffer) {
util::CriticalSection sec;
_buffer = buffer;
}
void Logger::setupSyslog(int baudRate) {
util::CriticalSection sec;
if (baudRate) {
initSerialIO(baudRate);
_enableSyslog = true;
} else {
_enableSyslog = false;
}
}
void Logger::log(const char *format, ...) {
util::CriticalSection sec;
va_list ap;
if (_buffer) {
auto line = _buffer->allocateLine();
va_start(ap, format);
vsnprintf(line, MAX_LOG_LINE_LENGTH, format, ap);
va_end(ap);
if (_enableSyslog)
puts(line);
} else if (_enableSyslog) {
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
putchar('\n');
}
}
/* MD5 hash */
static const uint32_t _MD5_SEED[]{
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
};
static const uint32_t _MD5_ADD[][16]{
{
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
}, {
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
}, {
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
}, {
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
}
};
static const uint8_t _MD5_SHIFT[][4]{
{ 7, 12, 17, 22 },
{ 5, 9, 14, 20 },
{ 4, 11, 16, 23 },
{ 6, 10, 15, 21 }
};
MD5::MD5(void)
: _blockCount(0), _bufferLength(0) {
__builtin_memcpy(_state, _MD5_SEED, sizeof(_state));
}
void MD5::_flushBlock(const void *data) {
auto input = reinterpret_cast<const uint32_t *>(data);
assertAligned<uint32_t>(data);
auto a = _state[0], b = _state[1], c = _state[2], d = _state[3];
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addF(b, c, d) + input[_indexF(i)] + _MD5_ADD[0][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[0][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addG(b, c, d) + input[_indexG(i)] + _MD5_ADD[1][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[1][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addH(b, c, d) + input[_indexH(i)] + _MD5_ADD[2][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[2][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addI(b, c, d) + input[_indexI(i)] + _MD5_ADD[3][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[3][i % 4]);
a = _d;
}
_state[0] += a;
_state[1] += b;
_state[2] += c;
_state[3] += d;
_blockCount++;
}
void MD5::update(const uint8_t *data, size_t length) {
if (_bufferLength > 0) {
auto ptr = &_blockBuffer[_bufferLength];
auto freeSpace = sizeof(_blockBuffer) - _bufferLength;
if (length >= freeSpace) {
__builtin_memcpy(ptr, data, freeSpace);
_flushBlock(_blockBuffer);
data += freeSpace;
length -= freeSpace;
_bufferLength = 0;
} else {
__builtin_memcpy(ptr, data, length);
_bufferLength += length;
return;
}
}
// Avoid copying data to the intermediate block buffer whenever possible.
for (;
length >= sizeof(_blockBuffer);
length -= sizeof(_blockBuffer), data += sizeof(_blockBuffer)
)
_flushBlock(data);
if (length > 0) {
__builtin_memcpy(_blockBuffer, data, length);
_bufferLength = length;
}
}
void MD5::digest(uint8_t *output) {
uint64_t length = (
uint64_t(_blockCount) * sizeof(_blockBuffer) + uint64_t(_bufferLength)
) * 8;
_blockBuffer[_bufferLength++] = 1 << 7;
while (_bufferLength != (sizeof(_blockBuffer) - 8)) {
if (_bufferLength == sizeof(_blockBuffer)) {
_flushBlock(_blockBuffer);
_bufferLength = 0;
}
_blockBuffer[_bufferLength++] = 0;
}
for (int i = 8; i > 0; i--, length >>= 8)
_blockBuffer[_bufferLength++] = uint8_t(length & 0xff);
_flushBlock(_blockBuffer);
__builtin_memcpy(output, _state, sizeof(_state));
}
/* LZ4 decompressor */
void decompressLZ4(
uint8_t *output, const uint8_t *input, size_t maxOutputLength,
size_t inputLength
) {
auto outputEnd = &output[maxOutputLength];
auto inputEnd = &input[inputLength];
while (input < inputEnd) {
uint8_t token = *(input++);
// Copy literals from the input stream.
int literalLength = token >> 4;
if (literalLength == 0xf) {
uint8_t addend;
do {
addend = *(input++);
literalLength += addend;
} while (addend == 0xff);
}
for (; literalLength && (output < outputEnd); literalLength--)
*(output++) = *(input++);
if (input >= inputEnd)
break;
int offset = input[0] | (input[1] << 8);
input += 2;
// Copy from previously decompressed data. Note that this *must* be done
// one byte at a time, as the compressor relies on out-of-bounds copies
// repeating the last byte.
int copyLength = token & 0xf;
if (copyLength == 0xf) {
uint8_t addend;
do {
addend = *(input++);
copyLength += addend;
} while (addend == 0xff);
}
auto copySource = output - offset;
copyLength += 4;
for (; copyLength && (output < outputEnd); copyLength--)
*(output++) = *(copySource++);
}
}
/* CRC calculation */
static constexpr uint8_t _CRC8_POLY = 0x8c;
static constexpr uint16_t _CRC16_POLY = 0x1021;
static constexpr uint32_t _CRC32_POLY = 0xedb88320;
uint8_t dsCRC8(const uint8_t *data, size_t length) {
uint8_t crc = 0;
for (; length; length--) {
uint8_t value = *(data++);
for (int bit = 8; bit; bit--) {
uint8_t temp = crc ^ value;
value >>= 1;
crc >>= 1;
if (temp & 1)
crc ^= _CRC8_POLY;
}
}
return crc & 0xff;
}
uint16_t zsCRC16(const uint8_t *data, size_t length) {
uint16_t crc = 0xffff;
for (; length; length--) {
crc ^= *(data++) << 8;
for (int bit = 8; bit; bit--) {
uint16_t temp = crc;
crc <<= 1;
if (temp & (1 << 15))
crc ^= _CRC16_POLY;
}
}
return (crc ^ 0xffff) & 0xffff;
}
uint32_t zipCRC32(const uint8_t *data, size_t length, uint32_t crc) {
// This CRC32 implementation uses a lookup table cached in the scratchpad
// area in order to improve performance.
auto table = reinterpret_cast<const uint32_t *>(CACHE_BASE);
crc = ~crc;
for (; length; length--)
crc = (crc >> 8) ^ table[(crc ^ *(data++)) & 0xff];
return ~crc;
}
void initZipCRC32(void) {
auto table = reinterpret_cast<uint32_t *>(CACHE_BASE);
for (int i = 0; i < 256; i++) {
uint32_t crc = i;
for (int bit = 8; bit; bit--) {
uint32_t temp = crc;
crc >>= 1;
if (temp & 1)
crc ^= _CRC32_POLY;
}
*(table++) = crc;
}
}
extern "C" uint32_t mz_crc32(uint32_t crc, const uint8_t *data, size_t length) {
return zipCRC32(data, length, crc);
}
/* String manipulation */
const char HEX_CHARSET[]{ "0123456789ABCDEF" };
const char BASE41_CHARSET[]{ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./:" };
size_t hexValueToString(char *output, uint32_t value, size_t numDigits) {
output += numDigits;
*output = 0;
for (size_t i = numDigits; i; i--, value >>= 4)
*(--output) = HEX_CHARSET[value & 0xf];
return numDigits;
}
size_t hexToString(
char *output, const uint8_t *input, size_t length, char separator
) {
size_t outLength = 0;
for (; length; length--) {
uint8_t value = *(input++);
*(output++) = HEX_CHARSET[value >> 4];
*(output++) = HEX_CHARSET[value & 0xf];
if (separator && (length > 1)) {
*(output++) = separator;
outLength += 3;
} else {
outLength += 2;
}
}
*output = 0;
return outLength;
}
size_t serialNumberToString(char *output, const uint8_t *input) {
uint32_t value =
input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24);
return sprintf(output, "%04d-%04d", (value / 10000) % 10000, value % 10000);
}
// This format is used by Konami's tools to display trace IDs in the TID_81
// format.
static const char _TRACE_ID_CHECKSUM_CHARSET[]{ "0X987654321" };
size_t traceIDToString(char *output, const uint8_t *input) {
uint16_t high = (input[0] << 8) | input[1];
uint32_t low =
(input[2] << 24) | (input[3] << 16) | (input[4] << 8) | input[5];
size_t length = sprintf(&output[1], "%02d-%04d", high % 100, low % 10000);
// The checksum is calculated in a very weird way:
// code = AB-CDEF
// checksum = (A*7 + B*6 + C*5 + D*4 + E*3 + F*2) % 11
int checksum = 0, multiplier = 7;
for (const char *ptr = &output[1]; *ptr; ptr++) {
if (*ptr != '-')
checksum += (*ptr - '0') * (multiplier--);
}
output[0] = _TRACE_ID_CHECKSUM_CHARSET[checksum % 11];
return length + 1;
}
// This encoding is similar to standard base45, but with some problematic
// characters (' ', '$', '%', '*') excluded.
size_t encodeBase41(char *output, const uint8_t *input, size_t length) {
size_t outLength = 0;
for (int i = length + 1; i > 0; i -= 2) {
int value = *(input++) << 8;
value |= *(input++);
*(output++) = BASE41_CHARSET[value % 41];
*(output++) = BASE41_CHARSET[(value / 41) % 41];
*(output++) = BASE41_CHARSET[value / 1681];
outLength += 3;
}
*output = 0;
return outLength;
}
/* PS1 executable loader */
bool ExecutableHeader::validateMagic(void) const {
#if 0
return (
hash(magic, sizeof(magic)) ==
hash("PS-X EXE\0\0\0\0\0\0\0\0", sizeof(magic), 0)
);
#else
return true
&& (magic[0] == concatenate('P', 'S', '-', 'X'))
&& (magic[1] == concatenate(' ', 'E', 'X', 'E'))
&& !magic[2]
&& !magic[3]
&& !(entryPoint % 4)
&& !(textOffset % 4)
&& !(textLength % 2048)
&& !dataLength
&& !bssLength;
#endif
}
ExecutableLoader::ExecutableLoader(
void *entryPoint, void *initialGP, void *stackTop
) : _entryPoint(entryPoint), _initialGP(initialGP), _numArgs(0) {
_argListPtr = reinterpret_cast<const char **>(uintptr_t(stackTop) & ~7)
- MAX_EXECUTABLE_ARGS;
_currentStackPtr = reinterpret_cast<char *>(_argListPtr);
}
bool ExecutableLoader::addArgument(const char *arg) {
if (_numArgs >= MAX_EXECUTABLE_ARGS)
return false;
_argListPtr[_numArgs++] = arg;
return true;
}
bool ExecutableLoader::copyArgument(const char *arg, size_t length) {
if (_numArgs >= MAX_EXECUTABLE_ARGS)
return false;
// Command-line arguments must be copied to the top of the new stack in
// order to ensure the executable is going to be able to access them at any
// time.
*(--_currentStackPtr) = 0;
_currentStackPtr -= length;
__builtin_memcpy(_currentStackPtr, arg, length);
_argListPtr[_numArgs++] = _currentStackPtr;
return true;
}
bool ExecutableLoader::formatArgument(const char *format, ...) {
char buffer[64];
va_list ap;
va_start(ap, format);
int length = vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
return copyArgument(buffer, length + 1);
}
[[noreturn]] void ExecutableLoader::run(
int rawArgc, const char *const *rawArgv
) {
#if 0
disableInterrupts();
flushCache();
#endif
register int a0 __asm__("a0") = rawArgc;
register const char *const *a1 __asm__("a1") = rawArgv;
register void *gp __asm__("gp") = _initialGP;
auto stackTop = uintptr_t(_currentStackPtr) & ~7;
// Changing the stack pointer and return address is not something that
// should be done in a C++ function, but hopefully it's fine here since
// we're jumping out right after setting it.
__asm__ volatile(
".set push\n"
".set noreorder\n"
"li $ra, %0\n"
"jr %1\n"
"addiu $sp, %2, -8\n"
".set pop\n"
:: "i"(DEV2_BASE), "r"(_entryPoint), "r"(stackTop),
"r"(a0), "r"(a1), "r"(gp)
);
__builtin_unreachable();
}
}

View File

@ -1,518 +0,0 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "ps1/system.h"
namespace util {
/* Misc. template utilities */
template<typename T> static inline uint32_t sum(const T *data, size_t length) {
uint32_t value = 0;
for (; length; length--)
value += uint32_t(*(data++));
return value;
}
template<typename T> static inline T min(T a, T b) {
return (a < b) ? a : b;
}
template<typename T> static inline T max(T a, T b) {
return (a > b) ? a : b;
}
template<typename T> static inline T clamp(T value, T minValue, T maxValue) {
return (value < minValue) ? minValue :
((value > maxValue) ? maxValue : value);
}
template<typename T> static inline T rotateLeft(T value, int amount) {
return T((value << amount) | (value >> (sizeof(T) * 8 - amount)));
}
template<typename T> static inline T rotateRight(T value, int amount) {
return T((value >> amount) | (value << (sizeof(T) * 8 - amount)));
}
// These shall only be used with unsigned types.
template<typename T> static inline T truncateToMultiple(T value, T length) {
return value - (value % length);
}
template<typename T> static inline T roundUpToMultiple(T value, T length) {
T diff = value % length;
return diff ? (value - diff + length) : value;
}
template<typename T, typename X> static inline void assertAligned(X *ptr) {
assert(!(reinterpret_cast<uintptr_t>(ptr) % alignof(T)));
}
template<typename T> static inline void clear(T &obj, uint8_t value = 0) {
__builtin_memset(&obj, value, sizeof(obj));
}
template<typename T> static constexpr inline size_t countOf(T &array) {
return sizeof(array) / sizeof(array[0]);
}
template<typename T, typename X> static inline T forcedCast(X item) {
return reinterpret_cast<T>(reinterpret_cast<void *>(item));
}
static constexpr inline uint16_t concatenate(uint8_t a, uint8_t b) {
return a | (b << 8);
}
static constexpr inline uint32_t concatenate(
uint8_t a, uint8_t b, uint8_t c, uint8_t d
) {
return a | (b << 8) | (c << 16) | (d << 24);
}
/* String hashing (http://www.cse.yorku.ca/~oz/hash.html) */
using Hash = uint32_t;
template<typename T> static constexpr inline Hash hash(
const T *const data, size_t length = -1, Hash value = 0
) {
if (*data && length)
return hash(
&data[1], length - 1,
Hash(*data) + (value << 6) + (value << 16) - value
);
return value;
}
Hash hash(const char *str, char terminator = 0);
Hash hash(const uint8_t *data, size_t length);
/* Critical section helper */
class CriticalSection {
private:
bool _enable;
public:
inline CriticalSection(void) {
_enable = disableInterrupts();
}
inline ~CriticalSection(void) {
if (_enable)
enableInterrupts();
}
};
class ThreadCriticalSection {
public:
inline ThreadCriticalSection(void) {
bool enable = disableInterrupts();
assert(enable);
}
inline ~ThreadCriticalSection(void) {
enableInterrupts();
}
};
/* Simple "smart" pointer */
class Data {
public:
void *ptr;
size_t length;
inline Data(void)
: ptr(nullptr), length(0) {}
inline ~Data(void) {
destroy();
}
template<typename T> inline T *as(void) {
return reinterpret_cast<T *>(ptr);
}
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)
delete[] as<uint8_t>();
ptr = _length ? (new uint8_t[_length]) : nullptr;
length = _length;
return ptr;
}
inline void destroy(void) {
if (ptr) {
delete[] as<uint8_t>();
ptr = nullptr;
}
}
};
/* Simple ring buffer */
template<typename T, size_t N> class RingBuffer {
private:
T _items[N];
size_t _head, _tail;
public:
size_t length;
inline RingBuffer(void)
: _head(0), _tail(0), length(0) {}
inline T *pushItem(void) volatile {
if (length >= N)
return nullptr;
size_t i = _tail;
_tail = (i + 1) % N;
length++;
return &_items[i];
}
inline T *popItem(void) volatile {
if (!length)
return nullptr;
size_t i = _head;
_head = (i + 1) % N;
length--;
return &_items[i];
}
inline T *peekItem(void) const {
if (!length)
return nullptr;
return &_items[_head];
}
};
/* Date and time class */
class Date {
public:
uint16_t year;
uint8_t month, day, hour, minute, second;
inline void reset(void) {
year = 2024;
month = 1;
day = 1;
hour = 0;
minute = 0;
second = 0;
}
bool isValid(void) const;
bool isLeapYear(void) const;
int getDayOfWeek(void) const;
int getMonthDayCount(void) const;
uint32_t toDOSTime(void) const;
size_t toString(char *output) const;
};
/* Tween/animation classes */
static constexpr int TWEEN_UNIT = 1 << 12;
class LinearEasing {
public:
template<typename T> static inline T apply(T value) {
return value;
}
};
class QuadInEasing {
public:
template<typename T> static inline T apply(T value) {
return (value * value) / TWEEN_UNIT;
}
};
class QuadOutEasing {
public:
template<typename T> static inline T apply(T value) {
return (value * 2) - ((value * value) / TWEEN_UNIT);
}
};
template<typename T, typename E> class Tween {
private:
T _base, _delta;
int _endTime, _timeScale;
public:
inline Tween(void) {
setValue(static_cast<T>(0));
}
inline Tween(T start) {
setValue(start);
}
inline T getTargetValue(void) const {
return _base + _delta;
}
inline bool isDone(int time) const {
return time >= _endTime;
}
inline void setValue(int time, T target, int duration) {
setValue(time, getValue(time), target, duration);
}
void setValue(int time, T start, T target, int duration);
void setValue(T target);
T getValue(int time) const;
};
/* Logging framework */
static constexpr int MAX_LOG_LINE_LENGTH = 128;
static constexpr int MAX_LOG_LINES = 64;
class LogBuffer {
private:
char _lines[MAX_LOG_LINES][MAX_LOG_LINE_LENGTH];
int _tail;
public:
inline LogBuffer(void)
: _tail(0) {
clear();
}
// 0 = last line, 1 = second to last, etc.
inline const char *getLine(int line) const {
return _lines[size_t(_tail - (line + 1)) % MAX_LOG_LINES];
}
void clear(void);
char *allocateLine(void);
};
class Logger {
private:
LogBuffer *_buffer;
bool _enableSyslog;
public:
inline Logger(void)
: _buffer(nullptr), _enableSyslog(false) {}
void setLogBuffer(LogBuffer *buffer);
void setupSyslog(int baudRate);
void log(const char *format, ...);
};
extern Logger logger;
/* PS1 executable loader */
static constexpr size_t EXECUTABLE_BODY_OFFSET = 2048;
static constexpr size_t MAX_EXECUTABLE_ARGS = 32;
class ExecutableHeader {
public:
uint32_t magic[4];
uint32_t entryPoint, initialGP;
uint32_t textOffset, textLength;
uint32_t dataOffset, dataLength;
uint32_t bssOffset, bssLength;
uint32_t stackOffset, stackLength;
uint32_t _reserved[5];
inline void *getEntryPoint(void) const {
return reinterpret_cast<void *>(entryPoint);
}
inline void *getInitialGP(void) const {
return reinterpret_cast<void *>(initialGP);
}
inline void *getTextPtr(void) const {
return reinterpret_cast<void *>(textOffset);
}
inline void *getStackPtr(void) const {
return reinterpret_cast<void *>(stackOffset + stackLength);
}
inline const char *getRegionString(void) const {
return reinterpret_cast<const char *>(this + 1);
}
inline void relocateText(const void *source) const {
__builtin_memcpy(getTextPtr(), source, textLength);
}
bool validateMagic(void) const;
};
class ExecutableLoader {
private:
void *_entryPoint, *_initialGP;
size_t _numArgs;
const char **_argListPtr;
char *_currentStackPtr;
public:
inline bool copyArgument(const char *arg) {
return copyArgument(arg, __builtin_strlen(arg));
}
[[noreturn]] inline void run(void) {
run(_numArgs, _argListPtr);
}
ExecutableLoader(void *entryPoint, void *initialGP, void *stackTop);
bool addArgument(const char *arg);
bool copyArgument(const char *arg, size_t length);
bool formatArgument(const char *format, ...);
[[noreturn]] void run(int rawArgc, const char *const *rawArgv);
};
/* MD5 hash */
class MD5 {
private:
uint32_t _state[4];
uint8_t _blockBuffer[64];
size_t _blockCount, _bufferLength;
static inline int _indexF(int index) {
return index;
}
static inline uint32_t _addF(uint32_t x, uint32_t y, uint32_t z) {
return z ^ (x & (y ^ z)); // (x & y) | ((~x) & z)
}
static inline int _indexG(int index) {
return ((index * 5) + 1) % 16;
}
static inline uint32_t _addG(uint32_t x, uint32_t y, uint32_t z) {
return y ^ (z & (x ^ y)); // (x & z) | (y & (~z))
}
static inline int _indexH(int index) {
return ((index * 3) + 5) % 16;
}
static inline uint32_t _addH(uint32_t x, uint32_t y, uint32_t z) {
return x ^ y ^ z;
}
static inline int _indexI(int index) {
return (index * 7) % 16;
}
static inline uint32_t _addI(uint32_t x, uint32_t y, uint32_t z) {
return (y ^ (x | (~z)));
}
void _flushBlock(const void *data);
public:
MD5(void);
void update(const uint8_t *data, size_t length);
void digest(uint8_t *output);
};
/* Other APIs */
static inline size_t getLZ4InPlaceMargin(size_t inputLength) {
return (inputLength >> 8) + 32;
}
void decompressLZ4(
uint8_t *output, const uint8_t *input, size_t maxOutputLength,
size_t inputLength
);
uint8_t dsCRC8(const uint8_t *data, size_t length);
uint16_t zsCRC16(const uint8_t *data, size_t length);
uint32_t zipCRC32(const uint8_t *data, size_t length, uint32_t crc = 0);
void initZipCRC32(void);
extern const char HEX_CHARSET[], BASE41_CHARSET[];
size_t hexValueToString(char *output, uint32_t value, size_t numDigits = 8);
size_t hexToString(
char *output, const uint8_t *input, size_t length, char separator = 0
);
size_t serialNumberToString(char *output, const uint8_t *input);
size_t traceIDToString(char *output, const uint8_t *input);
size_t encodeBase41(char *output, const uint8_t *input, size_t length);
}
static constexpr inline util::Hash operator""_h(
const char *const literal, size_t length
) {
return util::hash(literal, length);
}
/* Logging macros */
#define LOG(type, fmt, ...) \
util::logger.log( \
type ",%s(%d): " fmt, __func__, __LINE__ __VA_OPT__(,) __VA_ARGS__ \
)
#ifdef ENABLE_APP_LOGGING
#define LOG_APP(fmt, ...) LOG("app", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_APP(fmt, ...)
#endif
#ifdef ENABLE_CART_IO_LOGGING
#define LOG_CART_IO(fmt, ...) LOG("cart", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_CART_IO(fmt, ...)
#endif
#ifdef ENABLE_CART_DATA_LOGGING
#define LOG_CART_DATA(fmt, ...) LOG("data", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_CART_DATA(fmt, ...)
#endif
#ifdef ENABLE_ROM_LOGGING
#define LOG_ROM(fmt, ...) LOG("rom", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_ROM(fmt, ...)
#endif
#ifdef ENABLE_IDE_LOGGING
#define LOG_IDE(fmt, ...) LOG("ide", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_IDE(fmt, ...)
#endif
#ifdef ENABLE_FS_LOGGING
#define LOG_FS(fmt, ...) LOG("fs", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_FS(fmt, ...)
#endif

272
src/common/util/hash.cpp Normal file
View File

@ -0,0 +1,272 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "ps1/registers.h"
namespace util {
/* String hashing (http://www.cse.yorku.ca/~oz/hash.html) */
Hash hash(const char *str, char terminator) {
auto _str = reinterpret_cast<const uint8_t *>(str);
Hash value = 0;
while (*_str && (*_str != terminator))
value = Hash(*(_str++)) + (value << 6) + (value << 16) - value;
return value;
}
Hash hash(const uint8_t *data, size_t length) {
Hash value = 0;
for (; length; length--)
value = Hash(*(data++)) + (value << 6) + (value << 16) - value;
return value;
}
/* CRC calculation */
static constexpr uint8_t _CRC8_POLY = 0x8c;
static constexpr uint16_t _CRC16_POLY = 0x1021;
static constexpr uint32_t _CRC32_POLY = 0xedb88320;
uint8_t dsCRC8(const uint8_t *data, size_t length) {
uint8_t crc = 0;
for (; length; length--) {
uint8_t value = *(data++);
for (int bit = 8; bit; bit--) {
uint8_t temp = crc ^ value;
value >>= 1;
crc >>= 1;
if (temp & 1)
crc ^= _CRC8_POLY;
}
}
return crc & 0xff;
}
uint16_t zsCRC16(const uint8_t *data, size_t length) {
uint16_t crc = 0xffff;
for (; length; length--) {
crc ^= *(data++) << 8;
for (int bit = 8; bit; bit--) {
uint16_t temp = crc;
crc <<= 1;
if (temp & (1 << 15))
crc ^= _CRC16_POLY;
}
}
return (crc ^ 0xffff) & 0xffff;
}
uint32_t zipCRC32(const uint8_t *data, size_t length, uint32_t crc) {
// This CRC32 implementation uses a lookup table cached in the scratchpad
// area in order to improve performance.
auto table = reinterpret_cast<const uint32_t *>(CACHE_BASE);
crc = ~crc;
for (; length; length--)
crc = (crc >> 8) ^ table[(crc ^ *(data++)) & 0xff];
return ~crc;
}
void initZipCRC32(void) {
auto table = reinterpret_cast<uint32_t *>(CACHE_BASE);
for (int i = 0; i < 256; i++) {
uint32_t crc = i;
for (int bit = 8; bit; bit--) {
uint32_t temp = crc;
crc >>= 1;
if (temp & 1)
crc ^= _CRC32_POLY;
}
*(table++) = crc;
}
}
extern "C" uint32_t mz_crc32(uint32_t crc, const uint8_t *data, size_t length) {
return zipCRC32(data, length, crc);
}
/* MD5 hash */
static const uint32_t _MD5_SEED[]{
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
};
static const uint32_t _MD5_ADD[][16]{
{
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
}, {
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
}, {
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
}, {
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
}
};
static const uint8_t _MD5_SHIFT[][4]{
{ 7, 12, 17, 22 },
{ 5, 9, 14, 20 },
{ 4, 11, 16, 23 },
{ 6, 10, 15, 21 }
};
MD5::MD5(void)
: _blockCount(0), _bufferLength(0) {
__builtin_memcpy(_state, _MD5_SEED, sizeof(_state));
}
void MD5::_flushBlock(const void *data) {
auto input = reinterpret_cast<const uint32_t *>(data);
assertAligned<uint32_t>(data);
auto a = _state[0], b = _state[1], c = _state[2], d = _state[3];
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addF(b, c, d) + input[_indexF(i)] + _MD5_ADD[0][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[0][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addG(b, c, d) + input[_indexG(i)] + _MD5_ADD[1][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[1][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addH(b, c, d) + input[_indexH(i)] + _MD5_ADD[2][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[2][i % 4]);
a = _d;
}
for (int i = 0; i < 16; i++) {
auto _d = d;
auto _e = a + _addI(b, c, d) + input[_indexI(i)] + _MD5_ADD[3][i];
d = c;
c = b;
b += rotateLeft(_e, _MD5_SHIFT[3][i % 4]);
a = _d;
}
_state[0] += a;
_state[1] += b;
_state[2] += c;
_state[3] += d;
_blockCount++;
}
void MD5::update(const uint8_t *data, size_t length) {
if (_bufferLength > 0) {
auto ptr = &_blockBuffer[_bufferLength];
auto freeSpace = sizeof(_blockBuffer) - _bufferLength;
if (length >= freeSpace) {
__builtin_memcpy(ptr, data, freeSpace);
_flushBlock(_blockBuffer);
data += freeSpace;
length -= freeSpace;
_bufferLength = 0;
} else {
__builtin_memcpy(ptr, data, length);
_bufferLength += length;
return;
}
}
// Avoid copying data to the intermediate block buffer whenever possible.
for (;
length >= sizeof(_blockBuffer);
length -= sizeof(_blockBuffer), data += sizeof(_blockBuffer)
)
_flushBlock(data);
if (length > 0) {
__builtin_memcpy(_blockBuffer, data, length);
_bufferLength = length;
}
}
void MD5::digest(uint8_t *output) {
uint64_t length = (
uint64_t(_blockCount) * sizeof(_blockBuffer) + uint64_t(_bufferLength)
) * 8;
_blockBuffer[_bufferLength++] = 1 << 7;
while (_bufferLength != (sizeof(_blockBuffer) - 8)) {
if (_bufferLength == sizeof(_blockBuffer)) {
_flushBlock(_blockBuffer);
_bufferLength = 0;
}
_blockBuffer[_bufferLength++] = 0;
}
for (int i = 8; i > 0; i--, length >>= 8)
_blockBuffer[_bufferLength++] = uint8_t(length & 0xff);
_flushBlock(_blockBuffer);
__builtin_memcpy(output, _state, sizeof(_state));
}
}

99
src/common/util/hash.hpp Normal file
View File

@ -0,0 +1,99 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
namespace util {
/* String hashing (http://www.cse.yorku.ca/~oz/hash.html) */
using Hash = uint32_t;
template<typename T> static constexpr inline Hash hash(
const T *const data, size_t length = -1, Hash value = 0
) {
if (*data && length)
return hash(
&data[1], length - 1,
Hash(*data) + (value << 6) + (value << 16) - value
);
return value;
}
Hash hash(const char *str, char terminator = 0);
Hash hash(const uint8_t *data, size_t length);
/* CRC calculation */
uint8_t dsCRC8(const uint8_t *data, size_t length);
uint16_t zsCRC16(const uint8_t *data, size_t length);
uint32_t zipCRC32(const uint8_t *data, size_t length, uint32_t crc = 0);
void initZipCRC32(void);
/* MD5 hash */
class MD5 {
private:
uint32_t _state[4];
uint8_t _blockBuffer[64];
size_t _blockCount, _bufferLength;
static inline int _indexF(int index) {
return index;
}
static inline uint32_t _addF(uint32_t x, uint32_t y, uint32_t z) {
return z ^ (x & (y ^ z)); // (x & y) | ((~x) & z)
}
static inline int _indexG(int index) {
return ((index * 5) + 1) % 16;
}
static inline uint32_t _addG(uint32_t x, uint32_t y, uint32_t z) {
return y ^ (z & (x ^ y)); // (x & z) | (y & (~z))
}
static inline int _indexH(int index) {
return ((index * 3) + 5) % 16;
}
static inline uint32_t _addH(uint32_t x, uint32_t y, uint32_t z) {
return x ^ y ^ z;
}
static inline int _indexI(int index) {
return (index * 7) % 16;
}
static inline uint32_t _addI(uint32_t x, uint32_t y, uint32_t z) {
return (y ^ (x | (~z)));
}
void _flushBlock(const void *data);
public:
MD5(void);
void update(const uint8_t *data, size_t length);
void digest(uint8_t *output);
};
}
/* String hashing operator */
static constexpr inline util::Hash operator""_h(
const char *const literal, size_t length
) {
return util::hash(literal, length);
}

81
src/common/util/log.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
namespace util {
/* Logging framework */
Logger logger;
void LogBuffer::clear(void) {
for (auto line : _lines)
line[0] = 0;
}
char *LogBuffer::allocateLine(void) {
size_t tail = _tail;
_tail = (tail + 1) % MAX_LOG_LINES;
return _lines[tail];
}
void Logger::setLogBuffer(LogBuffer *buffer) {
CriticalSection sec;
_buffer = buffer;
}
void Logger::setupSyslog(int baudRate) {
CriticalSection sec;
if (baudRate) {
initSerialIO(baudRate);
_enableSyslog = true;
} else {
_enableSyslog = false;
}
}
void Logger::log(const char *format, ...) {
CriticalSection sec;
va_list ap;
if (_buffer) {
auto line = _buffer->allocateLine();
va_start(ap, format);
vsnprintf(line, MAX_LOG_LINE_LENGTH, format, ap);
va_end(ap);
if (_enableSyslog)
puts(line);
} else if (_enableSyslog) {
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
putchar('\n');
}
}
}

107
src/common/util/log.hpp Normal file
View File

@ -0,0 +1,107 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stddef.h>
namespace util {
/* Logging framework */
static constexpr int MAX_LOG_LINE_LENGTH = 128;
static constexpr int MAX_LOG_LINES = 64;
class LogBuffer {
private:
char _lines[MAX_LOG_LINES][MAX_LOG_LINE_LENGTH];
int _tail;
public:
inline LogBuffer(void)
: _tail(0) {
clear();
}
// 0 = last line, 1 = second to last, etc.
inline const char *getLine(int line) const {
return _lines[size_t(_tail - (line + 1)) % MAX_LOG_LINES];
}
void clear(void);
char *allocateLine(void);
};
class Logger {
private:
LogBuffer *_buffer;
bool _enableSyslog;
public:
inline Logger(void)
: _buffer(nullptr), _enableSyslog(false) {}
void setLogBuffer(LogBuffer *buffer);
void setupSyslog(int baudRate);
void log(const char *format, ...);
};
extern Logger logger;
}
/* Logging macros */
#define LOG(type, fmt, ...) \
util::logger.log( \
type ",%s(%d): " fmt, __func__, __LINE__ __VA_OPT__(,) __VA_ARGS__ \
)
#ifdef ENABLE_APP_LOGGING
#define LOG_APP(fmt, ...) LOG("app", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_APP(fmt, ...)
#endif
#ifdef ENABLE_CART_IO_LOGGING
#define LOG_CART_IO(fmt, ...) LOG("cart", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_CART_IO(fmt, ...)
#endif
#ifdef ENABLE_CART_DATA_LOGGING
#define LOG_CART_DATA(fmt, ...) LOG("data", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_CART_DATA(fmt, ...)
#endif
#ifdef ENABLE_ROM_LOGGING
#define LOG_ROM(fmt, ...) LOG("rom", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_ROM(fmt, ...)
#endif
#ifdef ENABLE_IDE_LOGGING
#define LOG_IDE(fmt, ...) LOG("ide", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_IDE(fmt, ...)
#endif
#ifdef ENABLE_FS_LOGGING
#define LOG_FS(fmt, ...) LOG("fs", fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define LOG_FS(fmt, ...)
#endif

211
src/common/util/misc.cpp Normal file
View File

@ -0,0 +1,211 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "common/util/hash.hpp"
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "ps1/system.h"
namespace util {
/* 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;
if (_month <= 0) {
_month += 12;
_year--;
}
int century = _year / 100;
_year %= 100;
int weekday = 0
+ day
+ (_month * 26 - 2) / 10
+ _year
+ _year / 4
+ century / 4
+ century * 5;
return weekday % 7;
}
int Date::getMonthDayCount(void) const {
switch (month) {
case 2:
return isLeapYear() ? 29 : 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
uint32_t Date::toDOSTime(void) const {
int _year = year - 1980;
if (!isValid())
return 0;
if ((_year < 0) || (_year > 127))
return 0;
return 0
| (_year << 25)
| (month << 21)
| (day << 16)
| (hour << 11)
| (minute << 5)
| (second >> 1);
}
size_t Date::toString(char *output) const {
if (!isValid()) {
*output = 0;
return 0;
}
return sprintf(
output, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute,
second
);
}
/* PS1 executable loader */
bool ExecutableHeader::validateMagic(void) const {
#if 0
return (
hash(magic, sizeof(magic)) ==
hash("PS-X EXE\0\0\0\0\0\0\0\0", sizeof(magic), 0)
);
#else
return true
&& (magic[0] == concatenate('P', 'S', '-', 'X'))
&& (magic[1] == concatenate(' ', 'E', 'X', 'E'))
&& !magic[2]
&& !magic[3]
&& !(entryPoint % 4)
&& !(textOffset % 4)
&& !(textLength % 2048)
&& !dataLength
&& !bssLength;
#endif
}
ExecutableLoader::ExecutableLoader(
void *entryPoint, void *initialGP, void *stackTop
) : _entryPoint(entryPoint), _initialGP(initialGP), _numArgs(0) {
_argListPtr = reinterpret_cast<const char **>(uintptr_t(stackTop) & ~7)
- MAX_EXECUTABLE_ARGS;
_currentStackPtr = reinterpret_cast<char *>(_argListPtr);
}
bool ExecutableLoader::addArgument(const char *arg) {
if (_numArgs >= MAX_EXECUTABLE_ARGS)
return false;
_argListPtr[_numArgs++] = arg;
return true;
}
bool ExecutableLoader::copyArgument(const char *arg, size_t length) {
if (_numArgs >= MAX_EXECUTABLE_ARGS)
return false;
// Command-line arguments must be copied to the top of the new stack in
// order to ensure the executable is going to be able to access them at any
// time.
*(--_currentStackPtr) = 0;
_currentStackPtr -= length;
__builtin_memcpy(_currentStackPtr, arg, length);
_argListPtr[_numArgs++] = _currentStackPtr;
return true;
}
bool ExecutableLoader::formatArgument(const char *format, ...) {
char buffer[64];
va_list ap;
va_start(ap, format);
int length = vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
return copyArgument(buffer, length + 1);
}
[[noreturn]] void ExecutableLoader::run(
int rawArgc, const char *const *rawArgv
) {
#if 0
disableInterrupts();
flushCache();
#endif
register int a0 __asm__("a0") = rawArgc;
register const char *const *a1 __asm__("a1") = rawArgv;
register void *gp __asm__("gp") = _initialGP;
auto stackTop = uintptr_t(_currentStackPtr) & ~7;
// Changing the stack pointer and return address is not something that
// should be done in a C++ function, but hopefully it's fine here since
// we're jumping out right after setting it.
__asm__ volatile(
".set push\n"
".set noreorder\n"
"li $ra, %0\n"
"jr %1\n"
"addiu $sp, %2, -8\n"
".set pop\n"
:: "i"(DEV2_BASE), "r"(_entryPoint), "r"(stackTop),
"r"(a0), "r"(a1), "r"(gp)
);
__builtin_unreachable();
}
}

139
src/common/util/misc.hpp Normal file
View File

@ -0,0 +1,139 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "ps1/system.h"
namespace util {
/* Date and time class */
class Date {
public:
uint16_t year;
uint8_t month, day, hour, minute, second;
inline void reset(void) {
year = 2024;
month = 1;
day = 1;
hour = 0;
minute = 0;
second = 0;
}
bool isValid(void) const;
bool isLeapYear(void) const;
int getDayOfWeek(void) const;
int getMonthDayCount(void) const;
uint32_t toDOSTime(void) const;
size_t toString(char *output) const;
};
/* Critical section helper */
class CriticalSection {
private:
bool _enable;
public:
inline CriticalSection(void) {
_enable = disableInterrupts();
}
inline ~CriticalSection(void) {
if (_enable)
enableInterrupts();
}
};
class ThreadCriticalSection {
public:
inline ThreadCriticalSection(void) {
bool enable = disableInterrupts();
//assert(enable);
}
inline ~ThreadCriticalSection(void) {
enableInterrupts();
}
};
/* PS1 executable loader */
static constexpr size_t EXECUTABLE_BODY_OFFSET = 2048;
static constexpr size_t MAX_EXECUTABLE_ARGS = 32;
class ExecutableHeader {
public:
uint32_t magic[4];
uint32_t entryPoint, initialGP;
uint32_t textOffset, textLength;
uint32_t dataOffset, dataLength;
uint32_t bssOffset, bssLength;
uint32_t stackOffset, stackLength;
uint32_t _reserved[5];
inline void *getEntryPoint(void) const {
return reinterpret_cast<void *>(entryPoint);
}
inline void *getInitialGP(void) const {
return reinterpret_cast<void *>(initialGP);
}
inline void *getTextPtr(void) const {
return reinterpret_cast<void *>(textOffset);
}
inline void *getStackPtr(void) const {
return reinterpret_cast<void *>(stackOffset + stackLength);
}
inline const char *getRegionString(void) const {
return reinterpret_cast<const char *>(this + 1);
}
inline void relocateText(const void *source) const {
__builtin_memcpy(getTextPtr(), source, textLength);
}
bool validateMagic(void) const;
};
class ExecutableLoader {
private:
void *_entryPoint, *_initialGP;
size_t _numArgs;
const char **_argListPtr;
char *_currentStackPtr;
public:
inline bool copyArgument(const char *arg) {
return copyArgument(arg, __builtin_strlen(arg));
}
[[noreturn]] inline void run(void) {
run(_numArgs, _argListPtr);
}
ExecutableLoader(void *entryPoint, void *initialGP, void *stackTop);
bool addArgument(const char *arg);
bool copyArgument(const char *arg, size_t length);
bool formatArgument(const char *format, ...);
[[noreturn]] void run(int rawArgc, const char *const *rawArgv);
};
}

167
src/common/util/string.cpp Normal file
View File

@ -0,0 +1,167 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "common/util/string.hpp"
namespace util {
/* String manipulation */
const char HEX_CHARSET[]{ "0123456789ABCDEF" };
const char BASE41_CHARSET[]{ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./:" };
size_t hexValueToString(char *output, uint32_t value, size_t numDigits) {
output += numDigits;
*output = 0;
for (size_t i = numDigits; i; i--, value >>= 4)
*(--output) = HEX_CHARSET[value & 0xf];
return numDigits;
}
size_t hexToString(
char *output, const uint8_t *input, size_t length, char separator
) {
size_t outLength = 0;
for (; length; length--) {
uint8_t value = *(input++);
*(output++) = HEX_CHARSET[value >> 4];
*(output++) = HEX_CHARSET[value & 0xf];
if (separator && (length > 1)) {
*(output++) = separator;
outLength += 3;
} else {
outLength += 2;
}
}
*output = 0;
return outLength;
}
size_t serialNumberToString(char *output, const uint8_t *input) {
uint32_t value =
input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24);
return sprintf(output, "%04d-%04d", (value / 10000) % 10000, value % 10000);
}
// This format is used by Konami's tools to display trace IDs in the TID_81
// format.
static const char _TRACE_ID_CHECKSUM_CHARSET[]{ "0X987654321" };
size_t traceIDToString(char *output, const uint8_t *input) {
uint16_t high = (input[0] << 8) | input[1];
uint32_t low =
(input[2] << 24) | (input[3] << 16) | (input[4] << 8) | input[5];
size_t length = sprintf(&output[1], "%02d-%04d", high % 100, low % 10000);
// The checksum is calculated in a very weird way:
// code = AB-CDEF
// checksum = (A*7 + B*6 + C*5 + D*4 + E*3 + F*2) % 11
int checksum = 0, multiplier = 7;
for (const char *ptr = &output[1]; *ptr; ptr++) {
if (*ptr != '-')
checksum += (*ptr - '0') * (multiplier--);
}
output[0] = _TRACE_ID_CHECKSUM_CHARSET[checksum % 11];
return length + 1;
}
// This encoding is similar to standard base45, but with some problematic
// characters (' ', '$', '%', '*') excluded.
size_t encodeBase41(char *output, const uint8_t *input, size_t length) {
size_t outLength = 0;
for (int i = length + 1; i > 0; i -= 2) {
int value = *(input++) << 8;
value |= *(input++);
*(output++) = BASE41_CHARSET[value % 41];
*(output++) = BASE41_CHARSET[(value / 41) % 41];
*(output++) = BASE41_CHARSET[value / 1681];
outLength += 3;
}
*output = 0;
return outLength;
}
/* LZ4 decompressor */
void decompressLZ4(
uint8_t *output, const uint8_t *input, size_t maxOutputLength,
size_t inputLength
) {
auto outputEnd = &output[maxOutputLength];
auto inputEnd = &input[inputLength];
while (input < inputEnd) {
uint8_t token = *(input++);
// Copy literals from the input stream.
int literalLength = token >> 4;
if (literalLength == 0xf) {
uint8_t addend;
do {
addend = *(input++);
literalLength += addend;
} while (addend == 0xff);
}
for (; literalLength && (output < outputEnd); literalLength--)
*(output++) = *(input++);
if (input >= inputEnd)
break;
int offset = input[0] | (input[1] << 8);
input += 2;
// Copy from previously decompressed data. Note that this *must* be done
// one byte at a time, as the compressor relies on out-of-bounds copies
// repeating the last byte.
int copyLength = token & 0xf;
if (copyLength == 0xf) {
uint8_t addend;
do {
addend = *(input++);
copyLength += addend;
} while (addend == 0xff);
}
auto copySource = output - offset;
copyLength += 4;
for (; copyLength && (output < outputEnd); copyLength--)
*(output++) = *(copySource++);
}
}
}

View File

@ -0,0 +1,47 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
namespace util {
/* String manipulation */
extern const char HEX_CHARSET[], BASE41_CHARSET[];
size_t hexValueToString(char *output, uint32_t value, size_t numDigits = 8);
size_t hexToString(
char *output, const uint8_t *input, size_t length, char separator = 0
);
size_t serialNumberToString(char *output, const uint8_t *input);
size_t traceIDToString(char *output, const uint8_t *input);
size_t encodeBase41(char *output, const uint8_t *input, size_t length);
/* LZ4 decompressor */
static inline size_t getLZ4InPlaceMargin(size_t inputLength) {
return (inputLength >> 8) + 32;
}
void decompressLZ4(
uint8_t *output, const uint8_t *input, size_t maxOutputLength,
size_t inputLength
);
}

View File

@ -0,0 +1,174 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
namespace util {
/* Misc. template utilities */
template<typename T> static inline uint32_t sum(const T *data, size_t length) {
uint32_t value = 0;
for (; length; length--)
value += uint32_t(*(data++));
return value;
}
template<typename T> static inline T min(T a, T b) {
return (a < b) ? a : b;
}
template<typename T> static inline T max(T a, T b) {
return (a > b) ? a : b;
}
template<typename T> static inline T clamp(T value, T minValue, T maxValue) {
return (value < minValue) ? minValue :
((value > maxValue) ? maxValue : value);
}
template<typename T> static inline T rotateLeft(T value, int amount) {
return T((value << amount) | (value >> (sizeof(T) * 8 - amount)));
}
template<typename T> static inline T rotateRight(T value, int amount) {
return T((value >> amount) | (value << (sizeof(T) * 8 - amount)));
}
// These shall only be used with unsigned types.
template<typename T> static inline T truncateToMultiple(T value, T length) {
return value - (value % length);
}
template<typename T> static inline T roundUpToMultiple(T value, T length) {
T diff = value % length;
return diff ? (value - diff + length) : value;
}
template<typename T, typename X> static inline void assertAligned(X *ptr) {
//assert(!(reinterpret_cast<uintptr_t>(ptr) % alignof(T)));
}
template<typename T> static inline void clear(T &obj, uint8_t value = 0) {
__builtin_memset(&obj, value, sizeof(obj));
}
template<typename T> static constexpr inline size_t countOf(T &array) {
return sizeof(array) / sizeof(array[0]);
}
template<typename T, typename X> static inline T forcedCast(X item) {
return reinterpret_cast<T>(reinterpret_cast<void *>(item));
}
static constexpr inline uint16_t concatenate(uint8_t a, uint8_t b) {
return a | (b << 8);
}
static constexpr inline uint32_t concatenate(
uint8_t a, uint8_t b, uint8_t c, uint8_t d
) {
return a | (b << 8) | (c << 16) | (d << 24);
}
/* Simple "smart" pointer */
class Data {
public:
void *ptr;
size_t length;
inline Data(void)
: ptr(nullptr), length(0) {}
inline ~Data(void) {
destroy();
}
template<typename T> inline T *as(void) {
return reinterpret_cast<T *>(ptr);
}
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)
delete[] as<uint8_t>();
ptr = _length ? (new uint8_t[_length]) : nullptr;
length = _length;
return ptr;
}
inline void destroy(void) {
if (ptr) {
delete[] as<uint8_t>();
ptr = nullptr;
}
}
};
/* Simple ring buffer */
template<typename T, size_t N> class RingBuffer {
private:
T _items[N];
size_t _head, _tail;
public:
size_t length;
inline RingBuffer(void)
: _head(0), _tail(0), length(0) {}
inline T *pushItem(void) volatile {
if (length >= N)
return nullptr;
size_t i = _tail;
_tail = (i + 1) % N;
length++;
return &_items[i];
}
inline T *popItem(void) volatile {
if (!length)
return nullptr;
size_t i = _head;
_head = (i + 1) % N;
length--;
return &_items[i];
}
inline T *peekItem(void) const {
if (!length)
return nullptr;
return &_items[_head];
}
};
}

63
src/common/util/tween.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdint.h>
#include "common/util/tween.hpp"
namespace util {
template<typename T, typename E> void Tween<T, E>::setValue(
int time, T start, T target, int duration
) {
//assert(duration <= 0x800);
_base = start;
_delta = target - start;
_endTime = time + duration;
_timeScale = TWEEN_UNIT / duration;
}
template<typename T, typename E> void Tween<T, E>::setValue(T target) {
_base = target;
_delta = static_cast<T>(0);
_endTime = 0;
}
template<typename T, typename E> T Tween<T, E>::getValue(int time) const {
int remaining = time - _endTime;
if (remaining >= 0)
return _base + _delta;
return _base + (
_delta * E::apply(remaining * _timeScale + TWEEN_UNIT)
) / TWEEN_UNIT;
}
template class Tween<int, LinearEasing>;
template class Tween<int, QuadInEasing>;
template class Tween<int, QuadOutEasing>;
template class Tween<uint16_t, LinearEasing>;
template class Tween<uint16_t, QuadInEasing>;
template class Tween<uint16_t, QuadOutEasing>;
template class Tween<uint32_t, LinearEasing>;
template class Tween<uint32_t, QuadInEasing>;
template class Tween<uint32_t, QuadOutEasing>;
}

72
src/common/util/tween.hpp Normal file
View File

@ -0,0 +1,72 @@
/*
* 573in1 - Copyright (C) 2022-2024 spicyjpeg
*
* 573in1 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* 573in1. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
namespace util {
static constexpr int TWEEN_UNIT = 1 << 12;
class LinearEasing {
public:
template<typename T> static inline T apply(T value) {
return value;
}
};
class QuadInEasing {
public:
template<typename T> static inline T apply(T value) {
return (value * value) / TWEEN_UNIT;
}
};
class QuadOutEasing {
public:
template<typename T> static inline T apply(T value) {
return (value * 2) - ((value * value) / TWEEN_UNIT);
}
};
template<typename T, typename E> class Tween {
private:
T _base, _delta;
int _endTime, _timeScale;
public:
inline Tween(void) {
setValue(static_cast<T>(0));
}
inline Tween(T start) {
setValue(start);
}
inline T getTargetValue(void) const {
return _base + _delta;
}
inline bool isDone(int time) const {
return time >= _endTime;
}
inline void setValue(int time, T target, int duration) {
setValue(time, getValue(time), target, duration);
}
void setValue(int time, T start, T target, int duration);
void setValue(T target);
T getValue(int time) const;
};
}

View File

@ -15,10 +15,12 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "common/args.hpp" #include "common/args.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "ps1/system.h" #include "ps1/system.h"
extern "C" uint8_t _textStart[]; extern "C" uint8_t _textStart[];

View File

@ -21,12 +21,14 @@
#include "common/file/iso9660.hpp" #include "common/file/iso9660.hpp"
#include "common/file/misc.hpp" #include "common/file/misc.hpp"
#include "common/file/zip.hpp" #include "common/file/zip.hpp"
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -20,6 +20,8 @@
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/file/misc.hpp" #include "common/file/misc.hpp"
#include "common/file/zip.hpp" #include "common/file/zip.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "main/app/cartactions.hpp" #include "main/app/cartactions.hpp"
#include "main/app/cartunlock.hpp" #include "main/app/cartunlock.hpp"

View File

@ -14,7 +14,10 @@
* 573in1. If not, see <https://www.gnu.org/licenses/>. * 573in1. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "main/app/cartactions.hpp" #include "main/app/cartactions.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -15,7 +15,10 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/cartunlock.hpp" #include "main/app/cartunlock.hpp"
#include "main/cart/cartdata.hpp" #include "main/cart/cartdata.hpp"

View File

@ -18,9 +18,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
#include "main/cart/cartdata.hpp" #include "main/cart/cartdata.hpp"

View File

@ -15,7 +15,8 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/main.hpp" #include "main/app/main.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -18,10 +18,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/misc.hpp" #include "main/app/misc.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -17,8 +17,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "common/util/templates.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
#include "main/uicommon.hpp" #include "main/uicommon.hpp"
#include "main/uimodals.hpp" #include "main/uimodals.hpp"

View File

@ -17,12 +17,14 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/idedefs.hpp" #include "common/idedefs.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "ps1/system.h" #include "ps1/system.h"

View File

@ -18,9 +18,11 @@
#include <stdio.h> #include <stdio.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/file/misc.hpp" #include "common/file/misc.hpp"
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/modals.hpp" #include "main/app/modals.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -17,8 +17,8 @@
#pragma once #pragma once
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/templates.hpp"
#include "common/ide.hpp" #include "common/ide.hpp"
#include "common/util.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
#include "main/uicommon.hpp" #include "main/uicommon.hpp"
#include "main/uimodals.hpp" #include "main/uimodals.hpp"

View File

@ -15,9 +15,9 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "common/util/log.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/romactions.hpp" #include "main/app/romactions.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -18,10 +18,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/file/file.hpp" #include "common/file/file.hpp"
#include "common/util/hash.hpp"
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/romdrivers.hpp" #include "common/romdrivers.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/romactions.hpp" #include "main/app/romactions.hpp"

View File

@ -14,10 +14,13 @@
* 573in1. If not, see <https://www.gnu.org/licenses/>. * 573in1. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/app/tests.hpp" #include "main/app/tests.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -16,7 +16,10 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
#include "vendor/miniz.h" #include "vendor/miniz.h"

View File

@ -18,8 +18,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "common/rom.hpp" #include "common/rom.hpp"
#include "common/util.hpp"
namespace cart { namespace cart {

View File

@ -16,7 +16,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
#include "main/cart/cartdata.hpp" #include "main/cart/cartdata.hpp"

View File

@ -19,7 +19,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "common/util.hpp" #include "common/util/templates.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
namespace cart { namespace cart {

View File

@ -15,8 +15,11 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/util/misc.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/util.hpp"
#include "main/cart/cart.hpp" #include "main/cart/cart.hpp"
#include "main/cart/cartio.hpp" #include "main/cart/cartio.hpp"
#include "main/cart/zs01.hpp" #include "main/cart/zs01.hpp"

View File

@ -16,7 +16,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util.hpp" #include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "main/cart/zs01.hpp" #include "main/cart/zs01.hpp"
namespace cart { namespace cart {

View File

@ -14,11 +14,12 @@
* 573in1. If not, see <https://www.gnu.org/licenses/>. * 573in1. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "common/util/hash.hpp"
#include "common/util/log.hpp"
#include "common/args.hpp" #include "common/args.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
#include "main/app/app.hpp" #include "main/app/app.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
#include "ps1/gpucmd.h" #include "ps1/gpucmd.h"

View File

@ -15,11 +15,13 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/util/templates.hpp"
#include "common/util/tween.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/gpufont.hpp" #include "common/gpufont.hpp"
#include "common/io.hpp" #include "common/io.hpp"
#include "common/pad.hpp" #include "common/pad.hpp"
#include "common/util.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
#include "ps1/gpucmd.h" #include "ps1/gpucmd.h"

View File

@ -17,10 +17,11 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "common/util/log.hpp"
#include "common/util/tween.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/gpufont.hpp" #include "common/gpufont.hpp"
#include "common/spu.hpp" #include "common/spu.hpp"
#include "common/util.hpp"
namespace ui { namespace ui {

View File

@ -14,6 +14,7 @@
* 573in1. If not, see <https://www.gnu.org/licenses/>. * 573in1. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "common/util/templates.hpp"
#include "common/defs.hpp" #include "common/defs.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"

View File

@ -17,8 +17,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "common/util/tween.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/util.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
namespace ui { namespace ui {

View File

@ -16,8 +16,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common/util/misc.hpp"
#include "common/util/string.hpp"
#include "common/util/templates.hpp"
#include "common/util/tween.hpp"
#include "common/gpu.hpp" #include "common/gpu.hpp"
#include "common/util.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
#include "main/uimodals.hpp" #include "main/uimodals.hpp"

View File

@ -17,7 +17,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "common/util.hpp" #include "common/util/misc.hpp"
#include "common/util/tween.hpp"
#include "main/uibase.hpp" #include "main/uibase.hpp"
namespace ui { namespace ui {