mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-03-01 15:30:31 +01:00
Update ldscript, split off util.cpp into multiple files
This commit is contained in:
parent
661cba0e1a
commit
3f06ea5c50
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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[];
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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
272
src/common/util/hash.cpp
Normal 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
99
src/common/util/hash.hpp
Normal 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
81
src/common/util/log.cpp
Normal 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
107
src/common/util/log.hpp
Normal 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
211
src/common/util/misc.cpp
Normal 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
139
src/common/util/misc.hpp
Normal 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
167
src/common/util/string.cpp
Normal 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++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
src/common/util/string.hpp
Normal file
47
src/common/util/string.hpp
Normal 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
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
174
src/common/util/templates.hpp
Normal file
174
src/common/util/templates.hpp
Normal 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
63
src/common/util/tween.cpp
Normal 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
72
src/common/util/tween.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -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[];
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user